strconv.odin 9.3 KB

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