//===- HandleToArea.h -----------------------------------------------------===//
//
//                     The MCLinker Project
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef MCLD_FILE_HANDLE_TO_MEMORY_AREA_H
#define MCLD_FILE_HANDLE_TO_MEMORY_AREA_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
#include <mcld/ADT/Uncopyable.h>
#include <mcld/ADT/TypeTraits.h>
#include <mcld/ADT/StringHash.h>
#include <mcld/Support/Path.h>
#include <mcld/Support/FileHandle.h>
#include <vector>

namespace mcld
{

class MemoryArea;

/** \class HandleToArea
 *
 *  Special double-key associative container. Keys are Path and file handler,
 *  associative value is MemoryArea.
 *
 *  For high performance, HandleToArea is not designed to contain unique
 *  <key, value> pair. The key and value may be duplicated.
 *
 *  Like FileHandle, HandleToArea should neither throw exception nor call
 *  expressive diagnostic.
 */
class HandleToArea : private Uncopyable
{
private:
  struct Bucket {
    unsigned int hash_value;
    FileHandle* handle;
    MemoryArea* area;
  };

  // the best data structure is a binary search tree.
  // However, by the shrinking time-to-market constraint, I used
  // vector and sequential search here.
  typedef std::vector<Bucket> HandleToAreaMap;

  typedef StringHash<BKDR> HashFunction;

public:
  typedef HandleToAreaMap::iterator iterator;
  typedef HandleToAreaMap::const_iterator const_iterator;

public:
  struct Result {
  public:
    Result(FileHandle* pHandle, MemoryArea* pArea)
      : handle(pHandle), area(pArea) { }

  public:
    FileHandle* handle;
    MemoryArea* area;
  };

  struct ConstResult {
  public:
    ConstResult(const FileHandle* pHandle, const MemoryArea* pArea)
      : handle(pHandle), area(pArea) { }

  public:
    const FileHandle* handle;
    const MemoryArea* area;
  };

public:
  bool push_back(FileHandle* pHandle, MemoryArea* pArea);

  bool erase(MemoryArea* pArea);

  bool erase(const sys::fs::Path& pPath);

  Result findFirst(const sys::fs::Path& pPath);

  ConstResult findFirst(const sys::fs::Path& pPath) const;

  iterator begin()
  { return m_AreaMap.begin(); }

  iterator end()
  { return m_AreaMap.end(); }

  const_iterator begin() const
  { return m_AreaMap.begin(); }

  const_iterator end() const
  { return m_AreaMap.end(); }

  // -----  capacity  ----- //
  bool empty() const
  { return m_AreaMap.empty(); }

  size_t size() const
  { return m_AreaMap.size(); }

  HandleToArea() : m_AreaMap() { }

  ~HandleToArea() { }

private:
  HandleToAreaMap m_AreaMap;
};

} // namespace of mcld

#endif