// VectorSet.h
//
// Copyright (c) 2003, Ingo Weinhold (bonefish@cs.tu-berlin.de)
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation 
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
// 
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
// 
// Except as contained in this notice, the name of a copyright holder shall
// not be used in advertising or otherwise to promote the sale, use or other
// dealings in this Software without prior written authorization of the
// copyright holder.

#ifndef _VECTOR_SET_H
#define _VECTOR_SET_H

#include <new>
#include <stdlib.h>
#include <string.h>

#include <SupportDefs.h>

#include <Vector.h>

// element orders
namespace VectorSetOrder {
	template<typename Value> class Ascending;
	template<typename Value> class Descending;
}

// for convenience
#define _VECTOR_SET_TEMPLATE_LIST template<typename Value, \
										   typename ElementOrder>
#define _VECTOR_SET_CLASS_NAME VectorSet<Value, ElementOrder>

/*!
	\class VectorSet
	\brief A generic vector-based set implementation.

	The elements of the set are ordered according to the supplied
	compare function object. Default is ascending order.
*/
template<typename Value,
		 typename ElementOrder = VectorSetOrder::Ascending<Value> >
class VectorSet {
private:
	typedef Vector<Value>							ElementVector;

public:
	typedef typename ElementVector::Iterator		Iterator;
	typedef typename ElementVector::ConstIterator	ConstIterator;

private:
	static const size_t				kDefaultChunkSize = 10;
	static const size_t				kMaximalChunkSize = 1024 * 1024;

public:
	VectorSet(size_t chunkSize = kDefaultChunkSize);
// TODO: Copy constructor, assignment operator.
	~VectorSet();

	status_t Insert(const Value &value, bool replace = true);

	int32 Remove(const Value &value);
	Iterator Erase(const Iterator &iterator);

	inline int32 Count() const;
	inline bool IsEmpty() const;
	void MakeEmpty();

	inline Iterator Begin();
	inline ConstIterator Begin() const;
	inline Iterator End();
	inline ConstIterator End() const;
	inline Iterator Null();
	inline ConstIterator Null() const;

	Iterator Find(const Value &value);
	ConstIterator Find(const Value &value) const;
	Iterator FindClose(const Value &value, bool less);
	ConstIterator FindClose(const Value &value, bool less) const;

private:
	int32 _FindInsertionIndex(const Value &value, bool &exists) const;

private:
	ElementVector	fElements;
	ElementOrder	fCompare;
};


// VectorSet

// constructor
/*!	\brief Creates an empty set.
	\param chunkSize The granularity for the underlying vector's capacity,
		   i.e. the minimal number of elements the capacity grows or shrinks
		   when necessary.
*/
_VECTOR_SET_TEMPLATE_LIST
_VECTOR_SET_CLASS_NAME::VectorSet(size_t chunkSize)
	: fElements(chunkSize)
{
}

// destructor
/*!	\brief Frees all resources associated with the object.

	The contained elements are destroyed. Note, that, if the element
	type is a pointer type, only the pointer is destroyed, not the object
	it points to.
*/
_VECTOR_SET_TEMPLATE_LIST
_VECTOR_SET_CLASS_NAME::~VectorSet()
{
}

// Insert
/*!	\brief Inserts a copy of the the supplied value.

	If an element with the supplied value is already in the set, the
	operation will not fail, but return \c B_OK. \a replace specifies
	whether the element shall be replaced with the supplied in such a case.
	Otherwise \a replace is ignored.

	\param value The value to be inserted.
	\param replace If the an element with this value does already exist and
		   \a replace is \c true, the element is replaced, otherwise left
		   untouched.
	\return
	- \c B_OK: Everything went fine.
	- \c B_NO_MEMORY: Insufficient memory for this operation.
*/
_VECTOR_SET_TEMPLATE_LIST
status_t
_VECTOR_SET_CLASS_NAME::Insert(const Value &value, bool replace)
{
	bool exists = false;
	int32 index = _FindInsertionIndex(value, exists);
	if (exists) {
		if (replace)
			fElements[index] = value;
		return B_OK;
	}
	return fElements.Insert(value, index);
}

// Remove
/*!	\brief Removes the element with the supplied value.
	\param value The value of the element to be removed.
	\return The number of removed occurrences, i.e. \c 1, if the set
			contained an element with the value, \c 0 otherwise.
*/
_VECTOR_SET_TEMPLATE_LIST
int32
_VECTOR_SET_CLASS_NAME::Remove(const Value &value)
{
	bool exists = false;
	int32 index = _FindInsertionIndex(value, exists);
	if (!exists)
		return 0;
	fElements.Erase(index);
	return 1;
}

// Erase
/*!	\brief Removes the element at the given position.
	\param iterator An iterator referring to the element to be removed.
	\return An iterator referring to the element succeeding the removed
			one (End(), if it was the last element that has been
			removed), or Null(), if \a iterator was an invalid iterator
			(in this case including End()).
*/
_VECTOR_SET_TEMPLATE_LIST
_VECTOR_SET_CLASS_NAME::Iterator
_VECTOR_SET_CLASS_NAME::Erase(const Iterator &iterator)
{
	return fElements.Erase(iterator);
}

// Count
/*!	\brief Returns the number of elements the set contains.
	\return The number of elements the set contains.
*/
_VECTOR_SET_TEMPLATE_LIST
inline
int32
_VECTOR_SET_CLASS_NAME::Count() const
{
	return fElements.Count();
}

// IsEmpty
/*!	\brief Returns whether the set is empty.
	\return \c true, if the set is empty, \c false otherwise.
*/
_VECTOR_SET_TEMPLATE_LIST
inline
bool
_VECTOR_SET_CLASS_NAME::IsEmpty() const
{
	return fElements.IsEmpty();
}

// MakeEmpty
/*!	\brief Removes all elements from the set.
*/
_VECTOR_SET_TEMPLATE_LIST
void
_VECTOR_SET_CLASS_NAME::MakeEmpty()
{
	fElements.MakeEmpty();
}

// Begin
/*!	\brief Returns an iterator referring to the beginning of the set.

	If the set is not empty, Begin() refers to its first element,
	otherwise it is equal to End() and must not be dereferenced!

	\return An iterator referring to the beginning of the set.
*/
_VECTOR_SET_TEMPLATE_LIST
inline
_VECTOR_SET_CLASS_NAME::Iterator
_VECTOR_SET_CLASS_NAME::Begin()
{
	return fElements.Begin();
}

// Begin
/*!	\brief Returns an iterator referring to the beginning of the set.

	If the set is not empty, Begin() refers to its first element,
	otherwise it is equal to End() and must not be dereferenced!

	\return An iterator referring to the beginning of the set.
*/
_VECTOR_SET_TEMPLATE_LIST
inline
_VECTOR_SET_CLASS_NAME::ConstIterator
_VECTOR_SET_CLASS_NAME::Begin() const
{
	return fElements.Begin();
}

// End
/*!	\brief Returns an iterator referring to the end of the set.

	The position identified by End() is the one succeeding the last
	element, i.e. it must not be dereferenced!

	\return An iterator referring to the end of the set.
*/
_VECTOR_SET_TEMPLATE_LIST
inline
_VECTOR_SET_CLASS_NAME::Iterator
_VECTOR_SET_CLASS_NAME::End()
{
	return fElements.End();
}

// End
/*!	\brief Returns an iterator referring to the end of the set.

	The position identified by End() is the one succeeding the last
	element, i.e. it must not be dereferenced!

	\return An iterator referring to the end of the set.
*/
_VECTOR_SET_TEMPLATE_LIST
inline
_VECTOR_SET_CLASS_NAME::ConstIterator
_VECTOR_SET_CLASS_NAME::End() const
{
	return fElements.End();
}

// Null
/*!	\brief Returns an invalid iterator.

	Null() is used as a return value, if something went wrong. It must
	neither be incremented or decremented nor dereferenced!

	\return An invalid iterator.
*/
_VECTOR_SET_TEMPLATE_LIST
inline
_VECTOR_SET_CLASS_NAME::Iterator
_VECTOR_SET_CLASS_NAME::Null()
{
	return fElements.Null();
}

// Null
/*!	\brief Returns an invalid iterator.

	Null() is used as a return value, if something went wrong. It must
	neither be incremented or decremented nor dereferenced!

	\return An invalid iterator.
*/
_VECTOR_SET_TEMPLATE_LIST
inline
_VECTOR_SET_CLASS_NAME::ConstIterator
_VECTOR_SET_CLASS_NAME::Null() const
{
	return fElements.Null();
}

// Find
/*!	\brief Returns an iterator referring to the element with the
		   specified value.
	\param value The value of the element to be found.
	\return An iterator referring to the found element, or End(), if the
			set doesn't contain any element with the given value.
*/
_VECTOR_SET_TEMPLATE_LIST
_VECTOR_SET_CLASS_NAME::Iterator
_VECTOR_SET_CLASS_NAME::Find(const Value &value)
{
	bool exists = false;
	int32 index = _FindInsertionIndex(value, exists);
	if (!exists)
		return fElements.End();
	return fElements.IteratorForIndex(index);
}

// Find
/*!	\brief Returns an iterator referring to the element with the
		   specified value.
	\param value The value of the element to be found.
	\return An iterator referring to the found element, or End(), if the
			set doesn't contain any element with the given value.
*/
_VECTOR_SET_TEMPLATE_LIST
_VECTOR_SET_CLASS_NAME::ConstIterator
_VECTOR_SET_CLASS_NAME::Find(const Value &value) const
{
	bool exists = false;
	int32 index = _FindInsertionIndex(value, exists);
	if (!exists)
		return fElements.End();
	return fElements.IteratorForIndex(index);
}

// FindClose
/*!	\brief Returns an iterator referring to the element with a value closest
		   to the specified one.

	If the set contains an element with the specified value, an iterator
	to it is returned. Otherwise \a less indicates whether an iterator to
	the directly smaller or greater element shall be returned.

	If \a less is \c true and the first element in the set has a greater
	value than the specified one, End() is returned. Similarly, when \a less
	is \c false and the last element is smaller. Find() invoked on an empty
	set always returns End().

	Note, that the element order used for the set is specified as template
	argument to the class. Default is ascending order. Descending order
	inverts the meaning of \a less, i.e. if \c true, greater values will
	be returned, since they are smaller ones according to the order.

	\param value The value of the element to be found.
	\return An iterator referring to the found element, or End(), if the
			set doesn't contain any element with the given value or a close
			one according to \a less.
*/
_VECTOR_SET_TEMPLATE_LIST
_VECTOR_SET_CLASS_NAME::Iterator
_VECTOR_SET_CLASS_NAME::FindClose(const Value &value, bool less)
{
	bool exists = false;
	int32 index = _FindInsertionIndex(value, exists);
	// If not found, the index _FindInsertionIndex() returns will point to
	// an element with a greater value or to End(). So, no special handling
	// is needed for !less.
	if (exists || !less)
		return fElements.IteratorForIndex(index);
	// An element with a smaller value is desired. The previous one (if any)
	// will do.
	if (index > 0)
		return fElements.IteratorForIndex(index - 1);
	return fElements.End();
}

// FindClose
/*!	\brief Returns an iterator referring to the element with a value closest
		   to the specified one.

	If the set contains an element with the specified value, an iterator
	to it is returned. Otherwise \a less indicates whether an iterator to
	the directly smaller or greater element shall be returned.

	If \a less is \c true and the first element in the set has a greater
	value than the specified one, End() is returned. Similarly, when \a less
	is \c false and the last element is smaller. Find() invoked on an empty
	set always returns End().

	Note, that the element order used for the set is specified as template
	argument to the class. Default is ascending order. Descending order
	inverts the meaning of \a less, i.e. if \c true, greater values will
	be returned, since they are smaller ones according to the order.

	\param value The value of the element to be found.
	\return An iterator referring to the found element, or End(), if the
			set doesn't contain any element with the given value or a close
			one according to \a less.
*/
_VECTOR_SET_TEMPLATE_LIST
_VECTOR_SET_CLASS_NAME::ConstIterator
_VECTOR_SET_CLASS_NAME::FindClose(const Value &value, bool less) const
{
	bool exists = false;
	int32 index = _FindInsertionIndex(value, exists);
	// If not found, the index _FindInsertionIndex() returns will point to
	// an element with a greater value or to End(). So, no special handling
	// is needed for !less.
	if (exists || !less)
		return fElements.IteratorForIndex(index);
	// An element with a smaller value is desired. The previous one (if any)
	// will do.
	if (index > 0)
		return fElements.IteratorForIndex(index - 1);
	return fElements.End();
}

// _FindInsertionIndex
/*!	\brief Finds the index at which the element with the supplied value is
		   located or at which it would need to be inserted.
	\param value The value.
	\param exists Is set to \c true, if the set does already contain an
		   element with that value.
	\return The index at which the element with the supplied value is
			located or at which it would need to be inserted.
*/
_VECTOR_SET_TEMPLATE_LIST
int32
_VECTOR_SET_CLASS_NAME::_FindInsertionIndex(const Value &value,
											bool &exists) const
{
	// binary search
	int32 lower = 0;
	int32 upper = Count();
	while (lower < upper) {
		int32 mid = (lower + upper) / 2;
		int cmp = fCompare(fElements[mid], value);
		if (cmp < 0)
			lower = mid + 1;
		else
			upper = mid;
	}
	exists = (lower < Count() && fCompare(value, fElements[lower]) == 0);
	return lower;
}


// element orders

namespace VectorSetOrder {

// Ascending
/*!	\brief A compare function object implying and ascending order.

	The < operator must be defined on the template argument.
*/
template<typename Value>
class Ascending {
public:
	inline int operator()(const Value &a, const Value &b) const
	{
		if (a < b)
			return -1;
		else if (b < a)
			return 1;
		return 0;
	}
};

// Descending
/*!	\brief A compare function object implying and descending order.

	The < operator must be defined on the template argument.
*/
template<typename Value>
class Descending {
public:
	inline int operator()(const Value &a, const Value &b) const
	{
		if (a < b)
			return -1;
		else if (b < a)
			return 1;
		return 0;
	}
};

}	// namespace VectorSetOrder

#endif	// _VECTOR_SET_H
