@@ -19,10 +19,16 @@ type BigInt
1919let zero = 0N
2020
2121///|
22- pub fn BigInt ::from_string (str : String ) -> BigInt {
22+ pub fn BigInt ::from_string (str : String , radix ? : Int = 10 ) -> BigInt {
2323 if str .length () == 0 {
2424 abort ("empty string" )
2525 }
26+ if radix < 2 || radix > 36 {
27+ abort ("radix must be between 2 and 36" )
28+ }
29+ if radix != 10 {
30+ return BigInt ::from_string_radix (str , radix )
31+ }
2632 BigInt ::js_from_string (str )
2733}
2834
@@ -31,27 +37,76 @@ extern "js" fn BigInt::js_from_string(str : String) -> BigInt =
3137 #| (x) => BigInt(x)
3238
3339///|
34- pub impl Show for BigInt with output (self , logger ) {
35- logger .write_string (self .to_string ())
40+ fn digit_from_char (x : Int ) -> Int {
41+ match x {
42+ '0' ..= '9' => x - '0'
43+ 'A' ..= 'Z' => x + (10 - 'A' )
44+ 'a' ..= 'z' => x + (10 - 'a' )
45+ _ => - 1
46+ }
3647}
3748
3849///|
39- pub extern "js" fn BigInt ::to_string (self : BigInt ) -> String =
40- #| (x) => String(x)
50+ fn pow2_shift (radix : Int ) -> Int? {
51+ if radix >= 2 && (radix & (radix - 1 )) == 0 {
52+ Some (radix .ctz ())
53+ } else {
54+ None
55+ }
56+ }
4157
4258///|
43- pub extern "js" fn BigInt ::from_hex (str : String ) -> BigInt =
44- #| (x) => x.startsWith('-') ? -BigInt(`0x${x.slice(1)}`) : BigInt(`0x${x}`)
59+ fn BigInt ::from_string_radix (str : String , radix : Int ) -> BigInt {
60+ let len = str .length ()
61+ let sign = if str .unsafe_get (0 ) == '-' { - 1 } else { 1 }
62+ let start = if sign == - 1 { 1 } else { 0 }
63+ if start == len {
64+ abort ("invalid character" )
65+ }
66+ let mut acc = 0N
67+ match pow2_shift (radix ) {
68+ Some (shift ) =>
69+ for i in start ..< len {
70+ let digit = digit_from_char (str .unsafe_get (i ).to_int ())
71+ if digit < 0 || digit >= radix {
72+ abort ("invalid character" )
73+ }
74+ acc = (acc << shift ) | BigInt ::from_int (digit )
75+ }
76+ None => {
77+ let base = BigInt ::from_int (radix )
78+ for i in start ..< len {
79+ let digit = digit_from_char (str .unsafe_get (i ).to_int ())
80+ if digit < 0 || digit >= radix {
81+ abort ("invalid character" )
82+ }
83+ acc = acc * base + BigInt ::from_int (digit )
84+ }
85+ }
86+ }
87+ if sign == - 1 {
88+ - acc
89+ } else {
90+ acc
91+ }
92+ }
4593
4694///|
47- pub extern "js" fn BigInt ::to_hex (
48- self : BigInt ,
49- uppercase ? : Bool = true ,
50- ) -> String =
51- #| (x, uppercase) => {
52- #| const r = x.toString(16);
53- #| return uppercase ? r.toUpperCase() : r;
54- #| }
95+ pub impl Show for BigInt with output (self , logger ) {
96+ logger .write_string (self .to_string ())
97+ }
98+
99+ ///|
100+ pub fn BigInt ::to_string (self : BigInt , radix ? : Int = 10 ) -> String {
101+ if radix < 2 || radix > 36 {
102+ abort ("radix must be between 2 and 36" )
103+ }
104+ BigInt ::js_to_string_radix (self , radix )
105+ }
106+
107+ ///|
108+ extern "js" fn BigInt ::js_to_string_radix (self : BigInt , radix : Int ) -> String =
109+ #| (x, radix) => x.toString(radix)
55110
56111///|
57112extern "js" fn hex2 (b : Byte ) -> String =
0 commit comments