//===- SectionMap.cpp -----------------------------------------------------===//
//
//                     The MCLinker Project
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include <mcld/Object/SectionMap.h>
#include <mcld/ADT/StringHash.h>
#include <cassert>
#include <cstring>

using namespace mcld;


SectionMap::NamePair SectionMap::NullName;

//===----------------------------------------------------------------------===//
// SectionMap::NamePair
//===----------------------------------------------------------------------===//
SectionMap::NamePair::NamePair()
  : hash(-1) {
}

SectionMap::NamePair::NamePair(const std::string& pFrom, const std::string& pTo)
  : from(pFrom), to(pTo) {
  hash = SectionMap::hash(pFrom);
}

bool SectionMap::NamePair::isNull() const
{
  return (&NullName == this);
}

//===----------------------------------------------------------------------===//
// SectionMap
//===----------------------------------------------------------------------===//
const SectionMap::NamePair& SectionMap::find(const std::string& pFrom) const
{
  unsigned int hash = SectionMap::hash(pFrom);
  return find(pFrom, hash);
}

SectionMap::NamePair& SectionMap::find(const std::string& pFrom)
{
  unsigned int hash = SectionMap::hash(pFrom);
  return find(pFrom, hash);
}

const SectionMap::NamePair&
SectionMap::find(const std::string& pFrom, unsigned int pHash) const
{
  NamePairList::const_iterator name_hash, nEnd = m_NamePairList.end();
  for (name_hash = m_NamePairList.begin(); name_hash != nEnd; ++name_hash) {
    if (matched(*name_hash, pFrom, pHash)) {
      return *name_hash;
    }
  }
  return NullName;
}

SectionMap::NamePair&
SectionMap::find(const std::string& pFrom, unsigned int pHash)
{
  NamePairList::iterator name_hash, nEnd = m_NamePairList.end();
  for (name_hash = m_NamePairList.begin(); name_hash != nEnd; ++name_hash) {
    if (matched(*name_hash, pFrom, pHash)) {
      return *name_hash;
    }
  }
  return NullName;
}

SectionMap::NamePair& SectionMap::append(const std::string &pFrom,
                                         const std::string &pTo,
                                         bool &pExist)
{
  NamePair& result = find(pFrom);
  if (!result.isNull()) {
    pExist = true;
    return result;
  }

  pExist = false;
  NamePair entry(pFrom, pTo);
  m_NamePairList.push_back(entry);
  return m_NamePairList.back();
}

bool SectionMap::matched(const NamePair& pNamePair,
                         const std::string& pInput,
                         unsigned int pHashValue) const
{
  if ('*' == pNamePair.from[0])
    return true;

  if (pNamePair.from.size() > pInput.size())
    return false;

  if (!StringHash<ES>::may_include(pNamePair.hash, pHashValue))
    return false;

  if (0 == strncmp(pInput.c_str(),
                   pNamePair.from.c_str(),
                   pNamePair.from.size())) {
    return true;
  }

  return false;
}

unsigned int SectionMap::hash(const std::string& pString)
{
  static StringHash<ES> hash_func;
  return hash_func(pString);
}