Annotation of parser3/src/include/pa_array.h, revision 1.89

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.89    ! moko       11: #define IDENT_PA_ARRAY_H "$Id: pa_array.h,v 1.88 2024/09/07 15:01:38 moko Exp $"
1.24      paf        12: 
1.59      paf        13: // includes
                     14: 
                     15: #include "pa_memory.h"
                     16: #include "pa_exception.h"
                     17: 
                     18: // forwards
                     19: 
                     20: template<typename T> class Array_iterator;
                     21: 
                     22: // defines
                     23: 
                     24: #define ARRAY_OPTION_LIMIT_ALL ((size_t)-1)
                     25: 
                     26: /// Simple Array
                     27: template<typename T> class Array: public PA_Object {
                     28: 
                     29:        friend class Array_iterator<T>;
                     30: 
                     31: protected:
                     32: 
                     33:        /// elements[growing size] here
                     34:        T *felements;
                     35: 
                     36:        // allocated size
                     37:        size_t fallocated;
                     38: 
                     39:        // array size
                     40:        size_t fused;
1.1       paf        41: 
                     42: public:
1.88      moko       43:        typedef Array_iterator<T> Iterator;
                     44: 
1.59      paf        45:        struct Action_options {
                     46:                size_t offset;
                     47:                size_t limit; //< ARRAY_OPTION_LIMIT_ALL means 'all'. zero limit means 'nothing'
                     48:                bool reverse;
                     49:                bool defined;
                     50:                
                     51:                Action_options(
                     52:                        size_t aoffset=0, 
                     53:                        size_t alimit=ARRAY_OPTION_LIMIT_ALL, 
                     54:                        bool areverse=false): 
                     55:                        offset(aoffset), limit(alimit), reverse(areverse), 
                     56:                        defined(false) {}
                     57: 
                     58:                bool adjust(size_t count) {
                     59:                        if(!count || !limit)
                     60:                                return false;
1.70      misha      61:                        if(offset>=count)
1.59      paf        62:                                return false;
                     63:                        // max(limit)
                     64:                        size_t m=reverse?
1.69      misha      65:                                offset+1
1.59      paf        66:                                :count-offset;
                     67:                        if(!m)
                     68:                                return false;
                     69:                        // fix limit
                     70:                        if(limit==ARRAY_OPTION_LIMIT_ALL || limit>m)
                     71:                                limit=m;
1.7       paf        72: 
1.59      paf        73:                        return true;
                     74:                }
1.29      paf        75: 
1.59      paf        76:                
1.1       paf        77:        };
                     78: 
1.59      paf        79:        typedef T element_type;
                     80: 
1.71      misha      81:        inline Array(size_t initial=0):
                     82:                fallocated(initial),
1.59      paf        83:                fused(0)
                     84:        {
1.77      misha      85:                felements=fallocated?(T *)pa_malloc(fallocated*sizeof(T)):0;
1.59      paf        86:        }
1.6       paf        87: 
1.74      misha      88: #ifdef USE_DESTRUCTORS 
1.73      misha      89:        inline ~Array(){
1.75      misha      90:                if(felements)
1.77      misha      91:                        pa_free(felements);
1.72      misha      92:        }
1.74      misha      93: #endif
1.72      misha      94: 
1.59      paf        95:        /// how many items are in Array
1.71      misha      96:        inline size_t count() const { return fused; }
1.59      paf        97:        /// append to array
1.71      misha      98:        inline Array& operator+=(T src) {
1.59      paf        99:                if(is_full())
1.79      misha     100:                        expand(fallocated>0? 2+fallocated/32 : 3); // 3 is PAF default, confirmed by tests
1.7       paf       101: 
1.59      paf       102:                felements[fused++]=src;
1.24      paf       103: 
1.59      paf       104:                return *this;
                    105:        }
1.24      paf       106: 
                    107:        /// append other Array portion to this one. starting from offset
1.59      paf       108:        Array& append(const Array& src, 
                    109:                size_t offset=0, 
1.82      moko      110:                size_t limit=ARRAY_OPTION_LIMIT_ALL) { //< negative limit means 'all'. zero limit means 'nothing'
1.59      paf       111: 
                    112:                size_t src_count=src.count();
                    113:                // skip tivials
                    114:                if(!src_count || !limit || offset>=src_count)
                    115:                        return *this;
                    116:                // max(limit)
1.82      moko      117:                size_t m=src_count-offset;
1.59      paf       118:                // fix limit
                    119:                if(limit==ARRAY_OPTION_LIMIT_ALL || limit>m)
                    120:                        limit=m;
                    121: 
1.82      moko      122:                ssize_t delta=limit-(fallocated-fused);
1.59      paf       123:                if(delta>0)
                    124:                        expand(delta);
                    125: 
                    126:                T* from=&src.felements[offset];
                    127:                T* to=&felements[fused];
1.82      moko      128:                for(T* from_end=from+limit; from<from_end; from++)
                    129:                        *to++=*from;
1.59      paf       130:                fused+=limit;
                    131:                return *this;
                    132:        }
                    133: 
                    134:        /// get index-element
1.71      misha     135:        inline T get(size_t index) const {
1.63      paf       136:                assert(index<count());
1.59      paf       137:                return felements[index];
                    138:        }
                    139: 
                    140:        /// ref version of get
1.71      misha     141:        inline T& get_ref(size_t index) const {
1.63      paf       142:                assert(index<count());
1.59      paf       143:                return felements[index];
                    144:        }
                    145: 
                    146:        /// put index-element
1.71      misha     147:        inline void put(size_t index, T element) {
1.63      paf       148:                assert(index<count());
1.59      paf       149:                felements[index]=element;
                    150:        }
                    151: 
1.82      moko      152:        /// insert index-element
                    153:        inline void insert(size_t index, T element) {
                    154:                assert(index<=count());
                    155: 
                    156:                if(is_full())
                    157:                        expand(fallocated>0? 2+fallocated/32 : 3); // 3 is PAF default, confirmed by tests
                    158: 
                    159:                memmove(felements+index+1, felements+index, (fused-index) * sizeof(T));
                    160: 
                    161:                felements[index]=element;
                    162:                fused++;
                    163:        }
                    164: 
1.80      moko      165:        /// remove index-element
                    166:        inline void remove(size_t index) {
                    167:                assert(index<count());
                    168:                if (index<--fused)
1.82      moko      169:                        memmove(felements+index, felements+index+1, (fused-index) * sizeof(T));
1.80      moko      170:        }
                    171: 
1.71      misha     172:        inline T operator [](size_t index) const { return get(index); }
1.29      paf       173: 
1.84      moko      174:        inline void clear() {
                    175:                fused=0;
                    176:        }
                    177: 
1.29      paf       178:        /// iterate over all elements
1.59      paf       179:        template<typename I> void for_each(void (*callback)(T, I), I info) const {
1.60      paf       180:                T *last=felements+fused;
                    181:                for(T *current=felements; current<last; current++)
                    182:                        callback(*current, info);
                    183:        }
                    184: 
                    185:        /// iterate over all elements
1.68      paf       186:        template<typename I> void for_each(bool (*callback)(T, I), I info) const {
                    187:                T *last=felements+fused;
                    188:                for(T *current=felements; current<last; current++)
                    189:                        if(callback(*current, info))
                    190:                                return;
                    191:        }
                    192: 
                    193:        /// iterate over all elements
1.60      paf       194:        template<typename I> void for_each_ref(void (*callback)(T&, I), I info) {
1.59      paf       195:                T *last=felements+fused;
                    196:                for(T *current=felements; current<last; current++)
                    197:                        callback(*current, info);
                    198:        }
1.49      paf       199: 
1.59      paf       200:        /// iterate over all elements until condition becomes true, return that element
                    201:        template<typename I> T first_that(bool (*callback)(T, I), I info) const {
                    202:                T *last=felements+fused;
                    203:                for(T *current=felements; current<last; current++)
                    204:                        if(callback(*current, info))
                    205:                                return *current;
1.1       paf       206: 
1.59      paf       207:                return T(0);
                    208:        }
1.1       paf       209: 
1.76      misha     210:        inline T* ptr(size_t index){
                    211:                return felements + index;
                    212:        }
                    213: 
1.88      moko      214:        void fit(size_t index, T element){
                    215:                if(index >= fallocated){
                    216:                        size_t new_allocated=fallocated>0 ? fallocated : 3;
                    217:                        while(new_allocated <= index){
                    218:                                new_allocated+=2 + new_allocated/32;
                    219:                        }
                    220:                        expand(new_allocated - fallocated);
                    221:                }
                    222:                felements[index]=element;
                    223:                if(index >= fused){
                    224:                        fused=index+1;
                    225:                }
                    226:        }
                    227: 
1.59      paf       228: protected:
1.1       paf       229: 
1.59      paf       230:        bool is_full() {
                    231:                return fused == fallocated;
                    232:        }
1.88      moko      233: 
1.59      paf       234:        void expand(size_t delta) {
1.71      misha     235:                if(fallocated){
                    236:                        size_t new_allocated=fallocated+delta;
1.77      misha     237:                        felements=(T *)pa_realloc(felements, new_allocated*sizeof(T));
1.71      misha     238:                        fallocated=new_allocated;
                    239:                } else {
                    240:                        fallocated=delta;
1.77      misha     241:                        felements=(T *)pa_malloc(fallocated*sizeof(T));
1.71      misha     242:                }
1.1       paf       243:        }
1.2       paf       244: 
1.1       paf       245: private: //disabled
                    246: 
1.59      paf       247:        Array(const Array&) {}
1.12      paf       248:        Array& operator = (const Array&) { return *this; }
1.42      parser    249: };
                    250: 
                    251: 
1.59      paf       252: /** Array iterator, usage:
                    253:        @code
                    254:        // Array<T> a;
1.89    ! moko      255:        for(Array_iterator<T> i(a); i; ) {
1.59      paf       256:                T& element=i.next();
                    257:                ...
                    258:        }       
                    259:        @endcode
                    260: */
                    261: template<typename T> class Array_iterator {
                    262: 
                    263:        const Array<T>& farray;
                    264:        T *fcurrent;
                    265:        T *flast;
                    266: 
1.42      parser    267: public:
                    268: 
1.59      paf       269:        Array_iterator(const Array<T>& aarray): farray(aarray) {
                    270:                fcurrent=farray.felements;
                    271:                flast=farray.felements+farray.count();
1.42      parser    272:        }
                    273: 
                    274:        /// there are still elements
1.89    ! moko      275:        operator bool () {
1.59      paf       276:                return fcurrent<flast;
1.42      parser    277:        }
                    278: 
1.88      moko      279:        /// returns the current element and advances the iterator
1.68      paf       280:        T next() {
1.59      paf       281:                return *(fcurrent++);
                    282:        }
                    283: 
1.88      moko      284:        /// returns the current element
                    285:        T value() {
                    286:                return *(fcurrent);
                    287:        }
                    288: 
                    289:        // returns the current index of the iterator
                    290:        size_t index() {
                    291:                return fcurrent - farray.felements;
                    292:        }
                    293: 
1.59      paf       294: };
1.1       paf       295: #endif

E-mail: