#include <stdint.h>
#include <stddef.h>
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "jv.h"
/*
* Internal refcounting helpers
*/
static void jvp_refcnt_init(jv_complex* c) {
c->ptr->count = 1;
}
static void jvp_refcnt_inc(jv_complex* c) {
c->ptr->count++;
}
static int jvp_refcnt_dec(jv_complex* c) {
c->ptr->count--;
return c->ptr->count == 0;
}
static int jvp_refcnt_unshared(jv_complex* c) {
assert(c->ptr->count > 0);
return c->ptr->count == 1;
}
/*
* Simple values (true, false, null)
*/
jv_kind jv_get_kind(jv x) {
return x.kind;
}
static const jv JV_INVALID = {JV_KIND_INVALID, {0}};
static const jv JV_NULL = {JV_KIND_NULL, {0}};
static const jv JV_FALSE = {JV_KIND_FALSE, {0}};
static const jv JV_TRUE = {JV_KIND_TRUE, {0}};
jv jv_invalid() {
return JV_INVALID;
}
jv jv_true() {
return JV_TRUE;
}
jv jv_false() {
return JV_FALSE;
}
jv jv_null() {
return JV_NULL;
}
jv jv_bool(int x) {
return x ? JV_TRUE : JV_FALSE;
}
/*
* Numbers
*/
jv jv_number(double x) {
jv j;
j.kind = JV_KIND_NUMBER;
j.val.number = x;
return j;
}
double jv_number_value(jv j) {
assert(jv_get_kind(j) == JV_KIND_NUMBER);
return j.val.number;
}
/*
* Arrays (internal helpers)
*/
#define ARRAY_SIZE_ROUND_UP(n) (((n)*3)/2)
static int imax(int a, int b) {
if (a>b) return a;
else return b;
}
//FIXME signed vs unsigned
typedef struct {
jv_refcnt refcnt;
int length, alloc_length;
jv elements[];
} jvp_array;
static jvp_array* jvp_array_ptr(jv_complex* a) {
return (jvp_array*)a->ptr;
}
static jvp_array* jvp_array_alloc(unsigned size) {
jvp_array* a = malloc(sizeof(jvp_array) + sizeof(jv) * size);
a->refcnt.count = 1;
a->length = 0;
a->alloc_length = size;
return a;
}
static jv_complex jvp_array_new(unsigned size) {
jv_complex r = {&jvp_array_alloc(size)->refcnt, {0, 0}};
return r;
}
static void jvp_array_free(jv_complex* a) {
if (jvp_refcnt_dec(a)) {
jvp_array* array = jvp_array_ptr(a);
for (int i=0; i<array->length; i++) {
jv_free(array->elements[i]);
}
free(array);
}
}
static int jvp_array_length(jv_complex* a) {
return a->i[1] - a->i[0];
}
static jv* jvp_array_read(jv_complex* a, int i) {
if (i >= 0 && i < jvp_array_length(a)) {
jvp_array* array = jvp_array_ptr(a);
assert(i + a->i[0] < array->length);
return &array->elements[i + a->i[0]];
} else {
return 0;
}
}
static jv* jvp_array_write(jv_complex* a, int i) {
assert(i >= 0);
jvp_array* array = jvp_array_ptr(a);
int pos = i + a->i[0];
if (pos < array->alloc_length) {
// maybe we can update it in-place
// FIXME: this "optimisation" can cause circular references
#if 0
int can_write_past_end =
array->length <= pos && /* the end of this array has never been used */
a->i[1] == array->length; /* the current slice sees the end of the array */
#endif
int can_write_past_end = 0;
if (can_write_past_end || jvp_refcnt_unshared(a)) {
// extend the array
for (int j = array->length; j <= pos; j++) {
array->elements[j] = JV_NULL;
}
array->length = imax(pos + 1, array->length);
a->i[1] = imax(pos + 1, array->length);
return &array->elements[pos];
}
}
int new_length = imax(i + 1, jvp_array_length(a));
jvp_array* new_arra