Annotation of parser3/src/include/pa_array.h, revision 1.93
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.93 ! moko 11: #define IDENT_PA_ARRAY_H "$Id: pa_array.h,v 1.92 2024/09/14 22:58:50 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.93 ! moko 103: expand();
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.93 ! moko 125: size_t required=fused+limit;
! 126: if(required>fallocated)
! 127: resize(required);
1.59 paf 128:
129: T* from=&src.felements[offset];
130: T* to=&felements[fused];
1.93 ! moko 131: for(T* from_end=from+limit; from<from_end;)
! 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())
1.93 ! moko 160: expand();
1.82 moko 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.93 ! moko 225: inline void expand() {
! 226: resize(fallocated>0 ? fallocated+fallocated/4+2 : 3); // 3 is PAF default, confirmed by tests
! 227: }
! 228:
! 229: void resize(size_t asize) {
1.71 misha 230: if(fallocated){
1.93 ! moko 231: felements=(T *)pa_realloc(felements, asize*sizeof(T));
! 232: fallocated=asize;
1.71 misha 233: } else {
1.93 ! moko 234: fallocated=asize;
! 235: felements=(T *)pa_malloc(asize*sizeof(T));
1.71 misha 236: }
1.1 paf 237: }
1.2 paf 238:
1.1 paf 239: private: //disabled
240:
1.59 paf 241: Array(const Array&) {}
1.12 paf 242: Array& operator = (const Array&) { return *this; }
1.42 parser 243: };
244:
1.92 moko 245:
1.91 moko 246: /// Commonly used, templated to work with any integer type
247:
248: template<typename T> char* pa_itoa(T n, T base=10){
249: char buf[MAX_NUMBER + 1];
250: char* pos=buf + MAX_NUMBER;
251: *pos='\0';
252:
253: bool negative=n < 0;
254: if (n < 0){
255: n=-n;
256: }
257:
258: do {
259: *(--pos)=(n % base) + '0';
260: n/=base;
261: } while (n > 0);
262:
263: if (negative) {
264: *(--pos) = '-';
265: }
266: return pa_strdup(pos, buf + MAX_NUMBER - pos);
267: }
268:
269: template<typename T> char* pa_uitoa(T n, T base=10){
270: char buf[MAX_NUMBER + 1];
271: char* pos=buf + MAX_NUMBER;
272: *pos='\0';
273:
274: do {
275: *(--pos)=(n % base) + '0';
276: n/=base;
277: } while (n > 0);
278:
279: return pa_strdup(pos, buf + MAX_NUMBER - pos);
280: }
281:
1.42 parser 282:
1.59 paf 283: /** Array iterator, usage:
284: @code
285: // Array<T> a;
1.89 moko 286: for(Array_iterator<T> i(a); i; ) {
1.59 paf 287: T& element=i.next();
288: ...
289: }
290: @endcode
291: */
292: template<typename T> class Array_iterator {
293:
294: const Array<T>& farray;
295: T *fcurrent;
296: T *flast;
297:
1.42 parser 298: public:
299:
1.59 paf 300: Array_iterator(const Array<T>& aarray): farray(aarray) {
301: fcurrent=farray.felements;
1.92 moko 302: flast=farray.felements + farray.fused;
1.42 parser 303: }
304:
305: /// there are still elements
1.90 moko 306: inline operator bool () {
307: return fcurrent < flast;
1.42 parser 308: }
309:
1.88 moko 310: /// returns the current element and advances the iterator
1.90 moko 311: inline T next() {
1.59 paf 312: return *(fcurrent++);
313: }
314:
1.88 moko 315: /// returns the current element
1.90 moko 316: inline T value() {
1.88 moko 317: return *(fcurrent);
318: }
319:
320: // returns the current index of the iterator
1.90 moko 321: inline size_t index() {
1.88 moko 322: return fcurrent - farray.felements;
323: }
324:
1.90 moko 325: inline char *key(){
1.91 moko 326: return pa_uitoa(index());
1.90 moko 327: }
328:
329: };
330:
331: template<typename T> class Array_reverse_iterator {
332:
333: const Array<T>& farray;
334: T *fcurrent;
335:
336: public:
337:
338: Array_reverse_iterator(const Array<T>& aarray): farray(aarray) {
1.92 moko 339: fcurrent=farray.felements + farray.fused;
1.90 moko 340: }
341:
342: /// there are still elements
343: inline operator bool () {
344: return fcurrent > farray.felements;
345: }
346:
347: /// returns the current element and advances the iterator
348: inline T prev() {
349: return *(--fcurrent);
350: }
351:
352: // returns the current index of the iterator
353: inline size_t index() {
354: return fcurrent - farray.felements;
355: }
356:
357: inline char *key(){
1.91 moko 358: return pa_uitoa(index());
1.90 moko 359: }
360:
1.59 paf 361: };
1.1 paf 362: #endif
E-mail: