aboutsummaryrefslogtreecommitdiff
path: root/src/stdlib
diff options
context:
space:
mode:
authorBruce Hill <bruce@bruce-hill.com>2025-09-13 12:01:52 -0400
committerBruce Hill <bruce@bruce-hill.com>2025-09-13 12:01:52 -0400
commit981da7f0c6c47f66120482e7a7885cb5719d6959 (patch)
treec0d5bf912e7e477a0486120b8ac4aea8c49833f9 /src/stdlib
parent3a8841af6d15763e4c322c2c7671582ed6c3b006 (diff)
parentb4f2d03db2cd20688d6bb537904998e997bc48aa (diff)
Merge branch 'optional-list-indexing' into dev
Diffstat (limited to 'src/stdlib')
-rw-r--r--src/stdlib/lists.h47
-rw-r--r--src/stdlib/tables.h12
-rw-r--r--src/stdlib/text.c5
-rw-r--r--src/stdlib/text.h12
4 files changed, 48 insertions, 28 deletions
diff --git a/src/stdlib/lists.h b/src/stdlib/lists.h
index 1ba46222..1386b2fa 100644
--- a/src/stdlib/lists.h
+++ b/src/stdlib/lists.h
@@ -10,26 +10,29 @@
#include "util.h"
// Convert negative indices to back-indexed without branching: index0 = index + (index < 0)*(len+1)) - 1
-#define List_get(item_type, arr_expr, index_expr, start, end) \
- *({ \
- const List_t list = arr_expr; \
+#define List_get_checked(list_expr, index_expr, item_type, start, end) \
+ ({ \
+ const List_t list = list_expr; \
int64_t index = index_expr; \
int64_t off = index + (index < 0) * (list.length + 1) - 1; \
if (unlikely(off < 0 || off >= list.length)) \
fail_source(__SOURCE_FILE__, start, end, "Invalid list index: ", index, " (list has length ", \
(int64_t)list.length, ")\n"); \
- (item_type *)(list.data + list.stride * off); \
+ *(item_type *)(list.data + list.stride * off); \
})
-#define List_get_unchecked(type, x, i) \
- *({ \
- const List_t list = x; \
- int64_t index = i; \
- int64_t off = index + (index < 0) * (list.length + 1) - 1; \
- (type *)(list.data + list.stride * off); \
+#define List_get(list_expr, index_expr, item_type, var, optional_expr, none_expr) \
+ ({ \
+ const List_t list = list_expr; \
+ int64_t index = index_expr; \
+ int64_t offset = index + (index < 0) * (list.length + 1) - 1; \
+ unlikely(offset < 0 || offset >= list.length) ? none_expr : ({ \
+ item_type var = *(item_type *)(list.data + list.stride * offset); \
+ optional_expr; \
+ }); \
})
-#define List_lvalue(item_type, arr_expr, index_expr, start, end) \
+#define List_lvalue(item_type, list_expr, index_expr, start, end) \
*({ \
- List_t *list = arr_expr; \
+ List_t *list = list_expr; \
int64_t index = index_expr; \
int64_t off = index + (index < 0) * (list->length + 1) - 1; \
if (unlikely(off < 0 || off >= list->length)) \
@@ -38,15 +41,7 @@
if (list->data_refcount > 0) List$compact(list, sizeof(item_type)); \
(item_type *)(list->data + list->stride * off); \
})
-#define List_lvalue_unchecked(item_type, arr_expr, index_expr) \
- *({ \
- List_t *list = arr_expr; \
- int64_t index = index_expr; \
- int64_t off = index + (index < 0) * (list->length + 1) - 1; \
- if (list->data_refcount > 0) List$compact(list, sizeof(item_type)); \
- (item_type *)(list->data + list->stride * off); \
- })
-#define List_set(item_type, list, index, value, start, end) List_lvalue(item_type, arr_expr, index, start, end) = value
+#define List_set(item_type, list, index, value, start, end) List_lvalue(item_type, list_expr, index, start, end) = value
#define is_atomic(x) \
_Generic(x, \
bool: true, \
@@ -103,9 +98,9 @@ void List$remove_item(List_t *list, void *item, Int_t max_removals, const TypeIn
#define List$remove_item_value(list, item_expr, max, type) \
List$remove_item(list, (__typeof(item_expr)[1]){item_expr}, max, type)
-#define List$pop(arr_expr, index_expr, item_type, nonnone_var, nonnone_expr, none_expr) \
+#define List$pop(list_expr, index_expr, item_type, nonnone_var, nonnone_expr, none_expr) \
({ \
- List_t *list = arr_expr; \
+ List_t *list = list_expr; \
Int_t index = index_expr; \
int64_t index64 = Int64$from_int(index, false); \
int64_t off = index64 + (index64 < 0) * (list->length + 1) - 1; \
@@ -131,9 +126,9 @@ List_t List$shuffled(List_t list, OptionalClosure_t random_int64, int64_t padded
void *List$random(List_t list, OptionalClosure_t random_int64);
#define List$random_value(list, random_int64, t) \
({ \
- List_t _arr = list; \
- if (_arr.length == 0) fail("Cannot get a random value from an empty list!"); \
- *(t *)List$random(_arr, random_int64); \
+ List_t _list_expr = list; \
+ if (_list_expr.length == 0) fail("Cannot get a random value from an empty list!"); \
+ *(t *)List$random(_list_expr, random_int64); \
})
List_t List$sample(List_t list, Int_t n, List_t weights, Closure_t random_num, int64_t padded_item_size);
Table_t List$counts(List_t list, const TypeInfo_t *type);
diff --git a/src/stdlib/tables.h b/src/stdlib/tables.h
index 208bf6b2..129aa5ec 100644
--- a/src/stdlib/tables.h
+++ b/src/stdlib/tables.h
@@ -49,6 +49,18 @@ void *Table$get(Table_t t, const void *key, const TypeInfo_t *type);
val_t *nonnull_var = Table$get(t, &k, info_expr); \
nonnull_var ? nonnull_expr : null_expr; \
})
+#define Table$get_checked(table_expr, key_t, val_t, key_expr, start, end, info_expr) \
+ ({ \
+ const Table_t t = table_expr; \
+ const key_t key = key_expr; \
+ const TypeInfo_t *info = info_expr; \
+ val_t *value = Table$get(t, &key, info); \
+ if (unlikely(value == NULL)) \
+ fail_source(__SOURCE_FILE__, start, end, \
+ "This key was not found in the table: ", generic_as_text(&key, false, info->TableInfo.key), \
+ "\n"); \
+ *value; \
+ })
#define Table$get_or_setdefault(table_expr, key_t, val_t, key_expr, default_expr, info_expr) \
({ \
Table_t *t = table_expr; \
diff --git a/src/stdlib/text.c b/src/stdlib/text.c
index b6b7e0bb..cda7dd31 100644
--- a/src/stdlib/text.c
+++ b/src/stdlib/text.c
@@ -726,7 +726,10 @@ Text_t Text$reversed(Text_t text) {
}
public
-PUREFUNC Text_t Text$cluster(Text_t text, Int_t index) { return Text$slice(text, index, index); }
+PUREFUNC OptionalText_t Text$cluster(Text_t text, Int_t index) {
+ Text_t slice = Text$slice(text, index, index);
+ return slice.length <= 0 ? NONE_TEXT : slice;
+}
static Text_t Text$from_components(List_t graphemes, Table_t unique_clusters) {
size_t blob_size = (sizeof(int32_t[unique_clusters.entries.length]) + sizeof(uint8_t[graphemes.length]));
diff --git a/src/stdlib/text.h b/src/stdlib/text.h
index 4d2f16b8..281c1880 100644
--- a/src/stdlib/text.h
+++ b/src/stdlib/text.h
@@ -53,7 +53,17 @@ Text_t Text$slice(Text_t text, Int_t first_int, Int_t last_int);
Text_t Text$from(Text_t text, Int_t first);
Text_t Text$to(Text_t text, Int_t last);
Text_t Text$reversed(Text_t text);
-Text_t Text$cluster(Text_t text, Int_t index_int);
+OptionalText_t Text$cluster(Text_t text, Int_t index_int);
+#define Text$cluster_checked(text_expr, index_expr, start, end) \
+ ({ \
+ const Text_t text = text_expr; \
+ Int_t index = index_expr; \
+ OptionalText_t cluster = Text$cluster(text, index); \
+ if (unlikely(cluster.length < 0)) \
+ fail_source(__SOURCE_FILE__, start, end, "Invalid text index: ", index, " (text has length ", \
+ (int64_t)text.length, ")\n"); \
+ cluster; \
+ })
OptionalText_t Text$from_str(const char *str);
OptionalText_t Text$from_strn(const char *str, size_t len);
PUREFUNC uint64_t Text$hash(const void *text, const TypeInfo_t *);