pike.git/
src/
builtin.cmod
Branch:
Tag:
Non-build tags
All tags
No tags
2001-06-19
2001-06-19 22:48:14 by Per Hedbor <ph@opera.com>
a3c4337ef2bce44dd3650a47d9c2b9e784f1e725 (
341
lines) (+
340
/-
1
)
[
Show
|
Annotate
]
Branch:
7.9
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 }