Diff for /parser3/src/include/pa_array.h between versions 1.41 and 1.93

version 1.41, 2001/05/17 10:22:24 version 1.93, 2024/09/15 00:38:27
Line 1 Line 1
 /** @file  /** @file
         Parser: array class decl.          Parser: Array & Array_iterator classes decls.
   
         Copyright (c) 2001 ArtLebedev Group (http://www.artlebedev.com)          Copyright (c) 2001-2023 Art. Lebedev Studio (http://www.artlebedev.com)
           Authors: Konstantin Morshnev <moko@design.ru>, Alexandr Petrosian <paf@design.ru>
         Author: Alexander Petrosyan <paf@design.ru> (http://design.ru/paf)  
   
         $Id$  
 */  */
   
 #ifndef PA_ARRAY_H  #ifndef PA_ARRAY_H
 #define PA_ARRAY_H  #define PA_ARRAY_H
   
 #include "pa_config_includes.h"  #define IDENT_PA_ARRAY_H "$Id$"
 #include "pa_pool.h"  
   // includes
   
   #include "pa_memory.h"
 #include "pa_types.h"  #include "pa_types.h"
 #include "pa_string.h"  #include "pa_exception.h"
   
 /**       // forwards
         Pooled Array.  
   
         Internal structure:  template<typename T> class Array_iterator;
         @verbatim  template<typename T> class Array_reverse_iterator;
                 Array               Chunk0  
                 ======              ========  
                 head--------------->[ptr]  
                 append_here-------->[ptr]  
                 link_row            ........  
                                 .                       .  
                                 .                       [ptr]  
                                 ...........>[link to the next chunk]  
         @endverbatim  
 */  
   
 class Array : public Pooled {  // defines
 public:  
   
         /// Array item type  #define ARRAY_OPTION_LIMIT_ALL ((size_t)-1)
         typedef void Item;  
   
         /*/// for_each iterator function type, const info  /// Simple Array
         typedef void (*For_each_func_const)(Item *value, const void *info);  template<typename T> class Array: public PA_Object {
         */  
   
         /// for_each iterator function type          friend class Array_iterator<T>;
         typedef void (*For_each_func)(Item *value, void *info);          friend class Array_reverse_iterator<T>;
   
         /// first_that iterator function type, const info  protected:
         typedef bool (*First_that_func_const)(Item *value, const void *info);  
   
         /// first_that iterator function type          /// elements[growing size] here
         typedef bool (*First_that_func)(Item *value, void *info);          T *felements;
   
         enum {          // allocated size
                 CR_INITIAL_ROWS_DEFAULT=3, ///< default preallocated row count          size_t fallocated;
                 CR_GROW_COUNT=3 ///< each time the Array chunk_is_full() array expanded()  
         };          // array size
           size_t fused;
   
 public:  public:
           typedef Array_iterator<T> Iterator;
           typedef Array_reverse_iterator<T> ReverseIterator;
   
           struct Action_options {
                   size_t offset;
                   size_t limit; //< ARRAY_OPTION_LIMIT_ALL means 'all'. zero limit means 'nothing'
                   bool reverse;
                   bool defined;
                   
                   Action_options(
                           size_t aoffset=0, 
                           size_t alimit=ARRAY_OPTION_LIMIT_ALL, 
                           bool areverse=false): 
                           offset(aoffset), limit(alimit), reverse(areverse), 
                           defined(false) {}
   
                   bool adjust(size_t count) {
                           if(!count || !limit)
                                   return false;
                           if(offset>=count)
                                   return false;
                           // max(limit)
                           size_t m=reverse?
                                   offset+1
                                   :count-offset;
                           if(!m)
                                   return false;
                           // fix limit
                           if(limit==ARRAY_OPTION_LIMIT_ALL || limit>m)
                                   limit=m;
   
         Array(Pool& apool, int initial_rows=CR_INITIAL_ROWS_DEFAULT);                          return true;
                   }
           };
   
           typedef T element_type;
   
         /**          inline Array(size_t initial=0):
                 size Array. how many items are in it.                   fallocated(initial),
                 must be used with quick_get like this:                  fused(0)
                 @code          {
                         int size=src.quick_size();                  felements=fallocated?(T *)pa_malloc(fallocated*sizeof(T)):0;
                         for(int i=0; i<size; i++) {          }
                                 z=src.quick_get(i);  
                         }  
                 @endcode  
         */  
         int quick_size() const {   
                 // for quick_get  
                 cache_chunk_base=0;  
                 cache_chunk=head;  
                 return size();   
         }  
         /// size Array. how many items are in it  
         int size() const { return fused_rows; }  
         /// append Item to array  
         Array& operator += (Item *src);  
         /// append int value to array  
         Array& operator += (int value) { return *this+=reinterpret_cast<Item *>(value); }  
   
         /// dirty hack to allow constant items storage. I long for Array<const Item*>  #ifdef USE_DESTRUCTORS
         Array& operator += (const Item *src) { return *this+=const_cast<Item *>(src); }          inline ~Array(){
                   if(felements)
                           pa_free(felements);
           }
   #endif
   
           /// how many items are in Array
           inline size_t count() const { return fused; }
   
           /// append to array
           inline Array& operator+=(T src) {
                   if(is_full())
                           expand();
   
                   felements[fused++]=src;
   
                   return *this;
           }
   
         /// append other Array portion to this one. starting from offset          /// append other Array portion to this one. starting from offset
         Array& append_array(const Array& src, int offset=0);          Array& append(const Array& src, 
                   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();
                   // skip tivials
                   if(!src_count || !limit || offset>=src_count)
                           return *this;
                   // max(limit)
                   size_t m=src_count-offset;
                   // fix limit
                   if(limit==ARRAY_OPTION_LIMIT_ALL || limit>m)
                           limit=m;
   
                   size_t required=fused+limit;
                   if(required>fallocated)
                           resize(required);
   
                   T* from=&src.felements[offset];
                   T* to=&felements[fused];
                   for(T* from_end=from+limit; from<from_end;)
                           *to++=*from++;
                   fused+=limit;
                   return *this;
           }
   
         /**           /// get index-element
                 quickly gets some item considering...          inline T get(size_t index) const {
                   assert(index<count());
                   return felements[index];
           }
   
                 these true:          /// ref version of get
                         - index increments from 0 to size()-1          inline T& get_ref(size_t index) const {
                         - index>=0 && index<size()                  assert(index<count());
                         - index>=cache_chunk_base                  return felements[index];
         */          }
         Item *quick_get(int index) const {  
                 // next chunk will be with "index" row          /// put index-element
                 if(!(index<cache_chunk_base+cache_chunk->count)) {          inline void put(size_t index, T element) {
                         int count=cache_chunk->count;                  assert(index<count());
                         cache_chunk_base+=count;                  felements[index]=element;
                         cache_chunk=cache_chunk->rows[count].link;  
                 }  
                   
                 return cache_chunk->rows[index-cache_chunk_base].item;  
         }          }
   
         Item *get(int index) const;          /// insert index-element
         int get_int(int index) const { return reinterpret_cast<int>(get(index)); }          inline void insert(size_t index, T element) {
                   assert(index<=count());
   
         void put(int index, Item *item);                  if(is_full())
         /// convinient way to get strings from Array. I long for Array<const String *>                          expand();
         const String *get_string(int index) const {   
                 return const_cast<const String *>(static_cast<String *>(get(index)));                   memmove(felements+index+1, felements+index, (fused-index) * sizeof(T));
   
                   felements[index]=element;
                   fused++;
         }          }
         const String *quick_get_string(int index) const {   
                 return const_cast<const String *>(static_cast<String *>(quick_get(index)));           /// remove index-element
           inline void remove(size_t index) {
                   assert(index<count());
                   if (index<--fused)
                           memmove(felements+index, felements+index+1, (fused-index) * sizeof(T));
           }
   
           inline T operator [](size_t index) const { return get(index); }
   
           inline void clear() {
                   if(fused)
                           memset(felements, 0, fused * sizeof(T));
                   fused=0;
         }          }
   
         /*/// iterate over all elements, const info          /// iterate over all elements
         void for_each(For_each_func_const func, const void *info=0) const;          template<typename I> void for_each(void (*callback)(T, I), I info) const {
         /*/                  T *last=felements+fused;
                   for(T *current=felements; current<last; current++)
                           callback(*current, info);
           }
   
         /// iterate over all elements          /// iterate over all elements
         void for_each(For_each_func func, void *info=0) const;          template<typename I> void for_each(bool (*callback)(T, I), I info) const {
                   T *last=felements+fused;
                   for(T *current=felements; current<last; current++)
                           if(callback(*current, info))
                                   return;
           }
   
         /// iterate over all elements until condition, const info          /// iterate over all elements
         void* first_that(First_that_func_const func, const void *info=0) const;          template<typename I> void for_each_ref(void (*callback)(T&, I), I info) {
                   T *last=felements+fused;
                   for(T *current=felements; current<last; current++)
                           callback(*current, info);
           }
   
         /// iterate over all elements until condition          /// iterate over all elements until condition becomes true, return that element
         void* first_that(First_that_func func, void *info=0) const;          template<typename I> T first_that(bool (*callback)(T, I), I info) const {
                   T *last=felements+fused;
                   for(T *current=felements; current<last; current++)
                           if(callback(*current, info))
                                   return *current;
   
 private:                  return T(0);
           }
         /// several record elements  
         struct Chunk {  
                 int count;  ///< the number of rows in chunk  
                 /// item or a link to next chunk union  
                 union Row {  
                         Item *item;  
                         Chunk *link;  ///< link to the next chunk in chain  
                 } rows[1];  
                 // next rows are here  
         }  
                 *head;  ///< the head chunk of the chunk chain  
   
         /** last allocated chunk  
                 helps appending Arrays  
         */  
         Chunk *tail;  
   
         /// next append would write to this record  
         Chunk::Row *append_here;  
           
         /**     the address of place where lies address   
                 of the link to the next chunk to allocate  
         */  
         Chunk::Row *link_row;  
   
 private:          inline T* ptr(size_t index){
                   return felements + index;
           }
   
         // array size  protected:
         int fused_rows;  
   
         mutable int cache_chunk_base;          bool is_full() {
         mutable Chunk *cache_chunk;                  return fused == fallocated;
                   }
 private:  
   
         bool chunk_is_full() {          inline void expand() {
                 return append_here == link_row;                  resize(fallocated>0 ? fallocated+fallocated/4+2 : 3); // 3 is PAF default, confirmed by tests
           }
   
           void resize(size_t asize) {
                   if(fallocated){
                           felements=(T *)pa_realloc(felements, asize*sizeof(T));
                           fallocated=asize;
                   } else {
                           fallocated=asize;
                           felements=(T *)pa_malloc(asize*sizeof(T));
                   }
         }          }
         void expand(int chunk_rows);  
   
 private: //disabled  private: //disabled
   
         //Array(Array&) { }          Array(const Array&) {}
         Array& operator = (const Array&) { return *this; }          Array& operator = (const Array&) { return *this; }
 };  };
   
   
   /// Commonly used, templated to work with any integer type
   
   template<typename T> char* pa_itoa(T n, T base=10){
           char buf[MAX_NUMBER + 1];
           char* pos=buf + MAX_NUMBER;
           *pos='\0';
   
           bool negative=n < 0;
           if (n < 0){
                   n=-n;
           }
   
           do {
                   *(--pos)=(n % base) + '0';
                   n/=base;
           } while (n > 0);
   
           if (negative) {
                   *(--pos) = '-';
           }
           return pa_strdup(pos, buf + MAX_NUMBER - pos);
   }
   
   template<typename T> char* pa_uitoa(T n, T base=10){
           char buf[MAX_NUMBER + 1];
           char* pos=buf + MAX_NUMBER;
           *pos='\0';
   
           do {
                   *(--pos)=(n % base) + '0';
                   n/=base;
           } while (n > 0);
   
           return pa_strdup(pos, buf + MAX_NUMBER - pos);
   }
   
   
   /** Array iterator, usage:
           @code
           // Array<T> a;
           for(Array_iterator<T> i(a); i; ) {
                   T& element=i.next();
                   ...
           }       
           @endcode
   */
   template<typename T> class Array_iterator {
   
           const Array<T>& farray;
           T *fcurrent;
           T *flast;
   
   public:
   
           Array_iterator(const Array<T>& aarray): farray(aarray) {
                   fcurrent=farray.felements;
                   flast=farray.felements + farray.fused;
           }
   
           /// there are still elements
           inline operator bool () {
                   return fcurrent < flast;
           }
   
           /// returns the current element and advances the iterator
           inline T next() {
                   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;
           }
   
           inline char *key(){
                   return pa_uitoa(index());
           }
   
   };
   
   template<typename T> class Array_reverse_iterator {
   
           const Array<T>& farray;
           T *fcurrent;
   
   public:
   
           Array_reverse_iterator(const Array<T>& aarray): farray(aarray) {
                   fcurrent=farray.felements + farray.fused;
           }
   
           /// there are still elements
           inline operator bool () {
                   return fcurrent > farray.felements;
           }
   
           /// returns the current element and advances the iterator
           inline T prev() {
                   return *(--fcurrent);
           }
   
           // returns the current index of the iterator
           inline size_t index() {
                   return fcurrent - farray.felements;
           }
   
           inline char *key(){
                   return pa_uitoa(index());
           }
   
   };
 #endif  #endif

Removed from v.1.41  
changed lines
  Added in v.1.93


E-mail: