diff options
| author | Bruce Hill <bruce@bruce-hill.com> | 2025-10-01 12:43:00 -0400 |
|---|---|---|
| committer | Bruce Hill <bruce@bruce-hill.com> | 2025-10-01 12:43:00 -0400 |
| commit | 6583fe9b389a6b4698f9364945885e6783506886 (patch) | |
| tree | 0464456d177eab051b03f29a74218a45b301f174 /src/stdlib | |
| parent | 0cfae753aa131f949253f3fba1e3a36c2bde6ac0 (diff) | |
Convert to using more zero values for `none`
Diffstat (limited to 'src/stdlib')
| -rw-r--r-- | src/stdlib/cli.c | 8 | ||||
| -rw-r--r-- | src/stdlib/datatypes.h | 8 | ||||
| -rw-r--r-- | src/stdlib/lists.c | 174 | ||||
| -rw-r--r-- | src/stdlib/lists.h | 4 | ||||
| -rw-r--r-- | src/stdlib/metamethods.c | 7 | ||||
| -rw-r--r-- | src/stdlib/optionals.c | 4 | ||||
| -rw-r--r-- | src/stdlib/optionals.h | 6 | ||||
| -rw-r--r-- | src/stdlib/paths.c | 43 | ||||
| -rw-r--r-- | src/stdlib/pointers.c | 8 | ||||
| -rw-r--r-- | src/stdlib/tables.c | 62 | ||||
| -rw-r--r-- | src/stdlib/tables.h | 2 | ||||
| -rw-r--r-- | src/stdlib/text.c | 74 | ||||
| -rw-r--r-- | src/stdlib/text.h | 2 |
13 files changed, 206 insertions, 196 deletions
diff --git a/src/stdlib/cli.c b/src/stdlib/cli.c index 62174f19..1e4324f9 100644 --- a/src/stdlib/cli.c +++ b/src/stdlib/cli.c @@ -124,9 +124,10 @@ static List_t parse_list(const TypeInfo_t *item_info, int n, char *args[]) { if ((padded_size % item_info->align) > 0) padded_size = padded_size + item_info->align - (padded_size % item_info->align); + uint64_t u = (uint64_t)n; List_t items = { .stride = padded_size, - .length = n, + .length = u, .data = GC_MALLOC((size_t)(padded_size * n)), }; for (int i = 0; i < n; i++) { @@ -145,9 +146,10 @@ static Table_t parse_table(const TypeInfo_t *table, int n, char *args[]) { padded_size += value->size; if ((padded_size % key->align) > 0) padded_size = padded_size + key->align - (padded_size % key->align); + uint64_t u = (uint64_t)n; List_t entries = { .stride = padded_size, - .length = n, + .length = u, .data = GC_MALLOC((size_t)(padded_size * n)), }; for (int i = 0; i < n; i++) { @@ -378,7 +380,7 @@ void _tomo_parse_args(int argc, char *argv[], Text_t usage, Text_t help, const c for (int s = 0; s < spec_len; s++) { if (!populated_args[s] && spec[s].required) { - if (spec[s].type->tag == ListInfo) *(OptionalList_t *)spec[s].dest = (List_t){}; + if (spec[s].type->tag == ListInfo) *(OptionalList_t *)spec[s].dest = EMPTY_LIST; else if (spec[s].type->tag == TableInfo) *(OptionalTable_t *)spec[s].dest = (Table_t){}; else print_err("The required argument '", spec[s].name, "' was not provided\n", usage); } diff --git a/src/stdlib/datatypes.h b/src/stdlib/datatypes.h index 373cbc47..cbf09519 100644 --- a/src/stdlib/datatypes.h +++ b/src/stdlib/datatypes.h @@ -41,7 +41,7 @@ typedef struct { // structs can be passed in two 64-bit registers. C will handle doing the // bit arithmetic to extract the necessary values, which is cheaper than // spilling onto the stack and needing to retrieve data from the stack. - int64_t length : LIST_LENGTH_BITS; + uint64_t length : LIST_LENGTH_BITS; uint64_t free : LIST_FREE_BITS; bool atomic : LIST_ATOMIC_BITS; uint8_t data_refcount : LIST_REFCOUNT_BITS; @@ -73,11 +73,11 @@ typedef struct { void *fn, *userdata; } Closure_t; -enum text_type { TEXT_ASCII, TEXT_GRAPHEMES, TEXT_CONCAT, TEXT_BLOB }; +enum text_type { TEXT_NONE, TEXT_ASCII, TEXT_GRAPHEMES, TEXT_CONCAT, TEXT_BLOB }; typedef struct Text_s { - int64_t length : 54; // Number of grapheme clusters - uint8_t tag : 2; + uint64_t length : 53; // Number of grapheme clusters + uint8_t tag : 3; uint8_t depth : 8; union { struct { diff --git a/src/stdlib/lists.c b/src/stdlib/lists.c index bae79dfd..516f37e2 100644 --- a/src/stdlib/lists.c +++ b/src/stdlib/lists.c @@ -18,6 +18,9 @@ // Use inline version of siphash code: #include "siphash-internals.h" +public +char _EMPTY_LIST_SENTINEL = '\0'; + PUREFUNC static INLINE int64_t get_padded_item_size(const TypeInfo_t *info) { int64_t size = info->ListInfo.item->size; if (info->ListInfo.item->align > 1 && size % info->ListInfo.item->align) errx(1, "Item size is not padded!"); @@ -35,7 +38,7 @@ void List$compact(List_t *list, int64_t padded_item_size) { if ((int64_t)list->stride == padded_item_size) { memcpy(copy, list->data, (size_t)list->length * (size_t)padded_item_size); } else { - for (int64_t i = 0; i < list->length; i++) + for (int64_t i = 0; i < (int64_t)list->length; i++) memcpy(copy + i * padded_item_size, list->data + list->stride * i, (size_t)padded_item_size); } } @@ -50,7 +53,7 @@ void List$compact(List_t *list, int64_t padded_item_size) { public void List$insert(List_t *list, const void *item, Int_t int_index, int64_t padded_item_size) { int64_t index = Int64$from_int(int_index, false); - if (index <= 0) index = list->length + index + 1; + if (index <= 0) index = (int64_t)list->length + index + 1; if (index < 1) index = 1; else if (index > (int64_t)list->length + 1) @@ -74,9 +77,9 @@ void List$insert(List_t *list, const void *item, Int_t int_index, int64_t padded list->data_refcount = 0; list->stride = padded_item_size; } else { - if (index != list->length + 1) { - assert(list->length >= index); - size_t size = (size_t)((list->length - index + 1) * padded_item_size); + if (index != (int64_t)list->length + 1) { + assert((int64_t)list->length >= index); + size_t size = (size_t)(((int64_t)list->length - index + 1) * padded_item_size); assert(size < SIZE_MAX); memmove(list->data + index * padded_item_size, list->data + (index - 1) * padded_item_size, size); } @@ -98,7 +101,7 @@ void List$insert_all(List_t *list, List_t to_insert, Int_t int_index, int64_t pa return; } - if (index < 1) index = list->length + index + 1; + if (index < 1) index = (int64_t)list->length + index + 1; if (index < 1) index = 1; else if (index > (int64_t)list->length + 1) @@ -110,15 +113,15 @@ void List$insert_all(List_t *list, List_t to_insert, Int_t int_index, int64_t pa // If we can fit this within the list's preallocated free space, do that: list->free -= to_insert.length; list->length += to_insert.length; - if (index != list->length + 1) + if (index != (int64_t)list->length + 1) memmove((void *)list->data + index * padded_item_size, list->data + (index - 1) * padded_item_size, - (size_t)((list->length - index + to_insert.length - 1) * padded_item_size)); - for (int64_t i = 0; i < to_insert.length; i++) + (size_t)(((int64_t)list->length - index + (int64_t)to_insert.length - 1) * padded_item_size)); + for (int64_t i = 0; i < (int64_t)to_insert.length; i++) memcpy((void *)list->data + (index - 1 + i) * padded_item_size, to_insert.data + i * to_insert.stride, (size_t)padded_item_size); } else { // Otherwise, allocate a new chunk of memory for the list and populate it: - int64_t new_len = list->length + to_insert.length; + int64_t new_len = (int64_t)list->length + (int64_t)to_insert.length; list->free = MIN(LIST_MAX_FREE_ENTRIES, MAX(8, new_len / 4)); void *data = list->atomic ? GC_MALLOC_ATOMIC((size_t)((new_len + list->free) * padded_item_size)) : GC_MALLOC((size_t)((new_len + list->free) * padded_item_size)); @@ -139,8 +142,8 @@ void List$insert_all(List_t *list, List_t to_insert, Int_t int_index, int64_t pa // Copy `to_insert` if (to_insert.stride == padded_item_size) { - memcpy(p, to_insert.data, (size_t)(to_insert.length * padded_item_size)); - p += to_insert.length * padded_item_size; + memcpy(p, to_insert.data, (size_t)((int64_t)to_insert.length * padded_item_size)); + p += (int64_t)to_insert.length * padded_item_size; } else { for (int64_t i = 0; i < index - 1; i++) { memcpy(p, to_insert.data + to_insert.stride * i, (size_t)padded_item_size); @@ -149,19 +152,19 @@ void List$insert_all(List_t *list, List_t to_insert, Int_t int_index, int64_t pa } // Copy last chunk of `list` if needed: - if (index < list->length + 1) { + if (index < (int64_t)list->length + 1) { if (list->stride == padded_item_size) { memcpy(p, list->data + padded_item_size * (index - 1), - (size_t)((list->length - index + 1) * padded_item_size)); - p += (list->length - index + 1) * padded_item_size; + (size_t)(((int64_t)list->length - index + 1) * padded_item_size)); + p += ((int64_t)list->length - index + 1) * padded_item_size; } else { - for (int64_t i = index - 1; i < list->length - 1; i++) { + for (int64_t i = index - 1; i < (int64_t)list->length - 1; i++) { memcpy(p, list->data + list->stride * i, (size_t)padded_item_size); p += padded_item_size; } } } - list->length = new_len; + list->length = (uint64_t)new_len; list->stride = padded_item_size; list->data = data; list->data_refcount = 0; @@ -171,20 +174,20 @@ void List$insert_all(List_t *list, List_t to_insert, Int_t int_index, int64_t pa public void List$remove_at(List_t *list, Int_t int_index, Int_t int_count, int64_t padded_item_size) { int64_t index = Int64$from_int(int_index, false); - if (index < 1) index = list->length + index + 1; + if (index < 1) index = (int64_t)list->length + index + 1; int64_t count = Int64$from_int(int_count, false); if (index < 1 || index > (int64_t)list->length || count < 1) return; - if (count > list->length - index + 1) count = (list->length - index) + 1; + if (count > (int64_t)list->length - index + 1) count = ((int64_t)list->length - index) + 1; if (index == 1) { list->data += list->stride * count; - } else if (index + count > list->length) { + } else if (index + count > (int64_t)list->length) { list->free += count; } else if (list->data_refcount != 0 || (int64_t)list->stride != padded_item_size) { - void *copy = list->atomic ? GC_MALLOC_ATOMIC((size_t)((list->length - 1) * padded_item_size)) - : GC_MALLOC((size_t)((list->length - 1) * padded_item_size)); + void *copy = list->atomic ? GC_MALLOC_ATOMIC((size_t)(((int64_t)list->length - 1) * padded_item_size)) + : GC_MALLOC((size_t)(((int64_t)list->length - 1) * padded_item_size)); for (int64_t src = 1, dest = 1; src <= (int64_t)list->length; src++) { if (src < index || src >= index + count) { memcpy(copy + (dest - 1) * padded_item_size, list->data + list->stride * (src - 1), @@ -198,10 +201,10 @@ void List$remove_at(List_t *list, Int_t int_index, Int_t int_count, int64_t padd } else { memmove((void *)list->data + (index - 1) * padded_item_size, list->data + (index - 1 + count) * padded_item_size, - (size_t)((list->length - index + count - 1) * padded_item_size)); + (size_t)(((int64_t)list->length - index + count - 1) * padded_item_size)); list->free += count; } - list->length -= count; + list->length -= (uint64_t)count; if (list->length == 0) list->data = NULL; } @@ -211,7 +214,7 @@ void List$remove_item(List_t *list, void *item, Int_t max_removals, const TypeIn const Int_t ZERO = (Int_t){.small = (0 << 2) | 1}; const Int_t ONE = (Int_t){.small = (1 << 2) | 1}; const TypeInfo_t *item_type = type->ListInfo.item; - for (int64_t i = 0; i < list->length;) { + for (int64_t i = 0; i < (int64_t)list->length;) { if (max_removals.small == ZERO.small) // zero break; @@ -227,7 +230,7 @@ void List$remove_item(List_t *list, void *item, Int_t max_removals, const TypeIn public OptionalInt_t List$find(List_t list, void *item, const TypeInfo_t *type) { const TypeInfo_t *item_type = type->ListInfo.item; - for (int64_t i = 0; i < list.length; i++) { + for (int64_t i = 0; i < (int64_t)list.length; i++) { if (generic_equal(item, list.data + i * list.stride, item_type)) return I(i + 1); } return NONE_INT; @@ -236,7 +239,7 @@ OptionalInt_t List$find(List_t list, void *item, const TypeInfo_t *type) { public OptionalInt_t List$first(List_t list, Closure_t predicate) { bool (*is_good)(void *, void *) = (void *)predicate.fn; - for (int64_t i = 0; i < list.length; i++) { + for (int64_t i = 0; i < (int64_t)list.length; i++) { if (is_good(list.data + i * list.stride, predicate.userdata)) return I(i + 1); } return NONE_INT; @@ -300,9 +303,9 @@ void List$shuffle(List_t *list, OptionalClosure_t random_int64, int64_t padded_i typedef int64_t (*rng_fn_t)(int64_t, int64_t, void *); rng_fn_t rng_fn = random_int64.fn ? (rng_fn_t)random_int64.fn : _default_random_int64; char tmp[padded_item_size]; - for (int64_t i = list->length - 1; i > 1; i--) { + for (int64_t i = (int64_t)list->length - 1; i > 1; i--) { int64_t j = rng_fn(0, i, random_int64.userdata); - if unlikely (j < 0 || j > list->length - 1) + if unlikely (j < 0 || j > (int64_t)list->length - 1) fail("The provided random number function returned an invalid value: ", j, " (not between 0 and ", i, ")"); memcpy(tmp, list->data + i * padded_item_size, (size_t)padded_item_size); memcpy((void *)list->data + i * padded_item_size, list->data + j * padded_item_size, (size_t)padded_item_size); @@ -323,8 +326,8 @@ void *List$random(List_t list, OptionalClosure_t random_int64) { typedef int64_t (*rng_fn_t)(int64_t, int64_t, void *); rng_fn_t rng_fn = random_int64.fn ? (rng_fn_t)random_int64.fn : _default_random_int64; - int64_t index = rng_fn(0, list.length - 1, random_int64.userdata); - if unlikely (index < 0 || index > list.length - 1) + int64_t index = rng_fn(0, (int64_t)list.length - 1, random_int64.userdata); + if unlikely (index < 0 || index > (int64_t)list.length - 1) fail("The provided random number function returned an invalid value: ", index, " (not between 0 and ", (int64_t)list.length, ")"); return list.data + list.stride * index; @@ -332,9 +335,9 @@ void *List$random(List_t list, OptionalClosure_t random_int64) { public Table_t List$counts(List_t list, const TypeInfo_t *type) { - Table_t counts = {}; + Table_t counts = EMPTY_TABLE; const TypeInfo_t count_type = *Table$info(type->ListInfo.item, &Int$info); - for (int64_t i = 0; i < list.length; i++) { + for (int64_t i = 0; i < (int64_t)list.length; i++) { void *key = list.data + i * list.stride; int64_t *count = Table$get(counts, key, &count_type); int64_t val = count ? *count + 1 : 1; @@ -362,7 +365,7 @@ List_t List$sample(List_t list, Int_t int_n, List_t weights, OptionalClosure_t r int64_t n = Int64$from_int(int_n, false); if (n < 0) fail("Cannot select a negative number of values"); - if (n == 0) return (List_t){}; + if (n == 0) return EMPTY_LIST; if (list.length == 0) fail("There are no elements in this list!"); @@ -370,7 +373,7 @@ List_t List$sample(List_t list, Int_t int_n, List_t weights, OptionalClosure_t r fail("List has ", (int64_t)list.length, " elements, but there are ", (int64_t)weights.length, " weights given"); double total = 0.0; - for (int64_t i = 0; i < weights.length && i < list.length; i++) { + for (int64_t i = 0; i < (int64_t)weights.length && i < (int64_t)list.length; i++) { double weight = *(double *)(weights.data + weights.stride * i); if (isinf(weight)) fail("Infinite weight!"); else if (isnan(weight)) fail("NaN weight!"); @@ -389,19 +392,19 @@ List_t List$sample(List_t list, Int_t int_n, List_t weights, OptionalClosure_t r double odds; } aliases[list.length]; - for (int64_t i = 0; i < list.length; i++) { - double weight = i >= weights.length ? 0.0 : *(double *)(weights.data + weights.stride * i); + for (int64_t i = 0; i < (int64_t)list.length; i++) { + double weight = i >= (int64_t)weights.length ? 0.0 : *(double *)(weights.data + weights.stride * i); aliases[i].odds = weight * inverse_average; aliases[i].alias = -1; } int64_t small = 0; - for (int64_t big = 0; big < list.length; big++) { + for (int64_t big = 0; big < (int64_t)list.length; big++) { while (aliases[big].odds >= 1.0) { - while (small < list.length && (aliases[small].odds >= 1.0 || aliases[small].alias != -1)) + while (small < (int64_t)list.length && (aliases[small].odds >= 1.0 || aliases[small].alias != -1)) ++small; - if (small >= list.length) { + if (small >= (int64_t)list.length) { aliases[big].odds = 1.0; aliases[big].alias = big; break; @@ -413,7 +416,7 @@ List_t List$sample(List_t list, Int_t int_n, List_t weights, OptionalClosure_t r if (big < small) small = big; } - for (int64_t i = small; i < list.length; i++) + for (int64_t i = small; i < (int64_t)list.length; i++) if (aliases[i].alias == -1) aliases[i].alias = i; typedef double (*rng_fn_t)(void *); @@ -421,7 +424,7 @@ List_t List$sample(List_t list, Int_t int_n, List_t weights, OptionalClosure_t r List_t selected = {.data = list.atomic ? GC_MALLOC_ATOMIC((size_t)(n * padded_item_size)) : GC_MALLOC((size_t)(n * padded_item_size)), - .length = n, + .length = (uint64_t)n, .stride = padded_item_size, .atomic = list.atomic}; for (int64_t i = 0; i < n; i++) { @@ -430,7 +433,7 @@ List_t List$sample(List_t list, Int_t int_n, List_t weights, OptionalClosure_t r fail("The random number function returned a value not between 0.0 (inclusive) and 1.0 (exclusive): ", r); r *= (double)list.length; int64_t index = (int64_t)r; - assert(index >= 0 && index < list.length); + assert(index >= 0 && index < (int64_t)list.length); if ((r - (double)index) > aliases[index].odds) index = aliases[index].alias; memcpy(selected.data + i * selected.stride, list.data + index * list.stride, (size_t)padded_item_size); } @@ -449,29 +452,29 @@ List_t List$by(List_t list, Int_t int_stride, int64_t padded_item_size) { // In the unlikely event that the stride value would be too large to fit in // a 15-bit integer, fall back to creating a copy of the list: if (unlikely(list.stride * stride < LIST_MIN_STRIDE || list.stride * stride > LIST_MAX_STRIDE)) { - void *copy = NULL; - int64_t len = (stride < 0 ? list.length / -stride : list.length / stride) + ((list.length % stride) != 0); - if (len > 0) { - copy = list.atomic ? GC_MALLOC_ATOMIC((size_t)(len * padded_item_size)) - : GC_MALLOC((size_t)(len * padded_item_size)); - void *start = (stride < 0 ? list.data + (list.stride * (list.length - 1)) : list.data); - for (int64_t i = 0; i < len; i++) - memcpy(copy + i * padded_item_size, start + list.stride * stride * i, (size_t)padded_item_size); - } + int64_t len = (stride < 0 ? (int64_t)list.length / -stride : (int64_t)list.length / stride) + + (((int64_t)list.length % stride) != 0); + if (len <= 0) return list.atomic ? EMPTY_ATOMIC_LIST : EMPTY_LIST; + void *copy = list.atomic ? GC_MALLOC_ATOMIC((size_t)(len * padded_item_size)) + : GC_MALLOC((size_t)(len * padded_item_size)); + void *start = (stride < 0 ? list.data + (list.stride * ((int64_t)list.length - 1)) : list.data); + for (int64_t i = 0; i < len; i++) + memcpy(copy + i * padded_item_size, start + list.stride * stride * i, (size_t)padded_item_size); return (List_t){ .data = copy, - .length = len, + .length = (uint64_t)len, .stride = padded_item_size, .atomic = list.atomic, }; } - if (stride == 0) return (List_t){.atomic = list.atomic}; + if (stride == 0) return list.atomic ? EMPTY_ATOMIC_LIST : EMPTY_LIST; return (List_t){ .atomic = list.atomic, - .data = (stride < 0 ? list.data + (list.stride * (list.length - 1)) : list.data), - .length = (stride < 0 ? list.length / -stride : list.length / stride) + ((list.length % stride) != 0), + .data = (stride < 0 ? list.data + (list.stride * ((int64_t)list.length - 1)) : list.data), + .length = (uint64_t)((stride < 0 ? (int64_t)list.length / -stride : (int64_t)list.length / stride) + + (((int64_t)list.length % stride) != 0)), .stride = list.stride * stride, .data_refcount = list.data_refcount, }; @@ -482,19 +485,19 @@ List_t List$slice(List_t list, Int_t int_first, Int_t int_last) { int64_t first = Int64$from_int(int_first, false); - if (first < 0) first = list.length + first + 1; + if (first < 0) first = (int64_t)list.length + first + 1; int64_t last = Int64$from_int(int_last, false); - if (last < 0) last = list.length + last + 1; + if (last < 0) last = (int64_t)list.length + last + 1; - if (last > list.length) last = list.length; + if (last > (int64_t)list.length) last = (int64_t)list.length; - if (first < 1 || first > list.length || last == 0) return (List_t){.atomic = list.atomic}; + if (first < 1 || first > (int64_t)list.length || last == 0) return EMPTY_ATOMIC_LIST; return (List_t){ .atomic = list.atomic, .data = list.data + list.stride * (first - 1), - .length = last - first + 1, + .length = (uint64_t)(last - first + 1), .stride = list.stride, .data_refcount = list.data_refcount, }; @@ -511,26 +514,26 @@ List_t List$reversed(List_t list, int64_t padded_item_size) { List_t reversed = list; reversed.stride = -list.stride; - reversed.data = list.data + (list.length - 1) * list.stride; + reversed.data = list.data + ((int64_t)list.length - 1) * list.stride; return reversed; } public List_t List$concat(List_t x, List_t y, int64_t padded_item_size) { - void *data = x.atomic ? GC_MALLOC_ATOMIC((size_t)(padded_item_size * (x.length + y.length))) - : GC_MALLOC((size_t)(padded_item_size * (x.length + y.length))); + void *data = x.atomic ? GC_MALLOC_ATOMIC((size_t)(padded_item_size * (int64_t)(x.length + y.length))) + : GC_MALLOC((size_t)(padded_item_size * (int64_t)(x.length + y.length))); if (x.stride == padded_item_size) { - memcpy(data, x.data, (size_t)(padded_item_size * x.length)); + memcpy(data, x.data, (size_t)(padded_item_size * (int64_t)x.length)); } else { - for (int64_t i = 0; i < x.length; i++) + for (int64_t i = 0; i < (int64_t)x.length; i++) memcpy(data + i * padded_item_size, x.data + i * padded_item_size, (size_t)padded_item_size); } - void *dest = data + padded_item_size * x.length; + void *dest = data + padded_item_size * (int64_t)x.length; if (y.stride == padded_item_size) { - memcpy(dest, y.data, (size_t)(padded_item_size * y.length)); + memcpy(dest, y.data, (size_t)(padded_item_size * (int64_t)y.length)); } else { - for (int64_t i = 0; i < y.length; i++) + for (int64_t i = 0; i < (int64_t)y.length; i++) memcpy(dest + i * padded_item_size, y.data + i * y.stride, (size_t)padded_item_size); } @@ -545,14 +548,14 @@ List_t List$concat(List_t x, List_t y, int64_t padded_item_size) { public bool List$has(List_t list, void *item, const TypeInfo_t *type) { const TypeInfo_t *item_type = type->ListInfo.item; - for (int64_t i = 0; i < list.length; i++) { + for (int64_t i = 0; i < (int64_t)list.length; i++) { if (generic_equal(list.data + i * list.stride, item, item_type)) return true; } return false; } public -void List$clear(List_t *list) { *list = (List_t){.data = 0, .length = 0}; } +void List$clear(List_t *list) { *list = list->atomic ? EMPTY_ATOMIC_LIST : EMPTY_LIST; } public int32_t List$compare(const void *vx, const void *vy, const TypeInfo_t *type) { @@ -568,7 +571,8 @@ int32_t List$compare(const void *vx, const void *vy, const TypeInfo_t *type) { if ((int64_t)x->stride == item_padded_size && (int64_t)y->stride == item_padded_size && item->size == item_padded_size) { - int32_t cmp = (int32_t)memcmp(x->data, y->data, (size_t)(MIN(x->length, y->length) * item_padded_size)); + int32_t cmp = (int32_t)memcmp(x->data, y->data, + (size_t)(MIN((int64_t)x->length, (int64_t)y->length) * item_padded_size)); if (cmp != 0) return cmp; } else { for (int32_t i = 0, len = MIN(x->length, y->length); i < len; i++) { @@ -597,7 +601,7 @@ Text_t List$as_text(const void *obj, bool colorize, const TypeInfo_t *type) { const TypeInfo_t *item_type = type->ListInfo.item; Text_t text = Text("["); - for (int64_t i = 0; i < list->length; i++) { + for (int64_t i = 0; i < (int64_t)list->length; i++) { if (i > 0) text = Text$concat(text, Text(", ")); Text_t item_text = generic_as_text(list->data + i * list->stride, colorize, item_type); text = Text$concat(text, item_text); @@ -613,10 +617,10 @@ uint64_t List$hash(const void *obj, const TypeInfo_t *type) { siphash sh; siphashinit(&sh, sizeof(uint64_t[list->length])); if (item->tag == PointerInfo || (!item->metamethods.hash && item->size == sizeof(void *))) { // Raw data hash - for (int64_t i = 0; i < list->length; i++) + for (int64_t i = 0; i < (int64_t)list->length; i++) siphashadd64bits(&sh, (uint64_t)(list->data + i * list->stride)); } else { - for (int64_t i = 0; i < list->length; i++) { + for (int64_t i = 0; i < (int64_t)list->length; i++) { uint64_t item_hash = generic_hash(list->data + i * list->stride, item); siphashadd64bits(&sh, item_hash); } @@ -625,7 +629,7 @@ uint64_t List$hash(const void *obj, const TypeInfo_t *type) { } static void siftdown(List_t *heap, int64_t startpos, int64_t pos, Closure_t comparison, int64_t padded_item_size) { - assert(pos > 0 && pos < heap->length); + assert(pos > 0 && pos < (int64_t)heap->length); char newitem[padded_item_size]; memcpy(newitem, heap->data + heap->stride * pos, (size_t)(padded_item_size)); while (pos > startpos) { @@ -641,7 +645,7 @@ static void siftdown(List_t *heap, int64_t startpos, int64_t pos, Closure_t comp } static void siftup(List_t *heap, int64_t pos, Closure_t comparison, int64_t padded_item_size) { - int64_t endpos = heap->length; + int64_t endpos = (int64_t)heap->length; int64_t startpos = pos; assert(pos < endpos); @@ -673,7 +677,7 @@ void List$heap_push(List_t *heap, const void *item, Closure_t comparison, int64_ if (heap->length > 1) { if (heap->data_refcount != 0) List$compact(heap, padded_item_size); - siftdown(heap, 0, heap->length - 1, comparison, padded_item_size); + siftdown(heap, 0, (int64_t)heap->length - 1, comparison, padded_item_size); } } @@ -682,13 +686,13 @@ void List$heap_pop(List_t *heap, Closure_t comparison, int64_t padded_item_size) if (heap->length == 0) fail("Attempt to pop from an empty list"); if (heap->length == 1) { - *heap = (List_t){}; + *heap = EMPTY_LIST; } else if (heap->length == 2) { heap->data += heap->stride; --heap->length; } else { if (heap->data_refcount != 0) List$compact(heap, padded_item_size); - memcpy(heap->data, heap->data + heap->stride * (heap->length - 1), (size_t)(padded_item_size)); + memcpy(heap->data, heap->data + heap->stride * ((int64_t)heap->length - 1), (size_t)(padded_item_size)); --heap->length; siftup(heap, 0, comparison, padded_item_size); } @@ -701,7 +705,7 @@ void List$heapify(List_t *heap, Closure_t comparison, int64_t padded_item_size) // It's necessary to bump the refcount because the user's comparison // function could do stuff that modifies the heap's data. LIST_INCREF(*heap); - int64_t i, n = heap->length; + int64_t i, n = (int64_t)heap->length; for (i = (n >> 1) - 1; i >= 0; i--) siftup(heap, i, comparison, padded_item_size); LIST_DECREF(*heap); @@ -710,7 +714,7 @@ void List$heapify(List_t *heap, Closure_t comparison, int64_t padded_item_size) public Int_t List$binary_search(List_t list, void *target, Closure_t comparison) { typedef int32_t (*cmp_fn_t)(void *, void *, void *); - int64_t lo = 0, hi = list.length - 1; + int64_t lo = 0, hi = (int64_t)list.length - 1; while (lo <= hi) { int64_t mid = (lo + hi) / 2; int32_t cmp = ((cmp_fn_t)comparison.fn)(list.data + list.stride * mid, target, comparison.userdata); @@ -724,13 +728,13 @@ Int_t List$binary_search(List_t list, void *target, Closure_t comparison) { public PUREFUNC bool List$is_none(const void *obj, const TypeInfo_t *info) { (void)info; - return ((List_t *)obj)->length < 0; + return ((List_t *)obj)->data == NULL; } public void List$serialize(const void *obj, FILE *out, Table_t *pointers, const TypeInfo_t *type) { List_t list = *(List_t *)obj; - int64_t len = list.length; + int64_t len = (int64_t)list.length; Int64$serialize(&len, out, pointers, &Int64$info); serialize_fn_t item_serialize = type->ListInfo.item->metamethods.serialize; if (item_serialize) { @@ -752,7 +756,7 @@ void List$deserialize(FILE *in, void *obj, List_t *pointers, const TypeInfo_t *t if (type->ListInfo.item->align > 0 && padded_size % type->ListInfo.item->align > 0) padded_size += type->ListInfo.item->align - (padded_size % type->ListInfo.item->align); List_t list = { - .length = len, + .length = (uint64_t)len, .data = GC_MALLOC((size_t)(len * padded_size)), .stride = padded_size, }; diff --git a/src/stdlib/lists.h b/src/stdlib/lists.h index 1386b2fa..457fed52 100644 --- a/src/stdlib/lists.h +++ b/src/stdlib/lists.h @@ -9,6 +9,10 @@ #include "types.h" #include "util.h" +extern char _EMPTY_LIST_SENTINEL; +#define EMPTY_LIST ((List_t){.data = &_EMPTY_LIST_SENTINEL}) +#define EMPTY_ATOMIC_LIST ((List_t){.data = &_EMPTY_LIST_SENTINEL, .atomic = 1}) + // Convert negative indices to back-indexed without branching: index0 = index + (index < 0)*(len+1)) - 1 #define List_get_checked(list_expr, index_expr, item_type, start, end) \ ({ \ diff --git a/src/stdlib/metamethods.c b/src/stdlib/metamethods.c index 6161918c..3eff2dd3 100644 --- a/src/stdlib/metamethods.c +++ b/src/stdlib/metamethods.c @@ -6,6 +6,7 @@ #include "lists.h" #include "metamethods.h" #include "siphash.h" +#include "tables.h" #include "types.h" #include "util.h" @@ -50,12 +51,12 @@ List_t generic_serialize(const void *x, const TypeInfo_t *type) { char *buf = NULL; size_t size = 0; FILE *stream = open_memstream(&buf, &size); - Table_t pointers = {}; + Table_t pointers = EMPTY_TABLE; _serialize(x, stream, &pointers, type); fclose(stream); List_t bytes = { .data = GC_MALLOC_ATOMIC(size), - .length = (int64_t)size, + .length = (uint64_t)size, .stride = 1, .atomic = 1, }; @@ -79,7 +80,7 @@ void generic_deserialize(List_t bytes, void *outval, const TypeInfo_t *type) { if (bytes.stride != 1) List$compact(&bytes, 1); FILE *input = fmemopen(bytes.data, (size_t)bytes.length, "r"); - List_t pointers = {}; + List_t pointers = EMPTY_LIST; _deserialize(input, outval, &pointers, type); fclose(input); } diff --git a/src/stdlib/optionals.c b/src/stdlib/optionals.c index e9184e4d..41d38a19 100644 --- a/src/stdlib/optionals.c +++ b/src/stdlib/optionals.c @@ -64,8 +64,8 @@ void Optional$deserialize(FILE *in, void *outval, List_t *pointers, const TypeIn _deserialize(in, outval, pointers, nonnull); } else { if (nonnull->tag == TextInfo) *(Text_t *)outval = NONE_TEXT; - else if (nonnull->tag == ListInfo) *(List_t *)outval = (List_t){.length = -1}; - else if (nonnull->tag == TableInfo) *(Table_t *)outval = (Table_t){.entries = {.length = -1}}; + else if (nonnull->tag == ListInfo) *(List_t *)outval = NONE_LIST; + else if (nonnull->tag == TableInfo) *(Table_t *)outval = NONE_TABLE; else if (nonnull == &Num$info) *(double *)outval = (double)NAN; else if (nonnull == &Num32$info) *(float *)outval = (float)NAN; else if (nonnull->tag == StructInfo || (nonnull->tag == OpaqueInfo && type->size > nonnull->size)) diff --git a/src/stdlib/optionals.h b/src/stdlib/optionals.h index 145fda60..9c875bd1 100644 --- a/src/stdlib/optionals.h +++ b/src/stdlib/optionals.h @@ -9,12 +9,12 @@ #include "types.h" #include "util.h" -#define NONE_LIST ((List_t){.length = -1}) +#define NONE_LIST ((List_t){.data = NULL}) #define NONE_BOOL ((OptionalBool_t)2) #define NONE_INT ((OptionalInt_t){.small = 0}) -#define NONE_TABLE ((OptionalTable_t){.entries.length = -1}) +#define NONE_TABLE ((OptionalTable_t){.entries.data = NULL}) #define NONE_CLOSURE ((OptionalClosure_t){.fn = NULL}) -#define NONE_TEXT ((OptionalText_t){.length = -1}) +#define NONE_TEXT ((OptionalText_t){.tag = TEXT_NONE}) #define NONE_PATH ((Path_t){.type = PATH_NONE}) PUREFUNC bool is_none(const void *obj, const TypeInfo_t *non_optional_type); diff --git a/src/stdlib/paths.c b/src/stdlib/paths.c index 385f3bdf..6db51e41 100644 --- a/src/stdlib/paths.c +++ b/src/stdlib/paths.c @@ -36,7 +36,7 @@ static const Path_t HOME_PATH = {.type.$tag = PATH_HOME}, ROOT_PATH = {.type.$ta CURDIR_PATH = {.type.$tag = PATH_RELATIVE}; static void clean_components(List_t *components) { - for (int64_t i = 0; i < components->length;) { + for (int64_t i = 0; i < (int64_t)components->length;) { Text_t *component = (Text_t *)(components->data + i * components->stride); if (component->length == 0 || Text$equal_values(*component, Text("."))) { List$remove_at(components, I(i + 1), I(1), sizeof(Text_t)); @@ -83,10 +83,11 @@ Path_t Path$from_str(const char *str) { // ignore /./ } else if (component_len == 2 && strncmp(str, "..", 2) == 0 && result.components.length > 1 && !Text$equal_values( - Text(".."), *(Text_t *)(result.components.data - + result.components.stride * (result.components.length - 1)))) { + Text(".."), + *(Text_t *)(result.components.data + + result.components.stride * ((int64_t)result.components.length - 1)))) { // Pop off /foo/baz/.. -> /foo - List$remove_at(&result.components, I(result.components.length), I(1), sizeof(Text_t)); + List$remove_at(&result.components, I((int64_t)result.components.length), I(1), sizeof(Text_t)); } else { Text_t component = Text$from_strn(str, component_len); List$insert_value(&result.components, component, I(0), sizeof(Text_t)); @@ -149,16 +150,16 @@ Path_t Path$relative_to(Path_t path, Path_t relative_to) { Path_t result = {.type.$tag = PATH_RELATIVE}; int64_t shared = 0; - for (; shared < path.components.length && shared < relative_to.components.length; shared++) { + for (; shared < (int64_t)path.components.length && shared < (int64_t)relative_to.components.length; shared++) { Text_t *p = (Text_t *)(path.components.data + shared * path.components.stride); Text_t *r = (Text_t *)(relative_to.components.data + shared * relative_to.components.stride); if (!Text$equal_values(*p, *r)) break; } - for (int64_t i = shared; i < relative_to.components.length; i++) + for (int64_t i = shared; i < (int64_t)relative_to.components.length; i++) List$insert_value(&result.components, Text(".."), I(1), sizeof(Text_t)); - for (int64_t i = shared; i < path.components.length; i++) { + for (int64_t i = shared; i < (int64_t)path.components.length; i++) { Text_t *p = (Text_t *)(path.components.data + i * path.components.stride); List$insert(&result.components, p, I(0), sizeof(Text_t)); } @@ -331,7 +332,7 @@ OptionalList_t Path$read_bytes(Path_t path, OptionalInt_t count) { if (count.small && (int64_t)sb.st_size < target_count) fail("Could not read ", target_count, " bytes from ", path, " (only got ", (uint64_t)sb.st_size, ")"); int64_t len = count.small ? target_count : (int64_t)sb.st_size; - return (List_t){.data = content, .atomic = 1, .stride = 1, .length = len}; + return (List_t){.data = content, .atomic = 1, .stride = 1, .length = (uint64_t)len}; } else { size_t capacity = 256, len = 0; char *content = GC_MALLOC_ATOMIC(capacity); @@ -359,14 +360,14 @@ OptionalList_t Path$read_bytes(Path_t path, OptionalInt_t count) { close(fd); if (count.small != 0 && (int64_t)len < target_count) fail("Could not read ", target_count, " bytes from ", path, " (only got ", (uint64_t)len, ")"); - return (List_t){.data = content, .atomic = 1, .stride = 1, .length = (int64_t)len}; + return (List_t){.data = content, .atomic = 1, .stride = 1, .length = (uint64_t)len}; } } public OptionalText_t Path$read(Path_t path) { List_t bytes = Path$read_bytes(path, NONE_INT); - if (bytes.length < 0) return NONE_TEXT; + if (bytes.data == NULL) return NONE_TEXT; return Text$from_utf8(bytes); } @@ -391,14 +392,14 @@ OptionalText_t Path$group(Path_t path, bool follow_symlinks) { public void Path$set_owner(Path_t path, OptionalText_t owner, OptionalText_t group, bool follow_symlinks) { uid_t owner_id = (uid_t)-1; - if (owner.length >= 0) { + if (owner.tag == TEXT_NONE) { struct passwd *pwd = getpwnam(Text$as_c_string(owner)); if (pwd == NULL) fail("Not a valid user: ", owner); owner_id = pwd->pw_uid; } gid_t group_id = (gid_t)-1; - if (group.length >= 0) { + if (group.tag == TEXT_NONE) { struct group *grp = getgrnam(Text$as_c_string(group)); if (grp == NULL) fail("Not a valid group: ", group); group_id = grp->gr_gid; @@ -459,7 +460,7 @@ void Path$create_directory(Path_t path, int permissions) { static List_t _filtered_children(Path_t path, bool include_hidden, mode_t filter) { path = Path$expand_home(path); struct dirent *dir; - List_t children = {}; + List_t children = EMPTY_LIST; const char *path_str = Path$as_c_string(path); size_t path_len = strlen(path_str); DIR *d = opendir(path_str); @@ -545,7 +546,7 @@ Path_t Path$parent(Path_t path) { return path; } else if (path.components.length > 0 && !Text$equal_values( - *(Text_t *)(path.components.data + path.components.stride * (path.components.length - 1)), + *(Text_t *)(path.components.data + path.components.stride * ((int64_t)path.components.length - 1)), Text(".."))) { return (Path_t){.type.$tag = path.type.$tag, .components = List$slice(path.components, I(1), I(-2))}; } else { @@ -559,7 +560,7 @@ Path_t Path$parent(Path_t path) { public PUREFUNC Text_t Path$base_name(Path_t path) { if (path.components.length >= 1) - return *(Text_t *)(path.components.data + path.components.stride * (path.components.length - 1)); + return *(Text_t *)(path.components.data + path.components.stride * ((int64_t)path.components.length - 1)); else if (path.type.$tag == PATH_HOME) return Text("~"); else if (path.type.$tag == PATH_RELATIVE) return Text("."); else return EMPTY_TEXT; @@ -577,7 +578,7 @@ public bool Path$has_extension(Path_t path, Text_t extension) { if (path.components.length < 2) return extension.length == 0; - Text_t last = *(Text_t *)(path.components.data + path.components.stride * (path.components.length - 1)); + Text_t last = *(Text_t *)(path.components.data + path.components.stride * ((int64_t)path.components.length - 1)); if (extension.length == 0) return !Text$has(Text$from(last, I(2)), Text(".")) || Text$equal_values(last, Text("..")); @@ -615,7 +616,7 @@ Path_t Path$with_extension(Path_t path, Text_t extension, bool replace) { .components = path.components, }; LIST_INCREF(result.components); - Text_t last = *(Text_t *)(path.components.data + path.components.stride * (path.components.length - 1)); + Text_t last = *(Text_t *)(path.components.data + path.components.stride * ((int64_t)path.components.length - 1)); List$remove_at(&result.components, I(-1), I(1), sizeof(Text_t)); if (replace) { const char *base = Text$as_c_string(last); @@ -675,7 +676,7 @@ List_t Path$glob(Path_t path) { int status = glob(Path$as_c_string(path), GLOB_BRACE | GLOB_TILDE, NULL, &glob_result); if (status != 0 && status != GLOB_NOMATCH) fail("Failed to perform globbing"); - List_t glob_files = {}; + List_t glob_files = EMPTY_LIST; for (size_t i = 0; i < glob_result.gl_pathc; i++) { size_t len = strlen(glob_result.gl_pathv[i]); if ((len >= 2 && glob_result.gl_pathv[i][len - 1] == '.' && glob_result.gl_pathv[i][len - 2] == '/') @@ -701,7 +702,7 @@ PUREFUNC uint64_t Path$hash(const void *obj, const TypeInfo_t *type) { Path_t *path = (Path_t *)obj; siphash sh; siphashinit(&sh, (uint64_t)path->type.$tag); - for (int64_t i = 0; i < path->components.length; i++) { + for (int64_t i = 0; i < (int64_t)path->components.length; i++) { uint64_t item_hash = Text$hash(path->components.data + i * path->components.stride, &Text$info); siphashadd64bits(&sh, item_hash); } @@ -748,10 +749,10 @@ int Path$print(FILE *f, Path_t path) { if (!Text$equal_values(*(Text_t *)path.components.data, Text(".."))) n += fputs("./", f); } - for (int64_t i = 0; i < path.components.length; i++) { + for (int64_t i = 0; i < (int64_t)path.components.length; i++) { Text_t *comp = (Text_t *)(path.components.data + i * path.components.stride); n += Text$print(f, *comp); - if (i + 1 < path.components.length) n += fputc('/', f); + if (i + 1 < (int64_t)path.components.length) n += fputc('/', f); } return n; } diff --git a/src/stdlib/pointers.c b/src/stdlib/pointers.c index 0a1623a0..74037613 100644 --- a/src/stdlib/pointers.c +++ b/src/stdlib/pointers.c @@ -30,7 +30,7 @@ Text_t Pointer$as_text(const void *x, bool colorize, const TypeInfo_t *type) { } static const void *root = NULL; - static Table_t pending = {}; + static Table_t pending = EMPTY_TABLE; bool top_level = (root == NULL); // Check for recursive references, so if `x.foo = x`, then it prints as @@ -47,7 +47,7 @@ Text_t Pointer$as_text(const void *x, bool colorize, const TypeInfo_t *type) { Text_t text = Texts(Text$from_str(ptr_info.sigil), Int64$value_as_text(*id)); return colorize ? Texts(Text("\x1b[34;1m"), text, Text("\x1b[m")) : text; } - int64_t next_id = pending.entries.length + 2; + int64_t next_id = (int64_t)pending.entries.length + 2; Table$set(&pending, x, &next_id, &rec_table); } @@ -97,7 +97,7 @@ void Pointer$serialize(const void *obj, FILE *out, Table_t *pointers, const Type if (id_ptr) { id = *id_ptr; } else { - id = pointers->entries.length + 1; + id = (int64_t)pointers->entries.length + 1; Table$set(pointers, &ptr, &id, &ptr_to_int_table); } @@ -112,7 +112,7 @@ void Pointer$deserialize(FILE *in, void *outval, List_t *pointers, const TypeInf Int64$deserialize(in, &id, pointers, &Int64$info); assert(id != 0); - if (id > pointers->length) { + if (id > (int64_t)pointers->length) { void *obj = GC_MALLOC((size_t)type->PointerInfo.pointed->size); List$insert(pointers, &obj, I(0), sizeof(void *)); _deserialize(in, obj, pointers, type->PointerInfo.pointed); diff --git a/src/stdlib/tables.c b/src/stdlib/tables.c index 6698dea3..c093e4c2 100644 --- a/src/stdlib/tables.c +++ b/src/stdlib/tables.c @@ -187,7 +187,7 @@ static void hashmap_resize_buckets(Table_t *t, uint32_t new_capacity, const Type t->bucket_info->count = new_capacity; t->bucket_info->last_free = new_capacity - 1; // Rehash: - for (int64_t i = 0; i < Table$length(*t); i++) { + for (int64_t i = 0; i < (int64_t)Table$length(*t); i++) { hdebug("Rehashing ", i, "\n"); Table$set_bucket(t, GET_ENTRY(*t, i), i, type); } @@ -252,7 +252,7 @@ void *Table$reserve(Table_t *t, const void *key, const void *value, const TypeIn else if (value_size > 0) memset(buf + value_offset(type), 0, (size_t)value_size); List$insert(&t->entries, buf, I(0), (int64_t)entry_size(type)); - int64_t entry_index = t->entries.length - 1; + int64_t entry_index = (int64_t)t->entries.length - 1; void *entry = GET_ENTRY(*t, entry_index); Table$set_bucket(t, entry, entry_index, type); return entry + value_offset(type); @@ -276,7 +276,7 @@ void Table$remove(Table_t *t, const void *key, const TypeInfo_t *type) { maybe_copy_on_write(t, type); // If unspecified, pop the last key: - if (!key) key = GET_ENTRY(*t, t->entries.length - 1); + if (!key) key = GET_ENTRY(*t, (int64_t)t->entries.length - 1); // Steps: look up the bucket for the removed key // If missing, then return immediately @@ -316,7 +316,7 @@ found_it:; // swap the other entry into the last position and then remove the last // entry. This disturbs the ordering of the table, but keeps removal O(1) // instead of O(N) - int64_t last_entry = t->entries.length - 1; + int64_t last_entry = (int64_t)t->entries.length - 1; if (bucket->index != last_entry) { hdebug("Removing key/value from the middle of the entries list\n"); @@ -336,7 +336,7 @@ found_it:; // Last entry is being removed, so clear it out to be safe: memset(GET_ENTRY(*t, last_entry), 0, entry_size(type)); - List$remove_at(&t->entries, I(t->entries.length), I(1), (int64_t)entry_size(type)); + List$remove_at(&t->entries, I((int64_t)t->entries.length), I(1), (int64_t)entry_size(type)); int64_t bucket_to_clear; if (prev) { // Middle (or end) of a chain @@ -359,7 +359,7 @@ found_it:; } CONSTFUNC public void *Table$entry(Table_t t, int64_t n) { - if (n < 1 || n > Table$length(t)) return NULL; + if (n < 1 || n > (int64_t)Table$length(t)) return NULL; return GET_ENTRY(t, n - 1); } @@ -386,7 +386,7 @@ PUREFUNC public bool Table$equal(const void *vx, const void *vy, const TypeInfo_ const TypeInfo_t *value_type = type->TableInfo.value; size_t offset = value_offset(type); - for (int64_t i = 0; i < x->entries.length; i++) { + for (int64_t i = 0; i < (int64_t)x->entries.length; i++) { void *x_key = x->entries.data + i * x->entries.stride; void *y_value = Table$get_raw(*y, x_key, type); if (!y_value) return false; @@ -418,7 +418,7 @@ PUREFUNC public int32_t Table$compare(const void *vx, const void *vy, const Type // `x[k] != y[k]`, as well as the largest key in `x` and `y`. void *mismatched_key = NULL, *max_x_key = NULL; - for (int64_t i = 0; i < x->entries.length; i++) { + for (int64_t i = 0; i < (int64_t)x->entries.length; i++) { void *key = x->entries.data + x->entries.stride * i; if (max_x_key == NULL || generic_compare(key, max_x_key, table.key) > 0) max_x_key = key; @@ -433,7 +433,7 @@ PUREFUNC public int32_t Table$compare(const void *vx, const void *vy, const Type // If the keys are not all equal, we gotta check to see if there exists a // `y[k]` such that `k` is smaller than all keys that `x` has and `y` doesn't: void *max_y_key = NULL; - for (int64_t i = 0; i < y->entries.length; i++) { + for (int64_t i = 0; i < (int64_t)y->entries.length; i++) { void *key = y->entries.data + y->entries.stride * i; if (max_y_key == NULL || generic_compare(key, max_y_key, table.key) > 0) max_y_key = key; @@ -474,7 +474,7 @@ PUREFUNC public int32_t Table$compare(const void *vx, const void *vy, const Type // Assuming keys are the same, compare values: if (table.value->size > 0) { - for (int64_t i = 0; i < x->entries.length; i++) { + for (int64_t i = 0; i < (int64_t)x->entries.length; i++) { void *key = x->entries.data + x->entries.stride * i; void *x_value = key + value_offset(type); void *y_value = Table$get_raw(*y, key, type); @@ -504,12 +504,12 @@ PUREFUNC public uint64_t Table$hash(const void *obj, const TypeInfo_t *type) { uint64_t keys_hash = 0, values_hash = 0; size_t offset = value_offset(type); if (table.value->size > 0) { - for (int64_t i = 0; i < t->entries.length; i++) { + for (int64_t i = 0; i < (int64_t)t->entries.length; i++) { keys_hash ^= generic_hash(t->entries.data + i * t->entries.stride, table.key); values_hash ^= generic_hash(t->entries.data + i * t->entries.stride + offset, table.value); } } else { - for (int64_t i = 0; i < t->entries.length; i++) + for (int64_t i = 0; i < (int64_t)t->entries.length; i++) keys_hash ^= generic_hash(t->entries.data + i * t->entries.stride, table.key); } @@ -517,7 +517,7 @@ PUREFUNC public uint64_t Table$hash(const void *obj, const TypeInfo_t *type) { int64_t length; uint64_t keys_hash, values_hash, fallback_hash; } components = { - t->entries.length, + (int64_t)t->entries.length, keys_hash, values_hash, t->fallback ? Table$hash(t->fallback, type) : 0, @@ -540,7 +540,7 @@ Text_t Table$as_text(const void *obj, bool colorize, const TypeInfo_t *type) { int64_t val_off = (int64_t)value_offset(type); Text_t text = Text("{"); - for (int64_t i = 0, length = Table$length(*t); i < length; i++) { + for (int64_t i = 0, length = (int64_t)Table$length(*t); i < length; i++) { if (i > 0) text = Text$concat(text, Text(", ")); void *entry = GET_ENTRY(*t, i); text = Text$concat(text, generic_as_text(entry, colorize, table.key)); @@ -561,8 +561,8 @@ Table_t Table$from_entries(List_t entries, const TypeInfo_t *type) { assert(type->tag == TableInfo); if (entries.length == 0) return (Table_t){}; - Table_t t = {}; - int64_t length = entries.length + entries.length / 4; + Table_t t = EMPTY_TABLE; + int64_t length = (int64_t)entries.length + (int64_t)entries.length / 4; size_t alloc_size = sizeof(bucket_info_t) + sizeof(bucket_t[length]); t.bucket_info = GC_MALLOC_ATOMIC(alloc_size); memset(t.bucket_info->buckets, 0, sizeof(bucket_t[length])); @@ -570,7 +570,7 @@ Table_t Table$from_entries(List_t entries, const TypeInfo_t *type) { t.bucket_info->last_free = length - 1; size_t offset = value_offset(type); - for (int64_t i = 0; i < entries.length; i++) { + for (int64_t i = 0; i < (int64_t)entries.length; i++) { void *key = entries.data + i * entries.stride; Table$set(&t, key, key + offset, type); } @@ -581,10 +581,10 @@ Table_t Table$from_entries(List_t entries, const TypeInfo_t *type) { public Table_t Table$intersection(Table_t a, Table_t b, const TypeInfo_t *type) { // Return a table such that t[k]==a[k] for all k such that a.has(k), b.has(k), and a[k]==b[k] - Table_t result = {}; + Table_t result = EMPTY_TABLE; const size_t offset = value_offset(type); for (Table_t *t = &a; t; t = t->fallback) { - for (int64_t i = 0; i < Table$length(*t); i++) { + for (int64_t i = 0; i < (int64_t)Table$length(*t); i++) { void *key = GET_ENTRY(*t, i); void *a_value = key + offset; void *b_value = Table$get(b, key, type); @@ -600,16 +600,16 @@ public Table_t Table$with(Table_t a, Table_t b, const TypeInfo_t *type) { // return a table such that t[k]==b[k] for all k such that b.has(k), and t[k]==a[k] for all k such that a.has(k) and // not b.has(k) - Table_t result = {}; + Table_t result = EMPTY_TABLE; const size_t offset = value_offset(type); for (Table_t *t = &a; t; t = t->fallback) { - for (int64_t i = 0; i < Table$length(*t); i++) { + for (int64_t i = 0; i < (int64_t)Table$length(*t); i++) { void *key = GET_ENTRY(*t, i); Table$set(&result, key, key + offset, type); } } for (Table_t *t = &b; t; t = t->fallback) { - for (int64_t i = 0; i < Table$length(*t); i++) { + for (int64_t i = 0; i < (int64_t)Table$length(*t); i++) { void *key = GET_ENTRY(*t, i); Table$set(&result, key, key + offset, type); } @@ -621,16 +621,16 @@ Table_t Table$with(Table_t a, Table_t b, const TypeInfo_t *type) { public Table_t Table$difference(Table_t a, Table_t b, const TypeInfo_t *type) { // return a table with elements in `a` or `b`, but not both - Table_t result = {}; + Table_t result = EMPTY_TABLE; const size_t offset = value_offset(type); for (Table_t *t = &a; t; t = t->fallback) { - for (int64_t i = 0; i < Table$length(*t); i++) { + for (int64_t i = 0; i < (int64_t)Table$length(*t); i++) { void *key = GET_ENTRY(*t, i); if (Table$get(b, key, type) == NULL) Table$set(&result, key, key + offset, type); } } for (Table_t *t = &b; t; t = t->fallback) { - for (int64_t i = 0; i < Table$length(*t); i++) { + for (int64_t i = 0; i < (int64_t)Table$length(*t); i++) { void *key = GET_ENTRY(*t, i); if (Table$get(a, key, type) == NULL) Table$set(&result, key, key + offset, type); } @@ -642,10 +642,10 @@ Table_t Table$difference(Table_t a, Table_t b, const TypeInfo_t *type) { public Table_t Table$without(Table_t a, Table_t b, const TypeInfo_t *type) { // Return a table such that t[k]==a[k] for all k such that not b.has(k) or b[k] != a[k] - Table_t result = {}; + Table_t result = EMPTY_TABLE; const size_t offset = value_offset(type); for (Table_t *t = &a; t; t = t->fallback) { - for (int64_t i = 0; i < Table$length(*t); i++) { + for (int64_t i = 0; i < (int64_t)Table$length(*t); i++) { void *key = GET_ENTRY(*t, i); void *a_value = key + offset; void *b_value = Table$get(b, key, type); @@ -672,7 +672,7 @@ Table_t Table$with_fallback(Table_t t, OptionalTable_t fallback) { PUREFUNC public bool Table$is_subset_of(Table_t a, Table_t b, bool strict, const TypeInfo_t *type) { if (a.entries.length > b.entries.length || (strict && a.entries.length == b.entries.length)) return false; - for (int64_t i = 0; i < Table$length(a); i++) { + for (int64_t i = 0; i < (int64_t)Table$length(a); i++) { void *found = Table$get_raw(b, GET_ENTRY(a, i), type); if (!found) return false; } @@ -708,13 +708,13 @@ CONSTFUNC public void *Table$str_entry(Table_t t, int64_t n) { return Table$entr PUREFUNC public bool Table$is_none(const void *obj, const TypeInfo_t *info) { (void)info; - return ((Table_t *)obj)->entries.length < 0; + return ((Table_t *)obj)->entries.data == NULL; } public void Table$serialize(const void *obj, FILE *out, Table_t *pointers, const TypeInfo_t *type) { Table_t *t = (Table_t *)obj; - int64_t len = t->entries.length; + int64_t len = (int64_t)t->entries.length; Int64$serialize(&len, out, pointers, &Int64$info); size_t offset = value_offset(type); @@ -737,7 +737,7 @@ void Table$deserialize(FILE *in, void *outval, List_t *pointers, const TypeInfo_ int64_t len; Int64$deserialize(in, &len, pointers, &Int$info); - Table_t t = {}; + Table_t t = EMPTY_TABLE; for (int64_t i = 0; i < len; i++) { char key[type->TableInfo.key->size]; _deserialize(in, key, pointers, type->TableInfo.key); diff --git a/src/stdlib/tables.h b/src/stdlib/tables.h index f4870f80..cc2b3b91 100644 --- a/src/stdlib/tables.h +++ b/src/stdlib/tables.h @@ -11,6 +11,8 @@ #include "types.h" #include "util.h" +#define EMPTY_TABLE ((Table_t){.entries.data = &_EMPTY_LIST_SENTINEL}) + #define Table(key_t, val_t, key_info, value_info, fb, N, ...) \ ({ \ struct { \ diff --git a/src/stdlib/text.c b/src/stdlib/text.c index cda7dd31..0f40aef9 100644 --- a/src/stdlib/text.c +++ b/src/stdlib/text.c @@ -127,7 +127,7 @@ typedef struct { } synthetic_grapheme_t; // Synthetic grapheme clusters (clusters of more than one codepoint): -static Table_t grapheme_ids_by_codepoints = {}; // ucs4_t* length-prefixed codepoints -> int32_t ID +static Table_t grapheme_ids_by_codepoints = EMPTY_TABLE; // ucs4_t* length-prefixed codepoints -> int32_t ID // This will hold a dynamically growing list of synthetic graphemes: static synthetic_grapheme_t *synthetic_graphemes = NULL; @@ -521,8 +521,7 @@ static Text_t concat2(Text_t a, Text_t b) { } OptionalText_t glue = - Text$from_utf32((List_t){.data = normalized, .length = (int64_t)norm_length, .stride = sizeof(ucs4_t)}); - assert(glue.length >= 0); + Text$from_utf32((List_t){.data = normalized, .length = (uint64_t)norm_length, .stride = sizeof(ucs4_t)}); if (normalized != norm_buf) free(normalized); @@ -743,14 +742,14 @@ static Text_t Text$from_components(List_t graphemes, Table_t unique_clusters) { void *blob = GC_MALLOC_ATOMIC(blob_size); int32_t *map = blob; uint8_t *bytes = blob + sizeof(int32_t[unique_clusters.entries.length]); - for (int64_t i = 0; i < unique_clusters.entries.length; i++) { + for (int64_t i = 0; i < (int64_t)unique_clusters.entries.length; i++) { struct { int32_t g; uint8_t b; } *entry = unique_clusters.entries.data + i * unique_clusters.entries.stride; map[entry->b] = entry->g; } - for (int64_t i = 0; i < graphemes.length; i++) { + for (int64_t i = 0; i < (int64_t)graphemes.length; i++) { int32_t g = *(int32_t *)(graphemes.data + i * graphemes.stride); uint8_t *byte = Table$get(unique_clusters, &g, Table$info(&Int32$info, &Byte$info)); assert(byte); @@ -785,8 +784,8 @@ OptionalText_t Text$from_strn(const char *str, size_t len) { } if (u8_check((uint8_t *)str, len) != NULL) return NONE_TEXT; - List_t graphemes = {}; - Table_t unique_clusters = {}; + List_t graphemes = EMPTY_LIST; + Table_t unique_clusters = EMPTY_TABLE; const uint8_t *pos = (const uint8_t *)str; const uint8_t *end = (const uint8_t *)&str[len]; // Iterate over grapheme clusters @@ -1138,7 +1137,7 @@ Text_t Text$translate(Text_t text, Table_t translations) { int64_t span_start = 0; List_t replacement_list = translations.entries; for (int64_t i = 0; i < text.length;) { - for (int64_t r = 0; r < replacement_list.length; r++) { + for (int64_t r = 0; r < (int64_t)replacement_list.length; r++) { struct { Text_t target, replacement; } *entry = replacement_list.data + r * replacement_list.stride; @@ -1194,7 +1193,7 @@ List_t Text$split(Text_t text, Text_t delimiters) { if (delimiters.length == 0) return Text$clusters(text); TextIter_t text_state = NEW_TEXT_ITER_STATE(text), delim_state = NEW_TEXT_ITER_STATE(delimiters); - List_t splits = {}; + List_t splits = EMPTY_LIST; for (int64_t i = 0; i < text.length;) { int64_t span_len = 0; while (i + span_len < text.length && !_matches(&text_state, &delim_state, i + span_len)) { @@ -1216,7 +1215,7 @@ List_t Text$split_any(Text_t text, Text_t delimiters) { if (delimiters.length == 0) return List(text); TextIter_t text_state = NEW_TEXT_ITER_STATE(text), delim_state = NEW_TEXT_ITER_STATE(delimiters); - List_t splits = {}; + List_t splits = EMPTY_LIST; for (int64_t i = 0; i < text.length;) { int64_t span_len = 0; while (i + span_len < text.length @@ -1370,8 +1369,7 @@ Text_t Text$upper(Text_t text, Text_t language) { uint32_t buf[out_len]; ucs4_t *upper = u32_toupper(codepoints.data, (size_t)codepoints.length, uc_language, UNINORM_NFC, buf, &out_len); OptionalText_t ret = - Text$from_utf32((List_t){.data = upper, .length = (int64_t)out_len, .stride = sizeof(int32_t)}); - assert(ret.length >= 0); + Text$from_utf32((List_t){.data = upper, .length = (uint64_t)out_len, .stride = sizeof(int32_t)}); if (upper != buf) free(upper); return ret; } @@ -1386,8 +1384,7 @@ Text_t Text$lower(Text_t text, Text_t language) { uint32_t buf[out_len]; ucs4_t *lower = u32_tolower(codepoints.data, (size_t)codepoints.length, uc_language, UNINORM_NFC, buf, &out_len); OptionalText_t ret = - Text$from_utf32((List_t){.data = lower, .length = (int64_t)out_len, .stride = sizeof(int32_t)}); - assert(ret.length >= 0); + Text$from_utf32((List_t){.data = lower, .length = (uint64_t)out_len, .stride = sizeof(int32_t)}); if (lower != buf) free(lower); return ret; } @@ -1402,8 +1399,7 @@ Text_t Text$title(Text_t text, Text_t language) { uint32_t buf[out_len]; ucs4_t *title = u32_totitle(codepoints.data, (size_t)codepoints.length, uc_language, UNINORM_NFC, buf, &out_len); OptionalText_t ret = - Text$from_utf32((List_t){.data = title, .length = (int64_t)out_len, .stride = sizeof(int32_t)}); - assert(ret.length >= 0); + Text$from_utf32((List_t){.data = title, .length = (uint64_t)out_len, .stride = sizeof(int32_t)}); if (title != buf) free(title); return ret; } @@ -1543,7 +1539,7 @@ Text_t Text$join(Text_t glue, List_t pieces) { if (pieces.length == 0) return EMPTY_TEXT; Text_t result = *(Text_t *)pieces.data; - for (int64_t i = 1; i < pieces.length; i++) { + for (int64_t i = 1; i < (int64_t)pieces.length; i++) { result = Text$concat(result, glue, *(Text_t *)(pieces.data + i * pieces.stride)); } return result; @@ -1551,8 +1547,8 @@ Text_t Text$join(Text_t glue, List_t pieces) { public List_t Text$clusters(Text_t text) { - List_t clusters = {}; - for (int64_t i = 1; i <= text.length; i++) { + List_t clusters = EMPTY_LIST; + for (int64_t i = 1; i <= (int64_t)text.length; i++) { Text_t cluster = Text$slice(text, I(i), I(i)); List$insert(&clusters, &cluster, I_small(0), sizeof(Text_t)); } @@ -1561,27 +1557,27 @@ List_t Text$clusters(Text_t text) { public List_t Text$utf8(Text_t text) { - if (text.length == 0) return (List_t){.atomic = 1}; - int64_t capacity = text.length; + if (text.length == 0) return EMPTY_ATOMIC_LIST; + int64_t capacity = (int64_t)text.length; Byte_t *buf = GC_MALLOC_ATOMIC(sizeof(Byte_t[capacity])); int64_t i = 0; u8_buf_append(text, &buf, &capacity, &i); return (List_t){ - .data = buf, .length = i, .stride = 1, .atomic = 1, .free = MIN(LIST_MAX_FREE_ENTRIES, capacity - i)}; + .data = buf, .length = (uint64_t)i, .stride = 1, .atomic = 1, .free = MIN(LIST_MAX_FREE_ENTRIES, capacity - i)}; } public List_t Text$utf16(Text_t text) { - if (text.length == 0) return (List_t){.atomic = 1}; + if (text.length == 0) return EMPTY_ATOMIC_LIST; List_t utf32 = Text$utf32(text); List_t utf16 = {.free = MIN(LIST_MAX_FREE_ENTRIES, (uint64_t)utf32.length), .atomic = 1}; utf16.data = GC_MALLOC_ATOMIC(sizeof(int32_t[utf16.free])); - for (int64_t i = 0; i < utf32.length; i++) { + for (int64_t i = 0; i < (int64_t)utf32.length; i++) { uint16_t u16_buf[4]; size_t u16_len = sizeof(u16_buf) / sizeof(u16_buf[0]); uint16_t *chunk_u16 = u32_to_u16(utf32.data + utf32.stride * i, 1, u16_buf, &u16_len); if (chunk_u16 == NULL) fail("Invalid codepoints encountered!"); - List$insert_all(&utf16, (List_t){.data = chunk_u16, .stride = sizeof(uint16_t), .length = (int64_t)u16_len}, + List$insert_all(&utf16, (List_t){.data = chunk_u16, .stride = sizeof(uint16_t), .length = (uint64_t)u16_len}, I(0), sizeof(uint16_t)); if (chunk_u16 != u16_buf) free(chunk_u16); } @@ -1590,10 +1586,10 @@ List_t Text$utf16(Text_t text) { public List_t Text$utf32(Text_t text) { - if (text.length == 0) return (List_t){.atomic = 1}; - List_t codepoints = {.atomic = 1}; + if (text.length == 0) return EMPTY_ATOMIC_LIST; + List_t codepoints = EMPTY_ATOMIC_LIST; TextIter_t state = NEW_TEXT_ITER_STATE(text); - for (int64_t i = 0; i < text.length; i++) { + for (int64_t i = 0; i < (int64_t)text.length; i++) { int32_t grapheme = Text$get_grapheme_fast(&state, i); if (grapheme < 0) { for (int64_t c = 0; c < NUM_GRAPHEME_CODEPOINTS(grapheme); c++) { @@ -1618,7 +1614,7 @@ static INLINE const char *codepoint_name(ucs4_t c) { public List_t Text$codepoint_names(Text_t text) { - List_t names = {}; + List_t names = EMPTY_LIST; TextIter_t state = NEW_TEXT_ITER_STATE(text); for (int64_t i = 0; i < text.length; i++) { int32_t grapheme = Text$get_grapheme_fast(&state, i); @@ -1653,7 +1649,7 @@ OptionalText_t Text$from_utf16(List_t units) { uint8_t buf[length]; uint8_t *u8 = u16_to_u8(units.data, (size_t)units.length, buf, &length); Text_t ret = - Text$from_utf8((List_t){.data = u8, .length = (int64_t)length, .stride = sizeof(uint8_t), .atomic = 1}); + Text$from_utf8((List_t){.data = u8, .length = (uint64_t)length, .stride = sizeof(uint8_t), .atomic = 1}); if (u8 != buf) free(u8); return ret; } @@ -1663,8 +1659,8 @@ OptionalText_t Text$from_utf32(List_t codepoints) { if (codepoints.length == 0) return EMPTY_TEXT; if (codepoints.stride != sizeof(uint32_t)) List$compact(&codepoints, sizeof(uint32_t)); - List_t graphemes = {}; - Table_t unique_clusters = {}; + List_t graphemes = EMPTY_ATOMIC_LIST; + Table_t unique_clusters = EMPTY_TABLE; const uint32_t *pos = (const uint32_t *)codepoints.data; const uint32_t *end = (const uint32_t *)&pos[codepoints.length]; // Iterate over grapheme clusters @@ -1684,12 +1680,12 @@ OptionalText_t Text$from_utf32(List_t codepoints) { if (unique_clusters.entries.length == 256) { List_t remaining_codepoints = { - .length = (int64_t)(end - next), + .length = (uint64_t)(end - next), .data = (void *)next, .stride = sizeof(int32_t), }; OptionalText_t remainder = Text$from_utf32(remaining_codepoints); - if (remainder.length < 0) return NONE_TEXT; + if (remainder.tag == TEXT_NONE) return NONE_TEXT; return concat2_assuming_safe(Text$from_components(graphemes, unique_clusters), remainder); } } @@ -1698,8 +1694,8 @@ OptionalText_t Text$from_utf32(List_t codepoints) { public OptionalText_t Text$from_codepoint_names(List_t codepoint_names) { - List_t codepoints = {}; - for (int64_t i = 0; i < codepoint_names.length; i++) { + List_t codepoints = EMPTY_LIST; + for (int64_t i = 0; i < (int64_t)codepoint_names.length; i++) { Text_t *name = ((Text_t *)(codepoint_names.data + i * codepoint_names.stride)); const char *name_str = Text$as_c_string(*name); ucs4_t codepoint = unicode_name_character(name_str); @@ -1711,9 +1707,9 @@ OptionalText_t Text$from_codepoint_names(List_t codepoint_names) { public List_t Text$lines(Text_t text) { - List_t lines = {}; + List_t lines = EMPTY_LIST; TextIter_t state = NEW_TEXT_ITER_STATE(text); - for (int64_t i = 0, line_start = 0; i < text.length; i++) { + for (int64_t i = 0, line_start = 0; i < (int64_t)text.length; i++) { int32_t grapheme = Text$get_grapheme_fast(&state, i); if (grapheme == '\r' && Text$get_grapheme_fast(&state, i + 1) == '\n') { // CRLF Text_t line = Text$slice(text, I(line_start + 1), I(i)); @@ -1768,7 +1764,7 @@ Closure_t Text$by_line(Text_t text) { PUREFUNC public bool Text$is_none(const void *t, const TypeInfo_t *info) { (void)info; - return ((Text_t *)t)->length < 0; + return ((Text_t *)t)->tag == TEXT_NONE; } public diff --git a/src/stdlib/text.h b/src/stdlib/text.h index 281c1880..75f300eb 100644 --- a/src/stdlib/text.h +++ b/src/stdlib/text.h @@ -59,7 +59,7 @@ OptionalText_t Text$cluster(Text_t text, Int_t index_int); const Text_t text = text_expr; \ Int_t index = index_expr; \ OptionalText_t cluster = Text$cluster(text, index); \ - if (unlikely(cluster.length < 0)) \ + if (unlikely(!cluster.has_value)) \ fail_source(__SOURCE_FILE__, start, end, "Invalid text index: ", index, " (text has length ", \ (int64_t)text.length, ")\n"); \ cluster; \ |
