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
26 #include "Comparable.h"
27 #include "Exception.h"
29 #include "Primitives.h"
32 #include <initializer_list>
37 template<class T
> class Array
;
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
56 class Array
: public virtual Object
{
62 * @todo Write documentation!
64 class iterator
: public RandomAccessIterator
<T
, iterator
> {
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
&&
83 iterator(const iterator
& other
) {
84 _currentIndex
= other
._currentIndex
;
88 typename
super::reference
current() const {
89 return (*_obj
)[_currentIndex
];
92 bool hasNext() const {
93 return _currentIndex
< (_obj
->length
- 1);
100 bool hasPrevious() const {
101 return _currentIndex
>= 0;
104 void previous() const {
108 idx_t
currentIndex() const {
109 return _currentIndex
;
112 size_t length() const {
116 mutable idx_t _currentIndex
;
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
) {
145 for (int x
= 0; x
< length
; x
++)ar
[x
] = orig
[x
];
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.
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
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
),
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
)) {
222 for (T x
= ran
.first(); x
< ran
.last(); x
++) {
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
),
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.
249 if (!data
->refcount
) {
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
];
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.
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...
309 for (idx_t i
= 0; i
< length
; i
++) {
310 if (func(*this[i
], clientData
)) newlength
++;
312 Array
<T
> toReturn(newlength
);
314 for (idx_t i
= 0; i
< length
; i
++) {
315 if (func(*this[i
], clientData
)) {
316 toReturn
[curpos
] = *this[i
];
324 * Sets every entry in the array to the object returned by that classes'
325 * default constructor.
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
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
;
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
];
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
];
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());
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());
412 #ifndef SYLPH_DOXYGEN
417 explicit Data(size_t length
) : _length(length
),
418 _carray(new T
[length
]()), refcount(1) {
425 const size_t _length
;
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>
438 * @tplreqs T EqualityComparable
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;
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
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]);
466 std::ostream
& operator<<(std::ostream
& out
, const Array
<T
>& rhs
) {
468 for(idx_t i
= 0; i
< rhs
.length
- 1; ++i
) {
469 out
<< rhs
[i
] << ", ";
471 out
<< rhs
[rhs
.length
-1] << " }";
477 #endif /* ARRAY_H_ */