#ifndef ARRAY_H
#define ARRAY_H

#include <cstddef>

const size_t incrementFactor = 2;
const size_t initialCapacity = 10;

template <typename DataType>
class Array
{
  private:
	/// The count of elements stored in the array
	size_t size;
	/// The quantity of elements that can be stored in the array
	/// without asking for more memory
	size_t capacity;
	/// A C-type array of elements
	DataType* arr;

  public:
	/// Default constructor and conversion constructor
	explicit Array(size_t capacity = initialCapacity);
	/// Destructor
	~Array();
	/// Adds a copy of the given value to the ending position of the array
	/// @return true if the element was added, false if no enough memory is available
	bool add(const DataType& element);
	/// Returns the number of elements stored in the array
	inline size_t count() const { return size; }
	/// Gets read and write access to the i-th element
	inline DataType& operator[](size_t i) { return arr[i]; }
	/// Gets read-only access to the i-th element
	inline const DataType& operator[](size_t i) const { return arr[i]; }

  private:
	/// Copy constructor
	Array(const Array& other);
	/// Assignment operator
	const Array& operator=(const Array& other);
	/// Makes room for more values
	bool incrementArray();
};

#include <cassert>

template <typename DataType>
Array<DataType>::Array(size_t capacity)
	: size(0)
	, capacity(capacity ? capacity : initialCapacity)
	, arr( new DataType[capacity] )
{
	assert(arr);
}

template <typename DataType>
Array<DataType>::~Array()
{
	delete [] arr;
}

template <typename DataType>
bool Array<DataType>::add(const DataType &element)
{
	if ( size == capacity )
		if ( ! incrementArray() )
			return false;

	arr[size++] = element;
	return true;
}

template <typename DataType>
bool Array<DataType>::incrementArray()
{
	size_t newCapacity = capacity * incrementFactor;
	DataType* newArr = new DataType[newCapacity];
	if ( ! newArr ) return false;

	for ( size_t i = 0; i < size; ++i )
		newArr[i] = arr[i];

	capacity = newCapacity;
	delete [] arr;
	arr = newArr;
	return true;
}

#endif // ARRAY_H
