Diff for /parser3/src/main/pa_string.C between versions 1.131 and 1.146

version 1.131, 2001/12/13 10:47:34 version 1.146, 2002/02/22 12:25:45
Line 1 Line 1
 /** @file  /** @file
         Parser: string class. @see untasize_t.C.          Parser: string class. @see untasize_t.C.
   
         Copyright (c) 2001 ArtLebedev Group (http://www.artlebedev.com)          Copyright (c) 2001, 2002 ArtLebedev Group (http://www.artlebedev.com)
         Author: Alexander Petrosyan <paf@design.ru> (http://paf.design.ru)          Author: Alexandr Petrosian <paf@design.ru> (http://paf.design.ru)
   
         $Id$          $Id$
 */  */
   
 #include "pa_config_includes.h"  
   
 #include "pcre.h"  #include "pcre.h"
 #include "internal.h"  
   
 #include "pa_pool.h"  #include "pa_pool.h"
 #include "pa_string.h"  #include "pa_string.h"
Line 21 Line 18
 #include "pa_globals.h"  #include "pa_globals.h"
 #include "pa_table.h"  #include "pa_table.h"
 #include "pa_dictionary.h"  #include "pa_dictionary.h"
   #include "pa_charset.h"
   
   #define DEBUG_STRING_APPENDS_VS_EXPANDS
   
   
   #ifdef DEBUG_STRING_APPENDS_VS_EXPANDS
   ulong string_piece_appends=0;
   #endif
   
 String::String(Pool& apool, const char *src, size_t src_size, bool tainted) :  String::String(Pool& apool, const char *src, size_t src_size, bool tainted) :
         Pooled(apool) {          Pooled(apool) {
         last_chunk=&head;          last_chunk=&head;
         head.count=CR_PREALLOCATED_COUNT;          head.count=CR_PREALLOCATED_COUNT;
         append_here=head.rows;          append_here=head.rows;
         head_link=0;  
         link_row=&head.rows[head.count];  
   
         if(src)          if(src)
                 if(tainted)                  if(tainted)
Line 39  String::String(Pool& apool, const char * Line 42  String::String(Pool& apool, const char *
   
 String::String(const String& src) :       String::String(const String& src) :     
         Pooled(src.pool()) {          Pooled(src.pool()) {
           last_chunk=&head;
         head.count=CR_PREALLOCATED_COUNT;          head.count=CR_PREALLOCATED_COUNT;
                   append_here=head.rows;
         uint src_used_rows=src.used_rows();  
         if(src_used_rows<=head.count) {  
                 // all new rows fit size_to preallocated area  
                 last_chunk=&head;  
                 uint curr_chunk_rows=head.count;  
                 memcpy(head.rows, src.head.rows, sizeof(Chunk::Row)*src_used_rows);  
                 append_here=&head.rows[src_used_rows];  
                 link_row=&head.rows[curr_chunk_rows];  
         } else {  
                 // warning:   
                 //   heavily relies on the fact   
                 //   "preallocated area is the same for all strings"  
                 //  
                 // info:  
                 //   allocating only enough mem to fit src string rows  
                 //   next append would allocate a new chunk  
                 //  
                 // new rows don't fit size_to preallocated area: splitting size_to two chunks  
                 // preallocated chunk src to constructing head  
                 memcpy(head.rows, src.head.rows, sizeof(Chunk::Row)*head.count);  
                 // remaining rows size_to new_chunk  
                 uint curr_chunk_rows=src_used_rows-head.count;  
                 last_chunk=static_cast<Chunk *>(  
                         malloc(sizeof(uint)+sizeof(Chunk::Row)*curr_chunk_rows+sizeof(Chunk *), 9));  
                 last_chunk->count=curr_chunk_rows;  
                 head_link=last_chunk;  
                 append_here=link_row=&last_chunk->rows[last_chunk->count];  
   
                 Chunk *old_chunk=src.head_link;   
                 Chunk::Row *new_rows=last_chunk->rows;  
                 uint rows_left_to_copy=last_chunk->count;  
                 while(true) {  
                         uint old_count=old_chunk->count;  
                         Chunk *next_chunk=old_chunk->rows[old_count].link;  
                         if(next_chunk) {  
                                 // not last source chunk  
                                 // taking it all  
                                 memcpy(new_rows, old_chunk->rows, sizeof(Chunk::Row)*old_count);  
                                 new_rows+=old_count;  
                                 rows_left_to_copy-=old_count;  
   
                                 old_chunk=next_chunk;          append(src, UL_UNSPECIFIED);
                         } else {  
                                 // the last source chunk  
                                 // taking only those rows of chunk that _left_to_copy  
                                 memcpy(new_rows, old_chunk->rows, sizeof(Chunk::Row)*rows_left_to_copy);  
                                 break;  
                         }  
                 }  
         }  
         link_row->link=0;  
         src_used_rows;  
 }  }
   
 size_t  String::size() const {  size_t  String::size() const {
Line 100  size_t  String::size() const { Line 54  size_t  String::size() const {
         STRING_FOREACH_ROW(          STRING_FOREACH_ROW(
                         result+=row->item.size;                          result+=row->item.size;
         );          );
 break2:  
         return result;          return result;
 }  }
   
Line 110  uint String::used_rows() const { Line 63  uint String::used_rows() const {
         STRING_FOREACH_ROW(          STRING_FOREACH_ROW(
                 result++;                  result++;
         );          );
 break2:  
         return result;          return result;
 }  }
 void String::expand() {  void String::expand() {
         uint new_chunk_count=last_chunk->count+CR_GROW_COUNT;          uint new_chunk_count=last_chunk->count+CR_GROW_COUNT;
         if(new_chunk_count>MAX_USHORT)          if(new_chunk_count>max_integral(Chunk::count_type))
                 new_chunk_count=MAX_USHORT;                  new_chunk_count=max_integral(Chunk::count_type);
   
         last_chunk=static_cast<Chunk *>(          Chunk *new_chunk=static_cast<Chunk *>(
                 malloc(sizeof(uint)+sizeof(Chunk::Row)*new_chunk_count+sizeof(Chunk *), 10));                  malloc(sizeof(Chunk::count_type)+sizeof(Chunk::Row)*new_chunk_count+sizeof(Chunk *), 10));
         last_chunk->count=new_chunk_count;          new_chunk->rows[new_chunk->count=new_chunk_count].link=0;
         link_row->link=last_chunk;          last_chunk->rows[last_chunk->count].link=new_chunk;
           
           last_chunk=new_chunk;
         append_here=last_chunk->rows;          append_here=last_chunk->rows;
         link_row=&last_chunk->rows[last_chunk->count];  
         link_row->link=0;  
 }  }
   
 String& String::real_append(STRING_APPEND_PARAMS) {  String& String::real_append(STRING_APPEND_PARAMS) {
           if(!last_chunk) // growth stopped [we're appended as string to somebody]
                   throw Exception(0, 0,
                           this,
                           "string growth stopped (append cstr)");
   
         if(!src)          if(!src)
                 return *this;                  return *this;
         if(!size)          if(!size)
Line 135  String& String::real_append(STRING_APPEN Line 92  String& String::real_append(STRING_APPEN
         if(!size)          if(!size)
                 return *this;                  return *this;
   
         while(size>MAX_USHORT) {  #ifdef DEBUG_STRING_APPENDS_VS_EXPANDS
           string_piece_appends++;
   #endif
   
           // manually unrolled to avoid extra check
           while(size>max_integral(Chunk::Row::item_size_type)) {
                 if(chunk_is_full())                  if(chunk_is_full())
                         expand();                          expand();
   
                 append_here->item.ptr=src;                  append_here->item.ptr=src;
                 append_here->item.size=MAX_USHORT;                  append_here->item.size=max_integral(Chunk::Row::item_size_type);
                 append_here->item.lang=lang;                  append_here->item.lang=lang;
 #ifndef NO_STRING_ORIGIN  #ifndef NO_STRING_ORIGIN
                 append_here->item.origin.file=file;                  append_here->item.origin.file=file;
Line 148  String& String::real_append(STRING_APPEN Line 110  String& String::real_append(STRING_APPEN
 #endif  #endif
                 append_here++;                  append_here++;
   
                 src+=MAX_USHORT;                  src+=max_integral(Chunk::Row::item_size_type);
                 size-=MAX_USHORT;                  size-=max_integral(Chunk::Row::item_size_type);
         }          }
   
         if(chunk_is_full())          if(chunk_is_full())
Line 168  String& String::real_append(STRING_APPEN Line 130  String& String::real_append(STRING_APPEN
 }  }
   
 char String::first_char() const {  char String::first_char() const {
         if(!used_rows())          if(is_empty())
                 throw Exception(0, 0,                  throw Exception(0, 0,
                         this,                          this,
                         "getting first char of empty string");                          "getting first char of empty string");
Line 181  uint String::hash_code() const { Line 143  uint String::hash_code() const {
         STRING_FOREACH_ROW(          STRING_FOREACH_ROW(
                         result=Hash::generic_code(result, row->item.ptr, row->item.size);                          result=Hash::generic_code(result, row->item.ptr, row->item.size);
         );          );
 break2:  
         return result;          return result;
 }  }
   
Line 206  int String::cmp(int& partial, const Stri Line 167  int String::cmp(int& partial, const Stri
         size_t pos=0;           size_t pos=0; 
   
         bool a_break=a_size==0;          bool a_break=a_size==0;
         bool b_break=src.size()==0;          bool b_break=src.is_empty();
         if(!(a_break || b_break)) while(true) {          if(!(a_break || b_break)) while(true) {
                 if(pos+a_row->item.size > this_offset) {                  if(pos+a_row->item.size > this_offset) {
                         if(lang!=UL_UNSPECIFIED && a_row->item.lang!=lang)                           if(lang!=UL_UNSPECIFIED && a_row->item.lang>lang) 
                                 return -1; // wrong lang -- bail out                                  return -1; // wrong lang -- bail out
   
                         int size_diff=                          int size_diff=
Line 294  int String::cmp(int& partial, const char Line 255  int String::cmp(int& partial, const char
         bool b_break=b_size==0;          bool b_break=b_size==0;
         if(!(a_break || b_break)) while(true) {          if(!(a_break || b_break)) while(true) {
                 if(pos+a_row->item.size > this_offset) {                  if(pos+a_row->item.size > this_offset) {
                         if(lang!=UL_UNSPECIFIED && a_row->item.lang!=lang)                           if(lang!=UL_UNSPECIFIED && a_row->item.lang>lang) 
                                 return -1; // wrong lang -- bail out                                  return -1; // wrong lang -- bail out
   
                         int size_diff=                          int size_diff=
Line 348  int String::cmp(int& partial, const char Line 309  int String::cmp(int& partial, const char
   
 #ifndef NO_STRING_ORIGIN  #ifndef NO_STRING_ORIGIN
 const Origin& String::origin() const {   const Origin& String::origin() const { 
         if(!used_rows()) {          if(is_empty()) {
                 static const Origin empty_origin={"empty string"};                  static const Origin empty_origin={"empty string"};
                 return empty_origin;                  return empty_origin;
         }          }
Line 367  const Origin& String::origin() const { Line 328  const Origin& String::origin() const {
 String& String::mid(size_t start, size_t finish) const {  String& String::mid(size_t start, size_t finish) const {
         String& result=*NEW String(pool());          String& result=*NEW String(pool());
   
         start=max(0, start);          start=max(size_t(0), start);
         finish=min(size(), finish);          finish=min(size(), finish);
         if(start==finish)          if(start==finish)
                 return result;                  return result;
Line 376  String& String::mid(size_t start, size_t Line 337  String& String::mid(size_t start, size_t
         STRING_FOREACH_ROW(          STRING_FOREACH_ROW(
                 size_t item_finish=pos+row->item.size;                  size_t item_finish=pos+row->item.size;
                 if(item_finish > start) { // started now or already?                  if(item_finish > start) { // started now or already?
                         bool started=result.size()==0; // started now?                          bool started=result.is_empty(); // started now?
                         bool finished=finish <= item_finish; // finished now?                          bool finished=finish <= item_finish; // finished now?
                         size_t offset=started?start-pos:0;                          size_t offset=started?start-pos:0;
                         size_t size=finished?finish-pos:row->item.size;                          size_t size=finished?finish-pos:row->item.size;
Line 454  void String::split(Array& result, Line 415  void String::split(Array& result,
                                    size_t* pos_after_ref,                                      size_t* pos_after_ref, 
                                    const String& delim, Untaint_lang lang,                                      const String& delim, Untaint_lang lang, 
                                    int limit) const {                                     int limit) const {
         if(delim.size()) {          if(!delim.is_empty()) {
                 size_t pos_after=pos_after_ref?*pos_after_ref:0;                  size_t pos_after=pos_after_ref?*pos_after_ref:0;
                 int pos_before;                  int pos_before;
                 // while we have 'delim'...                  // while we have 'delim'...
Line 503  static void regex_options(char *options, Line 464  static void regex_options(char *options,
 }  }
   
 /// @todo maybe need speedup: some option to remove pre/match/post string generation  /// @todo maybe need speedup: some option to remove pre/match/post string generation
 bool String::match(const unsigned char *pcre_tables,  bool String::match(
                                    const String *aorigin,                                     const String *aorigin,
                                    const String& regexp,                                      const String& regexp, 
                                    const String *options,                                     const String *options,
Line 511  bool String::match(const unsigned char * Line 472  bool String::match(const unsigned char *
                                    Row_action row_action, void *info,                                     Row_action row_action, void *info,
                                    bool *was_global) const {                                      bool *was_global) const { 
   
         if(!regexp.size())          if(regexp.is_empty())
                 throw Exception(0, 0,                  throw Exception(0, 0,
                         aorigin,                          aorigin,
                         "regexp is empty");                          "regexp is empty");
Line 523  bool String::match(const unsigned char * Line 484  bool String::match(const unsigned char *
                 *was_global=option_bits[1]!=0;                  *was_global=option_bits[1]!=0;
         pcre *code=pcre_compile(pattern, option_bits[0],           pcre *code=pcre_compile(pattern, option_bits[0], 
                 &errptr, &erroffset,                  &errptr, &erroffset,
                 pcre_tables);                  pool().get_source_charset().pcre_tables);
   
         if(!code)          if(!code)
                 throw Exception(0, 0,                  throw Exception(0, 0,
Line 605  bool String::match(const unsigned char * Line 566  bool String::match(const unsigned char *
         }          }
 }  }
   
 String& String::change_case(Pool& pool, const unsigned char *tables,   String& String::change_case(Pool& pool, 
                                                         Change_case_kind kind) const {                                                          Change_case_kind kind) const {
           const unsigned char *tables=pool.get_source_charset().pcre_tables;
         String& result=*new(pool) String(pool);          String& result=*new(pool) String(pool);
   
         const unsigned char *a;          const unsigned char *a;
Line 629  String& String::change_case(Pool& pool, Line 591  String& String::change_case(Pool& pool,
                 break; // never                  break; // never
         }                 }       
   
         const Chunk *chunk=&head;           STRING_FOREACH_ROW(
         do {                  char *new_cstr=(char *)pool.malloc(row->item.size, 12);
                 const Chunk::Row *row=chunk->rows;                  char *dest=new_cstr;
                 for(uint i=0; i<chunk->count; i++, row++) {                  const char *src=row->item.ptr; 
                         if(row==append_here)                  for(int size=row->item.size; size--; src++) {
                                 goto break2;                          unsigned char c=a[(unsigned char)*src];
                           if(b)
                         char *new_cstr=(char *)pool.malloc(row->item.size, 12);                                  c=b[c];
                         char *dest=new_cstr;  
                         const char *src=row->item.ptr;   
                         for(int size=row->item.size; size--; src++) {  
                                 unsigned char c=a[(unsigned char)*src];  
                                 if(b)  
                                         c=b[c];  
   
                                 *dest++=(char)c;                          *dest++=(char)c;
                         }  
                           
                         result.APPEND(new_cstr, row->item.size,   
                                 row->item.lang,  
                                 row->item.origin.file, row->item.origin.line);  
                 }                  }
                 chunk=row->link;                  
         } while(chunk);                  result.APPEND(new_cstr, row->item.size, 
 break2:                          row->item.lang,
                           row->item.origin.file, row->item.origin.line);
           );
   
         return result;          return result;
 }  }
   
 void String::join_chain(Pool& pool,   void String::join_chain(Pool& pool, 
                                            uint& ai, const Chunk*& achunk, const Chunk::Row*& arow,                                             const Chunk*& achunk, const Chunk::Row*& arow, uint& acountdown, 
                                            uchar& joined_lang, const char *& joined_ptr, size_t& joined_size) const {                                             uchar& joined_lang, const char *& joined_ptr, size_t& joined_size) const {
         joined_lang=arow->item.lang;          joined_lang=arow->item.lang;
                   
         // calc size          // calc size
         joined_size=0;          joined_size=0;
         {          {
                 uint start_i=ai;                  const Chunk* chunk=achunk;
                 const Chunk::Row *start_row=arow;                  const Chunk::Row* row=arow;
                 const Chunk *chunk=achunk;                  uint countdown=acountdown;
                 do {                  STRING_PREPARED_FOREACH_ROW(*this, 
                         const Chunk::Row *row=start_row;                          if(row->item.lang==joined_lang)
                         for(uint i=start_i; i<chunk->count; i++, row++) {                                  joined_size+=row->item.size;
                                 if(row==append_here)                          else
                                         goto break21;  
                                   
                                 if(row->item.lang==joined_lang)  
                                         joined_size+=row->item.size;  
                                 else  
                                         goto break21;  
                         }  
                         if(chunk=row->link) {  
                                 start_i=0;  
                                 start_row=chunk->rows;  
                         } else  
                                 break;                                  break;
                 } while(true);                  );
 break21:;  
         }          }
   
         // if one row, return simply itself          // if one row, return simply itself
         if(joined_size==arow->item.size) {          if(joined_size==arow->item.size) {
                 joined_ptr=arow->item.ptr;                  joined_ptr=arow->item.ptr;
                 ai++; arow++;  
                 if(ai==achunk->count)  
                         achunk=arow->link;                
         } else {          } else {
                 // join adjacent rows                  // join adjacent rows
                 char *ptr=(char *)pool.malloc(joined_size,13);                  char *ptr=(char *)pool.malloc(joined_size,13);  
                 joined_ptr=ptr;                  joined_ptr=ptr;
                 uint start_i=ai;  
                 const Chunk::Row *start_row=arow;                  const Chunk* chunk=achunk;
                 const Chunk *chunk=achunk;                  const Chunk::Row* row=arow;
                 uint i;                  uint countdown=acountdown;
                 const Chunk::Row *row;                  STRING_PREPARED_FOREACH_ROW(*this, 
                 do {                          if(row->item.lang==joined_lang) {
                         row=start_row;                                  memcpy(ptr, row->item.ptr, row->item.size);  ptr+=row->item.size;
                         for(i=start_i; i<chunk->count; i++, row++) {  
                                 if(row==append_here)  
                                         goto break22;  
                                   
                                 if(row->item.lang==joined_lang) {  
                                         memcpy(ptr, row->item.ptr, row->item.size);  
                                         ptr+=row->item.size;  
                                 } else  
                                         goto break22;  
                         }  
                         if(chunk=row->link) {  
                                 start_i=0;  
                                 start_row=chunk->rows;  
                         } else                          } else
                                 break;                                  break; // before non-ours
                 } while(true);                  );
 break22:;  
                                   
                 // return joined rows                  // set pointers after joined piece
                 ai=i;                  achunk=chunk;  arow=row;  acountdown=countdown;
                 arow=row;                  // & one step back, see String::reconstruct
                 achunk=chunk;                  --arow;  ++acountdown;
         }          }
 }  }
   
 String& String::reconstruct(Pool& pool) const {  String& String::reconstruct(Pool& pool) const {
         //_asm int 3;          //_asm int 3;
         String& result=*new(pool) String(pool);          String& result=*new(pool) String(pool);
         const Chunk *chunk=&head;           STRING_FOREACH_ROW(
         while(true) {                  uchar joined_lang;
                 const Chunk::Row *row=chunk->rows;                  const char *joined_ptr;
                 for(uint i=0; i<chunk->count; ) {                  size_t joined_size;
                         if(row==append_here)  IFNDEF_NO_STRING_ORIGIN(
                                 goto break2;                  const char *joined_origin_file=row->item.origin.file;
                   const size_t joined_origin_line=row->item.origin.line;
                         uchar joined_lang;  );
                         const char *joined_ptr;                  join_chain(pool, chunk, row, countdown,
                         size_t joined_size;                          joined_lang, joined_ptr, joined_size);
 #ifndef NO_STRING_ORIGIN  
                         const char *joined_origin_file=row->item.origin.file;  
                         const size_t joined_origin_line=row->item.origin.line;  
 #endif  
                         join_chain(pool, i, chunk, row,  
                                 joined_lang, joined_ptr, joined_size);  
   
                         result.APPEND(joined_ptr, joined_size, joined_lang,                  result.APPEND(joined_ptr, joined_size, joined_lang,
                                 joined_origin_file, joined_origin_line);                          joined_origin_file, joined_origin_line);
                         if(!chunk)          );
                                 goto break2;  
                 }  
         }  
 break2:  
   
         return result;          return result;
 };  };
Line 790  String& String::replace_in_reconstructed Line 704  String& String::replace_in_reconstructed
                         row->item.lang,                          row->item.lang,
                         row->item.origin.file, row->item.origin.line);                          row->item.origin.file, row->item.origin.line);
         );          );
 break2:  
         return result;          return result;
 }  }
   
Line 888  void String::serialize(size_t prolog_siz Line 801  void String::serialize(size_t prolog_siz
                 memcpy(cur, row->item.ptr, row->item.size);                  memcpy(cur, row->item.ptr, row->item.size);
                 cur+=row->item.size;                  cur+=row->item.size;
         );          );
 break2:  
         ;  
 }  }
 void String::deserialize(size_t prolog_size, void *buf, size_t buf_size, const char *file) {  void String::deserialize(size_t prolog_size, void *buf, size_t buf_size, const char *file) {
           if(buf_size<=prolog_size)
                   return;
   
         char *cur=(char *)buf+prolog_size;          char *cur=(char *)buf+prolog_size;
         buf_size-=prolog_size;          buf_size-=prolog_size;
   

Removed from v.1.131  
changed lines
  Added in v.1.146


E-mail: