yeptris 0.6.18.2-arm-linux-eabihf

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (142) hide show
  1. checksums.yaml +7 -0
  2. data/README.adoc +141 -0
  3. data/ext/build_windows_native.rb +41 -0
  4. data/ext/libyeptris/extconf.rb +57 -0
  5. data/ext/yeptris_native/cbor_ruby.c +193 -0
  6. data/ext/yeptris_native/extconf.rb +47 -0
  7. data/ext/yeptris_native/json_ruby.c +354 -0
  8. data/ext/yeptris_native/yeptris_native.c +497 -0
  9. data/lib/yeptris/cbor.rb +130 -0
  10. data/lib/yeptris/document.rb +255 -0
  11. data/lib/yeptris/ffi.rb +426 -0
  12. data/lib/yeptris/json/descriptor.rb +266 -0
  13. data/lib/yeptris/json.rb +394 -0
  14. data/lib/yeptris/materializer.rb +354 -0
  15. data/lib/yeptris/native-3.4.so +0 -0
  16. data/lib/yeptris/node.rb +453 -0
  17. data/lib/yeptris/psych/class_loader.rb +24 -0
  18. data/lib/yeptris/psych/coder_shim.rb +55 -0
  19. data/lib/yeptris/psych/drop_in.rb +63 -0
  20. data/lib/yeptris/psych/encodable.rb +14 -0
  21. data/lib/yeptris/psych/handler.rb +90 -0
  22. data/lib/yeptris/psych/parser.rb +105 -0
  23. data/lib/yeptris/psych/scalar_scanner.rb +149 -0
  24. data/lib/yeptris/psych/visitors.rb +545 -0
  25. data/lib/yeptris/psych.rb +622 -0
  26. data/lib/yeptris/schema.rb +253 -0
  27. data/lib/yeptris/valueml.rb +455 -0
  28. data/lib/yeptris/yaml/descriptor.rb +56 -0
  29. data/lib/yeptris/yaml.rb +422 -0
  30. data/lib/yeptris.rb +113 -0
  31. data/libyeptris.so +0 -0
  32. data/vendor/libyeptris/CMakeLists.txt +254 -0
  33. data/vendor/libyeptris/cmake/yeptris-config.cmake.in +5 -0
  34. data/vendor/libyeptris/cmake/yeptris.pc.in +11 -0
  35. data/vendor/libyeptris/src/CMakeLists.txt +167 -0
  36. data/vendor/libyeptris/src/include/yeptris/api.h +32 -0
  37. data/vendor/libyeptris/src/include/yeptris/cbor.h +101 -0
  38. data/vendor/libyeptris/src/include/yeptris/dom.h +190 -0
  39. data/vendor/libyeptris/src/include/yeptris/emit.h +81 -0
  40. data/vendor/libyeptris/src/include/yeptris/error.h +41 -0
  41. data/vendor/libyeptris/src/include/yeptris/events.h +157 -0
  42. data/vendor/libyeptris/src/include/yeptris/json.h +45 -0
  43. data/vendor/libyeptris/src/include/yeptris/json.hpp +258 -0
  44. data/vendor/libyeptris/src/include/yeptris/jsonc_compat.h +115 -0
  45. data/vendor/libyeptris/src/include/yeptris/marshal.h +52 -0
  46. data/vendor/libyeptris/src/include/yeptris/parse.h +48 -0
  47. data/vendor/libyeptris/src/include/yeptris/plan.h +100 -0
  48. data/vendor/libyeptris/src/include/yeptris/resolve.h +71 -0
  49. data/vendor/libyeptris/src/include/yeptris/schema.h +121 -0
  50. data/vendor/libyeptris/src/include/yeptris/tape.h +123 -0
  51. data/vendor/libyeptris/src/include/yeptris/types.h +38 -0
  52. data/vendor/libyeptris/src/include/yeptris/values.h +102 -0
  53. data/vendor/libyeptris/src/include/yeptris/version.h.in +29 -0
  54. data/vendor/libyeptris/src/include/yeptris/visit.h +77 -0
  55. data/vendor/libyeptris/src/include/yeptris/yajl_compat.h +135 -0
  56. data/vendor/libyeptris/src/include/yeptris.h +23 -0
  57. data/vendor/libyeptris/src/yeptris/build.c +376 -0
  58. data/vendor/libyeptris/src/yeptris/cbor/cbor.h +25 -0
  59. data/vendor/libyeptris/src/yeptris/cbor/decode.c +981 -0
  60. data/vendor/libyeptris/src/yeptris/cbor/encode.c +835 -0
  61. data/vendor/libyeptris/src/yeptris/cbor/sink.h +58 -0
  62. data/vendor/libyeptris/src/yeptris/common/chartype.c +41 -0
  63. data/vendor/libyeptris/src/yeptris/common/chartype.h +77 -0
  64. data/vendor/libyeptris/src/yeptris/common/cpu.c +81 -0
  65. data/vendor/libyeptris/src/yeptris/common/cpu.h +40 -0
  66. data/vendor/libyeptris/src/yeptris/common/error.c +65 -0
  67. data/vendor/libyeptris/src/yeptris/common/error.h +79 -0
  68. data/vendor/libyeptris/src/yeptris/common/mutex.h +45 -0
  69. data/vendor/libyeptris/src/yeptris/common/nametab.c +275 -0
  70. data/vendor/libyeptris/src/yeptris/common/nametab.h +68 -0
  71. data/vendor/libyeptris/src/yeptris/common/port.h +74 -0
  72. data/vendor/libyeptris/src/yeptris/common/simd_text.c +49 -0
  73. data/vendor/libyeptris/src/yeptris/common/simd_text.h +295 -0
  74. data/vendor/libyeptris/src/yeptris/common/simd_text_avx2.c +534 -0
  75. data/vendor/libyeptris/src/yeptris/common/simd_text_neon.c +662 -0
  76. data/vendor/libyeptris/src/yeptris/common/simd_text_scalar.c +298 -0
  77. data/vendor/libyeptris/src/yeptris/common/string_view.c +34 -0
  78. data/vendor/libyeptris/src/yeptris/common/string_view.h +93 -0
  79. data/vendor/libyeptris/src/yeptris/doc.h +56 -0
  80. data/vendor/libyeptris/src/yeptris/dom/dom.c +1192 -0
  81. data/vendor/libyeptris/src/yeptris/dom/dom.h +312 -0
  82. data/vendor/libyeptris/src/yeptris/dom/hpool.c +107 -0
  83. data/vendor/libyeptris/src/yeptris/dom/mapindex.c +173 -0
  84. data/vendor/libyeptris/src/yeptris/dom/mapindex.h +61 -0
  85. data/vendor/libyeptris/src/yeptris/dom/mutate.c +431 -0
  86. data/vendor/libyeptris/src/yeptris/emit/emit.c +434 -0
  87. data/vendor/libyeptris/src/yeptris/emit/float/api.h +38 -0
  88. data/vendor/libyeptris/src/yeptris/emit/float/dragon.c +405 -0
  89. data/vendor/libyeptris/src/yeptris/emit/float/floatint.h +231 -0
  90. data/vendor/libyeptris/src/yeptris/emit/float/print.c +396 -0
  91. data/vendor/libyeptris/src/yeptris/emit/style.c +81 -0
  92. data/vendor/libyeptris/src/yeptris/emit/style.h +24 -0
  93. data/vendor/libyeptris/src/yeptris/emit/writer.c +816 -0
  94. data/vendor/libyeptris/src/yeptris/emit/writer.h +76 -0
  95. data/vendor/libyeptris/src/yeptris/encoding/bom.c +31 -0
  96. data/vendor/libyeptris/src/yeptris/encoding/encoding.h +63 -0
  97. data/vendor/libyeptris/src/yeptris/encoding/transcode.c +148 -0
  98. data/vendor/libyeptris/src/yeptris/encoding/utf8_validate.c +178 -0
  99. data/vendor/libyeptris/src/yeptris/events/capture.c +150 -0
  100. data/vendor/libyeptris/src/yeptris/events/capture.h +39 -0
  101. data/vendor/libyeptris/src/yeptris/events/iterparse.c +208 -0
  102. data/vendor/libyeptris/src/yeptris/events/pull.c +97 -0
  103. data/vendor/libyeptris/src/yeptris/events/push.c +104 -0
  104. data/vendor/libyeptris/src/yeptris/events/recorder.c +107 -0
  105. data/vendor/libyeptris/src/yeptris/events/values.c +527 -0
  106. data/vendor/libyeptris/src/yeptris/events/values_priv.h +51 -0
  107. data/vendor/libyeptris/src/yeptris/events/yaml_compat.c +86 -0
  108. data/vendor/libyeptris/src/yeptris/events/yaml_compat.h +90 -0
  109. data/vendor/libyeptris/src/yeptris/jsonapi/jsonc_compat.c +687 -0
  110. data/vendor/libyeptris/src/yeptris/jsonapi/yajl_compat.c +728 -0
  111. data/vendor/libyeptris/src/yeptris/marshal.c +782 -0
  112. data/vendor/libyeptris/src/yeptris/memory/allocator.c +20 -0
  113. data/vendor/libyeptris/src/yeptris/memory/allocator.h +43 -0
  114. data/vendor/libyeptris/src/yeptris/memory/arena.c +134 -0
  115. data/vendor/libyeptris/src/yeptris/memory/arena.h +52 -0
  116. data/vendor/libyeptris/src/yeptris/memory/pool.c +122 -0
  117. data/vendor/libyeptris/src/yeptris/memory/pool.h +36 -0
  118. data/vendor/libyeptris/src/yeptris/parse/engine.c +3698 -0
  119. data/vendor/libyeptris/src/yeptris/parse/engine.h +65 -0
  120. data/vendor/libyeptris/src/yeptris/parse/events.h +124 -0
  121. data/vendor/libyeptris/src/yeptris/parse/numbers.c +349 -0
  122. data/vendor/libyeptris/src/yeptris/parse/numbers.h +33 -0
  123. data/vendor/libyeptris/src/yeptris/parse/scalars.c +416 -0
  124. data/vendor/libyeptris/src/yeptris/parse/scalars.h +75 -0
  125. data/vendor/libyeptris/src/yeptris/parse.c +737 -0
  126. data/vendor/libyeptris/src/yeptris/plan.c +824 -0
  127. data/vendor/libyeptris/src/yeptris/resolve/compat11.c +334 -0
  128. data/vendor/libyeptris/src/yeptris/resolve/core12.c +143 -0
  129. data/vendor/libyeptris/src/yeptris/resolve/resolver.h +56 -0
  130. data/vendor/libyeptris/src/yeptris/resolve/tags.c +58 -0
  131. data/vendor/libyeptris/src/yeptris/scan/json.c +792 -0
  132. data/vendor/libyeptris/src/yeptris/scan/json.h +109 -0
  133. data/vendor/libyeptris/src/yeptris/scan/scan.c +463 -0
  134. data/vendor/libyeptris/src/yeptris/scan/scan.h +150 -0
  135. data/vendor/libyeptris/src/yeptris/schema.c +308 -0
  136. data/vendor/libyeptris/src/yeptris/tape.c +1308 -0
  137. data/vendor/libyeptris/src/yeptris/tape_in.h +19 -0
  138. data/vendor/libyeptris/src/yeptris/version.c +7 -0
  139. data/vendor/libyeptris/src/yeptris/visit/dom_visit.c +115 -0
  140. data/vendor/libyeptris/src/yeptris/visit/json_visit.c +293 -0
  141. data/vendor/libyeptris/src/yeptris/visit/yaml_visit.c +127 -0
  142. metadata +199 -0
@@ -0,0 +1,405 @@
1
+ /* dragon.c — tier B: exact shortest/fixed output via the interval
2
+ * method over a fixed-capacity limb vector (TODO.impl/14, clean room).
3
+ *
4
+ * v = r/s exactly with r, s, mm, mp integers: value r/s, round-trip
5
+ * interval ((r - mm)/s, (r + mp)/s). Each digit step advances r, mm,
6
+ * mp by 10 (s fixed) so the boundaries stay in the remaining-value
7
+ * space. A position can stop iff truncating (error r/s <= mm/s) or
8
+ * rounding up (error (s-r)/s <= mp/s) stays inside; when both are
9
+ * legal the nearer wins, ties to the even digit (reparse is
10
+ * round-to-nearest-even). When neither is legal, another digit is
11
+ * required — IEEE-754 guarantees termination by 17 digits (double) /
12
+ * 9 (float).
13
+ */
14
+
15
+ #include <string.h>
16
+
17
+ #include "emit/float/floatint.h"
18
+
19
+ /* ---- tiny limb vector: 32-bit limbs, little-endian ---- */
20
+
21
+ #define LIMBS 44 /* < 1080 binary digits + decimal scaling headroom */
22
+
23
+ typedef struct {
24
+ uint32_t d[LIMBS];
25
+ int n;
26
+ } num;
27
+
28
+ static void num_zero(num* a) {
29
+ memset(a, 0, sizeof(*a));
30
+ a->n = 1;
31
+ }
32
+
33
+ static void num_set_u64(num* a, uint64_t v) {
34
+ num_zero(a);
35
+ a->d[0] = (uint32_t)v;
36
+ a->d[1] = (uint32_t)(v >> 32);
37
+ a->n = a->d[1] ? 2 : 1;
38
+ }
39
+
40
+ static int num_cmp(const num* a, const num* b) {
41
+ if (a->n != b->n) {
42
+ return a->n < b->n ? -1 : 1;
43
+ }
44
+ for (int i = a->n - 1; i >= 0; i--) {
45
+ if (a->d[i] != b->d[i]) {
46
+ return a->d[i] < b->d[i] ? -1 : 1;
47
+ }
48
+ }
49
+ return 0;
50
+ }
51
+
52
+ static void num_trim(num* a) {
53
+ while (a->n > 1 && a->d[a->n - 1] == 0) {
54
+ a->n--;
55
+ }
56
+ }
57
+
58
+ static int num_add(num* a, const num* b) {
59
+ uint64_t carry = 0;
60
+ int n = a->n > b->n ? a->n : b->n;
61
+ for (int i = 0; i < n; i++) {
62
+ uint64_t s = (uint64_t)a->d[i] + (uint64_t)(i < b->n ? b->d[i] : 0) + carry;
63
+ a->d[i] = (uint32_t)s;
64
+ carry = s >> 32;
65
+ }
66
+ a->n = n;
67
+ if (carry) {
68
+ if (a->n >= LIMBS) {
69
+ return -1;
70
+ }
71
+ a->d[a->n++] = (uint32_t)carry;
72
+ }
73
+ return 0;
74
+ }
75
+
76
+ static void num_sub(num* a, const num* b) {
77
+ int64_t borrow = 0;
78
+ for (int i = 0; i < a->n; i++) {
79
+ int64_t s = (int64_t)a->d[i] - (int64_t)(i < b->n ? b->d[i] : 0) - borrow;
80
+ if (s < 0) {
81
+ s += ((int64_t)1 << 32);
82
+ borrow = 1;
83
+ } else {
84
+ borrow = 0;
85
+ }
86
+ a->d[i] = (uint32_t)s;
87
+ }
88
+ num_trim(a);
89
+ }
90
+
91
+ static int num_shl(num* a, int bits) {
92
+ for (; bits >= 32; bits -= 32) {
93
+ for (int i = a->n; i > 0; i--) {
94
+ a->d[i] = a->d[i - 1];
95
+ }
96
+ a->d[0] = 0;
97
+ a->n++;
98
+ if (a->n > LIMBS) {
99
+ return -1;
100
+ }
101
+ }
102
+ if (bits > 0) {
103
+ uint32_t carry = 0;
104
+ for (int i = 0; i < a->n; i++) {
105
+ uint32_t nc = a->d[i] >> (32 - bits);
106
+ a->d[i] = (a->d[i] << bits) | carry;
107
+ carry = nc;
108
+ }
109
+ if (carry) {
110
+ if (a->n >= LIMBS) {
111
+ return -1;
112
+ }
113
+ a->d[a->n++] = carry;
114
+ }
115
+ }
116
+ return 0;
117
+ }
118
+
119
+ static void num_shr(num* a, int bits) {
120
+ int limbs = bits / 32;
121
+ int rem = bits % 32;
122
+ if (limbs >= a->n) {
123
+ memset(a->d, 0, sizeof(uint32_t) * (size_t)a->n);
124
+ a->n = 1;
125
+ return;
126
+ }
127
+ for (int i = 0; i + limbs < a->n; i++) {
128
+ /* rem == 0 would shift by 32 (UB on uint32_t) — the hi limb
129
+ * is only meaningful when there IS a fractional shift */
130
+ if (rem == 0) {
131
+ a->d[i] = a->d[i + limbs];
132
+ continue;
133
+ }
134
+ uint32_t lo = a->d[i + limbs] >> rem;
135
+ uint32_t hi = (i + limbs + 1 < a->n) ? a->d[i + limbs + 1] << (32 - rem) : 0;
136
+ a->d[i] = lo | hi;
137
+ }
138
+ for (int i = a->n - limbs; i < a->n; i++) {
139
+ a->d[i] = 0;
140
+ }
141
+ a->n -= limbs;
142
+ num_trim(a);
143
+ }
144
+
145
+ static int num_mul10(num* a) {
146
+ uint64_t carry = 0;
147
+ for (int i = 0; i < a->n; i++) {
148
+ uint64_t p = (uint64_t)a->d[i] * 10 + carry;
149
+ a->d[i] = (uint32_t)p;
150
+ carry = p >> 32;
151
+ }
152
+ if (carry) {
153
+ if (a->n >= LIMBS) {
154
+ return -1;
155
+ }
156
+ a->d[a->n++] = (uint32_t)carry;
157
+ }
158
+ return 0;
159
+ }
160
+
161
+ static int num_is_zero(const num* a) {
162
+ return a->n == 1 && a->d[0] == 0;
163
+ }
164
+
165
+ /* Decimal digits of a (a >= 0) into dst[cap]; a == 0 yields "0".
166
+ * Returns the length, or -1 on overflow of cap. */
167
+ static int num_to_digits(const num* a, char* dst, int cap) {
168
+ char rev[400];
169
+ int n = 0;
170
+ if (num_is_zero(a)) {
171
+ if (cap < 1) {
172
+ return -1;
173
+ }
174
+ dst[0] = '0';
175
+ return 1;
176
+ }
177
+ num t = *a;
178
+ while (!num_is_zero(&t)) {
179
+ uint64_t rem = 0;
180
+ for (int i = t.n - 1; i >= 0; i--) {
181
+ uint64_t cur = (rem << 32) | t.d[i];
182
+ t.d[i] = (uint32_t)(cur / 1000000000u);
183
+ rem = cur % 1000000000u;
184
+ }
185
+ num_trim(&t);
186
+ for (int k = 0; k < 9; k++) {
187
+ rev[n++] = (char)('0' + (int)(rem % 10));
188
+ rem /= 10;
189
+ if (rem == 0 && num_is_zero(&t)) {
190
+ break;
191
+ }
192
+ }
193
+ if (n >= (int)sizeof(rev)) {
194
+ return -1;
195
+ }
196
+ }
197
+ if (n > cap) {
198
+ return -1;
199
+ }
200
+ for (int i = 0; i < n; i++) {
201
+ dst[i] = rev[n - 1 - i];
202
+ }
203
+ return n;
204
+ }
205
+
206
+ /* ---- exact shortest ---- */
207
+
208
+ int yep_dragon_shortest(uint64_t m2, int e2, int mb, int pow2_low, int tie_even, yep_dsplit* out) {
209
+ num r, s, mm, mp;
210
+ num_set_u64(&r, m2);
211
+ num_zero(&s);
212
+ s.d[0] = 1;
213
+ num_set_u64(&mm, 1);
214
+ num_set_u64(&mp, 1);
215
+ if (e2 >= 0) {
216
+ if (num_shl(&r, e2) != 0 || num_shl(&mm, e2 - 1) != 0) {
217
+ return -1;
218
+ }
219
+ mp = mm;
220
+ } else {
221
+ /* v = m2 / 2^-e2 with HALF-ulp boundaries: express with r = 2*m2
222
+ * over s = 2^(1-e2) so mm = mp = 1 is exactly the half-ulp */
223
+ if (num_shl(&r, 1) != 0 || num_shl(&s, 1 - e2) != 0) {
224
+ return -1;
225
+ }
226
+ }
227
+ if (pow2_low) {
228
+ /* power of two: the lower neighbor is one binade down, so the
229
+ * lower half-ulp is half the upper — widen by scaling r, s, mp
230
+ * by 2 (mm untouched halves relative to mp) */
231
+ if (num_shl(&r, 1) != 0 || num_shl(&s, 1) != 0 || num_shl(&mp, 1) != 0) {
232
+ return -1;
233
+ }
234
+ }
235
+
236
+ /* normalize the remaining value into [1/10, 1): v = 0.<digits> x 10^k */
237
+ int k = 0;
238
+ {
239
+ num rmp = r;
240
+ if (num_add(&rmp, &mp) != 0) {
241
+ return -1;
242
+ }
243
+ while (num_cmp(&rmp, &s) <= 0) {
244
+ num_mul10(&r);
245
+ num_mul10(&mm);
246
+ num_mul10(&mp);
247
+ rmp = r;
248
+ if (num_add(&rmp, &mp) != 0) {
249
+ return -1;
250
+ }
251
+ k--;
252
+ }
253
+ while (num_cmp(&r, &s) >= 0) {
254
+ if (num_mul10(&s) != 0) {
255
+ return -1;
256
+ }
257
+ k++;
258
+ }
259
+ }
260
+
261
+ const int max_digits = (mb >= 52) ? 17 : 9;
262
+ char digits[24];
263
+ int n = 0;
264
+ for (;;) {
265
+ num_mul10(&r);
266
+ num_mul10(&mm);
267
+ num_mul10(&mp);
268
+ int d = 0;
269
+ while (num_cmp(&r, &s) >= 0) {
270
+ num_sub(&r, &s);
271
+ d++;
272
+ }
273
+ digits[n] = (char)('0' + d);
274
+ n++;
275
+ /* can truncation stay inside? error r <= mm */
276
+ num rmm = mm;
277
+ int eq_down = num_cmp(&r, &rmm) == 0;
278
+ int can_down = num_cmp(&r, &rmm) < 0 || (tie_even && eq_down);
279
+ /* can rounding up stay inside? error (s - r) <= mp */
280
+ num sr = s;
281
+ num_sub(&sr, &r);
282
+ int eq_up = num_cmp(&sr, &mp) == 0;
283
+ int can_up = num_cmp(&sr, &mp) < 0 || (tie_even && eq_up);
284
+ if (can_down || can_up) {
285
+ int up;
286
+ if (can_down && can_up) {
287
+ num t = r;
288
+ if (num_add(&t, &r) != 0) {
289
+ return -1;
290
+ }
291
+ int c = num_cmp(&t, &s);
292
+ if (c > 0) {
293
+ up = 1;
294
+ } else if (c < 0) {
295
+ up = 0;
296
+ } else {
297
+ up = (d % 2) != 0; /* tie to the even digit */
298
+ }
299
+ } else {
300
+ up = can_up;
301
+ }
302
+ if (up) {
303
+ int i = n - 1;
304
+ for (;;) {
305
+ if (digits[i] != '9') {
306
+ digits[i]++;
307
+ break;
308
+ }
309
+ digits[i] = '0';
310
+ if (i == 0) {
311
+ for (int j = n; j > 0; j--) {
312
+ digits[j] = digits[j - 1];
313
+ }
314
+ digits[0] = '1';
315
+ n++;
316
+ k++;
317
+ break;
318
+ }
319
+ i--;
320
+ }
321
+ }
322
+ break;
323
+ }
324
+ if (n >= max_digits) {
325
+ /* safety net: 17 (9) significant digits always round-trip */
326
+ break;
327
+ }
328
+ if (n >= 23) {
329
+ return -1;
330
+ }
331
+ }
332
+ memcpy(out->digits, digits, (size_t)n);
333
+ out->len = n;
334
+ out->k = k;
335
+ return 0;
336
+ }
337
+
338
+ /* ---- exact fixed notation: digits of round_half_even(v x 10^p) ---- */
339
+
340
+ int yep_dragon_fixed(uint64_t m2, int e2, uint32_t precision, char* buf) {
341
+ num q;
342
+ num_set_u64(&q, m2);
343
+ if (e2 >= 0) {
344
+ if (num_shl(&q, e2) != 0) {
345
+ return -1;
346
+ }
347
+ }
348
+ for (uint32_t i = 0; i < precision; i++) {
349
+ if (num_mul10(&q) != 0) {
350
+ return -1;
351
+ }
352
+ }
353
+ if (e2 < 0) {
354
+ /* digits = round_half_even(N / 2^-e2): the remainder against
355
+ * the exact half decides; ties round to the even quotient */
356
+ int bits = -e2;
357
+ num half;
358
+ num_set_u64(&half, 1);
359
+ if (num_shl(&half, bits - 1) != 0) {
360
+ return -1;
361
+ }
362
+ num qshift = q;
363
+ num_shr(&qshift, bits);
364
+ num back = qshift;
365
+ if (num_shl(&back, bits) != 0) {
366
+ return -1;
367
+ }
368
+ num rem = q;
369
+ num_sub(&rem, &back);
370
+ int cmp = num_cmp(&rem, &half);
371
+ if (cmp > 0 || (cmp == 0 && (qshift.d[0] & 1))) {
372
+ num one;
373
+ num_set_u64(&one, 1);
374
+ if (num_add(&qshift, &one) != 0) {
375
+ return -1;
376
+ }
377
+ }
378
+ q = qshift;
379
+ }
380
+ char digits[400];
381
+ int len = num_to_digits(&q, digits, (int)sizeof(digits));
382
+ if (len < 0) {
383
+ return -1;
384
+ }
385
+ const char* tmp = digits;
386
+ if (precision == 0) {
387
+ memcpy(buf, tmp, (size_t)len);
388
+ return len;
389
+ }
390
+ if ((uint32_t)len <= precision) {
391
+ int pad = (int)precision - len;
392
+ int o = 0;
393
+ buf[o++] = '0';
394
+ buf[o++] = '.';
395
+ for (int i = 0; i < pad; i++) {
396
+ buf[o++] = '0';
397
+ }
398
+ memcpy(buf + o, tmp, (size_t)len);
399
+ return o + len;
400
+ }
401
+ memcpy(buf, tmp, (size_t)(len - (int)precision));
402
+ buf[len - (int)precision] = '.';
403
+ memcpy(buf + len - (int)precision + 1, tmp + (len - (int)precision), (size_t)precision);
404
+ return len + 1;
405
+ }
@@ -0,0 +1,231 @@
1
+ /* floatint.h — internal float-printing declarations (TODO.impl/14).
2
+ *
3
+ * CLEAN-ROOM IMPLEMENTATION: no third-party code is vendored (licensing
4
+ * decision 2026-09-01). What follows implements the published interval
5
+ * method for shortest round-trip decimal output (the Dragon4/Steele-
6
+ * White family, described in the literature) entirely from the math:
7
+ * find the shortest decimal that lies strictly inside the rounding
8
+ * interval (v - w_low, v + w_high) of the binary value.
9
+ *
10
+ * Two tiers, one algorithm:
11
+ * - tier A (print.c): the same digit loop over exact 128-bit
12
+ * integers — covers every value whose scaled representation fits
13
+ * (doubles with E in [-32, 75], floats with E in [-32, 104]);
14
+ * - tier B (dragon.c): the same loop over a fixed-capacity limb
15
+ * vector — exact for everything else (extreme exponents), and the
16
+ * correctness oracle for tier A in tests.
17
+ */
18
+
19
+ #ifndef YEP_FLOATINT_H
20
+ #define YEP_FLOATINT_H
21
+
22
+ #include <stdint.h>
23
+
24
+ #include "emit/float/api.h"
25
+
26
+ /* YEP_FLOAT_FORCE_LIMBS: test hook — exercises the portable lo/hi
27
+ * tier on hosts that also have __int128 (the limbs math is otherwise
28
+ * only compiled on 32-bit targets). */
29
+ #if defined(__SIZEOF_INT128__) && !defined(YEP_FLOAT_FORCE_LIMBS) && !defined(YEP_FLOAT_FORCE_LIMBS)
30
+ typedef unsigned __int128 yep_u128;
31
+ #define YEP_MUL64(a, b) ((yep_u128)(uint64_t)(a) * (uint64_t)(b))
32
+ #elif defined(_MSC_VER) && (defined(_M_X64) || defined(_M_ARM64))
33
+ #include <intrin.h>
34
+ /* MSVC has no __int128: the lo/hi pair behind the SAME helper surface
35
+ * (print.c's interval loop rides only these — no operator arithmetic
36
+ * anywhere, so both branches share one source shape). */
37
+ typedef struct {
38
+ uint64_t lo, hi;
39
+ } yep_u128;
40
+ #define YEP_MUL64(a, b) yep_u128_mul64(a, b)
41
+ #else
42
+ /* Any compiler without __int128 (32-bit GCC/Clang, MSVC x86-32): the
43
+ * same lo/hi pair; multiplication via 32-bit limbs (below). */
44
+ typedef struct {
45
+ uint64_t lo, hi;
46
+ } yep_u128;
47
+ #define YEP_MUL64(a, b) yep_u128_mul64(a, b)
48
+ #endif
49
+
50
+ static inline yep_u128 yep_u128_of(uint64_t v) {
51
+ #if defined(__SIZEOF_INT128__) && !defined(YEP_FLOAT_FORCE_LIMBS)
52
+ return (yep_u128)v;
53
+ #else
54
+ yep_u128 r = {v, 0};
55
+ return r;
56
+ #endif
57
+ }
58
+
59
+ static inline yep_u128 yep_u128_max(void) {
60
+ #if defined(__SIZEOF_INT128__) && !defined(YEP_FLOAT_FORCE_LIMBS)
61
+ return ~(yep_u128)0;
62
+ #else
63
+ yep_u128 r = {~(uint64_t)0, ~(uint64_t)0};
64
+ return r;
65
+ #endif
66
+ }
67
+
68
+ static inline yep_u128 yep_u128_add(yep_u128 a, yep_u128 b) {
69
+ #if defined(__SIZEOF_INT128__) && !defined(YEP_FLOAT_FORCE_LIMBS)
70
+ return a + b;
71
+ #else
72
+ yep_u128 r;
73
+ r.lo = a.lo + b.lo;
74
+ r.hi = a.hi + b.hi + (r.lo < a.lo ? 1u : 0u);
75
+ return r;
76
+ #endif
77
+ }
78
+
79
+ static inline yep_u128 yep_u128_sub(yep_u128 a, yep_u128 b) {
80
+ #if defined(__SIZEOF_INT128__) && !defined(YEP_FLOAT_FORCE_LIMBS)
81
+ return a - b;
82
+ #else
83
+ yep_u128 r;
84
+ r.lo = a.lo - b.lo;
85
+ r.hi = a.hi - b.hi - (a.lo < b.lo ? 1u : 0u);
86
+ return r;
87
+ #endif
88
+ }
89
+
90
+ /* n < 128 */
91
+ static inline yep_u128 yep_u128_shl(yep_u128 a, unsigned n) {
92
+ #if defined(__SIZEOF_INT128__) && !defined(YEP_FLOAT_FORCE_LIMBS)
93
+ return a << n;
94
+ #else
95
+ yep_u128 r = {0, 0};
96
+ if (n == 0) {
97
+ return a;
98
+ }
99
+ if (n < 64) {
100
+ r.hi = (a.hi << n) | (a.lo >> (64 - n));
101
+ r.lo = a.lo << n;
102
+ } else {
103
+ r.hi = a.lo << (n - 64);
104
+ }
105
+ return r;
106
+ #endif
107
+ }
108
+
109
+ /* n < 128 */
110
+ static inline yep_u128 yep_u128_shr(yep_u128 a, unsigned n) {
111
+ #if defined(__SIZEOF_INT128__) && !defined(YEP_FLOAT_FORCE_LIMBS)
112
+ return a >> n;
113
+ #else
114
+ yep_u128 r = {0, 0};
115
+ if (n == 0) {
116
+ return a;
117
+ }
118
+ if (n < 64) {
119
+ r.lo = (a.lo >> n) | (a.hi << (64 - n));
120
+ r.hi = a.hi >> n;
121
+ } else {
122
+ r.lo = a.hi >> (n - 64);
123
+ }
124
+ return r;
125
+ #endif
126
+ }
127
+
128
+ static inline int yep_u128_cmp(yep_u128 a, yep_u128 b) {
129
+ #if defined(__SIZEOF_INT128__) && !defined(YEP_FLOAT_FORCE_LIMBS)
130
+ return a < b ? -1 : (a > b ? 1 : 0);
131
+ #else
132
+ if (a.hi != b.hi) {
133
+ return a.hi < b.hi ? -1 : 1;
134
+ }
135
+ if (a.lo != b.lo) {
136
+ return a.lo < b.lo ? -1 : 1;
137
+ }
138
+ return 0;
139
+ #endif
140
+ }
141
+
142
+ #if defined(_MSC_VER) && defined(_M_X64)
143
+ static inline yep_u128 yep_u128_mul64(uint64_t a, uint64_t b) {
144
+ yep_u128 r;
145
+ r.lo = _umul128(a, b, &r.hi);
146
+ return r;
147
+ }
148
+ #elif defined(_MSC_VER) && defined(_M_ARM64)
149
+ static inline yep_u128 yep_u128_mul64(uint64_t a, uint64_t b) {
150
+ yep_u128 r;
151
+ r.hi = __umulh(a, b);
152
+ r.lo = a * b;
153
+ return r;
154
+ }
155
+ #elif !defined(__SIZEOF_INT128__) || defined(YEP_FLOAT_FORCE_LIMBS)
156
+ /* portable: 32-bit limbs, exact (the struct tier only) */
157
+ static inline yep_u128 yep_u128_mul64(uint64_t a, uint64_t b) {
158
+ uint64_t a0 = (uint32_t)a, a1 = a >> 32;
159
+ uint64_t b0 = (uint32_t)b, b1 = b >> 32;
160
+ uint64_t ll = a0 * b0;
161
+ uint64_t lh = a0 * b1;
162
+ uint64_t hl = a1 * b0;
163
+ uint64_t mid = (ll >> 32) + (uint32_t)lh + (uint32_t)hl;
164
+ yep_u128 r;
165
+ r.lo = (mid << 32) | (uint32_t)ll;
166
+ r.hi = (a1 * b1) + (lh >> 32) + (hl >> 32) + (mid >> 32);
167
+ return r;
168
+ }
169
+ #endif
170
+
171
+ /* x * 10 stays in range */
172
+ static inline int yep_u128_fits10(yep_u128 x) {
173
+ #if defined(__SIZEOF_INT128__) && !defined(YEP_FLOAT_FORCE_LIMBS)
174
+ return x <= (~(yep_u128)0) / 10;
175
+ #else
176
+ /* exact: x*10 = (hi*10 << 64) + lo*10 — overflow iff hi*10
177
+ * escapes 64 bits or the lo-carry wraps the sum */
178
+ yep_u128 hp = YEP_MUL64(x.hi, 10u);
179
+ if (hp.hi != 0) {
180
+ return 0;
181
+ }
182
+ yep_u128 lp = YEP_MUL64(x.lo, 10u);
183
+ return hp.lo + lp.hi >= hp.lo;
184
+ #endif
185
+ }
186
+
187
+ /* m small (< 2^32); caller guarantees no overflow (fits10 guarded) */
188
+ static inline yep_u128 yep_u128_mul_small(yep_u128 a, uint32_t m) {
189
+ #if defined(__SIZEOF_INT128__) && !defined(YEP_FLOAT_FORCE_LIMBS)
190
+ return a * m;
191
+ #else
192
+ yep_u128 r;
193
+ yep_u128 lp = YEP_MUL64(a.lo, m);
194
+ r.lo = lp.lo;
195
+ r.hi = a.hi * m + lp.hi;
196
+ return r;
197
+ #endif
198
+ }
199
+
200
+ /* The shortest-roundtrip result both tiers produce. digits[] is the
201
+ * rounded digit sequence (no leading zero, trailing zeros kept only
202
+ * when significant), len its length; k is the decimal exponent so the
203
+ * value is 0.<digits> * 10^k (i.e. in [10^(k-1), 10^k)). */
204
+ typedef struct {
205
+ char digits[24];
206
+ int len;
207
+ int k;
208
+ } yep_dsplit;
209
+
210
+ /* Tier B (dragon.c): exact shortest for any finite double/float bits.
211
+ * m2/e2 is the (unified) significand/exponent: v = m2 * 2^e2 with
212
+ * 2^mb <= m2 < 2^(mb+1) for normals, m2 < 2^mb for subnormals. */
213
+ int yep_dragon_shortest(uint64_t m2, int e2, int mb, int pow2_low, int tie_even, yep_dsplit* out);
214
+
215
+ /* Tier B exact fixed notation: digits of round_half_even(v * 10^p). */
216
+ int yep_dragon_fixed(uint64_t m2, int e2, uint32_t precision, char* buf);
217
+
218
+ /* Tier A (print.c): u128 fast tier; returns 0 when the value is out
219
+ * of the exact-128 range and tier B must be used. */
220
+ int yep_u128_shortest(uint64_t m2, int e2, int mb, int pow2_low, int tie_even, yep_dsplit* out);
221
+
222
+ /* tie_even: whether a decimal landing exactly on a round-trip boundary
223
+ * may be accepted — reparse ties to the even float, which is v only
224
+ * when v's significand is even (callers pass m2 % 2 == 0). */
225
+
226
+ /* Shared rendering of a digit split into the canonical YAML form:
227
+ * plain notation for 10^-4 <= |v| < 10^16, else d.dddde[+-]XX with a
228
+ * leading "1.0e+20"-style fraction so the value re-parses as float. */
229
+ int yep_float_render(const yep_dsplit* ds, int negative, char* buf);
230
+
231
+ #endif /* YEP_FLOATINT_H */