|
|
| version 1.32, 2001/03/28 08:01:41 | version 1.57.2.27.2.8, 2003/03/27 10:04:06 |
|---|---|
| Line 1 | Line 1 |
| /** @file | /** @file |
| Parser: array class decl. | Parser: Array & Array_iterator classes decls. |
| Copyright (c) 2001 ArtLebedev Group (http://www.artlebedev.com) | Copyright (c) 2001-2003 ArtLebedev Group (http://www.artlebedev.com) |
| Author: Alexandr Petrosian <paf@design.ru> (http://paf.design.ru) | |
| Author: Alexander Petrosyan <paf@design.ru> (http://design.ru/paf) | |
| $Id$ | |
| */ | */ |
| #ifndef PA_ARRAY_H | #ifndef PA_ARRAY_H |
| #define PA_ARRAY_H | #define PA_ARRAY_H |
| #include <stddef.h> | static const char* IDENT_ARRAY_H="$Date$"; |
| #include "pa_pool.h" | // includes |
| #include "pa_types.h" | |
| #include "pa_string.h" | |
| /** | |
| Pooled Array. | |
| Internal structure: | |
| @verbatim | |
| Array Chunk0 | |
| ====== ======== | |
| head--------------->[ptr] | |
| append_here-------->[ptr] | |
| link_row ........ | |
| . . | |
| . [ptr] | |
| ...........>[link to the next chunk] | |
| @endverbatim | |
| */ | |
| class Array : public Pooled { | #include "pa_memory.h" |
| public: | #include "pa_exception.h" |
| /// Array item type | // forwards |
| typedef void Item; | |
| /// for_each iterator function type | template<typename T> class Array_iterator; |
| typedef void (*For_each_func)(Item *value, void *info); | |
| /// first_that iterator function type, const info | /// Simple Array |
| typedef bool (*First_that_func_const)(Item *value, const void *info); | template<typename T> class Array: public PA_Object { |
| /// first_that iterator function type | friend class Array_iterator<T>; |
| typedef bool (*First_that_func)(Item *value, void *info); | |
| enum { | |
| CR_INITIAL_ROWS_DEFAULT=10, ///< default preallocated row count | |
| CR_GROW_PERCENT=60 ///< each time the Array chunk_is_full() array expanded() | |
| }; | |
| public: | protected: |
| /// elements[growing size] here | |
| T *felements; | |
| // allocated size | |
| size_t fallocated; | |
| Array(Pool& apool, int initial_rows=CR_INITIAL_ROWS_DEFAULT); | // array size |
| size_t fused; | |
| public: | |
| typedef T element_type; | |
| /// size Array. how many items are in it | Array(int initial=3): |
| int size() const { | fallocated(initial>3?initial:3), |
| // for get and quick_get | fused(0) |
| cache_chunk_base=0; | { |
| cache_chunk=head; | felements=static_cast<T*>(malloc(fallocated*sizeof(T))); |
| return fused_rows; | |
| } | } |
| /// append Item to array | |
| Array& operator += (Item *src); | |
| /// dirty hack to allow constant items storage. I long for Array<const Item*> | /// how many items are in Array |
| Array& operator += (const Item *src) { return *this+=const_cast<Item*>(src); } | size_t count() const { return fused; } |
| /// append to array | |
| Array& operator += (T src) { | |
| if(is_full()) | |
| expand(2); | |
| /// append other Array portion to this one. starting from offset | felements[fused++]=src; |
| Array& append_array(const Array& src, int offset=0); | |
| /** | return *this; |
| quickly gets some item considering... | } |
| these true: | /// append other Array portion to this one. starting from offset |
| - index increments from 0 to size()-1 | Array& append(const Array& src, int offset=0, int limit=0) { |
| - index>=0 && index<size() | if(offset<0) { |
| - index>=cache_chunk_base | throw Exception(0, |
| */ | 0, |
| Item *quick_get(int index) const { | "Array::append(offset=%d) out <0", offset); |
| // next chunk will be with "index" row | //return Nothing; // never |
| if(!(index<cache_chunk_base+cache_chunk->count)) { | } |
| int count=cache_chunk->count; | // fix limit |
| cache_chunk_base+=count; | { |
| cache_chunk=cache_chunk->rows[count].link; | 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++; | |
| return cache_chunk->rows[index-cache_chunk_base].item; | fused+=limit; |
| return *this; | |
| } | } |
| Item *get(int index) const; | /// quick version of get index-element [use in tight places when sure] |
| void put(int index, Item *item); | T unchecked_get(size_t index) const { |
| /// convinient way to get strings from Array. I long for Array<const String *> | return felements[index]; |
| const String *get_string(int index) const { | |
| return const_cast<const String *>(static_cast<String *>(get(index))); | |
| } | } |
| /// iterate over all elements | size_t check(const char* name, size_t index) const { |
| void for_each(For_each_func func, void *info=0) const; | size_t lcount=count(); |
| if(!(index>=0 && index<lcount)) { | |
| throw Exception(0, | |
| 0, | |
| "Array::%s(%d) out of range [0..%d]", name, index, lcount-1); | |
| return 0; // never | |
| } | |
| return index; | |
| } | |
| /// iterate over all elements until condition, const info | /// get index-element |
| void* first_that(First_that_func_const func, const void *info=0) const; | T get(size_t index) const { |
| return unchecked_get(check("get", index)); | |
| } | |
| /// iterate over all elements until condition | T operator [](size_t index) const { return get(index); } |
| void* first_that(First_that_func func, void *info=0) const; | |
| private: | /*/// get the reference to index-element |
| T& get_ref(size_t index) { | |
| struct Chunk { | return felements[check("get_ref", index)]; |
| // the number of rows in chunk | }*/ |
| int count; | |
| union Row { | /// put index-element |
| Item *item; | void put(size_t index, T element) { |
| Chunk *link; // link to the next chunk in chain | felements[check("put", index)]=element; |
| } rows[1]; | } |
| // next rows are here | |
| } | |
| *head; // the head chunk of the chunk chain | |
| // last allocated chunk | |
| // helps appending Arrays | |
| Chunk *tail; | |
| // next append would write to this record | |
| Chunk::Row *append_here; | |
| // the address of place where lies address | |
| // of the link to the next chunk to allocate | |
| Chunk::Row *link_row; | |
| private: | |
| // array size | /// iterate over all elements |
| int fused_rows; | 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; | |
| mutable int cache_chunk_base; | return T(0); |
| mutable Chunk *cache_chunk; | } |
| private: | protected: |
| bool chunk_is_full() { | bool is_full() { |
| return append_here == link_row; | return fused == fallocated; |
| } | |
| void expand(size_t delta) { | |
| size_t new_allocated=fallocated+delta; | |
| felements = (T *)realloc(felements, new_allocated*sizeof(T)); | |
| memset(&felements[fallocated], 0, delta*sizeof(T)); | |
| fallocated=new_allocated; | |
| } | } |
| void expand(int chunk_rows); | |
| private: //disabled | private: //disabled |
| //Array(Array&) { } | Array(const Array&) {} |
| Array& operator = (const Array&) { return *this; } | Array& operator = (const Array&) { return *this; } |
| }; | }; |
| /** Array iterator, usage: | |
| @code | |
| // Array<T> a; | |
| Array_iterator<T> i(a); | |
| while(i.has_next()) { | |
| T& element=i.next(); | |
| ... | |
| } | |
| @endcode | |
| */ | |
| template<typename T> class Array_iterator { | |
| const Array<T>& farray; | |
| T *fcurrent; | |
| T *flast; | |
| public: | |
| Array_iterator(const 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 | |
| const T next() { | |
| return *(fcurrent++); | |
| } | |
| }; | |
| /** Nonconst array iterator, usage: | |
| @code | |
| // Array<T> a; | |
| Array_iterator<T> i(a); | |
| while(i.has_next()) { | |
| T& element=i.next(); | |
| ... | |
| } | |
| @endcode | |
| */ | |
| template<typename T> class Array_modifing_iterator { | |
| Array<T>& farray; | |
| T *fcurrent; | |
| T *flast; | |
| public: | |
| Array_modifing_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 | #endif |