/** @file
Parser: Array & Array_iterator classes decls.
Copyright (c) 2001-2003 ArtLebedev Group (http://www.artlebedev.com)
Author: Alexandr Petrosian <paf@design.ru> (http://paf.design.ru)
*/
#ifndef PA_ARRAY_H
#define PA_ARRAY_H
static const char* IDENT_ARRAY_H="$Date: 2003/02/26 10:17:30 $";
// includes
#include "pa_memory.h"
#include "pa_exception.h"
// forwards
template<typename T> class Array_iterator;
/// Simple Array
template<typename T> class Array: public PA_Object {
friend class Array_iterator<T>;
protected:
// default expand delta size
int fdelta;
/// elements[growing size] here
T *felements;
// allocated size
int fallocated;
// array size
int fused;
public:
typedef T element_type;
Array(int initial=3, int delta=1):
fallocated(initial?initial:3),
fdelta(delta),
fused(0)
{
if(fallocated<=0 || fdelta<1)
throw Exception(0,
Exception::undefined_source,
"Array::Array(%d, %d) too small", initial, delta);
// we can't use new(0) here[like we did in Hash] because we need to use realloc
// on MSVC new returns NOT pointer learned from pa_malloc, so we can't do new+realloc
felements=static_cast<T*>(calloc(fallocated*sizeof(T)));
}
override ~Array() {
// see comment in ctor
T *last=felements+fused;
for(T *current=felements; current<last; current++)
current->~T(); // manually invoking destructors
free(felements);
}
/// how many items are in Array
int count() const { return fused; }
/// append to array
Array& operator += (T src) {
if(is_full())
expand(fdelta);
felements[fused++]=src;
return *this;
}
/// append other Array portion to this one. starting from offset
Array& append(const Array& src, int offset=0, int limit=0) {
if(offset<0) {
throw Exception(0,
Exception::undefined_source,
"Array::append(offset=%d) out <0", offset);
//return Nothing; // never
}
// fix limit
{
int m=src.count()-offset;
if(!m || limit<0)
return *this;
if(!limit || limit>m)
limit=m;
}
int delta=limit-(fallocated-fused);
if(delta>0)
expand(delta);
T* from=&src.felements[offset];
T* to=&felements[fused];
T* from_end=from+limit;
while(from<from_end)
*to++=*from++;
fused+=limit;
return *this;
}
/// get index-element
T& get(int index) const {
if(!(index>=0 && index<count())) {
throw Exception(0,
Exception::undefined_source,
"Array::get(%d) out of range [0..%d]", index, count()-1);
return felements[0]; // never
}
return felements[index];
}
T& operator [](int index) const { return get(index); }
/// put index-element
void put(int index, T& element) {
if(!(index>=0 && index<count())) {
throw Exception(0,
Exception::undefined_source,
"Array::put(%d) out of range [0..%d]", index, count()-1);
return; // never
}
felements[index]=element;
}
/// iterate over all elements
template<typename I> void for_each(void (*callback)(T, I), I info) const {
T *last=felements+fused;
for(T *current=felements; current<last; current++)
callback(*current, info);
}
/// iterate over all elements until condition becomes true, return that element
template<typename I> T first_that(bool (*callback)(T, I), I info) const {
T *last=felements+fused;
for(T *current=felements; current<last; current++)
if(callback(*current, info))
return *current;
return T(0);
}
protected:
bool is_full() {
return fused == fallocated;
}
void expand(int delta) {
felements = (T *)realloc(felements, (fallocated+delta)*sizeof(T));
memset(&felements[fallocated], 0, delta*sizeof(T));
fallocated+=delta;
}
private: //disabled
Array& operator = (const Array&) { return *this; }
};
/// handy array iterator
template<typename T> class Array_iterator {
Array<T>& farray;
T *fcurrent;
T *flast;
public:
Array_iterator(Array<T>& aarray): farray(aarray) {
fcurrent=farray.felements;
flast=farray.felements+farray.count();
}
/// there are still elements
bool has_next() {
return fcurrent<flast;
}
/// quickly extracts next Array element
T& next() {
return *(fcurrent++);
}
};
#endif
E-mail: