#ifndef ALREADY_INCLUDED_2006_LIBD__ARRAY_HH
#define ALREADY_INCLUDED_2006_LIBD__ARRAY_HH
#include "_Single.hh"
namespace dmp
{
template<class X>
class Array : private Single
{
private:
ptr<X>* private_array;
int private_length;
int private_capacity;
private:
Array(int nominal_length = 10) : Single(DCODE_ARRAY)
{
private_length = 0;
private_capacity = nominal_length;
private_array = reinterpret_cast<ptr<X>*>(calloc(sizeof(ptr<X>), nominal_length));
}
public:
static ptr<Array> ctor(int nominal_length = 10)
{
return new Array(nominal_length);
}
private:
template <class T> friend class ptr;
~Array()
{
#ifdef ALLEGRO_ONLINE
if (!allegro_on)
{
return;
}
#endif
if (this == null)
{
return;
}
if (private_array != null)
{
for (int i=0; i<private_length; i++)
{
*(private_array + i) = null;
}
free(private_array);
private_array = null;
private_length = 0;
private_capacity = 0;
}
else
{
assert(private_length == 0);
assert(private_capacity == 0);
}
}
private:
Array(const Array& a);
Array& operator = (const Array&);
public:
int get_length() const
{
ASSERT(this != null);
return private_length;
}
public:
ptr<X> get_element_at(int i) const
{
ASSERT(this != null);
ASSERT_INFO(i >= 0, dmp::string() + "i=" + i + ", private_length=" + private_length);
ASSERT_INFO(i < private_length, dmp::string() + "i=" + i + ", private_length=" + private_length);
return private_array[i];
}
void set_element_at(int i, const ptr<X>& element)
{
ASSERT(&element != null);
set_element_at(i, element.operator->());
}
void set_element_at(int i, X* element)
{
ASSERT(this != null);
ASSERT(i >= 0);
ASSERT(i < private_length);
private_array[i] = element;
}
ptr<Array<X> > add_element(const ptr<X>& new_element)
{
ASSERT(&new_element != null);
add_element(new_element.get_ptr());
return this;
}
ptr<Array<X> > add_element(X* new_element)
{
ASSERT(this != null);
if (private_length >= private_capacity)
{
bool was_zero = (0 == private_capacity);
if (was_zero)
{
private_capacity = 10;
}
else
{
private_capacity *= 2;
}
ptr<X>* new_array = reinterpret_cast<ptr<X>*>(calloc(sizeof(ptr<X>), private_capacity));
for (int i=0; i<private_length; i++)
{
new_array[i] = private_array[i];
(private_array + i)->~ptr();
}
if (!was_zero)
{
free(private_array);
}
private_array = new_array;
}
ASSERT(private_length < private_capacity);
private_array[private_length] = new_element;
private_length++;
return this;
}
void delete_element_at(int i)
{
cascade_down(i);
}
void add_element_at(int i, const ptr<X>& element)
{
ASSERT(&element != null);
add_element_at(i, element.operator->());
}
void add_element_at(int i, X* element)
{
cascade_up(i);
private_array[i] = element;
}
private:
void cascade_down(int index)
{
for (int i=index; i<private_length-1; i++)
{
private_array[i] = private_array[i+1];
}
private_length--;
}
void cascade_up(int index)
{
add_element(null);
for (int i=private_length-1; i>index; i--)
{
private_array[i] = private_array[i-1];
}
private_array[index] = null;
}
#ifdef DAVINS_IO_ONLINE
friend dmp::Writer& operator << (dmp::Writer& w, const Array<X>& a)
{
ASSERT(&w != null);
ASSERT(&a != null);
w << '(' << "Array";
for (int i=0; i < a.get_length(); i++)
{
w << ' ' << a.get_element_at(i);
}
w << ')';
return w;
}
friend dmp::Reader& operator >> (dmp::Reader& r, Array<X>& a)
{
ASSERT(&r != null);
ASSERT(&a != null);
if (r.looking_at("null"))
{
r.next_token(); }
else
{
ASSERT(a.get_length() == 0);
r >> '(' >> "Array";
while (!r.looking_at(')'))
{
ptr<X> t = X::ctor();
r >> t;
a.add_element(t);
}
r >> ')';
}
return r;
}
#endif
public:
int find_element_eq(int start, ptr<X> key)
{
const int len = private_length;
for (int i=start; i<len; i++)
{
if (private_array[i] == key)
{
return i;
}
}
return -1;
}
int find_element_equal(int start, ptr<X> key)
{
const int LEN = private_length;
for (int i=start; i<LEN; i++)
{
if (*(private_array[i]) == *key)
{
return i;
}
}
return -1;
}
ptr<Array<X> > clone_deep()
{
const int LEN = private_length;
ptr<Array<X> > a = Array<X>::ctor(LEN);
for (int i=0; i<LEN; i++)
{
a->add_element(get_element_at(i)->clone_deep());
}
return a;
}
ptr<X> get_cyclic_at(int index)
{
const int LEN = this->get_length();
ASSERT(LEN != 0);
while (index < 0)
{
index += LEN;
}
while (index >= LEN)
{
index -= LEN;
}
return this->get_element_at(index);
}
friend bool operator == (const Array<X>& array1, const Array<X>& array2)
{
if (array1.get_length() != array2.get_length())
{
return false;
}
const int LEN = array1.get_length();
for (int i=0; i<LEN; i++)
{
ptr<X> p1 = array1.get_element_at(i);
ptr<X> p2 = array2.get_element_at(i);
if (*p1 != *p2)
{
return false;
}
}
return true;
}
friend bool operator != (const Array<X>& array1, const Array<X>& array2)
{
return !(array1 == array2);
}
};
}
#endif