faster text conversion to hex; guid generation now dealt with with -u.random_fit and blob formation; mersenne twister used for -u.random functions
This commit is contained in:
@@ -295,7 +295,7 @@ src += [
|
|||||||
'anim.c', 'config.c', 'datastream.c','font.c','HandmadeMath.c','jsffi.c','model.c',
|
'anim.c', 'config.c', 'datastream.c','font.c','HandmadeMath.c','jsffi.c','model.c',
|
||||||
'render.c','simplex.c','spline.c', 'transform.c','cell.c', 'wildmatch.c',
|
'render.c','simplex.c','spline.c', 'transform.c','cell.c', 'wildmatch.c',
|
||||||
'sprite.c', 'rtree.c', 'qjs_nota.c', 'qjs_soloud.c', 'qjs_sdl.c', 'qjs_sdl_input.c', 'qjs_sdl_video.c', 'qjs_sdl_surface.c', 'qjs_math.c', 'qjs_geometry.c', 'qjs_transform.c', 'qjs_sprite.c', 'qjs_io.c', 'qjs_fd.c', 'qjs_os.c', 'qjs_actor.c',
|
'sprite.c', 'rtree.c', 'qjs_nota.c', 'qjs_soloud.c', 'qjs_sdl.c', 'qjs_sdl_input.c', 'qjs_sdl_video.c', 'qjs_sdl_surface.c', 'qjs_math.c', 'qjs_geometry.c', 'qjs_transform.c', 'qjs_sprite.c', 'qjs_io.c', 'qjs_fd.c', 'qjs_os.c', 'qjs_actor.c',
|
||||||
'qjs_qr.c', 'qjs_wota.c', 'monocypher.c', 'qjs_blob.c', 'qjs_crypto.c', 'qjs_time.c', 'qjs_http.c', 'qjs_rtree.c', 'qjs_spline.c', 'qjs_js.c', 'qjs_debug.c', 'picohttpparser.c', 'qjs_miniz.c', 'timer.c', 'qjs_socket.c', 'qjs_kim.c', 'qjs_utf8.c', 'qjs_fit.c'
|
'qjs_qr.c', 'qjs_wota.c', 'monocypher.c', 'qjs_blob.c', 'qjs_crypto.c', 'qjs_time.c', 'qjs_http.c', 'qjs_rtree.c', 'qjs_spline.c', 'qjs_js.c', 'qjs_debug.c', 'picohttpparser.c', 'qjs_miniz.c', 'timer.c', 'qjs_socket.c', 'qjs_kim.c', 'qjs_utf8.c', 'qjs_fit.c', 'qjs_text.c'
|
||||||
]
|
]
|
||||||
# quirc src
|
# quirc src
|
||||||
src += [
|
src += [
|
||||||
|
|||||||
@@ -339,12 +339,16 @@ stone.p = function(object)
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var util = use('util')
|
function guid(bits = 256)
|
||||||
var crypto = use('crypto')
|
{
|
||||||
|
var guid = new blob(bits, hidden.randi)
|
||||||
|
stone(guid)
|
||||||
|
return text(guid,'h')
|
||||||
|
}
|
||||||
|
|
||||||
var HEADER = Symbol()
|
var HEADER = Symbol()
|
||||||
|
|
||||||
function create_actor(desc = {id:util.guid()}) {
|
function create_actor(desc = {id:guid()}) {
|
||||||
var actor = {}
|
var actor = {}
|
||||||
actor[ACTORDATA] = desc
|
actor[ACTORDATA] = desc
|
||||||
return actor
|
return actor
|
||||||
@@ -352,10 +356,10 @@ function create_actor(desc = {id:util.guid()}) {
|
|||||||
|
|
||||||
var $_ = create_actor()
|
var $_ = create_actor()
|
||||||
|
|
||||||
$_.random = crypto.random
|
$_.random = hidden.rand
|
||||||
$_.random[cell.DOC] = "returns a number between 0 and 1. There is a 50% chance that the result is less than 0.5."
|
$_.random[cell.DOC] = "returns a number between 0 and 1. There is a 50% chance that the result is less than 0.5."
|
||||||
|
|
||||||
$_.random_fit = crypto.random_fit
|
$_.random_fit = hidden.randi
|
||||||
|
|
||||||
$_.clock = function(fn) {
|
$_.clock = function(fn) {
|
||||||
actor_mod.clock(_ => {
|
actor_mod.clock(_ => {
|
||||||
@@ -484,7 +488,7 @@ $_.receiver[cell.DOC] = "registers a function that will receive all messages..."
|
|||||||
|
|
||||||
$_.start = function start(cb, program, ...args) {
|
$_.start = function start(cb, program, ...args) {
|
||||||
if (!program) return
|
if (!program) return
|
||||||
var id = util.guid()
|
var id = guid()
|
||||||
|
|
||||||
if (args.length === 1 && Array.isArray(args[0]))
|
if (args.length === 1 && Array.isArray(args[0]))
|
||||||
args = args[0]
|
args = args[0]
|
||||||
@@ -636,7 +640,7 @@ globalThis.send = function send(actor, message, reply) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (reply) {
|
if (reply) {
|
||||||
var id = util.guid()
|
var id = guid()
|
||||||
replies[id] = reply
|
replies[id] = reply
|
||||||
$_.delay(_ => {
|
$_.delay(_ => {
|
||||||
if (replies[id]) {
|
if (replies[id]) {
|
||||||
@@ -654,7 +658,7 @@ globalThis.send = function send(actor, message, reply) {
|
|||||||
|
|
||||||
stone(send)
|
stone(send)
|
||||||
|
|
||||||
if (!cell.args.id) cell.id = util.guid()
|
if (!cell.args.id) cell.id = guid()
|
||||||
else cell.id = cell.args.id
|
else cell.id = cell.args.id
|
||||||
|
|
||||||
$_[ACTORDATA].id = cell.id
|
$_[ACTORDATA].id = cell.id
|
||||||
|
|||||||
@@ -22,10 +22,6 @@ math.sigma[cell.DOC] = "Compute standard deviation of an array of numbers."
|
|||||||
math.median[cell.DOC] = "Compute the median of an array of numbers."
|
math.median[cell.DOC] = "Compute the median of an array of numbers."
|
||||||
math.length[cell.DOC] = "Return the length of a vector (i.e. sqrt of sum of squares)."
|
math.length[cell.DOC] = "Return the length of a vector (i.e. sqrt of sum of squares)."
|
||||||
math.from_to[cell.DOC] = "Return an array of points from a start to an end, spaced out by a certain distance."
|
math.from_to[cell.DOC] = "Return an array of points from a start to an end, spaced out by a certain distance."
|
||||||
math.rand[cell.DOC] = "Return a random float in [0,1)."
|
|
||||||
math.randi[cell.DOC] = "Return a random 32-bit integer."
|
|
||||||
math.srand[cell.DOC] = "Seed the random number generator with the given integer, or with current time if none."
|
|
||||||
|
|
||||||
|
|
||||||
math.TAU = Math.PI * 2;
|
math.TAU = Math.PI * 2;
|
||||||
math.deg2rad = function (deg) { return deg * 0.0174533; };
|
math.deg2rad = function (deg) { return deg * 0.0174533; };
|
||||||
|
|||||||
@@ -5,6 +5,8 @@
|
|||||||
var blob = use('blob')
|
var blob = use('blob')
|
||||||
var utf8 = use('utf8')
|
var utf8 = use('utf8')
|
||||||
|
|
||||||
|
var that = this
|
||||||
|
|
||||||
// Convert number to string with given radix
|
// Convert number to string with given radix
|
||||||
function to_radix(num, radix) {
|
function to_radix(num, radix) {
|
||||||
if (radix < 2 || radix > 36) return null;
|
if (radix < 2 || radix > 36) return null;
|
||||||
@@ -98,54 +100,10 @@ function text() {
|
|||||||
// Handle blob encoding styles
|
// Handle blob encoding styles
|
||||||
switch (style) {
|
switch (style) {
|
||||||
case 'h': // hexadecimal
|
case 'h': // hexadecimal
|
||||||
// Read 8 bits at a time for full bytes
|
return that.blob_to_hex(arg);
|
||||||
var hex_digits = "0123456789ABCDEF";
|
|
||||||
for (var i = 0; i < bit_length; i += 8) {
|
|
||||||
var byte_val = 0;
|
|
||||||
for (var j = 0; j < 8 && i + j < bit_length; j++) {
|
|
||||||
var bit = arg.read_logical(i + j);
|
|
||||||
if (bit) byte_val |= (1 << j);
|
|
||||||
}
|
|
||||||
result += hex_digits[(byte_val >> 4) & 0xF];
|
|
||||||
result += hex_digits[byte_val & 0xF];
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
|
|
||||||
case 't': // base32
|
case 't': // base32
|
||||||
var b32_digits = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
|
return that.blob_to_base32(arg);
|
||||||
var bits = 0;
|
|
||||||
var value = 0;
|
|
||||||
|
|
||||||
// Read bits from LSB to MSB within each byte
|
|
||||||
for (var byte_idx = 0; byte_idx < Math.ceil(bit_length / 8); byte_idx++) {
|
|
||||||
for (var bit_in_byte = 0; bit_in_byte < 8 && byte_idx * 8 + bit_in_byte < bit_length; bit_in_byte++) {
|
|
||||||
var bit_pos = byte_idx * 8 + bit_in_byte;
|
|
||||||
var bit = arg.read_logical(bit_pos);
|
|
||||||
|
|
||||||
// Accumulate bits from MSB to LSB for base32
|
|
||||||
value = (value << 1) | (bit ? 1 : 0);
|
|
||||||
bits++;
|
|
||||||
|
|
||||||
if (bits === 5) {
|
|
||||||
result += b32_digits[value];
|
|
||||||
bits = 0;
|
|
||||||
value = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle remaining bits
|
|
||||||
if (bits > 0) {
|
|
||||||
value = value << (5 - bits);
|
|
||||||
result += b32_digits[value];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add padding to make length multiple of 8
|
|
||||||
while (result.length % 8 !== 0) {
|
|
||||||
result += '=';
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
|
|
||||||
case 'b': // binary
|
case 'b': // binary
|
||||||
for (var i = 0; i < bit_length; i++) {
|
for (var i = 0; i < bit_length; i++) {
|
||||||
|
|||||||
@@ -21,8 +21,8 @@ typedef struct letter {
|
|||||||
};
|
};
|
||||||
} letter;
|
} letter;
|
||||||
|
|
||||||
#define STATE_VECTOR_LENGTH 624
|
#define STATE_VECTOR_LENGTH 312
|
||||||
#define STATE_VECTOR_M 397
|
#define STATE_VECTOR_M 156
|
||||||
|
|
||||||
#define ACTOR_IDLE 0 // Actor not doing anything
|
#define ACTOR_IDLE 0 // Actor not doing anything
|
||||||
#define ACTOR_READY 1 // Actor ready for a turn
|
#define ACTOR_READY 1 // Actor ready for a turn
|
||||||
@@ -36,7 +36,7 @@ typedef JSValue (*MODULEFN)(JSContext *js);
|
|||||||
extern int tracy_profiling_enabled;
|
extern int tracy_profiling_enabled;
|
||||||
|
|
||||||
typedef struct tagMTRand {
|
typedef struct tagMTRand {
|
||||||
uint32_t mt[STATE_VECTOR_LENGTH];
|
uint64_t mt[STATE_VECTOR_LENGTH];
|
||||||
int32_t index;
|
int32_t index;
|
||||||
} MTRand;
|
} MTRand;
|
||||||
|
|
||||||
|
|||||||
126
source/jsffi.c
126
source/jsffi.c
@@ -56,6 +56,7 @@
|
|||||||
#include "qjs_kim.h"
|
#include "qjs_kim.h"
|
||||||
#include "qjs_utf8.h"
|
#include "qjs_utf8.h"
|
||||||
#include "qjs_fit.h"
|
#include "qjs_fit.h"
|
||||||
|
#include "qjs_text.h"
|
||||||
#ifndef NSTEAM
|
#ifndef NSTEAM
|
||||||
#include "qjs_steam.h"
|
#include "qjs_steam.h"
|
||||||
#endif
|
#endif
|
||||||
@@ -102,55 +103,59 @@ transform *js2transform(JSContext *js, JSValue v);
|
|||||||
//#include <cblas.h>
|
//#include <cblas.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Random number generation constants
|
// Random number generation constants for MT19937-64
|
||||||
#define UPPER_MASK 0x80000000
|
#define NN STATE_VECTOR_LENGTH
|
||||||
#define LOWER_MASK 0x7fffffff
|
#define MM STATE_VECTOR_M
|
||||||
#define TEMPERING_MASK_B 0x9d2c5680
|
#define MATRIX_A 0xB5026F5AA96619E9ULL
|
||||||
#define TEMPERING_MASK_C 0xefc60000
|
#define UM 0xFFFFFFFF80000000ULL /* Most significant 33 bits */
|
||||||
|
#define LM 0x7FFFFFFFULL /* Least significant 31 bits */
|
||||||
|
|
||||||
// Random number generation functions
|
// Random number generation functions
|
||||||
void m_seedRand(MTRand* rand, uint32_t seed) {
|
void m_seedRand(MTRand* rand, uint64_t seed) {
|
||||||
/* set initial seeds to mt[STATE_VECTOR_LENGTH] using the generator
|
rand->mt[0] = seed;
|
||||||
* from Line 25 of Table 1 in: Donald Knuth, "The Art of Computer
|
for(rand->index = 1; rand->index < NN; rand->index++) {
|
||||||
* Programming," Vol. 2 (2nd Ed.) pp.102.
|
rand->mt[rand->index] = (6364136223846793005ULL * (rand->mt[rand->index-1] ^ (rand->mt[rand->index-1] >> 62)) + rand->index);
|
||||||
*/
|
|
||||||
rand->mt[0] = seed & 0xffffffff;
|
|
||||||
for(rand->index=1; rand->index<STATE_VECTOR_LENGTH; rand->index++) {
|
|
||||||
rand->mt[rand->index] = (6069 * rand->mt[rand->index-1]) & 0xffffffff;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t genRandLong(MTRand* rand) {
|
int64_t genRandLong(MTRand* rand) {
|
||||||
uint32_t y;
|
int i;
|
||||||
static uint32_t mag[2] = {0x0, 0x9908b0df}; /* mag[x] = x * 0x9908b0df for x = 0,1 */
|
uint64_t x;
|
||||||
if(rand->index >= STATE_VECTOR_LENGTH || rand->index < 0) {
|
static uint64_t mag01[2] = {0ULL, MATRIX_A};
|
||||||
/* generate STATE_VECTOR_LENGTH words at a time */
|
|
||||||
int32_t kk;
|
if (rand->index >= NN) { /* generate NN words at one time */
|
||||||
if(rand->index >= STATE_VECTOR_LENGTH+1 || rand->index < 0) {
|
/* if init_genrand64() has not been called, */
|
||||||
m_seedRand(rand, 4357);
|
/* a default initial seed is used */
|
||||||
|
if (rand->index == NN+1)
|
||||||
|
m_seedRand(rand, 5489ULL);
|
||||||
|
|
||||||
|
for (i = 0; i < NN-MM; i++) {
|
||||||
|
x = (rand->mt[i] & UM) | (rand->mt[i+1] & LM);
|
||||||
|
rand->mt[i] = rand->mt[i+MM] ^ (x>>1) ^ mag01[(int)(x&1ULL)];
|
||||||
}
|
}
|
||||||
for(kk=0; kk<STATE_VECTOR_LENGTH-STATE_VECTOR_M; kk++) {
|
for (; i < NN-1; i++) {
|
||||||
y = (rand->mt[kk] & UPPER_MASK) | (rand->mt[kk+1] & LOWER_MASK);
|
x = (rand->mt[i] & UM) | (rand->mt[i+1] & LM);
|
||||||
rand->mt[kk] = rand->mt[kk+STATE_VECTOR_M] ^ (y >> 1) ^ mag[y & 0x1];
|
rand->mt[i] = rand->mt[i+(MM-NN)] ^ (x>>1) ^ mag01[(int)(x&1ULL)];
|
||||||
}
|
}
|
||||||
for(; kk<STATE_VECTOR_LENGTH-1; kk++) {
|
x = (rand->mt[NN-1] & UM) | (rand->mt[0] & LM);
|
||||||
y = (rand->mt[kk] & UPPER_MASK) | (rand->mt[kk+1] & LOWER_MASK);
|
rand->mt[NN-1] = rand->mt[MM-1] ^ (x>>1) ^ mag01[(int)(x&1ULL)];
|
||||||
rand->mt[kk] = rand->mt[kk+(STATE_VECTOR_M-STATE_VECTOR_LENGTH)] ^ (y >> 1) ^ mag[y & 0x1];
|
|
||||||
}
|
|
||||||
y = (rand->mt[STATE_VECTOR_LENGTH-1] & UPPER_MASK) | (rand->mt[0] & LOWER_MASK);
|
|
||||||
rand->mt[STATE_VECTOR_LENGTH-1] = rand->mt[STATE_VECTOR_M-1] ^ (y >> 1) ^ mag[y & 0x1];
|
|
||||||
rand->index = 0;
|
rand->index = 0;
|
||||||
}
|
}
|
||||||
y = rand->mt[rand->index++];
|
|
||||||
y ^= (y >> 11);
|
x = rand->mt[rand->index++];
|
||||||
y ^= (y << 7) & TEMPERING_MASK_B;
|
|
||||||
y ^= (y << 15) & TEMPERING_MASK_C;
|
x ^= (x >> 29) & 0x5555555555555555ULL;
|
||||||
y ^= (y >> 18);
|
x ^= (x << 17) & 0x71D67FFFEDA60000ULL;
|
||||||
return y;
|
x ^= (x << 37) & 0xFFF7EEE000000000ULL;
|
||||||
|
x ^= (x >> 43);
|
||||||
|
|
||||||
|
return (int64_t)(x & 0x000FFFFFFFFFFFFFULL); /* return 52-bit value safe for JS */
|
||||||
}
|
}
|
||||||
|
|
||||||
double genRand(MTRand* rand) {
|
double genRand(MTRand* rand) {
|
||||||
return((double)genRandLong(rand) / (uint32_t)0xffffffff);
|
/* generates a random number on [0,1)-real-interval */
|
||||||
|
return (genRandLong(rand) >> 11) * (1.0/9007199254740992.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
double rand_range(JSContext *js, double min, double max)
|
double rand_range(JSContext *js, double min, double max)
|
||||||
@@ -947,15 +952,31 @@ static const JSCFunctionListEntry js_number_funcs[] = {
|
|||||||
PROTO_FUNC_DEF(number, lerp, 2),
|
PROTO_FUNC_DEF(number, lerp, 2),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static uint32_t rng_state = 123456789;
|
||||||
|
static uint32_t xorshift32(){
|
||||||
|
uint32_t x = rng_state;
|
||||||
|
x ^= x << 13;
|
||||||
|
x ^= x >> 17;
|
||||||
|
x ^= x << 5;
|
||||||
|
return rng_state = x;
|
||||||
|
}
|
||||||
|
|
||||||
JSC_CCALL(os_guid,
|
JSC_CCALL(os_guid,
|
||||||
SDL_GUID guid;
|
uint8_t data[16];
|
||||||
randombytes(guid.data, 16);
|
for(int i = 0; i < 4; i++){
|
||||||
|
uint32_t v = xorshift32();
|
||||||
|
memcpy(&data[i*4], &v, 4);
|
||||||
|
}
|
||||||
|
|
||||||
char guid_str[33];
|
static const char hex[] = "0123456789abcdef";
|
||||||
|
char buf[32];
|
||||||
|
for(int i = 0; i < 16; i++){
|
||||||
|
uint8_t b = data[i];
|
||||||
|
buf[i*2 ] = hex[b >> 4];
|
||||||
|
buf[i*2 + 1] = hex[b & 0x0f];
|
||||||
|
}
|
||||||
|
|
||||||
SDL_GUIDToString(guid, guid_str, 33);
|
return JS_NewStringLen(js, buf, 32);
|
||||||
|
|
||||||
return JS_NewString(js,guid_str);
|
|
||||||
)
|
)
|
||||||
|
|
||||||
JSC_SCALL(console_print, printf("%s", str); )
|
JSC_SCALL(console_print, printf("%s", str); )
|
||||||
@@ -1197,6 +1218,21 @@ JSC_CCALL(os_make_font,
|
|||||||
|
|
||||||
JSC_SCALL(os_system, ret = number2js(js,system(str)); )
|
JSC_SCALL(os_system, ret = number2js(js,system(str)); )
|
||||||
|
|
||||||
|
JSC_CCALL(os_rand,
|
||||||
|
MTRand *mrand = &((cell_rt*)JS_GetContextOpaque(js))->mrand;
|
||||||
|
return number2js(js, genRand(mrand));
|
||||||
|
)
|
||||||
|
|
||||||
|
JSC_CCALL(os_randi,
|
||||||
|
MTRand *mrand = &((cell_rt*)JS_GetContextOpaque(js))->mrand;
|
||||||
|
return JS_NewInt64(js, genRandLong(mrand));
|
||||||
|
)
|
||||||
|
|
||||||
|
JSC_CCALL(os_srand,
|
||||||
|
MTRand *mrand = &((cell_rt*)JS_GetContextOpaque(js))->mrand;
|
||||||
|
m_seedRand(mrand, js2number(js,argv[0]));
|
||||||
|
)
|
||||||
|
|
||||||
JSValue make_color_buffer(JSContext *js, colorf c, int verts)
|
JSValue make_color_buffer(JSContext *js, colorf c, int verts)
|
||||||
{
|
{
|
||||||
HMM_Vec4 *colordata = malloc(sizeof(*colordata)*verts);
|
HMM_Vec4 *colordata = malloc(sizeof(*colordata)*verts);
|
||||||
@@ -1561,6 +1597,7 @@ void ffi_load(JSContext *js)
|
|||||||
arrput(rt->module_registry, MISTLINE(kim));
|
arrput(rt->module_registry, MISTLINE(kim));
|
||||||
arrput(rt->module_registry, MISTLINE(utf8));
|
arrput(rt->module_registry, MISTLINE(utf8));
|
||||||
arrput(rt->module_registry, MISTLINE(fit));
|
arrput(rt->module_registry, MISTLINE(fit));
|
||||||
|
arrput(rt->module_registry, MISTLINE(text));
|
||||||
arrput(rt->module_registry, MISTLINE(wota));
|
arrput(rt->module_registry, MISTLINE(wota));
|
||||||
arrput(rt->module_registry, MISTLINE(nota));
|
arrput(rt->module_registry, MISTLINE(nota));
|
||||||
|
|
||||||
@@ -1623,6 +1660,9 @@ void ffi_load(JSContext *js)
|
|||||||
// Add functions that should only be accessible to engine.js
|
// Add functions that should only be accessible to engine.js
|
||||||
JS_SetPropertyStr(js, hidden_fn, "use_dyn", JS_NewCFunction(js, js_os_use_dyn, "use_dyn", 1));
|
JS_SetPropertyStr(js, hidden_fn, "use_dyn", JS_NewCFunction(js, js_os_use_dyn, "use_dyn", 1));
|
||||||
JS_SetPropertyStr(js, hidden_fn, "use_embed", JS_NewCFunction(js, js_os_use_embed, "use_embed", 1));
|
JS_SetPropertyStr(js, hidden_fn, "use_embed", JS_NewCFunction(js, js_os_use_embed, "use_embed", 1));
|
||||||
|
JS_SetPropertyStr(js, hidden_fn, "rand", JS_NewCFunction(js, js_os_rand, "rand", 0));
|
||||||
|
JS_SetPropertyStr(js, hidden_fn, "randi", JS_NewCFunction(js, js_os_randi, "randi", 0));
|
||||||
|
JS_SetPropertyStr(js, hidden_fn, "srand", JS_NewCFunction(js, js_os_srand, "srand", 1));
|
||||||
|
|
||||||
const char actorsym_script[] = "var sym = Symbol(`actordata`); sym;";
|
const char actorsym_script[] = "var sym = Symbol(`actordata`); sym;";
|
||||||
|
|
||||||
|
|||||||
@@ -42,8 +42,8 @@ typedef struct tagMTRand MTRand;
|
|||||||
|
|
||||||
// Random number generation functions
|
// Random number generation functions
|
||||||
double genRand(MTRand *mrand);
|
double genRand(MTRand *mrand);
|
||||||
uint32_t genRandLong(MTRand *mrand);
|
int64_t genRandLong(MTRand *mrand);
|
||||||
void m_seedRand(MTRand *mrand, uint32_t seed);
|
void m_seedRand(MTRand *mrand, uint64_t seed);
|
||||||
double rand_range(JSContext *js, double min, double max);
|
double rand_range(JSContext *js, double min, double max);
|
||||||
|
|
||||||
// Common data structures
|
// Common data structures
|
||||||
|
|||||||
@@ -50,33 +50,44 @@ static JSValue js_blob_constructor(JSContext *ctx, JSValueConst new_target,
|
|||||||
int is_one = JS_ToBool(ctx, argv[1]);
|
int is_one = JS_ToBool(ctx, argv[1]);
|
||||||
bd = blob_new_with_fill((size_t)length_bits, is_one);
|
bd = blob_new_with_fill((size_t)length_bits, is_one);
|
||||||
} else if (JS_IsFunction(ctx, argv[1])) {
|
} else if (JS_IsFunction(ctx, argv[1])) {
|
||||||
/* Random function provided – call it for each bit */
|
/* Random function provided – call it and use up to 56 bits at a time */
|
||||||
size_t bytes = (length_bits + 7) / 8;
|
size_t bytes = (length_bits + 7) / 8;
|
||||||
bd = blob_new((size_t)length_bits);
|
bd = blob_new((size_t)length_bits);
|
||||||
if (bd) {
|
if (bd) {
|
||||||
bd->length = length_bits;
|
bd->length = length_bits;
|
||||||
/* Ensure the backing storage starts out zeroed */
|
/* Ensure the backing storage starts out zeroed */
|
||||||
memset(bd->data, 0, bytes);
|
memset(bd->data, 0, bytes);
|
||||||
for (size_t i = 0; i < length_bits; i++) {
|
|
||||||
|
size_t bits_written = 0;
|
||||||
|
while (bits_written < length_bits) {
|
||||||
JSValue randval = JS_Call(ctx, argv[1], JS_UNDEFINED, 0, NULL);
|
JSValue randval = JS_Call(ctx, argv[1], JS_UNDEFINED, 0, NULL);
|
||||||
if (JS_IsException(randval)) {
|
if (JS_IsException(randval)) {
|
||||||
blob_destroy(bd);
|
blob_destroy(bd);
|
||||||
return JS_EXCEPTION;
|
return JS_EXCEPTION;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t fitval;
|
int64_t fitval;
|
||||||
JS_ToInt32(ctx, &fitval, randval);
|
JS_ToInt64(ctx, &fitval, randval);
|
||||||
JS_FreeValue(ctx, randval);
|
JS_FreeValue(ctx, randval);
|
||||||
|
|
||||||
/* Compute which byte and which bit within that byte to set/clear */
|
/* Extract up to 56 bits from the random value */
|
||||||
size_t byte_idx = i / 8;
|
size_t bits_to_use = length_bits - bits_written;
|
||||||
size_t bit_idx = i % 8;
|
if (bits_to_use > 52) bits_to_use = 52;
|
||||||
|
|
||||||
if (fitval & 1)
|
/* Write bits from the random value */
|
||||||
|
for (size_t j = 0; j < bits_to_use; j++) {
|
||||||
|
size_t bit_pos = bits_written + j;
|
||||||
|
size_t byte_idx = bit_pos / 8;
|
||||||
|
size_t bit_idx = bit_pos % 8;
|
||||||
|
|
||||||
|
if (fitval & (1LL << j))
|
||||||
bd->data[byte_idx] |= (uint8_t)(1 << bit_idx);
|
bd->data[byte_idx] |= (uint8_t)(1 << bit_idx);
|
||||||
else
|
else
|
||||||
bd->data[byte_idx] &= (uint8_t)~(1 << bit_idx);
|
bd->data[byte_idx] &= (uint8_t)~(1 << bit_idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bits_written += bits_to_use;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return JS_ThrowTypeError(ctx, "Second argument must be boolean or random function");
|
return JS_ThrowTypeError(ctx, "Second argument must be boolean or random function");
|
||||||
|
|||||||
@@ -231,20 +231,6 @@ JSC_CCALL(math_from_to,
|
|||||||
return jsarr;
|
return jsarr;
|
||||||
)
|
)
|
||||||
|
|
||||||
JSC_CCALL(math_rand,
|
|
||||||
MTRand *mrand = &((cell_rt*)JS_GetContextOpaque(js))->mrand;
|
|
||||||
return number2js(js, genRand(mrand));
|
|
||||||
)
|
|
||||||
|
|
||||||
JSC_CCALL(math_randi,
|
|
||||||
MTRand *mrand = &((cell_rt*)JS_GetContextOpaque(js))->mrand;
|
|
||||||
return number2js(js, genRandLong(mrand));
|
|
||||||
)
|
|
||||||
|
|
||||||
JSC_CCALL(math_srand,
|
|
||||||
MTRand *mrand = &((cell_rt*)JS_GetContextOpaque(js))->mrand;
|
|
||||||
m_seedRand(mrand, js2number(js,argv[0]));
|
|
||||||
)
|
|
||||||
|
|
||||||
JSC_CCALL(math_dot,
|
JSC_CCALL(math_dot,
|
||||||
size_t alen, blen;
|
size_t alen, blen;
|
||||||
@@ -497,9 +483,6 @@ static const JSCFunctionListEntry js_math_funcs[] = {
|
|||||||
MIST_FUNC_DEF(math, median, 1),
|
MIST_FUNC_DEF(math, median, 1),
|
||||||
MIST_FUNC_DEF(math, length, 1),
|
MIST_FUNC_DEF(math, length, 1),
|
||||||
MIST_FUNC_DEF(math, from_to, 5),
|
MIST_FUNC_DEF(math, from_to, 5),
|
||||||
MIST_FUNC_DEF(math, rand, 0),
|
|
||||||
MIST_FUNC_DEF(math, randi, 0),
|
|
||||||
MIST_FUNC_DEF(math, srand,0),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
JSValue js_math_use(JSContext *js) {
|
JSValue js_math_use(JSContext *js) {
|
||||||
|
|||||||
94
source/qjs_text.c
Normal file
94
source/qjs_text.c
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
#include "qjs_text.h"
|
||||||
|
#include "qjs_blob.h"
|
||||||
|
#include "blob.h"
|
||||||
|
#include "jsffi.h"
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
JSC_CCALL(text_blob_to_hex,
|
||||||
|
size_t blob_len;
|
||||||
|
void *blob_data = js_get_blob_data(js, &blob_len, argv[0]);
|
||||||
|
if (!blob_data) return JS_ThrowTypeError(js, "Expected stone blob");
|
||||||
|
|
||||||
|
uint8_t *bytes = (uint8_t *)blob_data;
|
||||||
|
|
||||||
|
// Hex encoding: each byte becomes 2 hex characters
|
||||||
|
size_t hex_len = blob_len * 2;
|
||||||
|
char *hex_str = malloc(hex_len + 1);
|
||||||
|
|
||||||
|
static const char hex_digits[] = "0123456789ABCDEF";
|
||||||
|
|
||||||
|
for (size_t i = 0; i < blob_len; i++) {
|
||||||
|
hex_str[i * 2] = hex_digits[(bytes[i] >> 4) & 0xF];
|
||||||
|
hex_str[i * 2 + 1] = hex_digits[bytes[i] & 0xF];
|
||||||
|
}
|
||||||
|
|
||||||
|
hex_str[hex_len] = '\0';
|
||||||
|
ret = JS_NewString(js, hex_str);
|
||||||
|
free(hex_str);
|
||||||
|
)
|
||||||
|
|
||||||
|
JSC_CCALL(text_blob_to_base32,
|
||||||
|
size_t blob_len;
|
||||||
|
void *blob_data = js_get_blob_data(js, &blob_len, argv[0]);
|
||||||
|
if (!blob_data) return JS_ThrowTypeError(js, "Expected stone blob");
|
||||||
|
|
||||||
|
uint8_t *bytes = (uint8_t *)blob_data;
|
||||||
|
|
||||||
|
static const char b32_digits[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
|
||||||
|
|
||||||
|
// Calculate output length: each 5 bytes becomes 8 base32 chars
|
||||||
|
size_t groups = (blob_len + 4) / 5;
|
||||||
|
size_t b32_len = groups * 8;
|
||||||
|
char *b32_str = malloc(b32_len + 1);
|
||||||
|
|
||||||
|
size_t in_idx = 0;
|
||||||
|
size_t out_idx = 0;
|
||||||
|
|
||||||
|
while (in_idx < blob_len) {
|
||||||
|
// Process 5 bytes (40 bits) at a time to produce 8 base32 chars
|
||||||
|
uint64_t buf = 0;
|
||||||
|
int bytes_read = 0;
|
||||||
|
|
||||||
|
// Read up to 5 bytes into buffer
|
||||||
|
for (int i = 0; i < 5 && in_idx < blob_len; i++) {
|
||||||
|
buf = (buf << 8) | bytes[in_idx++];
|
||||||
|
bytes_read++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pad with zeros if we read fewer than 5 bytes
|
||||||
|
buf = buf << (8 * (5 - bytes_read));
|
||||||
|
|
||||||
|
// Extract 8 groups of 5 bits from the 40-bit buffer
|
||||||
|
for (int i = 7; i >= 0; i--) {
|
||||||
|
b32_str[out_idx + i] = b32_digits[buf & 0x1F];
|
||||||
|
buf >>= 5;
|
||||||
|
}
|
||||||
|
out_idx += 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Replace trailing chars with padding if needed
|
||||||
|
int padding = (5 - (blob_len % 5)) % 5;
|
||||||
|
if (padding > 0) {
|
||||||
|
static const int pad_chars[] = {0, 6, 4, 3, 1};
|
||||||
|
for (int i = 0; i < pad_chars[padding]; i++) {
|
||||||
|
b32_str[b32_len - 1 - i] = '=';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
b32_str[b32_len] = '\0';
|
||||||
|
ret = JS_NewString(js, b32_str);
|
||||||
|
free(b32_str);
|
||||||
|
)
|
||||||
|
|
||||||
|
static const JSCFunctionListEntry js_text_funcs[] = {
|
||||||
|
MIST_FUNC_DEF(text, blob_to_hex, 1),
|
||||||
|
MIST_FUNC_DEF(text, blob_to_base32, 1),
|
||||||
|
};
|
||||||
|
|
||||||
|
JSValue js_text_use(JSContext *js)
|
||||||
|
{
|
||||||
|
JSValue mod = JS_NewObject(js);
|
||||||
|
JS_SetPropertyFunctionList(js, mod, js_text_funcs, countof(js_text_funcs));
|
||||||
|
return mod;
|
||||||
|
}
|
||||||
8
source/qjs_text.h
Normal file
8
source/qjs_text.h
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#ifndef QJS_TEXT_H
|
||||||
|
#define QJS_TEXT_H
|
||||||
|
|
||||||
|
#include <quickjs.h>
|
||||||
|
|
||||||
|
JSValue js_text_use(JSContext *js);
|
||||||
|
|
||||||
|
#endif
|
||||||
14
tests/guid.ce
Normal file
14
tests/guid.ce
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
var blob = use('blob')
|
||||||
|
var time = use('time')
|
||||||
|
|
||||||
|
var st = time.number()
|
||||||
|
var guid = new blob(256, $_.random_fit)
|
||||||
|
stone(guid)
|
||||||
|
var btime = time.number()-st
|
||||||
|
st = time.number()
|
||||||
|
guid = text(guid,'h')
|
||||||
|
st = time.number()-st
|
||||||
|
log.console(`took ${btime*1000000} us to make blob; took ${st*1000000} us to make it text`)
|
||||||
|
log.console(guid.toLowerCase())
|
||||||
|
log.console(guid.length)
|
||||||
|
$_.stop()
|
||||||
23
tests/text_test.ce
Normal file
23
tests/text_test.ce
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
// Test text module
|
||||||
|
var text = use('text')
|
||||||
|
var blob = use('blob')
|
||||||
|
|
||||||
|
// Create a test blob with some data
|
||||||
|
var b = new blob()
|
||||||
|
b.write_text("Hello")
|
||||||
|
b.stone()
|
||||||
|
|
||||||
|
log.console("Original blob content (as text):", text(b))
|
||||||
|
log.console("Hex encoding:", text(b, 'h'))
|
||||||
|
log.console("Base32 encoding:", text(b, 't'))
|
||||||
|
|
||||||
|
// Test with binary data
|
||||||
|
var b2 = new blob()
|
||||||
|
b2.write_fit(255, 8)
|
||||||
|
b2.write_fit(170, 8) // 10101010 in binary
|
||||||
|
b2.write_fit(15, 8) // 00001111 in binary
|
||||||
|
b2.stone()
|
||||||
|
|
||||||
|
log.console("\nBinary data tests:")
|
||||||
|
log.console("Hex encoding:", text(b2, 'h'))
|
||||||
|
log.console("Base32 encoding:", text(b2, 't'))
|
||||||
Reference in New Issue
Block a user