strconv.odin 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367
  1. #import . "decimal.odin";
  2. #import "math.odin";
  3. Int_Flag :: enum {
  4. PREFIX = 1<<0,
  5. PLUS = 1<<1,
  6. SPACE = 1<<2,
  7. }
  8. parse_bool :: proc(s: string) -> (result: bool, ok: bool) {
  9. match s {
  10. case "1", "t", "T", "true", "TRUE", "True":
  11. return true, true;
  12. case "0", "f", "F", "false", "FALSE", "False":
  13. return false, true;
  14. }
  15. return false, false;
  16. }
  17. append_bool :: proc(buf: []byte, b: bool) -> string {
  18. s := b ? "true" : "false";
  19. append(buf, ..cast([]byte)s);
  20. return cast(string)buf;
  21. }
  22. append_uint :: proc(buf: []byte, u: u64, base: int) -> string {
  23. return append_bits(buf, u, base, false, 8*size_of(uint), digits, 0);
  24. }
  25. append_int :: proc(buf: []byte, i: i64, base: int) -> string {
  26. return append_bits(buf, cast(u64)i, base, true, 8*size_of(int), digits, 0);
  27. }
  28. itoa :: proc(buf: []byte, i: int) -> string { return append_int(buf, cast(i64)i, 10); }
  29. append_float :: proc(buf: []byte, f: f64, fmt: byte, prec, bit_size: int) -> string {
  30. return cast(string)generic_ftoa(buf, f, fmt, prec, bit_size);
  31. }
  32. Decimal_Slice :: struct {
  33. digits: []byte,
  34. count: int,
  35. decimal_point: int,
  36. neg: bool,
  37. }
  38. Float_Info :: struct {
  39. mantbits: uint,
  40. expbits: uint,
  41. bias: int,
  42. }
  43. f32_info := Float_Info{23, 8, -127};
  44. f64_info := Float_Info{52, 11, -1023};
  45. generic_ftoa :: proc(buf: []byte, val: f64, fmt: byte, prec, bit_size: int) -> []byte {
  46. bits: u64;
  47. flt: ^Float_Info;
  48. match bit_size {
  49. case 32:
  50. bits = cast(u64)transmute(u32)cast(f32)val;
  51. flt = ^f32_info;
  52. case 64:
  53. bits = transmute(u64)val;
  54. flt = ^f64_info;
  55. default:
  56. panic("strconv: invalid bit_size");
  57. }
  58. neg := bits>>(flt.expbits+flt.mantbits) != 0;
  59. exp := cast(int)(bits>>flt.mantbits) & (1<<flt.expbits - 1);
  60. mant := bits & (cast(u64)1 << flt.mantbits - 1);
  61. match exp {
  62. case 1<<flt.expbits - 1:
  63. s: string;
  64. if mant != 0 {
  65. s = "NaN";
  66. } else if neg {
  67. s = "-Inf";
  68. } else {
  69. s = "+Inf";
  70. }
  71. append(buf, ..cast([]byte)s);
  72. return buf;
  73. case 0: // denormalized
  74. exp++;
  75. default:
  76. mant |= cast(u64)1 << flt.mantbits;
  77. }
  78. exp += flt.bias;
  79. d_: Decimal;
  80. d := ^d_;
  81. assign(d, mant);
  82. shift(d, exp - cast(int)flt.mantbits);
  83. digs: Decimal_Slice;
  84. shortest := prec < 0;
  85. if shortest {
  86. round_shortest(d, mant, exp, flt);
  87. digs = Decimal_Slice{digits = d.digits[..], count = d.count, decimal_point = d.decimal_point};
  88. match fmt {
  89. case 'e', 'E': prec = digs.count-1;
  90. case 'f', 'F': prec = max(digs.count-digs.decimal_point, 0);
  91. case 'g', 'G': prec = digs.count;
  92. }
  93. } else {
  94. match fmt {
  95. case 'e', 'E': round(d, prec+1);
  96. case 'f', 'F': round(d, d.decimal_point+prec);
  97. case 'g', 'G':
  98. if prec == 0 {
  99. prec = 1;
  100. }
  101. round(d, prec);
  102. }
  103. digs = Decimal_Slice{digits = d.digits[..], count = d.count, decimal_point = d.decimal_point};
  104. }
  105. return format_digits(buf, shortest, neg, digs, prec, fmt);
  106. }
  107. format_digits :: proc(buf: []byte, shortest: bool, neg: bool, digs: Decimal_Slice, prec: int, fmt: byte) -> []byte {
  108. match fmt {
  109. case 'f', 'F':
  110. add_bytes :: proc(dst: ^[]byte, w: ^int, bytes: ..byte) {
  111. for b in bytes {
  112. if dst.capacity <= w^ {
  113. break;
  114. }
  115. dst.count++;
  116. dst[w^] = b;
  117. w^++;
  118. }
  119. }
  120. dst := buf[..];
  121. w := 0;
  122. if neg {
  123. add_bytes(^dst, ^w, '-');
  124. } else {
  125. add_bytes(^dst, ^w, '+');
  126. }
  127. // integer, padded with zeros when needed
  128. if digs.decimal_point > 0 {
  129. m := min(digs.count, digs.decimal_point);
  130. add_bytes(^dst, ^w, ..digs.digits[..m]);
  131. for ; m < digs.decimal_point; m++ {
  132. add_bytes(^dst, ^w, '0');
  133. }
  134. } else {
  135. add_bytes(^dst, ^w, '0');
  136. }
  137. // fractional part
  138. if prec > 0 {
  139. add_bytes(^dst, ^w, '.');
  140. for i in 0..prec {
  141. c: byte = '0';
  142. if j := digs.decimal_point + i; 0 <= j && j < digs.count {
  143. c = digs.digits[j];
  144. }
  145. add_bytes(^dst, ^w, c);
  146. }
  147. }
  148. return buf[..w];
  149. case 'e', 'E':
  150. panic("strconv: e/E float printing is not yet supported");
  151. return buf; // TODO
  152. case 'g', 'G':
  153. panic("strconv: g/G float printing is not yet supported");
  154. return buf; // TODO
  155. }
  156. c: [2]byte;
  157. c[0] = '%';
  158. c[1] = fmt;
  159. append(buf, ..c[..]);
  160. return buf;
  161. }
  162. round_shortest :: proc(d: ^Decimal, mant: u64, exp: int, flt: ^Float_Info) {
  163. if mant == 0 { // If mantissa is zero, the number is zero
  164. d.count = 0;
  165. return;
  166. }
  167. /*
  168. 10^(dp-nd) > 2^(exp-mantbits)
  169. log2(10) * (dp-nd) > exp-mantbits
  170. log(2) >~ 0.332
  171. 332*(dp-nd) >= 100*(exp-mantbits)
  172. */
  173. minexp := flt.bias+1;
  174. if exp > minexp && 332*(d.decimal_point-d.count) >= 100*(exp - cast(int)flt.mantbits) {
  175. // Number is already its shortest
  176. return;
  177. }
  178. upper_: Decimal; upper: = ^upper_;
  179. assign(upper, 2*mant - 1);
  180. shift(upper, exp - cast(int)flt.mantbits - 1);
  181. mantlo: u64;
  182. explo: int;
  183. if mant > 1<<flt.mantbits || exp == minexp {
  184. mantlo = mant-1;
  185. explo = exp;
  186. } else {
  187. mantlo = 2*mant - 1;
  188. explo = exp-1;
  189. }
  190. lower_: Decimal; lower: = ^lower_;
  191. assign(lower, 2*mantlo + 1);
  192. shift(lower, explo - cast(int)flt.mantbits - 1);
  193. inclusive := mant%2 == 0;
  194. for i in 0..d.count {
  195. l: byte = '0'; // lower digit
  196. if i < lower.count {
  197. l = lower.digits[i];
  198. }
  199. m := d.digits[i]; // middle digit
  200. u: byte = '0'; // upper digit
  201. if i < upper.count {
  202. u = upper.digits[i];
  203. }
  204. ok_round_down := l != m || inclusive && i+1 == lower.count;
  205. ok_round_up := m != u && (inclusive || m+1 < u || i+1 < upper.count);
  206. if (ok_round_down && ok_round_up) {
  207. round(d, i+1);
  208. return;
  209. }
  210. if (ok_round_down) {
  211. round_down(d, i+1);
  212. return;
  213. }
  214. if (ok_round_up) {
  215. round_up(d, i+1);
  216. return;
  217. }
  218. }
  219. }
  220. MAX_BASE :: 32;
  221. immutable digits := "0123456789abcdefghijklmnopqrstuvwxyz";
  222. is_integer_negative :: proc(u: u64, is_signed: bool, bit_size: int) -> (unsigned: u64, neg: bool) {
  223. neg := false;
  224. if is_signed {
  225. match bit_size {
  226. case 8:
  227. i := cast(i8)u;
  228. neg = i < 0;
  229. if neg { i = -i; }
  230. u = cast(u64)i;
  231. case 16:
  232. i := cast(i16)u;
  233. neg = i < 0;
  234. if neg { i = -i; }
  235. u = cast(u64)i;
  236. case 32:
  237. i := cast(i32)u;
  238. neg = i < 0;
  239. if neg { i = -i; }
  240. u = cast(u64)i;
  241. case 64:
  242. i := cast(i64)u;
  243. neg = i < 0;
  244. if neg { i = -i; }
  245. u = cast(u64)i;
  246. default:
  247. panic("is_integer_negative: Unknown integer size");
  248. }
  249. }
  250. return u, neg;
  251. }
  252. append_bits :: proc(buf: []byte, u: u64, base: int, is_signed: bool, bit_size: int, digits: string, flags: Int_Flag) -> string {
  253. is_pow2 :: proc(x: i64) -> bool {
  254. if (x <= 0) {
  255. return false;
  256. }
  257. return x&(x-1) == 0;
  258. }
  259. if base < 2 || base > MAX_BASE {
  260. panic("strconv: illegal base passed to append_bits");
  261. }
  262. a: [65]byte;
  263. i := a.count;
  264. neg: bool;
  265. u, neg = is_integer_negative(u, is_signed, bit_size);
  266. if is_pow2(cast(i64)base) {
  267. b := cast(u64)base;
  268. m := cast(uint)b - 1;
  269. for u >= b {
  270. i--;
  271. a[i] = digits[cast(uint)u & m];
  272. u >>= b;
  273. }
  274. i--;
  275. a[i] = digits[cast(uint)u];
  276. } else {
  277. b := cast(u64)base;
  278. for u >= b {
  279. i--;
  280. q := u / b;
  281. a[i] = digits[cast(uint)(u-q*b)];
  282. u = q;
  283. }
  284. i--;
  285. a[i] = digits[cast(uint)u];
  286. }
  287. if flags&Int_Flag.PREFIX != 0 {
  288. ok := true;
  289. match base {
  290. case 2: i--; a[i] = 'b';
  291. case 8: i--; a[i] = 'o';
  292. case 10: i--; a[i] = 'd';
  293. case 12: i--; a[i] = 'z';
  294. case 16: i--; a[i] = 'x';
  295. default: ok = false;
  296. }
  297. if ok {
  298. i--;
  299. a[i] = '0';
  300. }
  301. }
  302. if neg {
  303. i--; a[i] = '-';
  304. } else if flags&Int_Flag.PLUS != 0 {
  305. i--; a[i] = '+';
  306. } else if flags&Int_Flag.SPACE != 0 {
  307. i--; a[i] = ' ';
  308. }
  309. append(buf, ..a[i..]);
  310. return cast(string)buf;
  311. }