Branch: Tag:

2001-06-21

2001-06-21 00:25:15 by Per Hedbor <ph@opera.com>

Use a .cmod for String.Buffer, also String.Buffer now uses stringbuilder (slower (10% or so), but less code, and it should be possible to optimize the stringbuilder so that it's just as fast.)

Rev: src/builtin.cmod:1.20
Rev: src/builtin_functions.c:1.344

1:   /* -*- c -*- -  * $Id: builtin.cmod,v 1.19 2001/06/15 00:26:09 mast Exp $ +  * $Id: builtin.cmod,v 1.20 2001/06/21 00:25:15 per Exp $    */      #include "global.h"
333:    push_int(flag);   }    + #define INITIAL_BUF_LEN 4096 +  + /*! @module String +  */ +  + PIKECLASS Buffer + /*! @class Buffer +  *! A buffer, used for building strings. It's +  *! conceptually similar to a string, but you can only @[add] +  *! strings to it, and you can only @[get] the value from it once. +  *! +  *! There is a reason for those seemingly rather odd limitations, +  *! it makes it possible to do some optimizations that really speed +  *! things up. +  *! +  *! You do not need to use this class unless you add very many +  *! strings together, or very large strings. +  *! +  *! @example +  *! For the fastest possible operation, write your code like this: +  *! +  *! @code{ +  *! String.Buffer b = String.Buffer( ); +  *! +  *! function add = b->add; +  *! +  *! .. call add several times in code ... +  *! +  *! string result = b->get(); // also clears the buffer +  *! @} +  */ + { +  CVAR struct string_builder str; +  CVAR int initial; +  +  void f_Buffer_get_copy( INT32 args ); +  void f_Buffer_get( INT32 args ); +  void f_Buffer_add( INT32 args ); +  +  +  PIKEFUN void create( int|void size ) +  /*! @decl void create() +  *! +  *! Initializes a new buffer. +  *! +  *! If no @[initial_size] is specified, 4096 is used. If you +  *! know approximately how big the buffer will be, you can optimize +  *! the operation of @[add()] (slightly) by passing the size to this +  *! function. +  */ +  { +  struct Buffer_struct *str = THIS; +  if( args ) +  str->initial = MAXIMUM( size->u.integer, 512 ); +  else +  { +  str->initial = 256; +  push_int(0); +  } +  } +  +  PIKEFUN string _sprintf( int flag, mapping flags ) +  { +  switch( flag ) +  { +  case 'O': +  { +  struct pike_string *res; +  struct Buffer_struct *str = THIS; +  push_text( "Buffer(%d /* %d */)" ); +  if( str->str.s ) +  { +  push_int(str->str.s->len); +  push_int(str->str.malloced); +  } +  else +  { +  push_int( 0 ); +  push_int( 0 ); +  } +  f_sprintf( 3 ); +  res = Pike_sp[-1].u.string; +  Pike_sp--; +  RETURN res; +  } +  +  case 's': +  { +  pop_n_elems( args ); +  if( Pike_fp->current_object->refs != 1 ) +  f_Buffer_get_copy( 0 ); +  else +  f_Buffer_get( 0 ); +  } +  return; +  +  case 't': +  RETURN make_shared_binary_string("Buffer",6); +  } +  pop_n_elems( args ); +  push_int( 0 ); +  Pike_sp[-1].subtype = 1; +  } +  +  PIKEFUN mixed cast( string type ) +  { +  struct pike_string *string_t; +  MAKE_CONSTANT_SHARED_STRING( string_t, "string" ); +  +  if( type == string_t ) +  { +  pop_n_elems( args ); +  if( Pike_fp->current_object->refs != 1 ) +  f_Buffer_get_copy( 0 ); +  else +  f_Buffer_get( 0 ); +  return; +  } +  Pike_error("Cannot cast to %s\n", type->str ); +  } +  +  PIKEFUN object `+( string what ) +  { +  struct Buffer_struct *str = THIS, *str2; +  struct object *res = clone_object( Buffer_program, 0 ); +  +  if( str->str.s ) +  { +  str2 = OBJ2_BUFFER( res ); +  +  if( str2->str.s ) free_string_builder( &str2->str ); +  *str2 = *str; +  init_string_builder_alloc( &str2->str, +  str->str.malloced, +  str->str.s->size_shift ); +  MEMCPY( (void *)str2->str.s, (void *)str->str.s, +  str->str.malloced+sizeof(struct pike_string)); +  } +  apply( res, "add", 1 ); +  RETURN res; +  } +  +  PIKEFUN object `+=( string what ) +  { +  f_Buffer_add( 1 ); +  REF_RETURN fp->current_object; +  } +  +  PIKEFUN int add( string ... arg1 ) + /*! @decl void add(string ... data) +  *! +  *! Adds @[data] to the buffer. Returns the size of the buffer. +  *! +  */ +  { +  struct Buffer_struct *str = THIS; +  int j; +  struct pike_string *a; +  +  for( j = 0; j<args; j++ ) +  { +  a = Pike_sp[-args+j].u.string; +  if( !str->str.s ) +  init_string_builder_alloc( &str->str, str->initial, a->size_shift ); +  string_builder_shared_strcat( &str->str, a ); +  } +  RETURN str->str.s->len; +  } +  +  PIKEFUN string get_copy() +  /*! @decl string get_copy() +  *! +  *! Get the data from the buffer. Significantly slower than @[get], +  *! but does not clear the buffer. +  */ +  { +  struct pike_string *str = THIS->str.s; +  if( str ) +  { +  ptrdiff_t len = str->len; +  if( len > 0 ) +  { +  char *d = (char *)str->str; +  switch( str->size_shift ) +  { +  case 0: +  RETURN make_shared_binary_string(d,len); +  break; +  case 1: +  RETURN make_shared_binary_string1((short*)d,len>>1); +  break; +  case 2: +  RETURN make_shared_binary_string2((int*)d,len>>2); +  break; +  } +  } +  } +  push_text(""); +  return; +  } +  +  PIKEFUN string get( ) +  /*! @decl string get() +  *! +  *! Get the data from the buffer. +  *! +  *! @note +  *! This will clear the data in the buffer +  */ +  { +  struct Buffer_struct *str = THIS; +  struct pike_string *s = finish_string_builder( &str->str ); +  str->str.malloced = 0; +  str->str.s = 0; +  RETURN s; +  } +  +  INIT +  { +  struct Buffer_struct *str = THIS; +  MEMSET( str, 0, sizeof( *str ) ); +  } +  +  EXIT +  { +  struct Buffer_struct *str = THIS; +  if( str->str.s ) +  free_string_builder( &str->str ); +  } + } +  + /* @endmodule */ +    void init_builtin(void)   {   INIT   }