Added some more docs to String
[libs.git] / src / Sylph / Core / Array.h
bloba7c65a4c407446586a63b2829ea152c1e8c92078
1 /*
2 * LibSylph Class Library
3 * Copyright (C) 2009 Frank "SeySayux" Erens <seysayux@gmail.com>
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the LibSylph Pulbic License as published
7 * by the LibSylph Developers; either version 1.0 of the License, or
8 * (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the LibSylph
13 * Public License for more details.
15 * You should have received a copy of the LibSylph Public License
16 * along with this Library, if not, contact the LibSylph Developers.
18 * Created on 8 februari 2009, 14:18
21 #ifndef ARRAY_H_
22 #define ARRAY_H_
24 #include "Iterable.h"
25 #include "Iterator.h"
26 #include "Comparable.h"
27 #include "Exception.h"
28 #include "Range.h"
29 #include "Primitives.h"
31 #include <algorithm>
32 #include <initializer_list>
33 #include <iostream>
35 SYLPH_BEGIN_NAMESPACE
36 class Any;
37 template<class T> class Array;
39 SYLPH_PUBLIC
41 /**
42 * Array provides a safe array. It works the same like a c-style array (not like
43 * std::vector which can expand), but instead of overflowing, it throws an
44 * @c Exception whenever you try to access data outside its bounds. Therefore it
45 * also keeps track of its own length. <p>
46 * The Array class provided here is reference-counted, which means it's
47 * perfectly safe and even recommended to pass it by value instead of by
48 * reference or by pointer. This way, the Array acts more like a builtin type
49 * and does not obstruct the workflow. <p>
50 * Please note that most constructors copy the contents into the array, which
51 * means that unless the type used is easy to copy, using the specialized
52 * array-to-pointer ( Array<T*> ) is preferred.
53 * @tplreqs T CopyConstructible, DefaultConstructible, Assignable
55 template<class T>
56 class Array : public virtual Object {
57 private:
58 size_t _length;
59 public:
61 /**
62 * @todo Write documentation!
64 class iterator : public RandomAccessIterator<T, iterator> {
65 public:
66 typedef RandomAccessIterator<T, iterator> super;
68 iterator(bool begin = false, Array<T>* obj = null)
69 : super(begin), _obj(obj) {
70 _currentIndex = begin ? 0 : (_obj->length - 1);
73 iterator(bool begin = false, const Array<T>* obj = null)
74 : super(begin), _obj(const_cast<Array<T>*> (obj)) {
75 _currentIndex = begin ? 0 : (_obj->length - 1);
78 bool equals(const iterator& other) const {
79 return _currentIndex == other._currentIndex &&
80 _obj == other._obj;
83 iterator(const iterator& other) {
84 _currentIndex = other._currentIndex;
85 _obj = other._obj;
88 typename super::reference current() const {
89 return (*_obj)[_currentIndex];
92 bool hasNext() const {
93 return _currentIndex < (_obj->length - 1);
96 void next() const {
97 _currentIndex++;
100 bool hasPrevious() const {
101 return _currentIndex >= 0;
104 void previous() const {
105 _currentIndex--;
108 idx_t currentIndex() const {
109 return _currentIndex;
112 size_t length() const {
113 return _obj->length;
115 private:
116 mutable idx_t _currentIndex;
117 Array<T>* _obj;
119 S_ITERABLE(T)
120 public:
122 * A function that is used for filtering by the filter() method. This
123 * function takes both an instance of the class this Array contains, and
124 * a reference to a reference to any kind of other data that may need to
125 * be passed to the FilterFunction.
127 typedef bool(*FilterFunction)(const T&, Any&);
129 * The length of the array. This variable is 1-based, while the array itself
130 * is 0-based, i.e. if length == N the highest entry in this array is N-1.
131 * E.g if array.length == 5, then the higest entry is array[4]
133 const size_t & length;
136 * Creates an Array<T> from a pointer to T and a length. The new array will
137 * have the length specified in <code>length</code>. The original array will
138 * not be modified, the contents are copied. No bounds-checking
139 * is done, therefore, use this function at your own responsability!
140 * @param length The length of the original C array
141 * @param orig The original C array, supplied as a pointer.
143 inline static Array<T> fromPointer(std::size_t length, T * orig) {
144 Array<T> ar(length);
145 for (int x = 0; x < length; x++)ar[x] = orig[x];
146 return ar;
148 public:
151 * Creates an Array with the specified length. A new instance of the
152 * reference counted data is created, its reference count set to 1 and the
153 * internal C array is allocated to have the specified length.
154 * @param len The length of the new Array.
156 explicit Array(std::size_t len = 0) : _length(len), length(_length),
157 data(new Data(len)) {
161 * Creates an Array from an intializer list. This constructor allows the
162 * easier, more familiar syntax of Array creation, but requires C++0x. Using
163 * this constructor, arrays can be initialized as following:
164 * <pre>Array<int> myarr = {5,4,7,9};</pre>
165 * A new instance of the reference counted data is created, the reference
166 * count is set to 1, the length is set to the length of the intializer
167 * list, and all data is copied into a newly allocated C array.
168 * @param il The initializer_list used to create the array.
170 Array(const std::initializer_list<T> & il) : _length(il.size()),
171 length(_length), data(new Data(_length)) {
172 for (idx_t i = 0; i < il.size(); i++) {
173 data->_carray[i] = il.begin()[i];
178 * Creates an Array from an existing C-style array. Note that you can only
179 * pass a true array, i.e. you cannot pass a pointer that acts as an array.
180 * If you only have a pointer, you'll have to initialize using
181 * Array::fromPointer(size_t, length) . <p>
182 * A new instance of the reference counted data is created, the reference
183 * count is set to 1, the length is set to the length of the Array, all
184 * data is copied into a newly allocated C array with the same length as
185 * the original array. The original array remains unmodified.
186 * @param array A traditional, C-style array to create this Array from.
188 template<size_t N>
189 Array(const T(&array)[N]) : _length(N), length(_length), data(new Data(N)) {
190 for (idx_t i = 0; i < _length; i++) {
191 data->_carray[i] = array[i];
196 * Creates an Array from another instance of the Array class. The data is
197 * not copied, instead, the pointer to the refernce counted data will be
198 * set to the reference counted data of the other Array, and the reference
199 * count will increase by 1. Other fields of the reference counted data
200 * remain unmodified.
201 * @param other An other Array from which to use the reference counted data.
203 Array(const Array<T> & other) : _length(other._length), length(_length),
204 data(other.data){
205 data->refcount++;
209 * Creates an array from a range of items. Every item within the range will
210 * be added to the array. This is most useful for integral types, as other
211 * types usually don't support the required semantics.<p>
212 * A new instance of the reference counted data is created, the reference
213 * count is set to 1, the length is set to <code>ran.last() - ran.first()
214 * </code>, a new C-style array with this length will be allocated.
215 * @param ran a range class that specifies the lower and upper boundaries.
216 * @tplreqs T operator++, LessThanComparable
219 Array(const basic_range<T> & ran) : _length(ran.last() - ran.first()),
220 length(_length), data(new Data(length)) {
221 idx_t idx = 0;
222 for (T x = ran.first(); x < ran.last(); x++) {
223 *this[idx] = x;
224 idx++;
229 * Creates an Array from a single item. This is useful for implicit
230 * conversions, as it allows a single instance of a class to be passed as
231 * an Array of that class with length 1. <p>
232 * A new instance of the reference counted data is created, the reference
233 * count set to 1, the length is set to 1, and a new C-style array with
234 * length 1 is allocated. The object is copied into this array, the original
235 * object remains unmodified.
236 * @param t An object to create a length-1 array from.
238 explicit Array(const T& t) : _length(1), length(_length),
239 data(new Data(1)) {
240 data->_carray[0] = t;
244 * Destructor. Reduces the reference count by 1. If the reference count
245 * reaches 0, the internal backing data will be destroyed.
247 virtual ~Array() {
248 data->refcount--;
249 if (!data->refcount) {
250 delete data;
251 data = null;
255 const T& get(idx_t i) const {
256 return data->_carray[i];
259 void put(idx_t i, const T& t) {
260 data->_carray[i] = t;
264 * Creates a copy of this array. The Array returned from this method is
265 * an exact copy of this Array, such that ar == ar.copy() . The returned
266 * Array is different from the one returned by operator=, as the reference
267 * counted data gets copied as well, in other words, both Arrays will have
268 * a different, equal instance of the reference counted data.
269 * @return A new Array containing the same data as this Array.
271 Array<T> copy() const {
272 Array<T> toReturn((std::size_t)length);
273 for (idx_t i = 0; i < length; i++) {
274 toReturn[i] = (*this)[i];
276 return toReturn;
280 * Returns a c-style array representing the contents of this Array. The
281 * array returned is not a copy of this array, in fact, changes to the
282 * returned array are reflected in this Array.
284 T * carray() {
285 return data->_carray;
289 * Returns a c-style array representing the contents of this Array. The
290 * array returned is not a copy of this array, in fact, changes to the
291 * returned array are reflected in this Array. This version returns a const
292 * c-style array and is used when this Array is const.
294 const T *carray() const {
295 return data->_carray;
299 * This will filter the Array according to a FilterFunction. This function
300 * returns a new, 'filtered' Array, which only contains the entries for
301 * which the FilterFunction returns true.
302 * @param func A pointer to the function which is used for filtering
303 * @param clientData %Any data to be passed to the FilterFunction
304 * @return A new array containing only the filtered data
306 Array<T> filter(FilterFunction func, Any& clientData) {
307 // I'm terribly sorry but we'll need to iterate twice over the Array...
308 size_t newlength;
309 for (idx_t i = 0; i < length; i++) {
310 if (func(*this[i], clientData)) newlength++;
312 Array<T> toReturn(newlength);
313 idx_t curpos = 0;
314 for (idx_t i = 0; i < length; i++) {
315 if (func(*this[i], clientData)) {
316 toReturn[curpos] = *this[i];
317 curpos++;
320 return toReturn;
324 * Sets every entry in the array to the object returned by that classes'
325 * default constructor.
327 void clear() {
328 delete this->data->_carray;
329 this->data->_carray = new T[this->data->_length];
333 * Swaps the data pointer of this Array with the other Array. The refcount
334 * for the current data pointer gets decreased by 1, the refcount for the
335 * data pointer of the other array gets increased by 1. In case the this
336 * Array'soriginal data pointer's refcount reaches zero, the original data
337 * will be deleted.
338 * @param other The other array from which to use the data pointer
340 Array<T> & operator=(const Array<T> & other) {
341 if (this->data == other.data) return *this;
342 this->data->refcount--;
343 if (!this->data->refcount) delete this->data;
344 this->data = other.data;
345 this->_length = other.data->_length;
346 data->refcount++;
347 return *this;
351 * Used for accessing the Array's contents. Its behaviour is identical to
352 * that of c-style arrays, but throws an exception instead of overflowing
353 * or causing segfaults. <p>
354 * The Array will assume ownership over any pointers entered in this way.
355 * @param idx the index in the array from which to return an element
356 * @throw ArrayException if <code>idx > length</code>
358 T & operator[](std::sidx_t idx) throw (Exception) {
359 if ((idx < (sidx_t)length) && (idx >= -(sidx_t)length)) {
360 return idx >= 0 ? data->_carray[idx] : data->_carray[length + idx];
361 } else {
362 sthrow(ArrayException, "Array overflow");
367 * This is the <code>const</code> version of T& operator[] . Its behaviour
368 * is identical to that of c-style const arrays, but throws an exception
369 * instead of overflowing or causing segfaults.
370 * @param idx the index in the array from which to return an element
371 * @throw ArrayException if <code>idx > length</code>
373 const T & operator[](std::sidx_t idx) const throw (Exception) {
374 if ((idx < (sidx_t)length) && (idx >= -(sidx_t)length)) {
375 return idx >= 0 ? data->_carray[idx] : data->_carray[length + idx];
376 } else {
377 sthrow(ArrayException, "Array overflow");
382 * Slices the array and returns the subarray. E.g. :
383 * <pre>Array<String> subarr = myarr[range(5,8)]</pre>
384 * <code>subarr</code> now contains the values of @c myarr[5] to @c myarr[8]
385 * . Please note that the subarray contains a copy of the original.
386 * @param ran The range describing the slice.
387 * @throw ArrayException if ran.last() > length
389 Array<T> operator[](const range & ran) throw (Exception) {
390 if (ran.first() < 0 || ran.last() >= length)
391 sthrow(ArrayException, "Array overflow");
393 Array<T> toReturn = Array<T>::fromPointer((ran.last() - ran.first())+1,
394 data->_carray + ran.first());
395 return toReturn;
399 * Const-version of operator[](const range &) .
400 * @param ran The range describing the slice
401 * @throw ArrayException if ran.last() > length
403 const Array<T> operator[](const range & ran) const throw (Exception) {
404 if (ran.first() < 0 || ran.last() >= length)
405 sthrow(ArrayException, "Array overflow");
407 Array<T> toReturn = Array<T>::fromPointer((ran.last() - ran.first())+1,
408 data->_carray + ran.first());
409 return toReturn;
412 #ifndef SYLPH_DOXYGEN
413 protected:
415 struct Data {
417 explicit Data(size_t length) : _length(length),
418 _carray(new T[length]()), refcount(1) {
422 virtual ~Data() {
423 delete _carray;
425 const size_t _length;
426 T * _carray;
427 suint refcount;
428 } * data;
429 #endif
433 * Compares the two Arrays on equality. To Arrays compare equal when their
434 * lengths are identical and each of the items compare equal to the item on the
435 * same position in the other array.
436 * @return <i>true</i> when the two arrays compare equal, <i>false</i>
437 * otherwise.
438 * @tplreqs T EqualityComparable
440 template<class T>
441 inline bool operator==(const Array<T>& lhs, const Array<T>& rhs) {
442 if(lhs.length == rhs.length) {
443 for(idx_t i = 0; i < lhs.length; i++) {
444 if(lhs[i] != rhs[i]) return false;
446 return true;
448 return false;
452 * Compares the two Arrays. To Arrays compare less than when their lengths are
453 * identical and each of the items compare less than to the item on the same
454 * position in the other array.
455 * @return <i>true</i> when the first array compares less than the first,
456 * <i>false</i> otherwise.
457 * @tplreqs T LessThanComparable
459 template<class T>
460 inline bool operator<(const Array<T>& lhs, const Array<T>& rhs) {
461 return std::lexicographical_compare(&lhs[0], &lhs[lhs.length-1],
462 &rhs[0], &rhs[rhs.length-1]);
465 template<class T>
466 std::ostream& operator<<(std::ostream& out, const Array<T>& rhs) {
467 out << "{ ";
468 for(idx_t i = 0; i < rhs.length - 1; ++i) {
469 out << rhs[i] << ", ";
471 out << rhs[rhs.length-1] << " }";
472 return out;
475 SYLPH_END_NAMESPACE
477 #endif /* ARRAY_H_ */