/* Copyright (c) 1997-2010
   Ewgenij Gawrilow, Michael Joswig (Technische Universitaet Darmstadt, Germany)
   http://www.polymake.de

   This program is free software; you can redistribute it and/or modify it
   under the terms of the GNU General Public License as published by the
   Free Software Foundation; either version 2, or (at your option) any
   later version: http://www.gnu.org/licenses/gpl.txt.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
--------------------------------------------------------------------------------
   $Project: polymake $$Id: hash_map 9436 2010-02-03 01:08:34Z gawrilow $
*/

#ifndef _POLYMAKE_HASH_MAP
#define _POLYMAKE_HASH_MAP

#if defined(__GNUC__)
#if __GNUC__>4 || __GNUC__==4 && __GNUC_MINOR__>=2
#  include <tr1/unordered_map>
#  define pm_hash_map_impl std::tr1::unordered_map
#else  // gcc<=4.1
#  include <ext/hash_map>
#  define pm_hash_map_impl __gnu_cxx::hash_map
#endif

#include <assoc.h>
#include <hash_iterators.h>

namespace pm {

template <typename Key, typename Value, typename Params=void>
class hash_map :
   public pm_hash_map_impl<Key, Value, hash_func<Key>, typename hash_table_cmp_adapter<Key,Params>::type> {
   typedef pm_hash_map_impl<Key, Value, hash_func<Key>, typename hash_table_cmp_adapter<Key,Params>::type> _super;

   typedef typename extract_type_param<Params, DefaultValue, operations::clear<Value> >::type default_value_supplier;
   default_value_supplier dflt;

public:
   hash_map() {}
   explicit hash_map(size_t start_cap) : _super(start_cap) {}

   explicit hash_map(const default_value_supplier& dflt_arg) : dflt(dflt_arg) {}

   hash_map(const default_value_supplier& dflt_arg, size_t start_cap) : _super(start_cap), dflt(dflt_arg) {}

   template <typename Iterator>
   hash_map(Iterator first, Iterator last) : _super(first,last) {}

   template <typename Iterator>
   hash_map(Iterator first, Iterator last, const default_value_supplier& dflt_arg) : _super(first,last), dflt(dflt_arg) {}

   typename _super::iterator
   insert(typename function_argument<Key>::type k)
   {
      return _super::insert(typename _super::value_type(k, dflt())).first;
   }

   template <typename Operation>
   typename _super::iterator
   insert(typename function_argument<Key>::type k, const Operation& op, typename disable_if<int, identical<Operation,Value>::value>::type=0)
   {
      std::pair<typename _super::iterator,bool> ret=_super::insert(typename _super::value_type(k, dflt()));
      if (!ret.second) op(ret.first->second);
      return ret.first;
   }

   typename _super::iterator
   insert(typename function_argument<Key>::type k, typename function_argument<Value>::type v)
   {
      std::pair<typename _super::iterator,bool> ret=_super::insert(typename _super::value_type(k,v));
      if (!ret.second) ret.first->second=v;
      return ret.first;
   }

   template <typename Operation>
   typename _super::iterator
   insert(typename function_argument<Key>::type k, typename function_argument<Value>::type v, const Operation& op)
   {
      std::pair<typename _super::iterator,bool> ret=_super::insert(typename _super::value_type(k,v));
      if (!ret.second) op(ret.first->second,v);
      return ret.first;
   }

   std::pair<typename _super::iterator,bool>
   insert(const typename _super::value_type& p) { return _super::insert(p); }

   template <typename Iterator>
   void insert(Iterator first, Iterator last, typename disable_if<int, identical<Iterator,Key>::value && identical<Iterator,Value>::value>::type=0)
   {
      _super::insert(first,last);
   }

   bool operator== (const hash_map& other) const
   {
      if (this->size() != other.size()) return false;
      typename _super::const_iterator not_found=this->end();
      for (typename _super::const_iterator elem=other.begin(), other_end=other.end(); elem != other_end; ++elem) {
	 typename _super::const_iterator my=this->find(elem->first);
	 if (my==not_found || my->second != elem->second)
	    return false;
      }
      return true;
   }

   bool operator!= (const hash_map& other) const { return !operator==(other); }
};

template <typename Key, typename Value, typename Params>
struct spec_object_traits< hash_map<Key,Value,Params> >
   : spec_object_traits<is_container> {
   static const IO_separator_kind IO_separator=IO_sep_inherit;
};

// FIXME: soon deprecated
template <typename Key, typename Value, typename HashFcn=hash_func<Key>, typename EqualKey=std::equal_to<Key> >
class hash_map_as_property_map
   : public pm_hash_map_impl<Key, Value, HashFcn, EqualKey> {
   typedef pm_hash_map_impl<Key, Value, HashFcn, EqualKey> _super;
public:
   hash_map_as_property_map() {}

   explicit hash_map_as_property_map(size_t start_cap)
      : _super(start_cap) {}

   Value& operator() (const Key& k)
   {
      return (_super::insert(typename _super::value_type(k, def_val))).first->second;
   }

   const Value& operator() (const Key& k) const
   {
      typename _super::const_iterator ii=this->find(k);
      return ii==this->end() ? def_val : ii->second;
   }

   std::pair<typename _super::iterator, bool>
   insert(const Key& k, typename function_argument<Value>::type v)
   {
      return _super::insert(typename _super::value_type(k, v));
   }

   void set_default_value(typename function_argument<Value>::type default_value)
   {
      def_val=default_value;
   }
protected:
   Value def_val;
};

} // end namespace pm

namespace polymake {
   using pm::hash_map;
}

#undef pm_hash_map_impl

#endif // GNUC
#endif // _POLYMAKE_HASH_MAP

// Local Variables:
// mode:C++
// End:
