Annotation of parser3/src/include/pa_array.h, revision 1.92
1.24 paf 1: /** @file
1.59 paf 2: Parser: Array & Array_iterator classes decls.
1.26 paf 3:
1.87 moko 4: Copyright (c) 2001-2023 Art. Lebedev Studio (http://www.artlebedev.com)
5: Authors: Konstantin Morshnev <moko@design.ru>, Alexandr Petrosian <paf@design.ru>
1.1 paf 6: */
7:
1.24 paf 8: #ifndef PA_ARRAY_H
9: #define PA_ARRAY_H
1.54 paf 10:
1.92 ! moko 11: #define IDENT_PA_ARRAY_H "$Id: pa_array.h,v 1.91 2024/09/11 21:07:36 moko Exp $"
1.24 paf 12:
1.59 paf 13: // includes
14:
15: #include "pa_memory.h"
1.90 moko 16: #include "pa_types.h"
1.59 paf 17: #include "pa_exception.h"
18:
19: // forwards
20:
21: template<typename T> class Array_iterator;
1.90 moko 22: template<typename T> class Array_reverse_iterator;
1.59 paf 23:
24: // defines
25:
26: #define ARRAY_OPTION_LIMIT_ALL ((size_t)-1)
27:
28: /// Simple Array
29: template<typename T> class Array: public PA_Object {
30:
31: friend class Array_iterator<T>;
1.90 moko 32: friend class Array_reverse_iterator<T>;
1.59 paf 33:
34: protected:
35:
36: /// elements[growing size] here
37: T *felements;
38:
39: // allocated size
40: size_t fallocated;
41:
42: // array size
43: size_t fused;
1.1 paf 44:
45: public:
1.88 moko 46: typedef Array_iterator<T> Iterator;
1.90 moko 47: typedef Array_reverse_iterator<T> ReverseIterator;
1.88 moko 48:
1.59 paf 49: struct Action_options {
50: size_t offset;
51: size_t limit; //< ARRAY_OPTION_LIMIT_ALL means 'all'. zero limit means 'nothing'
52: bool reverse;
53: bool defined;
54:
55: Action_options(
56: size_t aoffset=0,
57: size_t alimit=ARRAY_OPTION_LIMIT_ALL,
58: bool areverse=false):
59: offset(aoffset), limit(alimit), reverse(areverse),
60: defined(false) {}
61:
62: bool adjust(size_t count) {
63: if(!count || !limit)
64: return false;
1.70 misha 65: if(offset>=count)
1.59 paf 66: return false;
67: // max(limit)
68: size_t m=reverse?
1.69 misha 69: offset+1
1.59 paf 70: :count-offset;
71: if(!m)
72: return false;
73: // fix limit
74: if(limit==ARRAY_OPTION_LIMIT_ALL || limit>m)
75: limit=m;
1.7 paf 76:
1.59 paf 77: return true;
78: }
1.1 paf 79: };
80:
1.59 paf 81: typedef T element_type;
82:
1.71 misha 83: inline Array(size_t initial=0):
84: fallocated(initial),
1.59 paf 85: fused(0)
86: {
1.77 misha 87: felements=fallocated?(T *)pa_malloc(fallocated*sizeof(T)):0;
1.59 paf 88: }
1.6 paf 89:
1.92 ! moko 90: #ifdef USE_DESTRUCTORS
1.73 misha 91: inline ~Array(){
1.75 misha 92: if(felements)
1.77 misha 93: pa_free(felements);
1.72 misha 94: }
1.74 misha 95: #endif
1.72 misha 96:
1.59 paf 97: /// how many items are in Array
1.71 misha 98: inline size_t count() const { return fused; }
1.92 ! moko 99:
1.59 paf 100: /// append to array
1.71 misha 101: inline Array& operator+=(T src) {
1.59 paf 102: if(is_full())
1.79 misha 103: expand(fallocated>0? 2+fallocated/32 : 3); // 3 is PAF default, confirmed by tests
1.7 paf 104:
1.59 paf 105: felements[fused++]=src;
1.24 paf 106:
1.59 paf 107: return *this;
108: }
1.24 paf 109:
110: /// append other Array portion to this one. starting from offset
1.59 paf 111: Array& append(const Array& src,
112: size_t offset=0,
1.82 moko 113: size_t limit=ARRAY_OPTION_LIMIT_ALL) { //< negative limit means 'all'. zero limit means 'nothing'
1.59 paf 114:
115: size_t src_count=src.count();
116: // skip tivials
117: if(!src_count || !limit || offset>=src_count)
118: return *this;
119: // max(limit)
1.82 moko 120: size_t m=src_count-offset;
1.59 paf 121: // fix limit
122: if(limit==ARRAY_OPTION_LIMIT_ALL || limit>m)
123: limit=m;
124:
1.82 moko 125: ssize_t delta=limit-(fallocated-fused);
1.59 paf 126: if(delta>0)
127: expand(delta);
128:
129: T* from=&src.felements[offset];
130: T* to=&felements[fused];
1.82 moko 131: for(T* from_end=from+limit; from<from_end; from++)
132: *to++=*from;
1.59 paf 133: fused+=limit;
134: return *this;
135: }
136:
137: /// get index-element
1.71 misha 138: inline T get(size_t index) const {
1.63 paf 139: assert(index<count());
1.59 paf 140: return felements[index];
141: }
142:
143: /// ref version of get
1.71 misha 144: inline T& get_ref(size_t index) const {
1.63 paf 145: assert(index<count());
1.59 paf 146: return felements[index];
147: }
148:
149: /// put index-element
1.71 misha 150: inline void put(size_t index, T element) {
1.63 paf 151: assert(index<count());
1.59 paf 152: felements[index]=element;
153: }
154:
1.82 moko 155: /// insert index-element
156: inline void insert(size_t index, T element) {
157: assert(index<=count());
158:
159: if(is_full())
160: expand(fallocated>0? 2+fallocated/32 : 3); // 3 is PAF default, confirmed by tests
161:
162: memmove(felements+index+1, felements+index, (fused-index) * sizeof(T));
163:
164: felements[index]=element;
165: fused++;
166: }
167:
1.80 moko 168: /// remove index-element
169: inline void remove(size_t index) {
170: assert(index<count());
171: if (index<--fused)
1.82 moko 172: memmove(felements+index, felements+index+1, (fused-index) * sizeof(T));
1.80 moko 173: }
174:
1.71 misha 175: inline T operator [](size_t index) const { return get(index); }
1.29 paf 176:
1.84 moko 177: inline void clear() {
1.90 moko 178: if(fused)
179: memset(felements, 0, fused * sizeof(T));
1.84 moko 180: fused=0;
181: }
182:
1.29 paf 183: /// iterate over all elements
1.59 paf 184: template<typename I> void for_each(void (*callback)(T, I), I info) const {
1.60 paf 185: T *last=felements+fused;
186: for(T *current=felements; current<last; current++)
187: callback(*current, info);
188: }
189:
190: /// iterate over all elements
1.68 paf 191: template<typename I> void for_each(bool (*callback)(T, I), I info) const {
192: T *last=felements+fused;
193: for(T *current=felements; current<last; current++)
194: if(callback(*current, info))
195: return;
196: }
197:
198: /// iterate over all elements
1.60 paf 199: template<typename I> void for_each_ref(void (*callback)(T&, I), I info) {
1.59 paf 200: T *last=felements+fused;
201: for(T *current=felements; current<last; current++)
202: callback(*current, info);
203: }
1.49 paf 204:
1.59 paf 205: /// iterate over all elements until condition becomes true, return that element
206: template<typename I> T first_that(bool (*callback)(T, I), I info) const {
207: T *last=felements+fused;
208: for(T *current=felements; current<last; current++)
209: if(callback(*current, info))
210: return *current;
1.1 paf 211:
1.59 paf 212: return T(0);
213: }
1.1 paf 214:
1.76 misha 215: inline T* ptr(size_t index){
216: return felements + index;
217: }
218:
1.59 paf 219: protected:
1.1 paf 220:
1.59 paf 221: bool is_full() {
222: return fused == fallocated;
223: }
1.88 moko 224:
1.59 paf 225: void expand(size_t delta) {
1.71 misha 226: if(fallocated){
227: size_t new_allocated=fallocated+delta;
1.77 misha 228: felements=(T *)pa_realloc(felements, new_allocated*sizeof(T));
1.71 misha 229: fallocated=new_allocated;
230: } else {
231: fallocated=delta;
1.77 misha 232: felements=(T *)pa_malloc(fallocated*sizeof(T));
1.71 misha 233: }
1.1 paf 234: }
1.2 paf 235:
1.1 paf 236: private: //disabled
237:
1.59 paf 238: Array(const Array&) {}
1.12 paf 239: Array& operator = (const Array&) { return *this; }
1.42 parser 240: };
241:
1.92 ! moko 242:
1.91 moko 243: /// Commonly used, templated to work with any integer type
244:
245: template<typename T> char* pa_itoa(T n, T base=10){
246: char buf[MAX_NUMBER + 1];
247: char* pos=buf + MAX_NUMBER;
248: *pos='\0';
249:
250: bool negative=n < 0;
251: if (n < 0){
252: n=-n;
253: }
254:
255: do {
256: *(--pos)=(n % base) + '0';
257: n/=base;
258: } while (n > 0);
259:
260: if (negative) {
261: *(--pos) = '-';
262: }
263: return pa_strdup(pos, buf + MAX_NUMBER - pos);
264: }
265:
266: template<typename T> char* pa_uitoa(T n, T base=10){
267: char buf[MAX_NUMBER + 1];
268: char* pos=buf + MAX_NUMBER;
269: *pos='\0';
270:
271: do {
272: *(--pos)=(n % base) + '0';
273: n/=base;
274: } while (n > 0);
275:
276: return pa_strdup(pos, buf + MAX_NUMBER - pos);
277: }
278:
1.42 parser 279:
1.59 paf 280: /** Array iterator, usage:
281: @code
282: // Array<T> a;
1.89 moko 283: for(Array_iterator<T> i(a); i; ) {
1.59 paf 284: T& element=i.next();
285: ...
286: }
287: @endcode
288: */
289: template<typename T> class Array_iterator {
290:
291: const Array<T>& farray;
292: T *fcurrent;
293: T *flast;
294:
1.42 parser 295: public:
296:
1.59 paf 297: Array_iterator(const Array<T>& aarray): farray(aarray) {
298: fcurrent=farray.felements;
1.92 ! moko 299: flast=farray.felements + farray.fused;
1.42 parser 300: }
301:
302: /// there are still elements
1.90 moko 303: inline operator bool () {
304: return fcurrent < flast;
1.42 parser 305: }
306:
1.88 moko 307: /// returns the current element and advances the iterator
1.90 moko 308: inline T next() {
1.59 paf 309: return *(fcurrent++);
310: }
311:
1.88 moko 312: /// returns the current element
1.90 moko 313: inline T value() {
1.88 moko 314: return *(fcurrent);
315: }
316:
317: // returns the current index of the iterator
1.90 moko 318: inline size_t index() {
1.88 moko 319: return fcurrent - farray.felements;
320: }
321:
1.90 moko 322: inline char *key(){
1.91 moko 323: return pa_uitoa(index());
1.90 moko 324: }
325:
326: };
327:
328: template<typename T> class Array_reverse_iterator {
329:
330: const Array<T>& farray;
331: T *fcurrent;
332:
333: public:
334:
335: Array_reverse_iterator(const Array<T>& aarray): farray(aarray) {
1.92 ! moko 336: fcurrent=farray.felements + farray.fused;
1.90 moko 337: }
338:
339: /// there are still elements
340: inline operator bool () {
341: return fcurrent > farray.felements;
342: }
343:
344: /// returns the current element and advances the iterator
345: inline T prev() {
346: return *(--fcurrent);
347: }
348:
349: // returns the current index of the iterator
350: inline size_t index() {
351: return fcurrent - farray.felements;
352: }
353:
354: inline char *key(){
1.91 moko 355: return pa_uitoa(index());
1.90 moko 356: }
357:
1.59 paf 358: };
1.1 paf 359: #endif
E-mail: