Branch: Tag:

2001-06-19

2001-06-19 22:48:14 by Per Hedbor <ph@opera.com>

Moved String.Buffer to a .cmod

Rev: src/builtin.cmod:1.42
Rev: src/builtin_functions.c:1.379

1:   /* -*- c -*- -  * $Id: builtin.cmod,v 1.41 2001/06/19 22:11:59 grubba Exp $ +  * $Id: builtin.cmod,v 1.42 2001/06/19 22:48:14 per Exp $    */      #include "global.h"
936:    f_reverse(1);   }    + #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 size_t len, size, initial; +  CVAR unsigned char *data; +  CVAR int shift; +  +  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(int|void initial_size) +  *! +  *! 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 = INITIAL_BUF_LEN; +  push_int(0); +  } +  } +  +  + /* The size of the 'str' member of the pike_string struct. */ + #define PIKE_STRING_STR_SIZE 4 +  +  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->size ) +  { +  push_int(((str->len-sizeof(struct pike_string)+ +  PIKE_STRING_STR_SIZE)>>str->shift) ); +  push_int(((str->size-sizeof(struct pike_string)+ +  PIKE_STRING_STR_SIZE)>>str->shift) ); +  } +  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; +  struct pike_string *int_t; +  MAKE_CONSTANT_SHARED_STRING( string_t, "string" ); +  MAKE_CONSTANT_SHARED_STRING( int_t, "int" ); +  +  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; +  } +  +  if( type == int_t ) +  { +  struct Buffer_struct *str = THIS; +  pop_stack(); +  if( Pike_fp->current_object->refs != 1 ) +  f_Buffer_get_copy( 0 ); +  else +  f_Buffer_get( 0 ); +  o_cast_to_int( ); +  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 ); +  +  str2 = OBJ2_BUFFER( res ); +  +  if( str2->data ) +  xfree( str2->data ); +  +  *str2 = *str; +  str2->data = xalloc( str2->size ); +  MEMCPY( str2->data, str->data, str->size ); +  apply( res, "add", 1 ); +  RETURN res; +  } +  +  PIKEFUN object `+=( string what ) +  { +  f_Buffer_add( 1 ); +  REF_RETURN fp->current_object; +  } +  +  PIKEFUN int add( string a ) + /*! @decl void add(string data) +  *! +  *! Adds @[data] to the buffer. Returns the size of the buffer. +  *! +  */ +  { +  struct Buffer_struct *str = THIS; +  size_t l; +  +  if(!(l = (size_t)a->len) ) +  return; +  +  +  if( !str->size ) +  { +  str->shift = a->size_shift; +  str->size = str->initial + +  (sizeof( struct pike_string ) - PIKE_STRING_STR_SIZE); +  str->data = xalloc( str->size ); +  str->len = (sizeof( struct pike_string ) - PIKE_STRING_STR_SIZE); +  } +  else if( str->shift < a->size_shift ) +  { +  /* This will not win the "most optimal code of the year" +  award, but it works, and is rather fast. */ +  f_Buffer_get( 0 ); +  stack_swap(); +  f_add( 2 ); +  f_Buffer_add( 1 ); +  return; +  } +  +  l<<=str->shift; +  +  while( str->size < ((unsigned)l+str->len) ) +  { +  str->size *= 2; +  str->data = realloc( str->data, str->size ); +  if( !str->data ) +  { +  int sz = str->size; +  str->len = 0; +  str->size = 0; +  Pike_error( "Malloc %d failed!\n", sz ); +  } +  } +  + #ifdef PIKE_DEBUG +  if( str->shift < a->size_shift ) +  fatal("Impossible!\n"); + #endif +  +  if( a->size_shift == str->shift ) +  MEMCPY( (str->data+str->len), a->str, l ); +  else +  if( a->size_shift ) +  convert_1_to_2((p_wchar2 *)(str->data+str->len), +  (p_wchar1 *)a->str, a->len); +  else +  if( str->shift & 1 ) +  convert_0_to_1((p_wchar1 *)(str->data+str->len), +  (p_wchar0 *)a->str, a->len); +  else +  convert_0_to_2((p_wchar2 *)(str->data+str->len), +  (p_wchar0 *)a->str, a->len); +  str->len += l; +  RETURN str->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 Buffer_struct *str = THIS; +  ptrdiff_t len = str->len-(sizeof(struct pike_string)-PIKE_STRING_STR_SIZE); +  char *d = str->data+(sizeof(struct pike_string)-PIKE_STRING_STR_SIZE); +  if( len <= 0 ) +  { +  push_text(""); +  return; +  } +  +  switch( str->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; +  } +  } +  +  PIKEFUN string get( ) +  /*! @decl string get() +  *! +  *! Get the data from the buffer. +  *! +  *! @note +  *! This will clear the data in the buffer +  */ +  { +  struct pike_string *res; +  struct Buffer_struct *str = THIS; +  ptrdiff_t len = str->len-(sizeof(struct pike_string)-PIKE_STRING_STR_SIZE); +  if( len <= 0 ) +  { +  push_text(""); +  return; +  } +  +  if( str->len < 64 ) +  { +  char *d = str->data+(sizeof(struct pike_string)-PIKE_STRING_STR_SIZE); +  switch( str->shift ) +  { +  case 0: +  res=make_shared_binary_string(d,len); +  break; +  case 1: +  res=make_shared_binary_string1((short*)d,len>>1); +  break; +  case 2: +  res=make_shared_binary_string2((int*)d,len>>2); +  break; +  default: +  fatal("Unknown size_sift %d\n", str->shift); +  } +  xfree( str->data ); +  } +  else +  { +  str->data = realloc( str->data, str->len+(1<<str->shift) ); +  { +  res = (struct pike_string *)str->data; +  res->len = len>>str->shift; +  res->size_shift = str->shift; +  res=low_end_shared_string( res ); +  } +  } +  str->data = 0; +  str->size = 0; +  str->len = 0; +  str->shift = 0; +  RETURN res; +  } +  +  INIT +  { +  struct Buffer_struct *str = THIS; +  str->data = 0; +  str->size = 0; +  str->len = 0; +  str->shift = 0; +  } +  +  EXIT +  { +  struct Buffer_struct *str = THIS; +  if( str->data ) +  xfree( str->data ); +  } + } +  + /* @endmodule */ +    void init_builtin(void)   {   INIT   }