code / tomo

Lines41.3K C23.7K Markdown9.7K YAML5.0K Tomo2.3K
7 others 763
Python231 Shell230 make212 INI47 Text21 SVG16 Lua6
(273 lines)
1 // Fixed-width integer type infos and methods
2 // This file is intended to be used by defining `INTX_C_H__INT_BITS` before including:
3 //
4 // #define INTX_C_H__INT_BITS 32
5 // #include "intX.c.h"
6 //
8 #include <gc.h>
9 #include <stdbool.h>
10 #include <stdint.h>
11 #include <stdio.h>
12 #include <stdlib.h>
14 #include "datatypes.h"
15 #include "integers.h"
16 #include "text.h"
17 #include "types.h"
19 #ifndef INTX_C_H__INT_BITS
20 #define INTX_C_H__INT_BITS 32
21 #endif
23 #define CAT_(a, b) a##b
24 #define CAT(a, b) CAT_(a, b)
25 #define STRINGIFY_(s) #s
26 #define STRINGIFY(s) STRINGIFY_(s)
28 #define INT_T CAT(CAT(int, INTX_C_H__INT_BITS), _t)
29 #define UINT_T CAT(CAT(uint, INTX_C_H__INT_BITS), _t)
30 #define OPT_T CAT(CAT(OptionalInt, INTX_C_H__INT_BITS), _t)
32 #define NAME_STR "Int" STRINGIFY(INTX_C_H__INT_BITS)
34 #define NAMESPACED(method_name) CAT(CAT(Int, INTX_C_H__INT_BITS), CAT($, method_name))
36 static Text_t _int64_to_text(int64_t n) {
37 if (n == INT64_MIN) return Text("-9223372036854775808");
39 char buf[21] = {[20] = 0}; // Big enough for INT64_MIN + '\0'
40 char *p = &buf[19];
41 bool negative = n < 0;
42 if (negative) n = -n; // Safe to do because we checked for INT64_MIN earlier
44 do {
45 *(p--) = '0' + (n % 10);
46 n /= 10;
47 } while (n > 0);
49 if (negative) *(p--) = '-';
51 return Text$from_strn(p + 1, (size_t)(&buf[19] - p));
54 public
55 void NAMESPACED(serialize)(const void *obj, FILE *out, Table_t *pointers, const TypeInfo_t *info) {
56 (void)info, (void)pointers;
57 #if INTX_C_H__INT_BITS < 32
58 if (fwrite(obj, sizeof(INT_T), 1, out) != sizeof(INT_T)) fail("Failed to write whole integer");
59 #else
60 INT_T i = *(INT_T *)obj;
61 UINT_T z = (UINT_T)((i << 1L) ^ (i >> (INTX_C_H__INT_BITS - 1L))); // Zigzag encode
62 while (z >= 0x80L) {
63 if (fputc((uint8_t)(z | 0x80L), out) == EOF) fail("Failed to write full integer");
64 z >>= 7L;
66 fputc((uint8_t)z, out);
67 #endif
70 public
71 void NAMESPACED(deserialize)(FILE *in, void *outval, List_t *pointers, const TypeInfo_t *info) {
72 (void)info, (void)pointers;
73 #if INTX_C_H__INT_BITS < 32
74 if (fread(outval, sizeof(INT_T), 1, in) != sizeof(INT_T)) fail("Failed to read full integer");
75 #else
76 UINT_T z = 0;
77 for (size_t shift = 0;; shift += 7) {
78 int i = fgetc(in);
79 if (i == EOF) fail("Failed to read whole integer");
80 uint8_t byte = (uint8_t)i;
81 z |= ((UINT_T)(byte & 0x7F)) << shift;
82 if ((byte & 0x80) == 0) break;
84 *(INT_T *)outval = (INT_T)((z >> 1L) ^ -(z & 1L)); // Zigzag decode
85 #endif
88 #ifdef __TINYC__
89 #define __builtin_add_overflow(x, y, result) \
90 ({ \
91 *(result) = (x) + (y); \
92 false; \
93 })
94 #endif
96 public
97 Text_t NAMESPACED(as_text)(const void *i, bool colorize, const TypeInfo_t *info) {
98 (void)info;
99 if (!i) return Text(NAME_STR);
100 Text_t text = _int64_to_text((int64_t)(*(INT_T *)i));
101 return colorize ? Text$concat(Text("\033[35m"), text, Text("\033[m")) : text;
103 public
104 Text_t NAMESPACED(value_as_text)(INT_T i) {
105 return _int64_to_text((int64_t)i);
107 public
108 PUREFUNC int32_t NAMESPACED(compare)(const void *x, const void *y, const TypeInfo_t *info) {
109 (void)info;
110 return (*(INT_T *)x > *(INT_T *)y) - (*(INT_T *)x < *(INT_T *)y);
112 public
113 PUREFUNC bool NAMESPACED(equal)(const void *x, const void *y, const TypeInfo_t *info) {
114 (void)info;
115 return *(INT_T *)x == *(INT_T *)y;
117 public
118 CONSTFUNC bool NAMESPACED(is_between)(const INT_T x, const INT_T low, const INT_T high) {
119 return (low <= x && x <= high) || (high <= x && x <= low);
121 public
122 CONSTFUNC INT_T NAMESPACED(clamped)(INT_T x, INT_T min, INT_T max) {
123 return x < min ? min : (x > max ? max : x);
125 public
126 Text_t NAMESPACED(hex)(INT_T i, Int_t digits_int, bool uppercase, bool prefix) {
127 Int_t as_int = Int$from_int64((int64_t)i);
128 return Int$hex(as_int, digits_int, uppercase, prefix);
130 public
131 Text_t NAMESPACED(octal)(INT_T i, Int_t digits_int, bool prefix) {
132 Int_t as_int = Int$from_int64((int64_t)i);
133 return Int$octal(as_int, digits_int, prefix);
135 public
136 List_t NAMESPACED(bits)(INT_T x) {
137 List_t bit_list = (List_t){.data = GC_MALLOC_ATOMIC(sizeof(bool[8 * sizeof(INT_T)])),
138 .atomic = 1,
139 .stride = sizeof(bool),
140 .length = 8 * sizeof(INT_T)};
141 bool *bits = bit_list.data + sizeof(INT_T) * 8;
142 for (size_t i = 0; i < 8 * sizeof(INT_T); i++) {
143 *(bits--) = x & 1;
144 x >>= 1;
146 return bit_list;
148 public
149 bool NAMESPACED(get_bit)(INT_T x, Int_t bit_index) {
150 if (Int$compare_value(bit_index, I(1)) < 0) fail("Invalid bit index (expected 1 or higher): ", bit_index);
151 if (Int$compare_value(bit_index, Int$from_int64(sizeof(INT_T) * 8)) > 0)
152 fail("Bit index is too large! There are only ", (uint64_t)sizeof(INT_T) * 8,
153 " bits, but index is: ", bit_index);
154 return ((x & (INT_T)(1L << (Int64$from_int(bit_index, true) - 1L))) != 0);
156 typedef struct {
157 OPT_T current, last;
158 INT_T step;
159 } NAMESPACED(Range_t);
161 static OPT_T _next_int(NAMESPACED(Range_t) * info) {
162 OPT_T i = info->current;
163 if (i.has_value) {
164 INT_T next;
165 bool overflow = __builtin_add_overflow(i.value, info->step, &next);
166 if (overflow || (info->last.has_value && (info->step >= 0 ? next > info->last.value : next < info->last.value)))
167 info->current = (OPT_T){.has_value = false};
168 else info->current = (OPT_T){.has_value = true, .value = next};
170 return i;
173 public
174 #if INTX_C_H__INT_BITS < 64
175 CONSTFUNC
176 #endif
177 Closure_t NAMESPACED(to)(INT_T first, INT_T last, OPT_T step) {
178 NAMESPACED(Range_t) *range = GC_MALLOC(sizeof(NAMESPACED(Range_t)));
179 range->current = (OPT_T){.has_value = true, .value = first};
180 range->last = (OPT_T){.has_value = true, .value = last};
181 range->step = step.has_value ? step.value : (last >= first ? 1 : -1);
182 return (Closure_t){.fn = _next_int, .userdata = range};
185 public
186 #if INTX_C_H__INT_BITS < 64
187 CONSTFUNC
188 #endif
189 Closure_t NAMESPACED(onward)(INT_T first, INT_T step) {
190 NAMESPACED(Range_t) *range = GC_MALLOC(sizeof(NAMESPACED(Range_t)));
191 range->current = (OPT_T){.has_value = true, .value = first};
192 range->last = (OPT_T){.has_value = false};
193 range->step = step;
194 return (Closure_t){.fn = _next_int, .userdata = range};
196 public
197 PUREFUNC OPT_T NAMESPACED(parse)(Text_t text, OptionalInt_t base, Text_t *remainder) {
198 OptionalInt_t full_int = Int$parse(text, base, remainder);
199 if (full_int.small == 0L) return (OPT_T){.has_value = false};
200 if (Int$compare_value(full_int, I(NAMESPACED(min))) < 0) {
201 return (OPT_T){.has_value = false};
203 if (Int$compare_value(full_int, I(NAMESPACED(max))) > 0) {
204 return (OPT_T){.has_value = false};
206 return (OPT_T){.has_value = true, .value = NAMESPACED(from_int)(full_int, true)};
209 public
210 CONSTFUNC INT_T NAMESPACED(gcd)(INT_T x, INT_T y) {
211 if (x == 0 || y == 0) return 0;
212 x = NAMESPACED(abs)(x);
213 y = NAMESPACED(abs)(y);
214 while (x != y) {
215 if (x > y) x -= y;
216 else y -= x;
218 return x;
221 public
222 const INT_T NAMESPACED(min) =
223 #if INTX_C_H__INT_BITS == 64
224 INT64_MIN
225 #elif INTX_C_H__INT_BITS == 32
226 INT32_MIN
227 #elif INTX_C_H__INT_BITS == 16
228 INT16_MIN
229 #elif INTX_C_H__INT_BITS == 8
230 INT8_MIN
231 #else
232 #error "Unsupported integer bit width"
233 #endif
236 public
237 const INT_T NAMESPACED(max) =
238 #if INTX_C_H__INT_BITS == 64
239 INT64_MAX
240 #elif INTX_C_H__INT_BITS == 32
241 INT32_MAX
242 #elif INTX_C_H__INT_BITS == 16
243 INT16_MAX
244 #elif INTX_C_H__INT_BITS == 8
245 INT8_MAX
246 #else
247 #error "Unsupported integer bit width"
248 #endif
251 public
252 const TypeInfo_t NAMESPACED(info) = {
253 .size = sizeof(INT_T),
254 .align = __alignof__(INT_T),
255 .metamethods =
257 .compare = NAMESPACED(compare),
258 .as_text = NAMESPACED(as_text),
259 .serialize = NAMESPACED(serialize),
260 .deserialize = NAMESPACED(deserialize),
264 #undef CAT_
265 #undef CAT
266 #undef STRINGIFY_
267 #undef STRINGIFY
268 #undef INT_T
269 #undef UINT_T
270 #undef OPT_T
271 #undef NAME_STR
272 #undef NAMESPACED
273 #undef INTX_C_H__INT_BITS