]> git.kaiwu.me - njs.git/commitdiff
Number.toString(radix).
authorIgor Sysoev <igor@sysoev.ru>
Tue, 19 Apr 2016 14:26:25 +0000 (17:26 +0300)
committerIgor Sysoev <igor@sysoev.ru>
Tue, 19 Apr 2016 14:26:25 +0000 (17:26 +0300)
njs/njs_number.c
njs/test/njs_unit_test.c

index f5c66422fafa56147625bda2e6b811bf0af2257c..8c0bf79a85c383d530a0890fcbf59fe97bfefcad 100644 (file)
 #include <stdio.h>
 
 
+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),
     },
 };
 
index d3fddb003a8ae16f456c6ae05104f60fcb0a5579..01038d656377e661cc99b3386053632c08eb6388 100644 (file)
@@ -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"),