benchmark encoders and speed them up
This commit is contained in:
405
benches/encoders.cm
Normal file
405
benches/encoders.cm
Normal file
@@ -0,0 +1,405 @@
|
||||
// encoders.cm — nota/wota/json encode+decode benchmark
|
||||
// Isolates per-type bottlenecks across all three serializers.
|
||||
|
||||
var nota = use('nota')
|
||||
var wota = use('wota')
|
||||
var json = use('json')
|
||||
|
||||
// --- Test data shapes ---
|
||||
|
||||
// Small integers: fast path for all encoders
|
||||
var integers_small = array(100, function(i) { return i + 1 })
|
||||
|
||||
// Floats: stresses nota's snprintf path
|
||||
var floats_array = array(100, function(i) {
|
||||
return 3.14159 * (i + 1) + 0.00001 * i
|
||||
})
|
||||
|
||||
// Short strings in records: per-string overhead, property enumeration
|
||||
var strings_short = array(50, function(i) {
|
||||
var r = {}
|
||||
r[`k${i}`] = `value_${i}`
|
||||
return r
|
||||
})
|
||||
|
||||
// Single long string: throughput test (wota byte loop, nota kim)
|
||||
var long_str = ""
|
||||
var li = 0
|
||||
for (li = 0; li < 100; li++) {
|
||||
long_str = `${long_str}abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMN`
|
||||
}
|
||||
var strings_long = long_str
|
||||
|
||||
// Unicode text: nota's kim encoding, wota's byte packing
|
||||
var strings_unicode = "こんにちは世界 🌍🌎🌏 Ñoño café résumé naïve Ω∑∏ 你好世界"
|
||||
|
||||
// Nested records: cycle detection, property enumeration
|
||||
function make_nested(depth, breadth) {
|
||||
var obj = {}
|
||||
var i = 0
|
||||
var k = null
|
||||
if (depth <= 0) {
|
||||
for (i = 0; i < breadth; i++) {
|
||||
k = `v${i}`
|
||||
obj[k] = i * 2.5
|
||||
}
|
||||
return obj
|
||||
}
|
||||
for (i = 0; i < breadth; i++) {
|
||||
k = `n${i}`
|
||||
obj[k] = make_nested(depth - 1, breadth)
|
||||
}
|
||||
return obj
|
||||
}
|
||||
var nested_records = make_nested(3, 4)
|
||||
|
||||
// Flat record: property enumeration cost
|
||||
var flat_record = {}
|
||||
var fi = 0
|
||||
for (fi = 0; fi < 50; fi++) {
|
||||
flat_record[`prop_${fi}`] = fi * 1.1
|
||||
}
|
||||
|
||||
// Mixed payload: realistic workload
|
||||
var mixed_payload = array(50, function(i) {
|
||||
var r = {}
|
||||
r.id = i
|
||||
r.name = `item_${i}`
|
||||
r.active = i % 2 == 0
|
||||
r.score = i * 3.14
|
||||
r.tags = [`t${i % 5}`, `t${(i + 1) % 5}`]
|
||||
return r
|
||||
})
|
||||
|
||||
// --- Pre-encode for decode benchmarks ---
|
||||
|
||||
var nota_enc_integers = nota.encode(integers_small)
|
||||
var nota_enc_floats = nota.encode(floats_array)
|
||||
var nota_enc_strings_short = nota.encode(strings_short)
|
||||
var nota_enc_strings_long = nota.encode(strings_long)
|
||||
var nota_enc_strings_unicode = nota.encode(strings_unicode)
|
||||
var nota_enc_nested = nota.encode(nested_records)
|
||||
var nota_enc_flat = nota.encode(flat_record)
|
||||
var nota_enc_mixed = nota.encode(mixed_payload)
|
||||
|
||||
var wota_enc_integers = wota.encode(integers_small)
|
||||
var wota_enc_floats = wota.encode(floats_array)
|
||||
var wota_enc_strings_short = wota.encode(strings_short)
|
||||
var wota_enc_strings_long = wota.encode(strings_long)
|
||||
var wota_enc_strings_unicode = wota.encode(strings_unicode)
|
||||
var wota_enc_nested = wota.encode(nested_records)
|
||||
var wota_enc_flat = wota.encode(flat_record)
|
||||
var wota_enc_mixed = wota.encode(mixed_payload)
|
||||
|
||||
var json_enc_integers = json.encode(integers_small)
|
||||
var json_enc_floats = json.encode(floats_array)
|
||||
var json_enc_strings_short = json.encode(strings_short)
|
||||
var json_enc_strings_long = json.encode(strings_long)
|
||||
var json_enc_strings_unicode = json.encode(strings_unicode)
|
||||
var json_enc_nested = json.encode(nested_records)
|
||||
var json_enc_flat = json.encode(flat_record)
|
||||
var json_enc_mixed = json.encode(mixed_payload)
|
||||
|
||||
// --- Benchmark functions ---
|
||||
|
||||
return {
|
||||
// NOTA encode
|
||||
nota_encode_integers: function(n) {
|
||||
var i = 0
|
||||
var r = null
|
||||
for (i = 0; i < n; i++) { r = nota.encode(integers_small) }
|
||||
return r
|
||||
},
|
||||
nota_encode_floats: function(n) {
|
||||
var i = 0
|
||||
var r = null
|
||||
for (i = 0; i < n; i++) { r = nota.encode(floats_array) }
|
||||
return r
|
||||
},
|
||||
nota_encode_strings_short: function(n) {
|
||||
var i = 0
|
||||
var r = null
|
||||
for (i = 0; i < n; i++) { r = nota.encode(strings_short) }
|
||||
return r
|
||||
},
|
||||
nota_encode_strings_long: function(n) {
|
||||
var i = 0
|
||||
var r = null
|
||||
for (i = 0; i < n; i++) { r = nota.encode(strings_long) }
|
||||
return r
|
||||
},
|
||||
nota_encode_strings_unicode: function(n) {
|
||||
var i = 0
|
||||
var r = null
|
||||
for (i = 0; i < n; i++) { r = nota.encode(strings_unicode) }
|
||||
return r
|
||||
},
|
||||
nota_encode_nested: function(n) {
|
||||
var i = 0
|
||||
var r = null
|
||||
for (i = 0; i < n; i++) { r = nota.encode(nested_records) }
|
||||
return r
|
||||
},
|
||||
nota_encode_flat: function(n) {
|
||||
var i = 0
|
||||
var r = null
|
||||
for (i = 0; i < n; i++) { r = nota.encode(flat_record) }
|
||||
return r
|
||||
},
|
||||
nota_encode_mixed: function(n) {
|
||||
var i = 0
|
||||
var r = null
|
||||
for (i = 0; i < n; i++) { r = nota.encode(mixed_payload) }
|
||||
return r
|
||||
},
|
||||
|
||||
// NOTA decode
|
||||
nota_decode_integers: function(n) {
|
||||
var i = 0
|
||||
var r = null
|
||||
for (i = 0; i < n; i++) { r = nota.decode(nota_enc_integers) }
|
||||
return r
|
||||
},
|
||||
nota_decode_floats: function(n) {
|
||||
var i = 0
|
||||
var r = null
|
||||
for (i = 0; i < n; i++) { r = nota.decode(nota_enc_floats) }
|
||||
return r
|
||||
},
|
||||
nota_decode_strings_short: function(n) {
|
||||
var i = 0
|
||||
var r = null
|
||||
for (i = 0; i < n; i++) { r = nota.decode(nota_enc_strings_short) }
|
||||
return r
|
||||
},
|
||||
nota_decode_strings_long: function(n) {
|
||||
var i = 0
|
||||
var r = null
|
||||
for (i = 0; i < n; i++) { r = nota.decode(nota_enc_strings_long) }
|
||||
return r
|
||||
},
|
||||
nota_decode_strings_unicode: function(n) {
|
||||
var i = 0
|
||||
var r = null
|
||||
for (i = 0; i < n; i++) { r = nota.decode(nota_enc_strings_unicode) }
|
||||
return r
|
||||
},
|
||||
nota_decode_nested: function(n) {
|
||||
var i = 0
|
||||
var r = null
|
||||
for (i = 0; i < n; i++) { r = nota.decode(nota_enc_nested) }
|
||||
return r
|
||||
},
|
||||
nota_decode_flat: function(n) {
|
||||
var i = 0
|
||||
var r = null
|
||||
for (i = 0; i < n; i++) { r = nota.decode(nota_enc_flat) }
|
||||
return r
|
||||
},
|
||||
nota_decode_mixed: function(n) {
|
||||
var i = 0
|
||||
var r = null
|
||||
for (i = 0; i < n; i++) { r = nota.decode(nota_enc_mixed) }
|
||||
return r
|
||||
},
|
||||
|
||||
// WOTA encode
|
||||
wota_encode_integers: function(n) {
|
||||
var i = 0
|
||||
var r = null
|
||||
for (i = 0; i < n; i++) { r = wota.encode(integers_small) }
|
||||
return r
|
||||
},
|
||||
wota_encode_floats: function(n) {
|
||||
var i = 0
|
||||
var r = null
|
||||
for (i = 0; i < n; i++) { r = wota.encode(floats_array) }
|
||||
return r
|
||||
},
|
||||
wota_encode_strings_short: function(n) {
|
||||
var i = 0
|
||||
var r = null
|
||||
for (i = 0; i < n; i++) { r = wota.encode(strings_short) }
|
||||
return r
|
||||
},
|
||||
wota_encode_strings_long: function(n) {
|
||||
var i = 0
|
||||
var r = null
|
||||
for (i = 0; i < n; i++) { r = wota.encode(strings_long) }
|
||||
return r
|
||||
},
|
||||
wota_encode_strings_unicode: function(n) {
|
||||
var i = 0
|
||||
var r = null
|
||||
for (i = 0; i < n; i++) { r = wota.encode(strings_unicode) }
|
||||
return r
|
||||
},
|
||||
wota_encode_nested: function(n) {
|
||||
var i = 0
|
||||
var r = null
|
||||
for (i = 0; i < n; i++) { r = wota.encode(nested_records) }
|
||||
return r
|
||||
},
|
||||
wota_encode_flat: function(n) {
|
||||
var i = 0
|
||||
var r = null
|
||||
for (i = 0; i < n; i++) { r = wota.encode(flat_record) }
|
||||
return r
|
||||
},
|
||||
wota_encode_mixed: function(n) {
|
||||
var i = 0
|
||||
var r = null
|
||||
for (i = 0; i < n; i++) { r = wota.encode(mixed_payload) }
|
||||
return r
|
||||
},
|
||||
|
||||
// WOTA decode
|
||||
wota_decode_integers: function(n) {
|
||||
var i = 0
|
||||
var r = null
|
||||
for (i = 0; i < n; i++) { r = wota.decode(wota_enc_integers) }
|
||||
return r
|
||||
},
|
||||
wota_decode_floats: function(n) {
|
||||
var i = 0
|
||||
var r = null
|
||||
for (i = 0; i < n; i++) { r = wota.decode(wota_enc_floats) }
|
||||
return r
|
||||
},
|
||||
wota_decode_strings_short: function(n) {
|
||||
var i = 0
|
||||
var r = null
|
||||
for (i = 0; i < n; i++) { r = wota.decode(wota_enc_strings_short) }
|
||||
return r
|
||||
},
|
||||
wota_decode_strings_long: function(n) {
|
||||
var i = 0
|
||||
var r = null
|
||||
for (i = 0; i < n; i++) { r = wota.decode(wota_enc_strings_long) }
|
||||
return r
|
||||
},
|
||||
wota_decode_strings_unicode: function(n) {
|
||||
var i = 0
|
||||
var r = null
|
||||
for (i = 0; i < n; i++) { r = wota.decode(wota_enc_strings_unicode) }
|
||||
return r
|
||||
},
|
||||
wota_decode_nested: function(n) {
|
||||
var i = 0
|
||||
var r = null
|
||||
for (i = 0; i < n; i++) { r = wota.decode(wota_enc_nested) }
|
||||
return r
|
||||
},
|
||||
wota_decode_flat: function(n) {
|
||||
var i = 0
|
||||
var r = null
|
||||
for (i = 0; i < n; i++) { r = wota.decode(wota_enc_flat) }
|
||||
return r
|
||||
},
|
||||
wota_decode_mixed: function(n) {
|
||||
var i = 0
|
||||
var r = null
|
||||
for (i = 0; i < n; i++) { r = wota.decode(wota_enc_mixed) }
|
||||
return r
|
||||
},
|
||||
|
||||
// JSON encode
|
||||
json_encode_integers: function(n) {
|
||||
var i = 0
|
||||
var r = null
|
||||
for (i = 0; i < n; i++) { r = json.encode(integers_small) }
|
||||
return r
|
||||
},
|
||||
json_encode_floats: function(n) {
|
||||
var i = 0
|
||||
var r = null
|
||||
for (i = 0; i < n; i++) { r = json.encode(floats_array) }
|
||||
return r
|
||||
},
|
||||
json_encode_strings_short: function(n) {
|
||||
var i = 0
|
||||
var r = null
|
||||
for (i = 0; i < n; i++) { r = json.encode(strings_short) }
|
||||
return r
|
||||
},
|
||||
json_encode_strings_long: function(n) {
|
||||
var i = 0
|
||||
var r = null
|
||||
for (i = 0; i < n; i++) { r = json.encode(strings_long) }
|
||||
return r
|
||||
},
|
||||
json_encode_strings_unicode: function(n) {
|
||||
var i = 0
|
||||
var r = null
|
||||
for (i = 0; i < n; i++) { r = json.encode(strings_unicode) }
|
||||
return r
|
||||
},
|
||||
json_encode_nested: function(n) {
|
||||
var i = 0
|
||||
var r = null
|
||||
for (i = 0; i < n; i++) { r = json.encode(nested_records) }
|
||||
return r
|
||||
},
|
||||
json_encode_flat: function(n) {
|
||||
var i = 0
|
||||
var r = null
|
||||
for (i = 0; i < n; i++) { r = json.encode(flat_record) }
|
||||
return r
|
||||
},
|
||||
json_encode_mixed: function(n) {
|
||||
var i = 0
|
||||
var r = null
|
||||
for (i = 0; i < n; i++) { r = json.encode(mixed_payload) }
|
||||
return r
|
||||
},
|
||||
|
||||
// JSON decode
|
||||
json_decode_integers: function(n) {
|
||||
var i = 0
|
||||
var r = null
|
||||
for (i = 0; i < n; i++) { r = json.decode(json_enc_integers) }
|
||||
return r
|
||||
},
|
||||
json_decode_floats: function(n) {
|
||||
var i = 0
|
||||
var r = null
|
||||
for (i = 0; i < n; i++) { r = json.decode(json_enc_floats) }
|
||||
return r
|
||||
},
|
||||
json_decode_strings_short: function(n) {
|
||||
var i = 0
|
||||
var r = null
|
||||
for (i = 0; i < n; i++) { r = json.decode(json_enc_strings_short) }
|
||||
return r
|
||||
},
|
||||
json_decode_strings_long: function(n) {
|
||||
var i = 0
|
||||
var r = null
|
||||
for (i = 0; i < n; i++) { r = json.decode(json_enc_strings_long) }
|
||||
return r
|
||||
},
|
||||
json_decode_strings_unicode: function(n) {
|
||||
var i = 0
|
||||
var r = null
|
||||
for (i = 0; i < n; i++) { r = json.decode(json_enc_strings_unicode) }
|
||||
return r
|
||||
},
|
||||
json_decode_nested: function(n) {
|
||||
var i = 0
|
||||
var r = null
|
||||
for (i = 0; i < n; i++) { r = json.decode(json_enc_nested) }
|
||||
return r
|
||||
},
|
||||
json_decode_flat: function(n) {
|
||||
var i = 0
|
||||
var r = null
|
||||
for (i = 0; i < n; i++) { r = json.decode(json_enc_flat) }
|
||||
return r
|
||||
},
|
||||
json_decode_mixed: function(n) {
|
||||
var i = 0
|
||||
var r = null
|
||||
for (i = 0; i < n; i++) { r = json.decode(json_enc_mixed) }
|
||||
return r
|
||||
}
|
||||
}
|
||||
@@ -308,6 +308,30 @@ void nota_write_blob(NotaBuffer *nb, unsigned long long nbits, const char *data)
|
||||
|
||||
void nota_write_text(NotaBuffer *nb, const char *s)
|
||||
{
|
||||
/* ASCII fast path: if all bytes < 0x80, KIM == UTF-8 and rune count == byte count */
|
||||
size_t slen = strlen(s);
|
||||
const unsigned char *scan = (const unsigned char *)s;
|
||||
int is_ascii = 1;
|
||||
for (size_t k = 0; k < slen; k++) {
|
||||
if (scan[k] >= 0x80) {
|
||||
is_ascii = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_ascii) {
|
||||
long long runes = (long long)slen;
|
||||
char *p = nota_buffer_alloc(nb, 1 + 10 + slen);
|
||||
p[0] = NOTA_TEXT;
|
||||
char *end = nota_continue_num(runes, p, 4);
|
||||
memcpy(end, s, slen);
|
||||
size_t used = (size_t)(end - p) + slen;
|
||||
size_t allocated = 1 + 10 + slen;
|
||||
nb->size -= (allocated - used);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Non-ASCII path: full UTF-8 decode + KIM encode */
|
||||
long long runes = utf8_count(s);
|
||||
|
||||
size_t max_kim = (size_t)(runes * 5);
|
||||
@@ -367,6 +391,13 @@ static void nota_write_int_buf(NotaBuffer *nb, long long n)
|
||||
nb->size -= (10 - used);
|
||||
}
|
||||
|
||||
static const double nota_pow10_table[29] = {
|
||||
1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7,
|
||||
1e8, 1e9, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15,
|
||||
1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22, 1e23,
|
||||
1e24, 1e25, 1e26, 1e27, 1e28
|
||||
};
|
||||
|
||||
static void extract_mantissa_coefficient(double num, long *coefficient, long *exponent)
|
||||
{
|
||||
if (num == 0.0) {
|
||||
@@ -375,32 +406,46 @@ static void extract_mantissa_coefficient(double num, long *coefficient, long *ex
|
||||
return;
|
||||
}
|
||||
|
||||
/* Round to 12 decimal places to avoid floating artifacts. */
|
||||
double rounded = floor(fabs(num) * 1e12 + 0.5) / 1e12;
|
||||
if (num < 0) {
|
||||
rounded = -rounded;
|
||||
double absval = fabs(num);
|
||||
int sign = (num < 0) ? -1 : 1;
|
||||
|
||||
/* Get decimal exponent via log10 */
|
||||
int dec_exp = (int)floor(log10(absval));
|
||||
|
||||
/* Scale to extract 14-digit coefficient.
|
||||
We want coeff * 10^exp = absval, with coeff having up to 14 digits.
|
||||
So coeff = absval * 10^(13 - dec_exp), exp = dec_exp - 13 */
|
||||
int shift = 13 - dec_exp;
|
||||
double scaled;
|
||||
if (shift >= 0 && shift <= 28) {
|
||||
scaled = absval * nota_pow10_table[shift];
|
||||
} else if (shift < 0 && -shift <= 28) {
|
||||
scaled = absval / nota_pow10_table[-shift];
|
||||
} else {
|
||||
scaled = absval * pow(10.0, (double)shift);
|
||||
}
|
||||
|
||||
char buf[64];
|
||||
snprintf(buf, sizeof(buf), "%.14g", rounded);
|
||||
long long coeff = (long long)(scaled + 0.5);
|
||||
|
||||
char *exp_pos = strpbrk(buf, "eE");
|
||||
long exp_from_sci = 0;
|
||||
if (exp_pos) {
|
||||
exp_from_sci = atol(exp_pos + 1);
|
||||
*exp_pos = '\0';
|
||||
/* Correct off-by-one from log10 rounding */
|
||||
if (coeff >= 100000000000000LL) {
|
||||
coeff = (coeff + 5) / 10;
|
||||
shift--;
|
||||
} else if (coeff < 10000000000000LL && coeff > 0) {
|
||||
coeff = (long long)(absval * pow(10.0, (double)(shift + 1)) + 0.5);
|
||||
shift++;
|
||||
}
|
||||
|
||||
char *dec_point = strchr(buf, '.');
|
||||
int digits_after_decimal = 0;
|
||||
if (dec_point) {
|
||||
digits_after_decimal = (int)strlen(dec_point + 1);
|
||||
memmove(dec_point, dec_point + 1, strlen(dec_point));
|
||||
int exp_out = -shift;
|
||||
|
||||
/* Strip trailing zeros */
|
||||
while (coeff != 0 && coeff % 10 == 0) {
|
||||
coeff /= 10;
|
||||
exp_out++;
|
||||
}
|
||||
|
||||
long long coeff_ll = atoll(buf);
|
||||
*coefficient = (long)coeff_ll;
|
||||
*exponent = exp_from_sci - digits_after_decimal;
|
||||
*coefficient = (long)(coeff * sign);
|
||||
*exponent = (long)exp_out;
|
||||
}
|
||||
|
||||
static void nota_write_float_buf(NotaBuffer *nb, double d)
|
||||
|
||||
@@ -11292,38 +11292,41 @@ static int nota_get_arr_len (JSContext *ctx, JSValue arr) {
|
||||
return (int)len;
|
||||
}
|
||||
|
||||
typedef struct NotaVisitedNode {
|
||||
JSGCRef ref;
|
||||
struct NotaVisitedNode *next;
|
||||
} NotaVisitedNode;
|
||||
|
||||
typedef struct NotaEncodeContext {
|
||||
JSContext *ctx;
|
||||
JSGCRef *visitedStack_ref; /* pointer to GC-rooted ref */
|
||||
NotaVisitedNode *visited_list;
|
||||
NotaBuffer nb;
|
||||
int cycle;
|
||||
JSGCRef *replacer_ref; /* pointer to GC-rooted ref */
|
||||
} NotaEncodeContext;
|
||||
|
||||
static void nota_stack_push (NotaEncodeContext *enc, JSValueConst val) {
|
||||
JSContext *ctx = enc->ctx;
|
||||
int len = nota_get_arr_len (ctx, enc->visitedStack_ref->val);
|
||||
JS_SetPropertyNumber (ctx, enc->visitedStack_ref->val, len, JS_DupValue (ctx, val));
|
||||
NotaVisitedNode *node = (NotaVisitedNode *)sys_malloc (sizeof (NotaVisitedNode));
|
||||
JS_PushGCRef (enc->ctx, &node->ref);
|
||||
node->ref.val = JS_DupValue (enc->ctx, val);
|
||||
node->next = enc->visited_list;
|
||||
enc->visited_list = node;
|
||||
}
|
||||
|
||||
static void nota_stack_pop (NotaEncodeContext *enc) {
|
||||
JSContext *ctx = enc->ctx;
|
||||
int len = nota_get_arr_len (ctx, enc->visitedStack_ref->val);
|
||||
JS_SetPropertyStr (ctx, enc->visitedStack_ref->val, "length", JS_NewUint32 (ctx, len - 1));
|
||||
NotaVisitedNode *node = enc->visited_list;
|
||||
enc->visited_list = node->next;
|
||||
JS_FreeValue (enc->ctx, node->ref.val);
|
||||
JS_PopGCRef (enc->ctx, &node->ref);
|
||||
sys_free (node);
|
||||
}
|
||||
|
||||
static int nota_stack_has (NotaEncodeContext *enc, JSValueConst val) {
|
||||
JSContext *ctx = enc->ctx;
|
||||
int len = nota_get_arr_len (ctx, enc->visitedStack_ref->val);
|
||||
for (int i = 0; i < len; i++) {
|
||||
JSValue elem = JS_GetPropertyNumber (ctx, enc->visitedStack_ref->val, i);
|
||||
if (mist_is_gc_object (elem) && mist_is_gc_object (val)) {
|
||||
if (JS_StrictEq (ctx, elem, val)) {
|
||||
JS_FreeValue (ctx, elem);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
JS_FreeValue (ctx, elem);
|
||||
NotaVisitedNode *node = enc->visited_list;
|
||||
while (node) {
|
||||
if (JS_StrictEq (enc->ctx, node->ref.val, val))
|
||||
return 1;
|
||||
node = node->next;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -11465,6 +11468,13 @@ static void nota_encode_value (NotaEncodeContext *enc, JSValueConst val, JSValue
|
||||
nota_write_sym (&enc->nb, NOTA_NULL);
|
||||
break;
|
||||
case JS_TAG_PTR: {
|
||||
if (JS_IsText (replaced_ref.val)) {
|
||||
const char *str = JS_ToCString (ctx, replaced_ref.val);
|
||||
nota_write_text (&enc->nb, str);
|
||||
JS_FreeCString (ctx, str);
|
||||
break;
|
||||
}
|
||||
|
||||
if (js_is_blob (ctx, replaced_ref.val)) {
|
||||
size_t buf_len;
|
||||
void *buf_data = js_get_blob_data (ctx, &buf_len, replaced_ref.val);
|
||||
@@ -11576,16 +11586,14 @@ static void nota_encode_value (NotaEncodeContext *enc, JSValueConst val, JSValue
|
||||
}
|
||||
|
||||
void *value2nota (JSContext *ctx, JSValue v) {
|
||||
JSGCRef val_ref, stack_ref, key_ref;
|
||||
JSGCRef val_ref, key_ref;
|
||||
JS_PushGCRef (ctx, &val_ref);
|
||||
JS_PushGCRef (ctx, &stack_ref);
|
||||
JS_PushGCRef (ctx, &key_ref);
|
||||
val_ref.val = v;
|
||||
|
||||
NotaEncodeContext enc_s, *enc = &enc_s;
|
||||
enc->ctx = ctx;
|
||||
stack_ref.val = JS_NewArray (ctx);
|
||||
enc->visitedStack_ref = &stack_ref;
|
||||
enc->visited_list = NULL;
|
||||
enc->cycle = 0;
|
||||
enc->replacer_ref = NULL;
|
||||
|
||||
@@ -11595,14 +11603,12 @@ void *value2nota (JSContext *ctx, JSValue v) {
|
||||
|
||||
if (enc->cycle) {
|
||||
JS_PopGCRef (ctx, &key_ref);
|
||||
JS_PopGCRef (ctx, &stack_ref);
|
||||
JS_PopGCRef (ctx, &val_ref);
|
||||
nota_buffer_free (&enc->nb);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
JS_PopGCRef (ctx, &key_ref);
|
||||
JS_PopGCRef (ctx, &stack_ref);
|
||||
JS_PopGCRef (ctx, &val_ref);
|
||||
void *data_ptr = enc->nb.data;
|
||||
enc->nb.data = NULL;
|
||||
@@ -11630,18 +11636,16 @@ JSValue nota2value (JSContext *js, void *nota) {
|
||||
static JSValue js_nota_encode (JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) {
|
||||
if (argc < 1) return JS_ThrowTypeError (ctx, "nota.encode requires at least 1 argument");
|
||||
|
||||
JSGCRef val_ref, stack_ref, replacer_ref, key_ref;
|
||||
JSGCRef val_ref, replacer_ref, key_ref;
|
||||
JS_PushGCRef (ctx, &val_ref);
|
||||
JS_PushGCRef (ctx, &stack_ref);
|
||||
JS_PushGCRef (ctx, &replacer_ref);
|
||||
JS_PushGCRef (ctx, &key_ref);
|
||||
val_ref.val = argv[0];
|
||||
stack_ref.val = JS_NewArray (ctx);
|
||||
replacer_ref.val = (argc > 1 && JS_IsFunction (argv[1])) ? argv[1] : JS_NULL;
|
||||
|
||||
NotaEncodeContext enc_s, *enc = &enc_s;
|
||||
enc->ctx = ctx;
|
||||
enc->visitedStack_ref = &stack_ref;
|
||||
enc->visited_list = NULL;
|
||||
enc->cycle = 0;
|
||||
enc->replacer_ref = &replacer_ref;
|
||||
|
||||
@@ -11662,7 +11666,6 @@ static JSValue js_nota_encode (JSContext *ctx, JSValueConst this_val, int argc,
|
||||
|
||||
JS_PopGCRef (ctx, &key_ref);
|
||||
JS_PopGCRef (ctx, &replacer_ref);
|
||||
JS_PopGCRef (ctx, &stack_ref);
|
||||
JS_PopGCRef (ctx, &val_ref);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -429,11 +429,15 @@ char *wota_read_text_len(size_t *byte_len, char **text_utf8, char *wota)
|
||||
}
|
||||
|
||||
/* Copy bytes from the packed 64-bit words */
|
||||
for (long long i = 0; i < nwords; i++) {
|
||||
uint64_t wval = data_words[i];
|
||||
for (int j = 0; j < 8 && (i * 8 + j) < (long long)nbytes; j++) {
|
||||
out[i * 8 + j] = (char)((wval >> (56 - j * 8)) & 0xff);
|
||||
}
|
||||
size_t full_words = nbytes / 8;
|
||||
size_t remainder = nbytes % 8;
|
||||
for (size_t i = 0; i < full_words; i++) {
|
||||
uint64_t wval = wota_bswap64(data_words[i]);
|
||||
memcpy(out + i * 8, &wval, 8);
|
||||
}
|
||||
if (remainder > 0) {
|
||||
uint64_t wval = wota_bswap64(data_words[full_words]);
|
||||
memcpy(out + full_words * 8, &wval, remainder);
|
||||
}
|
||||
|
||||
out[nbytes] = '\0';
|
||||
@@ -609,14 +613,18 @@ void wota_write_text_len(WotaBuffer *wb, const char *utf8, size_t nbytes)
|
||||
}
|
||||
|
||||
uint64_t *blocks = wota_buffer_alloc(wb, nwords);
|
||||
memset(blocks, 0, nwords * sizeof(uint64_t));
|
||||
|
||||
for (size_t i = 0; i < nwords; i++) {
|
||||
size_t full_words = nbytes / 8;
|
||||
size_t remainder = nbytes % 8;
|
||||
for (size_t i = 0; i < full_words; i++) {
|
||||
uint64_t wval;
|
||||
memcpy(&wval, utf8 + i * 8, 8);
|
||||
blocks[i] = wota_bswap64(wval);
|
||||
}
|
||||
if (remainder > 0) {
|
||||
uint64_t wval = 0;
|
||||
for (int j = 0; j < 8 && (i * 8 + j) < nbytes; j++) {
|
||||
wval |= ((uint64_t)(unsigned char)utf8[i * 8 + j]) << (56 - j * 8);
|
||||
}
|
||||
blocks[i] = wval;
|
||||
memcpy(&wval, utf8 + full_words * 8, remainder);
|
||||
blocks[full_words] = wota_bswap64(wval);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user