00001 #ifndef GSGL_DATA_ARRAY_H
00002 #define GSGL_DATA_ARRAY_H
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037 #include "data/data.hpp"
00038 #include "data/indexable.hpp"
00039 #include "data/exception.hpp"
00040
00041 namespace gsgl
00042 {
00043
00044 namespace data
00045 {
00046
00047
00048
00049 class DATA_API array_base
00050 : public data_object
00051 {
00052 protected:
00053 array_base() : data_object() {}
00054 virtual ~array_base() {}
00055
00056 void *allocate(const gsgl::index_t & num_bytes);
00057 void *reallocate(void *, const gsgl::index_t & num_bytes);
00058 void deallocate(void *);
00059
00060 void move(void *dest, void *src, const gsgl::index_t & num_bytes);
00061 void copy(void *dest, void *src, const gsgl::index_t & num_bytes);
00062 void set(void *dest, const unsigned char & val, const gsgl::index_t & num_bytes);
00063 };
00064
00065
00066 template <typename T>
00067 class simple_array_iterator;
00068
00069
00070
00071
00072
00073
00074 template <typename T>
00075 class simple_array
00076 : public array_base,
00077 public iterable<T, simple_array_iterator<T> >,
00078 public indexable<T, gsgl::index_t>
00079 {
00080 friend class simple_array_iterator<T>;
00081
00082 gsgl::index_t capacity;
00083 gsgl::index_t num_elements;
00084
00085 T * data;
00086
00087 public:
00088 simple_array(const gsgl::index_t & initial_capacity = 0);
00089 simple_array(const simple_array & a);
00090 simple_array & operator= (const simple_array & a);
00091 virtual ~simple_array();
00092
00093
00094
00095
00096 virtual gsgl::index_t size() const { return num_elements; }
00097 virtual void clear() { resize(num_elements = 0); }
00098
00099
00100
00101
00102
00103 using iterable::append;
00104 virtual void append(const T &);
00105 virtual void insert(const iterator & i, const T & item);
00106 virtual void remove(const iterator & i);
00107
00108
00109
00110
00111
00112 virtual const T & item(const gsgl::index_t & index) const;
00113 virtual T & item(const gsgl::index_t & index);
00114 virtual bool contains_index(const gsgl::index_t & index) const { return index < num_elements; }
00115
00116
00117
00118
00119
00120 inline const T *ptr() const { return data; }
00121 inline T * ptr() { return data; }
00122
00123 void insert(const T & item, const typename index_t & index);
00124 void remove(const typename index_t & index);
00125
00126
00127 protected:
00128 void resize(const gsgl::index_t & new_num_elements);
00129 };
00130
00131
00132
00133
00134 template <typename T>
00135 simple_array<T>::simple_array(const gsgl::index_t & initial_capacity)
00136 : array_base(),
00137 iterable<T, simple_array_iterator<T> >(),
00138 indexable<T, gsgl::index_t>(),
00139 capacity(initial_capacity),
00140 num_elements(0),
00141 data(0)
00142 {
00143 if (initial_capacity)
00144 data = reinterpret_cast<T *>(allocate(initial_capacity * sizeof(T)));
00145 }
00146
00147
00148 template <typename T>
00149 simple_array<T>::simple_array(const simple_array<T> & a)
00150 : array_base(),
00151 iterable<T, simple_array_iterator<T> >(),
00152 indexable<T, gsgl::index_t>(),
00153 capacity(a.capacity),
00154 num_elements(a.num_elements),
00155 data(0)
00156 {
00157 if (num_elements)
00158 {
00159 data = reinterpret_cast<T *>(allocate(num_elements * sizeof(T)));
00160 copy(data, a.data, num_elements * sizeof(T));
00161 }
00162 }
00163
00164
00165 template <typename T>
00166 simple_array<T> & simple_array<T>::operator= (const simple_array<T> & a)
00167 {
00168 if (a.num_elements)
00169 {
00170 resize(a.num_elements);
00171 copy(data, a.data, num_elements * sizeof(T));
00172 }
00173 else
00174 {
00175 capacity = 0;
00176 num_elements = 0;
00177 deallocate(data);
00178 data = 0;
00179 }
00180
00181 return *this;
00182 }
00183
00184
00185 template <typename T>
00186 simple_array<T>::~simple_array()
00187 {
00188 deallocate(data);
00189 }
00190
00191
00192 template <typename T>
00193 void simple_array<T>::append(const T & item)
00194 {
00195 resize(num_elements+1);
00196 data[num_elements-1] = item;
00197 }
00198
00199
00200 template <typename T>
00201 void simple_array<T>::insert(const iterator & i, const T & item)
00202 {
00203 insert(item, i.position);
00204 }
00205
00206
00207 template <typename T>
00208 void simple_array<T>::remove(const iterator & i)
00209 {
00210 remove(i.position);
00211 }
00212
00213
00214 template <typename T>
00215 const T & simple_array<T>::item(const gsgl::index_t & index) const
00216 {
00217 if (index < num_elements)
00218 return data[index];
00219 else
00220 throw memory_exception(__FILE__, __LINE__, L"Array index overflow in const item access.");
00221 }
00222
00223
00224 template <typename T>
00225 T & simple_array<T>::item(const gsgl::index_t & index)
00226 {
00227 if (index >= num_elements)
00228 resize(index+1);
00229 return data[index];
00230 }
00231
00232
00233 template <typename T>
00234 void simple_array<T>::insert(const T & item, const gsgl::index_t & index)
00235 {
00236 const index_t old_num_elements = num_elements;
00237
00238 resize(gsgl::max_val(old_num_elements+1, index+1));
00239 if (index < old_num_elements)
00240 move(data + (index+1), data + index, (old_num_elements - index) * sizeof(T));
00241 data[index] = item;
00242 }
00243
00244
00245 template <typename T>
00246 void simple_array<T>::remove(const gsgl::index_t & index)
00247 {
00248 if (index < num_elements)
00249 move(data + index, data + (index+1), (num_elements - (index+1)) * sizeof(T));
00250 else
00251 throw memory_exception(__FILE__, __LINE__, L"Array index out of bounds in remove.");
00252
00253 --num_elements;
00254 }
00255
00256
00257 template <typename T>
00258 void simple_array<T>::resize(const gsgl::index_t & new_num_elements)
00259 {
00260 if (new_num_elements > capacity)
00261 {
00262 index_t new_capacity = new_num_elements * 3 / 2;
00263 new_capacity = new_capacity + ((new_capacity + 256) % 256);
00264 data = reinterpret_cast<T *>(reallocate(data, new_capacity * sizeof(T)));
00265 set(data + capacity, 0, (new_capacity - capacity) * sizeof(T));
00266 capacity = new_capacity;
00267 }
00268
00269 num_elements = new_num_elements;
00270 }
00271
00272
00273
00274
00275
00276 template <typename T>
00277 class simple_array_iterator
00278 {
00279 friend class simple_array<T>;
00280 const simple_array<T> & parent;
00281 gsgl::index_t position;
00282 protected:
00283 simple_array_iterator(const iterable<T, simple_array_iterator<T> > & parent_iterable)
00284 : parent(dynamic_cast<const simple_array<T> &>(parent_iterable)), position(0) {}
00285
00286 simple_array_iterator(const simple_array_iterator & i)
00287 : parent(i.parent), position(i.position) {}
00288
00289 simple_array_iterator & operator=(const simple_array_iterator & i)
00290 {
00291 parent = i.parent;
00292 position = i.position;
00293 return *this;
00294 }
00295
00296 inline bool is_valid() const { return position < parent.num_elements; }
00297
00298 inline const T & operator*() const
00299 {
00300 if (position < parent.num_elements)
00301 return const_cast<T &>(parent.data[position]);
00302 else
00303 throw memory_exception(__FILE__, __LINE__, L"Array iterator overflow in dereference operator.");
00304 }
00305
00306 inline simple_array_iterator & operator++()
00307 {
00308 if (position < parent.num_elements)
00309 ++position;
00310 else
00311 throw memory_exception(__FILE__, __LINE__, L"Array iterator overflow in preincrement operator.");
00312
00313 return *this;
00314 }
00315 };
00316
00317
00318 }
00319
00320 }
00321
00322 #endif