strconv.odin 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483
  1. using import "core:decimal.odin"
  2. Int_Flag :: enum {
  3. Prefix = 1<<0,
  4. Plus = 1<<1,
  5. Space = 1<<2,
  6. }
  7. parse_bool :: proc(s: string) -> (result: bool = false, ok: bool) {
  8. switch s {
  9. case "1", "t", "T", "true", "TRUE", "True":
  10. return true, true;
  11. case "0", "f", "F", "false", "FALSE", "False":
  12. return false, true;
  13. }
  14. return ok = false;
  15. }
  16. _digit_value :: proc(r: rune) -> int {
  17. ri := int(r);
  18. v: int = 16;
  19. switch r {
  20. case '0'...'9': v = ri-'0';
  21. case 'a'...'z': v = ri-'a'+10;
  22. case 'A'...'Z': v = ri-'A'+10;
  23. }
  24. return v;
  25. }
  26. parse_i128 :: proc(s: string) -> i128 {
  27. neg := false;
  28. if len(s) > 1 {
  29. switch s[0] {
  30. case '-':
  31. neg = true;
  32. s = s[1..];
  33. case '+':
  34. s = s[1..];
  35. }
  36. }
  37. base: i128 = 10;
  38. if len(s) > 2 && s[0] == '0' {
  39. switch s[1] {
  40. case 'b': base = 2; s = s[2..];
  41. case 'o': base = 8; s = s[2..];
  42. case 'd': base = 10; s = s[2..];
  43. case 'z': base = 12; s = s[2..];
  44. case 'x': base = 16; s = s[2..];
  45. }
  46. }
  47. value: i128;
  48. for r in s {
  49. if r == '_' {
  50. continue;
  51. }
  52. v := i128(_digit_value(r));
  53. if v >= base {
  54. break;
  55. }
  56. value *= base;
  57. value += v;
  58. }
  59. if neg do return -value;
  60. return value;
  61. }
  62. parse_u128 :: proc(s: string) -> u128 {
  63. neg := false;
  64. if len(s) > 1 && s[0] == '+' {
  65. s = s[1..];
  66. }
  67. base := u128(10);
  68. if len(s) > 2 && s[0] == '0' {
  69. switch s[1] {
  70. case 'b': base = 2; s = s[2..];
  71. case 'o': base = 8; s = s[2..];
  72. case 'd': base = 10; s = s[2..];
  73. case 'z': base = 12; s = s[2..];
  74. case 'x': base = 16; s = s[2..];
  75. }
  76. }
  77. value: u128;
  78. for r in s {
  79. if r == '_' do continue;
  80. v := u128(_digit_value(r));
  81. if v >= base do break;
  82. value *= base;
  83. value += u128(v);
  84. }
  85. if neg do return -value;
  86. return value;
  87. }
  88. parse_int :: proc(s: string) -> int {
  89. return int(parse_i128(s));
  90. }
  91. parse_uint :: proc(s: string, base: int) -> uint {
  92. return uint(parse_u128(s));
  93. }
  94. parse_f64 :: proc(s: string) -> f64 {
  95. i := 0;
  96. sign: f64 = 1;
  97. switch s[i] {
  98. case '-': i += 1; sign = -1;
  99. case '+': i += 1;
  100. }
  101. value: f64 = 0;
  102. for ; i < len(s); i += 1 {
  103. r := rune(s[i]);
  104. if r == '_' do continue;
  105. v := _digit_value(r);
  106. if v >= 10 do break;
  107. value *= 10;
  108. value += f64(v);
  109. }
  110. if i < len(s) && s[i] == '.' {
  111. pow10: f64 = 10;
  112. i += 1;
  113. for ; i < len(s); i += 1 {
  114. r := rune(s[i]);
  115. if r == '_' do continue;
  116. v := _digit_value(r);
  117. if v >= 10 do break;
  118. value += f64(v)/pow10;
  119. pow10 *= 10;
  120. }
  121. }
  122. frac := false;
  123. scale: f64 = 1;
  124. if i < len(s) && (s[i] == 'e' || s[i] == 'E') {
  125. i += 1;
  126. if i < len(s) {
  127. switch s[i] {
  128. case '-': i += 1; frac = true;
  129. case '+': i += 1;
  130. }
  131. exp: u32 = 0;
  132. for ; i < len(s); i += 1 {
  133. r := rune(s[i]);
  134. if r == '_' do continue;
  135. d := u32(_digit_value(r));
  136. if d >= 10 do break;
  137. exp = exp * 10 + d;
  138. }
  139. if exp > 308 { exp = 308; }
  140. for exp >= 50 { scale *= 1e50; exp -= 50; }
  141. for exp >= 8 { scale *= 1e8; exp -= 8; }
  142. for exp > 0 { scale *= 10; exp -= 1; }
  143. }
  144. }
  145. if frac do return sign * (value/scale);
  146. return sign * (value*scale);
  147. }
  148. append_bool :: proc(buf: []u8, b: bool) -> string {
  149. if b do append(&buf, "true");
  150. else do append(&buf, "false");
  151. return string(buf);
  152. }
  153. append_uint :: proc(buf: []u8, u: u64, base: int) -> string {
  154. return append_bits(buf, u128(u), base, false, 8*size_of(uint), digits, 0);
  155. }
  156. append_int :: proc(buf: []u8, i: i64, base: int) -> string {
  157. return append_bits(buf, u128(i), base, true, 8*size_of(int), digits, 0);
  158. }
  159. itoa :: proc(buf: []u8, i: int) -> string do return append_int(buf, i64(i), 10);
  160. append_float :: proc(buf: []u8, f: f64, fmt: u8, prec, bit_size: int) -> string {
  161. return string(generic_ftoa(buf, f, fmt, prec, bit_size));
  162. }
  163. DecimalSlice :: struct {
  164. digits: []u8,
  165. count: int,
  166. decimal_point: int,
  167. neg: bool,
  168. }
  169. FloatInfo :: struct {
  170. mantbits: uint,
  171. expbits: uint,
  172. bias: int,
  173. }
  174. _f16_info := FloatInfo{10, 5, -15};
  175. _f32_info := FloatInfo{23, 8, -127};
  176. _f64_info := FloatInfo{52, 11, -1023};
  177. generic_ftoa :: proc(buf: []u8, val: f64, fmt: u8, prec, bit_size: int) -> []u8 {
  178. bits: u64;
  179. flt: ^FloatInfo;
  180. switch bit_size {
  181. case 32:
  182. bits = u64(transmute(u32)f32(val));
  183. flt = &_f32_info;
  184. case 64:
  185. bits = transmute(u64)val;
  186. flt = &_f64_info;
  187. case:
  188. panic("strconv: invalid bit_size");
  189. }
  190. neg := bits>>(flt.expbits+flt.mantbits) != 0;
  191. exp := int(bits>>flt.mantbits) & (1<<flt.expbits - 1);
  192. mant := bits & (u64(1) << flt.mantbits - 1);
  193. switch exp {
  194. case 1<<flt.expbits - 1:
  195. s: string;
  196. if mant != 0 {
  197. s = "NaN";
  198. } else if neg {
  199. s = "-Inf";
  200. } else {
  201. s = "+Inf";
  202. }
  203. append(&buf, ...cast([]u8)s);
  204. return buf;
  205. case 0: // denormalized
  206. exp += 1;
  207. case:
  208. mant |= u64(1) << flt.mantbits;
  209. }
  210. exp += flt.bias;
  211. d_: Decimal;
  212. d := &d_;
  213. assign(d, mant);
  214. shift(d, exp - int(flt.mantbits));
  215. digs: DecimalSlice;
  216. shortest := prec < 0;
  217. if shortest {
  218. round_shortest(d, mant, exp, flt);
  219. digs = DecimalSlice{digits = d.digits[..], count = d.count, decimal_point = d.decimal_point};
  220. switch fmt {
  221. case 'e', 'E': prec = digs.count-1;
  222. case 'f', 'F': prec = max(digs.count-digs.decimal_point, 0);
  223. case 'g', 'G': prec = digs.count;
  224. }
  225. } else {
  226. switch fmt {
  227. case 'e', 'E': round(d, prec+1);
  228. case 'f', 'F': round(d, d.decimal_point+prec);
  229. case 'g', 'G':
  230. if prec == 0 {
  231. prec = 1;
  232. }
  233. round(d, prec);
  234. }
  235. digs = DecimalSlice{digits = d.digits[..], count = d.count, decimal_point = d.decimal_point};
  236. }
  237. return format_digits(buf, shortest, neg, digs, prec, fmt);
  238. }
  239. format_digits :: proc(buf: []u8, shortest: bool, neg: bool, digs: DecimalSlice, prec: int, fmt: u8) -> []u8 {
  240. switch fmt {
  241. case 'f', 'F':
  242. append(&buf, neg ? '-' : '+');
  243. // integer, padded with zeros when needed
  244. if digs.decimal_point > 0 {
  245. m := min(digs.count, digs.decimal_point);
  246. append(&buf, ...digs.digits[0..m]);
  247. for ; m < digs.decimal_point; m += 1 {
  248. append(&buf, '0');
  249. }
  250. } else {
  251. append(&buf, '0');
  252. }
  253. // fractional part
  254. if prec > 0 {
  255. append(&buf, '.');
  256. for i in 0..prec {
  257. c: u8 = '0';
  258. if j := digs.decimal_point + i; 0 <= j && j < digs.count {
  259. c = digs.digits[j];
  260. }
  261. append(&buf, c);
  262. }
  263. }
  264. return buf;
  265. case 'e', 'E':
  266. panic("strconv: e/E float printing is not yet supported");
  267. return buf; // TODO
  268. case 'g', 'G':
  269. panic("strconv: g/G float printing is not yet supported");
  270. return buf; // TODO
  271. }
  272. c := [2]u8{'%', fmt};
  273. append(&buf, ...c[..]);
  274. return buf;
  275. }
  276. round_shortest :: proc(d: ^Decimal, mant: u64, exp: int, flt: ^FloatInfo) {
  277. if mant == 0 { // If mantissa is zero, the number is zero
  278. d.count = 0;
  279. return;
  280. }
  281. /*
  282. 10^(dp-nd) > 2^(exp-mantbits)
  283. log2(10) * (dp-nd) > exp-mantbits
  284. log(2) >~ 0.332
  285. 332*(dp-nd) >= 100*(exp-mantbits)
  286. */
  287. minexp := flt.bias+1;
  288. if exp > minexp && 332*(d.decimal_point-d.count) >= 100*(exp - int(flt.mantbits)) {
  289. // Number is already its shortest
  290. return;
  291. }
  292. upper_: Decimal; upper := &upper_;
  293. assign(upper, 2*mant - 1);
  294. shift(upper, exp - int(flt.mantbits) - 1);
  295. mantlo: u64;
  296. explo: int;
  297. if mant > 1<<flt.mantbits || exp == minexp {
  298. mantlo = mant-1;
  299. explo = exp;
  300. } else {
  301. mantlo = 2*mant - 1;
  302. explo = exp-1;
  303. }
  304. lower_: Decimal; lower := &lower_;
  305. assign(lower, 2*mantlo + 1);
  306. shift(lower, explo - int(flt.mantbits) - 1);
  307. inclusive := mant%2 == 0;
  308. for i in 0..d.count {
  309. l: u8 = '0'; // lower digit
  310. if i < lower.count {
  311. l = lower.digits[i];
  312. }
  313. m := d.digits[i]; // middle digit
  314. u: u8 = '0'; // upper digit
  315. if i < upper.count {
  316. u = upper.digits[i];
  317. }
  318. ok_round_down := l != m || inclusive && i+1 == lower.count;
  319. ok_round_up := m != u && (inclusive || m+1 < u || i+1 < upper.count);
  320. if ok_round_down && ok_round_up {
  321. round(d, i+1);
  322. return;
  323. }
  324. if ok_round_down {
  325. round_down(d, i+1);
  326. return;
  327. }
  328. if ok_round_up {
  329. round_up(d, i+1);
  330. return;
  331. }
  332. }
  333. }
  334. MAX_BASE :: 32;
  335. digits := "0123456789abcdefghijklmnopqrstuvwxyz";
  336. is_integer_negative :: proc(u: u128, is_signed: bool, bit_size: int) -> (unsigned: u128, neg: bool) {
  337. neg := false;
  338. if is_signed {
  339. switch bit_size {
  340. case 8:
  341. i := i8(u);
  342. neg = i < 0;
  343. u = u128(abs(i));
  344. case 16:
  345. i := i16(u);
  346. neg = i < 0;
  347. u = u128(abs(i));
  348. case 32:
  349. i := i32(u);
  350. neg = i < 0;
  351. u = u128(abs(i));
  352. case 64:
  353. i := i64(u);
  354. neg = i < 0;
  355. u = u128(abs(i));
  356. case 128:
  357. i := i128(u);
  358. neg = i < 0;
  359. u = u128(abs(i));
  360. case:
  361. panic("is_integer_negative: Unknown integer size");
  362. }
  363. }
  364. return u, neg;
  365. }
  366. append_bits :: proc(buf: []u8, u: u128, base: int, is_signed: bool, bit_size: int, digits: string, flags: Int_Flag) -> string {
  367. if base < 2 || base > MAX_BASE {
  368. panic("strconv: illegal base passed to append_bits");
  369. }
  370. neg: bool;
  371. a: [129]u8;
  372. i := len(a);
  373. u, neg = is_integer_negative(u, is_signed, bit_size);
  374. b := u128(base);
  375. for u >= b {
  376. i-=1; a[i] = digits[uint(u % b)];
  377. u /= b;
  378. }
  379. i-=1; a[i] = digits[uint(u % b)];
  380. if flags&Int_Flag.Prefix != 0 {
  381. ok := true;
  382. switch base {
  383. case 2: i-=1; a[i] = 'b';
  384. case 8: i-=1; a[i] = 'o';
  385. case 10: i-=1; a[i] = 'd';
  386. case 12: i-=1; a[i] = 'z';
  387. case 16: i-=1; a[i] = 'x';
  388. case: ok = false;
  389. }
  390. if ok {
  391. i-=1; a[i] = '0';
  392. }
  393. }
  394. if neg {
  395. i-=1; a[i] = '-';
  396. } else if flags&Int_Flag.Plus != 0 {
  397. i-=1; a[i] = '+';
  398. } else if flags&Int_Flag.Space != 0 {
  399. i-=1; a[i] = ' ';
  400. }
  401. append(&buf, ...a[i..]);
  402. return string(buf);
  403. }