1
0
mirror of https://github.com/janet-lang/janet synced 2024-06-16 18:29:56 +00:00

More work on cleaning up string implementation.

This commit is contained in:
Calvin Rose 2017-03-22 18:35:54 -04:00
parent 841ee3696d
commit 6365a007b6
11 changed files with 278 additions and 279 deletions

View File

@ -15,7 +15,7 @@ all: $(GST_TARGET)
##### The core vm and runtime #####
###################################
GST_CORE_SOURCES=$(addprefix core/,\
compile.c disasm.c parse.c stl.c strings.c stringcache.c\
compile.c disasm.c parse.c stl.c strings.c \
value.c vm.c ds.c gc.c thread.c serialize.c)
GST_CORE_OBJECTS=$(patsubst %.c,%.o,$(GST_CORE_SOURCES))
$(GST_CORELIB): $(GST_CORE_OBJECTS) $(GST_HEADERS)

View File

@ -1010,7 +1010,7 @@ typedef Slot (*SpecialFormHelper) (GstCompiler *c, FormOptions opts, GstValue *f
/* Dispatch to a special form */
static SpecialFormHelper get_special(GstValue *form) {
uint8_t *name;
const uint8_t *name;
if (gst_tuple_length(form) < 1 || form[0].type != GST_SYMBOL)
return NULL;
name = form[0].data.string;

View File

@ -42,7 +42,7 @@ void gst_buffer_push(Gst *vm, GstBuffer * buffer, uint8_t c) {
}
/* Push multiple bytes into the buffer */
void gst_buffer_append(Gst *vm, GstBuffer *buffer, uint8_t *string, uint32_t length) {
void gst_buffer_append(Gst *vm, GstBuffer *buffer, const uint8_t *string, uint32_t length) {
uint32_t newSize = buffer->count + length;
if (newSize > buffer->capacity) {
gst_buffer_ensure(vm, buffer, 2 * newSize);
@ -52,8 +52,8 @@ void gst_buffer_append(Gst *vm, GstBuffer *buffer, uint8_t *string, uint32_t len
}
/* Convert the buffer to a string */
uint8_t *gst_buffer_to_string(Gst *vm, GstBuffer *buffer) {
return gst_load_cstring_rawlen(vm, (char *) buffer->data, buffer->count);
const uint8_t *gst_buffer_to_string(Gst *vm, GstBuffer *buffer) {
return gst_string_loadbuffer(vm, buffer->data, buffer->count);
}
/****/
@ -218,39 +218,6 @@ GstValue gst_object_get(GstObject *o, GstValue key) {
}
}
/* Get a value of the object with a cstring key */
GstValue gst_object_get_cstring(GstObject *obj, const char *key) {
uint32_t len;
for (len = 0; key[len]; ++len);
uint32_t hash = gst_cstring_calchash((uint8_t *)key, len);
uint32_t index = hash % obj->capacity;
GstBucket *bucket = obj->buckets[index];
while (bucket) {
if (bucket->key.type == GST_STRING) {
uint8_t *s = bucket->key.data.string;
if (gst_string_length(s) == len) {
if (!gst_string_hash(s))
gst_string_hash(s) = gst_string_calchash(s);
if (gst_string_hash(s) == hash) {
uint32_t i;
for (i = 0; i < len; ++i)
if (s[i] != key[i])
goto notequal;
return bucket->value;
}
}
}
notequal:
bucket = bucket->next;
}
/* Return nil */
{
GstValue ret;
ret.type = GST_NIL;
return ret;
}
}
/* Remove an entry from the dictionary */
GstValue gst_object_remove(Gst * vm, GstObject *o, GstValue key) {
GstBucket *bucket, *previous;

View File

@ -219,8 +219,8 @@ static int check_str_const(const char *ref, const uint8_t *start, const uint8_t
static GstValue build_token(GstParser *p, GstBuffer *buf) {
GstValue x;
GstNumber number;
uint8_t * data = buf->data;
uint8_t * back = data + buf->count;
uint8_t *data = buf->data;
uint8_t *back = data + buf->count;
if (read_number(data, back, &number, 0)) {
x.type = GST_NUMBER;
x.data.number = number;
@ -453,7 +453,7 @@ int gst_parse_cstring(GstParser *p, const char *string) {
}
/* Parse a gst string */
int gst_parse_string(GstParser *p, uint8_t *string) {
int gst_parse_string(GstParser *p, const uint8_t *string) {
uint32_t i;
p->status = GST_PARSER_PENDING;
for (i = 0; i < gst_string_length(string); ++i) {

View File

@ -34,7 +34,7 @@
static const char UEB[] = "unexpected end of buffer";
/* Read 4 bytes as an unsigned integer */
static uint32_t bytes2u32(uint8_t *bytes) {
static uint32_t bytes2u32(const uint8_t *bytes) {
union {
uint8_t bytes[4];
uint32_t u32;
@ -44,7 +44,7 @@ static uint32_t bytes2u32(uint8_t *bytes) {
}
/* Read 2 bytes as unsigned short */
static uint16_t bytes2u16(uint8_t *bytes) {
static uint16_t bytes2u16(const uint8_t *bytes) {
union {
uint8_t bytes[2];
uint16_t u16;
@ -54,7 +54,7 @@ static uint16_t bytes2u16(uint8_t *bytes) {
}
/* Read 8 bytes as a double */
static uint32_t bytes2dbl(uint8_t *bytes) {
static uint32_t bytes2dbl(const uint8_t *bytes) {
union {
uint8_t bytes[8];
double dbl;
@ -69,16 +69,16 @@ static uint32_t bytes2dbl(uint8_t *bytes) {
* passed by reference. */
static const char *gst_deserialize_impl(
Gst *vm,
uint8_t *data,
uint8_t *end,
uint8_t **newData,
const uint8_t *data,
const uint8_t *end,
const uint8_t **newData,
GstArray *visited,
GstValue *out) {
GstValue ret;
ret.type = GST_NIL;
GstValue *buffer;
uint8_t *bytebuf;
const uint8_t *bytebuf;
uint32_t length, i;
const char *err;
@ -135,12 +135,7 @@ static const char *gst_deserialize_impl(
ret.type = data[-1] == 205 ? GST_STRING : GST_SYMBOL;
read_u32(length);
deser_datacheck(length);
ret.data.string = gst_alloc(vm, 2 * sizeof(uint32_t) + length + 1);
ret.data.string += 2 * sizeof(uint32_t);
gst_string_length(ret.data.string) = length;
gst_string_hash(ret.data.string) = 0;
gst_memcpy(ret.data.string, data, length);
ret.data.string[length] = 0;
ret.data.string = gst_string_loadbuffer(vm, data, length);
data += length;
gst_array_push(vm, visited, ret);
break;
@ -151,7 +146,7 @@ static const char *gst_deserialize_impl(
deser_datacheck(length);
ret.data.buffer = gst_alloc(vm, sizeof(GstBuffer));
ret.data.buffer->data = gst_alloc(vm, length);
gst_memcpy(ret.data.string, data, length);
gst_memcpy(ret.data.buffer->data, data, length);
ret.data.buffer->count = length;
ret.data.buffer->capacity = length;
data += length;
@ -391,10 +386,10 @@ static const char *gst_deserialize_impl(
/* Load a value from data */
const char *gst_deserialize(
Gst *vm,
uint8_t *data,
const uint8_t *data,
uint32_t len,
GstValue *out,
uint8_t *nextData) {
const uint8_t *nextData) {
GstValue ret;
const char *err;
GstArray *visited = gst_array(vm, 10);

View File

@ -13,7 +13,7 @@ int gst_stl_print(Gst *vm) {
count = gst_count_args(vm);
for (j = 0; j < count; ++j) {
uint32_t i;
uint8_t *string = gst_to_string(vm, gst_arg(vm, j));
const uint8_t *string = gst_to_string(vm, gst_arg(vm, j));
uint32_t len = gst_string_length(string);
for (i = 0; i < len; ++i)
fputc(string[i], stdout);
@ -46,7 +46,7 @@ int gst_stl_make_buffer(Gst *vm) {
buf.data.buffer = gst_buffer(vm, 10);
count = gst_count_args(vm);
for (i = 0; i < count; ++i) {
uint8_t *string = gst_to_string(vm, gst_arg(vm, i));
const uint8_t *string = gst_to_string(vm, gst_arg(vm, i));
gst_buffer_append(vm, buf.data.buffer, string, gst_string_length(string));
}
gst_c_return(vm, buf);
@ -55,7 +55,7 @@ int gst_stl_make_buffer(Gst *vm) {
/* To string */
int gst_stl_tostring(Gst *vm) {
GstValue ret;
uint8_t *string = gst_to_string(vm, gst_arg(vm, 0));
const uint8_t *string = gst_to_string(vm, gst_arg(vm, 0));
ret.type = GST_STRING;
ret.data.string = string;
gst_c_return(vm, ret);
@ -147,8 +147,8 @@ static int read_number(const uint8_t *string, const uint8_t *end, double *ret, i
int gst_stl_parse_number(Gst *vm) {
GstValue ret;
double number;
uint8_t *str = gst_to_string(vm, gst_arg(vm, 0));
uint8_t *end = str + gst_string_length(str);
const uint8_t *str = gst_to_string(vm, gst_arg(vm, 0));
const uint8_t *end = str + gst_string_length(str);
if (read_number(str, end, &number, 0)) {
ret.type = GST_NUMBER;
ret.data.number = number;
@ -161,7 +161,7 @@ int gst_stl_parse_number(Gst *vm) {
/* Parse a source string into an AST */
int gst_stl_parse(Gst *vm) {
uint8_t *source = gst_to_string(vm, gst_arg(vm, 0));
const uint8_t *source = gst_to_string(vm, gst_arg(vm, 0));
GstParser p;
/* init state */
gst_parser(&p, vm);

View File

@ -1,120 +0,0 @@
#include <gst/gst.h>
#include "stringcache.h"
/* Dud pointer to serve as deletion marker */
static uint8_t *deleted = (uint8_t *) "DELETED";
/* Initialize the string cache for a vm */
void gst_stringcache_init(Gst *vm, uint32_t capacity) {
vm->strings = gst_raw_calloc(1, capacity * sizeof(uint8_t *));
if (vm->strings == NULL)
GST_OUT_OF_MEMORY;
vm->stringsCapacity = capacity;
vm->stringsCount = 0;
vm->stringsDeleted = 0;
}
/* Deinitialize the stringcache for a vm */
void gst_stringcache_deinit(Gst *vm) {
gst_raw_free(vm->strings);
vm->stringsCapacity = 0;
vm->stringsCount = 0;
vm->stringsDeleted = 0;
}
/* Find a string in the hashtable. Returns null if
* not found. */
static uint8_t **gst_stringcache_find(Gst *vm, uint8_t *str, int *success) {
uint32_t bounds[4];
uint32_t i, j, index, hash;
uint8_t **firstEmpty = NULL;
hash = gst_string_hash(str);
if (!hash) {
hash = gst_string_hash(str) = gst_string_calchash(str);
}
index = hash % vm->stringsCapacity;
bounds[0] = index;
bounds[1] = vm->stringsCapacity;
bounds[2] = 0;
bounds[3] = index;
for (j = 0; j < 4; j += 2)
for (i = bounds[j]; i < bounds[j+1]; ++i) {
uint8_t *testStr = vm->strings[i];
/* Check empty spots */
if (testStr == NULL) {
if (firstEmpty == NULL)
firstEmpty = vm->strings + i;
goto notfound;
}
if (testStr == deleted) {
if (firstEmpty == NULL)
firstEmpty = vm->strings + i;
continue;
}
if (gst_string_equal(testStr, str)) {
/* Replace first deleted */
*success = 1;
if (firstEmpty != NULL) {
*firstEmpty = testStr;
vm->strings[i] = deleted;
return firstEmpty;
}
return vm->strings + i;
}
}
notfound:
*success = 0;
return firstEmpty;
}
/* Resize the hashtable. */
static void gst_stringcache_resize(Gst *vm, uint32_t newCapacity) {
uint32_t i, oldCapacity;
uint8_t **oldCache = vm->strings;
uint8_t **newCache = gst_raw_calloc(1, newCapacity * sizeof(uint8_t *));
if (newCache == NULL)
GST_OUT_OF_MEMORY;
oldCapacity = vm->stringsCapacity;
vm->strings = newCache;
vm->stringsCapacity = newCapacity;
vm->stringsCount = 0;
vm->stringsDeleted = 0;
/* Add all of the old strings back */
for (i = 0; i < oldCapacity; ++i) {
uint8_t *str = oldCache[i];
if (str != NULL && str != deleted)
gst_stringcache_get(vm, str);
}
/* Free the old cache */
gst_raw_free(oldCache);
}
/* Get a string from the string cache */
uint8_t *gst_stringcache_get(Gst *vm, uint8_t *str) {
int status = 0;
uint8_t **bucket = gst_stringcache_find(vm, str, &status);
if (status) {
return *bucket;
} else {
if ((vm->stringsCount + vm->stringsDeleted) * 2 > vm->stringsCapacity) {
gst_stringcache_resize(vm, vm->stringsCount * 4);
bucket = gst_stringcache_find(vm, str, &status);
}
vm->stringsCount++;
*bucket = str;
/* Mark the memory as string memory */
gst_mem_tag(gst_string_raw(str), GST_MEMTAG_STRING);
return str;
}
}
/* Remove a string from the cache */
void gst_stringcache_remove(Gst *vm, uint8_t *str) {
int status = 0;
uint8_t **bucket = gst_stringcache_find(vm, str, &status);
if (status) {
vm->stringsCount--;
vm->stringsDeleted++;
*bucket = deleted;
}
}

View File

@ -9,7 +9,6 @@
void gst_stringcache_init(Gst *vm, uint32_t capacity);
void gst_stringcache_deinit(Gst *vm);
uint8_t *gst_stringcache_get(Gst *vm, uint8_t *str);
void gst_stringcache_remove(Gst *vm, uint8_t *str);
void gst_stringcache_remove(Gst *vm, const uint8_t *str);
#endif

View File

@ -1,35 +1,28 @@
#include <gst/gst.h>
#include "stringcache.h"
uint8_t *gst_load_cstring_rawlen(Gst *vm, const char *string, uint32_t len) {
uint8_t *data = gst_alloc(vm, len + 1 + 2 * sizeof(uint32_t));
data += 2 * sizeof(uint32_t);
gst_string_hash(data) = 0;
gst_string_length(data) = len;
gst_memcpy(data, string, len);
data[len] = 0;
/* Check string cache */
return gst_stringcache_get(vm, data);
}
/* Dud pointer to serve as deletion marker */
static uint8_t *deleted = (uint8_t *) "";
/* Load a c string into a GST string */
GstValue gst_load_cstring(Gst *vm, const char *string) {
GstValue ret;
ret.type = GST_STRING;
ret.data.string = gst_load_cstring_rawlen(vm, string, strlen(string));
return ret;
}
/* Load a c string into a GST symbol */
GstValue gst_load_csymbol(Gst *vm, const char *string) {
GstValue ret;
ret.type = GST_SYMBOL;
ret.data.string = gst_load_cstring_rawlen(vm, string, strlen(string));
return ret;
/* Check if string and cstring are equal */
/* To check if strings are equal externally, one can
* just use == */
static int gst_cstring_equal(const uint8_t *lhs, const uint8_t *rhs, uint32_t rlen, uint32_t rhash) {
uint32_t lhash, len, i;
/* Check lengths */
len = gst_string_length(lhs);
if (len != rlen) return 0;
/* Check hashes */
lhash = gst_string_hash(lhs);
if (lhash != rhash) return 0;
for (i = 0; i < len; ++i)
if (lhs[i] != rhs[i])
return 0;
return 1;
}
/* Simple hash function (djb2) */
uint32_t gst_cstring_calchash(const uint8_t *str, uint32_t len) {
static uint32_t gst_string_calchash(const uint8_t *str, uint32_t len) {
const uint8_t *end = str + len;
uint32_t hash = 5381;
while (str < end)
@ -37,31 +30,202 @@ uint32_t gst_cstring_calchash(const uint8_t *str, uint32_t len) {
return hash;
}
/* GST string version */
uint32_t gst_string_calchash(const uint8_t *str) {
return gst_cstring_calchash(str, gst_string_length(str));
/* Find a string in the hashtable. Returns null if
* not found. */
static const uint8_t **gst_stringcache_find(
Gst *vm,
const uint8_t *str,
uint32_t len,
uint32_t hash,
int *success) {
uint32_t bounds[4];
uint32_t i, j, index;
const uint8_t **firstEmpty = NULL;
index = hash % vm->stringsCapacity;
bounds[0] = index;
bounds[1] = vm->stringsCapacity;
bounds[2] = 0;
bounds[3] = index;
for (j = 0; j < 4; j += 2)
for (i = bounds[j]; i < bounds[j+1]; ++i) {
const uint8_t *testStr = vm->strings[i];
/* Check empty spots */
if (testStr == NULL) {
if (firstEmpty == NULL)
firstEmpty = vm->strings + i;
goto notfound;
}
if (testStr == deleted) {
if (firstEmpty == NULL)
firstEmpty = vm->strings + i;
continue;
}
if (gst_cstring_equal(testStr, str, len, hash)) {
/* Replace first deleted */
*success = 1;
if (firstEmpty != NULL) {
*firstEmpty = testStr;
vm->strings[i] = deleted;
return firstEmpty;
}
return vm->strings + i;
}
}
notfound:
*success = 0;
return firstEmpty;
}
/* Check if two strings are equal. Does not check the string cache. */
int gst_string_equal(const uint8_t *lhs, const uint8_t *rhs) {
uint32_t hash_l, hash_r, len, i;
if (lhs == rhs)
return 1;
/* Check lengths */
len = gst_string_length(lhs);
if (len != gst_string_length(rhs)) return 0;
/* Check hashes */
hash_l = gst_string_hash(lhs);
hash_r = gst_string_hash(rhs);
if (!hash_l)
hash_l = gst_string_hash(lhs) = gst_string_calchash(lhs);
if (!hash_r)
hash_r = gst_string_hash(rhs) = gst_string_calchash(rhs);
if (hash_l != hash_r) return 0;
for (i = 0; i < len; ++i)
if (lhs[i] != rhs[i])
return 0;
return 1;
/* Resize the hashtable. */
static void gst_stringcache_resize(Gst *vm, uint32_t newCapacity) {
uint32_t i, oldCapacity;
const uint8_t **oldCache = vm->strings;
const uint8_t **newCache = gst_raw_calloc(1, newCapacity * sizeof(uint8_t *));
if (newCache == NULL)
GST_OUT_OF_MEMORY;
oldCapacity = vm->stringsCapacity;
vm->strings = newCache;
vm->stringsCapacity = newCapacity;
vm->stringsDeleted = 0;
/* Add all of the old strings back */
for (i = 0; i < oldCapacity; ++i) {
int status;
const uint8_t **bucket;
const uint8_t *str = oldCache[i];
if (str != NULL && str != deleted) {
bucket = gst_stringcache_find(vm, str,
gst_string_length(str),
gst_string_hash(str), &status);
if (status || bucket == NULL) {
/* there was a problem with the algorithm. */
break;
}
*bucket = str;
}
}
/* Free the old cache */
gst_raw_free(oldCache);
}
/****/
/* Internal API */
/****/
/* Initialize the string cache for a vm */
void gst_stringcache_init(Gst *vm, uint32_t capacity) {
vm->strings = gst_raw_calloc(1, capacity * sizeof(uint8_t *));
if (vm->strings == NULL)
GST_OUT_OF_MEMORY;
vm->stringsCapacity = capacity;
vm->stringsCount = 0;
vm->stringsDeleted = 0;
}
/* Deinitialize the stringcache for a vm */
void gst_stringcache_deinit(Gst *vm) {
gst_raw_free(vm->strings);
vm->stringsCapacity = 0;
vm->stringsCount = 0;
vm->stringsDeleted = 0;
}
/* Remove a string from the cache */
void gst_stringcache_remove(Gst *vm, const uint8_t *str) {
int status = 0;
const uint8_t **bucket = gst_stringcache_find(vm, str,
gst_string_length(str),
gst_string_hash(str),
&status);
if (status) {
vm->stringsCount--;
vm->stringsDeleted++;
*bucket = deleted;
}
}
/****/
/* Public C API */
/****/
/* Begin creation of a string */
uint8_t *gst_string_begin(Gst *vm, uint32_t len) {
uint8_t *data = gst_alloc(vm, len + 1 + 2 * sizeof(uint32_t));
data += 2 * sizeof(uint32_t);
gst_string_length(data) = len;
data[len] = 0;
return data;
}
/* Finish building the string. Calculates the hash and deduplicates it */
const uint8_t *gst_string_end(Gst *vm, uint8_t *str) {
int status = 0;
const uint8_t **bucket;
uint32_t hash, len;
len = gst_string_length(str);
hash = gst_string_hash(str) = gst_string_calchash(str, len);
bucket = gst_stringcache_find(vm, str, len, hash, &status);
if (status) {
return *bucket;
} else {
if ((vm->stringsCount + vm->stringsDeleted) * 2 > vm->stringsCapacity) {
gst_stringcache_resize(vm, vm->stringsCount * 4);
bucket = gst_stringcache_find(vm, str, len, hash, &status);
}
/* Mark the memory as string memory */
gst_mem_tag(gst_string_raw(str), GST_MEMTAG_STRING);
vm->stringsCount++;
*bucket = str;
return str;
}
}
/* Loads a constant buffer as a string into a gst vm */
const uint8_t *gst_string_loadbuffer(Gst *vm, const uint8_t *buf, uint32_t len) {
int status = 0;
const uint8_t **bucket;
uint32_t hash;
hash = gst_string_calchash(buf, len);
bucket = gst_stringcache_find(vm, buf, len, hash, &status);
if (status) {
return *bucket;
} else {
uint8_t *str;
if ((vm->stringsCount + vm->stringsDeleted) * 2 > vm->stringsCapacity) {
gst_stringcache_resize(vm, vm->stringsCount * 4);
bucket = gst_stringcache_find(vm, buf, len, hash, &status);
}
vm->stringsCount++;
str = gst_string_begin(vm, len);
gst_memcpy(str, buf, len);
gst_string_hash(str) = hash;
/* Mark the memory as string memory */
gst_mem_tag(gst_string_raw(str), GST_MEMTAG_STRING);
*bucket = str;
return str;
}
}
/* Converts a c style string to a gst string */
const uint8_t *gst_cstring_to_string(Gst *vm, const char *cstring) {
uint32_t len = 0;
while (cstring[len]) ++len;
return gst_string_loadbuffer(vm, (const uint8_t *)cstring, len);
}
/* Load a c string into a GST string */
GstValue gst_load_cstring(Gst *vm, const char *string) {
GstValue ret;
ret.type = GST_STRING;
ret.data.string = gst_cstring_to_string(vm, string);
return ret;
}
/* Load a c string into a GST symbol */
GstValue gst_load_csymbol(Gst *vm, const char *string) {
GstValue ret;
ret.type = GST_SYMBOL;
ret.data.string = gst_cstring_to_string(vm, string);
return ret;
}
/* Compares two strings */

View File

@ -105,12 +105,12 @@ GstValue *gst_thread_expand_callable(Gst *vm, GstThread *thread, GstValue callee
meta = callee.data.object->meta;
if (meta == NULL) return NULL;
gst_thread_push(vm, thread, callee);
callee = gst_object_get_cstring(meta, "call");
callee = gst_object_get(meta, gst_load_cstring(vm, "call"));
continue;
case GST_USERDATA:
meta = ((GstUserdataHeader *)callee.data.pointer - 1)->meta;
gst_thread_push(vm, thread, callee);
callee = gst_object_get_cstring(meta, "call");
callee = gst_object_get(meta, gst_load_cstring(vm, "call"));
continue;
}
}

View File

@ -6,90 +6,86 @@ int gst_truthy(GstValue v) {
return v.type != GST_NIL && !(v.type == GST_BOOLEAN && !v.data.boolean);
}
static uint8_t * number_to_string(Gst *vm, GstNumber x) {
static const uint32_t SIZE = 20;
uint8_t *data = gst_alloc(vm, SIZE + 1 + 2 * sizeof(uint32_t));
data += 2 * sizeof(uint32_t);
/* Temporary buffer size */
#define GST_BUFSIZE 36
static const uint8_t *number_to_string(Gst *vm, GstNumber x) {
uint8_t buf[GST_BUFSIZE];
/* TODO - not depend on stdio */
snprintf((char *) data, SIZE, "%.21g", x);
gst_string_hash(data) = 0;
gst_string_length(data) = strlen((char *) data);
return data;
int count = snprintf((char *) buf, GST_BUFSIZE, "%.21g", x);
return gst_string_loadbuffer(vm, buf, (uint32_t) count);
}
static const char *HEX_CHARACTERS = "0123456789abcdef";
#define HEX(i) (((uint8_t *) HEX_CHARACTERS)[(i)])
/* Returns a string description for a pointer */
static uint8_t *string_description(Gst *vm, const char *title, uint32_t titlelen, void *pointer) {
uint32_t len = 5 + titlelen + sizeof(void *) * 2;
/* Returns a string description for a pointer. Max titlelen is GST_BUFSIZE
* - 5 - 2 * sizeof(void *). */
static const uint8_t *string_description(Gst *vm, const char *title, void *pointer) {
uint8_t buf[GST_BUFSIZE];
uint8_t *c = buf;
uint32_t i;
uint8_t *data = gst_alloc(vm, len + 1 + 2 * sizeof(uint32_t));
uint8_t *c;
union {
uint8_t bytes[sizeof(void *)];
void *p;
} buf;
buf.p = pointer;
data += 2 * sizeof(uint32_t);
c = data;
} pbuf;
pbuf.p = pointer;
*c++ = '<';
for (i = 0; i < titlelen; ++i) {
for (i = 0; title[i]; ++i)
*c++ = ((uint8_t *)title) [i];
}
*c++ = ' ';
*c++ = '0';
*c++ = 'x';
for (i = sizeof(void *); i > 0; --i) {
uint8_t byte = buf.bytes[i - 1];
uint8_t byte = pbuf.bytes[i - 1];
if (!byte) continue;
*c++ = HEX(byte >> 4);
*c++ = HEX(byte & 0xF);
}
*c++ = '>';
gst_string_hash(data) = 0;
gst_string_length(data) = c - data;
*c = 0;
return data;
return gst_string_loadbuffer(vm, buf, c - buf);
}
#undef GST_BUFSIZE
/* Returns a string pointer or NULL if could not allocate memory. */
uint8_t *gst_to_string(Gst *vm, GstValue x) {
const uint8_t *gst_to_string(Gst *vm, GstValue x) {
switch (x.type) {
case GST_NIL:
return gst_load_cstring_rawlen(vm, "nil", 3);
return gst_cstring_to_string(vm, "nil");
case GST_BOOLEAN:
if (x.data.boolean) {
return gst_load_cstring_rawlen(vm, "true", 4);
return gst_cstring_to_string(vm, "true");
} else {
return gst_load_cstring_rawlen(vm, "false", 5);
return gst_cstring_to_string(vm, "false");
}
case GST_NUMBER:
return number_to_string(vm, x.data.number);
case GST_ARRAY:
return string_description(vm, "array", 5, x.data.pointer);
return string_description(vm, "array", x.data.pointer);
case GST_TUPLE:
return string_description(vm, "tuple", 5, x.data.pointer);
return string_description(vm, "tuple", x.data.pointer);
case GST_OBJECT:
return string_description(vm, "object", 6, x.data.pointer);
return string_description(vm, "object", x.data.pointer);
case GST_STRING:
return x.data.string;
case GST_SYMBOL:
return string_description(vm, "symbol", 6, x.data.pointer);
return string_description(vm, "symbol", x.data.pointer);
case GST_BYTEBUFFER:
return string_description(vm, "buffer", 6, x.data.pointer);
return string_description(vm, "buffer", x.data.pointer);
case GST_CFUNCTION:
return string_description(vm, "cfunction", 9, x.data.pointer);
return string_description(vm, "cfunction", x.data.pointer);
case GST_FUNCTION:
return string_description(vm, "function", 8, x.data.pointer);
return string_description(vm, "function", x.data.pointer);
case GST_THREAD:
return string_description(vm, "thread", 6, x.data.pointer);
return string_description(vm, "thread", x.data.pointer);
case GST_USERDATA:
return string_description(vm, "userdata", 8, x.data.pointer);
return string_description(vm, "userdata", x.data.pointer);
case GST_FUNCENV:
return string_description(vm, "funcenv", 7, x.data.pointer);
return string_description(vm, "funcenv", x.data.pointer);
case GST_FUNCDEF:
return string_description(vm, "funcdef", 7, x.data.pointer);
return string_description(vm, "funcdef", x.data.pointer);
}
return NULL;
}
@ -173,10 +169,7 @@ uint32_t gst_hash(GstValue x) {
/* String hashes */
case GST_STRING:
case GST_SYMBOL:
/* Assume 0 is not hashed. */
hash = gst_string_hash(x.data.string);
if (!hash)
hash = gst_string_hash(x.data.string) = gst_string_calchash(x.data.string);
break;
case GST_TUPLE:
if (gst_tuple_hash(x.data.tuple))
@ -418,8 +411,9 @@ int gst_length(Gst *vm, GstValue x, GstValue *len) {
case GST_OBJECT:
/* TODO - Check for class override */
if (x.data.object->meta != NULL) {
GstValue check = gst_object_get_cstring(
x.data.object->meta, "length");
GstValue check = gst_object_get(
x.data.object->meta,
gst_load_cstring(vm, "length"));
if (check.type != GST_NIL) {
int status = gst_call(vm, check, 1, &x);
if (status == GST_RETURN_OK)