#ifndef H_CORAL_AUTOVECTOR
#define H_CORAL_AUTOVECTOR
// This file is part of the Coral project.
// Please read the copyright notice in the LICENSE file.

#include <coral/lib/ref_counted.h>

#include <list>
#include <vector>
#include <map>
#include <set>
#include <functional>

#include <ext/hash_set>
#include <ext/hash_map>

#define DEL_ALL do { \
	  for (iterator i = this->begin(); \
	       i != this->end(); \
	       ++i) { \
	       delete *i; \
	  } \
	  } while (0)

/*
  Simple vector class which deletes the contents of the pointers
  upon destruction.
*/
template <class T>
class autovector : public std::vector<T> {
 public:
     typedef typename std::vector<T>::iterator iterator;
     autovector() : std::vector<T>() { ; }
     ~autovector() throw () {
	  DEL_ALL;
     }
};

/*
  Simple map class which deletes both .first and .second upon destruction.
*/
template <class K, class T, typename Comp>
class automap : public std::map<K, T, Comp> {
 public:
     typedef typename std::map<K, T, Comp>::iterator iterator;
     automap() : std::map<K, T, Comp>() { ; }
     ~automap() throw () {
	  for (iterator i = this->begin();
	       i != this->end();
	       ++i) {
	       delete (*i).first;
	       delete (*i).second;
	  }
     }
};

/*
  Simple map class which deletes .second upon destruction.
*/
template <class K, class T, typename Comp>
class auto2map : public std::map<K, T, Comp> {
 public:
     typedef typename std::map<K, T, Comp>::iterator iterator;
     auto2map() : std::map<K, T, Comp>() { ; }
     ~auto2map() throw () {
	  for (iterator i = this->begin();
	       i != this->end();
	       ++i) {
	       delete (*i).second;
	  }
     }
};

/*
  Simple map class which deletes .first upon destruction.
*/
template <class K, class T, typename Comp>
class auto1map : public std::map<K, T, Comp> {
 public:
     typedef typename std::map<K, T, Comp>::iterator iterator;
     auto1map() : std::map<K, T, Comp>() { ; }
     ~auto1map() throw () {
	  for (iterator i = this->begin();
	       i != this->end();
	       ++i) {
	       delete (*i).first;
	  }
     }
};

/*
  Simple list class which deletes the contents of the pointers
  upon destruction.
*/
template <class T>
class autolist : public std::list<T> {
 public:
     typedef typename std::list<T>::iterator iterator;
     autolist() : std::list<T>() { ; }
     ~autolist() throw () {
	  DEL_ALL;
     }
};

/*
  Simple hash_set class which deletes the contents of the pointers
  upon destruction.
*/
template <class T>
class autohash_set : public __gnu_cxx::hash_set<T> {
 public:
     typedef typename __gnu_cxx::hash_set<T>::iterator iterator;
     autohash_set() : __gnu_cxx::hash_set<T>() { ; }
     ~autohash_set() throw () {
	  DEL_ALL;
     }
};

/*
  Simple hash_map class which deletes the contents of the pointers
  upon destruction.
*/
template <class _Key, class _Data>
class autohash_map : public __gnu_cxx::hash_map<_Key, _Data> {
 public:
     typedef typename __gnu_cxx::hash_map<_Key, _Data>::iterator iterator;
     autohash_map() : __gnu_cxx::hash_map<_Key, _Data>() { ; }
     ~autohash_map() throw () {
	  DEL_ALL;
     }
};


/*
  Simple set class which deletes the contents of the pointers
  upon destruction.
*/
template <class _Key, class _Cmp>
class autoset : public std::set<_Key, _Cmp> {
 public:
     typedef typename std::set<_Key, _Cmp>::iterator iterator;
     autoset() : std::set<_Key, _Cmp>() { ; }
     ~autoset() throw () {
	  DEL_ALL;
     }
};


/***********************************************************************/

#define UNREF_ALL(containertype) \
  for (iterator i = containertype::begin(); \
	 i != containertype::end(); \
       ++i) { \
    (*i)->unref(); \
  }
//  std::for_each(this->begin(), this->end(), std::mem_fun(&coral::ref_counted::unref))

#define UNREF_ALL_TWICE do { \
	  for (iterator i = this->begin(); \
	       i != this->end(); \
	       ++i) { \
	       (*i).second->unref(); \
	       (*i).first->unref(); \
	  } \
	  } while (0)

/*
  Simple vector class which unrefs the contents of the pointers
  upon destruction.
*/
template <class T>
class autounrefvector : public std::vector<T> {
 public:
     typedef typename std::vector<T>::iterator iterator;
     autounrefvector() : std::vector<T>() { ; }
     ~autounrefvector() throw () {
       UNREF_ALL(std::vector<T>);
     }
};

/*
  Simple map class which unrefs .first and .second upon destruction.
*/
template <class K, class T, typename Comp>
class autounrefmap : public std::map<K, T, Comp> {
 public:
     typedef typename std::map<K, T, Comp>::iterator iterator;
     autounrefmap() : std::map<K, T, Comp>() { ; }
     ~autounrefmap() throw () {
	  for (iterator i = this->begin();
	       i != this->end();
	       ++i) {
	       (*i).first->unref();
	       (*i).second->unref();
	  }
     }
};

/*
  Simple map class which unrefs .first upon destruction.
*/
template <class K, class T, typename Comp>
class auto1unrefmap : public std::map<K, T, Comp> {
 public:
     typedef typename std::map<K, T, Comp>::iterator iterator;
     auto1unrefmap() : std::map<K, T, Comp>() { ; }
     ~auto1unrefmap() throw () {
	  for (iterator i = this->begin();
	       i != this->end();
	       ++i) {
	       (*i).first->unref();
	  }
     }
};

/*
  Simple map class which unrefs .second upon destruction.
*/
template <class K, class T, typename Comp = std::less<K> >
class auto2unrefmap : public std::map<K, T, Comp> {
 public:
     typedef typename std::map<K, T, Comp>::iterator iterator;
     auto2unrefmap() : std::map<K, T, Comp>() { ; }
     ~auto2unrefmap() throw () {
	  for (iterator i = this->begin();
	       i != this->end();
	       ++i) {
	       (*i).second->unref();
	  }
     }
};

/*
  Simple list class which unrefs the contents of the pointers
  upon destruction.
*/
template <class T>
class autounreflist : public std::list<T> {
 public:
     typedef typename std::list<T>::iterator iterator;
     autounreflist() : std::list<T>() { ; }
     ~autounreflist() throw () {
       UNREF_ALL(std::list<T>);
     }
};

/*
  Simple hash_set class which unrefs the contents of the pointers
  upon destruction.
*/
template <class T>
class autounrefhash_set : public __gnu_cxx::hash_set<T> {
 public:
     typedef typename __gnu_cxx::hash_set<T>::iterator iterator;
     autounrefhash_set() : __gnu_cxx::hash_set<T>() { ; }
     ~autounrefhash_set() throw () {
       UNREF_ALL(__gnu_cxx::hash_set<T>);
     }
};

/*
  Simple hash_map class which unrefs the contents of the pointers
  upon destruction.
*/
template <class _Key, class _Data, class _Hashfunc>
class autounrefhash_map : public __gnu_cxx::hash_map<_Key, _Data, _Hashfunc> {
 public:
     typedef typename __gnu_cxx::hash_map<_Key, _Data, _Hashfunc>::iterator iterator;
     autounrefhash_map() : __gnu_cxx::hash_map<_Key, _Data, _Hashfunc>() { ; }
     ~autounrefhash_map() throw () {
	  UNREF_ALL_TWICE;
     }
};

/*
  Simple set class which deletes the contents of the pointers
  upon destruction.
*/
template <class _Key, class _Cmp>
class autounrefset : public std::set<_Key, _Cmp> {
 public:
     typedef typename std::set<_Key, _Cmp>::iterator iterator;
     autounrefset() : std::set<_Key, _Cmp>() { ; }
     ~autounrefset() throw () {
       for (iterator i = std::set<_Key, _Cmp>::begin();
	    i != std::set<_Key, _Cmp>::end();
	    ++i) {
	 (*i)->unref();
       }
     }
};

#undef UNREF_ALL
#undef DEL_ALL

#endif
