|
|
| version 1.11, 2001/01/29 20:10:31 | version 1.57.2.16, 2003/01/31 12:34:29 |
|---|---|
| Line 1 | Line 1 |
| /* | /** @file |
| $Id$ | 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_Y="$Date$"; | |
| #include "pa_pool.h" | |
| #include "pa_exception.h" | |
| template<typename T> class Array_iterator; | |
| Array Chunk0 | /** |
| ====== ======== | Simple Array. |
| head--------------->[ptr] | |
| append_here-------->[ptr] | |
| link_row ........ | |
| . . | |
| . [ptr] | |
| ...........>[link to the next chunk] | |
| */ | */ |
| template<typename T> class Array: public PA_Object { | |
| #ifndef PA_ARRAY_H | friend class Array_iterator<T>; |
| #define PA_ARRAY_H | |
| protected: | |
| // default expand delta size | |
| int fdelta; | |
| #include <stddef.h> | /// elements[growing size] here |
| T *felements; | |
| #include "pa_types.h" | // allocated size |
| #include "pa_string.h" | int fallocated; |
| class Pool; | // array size |
| int fused; | |
| class Array { | |
| public: | public: |
| typedef T element_type; | |
| typedef void Item; | 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); | |
| enum { | felements=new T[fallocated]; |
| CR_INITIAL_ROWS_DEFAULT=10, | } |
| CR_GROW_PERCENT=60 | override ~Array() { |
| }; | T *last=felements+fused; |
| for(T *current=felements; current<last; current++) | |
| delete current; | |
| public: | delete felements; |
| } | |
| void *operator new(size_t size, Pool& apool); | /// how many items are in Array |
| Array(Pool& apool, int initial_rows=CR_INITIAL_ROWS_DEFAULT); | int count() const { return fused; } |
| /// append to array | |
| Array& operator += (T src) { | |
| if(is_full()) | |
| expand(fdelta); | |
| int size() { return fused_rows; } | felements[fused++]=src; |
| Array& operator += (Item *src); | |
| Array& append_array(Array& src); | |
| Item *get(int index); | |
| char *get_cstr(int index) { return static_cast<char *>(get(index)); } | |
| String *get_string(int index) { return static_cast<String *>(get(index)); } | |
| protected: | 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 && offset<src.count())) { | |
| throw Exception(0, | |
| Exception::undefined_source, | |
| "Array::append(offset=%d) out of range [0..%d]", offset, src.count()-1); | |
| //return 0; // never | |
| } | |
| // fix limit | |
| { | |
| int m=src.count()-offset; | |
| if(!m || limit<0) | |
| return *this; | |
| if(!limit || limit>m) | |
| limit=m; | |
| } | |
| int needed=limit-(fallocated-fused); | |
| if(needed>0) | |
| expand(needed); | |
| // the pool I'm allocated on | memcpy(&felements[fused+=limit], &src.felements[offset], limit*sizeof(T)); |
| Pool& pool; | return *this; |
| } | |
| private: | /// get index-element |
| T& get(int index) { | |
| 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 | |
| } | |
| struct Chunk { | return felements[index]; |
| // the number of rows in chunk | } |
| int count; | |
| union Row { | |
| Item *item; | |
| Chunk *link; // link to the next chunk in chain | |
| } 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: | T& operator [](int index) { return get(index); } |
| // array size | /// put index-element |
| int fused_rows; | 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 0;//T(0); | |
| } | |
| int cache_chunk_base; | protected: |
| Chunk *cache_chunk; | |
| private: | |
| bool chunk_is_full() { | bool is_full() { |
| return append_here == link_row; | return fused == fallocated; |
| } | |
| void expand(int delta) { | |
| fallocated+=delta; | |
| felements = (T *)realloc(felements, fallocated*sizeof(T)); | |
| } | } |
| void expand(int chunk_rows); | |
| private: //disabled | private: //disabled |
| //Array(Array&) { } | Array& operator = (const Array&) { return *this; } |
| Array& operator = (Array&) { return *this; } | }; |
| typedef smart_ptr<char> CharPtr; | |
| class Pool: public Array<CharPtr> { | |
| public: | |
| char *malloc(size_t size) { | |
| CharPtr result=CharPtr((char *)Array<CharPtr>::malloc(size)); | |
| *this += result; | |
| return result.get(); | |
| } | |
| char *copy(const char* buf, size_t size=0) { | |
| if(!size) | |
| size=strlen(buf)+1; | |
| char *result=malloc(size); | |
| memcpy(result, buf, size); | |
| return result; | |
| } | |
| }; | |
| inline void *operator new(size_t size, Pool& pool) { | |
| return pool.malloc(size); | |
| } | |
| /// 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 | #endif |