From: Igor Sysoev Date: Tue, 28 Jun 2016 16:28:00 +0000 (+0300) Subject: String.split() method. X-Git-Tag: 0.1.0~18 X-Git-Url: http://git.kaiwu.me/postgresql/log/contrib/postgres_fdw/static/gitweb.js?a=commitdiff_plain;h=d83b756874cca0c574a4ba0caf72a65f3d035e37;p=njs.git String.split() method. --- diff --git a/njs/njs_array.c b/njs/njs_array.c index 45b6b8fa..9c154667 100644 --- a/njs/njs_array.c +++ b/njs/njs_array.c @@ -63,50 +63,6 @@ static nxt_noinline njs_ret_t njs_array_iterator_apply(njs_vm_t *vm, njs_array_next_t *next, njs_value_t *args, nxt_uint_t nargs); -njs_value_t * -njs_array_add(njs_vm_t *vm, njs_value_t *value, u_char *start, size_t size) -{ - njs_ret_t ret; - njs_array_t *array; - - if (value != NULL) { - array = value->data.u.array; - - if (array->size == array->length) { - ret = njs_array_realloc(vm, array, 0, array->size + 1); - if (nxt_slow_path(ret != NXT_OK)) { - return NULL; - } - } - - } else { - value = nxt_mem_cache_align(vm->mem_cache_pool, sizeof(njs_value_t), - sizeof(njs_value_t)); - - if (nxt_slow_path(value == NULL)) { - return NULL; - } - - array = njs_array_alloc(vm, 0, NJS_ARRAY_SPARE); - if (nxt_slow_path(array == NULL)) { - return NULL; - } - - value->data.u.array = array; - value->type = NJS_ARRAY; - value->data.truth = 1; - } - - ret = njs_string_create(vm, &array->start[array->length++], start, size, 0); - - if (nxt_fast_path(ret == NXT_OK)) { - return value; - } - - return NULL; -} - - nxt_noinline njs_array_t * njs_array_alloc(njs_vm_t *vm, uint32_t length, uint32_t spare) { @@ -138,6 +94,24 @@ njs_array_alloc(njs_vm_t *vm, uint32_t length, uint32_t spare) } +njs_ret_t +njs_array_string_add(njs_vm_t *vm, njs_array_t *array, u_char *start, + size_t size, size_t length) +{ + njs_ret_t ret; + + if (array->size == array->length) { + ret = njs_array_realloc(vm, array, 0, array->size + 1); + if (nxt_slow_path(ret != NXT_OK)) { + return ret; + } + } + + return njs_string_create(vm, &array->start[array->length++], + start, size, length); +} + + njs_ret_t njs_array_realloc(njs_vm_t *vm, njs_array_t *array, uint32_t prepend, uint32_t size) diff --git a/njs/njs_array.h b/njs/njs_array.h index c6b8d0b0..f853f8a2 100644 --- a/njs/njs_array.h +++ b/njs/njs_array.h @@ -21,6 +21,8 @@ struct njs_array_s { njs_array_t *njs_array_alloc(njs_vm_t *vm, uint32_t length, uint32_t spare); +njs_ret_t njs_array_string_add(njs_vm_t *vm, njs_array_t *array, u_char *start, + size_t size, size_t length); njs_ret_t njs_array_realloc(njs_vm_t *vm, njs_array_t *array, uint32_t prepend, uint32_t size); njs_ret_t njs_array_constructor(njs_vm_t *vm, njs_value_t *args, diff --git a/njs/njs_string.c b/njs/njs_string.c index 7eff704a..af02fa31 100644 --- a/njs/njs_string.c +++ b/njs/njs_string.c @@ -1645,6 +1645,160 @@ empty: } +/* + * String.split([string|regexp[, limit]]) + */ + +static njs_ret_t +njs_string_prototype_split(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, + njs_index_t unused) +{ + int ret, *captures; + u_char *p, *start, *next; + size_t size, length; + uint32_t limit; + nxt_uint_t n; + njs_array_t *array; + const u_char *end; + njs_string_prop_t string, split; + njs_regexp_pattern_t *pattern; + + array = njs_array_alloc(vm, 0, NJS_ARRAY_SPARE); + if (nxt_slow_path(array == NULL)) { + return NXT_ERROR; + } + + if (nargs > 1) { + + if (nargs > 2) { + limit = args[2].data.u.number; + + if (limit == 0) { + goto done; + } + + } else { + limit = (uint32_t) -1; + } + + switch (args[1].type) { + + case NJS_STRING: + (void) njs_string_prop(&split, &args[1]); + + length = njs_string_prop(&string, &args[0]); + + if (string.size < split.size) { + goto single; + } + + start = string.start; + end = string.start + string.size; + + do { + for (p = start; p < end; p++) { + if (memcmp(p, split.start, split.size) == 0) { + break; + } + } + + next = p + split.size; + + /* Empty split string. */ + if (p == next) { + p++; + next++; + } + + size = p - start; + length = nxt_utf8_length(start, size); + + ret = njs_array_string_add(vm, array, start, size, length); + if (nxt_slow_path(ret != NXT_OK)) { + return ret; + } + + start = next; + limit--; + + } while (limit != 0 && p < end); + + goto done; + + case NJS_REGEXP: + pattern = args[1].data.u.regexp->pattern; + + (void) njs_string_prop(&string, &args[0]); + + n = (string.length != 0 && string.length != string.size); + + if (!nxt_regex_is_valid(&pattern->regex[n])) { + goto single; + } + + start = string.start; + end = string.start + string.size; + + do { + ret = nxt_regex_match(&pattern->regex[n], start, end - start, + vm->single_match_data, vm->regex_context); + if (ret >= 0) { + captures = nxt_regex_captures(vm->single_match_data); + + p = start + captures[0]; + next = start + captures[1]; + + } else if (ret == NGX_REGEX_NOMATCH) { + p = (u_char *) end; + next = (u_char *) end + 1; + + } else { + return njs_string_exception(vm, NJS_INTERNAL_ERROR, + vm->regex_context->error); + } + + /* Empty split regexp. */ + if (p == next) { + p++; + next++; + } + + size = p - start; + length = nxt_utf8_length(start, size); + + ret = njs_array_string_add(vm, array, start, size, length); + if (nxt_slow_path(ret != NXT_OK)) { + return ret; + } + + start = next; + limit--; + + } while (limit != 0 && p < end); + + goto done; + + default: /* NJS_VOID */ + break; + } + } + +single: + + /* GC: retain. */ + array->start[0] = args[0]; + array->length = 1; + +done: + + vm->retval.data.u.array = array; + vm->retval.type = NJS_ARRAY; + vm->retval.data.truth = 1; + + return NXT_OK; +} + + njs_ret_t njs_primitive_value_to_string(njs_vm_t *vm, njs_value_t *dst, const njs_value_t *src) @@ -1901,6 +2055,13 @@ static const njs_object_prop_t njs_string_prototype_properties[] = .value = njs_native_function(njs_string_prototype_match, 0, NJS_STRING_ARG, NJS_REGEXP_ARG), }, + + { + .type = NJS_METHOD, + .name = njs_string("split"), + .value = njs_native_function(njs_string_prototype_split, 0, + NJS_STRING_OBJECT_ARG, NJS_REGEXP_ARG, NJS_INTEGER_ARG), + }, }; diff --git a/njs/njscript.h b/njs/njscript.h index 93509352..188e13c6 100644 --- a/njs/njscript.h +++ b/njs/njscript.h @@ -106,8 +106,5 @@ NXT_EXPORT void *njs_value_data(njs_value_t *value); NXT_EXPORT nxt_int_t njs_value_string_copy(njs_vm_t *vm, nxt_str_t *retval, njs_value_t *value, uintptr_t *next); -NXT_EXPORT njs_value_t *njs_array_add(njs_vm_t *vm, njs_value_t *array, - u_char *start, size_t size); - #endif /* _NJSCRIPT_H_INCLUDED_ */ diff --git a/njs/test/njs_unit_test.c b/njs/test/njs_unit_test.c index e07ca74f..0c2b9a93 100644 --- a/njs/test/njs_unit_test.c +++ b/njs/test/njs_unit_test.c @@ -2924,6 +2924,48 @@ static njs_unit_test_t njs_test[] = "a +' '+ a.length"), nxt_string("αα 4") }, + { nxt_string("'abc'.split()"), + nxt_string("abc") }, + + { nxt_string("'abc'.split(undefined)"), + nxt_string("abc") }, + + { nxt_string("''.split('').length"), + nxt_string("1") }, + + { nxt_string("'abc'.split('')"), + nxt_string("a,b,c") }, + + { nxt_string("'a bc def'.split(' ')"), + nxt_string("a,bc,def") }, + + { nxt_string("'a bc def'.split(' ')"), + nxt_string("a,bc,,def") }, + + { nxt_string("'a bc def'.split(' ', 3)"), + nxt_string("a,bc,") }, + + { nxt_string("'abc'.split('abc')"), + nxt_string(",") }, + + { nxt_string("'ab'.split('123')"), + nxt_string("ab") }, + + { nxt_string("''.split(/0/).length"), + nxt_string("1") }, + + { nxt_string("'abc'.split(/(?:)/)"), + nxt_string("a,b,c") }, + + { nxt_string("'a bc def'.split(/ /)"), + nxt_string("a,bc,def") }, + + { nxt_string("'a bc def'.split(/ /)"), + nxt_string("a,bc,,def") }, + + { nxt_string("'abc'.split(/abc/)"), + nxt_string(",") }, + /* Functions. */ { nxt_string("function f() { } f()"),