/* libsswf_vectors.c++ -- written by Alexis WILKE for Made to Order Software Corp. (c) 2002-2008 */

/*

Copyright (c) 2002-2008 Made to Order Software Corp.

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.

*/

/** \file
 *
 * \brief The implementation of the sswf::Vectors class
 *
 * This file declares the body of the functions which are not
 * inline. It is part of the SSWF library.
 */

#include	"sswf/libsswf.h"

using namespace sswf;


/////////////////////////////////////////// Vectors

/** \class sswf::Vectors
 *
 * \brief Manages an array of pointers to other objects
 *
 * This class is similar to the std::vector class from the STL.
 */


/** \brief Initialize an empty vector
 *
 * This function initializes the corresponding vector to an
 * empty vector.
 */
Vectors::Vectors(void)
{
	f_count = 0;
	f_max = 0;
	f_vectors = 0;
}


/** \brief Copy a vector in another
 *
 * This function is the copy operator which copies the specified
 * vector in this vector.
 *
 * \param[in] vectors The vector to be copied
 */
Vectors::Vectors(const Vectors& vectors)
{
	f_max = 0;
	f_vectors = 0;
	SetSize(f_count = vectors.f_count);
	if(f_count > 0) {
		// NOTE: the vector data pointer is duplicated but not the objects
		//	 it points to...
		memcpy(f_vectors, vectors.f_vectors, sizeof(ItemBase *) * f_count);
	}
}


/** \brief Copy a vector in another
 *
 * This is the equal operator which copies the source vector
 * to this vector. Anything in the old vector will be freed
 * as required.
 *
 * \param[in] vectors The source vector to be copied
 */
Vectors& Vectors::operator = (const Vectors& vectors)
{
	if(this != &vectors) {
		SetSize(f_count = vectors.f_count);
		if(f_count > 0) {
			// NOTE: the vector data pointer is duplicated but not the objects
			//	 it points to...
			memcpy(f_vectors, vectors.f_vectors, sizeof(ItemBase *) * f_count);
		}
	}

	return *this;
}


/** \brief The destructor ensures that the vectors is empty
 *
 * This function reset the size of the vectors to zero. This
 * means anything still allocated by this vector is removed.
 *
 * \bug
 * This function does not clean up what is pointed to by this
 * vector. It only clears the vector itself.
 */
Vectors::~Vectors()
{
	SetSize(0);		// free everything
}


/** \fn sswf::Vectors::Count(void) const
 *
 * \brief Return the size of the vectors
 *
 * This function returns the current size of the vectors.
 *
 * All the items defined in the vectors can be retrieved
 * using the Get() function. These items have index starting
 * at zero and ending at Count() - 1. If Count() is zero,
 * then one cannot call the Get() function since the vectors
 * is empty.
 *
 * \sa sswf::Vectors::SetSize()
 */


/** \fn sswf::Vectors::Empty(void)
 *
 * \brief Make the vectors empty
 *
 * This function marks the vectors as empty.
 *
 * The vectors buffer is kept so it can be reused avoiding allocating
 * and deallocating it for no reason.
 *
 * In order for the vectors to lose their buffer, call SetSize() with
 * zero as the size.
 *
 * \sa sswf::Vectors::SetSize()
 */


/** \brief Change the size of the vectors.
 *
 * This function sets the new size of the vectors internal buffer.
 * If the internal buffer is already large enough, then nothing happens
 * (i.e. the size is not reduced.)
 *
 * A size of zero (or negative) means that the vectors should be
 * emptied. Thus the array is freed and the counters are reset.
 *
 * Note that this function does not change the count unless the new
 * size is smaller than the current count or is zero. In the latter
 * case, the count is set to zero also.
 *
 * \note
 * At this time, the size is always rounded up to the next multiple
 * of 256. This ensures that vectors aren't grown too often.
 *
 * \param[in] size The size of the buffer used to save the pointers
 *
 * \sa sswf::Vectors::Count()
 * \sa sswf::Vectors::Empty()
 */
void Vectors::SetSize(int size)
{
	if(size <= 0) {
		MemClean(&f_vectors);
		f_count = 0;
		f_max = 0;
		return;
	}
	if(size <= f_max) {
		// size already available
		return;
	}
	// round the size up
	size = (size + 255) & -256;

//fprintf(stderr, "Enlarging vector table at %p (%d)\n", this, size);

	f_vectors = (ItemBase **) MemRealloc(f_vectors, size * sizeof(ItemBase *), "Vectors::SetSize() -- create an array of vectors");
	f_max = size;
	if(f_count > size) {
		f_count = size;
	}
}


/** \brief Get an item out of the vectors.
 *
 * This function is used to read one item out of the vectors.
 *
 * In debug mode, the function asserts if the index is out of range
 * (i.e. negative or larger or equal to the number if items available.)
 *
 * \param[in] index
 *
 * \return The item at the specified index.
 */
ItemBase *Vectors::Get(int index) const
{
	assert((unsigned int) index < (unsigned int) f_count, "FATAL ERROR: invalid vector index (%d - max is %d).\n", index, f_count);
	return f_vectors[index];
}


/** \brief Replace an item in a vector
 *
 * This function sets the specified item at the specified index in the
 * vectors. If another item was defined at that index, it is overwritten.
 *
 * It is possible to set an item at an index which does not exist yet.
 * If the index is beyond of the last item, the pointers in between are
 * set to all zeroes.
 *
 * \param[in] index The index (position) where the item is saved
 * \param[in] ptr The pointer to save at the specified position
 */
void Vectors::Set(int index, ItemBase *ptr)
{
	if(index == -1) {		// append?
		index = f_count;
	}
	SetSize(index + 1);
	if(index > f_count) {		// ensure all the vectors to that point are cleared
		memset(f_vectors + f_count, 0, (index - f_count) * sizeof(ItemBase *));
	}
	f_vectors[index] = ptr;
	if(f_count < index + 1) {
		f_count = index + 1;
	}
}


/** \brief Insert the specified item at the specified index
 *
 * This function is used to add an item at the specified index.
 *
 * If items exist after the specified position, then their index
 * position is incremented by one each before the new item is
 * saved.
 *
 * \param[in] index The position where the new item is saved
 * \param[in] ptr The pointer to be saved at that specific position
 */
void Vectors::Insert(int index, ItemBase *ptr)
{
	if(index == -1) {		// append?
		index = f_count;
	}
	SetSize(index + 1);
	if(index > f_count) {		// ensure all the vectors to that point are cleared
		memset(f_vectors + f_count, 0, (index - f_count) * sizeof(ItemBase *));
	}
	else if(index < f_count) {
		memmove(f_vectors + index + 1, f_vectors + index, (f_count - index) * sizeof(ItemBase *));
	}
	f_vectors[index] = ptr;
	f_count++;
}







/* The following options fold the documentation; use 'zi' to turn on and off
 *
 * vim: foldexpr=getline(v\:lnum)!~'^/\\*\\*'&&getline(v\:lnum)!~'^\ \\*'?0\:1 foldcolumn=2 foldmethod=expr
 */
