|
|
| version 1.82, 2015/07/28 14:41:32 | version 1.106, 2026/01/06 13:07:58 |
|---|---|
| Line 1 | Line 1 |
| /** @file | /** @file |
| Parser: Array & Array_iterator classes decls. | Parser: Array & Array_iterator classes decls. |
| Copyright (c) 2001-2012 Art. Lebedev Studio (http://www.artlebedev.com) | Copyright (c) 2001-2024 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 |
| Line 13 | Line 13 |
| // includes | // includes |
| #include "pa_memory.h" | #include "pa_memory.h" |
| #include "pa_types.h" | |
| #include "pa_int.h" | |
| #include "pa_exception.h" | #include "pa_exception.h" |
| // forwards | // forwards |
| template<typename T> class Array_iterator; | template<typename T> class Array_iterator; |
| template<typename T> class Array_robust_iterator; | |
| template<typename T> class Array_reverse_iterator; | |
| // defines | // defines |
| Line 27 template<typename T> class Array_iterato | Line 31 template<typename T> class Array_iterato |
| 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>; |
| friend class Array_robust_iterator<T>; | |
| friend class Array_reverse_iterator<T>; | |
| protected: | protected: |
| Line 37 protected: | Line 43 protected: |
| size_t fallocated; | size_t fallocated; |
| // array size | // array size |
| size_t fused; | size_t fsize; |
| public: | public: |
| typedef Array_iterator<T> Iterator; | |
| typedef Array_robust_iterator<T> RobustIterator; | |
| typedef Array_reverse_iterator<T> ReverseIterator; | |
| struct Action_options { | struct Action_options { |
| size_t offset; | size_t offset; |
| size_t limit; //< ARRAY_OPTION_LIMIT_ALL means 'all'. zero limit means 'nothing' | size_t limit; //< ARRAY_OPTION_LIMIT_ALL means 'all'. zero limit means 'nothing' |
| Line 47 public: | Line 57 public: |
| bool defined; | bool defined; |
| Action_options( | Action_options( |
| size_t aoffset=0, | size_t aoffset=0, |
| size_t alimit=ARRAY_OPTION_LIMIT_ALL, | size_t alimit=ARRAY_OPTION_LIMIT_ALL, |
| bool areverse=false): | bool areverse=false): |
| offset(aoffset), limit(alimit), reverse(areverse), | offset(aoffset), limit(alimit), reverse(areverse), |
| defined(false) {} | defined(false) {} |
| Line 65 public: | Line 75 public: |
| if(!m) | if(!m) |
| return false; | return false; |
| // fix limit | // fix limit |
| if(limit==ARRAY_OPTION_LIMIT_ALL || limit>m) | if(limit>m) |
| limit=m; | limit=m; |
| return true; | return true; |
| } | } |
| }; | }; |
| typedef T element_type; | typedef T element_type; |
| inline Array(size_t initial=0): | inline Array(size_t initial=0): |
| fallocated(initial), | fallocated(initial), |
| fused(0) | fsize(0) |
| { | { |
| felements=fallocated?(T *)pa_malloc(fallocated*sizeof(T)):0; | felements=fallocated?(T *)pa_malloc(fallocated*sizeof(T)):0; |
| } | } |
| #ifdef USE_DESTRUCTORS | #ifdef USE_DESTRUCTORS |
| inline ~Array(){ | inline ~Array(){ |
| if(felements) | if(felements) |
| pa_free(felements); | pa_free(felements); |
| Line 91 public: | Line 99 public: |
| #endif | #endif |
| /// how many items are in Array | /// how many items are in Array |
| inline size_t count() const { return fused; } | inline size_t count() const { return fsize; } |
| /// append to array | /// append to array |
| inline Array& operator+=(T src) { | inline Array& operator+=(T src) { |
| if(is_full()) | if(is_full()) |
| expand(fallocated>0? 2+fallocated/32 : 3); // 3 is PAF default, confirmed by tests | expand(); |
| felements[fused++]=src; | felements[fsize++]=src; |
| return *this; | return *this; |
| } | } |
| /// 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, | void append(const Array& src, size_t offset=0, size_t limit=ARRAY_OPTION_LIMIT_ALL) { //< zero limit means 'nothing' |
| size_t offset=0, | |
| size_t limit=ARRAY_OPTION_LIMIT_ALL) { //< negative limit means 'all'. zero limit means 'nothing' | |
| size_t src_count=src.count(); | size_t src_count=src.count(); |
| // skip tivials | // skip tivials |
| if(!src_count || !limit || offset>=src_count) | if(!src_count || !limit || offset>=src_count) |
| return *this; | return; |
| // max(limit) | // max(limit) |
| size_t m=src_count-offset; | size_t m=src_count-offset; |
| // fix limit | // fix limit |
| if(limit==ARRAY_OPTION_LIMIT_ALL || limit>m) | if(limit>m) |
| limit=m; | limit=m; |
| ssize_t delta=limit-(fallocated-fused); | fit(fsize-1+limit); |
| if(delta>0) | memcpy(felements+fsize, src.felements+offset, limit * sizeof(T)); |
| expand(delta); | fsize+=limit; |
| 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; | |
| } | } |
| /// get index-element | /// get index-element |
| Line 152 public: | Line 151 public: |
| assert(index<=count()); | assert(index<=count()); |
| if(is_full()) | if(is_full()) |
| expand(fallocated>0? 2+fallocated/32 : 3); // 3 is PAF default, confirmed by tests | expand(); |
| memmove(felements+index+1, felements+index, (fused-index) * sizeof(T)); | memmove(felements+index+1, felements+index, (fsize-index) * sizeof(T)); |
| felements[index]=element; | felements[index]=element; |
| fused++; | fsize++; |
| } | } |
| /// remove index-element | /// remove index-element |
| inline void remove(size_t index) { | inline void remove(size_t index) { |
| assert(index<count()); | assert(index<count()); |
| if (index<--fused) | if (index<--fsize) |
| memmove(felements+index, felements+index+1, (fused-index) * sizeof(T)); | memmove(felements+index, felements+index+1, (fsize-index) * sizeof(T)); |
| } | } |
| inline T operator [](size_t index) const { return get(index); } | inline T operator [](size_t index) const { return get(index); } |
| inline void clear() { | |
| if(fsize) | |
| memset((void *)felements, 0, fsize * sizeof(T)); | |
| fsize=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 { |
| T *last=felements+fused; | T *last=felements+fsize; |
| for(T *current=felements; current<last; current++) | for(T *current=felements; current<last; current++) |
| callback(*current, info); | callback(*current, info); |
| } | } |
| /// iterate over all elements | /// iterate over all elements |
| template<typename I> void for_each(bool (*callback)(T, I), I info) const { | template<typename I> void for_each(bool (*callback)(T, I), I info) const { |
| T *last=felements+fused; | T *last=felements+fsize; |
| for(T *current=felements; current<last; current++) | for(T *current=felements; current<last; current++) |
| if(callback(*current, info)) | if(callback(*current, info)) |
| return; | return; |
| Line 186 public: | Line 191 public: |
| /// iterate over all elements | /// iterate over all elements |
| template<typename I> void for_each_ref(void (*callback)(T&, I), I info) { | template<typename I> void for_each_ref(void (*callback)(T&, I), I info) { |
| T *last=felements+fused; | T *last=felements+fsize; |
| for(T *current=felements; current<last; current++) | for(T *current=felements; current<last; current++) |
| callback(*current, info); | 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+fsize; |
| for(T *current=felements; current<last; current++) | for(T *current=felements; current<last; current++) |
| if(callback(*current, info)) | if(callback(*current, info)) |
| return *current; | return *current; |
| Line 207 public: | Line 212 public: |
| protected: | protected: |
| bool is_full() { | inline bool is_full() { |
| return fused == fallocated; | return fsize == fallocated; |
| } | |
| inline void expand() { | |
| resize(fallocated>0 ? fallocated+fallocated/2+2 : 3); // 3 is PAF default, confirmed by tests | |
| } | |
| inline void fit(size_t index){ | |
| if(index >= fallocated) | |
| resize(max(fallocated+fallocated/4, index+1)); | |
| } | } |
| void expand(size_t delta) { | |
| void resize(size_t asize) { | |
| if(fallocated){ | if(fallocated){ |
| size_t new_allocated=fallocated+delta; | felements=(T *)pa_realloc(felements, asize*sizeof(T)); |
| felements=(T *)pa_realloc(felements, new_allocated*sizeof(T)); | #ifdef PA_DEBUG_DISABLE_GC |
| fallocated=new_allocated; | // non-gc realloc doesn't zero; manually zero expanded region |
| if(asize > fallocated) | |
| memset((void *)(felements+fallocated), 0, (asize-fallocated) * sizeof(T)); | |
| #endif | |
| fallocated=asize; | |
| } else { | } else { |
| fallocated=delta; | fallocated=asize; |
| felements=(T *)pa_malloc(fallocated*sizeof(T)); | felements=(T *)pa_malloc(asize*sizeof(T)); |
| } | } |
| } | } |
| Line 231 private: //disabled | Line 250 private: //disabled |
| /** Array iterator, usage: | /** Array iterator, usage: |
| @code | @code |
| // Array<T> a; | // Array<T> a; |
| for(Array_iterator<T> i(a); i.has_next(); ) { | for(Array_iterator<T> i(a); i; ) { |
| T& element=i.next(); | T& element=i.next(); |
| ... | ... |
| } | } |
| Line 244 template<typename T> class Array_iterato | Line 263 template<typename T> class Array_iterato |
| T *flast; | T *flast; |
| public: | public: |
| Array_iterator(const 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.fsize; |
| } | } |
| /// there are still elements | /// there are still elements |
| bool has_next() { | inline operator bool () { |
| return fcurrent<flast; | return fcurrent < flast; |
| } | } |
| /// quickly extracts next Array element | /// returns the current element and advances the iterator |
| T next() { | inline T next() { |
| return *(fcurrent++); | return *(fcurrent++); |
| } | } |
| /// returns the current element | |
| inline T value() { | |
| return *(fcurrent); | |
| } | |
| // returns the current index of the iterator | |
| inline size_t index() { | |
| return fcurrent - farray.felements; | |
| } | |
| }; | |
| // Slower array iterator for arrays that can be modified during iteration | |
| template<typename T> class Array_robust_iterator { | |
| const Array<T>& farray; | |
| size_t findex; | |
| public: | |
| Array_robust_iterator(const Array<T>& aarray) : farray(aarray), findex(0) {} | |
| inline operator bool() { | |
| return findex < farray.fsize; | |
| } | |
| inline void next() { | |
| findex++; | |
| } | |
| inline T value() { | |
| return farray.felements[findex]; | |
| } | |
| inline size_t index() { | |
| return findex; | |
| } | |
| }; | |
| // Robust as used for arrays that can be modified during iteration | |
| template<typename T> class Array_reverse_iterator { | |
| const Array<T>& farray; | |
| size_t findex; | |
| public: | |
| Array_reverse_iterator(const Array<T>& aarray): farray(aarray), findex(aarray.fsize) {} | |
| inline operator bool () { | |
| return (findex > 0) && (findex <= farray.fsize); | |
| } | |
| inline T prev() { | |
| return farray.felements[--findex]; | |
| } | |
| inline size_t index() { | |
| return findex; | |
| } | |
| }; | }; |
| #endif | #endif |