Add ability to index into structs and dictionaries generically.

This commit is contained in:
Calvin Rose 2018-09-09 12:13:32 -04:00
parent 08dd06918e
commit 56c3b8aa94
7 changed files with 66 additions and 46 deletions

View File

@ -70,7 +70,8 @@ static char *decode_utf16_escape(const char *p, uint32_t *outpoint) {
return NULL;
}
/* Parse a string */
/* Parse a string. Also handles the conversion of utf-16 to
* utf-8. */
const char *decode_string(const char **p, Janet *out) {
JanetBuffer *buffer = janet_buffer(0);
const char *cp = *p;
@ -571,7 +572,7 @@ static int json_encode(JanetArgs args) {
JANET_ARG_BYTES(e.newline, e.newlinelen, args, 2);
} else {
e.newline = (const uint8_t *)"\r\n";
e.newlinelen = 1;
e.newlinelen = 2;
}
}
const char *err = encode_one(&e, args.v[0], 0);

View File

@ -77,8 +77,7 @@ static int sql_open(JanetArgs args) {
static int sql_close(JanetArgs args) {
Db *db;
JANET_FIXARITY(args, 1);
JANET_CHECKABSTRACT(args, 0, &sql_conn_type);
db = (Db *)janet_unwrap_abstract(args.v[0]);
JANET_ARG_ABSTRACT(db, args, 0, &sql_conn_type);
closedb(db);
JANET_RETURN_NIL(args);
}

View File

@ -24,8 +24,6 @@
#include "gc.h"
#include "util.h"
#define janet_struct_maphash(cap, hash) ((uint32_t)(hash & (cap - 1)));
/* Begin creation of a struct */
JanetKV *janet_struct_begin(int32_t count) {
@ -43,10 +41,11 @@ JanetKV *janet_struct_begin(int32_t count) {
return st;
}
/* Find an item in a struct */
/* Find an item in a struct. Should be similar to janet_dict_find, but
* specialized to structs (slightly more compact). */
const JanetKV *janet_struct_find(const JanetKV *st, Janet key) {
int32_t cap = janet_struct_capacity(st);
int32_t index = janet_struct_maphash(cap, janet_hash(key));
int32_t index = janet_maphash(cap, janet_hash(key));
int32_t i;
for (i = index; i < cap; i++)
if (janet_checktype(st[i].key, JANET_NIL) || janet_equals(st[i].key, key))
@ -68,7 +67,7 @@ const JanetKV *janet_struct_find(const JanetKV *st, Janet key) {
void janet_struct_put(JanetKV *st, Janet key, Janet value) {
int32_t cap = janet_struct_capacity(st);
int32_t hash = janet_hash(key);
int32_t index = janet_struct_maphash(cap, hash);
int32_t index = janet_maphash(cap, hash);
int32_t i, j, dist;
int32_t bounds[4] = {index, cap, 0, index};
if (janet_checktype(key, JANET_NIL) || janet_checktype(value, JANET_NIL)) return;
@ -95,7 +94,7 @@ void janet_struct_put(JanetKV *st, Janet key, Janet value) {
* will compare properly - i.e., {1 2 3 4} should equal {3 4 1 2}.
* Collisions are resolved via an insertion sort insertion. */
otherhash = janet_hash(kv->key);
otherindex = janet_struct_maphash(cap, otherhash);
otherindex = janet_maphash(cap, otherhash);
otherdist = (i + cap - otherindex) & (cap - 1);
if (dist < otherdist)
status = -1;
@ -231,4 +230,4 @@ int janet_struct_compare(const JanetKV *lhs, const JanetKV *rhs) {
return 0;
}
#undef janet_struct_maphash
#undef janet_maphash

View File

@ -24,8 +24,6 @@
#include "gc.h"
#include "util.h"
#define janet_table_maphash(cap, hash) ((uint32_t)(hash) & (cap - 1))
/* Initialize a table */
JanetTable *janet_table_init(JanetTable *table, int32_t capacity) {
JanetKV *data;
@ -61,36 +59,7 @@ JanetTable *janet_table(int32_t capacity) {
/* Find the bucket that contains the given key. Will also return
* bucket where key should go if not in the table. */
JanetKV *janet_table_find(JanetTable *t, Janet key) {
int32_t index = janet_table_maphash(t->capacity, janet_hash(key));
int32_t i;
JanetKV *first_bucket = NULL;
/* Higher half */
for (i = index; i < t->capacity; i++) {
JanetKV *kv = t->data + i;
if (janet_checktype(kv->key, JANET_NIL)) {
if (janet_checktype(kv->value, JANET_NIL)) {
return kv;
} else if (NULL == first_bucket) {
first_bucket = kv;
}
} else if (janet_equals(kv->key, key)) {
return t->data + i;
}
}
/* Lower half */
for (i = 0; i < index; i++) {
JanetKV *kv = t->data + i;
if (janet_checktype(kv->key, JANET_NIL)) {
if (janet_checktype(kv->value, JANET_NIL)) {
return kv;
} else if (NULL == first_bucket) {
first_bucket = kv;
}
} else if (janet_equals(kv->key, key)) {
return t->data + i;
}
}
return first_bucket;
return (JanetKV *) janet_dict_find(t->data, t->capacity, key);
}
/* Resize the dictionary table. */
@ -298,4 +267,4 @@ int janet_lib_table(JanetArgs args) {
return 0;
}
#undef janet_table_maphash
#undef janet_maphash

View File

@ -95,6 +95,50 @@ int32_t janet_tablen(int32_t n) {
return n + 1;
}
/* Helper to find a value in a Janet struct or table. Returns the bucket
* containg the key, or the first empty bucket if there is no such key. */
const JanetKV *janet_dict_find(const JanetKV *buckets, int32_t cap, Janet key) {
int32_t index = janet_maphash(cap, janet_hash(key));
int32_t i;
const JanetKV *first_bucket = NULL;
/* Higher half */
for (i = index; i < cap; i++) {
const JanetKV *kv = buckets + i;
if (janet_checktype(kv->key, JANET_NIL)) {
if (janet_checktype(kv->value, JANET_NIL)) {
return kv;
} else if (NULL == first_bucket) {
first_bucket = kv;
}
} else if (janet_equals(kv->key, key)) {
return buckets + i;
}
}
/* Lower half */
for (i = 0; i < index; i++) {
const JanetKV *kv = buckets + i;
if (janet_checktype(kv->key, JANET_NIL)) {
if (janet_checktype(kv->value, JANET_NIL)) {
return kv;
} else if (NULL == first_bucket) {
first_bucket = kv;
}
} else if (janet_equals(kv->key, key)) {
return buckets + i;
}
}
return first_bucket;
}
/* Get a value from a janet struct or table. */
Janet janet_dictionary_get(const JanetKV *data, int32_t cap, Janet key) {
const JanetKV *kv = janet_dict_find(data, cap, key);
if (kv && !janet_checktype(kv->key, JANET_NIL)) {
return kv->value;
}
return janet_wrap_nil();
}
/* Compare a janet string with a cstring. more efficient than loading
* c string as a janet string. */
int janet_cstrcmp(const uint8_t *str, const char *other) {

View File

@ -26,12 +26,15 @@
#include <janet/janet.h>
/* Utils */
#define janet_maphash(cap, hash) ((uint32_t)(hash) & (cap - 1))
extern const char janet_base64[65];
int32_t janet_array_calchash(const Janet *array, int32_t len);
int32_t janet_kv_calchash(const JanetKV *kvs, int32_t len);
int32_t janet_string_calchash(const uint8_t *str, int32_t len);
int32_t janet_tablen(int32_t n);
void janet_buffer_push_types(JanetBuffer *buffer, int types);
const JanetKV *janet_dict_find(const JanetKV *buckets, int32_t cap, Janet key);
Janet janet_dict_get(const JanetKV *buckets, int32_t cap, Janet key);
const void *janet_strbinsearch(
const void *tab,
size_t tabcount,

View File

@ -1001,6 +1001,7 @@ JANET_API JanetFiber *janet_fiber(JanetFunction *callee, int32_t capacity);
JANET_API int janet_indexed_view(Janet seq, const Janet **data, int32_t *len);
JANET_API int janet_bytes_view(Janet str, const uint8_t **data, int32_t *len);
JANET_API int janet_dictionary_view(Janet tab, const JanetKV **data, int32_t *len, int32_t *cap);
JANET_API Janet janet_dictionary_get(const JanetKV *data, int32_t cap, Janet key);
/* Abstract */
#define janet_abstract_header(u) ((JanetAbstractHeader *)(u) - 1)
@ -1100,7 +1101,7 @@ JANET_API int janet_typeabstract_err(JanetArgs args, int32_t n, const JanetAbstr
Janet x = (A).v[(N)];\
if (!janet_checktype(x, JANET_ABSTRACT) ||\
janet_abstract_type(janet_unwrap_abstract(x)) != (AT))\
return janet_typeabstract_err(A, N, AT);\
return janet_typeabstract_err(A, N, AT);\
} else {\
return janet_typeabstract_err(A, N, AT);\
}\
@ -1154,7 +1155,11 @@ JANET_API int janet_typeabstract_err(JanetArgs args, int32_t n, const JanetAbstr
#define JANET_ARG_BUFFER(DEST, A, N) _JANET_ARG(JANET_BUFFER, buffer, DEST, A, N)
#define JANET_ARG_FUNCTION(DEST, A, N) _JANET_ARG(JANET_FUNCTION, function, DEST, A, N)
#define JANET_ARG_CFUNCTION(DEST, A, N) _JANET_ARG(JANET_CFUNCTION, cfunction, DEST, A, N)
#define JANET_ARG_ABSTRACT(DEST, A, N) _JANET_ARG(JANET_ABSTRACT, abstract, DEST, A, N)
#define JANET_ARG_ABSTRACT(DEST, A, N, AT) do { \
JANET_CHECKABSTRACT(A, N, AT); \
DEST = janet_unwrap_abstract((A).v[(N)]); \
} while (0)
#define JANET_RETURN_NIL(A) do { return JANET_SIGNAL_OK; } while (0)
#define JANET_RETURN_FALSE(A) JANET_RETURN(A, janet_wrap_false())