From 5fcb6d322331a6e2f0eb06472ba403d18f021290 Mon Sep 17 00:00:00 2001 From: Igor Sysoev Date: Tue, 19 Apr 2016 17:26:25 +0300 Subject: [PATCH] Number.toString(radix). --- njs/njs_number.c | 94 +++++++++++++++++++++++++++++++++++++++- njs/test/njs_unit_test.c | 29 +++++++++++++ 2 files changed, 121 insertions(+), 2 deletions(-) diff --git a/njs/njs_number.c b/njs/njs_number.c index f5c66422..8c0bf79a 100644 --- a/njs/njs_number.c +++ b/njs/njs_number.c @@ -22,6 +22,10 @@ #include +static njs_ret_t njs_number_to_string_radix(njs_vm_t *vm, njs_value_t *string, + const njs_value_t *number, uint32_t radix); + + double njs_value_to_number(njs_value_t *value) { @@ -313,6 +317,7 @@ static njs_ret_t njs_number_prototype_to_string(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_index_t unused) { + double radix; njs_value_t *value; value = &args[0]; @@ -328,7 +333,91 @@ njs_number_prototype_to_string(njs_vm_t *vm, njs_value_t *args, } } - return njs_number_to_string(vm, &vm->retval, value); + if (nargs == 1 || args[1].data.u.number == 10) { + return njs_number_to_string(vm, &vm->retval, value); + } + + radix = args[1].data.u.number; + + if (radix < 2 || radix > 36 || radix != (int) radix) { + vm->exception = &njs_exception_range_error; + return NXT_ERROR; + } + + return njs_number_to_string_radix(vm, &vm->retval, value, radix); +} + + +/* + * The radix equal to 2 produces the longest intergral value of a number + * and the maximum value consists of 1024 digits and minus sign. + */ + +#define NJS_STRING_RADIX_INTERGRAL_LEN (1 + 1024) +#define NJS_STRING_RADIX_FRACTION_LEN (1 + 54) +#define NJS_STRING_RADIX_LEN \ + (NJS_STRING_RADIX_INTERGRAL_LEN + NJS_STRING_RADIX_FRACTION_LEN) + + +static njs_ret_t +njs_number_to_string_radix(njs_vm_t *vm, njs_value_t *string, + const njs_value_t *number, uint32_t radix) +{ + u_char *p, *f, *start, *end; + double n, next; + size_t size; + uint8_t reminder; + u_char buf[NJS_STRING_RADIX_LEN]; + + static const char *digits = "0123456789abcdefghijklmnopqrstuvwxyz"; + + end = buf + NJS_STRING_RADIX_LEN; + p = buf + NJS_STRING_RADIX_INTERGRAL_LEN; + + n = number->data.u.number; + + if (n < 0) { + n = -n; + } + + do { + next = trunc(n / radix); + reminder = n - next * radix; + *(--p) = digits[reminder]; + n = next; + } while (n != 0); + + n = number->data.u.number; + + if (n < 0) { + *(--p) = '-'; + } + + f = buf + NJS_STRING_RADIX_INTERGRAL_LEN; + + n = n - trunc(n); + + if (n != 0) { + *f++ = '.'; + + do { + n = n * radix; + reminder = trunc(n); + *f++ = digits[reminder]; + n = n - reminder; + } while (n != 0 && f < end); + } + + size = f - p; + + start = njs_string_alloc(vm, string, size, size); + + if (nxt_fast_path(start != NULL)) { + memcpy(start, p, size); + return NXT_OK; + } + + return NXT_ERROR; } @@ -349,7 +438,8 @@ static const njs_object_prop_t njs_number_prototype_properties[] = { .type = NJS_METHOD, .name = njs_string("toString"), - .value = njs_native_function(njs_number_prototype_to_string, 0, 0), + .value = njs_native_function(njs_number_prototype_to_string, 0, + NJS_SKIP_ARG, NJS_NUMBER_ARG), }, }; diff --git a/njs/test/njs_unit_test.c b/njs/test/njs_unit_test.c index d3fddb00..01038d65 100644 --- a/njs/test/njs_unit_test.c +++ b/njs/test/njs_unit_test.c @@ -92,6 +92,35 @@ static njs_unit_test_t njs_test[] = { nxt_string("\n +1"), nxt_string("1") }, + /* Number.toString(radix) method. */ + + { nxt_string("0..toString(2)"), + nxt_string("0") }, + + { nxt_string("240..toString(2)"), + nxt_string("11110000") }, + + { nxt_string("Math.pow(-2, 1023).toString(2).length"), + nxt_string("1025") }, + + { nxt_string("8.0625.toString(2)"), + nxt_string("1000.0001") }, + + { nxt_string("(1/3).toString(2)"), + nxt_string("0.010101010101010101010101010101010101010101010101010101") }, + + { nxt_string("9999..toString(3)"), + nxt_string("111201100") }, + + { nxt_string("-9999..toString(3)"), + nxt_string("-111201100") }, + + { nxt_string("81985529216486895..toString(16)"), + nxt_string("123456789abcdf0") }, + + { nxt_string("1845449130881..toString(36)"), + nxt_string("njscript") }, + /* An object "valueOf/toString" methods. */ { nxt_string("var a = { valueOf: function() { return 1 } }; +a"), -- 2.47.3