aboutsummaryrefslogtreecommitdiff
path: root/src/stdlib
diff options
context:
space:
mode:
Diffstat (limited to 'src/stdlib')
-rw-r--r--src/stdlib/cli.c8
-rw-r--r--src/stdlib/datatypes.h8
-rw-r--r--src/stdlib/lists.c174
-rw-r--r--src/stdlib/lists.h4
-rw-r--r--src/stdlib/metamethods.c7
-rw-r--r--src/stdlib/optionals.c4
-rw-r--r--src/stdlib/optionals.h6
-rw-r--r--src/stdlib/paths.c43
-rw-r--r--src/stdlib/pointers.c8
-rw-r--r--src/stdlib/tables.c62
-rw-r--r--src/stdlib/tables.h2
-rw-r--r--src/stdlib/text.c74
-rw-r--r--src/stdlib/text.h2
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; \