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 prefered.
55 class Array
: public virtual Object
{
60 class iterator
: public RandomAccessIterator
<T
, iterator
> {
62 typedef RandomAccessIterator
<T
, iterator
> super
;
64 iterator(bool begin
= false, Array
<T
>* obj
= NULL
)
65 : super(begin
), _obj(obj
) {
66 _currentIndex
= begin
? 0 : (_obj
->length
- 1);
69 iterator(bool begin
= false, const Array
<T
>* obj
= NULL
)
70 : super(begin
), _obj(const_cast<Array
<T
>*> (obj
)) {
71 _currentIndex
= begin
? 0 : (_obj
->length
- 1);
74 bool equals(const iterator
& other
) const {
75 return _currentIndex
== other
._currentIndex
&&
79 iterator(const iterator
& other
) {
80 _currentIndex
= other
._currentIndex
;
84 typename
super::reference
current() const {
85 return (*_obj
)[_currentIndex
];
88 bool hasNext() const {
89 return _currentIndex
< (_obj
->length
- 1);
96 bool hasPrevious() const {
97 return _currentIndex
>= 0;
100 void previous() const {
104 idx_t
currentIndex() const {
105 return _currentIndex
;
108 size_t length() const {
112 mutable idx_t _currentIndex
;
118 * A function that is used for filtering by the filter() method. This
119 * function takes both an instance of the class this Array contains, and
120 * a reference to a reference to any kind of other data that may need to
121 * be passed to the FilterFunction.
123 typedef bool(*FilterFunction
)(const T
&, Any
&);
125 * The length of the array. This variable is 1-based, while the array itself
126 * is 0-based, i.e. if length == N the highest entry in this array is N-1.
127 * E.g if array.length == 5, then the higest entry is array[4]
129 const size_t & length
;
132 * Creates an Array<T> from a pointer to T and a length. The new array will
133 * have the length specified in <code>length</code>. The original array will
134 * not be modified, the contents are copied. No bounds-checking
135 * is done, therefore, use this function at your own responsability!
136 * @param length The length of the original C array
137 * @param orig The original C array, supplied as a pointer.
139 inline static Array
<T
> fromPointer(std::size_t length
, T
* orig
) {
141 for (int x
= 0; x
< length
; x
++)ar
[x
] = orig
[x
];
147 * Creates an Array with the specified length. A new instance of the
148 * reference counted data is created, its reference count set to 1 and the
149 * internal C array is allocated to have the specified length.
150 * @param len The length of the new Array.
152 explicit Array(std::size_t len
= 0) : _length(len
), length(_length
),
153 data(new Data(len
)) {
157 * Creates an Array from an intializer list. This constructor allows the
158 * easier, more familiar syntax of Array creation, but requires C++0x. Using
159 * this constructor, arrays can be initialized as following:
160 * <pre>Array<int> myarr = {5,4,7,9};</pre>
161 * A new instance of the reference counted data is created, the reference
162 * count is set to 1, the length is set to the length of the intializer
163 * list, and all data is copied into a newly allocated C array.
164 * @param il The initializer_list used to create the array.
166 Array(const std::initializer_list
<T
> & il
) : _length(il
.size()),
167 length(_length
), data(new Data(_length
)) {
168 for (idx_t i
= 0; i
< il
.size(); i
++) {
169 data
->_carray
[i
] = il
.begin()[i
];
174 * Creates an Array from an existing C-style array. Note that you can only
175 * pass a true array, i.e. you cannot pass a pointer that acts as an array.
176 * If you only have a pointer, you'll have to initialize using
177 * Array::fromPointer(size_t, length) . <p>
178 * A new instance of the reference counted data is created, the reference
179 * count is set to 1, the length is set to the length of the Array, all
180 * data is copied into a newly allocated C array with the same length as
181 * the original array. The original array remains unmodified.
182 * @param array A traditional, C-style array to create this Array from.
185 Array(const T(&array
)[N
]) : _length(N
), length(_length
), data(new Data(N
)) {
186 for (idx_t i
= 0; i
< _length
; i
++) {
187 data
->_carray
[i
] = array
[i
];
192 * Creates an Array from another instance of the Array class. The data is
193 * not copied, instead, the pointer to the refernce counted data will be
194 * set to the reference counted data of the other Array, and the reference
195 * count will increase by 1. Other fields of the reference counted data
197 * @param other An other Array from which to use the reference counted data.
199 Array(const Array
<T
> & other
) : _length(other
._length
), length(_length
),
205 * Creates an array from a range of items. Every item within the range will
206 * be added to the array. This is most useful for integral types, as other
207 * types usually don't support the required semantics.<p>
208 * A new instance of the reference counted data is created, the reference
209 * count is set to 1, the length is set to <code>ran.last() - ran.first()
210 * </code>, a new C-style array with this length will be allocated.
211 * @param ran a range class that specifies the lower and upper boundaries.
214 Array(const basic_range
<T
> & ran
) : _length(ran
.last() - ran
.first()),
215 length(_length
), data(new Data(length
)) {
217 for (T x
= ran
.first(); x
< ran
.last(); x
++) {
224 * Creates an Array from a single item. This is useful for implicit
225 * conversions, as it allows a single instance of a class to be passed as
226 * an Array of that class with length 1. <p>
227 * A new instance of the reference counted data is created, the reference
228 * count set to 1, the length is set to 1, and a new C-style array with
229 * length 1 is allocated. The object is copied into this array, the original
230 * object remains unmodified.
231 * @param t An object to create a length-1 array from.
233 explicit Array(const T
& t
) : _length(1), length(_length
),
235 data
->_carray
[0] = t
;
239 * Destructor. Reduces the reference count by 1. If the reference count
240 * reaches 0, the internal backing data will be destroyed.
244 if (!data
->refcount
) {
251 * Creates a copy of this array. The Array returned from this method is
252 * an exact copy of this Array, such that ar == ar.copy() . The returned
253 * Array is different from the one returned by operator=, as the reference
254 * counted data gets copied as well, in other words, both Arrays will have
255 * a different, equal instance of the reference counted data.
256 * @return A new Array containing the same data as this Array.
258 Array
<T
> copy() const {
259 Array
<T
> toReturn((std::size_t)length
);
260 for (idx_t i
= 0; i
< length
; i
++) {
261 toReturn
[i
] = (*this)[i
];
267 * Returns a c-style array representing the contents of this Array. The
268 * array returned is not a copy of this array, in fact, changes to the
269 * returned array are reflected in this Array.
272 return data
->_carray
;
276 * Returns a c-style array representing the contents of this Array. The
277 * array returned is not a copy of this array, in fact, changes to the
278 * returned array are reflected in this Array. This version returns a const
279 * c-style array and is used when this Array is const.
281 const T
*carray() const {
282 return data
->_carray
;
286 * This will filter the Array according to a FilterFunction. This function
287 * returns a new, 'filtered' Array, which only contains the entries for
288 * which the FilterFunction returns true.
289 * @param func A pointer to the function which is used for filtering
290 * @param clientData %Any data to be passed to the FilterFunction
291 * @return A new array containing only the filtered data
293 Array
<T
> filter(FilterFunction func
, Any
& clientData
) {
294 // I'm terribly sorry but we'll need to iterate twice over the Array...
296 for (idx_t i
= 0; i
< length
; i
++) {
297 if (func(*this[i
], clientData
)) newlength
++;
299 Array
<T
> toReturn(newlength
);
301 for (idx_t i
= 0; i
< length
; i
++) {
302 if (func(*this[i
], clientData
)) {
303 toReturn
[curpos
] = *this[i
];
311 * Sets every entry in the array to the object returned by that classes'
312 * default constructor.
315 delete this->data
->_carray
;
316 this->data
->_carray
= new T
[this->data
->_length
];
320 * Swaps the data pointer of this Array with the other Array. The refcount
321 * for the current data pointer gets decreased by 1, the refcount for the
322 * data pointer of the other array gets increased by 1. In case the this
323 * Array'soriginal data pointer's refcount reaches zero, the original data
325 * @param other The other array from which to use the data pointer
327 Array
<T
> & operator=(const Array
<T
> & other
) {
328 if (this->data
== other
.data
) return *this;
329 this->data
->refcount
--;
330 if (!this->data
->refcount
) delete this->data
;
331 this->data
= other
.data
;
332 this->_length
= other
.data
->_length
;
338 * Used for accessing the Array's contents. Its behaviour is identical to
339 * that of c-style arrays, but throws an exception instead of overflowing
340 * or causing segfaults. <p>
341 * The Array will assume ownership over any pointers entered in this way.
342 * @param idx the index in the array from which to return an element
343 * @throw ArrayException if <code>idx > length</code>
345 T
& operator[](std::sidx_t idx
) throw (Exception
) {
346 if ((idx
< (sidx_t
)length
) && (idx
>= -(sidx_t
)length
)) {
347 return idx
>= 0 ? data
->_carray
[idx
] : data
->_carray
[length
+ idx
];
349 sthrow(ArrayException
, "Array overflow");
354 * This is the <code>const</code> version of T& operator[] . Its behaviour
355 * is identical to that of c-style const arrays, but throws an exception
356 * instead of overflowing or causing segfaults.
357 * @param idx the index in the array from which to return an element
358 * @throw ArrayException if <code>idx > length</code>
360 const T
& operator[](std::sidx_t idx
) const throw (Exception
) {
361 if ((idx
< (sidx_t
)length
) && (idx
>= -(sidx_t
)length
)) {
362 return idx
>= 0 ? data
->_carray
[idx
] : data
->_carray
[length
+ idx
];
364 sthrow(ArrayException
, "Array overflow");
369 * Slices the array and returns the subarray. E.g. :
370 * <pre>Array<String> subarr = myarr[range(5,8)]</pre>
371 * <code>subarr</code> now contains the values of @c myarr[5] to @c myarr[8]
372 * . Please note that the subarray contains a copy of the original.
373 * @param ran The range describing the slice.
374 * @throw ArrayException if ran.last() > length
376 Array
<T
> operator[](const range
& ran
) throw (Exception
) {
377 if (ran
.first() < 0 || ran
.last() >= length
)
378 sthrow(ArrayException
, "Array overflow");
380 Array
<T
> toReturn
= Array
<T
>::fromPointer((ran
.last() - ran
.first())+1,
381 data
->_carray
+ ran
.first());
386 * Const-version of operator[](const range &) .
387 * @param ran The range describing the slice
388 * @throw ArrayException if ran.last() > length
390 const Array
<T
> operator[](const range
& ran
) const throw (Exception
) {
391 if (ran
.first() < 0 || ran
.last() >= length
)
392 sthrow(ArrayException
, "Array overflow");
394 Array
<T
> toReturn
= Array
<T
>::fromPointer((ran
.last() - ran
.first())+1,
395 data
->_carray
+ ran
.first());
399 #ifndef SYLPH_DOXYGEN
404 explicit Data(size_t length
) : _length(length
),
405 _carray(new T
[length
]()), refcount(1) {
412 const size_t _length
;
420 * Compares the two Arrays on equality. To Arrays compare equal when their
421 * lengths are identical and each of the items compare equal to the item on the
422 * same position in the other array.
423 * @return <i>true</i> when the two arrays compare equal, <i>false</i>
427 inline bool operator==(const Array
<T
>& lhs
, const Array
<T
>& rhs
) {
428 if(lhs
.length
== rhs
.length
) {
429 for(idx_t i
= 0; i
< lhs
.length
; i
++) {
430 if(lhs
[i
] != rhs
[i
]) return false;
438 * Compares the two Arrays. To Arrays compare less than when their lengths are
439 * identical and each of the items compare less than to the item on the same
440 * position in the other array.
441 * @return <i>true</i> when the first array compares less than the first,
442 * <i>false</i> otherwise.
445 inline bool operator<(const Array
<T
>& lhs
, const Array
<T
>& rhs
) {
446 return std::lexicographical_compare(&lhs
[0], &lhs
[lhs
.length
-1],
447 &rhs
[0], &rhs
[rhs
.length
-1]);
452 #endif /* ARRAY_H_ */