/*	Copyright (C) 2007 Garrett A. Kajmowicz
	This file is part of the uClibc++ Library.

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library 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
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the Free Software
	Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

#ifndef __STD_HEADER_ASSOCIATIVE_BASE
#define __STD_HEADER_ASSOCIATIVE_BASE
#include "list"

#pragma GCC visibility push(default)

namespace std
{

	/*
	 *	The basic premise here is that most of the code used by map, multimap, set and
	 *	multiset is really common.  There are a number of interface additions, and
	 *	considerations about how to address multiple entries with the same key.
	 *	The goal is that the tree/storage code should be here, and managing
	 *	single or multiple counts will be left to subclasses.
	 *	Yes, inheritence for the purpose of code sharing is usually a bad idea.
	 *	However, since our goal is to reduce the total amount of code written
	 *	and the overall binary size, this seems to be the best approach possible.
	 */

	template <class Key, class ValueType, class Compare = less<Key>, class Allocator = allocator<ValueType>>
	class __base_associative;
	template <class ValueType, class Compare, class Allocator>
	class _associative_iter;
	template <class ValueType, class Compare, class Allocator>
	class _associative_citer;

	template <class Key, class ValueType, class Compare = less<Key>, class Allocator = allocator<ValueType>>
	class __single_associative;
	template <class Key, class ValueType, class Compare = less<Key>, class Allocator = allocator<ValueType>>
	class __multi_associative;

	template <class Key, class ValueType, class Compare, class Allocator>
	class _UCXXEXPORT __base_associative
	{

	protected:
	public:
		typedef Key key_type;
		typedef ValueType value_type;
		typedef Compare key_compare;
		typedef Allocator allocator_type;
		typedef typename Allocator::reference reference;
		typedef typename Allocator::const_reference const_reference;
		typedef typename Allocator::size_type size_type;
		typedef typename Allocator::difference_type difference_type;
		typedef typename Allocator::pointer pointer;
		typedef typename Allocator::const_pointer const_pointer;
		typedef __base_associative<Key, ValueType, Compare, Allocator> associative_type;

		typedef _associative_iter<value_type, Compare, Allocator> iterator;
		typedef _associative_citer<value_type, Compare, Allocator> const_iterator;
		typedef typename std::reverse_iterator<iterator> reverse_iterator;
		typedef typename std::reverse_iterator<const_iterator> const_reverse_iterator;

		explicit __base_associative(const Compare &comp, const Allocator &A, const key_type (*v_to_k)(const value_type))
			: c(comp), value_to_key(v_to_k) {}

	protected:
		__base_associative(const associative_type &x)
			: c(x.c), backing(x.backing), value_to_key(x.value_to_key) {}

	public:
		~__base_associative()
		{
		}

		bool empty() const
		{
			return backing.empty();
		}
		size_type size() const
		{
			return backing.size();
		}
		size_type max_size() const
		{
			return backing.max_size();
		}

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

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

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

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

		reverse_iterator rbegin()
		{
			return reverse_iterator(end());
		}

		const_reverse_iterator rbegin() const
		{
			return const_reverse_iterator(end());
		}

		reverse_iterator rend()
		{
			return reverse_iterator(begin());
		}

		const_reverse_iterator rend() const
		{
			return const_reverse_iterator(begin());
		}

		iterator lower_bound(const key_type &x);
		const_iterator lower_bound(const key_type &x) const;
		iterator upper_bound(const key_type &x);
		const_iterator upper_bound(const key_type &x) const;

		pair<iterator, iterator> equal_range(const key_type &x)
		{
			pair<iterator, iterator> retval;
			retval.first = lower_bound(x);
			retval.second = retval.first;
			while (retval.second != end() && !c(x, value_to_key(*retval.second)))
			{
				++retval.second;
			}
			return retval;
		}
		pair<const_iterator, const_iterator> equal_range(const key_type &x) const
		{
			pair<const_iterator, const_iterator> retval;
			retval.first = lower_bound(x);
			retval.second = retval.first;
			while (retval.second != end() && !c(x, value_to_key(*retval.second)))
			{
				++retval.second;
			}
			return retval;
		}

		iterator find(const key_type &x)
		{
			iterator retval = lower_bound(x);
			if (retval == end())
			{
				return retval;
			}
			if (c(x, value_to_key(*retval)))
			{
				return end();
			}
			return retval;
		}
		const_iterator find(const key_type &x) const
		{
			const_iterator retval = lower_bound(x);
			if (retval == end())
			{
				return retval;
			}
			if (c(x, value_to_key(*retval)))
			{
				return end();
			}
			return retval;
		}
		size_type count(const key_type &x) const
		{
			size_type retval(0);
			const_iterator first = lower_bound(x);
			while (first != end() && !c(x, value_to_key(*first)))
			{
				++retval;
				++first;
			}
			return retval;
		}

		void clear()
		{
			backing.clear();
		}

		void erase(iterator pos)
		{
			backing.erase(pos.base_iterator());
		}
		size_type erase(const key_type &x)
		{
			size_type count(0);
			iterator start = lower_bound(x);
			iterator end = upper_bound(x);
			while (start != end)
			{
				start = backing.erase(start.base_iterator());
				++count;
			}
			return count;
		}
		void erase(iterator first, iterator last)
		{
			while (first != last)
			{
				first = backing.erase(first.base_iterator());
			}
		}

		key_compare key_comp() const
		{
			return c;
		}

		__base_associative &operator=(const __base_associative &x)
		{
			c = x.c;
			backing = x.backing;
			value_to_key = x.value_to_key;
			return *this;
		}
		bool operator==(const __base_associative &x)
		{
			return x.backing == backing;
		}
		bool operator!=(const __base_associative &x)
		{
			return !(x.backing == backing);
		}

		void swap(__base_associative &x);
	protected:

		Compare c;
		std::list<value_type> backing;

		const key_type (*value_to_key)(const value_type);
	};

	/*
	 * Tree iterators for the base associative class
	 */

	template <class ValueType, class Compare, class Allocator>
	class _associative_citer
		: public std::iterator<
			  bidirectional_iterator_tag,
			  ValueType,
			  typename Allocator::difference_type,
			  ValueType *,
			  ValueType &>
	{
	protected:
		typedef std::list<ValueType> listtype;

		typename listtype::const_iterator base_iter;
		friend class _associative_iter<ValueType, Compare, Allocator>;

	public:
		_associative_citer() {}
		_associative_citer(const _associative_citer &m)
			: base_iter(m.base_iter) {}
		_associative_citer(const typename listtype::const_iterator &m)
			: base_iter(m) {}
		~_associative_citer() {}
		ValueType operator*() const
		{
			return *base_iter;
		}
		const ValueType *operator->() const
		{
			return &(*base_iter);
		}
		_associative_citer &operator=(const _associative_citer &m)
		{
			base_iter = m.base_iter;
			return *this;
		}
		bool operator==(const _associative_citer &m) const
		{
			return m.base_iter == base_iter;
		}
		bool operator!=(const _associative_citer &m) const
		{
			return m.base_iter != base_iter;
		}
		_associative_citer &operator++()
		{
			++base_iter;
			return *this;
		}
		_associative_citer operator++(int)
		{
			// The following approach ensures that we only need to
			// provide code for ++ in one place (above)
			_associative_citer temp(base_iter);
			++base_iter;
			return temp;
		}
		_associative_citer &operator--()
		{
			--base_iter;
			return *this;
		}
		_associative_citer operator--(int)
		{
			// The following approach ensures that we only need to
			// provide code for -- in one place (above)
			_associative_citer temp(base_iter);
			--base_iter;
			return temp;
		}

		// This is an implementation-defined function designed to make internals work correctly
		typename listtype::const_iterator base_iterator()
		{
			return base_iter;
		}
	};

	template <class ValueType, class Compare, class Allocator>
	class _associative_iter
		: public std::iterator<
			  bidirectional_iterator_tag,
			  ValueType,
			  typename Allocator::difference_type,
			  ValueType *,
			  ValueType &>
	{
	protected:
		typedef std::list<ValueType> listtype;

		typename listtype::iterator base_iter;
		typedef _associative_citer<ValueType, Compare, Allocator> __associative_citer;

	public:
		_associative_iter() {}
		_associative_iter(const _associative_iter &m)
			: base_iter(m.base_iter) {}
		_associative_iter(const typename listtype::iterator &m)
			: base_iter(m) {}
		~_associative_iter() {}
		const ValueType &operator*() const
		{
			return *base_iter;
		}
		ValueType &operator*()
		{
			return *base_iter;
		}
		ValueType *operator->()
		{
			return &(*base_iter);
		}
		const ValueType *operator->() const
		{
			return &(*base_iter);
		}
		_associative_iter &operator=(const _associative_iter &m)
		{
			base_iter = m.base_iter;
			return *this;
		}
		bool operator==(const _associative_iter &m) const
		{
			return m.base_iter == base_iter;
		}
		bool operator==(const __associative_citer &m) const
		{
			return m.base_iter == base_iter;
		}
		bool operator!=(const _associative_iter &m) const
		{
			return m.base_iter != base_iter;
		}
		bool operator!=(const __associative_citer &m) const
		{
			return m.base_iter != base_iter;
		}
		_associative_iter &operator++()
		{
			++base_iter;
			return *this;
		}
		_associative_iter operator++(int)
		{
			// The following approach ensures that we only need to
			// provide code for ++ in one place (above)
			_associative_iter temp(base_iter);
			++base_iter;
			return temp;
		}
		_associative_iter &operator--()
		{
			--base_iter;
			return *this;
		}
		_associative_iter operator--(int)
		{
			// The following approach ensures that we only need to
			// provide code for -- in one place (above)
			_associative_iter temp(base_iter);
			--base_iter;
			return temp;
		}
		operator __associative_citer() const
		{
			return __associative_citer(base_iter);
		}
		typename listtype::iterator base_iterator()
		{
			return base_iter;
		}
		const typename listtype::iterator base_iterator() const
		{
			return base_iter;
		}
	};

	// The lower_bound code is really crappy linear search.  However, it is a dead
	// simple implementation (easy to audit).  It can also be easily replaced.

	template <class Key, class ValueType, class Compare, class Allocator>
	typename __base_associative<Key, ValueType, Compare, Allocator>::iterator
	__base_associative<Key, ValueType, Compare, Allocator>::lower_bound(const key_type &x)
	{
		iterator retval = begin();
		while (retval != end() && c(value_to_key(*retval), x))
		{
			++retval;
		}
		return retval;
	}

	template <class Key, class ValueType, class Compare, class Allocator>
	typename __base_associative<Key, ValueType, Compare, Allocator>::const_iterator
	__base_associative<Key, ValueType, Compare, Allocator>::lower_bound(const key_type &x) const
	{
		const_iterator retval = begin();
		while (retval != end() && c(value_to_key(*retval), x))
		{
			++retval;
		}
		return retval;
	}

	// Upper bound search is linear from the point of lower_bound.  This is likely the best solution
	// in all but the most pathological of cases.

	template <class Key, class ValueType, class Compare, class Allocator>
	typename __base_associative<Key, ValueType, Compare, Allocator>::iterator
	__base_associative<Key, ValueType, Compare, Allocator>::upper_bound(const key_type &x)
	{
		iterator retval = lower_bound(x);
		while (retval != end() && !c(x, value_to_key(*retval)))
		{
			++retval;
		}
		return retval;
	}

	template <class Key, class ValueType, class Compare, class Allocator>
	typename __base_associative<Key, ValueType, Compare, Allocator>::const_iterator
	__base_associative<Key, ValueType, Compare, Allocator>::upper_bound(const key_type &x) const
	{
		const_iterator retval = begin();
		while (retval != end() && !c(x, value_to_key(*retval)))
		{
			++retval;
		}
		return retval;
	}

	template <class Key, class ValueType, class Compare, class Allocator>
	void __base_associative<Key, ValueType, Compare, Allocator>::swap(__base_associative<Key, ValueType, Compare, Allocator> &m)
	{
		Compare n = c;
		c = m.c;
		m.c = n;

		m.backing.swap(backing);
	}

	template <class Key, class ValueType, class Compare, class Allocator>
	class _UCXXEXPORT __single_associative : public __base_associative<Key, ValueType, Compare, Allocator>
	{
	protected:
		typedef __base_associative<Key, ValueType, Compare, Allocator> base;
		using base::backing;

		using base::c;

	public:
		typedef typename base::key_type key_type;
		typedef typename base::value_type value_type;
		typedef typename base::key_compare key_compare;
		typedef typename base::allocator_type allocator_type;
		typedef typename base::reference reference;
		typedef typename base::const_reference const_reference;
		typedef typename base::iterator iterator;
		typedef typename base::const_iterator const_iterator;
		typedef typename base::size_type size_type;
		typedef typename base::difference_type difference_type;
		typedef typename base::pointer pointer;
		typedef typename base::const_pointer const_pointer;
		typedef typename base::reverse_iterator reverse_iterator;
		typedef typename base::const_reverse_iterator const_reverse_iterator;

		using base::begin;
		using base::end;
		using base::rbegin;
		using base::rend;

		using base::empty;
		using base::max_size;
		using base::size;

		using base::count;
		using base::equal_range;
		using base::find;
		using base::lower_bound;
		using base::upper_bound;

		using base::operator=;
		using base::operator==;
		using base::operator!=;

		explicit __single_associative(const Compare &comp, const Allocator &A, const key_type (*v_to_k)(const value_type))
			: base(comp, A, v_to_k) {}

		template <class InputIterator>
		__single_associative(
			InputIterator first,
			InputIterator last,
			const Compare &comp,
			const Allocator &A,
			const key_type (*v_to_k)(const value_type)) : base(comp, A, v_to_k)
		{
			insert(first, last);
		}

		pair<iterator, bool> insert(const value_type &x)
		{
			pair<iterator, bool> retval;
			iterator location = lower_bound(this->value_to_key(x));
			retval.second = true;
			// Empty list or need to insert at end
			if (end() == location)
			{
				backing.push_back(x);
				retval.first = --(end());
				return retval;
			}
			// Something in the list
			if (c(this->value_to_key(x), this->value_to_key(*location)))
			{
				location = backing.insert(location.base_iterator(), x);
				retval.first = location;
			}
			else
			{
				retval.second = false;
				retval.first = location;
			}
			return retval;
		}

		iterator insert(iterator position, const value_type &x)
		{
			// FIXME - this is cheating and probably should be more efficient since we are
			// now log(n) to find for inserts
			return insert(x).first;
		}

		template <class InputIterator>
		void insert(InputIterator first, InputIterator last)
		{
			while (first != last)
			{
				insert(*first);
				++first;
			}
		}
	};

	template <class Key, class ValueType, class Compare, class Allocator>
	class _UCXXEXPORT __multi_associative : public __base_associative<Key, ValueType, Compare, Allocator>
	{
	protected:
		typedef __base_associative<Key, ValueType, Compare, Allocator> base;
		using base::backing;

		using base::c;

	public:
		typedef typename base::key_type key_type;
		typedef typename base::value_type value_type;
		typedef typename base::key_compare key_compare;
		typedef typename base::allocator_type allocator_type;
		typedef typename base::reference reference;
		typedef typename base::const_reference const_reference;
		typedef typename base::iterator iterator;
		typedef typename base::const_iterator const_iterator;
		typedef typename base::size_type size_type;
		typedef typename base::difference_type difference_type;
		typedef typename base::pointer pointer;
		typedef typename base::const_pointer const_pointer;
		typedef typename base::reverse_iterator reverse_iterator;
		typedef typename base::const_reverse_iterator const_reverse_iterator;

		using base::begin;
		using base::end;
		using base::rbegin;
		using base::rend;

		using base::empty;
		using base::max_size;
		using base::size;

		using base::count;
		using base::equal_range;
		using base::find;
		using base::lower_bound;
		using base::upper_bound;

		using base::operator=;
		using base::operator==;

		explicit __multi_associative(const Compare &comp, const Allocator &A, const key_type (*v_to_k)(const value_type))
			: base(comp, A, v_to_k) {}

		template <class InputIterator>
		__multi_associative(
			InputIterator first,
			InputIterator last,
			const Compare &comp,
			const Allocator &A,
			const key_type (*v_to_k)(const value_type)) : base(comp, A, v_to_k)
		{
			insert(first, last);
		}

		iterator insert(const value_type &x)
		{
			iterator location = lower_bound(this->value_to_key(x));

			if (location == begin())
			{
				backing.push_front(x);
				location = begin();
			}
			else
			{
				location = backing.insert(location.base_iterator(), x);
			}
			return location;
		}

		iterator insert(iterator position, const value_type &x)
		{
			// FIXME - this is cheating and probably should be more efficient since we are
			// now log(n) to find for inserts
			return insert(x);
		}

		template <class InputIterator>
		void insert(InputIterator first, InputIterator last)
		{
			while (first != last)
			{
				insert(*first);
				++first;
			}
		}
	};

}

#pragma GCC visibility pop

#endif //__STD_HEADER_ASSOCIATIVE_BASE
