factor/vm/strings.c

275 lines
6.5 KiB
C

#include "master.h"
CELL string_nth(F_STRING* string, CELL index)
{
/* If high bit is set, the most significant 16 bits of the char
come from the aux vector. The least significant bit of the
corresponding aux vector entry is negated, so that we can
XOR the two components together and get the original code point
back. */
CELL ch = bget(SREF(string,index));
if((ch & 0x80) == 0)
return ch;
else
{
F_BYTE_ARRAY *aux = untag_object(string->aux);
return (cget(BREF(aux,index * sizeof(u16))) << 7) ^ ch;
}
}
void set_string_nth_fast(F_STRING* string, CELL index, CELL ch)
{
bput(SREF(string,index),ch);
}
void set_string_nth_slow(F_STRING* string, CELL index, CELL ch)
{
F_BYTE_ARRAY *aux;
bput(SREF(string,index),(ch & 0x7f) | 0x80);
if(string->aux == F)
{
REGISTER_UNTAGGED(string);
/* We don't need to pre-initialize the
byte array with any data, since we
only ever read from the aux vector
if the most significant bit of a
character is set. Initially all of
the bits are clear. */
aux = allot_byte_array_internal(
untag_fixnum_fast(string->length)
* sizeof(u16));
UNREGISTER_UNTAGGED(string);
write_barrier((CELL)string);
string->aux = tag_object(aux);
}
else
aux = untag_object(string->aux);
cput(BREF(aux,index * sizeof(u16)),(ch >> 7) ^ 1);
}
/* allocates memory */
void set_string_nth(F_STRING* string, CELL index, CELL ch)
{
if(ch <= 0x7f)
set_string_nth_fast(string,index,ch);
else
set_string_nth_slow(string,index,ch);
}
/* untagged */
F_STRING* allot_string_internal(CELL capacity)
{
F_STRING *string = allot_object(STRING_TYPE,string_size(capacity));
string->length = tag_fixnum(capacity);
string->hashcode = F;
string->aux = F;
return string;
}
/* allocates memory */
void fill_string(F_STRING *string, CELL start, CELL capacity, CELL fill)
{
if(fill <= 0x7f)
memset((void *)SREF(string,start),fill,capacity - start);
else
{
CELL i;
for(i = start; i < capacity; i++)
{
REGISTER_UNTAGGED(string);
set_string_nth(string,i,fill);
UNREGISTER_UNTAGGED(string);
}
}
}
/* untagged */
F_STRING *allot_string(CELL capacity, CELL fill)
{
F_STRING* string = allot_string_internal(capacity);
REGISTER_UNTAGGED(string);
fill_string(string,0,capacity,fill);
UNREGISTER_UNTAGGED(string);
return string;
}
void primitive_string(void)
{
CELL initial = to_cell(dpop());
CELL length = unbox_array_size();
dpush(tag_object(allot_string(length,initial)));
}
F_STRING* reallot_string(F_STRING* string, CELL capacity)
{
CELL to_copy = string_capacity(string);
if(capacity < to_copy)
to_copy = capacity;
REGISTER_UNTAGGED(string);
F_STRING *new_string = allot_string_internal(capacity);
UNREGISTER_UNTAGGED(string);
memcpy(new_string + 1,string + 1,to_copy);
if(string->aux != F)
{
REGISTER_UNTAGGED(string);
REGISTER_UNTAGGED(new_string);
F_BYTE_ARRAY *new_aux = allot_byte_array(capacity * sizeof(u16));
UNREGISTER_UNTAGGED(new_string);
UNREGISTER_UNTAGGED(string);
write_barrier((CELL)new_string);
new_string->aux = tag_object(new_aux);
F_BYTE_ARRAY *aux = untag_object(string->aux);
memcpy(new_aux + 1,aux + 1,to_copy * sizeof(u16));
}
REGISTER_UNTAGGED(string);
REGISTER_UNTAGGED(new_string);
fill_string(new_string,to_copy,capacity,'\0');
UNREGISTER_UNTAGGED(new_string);
UNREGISTER_UNTAGGED(string);
return new_string;
}
void primitive_resize_string(void)
{
F_STRING* string = untag_string(dpop());
CELL capacity = unbox_array_size();
dpush(tag_object(reallot_string(string,capacity)));
}
/* Some ugly macros to prevent a 2x code duplication */
#define MEMORY_TO_STRING(type,utype) \
F_STRING *memory_to_##type##_string(const type *string, CELL length) \
{ \
REGISTER_C_STRING(string); \
F_STRING* s = allot_string_internal(length); \
UNREGISTER_C_STRING(string); \
CELL i; \
for(i = 0; i < length; i++) \
{ \
REGISTER_UNTAGGED(s); \
set_string_nth(s,i,(utype)*string); \
UNREGISTER_UNTAGGED(s); \
string++; \
} \
return s; \
} \
F_STRING *from_##type##_string(const type *str) \
{ \
CELL length = 0; \
const type *scan = str; \
while(*scan++) length++; \
return memory_to_##type##_string(str,length); \
} \
void box_##type##_string(const type *str) \
{ \
dpush(str ? tag_object(from_##type##_string(str)) : F); \
}
MEMORY_TO_STRING(char,u8)
MEMORY_TO_STRING(u16,u16)
MEMORY_TO_STRING(u32,u32)
bool check_string(F_STRING *s, CELL max)
{
CELL capacity = string_capacity(s);
CELL i;
for(i = 0; i < capacity; i++)
{
CELL ch = string_nth(s,i);
if(ch == '\0' || ch >= (1 << (max * 8)))
return false;
}
return true;
}
F_BYTE_ARRAY *allot_c_string(CELL capacity, CELL size)
{
return allot_byte_array((capacity + 1) * size);
}
#define STRING_TO_MEMORY(type) \
void type##_string_to_memory(F_STRING *s, type *string) \
{ \
CELL i; \
CELL capacity = string_capacity(s); \
for(i = 0; i < capacity; i++) \
string[i] = string_nth(s,i); \
} \
void primitive_##type##_string_to_memory(void) \
{ \
type *address = unbox_alien(); \
F_STRING *str = untag_string(dpop()); \
type##_string_to_memory(str,address); \
} \
F_BYTE_ARRAY *string_to_##type##_alien(F_STRING *s, bool check) \
{ \
CELL capacity = string_capacity(s); \
F_BYTE_ARRAY *_c_str; \
if(check && !check_string(s,sizeof(type))) \
general_error(ERROR_C_STRING,tag_object(s),F,NULL); \
REGISTER_UNTAGGED(s); \
_c_str = allot_c_string(capacity,sizeof(type)); \
UNREGISTER_UNTAGGED(s); \
type *c_str = (type*)(_c_str + 1); \
type##_string_to_memory(s,c_str); \
c_str[capacity] = 0; \
return _c_str; \
} \
type *to_##type##_string(F_STRING *s, bool check) \
{ \
return (type*)(string_to_##type##_alien(s,check) + 1); \
} \
type *unbox_##type##_string(void) \
{ \
return to_##type##_string(untag_string(dpop()),true); \
}
STRING_TO_MEMORY(char);
STRING_TO_MEMORY(u16);
void primitive_string_nth(void)
{
F_STRING *string = untag_object(dpop());
CELL index = untag_fixnum_fast(dpop());
dpush(tag_fixnum(string_nth(string,index)));
}
void primitive_set_string_nth(void)
{
F_STRING *string = untag_object(dpop());
CELL index = untag_fixnum_fast(dpop());
CELL value = untag_fixnum_fast(dpop());
set_string_nth(string,index,value);
}
void primitive_set_string_nth_fast(void)
{
F_STRING *string = untag_object(dpop());
CELL index = untag_fixnum_fast(dpop());
CELL value = untag_fixnum_fast(dpop());
set_string_nth_fast(string,index,value);
}
void primitive_set_string_nth_slow(void)
{
F_STRING *string = untag_object(dpop());
CELL index = untag_fixnum_fast(dpop());
CELL value = untag_fixnum_fast(dpop());
set_string_nth_slow(string,index,value);
}