Annotation of parser3/src/include/pa_array.h, revision 1.96
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.96 ! moko 11: #define IDENT_PA_ARRAY_H "$Id: pa_array.h,v 1.95 2024/09/21 23:51:04 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
1.94 moko 43: size_t fsize;
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(
1.95 moko 56: size_t aoffset=0,
57: size_t alimit=ARRAY_OPTION_LIMIT_ALL,
58: bool areverse=false):
1.59 paf 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
1.95 moko 74: if(limit>m)
1.59 paf 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.94 moko 85: fsize(0)
1.59 paf 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.94 moko 98: inline size_t count() const { return fsize; }
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.93 moko 103: expand();
1.7 paf 104:
1.94 moko 105: felements[fsize++]=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.95 moko 113: size_t limit=ARRAY_OPTION_LIMIT_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
1.95 moko 122: if(limit>m)
1.59 paf 123: limit=m;
124:
1.94 moko 125: fit(fsize-1+limit);
1.59 paf 126:
127: T* from=&src.felements[offset];
1.94 moko 128: T* to=&felements[fsize];
1.93 moko 129: for(T* from_end=from+limit; from<from_end;)
130: *to++=*from++;
1.94 moko 131: fsize+=limit;
1.59 paf 132: return *this;
133: }
134:
135: /// get index-element
1.71 misha 136: inline T get(size_t index) const {
1.63 paf 137: assert(index<count());
1.59 paf 138: return felements[index];
139: }
140:
141: /// ref version of get
1.71 misha 142: inline T& get_ref(size_t index) const {
1.63 paf 143: assert(index<count());
1.59 paf 144: return felements[index];
145: }
146:
147: /// put index-element
1.71 misha 148: inline void put(size_t index, T element) {
1.63 paf 149: assert(index<count());
1.59 paf 150: felements[index]=element;
151: }
152:
1.82 moko 153: /// insert index-element
154: inline void insert(size_t index, T element) {
155: assert(index<=count());
156:
157: if(is_full())
1.93 moko 158: expand();
1.82 moko 159:
1.94 moko 160: memmove(felements+index+1, felements+index, (fsize-index) * sizeof(T));
1.82 moko 161:
162: felements[index]=element;
1.94 moko 163: fsize++;
1.82 moko 164: }
165:
1.80 moko 166: /// remove index-element
167: inline void remove(size_t index) {
168: assert(index<count());
1.94 moko 169: if (index<--fsize)
170: memmove(felements+index, felements+index+1, (fsize-index) * sizeof(T));
1.80 moko 171: }
172:
1.71 misha 173: inline T operator [](size_t index) const { return get(index); }
1.29 paf 174:
1.84 moko 175: inline void clear() {
1.94 moko 176: if(fsize)
177: memset(felements, 0, fsize * sizeof(T));
178: fsize=0;
1.84 moko 179: }
180:
1.29 paf 181: /// iterate over all elements
1.59 paf 182: template<typename I> void for_each(void (*callback)(T, I), I info) const {
1.94 moko 183: T *last=felements+fsize;
1.60 paf 184: for(T *current=felements; current<last; current++)
185: callback(*current, info);
186: }
187:
188: /// iterate over all elements
1.68 paf 189: template<typename I> void for_each(bool (*callback)(T, I), I info) const {
1.94 moko 190: T *last=felements+fsize;
1.68 paf 191: for(T *current=felements; current<last; current++)
192: if(callback(*current, info))
193: return;
194: }
195:
196: /// iterate over all elements
1.60 paf 197: template<typename I> void for_each_ref(void (*callback)(T&, I), I info) {
1.94 moko 198: T *last=felements+fsize;
1.59 paf 199: for(T *current=felements; current<last; current++)
200: callback(*current, info);
201: }
1.49 paf 202:
1.59 paf 203: /// iterate over all elements until condition becomes true, return that element
204: template<typename I> T first_that(bool (*callback)(T, I), I info) const {
1.94 moko 205: T *last=felements+fsize;
1.59 paf 206: for(T *current=felements; current<last; current++)
207: if(callback(*current, info))
208: return *current;
1.1 paf 209:
1.59 paf 210: return T(0);
211: }
1.1 paf 212:
1.76 misha 213: inline T* ptr(size_t index){
214: return felements + index;
215: }
216:
1.59 paf 217: protected:
1.1 paf 218:
1.94 moko 219: inline bool is_full() {
220: return fsize == fallocated;
1.59 paf 221: }
1.88 moko 222:
1.93 moko 223: inline void expand() {
1.96 ! moko 224: resize(fallocated>0 ? fallocated+fallocated/2+2 : 3); // 3 is PAF default, confirmed by tests
1.93 moko 225: }
226:
1.94 moko 227: inline void fit(size_t index){
228: if(index >= fallocated)
229: resize(max(this->fallocated + this->fallocated/4, index+1));
230: }
231:
1.93 moko 232: void resize(size_t asize) {
1.71 misha 233: if(fallocated){
1.93 moko 234: felements=(T *)pa_realloc(felements, asize*sizeof(T));
235: fallocated=asize;
1.71 misha 236: } else {
1.93 moko 237: fallocated=asize;
238: felements=(T *)pa_malloc(asize*sizeof(T));
1.71 misha 239: }
1.1 paf 240: }
1.2 paf 241:
1.1 paf 242: private: //disabled
243:
1.59 paf 244: Array(const Array&) {}
1.12 paf 245: Array& operator = (const Array&) { return *this; }
1.42 parser 246: };
247:
1.92 moko 248:
1.91 moko 249: /// Commonly used, templated to work with any integer type
250:
251: template<typename T> char* pa_itoa(T n, T base=10){
252: char buf[MAX_NUMBER + 1];
253: char* pos=buf + MAX_NUMBER;
254: *pos='\0';
255:
256: bool negative=n < 0;
257: if (n < 0){
258: n=-n;
259: }
260:
261: do {
262: *(--pos)=(n % base) + '0';
263: n/=base;
264: } while (n > 0);
265:
266: if (negative) {
267: *(--pos) = '-';
268: }
269: return pa_strdup(pos, buf + MAX_NUMBER - pos);
270: }
271:
272: template<typename T> char* pa_uitoa(T n, T base=10){
273: char buf[MAX_NUMBER + 1];
274: char* pos=buf + MAX_NUMBER;
275: *pos='\0';
276:
277: do {
278: *(--pos)=(n % base) + '0';
279: n/=base;
280: } while (n > 0);
281:
282: return pa_strdup(pos, buf + MAX_NUMBER - pos);
283: }
284:
1.42 parser 285:
1.59 paf 286: /** Array iterator, usage:
287: @code
288: // Array<T> a;
1.89 moko 289: for(Array_iterator<T> i(a); i; ) {
1.59 paf 290: T& element=i.next();
291: ...
292: }
293: @endcode
294: */
295: template<typename T> class Array_iterator {
296:
297: const Array<T>& farray;
298: T *fcurrent;
299: T *flast;
300:
1.42 parser 301: public:
302:
1.59 paf 303: Array_iterator(const Array<T>& aarray): farray(aarray) {
304: fcurrent=farray.felements;
1.94 moko 305: flast=farray.felements + farray.fsize;
1.42 parser 306: }
307:
308: /// there are still elements
1.90 moko 309: inline operator bool () {
310: return fcurrent < flast;
1.42 parser 311: }
312:
1.88 moko 313: /// returns the current element and advances the iterator
1.90 moko 314: inline T next() {
1.59 paf 315: return *(fcurrent++);
316: }
317:
1.88 moko 318: /// returns the current element
1.90 moko 319: inline T value() {
1.88 moko 320: return *(fcurrent);
321: }
322:
323: // returns the current index of the iterator
1.90 moko 324: inline size_t index() {
1.88 moko 325: return fcurrent - farray.felements;
326: }
327:
1.90 moko 328: inline char *key(){
1.91 moko 329: return pa_uitoa(index());
1.90 moko 330: }
331:
332: };
333:
334: template<typename T> class Array_reverse_iterator {
335:
336: const Array<T>& farray;
337: T *fcurrent;
338:
339: public:
340:
341: Array_reverse_iterator(const Array<T>& aarray): farray(aarray) {
1.94 moko 342: fcurrent=farray.felements + farray.fsize;
1.90 moko 343: }
344:
345: /// there are still elements
346: inline operator bool () {
347: return fcurrent > farray.felements;
348: }
349:
350: /// returns the current element and advances the iterator
351: inline T prev() {
352: return *(--fcurrent);
353: }
354:
355: // returns the current index of the iterator
356: inline size_t index() {
357: return fcurrent - farray.felements;
358: }
359:
360: inline char *key(){
1.91 moko 361: return pa_uitoa(index());
1.90 moko 362: }
363:
1.59 paf 364: };
1.1 paf 365: #endif
E-mail: