} njs_array_iterator_fun_t;
+static void njs_typed_array_prop_set(njs_vm_t *vm, njs_typed_array_t *array,
+ uint32_t index, double v);
+
+
njs_typed_array_t *
njs_typed_array_alloc(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
njs_object_type_t type)
size = (uint64_t) njs_typed_array_length(src_tarray) * element_size;
} else if (njs_is_object(value)) {
- if (njs_is_array(value) && njs_object_hash_is_empty(value)) {
+ if (njs_is_fast_array(value)) {
src_array = njs_array(value);
length = src_array->length;
if (type != src_tarray->type) {
length = njs_typed_array_length(src_tarray);
for (i = 0; i < length; i++) {
- njs_typed_array_set(array, i,
- njs_typed_array_get(src_tarray, i));
+ njs_typed_array_prop_set(vm, array, i,
+ njs_typed_array_prop(src_tarray, i));
}
} else {
}
if (ret == NJS_OK) {
- njs_typed_array_set(array, i, num);
+ njs_typed_array_prop_set(vm, array, i, num);
}
}
}
}
- njs_typed_array_set(array, i, num);
+ njs_typed_array_prop_set(vm, array, i, num);
}
}
}
+njs_int_t
+njs_typed_array_uint8_set(njs_vm_t *vm, njs_value_t *value, const u_char *start,
+ uint32_t size)
+{
+ njs_object_t *proto;
+ njs_typed_array_t *array;
+ njs_array_buffer_t *buffer;
+
+ array = njs_mp_zalloc(vm->mem_pool, sizeof(njs_typed_array_t)
+ + sizeof(njs_array_buffer_t));
+ if (njs_slow_path(array == NULL)) {
+ njs_memory_error(vm);
+ return NJS_ERROR;
+ }
+
+ buffer = (njs_array_buffer_t *) &array[1];
+
+ proto = &vm->prototypes[NJS_OBJ_TYPE_ARRAY_BUFFER].object;
+
+ njs_lvlhsh_init(&buffer->object.hash);
+ njs_lvlhsh_init(&buffer->object.shared_hash);
+ buffer->object.__proto__ = proto;
+ buffer->object.slots = NULL;
+ buffer->object.type = NJS_ARRAY_BUFFER;
+ buffer->object.shared = 1;
+ buffer->object.extensible = 1;
+ buffer->object.error_data = 0;
+ buffer->object.fast_array = 0;
+ buffer->u.data = (void *) start;
+ buffer->size = size;
+
+ array->buffer = buffer;
+ array->byte_length = size;
+ array->type = NJS_OBJ_TYPE_UINT8_ARRAY;
+ njs_lvlhsh_init(&array->object.hash);
+ njs_lvlhsh_init(&array->object.shared_hash);
+ array->object.__proto__ = &vm->prototypes[array->type].object;
+ array->object.type = NJS_TYPED_ARRAY;
+ array->object.extensible = 1;
+ array->object.fast_array = 1;
+
+ njs_set_typed_array(value, array);
+
+ return NJS_OK;
+}
+
+
static njs_int_t
njs_typed_array_constructor(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
njs_index_t magic)
}
+njs_array_buffer_t *
+njs_typed_array_writable(njs_vm_t *vm, njs_typed_array_t *array)
+{
+ njs_int_t ret;
+ njs_array_buffer_t *buffer;
+
+ buffer = array->buffer;
+
+ ret = njs_array_buffer_writable(vm, buffer);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return NULL;
+ }
+
+ return buffer;
+}
+
+
static const njs_value_t njs_typed_array_uint8_tag = njs_string("Uint8Array");
static const njs_value_t njs_typed_array_uint8_clamped_tag =
njs_long_string("Uint8ClampedArray");
}
+static void
+njs_typed_array_prop_set(njs_vm_t *vm, njs_typed_array_t *array, uint32_t index,
+ double v)
+{
+ int8_t i8;
+ int16_t i16;
+ int32_t i32;
+ njs_array_buffer_t *buffer;
+
+ buffer = array->buffer;
+ index += array->offset;
+
+ njs_assert(!buffer->object.shared);
+
+ switch (array->type) {
+ case NJS_OBJ_TYPE_UINT8_CLAMPED_ARRAY:
+ if (isnan(v) || v < 0) {
+ v = 0;
+ } else if (v > 255) {
+ v = 255;
+ }
+
+ buffer->u.u8[index] = lrint(v);
+
+ break;
+
+ case NJS_OBJ_TYPE_UINT8_ARRAY:
+ case NJS_OBJ_TYPE_INT8_ARRAY:
+ i8 = njs_number_to_int32(v);
+ buffer->u.u8[index] = i8;
+ break;
+
+ case NJS_OBJ_TYPE_UINT16_ARRAY:
+ case NJS_OBJ_TYPE_INT16_ARRAY:
+ i16 = njs_number_to_int32(v);
+ buffer->u.u16[index] = i16;
+ break;
+
+ case NJS_OBJ_TYPE_UINT32_ARRAY:
+ case NJS_OBJ_TYPE_INT32_ARRAY:
+ i32 = njs_number_to_int32(v);
+ buffer->u.u32[index] = i32;
+ break;
+
+ case NJS_OBJ_TYPE_FLOAT32_ARRAY:
+ buffer->u.f32[index] = v;
+ break;
+
+ default:
+
+ /* NJS_OBJ_TYPE_FLOAT64_ARRAY. */
+
+ buffer->u.f64[index] = v;
+ }
+}
+
+
njs_int_t
njs_typed_array_set_value(njs_vm_t *vm, njs_typed_array_t *array,
uint32_t index, njs_value_t *setval)
{
- double num;
- njs_int_t ret;
+ double num;
+ njs_int_t ret;
+ njs_array_buffer_t *buffer;
ret = njs_value_to_number(vm, setval, &num);
if (njs_slow_path(ret != NJS_OK)) {
return ret;
}
- njs_typed_array_set(array, index, num);
+ buffer = njs_typed_array_writable(vm, array);
+ if (njs_slow_path(buffer == NULL)) {
+ return NJS_ERROR;
+ }
+
+ njs_typed_array_prop_set(vm, array, index, num);
njs_set_number(setval, num);
njs_typed_array_prototype_set(njs_vm_t *vm, njs_value_t *args,
njs_uint_t nargs, njs_index_t unused)
{
- double num;
- int64_t i, length, src_length, offset;
- njs_int_t ret;
- njs_value_t *this, *src, *value, prop;
- njs_array_t *array;
- njs_typed_array_t *self, *src_tarray;
+ double num;
+ int64_t i, length, src_length, offset;
+ njs_int_t ret;
+ njs_value_t *this, *src, *value, prop;
+ njs_array_t *array;
+ njs_typed_array_t *self, *src_tarray;
+ njs_array_buffer_t *buffer;
this = njs_argument(args, 0);
if (njs_slow_path(!njs_is_typed_array(this))) {
return NJS_ERROR;
}
+ buffer = njs_typed_array_writable(vm, self);
+ if (njs_slow_path(buffer == NULL)) {
+ return NJS_ERROR;
+ }
+
length = njs_typed_array_length(self);
if (njs_is_typed_array(src)) {
length = njs_min(njs_typed_array_length(src_tarray), length - offset);
for (i = 0; i < length; i++) {
- njs_typed_array_set(self, offset + i,
- njs_typed_array_get(src_tarray, i));
+ njs_typed_array_prop_set(vm, self, offset + i,
+ njs_typed_array_prop(src_tarray, i));
}
} else {
- if (njs_is_array(src) && njs_object_hash_is_empty(src)) {
+ if (njs_is_fast_array(src)) {
array = njs_array(src);
src_length = array->length;
for (i = 0; i < length; i++) {
ret = njs_value_to_number(vm, &array->start[i], &num);
if (ret == NJS_OK) {
- njs_typed_array_set(self, offset + i, num);
+ njs_typed_array_prop_set(vm, self, offset + i, num);
}
}
}
}
- njs_typed_array_set(self, offset + i, num);
+ njs_typed_array_prop_set(vm, self, offset + i, num);
}
}
end = (end < 0) ? njs_max(length + end, 0) : njs_min(end, length);
+ buffer = njs_typed_array_writable(vm, array);
+ if (njs_slow_path(buffer == NULL)) {
+ return NJS_ERROR;
+ }
+
njs_set_typed_array(&vm->retval, array);
- buffer = array->buffer;
offset = array->offset;
switch (array->type) {
} else {
for (i = 0; i < count; i++) {
- njs_typed_array_set(new_array, i,
- njs_typed_array_get(array, i + start));
+ njs_typed_array_prop_set(vm, new_array, i,
+ njs_typed_array_prop(array, i + start));
}
}
return NJS_OK;
}
- buffer = njs_typed_array_buffer(array);
+ buffer = njs_typed_array_writable(vm, array);
+ if (njs_slow_path(buffer == NULL)) {
+ return NJS_ERROR;
+ }
+
element_size = njs_typed_array_element_size(array->type);
to = (to + array->offset) * element_size;
}
for (i = 0; i < length; i++) {
- val = njs_typed_array_get(array, i);
+ val = njs_typed_array_prop(array, i);
arguments[0] = *this_arg;
njs_set_number(&arguments[1], val);
accumulator = *njs_argument(args, 2);
} else {
- njs_set_number(&accumulator, njs_typed_array_get(array, from));
+ njs_set_number(&accumulator, njs_typed_array_prop(array, from));
from += increment;
}
for (i = from; i != to; i += increment) {
njs_set_undefined(&arguments[0]);
arguments[1] = accumulator;
- njs_set_number(&arguments[2], njs_typed_array_get(array, i));
+ njs_set_number(&arguments[2], njs_typed_array_prop(array, i));
njs_set_number(&arguments[3], i);
njs_set_typed_array(&arguments[4], array);
array = njs_typed_array(this);
length = njs_typed_array_length(array);
- buffer = array->buffer;
+ buffer = njs_typed_array_writable(vm, array);
+ if (njs_slow_path(buffer == NULL)) {
+ return NJS_ERROR;
+ }
switch (array->type) {
case NJS_OBJ_TYPE_UINT8_ARRAY:
break;
}
+ buffer = njs_typed_array_writable(vm, array);
+ if (njs_slow_path(buffer == NULL)) {
+ return NJS_ERROR;
+ }
+
length = njs_typed_array_length(array);
- buffer = njs_typed_array_buffer(array);
element_size = njs_typed_array_element_size(array->type);
base = &buffer->u.u8[array->offset * element_size];
orig = base;
}
for (i = 0; i < arr_length; i++) {
- njs_number_to_chain(vm, chain, njs_typed_array_get(array, i));
+ njs_number_to_chain(vm, chain, njs_typed_array_prop(array, i));
njs_chb_append(chain, separator.start, separator.size);
}
njs_typed_array_t *njs_typed_array_alloc(njs_vm_t *vm, njs_value_t *args,
njs_uint_t nargs, njs_object_type_t type);
+njs_int_t njs_typed_array_uint8_set(njs_vm_t *vm, njs_value_t *value,
+ const u_char *start, uint32_t size);
+njs_array_buffer_t *njs_typed_array_writable(njs_vm_t *vm,
+ njs_typed_array_t *array);
njs_int_t njs_typed_array_set_value(njs_vm_t *vm, njs_typed_array_t *array,
uint32_t index, njs_value_t *setval);
njs_int_t njs_typed_array_to_chain(njs_vm_t *vm, njs_chb_t *chain,
njs_inline double
-njs_typed_array_get(const njs_typed_array_t *array, uint32_t index)
+njs_typed_array_prop(const njs_typed_array_t *array, uint32_t index)
{
njs_array_buffer_t *buffer;
}
-njs_inline void
-njs_typed_array_set(njs_typed_array_t *array, uint32_t index, double v)
-{
- int8_t i8;
- int16_t i16;
- int32_t i32;
- njs_array_buffer_t *buffer;
-
- index += array->offset;
-
- buffer = array->buffer;
-
- switch (array->type) {
- case NJS_OBJ_TYPE_UINT8_CLAMPED_ARRAY:
- if (isnan(v) || v < 0) {
- v = 0;
- } else if (v > 255) {
- v = 255;
- }
-
- buffer->u.u8[index] = lrint(v);
-
- break;
-
- case NJS_OBJ_TYPE_UINT8_ARRAY:
- case NJS_OBJ_TYPE_INT8_ARRAY:
- i8 = njs_number_to_int32(v);
- buffer->u.u8[index] = i8;
- break;
-
- case NJS_OBJ_TYPE_UINT16_ARRAY:
- case NJS_OBJ_TYPE_INT16_ARRAY:
- i16 = njs_number_to_int32(v);
- buffer->u.u16[index] = i16;
- break;
-
- case NJS_OBJ_TYPE_UINT32_ARRAY:
- case NJS_OBJ_TYPE_INT32_ARRAY:
- i32 = njs_number_to_int32(v);
- buffer->u.u32[index] = i32;
- break;
-
- case NJS_OBJ_TYPE_FLOAT32_ARRAY:
- buffer->u.f32[index] = v;
- break;
-
- default:
-
- /* NJS_OBJ_TYPE_FLOAT64_ARRAY. */
-
- buffer->u.f64[index] = v;
- }
-}
-
-
extern const njs_object_type_init_t njs_typed_array_type_init;
extern const njs_object_type_init_t njs_typed_array_u8_type_init;
extern const njs_object_type_init_t njs_typed_array_u8clamped_type_init;
{ njs_str("var r = JSON.parse(JSON.stringify($r));"
"[r.uri, r.host, r.props.a, njs.dump(r.vars), njs.dump(r.consts), r.header['02']]"),
njs_str("АБВ,АБВГДЕЁЖЗИЙ,1,{},{},02|АБВ") },
+
+ { njs_str("var s = (new TextDecoder()).decode($r.u8buffer); [s, s.length]"),
+ njs_str("АБВГДЕЁЖЗИЙ,11") },
+
+ { njs_str("var b = $r.u8buffer; "
+ "b[4] = '@'.codePointAt(0); b[5] = '#'.codePointAt(0);"
+ "var s = (new TextDecoder()).decode(b); [s, s.length]"),
+ njs_str("АБ@#ГДЕЁЖЗИЙ,12") },
+
+ { njs_str("var b = $r.u8buffer; "
+ "b.copyWithin(16,0,6);"
+ "var s = (new TextDecoder()).decode(b); [s, s.length]"),
+ njs_str("АБВГДЕЁЖАБВ,11") },
+
+ { njs_str("var b = $r.u8buffer; "
+ "b.fill('#'.codePointAt(0));"
+ "var s = (new TextDecoder()).decode(b); [s, s.length]"),
+ njs_str("######################,22") },
+
+ { njs_str("var b = $r.u8buffer; "
+ "b.set(['@'.codePointAt(0), '#'.codePointAt(0)], 4);"
+ "var s = (new TextDecoder()).decode(b); [s, s.length]"),
+ njs_str("АБ@#ГДЕЁЖЗИЙ,12") },
+
+ { njs_str("var b = $r.u8buffer; "
+ "var u16 = new Uint16Array(b.buffer); u16.reverse();"
+ "var s = (new TextDecoder()).decode(u16); [s, s.length]"),
+ njs_str("ЙИЗЖЁЕДГВБА,11") },
+
+ { njs_str("$r.u8buffer.sort().slice(0,3)"),
+ njs_str("129,144,145") },
};
static njs_unit_test_t njs_shared_test[] =