|
|
| version 1.57.2.17, 2003/01/31 16:45:26 | version 1.88, 2024/09/07 15:01:38 |
|---|---|
| Line 1 | Line 1 |
| /** @file | /** @file |
| Parser: Array & Array_iterator classes decls. | Parser: Array & Array_iterator classes decls. |
| Copyright (c) 2001-2003 ArtLebedev Group (http://www.artlebedev.com) | Copyright (c) 2001-2023 Art. Lebedev Studio (http://www.artlebedev.com) |
| Author: Alexandr Petrosian <paf@design.ru> (http://paf.design.ru) | Authors: Konstantin Morshnev <moko@design.ru>, Alexandr Petrosian <paf@design.ru> |
| */ | */ |
| #ifndef PA_ARRAY_H | #ifndef PA_ARRAY_H |
| #define PA_ARRAY_H | #define PA_ARRAY_H |
| static const char* IDENT_ARRAY_Y="$Date$"; | #define IDENT_PA_ARRAY_H "$Id$" |
| #include "pa_pool.h" | // includes |
| #include "pa_memory.h" | |
| #include "pa_exception.h" | #include "pa_exception.h" |
| // forwards | |
| template<typename T> class Array_iterator; | template<typename T> class Array_iterator; |
| /** | // defines |
| Simple Array. | |
| */ | #define ARRAY_OPTION_LIMIT_ALL ((size_t)-1) |
| /// Simple Array | |
| template<typename T> class Array: public PA_Object { | template<typename T> class Array: public PA_Object { |
| friend class Array_iterator<T>; | friend class Array_iterator<T>; |
| protected: | protected: |
| // default expand delta size | |
| int fdelta; | |
| /// elements[growing size] here | /// elements[growing size] here |
| T *felements; | T *felements; |
| // allocated size | // allocated size |
| int fallocated; | size_t fallocated; |
| // array size | // array size |
| int fused; | size_t fused; |
| public: | public: |
| typedef Array_iterator<T> Iterator; | |
| struct Action_options { | |
| size_t offset; | |
| size_t limit; //< ARRAY_OPTION_LIMIT_ALL means 'all'. zero limit means 'nothing' | |
| bool reverse; | |
| bool defined; | |
| Action_options( | |
| size_t aoffset=0, | |
| size_t alimit=ARRAY_OPTION_LIMIT_ALL, | |
| bool areverse=false): | |
| offset(aoffset), limit(alimit), reverse(areverse), | |
| defined(false) {} | |
| bool adjust(size_t count) { | |
| if(!count || !limit) | |
| return false; | |
| if(offset>=count) | |
| return false; | |
| // max(limit) | |
| size_t m=reverse? | |
| offset+1 | |
| :count-offset; | |
| if(!m) | |
| return false; | |
| // fix limit | |
| if(limit==ARRAY_OPTION_LIMIT_ALL || limit>m) | |
| limit=m; | |
| return true; | |
| } | |
| }; | |
| typedef T element_type; | typedef T element_type; |
| Array(int initial=3, int delta=1): | inline Array(size_t initial=0): |
| fallocated(initial?initial:3), | fallocated(initial), |
| fdelta(delta), | |
| fused(0) | fused(0) |
| { | { |
| if(fallocated<=0 || fdelta<1) | felements=fallocated?(T *)pa_malloc(fallocated*sizeof(T)):0; |
| throw Exception(0, | |
| Exception::undefined_source, | |
| "Array::Array(%d, %d) too small", initial, delta); | |
| felements=new T[fallocated]; | |
| } | } |
| override ~Array() { | |
| T *last=felements+fused; | |
| for(T *current=felements; current<last; current++) | |
| delete current; | |
| delete felements; | #ifdef USE_DESTRUCTORS |
| inline ~Array(){ | |
| if(felements) | |
| pa_free(felements); | |
| } | } |
| #endif | |
| /// how many items are in Array | /// how many items are in Array |
| int count() const { return fused; } | inline size_t count() const { return fused; } |
| /// append to array | /// append to array |
| Array& operator += (T src) { | inline Array& operator+=(T src) { |
| if(is_full()) | if(is_full()) |
| expand(fdelta); | expand(fallocated>0? 2+fallocated/32 : 3); // 3 is PAF default, confirmed by tests |
| felements[fused++]=src; | felements[fused++]=src; |
| Line 73 public: | Line 105 public: |
| } | } |
| /// append other Array portion to this one. starting from offset | /// append other Array portion to this one. starting from offset |
| Array& append(const Array& src, int offset=0, int limit=0) { | Array& append(const Array& src, |
| if(!(offset>=0 && offset<src.count())) { | size_t offset=0, |
| throw Exception(0, | size_t limit=ARRAY_OPTION_LIMIT_ALL) { //< negative limit means 'all'. zero limit means 'nothing' |
| Exception::undefined_source, | |
| "Array::append(offset=%d) out of range [0..%d]", offset, src.count()-1); | size_t src_count=src.count(); |
| //return 0; // never | // skip tivials |
| } | if(!src_count || !limit || offset>=src_count) |
| return *this; | |
| // max(limit) | |
| size_t m=src_count-offset; | |
| // fix limit | // fix limit |
| { | if(limit==ARRAY_OPTION_LIMIT_ALL || limit>m) |
| int m=src.count()-offset; | limit=m; |
| if(!m || limit<0) | |
| return *this; | |
| if(!limit || limit>m) | |
| limit=m; | |
| } | |
| int needed=limit-(fallocated-fused); | ssize_t delta=limit-(fallocated-fused); |
| if(needed>0) | if(delta>0) |
| expand(needed); | expand(delta); |
| memcpy(&felements[fused+=limit], &src.felements[offset], limit*sizeof(T)); | T* from=&src.felements[offset]; |
| T* to=&felements[fused]; | |
| for(T* from_end=from+limit; from<from_end; from++) | |
| *to++=*from; | |
| fused+=limit; | |
| return *this; | return *this; |
| } | } |
| /// get index-element | /// get index-element |
| T& get(int index) { | inline T get(size_t index) const { |
| if(!(index>=0 && index<count())) { | assert(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]; | return felements[index]; |
| } | } |
| T& operator [](int index) { return get(index); } | /// ref version of get |
| inline T& get_ref(size_t index) const { | |
| assert(index<count()); | |
| return felements[index]; | |
| } | |
| /// put index-element | /// put index-element |
| void put(int index, T& element) { | inline void put(size_t index, T element) { |
| if(!(index>=0 && index<count())) { | assert(index<count()); |
| throw Exception(0, | |
| Exception::undefined_source, | |
| "Array::put(%d) out of range [0..%d]", index, count()-1); | |
| return; // never | |
| } | |
| felements[index]=element; | felements[index]=element; |
| } | } |
| /// insert index-element | |
| inline void insert(size_t index, T element) { | |
| assert(index<=count()); | |
| if(is_full()) | |
| expand(fallocated>0? 2+fallocated/32 : 3); // 3 is PAF default, confirmed by tests | |
| memmove(felements+index+1, felements+index, (fused-index) * sizeof(T)); | |
| felements[index]=element; | |
| fused++; | |
| } | |
| /// remove index-element | |
| inline void remove(size_t index) { | |
| assert(index<count()); | |
| if (index<--fused) | |
| memmove(felements+index, felements+index+1, (fused-index) * sizeof(T)); | |
| } | |
| inline T operator [](size_t index) const { return get(index); } | |
| inline void clear() { | |
| fused=0; | |
| } | |
| /// iterate over all elements | /// iterate over all elements |
| template<typename I> void for_each(void (*callback)(T, I), I info) const { | template<typename I> void for_each(void (*callback)(T, I), I info) const { |
| Line 130 public: | Line 182 public: |
| callback(*current, info); | callback(*current, info); |
| } | } |
| /// iterate over all elements | |
| template<typename I> void for_each(bool (*callback)(T, I), I info) const { | |
| T *last=felements+fused; | |
| for(T *current=felements; current<last; current++) | |
| if(callback(*current, info)) | |
| return; | |
| } | |
| /// iterate over all elements | |
| template<typename I> void for_each_ref(void (*callback)(T&, I), I info) { | |
| 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 | /// iterate over all elements until condition becomes true, return that element |
| template<typename I> T first_that(bool (*callback)(T, I), I info) const { | template<typename I> T first_that(bool (*callback)(T, I), I info) const { |
| T *last=felements+fused; | T *last=felements+fused; |
| Line 137 public: | Line 204 public: |
| if(callback(*current, info)) | if(callback(*current, info)) |
| return *current; | return *current; |
| return 0;//T(0); | return T(0); |
| } | |
| inline T* ptr(size_t index){ | |
| return felements + index; | |
| } | |
| void fit(size_t index, T element){ | |
| if(index >= fallocated){ | |
| size_t new_allocated=fallocated>0 ? fallocated : 3; | |
| while(new_allocated <= index){ | |
| new_allocated+=2 + new_allocated/32; | |
| } | |
| expand(new_allocated - fallocated); | |
| } | |
| felements[index]=element; | |
| if(index >= fused){ | |
| fused=index+1; | |
| } | |
| } | } |
| protected: | protected: |
| Line 145 protected: | Line 230 protected: |
| bool is_full() { | bool is_full() { |
| return fused == fallocated; | return fused == fallocated; |
| } | } |
| void expand(int delta) { | |
| fallocated+=delta; | void expand(size_t delta) { |
| felements = (T *)realloc(felements, fallocated*sizeof(T)); | if(fallocated){ |
| size_t new_allocated=fallocated+delta; | |
| felements=(T *)pa_realloc(felements, new_allocated*sizeof(T)); | |
| fallocated=new_allocated; | |
| } else { | |
| fallocated=delta; | |
| felements=(T *)pa_malloc(fallocated*sizeof(T)); | |
| } | |
| } | } |
| private: //disabled | private: //disabled |
| Array(const Array&) {} | |
| Array& operator = (const Array&) { return *this; } | Array& operator = (const Array&) { return *this; } |
| }; | }; |
| typedef smart_ptr<char> CharPtr; | |
| class Pool: public Array<CharPtr> { | /** Array iterator, usage: |
| public: | @code |
| char *malloc(size_t size) { | // Array<T> a; |
| CharPtr result=CharPtr((char *)Array<CharPtr>::malloc(size)); | for(Array_iterator<T> i(a); i.has_next(); ) { |
| *this += result; | T& element=i.next(); |
| return result.get(); | ... |
| } | } |
| @endcode | |
| 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 { | template<typename T> class Array_iterator { |
| Array<T>& farray; | const Array<T>& farray; |
| T *fcurrent; | T *fcurrent; |
| T *flast; | T *flast; |
| public: | public: |
| Array_iterator(Array<T>& aarray): farray(aarray) { | Array_iterator(const Array<T>& aarray): farray(aarray) { |
| fcurrent=farray.felements; | fcurrent=farray.felements; |
| flast=farray.felements+farray.count(); | flast=farray.felements+farray.count(); |
| } | } |
| Line 198 public: | Line 276 public: |
| return fcurrent<flast; | return fcurrent<flast; |
| } | } |
| /// quickly extracts next Array element | /// returns the current element and advances the iterator |
| T& next() { | T next() { |
| return *(fcurrent++); | return *(fcurrent++); |
| } | } |
| }; | /// returns the current element |
| T value() { | |
| return *(fcurrent); | |
| } | |
| // returns the current index of the iterator | |
| size_t index() { | |
| return fcurrent - farray.felements; | |
| } | |
| }; | |
| #endif | #endif |