static jv* jvp_array_write(jv* a, int i) { assert(i >= 0); jvp_array* array = jvp_array_ptr(*a); int pos = i + jvp_array_offset(*a); if (pos < array->alloc_length && jvp_refcnt_unshared(a->u.ptr)) { // use existing array space for (int j = array->length; j <= pos; j++) { array->elements[j] = JV_NULL; } array->length = imax(pos + 1, array->length); a->size = imax(i + 1, a->size); return &array->elements[pos]; } else { // allocate a new array int new_length = imax(i + 1, jvp_array_length(*a)); jvp_array* new_array = jvp_array_alloc(ARRAY_SIZE_ROUND_UP(new_length)); int j; for (j = 0; j < jvp_array_length(*a); j++) { new_array->elements[j] = jv_copy(array->elements[j + jvp_array_offset(*a)]); } for (; j < new_length; j++) { new_array->elements[j] = JV_NULL; } new_array->length = new_length; jvp_array_free(*a); jv new_jv = {JV_KIND_ARRAY, 0, 0, new_length, {&new_array->refcnt}}; *a = new_jv; return &new_array->elements[i]; } }
static int jvp_array_equal(jv a, jv b) { if (jvp_array_length(a) != jvp_array_length(b)) return 0; if (jvp_array_ptr(a) == jvp_array_ptr(b) && jvp_array_offset(a) == jvp_array_offset(b)) return 1; for (int i=0; i<jvp_array_length(a); i++) { if (!jv_equal(jv_copy(*jvp_array_read(a, i)), jv_copy(*jvp_array_read(b, i)))) return 0; } return 1; }
static int jvp_array_equal(jv_nontrivial* a, jv_nontrivial* b) { if (jvp_array_length(a) != jvp_array_length(b)) return 0; if (jvp_array_ptr(a) == jvp_array_ptr(b) && a->i[0] == b->i[0]) return 1; for (int i=0; i<jvp_array_length(a); i++) { if (!jv_equal(jv_copy(*jvp_array_read(a, i)), jv_copy(*jvp_array_read(b,i)))) return 0; } return 1; }
static jv* jvp_array_read(jv_nontrivial* 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_slice(jv a, int start, int end) { assert(jv_get_kind(a) == JV_KIND_ARRAY); // FIXME: maybe slice should reallocate if the slice is small enough assert(0 <= start && start <= end); assert(end <= jvp_array_length(a)); // FIXME FIXME FIXME large offsets a.offset += start; a.size = end - start; return a; }
static jv* jvp_array_read(jv a, int i) { assert(jv_get_kind(a) == JV_KIND_ARRAY); if (i >= 0 && i < jvp_array_length(a)) { jvp_array* array = jvp_array_ptr(a); assert(i + jvp_array_offset(a) < array->length); return &array->elements[i + jvp_array_offset(a)]; } else { return 0; } }
static jv* jvp_array_write(jv_nontrivial* 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, a->i[1]); return &array->elements[pos]; } } int new_length = imax(i + 1, jvp_array_length(a)); jvp_array* new_array = jvp_array_alloc(ARRAY_SIZE_ROUND_UP(new_length)); int j; for (j = 0; j < jvp_array_length(a); j++) { new_array->elements[j] = jv_copy(array->elements[j + a->i[0]]); } for (; j < new_length; j++) { new_array->elements[j] = JV_NULL; } new_array->length = new_length; jvp_array_free(a); a->ptr = &new_array->refcnt; a->i[0] = 0; a->i[1] = new_length; return &new_array->elements[i]; }
int jv_array_length(jv j) { assert(jv_get_kind(j) == JV_KIND_ARRAY); int len = jvp_array_length(j); jv_free(j); return len; }