Diff for /parser3/src/main/pa_string.C between versions 1.124 and 1.144

version 1.124, 2001/11/21 08:26:55 version 1.144, 2002/02/22 12:14:11
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 189  break2: Line 150  break2:
 int String::cmp(int& partial, const String& src,   int String::cmp(int& partial, const String& src, 
                                 size_t this_offset, Untaint_lang lang) const {                                  size_t this_offset, Untaint_lang lang) const {
         partial=-1;          partial=-1;
         this_offset=min(this_offset, size()-1);          size_t a_size=size();
           this_offset=min(this_offset, a_size-1);
   
         const Chunk *a_chunk=&head;          const Chunk *a_chunk=&head;
         const Chunk *b_chunk=&src.head;          const Chunk *b_chunk=&src.head;
Line 204  int String::cmp(int& partial, const Stri Line 166  int String::cmp(int& partial, const Stri
         int result;          int result;
         size_t pos=0;           size_t pos=0; 
   
         bool a_break=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 277  int String::cmp(int& partial, const Stri Line 239  int String::cmp(int& partial, const Stri
 int String::cmp(int& partial, const char* b_ptr, size_t src_size,   int String::cmp(int& partial, const char* b_ptr, size_t src_size, 
                                 size_t this_offset, Untaint_lang lang) const {                                  size_t this_offset, Untaint_lang lang) const {
         partial=-1;          partial=-1;
           size_t a_size=size();
         size_t b_size=src_size?src_size:b_ptr?strlen(b_ptr):0;          size_t b_size=src_size?src_size:b_ptr?strlen(b_ptr):0;
         this_offset=min(this_offset, size()-1);          this_offset=min(this_offset, a_size-1);
   
         const Chunk *a_chunk=&head;          const Chunk *a_chunk=&head;
         const Chunk::Row *a_row=a_chunk->rows;          const Chunk::Row *a_row=a_chunk->rows;
Line 288  int String::cmp(int& partial, const char Line 251  int String::cmp(int& partial, const char
         uint a_countdown=a_chunk->count;          uint a_countdown=a_chunk->count;
         size_t pos=0;          size_t pos=0;
   
         bool a_break=size()==0;          bool a_break=a_size==0;
         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 346  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 365  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 374  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 395  break2: Line 358  break2:
   
 int String::pos(const String& substr,   int String::pos(const String& substr, 
                                 int result, Untaint_lang lang) const {                                  int result, Untaint_lang lang) const {
         for(; result<size(); result++) {          size_t self_size=size();
           for(; size_t(result)<self_size; result++) {
                 int partial; cmp(partial, substr, result, lang);                  int partial; cmp(partial, substr, result, lang);
                 if(                  if(
                         partial==0 || // full match                          partial==0 || // full match
Line 408  int String::pos(const String& substr, Line 372  int String::pos(const String& substr,
   
 int String::pos(const char *substr, size_t substr_size,   int String::pos(const char *substr, size_t substr_size, 
                                 int result, Untaint_lang lang) const {                                  int result, Untaint_lang lang) const {
         for(; result<size(); result++) {          size_t self_size=size();
           for(; size_t(result)<self_size; result++) {
                 int partial; cmp(partial, substr, substr_size, result, lang);                  int partial; cmp(partial, substr, substr_size, result, lang);
                 if(                  if(
                         partial==0 || // full match                          partial==0 || // full match
Line 423  void String::split(Array& result, Line 388  void String::split(Array& result,
                                    size_t* pos_after_ref,                                      size_t* pos_after_ref, 
                                    const char *delim, size_t delim_size,                                      const char *delim, size_t delim_size, 
                                    Untaint_lang lang, int limit) const {                                     Untaint_lang lang, int limit) const {
         int self_size=size();          size_t self_size=size();
         if(delim_size) {          if(delim_size) {
                 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;
Line 450  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 499  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 507  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 519  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 601  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 625  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  
                                         break;  
                         }  
                         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++) {                          } else {
                                 if(row==append_here)                                  --row;  ++countdown; // step back from not-ours
                                         goto break22;  
                                   
                                 if(row->item.lang==joined_lang) {  
                                         memcpy(ptr, row->item.ptr, row->item.size);  
                                         ptr+=row->item.size;  
                                 } else  
                                         break;  
                         }  
                         if(chunk=row->link) {  
                                 start_i=0;  
                                 start_row=chunk->rows;  
                         } else  
                                 break;                                  break;
                 } while(true);                          }
 break22:;                  );
                                   
                 // return joined rows                  // set pointers after joined piece & one step back, see String::reconstruct
                 ai=i;                  achunk=chunk;  arow=row-1;  acountdown=countdown-1;
                 arow=row;  
                 achunk=chunk;  
         }          }
 }  }
   
 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(
         do {                  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);
                         join_chain(pool, i, chunk, row,  
                                 joined_lang, joined_ptr, joined_size);  
   
                         result.APPEND(joined_ptr, joined_size,                   result.APPEND(joined_ptr, joined_size, joined_lang,
                                 joined_lang,                          joined_origin_file, joined_origin_line);
                                 row->item.origin.file, row->item.origin.line);          );
                         if(!chunk)  
                                 goto break2;  
                 }  
         } while(true);  
 break2:  
   
         return result;          return result;
 };  };
Line 783  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 848  int String::as_int() const { Line 768  int String::as_int() const {
         return result;          return result;
 }  }
   
   inline void ushort2uchars(ushort word, uchar& byte1, uchar& byte2) {
           byte1=word&0xFF;
           byte2=word>>8;
   }
   inline ushort uchars2ushort(uchar byte1, uchar byte2) {
           return (byte2<<8) | byte1;
   }
 /* @todo maybe network order worth spending some effort?  /* @todo maybe network order worth spending some effort?
         don't bothering myself with network byte order,          don't bothering myself with network byte order,
         am not planning to be able to move resulting file across platforms          am not planning to be able to move resulting file across platforms
Line 856  int String::as_int() const { Line 783  int String::as_int() const {
 void String::serialize(size_t prolog_size, void *& buf, size_t& buf_size) const {  void String::serialize(size_t prolog_size, void *& buf, size_t& buf_size) const {
         buf_size=          buf_size=
                 prolog_size                  prolog_size
                 +used_rows()*(sizeof(Untaint_lang)+sizeof(size_t))                  +used_rows()*(sizeof(uchar)+sizeof(ushort))
                 +size();                  +size();
         buf=malloc(buf_size,15);          buf=malloc(buf_size,15);
         char *cur=(char *)buf+prolog_size;          char *cur=(char *)buf+prolog_size;
   
         STRING_FOREACH_ROW(          STRING_FOREACH_ROW(
                 // lang                  // lang
                 memcpy(cur, &row->item.lang, sizeof(Untaint_lang));                  memcpy(cur, &row->item.lang, sizeof(uchar));
                 cur+=sizeof(Untaint_lang);                  cur+=sizeof(uchar);
                 // size                  // size
                 memcpy(cur, &row->item.size, sizeof(size_t));                  uchar byte1; uchar byte2;
                 cur+=sizeof(size_t);                  ushort2uchars(row->item.size, byte1, byte2);
                   memcpy(cur, &byte1, sizeof(uchar)); cur+=sizeof(uchar);
                   memcpy(cur, &byte2, sizeof(uchar)); cur+=sizeof(uchar);
                 // bytes                  // bytes
                 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:  
         ;  
 }  }
   
 /* @todo maybe network order worth spending some effort?  
         don't bothering myself with network byte order,  
         am not planning to be able to move resulting file across platforms  
         for now  
 */  
 #ifndef DOXYGEN  
 struct Serialized_piece {  
         String::Untaint_lang lang;  
         size_t size;  
         char ptr[1];  
 };  
 #endif  
   
 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) {
         char *cur=((char *)buf)+prolog_size;          if(buf_size<=prolog_size)
                   return;
   
           char *cur=(char *)buf+prolog_size;
         buf_size-=prolog_size;          buf_size-=prolog_size;
   
         while(buf_size) {          while(buf_size) {
                 Serialized_piece& p=*(Serialized_piece *)cur;                  uchar lang=*(uchar *)(cur);
                 APPEND(p.ptr, p.size, p.lang, file, 0);                  
                   ushort size=uchars2ushort(
                           *(uchar*)(cur+sizeof(uchar)*1),
                           *(uchar*)(cur+sizeof(uchar)*2)
                   );
   
                 size_t piece_size=sizeof(p.lang)+sizeof(p.size)+p.size;                  const char *ptr=(const char*)(cur+sizeof(uchar)*3); 
                   APPEND(ptr, size, lang, file, 0);
   
                   size_t piece_size=sizeof(uchar)+sizeof(ushort)+size;
                 cur+=piece_size;                  cur+=piece_size;
                 buf_size-=piece_size;                  buf_size-=piece_size;
         }          }
 }  }
   

Removed from v.1.124  
changed lines
  Added in v.1.144


E-mail: