diff options
| author | Bruce Hill <bruce@bruce-hill.com> | 2025-08-23 19:28:08 -0400 |
|---|---|---|
| committer | Bruce Hill <bruce@bruce-hill.com> | 2025-08-23 19:28:08 -0400 |
| commit | fcda36561d668f43bac91ea31cd55cbbd605d330 (patch) | |
| tree | eb74c0b17df584af0fd8154422ad924e04c96cc2 /src/stdlib | |
| parent | 414b0c7472c87c5a013029aefef49e2dbc41e700 (diff) | |
Autoformat everything with clang-format
Diffstat (limited to 'src/stdlib')
49 files changed, 3023 insertions, 3198 deletions
diff --git a/src/stdlib/bools.c b/src/stdlib/bools.c index 76de49e0..0231e21b 100644 --- a/src/stdlib/bools.c +++ b/src/stdlib/bools.c @@ -11,18 +11,14 @@ #include "text.h" #include "util.h" -PUREFUNC public Text_t Bool$as_text(const void *b, bool colorize, const TypeInfo_t *info) -{ +PUREFUNC public Text_t Bool$as_text(const void *b, bool colorize, const TypeInfo_t *info) { (void)info; if (!b) return Text("Bool"); - if (colorize) - return *(Bool_t*)b ? Text("\x1b[35myes\x1b[m") : Text("\x1b[35mno\x1b[m"); - else - return *(Bool_t*)b ? Text("yes") : Text("no"); + if (colorize) return *(Bool_t *)b ? Text("\x1b[35myes\x1b[m") : Text("\x1b[35mno\x1b[m"); + else return *(Bool_t *)b ? Text("yes") : Text("no"); } -static bool try_parse(Text_t text, Text_t target, bool target_value, Text_t *remainder, bool *result) -{ +static bool try_parse(Text_t text, Text_t target, bool target_value, Text_t *remainder, bool *result) { static const Text_t lang = Text("C"); if (text.length < target.length) return false; Text_t prefix = Text$to(text, Int$from_int64(target.length)); @@ -36,35 +32,33 @@ static bool try_parse(Text_t text, Text_t target, bool target_value, Text_t *rem } } -PUREFUNC public OptionalBool_t Bool$parse(Text_t text, Text_t *remainder) -{ +PUREFUNC public OptionalBool_t Bool$parse(Text_t text, Text_t *remainder) { bool result; if (try_parse(text, Text("yes"), true, remainder, &result) || try_parse(text, Text("true"), true, remainder, &result) - || try_parse(text, Text("on"), true, remainder, &result) - || try_parse(text, Text("1"), true, remainder, &result) + || try_parse(text, Text("on"), true, remainder, &result) || try_parse(text, Text("1"), true, remainder, &result) || try_parse(text, Text("no"), false, remainder, &result) || try_parse(text, Text("false"), false, remainder, &result) || try_parse(text, Text("off"), false, remainder, &result) || try_parse(text, Text("0"), false, remainder, &result)) return result; - else - return NONE_BOOL; + else return NONE_BOOL; } -static bool Bool$is_none(const void *b, const TypeInfo_t *info) -{ +static bool Bool$is_none(const void *b, const TypeInfo_t *info) { (void)info; - return *(OptionalBool_t*)b == NONE_BOOL; + return *(OptionalBool_t *)b == NONE_BOOL; } -public const TypeInfo_t Bool$info = { - .size=sizeof(bool), - .align=__alignof__(bool), - .metamethods={ - .as_text=Bool$as_text, - .is_none=Bool$is_none, - }, +public +const TypeInfo_t Bool$info = { + .size = sizeof(bool), + .align = __alignof__(bool), + .metamethods = + { + .as_text = Bool$as_text, + .is_none = Bool$is_none, + }, }; // vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0 diff --git a/src/stdlib/bools.h b/src/stdlib/bools.h index bdf80879..3eac0f0d 100644 --- a/src/stdlib/bools.h +++ b/src/stdlib/bools.h @@ -8,8 +8,8 @@ #include "types.h" #include "util.h" -#define yes (Bool_t)true -#define no (Bool_t)false +#define yes (Bool_t) true +#define no (Bool_t) false PUREFUNC Text_t Bool$as_text(const void *b, bool colorize, const TypeInfo_t *type); OptionalBool_t Bool$parse(Text_t text, Text_t *remainder); diff --git a/src/stdlib/bytes.c b/src/stdlib/bytes.c index 5a581e7e..d4bd5ef6 100644 --- a/src/stdlib/bytes.c +++ b/src/stdlib/bytes.c @@ -8,15 +8,18 @@ #include "text.h" #include "util.h" -public const Byte_t Byte$min = 0; -public const Byte_t Byte$max = UINT8_MAX; +public +const Byte_t Byte$min = 0; +public +const Byte_t Byte$max = UINT8_MAX; -PUREFUNC public Text_t Byte$as_text(const void *b, bool colorize, const TypeInfo_t *info) -{ +PUREFUNC public Text_t Byte$as_text(const void *b, bool colorize, const TypeInfo_t *info) { (void)info; if (!b) return Text("Byte"); - Byte_t byte = *(Byte_t*)b; - char digits[] = {'0', 'x', + Byte_t byte = *(Byte_t *)b; + char digits[] = { + '0', + 'x', (byte / 16) <= 9 ? '0' + (byte / 16) : 'a' + (byte / 16) - 10, (byte & 15) <= 9 ? '0' + (byte & 15) : 'a' + (byte & 15) - 10, '\0', @@ -26,52 +29,54 @@ PUREFUNC public Text_t Byte$as_text(const void *b, bool colorize, const TypeInfo return text; } -public CONSTFUNC bool Byte$is_between(const Byte_t x, const Byte_t low, const Byte_t high) { - return low <= x && x <= high; -} +public +CONSTFUNC bool Byte$is_between(const Byte_t x, const Byte_t low, const Byte_t high) { return low <= x && x <= high; } -public OptionalByte_t Byte$parse(Text_t text, Text_t *remainder) -{ +public +OptionalByte_t Byte$parse(Text_t text, Text_t *remainder) { OptionalInt_t full_int = Int$parse(text, remainder); - if (full_int.small != 0L - && Int$compare_value(full_int, I(0)) >= 0 - && Int$compare_value(full_int, I(255)) <= 0) { - return (OptionalByte_t){.value=Byte$from_int(full_int, true)}; + if (full_int.small != 0L && Int$compare_value(full_int, I(0)) >= 0 && Int$compare_value(full_int, I(255)) <= 0) { + return (OptionalByte_t){.value = Byte$from_int(full_int, true)}; } else { return NONE_BYTE; } } -public Text_t Byte$hex(Byte_t byte, bool uppercase, bool prefix) { - struct Text_s text = {.tag=TEXT_ASCII}; +public +Text_t Byte$hex(Byte_t byte, bool uppercase, bool prefix) { + struct Text_s text = {.tag = TEXT_ASCII}; text.ascii = GC_MALLOC_ATOMIC(8); - char *p = (char*)text.ascii; + char *p = (char *)text.ascii; if (prefix) { *(p++) = '0'; *(p++) = 'x'; } if (uppercase) { - *(p++) = (byte/16) > 9 ? 'A' + (byte/16) - 10 : '0' + (byte/16); + *(p++) = (byte / 16) > 9 ? 'A' + (byte / 16) - 10 : '0' + (byte / 16); *(p++) = (byte & 15) > 9 ? 'A' + (byte & 15) - 10 : '0' + (byte & 15); } else { - *(p++) = (byte/16) > 9 ? 'a' + (byte/16) - 10 : '0' + (byte/16); + *(p++) = (byte / 16) > 9 ? 'a' + (byte / 16) - 10 : '0' + (byte / 16); *(p++) = (byte & 15) > 9 ? 'a' + (byte & 15) - 10 : '0' + (byte & 15); } text.length = (int64_t)(p - text.ascii); return text; } -public bool Byte$get_bit(Byte_t x, Int_t bit_index) { - if (Int$compare_value(bit_index, I(1)) < 0) - fail("Invalid bit index (expected 1 or higher): ", bit_index); +public +bool Byte$get_bit(Byte_t x, Int_t bit_index) { + if (Int$compare_value(bit_index, I(1)) < 0) fail("Invalid bit index (expected 1 or higher): ", bit_index); if (Int$compare_value(bit_index, I(8)) > 0) fail("Bit index is too large! There are only 8 bits in a byte, but index is: ", bit_index); - return ((x & (Byte_t)(1L << (Int64$from_int(bit_index, true)-1L))) != 0); + return ((x & (Byte_t)(1L << (Int64$from_int(bit_index, true) - 1L))) != 0); } #ifdef __TINYC__ -#define __builtin_add_overflow(x, y, result) ({ *(result) = (x) + (y); false; }) +#define __builtin_add_overflow(x, y, result) \ + ({ \ + *(result) = (x) + (y); \ + false; \ + }) #endif typedef struct { @@ -82,52 +87,59 @@ typedef struct { static OptionalByte_t _next_Byte(ByteRange_t *info) { OptionalByte_t i = info->current; if (!i.is_none) { - Byte_t next; bool overflow = __builtin_add_overflow(i.value, info->step, &next); + Byte_t next; + bool overflow = __builtin_add_overflow(i.value, info->step, &next); if (overflow || (!info->last.is_none && (info->step >= 0 ? next > info->last.value : next < info->last.value))) - info->current = (OptionalByte_t){.is_none=true}; - else - info->current = (OptionalByte_t){.value=next}; + info->current = (OptionalByte_t){.is_none = true}; + else info->current = (OptionalByte_t){.value = next}; } return i; } -public CONSTFUNC Closure_t Byte$to(Byte_t first, Byte_t last, OptionalInt8_t step) { +public +CONSTFUNC Closure_t Byte$to(Byte_t first, Byte_t last, OptionalInt8_t step) { ByteRange_t *range = GC_MALLOC(sizeof(ByteRange_t)); - range->current = (OptionalByte_t){.value=first}; - range->last = (OptionalByte_t){.value=last}; + range->current = (OptionalByte_t){.value = first}; + range->last = (OptionalByte_t){.value = last}; range->step = step.is_none ? (last >= first ? 1 : -1) : step.value; - return (Closure_t){.fn=_next_Byte, .userdata=range}; + return (Closure_t){.fn = _next_Byte, .userdata = range}; } -public PUREFUNC Byte_t Byte$from_int(Int_t i, bool truncate) { +public +PUREFUNC Byte_t Byte$from_int(Int_t i, bool truncate) { if unlikely (!truncate && Int$compare_value(i, I_small(0xFF)) > 0) fail("This value is too large to convert to a byte without truncation: ", i); else if unlikely (!truncate && Int$compare_value(i, I_small(0)) < 0) fail("Negative values can't be converted to bytes: ", i); return (Byte_t)(i.small >> 2); } -public PUREFUNC Byte_t Byte$from_int64(Int64_t i, bool truncate) { +public +PUREFUNC Byte_t Byte$from_int64(Int64_t i, bool truncate) { if unlikely (!truncate && i != (Int64_t)(Byte_t)i) fail("This value can't be converted to a byte without truncation: ", i); return (Byte_t)i; } -public PUREFUNC Byte_t Byte$from_int32(Int32_t i, bool truncate) { +public +PUREFUNC Byte_t Byte$from_int32(Int32_t i, bool truncate) { if unlikely (!truncate && i != (Int32_t)(Byte_t)i) fail("This value can't be converted to a byte without truncation: ", i); return (Byte_t)i; } -public PUREFUNC Byte_t Byte$from_int16(Int16_t i, bool truncate) { +public +PUREFUNC Byte_t Byte$from_int16(Int16_t i, bool truncate) { if unlikely (!truncate && i != (Int16_t)(Byte_t)i) fail("This value can't be converted to a byte without truncation: ", i); return (Byte_t)i; } -public const TypeInfo_t Byte$info = { - .size=sizeof(Byte_t), - .align=__alignof__(Byte_t), - .metamethods={ - .as_text=Byte$as_text, - }, +public +const TypeInfo_t Byte$info = { + .size = sizeof(Byte_t), + .align = __alignof__(Byte_t), + .metamethods = + { + .as_text = Byte$as_text, + }, }; // vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0 diff --git a/src/stdlib/c_strings.c b/src/stdlib/c_strings.c index c2b8efbe..b965f04b 100644 --- a/src/stdlib/c_strings.c +++ b/src/stdlib/c_strings.c @@ -12,46 +12,40 @@ #include "text.h" #include "util.h" -public Text_t CString$as_text(const void *c_string, bool colorize, const TypeInfo_t *info) -{ +public +Text_t CString$as_text(const void *c_string, bool colorize, const TypeInfo_t *info) { (void)info; if (!c_string) return Text("CString"); - Text_t text = Text$from_str(*(const char**)c_string); - return Text$concat(colorize ? Text("\x1b[34mCString\x1b[m(") : Text("CString("), Text$quoted(text, colorize, Text("\"")), Text(")")); + Text_t text = Text$from_str(*(const char **)c_string); + return Text$concat(colorize ? Text("\x1b[34mCString\x1b[m(") : Text("CString("), + Text$quoted(text, colorize, Text("\"")), Text(")")); } -PUREFUNC public int32_t CString$compare(const void *x, const void *y, const TypeInfo_t *info) -{ +PUREFUNC public int32_t CString$compare(const void *x, const void *y, const TypeInfo_t *info) { (void)info; - if (x == y) - return 0; + if (x == y) return 0; - if (!*(const char**)x != !*(const char**)y) - return (!*(const char**)y) - (!*(const char**)x); + if (!*(const char **)x != !*(const char **)y) return (!*(const char **)y) - (!*(const char **)x); - return strcmp(*(const char**)x, *(const char**)y); + return strcmp(*(const char **)x, *(const char **)y); } -PUREFUNC public bool CString$equal(const void *x, const void *y, const TypeInfo_t *type) -{ +PUREFUNC public bool CString$equal(const void *x, const void *y, const TypeInfo_t *type) { return CString$compare(x, y, type) == 0; } -PUREFUNC public uint64_t CString$hash(const void *c_str, const TypeInfo_t *info) -{ +PUREFUNC public uint64_t CString$hash(const void *c_str, const TypeInfo_t *info) { (void)info; - if (!*(const char**)c_str) return 0; - return siphash24(*(void**)c_str, strlen(*(const char**)c_str)); + if (!*(const char **)c_str) return 0; + return siphash24(*(void **)c_str, strlen(*(const char **)c_str)); } -PUREFUNC public bool CString$is_none(const void *c_str, const TypeInfo_t *info) -{ +PUREFUNC public bool CString$is_none(const void *c_str, const TypeInfo_t *info) { (void)info; - return *(const char**)c_str == NULL; + return *(const char **)c_str == NULL; } -static void CString$serialize(const void *obj, FILE *out, Table_t *pointers, const TypeInfo_t *info) -{ +static void CString$serialize(const void *obj, FILE *out, Table_t *pointers, const TypeInfo_t *info) { (void)info; const char *str = *(const char **)obj; int64_t len = (int64_t)strlen(str); @@ -59,30 +53,30 @@ static void CString$serialize(const void *obj, FILE *out, Table_t *pointers, con fwrite(str, sizeof(char), (size_t)len, out); } -static void CString$deserialize(FILE *in, void *out, List_t *pointers, const TypeInfo_t *info) -{ +static void CString$deserialize(FILE *in, void *out, List_t *pointers, const TypeInfo_t *info) { (void)info; int64_t len = -1; Int64$deserialize(in, &len, pointers, &Int64$info); - char *str = GC_MALLOC_ATOMIC((size_t)len+1); - if (fread(str, sizeof(char), (size_t)len, in) != (size_t)len) - fail("Not enough data in stream to deserialize"); - str[len+1] = '\0'; - *(const char**)out = str; + char *str = GC_MALLOC_ATOMIC((size_t)len + 1); + if (fread(str, sizeof(char), (size_t)len, in) != (size_t)len) fail("Not enough data in stream to deserialize"); + str[len + 1] = '\0'; + *(const char **)out = str; } -public const TypeInfo_t CString$info = { - .size=sizeof(const char*), - .align=__alignof__(const char*), - .metamethods={ - .hash=CString$hash, - .compare=CString$compare, - .equal=CString$equal, - .as_text=CString$as_text, - .is_none=CString$is_none, - .serialize=CString$serialize, - .deserialize=CString$deserialize, - }, +public +const TypeInfo_t CString$info = { + .size = sizeof(const char *), + .align = __alignof__(const char *), + .metamethods = + { + .hash = CString$hash, + .compare = CString$compare, + .equal = CString$equal, + .as_text = CString$as_text, + .is_none = CString$is_none, + .serialize = CString$serialize, + .deserialize = CString$deserialize, + }, }; // vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0 diff --git a/src/stdlib/datatypes.h b/src/stdlib/datatypes.h index e473956e..5d016246 100644 --- a/src/stdlib/datatypes.h +++ b/src/stdlib/datatypes.h @@ -12,9 +12,9 @@ #define LIST_REFCOUNT_BITS 3 #define LIST_STRIDE_BITS 12 -#define MAX_FOR_N_BITS(N) ((1L<<(N))-1L) -#define LIST_MAX_STRIDE MAX_FOR_N_BITS(LIST_STRIDE_BITS-1) -#define LIST_MIN_STRIDE (~MAX_FOR_N_BITS(LIST_STRIDE_BITS-1)) +#define MAX_FOR_N_BITS(N) ((1L << (N)) - 1L) +#define LIST_MAX_STRIDE MAX_FOR_N_BITS(LIST_STRIDE_BITS - 1) +#define LIST_MIN_STRIDE (~MAX_FOR_N_BITS(LIST_STRIDE_BITS - 1)) #define LIST_MAX_DATA_REFCOUNT MAX_FOR_N_BITS(LIST_REFCOUNT_BITS) #define LIST_MAX_FREE_ENTRIES MAX_FOR_N_BITS(LIST_FREE_BITS) @@ -41,15 +41,15 @@ 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 free:LIST_FREE_BITS; - bool atomic:LIST_ATOMIC_BITS; - uint8_t data_refcount:LIST_REFCOUNT_BITS; - int16_t stride:LIST_STRIDE_BITS; + int64_t length : LIST_LENGTH_BITS; + uint64_t free : LIST_FREE_BITS; + bool atomic : LIST_ATOMIC_BITS; + uint8_t data_refcount : LIST_REFCOUNT_BITS; + int16_t stride : LIST_STRIDE_BITS; } List_t; typedef struct { - uint32_t occupied:1, index:31; + uint32_t occupied : 1, index : 31; uint32_t next_bucket; } bucket_t; @@ -57,8 +57,8 @@ typedef struct { #define TABLE_MAX_DATA_REFCOUNT 3 typedef struct { - uint32_t count:31, last_free:31; - uint8_t data_refcount:2; + uint32_t count : 31, last_free : 31; + uint8_t data_refcount : 2; bucket_t buckets[]; } bucket_info_t; @@ -76,9 +76,9 @@ typedef struct { enum text_type { TEXT_ASCII, TEXT_GRAPHEMES, TEXT_CONCAT, TEXT_BLOB }; typedef struct Text_s { - int64_t length:54; // Number of grapheme clusters - uint8_t tag:2; - uint8_t depth:8; + int64_t length : 54; // Number of grapheme clusters + uint8_t tag : 2; + uint8_t depth : 8; union { struct { const char *ascii; @@ -117,10 +117,9 @@ typedef struct { typedef struct { Byte_t value; - bool is_none:1; + bool is_none : 1; } OptionalByte_t; -#define NONE_BYTE ((OptionalByte_t){.is_none=true}) - +#define NONE_BYTE ((OptionalByte_t){.is_none = true}) // vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0 diff --git a/src/stdlib/enums.c b/src/stdlib/enums.c index ae0c976d..7f7c4284 100644 --- a/src/stdlib/enums.c +++ b/src/stdlib/enums.c @@ -11,34 +11,30 @@ CONSTFUNC static ptrdiff_t value_offset(const TypeInfo_t *type) { ptrdiff_t offset = sizeof(int32_t); for (int i = 0; i < type->EnumInfo.num_tags; i++) { - if (type->EnumInfo.tags[i].type) - offset = MAX(offset, type->EnumInfo.tags[i].type->align); + if (type->EnumInfo.tags[i].type) offset = MAX(offset, type->EnumInfo.tags[i].type->align); } return offset; } -PUREFUNC public uint64_t Enum$hash(const void *obj, const TypeInfo_t *type) -{ - int32_t tag = *(int32_t*)obj; +PUREFUNC public uint64_t Enum$hash(const void *obj, const TypeInfo_t *type) { + int32_t tag = *(int32_t *)obj; uint32_t components[2] = {(uint32_t)tag, 0}; - const TypeInfo_t *value = type->EnumInfo.tags[tag-1].type; + const TypeInfo_t *value = type->EnumInfo.tags[tag - 1].type; if (value && value->size > 0) { components[1] = generic_hash(obj + value_offset(type), value); } - return siphash24((void*)components, sizeof(components)); + return siphash24((void *)components, sizeof(components)); } -PUREFUNC public int32_t Enum$compare(const void *x, const void *y, const TypeInfo_t *type) -{ +PUREFUNC public int32_t Enum$compare(const void *x, const void *y, const TypeInfo_t *type) { if (x == y) return 0; - int32_t x_tag = *(int32_t*)x; - int32_t y_tag = *(int32_t*)y; - if (x_tag != y_tag) - return x_tag > y_tag ? 1 : -1; + int32_t x_tag = *(int32_t *)x; + int32_t y_tag = *(int32_t *)y; + if (x_tag != y_tag) return x_tag > y_tag ? 1 : -1; - const TypeInfo_t *value = type->EnumInfo.tags[x_tag-1].type; + const TypeInfo_t *value = type->EnumInfo.tags[x_tag - 1].type; if (value && value->size > 0) { ptrdiff_t byte_offset = value_offset(type); return generic_compare(x + byte_offset, y + byte_offset, value); @@ -46,16 +42,14 @@ PUREFUNC public int32_t Enum$compare(const void *x, const void *y, const TypeInf return 0; } -PUREFUNC public bool Enum$equal(const void *x, const void *y, const TypeInfo_t *type) -{ +PUREFUNC public bool Enum$equal(const void *x, const void *y, const TypeInfo_t *type) { if (x == y) return true; - int32_t x_tag = *(int32_t*)x; - int32_t y_tag = *(int32_t*)y; - if (x_tag != y_tag) - return false; + int32_t x_tag = *(int32_t *)x; + int32_t y_tag = *(int32_t *)y; + if (x_tag != y_tag) return false; - const TypeInfo_t *value = type->EnumInfo.tags[x_tag-1].type; + const TypeInfo_t *value = type->EnumInfo.tags[x_tag - 1].type; if (value && value->size > 0) { ptrdiff_t byte_offset = value_offset(type); return generic_equal(x + byte_offset, y + byte_offset, value); @@ -63,12 +57,12 @@ PUREFUNC public bool Enum$equal(const void *x, const void *y, const TypeInfo_t * return true; } -public Text_t Enum$as_text(const void *obj, bool colorize, const TypeInfo_t *type) -{ +public +Text_t Enum$as_text(const void *obj, bool colorize, const TypeInfo_t *type) { if (!obj) return Text$from_str(type->EnumInfo.name); - int32_t tag = *(int32_t*)obj; - NamedType_t value = type->EnumInfo.tags[tag-1]; + int32_t tag = *(int32_t *)obj; + NamedType_t value = type->EnumInfo.tags[tag - 1]; if (!value.type || value.type->size == 0) { Text_t text = Text$from_str(value.name); return colorize ? Texts(Text("\x1b[1m"), text, Text("\x1b[m")) : text; @@ -77,30 +71,29 @@ public Text_t Enum$as_text(const void *obj, bool colorize, const TypeInfo_t *typ return generic_as_text(obj + value_offset(type), colorize, value.type); } -PUREFUNC public bool Enum$is_none(const void *x, const TypeInfo_t *info) -{ +PUREFUNC public bool Enum$is_none(const void *x, const TypeInfo_t *info) { (void)info; - return *(int32_t*)x == 0; + return *(int32_t *)x == 0; } -public void Enum$serialize(const void *obj, FILE *out, Table_t *pointers, const TypeInfo_t *type) -{ - int32_t tag = *(int32_t*)obj; +public +void Enum$serialize(const void *obj, FILE *out, Table_t *pointers, const TypeInfo_t *type) { + int32_t tag = *(int32_t *)obj; Int32$serialize(&tag, out, pointers, &Int32$info); - NamedType_t value = type->EnumInfo.tags[tag-1]; + NamedType_t value = type->EnumInfo.tags[tag - 1]; if (value.type && value.type->size > 0) { _serialize(obj + value_offset(type), out, pointers, value.type); } } -public void Enum$deserialize(FILE *in, void *outval, List_t *pointers, const TypeInfo_t *type) -{ +public +void Enum$deserialize(FILE *in, void *outval, List_t *pointers, const TypeInfo_t *type) { int32_t tag = 0; Int32$deserialize(in, &tag, pointers, &Int32$info); - *(int32_t*)outval = tag; + *(int32_t *)outval = tag; - NamedType_t value = type->EnumInfo.tags[tag-1]; + NamedType_t value = type->EnumInfo.tags[tag - 1]; if (value.type && value.type->size > 0) { _deserialize(in, outval + value_offset(type), pointers, value.type); } diff --git a/src/stdlib/enums.h b/src/stdlib/enums.h index 8345c527..99a0f615 100644 --- a/src/stdlib/enums.h +++ b/src/stdlib/enums.h @@ -15,24 +15,26 @@ PUREFUNC bool Enum$is_none(const void *obj, const TypeInfo_t *type); void Enum$serialize(const void *obj, FILE *out, Table_t *pointers, const TypeInfo_t *type); void Enum$deserialize(FILE *in, void *outval, List_t *pointers, const TypeInfo_t *type); -#define Enum$metamethods { \ - .as_text=Enum$as_text, \ - .compare=Enum$compare, \ - .equal=Enum$equal, \ - .hash=Enum$hash, \ - .is_none=Enum$is_none, \ - .serialize=Enum$serialize, \ - .deserialize=Enum$deserialize, \ -} +#define Enum$metamethods \ + { \ + .as_text = Enum$as_text, \ + .compare = Enum$compare, \ + .equal = Enum$equal, \ + .hash = Enum$hash, \ + .is_none = Enum$is_none, \ + .serialize = Enum$serialize, \ + .deserialize = Enum$deserialize, \ + } -#define PackedDataEnum$metamethods { \ - .hash=PackedData$hash, \ - .compare=Enum$compare, \ - .equal=PackedData$equal, \ - .as_text=Enum$as_text, \ - .is_none=Enum$is_none, \ - .serialize=Enum$serialize, \ - .deserialize=Enum$deserialize, \ -} +#define PackedDataEnum$metamethods \ + { \ + .hash = PackedData$hash, \ + .compare = Enum$compare, \ + .equal = PackedData$equal, \ + .as_text = Enum$as_text, \ + .is_none = Enum$is_none, \ + .serialize = Enum$serialize, \ + .deserialize = Enum$deserialize, \ + } // vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0 diff --git a/src/stdlib/files.c b/src/stdlib/files.c index 87b0205c..08023e0e 100644 --- a/src/stdlib/files.c +++ b/src/stdlib/files.c @@ -20,8 +20,8 @@ static const int tabstop = 4; -public char *resolve_path(const char *path, const char *relative_to, const char *system_path) -{ +public +char *resolve_path(const char *path, const char *relative_to, const char *system_path) { if (!relative_to || streq(relative_to, "/dev/stdin")) relative_to = "."; if (!path || strlen(path) == 0) return NULL; @@ -29,7 +29,7 @@ public char *resolve_path(const char *path, const char *relative_to, const char // it was found in: char buf[PATH_MAX] = {0}; if (streq(path, "~") || starts_with(path, "~/")) { - char *resolved = realpath(String(getenv("HOME"), path+1), buf); + char *resolved = realpath(String(getenv("HOME"), path + 1), buf); if (resolved) return GC_strdup(resolved); } else if (streq(path, ".") || starts_with(path, "./") || starts_with(path, "../")) { char *relative_dir = dirname(GC_strdup(relative_to)); @@ -49,12 +49,13 @@ public char *resolve_path(const char *path, const char *relative_to, const char char *resolved = realpath(String(dir, "/", path), buf); if (resolved) return GC_strdup(resolved); } else if (dir[0] == '~' && (dir[1] == '\0' || dir[1] == '/')) { - char *resolved = realpath(String(getenv("HOME"), dir+1, "/", path), buf); + char *resolved = realpath(String(getenv("HOME"), dir + 1, "/", path), buf); if (resolved) return GC_strdup(resolved); } else if (streq(dir, ".") || strncmp(dir, "./", 2) == 0) { char *resolved = realpath(String(relative_dir, "/", path), buf); if (resolved) return GC_strdup(resolved); - } else if (streq(dir, ".") || streq(dir, "..") || strncmp(dir, "./", 2) == 0 || strncmp(dir, "../", 3) == 0) { + } else if (streq(dir, ".") || streq(dir, "..") || strncmp(dir, "./", 2) == 0 + || strncmp(dir, "../", 3) == 0) { char *resolved = realpath(String(relative_dir, "/", dir, "/", path), buf); if (resolved) return GC_strdup(resolved); } else { @@ -66,24 +67,23 @@ public char *resolve_path(const char *path, const char *relative_to, const char return NULL; } -public char *file_base_name(const char *path) -{ +public +char *file_base_name(const char *path) { const char *slash = strrchr(path, '/'); if (slash) path = slash + 1; assert(!isdigit(*path)); const char *end = path + strcspn(path, "."); size_t len = (size_t)(end - path); - char *buf = GC_MALLOC_ATOMIC(len+1); + char *buf = GC_MALLOC_ATOMIC(len + 1); strncpy(buf, path, len); buf[len] = '\0'; return buf; } -static file_t *_load_file(const char* filename, FILE *file) -{ +static file_t *_load_file(const char *filename, FILE *file) { if (!file) return NULL; - file_t *ret = new(file_t, .filename=filename); + file_t *ret = new (file_t, .filename = filename); size_t file_size = 0, line_cap = 0; char *file_buf = NULL, *line_buf = NULL; @@ -98,7 +98,7 @@ static file_t *_load_file(const char* filename, FILE *file) } fclose(file); - char *copy = GC_MALLOC_ATOMIC(file_size+1); + char *copy = GC_MALLOC_ATOMIC(file_size + 1); memcpy(copy, file_buf, file_size); copy[file_size] = '\0'; ret->text = copy; @@ -114,7 +114,7 @@ static file_t *_load_file(const char* filename, FILE *file) char *cwd = getcwd(buf, sizeof(buf)); size_t cwd_len = strlen(cwd); if (strncmp(cwd, filename, cwd_len) == 0 && filename[cwd_len] == '/') - ret->relative_filename = &filename[cwd_len+1]; + ret->relative_filename = &filename[cwd_len + 1]; } return ret; } @@ -122,8 +122,8 @@ static file_t *_load_file(const char* filename, FILE *file) // // Read an entire file into memory. // -public file_t *load_file(const char* filename) -{ +public +file_t *load_file(const char *filename) { FILE *file = filename[0] ? fopen(filename, "r") : stdin; return _load_file(filename, file); } @@ -131,30 +131,27 @@ public file_t *load_file(const char* filename) // // Create a virtual file from a string. // -public file_t *spoof_file(const char* filename, const char *text) -{ - FILE *file = fmemopen((char*)text, strlen(text)+1, "r"); +public +file_t *spoof_file(const char *filename, const char *text) { + FILE *file = fmemopen((char *)text, strlen(text) + 1, "r"); return _load_file(filename, file); } // // Given a pointer, determine which line number it points to (1-indexed) // -public int64_t get_line_number(file_t *f, const char *p) -{ +public +int64_t get_line_number(file_t *f, const char *p) { // Binary search: - int64_t lo = 0, hi = (int64_t)f->num_lines-1; + int64_t lo = 0, hi = (int64_t)f->num_lines - 1; if (p < f->text) return 0; int64_t offset = (int64_t)(p - f->text); while (lo <= hi) { int64_t mid = (lo + hi) / 2; int64_t line_offset = f->line_offsets[mid]; - if (line_offset == offset) - return mid + 1; - else if (line_offset < offset) - lo = mid + 1; - else if (line_offset > offset) - hi = mid - 1; + if (line_offset == offset) return mid + 1; + else if (line_offset < offset) lo = mid + 1; + else if (line_offset > offset) hi = mid - 1; } return lo; // Return the line number whose line starts closest before p } @@ -162,33 +159,32 @@ public int64_t get_line_number(file_t *f, const char *p) // // Given a pointer, determine which line column it points to. // -public int64_t get_line_column(file_t *f, const char *p) -{ +public +int64_t get_line_column(file_t *f, const char *p) { int64_t line_no = get_line_number(f, p); - int64_t line_offset = f->line_offsets[line_no-1]; + int64_t line_offset = f->line_offsets[line_no - 1]; return 1 + (int64_t)(p - (f->text + line_offset)); } // // Return a pointer to the line with the specified line number (1-indexed) // -public const char *get_line(file_t *f, int64_t line_number) -{ +public +const char *get_line(file_t *f, int64_t line_number) { if (line_number == 0 || line_number > (int64_t)f->num_lines) return NULL; - int64_t line_offset = f->line_offsets[line_number-1]; + int64_t line_offset = f->line_offsets[line_number - 1]; return f->text + line_offset; } // // Return a value like /foo:line.col // -public const char *get_file_pos(file_t *f, const char *p) -{ +public +const char *get_file_pos(file_t *f, const char *p) { return String(f->filename, ":", get_line_number(f, p), ".", get_line_column(f, p)); } -static int fputc_column(FILE *out, char c, char print_char, int *column) -{ +static int fputc_column(FILE *out, char c, char print_char, int *column) { int printed = 0; if (print_char == '\t') print_char = ' '; if (c == '\t') { @@ -206,18 +202,16 @@ static int fputc_column(FILE *out, char c, char print_char, int *column) // // Print a span from a file // -public int highlight_error(file_t *file, const char *start, const char *end, const char *hl_color, int64_t context_lines, bool use_color) -{ +public +int highlight_error(file_t *file, const char *start, const char *end, const char *hl_color, int64_t context_lines, + bool use_color) { if (!file) return 0; // Handle spans that come from multiple files: - if (start < file->text || start > file->text + file->len) - start = end; - if (end < file->text || end > file->text + file->len) - end = start; + if (start < file->text || start > file->text + file->len) start = end; + if (end < file->text || end > file->text + file->len) end = start; // Just in case neither end of the span came from this file: - if (end < file->text || end > file->text + file->len) - start = end = file->text; + if (end < file->text || end > file->text + file->len) start = end = file->text; const char *lineno_prefix, *lineno_suffix, *normal_color, *empty_marker; bool print_carets = false; @@ -238,27 +232,25 @@ public int highlight_error(file_t *file, const char *start, const char *end, con printed += fprint(stderr, file->relative_filename); } - if (context_lines == 0) - return fprint(stderr, hl_color, string_slice(start, (size_t)(end - start)), normal_color); + if (context_lines == 0) return fprint(stderr, hl_color, string_slice(start, (size_t)(end - start)), normal_color); - int64_t start_line = get_line_number(file, start), - end_line = get_line_number(file, end); + int64_t start_line = get_line_number(file, start), end_line = get_line_number(file, end); - int64_t first_line = start_line - (context_lines - 1), - last_line = end_line + (context_lines - 1); + int64_t first_line = start_line - (context_lines - 1), last_line = end_line + (context_lines - 1); if (first_line < 1) first_line = 1; if (last_line > file->num_lines) last_line = file->num_lines; int digits = 1; - for (int64_t i = last_line; i > 0; i /= 10) ++digits; + for (int64_t i = last_line; i > 0; i /= 10) + ++digits; for (int64_t line_no = first_line; line_no <= last_line; ++line_no) { if (line_no > first_line + 5 && line_no < last_line - 5) { if (use_color) - printed += fprint(stderr, "\x1b[0;2;3;4m ... ", (last_line - first_line) - 11, " lines omitted ... \x1b[m"); - else - printed += fprint(stderr, " ... ", (last_line - first_line) - 11, " lines omitted ..."); + printed += fprint(stderr, "\x1b[0;2;3;4m ... ", (last_line - first_line) - 11, + " lines omitted ... \x1b[m"); + else printed += fprint(stderr, " ... ", (last_line - first_line) - 11, " lines omitted ..."); line_no = last_line - 6; continue; } @@ -305,14 +297,10 @@ public int highlight_error(file_t *file, const char *start, const char *end, con int col = 0; for (const char *sp = line; *sp && *sp != '\n'; ++sp) { char print_char; - if (sp < start) - print_char = ' '; - else if (sp == start && sp == end) - print_char = '^'; - else if (sp >= start && sp < end) - print_char = '-'; - else - print_char = ' '; + if (sp < start) print_char = ' '; + else if (sp == start && sp == end) print_char = '^'; + else if (sp >= start && sp < end) print_char = '-'; + else print_char = ' '; printed += fputc_column(stderr, *sp, print_char, &col); } printed += fputs("\n", stderr); diff --git a/src/stdlib/files.h b/src/stdlib/files.h index f650f78e..d3e5ebe8 100644 --- a/src/stdlib/files.h +++ b/src/stdlib/files.h @@ -16,20 +16,14 @@ typedef struct { } file_t; char *resolve_path(const char *path, const char *relative_to, const char *system_path); -__attribute__((pure, nonnull)) -char *file_base_name(const char *path); -__attribute__((nonnull)) -file_t *load_file(const char *filename); -__attribute__((nonnull, returns_nonnull)) -file_t *spoof_file(const char *filename, const char *text); -__attribute__((pure, nonnull)) -int64_t get_line_number(file_t *f, const char *p); -__attribute__((pure, nonnull)) -int64_t get_line_column(file_t *f, const char *p); -__attribute__((pure, nonnull)) -const char *get_line(file_t *f, int64_t line_number); -__attribute__((pure, nonnull)) -const char *get_file_pos(file_t *f, const char *p); -int highlight_error(file_t *file, const char *start, const char *end, const char *hl_color, int64_t context_lines, bool use_color); +__attribute__((pure, nonnull)) char *file_base_name(const char *path); +__attribute__((nonnull)) file_t *load_file(const char *filename); +__attribute__((nonnull, returns_nonnull)) file_t *spoof_file(const char *filename, const char *text); +__attribute__((pure, nonnull)) int64_t get_line_number(file_t *f, const char *p); +__attribute__((pure, nonnull)) int64_t get_line_column(file_t *f, const char *p); +__attribute__((pure, nonnull)) const char *get_line(file_t *f, int64_t line_number); +__attribute__((pure, nonnull)) const char *get_file_pos(file_t *f, const char *p); +int highlight_error(file_t *file, const char *start, const char *end, const char *hl_color, int64_t context_lines, + bool use_color); // vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0 diff --git a/src/stdlib/fpconv.c b/src/stdlib/fpconv.c index 97699784..8b994cfa 100644 --- a/src/stdlib/fpconv.c +++ b/src/stdlib/fpconv.c @@ -6,37 +6,46 @@ #include "fpconv.h" #include "powers.h" -#define fracmask 0x000FFFFFFFFFFFFFU -#define expmask 0x7FF0000000000000U +#define fracmask 0x000FFFFFFFFFFFFFU +#define expmask 0x7FF0000000000000U #define hiddenbit 0x0010000000000000U -#define signmask 0x8000000000000000U -#define expbias (1023 + 52) +#define signmask 0x8000000000000000U +#define expbias (1023 + 52) #define absv(n) ((n) < 0 ? -(n) : (n)) #define minv(a, b) ((a) < (b) ? (a) : (b)) -static uint64_t tens[] = { - 10000000000000000000U, 1000000000000000000U, 100000000000000000U, - 10000000000000000U, 1000000000000000U, 100000000000000U, - 10000000000000U, 1000000000000U, 100000000000U, - 10000000000U, 1000000000U, 100000000U, - 10000000U, 1000000U, 100000U, - 10000U, 1000U, 100U, - 10U, 1U -}; - -static inline uint64_t get_dbits(double d) -{ +static uint64_t tens[] = {10000000000000000000U, + 1000000000000000000U, + 100000000000000000U, + 10000000000000000U, + 1000000000000000U, + 100000000000000U, + 10000000000000U, + 1000000000000U, + 100000000000U, + 10000000000U, + 1000000000U, + 100000000U, + 10000000U, + 1000000U, + 100000U, + 10000U, + 1000U, + 100U, + 10U, + 1U}; + +static inline uint64_t get_dbits(double d) { union { - double dbl; + double dbl; uint64_t i; - } dbl_bits = { d }; + } dbl_bits = {d}; return dbl_bits.i; } -static Fp build_fp(double d) -{ +static Fp build_fp(double d) { uint64_t bits = get_dbits(d); Fp fp; @@ -54,8 +63,7 @@ static Fp build_fp(double d) return fp; } -static void normalize(Fp* fp) -{ +static void normalize(Fp *fp) { while ((fp->frac & hiddenbit) == 0) { fp->frac <<= 1; fp->exp--; @@ -66,10 +74,9 @@ static void normalize(Fp* fp) fp->exp -= shift; } -static void get_normalized_boundaries(Fp* fp, Fp* lower, Fp* upper) -{ +static void get_normalized_boundaries(Fp *fp, Fp *lower, Fp *upper) { upper->frac = (fp->frac << 1) + 1; - upper->exp = fp->exp - 1; + upper->exp = fp->exp - 1; while ((upper->frac & (hiddenbit << 1)) == 0) { upper->frac <<= 1; @@ -81,64 +88,55 @@ static void get_normalized_boundaries(Fp* fp, Fp* lower, Fp* upper) upper->frac <<= u_shift; upper->exp = upper->exp - u_shift; - int l_shift = fp->frac == hiddenbit ? 2 : 1; lower->frac = (fp->frac << l_shift) - 1; lower->exp = fp->exp - l_shift; - lower->frac <<= lower->exp - upper->exp; lower->exp = upper->exp; } -static Fp multiply(Fp* a, Fp* b) -{ +static Fp multiply(Fp *a, Fp *b) { const uint64_t lomask = 0x00000000FFFFFFFF; - uint64_t ah_bl = (a->frac >> 32) * (b->frac & lomask); + uint64_t ah_bl = (a->frac >> 32) * (b->frac & lomask); uint64_t al_bh = (a->frac & lomask) * (b->frac >> 32); uint64_t al_bl = (a->frac & lomask) * (b->frac & lomask); - uint64_t ah_bh = (a->frac >> 32) * (b->frac >> 32); + uint64_t ah_bh = (a->frac >> 32) * (b->frac >> 32); uint64_t tmp = (ah_bl & lomask) + (al_bh & lomask) + (al_bl >> 32); /* round up */ tmp += 1U << 31; - Fp fp = { - ah_bh + (ah_bl >> 32) + (al_bh >> 32) + (tmp >> 32), - a->exp + b->exp + 64 - }; + Fp fp = {ah_bh + (ah_bl >> 32) + (al_bh >> 32) + (tmp >> 32), a->exp + b->exp + 64}; return fp; } -static void round_digit(char* digits, int ndigits, uint64_t delta, uint64_t rem, uint64_t kappa, uint64_t frac) -{ - while (rem < frac && delta - rem >= kappa && - (rem + kappa < frac || frac - rem > rem + kappa - frac)) { +static void round_digit(char *digits, int ndigits, uint64_t delta, uint64_t rem, uint64_t kappa, uint64_t frac) { + while (rem < frac && delta - rem >= kappa && (rem + kappa < frac || frac - rem > rem + kappa - frac)) { digits[ndigits - 1]--; rem += kappa; } } -static int generate_digits(Fp* fp, Fp* upper, Fp* lower, char* digits, int* K) -{ +static int generate_digits(Fp *fp, Fp *upper, Fp *lower, char *digits, int *K) { uint64_t wfrac = upper->frac - fp->frac; uint64_t delta = upper->frac - lower->frac; Fp one; one.frac = 1ULL << -upper->exp; - one.exp = upper->exp; + one.exp = upper->exp; uint64_t part1 = upper->frac >> -one.exp; uint64_t part2 = upper->frac & (one.frac - 1); int idx = 0, kappa = 10; - uint64_t* divp; + uint64_t *divp; /* 1000000000 */ - for(divp = tens + 10; kappa > 0; divp++) { + for (divp = tens + 10; kappa > 0; divp++) { uint64_t div = *divp; unsigned digit = part1 / div; @@ -150,7 +148,7 @@ static int generate_digits(Fp* fp, Fp* upper, Fp* lower, char* digits, int* K) part1 -= digit * div; kappa--; - uint64_t tmp = (part1 <<-one.exp) + part2; + uint64_t tmp = (part1 << -one.exp) + part2; if (tmp <= delta) { *K += kappa; round_digit(digits, idx, delta, tmp, div << -one.exp, wfrac); @@ -160,7 +158,7 @@ static int generate_digits(Fp* fp, Fp* upper, Fp* lower, char* digits, int* K) } /* 10 */ - uint64_t* unit = tens + 18; + uint64_t *unit = tens + 18; while (true) { part2 *= 10; @@ -184,8 +182,7 @@ static int generate_digits(Fp* fp, Fp* upper, Fp* lower, char* digits, int* K) } } -static int grisu2(double d, char* digits, int* K) -{ +static int grisu2(double d, char *digits, int *K) { Fp w = build_fp(d); Fp lower, upper; @@ -196,7 +193,7 @@ static int grisu2(double d, char* digits, int* K) int k; Fp cp = find_cachedpow10(upper.exp, &k); - w = multiply(&w, &cp); + w = multiply(&w, &cp); upper = multiply(&upper, &cp); lower = multiply(&lower, &cp); @@ -208,8 +205,7 @@ static int grisu2(double d, char* digits, int* K) return generate_digits(&w, &upper, &lower, digits, K); } -static int emit_digits(char* digits, int ndigits, char* dest, int K, bool neg) -{ +static int emit_digits(char *digits, int ndigits, char *dest, int K, bool neg) { int exp = absv(K + ndigits - 1); int max_trailing_zeros = 7; @@ -240,7 +236,7 @@ static int emit_digits(char* digits, int ndigits, char* dest, int K, bool neg) return ndigits + 2 + offset; - /* fp > 1.0 */ + /* fp > 1.0 */ } else { memcpy(dest, digits, (size_t)offset); dest[offset] = '.'; @@ -288,8 +284,7 @@ static int emit_digits(char* digits, int ndigits, char* dest, int K, bool neg) return idx; } -static int filter_special(double fp, char* dest) -{ +static int filter_special(double fp, char *dest) { if (fp == 0.0) { dest[0] = '0'; return 1; @@ -304,17 +299,20 @@ static int filter_special(double fp, char* dest) } if (bits & fracmask) { - dest[0] = 'n'; dest[1] = 'a'; dest[2] = 'n'; + dest[0] = 'n'; + dest[1] = 'a'; + dest[2] = 'n'; } else { - dest[0] = 'i'; dest[1] = 'n'; dest[2] = 'f'; + dest[0] = 'i'; + dest[1] = 'n'; + dest[2] = 'f'; } return 3; } -int fpconv_dtoa(double d, char dest[24]) -{ +int fpconv_dtoa(double d, char dest[24]) { char digits[18]; int str_len = 0; diff --git a/src/stdlib/functiontype.c b/src/stdlib/functiontype.c index 6d692c6d..a6e12798 100644 --- a/src/stdlib/functiontype.c +++ b/src/stdlib/functiontype.c @@ -9,18 +9,17 @@ #include "types.h" #include "util.h" -public Text_t Func$as_text(const void *fn, bool colorize, const TypeInfo_t *type) -{ +public +Text_t Func$as_text(const void *fn, bool colorize, const TypeInfo_t *type) { Text_t text = Text$from_str(type->FunctionInfo.type_str); - if (fn && colorize) - text = Text$concat(Text("\x1b[32;1m"), text, Text("\x1b[m")); + if (fn && colorize) text = Text$concat(Text("\x1b[32;1m"), text, Text("\x1b[m")); return text; } -public PUREFUNC bool Func$is_none(const void *obj, const TypeInfo_t *info) -{ +public +PUREFUNC bool Func$is_none(const void *obj, const TypeInfo_t *info) { (void)info; - return *(void**)obj == NULL; + return *(void **)obj == NULL; } // vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0 diff --git a/src/stdlib/functiontype.h b/src/stdlib/functiontype.h index 095d630e..3169cfc9 100644 --- a/src/stdlib/functiontype.h +++ b/src/stdlib/functiontype.h @@ -13,20 +13,27 @@ OptionalText_t get_function_name(void *fn); OptionalText_t get_function_filename(void *fn); int64_t get_function_line_num(void *fn); Text_t Func$as_text(const void *fn, bool colorize, const TypeInfo_t *type); -PUREFUNC bool Func$is_none(const void *obj, const TypeInfo_t*); +PUREFUNC bool Func$is_none(const void *obj, const TypeInfo_t *); -#define Func$metamethods { \ - .as_text=Func$as_text, \ - .is_none=Func$is_none, \ - .serialize=cannot_serialize, \ - .deserialize=cannot_deserialize, \ -} +#define Func$metamethods \ + { \ + .as_text = Func$as_text, \ + .is_none = Func$is_none, \ + .serialize = cannot_serialize, \ + .deserialize = cannot_deserialize, \ + } -#define Function$info(typestr) &((TypeInfo_t){.size=sizeof(void*), .align=__alignof__(void*), \ - .tag=FunctionInfo, .FunctionInfo.type_str=typestr, \ - .metamethods=Func$metamethods}) -#define Closure$info(typestr) &((TypeInfo_t){.size=sizeof(void*[2]), .align=__alignof__(void*), \ - .tag=FunctionInfo, .FunctionInfo.type_str=typestr, \ - .metamethods=Func$metamethods}) +#define Function$info(typestr) \ + &((TypeInfo_t){.size = sizeof(void *), \ + .align = __alignof__(void *), \ + .tag = FunctionInfo, \ + .FunctionInfo.type_str = typestr, \ + .metamethods = Func$metamethods}) +#define Closure$info(typestr) \ + &((TypeInfo_t){.size = sizeof(void *[2]), \ + .align = __alignof__(void *), \ + .tag = FunctionInfo, \ + .FunctionInfo.type_str = typestr, \ + .metamethods = Func$metamethods}) // vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0 diff --git a/src/stdlib/integers.c b/src/stdlib/integers.c index e24d984d..93095a70 100644 --- a/src/stdlib/integers.c +++ b/src/stdlib/integers.c @@ -17,20 +17,19 @@ #include "text.h" #include "types.h" -public int Int$print(FILE *f, Int_t i) { +public +int Int$print(FILE *f, Int_t i) { if (likely(i.small & 1L)) { - return _print_int(f, (int64_t)((i.small)>>2L)); + return _print_int(f, (int64_t)((i.small) >> 2L)); } else { return gmp_fprintf(f, "%Zd", *i.big); } } -static inline Text_t _int64_to_text(int64_t n) -{ - if (n == INT64_MIN) - return Text("-9223372036854775808"); +static inline Text_t _int64_to_text(int64_t n) { + if (n == INT64_MIN) return Text("-9223372036854775808"); - char buf[21] = {[20]=0}; // Big enough for INT64_MIN + '\0' + char buf[21] = {[20] = 0}; // Big enough for INT64_MIN + '\0' char *p = &buf[19]; bool negative = n < 0; if (negative) n = -n; // Safe to do because we checked for INT64_MIN earlier @@ -40,13 +39,13 @@ static inline Text_t _int64_to_text(int64_t n) n /= 10; } while (n > 0); - if (negative) - *(p--) = '-'; + if (negative) *(p--) = '-'; return Text$from_strn(p + 1, (size_t)(&buf[19] - p)); } -public Text_t Int$value_as_text(Int_t i) { +public +Text_t Int$value_as_text(Int_t i) { if (likely(i.small & 1L)) { return _int64_to_text(i.small >> 2L); } else { @@ -55,74 +54,76 @@ public Text_t Int$value_as_text(Int_t i) { } } -public Text_t Int$as_text(const void *i, bool colorize, const TypeInfo_t *info) { +public +Text_t Int$as_text(const void *i, bool colorize, const TypeInfo_t *info) { (void)info; if (!i) return Text("Int"); - Text_t text = Int$value_as_text(*(Int_t*)i); + Text_t text = Int$value_as_text(*(Int_t *)i); if (colorize) text = Text$concat(Text("\x1b[35m"), text, Text("\x1b[m")); return text; } -static bool Int$is_none(const void *i, const TypeInfo_t *info) -{ +static bool Int$is_none(const void *i, const TypeInfo_t *info) { (void)info; - return ((Int_t*)i)->small == 0L; + return ((Int_t *)i)->small == 0L; } -public PUREFUNC int32_t Int$compare_value(const Int_t x, const Int_t y) { - if (likely(x.small & y.small & 1L)) - return (x.small > y.small) - (x.small < y.small); - else if (x.small & 1) - return -mpz_cmp_si(*y.big, x.small); - else if (y.small & 1) - return mpz_cmp_si(*x.big, y.small); - else - return x.big == y.big ? 0 : mpz_cmp(*x.big, *y.big); +public +PUREFUNC int32_t Int$compare_value(const Int_t x, const Int_t y) { + if (likely(x.small & y.small & 1L)) return (x.small > y.small) - (x.small < y.small); + else if (x.small & 1) return -mpz_cmp_si(*y.big, x.small); + else if (y.small & 1) return mpz_cmp_si(*x.big, y.small); + else return x.big == y.big ? 0 : mpz_cmp(*x.big, *y.big); } -public PUREFUNC int32_t Int$compare(const void *x, const void *y, const TypeInfo_t *info) { +public +PUREFUNC int32_t Int$compare(const void *x, const void *y, const TypeInfo_t *info) { (void)info; - return Int$compare_value(*(Int_t*)x, *(Int_t*)y); + return Int$compare_value(*(Int_t *)x, *(Int_t *)y); } -public PUREFUNC bool Int$equal_value(const Int_t x, const Int_t y) { - if (likely((x.small | y.small) & 1L)) - return x.small == y.small; - else - return x.big == y.big ? 0 : (mpz_cmp(*x.big, *y.big) == 0); +public +PUREFUNC bool Int$equal_value(const Int_t x, const Int_t y) { + if (likely((x.small | y.small) & 1L)) return x.small == y.small; + else return x.big == y.big ? 0 : (mpz_cmp(*x.big, *y.big) == 0); } -public PUREFUNC bool Int$equal(const void *x, const void *y, const TypeInfo_t *info) { +public +PUREFUNC bool Int$equal(const void *x, const void *y, const TypeInfo_t *info) { (void)info; - return Int$equal_value(*(Int_t*)x, *(Int_t*)y); + return Int$equal_value(*(Int_t *)x, *(Int_t *)y); } -public CONSTFUNC Int_t Int$clamped(Int_t x, Int_t low, Int_t high) { +public +CONSTFUNC Int_t Int$clamped(Int_t x, Int_t low, Int_t high) { return (Int$compare(&x, &low, &Int$info) <= 0) ? low : (Int$compare(&x, &high, &Int$info) >= 0 ? high : x); } -public CONSTFUNC bool Int$is_between(const Int_t x, const Int_t low, const Int_t high) { +public +CONSTFUNC bool Int$is_between(const Int_t x, const Int_t low, const Int_t high) { return Int$compare_value(low, x) <= 0 && Int$compare_value(x, high) <= 0; } -public PUREFUNC uint64_t Int$hash(const void *vx, const TypeInfo_t *info) { +public +PUREFUNC uint64_t Int$hash(const void *vx, const TypeInfo_t *info) { (void)info; - Int_t *x = (Int_t*)vx; + Int_t *x = (Int_t *)vx; if (likely(x->small & 1L)) { - return siphash24((void*)x, sizeof(Int_t)); + return siphash24((void *)x, sizeof(Int_t)); } else { char *str = mpz_get_str(NULL, 16, *x->big); - return siphash24((void*)str, strlen(str)); + return siphash24((void *)str, strlen(str)); } } -public Text_t Int$hex(Int_t i, Int_t digits_int, bool uppercase, bool prefix) { - if (Int$is_negative(i)) - return Text$concat(Text("-"), Int$hex(Int$negative(i), digits_int, uppercase, prefix)); +public +Text_t Int$hex(Int_t i, Int_t digits_int, bool uppercase, bool prefix) { + if (Int$is_negative(i)) return Text$concat(Text("-"), Int$hex(Int$negative(i), digits_int, uppercase, prefix)); if (likely(i.small & 1L)) { uint64_t u64 = (uint64_t)(i.small >> 2); - return Text$from_str(String(hex(u64, .no_prefix=!prefix, .digits=Int32$from_int(digits_int, false), .uppercase=uppercase))); + return Text$from_str(String( + hex(u64, .no_prefix = !prefix, .digits = Int32$from_int(digits_int, false), .uppercase = uppercase))); } else { char *str = mpz_get_str(NULL, 16, *i.big); if (uppercase) { @@ -131,97 +132,88 @@ public Text_t Int$hex(Int_t i, Int_t digits_int, bool uppercase, bool prefix) { } int64_t digits = Int64$from_int(digits_int, false); int64_t needed_zeroes = digits - (int64_t)strlen(str); - if (needed_zeroes <= 0) - return prefix ? Text$concat(Text("0x"), Text$from_str(str)) : Text$from_str(str); + if (needed_zeroes <= 0) return prefix ? Text$concat(Text("0x"), Text$from_str(str)) : Text$from_str(str); char *zeroes = GC_MALLOC_ATOMIC((size_t)(needed_zeroes)); memset(zeroes, '0', (size_t)(needed_zeroes)); - if (prefix) - return Text$concat(Text("0x"), Text$from_str(zeroes), Text$from_str(str)); - else - return Text$concat(Text$from_str(zeroes), Text$from_str(str)); + if (prefix) return Text$concat(Text("0x"), Text$from_str(zeroes), Text$from_str(str)); + else return Text$concat(Text$from_str(zeroes), Text$from_str(str)); } } -public Text_t Int$octal(Int_t i, Int_t digits_int, bool prefix) { - if (Int$is_negative(i)) - return Text$concat(Text("-"), Int$octal(Int$negative(i), digits_int, prefix)); +public +Text_t Int$octal(Int_t i, Int_t digits_int, bool prefix) { + if (Int$is_negative(i)) return Text$concat(Text("-"), Int$octal(Int$negative(i), digits_int, prefix)); if (likely(i.small & 1L)) { uint64_t u64 = (uint64_t)(i.small >> 2); - return Text$from_str(String(oct(u64, .no_prefix=!prefix, .digits=Int32$from_int(digits_int, false)))); + return Text$from_str(String(oct(u64, .no_prefix = !prefix, .digits = Int32$from_int(digits_int, false)))); } else { int64_t digits = Int64$from_int(digits_int, false); char *str = mpz_get_str(NULL, 8, *i.big); int64_t needed_zeroes = digits - (int64_t)strlen(str); - if (needed_zeroes <= 0) - return prefix ? Text$concat(Text("0o"), Text$from_str(str)) : Text$from_str(str); + if (needed_zeroes <= 0) return prefix ? Text$concat(Text("0o"), Text$from_str(str)) : Text$from_str(str); char *zeroes = GC_MALLOC_ATOMIC((size_t)(needed_zeroes)); memset(zeroes, '0', (size_t)(needed_zeroes)); - if (prefix) - return Text$concat(Text("0o"), Text$from_str(zeroes), Text$from_str(str)); - else - return Text$concat(Text$from_str(zeroes), Text$from_str(str)); + if (prefix) return Text$concat(Text("0o"), Text$from_str(zeroes), Text$from_str(str)); + else return Text$concat(Text$from_str(zeroes), Text$from_str(str)); } } -public Int_t Int$slow_plus(Int_t x, Int_t y) { +public +Int_t Int$slow_plus(Int_t x, Int_t y) { mpz_t result; mpz_init_set_int(result, x); if (y.small & 1L) { - if (y.small < 0L) - mpz_sub_ui(result, result, (uint64_t)(-(y.small >> 2L))); - else - mpz_add_ui(result, result, (uint64_t)(y.small >> 2L)); + if (y.small < 0L) mpz_sub_ui(result, result, (uint64_t)(-(y.small >> 2L))); + else mpz_add_ui(result, result, (uint64_t)(y.small >> 2L)); } else { mpz_add(result, result, *y.big); } return Int$from_mpz(result); } -public Int_t Int$slow_minus(Int_t x, Int_t y) { +public +Int_t Int$slow_minus(Int_t x, Int_t y) { mpz_t result; mpz_init_set_int(result, x); if (y.small & 1L) { - if (y.small < 0L) - mpz_add_ui(result, result, (uint64_t)(-(y.small >> 2L))); - else - mpz_sub_ui(result, result, (uint64_t)(y.small >> 2L)); + if (y.small < 0L) mpz_add_ui(result, result, (uint64_t)(-(y.small >> 2L))); + else mpz_sub_ui(result, result, (uint64_t)(y.small >> 2L)); } else { mpz_sub(result, result, *y.big); } return Int$from_mpz(result); } -public Int_t Int$slow_times(Int_t x, Int_t y) { +public +Int_t Int$slow_times(Int_t x, Int_t y) { mpz_t result; mpz_init_set_int(result, x); - if (y.small & 1L) - mpz_mul_si(result, result, y.small >> 2L); - else - mpz_mul(result, result, *y.big); + if (y.small & 1L) mpz_mul_si(result, result, y.small >> 2L); + else mpz_mul(result, result, *y.big); return Int$from_mpz(result); } -public Int_t Int$slow_divided_by(Int_t dividend, Int_t divisor) { - // Euclidean division, see: https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/divmodnote-letter.pdf +public +Int_t Int$slow_divided_by(Int_t dividend, Int_t divisor) { + // Euclidean division, see: + // https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/divmodnote-letter.pdf mpz_t quotient, remainder; mpz_init_set_int(quotient, dividend); mpz_init_set_int(remainder, divisor); mpz_tdiv_qr(quotient, remainder, quotient, remainder); if (mpz_sgn(remainder) < 0) { bool d_positive = likely(divisor.small & 1L) ? divisor.small > 0x1L : mpz_sgn(*divisor.big) > 0; - if (d_positive) - mpz_sub_ui(quotient, quotient, 1); - else - mpz_add_ui(quotient, quotient, 1); + if (d_positive) mpz_sub_ui(quotient, quotient, 1); + else mpz_add_ui(quotient, quotient, 1); } return Int$from_mpz(quotient); } -public Int_t Int$slow_modulo(Int_t x, Int_t modulus) -{ +public +Int_t Int$slow_modulo(Int_t x, Int_t modulus) { mpz_t result; mpz_init_set_int(result, x); mpz_t divisor; @@ -230,8 +222,8 @@ public Int_t Int$slow_modulo(Int_t x, Int_t modulus) return Int$from_mpz(result); } -public Int_t Int$slow_modulo1(Int_t x, Int_t modulus) -{ +public +Int_t Int$slow_modulo1(Int_t x, Int_t modulus) { mpz_t result; mpz_init_set_int(result, x); mpz_sub_ui(result, result, 1); @@ -242,8 +234,8 @@ public Int_t Int$slow_modulo1(Int_t x, Int_t modulus) return Int$from_mpz(result); } -public Int_t Int$slow_left_shifted(Int_t x, Int_t y) -{ +public +Int_t Int$slow_left_shifted(Int_t x, Int_t y) { mp_bitcnt_t bits = (mp_bitcnt_t)Int64$from_int(y, false); mpz_t result; mpz_init_set_int(result, x); @@ -251,8 +243,8 @@ public Int_t Int$slow_left_shifted(Int_t x, Int_t y) return Int$from_mpz(result); } -public Int_t Int$slow_right_shifted(Int_t x, Int_t y) -{ +public +Int_t Int$slow_right_shifted(Int_t x, Int_t y) { mp_bitcnt_t bits = (mp_bitcnt_t)Int64$from_int(y, false); mpz_t result; mpz_init_set_int(result, x); @@ -260,8 +252,8 @@ public Int_t Int$slow_right_shifted(Int_t x, Int_t y) return Int$from_mpz(result); } -public Int_t Int$slow_bit_and(Int_t x, Int_t y) -{ +public +Int_t Int$slow_bit_and(Int_t x, Int_t y) { mpz_t result; mpz_init_set_int(result, x); mpz_t y_mpz; @@ -270,8 +262,8 @@ public Int_t Int$slow_bit_and(Int_t x, Int_t y) return Int$from_mpz(result); } -public Int_t Int$slow_bit_or(Int_t x, Int_t y) -{ +public +Int_t Int$slow_bit_or(Int_t x, Int_t y) { mpz_t result; mpz_init_set_int(result, x); mpz_t y_mpz; @@ -280,8 +272,8 @@ public Int_t Int$slow_bit_or(Int_t x, Int_t y) return Int$from_mpz(result); } -public Int_t Int$slow_bit_xor(Int_t x, Int_t y) -{ +public +Int_t Int$slow_bit_xor(Int_t x, Int_t y) { mpz_t result; mpz_init_set_int(result, x); mpz_t y_mpz; @@ -290,8 +282,8 @@ public Int_t Int$slow_bit_xor(Int_t x, Int_t y) return Int$from_mpz(result); } -public Int_t Int$slow_negated(Int_t x) -{ +public +Int_t Int$slow_negated(Int_t x) { mpz_t result; mpz_init_set_int(result, x); mpz_neg(result, result); @@ -299,10 +291,9 @@ public Int_t Int$slow_negated(Int_t x) return Int$from_mpz(result); } -public Int_t Int$slow_negative(Int_t x) -{ - if (likely(x.small & 1L)) - return (Int_t){.small=4L*-((x.small)>>2L) + 1L}; +public +Int_t Int$slow_negative(Int_t x) { + if (likely(x.small & 1L)) return (Int_t){.small = 4L * -((x.small) >> 2L) + 1L}; mpz_t result; mpz_init_set_int(result, x); @@ -310,10 +301,9 @@ public Int_t Int$slow_negative(Int_t x) return Int$from_mpz(result); } -public Int_t Int$abs(Int_t x) -{ - if (likely(x.small & 1L)) - return (Int_t){.small=4L*labs((x.small)>>2L) + 1L}; +public +Int_t Int$abs(Int_t x) { + if (likely(x.small & 1L)) return (Int_t){.small = 4L * labs((x.small) >> 2L) + 1L}; mpz_t result; mpz_init_set_int(result, x); @@ -321,53 +311,45 @@ public Int_t Int$abs(Int_t x) return Int$from_mpz(result); } -public Int_t Int$power(Int_t base, Int_t exponent) -{ +public +Int_t Int$power(Int_t base, Int_t exponent) { int64_t exp = Int64$from_int(exponent, false); - if (unlikely(exp < 0)) - fail("Cannot take a negative power of an integer!"); + if (unlikely(exp < 0)) fail("Cannot take a negative power of an integer!"); mpz_t result; mpz_init_set_int(result, base); mpz_pow_ui(result, result, (uint64_t)exp); return Int$from_mpz(result); } -public Int_t Int$gcd(Int_t x, Int_t y) -{ - if (likely(x.small & y.small & 0x1L)) - return I_small(Int32$gcd(x.small >> 2L, y.small >> 2L)); +public +Int_t Int$gcd(Int_t x, Int_t y) { + if (likely(x.small & y.small & 0x1L)) return I_small(Int32$gcd(x.small >> 2L, y.small >> 2L)); mpz_t result; mpz_init(result); - if (x.small & 0x1L) - mpz_gcd_ui(result, *y.big, (uint64_t)labs(x.small>>2L)); - else if (y.small & 0x1L) - mpz_gcd_ui(result, *x.big, (uint64_t)labs(y.small>>2L)); - else - mpz_gcd(result, *x.big, *y.big); + if (x.small & 0x1L) mpz_gcd_ui(result, *y.big, (uint64_t)labs(x.small >> 2L)); + else if (y.small & 0x1L) mpz_gcd_ui(result, *x.big, (uint64_t)labs(y.small >> 2L)); + else mpz_gcd(result, *x.big, *y.big); return Int$from_mpz(result); } -public OptionalInt_t Int$sqrt(Int_t i) -{ - if (Int$compare_value(i, I(0)) < 0) - return NONE_INT; +public +OptionalInt_t Int$sqrt(Int_t i) { + if (Int$compare_value(i, I(0)) < 0) return NONE_INT; mpz_t result; mpz_init_set_int(result, i); mpz_sqrt(result, result); return Int$from_mpz(result); } -public bool Int$get_bit(Int_t x, Int_t bit_index) -{ +public +bool Int$get_bit(Int_t x, Int_t bit_index) { mpz_t i; mpz_init_set_int(i, x); - if (Int$compare_value(bit_index, I(1)) < 0) - fail("Invalid bit index (expected 1 or higher): ", bit_index); - if (Int$compare_value(bit_index, Int$from_int64(INT64_MAX)) > 0) - fail("Bit index is too large! ", bit_index); + if (Int$compare_value(bit_index, I(1)) < 0) fail("Invalid bit index (expected 1 or higher): ", bit_index); + if (Int$compare_value(bit_index, Int$from_int64(INT64_MAX)) > 0) fail("Bit index is too large! ", bit_index); - int is_bit_set = mpz_tstbit(i, (mp_bitcnt_t)(Int64$from_int(bit_index, true)-1)); + int is_bit_set = mpz_tstbit(i, (mp_bitcnt_t)(Int64$from_int(bit_index, true) - 1)); return (bool)is_bit_set; } @@ -376,37 +358,41 @@ typedef struct { Int_t step; } IntRange_t; -static OptionalInt_t _next_int(IntRange_t *info) -{ +static OptionalInt_t _next_int(IntRange_t *info) { OptionalInt_t i = info->current; if (!Int$is_none(&i, &Int$info)) { Int_t next = Int$plus(i, info->step); - if (!Int$is_none(&info->last, &Int$info) && Int$compare_value(next, info->last) == Int$compare_value(info->step, I(0))) + if (!Int$is_none(&info->last, &Int$info) + && Int$compare_value(next, info->last) == Int$compare_value(info->step, I(0))) next = NONE_INT; info->current = next; } return i; } -public PUREFUNC Closure_t Int$to(Int_t first, Int_t last, OptionalInt_t step) { +public +PUREFUNC Closure_t Int$to(Int_t first, Int_t last, OptionalInt_t step) { IntRange_t *range = GC_MALLOC(sizeof(IntRange_t)); range->current = first; range->last = last; - range->step = Int$is_none(&step, &Int$info) ? - Int$compare_value(last, first) >= 0 ? (Int_t){.small=(1L<<2L)|1L} : (Int_t){.small=(-1L>>2L)|1L} - : step; - return (Closure_t){.fn=_next_int, .userdata=range}; + range->step = Int$is_none(&step, &Int$info) ? Int$compare_value(last, first) >= 0 + ? (Int_t){.small = (1L << 2L) | 1L} + : (Int_t){.small = (-1L >> 2L) | 1L} + : step; + return (Closure_t){.fn = _next_int, .userdata = range}; } -public PUREFUNC Closure_t Int$onward(Int_t first, Int_t step) { +public +PUREFUNC Closure_t Int$onward(Int_t first, Int_t step) { IntRange_t *range = GC_MALLOC(sizeof(IntRange_t)); range->current = first; range->last = NONE_INT; range->step = step; - return (Closure_t){.fn=_next_int, .userdata=range}; + return (Closure_t){.fn = _next_int, .userdata = range}; } -public Int_t Int$from_str(const char *str) { +public +Int_t Int$from_str(const char *str) { mpz_t i; int result; if (strncmp(str, "0x", 2) == 0) { @@ -418,12 +404,12 @@ public Int_t Int$from_str(const char *str) { } else { result = mpz_init_set_str(i, str, 10); } - if (result != 0) - return NONE_INT; + if (result != 0) return NONE_INT; return Int$from_mpz(i); } -public OptionalInt_t Int$parse(Text_t text, Text_t *remainder) { +public +OptionalInt_t Int$parse(Text_t text, Text_t *remainder) { const char *str = Text$as_c_string(text); mpz_t i; int result; @@ -455,8 +441,8 @@ public OptionalInt_t Int$parse(Text_t text, Text_t *remainder) { return Int$from_mpz(i); } -public bool Int$is_prime(Int_t x, Int_t reps) -{ +public +bool Int$is_prime(Int_t x, Int_t reps) { mpz_t p; mpz_init_set_int(p, x); if (unlikely(Int$compare_value(reps, I(9999)) > 0)) @@ -465,8 +451,8 @@ public bool Int$is_prime(Int_t x, Int_t reps) return (mpz_probab_prime_p(p, reps_int) != 0); } -public Int_t Int$next_prime(Int_t x) -{ +public +Int_t Int$next_prime(Int_t x) { mpz_t p; mpz_init_set_int(p, x); mpz_nextprime(p, p); @@ -475,28 +461,25 @@ public Int_t Int$next_prime(Int_t x) #if __GNU_MP_VERSION >= 6 #if __GNU_MP_VERSION_MINOR >= 3 -public OptionalInt_t Int$prev_prime(Int_t x) -{ +public +OptionalInt_t Int$prev_prime(Int_t x) { mpz_t p; mpz_init_set_int(p, x); - if (unlikely(mpz_prevprime(p, p) == 0)) - return NONE_INT; + if (unlikely(mpz_prevprime(p, p) == 0)) return NONE_INT; return Int$from_mpz(p); } #endif #endif -public Int_t Int$choose(Int_t n, Int_t k) -{ - if unlikely (Int$compare_value(n, I_small(0)) < 0) - fail("Negative inputs are not supported for choose()"); +public +Int_t Int$choose(Int_t n, Int_t k) { + if unlikely (Int$compare_value(n, I_small(0)) < 0) fail("Negative inputs are not supported for choose()"); mpz_t ret; mpz_init(ret); int64_t k_i64 = Int64$from_int(k, false); - if unlikely (k_i64 < 0) - fail("Negative inputs are not supported for choose()"); + if unlikely (k_i64 < 0) fail("Negative inputs are not supported for choose()"); if likely (n.small & 1L) { mpz_bin_uiui(ret, (unsigned long)(n.small >> 2L), (unsigned long)k_i64); @@ -508,21 +491,19 @@ public Int_t Int$choose(Int_t n, Int_t k) return Int$from_mpz(ret); } -public Int_t Int$factorial(Int_t n) -{ +public +Int_t Int$factorial(Int_t n) { mpz_t ret; mpz_init(ret); int64_t n_i64 = Int64$from_int(n, false); - if unlikely (n_i64 < 0) - fail("Factorials are not defined for negative numbers"); + if unlikely (n_i64 < 0) fail("Factorials are not defined for negative numbers"); mpz_fac_ui(ret, (unsigned long)n_i64); return Int$from_mpz(ret); } -static void Int$serialize(const void *obj, FILE *out, Table_t *pointers, const TypeInfo_t *info) -{ +static void Int$serialize(const void *obj, FILE *out, Table_t *pointers, const TypeInfo_t *info) { (void)info; - Int_t i = *(Int_t*)obj; + Int_t i = *(Int_t *)obj; if (likely(i.small & 1L)) { fputc(0, out); int64_t i64 = i.small >> 2L; @@ -530,44 +511,45 @@ static void Int$serialize(const void *obj, FILE *out, Table_t *pointers, const T } else { fputc(1, out); mpz_t n; - mpz_init_set_int(n, *(Int_t*)obj); + mpz_init_set_int(n, *(Int_t *)obj); mpz_out_raw(out, n); } } -static void Int$deserialize(FILE *in, void *obj, List_t *pointers, const TypeInfo_t *info) -{ +static void Int$deserialize(FILE *in, void *obj, List_t *pointers, const TypeInfo_t *info) { (void)info; if (fgetc(in) == 0) { int64_t i = 0; Int64$deserialize(in, &i, pointers, &Int64$info); - *(Int_t*)obj = (Int_t){.small=(i<<2L) | 1L}; + *(Int_t *)obj = (Int_t){.small = (i << 2L) | 1L}; } else { mpz_t n; mpz_init(n); mpz_inp_raw(n, in); - *(Int_t*)obj = Int$from_mpz(n); + *(Int_t *)obj = Int$from_mpz(n); } } -public const TypeInfo_t Int$info = { - .size=sizeof(Int_t), - .align=__alignof__(Int_t), - .metamethods={ - .compare=Int$compare, - .equal=Int$equal, - .hash=Int$hash, - .as_text=Int$as_text, - .is_none=Int$is_none, - .serialize=Int$serialize, - .deserialize=Int$deserialize, - }, +public +const TypeInfo_t Int$info = { + .size = sizeof(Int_t), + .align = __alignof__(Int_t), + .metamethods = + { + .compare = Int$compare, + .equal = Int$equal, + .hash = Int$hash, + .as_text = Int$as_text, + .is_none = Int$is_none, + .serialize = Int$serialize, + .deserialize = Int$deserialize, + }, }; -public void Int64$serialize(const void *obj, FILE *out, Table_t *pointers, const TypeInfo_t *info) -{ +public +void Int64$serialize(const void *obj, FILE *out, Table_t *pointers, const TypeInfo_t *info) { (void)info, (void)pointers; - int64_t i = *(int64_t*)obj; + int64_t i = *(int64_t *)obj; uint64_t z = (uint64_t)((i << 1L) ^ (i >> 63L)); // Zigzag encode while (z >= 0x80L) { fputc((uint8_t)(z | 0x80L), out); @@ -576,22 +558,22 @@ public void Int64$serialize(const void *obj, FILE *out, Table_t *pointers, const fputc((uint8_t)z, out); } -public void Int64$deserialize(FILE *in, void *outval, List_t *pointers, const TypeInfo_t *info) -{ +public +void Int64$deserialize(FILE *in, void *outval, List_t *pointers, const TypeInfo_t *info) { (void)info, (void)pointers; uint64_t z = 0; - for(size_t shift = 0; ; shift += 7) { + for (size_t shift = 0;; shift += 7) { uint8_t byte = (uint8_t)fgetc(in); z |= ((uint64_t)(byte & 0x7F)) << shift; if ((byte & 0x80) == 0) break; } - *(int64_t*)outval = (int64_t)((z >> 1L) ^ -(z & 1L)); // Zigzag decode + *(int64_t *)outval = (int64_t)((z >> 1L) ^ -(z & 1L)); // Zigzag decode } -public void Int32$serialize(const void *obj, FILE *out, Table_t *pointers, const TypeInfo_t *info) -{ +public +void Int32$serialize(const void *obj, FILE *out, Table_t *pointers, const TypeInfo_t *info) { (void)info, (void)pointers; - int32_t i = *(int32_t*)obj; + int32_t i = *(int32_t *)obj; uint32_t z = (uint32_t)((i << 1) ^ (i >> 31)); // Zigzag encode while (z >= 0x80) { fputc((uint8_t)(z | 0x80), out); @@ -600,16 +582,16 @@ public void Int32$serialize(const void *obj, FILE *out, Table_t *pointers, const fputc((uint8_t)z, out); } -public void Int32$deserialize(FILE *in, void *outval, List_t *pointers, const TypeInfo_t *info) -{ +public +void Int32$deserialize(FILE *in, void *outval, List_t *pointers, const TypeInfo_t *info) { (void)info, (void)pointers; uint32_t z = 0; - for(size_t shift = 0; ; shift += 7) { + for (size_t shift = 0;; shift += 7) { uint8_t byte = (uint8_t)fgetc(in); z |= ((uint32_t)(byte & 0x7F)) << shift; if ((byte & 0x80) == 0) break; } - *(int32_t*)outval = (int32_t)((z >> 1L) ^ -(z & 1L)); // Zigzag decode + *(int32_t *)outval = (int32_t)((z >> 1L) ^ -(z & 1L)); // Zigzag decode } // The space savings for smaller ints are not worth having: @@ -619,122 +601,146 @@ public void Int32$deserialize(FILE *in, void *outval, List_t *pointers, const Ty #define Int8$deserialize NULL #ifdef __TINYC__ -#define __builtin_add_overflow(x, y, result) ({ *(result) = (x) + (y); false; }) +#define __builtin_add_overflow(x, y, result) \ + ({ \ + *(result) = (x) + (y); \ + false; \ + }) #endif -#define DEFINE_INT_TYPE(c_type, KindOfInt, min_val, max_val, to_attr)\ - public Text_t KindOfInt ## $as_text(const void *i, bool colorize, const TypeInfo_t *info) { \ - (void)info; \ - if (!i) return Text(#KindOfInt); \ - Text_t text = _int64_to_text((int64_t)(*(c_type*)i)); \ - return colorize ? Texts(Text("\033[35m"), text, Text("\033[m")) : text; \ - } \ - public PUREFUNC int32_t KindOfInt ## $compare(const void *x, const void *y, const TypeInfo_t *info) { \ - (void)info; \ - return (*(c_type*)x > *(c_type*)y) - (*(c_type*)x < *(c_type*)y); \ - } \ - public PUREFUNC bool KindOfInt ## $equal(const void *x, const void *y, const TypeInfo_t *info) { \ - (void)info; \ - return *(c_type*)x == *(c_type*)y; \ - } \ - public CONSTFUNC bool KindOfInt ## $is_between(const c_type x, const c_type low, const c_type high) { \ - return low <= x && x <= high; \ - } \ - public CONSTFUNC c_type KindOfInt ## $clamped(c_type x, c_type min, c_type max) { \ - return x < min ? min : (x > max ? max : x); \ - } \ - public Text_t KindOfInt ## $hex(c_type i, Int_t digits_int, bool uppercase, bool prefix) { \ - Int_t as_int = Int$from_int64((int64_t)i); \ - return Int$hex(as_int, digits_int, uppercase, prefix); \ - } \ - public Text_t KindOfInt ## $octal(c_type i, Int_t digits_int, bool prefix) { \ - Int_t as_int = Int$from_int64((int64_t)i); \ - return Int$octal(as_int, digits_int, prefix); \ - } \ - public List_t KindOfInt ## $bits(c_type x) { \ - List_t bit_list = (List_t){.data=GC_MALLOC_ATOMIC(sizeof(bool[8*sizeof(c_type)])), .atomic=1, .stride=sizeof(bool), .length=8*sizeof(c_type)}; \ - bool *bits = bit_list.data + sizeof(c_type)*8; \ - for (size_t i = 0; i < 8*sizeof(c_type); i++) { \ - *(bits--) = x & 1; \ - x >>= 1; \ - } \ - return bit_list; \ - } \ - public bool KindOfInt ## $get_bit(c_type x, Int_t bit_index) { \ - if (Int$compare_value(bit_index, I(1)) < 0) \ - fail("Invalid bit index (expected 1 or higher): ", bit_index); \ - if (Int$compare_value(bit_index, Int$from_int64(sizeof(c_type)*8)) > 0) \ - fail("Bit index is too large! There are only ", (uint64_t)sizeof(c_type)*8, " bits, but index is: ", bit_index); \ - return ((x & (c_type)(1L << (Int64$from_int(bit_index, true)-1L))) != 0); \ - } \ - typedef struct { \ - Optional##KindOfInt##_t current, last; \ - KindOfInt##_t step; \ - } KindOfInt##Range_t; \ - static Optional##KindOfInt##_t _next_##KindOfInt(KindOfInt##Range_t *info) \ - { \ - Optional##KindOfInt##_t i = info->current; \ - if (!i.is_none) { \ - KindOfInt##_t next; bool overflow = __builtin_add_overflow(i.value, info->step, &next); \ - if (overflow || (!info->last.is_none && (info->step >= 0 ? next > info->last.value : next < info->last.value))) \ - info->current = (Optional##KindOfInt##_t){.is_none=true}; \ - else \ - info->current = (Optional##KindOfInt##_t){.value=next}; \ - } \ - return i; \ - } \ - public to_attr Closure_t KindOfInt ## $to(c_type first, c_type last, Optional ## KindOfInt ## _t step) { \ - KindOfInt##Range_t *range = GC_MALLOC(sizeof(KindOfInt##Range_t)); \ - range->current = (Optional##KindOfInt##_t){.value=first}; \ - range->last = (Optional##KindOfInt##_t){.value=last}; \ - range->step = step.is_none ? (last >= first ? 1 : -1) : step.value; \ - return (Closure_t){.fn=_next_##KindOfInt, .userdata=range}; \ - } \ - public to_attr Closure_t KindOfInt ## $onward(c_type first, c_type step) { \ - KindOfInt##Range_t *range = GC_MALLOC(sizeof(KindOfInt##Range_t)); \ - range->current = (Optional##KindOfInt##_t){.value=first}; \ - range->last = (Optional##KindOfInt##_t){.is_none=true}; \ - range->step = step; \ - return (Closure_t){.fn=_next_##KindOfInt, .userdata=range}; \ - } \ - public PUREFUNC Optional ## KindOfInt ## _t KindOfInt ## $parse(Text_t text, Text_t *remainder) { \ - OptionalInt_t full_int = Int$parse(text, remainder); \ - if (full_int.small == 0L) return (Optional ## KindOfInt ## _t){.is_none=true}; \ - if (Int$compare_value(full_int, I(min_val)) < 0) { \ - return (Optional ## KindOfInt ## _t){.is_none=true}; \ - } \ - if (Int$compare_value(full_int, I(max_val)) > 0) { \ - return (Optional ## KindOfInt ## _t){.is_none=true}; \ - } \ - return (Optional ## KindOfInt ## _t){.value=KindOfInt##$from_int(full_int, true)}; \ - } \ - public CONSTFUNC c_type KindOfInt ## $gcd(c_type x, c_type y) { \ - if (x == 0 || y == 0) return 0; \ - x = KindOfInt##$abs(x); \ - y = KindOfInt##$abs(y); \ - while (x != y) { \ - if (x > y) x -= y; \ - else y -= x; \ - } \ - return x; \ - } \ - public const c_type KindOfInt##$min = min_val; \ - public const c_type KindOfInt##$max = max_val; \ - public const TypeInfo_t KindOfInt##$info = { \ - .size=sizeof(c_type), \ - .align=__alignof__(c_type), \ - .metamethods={ \ - .compare=KindOfInt##$compare, \ - .as_text=KindOfInt##$as_text, \ - .serialize=KindOfInt##$serialize, \ - .deserialize=KindOfInt##$deserialize, \ - }, \ +#define DEFINE_INT_TYPE(c_type, KindOfInt, min_val, max_val, to_attr) \ + public \ + Text_t KindOfInt##$as_text(const void *i, bool colorize, const TypeInfo_t *info) { \ + (void)info; \ + if (!i) return Text(#KindOfInt); \ + Text_t text = _int64_to_text((int64_t)(*(c_type *)i)); \ + return colorize ? Texts(Text("\033[35m"), text, Text("\033[m")) : text; \ + } \ + public \ + PUREFUNC int32_t KindOfInt##$compare(const void *x, const void *y, const TypeInfo_t *info) { \ + (void)info; \ + return (*(c_type *)x > *(c_type *)y) - (*(c_type *)x < *(c_type *)y); \ + } \ + public \ + PUREFUNC bool KindOfInt##$equal(const void *x, const void *y, const TypeInfo_t *info) { \ + (void)info; \ + return *(c_type *)x == *(c_type *)y; \ + } \ + public \ + CONSTFUNC bool KindOfInt##$is_between(const c_type x, const c_type low, const c_type high) { \ + return low <= x && x <= high; \ + } \ + public \ + CONSTFUNC c_type KindOfInt##$clamped(c_type x, c_type min, c_type max) { \ + return x < min ? min : (x > max ? max : x); \ + } \ + public \ + Text_t KindOfInt##$hex(c_type i, Int_t digits_int, bool uppercase, bool prefix) { \ + Int_t as_int = Int$from_int64((int64_t)i); \ + return Int$hex(as_int, digits_int, uppercase, prefix); \ + } \ + public \ + Text_t KindOfInt##$octal(c_type i, Int_t digits_int, bool prefix) { \ + Int_t as_int = Int$from_int64((int64_t)i); \ + return Int$octal(as_int, digits_int, prefix); \ + } \ + public \ + List_t KindOfInt##$bits(c_type x) { \ + List_t bit_list = (List_t){.data = GC_MALLOC_ATOMIC(sizeof(bool[8 * sizeof(c_type)])), \ + .atomic = 1, \ + .stride = sizeof(bool), \ + .length = 8 * sizeof(c_type)}; \ + bool *bits = bit_list.data + sizeof(c_type) * 8; \ + for (size_t i = 0; i < 8 * sizeof(c_type); i++) { \ + *(bits--) = x & 1; \ + x >>= 1; \ + } \ + return bit_list; \ + } \ + public \ + bool KindOfInt##$get_bit(c_type x, Int_t bit_index) { \ + if (Int$compare_value(bit_index, I(1)) < 0) fail("Invalid bit index (expected 1 or higher): ", bit_index); \ + if (Int$compare_value(bit_index, Int$from_int64(sizeof(c_type) * 8)) > 0) \ + fail("Bit index is too large! There are only ", (uint64_t)sizeof(c_type) * 8, \ + " bits, but index is: ", bit_index); \ + return ((x & (c_type)(1L << (Int64$from_int(bit_index, true) - 1L))) != 0); \ + } \ + typedef struct { \ + Optional##KindOfInt##_t current, last; \ + KindOfInt##_t step; \ + } KindOfInt##Range_t; \ + static Optional##KindOfInt##_t _next_##KindOfInt(KindOfInt##Range_t *info) { \ + Optional##KindOfInt##_t i = info->current; \ + if (!i.is_none) { \ + KindOfInt##_t next; \ + bool overflow = __builtin_add_overflow(i.value, info->step, &next); \ + if (overflow \ + || (!info->last.is_none && (info->step >= 0 ? next > info->last.value : next < info->last.value))) \ + info->current = (Optional##KindOfInt##_t){.is_none = true}; \ + else info->current = (Optional##KindOfInt##_t){.value = next}; \ + } \ + return i; \ + } \ + public \ + to_attr Closure_t KindOfInt##$to(c_type first, c_type last, Optional##KindOfInt##_t step) { \ + KindOfInt##Range_t *range = GC_MALLOC(sizeof(KindOfInt##Range_t)); \ + range->current = (Optional##KindOfInt##_t){.value = first}; \ + range->last = (Optional##KindOfInt##_t){.value = last}; \ + range->step = step.is_none ? (last >= first ? 1 : -1) : step.value; \ + return (Closure_t){.fn = _next_##KindOfInt, .userdata = range}; \ + } \ + public \ + to_attr Closure_t KindOfInt##$onward(c_type first, c_type step) { \ + KindOfInt##Range_t *range = GC_MALLOC(sizeof(KindOfInt##Range_t)); \ + range->current = (Optional##KindOfInt##_t){.value = first}; \ + range->last = (Optional##KindOfInt##_t){.is_none = true}; \ + range->step = step; \ + return (Closure_t){.fn = _next_##KindOfInt, .userdata = range}; \ + } \ + public \ + PUREFUNC Optional##KindOfInt##_t KindOfInt##$parse(Text_t text, Text_t *remainder) { \ + OptionalInt_t full_int = Int$parse(text, remainder); \ + if (full_int.small == 0L) return (Optional##KindOfInt##_t){.is_none = true}; \ + if (Int$compare_value(full_int, I(min_val)) < 0) { \ + return (Optional##KindOfInt##_t){.is_none = true}; \ + } \ + if (Int$compare_value(full_int, I(max_val)) > 0) { \ + return (Optional##KindOfInt##_t){.is_none = true}; \ + } \ + return (Optional##KindOfInt##_t){.value = KindOfInt##$from_int(full_int, true)}; \ + } \ + public \ + CONSTFUNC c_type KindOfInt##$gcd(c_type x, c_type y) { \ + if (x == 0 || y == 0) return 0; \ + x = KindOfInt##$abs(x); \ + y = KindOfInt##$abs(y); \ + while (x != y) { \ + if (x > y) x -= y; \ + else y -= x; \ + } \ + return x; \ + } \ + public \ + const c_type KindOfInt##$min = min_val; \ + public \ + const c_type KindOfInt##$max = max_val; \ + public \ + const TypeInfo_t KindOfInt##$info = { \ + .size = sizeof(c_type), \ + .align = __alignof__(c_type), \ + .metamethods = \ + { \ + .compare = KindOfInt##$compare, \ + .as_text = KindOfInt##$as_text, \ + .serialize = KindOfInt##$serialize, \ + .deserialize = KindOfInt##$deserialize, \ + }, \ }; -DEFINE_INT_TYPE(int64_t, Int64, INT64_MIN, INT64_MAX, __attribute__(())) -DEFINE_INT_TYPE(int32_t, Int32, INT32_MIN, INT32_MAX, CONSTFUNC) -DEFINE_INT_TYPE(int16_t, Int16, INT16_MIN, INT16_MAX, CONSTFUNC) -DEFINE_INT_TYPE(int8_t, Int8, INT8_MIN, INT8_MAX, CONSTFUNC) +DEFINE_INT_TYPE(int64_t, Int64, INT64_MIN, INT64_MAX, __attribute__(())) +DEFINE_INT_TYPE(int32_t, Int32, INT32_MIN, INT32_MAX, CONSTFUNC) +DEFINE_INT_TYPE(int16_t, Int16, INT16_MIN, INT16_MAX, CONSTFUNC) +DEFINE_INT_TYPE(int8_t, Int8, INT8_MIN, INT8_MAX, CONSTFUNC) #undef DEFINE_INT_TYPE // vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0 diff --git a/src/stdlib/integers.h b/src/stdlib/integers.h index 744992dd..a7249495 100644 --- a/src/stdlib/integers.h +++ b/src/stdlib/integers.h @@ -2,9 +2,9 @@ // Integer type infos and methods +#include <gmp.h> #include <stdbool.h> #include <stdint.h> -#include <gmp.h> #include "datatypes.h" #include "stdlib.h" @@ -16,74 +16,72 @@ #define I16(x) ((int16_t)x) #define I8(x) ((int8_t)x) -#define DEFINE_INT_TYPE(c_type, type_name) \ - typedef struct { \ - c_type value; \ - bool is_none:1; \ - } Optional ## type_name ## _t; \ - Text_t type_name ## $as_text(const void *i, bool colorize, const TypeInfo_t *type); \ - PUREFUNC int32_t type_name ## $compare(const void *x, const void *y, const TypeInfo_t *type); \ - PUREFUNC bool type_name ## $equal(const void *x, const void *y, const TypeInfo_t *type); \ - Text_t type_name ## $hex(c_type i, Int_t digits, bool uppercase, bool prefix); \ - Text_t type_name ## $octal(c_type i, Int_t digits, bool prefix); \ - List_t type_name ## $bits(c_type x); \ - bool type_name ## $get_bit(c_type x, Int_t bit_index); \ - Closure_t type_name ## $to(c_type first, c_type last, Optional ## type_name ## _t step); \ - Closure_t type_name ## $onward(c_type first, c_type step); \ - PUREFUNC Optional ## type_name ## _t type_name ## $parse(Text_t text, Text_t *remainder); \ - CONSTFUNC bool type_name ## $is_between(const c_type x, const c_type low, const c_type high); \ - CONSTFUNC c_type type_name ## $clamped(c_type x, c_type min, c_type max); \ - MACROLIKE CONSTFUNC c_type type_name ## $from_byte(Byte_t b) { return (c_type)b; } \ - MACROLIKE CONSTFUNC c_type type_name ## $from_bool(Bool_t b) { return (c_type)b; } \ - CONSTFUNC c_type type_name ## $gcd(c_type x, c_type y); \ - extern const c_type type_name ## $min, type_name##$max; \ - extern const TypeInfo_t type_name ## $info; \ - MACROLIKE c_type type_name ## $divided_by(c_type D, c_type d) { \ - c_type q = D/d, r = D%d; \ - q -= (r < 0) * (2*(d > 0) - 1); \ - return q; \ - } \ - MACROLIKE c_type type_name ## $modulo(c_type D, c_type d) { \ - c_type r = D%d; \ - r -= (r < 0) * (2*(d < 0) - 1) * d; \ - return r; \ - } \ - MACROLIKE c_type type_name ## $modulo1(c_type D, c_type d) { \ - return type_name ## $modulo(D-1, d) + 1; \ - } \ - MACROLIKE PUREFUNC c_type type_name ## $wrapping_plus(c_type x, c_type y) { \ - return (c_type)((u##c_type)x + (u##c_type)y); \ - } \ - MACROLIKE PUREFUNC c_type type_name ## $wrapping_minus(c_type x, c_type y) { \ - return (c_type)((u##c_type)x + (u##c_type)y); \ - } \ - MACROLIKE PUREFUNC c_type type_name ## $unsigned_left_shifted(c_type x, c_type y) { \ - return (c_type)((u##c_type)x << y); \ - } \ - MACROLIKE PUREFUNC c_type type_name ## $unsigned_right_shifted(c_type x, c_type y) { \ - return (c_type)((u##c_type)x >> y); \ +#define DEFINE_INT_TYPE(c_type, type_name) \ + typedef struct { \ + c_type value; \ + bool is_none : 1; \ + } Optional##type_name##_t; \ + Text_t type_name##$as_text(const void *i, bool colorize, const TypeInfo_t *type); \ + PUREFUNC int32_t type_name##$compare(const void *x, const void *y, const TypeInfo_t *type); \ + PUREFUNC bool type_name##$equal(const void *x, const void *y, const TypeInfo_t *type); \ + Text_t type_name##$hex(c_type i, Int_t digits, bool uppercase, bool prefix); \ + Text_t type_name##$octal(c_type i, Int_t digits, bool prefix); \ + List_t type_name##$bits(c_type x); \ + bool type_name##$get_bit(c_type x, Int_t bit_index); \ + Closure_t type_name##$to(c_type first, c_type last, Optional##type_name##_t step); \ + Closure_t type_name##$onward(c_type first, c_type step); \ + PUREFUNC Optional##type_name##_t type_name##$parse(Text_t text, Text_t *remainder); \ + CONSTFUNC bool type_name##$is_between(const c_type x, const c_type low, const c_type high); \ + CONSTFUNC c_type type_name##$clamped(c_type x, c_type min, c_type max); \ + MACROLIKE CONSTFUNC c_type type_name##$from_byte(Byte_t b) { return (c_type)b; } \ + MACROLIKE CONSTFUNC c_type type_name##$from_bool(Bool_t b) { return (c_type)b; } \ + CONSTFUNC c_type type_name##$gcd(c_type x, c_type y); \ + extern const c_type type_name##$min, type_name##$max; \ + extern const TypeInfo_t type_name##$info; \ + MACROLIKE c_type type_name##$divided_by(c_type D, c_type d) { \ + c_type q = D / d, r = D % d; \ + q -= (r < 0) * (2 * (d > 0) - 1); \ + return q; \ + } \ + MACROLIKE c_type type_name##$modulo(c_type D, c_type d) { \ + c_type r = D % d; \ + r -= (r < 0) * (2 * (d < 0) - 1) * d; \ + return r; \ + } \ + MACROLIKE c_type type_name##$modulo1(c_type D, c_type d) { return type_name##$modulo(D - 1, d) + 1; } \ + MACROLIKE PUREFUNC c_type type_name##$wrapping_plus(c_type x, c_type y) { \ + return (c_type)((u##c_type)x + (u##c_type)y); \ + } \ + MACROLIKE PUREFUNC c_type type_name##$wrapping_minus(c_type x, c_type y) { \ + return (c_type)((u##c_type)x + (u##c_type)y); \ + } \ + MACROLIKE PUREFUNC c_type type_name##$unsigned_left_shifted(c_type x, c_type y) { \ + return (c_type)((u##c_type)x << y); \ + } \ + MACROLIKE PUREFUNC c_type type_name##$unsigned_right_shifted(c_type x, c_type y) { \ + return (c_type)((u##c_type)x >> y); \ } DEFINE_INT_TYPE(int64_t, Int64) DEFINE_INT_TYPE(int32_t, Int32) DEFINE_INT_TYPE(int16_t, Int16) -DEFINE_INT_TYPE(int8_t, Int8) +DEFINE_INT_TYPE(int8_t, Int8) #undef DEFINE_INT_TYPE -#define NONE_INT64 ((OptionalInt64_t){.is_none=true}) -#define NONE_INT32 ((OptionalInt32_t){.is_none=true}) -#define NONE_INT16 ((OptionalInt16_t){.is_none=true}) -#define NONE_INT8 ((OptionalInt8_t){.is_none=true}) +#define NONE_INT64 ((OptionalInt64_t){.is_none = true}) +#define NONE_INT32 ((OptionalInt32_t){.is_none = true}) +#define NONE_INT16 ((OptionalInt16_t){.is_none = true}) +#define NONE_INT8 ((OptionalInt8_t){.is_none = true}) #define Int64$abs(...) I64(labs(__VA_ARGS__)) #define Int32$abs(...) I32(abs(__VA_ARGS__)) #define Int16$abs(...) I16(abs(__VA_ARGS__)) #define Int8$abs(...) I8(abs(__VA_ARGS__)) -void Int64$serialize(const void *obj, FILE *out, Table_t*, const TypeInfo_t*); -void Int64$deserialize(FILE *in, void *outval, List_t*, const TypeInfo_t*); -void Int32$serialize(const void *obj, FILE *out, Table_t*, const TypeInfo_t*); -void Int32$deserialize(FILE *in, void *outval, List_t*, const TypeInfo_t*); +void Int64$serialize(const void *obj, FILE *out, Table_t *, const TypeInfo_t *); +void Int64$deserialize(FILE *in, void *outval, List_t *, const TypeInfo_t *); +void Int32$serialize(const void *obj, FILE *out, Table_t *, const TypeInfo_t *); +void Int32$deserialize(FILE *in, void *outval, List_t *, const TypeInfo_t *); Text_t Int$as_text(const void *i, bool colorize, const TypeInfo_t *type); Text_t Int$value_as_text(Int_t i); @@ -109,19 +107,17 @@ bool Int$get_bit(Int_t x, Int_t bit_index); #define BIGGEST_SMALL_INT 0x3fffffff #define SMALLEST_SMALL_INT -0x40000000 -#define Int$from_mpz(mpz) (\ - mpz_cmpabs_ui(mpz, BIGGEST_SMALL_INT) <= 0 ? ( \ - (Int_t){.small=(mpz_get_si(mpz)<<2L)|1L} \ - ) : ( \ - (Int_t){.big=memcpy(new(mpz_t), &mpz, sizeof(mpz_t))} \ - )) +#define Int$from_mpz(mpz) \ + (mpz_cmpabs_ui(mpz, BIGGEST_SMALL_INT) <= 0 ? ((Int_t){.small = (mpz_get_si(mpz) << 2L) | 1L}) \ + : ((Int_t){.big = memcpy(new (mpz_t), &mpz, sizeof(mpz_t))})) -#define mpz_init_set_int(mpz, i) do { \ - if likely ((i).small & 1L) mpz_init_set_si(mpz, (i).small >> 2L); \ - else mpz_init_set(mpz, *(i).big); \ -} while (0) +#define mpz_init_set_int(mpz, i) \ + do { \ + if likely ((i).small & 1L) mpz_init_set_si(mpz, (i).small >> 2L); \ + else mpz_init_set(mpz, *(i).big); \ + } while (0) -#define I_small(i) ((Int_t){.small=(int64_t)((uint64_t)(i)<<2L)|1L}) +#define I_small(i) ((Int_t){.small = (int64_t)((uint64_t)(i) << 2L) | 1L}) #define I(i) _Generic(i, int8_t: I_small(i), int16_t: I_small(i), default: Int$from_int64(i)) #define I_is_zero(i) ((i).small == 1L) @@ -155,116 +151,107 @@ extern const TypeInfo_t Int$info; MACROLIKE Int_t Int$plus(Int_t x, Int_t y) { const int64_t z = (int64_t)((uint64_t)x.small + (uint64_t)y.small); - if likely ((z|2L) == (int32_t)z) - return (Int_t){.small=(z-1L)}; + if likely ((z | 2L) == (int32_t)z) return (Int_t){.small = (z - 1L)}; return Int$slow_plus(x, y); } MACROLIKE Int_t Int$minus(Int_t x, Int_t y) { const int64_t z = (int64_t)(((uint64_t)x.small ^ 3L) - (uint64_t)y.small); - if likely ((z & ~2L) == (int32_t)z) - return (Int_t){.small=z}; + if likely ((z & ~2L) == (int32_t)z) return (Int_t){.small = z}; return Int$slow_minus(x, y); } MACROLIKE Int_t Int$times(Int_t x, Int_t y) { if likely ((x.small & y.small) & 1L) { - const int64_t z = (x.small>>1L) * (y.small>>1L); - if likely (z == (int32_t)z) - return (Int_t){.small=z+1L}; + const int64_t z = (x.small >> 1L) * (y.small >> 1L); + if likely (z == (int32_t)z) return (Int_t){.small = z + 1L}; } return Int$slow_times(x, y); } MACROLIKE Int_t Int$divided_by(Int_t x, Int_t y) { if likely (x.small & y.small & 1L) { - // Euclidean division, see: https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/divmodnote-letter.pdf - const int64_t D = (x.small>>2L); - const int64_t d = (y.small>>2L); - int64_t q = D/d, r = D%d; - q -= (r < 0L) * (2L*(d > 0L) - 1L); - if likely (q == (int32_t)q) - return (Int_t){.small=(q<<2L)|1L}; + // Euclidean division, see: + // https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/divmodnote-letter.pdf + const int64_t D = (x.small >> 2L); + const int64_t d = (y.small >> 2L); + int64_t q = D / d, r = D % d; + q -= (r < 0L) * (2L * (d > 0L) - 1L); + if likely (q == (int32_t)q) return (Int_t){.small = (q << 2L) | 1L}; } return Int$slow_divided_by(x, y); } MACROLIKE Int_t Int$modulo(Int_t x, Int_t y) { if likely (x.small & y.small & 1L) { - // Euclidean modulus, see: https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/divmodnote-letter.pdf - const int64_t D = (x.small>>2L); - const int64_t d = (y.small>>2L); - int64_t r = D%d; - r -= (r < 0L) * (2L*(d < 0L) - 1L) * d; - return (Int_t){.small=(r<<2L)|1L}; + // Euclidean modulus, see: + // https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/divmodnote-letter.pdf + const int64_t D = (x.small >> 2L); + const int64_t d = (y.small >> 2L); + int64_t r = D % d; + r -= (r < 0L) * (2L * (d < 0L) - 1L) * d; + return (Int_t){.small = (r << 2L) | 1L}; } return Int$slow_modulo(x, y); } MACROLIKE Int_t Int$modulo1(Int_t x, Int_t y) { if likely (x.small & y.small & 1L) { - // Euclidean modulus, see: https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/divmodnote-letter.pdf - const int64_t D = (x.small>>2L)-1L; - const int64_t d = (y.small>>2L); - int64_t r = D%d; - r -= (r < 0L) * (2L*(d < 0L) - 1L) * d; - return (Int_t){.small=((r+1L)<<2L)|1L}; + // Euclidean modulus, see: + // https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/divmodnote-letter.pdf + const int64_t D = (x.small >> 2L) - 1L; + const int64_t d = (y.small >> 2L); + int64_t r = D % d; + r -= (r < 0L) * (2L * (d < 0L) - 1L) * d; + return (Int_t){.small = ((r + 1L) << 2L) | 1L}; } return Int$slow_modulo1(x, y); } MACROLIKE Int_t Int$left_shifted(Int_t x, Int_t y) { if likely (x.small & y.small & 1L) { - const int64_t z = ((x.small>>2L) << (y.small>>2L))<<2L; - if likely (z == (int32_t)z) - return (Int_t){.small=z+1L}; + const int64_t z = ((x.small >> 2L) << (y.small >> 2L)) << 2L; + if likely (z == (int32_t)z) return (Int_t){.small = z + 1L}; } return Int$slow_left_shifted(x, y); } MACROLIKE Int_t Int$right_shifted(Int_t x, Int_t y) { if likely (x.small & y.small & 1L) { - const int64_t z = ((x.small>>2L) >> (y.small>>2L))<<2L; - if likely (z == (int32_t)z) - return (Int_t){.small=z+1L}; + const int64_t z = ((x.small >> 2L) >> (y.small >> 2L)) << 2L; + if likely (z == (int32_t)z) return (Int_t){.small = z + 1L}; } return Int$slow_right_shifted(x, y); } MACROLIKE Int_t Int$bit_and(Int_t x, Int_t y) { const int64_t z = x.small & y.small; - if likely (z & 1L) - return (Int_t){.small=z}; + if likely (z & 1L) return (Int_t){.small = z}; return Int$slow_bit_and(x, y); } MACROLIKE Int_t Int$bit_or(Int_t x, Int_t y) { - if likely (x.small & y.small & 1L) - return (Int_t){.small=(x.small | y.small)}; + if likely (x.small & y.small & 1L) return (Int_t){.small = (x.small | y.small)}; return Int$slow_bit_or(x, y); } MACROLIKE Int_t Int$bit_xor(Int_t x, Int_t y) { - if likely (x.small & y.small & 1L) - return (Int_t){.small=(x.small ^ y.small) | 1L}; + if likely (x.small & y.small & 1L) return (Int_t){.small = (x.small ^ y.small) | 1L}; return Int$slow_bit_xor(x, y); } MACROLIKE Int_t Int$negated(Int_t x) { - if likely (x.small & 1L) - return (Int_t){.small=(~x.small) ^ 3L}; + if likely (x.small & 1L) return (Int_t){.small = (~x.small) ^ 3L}; return Int$slow_negated(x); } MACROLIKE Int_t Int$negative(Int_t x) { - if likely (x.small & 1L) - return (Int_t){.small=((-((x.small)>>2L))<<2L) | 1L}; + if likely (x.small & 1L) return (Int_t){.small = ((-((x.small) >> 2L)) << 2L) | 1L}; return Int$slow_negative(x); } MACROLIKE PUREFUNC bool Int$is_negative(Int_t x) { - if likely (x.small & 1L) - return x.small < 0L; + if likely (x.small & 1L) return x.small < 0L; return Int$compare_value(x, I_small(0)) < 0L; } @@ -278,42 +265,36 @@ MACROLIKE PUREFUNC bool Int$is_negative(Int_t x) { MACROLIKE PUREFUNC Int_t Int$from_num(double n, bool truncate) { mpz_t result; mpz_init_set_d(result, n); - if (!truncate && unlikely(mpz_get_d(result) != n)) - fail("Could not convert to an integer without truncation: ", n); + if (!truncate && unlikely(mpz_get_d(result) != n)) fail("Could not convert to an integer without truncation: ", n); return Int$from_mpz(result); } MACROLIKE PUREFUNC Int_t Int$from_num32(float n, bool truncate) { return Int$from_num((double)n, truncate); } MACROLIKE Int_t Int$from_int64(int64_t i) { - if likely (i >= SMALLEST_SMALL_INT && i <= BIGGEST_SMALL_INT) - return (Int_t){.small=(i<<2L)|1L}; + if likely (i >= SMALLEST_SMALL_INT && i <= BIGGEST_SMALL_INT) return (Int_t){.small = (i << 2L) | 1L}; mpz_t result; mpz_init_set_si(result, i); return Int$from_mpz(result); } MACROLIKE CONSTFUNC Int_t Int$from_int32(Int32_t i) { return Int$from_int64((Int32_t)i); } MACROLIKE CONSTFUNC Int_t Int$from_int16(Int16_t i) { return I_small(i); } -MACROLIKE CONSTFUNC Int_t Int$from_int8(Int8_t i) { return I_small(i); } +MACROLIKE CONSTFUNC Int_t Int$from_int8(Int8_t i) { return I_small(i); } MACROLIKE CONSTFUNC Int_t Int$from_byte(Byte_t b) { return I_small(b); } MACROLIKE CONSTFUNC Int_t Int$from_bool(Bool_t b) { return I_small(b); } // Int64 constructors MACROLIKE PUREFUNC Int64_t Int64$from_num(Num_t n, bool truncate) { int64_t i64 = (int64_t)n; - if (!truncate && unlikely((Num_t)i64 != n)) - fail("Could not convert Num to Int64 without truncation: ", n); + if (!truncate && unlikely((Num_t)i64 != n)) fail("Could not convert Num to Int64 without truncation: ", n); return i64; } MACROLIKE PUREFUNC Int64_t Int64$from_num32(Num32_t n, bool truncate) { int64_t i64 = (int64_t)n; - if (!truncate && unlikely((Num32_t)i64 != n)) - fail("Could not convert Num32 to Int64 without truncation: ", n); + if (!truncate && unlikely((Num32_t)i64 != n)) fail("Could not convert Num32 to Int64 without truncation: ", n); return i64; } MACROLIKE PUREFUNC Int64_t Int64$from_int(Int_t i, bool truncate) { - if likely (i.small & 1L) - return (int64_t)(i.small >> 2L); - if (!truncate && unlikely(!mpz_fits_slong_p(*i.big))) - fail("Integer is too big to fit in a 64-bit integer: ", i); + if likely (i.small & 1L) return (int64_t)(i.small >> 2L); + if (!truncate && unlikely(!mpz_fits_slong_p(*i.big))) fail("Integer is too big to fit in a 64-bit integer: ", i); return mpz_get_si(*i.big); } MACROLIKE CONSTFUNC Int64_t Int64$from_int32(Int32_t i) { return (Int64_t)i; } @@ -323,27 +304,23 @@ MACROLIKE CONSTFUNC Int64_t Int64$from_int8(Int8_t i) { return (Int64_t)i; } // Int32 constructors MACROLIKE PUREFUNC Int32_t Int32$from_num(Num_t n, bool truncate) { int32_t i32 = (int32_t)n; - if (!truncate && unlikely((Num_t)i32 != n)) - fail("Could not convert Num to Int32 without truncation: ", n); + if (!truncate && unlikely((Num_t)i32 != n)) fail("Could not convert Num to Int32 without truncation: ", n); return i32; } MACROLIKE PUREFUNC Int32_t Int32$from_num32(Num32_t n, bool truncate) { int32_t i32 = (int32_t)n; - if (!truncate && unlikely((Num32_t)i32 != n)) - fail("Could not convert Num32 to Int32 without truncation: ", n); + if (!truncate && unlikely((Num32_t)i32 != n)) fail("Could not convert Num32 to Int32 without truncation: ", n); return i32; } MACROLIKE PUREFUNC Int32_t Int32$from_int(Int_t i, bool truncate) { int64_t i64 = Int64$from_int(i, truncate); int32_t i32 = (int32_t)i64; - if (!truncate && unlikely((int64_t)i32 != i64)) - fail("Integer is too big to fit in a 32-bit integer: ", i); + if (!truncate && unlikely((int64_t)i32 != i64)) fail("Integer is too big to fit in a 32-bit integer: ", i); return i32; } MACROLIKE PUREFUNC Int32_t Int32$from_int64(Int64_t i64, bool truncate) { int32_t i32 = (int32_t)i64; - if (!truncate && unlikely((int64_t)i32 != i64)) - fail("Integer is too big to fit in a 32-bit integer: ", i64); + if (!truncate && unlikely((int64_t)i32 != i64)) fail("Integer is too big to fit in a 32-bit integer: ", i64); return i32; } MACROLIKE CONSTFUNC Int32_t Int32$from_int16(Int16_t i) { return (Int32_t)i; } @@ -352,8 +329,7 @@ MACROLIKE CONSTFUNC Int32_t Int32$from_int8(Int8_t i) { return (Int32_t)i; } // Int16 constructors MACROLIKE PUREFUNC Int16_t Int16$from_num(Num_t n, bool truncate) { int16_t i16 = (int16_t)n; - if (!truncate && unlikely((Num_t)i16 != n)) - fail("Could not convert Num to Int16 without truncation: ", n); + if (!truncate && unlikely((Num_t)i16 != n)) fail("Could not convert Num to Int16 without truncation: ", n); return i16; } MACROLIKE PUREFUNC Int16_t Int16$from_num32(Num32_t n, bool truncate) { @@ -365,20 +341,17 @@ MACROLIKE PUREFUNC Int16_t Int16$from_num32(Num32_t n, bool truncate) { MACROLIKE PUREFUNC Int16_t Int16$from_int(Int_t i, bool truncate) { int64_t i64 = Int64$from_int(i, truncate); int16_t i16 = (int16_t)i64; - if (!truncate && unlikely((int64_t)i16 != i64)) - fail("Integer is too big to fit in a 16-bit integer!"); + if (!truncate && unlikely((int64_t)i16 != i64)) fail("Integer is too big to fit in a 16-bit integer!"); return i16; } MACROLIKE PUREFUNC Int16_t Int16$from_int64(Int64_t i64, bool truncate) { int16_t i16 = (int16_t)i64; - if (!truncate && unlikely((int64_t)i16 != i64)) - fail("Integer is too big to fit in a 16-bit integer: ", i64); + if (!truncate && unlikely((int64_t)i16 != i64)) fail("Integer is too big to fit in a 16-bit integer: ", i64); return i16; } MACROLIKE PUREFUNC Int16_t Int16$from_int32(Int32_t i32, bool truncate) { int16_t i16 = (int16_t)i32; - if (!truncate && unlikely((int32_t)i16 != i32)) - fail("Integer is too big to fit in a 16-bit integer: ", i32); + if (!truncate && unlikely((int32_t)i16 != i32)) fail("Integer is too big to fit in a 16-bit integer: ", i32); return i16; } MACROLIKE CONSTFUNC Int16_t Int16$from_int8(Int8_t i) { return (Int16_t)i; } @@ -386,39 +359,33 @@ MACROLIKE CONSTFUNC Int16_t Int16$from_int8(Int8_t i) { return (Int16_t)i; } // Int8 constructors MACROLIKE PUREFUNC Int8_t Int8$from_num(Num_t n, bool truncate) { int8_t i8 = (int8_t)n; - if (!truncate && unlikely((Num_t)i8 != n)) - fail("Could not convert Num to Int8 without truncation: ", n); + if (!truncate && unlikely((Num_t)i8 != n)) fail("Could not convert Num to Int8 without truncation: ", n); return i8; } MACROLIKE PUREFUNC Int8_t Int8$from_num32(Num32_t n, bool truncate) { int8_t i8 = (int8_t)n; - if (!truncate && unlikely((Num32_t)i8 != n)) - fail("Could not convert Num32 to Int8 without truncation: ", n); + if (!truncate && unlikely((Num32_t)i8 != n)) fail("Could not convert Num32 to Int8 without truncation: ", n); return i8; } MACROLIKE PUREFUNC Int8_t Int8$from_int(Int_t i, bool truncate) { int64_t i64 = Int64$from_int(i, truncate); int8_t i8 = (int8_t)i64; - if (!truncate && unlikely((int64_t)i8 != i64)) - fail("Integer is too big to fit in an 8-bit integer!"); + if (!truncate && unlikely((int64_t)i8 != i64)) fail("Integer is too big to fit in an 8-bit integer!"); return i8; } MACROLIKE PUREFUNC Int8_t Int8$from_int64(Int64_t i64, bool truncate) { int8_t i8 = (int8_t)i64; - if (!truncate && unlikely((int64_t)i8 != i64)) - fail("Integer is too big to fit in a 8-bit integer: ", i64); + if (!truncate && unlikely((int64_t)i8 != i64)) fail("Integer is too big to fit in a 8-bit integer: ", i64); return i8; } MACROLIKE PUREFUNC Int8_t Int8$from_int32(Int32_t i32, bool truncate) { int8_t i8 = (int8_t)i32; - if (!truncate && unlikely((int32_t)i8 != i32)) - fail("Integer is too big to fit in a 8-bit integer: ", i32); + if (!truncate && unlikely((int32_t)i8 != i32)) fail("Integer is too big to fit in a 8-bit integer: ", i32); return i8; } MACROLIKE PUREFUNC Int8_t Int8$from_int16(Int16_t i16, bool truncate) { int8_t i8 = (int8_t)i16; - if (!truncate && unlikely((int16_t)i8 != i16)) - fail("Integer is too big to fit in a 8-bit integer: ", i16); + if (!truncate && unlikely((int16_t)i8 != i16)) fail("Integer is too big to fit in a 8-bit integer: ", i16); return i8; } #ifdef __GNUC__ diff --git a/src/stdlib/lists.c b/src/stdlib/lists.c index ce27f822..415e28a5 100644 --- a/src/stdlib/lists.c +++ b/src/stdlib/lists.c @@ -6,8 +6,8 @@ #include <stdint.h> #include <sys/param.h> -#include "lists.h" #include "integers.h" +#include "lists.h" #include "math.h" #include "metamethods.h" #include "optionals.h" @@ -18,39 +18,37 @@ // Use inline version of siphash code: #include "siphash-internals.h" -PUREFUNC static INLINE int64_t get_padded_item_size(const TypeInfo_t *info) -{ +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!"); + if (info->ListInfo.item->align > 1 && size % info->ListInfo.item->align) errx(1, "Item size is not padded!"); return size; } // Replace the list's .data pointer with a new pointer to a copy of the // data that is compacted and has a stride of exactly `padded_item_size` -public void List$compact(List_t *list, int64_t padded_item_size) -{ +public +void List$compact(List_t *list, int64_t padded_item_size) { void *copy = NULL; if (list->length > 0) { copy = list->atomic ? GC_MALLOC_ATOMIC((size_t)list->length * (size_t)padded_item_size) - : GC_MALLOC((size_t)list->length * (size_t)padded_item_size); + : GC_MALLOC((size_t)list->length * (size_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++) - memcpy(copy + i*padded_item_size, list->data + list->stride*i, (size_t)padded_item_size); + memcpy(copy + i * padded_item_size, list->data + list->stride * i, (size_t)padded_item_size); } } *list = (List_t){ - .data=copy, - .length=list->length, - .stride=padded_item_size, - .atomic=list->atomic, + .data = copy, + .length = list->length, + .stride = padded_item_size, + .atomic = list->atomic, }; } -public void List$insert(List_t *list, const void *item, Int_t int_index, 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; @@ -61,42 +59,38 @@ public void List$insert(List_t *list, const void *item, Int_t int_index, int64_t if (!list->data) { list->free = 4; list->data = list->atomic ? GC_MALLOC_ATOMIC((size_t)list->free * (size_t)padded_item_size) - : GC_MALLOC((size_t)list->free * (size_t)padded_item_size); + : GC_MALLOC((size_t)list->free * (size_t)padded_item_size); list->stride = padded_item_size; } else if (list->free < 1 || list->data_refcount != 0 || (int64_t)list->stride != padded_item_size) { // Resize policy: +50% growth (clamped between 8 and LIST_MAX_FREE_ENTRIES) - list->free = MIN(LIST_MAX_FREE_ENTRIES, MAX(8, list->length)/2); + list->free = MIN(LIST_MAX_FREE_ENTRIES, MAX(8, list->length) / 2); void *copy = list->atomic ? GC_MALLOC_ATOMIC((size_t)(list->length + list->free) * (size_t)padded_item_size) - : GC_MALLOC((size_t)(list->length + list->free) * (size_t)padded_item_size); - for (int64_t i = 0; i < index-1; i++) - memcpy(copy + i*padded_item_size, list->data + list->stride*i, (size_t)padded_item_size); - for (int64_t i = index-1; i < (int64_t)list->length; i++) - memcpy(copy + (i+1)*padded_item_size, list->data + list->stride*i, (size_t)padded_item_size); + : GC_MALLOC((size_t)(list->length + list->free) * (size_t)padded_item_size); + for (int64_t i = 0; i < index - 1; i++) + memcpy(copy + i * padded_item_size, list->data + list->stride * i, (size_t)padded_item_size); + for (int64_t i = index - 1; i < (int64_t)list->length; i++) + memcpy(copy + (i + 1) * padded_item_size, list->data + list->stride * i, (size_t)padded_item_size); list->data = copy; list->data_refcount = 0; list->stride = padded_item_size; } else { - if (index != list->length+1) { + if (index != list->length + 1) { assert(list->length >= index); - size_t size = (size_t)((list->length - index + 1)*padded_item_size); + size_t size = (size_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); + memmove(list->data + index * padded_item_size, list->data + (index - 1) * padded_item_size, size); } } assert(list->free > 0); --list->free; ++list->length; - memcpy((void*)list->data + (index-1)*padded_item_size, item, (size_t)padded_item_size); + memcpy((void *)list->data + (index - 1) * padded_item_size, item, (size_t)padded_item_size); } -public void List$insert_all(List_t *list, List_t to_insert, Int_t int_index, int64_t padded_item_size) -{ +public +void List$insert_all(List_t *list, List_t to_insert, Int_t int_index, int64_t padded_item_size) { int64_t index = Int64$from_int(int_index, false); - if (to_insert.length == 0) - return; + if (to_insert.length == 0) return; if (!list->data) { *list = to_insert; @@ -111,34 +105,33 @@ public void List$insert_all(List_t *list, List_t to_insert, Int_t int_index, int fail("Invalid insertion index ", index, " for a list with length ", (int64_t)list->length); if ((int64_t)list->free >= (int64_t)to_insert.length // Adequate free space - && list->data_refcount == 0 // Not aliased memory - && (int64_t)list->stride == padded_item_size) { // Contiguous list + && list->data_refcount == 0 // Not aliased memory + && (int64_t)list->stride == padded_item_size) { // Contiguous list // 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) - 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)); + if (index != 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++) - memcpy((void*)list->data + (index-1 + i)*padded_item_size, - to_insert.data + i*to_insert.stride, (size_t)padded_item_size); + 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; - list->free = MIN(LIST_MAX_FREE_ENTRIES, MAX(8, new_len/4)); + 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)); + : GC_MALLOC((size_t)((new_len + list->free) * padded_item_size)); void *p = data; // Copy first chunk of `list` if needed: if (index > 1) { if (list->stride == padded_item_size) { - memcpy(p, list->data, (size_t)((index-1)*padded_item_size)); - p += (index-1)*padded_item_size; + memcpy(p, list->data, (size_t)((index - 1) * padded_item_size)); + p += (index - 1) * padded_item_size; } else { - for (int64_t i = 0; i < index-1; i++) { - memcpy(p, list->data + list->stride*i, (size_t)padded_item_size); + for (int64_t i = 0; i < index - 1; i++) { + memcpy(p, list->data + list->stride * i, (size_t)padded_item_size); p += padded_item_size; } } @@ -146,11 +139,11 @@ public void List$insert_all(List_t *list, List_t to_insert, Int_t int_index, int // 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)(to_insert.length * padded_item_size)); + p += 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); + for (int64_t i = 0; i < index - 1; i++) { + memcpy(p, to_insert.data + to_insert.stride * i, (size_t)padded_item_size); p += padded_item_size; } } @@ -158,11 +151,12 @@ public void List$insert_all(List_t *list, List_t to_insert, Int_t int_index, int // Copy last chunk of `list` if needed: if (index < 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; + 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; } else { - for (int64_t i = index-1; i < list->length-1; i++) { - memcpy(p, list->data + list->stride*i, (size_t)padded_item_size); + for (int64_t i = index - 1; i < list->length - 1; i++) { + memcpy(p, list->data + list->stride * i, (size_t)padded_item_size); p += padded_item_size; } } @@ -174,27 +168,27 @@ public void List$insert_all(List_t *list, List_t to_insert, Int_t int_index, int } } -public void List$remove_at(List_t *list, Int_t int_index, Int_t int_count, int64_t padded_item_size) -{ +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; 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 > list->length - index + 1) count = (list->length - index) + 1; if (index == 1) { list->data += list->stride * count; } else if (index + count > 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)((list->length - 1) * padded_item_size)) + : GC_MALLOC((size_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), (size_t)padded_item_size); + memcpy(copy + (dest - 1) * padded_item_size, list->data + list->stride * (src - 1), + (size_t)padded_item_size); ++dest; } } @@ -202,26 +196,27 @@ public void List$remove_at(List_t *list, Int_t int_index, Int_t int_count, int64 list->free = 0; list->data_refcount = 0; } 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)); + 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)); list->free += count; } list->length -= count; if (list->length == 0) list->data = NULL; } -public void List$remove_item(List_t *list, void *item, Int_t max_removals, const TypeInfo_t *type) -{ +public +void List$remove_item(List_t *list, void *item, Int_t max_removals, const TypeInfo_t *type) { int64_t padded_item_size = get_padded_item_size(type); - const Int_t ZERO = (Int_t){.small=(0<<2)|1}; - const Int_t ONE = (Int_t){.small=(1<<2)|1}; + 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 < list->length;) { if (max_removals.small == ZERO.small) // zero break; - if (generic_equal(item, list->data + i*list->stride, item_type)) { - List$remove_at(list, I(i+1), ONE, padded_item_size); + if (generic_equal(item, list->data + i * list->stride, item_type)) { + List$remove_at(list, I(i + 1), ONE, padded_item_size); max_removals = Int$minus(max_removals, ONE); } else { i++; @@ -229,45 +224,41 @@ public void List$remove_item(List_t *list, void *item, Int_t max_removals, const } } -public OptionalInt_t List$find(List_t list, void *item, const TypeInfo_t *type) -{ +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++) { - if (generic_equal(item, list.data + i*list.stride, item_type)) - return I(i+1); + if (generic_equal(item, list.data + i * list.stride, item_type)) return I(i + 1); } return NONE_INT; } -public OptionalInt_t List$first(List_t list, Closure_t predicate) -{ - bool (*is_good)(void*, void*) = (void*)predicate.fn; +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++) { - if (is_good(list.data + i*list.stride, predicate.userdata)) - return I(i+1); + if (is_good(list.data + i * list.stride, predicate.userdata)) return I(i + 1); } return NONE_INT; } -static Closure_t _sort_comparison = {.fn=NULL}; +static Closure_t _sort_comparison = {.fn = NULL}; -int _compare_closure(const void *a, const void *b) -{ - typedef int (*comparison_t)(const void*, const void*, void*); +int _compare_closure(const void *a, const void *b) { + typedef int (*comparison_t)(const void *, const void *, void *); return ((comparison_t)_sort_comparison.fn)(a, b, _sort_comparison.userdata); } -public void List$sort(List_t *list, Closure_t comparison, int64_t padded_item_size) -{ - if (list->data_refcount != 0 || (int64_t)list->stride != padded_item_size) - List$compact(list, padded_item_size); +public +void List$sort(List_t *list, Closure_t comparison, int64_t padded_item_size) { + if (list->data_refcount != 0 || (int64_t)list->stride != padded_item_size) List$compact(list, padded_item_size); _sort_comparison = comparison; qsort(list->data, (size_t)list->length, (size_t)padded_item_size, _compare_closure); } -public List_t List$sorted(List_t list, Closure_t comparison, int64_t padded_item_size) -{ +public +List_t List$sorted(List_t list, Closure_t comparison, int64_t padded_item_size) { List$compact(&list, padded_item_size); _sort_comparison = comparison; qsort(list.data, (size_t)list.length, (size_t)padded_item_size, _compare_closure); @@ -283,13 +274,12 @@ static ssize_t getrandom(void *buf, size_t buflen, unsigned int flags) { } #elif defined(__linux__) // Use getrandom() -# include <sys/random.h> +#include <sys/random.h> #else - #error "Unsupported platform for secure random number generation" +#error "Unsupported platform for secure random number generation" #endif -static int64_t _default_random_int64(int64_t min, int64_t max, void *userdata) -{ +static int64_t _default_random_int64(int64_t min, int64_t max, void *userdata) { (void)userdata; if (min > max) fail("Random minimum value (", min, ") is larger than the maximum value (", max, ")"); if (min == max) return min; @@ -303,50 +293,49 @@ static int64_t _default_random_int64(int64_t min, int64_t max, void *userdata) return (int64_t)((uint64_t)min + (r % range)); } -public void List$shuffle(List_t *list, OptionalClosure_t random_int64, int64_t padded_item_size) -{ - if (list->data_refcount != 0 || (int64_t)list->stride != padded_item_size) - List$compact(list, padded_item_size); +public +void List$shuffle(List_t *list, OptionalClosure_t random_int64, int64_t padded_item_size) { + if (list->data_refcount != 0 || (int64_t)list->stride != padded_item_size) List$compact(list, padded_item_size); - typedef int64_t (*rng_fn_t)(int64_t, int64_t, void*); + 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 = 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 > 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); - memcpy((void*)list->data + j*padded_item_size, tmp, (size_t)padded_item_size); + 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); + memcpy((void *)list->data + j * padded_item_size, tmp, (size_t)padded_item_size); } } -public List_t List$shuffled(List_t list, Closure_t random_int64, int64_t padded_item_size) -{ +public +List_t List$shuffled(List_t list, Closure_t random_int64, int64_t padded_item_size) { List$compact(&list, padded_item_size); List$shuffle(&list, random_int64, padded_item_size); return list; } -public void *List$random(List_t list, OptionalClosure_t random_int64) -{ - if (list.length == 0) - return NULL; // fail("Cannot get a random item from an empty list!"); +public +void *List$random(List_t list, OptionalClosure_t random_int64) { + if (list.length == 0) return NULL; // fail("Cannot get a random item from an empty list!"); - typedef int64_t (*rng_fn_t)(int64_t, int64_t, void*); + 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) - 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; + int64_t index = rng_fn(0, list.length - 1, random_int64.userdata); + if unlikely (index < 0 || index > 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; } -public Table_t List$counts(List_t list, const TypeInfo_t *type) -{ +public +Table_t List$counts(List_t list, const TypeInfo_t *type) { Table_t counts = {}; const TypeInfo_t count_type = *Table$info(type->ListInfo.item, &Int$info); for (int64_t i = 0; i < list.length; i++) { - void *key = list.data + i*list.stride; + void *key = list.data + i * list.stride; int64_t *count = Table$get(counts, key, &count_type); int64_t val = count ? *count + 1 : 1; Table$set(&counts, key, &val, &count_type); @@ -354,14 +343,13 @@ public Table_t List$counts(List_t list, const TypeInfo_t *type) return counts; } -static double _default_random_num(void *userdata) -{ +static double _default_random_num(void *userdata) { (void)userdata; union { Num_t num; uint64_t bits; - } r = {.bits=0}, one = {.num=1.0}; - assert(getrandom((uint8_t*)&r, sizeof(r), 0) == sizeof(r)); + } r = {.bits = 0}, one = {.num = 1.0}; + assert(getrandom((uint8_t *)&r, sizeof(r), 0) == sizeof(r)); // Set r.num to 1.<random-bits> r.bits &= ~(0xFFFULL << 52); @@ -369,39 +357,30 @@ static double _default_random_num(void *userdata) return r.num - 1.0; } -public List_t List$sample(List_t list, Int_t int_n, List_t weights, OptionalClosure_t random_num, int64_t padded_item_size) -{ +public +List_t List$sample(List_t list, Int_t int_n, List_t weights, OptionalClosure_t random_num, int64_t padded_item_size) { int64_t n = Int64$from_int(int_n, false); - if (n < 0) - fail("Cannot select a negative number of values"); + if (n < 0) fail("Cannot select a negative number of values"); - if (n == 0) - return (List_t){}; + if (n == 0) return (List_t){}; - if (list.length == 0) - fail("There are no elements in this list!"); + if (list.length == 0) fail("There are no elements in this list!"); if (weights.length != list.length) 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++) { - double weight = *(double*)(weights.data + weights.stride*i); - if (isinf(weight)) - fail("Infinite weight!"); - else if (isnan(weight)) - fail("NaN weight!"); - else if (weight < 0.0) - fail("Negative weight!"); - else - total += weight; + double weight = *(double *)(weights.data + weights.stride * i); + if (isinf(weight)) fail("Infinite weight!"); + else if (isnan(weight)) fail("NaN weight!"); + else if (weight < 0.0) fail("Negative weight!"); + else total += weight; } - if (isinf(total)) - fail("Sample weights have overflowed to infinity"); + if (isinf(total)) fail("Sample weights have overflowed to infinity"); - if (total == 0.0) - fail("None of the given weights are nonzero"); + if (total == 0.0) fail("None of the given weights are nonzero"); double inverse_average = (double)list.length / total; @@ -411,7 +390,7 @@ public List_t List$sample(List_t list, Int_t int_n, List_t weights, OptionalClos } 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); + double weight = i >= weights.length ? 0.0 : *(double *)(weights.data + weights.stride * i); aliases[i].odds = weight * inverse_average; aliases[i].alias = -1; } @@ -435,16 +414,16 @@ public List_t List$sample(List_t list, Int_t int_n, List_t weights, OptionalClos } for (int64_t i = small; i < list.length; i++) - if (aliases[i].alias == -1) - aliases[i].alias = i; + if (aliases[i].alias == -1) aliases[i].alias = i; - typedef double (*rng_fn_t)(void*); + typedef double (*rng_fn_t)(void *); rng_fn_t rng_fn = random_num.fn ? (rng_fn_t)random_num.fn : _default_random_num; - 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, - .stride=padded_item_size, .atomic=list.atomic}; + 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, + .stride = padded_item_size, + .atomic = list.atomic}; for (int64_t i = 0; i < n; i++) { double r = rng_fn(random_num.userdata); if unlikely (r < 0.0 || r >= 1.0) @@ -452,85 +431,77 @@ public List_t List$sample(List_t list, Int_t int_n, List_t weights, OptionalClos r *= (double)list.length; int64_t index = (int64_t)r; assert(index >= 0 && index < 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); + 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); } return selected; } -public List_t List$from(List_t list, Int_t first) -{ - return List$slice(list, first, I_small(-1)); -} +public +List_t List$from(List_t list, Int_t first) { return List$slice(list, first, I_small(-1)); } -public List_t List$to(List_t list, Int_t last) -{ - return List$slice(list, I_small(1), last); -} +public +List_t List$to(List_t list, Int_t last) { return List$slice(list, I_small(1), last); } -public List_t List$by(List_t list, Int_t int_stride, int64_t padded_item_size) -{ +public +List_t List$by(List_t list, Int_t int_stride, int64_t padded_item_size) { int64_t stride = Int64$from_int(int_stride, false); // 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)) { + 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)); + 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); + memcpy(copy + i * padded_item_size, start + list.stride * stride * i, (size_t)padded_item_size); } return (List_t){ - .data=copy, - .length=len, - .stride=padded_item_size, - .atomic=list.atomic, + .data = copy, + .length = len, + .stride = padded_item_size, + .atomic = list.atomic, }; } - if (stride == 0) - return (List_t){.atomic=list.atomic}; + if (stride == 0) return (List_t){.atomic = list.atomic}; 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), - .stride=list.stride * stride, - .data_refcount=list.data_refcount, + .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), + .stride = list.stride * stride, + .data_refcount = list.data_refcount, }; } -public List_t List$slice(List_t list, Int_t int_first, Int_t int_last) +public +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 = 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 = list.length + last + 1; - if (last > list.length) - last = list.length; + if (last > list.length) last = list.length; - if (first < 1 || first > list.length || last == 0) - return (List_t){.atomic=list.atomic}; + if (first < 1 || first > list.length || last == 0) return (List_t){.atomic = list.atomic}; return (List_t){ - .atomic=list.atomic, - .data=list.data + list.stride*(first-1), - .length=last - first + 1, - .stride=list.stride, - .data_refcount=list.data_refcount, + .atomic = list.atomic, + .data = list.data + list.stride * (first - 1), + .length = last - first + 1, + .stride = list.stride, + .data_refcount = list.data_refcount, }; } -public List_t List$reversed(List_t list, int64_t padded_item_size) -{ +public +List_t List$reversed(List_t list, int64_t padded_item_size) { // Just in case negating the stride gives a value that doesn't fit into a // 15-bit integer, fall back to List$by()'s more general method of copying // the list. This should only happen if list.stride is MIN_STRIDE to @@ -540,58 +511,54 @@ public 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 + (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))); +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))); 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 * x.length)); } else { for (int64_t i = 0; i < x.length; i++) - memcpy(data + i*padded_item_size, x.data + i*padded_item_size, (size_t)padded_item_size); + 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 * 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 * y.length)); } else { for (int64_t i = 0; i < y.length; i++) - memcpy(dest + i*padded_item_size, y.data + i*y.stride, (size_t)padded_item_size); + memcpy(dest + i * padded_item_size, y.data + i * y.stride, (size_t)padded_item_size); } return (List_t){ - .data=data, - .length=x.length + y.length, - .stride=padded_item_size, - .atomic=x.atomic, + .data = data, + .length = x.length + y.length, + .stride = padded_item_size, + .atomic = x.atomic, }; } -public bool List$has(List_t list, void *item, const TypeInfo_t *type) -{ +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++) { - if (generic_equal(list.data + i*list.stride, item, item_type)) - return true; + 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}; -} +public +void List$clear(List_t *list) { *list = (List_t){.data = 0, .length = 0}; } -public int32_t List$compare(const void *vx, const void *vy, const TypeInfo_t *type) -{ - const List_t *x = (List_t*)vx, *y = (List_t*)vy; +public +int32_t List$compare(const void *vx, const void *vy, const TypeInfo_t *type) { + const List_t *x = (List_t *)vx, *y = (List_t *)vy; // Early out for lists with the same data, e.g. two copies of the same list: - if (x->data == y->data && x->stride == y->stride) - return (x->length > y->length) - (x->length < y->length); + if (x->data == y->data && x->stride == y->stride) return (x->length > y->length) - (x->length < y->length); const TypeInfo_t *item = type->ListInfo.item; if (item->tag == PointerInfo || !item->metamethods.compare) { // data comparison @@ -599,128 +566,120 @@ public int32_t List$compare(const void *vx, const void *vy, const TypeInfo_t *ty if (type->ListInfo.item->align > 1 && item_padded_size % type->ListInfo.item->align) errx(1, "Item size is not padded!"); - 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)); + 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)); if (cmp != 0) return cmp; } else { for (int32_t i = 0, len = MIN(x->length, y->length); i < len; i++) { - int32_t cmp = (int32_t)memcmp(x->data+ x->stride*i, y->data + y->stride*i, (size_t)(item->size)); + int32_t cmp = (int32_t)memcmp(x->data + x->stride * i, y->data + y->stride * i, (size_t)(item->size)); if (cmp != 0) return cmp; } } } else { for (int32_t i = 0, len = MIN(x->length, y->length); i < len; i++) { - int32_t cmp = generic_compare(x->data + x->stride*i, y->data + y->stride*i, item); + int32_t cmp = generic_compare(x->data + x->stride * i, y->data + y->stride * i, item); if (cmp != 0) return cmp; } } return (x->length > y->length) - (x->length < y->length); } -public bool List$equal(const void *x, const void *y, const TypeInfo_t *type) -{ - return x == y || (((List_t*)x)->length == ((List_t*)y)->length && List$compare(x, y, type) == 0); +public +bool List$equal(const void *x, const void *y, const TypeInfo_t *type) { + return x == y || (((List_t *)x)->length == ((List_t *)y)->length && List$compare(x, y, type) == 0); } -public Text_t List$as_text(const void *obj, bool colorize, const TypeInfo_t *type) -{ - List_t *list = (List_t*)obj; - if (!list) - return Text$concat(Text("["), generic_as_text(NULL, false, type->ListInfo.item), Text("]")); +public +Text_t List$as_text(const void *obj, bool colorize, const TypeInfo_t *type) { + List_t *list = (List_t *)obj; + if (!list) return Text$concat(Text("["), generic_as_text(NULL, false, type->ListInfo.item), Text("]")); const TypeInfo_t *item_type = type->ListInfo.item; Text_t text = Text("["); for (int64_t i = 0; i < 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); + 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); } text = Text$concat(text, Text("]")); return text; } -public uint64_t List$hash(const void *obj, const TypeInfo_t *type) -{ - const List_t *list = (List_t*)obj; +public +uint64_t List$hash(const void *obj, const TypeInfo_t *type) { + const List_t *list = (List_t *)obj; const TypeInfo_t *item = type->ListInfo.item; siphash sh; siphashinit(&sh, sizeof(uint64_t[list->length])); - if (item->tag == PointerInfo || (!item->metamethods.hash && item->size == sizeof(void*))) { // Raw data hash + if (item->tag == PointerInfo || (!item->metamethods.hash && item->size == sizeof(void *))) { // Raw data hash for (int64_t i = 0; i < list->length; i++) - siphashadd64bits(&sh, (uint64_t)(list->data + i*list->stride)); + siphashadd64bits(&sh, (uint64_t)(list->data + i * list->stride)); } else { for (int64_t i = 0; i < list->length; i++) { - uint64_t item_hash = generic_hash(list->data + i*list->stride, item); + uint64_t item_hash = generic_hash(list->data + i * list->stride, item); siphashadd64bits(&sh, item_hash); } } return siphashfinish_last_part(&sh, 0); } -static void siftdown(List_t *heap, int64_t startpos, int64_t pos, Closure_t comparison, int64_t padded_item_size) -{ +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); char newitem[padded_item_size]; - memcpy(newitem, heap->data + heap->stride*pos, (size_t)(padded_item_size)); + memcpy(newitem, heap->data + heap->stride * pos, (size_t)(padded_item_size)); while (pos > startpos) { int64_t parentpos = (pos - 1) >> 1; - typedef int32_t (*cmp_fn_t)(void*, void*, void*); - int32_t cmp = ((cmp_fn_t)comparison.fn)(newitem, heap->data + heap->stride*parentpos, comparison.userdata); - if (cmp >= 0) - break; + typedef int32_t (*cmp_fn_t)(void *, void *, void *); + int32_t cmp = ((cmp_fn_t)comparison.fn)(newitem, heap->data + heap->stride * parentpos, comparison.userdata); + if (cmp >= 0) break; - memcpy(heap->data + heap->stride*pos, heap->data + heap->stride*parentpos, (size_t)(padded_item_size)); + memcpy(heap->data + heap->stride * pos, heap->data + heap->stride * parentpos, (size_t)(padded_item_size)); pos = parentpos; } - memcpy(heap->data + heap->stride*pos, newitem, (size_t)(padded_item_size)); + memcpy(heap->data + heap->stride * pos, newitem, (size_t)(padded_item_size)); } -static void siftup(List_t *heap, int64_t pos, Closure_t comparison, int64_t padded_item_size) -{ +static void siftup(List_t *heap, int64_t pos, Closure_t comparison, int64_t padded_item_size) { int64_t endpos = heap->length; int64_t startpos = pos; assert(pos < endpos); char old_top[padded_item_size]; - memcpy(old_top, heap->data + heap->stride*pos, (size_t)(padded_item_size)); + memcpy(old_top, heap->data + heap->stride * pos, (size_t)(padded_item_size)); // Bubble up the smallest leaf node int64_t limit = endpos >> 1; while (pos < limit) { - int64_t childpos = 2*pos + 1; // Smaller of the two child nodes + int64_t childpos = 2 * pos + 1; // Smaller of the two child nodes if (childpos + 1 < endpos) { - typedef int32_t (*cmp_fn_t)(void*, void*, void*); - int32_t cmp = ((cmp_fn_t)comparison.fn)( - heap->data + heap->stride*childpos, - heap->data + heap->stride*(childpos + 1), - comparison.userdata); + typedef int32_t (*cmp_fn_t)(void *, void *, void *); + int32_t cmp = ((cmp_fn_t)comparison.fn)(heap->data + heap->stride * childpos, + heap->data + heap->stride * (childpos + 1), comparison.userdata); childpos += (cmp >= 0); } // Move the child node up: - memcpy(heap->data + heap->stride*pos, heap->data + heap->stride*childpos, (size_t)(padded_item_size)); + memcpy(heap->data + heap->stride * pos, heap->data + heap->stride * childpos, (size_t)(padded_item_size)); pos = childpos; } - memcpy(heap->data + heap->stride*pos, old_top, (size_t)(padded_item_size)); + memcpy(heap->data + heap->stride * pos, old_top, (size_t)(padded_item_size)); // Shift the node's parents down: siftdown(heap, startpos, pos, comparison, padded_item_size); } -public void List$heap_push(List_t *heap, const void *item, Closure_t comparison, int64_t padded_item_size) -{ +public +void List$heap_push(List_t *heap, const void *item, Closure_t comparison, int64_t padded_item_size) { List$insert(heap, item, I(0), padded_item_size); 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); + if (heap->data_refcount != 0) List$compact(heap, padded_item_size); + siftdown(heap, 0, heap->length - 1, comparison, padded_item_size); } } -public 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"); +public +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){}; @@ -728,96 +687,90 @@ public void List$heap_pop(List_t *heap, Closure_t comparison, int64_t padded_ite 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)); + 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)); --heap->length; siftup(heap, 0, comparison, padded_item_size); } } -public void List$heapify(List_t *heap, Closure_t comparison, int64_t padded_item_size) -{ - if (heap->data_refcount != 0) - List$compact(heap, padded_item_size); +public +void List$heapify(List_t *heap, Closure_t comparison, int64_t padded_item_size) { + if (heap->data_refcount != 0) List$compact(heap, 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; - for (i = (n >> 1) - 1 ; i >= 0 ; i--) + for (i = (n >> 1) - 1; i >= 0; i--) siftup(heap, i, comparison, padded_item_size); LIST_DECREF(*heap); } -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; +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; 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); - if (cmp == 0) - return I(mid+1); - else if (cmp < 0) - lo = mid + 1; - else if (cmp > 0) - hi = mid - 1; + int32_t cmp = ((cmp_fn_t)comparison.fn)(list.data + list.stride * mid, target, comparison.userdata); + if (cmp == 0) return I(mid + 1); + else if (cmp < 0) lo = mid + 1; + else if (cmp > 0) hi = mid - 1; } - return I(lo+1); // Return the index where the target would be inserted + return I(lo + 1); // Return the index where the target would be inserted } -public PUREFUNC bool List$is_none(const void *obj, const TypeInfo_t *info) -{ +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)->length < 0; } -public void List$serialize(const void *obj, FILE *out, Table_t *pointers, const TypeInfo_t *type) -{ - List_t list = *(List_t*)obj; +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$serialize(&len, out, pointers, &Int64$info); serialize_fn_t item_serialize = type->ListInfo.item->metamethods.serialize; if (item_serialize) { for (int64_t i = 0; i < len; i++) - item_serialize(list.data + i*list.stride, out, pointers, type->ListInfo.item); + item_serialize(list.data + i * list.stride, out, pointers, type->ListInfo.item); } else if (list.stride == type->ListInfo.item->size) { fwrite(list.data, (size_t)type->ListInfo.item->size, (size_t)len, out); } else { for (int64_t i = 0; i < len; i++) - fwrite(list.data + i*list.stride, (size_t)type->ListInfo.item->size, 1, out); + fwrite(list.data + i * list.stride, (size_t)type->ListInfo.item->size, 1, out); } } -public void List$deserialize(FILE *in, void *obj, List_t *pointers, const TypeInfo_t *type) -{ +public +void List$deserialize(FILE *in, void *obj, List_t *pointers, const TypeInfo_t *type) { int64_t len = -1; Int64$deserialize(in, &len, pointers, &Int64$info); int64_t padded_size = type->ListInfo.item->size; 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, - .data=GC_MALLOC((size_t)(len*padded_size)), - .stride=padded_size, + .length = len, + .data = GC_MALLOC((size_t)(len * padded_size)), + .stride = padded_size, }; deserialize_fn_t item_deserialize = type->ListInfo.item->metamethods.deserialize; if (item_deserialize) { for (int64_t i = 0; i < len; i++) - item_deserialize(in, list.data + i*list.stride, pointers, type->ListInfo.item); + item_deserialize(in, list.data + i * list.stride, pointers, type->ListInfo.item); } else if (list.stride == type->ListInfo.item->size) { if (fread(list.data, (size_t)type->ListInfo.item->size, (size_t)len, in) != (size_t)len) fail("Not enough data in stream to deserialize"); } else { size_t item_size = (size_t)type->ListInfo.item->size; for (int64_t i = 0; i < len; i++) { - if (fread(list.data + i*list.stride, item_size, 1, in) != 1) + if (fread(list.data + i * list.stride, item_size, 1, in) != 1) fail("Not enough data in stream to deserialize"); } } - *(List_t*)obj = list; + *(List_t *)obj = list; } // vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0 diff --git a/src/stdlib/lists.h b/src/stdlib/lists.h index a2853e48..afda3d74 100644 --- a/src/stdlib/lists.h +++ b/src/stdlib/lists.h @@ -10,88 +10,141 @@ #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; 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);}) -#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_lvalue(item_type, arr_expr, index_expr, start, end) *({ \ - List_t *list = arr_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"); \ - 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 is_atomic(x) _Generic(x, bool: true, int8_t: true, int16_t: true, int32_t: true, int64_t: true, float: true, double: true, default: false) -#define TypedList(t, ...) ({ t items[] = {__VA_ARGS__}; \ - (List_t){.length=sizeof(items)/sizeof(items[0]), \ - .stride=(int64_t)&items[1] - (int64_t)&items[0], \ - .data=memcpy(GC_MALLOC(sizeof(items)), items, sizeof(items)), \ - .atomic=0, \ - .data_refcount=0}; }) -#define TypedListN(t, N, ...) ({ t items[N] = {__VA_ARGS__}; \ - (List_t){.length=N, \ - .stride=(int64_t)&items[1] - (int64_t)&items[0], \ - .data=memcpy(GC_MALLOC(sizeof(items)), items, sizeof(items)), \ - .atomic=0, \ - .data_refcount=0}; }) -#define List(x, ...) ({ __typeof(x) items[] = {x, __VA_ARGS__}; \ - (List_t){.length=sizeof(items)/sizeof(items[0]), \ - .stride=(int64_t)&items[1] - (int64_t)&items[0], \ - .data=memcpy(is_atomic(x) ? GC_MALLOC_ATOMIC(sizeof(items)) : GC_MALLOC(sizeof(items)), items, sizeof(items)), \ - .atomic=is_atomic(x), \ - .data_refcount=0}; }) +#define List_get(item_type, arr_expr, index_expr, start, end) \ + *({ \ + const List_t list = arr_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); \ + }) +#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_lvalue(item_type, arr_expr, index_expr, start, end) \ + *({ \ + List_t *list = arr_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"); \ + 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 is_atomic(x) \ + _Generic(x, \ + bool: true, \ + int8_t: true, \ + int16_t: true, \ + int32_t: true, \ + int64_t: true, \ + float: true, \ + double: true, \ + default: false) +#define TypedList(t, ...) \ + ({ \ + t items[] = {__VA_ARGS__}; \ + (List_t){.length = sizeof(items) / sizeof(items[0]), \ + .stride = (int64_t)&items[1] - (int64_t)&items[0], \ + .data = memcpy(GC_MALLOC(sizeof(items)), items, sizeof(items)), \ + .atomic = 0, \ + .data_refcount = 0}; \ + }) +#define TypedListN(t, N, ...) \ + ({ \ + t items[N] = {__VA_ARGS__}; \ + (List_t){.length = N, \ + .stride = (int64_t)&items[1] - (int64_t)&items[0], \ + .data = memcpy(GC_MALLOC(sizeof(items)), items, sizeof(items)), \ + .atomic = 0, \ + .data_refcount = 0}; \ + }) +#define List(x, ...) \ + ({ \ + __typeof(x) items[] = {x, __VA_ARGS__}; \ + (List_t){.length = sizeof(items) / sizeof(items[0]), \ + .stride = (int64_t)&items[1] - (int64_t)&items[0], \ + .data = memcpy(is_atomic(x) ? GC_MALLOC_ATOMIC(sizeof(items)) : GC_MALLOC(sizeof(items)), items, \ + sizeof(items)), \ + .atomic = is_atomic(x), \ + .data_refcount = 0}; \ + }) // List refcounts use a saturating add, where once it's at the max value, it stays there. #define LIST_INCREF(list) (list).data_refcount += ((list).data_refcount < LIST_MAX_DATA_REFCOUNT) #define LIST_DECREF(list) (list).data_refcount -= ((list).data_refcount < LIST_MAX_DATA_REFCOUNT) -#define LIST_COPY(list) ({ LIST_INCREF(list); list; }) +#define LIST_COPY(list) \ + ({ \ + LIST_INCREF(list); \ + list; \ + }) -#define List$insert_value(list, item_expr, index, padded_item_size) List$insert(list, (__typeof(item_expr)[1]){item_expr}, index, padded_item_size) +#define List$insert_value(list, item_expr, index, padded_item_size) \ + List$insert(list, (__typeof(item_expr)[1]){item_expr}, index, padded_item_size) void List$insert(List_t *list, const void *item, Int_t index, int64_t padded_item_size); void List$insert_all(List_t *list, List_t to_insert, Int_t index, int64_t padded_item_size); void List$remove_at(List_t *list, Int_t index, Int_t count, int64_t padded_item_size); void List$remove_item(List_t *list, void *item, Int_t max_removals, const TypeInfo_t *type); -#define List$remove_item_value(list, item_expr, max, type) List$remove_item(list, (__typeof(item_expr)[1]){item_expr}, max, type) +#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) ({ \ - List_t *list = arr_expr; \ - Int_t index = index_expr; \ - int64_t index64 = Int64$from_int(index, false); \ - int64_t off = index64 + (index64 < 0) * (list->length + 1) - 1; \ - (off >= 0 && off < list->length) ? ({ \ - item_type nonnone_var = *(item_type*)(list->data + off*list->stride); \ - List$remove_at(list, index, I_small(1), sizeof(item_type)); \ - nonnone_expr; \ - }) : none_expr; }) +#define List$pop(arr_expr, index_expr, item_type, nonnone_var, nonnone_expr, none_expr) \ + ({ \ + List_t *list = arr_expr; \ + Int_t index = index_expr; \ + int64_t index64 = Int64$from_int(index, false); \ + int64_t off = index64 + (index64 < 0) * (list->length + 1) - 1; \ + (off >= 0 && off < list->length) ? ({ \ + item_type nonnone_var = *(item_type *)(list->data + off * list->stride); \ + List$remove_at(list, index, I_small(1), sizeof(item_type)); \ + nonnone_expr; \ + }) \ + : none_expr; \ + }) OptionalInt_t List$find(List_t list, void *item, const TypeInfo_t *type); -#define List$find_value(list, item_expr, type) ({ __typeof(item_expr) item = item_expr; List$find(list, &item, type); }) +#define List$find_value(list, item_expr, type) \ + ({ \ + __typeof(item_expr) item = item_expr; \ + List$find(list, &item, type); \ + }) OptionalInt_t List$first(List_t list, Closure_t predicate); void List$sort(List_t *list, Closure_t comparison, int64_t padded_item_size); List_t List$sorted(List_t list, Closure_t comparison, int64_t padded_item_size); void List$shuffle(List_t *list, OptionalClosure_t random_int64, int64_t padded_item_size); List_t List$shuffled(List_t list, OptionalClosure_t random_int64, int64_t padded_item_size); 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); }) +#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$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); void List$clear(List_t *list); void List$compact(List_t *list, int64_t padded_item_size); PUREFUNC bool List$has(List_t list, void *item, const TypeInfo_t *type); -#define List$has_value(list, item_expr, type) ({ __typeof(item_expr) item = item_expr; List$has(list, &item, type); }) +#define List$has_value(list, item_expr, type) \ + ({ \ + __typeof(item_expr) item = item_expr; \ + List$has(list, &item, type); \ + }) PUREFUNC List_t List$from(List_t list, Int_t first); PUREFUNC List_t List$to(List_t list, Int_t last); PUREFUNC List_t List$by(List_t list, Int_t stride, int64_t padded_item_size); @@ -101,37 +154,51 @@ List_t List$concat(List_t x, List_t y, int64_t padded_item_size); PUREFUNC uint64_t List$hash(const void *list, const TypeInfo_t *type); PUREFUNC int32_t List$compare(const void *x, const void *y, const TypeInfo_t *type); PUREFUNC bool List$equal(const void *x, const void *y, const TypeInfo_t *type); -PUREFUNC bool List$is_none(const void *obj, const TypeInfo_t*); +PUREFUNC bool List$is_none(const void *obj, const TypeInfo_t *); Text_t List$as_text(const void *list, bool colorize, const TypeInfo_t *type); void List$heapify(List_t *heap, Closure_t comparison, int64_t padded_item_size); void List$heap_push(List_t *heap, const void *item, Closure_t comparison, int64_t padded_item_size); -#define List$heap_push_value(heap, _value, comparison, padded_item_size) ({ __typeof(_value) value = _value; List$heap_push(heap, &value, comparison, padded_item_size); }) +#define List$heap_push_value(heap, _value, comparison, padded_item_size) \ + ({ \ + __typeof(_value) value = _value; \ + List$heap_push(heap, &value, comparison, padded_item_size); \ + }) void List$heap_pop(List_t *heap, Closure_t comparison, int64_t padded_item_size); -#define List$heap_pop_value(heap, comparison, type, nonnone_var, nonnone_expr, none_expr) \ - ({ List_t *_heap = heap; \ - (_heap->length > 0) ? ({ \ - type nonnone_var = *(type*)_heap->data; \ - List$heap_pop(_heap, comparison, sizeof(type)); \ - nonnone_expr; \ - }) : none_expr; }) +#define List$heap_pop_value(heap, comparison, type, nonnone_var, nonnone_expr, none_expr) \ + ({ \ + List_t *_heap = heap; \ + (_heap->length > 0) ? ({ \ + type nonnone_var = *(type *)_heap->data; \ + List$heap_pop(_heap, comparison, sizeof(type)); \ + nonnone_expr; \ + }) \ + : none_expr; \ + }) Int_t List$binary_search(List_t list, void *target, Closure_t comparison); -#define List$binary_search_value(list, target, comparison) \ - ({ __typeof(target) _target = target; List$binary_search(list, &_target, comparison); }) +#define List$binary_search_value(list, target, comparison) \ + ({ \ + __typeof(target) _target = target; \ + List$binary_search(list, &_target, comparison); \ + }) void List$serialize(const void *obj, FILE *out, Table_t *pointers, const TypeInfo_t *type); void List$deserialize(FILE *in, void *obj, List_t *pointers, const TypeInfo_t *type); -#define List$metamethods { \ - .as_text=List$as_text, \ - .compare=List$compare, \ - .equal=List$equal, \ - .hash=List$hash, \ - .is_none=List$is_none, \ - .serialize=List$serialize, \ - .deserialize=List$deserialize, \ -} +#define List$metamethods \ + { \ + .as_text = List$as_text, \ + .compare = List$compare, \ + .equal = List$equal, \ + .hash = List$hash, \ + .is_none = List$is_none, \ + .serialize = List$serialize, \ + .deserialize = List$deserialize, \ + } -#define List$info(item_info) &((TypeInfo_t){.size=sizeof(List_t), .align=__alignof__(List_t), \ - .tag=ListInfo, .ListInfo.item=item_info, \ - .metamethods=List$metamethods}) +#define List$info(item_info) \ + &((TypeInfo_t){.size = sizeof(List_t), \ + .align = __alignof__(List_t), \ + .tag = ListInfo, \ + .ListInfo.item = item_info, \ + .metamethods = List$metamethods}) // vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0 diff --git a/src/stdlib/mapmacro.h b/src/stdlib/mapmacro.h index 5ed7a4b7..68834f8f 100644 --- a/src/stdlib/mapmacro.h +++ b/src/stdlib/mapmacro.h @@ -9,7 +9,7 @@ #define EVAL2(...) EVAL1(EVAL1(EVAL1(__VA_ARGS__))) #define EVAL3(...) EVAL2(EVAL2(EVAL2(__VA_ARGS__))) #define EVAL4(...) EVAL3(EVAL3(EVAL3(__VA_ARGS__))) -#define EVAL(...) EVAL4(EVAL4(EVAL4(__VA_ARGS__))) +#define EVAL(...) EVAL4(EVAL4(EVAL4(__VA_ARGS__))) #define MAP_END(...) #define MAP_OUT @@ -21,7 +21,7 @@ #define MAP_NEXT0(test, next, ...) next MAP_OUT #define MAP_LIST_NEXT1(test, next) MAP_NEXT0(test, MAP_COMMA next, 0) -#define MAP_LIST_NEXT(test, next) MAP_LIST_NEXT1(MAP_GET_END test, next) +#define MAP_LIST_NEXT(test, next) MAP_LIST_NEXT1(MAP_GET_END test, next) #define MAP_LIST0(f, x, peek, ...) f(x) MAP_LIST_NEXT(peek, MAP_LIST1)(f, peek, __VA_ARGS__) #define MAP_LIST1(f, x, peek, ...) f(x) MAP_LIST_NEXT(peek, MAP_LIST0)(f, peek, __VA_ARGS__) diff --git a/src/stdlib/memory.c b/src/stdlib/memory.c index a28b0069..90e14261 100644 --- a/src/stdlib/memory.c +++ b/src/stdlib/memory.c @@ -1,9 +1,9 @@ // Type info and methods for "Memory" opaque type +#include <err.h> #include <gc.h> #include <stdbool.h> #include <stdint.h> #include <sys/param.h> -#include <err.h> #include "memory.h" #include "metamethods.h" @@ -12,21 +12,24 @@ #include "types.h" #include "util.h" -public Text_t Memory$as_text(const void *p, bool colorize, const TypeInfo_t *info) { +public +Text_t Memory$as_text(const void *p, bool colorize, const TypeInfo_t *info) { (void)info; if (!p) return Text("Memory"); - Text_t text = Text$from_str(String("Memory<", *(void**)p, ">")); + Text_t text = Text$from_str(String("Memory<", *(void **)p, ">")); return colorize ? Texts(Text("\x1b[0;34;1m"), text, Text("\x1b[m")) : text; } -public const TypeInfo_t Memory$info = { - .size=0, - .align=0, - .metamethods={ - .as_text=Memory$as_text, - .serialize=cannot_serialize, - .deserialize=cannot_deserialize, - }, +public +const TypeInfo_t Memory$info = { + .size = 0, + .align = 0, + .metamethods = + { + .as_text = Memory$as_text, + .serialize = cannot_serialize, + .deserialize = cannot_deserialize, + }, }; // vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0 diff --git a/src/stdlib/metamethods.c b/src/stdlib/metamethods.c index 8c755c59..ea06d20b 100644 --- a/src/stdlib/metamethods.c +++ b/src/stdlib/metamethods.c @@ -9,52 +9,44 @@ #include "types.h" #include "util.h" -PUREFUNC public uint64_t generic_hash(const void *obj, const TypeInfo_t *type) -{ - if (type->metamethods.hash) - return type->metamethods.hash(obj, type); +PUREFUNC public uint64_t generic_hash(const void *obj, const TypeInfo_t *type) { + if (type->metamethods.hash) return type->metamethods.hash(obj, type); - return siphash24((void*)obj, (size_t)(type->size)); + return siphash24((void *)obj, (size_t)(type->size)); } -PUREFUNC public int32_t generic_compare(const void *x, const void *y, const TypeInfo_t *type) -{ +PUREFUNC public int32_t generic_compare(const void *x, const void *y, const TypeInfo_t *type) { if (x == y) return 0; - if (type->metamethods.compare) - return type->metamethods.compare(x, y, type); + if (type->metamethods.compare) return type->metamethods.compare(x, y, type); - return (int32_t)memcmp((void*)x, (void*)y, (size_t)(type->size)); + return (int32_t)memcmp((void *)x, (void *)y, (size_t)(type->size)); } -PUREFUNC public bool generic_equal(const void *x, const void *y, const TypeInfo_t *type) -{ +PUREFUNC public bool generic_equal(const void *x, const void *y, const TypeInfo_t *type) { if (x == y) return true; - if (type->metamethods.equal) - return type->metamethods.equal(x, y, type); + if (type->metamethods.equal) return type->metamethods.equal(x, y, type); return (generic_compare(x, y, type) == 0); } -public Text_t generic_as_text(const void *obj, bool colorize, const TypeInfo_t *type) -{ - if (!type->metamethods.as_text) - fail("No text metamethod provided for type!"); +public +Text_t generic_as_text(const void *obj, bool colorize, const TypeInfo_t *type) { + if (!type->metamethods.as_text) fail("No text metamethod provided for type!"); return type->metamethods.as_text(obj, colorize, type); } -public void _serialize(const void *obj, FILE *out, Table_t *pointers, const TypeInfo_t *type) -{ - if (type->metamethods.serialize) - return type->metamethods.serialize(obj, out, pointers, type); +public +void _serialize(const void *obj, FILE *out, Table_t *pointers, const TypeInfo_t *type) { + if (type->metamethods.serialize) return type->metamethods.serialize(obj, out, pointers, type); fwrite(obj, (size_t)type->size, 1, out); } -public List_t generic_serialize(const void *x, const TypeInfo_t *type) -{ +public +List_t generic_serialize(const void *x, const TypeInfo_t *type) { char *buf = NULL; size_t size = 0; FILE *stream = open_memstream(&buf, &size); @@ -62,31 +54,29 @@ public List_t generic_serialize(const void *x, const TypeInfo_t *type) _serialize(x, stream, &pointers, type); fclose(stream); List_t bytes = { - .data=GC_MALLOC_ATOMIC(size), - .length=(int64_t)size, - .stride=1, - .atomic=1, + .data = GC_MALLOC_ATOMIC(size), + .length = (int64_t)size, + .stride = 1, + .atomic = 1, }; memcpy(bytes.data, buf, size); free(buf); return bytes; } -public void _deserialize(FILE *input, void *outval, List_t *pointers, const TypeInfo_t *type) -{ +public +void _deserialize(FILE *input, void *outval, List_t *pointers, const TypeInfo_t *type) { if (type->metamethods.deserialize) { type->metamethods.deserialize(input, outval, pointers, type); return; } - if (fread(outval, (size_t)type->size, 1, input) != 1) - fail("Not enough data in stream to deserialize"); + if (fread(outval, (size_t)type->size, 1, input) != 1) fail("Not enough data in stream to deserialize"); } -public void generic_deserialize(List_t bytes, void *outval, const TypeInfo_t *type) -{ - if (bytes.stride != 1) - List$compact(&bytes, 1); +public +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 = {}; @@ -94,23 +84,21 @@ public void generic_deserialize(List_t bytes, void *outval, const TypeInfo_t *ty fclose(input); } -public int generic_print(const void *obj, bool colorize, const TypeInfo_t *type) -{ +public +int generic_print(const void *obj, bool colorize, const TypeInfo_t *type) { Text_t text = generic_as_text(obj, colorize, type); return Text$print(stdout, text) + fputc('\n', stdout); } -__attribute__((noreturn)) -public void cannot_serialize(const void *obj, FILE *out, Table_t *pointers, const TypeInfo_t *type) -{ +__attribute__((noreturn)) public +void cannot_serialize(const void *obj, FILE *out, Table_t *pointers, const TypeInfo_t *type) { (void)obj, (void)out, (void)pointers; Text_t typestr = generic_as_text(NULL, false, type); fail("Values of type ", typestr, " cannot be serialized or deserialized!"); } -__attribute__((noreturn)) -public void cannot_deserialize(FILE *in, void *obj, List_t *pointers, const TypeInfo_t *type) -{ +__attribute__((noreturn)) public +void cannot_deserialize(FILE *in, void *obj, List_t *pointers, const TypeInfo_t *type) { (void)obj, (void)in, (void)pointers; Text_t typestr = generic_as_text(NULL, false, type); fail("Values of type ", typestr, " cannot be serialized or deserialized!"); diff --git a/src/stdlib/metamethods.h b/src/stdlib/metamethods.h index ca0a1e7e..eda2230e 100644 --- a/src/stdlib/metamethods.h +++ b/src/stdlib/metamethods.h @@ -16,7 +16,7 @@ List_t generic_serialize(const void *x, const TypeInfo_t *type); void _deserialize(FILE *input, void *outval, List_t *pointers, const TypeInfo_t *type); void generic_deserialize(List_t bytes, void *outval, const TypeInfo_t *type); int generic_print(const void *obj, bool colorize, const TypeInfo_t *type); -void cannot_serialize(const void*, FILE*, Table_t*, const TypeInfo_t *type); -void cannot_deserialize(FILE*, void*, List_t*, const TypeInfo_t *type); +void cannot_serialize(const void *, FILE *, Table_t *, const TypeInfo_t *type); +void cannot_deserialize(FILE *, void *, List_t *, const TypeInfo_t *type); // vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0 diff --git a/src/stdlib/nums.c b/src/stdlib/nums.c index 83166659..05ed14a8 100644 --- a/src/stdlib/nums.c +++ b/src/stdlib/nums.c @@ -13,20 +13,21 @@ #include "text.h" #include "types.h" -public PUREFUNC Text_t Num$as_text(const void *f, bool colorize, const TypeInfo_t *info) { +public +PUREFUNC Text_t Num$as_text(const void *f, bool colorize, const TypeInfo_t *info) { (void)info; if (!f) return Text("Num"); char *str = GC_MALLOC_ATOMIC(24); - int len = fpconv_dtoa(*(double*)f, str); + int len = fpconv_dtoa(*(double *)f, str); static const Text_t color_prefix = Text("\x1b[35m"), color_suffix = Text("\x1b[m"); Text_t text = Text$from_strn(str, (size_t)len); return colorize ? Texts(color_prefix, text, color_suffix) : text; -} +} -public PUREFUNC int32_t Num$compare(const void *x, const void *y, const TypeInfo_t *info) { +public +PUREFUNC int32_t Num$compare(const void *x, const void *y, const TypeInfo_t *info) { (void)info; - int64_t rx = *(int64_t*)x, - ry = *(int64_t*)y; + int64_t rx = *(int64_t *)x, ry = *(int64_t *)y; if (rx == ry) return 0; @@ -34,14 +35,16 @@ public PUREFUNC int32_t Num$compare(const void *x, const void *y, const TypeInfo if (ry < 0) ry ^= INT64_MAX; return (rx > ry) - (rx < ry); -} +} -public PUREFUNC bool Num$equal(const void *x, const void *y, const TypeInfo_t *info) { +public +PUREFUNC bool Num$equal(const void *x, const void *y, const TypeInfo_t *info) { (void)info; - return *(double*)x == *(double*)y; -} + return *(double *)x == *(double *)y; +} -public CONSTFUNC bool Num$near(double a, double b, double ratio, double absolute) { +public +CONSTFUNC bool Num$near(double a, double b, double ratio, double absolute) { if (ratio < 0) ratio = 0; else if (ratio > 1) ratio = 1; @@ -56,17 +59,19 @@ public CONSTFUNC bool Num$near(double a, double b, double ratio, double absolute return (diff < epsilon); } -public Text_t Num$percent(double f, double precision) { +public +Text_t Num$percent(double f, double precision) { double d = 100. * f; d = Num$with_precision(d, precision); return Texts(Num$as_text(&d, false, &Num$info), Text("%")); } -public CONSTFUNC double Num$with_precision(double num, double precision) { +public +CONSTFUNC double Num$with_precision(double num, double precision) { if (precision == 0.0) return num; // Precision will be, e.g. 0.01 or 100. if (precision < 1.) { - double inv = round(1./precision); // Necessary to make the math work + double inv = round(1. / precision); // Necessary to make the math work double k = num * inv; return round(k) / inv; } else { @@ -75,37 +80,34 @@ public CONSTFUNC double Num$with_precision(double num, double precision) { } } -public CONSTFUNC double Num$mod(double num, double modulus) { - // Euclidean division, see: https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/divmodnote-letter.pdf +public +CONSTFUNC double Num$mod(double num, double modulus) { + // Euclidean division, see: + // https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/divmodnote-letter.pdf double r = remainder(num, modulus); - r -= (r < 0) * (2*(modulus < 0) - 1) * modulus; + r -= (r < 0) * (2 * (modulus < 0) - 1) * modulus; return r; } -public CONSTFUNC double Num$mod1(double num, double modulus) { - return 1.0 + Num$mod(num-1, modulus); -} +public +CONSTFUNC double Num$mod1(double num, double modulus) { return 1.0 + Num$mod(num - 1, modulus); } -public CONSTFUNC double Num$mix(double amount, double x, double y) { - return (1.0-amount)*x + amount*y; -} +public +CONSTFUNC double Num$mix(double amount, double x, double y) { return (1.0 - amount) * x + amount * y; } -public CONSTFUNC bool Num$is_between(const double x, const double low, const double high) { - return low <= x && x <= high; -} -public CONSTFUNC double Num$clamped(double x, double low, double high) { - return (x <= low) ? low : (x >= high ? high : x); -} +public +CONSTFUNC bool Num$is_between(const double x, const double low, const double high) { return low <= x && x <= high; } +public +CONSTFUNC double Num$clamped(double x, double low, double high) { return (x <= low) ? low : (x >= high ? high : x); } -public OptionalNum_t Num$parse(Text_t text, Text_t *remainder) { +public +OptionalNum_t Num$parse(Text_t text, Text_t *remainder) { const char *str = Text$as_c_string(text); char *end = NULL; double d = strtod(str, &end); if (end > str) { - if (remainder) - *remainder = Text$from_str(end); - else if (*end != '\0') - return nan("none"); + if (remainder) *remainder = Text$from_str(end); + else if (*end != '\0') return nan("none"); return d; } else { if (remainder) *remainder = text; @@ -113,45 +115,54 @@ public OptionalNum_t Num$parse(Text_t text, Text_t *remainder) { } } -public CONSTFUNC bool Num$is_none(const void *n, const TypeInfo_t *info) -{ +public +CONSTFUNC bool Num$is_none(const void *n, const TypeInfo_t *info) { (void)info; - return isnan(*(Num_t*)n); -} - -public CONSTFUNC bool Num$isinf(double n) { return (fpclassify(n) == FP_INFINITE); } -public CONSTFUNC bool Num$finite(double n) { return (fpclassify(n) != FP_INFINITE); } -public CONSTFUNC bool Num$isnan(double n) { return (fpclassify(n) == FP_NAN); } - -public const TypeInfo_t Num$info = { - .size=sizeof(double), - .align=__alignof__(double), - .metamethods={ - .compare=Num$compare, - .equal=Num$equal, - .as_text=Num$as_text, - .is_none=Num$is_none, - }, + return isnan(*(Num_t *)n); +} + +public +CONSTFUNC bool Num$isinf(double n) { return (fpclassify(n) == FP_INFINITE); } +public +CONSTFUNC bool Num$finite(double n) { return (fpclassify(n) != FP_INFINITE); } +public +CONSTFUNC bool Num$isnan(double n) { return (fpclassify(n) == FP_NAN); } + +public +const TypeInfo_t Num$info = { + .size = sizeof(double), + .align = __alignof__(double), + .metamethods = + { + .compare = Num$compare, + .equal = Num$equal, + .as_text = Num$as_text, + .is_none = Num$is_none, + }, }; -public PUREFUNC Text_t Num32$as_text(const void *f, bool colorize, const TypeInfo_t *info) { +public +PUREFUNC Text_t Num32$as_text(const void *f, bool colorize, const TypeInfo_t *info) { (void)info; if (!f) return Text("Num32"); - double d = (double)(*(float*)f); + double d = (double)(*(float *)f); return Num$as_text(&d, colorize, &Num$info); } -public PUREFUNC int32_t Num32$compare(const void *x, const void *y, const TypeInfo_t *info) { +public +PUREFUNC int32_t Num32$compare(const void *x, const void *y, const TypeInfo_t *info) { (void)info; - return (*(float*)x > *(float*)y) - (*(float*)x < *(float*)y); -} + return (*(float *)x > *(float *)y) - (*(float *)x < *(float *)y); +} -public PUREFUNC bool Num32$equal(const void *x, const void *y, const TypeInfo_t *info) { +public +PUREFUNC bool Num32$equal(const void *x, const void *y, const TypeInfo_t *info) { (void)info; - return *(float*)x == *(float*)y; + return *(float *)x == *(float *)y; } -public CONSTFUNC bool Num32$near(float a, float b, float ratio, float absolute) { +public +CONSTFUNC bool Num32$near(float a, float b, float ratio, float absolute) { if (ratio < 0) ratio = 0; else if (ratio > 1) ratio = 1; @@ -166,17 +177,19 @@ public CONSTFUNC bool Num32$near(float a, float b, float ratio, float absolute) return (diff < epsilon); } -public Text_t Num32$percent(float f, float precision) { +public +Text_t Num32$percent(float f, float precision) { double d = 100. * (double)f; d = Num$with_precision(d, (double)precision); return Texts(Num$as_text(&d, false, &Num$info), Text("%")); } -public CONSTFUNC float Num32$with_precision(float num, float precision) { +public +CONSTFUNC float Num32$with_precision(float num, float precision) { if (precision == 0.0f) return num; // Precision will be, e.g. 0.01 or 100. if (precision < 1.f) { - float inv = roundf(1.f/precision); // Necessary to make the math work + float inv = roundf(1.f / precision); // Necessary to make the math work float k = num * inv; return roundf(k) / inv; } else { @@ -185,37 +198,35 @@ public CONSTFUNC float Num32$with_precision(float num, float precision) { } } -public CONSTFUNC float Num32$mod(float num, float modulus) { - // Euclidean division, see: https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/divmodnote-letter.pdf +public +CONSTFUNC float Num32$mod(float num, float modulus) { + // Euclidean division, see: + // https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/divmodnote-letter.pdf float r = remainderf(num, modulus); - r -= (r < 0) * (2*(modulus < 0) - 1) * modulus; + r -= (r < 0) * (2 * (modulus < 0) - 1) * modulus; return r; } -public CONSTFUNC float Num32$mod1(float num, float modulus) { - return 1.0f + Num32$mod(num-1, modulus); -} +public +CONSTFUNC float Num32$mod1(float num, float modulus) { return 1.0f + Num32$mod(num - 1, modulus); } -public CONSTFUNC float Num32$mix(float amount, float x, float y) { - return (1.0f-amount)*x + amount*y; -} +public +CONSTFUNC float Num32$mix(float amount, float x, float y) { return (1.0f - amount) * x + amount * y; } -public CONSTFUNC bool Num32$is_between(const float x, const float low, const float high) { - return low <= x && x <= high; -} +public +CONSTFUNC bool Num32$is_between(const float x, const float low, const float high) { return low <= x && x <= high; } -public CONSTFUNC float Num32$clamped(float x, float low, float high) { - return (x <= low) ? low : (x >= high ? high : x); -} +public +CONSTFUNC float Num32$clamped(float x, float low, float high) { return (x <= low) ? low : (x >= high ? high : x); } -public OptionalNum32_t Num32$parse(Text_t text, Text_t *remainder) { +public +OptionalNum32_t Num32$parse(Text_t text, Text_t *remainder) { const char *str = Text$as_c_string(text); char *end = NULL; double d = strtod(str, &end); if (end > str && end[0] == '\0') { if (remainder) *remainder = Text$from_str(end); - else if (*end != '\0') - return nan("none"); + else if (*end != '\0') return nan("none"); return d; } else { if (remainder) *remainder = text; @@ -223,25 +234,30 @@ public OptionalNum32_t Num32$parse(Text_t text, Text_t *remainder) { } } -public CONSTFUNC bool Num32$is_none(const void *n, const TypeInfo_t *info) -{ +public +CONSTFUNC bool Num32$is_none(const void *n, const TypeInfo_t *info) { (void)info; - return isnan(*(Num32_t*)n); -} - -public CONSTFUNC bool Num32$isinf(float n) { return (fpclassify(n) == FP_INFINITE); } -public CONSTFUNC bool Num32$finite(float n) { return (fpclassify(n) != FP_INFINITE); } -public CONSTFUNC bool Num32$isnan(float n) { return (fpclassify(n) == FP_NAN); } - -public const TypeInfo_t Num32$info = { - .size=sizeof(float), - .align=__alignof__(float), - .metamethods={ - .compare=Num32$compare, - .equal=Num32$equal, - .as_text=Num32$as_text, - .is_none=Num32$is_none, - }, + return isnan(*(Num32_t *)n); +} + +public +CONSTFUNC bool Num32$isinf(float n) { return (fpclassify(n) == FP_INFINITE); } +public +CONSTFUNC bool Num32$finite(float n) { return (fpclassify(n) != FP_INFINITE); } +public +CONSTFUNC bool Num32$isnan(float n) { return (fpclassify(n) == FP_NAN); } + +public +const TypeInfo_t Num32$info = { + .size = sizeof(float), + .align = __alignof__(float), + .metamethods = + { + .compare = Num32$compare, + .equal = Num32$equal, + .as_text = Num32$as_text, + .is_none = Num32$is_none, + }, }; // vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0 diff --git a/src/stdlib/optionals.c b/src/stdlib/optionals.c index 36683241..a6f943ae 100644 --- a/src/stdlib/optionals.c +++ b/src/stdlib/optionals.c @@ -9,22 +9,19 @@ #include "text.h" #include "util.h" -public PUREFUNC bool is_none(const void *obj, const TypeInfo_t *non_optional_type) -{ - if (non_optional_type->metamethods.is_none) - return non_optional_type->metamethods.is_none(obj, non_optional_type); +public +PUREFUNC bool is_none(const void *obj, const TypeInfo_t *non_optional_type) { + if (non_optional_type->metamethods.is_none) return non_optional_type->metamethods.is_none(obj, non_optional_type); const void *dest = (obj + non_optional_type->size); - return *(bool*)dest; + return *(bool *)dest; } -PUREFUNC public uint64_t Optional$hash(const void *obj, const TypeInfo_t *type) -{ +PUREFUNC public uint64_t Optional$hash(const void *obj, const TypeInfo_t *type) { return is_none(obj, type->OptionalInfo.type) ? 0 : generic_hash(obj, type->OptionalInfo.type); } -PUREFUNC public int32_t Optional$compare(const void *x, const void *y, const TypeInfo_t *type) -{ +PUREFUNC public int32_t Optional$compare(const void *x, const void *y, const TypeInfo_t *type) { if (x == y) return 0; bool x_is_null = is_none(x, type->OptionalInfo.type); bool y_is_null = is_none(y, type->OptionalInfo.type); @@ -33,8 +30,7 @@ PUREFUNC public int32_t Optional$compare(const void *x, const void *y, const Typ else return generic_compare(x, y, type->OptionalInfo.type); } -PUREFUNC public bool Optional$equal(const void *x, const void *y, const TypeInfo_t *type) -{ +PUREFUNC public bool Optional$equal(const void *x, const void *y, const TypeInfo_t *type) { if (x == y) return true; bool x_is_null = is_none(x, type->OptionalInfo.type); @@ -44,46 +40,37 @@ PUREFUNC public bool Optional$equal(const void *x, const void *y, const TypeInfo else return generic_equal(x, y, type->OptionalInfo.type); } -public Text_t Optional$as_text(const void *obj, bool colorize, const TypeInfo_t *type) -{ - if (!obj) - return Text$concat(generic_as_text(obj, colorize, type->OptionalInfo.type), Text("?")); +public +Text_t Optional$as_text(const void *obj, bool colorize, const TypeInfo_t *type) { + if (!obj) return Text$concat(generic_as_text(obj, colorize, type->OptionalInfo.type), Text("?")); - if (is_none(obj, type->OptionalInfo.type)) - return colorize ? Text("\x1b[31mnone\x1b[m") : Text("none"); + if (is_none(obj, type->OptionalInfo.type)) return colorize ? Text("\x1b[31mnone\x1b[m") : Text("none"); return generic_as_text(obj, colorize, type->OptionalInfo.type); } -public void Optional$serialize(const void *obj, FILE *out, Table_t *pointers, const TypeInfo_t *type) -{ +public +void Optional$serialize(const void *obj, FILE *out, Table_t *pointers, const TypeInfo_t *type) { bool has_value = !is_none(obj, type->OptionalInfo.type); assert(fputc((int)has_value, out) != EOF); - if (has_value) - _serialize(obj, out, pointers, type->OptionalInfo.type); + if (has_value) _serialize(obj, out, pointers, type->OptionalInfo.type); } -public void Optional$deserialize(FILE *in, void *outval, List_t *pointers, const TypeInfo_t *type) -{ +public +void Optional$deserialize(FILE *in, void *outval, List_t *pointers, const TypeInfo_t *type) { bool has_value = (bool)fgetc(in); const TypeInfo_t *nonnull = type->OptionalInfo.type; if (has_value) { memset(outval, 0, (size_t)type->size); _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 == &Num$info) - *(double*)outval = (double)NAN; - else if (nonnull == &Num32$info) - *(float*)outval = (float)NAN; + 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 == &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)) memset(outval + type->size, -1, (size_t)(type->size - nonnull->size)); - else - memset(outval, 0, (size_t)type->size); + else memset(outval, 0, (size_t)type->size); } } diff --git a/src/stdlib/optionals.h b/src/stdlib/optionals.h index bd1f63b3..77ce6db4 100644 --- a/src/stdlib/optionals.h +++ b/src/stdlib/optionals.h @@ -9,13 +9,13 @@ #include "types.h" #include "util.h" -#define NONE_LIST ((List_t){.length=-1}) +#define NONE_LIST ((List_t){.length = -1}) #define NONE_BOOL ((OptionalBool_t)2) -#define NONE_INT ((OptionalInt_t){.small=0}) -#define NONE_TABLE ((OptionalTable_t){.entries.length=-1}) -#define NONE_CLOSURE ((OptionalClosure_t){.fn=NULL}) -#define NONE_TEXT ((OptionalText_t){.length=-1}) -#define NONE_PATH ((Path_t){.type=PATH_NONE}) +#define NONE_INT ((OptionalInt_t){.small = 0}) +#define NONE_TABLE ((OptionalTable_t){.entries.length = -1}) +#define NONE_CLOSURE ((OptionalClosure_t){.fn = NULL}) +#define NONE_TEXT ((OptionalText_t){.length = -1}) +#define NONE_PATH ((Path_t){.type = PATH_NONE}) PUREFUNC bool is_none(const void *obj, const TypeInfo_t *non_optional_type); PUREFUNC uint64_t Optional$hash(const void *obj, const TypeInfo_t *type); @@ -25,17 +25,21 @@ Text_t Optional$as_text(const void *obj, bool colorize, const TypeInfo_t *type); void Optional$serialize(const void *obj, FILE *out, Table_t *pointers, const TypeInfo_t *type); void Optional$deserialize(FILE *in, void *outval, List_t *pointers, const TypeInfo_t *type); -#define Optional$metamethods { \ - .hash=Optional$hash, \ - .compare=Optional$compare, \ - .equal=Optional$equal, \ - .as_text=Optional$as_text, \ - .serialize=Optional$serialize, \ - .deserialize=Optional$deserialize, \ -} - -#define Optional$info(_size, _align, t) &((TypeInfo_t){.size=_size, .align=_align, \ - .tag=OptionalInfo, .OptionalInfo.type=t, \ - .metamethods=Optional$metamethods}) +#define Optional$metamethods \ + { \ + .hash = Optional$hash, \ + .compare = Optional$compare, \ + .equal = Optional$equal, \ + .as_text = Optional$as_text, \ + .serialize = Optional$serialize, \ + .deserialize = Optional$deserialize, \ + } + +#define Optional$info(_size, _align, t) \ + &((TypeInfo_t){.size = _size, \ + .align = _align, \ + .tag = OptionalInfo, \ + .OptionalInfo.type = t, \ + .metamethods = Optional$metamethods}) // vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0 diff --git a/src/stdlib/paths.c b/src/stdlib/paths.c index a14b32c2..efe9f7ad 100644 --- a/src/stdlib/paths.c +++ b/src/stdlib/paths.c @@ -17,32 +17,30 @@ #include <unistd.h> #include <unistr.h> -#include "lists.h" #include "enums.h" #include "integers.h" +#include "lists.h" #include "optionals.h" #include "paths.h" +#include "print.h" #include "structs.h" #include "text.h" #include "types.h" #include "util.h" -#include "print.h" // Use inline version of the siphash code for performance: #include "siphash-internals.h" -static const Path_t HOME_PATH = {.type.$tag=PATH_HOME}, - ROOT_PATH = {.type.$tag=PATH_ABSOLUTE}, - CURDIR_PATH = {.type.$tag=PATH_RELATIVE}; +static const Path_t HOME_PATH = {.type.$tag = PATH_HOME}, ROOT_PATH = {.type.$tag = PATH_ABSOLUTE}, + CURDIR_PATH = {.type.$tag = PATH_RELATIVE}; -static void clean_components(List_t *components) -{ - for (int64_t i = 0; i < components->length; ) { - Text_t *component = (Text_t*)(components->data + i*components->stride); +static void clean_components(List_t *components) { + for (int64_t i = 0; i < 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)); + List$remove_at(components, I(i + 1), I(1), sizeof(Text_t)); } else if (i > 0 && Text$equal_values(*component, Text(".."))) { - Text_t *prev = (Text_t*)(components->data + (i-1)*components->stride); + Text_t *prev = (Text_t *)(components->data + (i - 1) * components->stride); if (!Text$equal_values(*prev, Text(".."))) { List$remove_at(components, I(i), I(2), sizeof(Text_t)); i -= 1; @@ -55,16 +53,15 @@ static void clean_components(List_t *components) } } -public Path_t Path$from_str(const char *str) -{ +public +Path_t Path$from_str(const char *str) { if (!str || str[0] == '\0' || streq(str, "/")) return ROOT_PATH; else if (streq(str, "~")) return HOME_PATH; else if (streq(str, ".")) return CURDIR_PATH; - if (strchr(str, ';') != NULL) - fail("Path has illegal character (semicolon): ", str); + if (strchr(str, ';') != NULL) fail("Path has illegal character (semicolon): ", str); - Path_t result = {.components={}}; + Path_t result = {.components = {}}; if (str[0] == '/') { result.type.$tag = PATH_ABSOLUTE; str += 1; @@ -83,12 +80,13 @@ public Path_t Path$from_str(const char *str) if (component_len > 0) { if (component_len == 1 && str[0] == '.') { // 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)))) { + } 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)))) { // Pop off /foo/baz/.. -> /foo List$remove_at(&result.components, I(result.components.length), I(1), sizeof(Text_t)); - } else { + } else { Text_t component = Text$from_strn(str, component_len); List$insert_value(&result.components, component, I(0), sizeof(Text_t)); } @@ -99,25 +97,23 @@ public Path_t Path$from_str(const char *str) return result; } -public Path_t Path$from_text(Text_t text) -{ - return Path$from_str(Text$as_c_string(text)); -} +public +Path_t Path$from_text(Text_t text) { return Path$from_str(Text$as_c_string(text)); } -public Path_t Path$expand_home(Path_t path) -{ +public +Path_t Path$expand_home(Path_t path) { if (path.type.$tag == PATH_HOME) { Path_t pwd = Path$from_str(getenv("HOME")); List_t components = List$concat(pwd.components, path.components, sizeof(Text_t)); assert(components.length == path.components.length + pwd.components.length); clean_components(&components); - path = (Path_t){.type.$tag=PATH_ABSOLUTE, .components=components}; + path = (Path_t){.type.$tag = PATH_ABSOLUTE, .components = components}; } return path; } -public Path_t Path$_concat(int n, Path_t items[n]) -{ +public +Path_t Path$_concat(int n, Path_t items[n]) { assert(n > 0); Path_t result = items[0]; LIST_INCREF(result.components); @@ -130,10 +126,11 @@ public Path_t Path$_concat(int n, Path_t items[n]) return result; } -public Path_t Path$resolved(Path_t path, Path_t relative_to) -{ - if (path.type.$tag == PATH_RELATIVE && !(relative_to.type.$tag == PATH_RELATIVE && relative_to.components.length == 0)) { - Path_t result = {.type.$tag=relative_to.type.$tag}; +public +Path_t Path$resolved(Path_t path, Path_t relative_to) { + if (path.type.$tag == PATH_RELATIVE + && !(relative_to.type.$tag == PATH_RELATIVE && relative_to.components.length == 0)) { + Path_t result = {.type.$tag = relative_to.type.$tag}; result.components = relative_to.components; LIST_INCREF(result.components); List$insert_all(&result.components, path.components, I(0), sizeof(Text_t)); @@ -143,87 +140,86 @@ public Path_t Path$resolved(Path_t path, Path_t relative_to) return path; } -public Path_t Path$relative_to(Path_t path, Path_t relative_to) -{ +public +Path_t Path$relative_to(Path_t path, Path_t relative_to) { if (path.type.$tag != relative_to.type.$tag) - fail("Cannot create a path relative to a different path with a mismatching type: (", path, ") relative to (", relative_to, ")"); + fail("Cannot create a path relative to a different path with a mismatching type: (", path, ") relative to (", + relative_to, ")"); - Path_t result = {.type.$tag=PATH_RELATIVE}; + Path_t result = {.type.$tag = PATH_RELATIVE}; int64_t shared = 0; for (; shared < path.components.length && shared < 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; + 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++) List$insert_value(&result.components, Text(".."), I(1), sizeof(Text_t)); for (int64_t i = shared; i < path.components.length; i++) { - Text_t *p = (Text_t*)(path.components.data + i*path.components.stride); + Text_t *p = (Text_t *)(path.components.data + i * path.components.stride); List$insert(&result.components, p, I(0), sizeof(Text_t)); } - //clean_components(&result.components); + // clean_components(&result.components); return result; } -public bool Path$exists(Path_t path) -{ +public +bool Path$exists(Path_t path) { path = Path$expand_home(path); struct stat sb; return (stat(Path$as_c_string(path), &sb) == 0); } -static INLINE int path_stat(Path_t path, bool follow_symlinks, struct stat *sb) -{ +static INLINE int path_stat(Path_t path, bool follow_symlinks, struct stat *sb) { path = Path$expand_home(path); const char *path_str = Path$as_c_string(path); return follow_symlinks ? stat(path_str, sb) : lstat(path_str, sb); } -public bool Path$is_file(Path_t path, bool follow_symlinks) -{ +public +bool Path$is_file(Path_t path, bool follow_symlinks) { struct stat sb; int status = path_stat(path, follow_symlinks, &sb); if (status != 0) return false; return (sb.st_mode & S_IFMT) == S_IFREG; } -public bool Path$is_directory(Path_t path, bool follow_symlinks) -{ +public +bool Path$is_directory(Path_t path, bool follow_symlinks) { struct stat sb; int status = path_stat(path, follow_symlinks, &sb); if (status != 0) return false; return (sb.st_mode & S_IFMT) == S_IFDIR; } -public bool Path$is_pipe(Path_t path, bool follow_symlinks) -{ +public +bool Path$is_pipe(Path_t path, bool follow_symlinks) { struct stat sb; int status = path_stat(path, follow_symlinks, &sb); if (status != 0) return false; return (sb.st_mode & S_IFMT) == S_IFIFO; } -public bool Path$is_socket(Path_t path, bool follow_symlinks) -{ +public +bool Path$is_socket(Path_t path, bool follow_symlinks) { struct stat sb; int status = path_stat(path, follow_symlinks, &sb); if (status != 0) return false; return (sb.st_mode & S_IFMT) == S_IFSOCK; } -public bool Path$is_symlink(Path_t path) -{ +public +bool Path$is_symlink(Path_t path) { struct stat sb; int status = path_stat(path, false, &sb); if (status != 0) return false; return (sb.st_mode & S_IFMT) == S_IFLNK; } -public bool Path$can_read(Path_t path) -{ +public +bool Path$can_read(Path_t path) { path = Path$expand_home(path); const char *path_str = Path$as_c_string(path); #ifdef _GNU_SOURCE @@ -233,8 +229,8 @@ public bool Path$can_read(Path_t path) #endif } -public bool Path$can_write(Path_t path) -{ +public +bool Path$can_write(Path_t path) { path = Path$expand_home(path); const char *path_str = Path$as_c_string(path); #ifdef _GNU_SOURCE @@ -244,8 +240,8 @@ public bool Path$can_write(Path_t path) #endif } -public bool Path$can_execute(Path_t path) -{ +public +bool Path$can_execute(Path_t path) { path = Path$expand_home(path); const char *path_str = Path$as_c_string(path); #ifdef _GNU_SOURCE @@ -255,93 +251,86 @@ public bool Path$can_execute(Path_t path) #endif } -public OptionalInt64_t Path$modified(Path_t path, bool follow_symlinks) -{ +public +OptionalInt64_t Path$modified(Path_t path, bool follow_symlinks) { struct stat sb; int status = path_stat(path, follow_symlinks, &sb); if (status != 0) return NONE_INT64; - return (OptionalInt64_t){.value=(int64_t)sb.st_mtime}; + return (OptionalInt64_t){.value = (int64_t)sb.st_mtime}; } -public OptionalInt64_t Path$accessed(Path_t path, bool follow_symlinks) -{ +public +OptionalInt64_t Path$accessed(Path_t path, bool follow_symlinks) { struct stat sb; int status = path_stat(path, follow_symlinks, &sb); if (status != 0) return NONE_INT64; - return (OptionalInt64_t){.value=(int64_t)sb.st_atime}; + return (OptionalInt64_t){.value = (int64_t)sb.st_atime}; } -public OptionalInt64_t Path$changed(Path_t path, bool follow_symlinks) -{ +public +OptionalInt64_t Path$changed(Path_t path, bool follow_symlinks) { struct stat sb; int status = path_stat(path, follow_symlinks, &sb); if (status != 0) return NONE_INT64; - return (OptionalInt64_t){.value=(int64_t)sb.st_ctime}; + return (OptionalInt64_t){.value = (int64_t)sb.st_ctime}; } -static void _write(Path_t path, List_t bytes, int mode, int permissions) -{ +static void _write(Path_t path, List_t bytes, int mode, int permissions) { path = Path$expand_home(path); const char *path_str = Path$as_c_string(path); int fd = open(path_str, mode, permissions); - if (fd == -1) - fail("Could not write to file: ", path_str, "\n", strerror(errno)); + if (fd == -1) fail("Could not write to file: ", path_str, "\n", strerror(errno)); - if (bytes.stride != 1) - List$compact(&bytes, 1); + if (bytes.stride != 1) List$compact(&bytes, 1); ssize_t written = write(fd, bytes.data, (size_t)bytes.length); - if (written != (ssize_t)bytes.length) - fail("Could not write to file: ", path_str, "\n", strerror(errno)); + if (written != (ssize_t)bytes.length) fail("Could not write to file: ", path_str, "\n", strerror(errno)); close(fd); } -public void Path$write(Path_t path, Text_t text, int permissions) -{ +public +void Path$write(Path_t path, Text_t text, int permissions) { List_t bytes = Text$utf8_bytes(text); _write(path, bytes, O_WRONLY | O_CREAT | O_TRUNC, permissions); } -public void Path$write_bytes(Path_t path, List_t bytes, int permissions) -{ +public +void Path$write_bytes(Path_t path, List_t bytes, int permissions) { _write(path, bytes, O_WRONLY | O_CREAT | O_TRUNC, permissions); } -public void Path$append(Path_t path, Text_t text, int permissions) -{ +public +void Path$append(Path_t path, Text_t text, int permissions) { List_t bytes = Text$utf8_bytes(text); _write(path, bytes, O_WRONLY | O_APPEND | O_CREAT, permissions); } -public void Path$append_bytes(Path_t path, List_t bytes, int permissions) -{ +public +void Path$append_bytes(Path_t path, List_t bytes, int permissions) { _write(path, bytes, O_WRONLY | O_APPEND | O_CREAT, permissions); } -public OptionalList_t Path$read_bytes(Path_t path, OptionalInt_t count) -{ +public +OptionalList_t Path$read_bytes(Path_t path, OptionalInt_t count) { path = Path$expand_home(path); int fd = open(Path$as_c_string(path), O_RDONLY); - if (fd == -1) - return NONE_LIST; + if (fd == -1) return NONE_LIST; struct stat sb; - if (fstat(fd, &sb) != 0) - return NONE_LIST; + if (fstat(fd, &sb) != 0) return NONE_LIST; int64_t const target_count = count.small ? Int64$from_int(count, false) : INT64_MAX; - if (target_count < 0) - fail("Cannot read a negative number of bytes!"); + if (target_count < 0) fail("Cannot read a negative number of bytes!"); if ((sb.st_mode & S_IFMT) == S_IFREG) { // Use memory mapping if it's a real file: const char *mem = mmap(NULL, (size_t)sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0); - char *content = GC_MALLOC_ATOMIC((size_t)sb.st_size+1); + char *content = GC_MALLOC_ATOMIC((size_t)sb.st_size + 1); memcpy(content, mem, (size_t)sb.st_size); content[sb.st_size] = '\0'; close(fd); 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 = len}; } else { size_t capacity = 256, len = 0; char *content = GC_MALLOC_ATOMIC(capacity); @@ -354,8 +343,7 @@ public OptionalList_t Path$read_bytes(Path_t path, OptionalInt_t count) close(fd); return NONE_LIST; } else if (just_read == 0) { - if (errno == EAGAIN || errno == EINTR) - continue; + if (errno == EAGAIN || errno == EINTR) continue; break; } count_remaining -= (int64_t)just_read; @@ -370,19 +358,19 @@ public 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 = (int64_t)len}; } } -public OptionalText_t Path$read(Path_t path) -{ +public +OptionalText_t Path$read(Path_t path) { List_t bytes = Path$read_bytes(path, NONE_INT); if (bytes.length < 0) return NONE_TEXT; return Text$from_bytes(bytes); } -public OptionalText_t Path$owner(Path_t path, bool follow_symlinks) -{ +public +OptionalText_t Path$owner(Path_t path, bool follow_symlinks) { struct stat sb; int status = path_stat(path, follow_symlinks, &sb); if (status != 0) return NONE_TEXT; @@ -390,8 +378,8 @@ public OptionalText_t Path$owner(Path_t path, bool follow_symlinks) return pw ? Text$from_str(pw->pw_name) : NONE_TEXT; } -public OptionalText_t Path$group(Path_t path, bool follow_symlinks) -{ +public +OptionalText_t Path$group(Path_t path, bool follow_symlinks) { struct stat sb; int status = path_stat(path, follow_symlinks, &sb); if (status != 0) return NONE_TEXT; @@ -399,8 +387,8 @@ public OptionalText_t Path$group(Path_t path, bool follow_symlinks) return gr ? Text$from_str(gr->gr_name) : NONE_TEXT; } -public void Path$set_owner(Path_t path, OptionalText_t owner, OptionalText_t group, 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) { struct passwd *pwd = getpwnam(Text$as_c_string(owner)); @@ -416,38 +404,34 @@ public void Path$set_owner(Path_t path, OptionalText_t owner, OptionalText_t gro } const char *path_str = Path$as_c_string(path); int result = follow_symlinks ? chown(path_str, owner_id, group_id) : lchown(path_str, owner_id, group_id); - if (result < 0) - fail("Could not set owner!"); + if (result < 0) fail("Could not set owner!"); } -static int _remove_files(const char *path, const struct stat *sbuf, int type, struct FTW *ftwb) -{ +static int _remove_files(const char *path, const struct stat *sbuf, int type, struct FTW *ftwb) { (void)sbuf, (void)ftwb; switch (type) { - case FTW_F: case FTW_SL: case FTW_SLN: + case FTW_F: + case FTW_SL: + case FTW_SLN: if (remove(path) < 0) { fail("Could not remove file: ", path, " (", strerror(errno), ")"); return -1; } return 0; case FTW_DP: - if (rmdir(path) != 0) - fail("Could not remove directory: ", path, " (", strerror(errno), ")"); + if (rmdir(path) != 0) fail("Could not remove directory: ", path, " (", strerror(errno), ")"); return 0; - default: - fail("Could not remove path: ", path, " (not a file or directory)"); - return -1; + default: fail("Could not remove path: ", path, " (not a file or directory)"); return -1; } } -public void Path$remove(Path_t path, bool ignore_missing) -{ +public +void Path$remove(Path_t path, bool ignore_missing) { path = Path$expand_home(path); const char *path_str = Path$as_c_string(path); struct stat sb; if (lstat(path_str, &sb) != 0) { - if (!ignore_missing) - fail("Could not remove file: ", path_str, " (", strerror(errno), ")"); + if (!ignore_missing) fail("Could not remove file: ", path_str, " (", strerror(errno), ")"); return; } @@ -456,48 +440,40 @@ public void Path$remove(Path_t path, bool ignore_missing) fail("Could not remove file: ", path_str, " (", strerror(errno), ")"); } else if ((sb.st_mode & S_IFMT) == S_IFDIR) { const int num_open_fd = 10; - if (nftw(path_str, _remove_files, num_open_fd, FTW_DEPTH|FTW_MOUNT|FTW_PHYS) < 0) + if (nftw(path_str, _remove_files, num_open_fd, FTW_DEPTH | FTW_MOUNT | FTW_PHYS) < 0) fail("Could not remove directory: %s (%s)", path_str, strerror(errno)); } else { fail("Could not remove path: ", path_str, " (not a file or directory)"); } } -public void Path$create_directory(Path_t path, int permissions) -{ +public +void Path$create_directory(Path_t path, int permissions) { path = Path$expand_home(path); const char *c_path = Path$as_c_string(path); int status = mkdir(c_path, (mode_t)permissions); - if (status != 0 && errno != EEXIST) - fail("Could not create directory: ", c_path, " (", strerror(errno), ")"); + if (status != 0 && errno != EEXIST) fail("Could not create directory: ", c_path, " (", strerror(errno), ")"); } -static List_t _filtered_children(Path_t path, bool include_hidden, mode_t filter) -{ +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 = {}; const char *path_str = Path$as_c_string(path); size_t path_len = strlen(path_str); DIR *d = opendir(path_str); - if (!d) - fail("Could not open directory: ", path, " (", strerror(errno), ")"); + if (!d) fail("Could not open directory: ", path, " (", strerror(errno), ")"); - if (path_str[path_len-1] == '/') - --path_len; + if (path_str[path_len - 1] == '/') --path_len; while ((dir = readdir(d)) != NULL) { - if (!include_hidden && dir->d_name[0] == '.') - continue; - if (streq(dir->d_name, ".") || streq(dir->d_name, "..")) - continue; + if (!include_hidden && dir->d_name[0] == '.') continue; + if (streq(dir->d_name, ".") || streq(dir->d_name, "..")) continue; const char *child_str = String(string_slice(path_str, path_len), "/", dir->d_name); struct stat sb; - if (stat(child_str, &sb) != 0) - continue; - if (!((sb.st_mode & S_IFMT) & filter)) - continue; + if (stat(child_str, &sb) != 0) continue; + if (!((sb.st_mode & S_IFMT) & filter)) continue; Path_t child = Path$from_str(child_str); List$insert(&children, &child, I(0), sizeof(Path_t)); @@ -506,23 +482,19 @@ static List_t _filtered_children(Path_t path, bool include_hidden, mode_t filter return children; } -public List_t Path$children(Path_t path, bool include_hidden) -{ - return _filtered_children(path, include_hidden, (mode_t)-1); -} +public +List_t Path$children(Path_t path, bool include_hidden) { return _filtered_children(path, include_hidden, (mode_t)-1); } -public List_t Path$files(Path_t path, bool include_hidden) -{ - return _filtered_children(path, include_hidden, S_IFREG); -} +public +List_t Path$files(Path_t path, bool include_hidden) { return _filtered_children(path, include_hidden, S_IFREG); } -public List_t Path$subdirectories(Path_t path, bool include_hidden) -{ +public +List_t Path$subdirectories(Path_t path, bool include_hidden) { return _filtered_children(path, include_hidden, S_IFDIR); } -public Path_t Path$unique_directory(Path_t path) -{ +public +Path_t Path$unique_directory(Path_t path) { path = Path$expand_home(path); const char *path_str = Path$as_c_string(path); size_t len = strlen(path_str); @@ -530,15 +502,14 @@ public Path_t Path$unique_directory(Path_t path) char buf[PATH_MAX] = {}; memcpy(buf, path_str, len); buf[len] = '\0'; - if (buf[len-1] == '/') - buf[--len] = '\0'; + if (buf[len - 1] == '/') buf[--len] = '\0'; char *created = mkdtemp(buf); if (!created) fail("Failed to create temporary directory: ", path_str, " (", strerror(errno), ")"); return Path$from_str(created); } -public Path_t Path$write_unique_bytes(Path_t path, List_t bytes) -{ +public +Path_t Path$write_unique_bytes(Path_t path, List_t bytes) { path = Path$expand_home(path); const char *path_str = Path$as_c_string(path); size_t len = strlen(path_str); @@ -554,82 +525,73 @@ public Path_t Path$write_unique_bytes(Path_t path, List_t bytes) ++suffixlen; int fd = mkstemps(buf, suffixlen); - if (fd == -1) - fail("Could not write to unique file: ", buf, "\n", strerror(errno)); + if (fd == -1) fail("Could not write to unique file: ", buf, "\n", strerror(errno)); - if (bytes.stride != 1) - List$compact(&bytes, 1); + if (bytes.stride != 1) List$compact(&bytes, 1); ssize_t written = write(fd, bytes.data, (size_t)bytes.length); - if (written != (ssize_t)bytes.length) - fail("Could not write to file: ", buf, "\n", strerror(errno)); + if (written != (ssize_t)bytes.length) fail("Could not write to file: ", buf, "\n", strerror(errno)); close(fd); return Path$from_str(buf); } -public Path_t Path$write_unique(Path_t path, Text_t text) -{ - return Path$write_unique_bytes(path, Text$utf8_bytes(text)); -} +public +Path_t Path$write_unique(Path_t path, Text_t text) { return Path$write_unique_bytes(path, Text$utf8_bytes(text)); } -public Path_t Path$parent(Path_t path) -{ +public +Path_t Path$parent(Path_t path) { if (path.type.$tag == PATH_ABSOLUTE && path.components.length == 0) { return path; - } else if (path.components.length > 0 && !Text$equal_values(*(Text_t*)(path.components.data + path.components.stride*(path.components.length-1)), - Text(".."))) { - return (Path_t){.type.$tag=path.type.$tag, .components=List$slice(path.components, I(1), I(-2))}; + } else if (path.components.length > 0 + && !Text$equal_values( + *(Text_t *)(path.components.data + path.components.stride * (path.components.length - 1)), + Text(".."))) { + return (Path_t){.type.$tag = path.type.$tag, .components = List$slice(path.components, I(1), I(-2))}; } else { - Path_t result = {.type.$tag=path.type.$tag, .components=path.components}; + Path_t result = {.type.$tag = path.type.$tag, .components = path.components}; LIST_INCREF(result.components); List$insert_value(&result.components, Text(".."), I(0), sizeof(Text_t)); return result; } } -public PUREFUNC Text_t Path$base_name(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)); - else if (path.type.$tag == PATH_HOME) - return Text("~"); - else if (path.type.$tag == PATH_RELATIVE) - return Text("."); - else - return EMPTY_TEXT; + return *(Text_t *)(path.components.data + path.components.stride * (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; } -public Text_t Path$extension(Path_t path, bool full) -{ +public +Text_t Path$extension(Path_t path, bool full) { const char *base = Text$as_c_string(Path$base_name(path)); const char *dot = full ? strchr(base + 1, '.') : strrchr(base + 1, '.'); const char *extension = dot ? dot + 1 : ""; return Text$from_str(extension); } -public bool Path$has_extension(Path_t path, Text_t extension) -{ - if (path.components.length < 2) - return extension.length == 0; +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 * (path.components.length - 1)); if (extension.length == 0) return !Text$has(Text$from(last, I(2)), Text(".")) || Text$equal_values(last, Text("..")); - if (!Text$starts_with(extension, Text("."), NULL)) - extension = Texts(Text("."), extension); + if (!Text$starts_with(extension, Text("."), NULL)) extension = Texts(Text("."), extension); return Text$ends_with(Text$from(last, I(2)), extension, NULL); } -public Path_t Path$child(Path_t path, Text_t name) -{ - if (Text$has(name, Text("/")) || Text$has(name, Text(";"))) - fail("Path name has invalid characters: ", name); +public +Path_t Path$child(Path_t path, Text_t name) { + if (Text$has(name, Text("/")) || Text$has(name, Text(";"))) fail("Path name has invalid characters: ", name); Path_t result = { - .type.$tag=path.type.$tag, - .components=path.components, + .type.$tag = path.type.$tag, + .components = path.components, }; LIST_INCREF(result.components); List$insert(&result.components, &name, I(0), sizeof(Text_t)); @@ -637,31 +599,27 @@ public Path_t Path$child(Path_t path, Text_t name) return result; } -public Path_t Path$sibling(Path_t path, Text_t name) -{ - return Path$child(Path$parent(path), name); -} +public +Path_t Path$sibling(Path_t path, Text_t name) { return Path$child(Path$parent(path), name); } -public Path_t Path$with_extension(Path_t path, Text_t extension, bool replace) -{ - if (path.components.length == 0) - fail("A path with no components can't have an extension!"); +public +Path_t Path$with_extension(Path_t path, Text_t extension, bool replace) { + if (path.components.length == 0) fail("A path with no components can't have an extension!"); if (Text$has(extension, Text("/")) || Text$has(extension, Text(";"))) fail("Path extension has invalid characters: ", extension); Path_t result = { - .type.$tag=path.type.$tag, - .components=path.components, + .type.$tag = path.type.$tag, + .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 * (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); const char *dot = strchr(base + 1, '.'); - if (dot) - last = Text$from_strn(base, (size_t)(dot - base)); + if (dot) last = Text$from_strn(base, (size_t)(dot - base)); } last = Text$concat(last, extension); @@ -669,16 +627,14 @@ public Path_t Path$with_extension(Path_t path, Text_t extension, bool replace) return result; } -static void _line_reader_cleanup(FILE **f) -{ +static void _line_reader_cleanup(FILE **f) { if (f && *f) { fclose(*f); *f = NULL; } } -static Text_t _next_line(FILE **f) -{ +static Text_t _next_line(FILE **f) { if (!f || !*f) return NONE_TEXT; char *line = NULL; @@ -689,43 +645,41 @@ static Text_t _next_line(FILE **f) return NONE_TEXT; } - while (len > 0 && (line[len-1] == '\r' || line[len-1] == '\n')) + while (len > 0 && (line[len - 1] == '\r' || line[len - 1] == '\n')) --len; - if (u8_check((uint8_t*)line, (size_t)len) != NULL) - fail("Invalid UTF8!"); + if (u8_check((uint8_t *)line, (size_t)len) != NULL) fail("Invalid UTF8!"); Text_t line_text = Text$from_strn(line, (size_t)len); free(line); return line_text; } -public OptionalClosure_t Path$by_line(Path_t path) -{ +public +OptionalClosure_t Path$by_line(Path_t path) { path = Path$expand_home(path); FILE *f = fopen(Path$as_c_string(path), "r"); - if (f == NULL) - return NONE_CLOSURE; + if (f == NULL) return NONE_CLOSURE; - FILE **wrapper = GC_MALLOC(sizeof(FILE*)); + FILE **wrapper = GC_MALLOC(sizeof(FILE *)); *wrapper = f; - GC_register_finalizer(wrapper, (void*)_line_reader_cleanup, NULL, NULL, NULL); - return (Closure_t){.fn=(void*)_next_line, .userdata=wrapper}; + GC_register_finalizer(wrapper, (void *)_line_reader_cleanup, NULL, NULL, NULL); + return (Closure_t){.fn = (void *)_next_line, .userdata = wrapper}; } -public List_t Path$glob(Path_t path) -{ +public +List_t Path$glob(Path_t path) { glob_t glob_result; 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"); + if (status != 0 && status != GLOB_NOMATCH) fail("Failed to perform globbing"); List_t glob_files = {}; 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] == '/') - || (len >= 2 && glob_result.gl_pathv[i][len-1] == '.' && glob_result.gl_pathv[i][len-2] == '.' && glob_result.gl_pathv[i][len-3] == '/')) + if ((len >= 2 && glob_result.gl_pathv[i][len - 1] == '.' && glob_result.gl_pathv[i][len - 2] == '/') + || (len >= 2 && glob_result.gl_pathv[i][len - 1] == '.' && glob_result.gl_pathv[i][len - 2] == '.' + && glob_result.gl_pathv[i][len - 3] == '/')) continue; Path_t p = Path$from_str(glob_result.gl_pathv[i]); List$insert(&glob_files, &p, I(0), sizeof(Path_t)); @@ -733,52 +687,51 @@ public List_t Path$glob(Path_t path) return glob_files; } -public Path_t Path$current_dir(void) -{ +public +Path_t Path$current_dir(void) { char cwd[PATH_MAX]; - if (getcwd(cwd, sizeof(cwd)) == NULL) - fail("Could not get current working directory"); + if (getcwd(cwd, sizeof(cwd)) == NULL) fail("Could not get current working directory"); return Path$from_str(cwd); } -public PUREFUNC uint64_t Path$hash(const void *obj, const TypeInfo_t *type) -{ +public +PUREFUNC uint64_t Path$hash(const void *obj, const TypeInfo_t *type) { (void)type; - Path_t *path = (Path_t*)obj; + 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++) { - uint64_t item_hash = Text$hash(path->components.data + i*path->components.stride, &Text$info); + uint64_t item_hash = Text$hash(path->components.data + i * path->components.stride, &Text$info); siphashadd64bits(&sh, item_hash); } return siphashfinish_last_part(&sh, (uint64_t)path->components.length); } -public PUREFUNC int32_t Path$compare(const void *va, const void *vb, const TypeInfo_t *type) -{ +public +PUREFUNC int32_t Path$compare(const void *va, const void *vb, const TypeInfo_t *type) { (void)type; - Path_t *a = (Path_t*)va, *b = (Path_t*)vb; + Path_t *a = (Path_t *)va, *b = (Path_t *)vb; int diff = ((int)a->type.$tag - (int)b->type.$tag); if (diff != 0) return diff; return List$compare(&a->components, &b->components, List$info(&Text$info)); } -public PUREFUNC bool Path$equal(const void *va, const void *vb, const TypeInfo_t *type) -{ +public +PUREFUNC bool Path$equal(const void *va, const void *vb, const TypeInfo_t *type) { (void)type; - Path_t *a = (Path_t*)va, *b = (Path_t*)vb; + Path_t *a = (Path_t *)va, *b = (Path_t *)vb; if (a->type.$tag != b->type.$tag) return false; return List$equal(&a->components, &b->components, List$info(&Text$info)); } -public PUREFUNC bool Path$equal_values(Path_t a, Path_t b) -{ +public +PUREFUNC bool Path$equal_values(Path_t a, Path_t b) { if (a.type.$tag != b.type.$tag) return false; return List$equal(&a.components, &b.components, List$info(&Text$info)); } -public int Path$print(FILE *f, Path_t path) -{ +public +int Path$print(FILE *f, Path_t path) { if (path.components.length == 0) { if (path.type.$tag == PATH_ABSOLUTE) return fputs("/", f); else if (path.type.$tag == PATH_RELATIVE) return fputs(".", f); @@ -791,91 +744,86 @@ public int Path$print(FILE *f, Path_t path) } else if (path.type.$tag == PATH_HOME) { n += fputs("~/", f); } else if (path.type.$tag == PATH_RELATIVE) { - if (!Text$equal_values(*(Text_t*)path.components.data, Text(".."))) - n += fputs("./", f); + if (!Text$equal_values(*(Text_t *)path.components.data, Text(".."))) n += fputs("./", f); } for (int64_t i = 0; i < path.components.length; i++) { - Text_t *comp = (Text_t*)(path.components.data + i*path.components.stride); + 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 < path.components.length) n += fputc('/', f); } return n; } -public const char *Path$as_c_string(Path_t path) -{ - return String(path); -} +public +const char *Path$as_c_string(Path_t path) { return String(path); } -public Text_t Path$as_text(const void *obj, bool color, const TypeInfo_t *type) -{ +public +Text_t Path$as_text(const void *obj, bool color, const TypeInfo_t *type) { (void)type; if (!obj) return Text("Path"); - Path_t *path = (Path_t*)obj; + Path_t *path = (Path_t *)obj; Text_t text = Text$join(Text("/"), path->components); - if (path->type.$tag == PATH_HOME) - text = Text$concat(path->components.length > 0 ? Text("~/") : Text("~"), text); - else if (path->type.$tag == PATH_ABSOLUTE) - text = Text$concat(Text("/"), text); - else if (path->type.$tag == PATH_RELATIVE && (path->components.length == 0 || !Text$equal_values(*(Text_t*)(path->components.data), Text("..")))) + if (path->type.$tag == PATH_HOME) text = Text$concat(path->components.length > 0 ? Text("~/") : Text("~"), text); + else if (path->type.$tag == PATH_ABSOLUTE) text = Text$concat(Text("/"), text); + else if (path->type.$tag == PATH_RELATIVE + && (path->components.length == 0 || !Text$equal_values(*(Text_t *)(path->components.data), Text("..")))) text = Text$concat(path->components.length > 0 ? Text("./") : Text("."), text); - if (color) - text = Texts(Text("\033[32;1m"), text, Text("\033[m")); + if (color) text = Texts(Text("\033[32;1m"), text, Text("\033[m")); return text; } -public CONSTFUNC bool Path$is_none(const void *obj, const TypeInfo_t *type) -{ +public +CONSTFUNC bool Path$is_none(const void *obj, const TypeInfo_t *type) { (void)type; - return ((Path_t*)obj)->type.$tag == PATH_NONE; + return ((Path_t *)obj)->type.$tag == PATH_NONE; } -public void Path$serialize(const void *obj, FILE *out, Table_t *pointers, const TypeInfo_t *type) -{ +public +void Path$serialize(const void *obj, FILE *out, Table_t *pointers, const TypeInfo_t *type) { (void)type; - Path_t *path = (Path_t*)obj; + Path_t *path = (Path_t *)obj; fputc((int)path->type.$tag, out); List$serialize(&path->components, out, pointers, List$info(&Text$info)); } -public void Path$deserialize(FILE *in, void *obj, List_t *pointers, const TypeInfo_t *type) -{ +public +void Path$deserialize(FILE *in, void *obj, List_t *pointers, const TypeInfo_t *type) { (void)type; Path_t path = {}; path.type.$tag = fgetc(in); List$deserialize(in, &path.components, pointers, List$info(&Text$info)); - *(Path_t*)obj = path; -} - -public const TypeInfo_t Path$info = { - .size=sizeof(Path_t), - .align=__alignof__(Path_t), - .tag=OpaqueInfo, - .metamethods={ - .as_text=Path$as_text, - .hash=Path$hash, - .compare=Path$compare, - .equal=Path$equal, - .is_none=Path$is_none, - .serialize=Path$serialize, - .deserialize=Path$deserialize, - } -}; - -public const TypeInfo_t PathType$info = { - .size=sizeof(PathType_t), - .align=__alignof__(PathType_t), - .metamethods=PackedDataEnum$metamethods, - .tag=EnumInfo, - .EnumInfo={ - .name="PathType", - .num_tags=3, - .tags=((NamedType_t[3]){{.name="Relative"}, {.name="Absolute"}, {.name="Home"}}), - }, + *(Path_t *)obj = path; +} + +public +const TypeInfo_t Path$info = {.size = sizeof(Path_t), + .align = __alignof__(Path_t), + .tag = OpaqueInfo, + .metamethods = { + .as_text = Path$as_text, + .hash = Path$hash, + .compare = Path$compare, + .equal = Path$equal, + .is_none = Path$is_none, + .serialize = Path$serialize, + .deserialize = Path$deserialize, + }}; + +public +const TypeInfo_t PathType$info = { + .size = sizeof(PathType_t), + .align = __alignof__(PathType_t), + .metamethods = PackedDataEnum$metamethods, + .tag = EnumInfo, + .EnumInfo = + { + .name = "PathType", + .num_tags = 3, + .tags = ((NamedType_t[3]){{.name = "Relative"}, {.name = "Absolute"}, {.name = "Home"}}), + }, }; // vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0 diff --git a/src/stdlib/paths.h b/src/stdlib/paths.h index 6284e55b..7f0d8830 100644 --- a/src/stdlib/paths.h +++ b/src/stdlib/paths.h @@ -15,7 +15,7 @@ Path_t Path$from_text(Text_t text); const char *Path$as_c_string(Path_t path); #define Path(str) Path$from_str(str) Path_t Path$_concat(int n, Path_t items[n]); -#define Path$concat(...) Path$_concat((int)sizeof((Path_t[]){__VA_ARGS__})/sizeof(Path_t), ((Path_t[]){__VA_ARGS__})) +#define Path$concat(...) Path$_concat((int)sizeof((Path_t[]){__VA_ARGS__}) / sizeof(Path_t), ((Path_t[]){__VA_ARGS__})) Path_t Path$resolved(Path_t path, Path_t relative_to); Path_t Path$relative_to(Path_t path, Path_t relative_to); Path_t Path$expand_home(Path_t path); @@ -59,7 +59,7 @@ Path_t Path$current_dir(void); Closure_t Path$by_line(Path_t path); List_t Path$glob(Path_t path); -uint64_t Path$hash(const void *obj, const TypeInfo_t*); +uint64_t Path$hash(const void *obj, const TypeInfo_t *); int32_t Path$compare(const void *a, const void *b, const TypeInfo_t *type); bool Path$equal(const void *a, const void *b, const TypeInfo_t *type); bool Path$equal_values(Path_t a, Path_t b); @@ -72,4 +72,3 @@ extern const TypeInfo_t Path$info; extern const TypeInfo_t PathType$info; // vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0 - diff --git a/src/stdlib/pointers.c b/src/stdlib/pointers.c index 3708da62..e94ede6d 100644 --- a/src/stdlib/pointers.c +++ b/src/stdlib/pointers.c @@ -13,22 +13,19 @@ #include "types.h" #include "util.h" -public Text_t Pointer$as_text(const void *x, bool colorize, const TypeInfo_t *type) { +public +Text_t Pointer$as_text(const void *x, bool colorize, const TypeInfo_t *type) { __typeof(type->PointerInfo) ptr_info = type->PointerInfo; if (!x) { Text_t typename = generic_as_text(NULL, false, ptr_info.pointed); - if (colorize) - return Text$concat(Text("\x1b[34;1m"), Text$from_str(ptr_info.sigil), typename, Text("\x1b[m")); - else - return Text$concat(Text$from_str(ptr_info.sigil), typename); + if (colorize) return Text$concat(Text("\x1b[34;1m"), Text$from_str(ptr_info.sigil), typename, Text("\x1b[m")); + else return Text$concat(Text$from_str(ptr_info.sigil), typename); } - const void *ptr = *(const void**)x; + const void *ptr = *(const void **)x; if (!ptr) { Text_t typename = generic_as_text(NULL, false, ptr_info.pointed); - if (colorize) - return Text$concat(Text("\x1b[34;1m!"), typename, Text("\x1b[m")); - else - return Text$concat(Text("!"), typename); + if (colorize) return Text$concat(Text("\x1b[34;1m!"), typename, Text("\x1b[m")); + else return Text$concat(Text("!"), typename); } static const void *root = NULL; @@ -61,38 +58,38 @@ public Text_t Pointer$as_text(const void *x, bool colorize, const TypeInfo_t *ty } Text_t text; - if (colorize) - text = Text$concat(Text("\x1b[34;1m"), Text$from_str(ptr_info.sigil), Text("\x1b[m"), pointed); - else - text = Text$concat(Text$from_str(ptr_info.sigil), pointed); + if (colorize) text = Text$concat(Text("\x1b[34;1m"), Text$from_str(ptr_info.sigil), Text("\x1b[m"), pointed); + else text = Text$concat(Text$from_str(ptr_info.sigil), pointed); return text; } PUREFUNC public int32_t Pointer$compare(const void *x, const void *y, const TypeInfo_t *info) { (void)info; - const void *xp = *(const void**)x, *yp = *(const void**)y; + const void *xp = *(const void **)x, *yp = *(const void **)y; return (xp > yp) - (xp < yp); } PUREFUNC public bool Pointer$equal(const void *x, const void *y, const TypeInfo_t *info) { (void)info; - const void *xp = *(const void**)x, *yp = *(const void**)y; + const void *xp = *(const void **)x, *yp = *(const void **)y; return xp == yp; } -PUREFUNC public bool Pointer$is_none(const void *x, const TypeInfo_t *info) -{ +PUREFUNC public bool Pointer$is_none(const void *x, const TypeInfo_t *info) { (void)info; - return *(void**)x == NULL; + return *(void **)x == NULL; } -public void Pointer$serialize(const void *obj, FILE *out, Table_t *pointers, const TypeInfo_t *type) -{ - void *ptr = *(void**)obj; +public +void Pointer$serialize(const void *obj, FILE *out, Table_t *pointers, const TypeInfo_t *type) { + void *ptr = *(void **)obj; assert(ptr != NULL); - const TypeInfo_t ptr_to_int_table = {.size=sizeof(Table_t), .align=__alignof__(Table_t), - .tag=TableInfo, .TableInfo.key=type, .TableInfo.value=&Int64$info}; + const TypeInfo_t ptr_to_int_table = {.size = sizeof(Table_t), + .align = __alignof__(Table_t), + .tag = TableInfo, + .TableInfo.key = type, + .TableInfo.value = &Int64$info}; int64_t *id_ptr = Table$get(*pointers, &ptr, &ptr_to_int_table); int64_t id; @@ -105,23 +102,22 @@ public void Pointer$serialize(const void *obj, FILE *out, Table_t *pointers, con Int64$serialize(&id, out, pointers, &Int64$info); - if (!id_ptr) - _serialize(ptr, out, pointers, type->PointerInfo.pointed); + if (!id_ptr) _serialize(ptr, out, pointers, type->PointerInfo.pointed); } -public void Pointer$deserialize(FILE *in, void *outval, List_t *pointers, const TypeInfo_t *type) -{ +public +void Pointer$deserialize(FILE *in, void *outval, List_t *pointers, const TypeInfo_t *type) { int64_t id = 0; Int64$deserialize(in, &id, pointers, &Int64$info); assert(id != 0); if (id > pointers->length) { void *obj = GC_MALLOC((size_t)type->PointerInfo.pointed->size); - List$insert(pointers, &obj, I(0), sizeof(void*)); + List$insert(pointers, &obj, I(0), sizeof(void *)); _deserialize(in, obj, pointers, type->PointerInfo.pointed); - *(void**)outval = obj; + *(void **)outval = obj; } else { - *(void**)outval = *(void**)(pointers->data + (id-1)*pointers->stride); + *(void **)outval = *(void **)(pointers->data + (id - 1) * pointers->stride); } } diff --git a/src/stdlib/pointers.h b/src/stdlib/pointers.h index 001dc5ce..522a97be 100644 --- a/src/stdlib/pointers.h +++ b/src/stdlib/pointers.h @@ -12,25 +12,33 @@ Text_t Pointer$as_text(const void *x, bool colorize, const TypeInfo_t *type); PUREFUNC int32_t Pointer$compare(const void *x, const void *y, const TypeInfo_t *type); PUREFUNC bool Pointer$equal(const void *x, const void *y, const TypeInfo_t *type); -PUREFUNC bool Pointer$is_none(const void *x, const TypeInfo_t*); +PUREFUNC bool Pointer$is_none(const void *x, const TypeInfo_t *); void Pointer$serialize(const void *obj, FILE *out, Table_t *pointers, const TypeInfo_t *type); void Pointer$deserialize(FILE *in, void *outval, List_t *pointers, const TypeInfo_t *type); -#define Null(t) (t*)NULL -#define POINTER_TYPE(_sigil, _pointed) (&(TypeInfo_t){\ - .size=sizeof(void*), .align=__alignof__(void*), .tag=PointerInfo, .PointerInfo.sigil=_sigil, .PointerInfo.pointed=_pointed}) - -#define Pointer$metamethods { \ - .as_text=Pointer$as_text, \ - .compare=Pointer$compare, \ - .equal=Pointer$equal, \ - .is_none=Pointer$is_none, \ - .serialize=Pointer$serialize, \ - .deserialize=Pointer$deserialize, \ -} - -#define Pointer$info(sigil_expr, pointed_info) &((TypeInfo_t){.size=sizeof(void*), .align=__alignof__(void*), \ - .tag=PointerInfo, .PointerInfo={.sigil=sigil_expr, .pointed=pointed_info}, \ - .metamethods=Pointer$metamethods}) +#define Null(t) (t *)NULL +#define POINTER_TYPE(_sigil, _pointed) \ + (&(TypeInfo_t){.size = sizeof(void *), \ + .align = __alignof__(void *), \ + .tag = PointerInfo, \ + .PointerInfo.sigil = _sigil, \ + .PointerInfo.pointed = _pointed}) + +#define Pointer$metamethods \ + { \ + .as_text = Pointer$as_text, \ + .compare = Pointer$compare, \ + .equal = Pointer$equal, \ + .is_none = Pointer$is_none, \ + .serialize = Pointer$serialize, \ + .deserialize = Pointer$deserialize, \ + } + +#define Pointer$info(sigil_expr, pointed_info) \ + &((TypeInfo_t){.size = sizeof(void *), \ + .align = __alignof__(void *), \ + .tag = PointerInfo, \ + .PointerInfo = {.sigil = sigil_expr, .pointed = pointed_info}, \ + .metamethods = Pointer$metamethods}) // vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0 diff --git a/src/stdlib/powers.h b/src/stdlib/powers.h index d1829b60..e9b6a74e 100644 --- a/src/stdlib/powers.h +++ b/src/stdlib/powers.h @@ -4,13 +4,12 @@ #include <stdint.h> -#define npowers 87 -#define steppowers 8 +#define npowers 87 +#define steppowers 8 #define firstpower -348 /* 10 ^ -348 */ -#define expmax -32 -#define expmin -60 - +#define expmax -32 +#define expmin -60 typedef struct Fp { uint64_t frac; @@ -18,54 +17,37 @@ typedef struct Fp { } Fp; static const Fp powers_ten[] = { - { 18054884314459144840U, -1220 }, { 13451937075301367670U, -1193 }, - { 10022474136428063862U, -1166 }, { 14934650266808366570U, -1140 }, - { 11127181549972568877U, -1113 }, { 16580792590934885855U, -1087 }, - { 12353653155963782858U, -1060 }, { 18408377700990114895U, -1034 }, - { 13715310171984221708U, -1007 }, { 10218702384817765436U, -980 }, - { 15227053142812498563U, -954 }, { 11345038669416679861U, -927 }, - { 16905424996341287883U, -901 }, { 12595523146049147757U, -874 }, - { 9384396036005875287U, -847 }, { 13983839803942852151U, -821 }, - { 10418772551374772303U, -794 }, { 15525180923007089351U, -768 }, - { 11567161174868858868U, -741 }, { 17236413322193710309U, -715 }, - { 12842128665889583758U, -688 }, { 9568131466127621947U, -661 }, - { 14257626930069360058U, -635 }, { 10622759856335341974U, -608 }, - { 15829145694278690180U, -582 }, { 11793632577567316726U, -555 }, - { 17573882009934360870U, -529 }, { 13093562431584567480U, -502 }, - { 9755464219737475723U, -475 }, { 14536774485912137811U, -449 }, - { 10830740992659433045U, -422 }, { 16139061738043178685U, -396 }, - { 12024538023802026127U, -369 }, { 17917957937422433684U, -343 }, - { 13349918974505688015U, -316 }, { 9946464728195732843U, -289 }, - { 14821387422376473014U, -263 }, { 11042794154864902060U, -236 }, - { 16455045573212060422U, -210 }, { 12259964326927110867U, -183 }, - { 18268770466636286478U, -157 }, { 13611294676837538539U, -130 }, - { 10141204801825835212U, -103 }, { 15111572745182864684U, -77 }, - { 11258999068426240000U, -50 }, { 16777216000000000000U, -24 }, - { 12500000000000000000U, 3 }, { 9313225746154785156U, 30 }, - { 13877787807814456755U, 56 }, { 10339757656912845936U, 83 }, - { 15407439555097886824U, 109 }, { 11479437019748901445U, 136 }, - { 17105694144590052135U, 162 }, { 12744735289059618216U, 189 }, - { 9495567745759798747U, 216 }, { 14149498560666738074U, 242 }, - { 10542197943230523224U, 269 }, { 15709099088952724970U, 295 }, - { 11704190886730495818U, 322 }, { 17440603504673385349U, 348 }, - { 12994262207056124023U, 375 }, { 9681479787123295682U, 402 }, - { 14426529090290212157U, 428 }, { 10748601772107342003U, 455 }, - { 16016664761464807395U, 481 }, { 11933345169920330789U, 508 }, - { 17782069995880619868U, 534 }, { 13248674568444952270U, 561 }, - { 9871031767461413346U, 588 }, { 14708983551653345445U, 614 }, - { 10959046745042015199U, 641 }, { 16330252207878254650U, 667 }, - { 12166986024289022870U, 694 }, { 18130221999122236476U, 720 }, - { 13508068024458167312U, 747 }, { 10064294952495520794U, 774 }, - { 14996968138956309548U, 800 }, { 11173611982879273257U, 827 }, - { 16649979327439178909U, 853 }, { 12405201291620119593U, 880 }, - { 9242595204427927429U, 907 }, { 13772540099066387757U, 933 }, - { 10261342003245940623U, 960 }, { 15290591125556738113U, 986 }, - { 11392378155556871081U, 1013 }, { 16975966327722178521U, 1039 }, - { 12648080533535911531U, 1066 } -}; + {18054884314459144840U, -1220}, {13451937075301367670U, -1193}, {10022474136428063862U, -1166}, + {14934650266808366570U, -1140}, {11127181549972568877U, -1113}, {16580792590934885855U, -1087}, + {12353653155963782858U, -1060}, {18408377700990114895U, -1034}, {13715310171984221708U, -1007}, + {10218702384817765436U, -980}, {15227053142812498563U, -954}, {11345038669416679861U, -927}, + {16905424996341287883U, -901}, {12595523146049147757U, -874}, {9384396036005875287U, -847}, + {13983839803942852151U, -821}, {10418772551374772303U, -794}, {15525180923007089351U, -768}, + {11567161174868858868U, -741}, {17236413322193710309U, -715}, {12842128665889583758U, -688}, + {9568131466127621947U, -661}, {14257626930069360058U, -635}, {10622759856335341974U, -608}, + {15829145694278690180U, -582}, {11793632577567316726U, -555}, {17573882009934360870U, -529}, + {13093562431584567480U, -502}, {9755464219737475723U, -475}, {14536774485912137811U, -449}, + {10830740992659433045U, -422}, {16139061738043178685U, -396}, {12024538023802026127U, -369}, + {17917957937422433684U, -343}, {13349918974505688015U, -316}, {9946464728195732843U, -289}, + {14821387422376473014U, -263}, {11042794154864902060U, -236}, {16455045573212060422U, -210}, + {12259964326927110867U, -183}, {18268770466636286478U, -157}, {13611294676837538539U, -130}, + {10141204801825835212U, -103}, {15111572745182864684U, -77}, {11258999068426240000U, -50}, + {16777216000000000000U, -24}, {12500000000000000000U, 3}, {9313225746154785156U, 30}, + {13877787807814456755U, 56}, {10339757656912845936U, 83}, {15407439555097886824U, 109}, + {11479437019748901445U, 136}, {17105694144590052135U, 162}, {12744735289059618216U, 189}, + {9495567745759798747U, 216}, {14149498560666738074U, 242}, {10542197943230523224U, 269}, + {15709099088952724970U, 295}, {11704190886730495818U, 322}, {17440603504673385349U, 348}, + {12994262207056124023U, 375}, {9681479787123295682U, 402}, {14426529090290212157U, 428}, + {10748601772107342003U, 455}, {16016664761464807395U, 481}, {11933345169920330789U, 508}, + {17782069995880619868U, 534}, {13248674568444952270U, 561}, {9871031767461413346U, 588}, + {14708983551653345445U, 614}, {10959046745042015199U, 641}, {16330252207878254650U, 667}, + {12166986024289022870U, 694}, {18130221999122236476U, 720}, {13508068024458167312U, 747}, + {10064294952495520794U, 774}, {14996968138956309548U, 800}, {11173611982879273257U, 827}, + {16649979327439178909U, 853}, {12405201291620119593U, 880}, {9242595204427927429U, 907}, + {13772540099066387757U, 933}, {10261342003245940623U, 960}, {15290591125556738113U, 986}, + {11392378155556871081U, 1013}, {16975966327722178521U, 1039}, {12648080533535911531U, 1066}}; -static Fp find_cachedpow10(int exp, int* k) -{ +static Fp find_cachedpow10(int exp, int *k) { const double one_log_ten = 0.30102999566398114; int approx = -(exp + npowers) * one_log_ten; diff --git a/src/stdlib/print.c b/src/stdlib/print.c index 8e2dd862..d246c9c3 100644 --- a/src/stdlib/print.c +++ b/src/stdlib/print.c @@ -8,9 +8,9 @@ #include "print.h" #include "util.h" -public int _print_int(FILE *f, int64_t n) -{ - char buf[21] = {[20]=0}; // Big enough for INT64_MIN + '\0' +public +int _print_int(FILE *f, int64_t n) { + char buf[21] = {[20] = 0}; // Big enough for INT64_MIN + '\0' char *p = &buf[19]; bool negative = n < 0; @@ -19,15 +19,14 @@ public int _print_int(FILE *f, int64_t n) n /= 10; } while (n > 0); - if (negative) - *(p--) = '-'; + if (negative) *(p--) = '-'; return fwrite(p + 1, sizeof(char), (size_t)(&buf[19] - p), f); } -public int _print_uint(FILE *f, uint64_t n) -{ - char buf[21] = {[20]=0}; // Big enough for UINT64_MAX + '\0' +public +int _print_uint(FILE *f, uint64_t n) { + char buf[21] = {[20] = 0}; // Big enough for UINT64_MAX + '\0' char *p = &buf[19]; do { @@ -38,8 +37,8 @@ public int _print_uint(FILE *f, uint64_t n) return fwrite(p + 1, sizeof(char), (size_t)(&buf[19] - p), f); } -public int _print_hex(FILE *f, hex_format_t hex) -{ +public +int _print_hex(FILE *f, hex_format_t hex) { int printed = 0; if (!hex.no_prefix) printed += fputs("0x", f); if (hex.digits > 0) { @@ -50,24 +49,21 @@ public int _print_hex(FILE *f, hex_format_t hex) printed += fputc('0', f); } } - char buf[9] = {[8]='\0'}; // Enough space for FFFFFFFF + '\0' + char buf[9] = {[8] = '\0'}; // Enough space for FFFFFFFF + '\0' char *p = &buf[7]; do { uint8_t digit = hex.n % 16; - if (digit <= 9) - *(p--) = '0' + digit; - else if (hex.uppercase) - *(p--) = 'A' + digit - 10; - else - *(p--) = 'a' + digit - 10; + if (digit <= 9) *(p--) = '0' + digit; + else if (hex.uppercase) *(p--) = 'A' + digit - 10; + else *(p--) = 'a' + digit - 10; hex.n /= 16; } while (hex.n > 0); printed += (int)fwrite(p + 1, sizeof(char), (size_t)(&buf[7] - p), f); return printed; } -public int _print_oct(FILE *f, oct_format_t oct) -{ +public +int _print_oct(FILE *f, oct_format_t oct) { int printed = 0; if (!oct.no_prefix) printed += fputs("0o", f); if (oct.digits > 0) { @@ -76,7 +72,7 @@ public int _print_oct(FILE *f, oct_format_t oct) for (; oct.digits > 0; oct.digits -= 1) printed += fputc('0', f); } - char buf[12] = {[11]='\0'}; // Enough space for octal UINT64_MAX + '\0' + char buf[12] = {[11] = '\0'}; // Enough space for octal UINT64_MAX + '\0' char *p = &buf[10]; do { *(p--) = '0' + (oct.n % 8); @@ -86,25 +82,24 @@ public int _print_oct(FILE *f, oct_format_t oct) return printed; } -public int _print_double(FILE *f, double n) -{ +public +int _print_double(FILE *f, double n) { static char buf[24]; int len = fpconv_dtoa(n, buf); return (int)fwrite(buf, sizeof(char), (size_t)len, f); } -public int _print_hex_double(FILE *f, hex_double_t hex) -{ - if (hex.d != hex.d) - return fputs("NAN", f); - else if (hex.d == 1.0/0.0) - return fputs("INF", f); - else if (hex.d == -1.0/0.0) - return fputs("-INF", f); - else if (hex.d == 0.0) - return fputs("0.0", f); +public +int _print_hex_double(FILE *f, hex_double_t hex) { + if (hex.d != hex.d) return fputs("NAN", f); + else if (hex.d == 1.0 / 0.0) return fputs("INF", f); + else if (hex.d == -1.0 / 0.0) return fputs("-INF", f); + else if (hex.d == 0.0) return fputs("0.0", f); - union { double d; uint64_t u; } bits = { .d = hex.d }; + union { + double d; + uint64_t u; + } bits = {.d = hex.d}; int sign = (bits.u >> 63) & 1ull; int exp = (int)((bits.u >> 52) & 0x7FF) - 1023ull; @@ -161,30 +156,27 @@ public int _print_hex_double(FILE *f, hex_double_t hex) return fwrite(buf, sizeof(char), (size_t)(p - buf), f); } -public int _print_char(FILE *f, char c) -{ +public +int _print_char(FILE *f, char c) { #define ESC(e) "'\\" e "'" - const char *named[256] = {['\'']=ESC("'"), ['\\']=ESC("\\"), - ['\n']=ESC("n"), ['\t']=ESC("t"), ['\r']=ESC("r"), - ['\033']=ESC("e"), ['\v']=ESC("v"), ['\a']=ESC("a"), ['\b']=ESC("b")}; + const char *named[256] = { + ['\''] = ESC("'"), ['\\'] = ESC("\\"), ['\n'] = ESC("n"), ['\t'] = ESC("t"), ['\r'] = ESC("r"), + ['\033'] = ESC("e"), ['\v'] = ESC("v"), ['\a'] = ESC("a"), ['\b'] = ESC("b")}; const char *name = named[(uint8_t)c]; - if (name != NULL) - return fputs(name, f); - else if (isprint(c)) - - return fputc('\'', f) + fputc(c, f) + fputc('\'', f); + if (name != NULL) return fputs(name, f); + else if (isprint(c)) return fputc('\'', f) + fputc(c, f) + fputc('\'', f); else - return (fputs("'\\x", f) + _print_hex(f, hex((uint64_t)c, .digits=2, .no_prefix=true, .uppercase=true)) + return (fputs("'\\x", f) + _print_hex(f, hex((uint64_t)c, .digits = 2, .no_prefix = true, .uppercase = true)) + fputs("'", f)); #undef ESC } -public int _print_quoted(FILE *f, quoted_t quoted) -{ +public +int _print_quoted(FILE *f, quoted_t quoted) { #define ESC(e) "\\" e - const char *named[256] = {['"']=ESC("\""), ['\\']=ESC("\\"), - ['\n']=ESC("n"), ['\t']=ESC("t"), ['\r']=ESC("r"), - ['\033']=ESC("e"), ['\v']=ESC("v"), ['\a']=ESC("a"), ['\b']=ESC("b")}; + const char *named[256] = { + ['"'] = ESC("\""), ['\\'] = ESC("\\"), ['\n'] = ESC("n"), ['\t'] = ESC("t"), ['\r'] = ESC("r"), + ['\033'] = ESC("e"), ['\v'] = ESC("v"), ['\a'] = ESC("a"), ['\b'] = ESC("b")}; int printed = fputc('"', f); for (const char *p = quoted.str; *p; p++) { const char *name = named[(uint8_t)*p]; @@ -193,7 +185,8 @@ public int _print_quoted(FILE *f, quoted_t quoted) } else if (isprint(*p) || (uint8_t)*p > 0x7F) { printed += fputc(*p, f); } else { - printed += fputs("\\x", f) + _print_hex(f, hex((uint64_t)*p, .digits=2, .no_prefix=true, .uppercase=true)); + printed += + fputs("\\x", f) + _print_hex(f, hex((uint64_t)*p, .digits = 2, .no_prefix = true, .uppercase = true)); } } printed += fputc('"', f); @@ -202,52 +195,56 @@ public int _print_quoted(FILE *f, quoted_t quoted) } #if defined(__GLIBC__) && defined(_GNU_SOURCE) - // GLIBC has fopencookie() - static ssize_t _gc_stream_write(void *cookie, const char *buf, size_t size) { - gc_stream_t *stream = (gc_stream_t *)cookie; - if (stream->position + size + 1 > *stream->size) - *stream->buffer = GC_REALLOC(*stream->buffer, (*stream->size += MAX(MAX(16UL, *stream->size/2UL), size + 1UL))); - memcpy(&(*stream->buffer)[stream->position], buf, size); - stream->position += size; - (*stream->buffer)[stream->position] = '\0'; - return (ssize_t)size; - } +// GLIBC has fopencookie() +static ssize_t _gc_stream_write(void *cookie, const char *buf, size_t size) { + gc_stream_t *stream = (gc_stream_t *)cookie; + if (stream->position + size + 1 > *stream->size) + *stream->buffer = + GC_REALLOC(*stream->buffer, (*stream->size += MAX(MAX(16UL, *stream->size / 2UL), size + 1UL))); + memcpy(&(*stream->buffer)[stream->position], buf, size); + stream->position += size; + (*stream->buffer)[stream->position] = '\0'; + return (ssize_t)size; +} - public FILE *gc_memory_stream(char **buf, size_t *size) { - gc_stream_t *stream = GC_MALLOC(sizeof(gc_stream_t)); - stream->size = size; - stream->buffer = buf; - *stream->size = 16; - *stream->buffer = GC_MALLOC_ATOMIC(*stream->size); - (*stream->buffer)[0] = '\0'; - stream->position = 0; - cookie_io_functions_t functions = {.write = _gc_stream_write}; - return fopencookie(stream, "w", functions); - } +public +FILE *gc_memory_stream(char **buf, size_t *size) { + gc_stream_t *stream = GC_MALLOC(sizeof(gc_stream_t)); + stream->size = size; + stream->buffer = buf; + *stream->size = 16; + *stream->buffer = GC_MALLOC_ATOMIC(*stream->size); + (*stream->buffer)[0] = '\0'; + stream->position = 0; + cookie_io_functions_t functions = {.write = _gc_stream_write}; + return fopencookie(stream, "w", functions); +} #elif defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) - // BSDs have funopen() and fwopen() - static int _gc_stream_write(void *cookie, const char *buf, int size) { - gc_stream_t *stream = (gc_stream_t *)cookie; - if (stream->position + size + 1 > *stream->size) - *stream->buffer = GC_REALLOC(*stream->buffer, (*stream->size += MAX(MAX(16UL, *stream->size/2UL), size + 1UL))); - memcpy(&(*stream->buffer)[stream->position], buf, size); - stream->position += size; - (*stream->buffer)[stream->position] = '\0'; - return size; - } +// BSDs have funopen() and fwopen() +static int _gc_stream_write(void *cookie, const char *buf, int size) { + gc_stream_t *stream = (gc_stream_t *)cookie; + if (stream->position + size + 1 > *stream->size) + *stream->buffer = + GC_REALLOC(*stream->buffer, (*stream->size += MAX(MAX(16UL, *stream->size / 2UL), size + 1UL))); + memcpy(&(*stream->buffer)[stream->position], buf, size); + stream->position += size; + (*stream->buffer)[stream->position] = '\0'; + return size; +} - public FILE *gc_memory_stream(char **buf, size_t *size) { - gc_stream_t *stream = GC_MALLOC(sizeof(gc_stream_t)); - stream->size = size; - stream->buffer = buf; - *stream->size = 16; - *stream->buffer = GC_MALLOC_ATOMIC(*stream->size); - (*stream->buffer)[0] = '\0'; - stream->position = 0; - return fwopen(stream, _gc_stream_write); - } +public +FILE *gc_memory_stream(char **buf, size_t *size) { + gc_stream_t *stream = GC_MALLOC(sizeof(gc_stream_t)); + stream->size = size; + stream->buffer = buf; + *stream->size = 16; + *stream->buffer = GC_MALLOC_ATOMIC(*stream->size); + (*stream->buffer)[0] = '\0'; + stream->position = 0; + return fwopen(stream, _gc_stream_write); +} #else -# error "This platform doesn't support fopencookie() or funopen()!" +#error "This platform doesn't support fopencookie() or funopen()!" #endif // vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0 diff --git a/src/stdlib/print.h b/src/stdlib/print.h index 56953866..c7e59f8b 100644 --- a/src/stdlib/print.h +++ b/src/stdlib/print.h @@ -38,19 +38,19 @@ typedef struct { bool uppercase; int digits; } hex_format_t; -#define hex(x, ...) ((hex_format_t){.n=x, __VA_ARGS__}) +#define hex(x, ...) ((hex_format_t){.n = x, __VA_ARGS__}) typedef struct { double d; } hex_double_t; -#define hex_double(x, ...) ((hex_double_t){.d=x, __VA_ARGS__}) +#define hex_double(x, ...) ((hex_double_t){.d = x, __VA_ARGS__}) typedef struct { uint64_t n; bool no_prefix; int digits; } oct_format_t; -#define oct(x, ...) ((oct_format_t){.n=x, __VA_ARGS__}) +#define oct(x, ...) ((oct_format_t){.n = x, __VA_ARGS__}) typedef struct { const char *str; @@ -67,7 +67,7 @@ typedef struct { char c; int length; } repeated_char_t; -#define repeated_char(ch, len) ((repeated_char_t){.c=ch, .length=len}) +#define repeated_char(ch, len) ((repeated_char_t){.c = ch, .length = len}) #if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) #define FMT64 "ll" @@ -87,7 +87,9 @@ PRINT_FN _print_bool(FILE *f, bool b) { return fputs(b ? "yes" : "no", f); } PRINT_FN _print_str(FILE *f, const char *s) { return fputs(s ? s : "(null)", f); } int _print_char(FILE *f, char c); int _print_quoted(FILE *f, quoted_t quoted); -PRINT_FN _print_string_slice(FILE *f, string_slice_t slice) { return slice.str ? fwrite(slice.str, 1, slice.length, f) : (size_t)fputs("(null)", f); } +PRINT_FN _print_string_slice(FILE *f, string_slice_t slice) { + return slice.str ? fwrite(slice.str, 1, slice.length, f) : (size_t)fputs("(null)", f); +} PRINT_FN _print_repeated_char(FILE *f, repeated_char_t repeated) { int len = 0; for (int n = 0; n < repeated.length; n++) @@ -99,31 +101,32 @@ extern int Text$print(FILE *stream, Text_t text); extern int Path$print(FILE *stream, Path_t path); extern int Int$print(FILE *f, Int_t i); #ifndef _fprint1 -#define _fprint1(f, x) _Generic((x), \ - char*: _print_str, \ - const char*: _print_str, \ - char: _print_char, \ - bool: _print_bool, \ - int64_t: _print_int, \ - int32_t: _print_int, \ - int16_t: _print_int, \ - int8_t: _print_int, \ - uint64_t: _print_uint, \ - uint32_t: _print_uint, \ - uint16_t: _print_uint, \ - uint8_t: _print_uint, \ - float: _print_float, \ - double: _print_double, \ - hex_format_t: _print_hex, \ - hex_double_t: _print_hex_double, \ - oct_format_t: _print_oct, \ - quoted_t: _print_quoted, \ - string_slice_t: _print_string_slice, \ - repeated_char_t: _print_repeated_char, \ - Text_t: Text$print, \ - Path_t: Path$print, \ - Int_t: Int$print, \ - void*: _print_pointer)(f, x) +#define _fprint1(f, x) \ + _Generic((x), \ + char *: _print_str, \ + const char *: _print_str, \ + char: _print_char, \ + bool: _print_bool, \ + int64_t: _print_int, \ + int32_t: _print_int, \ + int16_t: _print_int, \ + int8_t: _print_int, \ + uint64_t: _print_uint, \ + uint32_t: _print_uint, \ + uint16_t: _print_uint, \ + uint8_t: _print_uint, \ + float: _print_float, \ + double: _print_double, \ + hex_format_t: _print_hex, \ + hex_double_t: _print_hex_double, \ + oct_format_t: _print_oct, \ + quoted_t: _print_quoted, \ + string_slice_t: _print_string_slice, \ + repeated_char_t: _print_repeated_char, \ + Text_t: Text$print, \ + Path_t: Path$print, \ + Int_t: Int$print, \ + void *: _print_pointer)(f, x) #endif typedef struct { @@ -135,19 +138,31 @@ typedef struct { FILE *gc_memory_stream(char **buf, size_t *size); #define _print(x) _n += _fprint1(_printing, x) -#define _fprint(f, ...) ({ FILE *_printing = f; int _n = 0; MAP_LIST(_print, __VA_ARGS__); _n; }) +#define _fprint(f, ...) \ + ({ \ + FILE *_printing = f; \ + int _n = 0; \ + MAP_LIST(_print, __VA_ARGS__); \ + _n; \ + }) #define fprint(f, ...) _fprint(f, __VA_ARGS__, "\n") #define print(...) fprint(stdout, __VA_ARGS__) #define fprint_inline(f, ...) _fprint(f, __VA_ARGS__) #define print_inline(...) fprint_inline(stdout, __VA_ARGS__) -#define String(...) ({ \ - char *_buf = NULL; \ - size_t _size = 0; \ - FILE *_stream = gc_memory_stream(&_buf, &_size); \ - assert(_stream); \ - _fprint(_stream, __VA_ARGS__); \ - fflush(_stream); \ - _buf; }) -#define print_err(...) ({ fprint(stderr, "\033[31;1m", __VA_ARGS__, "\033[m"); exit(EXIT_FAILURE); }) +#define String(...) \ + ({ \ + char *_buf = NULL; \ + size_t _size = 0; \ + FILE *_stream = gc_memory_stream(&_buf, &_size); \ + assert(_stream); \ + _fprint(_stream, __VA_ARGS__); \ + fflush(_stream); \ + _buf; \ + }) +#define print_err(...) \ + ({ \ + fprint(stderr, "\033[31;1m", __VA_ARGS__, "\033[m"); \ + exit(EXIT_FAILURE); \ + }) // vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0 diff --git a/src/stdlib/random.h b/src/stdlib/random.h index 8509dbd7..1a6e89a5 100644 --- a/src/stdlib/random.h +++ b/src/stdlib/random.h @@ -1,5 +1,5 @@ -#include <stdint.h> #include <assert.h> +#include <stdint.h> #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__) #include <stdlib.h> @@ -10,9 +10,9 @@ static ssize_t getrandom(void *buf, size_t buflen, unsigned int flags) { } #elif defined(__linux__) // Use getrandom() -# include <sys/random.h> +#include <sys/random.h> #else - #error "Unsupported platform for secure random number generation" +#error "Unsupported platform for secure random number generation" #endif static int64_t random_range(int64_t low, int64_t high) { diff --git a/src/stdlib/simpleparse.c b/src/stdlib/simpleparse.c index 1ee64036..3929c32b 100644 --- a/src/stdlib/simpleparse.c +++ b/src/stdlib/simpleparse.c @@ -26,41 +26,42 @@ static bool _match_word(const char **str, const char *target) { return false; } -public const char *simpleparse(const char *str, int n, parse_type_e types[n], void *destinations[n]) -{ +public +const char *simpleparse(const char *str, int n, parse_type_e types[n], void *destinations[n]) { for (int i = 0; i < n; i++) { switch (types[i]) { case PARSE_SOME_OF: { - if (destinations[i]) str += strspn(str, (char*)destinations[i]); + if (destinations[i]) str += strspn(str, (char *)destinations[i]); break; } case PARSE_LITERAL: { - const char *target = (const char*)destinations[i]; + const char *target = (const char *)destinations[i]; if (target) { - if (strncmp(str, target, strlen(target)) != 0) - return str; + if (strncmp(str, target, strlen(target)) != 0) return str; str += strlen(target); } break; } case PARSE_STRING: { size_t len; - static const char matching_pair[256] = {[(int)'(']=')', [(int)'{']='}', [(int)'[']=']', - [(int)'"']='"', [(int)'\'']='\'', [(int)'`']='`', [(int)'<']='>'}; - if (i > 0 && i + 1 < n && types[i-1] == PARSE_LITERAL && types[i+1] == PARSE_LITERAL - && destinations[i-1] && destinations[i+1] - && strlen((char*)destinations[i-1]) == 1 && strlen((char*)destinations[i+1]) == 1 - && *(char*)destinations[i+1] == matching_pair[(int)*(char*)destinations[i-1]]) { + static const char matching_pair[256] = {[(int)'('] = ')', [(int)'{'] = '}', [(int)'['] = ']', + [(int)'"'] = '"', [(int)'\''] = '\'', [(int)'`'] = '`', + [(int)'<'] = '>'}; + if (i > 0 && i + 1 < n && types[i - 1] == PARSE_LITERAL && types[i + 1] == PARSE_LITERAL + && destinations[i - 1] && destinations[i + 1] && strlen((char *)destinations[i - 1]) == 1 + && strlen((char *)destinations[i + 1]) == 1 + && *(char *)destinations[i + 1] == matching_pair[(int)*(char *)destinations[i - 1]]) { len = 0; - char special_characters[4] = {'\\', *(char*)destinations[i-1], *(char*)destinations[i+1], 0}; - for (int depth = 1; depth > 0; ) { + char special_characters[4] = {'\\', *(char *)destinations[i - 1], *(char *)destinations[i + 1], 0}; + for (int depth = 1; depth > 0;) { len += strcspn(str + len, special_characters); if (str[len] == '\0') { return str; } else if (str[len] == '\\' - && (special_characters[1] == '"' || special_characters[1] == '\'' || special_characters[1] == '`')) { - if (str[len+1] == '\0') return str; - len += 2; + && (special_characters[1] == '"' || special_characters[1] == '\'' + || special_characters[1] == '`')) { + if (str[len + 1] == '\0') return str; + len += 2; } else if (str[len] == special_characters[2]) { // Check for closing quotes before opening quotes depth -= 1; if (depth > 0) len += 1; @@ -70,8 +71,8 @@ public const char *simpleparse(const char *str, int n, parse_type_e types[n], vo len += 1; } } - } else if (i + 1 < n && types[i+1] == PARSE_LITERAL) { - const char *terminator = (const char*)destinations[i+1]; + } else if (i + 1 < n && types[i + 1] == PARSE_LITERAL) { + const char *terminator = (const char *)destinations[i + 1]; if (terminator) { const char *end = strstr(str, terminator); if (!end) return str; @@ -79,16 +80,17 @@ public const char *simpleparse(const char *str, int n, parse_type_e types[n], vo } else { len = strlen(str); } - } else if (i + 1 < n && types[i+1] == PARSE_SOME_OF) { - len = destinations[i+1] ? strcspn(str, (char*)destinations[i+1]) : strlen(str);; + } else if (i + 1 < n && types[i + 1] == PARSE_SOME_OF) { + len = destinations[i + 1] ? strcspn(str, (char *)destinations[i + 1]) : strlen(str); + ; } else { len = strlen(str); } if (destinations[i]) { - char *matched = GC_MALLOC_ATOMIC(len+1); + char *matched = GC_MALLOC_ATOMIC(len + 1); memcpy(matched, str, len); matched[len] = '\0'; - *(const char**)destinations[i] = matched; + *(const char **)destinations[i] = matched; } str += len; break; @@ -97,7 +99,7 @@ public const char *simpleparse(const char *str, int n, parse_type_e types[n], vo char *end = NULL; double val = strtod(str, &end); if (end == str) return str; - if (destinations[i]) *(double*)destinations[i] = val; + if (destinations[i]) *(double *)destinations[i] = val; str = end; break; } @@ -105,15 +107,17 @@ public const char *simpleparse(const char *str, int n, parse_type_e types[n], vo char *end = NULL; long val = strtol(str, &end, 10); if (end == str) return str; - if (destinations[i]) *(long*)destinations[i] = val; + if (destinations[i]) *(long *)destinations[i] = val; str = end; break; } case PARSE_BOOL: { - if (_match_word(&str, "true") || _match_word(&str, "yes") || _match_word(&str, "on") || _match_word(&str, "1")) { - if (destinations[i]) *(bool*)destinations[i] = true; - } else if (_match_word(&str, "false") || _match_word(&str, "no") || _match_word(&str, "off") || _match_word(&str, "0")) { - if (destinations[i]) *(bool*)destinations[i] = false; + if (_match_word(&str, "true") || _match_word(&str, "yes") || _match_word(&str, "on") + || _match_word(&str, "1")) { + if (destinations[i]) *(bool *)destinations[i] = true; + } else if (_match_word(&str, "false") || _match_word(&str, "no") || _match_word(&str, "off") + || _match_word(&str, "0")) { + if (destinations[i]) *(bool *)destinations[i] = false; } else { return str; } diff --git a/src/stdlib/simpleparse.h b/src/stdlib/simpleparse.h index da077e20..d35a8b3b 100644 --- a/src/stdlib/simpleparse.h +++ b/src/stdlib/simpleparse.h @@ -22,30 +22,42 @@ #include "mapmacro.h" -typedef struct { char c; } some_char_t; -#define PARSE_SOME_OF(chars) ((some_char_t*)chars) +typedef struct { + char c; +} some_char_t; +#define PARSE_SOME_OF(chars) ((some_char_t *)chars) #define PARSE_WHITESPACE PARSE_SOME_OF(" \t\r\n\v") -typedef enum {PARSE_LITERAL, PARSE_LONG, PARSE_DOUBLE, PARSE_BOOL, PARSE_STRING, PARSE_SOME_OF} parse_type_e; - -typedef struct { parse_type_e type; void *dest; } parse_element_t; - -#define _parse_type(dest) _Generic((dest), \ - some_char_t*: PARSE_SOME_OF, \ - const char*: PARSE_LITERAL, \ - char*: PARSE_LITERAL, \ - const char**: PARSE_STRING, \ - char**: PARSE_STRING, \ - double*: PARSE_DOUBLE, \ - long*: PARSE_LONG, \ - bool*: PARSE_BOOL) - -#define as_void_star(x) ((void*)x) -#define strparse(str, ...) simpleparse(str, sizeof((const void*[]){__VA_ARGS__})/sizeof(void*), (parse_type_e[]){MAP_LIST(_parse_type, __VA_ARGS__)}, (void*[]){MAP_LIST(as_void_star, __VA_ARGS__)}) -#define fparse(file, ...) ({ char *_file_contents = NULL; size_t _capacity; \ - ssize_t _just_read = getdelim(&_file_contents, &_capacity, '\0', file); \ - const char *_parse_err = _just_read > 0 ? strparse(_file_contents, __VA_ARGS__) : "No such file"; \ - if (_file_contents) free(_file_contents); \ - _parse_err; }) +typedef enum { PARSE_LITERAL, PARSE_LONG, PARSE_DOUBLE, PARSE_BOOL, PARSE_STRING, PARSE_SOME_OF } parse_type_e; + +typedef struct { + parse_type_e type; + void *dest; +} parse_element_t; + +#define _parse_type(dest) \ + _Generic((dest), \ + some_char_t *: PARSE_SOME_OF, \ + const char *: PARSE_LITERAL, \ + char *: PARSE_LITERAL, \ + const char **: PARSE_STRING, \ + char **: PARSE_STRING, \ + double *: PARSE_DOUBLE, \ + long *: PARSE_LONG, \ + bool *: PARSE_BOOL) + +#define as_void_star(x) ((void *)x) +#define strparse(str, ...) \ + simpleparse(str, sizeof((const void *[]){__VA_ARGS__}) / sizeof(void *), \ + (parse_type_e[]){MAP_LIST(_parse_type, __VA_ARGS__)}, (void *[]){MAP_LIST(as_void_star, __VA_ARGS__)}) +#define fparse(file, ...) \ + ({ \ + char *_file_contents = NULL; \ + size_t _capacity; \ + ssize_t _just_read = getdelim(&_file_contents, &_capacity, '\0', file); \ + const char *_parse_err = _just_read > 0 ? strparse(_file_contents, __VA_ARGS__) : "No such file"; \ + if (_file_contents) free(_file_contents); \ + _parse_err; \ + }) const char *simpleparse(const char *str, int n, parse_type_e types[n], void *destinations[n]); diff --git a/src/stdlib/siphash-internals.h b/src/stdlib/siphash-internals.h index b359cea7..c8ec1142 100644 --- a/src/stdlib/siphash-internals.h +++ b/src/stdlib/siphash-internals.h @@ -51,24 +51,25 @@ struct siphash { uint64_t v1; uint64_t v2; uint64_t v3; - uint64_t b; + uint64_t b; }; typedef struct siphash siphash; -#define ROTATE(x, b) (uint64_t)( ((x) << (b)) | ( (x) >> (64 - (b))) ) +#define ROTATE(x, b) (uint64_t)(((x) << (b)) | ((x) >> (64 - (b)))) -#define HALF_ROUND(a,b,c,d,s,t) \ - a += b; c += d; \ - b = ROTATE(b, s) ^ a; \ - d = ROTATE(d, t) ^ c; \ +#define HALF_ROUND(a, b, c, d, s, t) \ + a += b; \ + c += d; \ + b = ROTATE(b, s) ^ a; \ + d = ROTATE(d, t) ^ c; \ a = ROTATE(a, 32); -#define DOUBLE_ROUND(v0,v1,v2,v3) \ - HALF_ROUND(v0,v1,v2,v3,13,16); \ - HALF_ROUND(v2,v1,v0,v3,17,21); \ - HALF_ROUND(v0,v1,v2,v3,13,16); \ - HALF_ROUND(v2,v1,v0,v3,17,21); +#define DOUBLE_ROUND(v0, v1, v2, v3) \ + HALF_ROUND(v0, v1, v2, v3, 13, 16); \ + HALF_ROUND(v2, v1, v0, v3, 17, 21); \ + HALF_ROUND(v0, v1, v2, v3, 13, 16); \ + HALF_ROUND(v2, v1, v0, v3, 17, 21); -MACROLIKE void siphashinit (siphash *sh, size_t src_sz) { +MACROLIKE void siphashinit(siphash *sh, size_t src_sz) { const uint64_t k0 = TOMO_HASH_KEY[0]; const uint64_t k1 = TOMO_HASH_KEY[1]; sh->b = (uint64_t)src_sz << 56; @@ -77,20 +78,20 @@ MACROLIKE void siphashinit (siphash *sh, size_t src_sz) { sh->v2 = k0 ^ 0x6c7967656e657261ULL; sh->v3 = k1 ^ 0x7465646279746573ULL; } -MACROLIKE void siphashadd64bits (siphash *sh, const uint64_t in) { +MACROLIKE void siphashadd64bits(siphash *sh, const uint64_t in) { const uint64_t mi = in; sh->v3 ^= mi; - DOUBLE_ROUND(sh->v0,sh->v1,sh->v2,sh->v3); + DOUBLE_ROUND(sh->v0, sh->v1, sh->v2, sh->v3); sh->v0 ^= mi; } -MACROLIKE uint64_t siphashfinish_last_part (siphash *sh, uint64_t t) { +MACROLIKE uint64_t siphashfinish_last_part(siphash *sh, uint64_t t) { sh->b |= t; sh->v3 ^= sh->b; - DOUBLE_ROUND(sh->v0,sh->v1,sh->v2,sh->v3); + DOUBLE_ROUND(sh->v0, sh->v1, sh->v2, sh->v3); sh->v0 ^= sh->b; sh->v2 ^= 0xff; - DOUBLE_ROUND(sh->v0,sh->v1,sh->v2,sh->v3); - DOUBLE_ROUND(sh->v0,sh->v1,sh->v2,sh->v3); + DOUBLE_ROUND(sh->v0, sh->v1, sh->v2, sh->v3); + DOUBLE_ROUND(sh->v0, sh->v1, sh->v2, sh->v3); return (sh->v0 ^ sh->v1) ^ (sh->v2 ^ sh->v3); } /* This union helps us avoid doing weird things with pointers that can cause old @@ -99,26 +100,26 @@ MACROLIKE uint64_t siphashfinish_last_part (siphash *sh, uint64_t t) { union SipHash64_union { uint64_t u64; uint32_t u32; - uint8_t u8[8]; + uint8_t u8[8]; }; -MACROLIKE uint64_t siphashfinish (siphash *sh, const uint8_t *src, size_t src_sz) { - union SipHash64_union t = { 0 }; +MACROLIKE uint64_t siphashfinish(siphash *sh, const uint8_t *src, size_t src_sz) { + union SipHash64_union t = {0}; switch (src_sz) { - /* Falls through */ - case 7: t.u8[6] = src[6]; - /* Falls through */ - case 6: t.u8[5] = src[5]; - /* Falls through */ - case 5: t.u8[4] = src[4]; - /* Falls through */ - case 4: t.u8[3] = src[3]; - /* Falls through */ - case 3: t.u8[2] = src[2]; - /* Falls through */ - case 2: t.u8[1] = src[1]; - /* Falls through */ - case 1: t.u8[0] = src[0]; - default: break; + /* Falls through */ + case 7: t.u8[6] = src[6]; + /* Falls through */ + case 6: t.u8[5] = src[5]; + /* Falls through */ + case 5: t.u8[4] = src[4]; + /* Falls through */ + case 4: t.u8[3] = src[3]; + /* Falls through */ + case 3: t.u8[2] = src[2]; + /* Falls through */ + case 2: t.u8[1] = src[1]; + /* Falls through */ + case 1: t.u8[0] = src[0]; + default: break; } return siphashfinish_last_part(sh, t.u64); } diff --git a/src/stdlib/siphash.c b/src/stdlib/siphash.c index 274b3195..9af845e7 100644 --- a/src/stdlib/siphash.c +++ b/src/stdlib/siphash.c @@ -5,7 +5,8 @@ #include "siphash.h" #include "util.h" -public uint64_t TOMO_HASH_KEY[2] = {23, 42}; // Randomized in tomo_init() +public +uint64_t TOMO_HASH_KEY[2] = {23, 42}; // Randomized in tomo_init() /* <MIT License> Copyright (c) 2013 Marek Majkowski <marek@popcount.org> @@ -53,10 +54,10 @@ PUREFUNC public uint64_t siphash24(const uint8_t *src, size_t src_sz) { #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wcast-align" #endif - const uint64_t *in = (uint64_t*)src; + const uint64_t *in = (uint64_t *)src; /* Find largest src_sz evenly divisible by 8 bytes. */ const ptrdiff_t src_sz_nearest_8bits = ((ptrdiff_t)src_sz >> 3) << 3; - const uint64_t *goal = (uint64_t*)(src + src_sz_nearest_8bits); + const uint64_t *goal = (uint64_t *)(src + src_sz_nearest_8bits); #ifdef __GNUC__ #pragma GCC diagnostic pop #endif @@ -74,7 +75,8 @@ PUREFUNC public uint64_t siphash24(const uint8_t *src, size_t src_sz) { uint64_t in_64; memcpy(&in_64, in, sizeof(uint64_t)); siphashadd64bits(&sh, in_64); - in += 8; src_sz -= 8; + in += 8; + src_sz -= 8; } return siphashfinish(&sh, (uint8_t *)in, src_sz); } diff --git a/src/stdlib/siphash.h b/src/stdlib/siphash.h index 67bad582..3dbef0fd 100644 --- a/src/stdlib/siphash.h +++ b/src/stdlib/siphash.h @@ -2,8 +2,8 @@ // An implementation of the SipHash algorithm. -#include <stdint.h> #include <stddef.h> +#include <stdint.h> #include "util.h" diff --git a/src/stdlib/stacktrace.c b/src/stdlib/stacktrace.c index f408d753..9f01a4bf 100644 --- a/src/stdlib/stacktrace.c +++ b/src/stdlib/stacktrace.c @@ -1,6 +1,6 @@ #ifndef _GNU_SOURCE #define _GNU_SOURCE -#endif +#endif #include <dlfcn.h> #include <err.h> @@ -19,8 +19,7 @@ extern bool USE_COLOR; -static void fprint_context(FILE *out, const char *filename, int lineno, int context_before, int context_after) -{ +static void fprint_context(FILE *out, const char *filename, int lineno, int context_before, int context_after) { FILE *f = fopen(filename, "r"); if (!f) return; char *line = NULL; @@ -33,35 +32,31 @@ static void fprint_context(FILE *out, const char *filename, int lineno, int cont num_width += 1; while ((nread = getline(&line, &size, f)) != -1) { - if (line[strlen(line)-1] == '\n') - line[strlen(line)-1] = '\0'; + if (line[strlen(line) - 1] == '\n') line[strlen(line) - 1] = '\0'; if (cur_line >= lineno - context_before) { int w = 1; - for (int n = cur_line; n >= 10; n /= 10) w += 1; + for (int n = cur_line; n >= 10; n /= 10) + w += 1; if (USE_COLOR) { fprint(out, cur_line == lineno ? "\033[31;1m>\033[m " : " ", "\033[2m", - repeated_char(' ', num_width-w), - cur_line, "\033(0\x78\033(B", cur_line == lineno ? "\033[0;31;1m" : "\033[0m", - line, "\033[m"); + repeated_char(' ', num_width - w), cur_line, "\033(0\x78\033(B", + cur_line == lineno ? "\033[0;31;1m" : "\033[0m", line, "\033[m"); } else { - fprint(out, cur_line == lineno ? "> " : " ", - repeated_char(' ', num_width-w), - cur_line, "| ", line); + fprint(out, cur_line == lineno ? "> " : " ", repeated_char(' ', num_width - w), cur_line, "| ", line); } } cur_line += 1; - if (cur_line > lineno + context_after) - break; + if (cur_line > lineno + context_after) break; } if (line) free(line); fclose(f); } -static void _print_stack_frame(FILE *out, const char *cwd, const char *install_dir, const char *function, const char *filename, int lineno) -{ +static void _print_stack_frame(FILE *out, const char *cwd, const char *install_dir, const char *function, + const char *filename, int lineno) { if (function == NULL) { fprint(out, USE_COLOR ? "\033[2m...unknown function...\033[m" : "...unknown function..."); return; @@ -71,7 +66,7 @@ static void _print_stack_frame(FILE *out, const char *cwd, const char *install_d if (function[0] == '\0') function = "???"; char *function_display = GC_MALLOC_ATOMIC(strlen(function)); - memcpy(function_display, function, strlen(function)+1); + memcpy(function_display, function, strlen(function) + 1); char *last_dollar = strrchr(function_display, '$'); if (last_dollar) *last_dollar = '\0'; for (char *p = function_display; *p; p++) { @@ -79,14 +74,12 @@ static void _print_stack_frame(FILE *out, const char *cwd, const char *install_d } if (filename) { - if (strncmp(filename, cwd, strlen(cwd)) == 0) - filename += strlen(cwd); + if (strncmp(filename, cwd, strlen(cwd)) == 0) filename += strlen(cwd); fprint_inline(out, USE_COLOR ? "\033[1mIn \033[33m" : "In ", function_display, USE_COLOR ? "()\033[37m" : "()"); if (install_dir[0] && strncmp(filename, install_dir, strlen(install_dir)) == 0) fprint_inline(out, USE_COLOR ? " in library \033[35m" : " in library ", filename, ":", lineno); - else - fprint(out, USE_COLOR ? " in \033[35m" : " in ", filename, ":", lineno); + else fprint(out, USE_COLOR ? " in \033[35m" : " in ", filename, ":", lineno); fprint(out, USE_COLOR ? "\033[m" : ""); fprint_context(out, filename, lineno, 3, 1); } else { @@ -94,48 +87,41 @@ static void _print_stack_frame(FILE *out, const char *cwd, const char *install_d } } -__attribute__ ((noinline)) -public void print_stacktrace(FILE *out, int offset) -{ +__attribute__((noinline)) public +void print_stacktrace(FILE *out, int offset) { char cwd[PATH_MAX]; - if (getcwd(cwd, sizeof(cwd)) == NULL) - errx(1, "Path too large!"); + if (getcwd(cwd, sizeof(cwd)) == NULL) errx(1, "Path too large!"); size_t cwd_len = strlen(cwd); - if (cwd_len + 2 > sizeof(cwd)) - errx(1, "Path too large!"); + if (cwd_len + 2 > sizeof(cwd)) errx(1, "Path too large!"); cwd[cwd_len++] = '/'; cwd[cwd_len] = '\0'; - const char *install_dir = TOMO_PREFIX"/share/tomo_"TOMO_VERSION"/installed/"; + const char *install_dir = TOMO_PREFIX "/share/tomo_" TOMO_VERSION "/installed/"; static void *stack[1024]; - int64_t size = (int64_t)backtrace(stack, sizeof(stack)/sizeof(stack[0])); + int64_t size = (int64_t)backtrace(stack, sizeof(stack) / sizeof(stack[0])); char **strings = backtrace_symbols(stack, size); bool main_func_onwards = false; - for (int64_t i = size-1; i > offset; i--) { + for (int64_t i = size - 1; i > offset; i--) { Dl_info info; - void *call_address = stack[i]-1; + void *call_address = stack[i] - 1; if (dladdr(call_address, &info) && info.dli_fname) { const char *file = info.dli_fname; uintptr_t frame_offset = (uintptr_t)call_address - (uintptr_t)info.dli_fbase; - FILE *fp = popen(String("addr2line -f -e '", file, "' ", (void*)frame_offset, " 2>/dev/null"), "r"); + FILE *fp = popen(String("addr2line -f -e '", file, "' ", (void *)frame_offset, " 2>/dev/null"), "r"); if (fp) { const char *function = NULL, *filename = NULL; long line_num = 0; if (fparse(fp, &function, "\n", &filename, ":", &line_num) == NULL) { - if (starts_with(function, "main$")) - main_func_onwards = true; - if (main_func_onwards) - _print_stack_frame(out, cwd, install_dir, function, filename, line_num); + if (starts_with(function, "main$")) main_func_onwards = true; + if (main_func_onwards) _print_stack_frame(out, cwd, install_dir, function, filename, line_num); } else { - if (main_func_onwards) - _print_stack_frame(out, cwd, install_dir, NULL, NULL, line_num); + if (main_func_onwards) _print_stack_frame(out, cwd, install_dir, NULL, NULL, line_num); } pclose(fp); } } else { - if (main_func_onwards) - _print_stack_frame(out, cwd, install_dir, NULL, NULL, 0); + if (main_func_onwards) _print_stack_frame(out, cwd, install_dir, NULL, NULL, 0); } if (main_func_onwards && i - 1 > offset) fputs("\n", out); } diff --git a/src/stdlib/stacktrace.h b/src/stdlib/stacktrace.h index 828bbe98..36e81bea 100644 --- a/src/stdlib/stacktrace.h +++ b/src/stdlib/stacktrace.h @@ -1,5 +1,4 @@ #pragma once #include <stdio.h> -__attribute__ ((noinline)) -void print_stacktrace(FILE *out, int offset); +__attribute__((noinline)) void print_stacktrace(FILE *out, int offset); diff --git a/src/stdlib/stdlib.c b/src/stdlib/stdlib.c index 159acdb3..411ce300 100644 --- a/src/stdlib/stdlib.c +++ b/src/stdlib/stdlib.c @@ -37,16 +37,17 @@ static ssize_t getrandom(void *buf, size_t buflen, unsigned int flags) { } #elif defined(__linux__) // Use getrandom() -# include <sys/random.h> +#include <sys/random.h> #else - #error "Unsupported platform for secure random number generation" +#error "Unsupported platform for secure random number generation" #endif -public bool USE_COLOR; -public Text_t TOMO_VERSION_TEXT = Text(TOMO_VERSION); +public +bool USE_COLOR; +public +Text_t TOMO_VERSION_TEXT = Text(TOMO_VERSION); -static _Noreturn void signal_handler(int sig, siginfo_t *info, void *userdata) -{ +static _Noreturn void signal_handler(int sig, siginfo_t *info, void *userdata) { (void)info, (void)userdata; assert(sig == SIGILL); fflush(stdout); @@ -58,107 +59,92 @@ static _Noreturn void signal_handler(int sig, siginfo_t *info, void *userdata) _exit(1); } -public void tomo_init(void) -{ - GC_INIT(); - USE_COLOR = getenv("COLOR") ? strcmp(getenv("COLOR"), "1") == 0 : isatty(STDOUT_FILENO); - if (getenv("NO_COLOR") && getenv("NO_COLOR")[0] != '\0') - USE_COLOR = false; - - setlocale(LC_ALL, ""); - assert(getrandom(TOMO_HASH_KEY, sizeof(TOMO_HASH_KEY), 0) == sizeof(TOMO_HASH_KEY)); - - struct sigaction sigact; - sigact.sa_sigaction = signal_handler; - sigemptyset(&sigact.sa_mask); - sigact.sa_flags = 0; - sigaction(SIGILL, &sigact, (struct sigaction *)NULL); +public +void tomo_init(void) { + GC_INIT(); + USE_COLOR = getenv("COLOR") ? strcmp(getenv("COLOR"), "1") == 0 : isatty(STDOUT_FILENO); + if (getenv("NO_COLOR") && getenv("NO_COLOR")[0] != '\0') USE_COLOR = false; + + setlocale(LC_ALL, ""); + assert(getrandom(TOMO_HASH_KEY, sizeof(TOMO_HASH_KEY), 0) == sizeof(TOMO_HASH_KEY)); + + struct sigaction sigact; + sigact.sa_sigaction = signal_handler; + sigemptyset(&sigact.sa_mask); + sigact.sa_flags = 0; + sigaction(SIGILL, &sigact, (struct sigaction *)NULL); } -static bool parse_single_arg(const TypeInfo_t *info, char *arg, void *dest) -{ +static bool parse_single_arg(const TypeInfo_t *info, char *arg, void *dest) { if (!arg) return false; - if (info->tag == OptionalInfo && streq(arg, "none")) - return true; + if (info->tag == OptionalInfo && streq(arg, "none")) return true; while (info->tag == OptionalInfo) info = info->OptionalInfo.type; if (info == &Int$info) { OptionalInt_t parsed = Int$from_str(arg); - if (parsed.small != 0) - *(OptionalInt_t*)dest = parsed; + if (parsed.small != 0) *(OptionalInt_t *)dest = parsed; return parsed.small != 0; } else if (info == &Int64$info) { OptionalInt64_t parsed = Int64$parse(Text$from_str(arg), NULL); - if (!parsed.is_none) - *(OptionalInt64_t*)dest = parsed; + if (!parsed.is_none) *(OptionalInt64_t *)dest = parsed; return !parsed.is_none; } else if (info == &Int32$info) { OptionalInt32_t parsed = Int32$parse(Text$from_str(arg), NULL); - if (!parsed.is_none) - *(OptionalInt32_t*)dest = parsed; + if (!parsed.is_none) *(OptionalInt32_t *)dest = parsed; return !parsed.is_none; } else if (info == &Int16$info) { OptionalInt16_t parsed = Int16$parse(Text$from_str(arg), NULL); - if (!parsed.is_none) - *(OptionalInt16_t*)dest = parsed; + if (!parsed.is_none) *(OptionalInt16_t *)dest = parsed; return !parsed.is_none; } else if (info == &Int8$info) { OptionalInt8_t parsed = Int8$parse(Text$from_str(arg), NULL); - if (!parsed.is_none) - *(OptionalInt8_t*)dest = parsed; + if (!parsed.is_none) *(OptionalInt8_t *)dest = parsed; return !parsed.is_none; } else if (info == &Bool$info) { OptionalBool_t parsed = Bool$parse(Text$from_str(arg), NULL); - if (parsed != NONE_BOOL) - *(OptionalBool_t*)dest = parsed; + if (parsed != NONE_BOOL) *(OptionalBool_t *)dest = parsed; return parsed != NONE_BOOL; } else if (info == &Num$info) { OptionalNum_t parsed = Num$parse(Text$from_str(arg), NULL); - if (!isnan(parsed)) - *(OptionalNum_t*)dest = parsed; + if (!isnan(parsed)) *(OptionalNum_t *)dest = parsed; return !isnan(parsed); } else if (info == &Num32$info) { OptionalNum32_t parsed = Num32$parse(Text$from_str(arg), NULL); - if (!isnan(parsed)) - *(OptionalNum32_t*)dest = parsed; + if (!isnan(parsed)) *(OptionalNum32_t *)dest = parsed; return !isnan(parsed); } else if (info == &Path$info) { - *(OptionalPath_t*)dest = Path$from_str(arg); + *(OptionalPath_t *)dest = Path$from_str(arg); return true; } else if (info->tag == TextInfo) { - *(OptionalText_t*)dest = Text$from_str(arg); + *(OptionalText_t *)dest = Text$from_str(arg); return true; } else if (info->tag == EnumInfo) { for (int t = 0; t < info->EnumInfo.num_tags; t++) { NamedType_t named = info->EnumInfo.tags[t]; size_t len = strlen(named.name); if (strncmp(arg, named.name, len) == 0 && (arg[len] == '\0' || arg[len] == ':')) { - *(int32_t*)dest = (t + 1); + *(int32_t *)dest = (t + 1); // Simple tag (no associated data): if (!named.type || (named.type->tag == StructInfo && named.type->StructInfo.num_fields == 0)) return true; // Single-argument tag: - if (arg[len] != ':') - print_err("Invalid value for ", t, ".", named.name, ": ", arg); + if (arg[len] != ':') print_err("Invalid value for ", t, ".", named.name, ": ", arg); size_t offset = sizeof(int32_t); if (named.type->align > 0 && offset % (size_t)named.type->align > 0) offset += (size_t)named.type->align - (offset % (size_t)named.type->align); - if (!parse_single_arg(named.type, arg + len + 1, dest + offset)) - return false; + if (!parse_single_arg(named.type, arg + len + 1, dest + offset)) return false; return true; } } print_err("Invalid value for ", info->EnumInfo.name, ": ", arg); } else if (info->tag == StructInfo) { - if (info->StructInfo.num_fields == 0) - return true; - else if (info->StructInfo.num_fields == 1) - return parse_single_arg(info->StructInfo.fields[0].type, arg, dest); + if (info->StructInfo.num_fields == 0) return true; + else if (info->StructInfo.num_fields == 1) return parse_single_arg(info->StructInfo.fields[0].type, arg, dest); Text_t t = generic_as_text(NULL, false, info); print_err("Unsupported multi-argument struct type for argument parsing: ", t); @@ -173,41 +159,36 @@ static bool parse_single_arg(const TypeInfo_t *info, char *arg, void *dest) return false; } -static List_t parse_list(const TypeInfo_t *item_info, int n, char *args[]) -{ +static List_t parse_list(const TypeInfo_t *item_info, int n, char *args[]) { int64_t padded_size = item_info->size; if ((padded_size % item_info->align) > 0) padded_size = padded_size + item_info->align - (padded_size % item_info->align); List_t items = { - .stride=padded_size, - .length=n, - .data=GC_MALLOC((size_t)(padded_size*n)), + .stride = padded_size, + .length = n, + .data = GC_MALLOC((size_t)(padded_size * n)), }; for (int i = 0; i < n; i++) { - bool success = parse_single_arg(item_info, args[i], items.data + items.stride*i); - if (!success) - print_err("Couldn't parse argument: ", args[i]); + bool success = parse_single_arg(item_info, args[i], items.data + items.stride * i); + if (!success) print_err("Couldn't parse argument: ", args[i]); } return items; } // Arguments take the form key=value, with a guarantee that there is an '=' -static Table_t parse_table(const TypeInfo_t *table, int n, char *args[]) -{ +static Table_t parse_table(const TypeInfo_t *table, int n, char *args[]) { const TypeInfo_t *key = table->TableInfo.key, *value = table->TableInfo.value; int64_t padded_size = key->size; - if ((padded_size % value->align) > 0) - padded_size = padded_size + value->align - (padded_size % value->align); + if ((padded_size % value->align) > 0) padded_size = padded_size + value->align - (padded_size % value->align); int64_t value_offset = padded_size; padded_size += value->size; - if ((padded_size % key->align) > 0) - padded_size = padded_size + key->align - (padded_size % key->align); + if ((padded_size % key->align) > 0) padded_size = padded_size + key->align - (padded_size % key->align); List_t entries = { - .stride=padded_size, - .length=n, - .data=GC_MALLOC((size_t)(padded_size*n)), + .stride = padded_size, + .length = n, + .data = GC_MALLOC((size_t)(padded_size * n)), }; for (int i = 0; i < n; i++) { char *key_arg = args[i]; @@ -216,13 +197,11 @@ static Table_t parse_table(const TypeInfo_t *table, int n, char *args[]) char *value_arg = equals + 1; *equals = '\0'; - bool success = parse_single_arg(key, key_arg, entries.data + entries.stride*i); - if (!success) - print_err("Couldn't parse table key: ", key_arg); + bool success = parse_single_arg(key, key_arg, entries.data + entries.stride * i); + if (!success) print_err("Couldn't parse table key: ", key_arg); - success = parse_single_arg(value, value_arg, entries.data + entries.stride*i + value_offset); - if (!success) - print_err("Couldn't parse table value: ", value_arg); + success = parse_single_arg(value, value_arg, entries.data + entries.stride * i + value_offset); + if (!success) print_err("Couldn't parse table value: ", value_arg); *equals = '='; } @@ -233,13 +212,14 @@ static Table_t parse_table(const TypeInfo_t *table, int n, char *args[]) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wstack-protector" #endif -public void _tomo_parse_args(int argc, char *argv[], Text_t usage, Text_t help, const char *version, int spec_len, cli_arg_t spec[spec_len]) -{ +public +void _tomo_parse_args(int argc, char *argv[], Text_t usage, Text_t help, const char *version, int spec_len, + cli_arg_t spec[spec_len]) { bool populated_args[spec_len]; bool used_args[argc]; memset(populated_args, 0, sizeof(populated_args)); memset(used_args, 0, sizeof(used_args)); - for (int i = 1; i < argc; ) { + for (int i = 1; i < argc;) { if (argv[i][0] == '-' && argv[i][1] == '-') { if (argv[i][2] == '\0') { // "--" signals the rest of the arguments are literal used_args[i] = true; @@ -252,58 +232,54 @@ public void _tomo_parse_args(int argc, char *argv[], Text_t usage, Text_t help, while (non_opt_type->tag == OptionalInfo) non_opt_type = non_opt_type->OptionalInfo.type; - if (non_opt_type == &Bool$info - && strncmp(argv[i], "--no-", strlen("--no-")) == 0 + if (non_opt_type == &Bool$info && strncmp(argv[i], "--no-", strlen("--no-")) == 0 && strcmp(argv[i] + strlen("--no-"), spec[s].name) == 0) { - *(OptionalBool_t*)spec[s].dest = false; + *(OptionalBool_t *)spec[s].dest = false; populated_args[s] = true; used_args[i] = true; goto next_arg; } - if (strncmp(spec[s].name, argv[i] + 2, strlen(spec[s].name)) != 0) - continue; + if (strncmp(spec[s].name, argv[i] + 2, strlen(spec[s].name)) != 0) continue; - char after_name = argv[i][2+strlen(spec[s].name)]; + char after_name = argv[i][2 + strlen(spec[s].name)]; if (after_name == '\0') { // --foo val used_args[i] = true; if (non_opt_type->tag == ListInfo) { int num_args = 0; while (i + 1 + num_args < argc) { - if (argv[i+1+num_args][0] == '-') - break; - used_args[i+1+num_args] = true; + if (argv[i + 1 + num_args][0] == '-') break; + used_args[i + 1 + num_args] = true; num_args += 1; } populated_args[s] = true; - *(OptionalList_t*)spec[s].dest = parse_list(non_opt_type->ListInfo.item, num_args, &argv[i+1]); + *(OptionalList_t *)spec[s].dest = + parse_list(non_opt_type->ListInfo.item, num_args, &argv[i + 1]); } else if (non_opt_type->tag == TableInfo) { int num_args = 0; while (i + 1 + num_args < argc) { - if (argv[i+1+num_args][0] == '-' || !strchr(argv[i+1+num_args], '=')) - break; - used_args[i+1+num_args] = true; + if (argv[i + 1 + num_args][0] == '-' || !strchr(argv[i + 1 + num_args], '=')) break; + used_args[i + 1 + num_args] = true; num_args += 1; } populated_args[s] = true; - *(OptionalTable_t*)spec[s].dest = parse_table(non_opt_type, num_args, &argv[i+1]); + *(OptionalTable_t *)spec[s].dest = parse_table(non_opt_type, num_args, &argv[i + 1]); } else if (non_opt_type == &Bool$info) { // --flag populated_args[s] = true; - *(OptionalBool_t*)spec[s].dest = true; + *(OptionalBool_t *)spec[s].dest = true; } else { - if (i + 1 >= argc) - print_err("Missing argument: ", argv[i], "\n", usage); - used_args[i+1] = true; - populated_args[s] = parse_single_arg(spec[s].type, argv[i+1], spec[s].dest); + if (i + 1 >= argc) print_err("Missing argument: ", argv[i], "\n", usage); + used_args[i + 1] = true; + populated_args[s] = parse_single_arg(spec[s].type, argv[i + 1], spec[s].dest); if (!populated_args[s]) - print_err("Couldn't parse argument: ", argv[i], " ", argv[i+1], "\n", usage); + print_err("Couldn't parse argument: ", argv[i], " ", argv[i + 1], "\n", usage); } goto next_arg; } else if (after_name == '=') { // --foo=val used_args[i] = true; - populated_args[s] = parse_single_arg(spec[s].type, 2 + argv[i] + strlen(spec[s].name) + 1, spec[s].dest); - if (!populated_args[s]) - print_err("Couldn't parse argument: ", argv[i], "\n", usage); + populated_args[s] = + parse_single_arg(spec[s].type, 2 + argv[i] + strlen(spec[s].name) + 1, spec[s].dest); + if (!populated_args[s]) print_err("Couldn't parse argument: ", argv[i], "\n", usage); goto next_arg; } else { continue; @@ -324,8 +300,7 @@ public void _tomo_parse_args(int argc, char *argv[], Text_t usage, Text_t help, for (char *f = argv[i] + 1; *f; f++) { char flag[] = {'-', *f, 0}; for (int s = 0; s < spec_len; s++) { - if (spec[s].name[0] != *f || strlen(spec[s].name) > 1) - continue; + if (spec[s].name[0] != *f || strlen(spec[s].name) > 1) continue; const TypeInfo_t *non_opt_type = spec[s].type; while (non_opt_type->tag == OptionalInfo) @@ -335,32 +310,31 @@ public void _tomo_parse_args(int argc, char *argv[], Text_t usage, Text_t help, if (f[1]) print_err("No value provided for ", flag, "\n", usage); int num_args = 0; while (i + 1 + num_args < argc) { - if (argv[i+1+num_args][0] == '-') - break; - used_args[i+1+num_args] = true; + if (argv[i + 1 + num_args][0] == '-') break; + used_args[i + 1 + num_args] = true; num_args += 1; } populated_args[s] = true; - *(OptionalList_t*)spec[s].dest = parse_list(non_opt_type->ListInfo.item, num_args, &argv[i+1]); + *(OptionalList_t *)spec[s].dest = + parse_list(non_opt_type->ListInfo.item, num_args, &argv[i + 1]); } else if (non_opt_type->tag == TableInfo) { int num_args = 0; while (i + 1 + num_args < argc) { - if (argv[i+1+num_args][0] == '-' || !strchr(argv[i+1+num_args], '=')) - break; - used_args[i+1+num_args] = true; + if (argv[i + 1 + num_args][0] == '-' || !strchr(argv[i + 1 + num_args], '=')) break; + used_args[i + 1 + num_args] = true; num_args += 1; } populated_args[s] = true; - *(OptionalTable_t*)spec[s].dest = parse_table(non_opt_type, num_args, &argv[i+1]); + *(OptionalTable_t *)spec[s].dest = parse_table(non_opt_type, num_args, &argv[i + 1]); } else if (non_opt_type == &Bool$info) { // -f populated_args[s] = true; - *(OptionalBool_t*)spec[s].dest = true; + *(OptionalBool_t *)spec[s].dest = true; } else { - if (f[1] || i+1 >= argc) print_err("No value provided for ", flag, "\n", usage); - used_args[i+1] = true; - populated_args[s] = parse_single_arg(spec[s].type, argv[i+1], spec[s].dest); + if (f[1] || i + 1 >= argc) print_err("No value provided for ", flag, "\n", usage); + used_args[i + 1] = true; + populated_args[s] = parse_single_arg(spec[s].type, argv[i + 1], spec[s].dest); if (!populated_args[s]) - print_err("Couldn't parse argument: ", argv[i], " ", argv[i+1], "\n", usage); + print_err("Couldn't parse argument: ", argv[i], " ", argv[i + 1], "\n", usage); } goto next_flag; } @@ -370,7 +344,7 @@ public void _tomo_parse_args(int argc, char *argv[], Text_t usage, Text_t help, exit(0); } print_err("Unrecognized flag: ", flag, "\n", usage); - next_flag:; + next_flag:; } } else { // Handle positional args later @@ -378,7 +352,7 @@ public void _tomo_parse_args(int argc, char *argv[], Text_t usage, Text_t help, continue; } - next_arg: + next_arg: while (used_args[i] && i < argc) i += 1; } @@ -393,10 +367,9 @@ public void _tomo_parse_args(int argc, char *argv[], Text_t usage, Text_t help, if (used_args[i]) continue; while (populated_args[s]) { - next_non_bool_flag: + next_non_bool_flag: ++s; - if (s >= spec_len) - print_err("Extra argument: ", argv[i], "\n", usage); + if (s >= spec_len) print_err("Extra argument: ", argv[i], "\n", usage); } const TypeInfo_t *non_opt_type = spec[s].type; @@ -404,45 +377,40 @@ public void _tomo_parse_args(int argc, char *argv[], Text_t usage, Text_t help, non_opt_type = non_opt_type->OptionalInfo.type; // You can't specify boolean flags positionally - if (non_opt_type == &Bool$info) - goto next_non_bool_flag; + if (non_opt_type == &Bool$info) goto next_non_bool_flag; if (non_opt_type->tag == ListInfo) { int num_args = 0; while (i + num_args < argc) { - if (!ignore_dashes && (argv[i+num_args][0] == '-' && !isdigit(argv[i+num_args][1]))) - break; - used_args[i+num_args] = true; + if (!ignore_dashes && (argv[i + num_args][0] == '-' && !isdigit(argv[i + num_args][1]))) break; + used_args[i + num_args] = true; num_args += 1; } populated_args[s] = true; - *(OptionalList_t*)spec[s].dest = parse_list(non_opt_type->ListInfo.item, num_args, &argv[i]); + *(OptionalList_t *)spec[s].dest = parse_list(non_opt_type->ListInfo.item, num_args, &argv[i]); } else if (non_opt_type->tag == TableInfo) { int num_args = 0; while (i + num_args < argc) { - if ((argv[i+num_args][0] == '-' && !isdigit(argv[i+num_args][1])) || !strchr(argv[i+num_args], '=')) + if ((argv[i + num_args][0] == '-' && !isdigit(argv[i + num_args][1])) + || !strchr(argv[i + num_args], '=')) break; - used_args[i+num_args] = true; + used_args[i + num_args] = true; num_args += 1; } populated_args[s] = true; - *(OptionalTable_t*)spec[s].dest = parse_table(non_opt_type, num_args, &argv[i]); + *(OptionalTable_t *)spec[s].dest = parse_table(non_opt_type, num_args, &argv[i]); } else { populated_args[s] = parse_single_arg(spec[s].type, argv[i], spec[s].dest); } - if (!populated_args[s]) - print_err("Invalid value for ", spec[s].name, ": ", argv[i], "\n", usage); + if (!populated_args[s]) print_err("Invalid value for ", spec[s].name, ": ", argv[i], "\n", usage); } 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){}; - 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); + if (spec[s].type->tag == ListInfo) *(OptionalList_t *)spec[s].dest = (List_t){}; + 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); } } } @@ -450,24 +418,18 @@ public void _tomo_parse_args(int argc, char *argv[], Text_t usage, Text_t help, #pragma GCC diagnostic pop #endif -public _Noreturn void fail_text(Text_t message) -{ - fail(message); -} +public +_Noreturn void fail_text(Text_t message) { fail(message); } -public Text_t builtin_last_err() -{ - return Text$from_str(strerror(errno)); -} +public +Text_t builtin_last_err() { return Text$from_str(strerror(errno)); } static int _inspect_depth = 0; static file_t *file = NULL; -__attribute__((nonnull)) -public void start_inspect(const char *filename, int64_t start, int64_t end) -{ - if (file == NULL || strcmp(file->filename, filename) != 0) - file = load_file(filename); +__attribute__((nonnull)) public +void start_inspect(const char *filename, int64_t start, int64_t end) { + if (file == NULL || strcmp(file->filename, filename) != 0) file = load_file(filename); if (file) { size_t first_line_len = strcspn(file->text + start, "\r\n"); @@ -476,26 +438,25 @@ public void start_inspect(const char *filename, int64_t start, int64_t end) int64_t line_num = get_line_number(file, file->text + start); if (USE_COLOR) { - print(repeated_char(' ', 3*_inspect_depth), "\x1b[33;1m>> \x1b[m", - string_slice(file->text + start, first_line_len), - " ", repeated_char(' ', MAX(0, 35-(int64_t)first_line_len-3*_inspect_depth)), - "\x1b[32;2m[", file_base, ":", line_num, "]\x1b[m"); + print(repeated_char(' ', 3 * _inspect_depth), "\x1b[33;1m>> \x1b[m", + string_slice(file->text + start, first_line_len), " ", + repeated_char(' ', MAX(0, 35 - (int64_t)first_line_len - 3 * _inspect_depth)), "\x1b[32;2m[", + file_base, ":", line_num, "]\x1b[m"); } else { - print(repeated_char(' ', 3*_inspect_depth), ">> ", - string_slice(file->text + start, first_line_len), - " ", repeated_char(' ', MAX(0, 35-(int64_t)first_line_len-3*_inspect_depth)), - "[", file_base, ":", line_num, "]"); + print(repeated_char(' ', 3 * _inspect_depth), ">> ", string_slice(file->text + start, first_line_len), + " ", repeated_char(' ', MAX(0, 35 - (int64_t)first_line_len - 3 * _inspect_depth)), "[", file_base, + ":", line_num, "]"); } // For multi-line expressions, dedent each and print it on a new line with ".. " in front: if (end > start + (int64_t)first_line_len) { const char *line_start = get_line(file, line_num); int64_t indent_len = (int64_t)strspn(line_start, " \t"); - for (const char *line = file->text + start + first_line_len; line < file->text + end; line += strcspn(line, "\r\n")) { + for (const char *line = file->text + start + first_line_len; line < file->text + end; + line += strcspn(line, "\r\n")) { line += strspn(line, "\r\n"); - if ((int64_t)strspn(line, " \t") >= indent_len) - line += indent_len; - print(repeated_char(' ', 3*_inspect_depth), USE_COLOR ? "\x1b[33m.. " : ".. ", + if ((int64_t)strspn(line, " \t") >= indent_len) line += indent_len; + print(repeated_char(' ', 3 * _inspect_depth), USE_COLOR ? "\x1b[33m.. " : ".. ", string_slice(line, strcspn(line, "\r\n"))); } } @@ -503,23 +464,24 @@ public void start_inspect(const char *filename, int64_t start, int64_t end) _inspect_depth += 1; } -public void end_inspect(const void *expr, const TypeInfo_t *type) -{ +public +void end_inspect(const void *expr, const TypeInfo_t *type) { _inspect_depth -= 1; if (type && type->metamethods.as_text) { Text_t expr_text = generic_as_text(expr, USE_COLOR, type); Text_t type_name = generic_as_text(NULL, false, type); - for (int i = 0; i < 3*_inspect_depth; i++) fputc(' ', stdout); - fprint(stdout, USE_COLOR ? "\x1b[33;1m=\x1b[0m " : "= ", expr_text, USE_COLOR ? " \x1b[2m: \x1b[36m" : " : ", type_name, USE_COLOR ? "\033[m" : ""); + for (int i = 0; i < 3 * _inspect_depth; i++) + fputc(' ', stdout); + fprint(stdout, USE_COLOR ? "\x1b[33;1m=\x1b[0m " : "= ", expr_text, USE_COLOR ? " \x1b[2m: \x1b[36m" : " : ", + type_name, USE_COLOR ? "\033[m" : ""); } } -__attribute__((nonnull)) -public void test_value(const char *filename, int64_t start, int64_t end, const void *expr, const void *expected, const TypeInfo_t *type) -{ - if (generic_equal(expr, expected, type)) - return; +__attribute__((nonnull)) public +void test_value(const char *filename, int64_t start, int64_t end, const void *expr, const void *expected, + const TypeInfo_t *type) { + if (generic_equal(expr, expected, type)) return; print_stacktrace(stderr, 2); fprint(stderr, ""); @@ -532,38 +494,42 @@ public void test_value(const char *filename, int64_t start, int64_t end, const v Text_t expr_text = generic_as_text(expr, USE_COLOR, type); Text_t expected_text = generic_as_text(expected, USE_COLOR, type); if (USE_COLOR) { - fprint(stderr, - "\n\x1b[31;7m ==================== TEST FAILED ==================== \x1b[0;1m\n\n" - "You expected: \x1b[m", expected_text, "\x1b[0m\n" - "\x1b[1m But I got:\x1b[m ", expr_text, "\n"); + fprint(stderr, + "\n\x1b[31;7m ==================== TEST FAILED ==================== \x1b[0;1m\n\n" + "You expected: \x1b[m", + expected_text, + "\x1b[0m\n" + "\x1b[1m But I got:\x1b[m ", + expr_text, "\n"); } else { - fprint(stderr, - "\n==================== TEST FAILED ====================\n\n" - "You expected: ", expected_text, "\n" - " But I got: ", expr_text, "\n"); + fprint(stderr, + "\n==================== TEST FAILED ====================\n\n" + "You expected: ", + expected_text, + "\n" + " But I got: ", + expr_text, "\n"); } fflush(stderr); raise(SIGABRT); } -public void say(Text_t text, bool newline) -{ +public +void say(Text_t text, bool newline) { Text$print(stdout, text); - if (newline) - fputc('\n', stdout); + if (newline) fputc('\n', stdout); fflush(stdout); } -public _Noreturn void tomo_exit(Text_t text, int32_t status) -{ - if (text.length > 0) - print(text); +public +_Noreturn void tomo_exit(Text_t text, int32_t status) { + if (text.length > 0) print(text); _exit(status); } -public OptionalText_t ask(Text_t prompt, bool bold, bool force_tty) -{ +public +OptionalText_t ask(Text_t prompt, bool bold, bool force_tty) { OptionalText_t ret = NONE_TEXT; FILE *out = stdout; FILE *in = stdin; @@ -597,8 +563,8 @@ public OptionalText_t ask(Text_t prompt, bool bold, bool force_tty) goto cleanup; } - if (length > 0 && line[length-1] == '\n') { - line[length-1] = '\0'; + if (length > 0 && line[length - 1] == '\n') { + line[length - 1] = '\0'; --length; } @@ -607,14 +573,14 @@ public OptionalText_t ask(Text_t prompt, bool bold, bool force_tty) ret = Text$from_strn(gc_input, (size_t)(length)); - cleanup: +cleanup: if (out && out != stdout) fclose(out); if (in && in != stdin) fclose(in); return ret; } -public bool pop_flag(char **argv, int *i, const char *flag, Text_t *result) -{ +public +bool pop_flag(char **argv, int *i, const char *flag, Text_t *result) { if (argv[*i][0] != '-' || argv[*i][1] != '-') { return false; } else if (streq(argv[*i] + 2, flag)) { @@ -637,23 +603,21 @@ public bool pop_flag(char **argv, int *i, const char *flag, Text_t *result) } } -public void sleep_num(double seconds) -{ +public +void sleep_num(double seconds) { struct timespec ts; ts.tv_sec = (time_t)seconds; ts.tv_nsec = (long)((seconds - (double)ts.tv_sec) * 1e9); nanosleep(&ts, NULL); } -public OptionalText_t getenv_text(Text_t name) -{ +public +OptionalText_t getenv_text(Text_t name) { const char *val = getenv(Text$as_c_string(name)); return val ? Text$from_str(val) : NONE_TEXT; } -public void setenv_text(Text_t name, Text_t value) -{ - setenv(Text$as_c_string(name), Text$as_c_string(value), 1); -} +public +void setenv_text(Text_t name, Text_t value) { setenv(Text$as_c_string(name), Text$as_c_string(value), 1); } // vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0 diff --git a/src/stdlib/stdlib.h b/src/stdlib/stdlib.h index 8ac35f72..c676beb1 100644 --- a/src/stdlib/stdlib.h +++ b/src/stdlib/stdlib.h @@ -23,66 +23,72 @@ typedef struct { } cli_arg_t; void tomo_init(void); -void _tomo_parse_args(int argc, char *argv[], Text_t usage, Text_t help, const char *version, int spec_len, cli_arg_t spec[spec_len]); -#define tomo_parse_args(argc, argv, usage, help, version, ...) \ - _tomo_parse_args(argc, argv, usage, help, version, sizeof((cli_arg_t[]){__VA_ARGS__})/sizeof(cli_arg_t), (cli_arg_t[]){__VA_ARGS__}) +void _tomo_parse_args(int argc, char *argv[], Text_t usage, Text_t help, const char *version, int spec_len, + cli_arg_t spec[spec_len]); +#define tomo_parse_args(argc, argv, usage, help, version, ...) \ + _tomo_parse_args(argc, argv, usage, help, version, sizeof((cli_arg_t[]){__VA_ARGS__}) / sizeof(cli_arg_t), \ + (cli_arg_t[]){__VA_ARGS__}) -#define fail(...) ({ \ - fflush(stdout); \ - if (USE_COLOR) fputs("\x1b[31;7m ==================== ERROR ==================== \033[m\n\n", stderr); \ - else fputs("==================== ERROR ====================\n\n", stderr); \ - print_stacktrace(stderr, 1); \ - if (USE_COLOR) fputs("\n\x1b[31;1m", stderr); \ - else fputs("\n", stderr); \ - fprint_inline(stderr, "Error: ", __VA_ARGS__); \ - if (USE_COLOR) fputs("\x1b[m\n", stderr); \ - else fputs("\n", stderr); \ - fflush(stderr); \ - raise(SIGABRT); \ - _exit(1); \ -}) +#define fail(...) \ + ({ \ + fflush(stdout); \ + if (USE_COLOR) fputs("\x1b[31;7m ==================== ERROR ==================== \033[m\n\n", stderr); \ + else fputs("==================== ERROR ====================\n\n", stderr); \ + print_stacktrace(stderr, 1); \ + if (USE_COLOR) fputs("\n\x1b[31;1m", stderr); \ + else fputs("\n", stderr); \ + fprint_inline(stderr, "Error: ", __VA_ARGS__); \ + if (USE_COLOR) fputs("\x1b[m\n", stderr); \ + else fputs("\n", stderr); \ + fflush(stderr); \ + raise(SIGABRT); \ + _exit(1); \ + }) -#define fail_source(filename, start, end, ...) ({ \ - fflush(stdout); \ - if (USE_COLOR) fputs("\x1b[31;7m ==================== ERROR ==================== \n\n\x1b[0;1m", stderr); \ - else fputs("==================== ERROR ====================\n\n", stderr); \ - print_stacktrace(stderr, 0); \ - fputs("\n", stderr); \ - if (USE_COLOR) fputs("\x1b[31;1m", stderr); \ - fprint_inline(stderr, __VA_ARGS__); \ - file_t *_file = (filename) ? load_file(filename) : NULL; \ - if ((filename) && _file) { \ - fputs("\n", stderr); \ - highlight_error(_file, _file->text+(start), _file->text+(end), "\x1b[31;1m", 1, USE_COLOR); \ - } \ - if (USE_COLOR) fputs("\x1b[m", stderr); \ - fflush(stderr); \ - raise(SIGABRT); \ - _exit(1); \ -}) +#define fail_source(filename, start, end, ...) \ + ({ \ + fflush(stdout); \ + if (USE_COLOR) fputs("\x1b[31;7m ==================== ERROR ==================== \n\n\x1b[0;1m", stderr); \ + else fputs("==================== ERROR ====================\n\n", stderr); \ + print_stacktrace(stderr, 0); \ + fputs("\n", stderr); \ + if (USE_COLOR) fputs("\x1b[31;1m", stderr); \ + fprint_inline(stderr, __VA_ARGS__); \ + file_t *_file = (filename) ? load_file(filename) : NULL; \ + if ((filename) && _file) { \ + fputs("\n", stderr); \ + highlight_error(_file, _file->text + (start), _file->text + (end), "\x1b[31;1m", 1, USE_COLOR); \ + } \ + if (USE_COLOR) fputs("\x1b[m", stderr); \ + fflush(stderr); \ + raise(SIGABRT); \ + _exit(1); \ + }) _Noreturn void fail_text(Text_t message); Text_t builtin_last_err(); -__attribute__((nonnull)) -void start_inspect(const char *filename, int64_t start, int64_t end); +__attribute__((nonnull)) void start_inspect(const char *filename, int64_t start, int64_t end); void end_inspect(const void *expr, const TypeInfo_t *type); -#define inspect(type, expr, typeinfo, start, end) {\ - start_inspect(__SOURCE_FILE__, start, end); \ - type _expr = expr; \ - end_inspect(&_expr, typeinfo); \ -} -#define inspect_void(expr, typeinfo, start, end) {\ - start_inspect(__SOURCE_FILE__, start, end); \ - expr; \ - end_inspect(NULL, typeinfo); \ -} -__attribute__((nonnull)) -void test_value(const char *filename, int64_t start, int64_t end, const void *expr, const void *expected, const TypeInfo_t *type); -#define test(type, expr, expected, typeinfo, start, end) {\ - type _expr = expr; \ - type _expected = expected; \ - test_value(__SOURCE_FILE__, start, end, &_expr, &_expected, typeinfo); \ -} +#define inspect(type, expr, typeinfo, start, end) \ + { \ + start_inspect(__SOURCE_FILE__, start, end); \ + type _expr = expr; \ + end_inspect(&_expr, typeinfo); \ + } +#define inspect_void(expr, typeinfo, start, end) \ + { \ + start_inspect(__SOURCE_FILE__, start, end); \ + expr; \ + end_inspect(NULL, typeinfo); \ + } +__attribute__((nonnull)) void test_value(const char *filename, int64_t start, int64_t end, const void *expr, + const void *expected, const TypeInfo_t *type); +#define test(type, expr, expected, typeinfo, start, end) \ + { \ + type _expr = expr; \ + type _expected = expected; \ + test_value(__SOURCE_FILE__, start, end, &_expr, &_expected, typeinfo); \ + } void say(Text_t text, bool newline); Text_t ask(Text_t prompt, bool bold, bool force_tty); diff --git a/src/stdlib/structs.c b/src/stdlib/structs.c index 5d6b2319..d2300b74 100644 --- a/src/stdlib/structs.c +++ b/src/stdlib/structs.c @@ -13,13 +13,10 @@ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wstack-protector" #endif -PUREFUNC public uint64_t Struct$hash(const void *obj, const TypeInfo_t *type) -{ - if (type->StructInfo.num_fields == 0) - return 0; +PUREFUNC public uint64_t Struct$hash(const void *obj, const TypeInfo_t *type) { + if (type->StructInfo.num_fields == 0) return 0; - if (type->StructInfo.num_fields == 1) - return generic_hash(obj, type->StructInfo.fields[0].type); + if (type->StructInfo.num_fields == 1) return generic_hash(obj, type->StructInfo.fields[0].type); uint64_t field_hashes[type->StructInfo.num_fields]; ptrdiff_t byte_offset = 0; @@ -27,7 +24,7 @@ PUREFUNC public uint64_t Struct$hash(const void *obj, const TypeInfo_t *type) for (int i = 0; i < type->StructInfo.num_fields; i++) { NamedType_t field = type->StructInfo.fields[i]; if (field.type == &Bool$info) { - bool b = ((*(char*)(obj + byte_offset)) >> bit_offset) & 0x1; + bool b = ((*(char *)(obj + byte_offset)) >> bit_offset) & 0x1; field_hashes[i] = (uint32_t)b; bit_offset += 1; if (bit_offset >= 8) { @@ -45,34 +42,29 @@ PUREFUNC public uint64_t Struct$hash(const void *obj, const TypeInfo_t *type) byte_offset += field.type->size; } } - return siphash24((void*)field_hashes, sizeof(field_hashes)); + return siphash24((void *)field_hashes, sizeof(field_hashes)); } #ifdef __GNUC__ #pragma GCC diagnostic pop #endif -PUREFUNC public uint64_t PackedData$hash(const void *obj, const TypeInfo_t *type) -{ - if (type->StructInfo.num_fields == 0) - return 0; +PUREFUNC public uint64_t PackedData$hash(const void *obj, const TypeInfo_t *type) { + if (type->StructInfo.num_fields == 0) return 0; return siphash24(obj, (size_t)type->size); } -PUREFUNC public int32_t Struct$compare(const void *x, const void *y, const TypeInfo_t *type) -{ - if (x == y) - return 0; +PUREFUNC public int32_t Struct$compare(const void *x, const void *y, const TypeInfo_t *type) { + if (x == y) return 0; ptrdiff_t byte_offset = 0; ptrdiff_t bit_offset = 0; for (int i = 0; i < type->StructInfo.num_fields; i++) { NamedType_t field = type->StructInfo.fields[i]; if (field.type == &Bool$info) { - bool bx = ((*(char*)(x + byte_offset)) >> bit_offset) & 0x1; - bool by = ((*(char*)(y + byte_offset)) >> bit_offset) & 0x1; - if (bx != by) - return (int32_t)bx - (int32_t)by; + bool bx = ((*(char *)(x + byte_offset)) >> bit_offset) & 0x1; + bool by = ((*(char *)(y + byte_offset)) >> bit_offset) & 0x1; + if (bx != by) return (int32_t)bx - (int32_t)by; bit_offset += 1; if (bit_offset >= 8) { byte_offset += 1; @@ -86,28 +78,24 @@ PUREFUNC public int32_t Struct$compare(const void *x, const void *y, const TypeI if (field.type->align && byte_offset % field.type->align > 0) byte_offset += field.type->align - (byte_offset % field.type->align); int32_t cmp = generic_compare(x + byte_offset, y + byte_offset, field.type); - if (cmp != 0) - return cmp; + if (cmp != 0) return cmp; byte_offset += field.type->size; } } return 0; } -PUREFUNC public bool Struct$equal(const void *x, const void *y, const TypeInfo_t *type) -{ - if (x == y) - return true; +PUREFUNC public bool Struct$equal(const void *x, const void *y, const TypeInfo_t *type) { + if (x == y) return true; ptrdiff_t byte_offset = 0; ptrdiff_t bit_offset = 0; for (int i = 0; i < type->StructInfo.num_fields; i++) { NamedType_t field = type->StructInfo.fields[i]; if (field.type == &Bool$info) { - bool bx = ((*(char*)(x + byte_offset)) >> bit_offset) & 0x1; - bool by = ((*(char*)(y + byte_offset)) >> bit_offset) & 0x1; - if (bx != by) - return false; + bool bx = ((*(char *)(x + byte_offset)) >> bit_offset) & 0x1; + bool by = ((*(char *)(y + byte_offset)) >> bit_offset) & 0x1; + if (bx != by) return false; bit_offset += 1; if (bit_offset >= 8) { byte_offset += 1; @@ -120,22 +108,19 @@ PUREFUNC public bool Struct$equal(const void *x, const void *y, const TypeInfo_t } if (field.type->align && byte_offset % field.type->align > 0) byte_offset += field.type->align - (byte_offset % field.type->align); - if (!generic_equal(x + byte_offset, y + byte_offset, field.type)) - return false; + if (!generic_equal(x + byte_offset, y + byte_offset, field.type)) return false; byte_offset += field.type->size; } } return true; } -PUREFUNC public bool PackedData$equal(const void *x, const void *y, const TypeInfo_t *type) -{ +PUREFUNC public bool PackedData$equal(const void *x, const void *y, const TypeInfo_t *type) { if (x == y) return true; return (memcmp(x, y, (size_t)type->size) == 0); } -PUREFUNC public Text_t Struct$as_text(const void *obj, bool colorize, const TypeInfo_t *type) -{ +PUREFUNC public Text_t Struct$as_text(const void *obj, bool colorize, const TypeInfo_t *type) { if (!obj) return Text$from_str(type->StructInfo.name); Text_t name = Text$from_str(type->StructInfo.name); @@ -148,15 +133,14 @@ PUREFUNC public Text_t Struct$as_text(const void *obj, bool colorize, const Type ptrdiff_t bit_offset = 0; for (int i = 0; i < type->StructInfo.num_fields; i++) { NamedType_t field = type->StructInfo.fields[i]; - if (i > 0) - text = Text$concat(text, Text(", ")); + if (i > 0) text = Text$concat(text, Text(", ")); - if (type->StructInfo.num_fields > 1) - text = Text$concat(text, Text$from_str(field.name), Text("=")); + if (type->StructInfo.num_fields > 1) text = Text$concat(text, Text$from_str(field.name), Text("=")); if (field.type == &Bool$info) { - bool b = ((*(char*)(obj + byte_offset)) >> bit_offset) & 0x1; - text = Text$concat(text, Text$from_str(colorize ? (b ? "\x1b[35myes\x1b[m" : "\x1b[35mno\x1b[m") : (b ? "yes" : "no"))); + bool b = ((*(char *)(obj + byte_offset)) >> bit_offset) & 0x1; + text = Text$concat( + text, Text$from_str(colorize ? (b ? "\x1b[35myes\x1b[m" : "\x1b[35mno\x1b[m") : (b ? "yes" : "no"))); bit_offset += 1; if (bit_offset >= 8) { byte_offset += 1; @@ -176,19 +160,16 @@ PUREFUNC public Text_t Struct$as_text(const void *obj, bool colorize, const Type return Text$concat(text, Text(")")); } -PUREFUNC public bool Struct$is_none(const void *obj, const TypeInfo_t *type) -{ - return *(bool*)(obj + type->size); -} +PUREFUNC public bool Struct$is_none(const void *obj, const TypeInfo_t *type) { return *(bool *)(obj + type->size); } -public void Struct$serialize(const void *obj, FILE *out, Table_t *pointers, const TypeInfo_t *type) -{ +public +void Struct$serialize(const void *obj, FILE *out, Table_t *pointers, const TypeInfo_t *type) { ptrdiff_t byte_offset = 0; ptrdiff_t bit_offset = 0; for (int i = 0; i < type->StructInfo.num_fields; i++) { NamedType_t field = type->StructInfo.fields[i]; if (field.type == &Bool$info) { - bool b = ((*(char*)(obj + byte_offset)) >> bit_offset) & 0x1; + bool b = ((*(char *)(obj + byte_offset)) >> bit_offset) & 0x1; fputc((int)b, out); bit_offset += 1; if (bit_offset >= 8) { @@ -208,15 +189,15 @@ public void Struct$serialize(const void *obj, FILE *out, Table_t *pointers, cons } } -public void Struct$deserialize(FILE *in, void *outval, List_t *pointers, const TypeInfo_t *type) -{ +public +void Struct$deserialize(FILE *in, void *outval, List_t *pointers, const TypeInfo_t *type) { ptrdiff_t byte_offset = 0; ptrdiff_t bit_offset = 0; for (int i = 0; i < type->StructInfo.num_fields; i++) { NamedType_t field = type->StructInfo.fields[i]; if (field.type == &Bool$info) { bool b = (bool)fgetc(in); - *(char*)(outval + byte_offset) |= (b << bit_offset); + *(char *)(outval + byte_offset) |= (b << bit_offset); bit_offset += 1; if (bit_offset >= 8) { byte_offset += 1; diff --git a/src/stdlib/structs.h b/src/stdlib/structs.h index c9c6c40a..03c051ec 100644 --- a/src/stdlib/structs.h +++ b/src/stdlib/structs.h @@ -17,24 +17,26 @@ PUREFUNC bool Struct$is_none(const void *obj, const TypeInfo_t *type); void Struct$serialize(const void *obj, FILE *out, Table_t *pointers, const TypeInfo_t *type); void Struct$deserialize(FILE *in, void *outval, List_t *pointers, const TypeInfo_t *type); -#define Struct$metamethods { \ - .hash=Struct$hash, \ - .compare=Struct$compare, \ - .equal=Struct$equal, \ - .as_text=Struct$as_text, \ - .is_none=Struct$is_none, \ - .serialize=Struct$serialize, \ - .deserialize=Struct$deserialize, \ -} +#define Struct$metamethods \ + { \ + .hash = Struct$hash, \ + .compare = Struct$compare, \ + .equal = Struct$equal, \ + .as_text = Struct$as_text, \ + .is_none = Struct$is_none, \ + .serialize = Struct$serialize, \ + .deserialize = Struct$deserialize, \ + } -#define PackedData$metamethods { \ - .hash=PackedData$hash, \ - .compare=Struct$compare, \ - .equal=PackedData$equal, \ - .as_text=Struct$as_text, \ - .is_none=Struct$is_none, \ - .serialize=Struct$serialize, \ - .deserialize=Struct$deserialize, \ -} +#define PackedData$metamethods \ + { \ + .hash = PackedData$hash, \ + .compare = Struct$compare, \ + .equal = PackedData$equal, \ + .as_text = Struct$as_text, \ + .is_none = Struct$is_none, \ + .serialize = Struct$serialize, \ + .deserialize = Struct$deserialize, \ + } // vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0 diff --git a/src/stdlib/tables.c b/src/stdlib/tables.c index 63f8eb09..781da415 100644 --- a/src/stdlib/tables.c +++ b/src/stdlib/tables.c @@ -41,29 +41,29 @@ #define EQUAL_KEYS(x, y) (generic_equal((x), (y), type->TableInfo.key)) #define END_OF_CHAIN UINT32_MAX -#define GET_ENTRY(t, i) ((t).entries.data + (t).entries.stride*(i)) +#define GET_ENTRY(t, i) ((t).entries.data + (t).entries.stride * (i)) static TypeInfo_t MemoryPointer = { - .size=sizeof(void*), - .align=__alignof__(void*), - .tag=PointerInfo, - .PointerInfo={ - .sigil="@", - .pointed=&Memory$info, - }, - .metamethods=Pointer$metamethods, + .size = sizeof(void *), + .align = __alignof__(void *), + .tag = PointerInfo, + .PointerInfo = + { + .sigil = "@", + .pointed = &Memory$info, + }, + .metamethods = Pointer$metamethods, }; const TypeInfo_t CStrToVoidStarTable = { - .size=sizeof(Table_t), - .align=__alignof__(Table_t), - .tag=TableInfo, - .TableInfo={.key=&CString$info, .value=&MemoryPointer}, - .metamethods=Table$metamethods, + .size = sizeof(Table_t), + .align = __alignof__(Table_t), + .tag = TableInfo, + .TableInfo = {.key = &CString$info, .value = &MemoryPointer}, + .metamethods = Table$metamethods, }; -PUREFUNC static INLINE size_t entry_size(const TypeInfo_t *info) -{ +PUREFUNC static INLINE size_t entry_size(const TypeInfo_t *info) { size_t size = (size_t)info->TableInfo.key->size; if (info->TableInfo.value->align > 1 && size % (size_t)info->TableInfo.value->align) size += (size_t)info->TableInfo.value->align - (size % (size_t)info->TableInfo.value->align); // padding @@ -73,31 +73,27 @@ PUREFUNC static INLINE size_t entry_size(const TypeInfo_t *info) return size; } -PUREFUNC static INLINE size_t value_offset(const TypeInfo_t *info) -{ +PUREFUNC static INLINE size_t value_offset(const TypeInfo_t *info) { size_t offset = (size_t)info->TableInfo.key->size; if ((size_t)info->TableInfo.value->align > 1 && offset % (size_t)info->TableInfo.value->align) offset += (size_t)info->TableInfo.value->align - (offset % (size_t)info->TableInfo.value->align); // padding return offset; } -static INLINE void hshow(const Table_t *t) -{ +static INLINE void hshow(const Table_t *t) { hdebug("{"); for (uint32_t i = 0; t->bucket_info && i < t->bucket_info->count; i++) { if (i > 0) hdebug(" "); if (t->bucket_info->buckets[i].occupied) - hdebug("[", i, "]=", (uint32_t)t->bucket_info->buckets[i].index, "(", t->bucket_info->buckets[i].next_bucket, ")"); - else - hdebug("[", i, "]=_"); + hdebug("[", i, "]=", (uint32_t)t->bucket_info->buckets[i].index, "(", + t->bucket_info->buckets[i].next_bucket, ")"); + else hdebug("[", i, "]=_"); } hdebug("}\n"); } -static void maybe_copy_on_write(Table_t *t, const TypeInfo_t *type) -{ - if (t->entries.data_refcount != 0) - List$compact(&t->entries, (int64_t)entry_size(type)); +static void maybe_copy_on_write(Table_t *t, const TypeInfo_t *type) { + if (t->entries.data_refcount != 0) List$compact(&t->entries, (int64_t)entry_size(type)); if (t->bucket_info && t->bucket_info->data_refcount != 0) { size_t size = sizeof(bucket_info_t) + sizeof(bucket_t[t->bucket_info->count]); @@ -107,8 +103,7 @@ static void maybe_copy_on_write(Table_t *t, const TypeInfo_t *type) } // Return address of value or NULL -PUREFUNC public void *Table$get_raw(Table_t t, const void *key, const TypeInfo_t *type) -{ +PUREFUNC public void *Table$get_raw(Table_t t, const void *key, const TypeInfo_t *type) { assert(type->tag == TableInfo); if (!key || !t.bucket_info) return NULL; @@ -123,14 +118,12 @@ PUREFUNC public void *Table$get_raw(Table_t t, const void *key, const TypeInfo_t hdebug("Found key!\n"); return entry + value_offset(type); } - if (buckets[i].next_bucket == END_OF_CHAIN) - break; + if (buckets[i].next_bucket == END_OF_CHAIN) break; } return NULL; } -PUREFUNC public void *Table$get(Table_t t, const void *key, const TypeInfo_t *type) -{ +PUREFUNC public void *Table$get(Table_t t, const void *key, const TypeInfo_t *type) { assert(type->tag == TableInfo); for (const Table_t *iter = &t; iter; iter = iter->fallback) { void *ret = Table$get_raw(*iter, key, type); @@ -139,8 +132,7 @@ PUREFUNC public void *Table$get(Table_t t, const void *key, const TypeInfo_t *ty return NULL; } -static void Table$set_bucket(Table_t *t, const void *entry, int32_t index, const TypeInfo_t *type) -{ +static void Table$set_bucket(Table_t *t, const void *entry, int32_t index, const TypeInfo_t *type) { assert(t->bucket_info); hshow(t); const void *key = entry; @@ -182,15 +174,14 @@ static void Table$set_bucket(Table_t *t, const void *entry, int32_t index, const bucket->next_bucket = END_OF_CHAIN; } else { // Collided with the start of a chain, put the new entry in chain position #2 hdebug("Hit start of a chain\n"); - buckets[t->bucket_info->last_free] = (bucket_t){ - .occupied = 1, .index=index, .next_bucket=bucket->next_bucket}; + buckets[t->bucket_info->last_free] = + (bucket_t){.occupied = 1, .index = index, .next_bucket = bucket->next_bucket}; bucket->next_bucket = t->bucket_info->last_free; } hshow(t); } -static void hashmap_resize_buckets(Table_t *t, uint32_t new_capacity, const TypeInfo_t *type) -{ +static void hashmap_resize_buckets(Table_t *t, uint32_t new_capacity, const TypeInfo_t *type) { if (unlikely(new_capacity > TABLE_MAX_BUCKETS)) fail("Table has exceeded the maximum table size (2^31) and cannot grow further!"); hdebug("About to resize from ", t->bucket_info ? (int32_t)t->bucket_info->count : 0, " to ", new_capacity, "\n"); @@ -199,7 +190,7 @@ static void hashmap_resize_buckets(Table_t *t, uint32_t new_capacity, const Type t->bucket_info = GC_MALLOC_ATOMIC(alloc_size); memset(t->bucket_info->buckets, 0, sizeof(bucket_t[new_capacity])); t->bucket_info->count = new_capacity; - t->bucket_info->last_free = new_capacity-1; + t->bucket_info->last_free = new_capacity - 1; // Rehash: for (int64_t i = 0; i < Table$length(*t); i++) { hdebug("Rehashing ", i, "\n"); @@ -215,16 +206,15 @@ static void hashmap_resize_buckets(Table_t *t, uint32_t new_capacity, const Type #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wstack-protector" #endif -public void *Table$reserve(Table_t *t, const void *key, const void *value, const TypeInfo_t *type) -{ +public +void *Table$reserve(Table_t *t, const void *key, const void *value, const TypeInfo_t *type) { assert(type->tag == TableInfo); if (!t || !key) return NULL; hshow(t); t->hash = 0; - int64_t key_size = type->TableInfo.key->size, - value_size = type->TableInfo.value->size; + int64_t key_size = type->TableInfo.key->size, value_size = type->TableInfo.value->size; if (!t->bucket_info || t->bucket_info->count == 0) { hashmap_resize_buckets(t, 8, type); } else { @@ -236,8 +226,7 @@ public void *Table$reserve(Table_t *t, const void *key, const void *value, const maybe_copy_on_write(t, type); value_home = t->entries.data + offset; - if (value && value_size > 0) - memcpy(value_home, value, (size_t)value_size); + if (value && value_size > 0) memcpy(value_home, value, (size_t)value_size); return value_home; } @@ -247,9 +236,8 @@ public void *Table$reserve(Table_t *t, const void *key, const void *value, const // Resize buckets if necessary if (t->entries.length >= (int64_t)t->bucket_info->count) { // Current resize policy: +50% at a time: - uint32_t newsize = MAX(8, (uint32_t)(3*t->bucket_info->count)/2); - if (unlikely(newsize > TABLE_MAX_BUCKETS)) - newsize = TABLE_MAX_BUCKETS; + uint32_t newsize = MAX(8, (uint32_t)(3 * t->bucket_info->count) / 2); + if (unlikely(newsize > TABLE_MAX_BUCKETS)) newsize = TABLE_MAX_BUCKETS; hashmap_resize_buckets(t, newsize, type); } @@ -265,13 +253,11 @@ public void *Table$reserve(Table_t *t, const void *key, const void *value, const char buf[entry_size(type)]; memset(buf, 0, sizeof(buf)); memcpy(buf, key, (size_t)key_size); - if (value && value_size > 0) - memcpy(buf + value_offset(type), value, (size_t)value_size); - else if (value_size > 0) - memset(buf + value_offset(type), 0, (size_t)value_size); + if (value && value_size > 0) memcpy(buf + value_offset(type), value, (size_t)value_size); + 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 = t->entries.length - 1; void *entry = GET_ENTRY(*t, entry_index); Table$set_bucket(t, entry, entry_index, type); return entry + value_offset(type); @@ -280,14 +266,14 @@ public void *Table$reserve(Table_t *t, const void *key, const void *value, const #pragma GCC diagnostic pop #endif -public void Table$set(Table_t *t, const void *key, const void *value, const TypeInfo_t *type) -{ +public +void Table$set(Table_t *t, const void *key, const void *value, const TypeInfo_t *type) { assert(type->tag == TableInfo); (void)Table$reserve(t, key, value, type); } -public void Table$remove(Table_t *t, const void *key, const TypeInfo_t *type) -{ +public +void Table$remove(Table_t *t, const void *key, const TypeInfo_t *type) { assert(type->tag == TableInfo); if (!t || Table$length(*t) == 0) return; @@ -295,8 +281,7 @@ public 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, t->entries.length - 1); // Steps: look up the bucket for the removed key // If missing, then return immediately @@ -322,13 +307,12 @@ public void Table$remove(Table_t *t, const void *key, const TypeInfo_t *type) hdebug("Found key to delete in bucket ", i, "\n"); goto found_it; } - if (t->bucket_info->buckets[i].next_bucket == END_OF_CHAIN) - return; + if (t->bucket_info->buckets[i].next_bucket == END_OF_CHAIN) return; prev = &t->bucket_info->buckets[i]; } return; - found_it:; +found_it:; assert(bucket->occupied); t->hash = 0; @@ -337,7 +321,7 @@ public void Table$remove(Table_t *t, const void *key, const TypeInfo_t *type) // 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 = t->entries.length - 1; if (bucket->index != last_entry) { hdebug("Removing key/value from the middle of the entries list\n"); @@ -374,70 +358,58 @@ public void Table$remove(Table_t *t, const void *key, const TypeInfo_t *type) } t->bucket_info->buckets[bucket_to_clear] = (bucket_t){0}; - if (bucket_to_clear > t->bucket_info->last_free) - t->bucket_info->last_free = bucket_to_clear; + if (bucket_to_clear > t->bucket_info->last_free) t->bucket_info->last_free = bucket_to_clear; hshow(t); } -CONSTFUNC public void *Table$entry(Table_t t, int64_t n) -{ - if (n < 1 || n > Table$length(t)) - return NULL; - return GET_ENTRY(t, n-1); +CONSTFUNC public void *Table$entry(Table_t t, int64_t n) { + if (n < 1 || n > Table$length(t)) return NULL; + return GET_ENTRY(t, n - 1); } -public void Table$clear(Table_t *t) -{ - memset(t, 0, sizeof(Table_t)); -} +public +void Table$clear(Table_t *t) { memset(t, 0, sizeof(Table_t)); } -public Table_t Table$sorted(Table_t t, const TypeInfo_t *type) -{ - Closure_t cmp = (Closure_t){.fn=generic_compare, .userdata=(void*)type->TableInfo.key}; +public +Table_t Table$sorted(Table_t t, const TypeInfo_t *type) { + Closure_t cmp = (Closure_t){.fn = generic_compare, .userdata = (void *)type->TableInfo.key}; List_t entries = List$sorted(t.entries, cmp, (int64_t)entry_size(type)); return Table$from_entries(entries, type); } -PUREFUNC public bool Table$equal(const void *vx, const void *vy, const TypeInfo_t *type) -{ +PUREFUNC public bool Table$equal(const void *vx, const void *vy, const TypeInfo_t *type) { if (vx == vy) return true; - Table_t *x = (Table_t*)vx, *y = (Table_t*)vy; + Table_t *x = (Table_t *)vx, *y = (Table_t *)vy; - if (x->hash && y->hash && x->hash != y->hash) - return false; + if (x->hash && y->hash && x->hash != y->hash) return false; assert(type->tag == TableInfo); - if (x->entries.length != y->entries.length) - return false; - - if ((x->fallback != NULL) != (y->fallback != NULL)) - return false; + if (x->entries.length != y->entries.length) return false; + + if ((x->fallback != NULL) != (y->fallback != NULL)) return false; const TypeInfo_t *value_type = type->TableInfo.value; size_t offset = value_offset(type); for (int64_t i = 0; i < x->entries.length; i++) { - void *x_key = x->entries.data + i*x->entries.stride; + 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; void *x_value = x_key + offset; - if (!generic_equal(y_value, x_value, value_type)) - return false; + if (!generic_equal(y_value, x_value, value_type)) return false; } return true; } -PUREFUNC public int32_t Table$compare(const void *vx, const void *vy, const TypeInfo_t *type) -{ +PUREFUNC public int32_t Table$compare(const void *vx, const void *vy, const TypeInfo_t *type) { if (vx == vy) return 0; - Table_t *x = (Table_t*)vx, *y = (Table_t*)vy; + Table_t *x = (Table_t *)vx, *y = (Table_t *)vy; assert(type->tag == TableInfo); __typeof(type->TableInfo) table = type->TableInfo; // Sort empty tables before non-empty tables: - if (x->entries.length == 0 || y->entries.length == 0) - return ((x->entries.length > 0) - (y->entries.length > 0)); + if (x->entries.length == 0 || y->entries.length == 0) return ((x->entries.length > 0) - (y->entries.length > 0)); // Table comparison rules: // - If two tables have different keys, then compare as if comparing a @@ -446,22 +418,20 @@ PUREFUNC public int32_t Table$compare(const void *vx, const void *vy, const Type // - Otherwise, compare as if comparing lists of values for the sorted key // lists: // `[x[k] for k in x.keys.sorted()] <> [y[k] for k in y.keys.sorted()]` - // + // // We can do this in _linear_ time if we find the smallest `k` such that // `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++) { 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; + if (max_x_key == NULL || generic_compare(key, max_x_key, table.key) > 0) max_x_key = key; void *x_value = key + value_offset(type); void *y_value = Table$get_raw(*y, key, type); if (!y_value || (table.value->size > 0 && !generic_equal(x_value, y_value, table.value))) { - if (mismatched_key == NULL || generic_compare(key, mismatched_key, table.key) < 0) - mismatched_key = key; + if (mismatched_key == NULL || generic_compare(key, mismatched_key, table.key) < 0) mismatched_key = key; } } @@ -470,14 +440,12 @@ PUREFUNC public int32_t Table$compare(const void *vx, const void *vy, const Type void *max_y_key = NULL; for (int64_t i = 0; i < 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; + if (max_y_key == NULL || generic_compare(key, max_y_key, table.key) > 0) max_y_key = key; void *y_value = key + value_offset(type); void *x_value = Table$get_raw(*x, key, type); if (!x_value || !generic_equal(x_value, y_value, table.value)) { - if (mismatched_key == NULL || generic_compare(key, mismatched_key, table.key) < 0) - mismatched_key = key; + if (mismatched_key == NULL || generic_compare(key, mismatched_key, table.key) < 0) mismatched_key = key; } } @@ -529,12 +497,10 @@ PUREFUNC public int32_t Table$compare(const void *vx, const void *vy, const Type return 0; } -PUREFUNC public uint64_t Table$hash(const void *obj, const TypeInfo_t *type) -{ +PUREFUNC public uint64_t Table$hash(const void *obj, const TypeInfo_t *type) { assert(type->tag == TableInfo); - Table_t *t = (Table_t*)obj; - if (t->hash != 0) - return t->hash; + Table_t *t = (Table_t *)obj; + if (t->hash != 0) return t->hash; // Table hashes are computed as: // hash(t.length, (xor: t.keys), (xor: t.values), t.fallback) @@ -544,12 +510,12 @@ PUREFUNC public uint64_t Table$hash(const void *obj, const TypeInfo_t *type) size_t offset = value_offset(type); if (table.value->size > 0) { for (int64_t i = 0; i < 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); + 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++) - keys_hash ^= generic_hash(t->entries.data + i*t->entries.stride, table.key); + keys_hash ^= generic_hash(t->entries.data + i * t->entries.stride, table.key); } volatile struct { @@ -561,41 +527,31 @@ PUREFUNC public uint64_t Table$hash(const void *obj, const TypeInfo_t *type) values_hash, t->fallback ? Table$hash(t->fallback, type) : 0, }; - t->hash = siphash24((void*)&components, sizeof(components)); - if unlikely (t->hash == 0) - t->hash = 1234567; + t->hash = siphash24((void *)&components, sizeof(components)); + if unlikely (t->hash == 0) t->hash = 1234567; return t->hash; } -public Text_t Table$as_text(const void *obj, bool colorize, const TypeInfo_t *type) -{ - Table_t *t = (Table_t*)obj; +public +Text_t Table$as_text(const void *obj, bool colorize, const TypeInfo_t *type) { + Table_t *t = (Table_t *)obj; assert(type->tag == TableInfo); __typeof(type->TableInfo) table = type->TableInfo; if (!t) { - if (table.value != &Void$info) - return Text$concat( - Text("{"), - generic_as_text(NULL, false, table.key), - Text("="), - generic_as_text(NULL, false, table.value), - Text("}")); - else - return Text$concat( - Text("|"), - generic_as_text(NULL, false, table.key), - Text("|")); + if (table.value != &Void$info) + return Text$concat(Text("{"), generic_as_text(NULL, false, table.key), Text("="), + generic_as_text(NULL, false, table.value), Text("}")); + else return Text$concat(Text("|"), generic_as_text(NULL, false, table.key), Text("|")); } int64_t val_off = (int64_t)value_offset(type); Text_t text = table.value == &Void$info ? Text("|") : Text("{"); for (int64_t i = 0, length = Table$length(*t); i < length; i++) { - if (i > 0) - text = Text$concat(text, Text(", ")); + 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)); - if (table.value != &Void$info) + if (table.value != &Void$info) text = Text$concat(text, Text("="), generic_as_text(entry + val_off, colorize, table.value)); } @@ -607,11 +563,10 @@ public Text_t Table$as_text(const void *obj, bool colorize, const TypeInfo_t *ty return text; } -public Table_t Table$from_entries(List_t entries, const TypeInfo_t *type) -{ +public +Table_t Table$from_entries(List_t entries, const TypeInfo_t *type) { assert(type->tag == TableInfo); - if (entries.length == 0) - return (Table_t){}; + if (entries.length == 0) return (Table_t){}; Table_t t = {}; int64_t length = entries.length + entries.length / 4; @@ -619,19 +574,19 @@ public Table_t Table$from_entries(List_t entries, const TypeInfo_t *type) t.bucket_info = GC_MALLOC_ATOMIC(alloc_size); memset(t.bucket_info->buckets, 0, sizeof(bucket_t[length])); t.bucket_info->count = length; - t.bucket_info->last_free = length-1; + t.bucket_info->last_free = length - 1; size_t offset = value_offset(type); for (int64_t i = 0; i < entries.length; i++) { - void *key = entries.data + i*entries.stride; + void *key = entries.data + i * entries.stride; Table$set(&t, key, key + offset, type); } return t; } // Overlap is "set intersection" in formal terms -public Table_t Table$overlap(Table_t a, Table_t b, const TypeInfo_t *type) -{ +public +Table_t Table$overlap(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 = {}; const size_t offset = value_offset(type); @@ -648,9 +603,10 @@ public Table_t Table$overlap(Table_t a, Table_t b, const TypeInfo_t *type) } // With is "set union" in formal terms -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) +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 = {}; const size_t offset = value_offset(type); for (Table_t *t = &a; t; t = t->fallback) { @@ -669,31 +625,29 @@ public Table_t Table$with(Table_t a, Table_t b, const TypeInfo_t *type) } // Xor is "disjunctive union" or "symmetric difference" in formal terms -public Table_t Table$xor(Table_t a, Table_t b, const TypeInfo_t *type) -{ +public +Table_t Table$xor(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 = {}; 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++) { void *key = GET_ENTRY(*t, i); - if (Table$get(b, key, type) == NULL) - Table$set(&result, key, key + offset, type); + 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++) { void *key = GET_ENTRY(*t, i); - if (Table$get(a, key, type) == NULL) - Table$set(&result, key, key + offset, type); + if (Table$get(a, key, type) == NULL) Table$set(&result, key, key + offset, type); } } return result; } // Without is "set difference" in formal terms -public Table_t Table$without(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 = {}; const size_t offset = value_offset(type); @@ -709,8 +663,8 @@ public Table_t Table$without(Table_t a, Table_t b, const TypeInfo_t *type) return result; } -public Table_t Table$with_fallback(Table_t t, OptionalTable_t fallback) -{ +public +Table_t Table$with_fallback(Table_t t, OptionalTable_t fallback) { if (fallback.entries.length <= 0) { t.fallback = NULL; return t; @@ -722,10 +676,8 @@ public 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; +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++) { void *found = Table$get_raw(b, GET_ENTRY(a, i), type); @@ -734,73 +686,61 @@ PUREFUNC public bool Table$is_subset_of(Table_t a, Table_t b, bool strict, const return true; } -PUREFUNC public bool Table$is_superset_of(Table_t a, Table_t b, bool strict, const TypeInfo_t *type) -{ +PUREFUNC public bool Table$is_superset_of(Table_t a, Table_t b, bool strict, const TypeInfo_t *type) { return Table$is_subset_of(b, a, strict, type); } -PUREFUNC public void *Table$str_get(Table_t t, const char *key) -{ +PUREFUNC public void *Table$str_get(Table_t t, const char *key) { void **ret = Table$get(t, &key, &CStrToVoidStarTable); return ret ? *ret : NULL; } -PUREFUNC public void *Table$str_get_raw(Table_t t, const char *key) -{ +PUREFUNC public void *Table$str_get_raw(Table_t t, const char *key) { void **ret = Table$get_raw(t, &key, &CStrToVoidStarTable); return ret ? *ret : NULL; } -public void *Table$str_reserve(Table_t *t, const char *key, const void *value) -{ +public +void *Table$str_reserve(Table_t *t, const char *key, const void *value) { return Table$reserve(t, &key, &value, &CStrToVoidStarTable); } -public void Table$str_set(Table_t *t, const char *key, const void *value) -{ - Table$set(t, &key, &value, &CStrToVoidStarTable); -} +public +void Table$str_set(Table_t *t, const char *key, const void *value) { Table$set(t, &key, &value, &CStrToVoidStarTable); } -public void Table$str_remove(Table_t *t, const char *key) -{ - return Table$remove(t, &key, &CStrToVoidStarTable); -} +public +void Table$str_remove(Table_t *t, const char *key) { return Table$remove(t, &key, &CStrToVoidStarTable); } -CONSTFUNC public void *Table$str_entry(Table_t t, int64_t n) -{ - return Table$entry(t, n); -} +CONSTFUNC public void *Table$str_entry(Table_t t, int64_t n) { return Table$entry(t, n); } -PUREFUNC public bool Table$is_none(const void *obj, const TypeInfo_t *info) -{ +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.length < 0; } -public void Table$serialize(const void *obj, FILE *out, Table_t *pointers, const TypeInfo_t *type) -{ - Table_t *t = (Table_t*)obj; +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$serialize(&len, out, pointers, &Int64$info); size_t offset = value_offset(type); for (int64_t i = 0; i < len; i++) { - _serialize(t->entries.data + i*t->entries.stride, out, pointers, type->TableInfo.key); + _serialize(t->entries.data + i * t->entries.stride, out, pointers, type->TableInfo.key); if (type->TableInfo.value->size > 0) - _serialize(t->entries.data + i*t->entries.stride + offset, out, pointers, type->TableInfo.value); + _serialize(t->entries.data + i * t->entries.stride + offset, out, pointers, type->TableInfo.value); } assert(fputc(t->fallback != NULL ? 1 : 0, out) != EOF); - if (t->fallback) - Table$serialize(t->fallback, out, pointers, type); + if (t->fallback) Table$serialize(t->fallback, out, pointers, type); } #ifdef __GNUC__ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wstack-protector" #endif -public void Table$deserialize(FILE *in, void *outval, List_t *pointers, const TypeInfo_t *type) -{ +public +void Table$deserialize(FILE *in, void *outval, List_t *pointers, const TypeInfo_t *type) { int64_t len; Int64$deserialize(in, &len, pointers, &Int$info); @@ -809,8 +749,7 @@ public void Table$deserialize(FILE *in, void *outval, List_t *pointers, const Ty char key[type->TableInfo.key->size]; _deserialize(in, key, pointers, type->TableInfo.key); char value[type->TableInfo.value->size]; - if (type->TableInfo.value->size > 0) - _deserialize(in, value, pointers, type->TableInfo.value); + if (type->TableInfo.value->size > 0) _deserialize(in, value, pointers, type->TableInfo.value); Table$set(&t, key, value, type); } @@ -819,7 +758,7 @@ public void Table$deserialize(FILE *in, void *outval, List_t *pointers, const Ty Table$deserialize(in, t.fallback, pointers, type); } - *(Table_t*)outval = t; + *(Table_t *)outval = t; } #ifdef __GNUC__ #pragma GCC diagnostic pop diff --git a/src/stdlib/tables.h b/src/stdlib/tables.h index f80c16c3..65f35060 100644 --- a/src/stdlib/tables.h +++ b/src/stdlib/tables.h @@ -2,59 +2,94 @@ // Hash table datastructure with methods and type information -#include <stdint.h> #include <stdbool.h> +#include <stdint.h> #include <string.h> -#include "lists.h" #include "datatypes.h" +#include "lists.h" #include "types.h" #include "util.h" -#define Table(key_t, val_t, key_info, value_info, fb, N, ...) ({ \ - struct { key_t k; val_t v; } ents[N] = {__VA_ARGS__}; \ - Table_t table = Table$from_entries((List_t){ \ - .data=memcpy(GC_MALLOC(sizeof(ents)), ents, sizeof(ents)), \ - .length=sizeof(ents)/sizeof(ents[0]), \ - .stride=(void*)&ents[1] - (void*)&ents[0], \ - }, Table$info(key_info, value_info)); \ - table.fallback = fb; \ - table; }) -#define Set(item_t, item_info, N, ...) ({ \ - item_t ents[N] = {__VA_ARGS__}; \ - Table_t set = Table$from_entries((List_t){ \ - .data=memcpy(GC_MALLOC(sizeof(ents)), ents, sizeof(ents)), \ - .length=sizeof(ents)/sizeof(ents[0]), \ - .stride=(void*)&ents[1] - (void*)&ents[0], \ - }, Set$info(item_info)); \ - set; }) +#define Table(key_t, val_t, key_info, value_info, fb, N, ...) \ + ({ \ + struct { \ + key_t k; \ + val_t v; \ + } ents[N] = {__VA_ARGS__}; \ + Table_t table = Table$from_entries( \ + (List_t){ \ + .data = memcpy(GC_MALLOC(sizeof(ents)), ents, sizeof(ents)), \ + .length = sizeof(ents) / sizeof(ents[0]), \ + .stride = (void *)&ents[1] - (void *)&ents[0], \ + }, \ + Table$info(key_info, value_info)); \ + table.fallback = fb; \ + table; \ + }) +#define Set(item_t, item_info, N, ...) \ + ({ \ + item_t ents[N] = {__VA_ARGS__}; \ + Table_t set = Table$from_entries( \ + (List_t){ \ + .data = memcpy(GC_MALLOC(sizeof(ents)), ents, sizeof(ents)), \ + .length = sizeof(ents) / sizeof(ents[0]), \ + .stride = (void *)&ents[1] - (void *)&ents[0], \ + }, \ + Set$info(item_info)); \ + set; \ + }) Table_t Table$from_entries(List_t entries, const TypeInfo_t *type); void *Table$get(Table_t t, const void *key, const TypeInfo_t *type); -#define Table$get_optional(table_expr, key_t, val_t, key_expr, nonnull_var, nonnull_expr, null_expr, info_expr) ({ \ - const Table_t t = table_expr; const key_t k = key_expr; \ - val_t *nonnull_var = Table$get(t, &k, info_expr); \ - nonnull_var ? nonnull_expr : null_expr; }) -#define Table$get_or_setdefault(table_expr, key_t, val_t, key_expr, default_expr, info_expr) ({ \ - Table_t *t = table_expr; const key_t k = key_expr; \ - if (t->entries.data_refcount > 0) List$compact(&t->entries, sizeof(struct {key_t k; val_t v;})); \ - val_t *v = Table$get(*t, &k, info_expr); \ - v ? v : (val_t*)Table$reserve(t, &k, (val_t[1]){default_expr}, info_expr); }) -#define Table$get_or_default(table_expr, key_t, val_t, key_expr, default_expr, info_expr) ({ \ - const Table_t t = table_expr; const key_t k = key_expr; \ - val_t *v = Table$get(t, &k, info_expr); \ - v ? *v : default_expr; }) -#define Table$has_value(table_expr, key_expr, info_expr) ({ \ - const Table_t t = table_expr; __typeof(key_expr) k = key_expr; \ - (Table$get(t, &k, info_expr) != NULL); }) +#define Table$get_optional(table_expr, key_t, val_t, key_expr, nonnull_var, nonnull_expr, null_expr, info_expr) \ + ({ \ + const Table_t t = table_expr; \ + const key_t k = key_expr; \ + val_t *nonnull_var = Table$get(t, &k, info_expr); \ + nonnull_var ? nonnull_expr : null_expr; \ + }) +#define Table$get_or_setdefault(table_expr, key_t, val_t, key_expr, default_expr, info_expr) \ + ({ \ + Table_t *t = table_expr; \ + const key_t k = key_expr; \ + if (t->entries.data_refcount > 0) \ + List$compact(&t->entries, sizeof(struct { \ + key_t k; \ + val_t v; \ + })); \ + val_t *v = Table$get(*t, &k, info_expr); \ + v ? v : (val_t *)Table$reserve(t, &k, (val_t[1]){default_expr}, info_expr); \ + }) +#define Table$get_or_default(table_expr, key_t, val_t, key_expr, default_expr, info_expr) \ + ({ \ + const Table_t t = table_expr; \ + const key_t k = key_expr; \ + val_t *v = Table$get(t, &k, info_expr); \ + v ? *v : default_expr; \ + }) +#define Table$has_value(table_expr, key_expr, info_expr) \ + ({ \ + const Table_t t = table_expr; \ + __typeof(key_expr) k = key_expr; \ + (Table$get(t, &k, info_expr) != NULL); \ + }) PUREFUNC void *Table$get_raw(Table_t t, const void *key, const TypeInfo_t *type); CONSTFUNC void *Table$entry(Table_t t, int64_t n); void *Table$reserve(Table_t *t, const void *key, const void *value, const TypeInfo_t *type); void Table$set(Table_t *t, const void *key, const void *value, const TypeInfo_t *type); -#define Table$set_value(t, key_expr, value_expr, type) ({ __typeof(key_expr) k = key_expr; __typeof(value_expr) v = value_expr; \ - Table$set(t, &k, &v, type); }) +#define Table$set_value(t, key_expr, value_expr, type) \ + ({ \ + __typeof(key_expr) k = key_expr; \ + __typeof(value_expr) v = value_expr; \ + Table$set(t, &k, &v, type); \ + }) void Table$remove(Table_t *t, const void *key, const TypeInfo_t *type); -#define Table$remove_value(t, key_expr, type) ({ __typeof(key_expr) k = key_expr; Table$remove(t, &k, type); }) +#define Table$remove_value(t, key_expr, type) \ + ({ \ + __typeof(key_expr) k = key_expr; \ + Table$remove(t, &k, type); \ + }) Table_t Table$overlap(Table_t a, Table_t b, const TypeInfo_t *type); Table_t Table$with(Table_t a, Table_t b, const TypeInfo_t *type); @@ -67,13 +102,22 @@ PUREFUNC bool Table$is_superset_of(Table_t a, Table_t b, bool strict, const Type void Table$clear(Table_t *t); Table_t Table$sorted(Table_t t, const TypeInfo_t *type); void Table$mark_copy_on_write(Table_t *t); -#define TABLE_INCREF(t) ({ LIST_INCREF((t).entries); if ((t).bucket_info) (t).bucket_info->data_refcount += ((t).bucket_info->data_refcount < TABLE_MAX_DATA_REFCOUNT); }) -#define TABLE_COPY(t) ({ TABLE_INCREF(t); t; }) +#define TABLE_INCREF(t) \ + ({ \ + LIST_INCREF((t).entries); \ + if ((t).bucket_info) \ + (t).bucket_info->data_refcount += ((t).bucket_info->data_refcount < TABLE_MAX_DATA_REFCOUNT); \ + }) +#define TABLE_COPY(t) \ + ({ \ + TABLE_INCREF(t); \ + t; \ + }) PUREFUNC int32_t Table$compare(const void *x, const void *y, const TypeInfo_t *type); PUREFUNC bool Table$equal(const void *x, const void *y, const TypeInfo_t *type); PUREFUNC uint64_t Table$hash(const void *t, const TypeInfo_t *type); Text_t Table$as_text(const void *t, bool colorize, const TypeInfo_t *type); -PUREFUNC bool Table$is_none(const void *obj, const TypeInfo_t*); +PUREFUNC bool Table$is_none(const void *obj, const TypeInfo_t *); CONSTFUNC void *Table$str_entry(Table_t t, int64_t n); PUREFUNC void *Table$str_get(Table_t t, const char *key); @@ -88,19 +132,30 @@ void Table$deserialize(FILE *in, void *outval, List_t *pointers, const TypeInfo_ extern const TypeInfo_t CStrToVoidStarTable; -#define Table$metamethods { \ - .as_text=Table$as_text, \ - .compare=Table$compare, \ - .equal=Table$equal, \ - .hash=Table$hash, \ - .is_none=Table$is_none, \ - .serialize=Table$serialize, \ - .deserialize=Table$deserialize, \ -} +#define Table$metamethods \ + { \ + .as_text = Table$as_text, \ + .compare = Table$compare, \ + .equal = Table$equal, \ + .hash = Table$hash, \ + .is_none = Table$is_none, \ + .serialize = Table$serialize, \ + .deserialize = Table$deserialize, \ + } -#define Table$info(key_expr, value_expr) &((TypeInfo_t){.size=sizeof(Table_t), .align=__alignof__(Table_t), \ - .tag=TableInfo, .TableInfo.key=key_expr, .TableInfo.value=value_expr, .metamethods=Table$metamethods}) -#define Set$info(item_info) &((TypeInfo_t){.size=sizeof(Table_t), .align=__alignof__(Table_t), \ - .tag=TableInfo, .TableInfo.key=item_info, .TableInfo.value=&Void$info, .metamethods=Table$metamethods}) +#define Table$info(key_expr, value_expr) \ + &((TypeInfo_t){.size = sizeof(Table_t), \ + .align = __alignof__(Table_t), \ + .tag = TableInfo, \ + .TableInfo.key = key_expr, \ + .TableInfo.value = value_expr, \ + .metamethods = Table$metamethods}) +#define Set$info(item_info) \ + &((TypeInfo_t){.size = sizeof(Table_t), \ + .align = __alignof__(Table_t), \ + .tag = TableInfo, \ + .TableInfo.key = item_info, \ + .TableInfo.value = &Void$info, \ + .metamethods = Table$metamethods}) // vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1 diff --git a/src/stdlib/text.c b/src/stdlib/text.c index d9793eb8..aad3fd76 100644 --- a/src/stdlib/text.c +++ b/src/stdlib/text.c @@ -116,8 +116,8 @@ #include "text.h" // Use inline version of the siphash code for performance: -#include "siphash.h" #include "siphash-internals.h" +#include "siphash.h" typedef struct { ucs4_t main_codepoint; @@ -133,9 +133,9 @@ static synthetic_grapheme_t *synthetic_graphemes = NULL; static int32_t synthetic_grapheme_capacity = 0; static int32_t num_synthetic_graphemes = 0; -#define NUM_GRAPHEME_CODEPOINTS(id) (synthetic_graphemes[-(id)-1].utf32_cluster[0]) -#define GRAPHEME_CODEPOINTS(id) (&synthetic_graphemes[-(id)-1].utf32_cluster[1]) -#define GRAPHEME_UTF8(id) (synthetic_graphemes[-(id)-1].utf8) +#define NUM_GRAPHEME_CODEPOINTS(id) (synthetic_graphemes[-(id) - 1].utf32_cluster[0]) +#define GRAPHEME_CODEPOINTS(id) (&synthetic_graphemes[-(id) - 1].utf32_cluster[1]) +#define GRAPHEME_UTF8(id) (synthetic_graphemes[-(id) - 1].utf8) // Somewhat arbitrarily chosen, if two short literal ASCII or grapheme chunks // are concatenated below this length threshold, we just merge them into a @@ -145,16 +145,17 @@ static int32_t num_synthetic_graphemes = 0; static Text_t simple_concatenation(Text_t a, Text_t b); -public Text_t EMPTY_TEXT = { - .length=0, - .tag=TEXT_ASCII, - .ascii=0, +public +Text_t EMPTY_TEXT = { + .length = 0, + .tag = TEXT_ASCII, + .ascii = 0, }; PUREFUNC static bool graphemes_equal(const void *va, const void *vb, const TypeInfo_t *info) { (void)info; - ucs4_t *a = *(ucs4_t**)va; - ucs4_t *b = *(ucs4_t**)vb; + ucs4_t *a = *(ucs4_t **)va; + ucs4_t *b = *(ucs4_t **)vb; if (a[0] != b[0]) return false; for (int i = 0; i < (int)a[0]; i++) if (a[i] != b[i]) return false; @@ -163,37 +164,37 @@ PUREFUNC static bool graphemes_equal(const void *va, const void *vb, const TypeI PUREFUNC static uint64_t grapheme_hash(const void *g, const TypeInfo_t *info) { (void)info; - ucs4_t *cluster = *(ucs4_t**)g; - return siphash24((void*)&cluster[1], sizeof(ucs4_t[cluster[0]])); + ucs4_t *cluster = *(ucs4_t **)g; + return siphash24((void *)&cluster[1], sizeof(ucs4_t[cluster[0]])); } static const TypeInfo_t GraphemeClusterInfo = { - .size=sizeof(ucs4_t*), - .align=__alignof__(ucs4_t*), - .metamethods={ - .equal=graphemes_equal, - .hash=grapheme_hash, - }, + .size = sizeof(ucs4_t *), + .align = __alignof__(ucs4_t *), + .metamethods = + { + .equal = graphemes_equal, + .hash = grapheme_hash, + }, }; #ifdef __GNUC__ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wstack-protector" #endif -public int32_t get_synthetic_grapheme(const ucs4_t *codepoints, int64_t utf32_len) -{ - if (utf32_len == 1) - return (int32_t)*codepoints; +public +int32_t get_synthetic_grapheme(const ucs4_t *codepoints, int64_t utf32_len) { + if (utf32_len == 1) return (int32_t)*codepoints; - ucs4_t length_prefixed[1+utf32_len]; + ucs4_t length_prefixed[1 + utf32_len]; length_prefixed[0] = (ucs4_t)utf32_len; for (int i = 0; i < utf32_len; i++) - length_prefixed[i+1] = codepoints[i]; + length_prefixed[i + 1] = codepoints[i]; ucs4_t *ptr = &length_prefixed[0]; // Optimization for common case of one frequently used synthetic grapheme: static int32_t last_grapheme = 0; - if (last_grapheme != 0 && graphemes_equal(&ptr, &synthetic_graphemes[-last_grapheme-1].utf32_cluster, NULL)) + if (last_grapheme != 0 && graphemes_equal(&ptr, &synthetic_graphemes[-last_grapheme - 1].utf32_cluster, NULL)) return last_grapheme; TypeInfo_t GraphemeIDLookupTableInfo = *Table$info(&GraphemeClusterInfo, &Int32$info); @@ -209,12 +210,12 @@ public int32_t get_synthetic_grapheme(const ucs4_t *codepoints, int64_t utf32_le synthetic_graphemes = new; } - int32_t grapheme_id = -(num_synthetic_graphemes+1); + int32_t grapheme_id = -(num_synthetic_graphemes + 1); num_synthetic_graphemes += 1; // Get UTF8 representation: uint8_t u8_buf[64]; - size_t u8_len = sizeof(u8_buf)/sizeof(u8_buf[0]); + size_t u8_len = sizeof(u8_buf) / sizeof(u8_buf[0]); uint8_t *u8 = u32_to_u8(codepoints, (size_t)utf32_len, u8_buf, &u8_len); if (u8 == NULL) fail("Invalid graphemes encountered!"); @@ -223,11 +224,10 @@ public int32_t get_synthetic_grapheme(const ucs4_t *codepoints, int64_t utf32_le // area with good cache locality: static void *arena = NULL, *arena_end = NULL; // Eat up any space needed to make arena 32-bit aligned: - if ((size_t)arena % __alignof__(ucs4_t) != 0) - arena += __alignof__(ucs4_t) - ((size_t)arena % __alignof__(ucs4_t)); + if ((size_t)arena % __alignof__(ucs4_t) != 0) arena += __alignof__(ucs4_t) - ((size_t)arena % __alignof__(ucs4_t)); // If we have filled up this arena, allocate a new one: - size_t needed_memory = sizeof(ucs4_t[1+utf32_len]) + sizeof(uint8_t[u8_len + 1]); + size_t needed_memory = sizeof(ucs4_t[1 + utf32_len]) + sizeof(uint8_t[u8_len + 1]); if (arena + needed_memory > arena_end) { // Do reasonably big chunks at a time, so most synthetic codepoints are // nearby each other in memory and cache locality is good. This is a @@ -239,28 +239,27 @@ public int32_t get_synthetic_grapheme(const ucs4_t *codepoints, int64_t utf32_le // Copy length-prefixed UTF32 codepoints into the arena and store where they live: ucs4_t *codepoint_copy = arena; - memcpy(codepoint_copy, length_prefixed, sizeof(ucs4_t[1+utf32_len])); - synthetic_graphemes[-grapheme_id-1].utf32_cluster = codepoint_copy; - arena += sizeof(ucs4_t[1+utf32_len]); + memcpy(codepoint_copy, length_prefixed, sizeof(ucs4_t[1 + utf32_len])); + synthetic_graphemes[-grapheme_id - 1].utf32_cluster = codepoint_copy; + arena += sizeof(ucs4_t[1 + utf32_len]); // Copy UTF8 bytes into the arena and store where they live: uint8_t *utf8_final = arena; memcpy(utf8_final, u8, sizeof(uint8_t[u8_len])); utf8_final[u8_len] = '\0'; // Add a terminating NUL byte - synthetic_graphemes[-grapheme_id-1].utf8 = utf8_final; + synthetic_graphemes[-grapheme_id - 1].utf8 = utf8_final; arena += sizeof(uint8_t[u8_len + 1]); // Sickos at the unicode consortium decreed that you can have grapheme clusters // that begin with *prefix* modifiers, so we gotta check for that case: - synthetic_graphemes[-grapheme_id-1].main_codepoint = length_prefixed[1]; + synthetic_graphemes[-grapheme_id - 1].main_codepoint = length_prefixed[1]; for (ucs4_t i = 0; i < utf32_len; i++) { #if _LIBUNISTRING_VERSION >= 0x010200 -// libuinstring version 1.2.0 introduced uc_is_property_prepended_concatenation_mark() -// It's not critical, but it's technically more correct to have this check: - if (unlikely(uc_is_property_prepended_concatenation_mark(length_prefixed[1+i]))) - continue; + // libuinstring version 1.2.0 introduced uc_is_property_prepended_concatenation_mark() + // It's not critical, but it's technically more correct to have this check: + if (unlikely(uc_is_property_prepended_concatenation_mark(length_prefixed[1 + i]))) continue; #endif - synthetic_graphemes[-grapheme_id-1].main_codepoint = length_prefixed[1+i]; + synthetic_graphemes[-grapheme_id - 1].main_codepoint = length_prefixed[1 + i]; break; } @@ -276,8 +275,8 @@ public int32_t get_synthetic_grapheme(const ucs4_t *codepoints, int64_t utf32_le #pragma GCC diagnostic pop #endif -public int Text$print(FILE *stream, Text_t t) -{ +public +int Text$print(FILE *stream, Text_t t) { if (t.length == 0) return 0; switch (t.tag) { @@ -290,14 +289,14 @@ public int Text$print(FILE *stream, Text_t t) if (grapheme >= 0) { uint8_t buf[8]; size_t len = sizeof(buf); - uint8_t *u8 = u32_to_u8((ucs4_t*)&grapheme, 1, buf, &len); + uint8_t *u8 = u32_to_u8((ucs4_t *)&grapheme, 1, buf, &len); if (u8 == NULL) fail("Invalid grapheme encountered: ", grapheme); written += (int)fwrite(u8, sizeof(char), len, stream); if (u8 != buf) free(u8); } else { const uint8_t *u8 = GRAPHEME_UTF8(grapheme); assert(u8); - written += (int)fwrite(u8, sizeof(uint8_t), strlen((char*)u8), stream); + written += (int)fwrite(u8, sizeof(uint8_t), strlen((char *)u8), stream); } } return written; @@ -309,14 +308,14 @@ public int Text$print(FILE *stream, Text_t t) if (grapheme >= 0) { uint8_t buf[8]; size_t len = sizeof(buf); - uint8_t *u8 = u32_to_u8((ucs4_t*)&grapheme, 1, buf, &len); + uint8_t *u8 = u32_to_u8((ucs4_t *)&grapheme, 1, buf, &len); if (u8 == NULL) fail("Invalid grapheme encountered: ", grapheme); written += (int)fwrite(u8, sizeof(char), len, stream); if (u8 != buf) free(u8); } else { const uint8_t *u8 = GRAPHEME_UTF8(grapheme); assert(u8); - written += (int)fwrite(u8, sizeof(uint8_t), strlen((char*)u8), stream); + written += (int)fwrite(u8, sizeof(uint8_t), strlen((char *)u8), stream); } } return written; @@ -332,16 +331,16 @@ public int Text$print(FILE *stream, Text_t t) static const int64_t min_len_for_depth[MAX_TEXT_DEPTH] = { // Fibonacci numbers (skipping first two) - 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765, 10946, - 17711, 28657, 46368, 75025, 121393, 196418, 317811, 514229, 832040, 1346269, 2178309, 3524578, - 5702887, 9227465, 14930352, 24157817, 39088169, 63245986, 102334155, 165580141, 267914296, - 433494437, 701408733, 1134903170, 1836311903, 2971215073, 4807526976, 7778742049, + 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, + 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765, 10946, + 17711, 28657, 46368, 75025, 121393, 196418, 317811, 514229, 832040, 1346269, + 2178309, 3524578, 5702887, 9227465, 14930352, 24157817, 39088169, 63245986, 102334155, 165580141, + 267914296, 433494437, 701408733, 1134903170, 1836311903, 2971215073, 4807526976, 7778742049, }; #define IS_BALANCED_TEXT(t) ((t).length >= min_len_for_depth[(t).depth]) -static void insert_balanced_recursive(Text_t balanced_texts[MAX_TEXT_DEPTH], Text_t text) -{ +static void insert_balanced_recursive(Text_t balanced_texts[MAX_TEXT_DEPTH], Text_t text) { if (text.tag == TEXT_CONCAT && (!IS_BALANCED_TEXT(text) || text.depth >= MAX_TEXT_DEPTH)) { insert_balanced_recursive(balanced_texts, *text.left); insert_balanced_recursive(balanced_texts, *text.right); @@ -370,8 +369,7 @@ static void insert_balanced_recursive(Text_t balanced_texts[MAX_TEXT_DEPTH], Tex balanced_texts[i] = accumulator; } -static Text_t rebalanced(Text_t a, Text_t b) -{ +static Text_t rebalanced(Text_t a, Text_t b) { Text_t balanced_texts[MAX_TEXT_DEPTH]; memset(balanced_texts, 0, sizeof(balanced_texts)); insert_balanced_recursive(balanced_texts, a); @@ -379,14 +377,12 @@ static Text_t rebalanced(Text_t a, Text_t b) Text_t ret = EMPTY_TEXT; for (int i = 0; ret.length < a.length + b.length; i++) { - if (balanced_texts[i].length) - ret = simple_concatenation(balanced_texts[i], ret); + if (balanced_texts[i].length) ret = simple_concatenation(balanced_texts[i], ret); } return ret; } -Text_t simple_concatenation(Text_t a, Text_t b) -{ +Text_t simple_concatenation(Text_t a, Text_t b) { if (a.length == 0) return b; if (b.length == 0) return a; @@ -395,53 +391,53 @@ Text_t simple_concatenation(Text_t a, Text_t b) // every concatenation to yield a balanced text, since many concatenations // are ephemeral (e.g. doing a loop repeatedly concatenating without using // the intermediary values). - if (new_depth >= MAX_TEXT_DEPTH) - return rebalanced(a, b); + if (new_depth >= MAX_TEXT_DEPTH) return rebalanced(a, b); Text_t *children = GC_MALLOC(sizeof(Text_t[2])); children[0] = a; children[1] = b; return (Text_t){ - .tag=TEXT_CONCAT, - .length=a.length + b.length, - .depth=new_depth, - .left=&children[0], - .right=&children[1], + .tag = TEXT_CONCAT, + .length = a.length + b.length, + .depth = new_depth, + .left = &children[0], + .right = &children[1], }; } -static Text_t concat2_assuming_safe(Text_t a, Text_t b) -{ +static Text_t concat2_assuming_safe(Text_t a, Text_t b) { if (a.length == 0) return b; if (b.length == 0) return a; if (a.tag == TEXT_ASCII && b.tag == TEXT_ASCII && (size_t)(a.length + b.length) <= SHORT_ASCII_LENGTH) { struct Text_s ret = { - .tag=TEXT_ASCII, - .length=a.length + b.length, + .tag = TEXT_ASCII, + .length = a.length + b.length, }; ret.ascii = GC_MALLOC_ATOMIC(sizeof(char[ret.length])); - memcpy((char*)ret.ascii, a.ascii, sizeof(char[a.length])); - memcpy((char*)&ret.ascii[a.length], b.ascii, sizeof(char[b.length])); + memcpy((char *)ret.ascii, a.ascii, sizeof(char[a.length])); + memcpy((char *)&ret.ascii[a.length], b.ascii, sizeof(char[b.length])); return ret; - } else if (a.tag == TEXT_GRAPHEMES && b.tag == TEXT_GRAPHEMES && (size_t)(a.length + b.length) <= SHORT_GRAPHEMES_LENGTH) { + } else if (a.tag == TEXT_GRAPHEMES && b.tag == TEXT_GRAPHEMES + && (size_t)(a.length + b.length) <= SHORT_GRAPHEMES_LENGTH) { struct Text_s ret = { - .tag=TEXT_GRAPHEMES, - .length=a.length + b.length, + .tag = TEXT_GRAPHEMES, + .length = a.length + b.length, }; ret.graphemes = GC_MALLOC_ATOMIC(sizeof(int32_t[ret.length])); - memcpy((int32_t*)ret.graphemes, a.graphemes, sizeof(int32_t[a.length])); - memcpy((int32_t*)&ret.graphemes[a.length], b.graphemes, sizeof(int32_t[b.length])); + memcpy((int32_t *)ret.graphemes, a.graphemes, sizeof(int32_t[a.length])); + memcpy((int32_t *)&ret.graphemes[a.length], b.graphemes, sizeof(int32_t[b.length])); return ret; - } else if (a.tag != TEXT_CONCAT && b.tag != TEXT_CONCAT && (size_t)(a.length + b.length) <= SHORT_GRAPHEMES_LENGTH) { + } else if (a.tag != TEXT_CONCAT && b.tag != TEXT_CONCAT + && (size_t)(a.length + b.length) <= SHORT_GRAPHEMES_LENGTH) { // Turn a small bit of ASCII into graphemes if it helps make things smaller // Text structs come with an extra 8 bytes, so allocate enough to hold the text struct Text_s ret = { - .tag=TEXT_GRAPHEMES, - .length=a.length + b.length, + .tag = TEXT_GRAPHEMES, + .length = a.length + b.length, }; ret.graphemes = GC_MALLOC_ATOMIC(sizeof(int32_t[ret.length])); - int32_t *dest = (int32_t*)ret.graphemes; + int32_t *dest = (int32_t *)ret.graphemes; if (a.tag == TEXT_GRAPHEMES) { memcpy(dest, a.graphemes, sizeof(int32_t[a.length])); dest += a.length; @@ -474,12 +470,11 @@ static Text_t concat2_assuming_safe(Text_t a, Text_t b) return simple_concatenation(a, b); } -static Text_t concat2(Text_t a, Text_t b) -{ +static Text_t concat2(Text_t a, Text_t b) { if (a.length == 0) return b; if (b.length == 0) return a; - int32_t last_a = Text$get_grapheme(a, a.length-1); + int32_t last_a = Text$get_grapheme(a, a.length - 1); int32_t first_b = Text$get_grapheme(b, 0); // Magic number, we know that no codepoints below here trigger instability: @@ -509,60 +504,51 @@ static Text_t concat2(Text_t a, Text_t b) // Do a normalization run for these two codepoints and see if it looks different. // Normalization should not exceed 3x in the input length (but if it does, it will be // handled gracefully) - ucs4_t norm_buf[3*len]; - size_t norm_length = sizeof(norm_buf)/sizeof(norm_buf[0]); + ucs4_t norm_buf[3 * len]; + size_t norm_length = sizeof(norm_buf) / sizeof(norm_buf[0]); ucs4_t *normalized = u32_normalize(UNINORM_NFC, codepoints, len, norm_buf, &norm_length); bool stable = (norm_length == len && memcmp(codepoints, normalized, sizeof(codepoints)) == 0); if (stable) { const void *second_grapheme = u32_grapheme_next(normalized, &normalized[norm_length]); - if (second_grapheme == &normalized[norm_length]) - stable = false; + if (second_grapheme == &normalized[norm_length]) stable = false; } if likely (stable) { - if (normalized != norm_buf) - free(normalized); + if (normalized != norm_buf) free(normalized); return concat2_assuming_safe(a, b); } - Text_t glue = Text$from_codepoints((List_t){.data=norm_buf, .length=(int64_t)norm_length, .stride=sizeof(int32_t)}); + Text_t glue = + Text$from_codepoints((List_t){.data = norm_buf, .length = (int64_t)norm_length, .stride = sizeof(int32_t)}); - if (normalized != norm_buf) - free(normalized); + if (normalized != norm_buf) free(normalized); - if (a.length == 1 && b.length == 1) - return glue; - else if (a.length == 1) - return concat2_assuming_safe(glue, Text$slice(b, I(2), I(b.length))); - else if (b.length == 1) - return concat2_assuming_safe(Text$slice(a, I(1), I(a.length-1)), glue); + if (a.length == 1 && b.length == 1) return glue; + else if (a.length == 1) return concat2_assuming_safe(glue, Text$slice(b, I(2), I(b.length))); + else if (b.length == 1) return concat2_assuming_safe(Text$slice(a, I(1), I(a.length - 1)), glue); else - return concat2_assuming_safe( - concat2_assuming_safe(Text$slice(a, I(1), I(a.length-1)), glue), - Text$slice(b, I(2), I(b.length))); + return concat2_assuming_safe(concat2_assuming_safe(Text$slice(a, I(1), I(a.length - 1)), glue), + Text$slice(b, I(2), I(b.length))); } -public Text_t Text$_concat(int n, Text_t items[n]) -{ +public +Text_t Text$_concat(int n, Text_t items[n]) { if (n == 0) return EMPTY_TEXT; Text_t ret = items[0]; for (int i = 1; i < n; i++) { - if (items[i].length > 0) - ret = concat2(ret, items[i]); + if (items[i].length > 0) ret = concat2(ret, items[i]); } return ret; } -public Text_t Text$repeat(Text_t text, Int_t count) -{ - if (text.length == 0 || Int$is_negative(count)) - return EMPTY_TEXT; +public +Text_t Text$repeat(Text_t text, Int_t count) { + if (text.length == 0 || Int$is_negative(count)) return EMPTY_TEXT; Int_t result_len = Int$times(count, I(text.length)); - if (Int$compare_value(result_len, I(1l<<40)) > 0) - fail("Text repeating would produce too big of an result!"); + if (Int$compare_value(result_len, I(1l << 40)) > 0) fail("Text repeating would produce too big of an result!"); int64_t count64 = Int64$from_int(count, false); Text_t ret = text; @@ -571,19 +557,17 @@ public Text_t Text$repeat(Text_t text, Int_t count) return ret; } -public Int_t Text$width(Text_t text, Text_t language) -{ - int width = u8_strwidth((const uint8_t*)Text$as_c_string(text), Text$as_c_string(language)); +public +Int_t Text$width(Text_t text, Text_t language) { + int width = u8_strwidth((const uint8_t *)Text$as_c_string(text), Text$as_c_string(language)); return Int$from_int32(width); } -static Text_t Text$repeat_to_width(Text_t to_repeat, int64_t target_width, Text_t language) -{ - if (target_width <= 0) - return EMPTY_TEXT; +static Text_t Text$repeat_to_width(Text_t to_repeat, int64_t target_width, Text_t language) { + if (target_width <= 0) return EMPTY_TEXT; const char *lang_str = Text$as_c_string(language); - int64_t width = (int64_t)u8_strwidth((const uint8_t*)Text$as_c_string(to_repeat), lang_str); + int64_t width = (int64_t)u8_strwidth((const uint8_t *)Text$as_c_string(to_repeat), lang_str); Text_t repeated = EMPTY_TEXT; int64_t repeated_width = 0; while (repeated_width + width <= target_width) { @@ -593,8 +577,8 @@ static Text_t Text$repeat_to_width(Text_t to_repeat, int64_t target_width, Text_ if (repeated_width < target_width) { for (int64_t i = 0; repeated_width < target_width && i < to_repeat.length; i++) { - Text_t c = Text$slice(to_repeat, I_small(i+1), I_small(i+1)); - int64_t w = (int64_t)u8_strwidth((const uint8_t*)Text$as_c_string(c), lang_str); + Text_t c = Text$slice(to_repeat, I_small(i + 1), I_small(i + 1)); + int64_t w = (int64_t)u8_strwidth((const uint8_t *)Text$as_c_string(c), lang_str); if (repeated_width + w > target_width) { repeated = concat2(repeated, Text$repeat(Text(" "), I(target_width - repeated_width))); repeated_width = target_width; @@ -608,35 +592,33 @@ static Text_t Text$repeat_to_width(Text_t to_repeat, int64_t target_width, Text_ return repeated; } -public Text_t Text$left_pad(Text_t text, Int_t width, Text_t padding, Text_t language) -{ - if (padding.length == 0) - fail("Cannot pad with an empty text!"); +public +Text_t Text$left_pad(Text_t text, Int_t width, Text_t padding, Text_t language) { + if (padding.length == 0) fail("Cannot pad with an empty text!"); int64_t needed = Int64$from_int(width, false) - Int64$from_int(Text$width(text, language), false); return concat2(Text$repeat_to_width(padding, needed, language), text); } -public Text_t Text$right_pad(Text_t text, Int_t width, Text_t padding, Text_t language) -{ - if (padding.length == 0) - fail("Cannot pad with an empty text!"); +public +Text_t Text$right_pad(Text_t text, Int_t width, Text_t padding, Text_t language) { + if (padding.length == 0) fail("Cannot pad with an empty text!"); int64_t needed = Int64$from_int(width, false) - Int64$from_int(Text$width(text, language), false); return concat2(text, Text$repeat_to_width(padding, needed, language)); } -public Text_t Text$middle_pad(Text_t text, Int_t width, Text_t padding, Text_t language) -{ - if (padding.length == 0) - fail("Cannot pad with an empty text!"); +public +Text_t Text$middle_pad(Text_t text, Int_t width, Text_t padding, Text_t language) { + if (padding.length == 0) fail("Cannot pad with an empty text!"); int64_t needed = Int64$from_int(width, false) - Int64$from_int(Text$width(text, language), false); - return Texts(Text$repeat_to_width(padding, needed/2, language), text, Text$repeat_to_width(padding, (needed+1)/2, language)); + return Texts(Text$repeat_to_width(padding, needed / 2, language), text, + Text$repeat_to_width(padding, (needed + 1) / 2, language)); } -public Text_t Text$slice(Text_t text, Int_t first_int, Int_t last_int) -{ +public +Text_t Text$slice(Text_t text, Int_t first_int, Int_t last_int) { int64_t first = Int64$from_int(first_int, false); int64_t last = Int64$from_int(last_int, false); if (first == 0) fail("Invalid index: 0"); @@ -647,11 +629,9 @@ public Text_t Text$slice(Text_t text, Int_t first_int, Int_t last_int) if (last > text.length) last = text.length; - if (first > text.length || last < first) - return EMPTY_TEXT; + if (first > text.length || last < first) return EMPTY_TEXT; - if (first == 1 && last == text.length) - return text; + if (first == 1 && last == text.length) return text; while (text.tag == TEXT_CONCAT) { if (last < text.left->length) { @@ -662,31 +642,31 @@ public Text_t Text$slice(Text_t text, Int_t first_int, Int_t last_int) text = *text.right; } else { return concat2_assuming_safe(Text$slice(*text.left, I(first), I(text.length)), - Text$slice(*text.right, I(1), I(last-text.left->length))); + Text$slice(*text.right, I(1), I(last - text.left->length))); } } switch (text.tag) { case TEXT_ASCII: { return (Text_t){ - .tag=TEXT_ASCII, - .length=last - first + 1, - .ascii=text.ascii + (first-1), + .tag = TEXT_ASCII, + .length = last - first + 1, + .ascii = text.ascii + (first - 1), }; } case TEXT_GRAPHEMES: { return (Text_t){ - .tag=TEXT_GRAPHEMES, - .length=last - first + 1, - .graphemes=text.graphemes + (first-1), + .tag = TEXT_GRAPHEMES, + .length = last - first + 1, + .graphemes = text.graphemes + (first - 1), }; } case TEXT_BLOB: { Text_t ret = (Text_t){ - .tag=TEXT_BLOB, - .length=last - first + 1, - .blob.map=text.blob.map, - .blob.bytes=text.blob.bytes + (first-1), + .tag = TEXT_BLOB, + .length = last - first + 1, + .blob.map = text.blob.map, + .blob.bytes = text.blob.bytes + (first - 1), }; return ret; } @@ -695,48 +675,44 @@ public Text_t Text$slice(Text_t text, Int_t first_int, Int_t last_int) return EMPTY_TEXT; } -public Text_t Text$from(Text_t text, Int_t first) -{ - return Text$slice(text, first, I_small(-1)); -} +public +Text_t Text$from(Text_t text, Int_t first) { return Text$slice(text, first, I_small(-1)); } -public Text_t Text$to(Text_t text, Int_t last) -{ - return Text$slice(text, I_small(1), last); -} +public +Text_t Text$to(Text_t text, Int_t last) { return Text$slice(text, I_small(1), last); } -public Text_t Text$reversed(Text_t text) -{ +public +Text_t Text$reversed(Text_t text) { switch (text.tag) { case TEXT_ASCII: { struct Text_s ret = { - .tag=TEXT_ASCII, - .length=text.length, + .tag = TEXT_ASCII, + .length = text.length, }; ret.ascii = GC_MALLOC_ATOMIC(sizeof(char[ret.length])); for (int64_t i = 0; i < text.length; i++) - ((char*)ret.ascii)[text.length-1-i] = text.ascii[i]; + ((char *)ret.ascii)[text.length - 1 - i] = text.ascii[i]; return ret; } case TEXT_GRAPHEMES: { struct Text_s ret = { - .tag=TEXT_GRAPHEMES, - .length=text.length, + .tag = TEXT_GRAPHEMES, + .length = text.length, }; ret.graphemes = GC_MALLOC_ATOMIC(sizeof(int32_t[ret.length])); for (int64_t i = 0; i < text.length; i++) - ((int32_t*)ret.graphemes)[text.length-1-i] = text.graphemes[i]; + ((int32_t *)ret.graphemes)[text.length - 1 - i] = text.graphemes[i]; return ret; } case TEXT_BLOB: { struct Text_s ret = { - .tag=TEXT_BLOB, - .length=text.length, - .blob.map=text.blob.map, + .tag = TEXT_BLOB, + .length = text.length, + .blob.map = text.blob.map, }; ret.blob.bytes = GC_MALLOC_ATOMIC(sizeof(uint8_t[ret.length])); for (int64_t i = 0; i < text.length; i++) - ((uint8_t*)ret.blob.bytes)[text.length-1-i] = text.graphemes[i]; + ((uint8_t *)ret.blob.bytes)[text.length - 1 - i] = text.graphemes[i]; return ret; } case TEXT_CONCAT: { @@ -747,32 +723,30 @@ public Text_t Text$reversed(Text_t text) return EMPTY_TEXT; } -public PUREFUNC Text_t Text$cluster(Text_t text, Int_t index) -{ - return Text$slice(text, index, index); -} +public +PUREFUNC Text_t Text$cluster(Text_t text, Int_t index) { return Text$slice(text, index, index); } -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])); +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])); // If blob optimization will save at least 200 bytes: if (unique_clusters.entries.length <= 256 && blob_size + 200 < sizeof(int32_t[graphemes.length])) { Text_t ret = { - .tag=TEXT_BLOB, - .length=graphemes.length, - .depth=0, + .tag = TEXT_BLOB, + .length = graphemes.length, + .depth = 0, }; 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++) { - struct { int32_t g; uint8_t b; } *entry = unique_clusters.entries.data + i*unique_clusters.entries.stride; + 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++) { - int32_t g = *(int32_t*)(graphemes.data + i*graphemes.stride); + 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); bytes[i] = *byte; @@ -782,15 +756,15 @@ static Text_t Text$from_components(List_t graphemes, Table_t unique_clusters) return ret; } else { return (Text_t){ - .tag=TEXT_GRAPHEMES, - .length=graphemes.length, - .graphemes=graphemes.data, + .tag = TEXT_GRAPHEMES, + .length = graphemes.length, + .graphemes = graphemes.data, }; } } -public OptionalText_t Text$from_strn(const char *str, size_t len) -{ +public +OptionalText_t Text$from_strn(const char *str, size_t len) { int64_t ascii_span = 0; for (size_t i = 0; i < len && isascii(str[i]); i++) ascii_span++; @@ -799,52 +773,48 @@ public OptionalText_t Text$from_strn(const char *str, size_t len) char *copy = GC_MALLOC_ATOMIC(len); memcpy(copy, str, len); return (Text_t){ - .tag=TEXT_ASCII, - .length=ascii_span, - .ascii=copy, + .tag = TEXT_ASCII, + .length = ascii_span, + .ascii = copy, }; } - if (u8_check((uint8_t*)str, len) != NULL) - return NONE_TEXT; + if (u8_check((uint8_t *)str, len) != NULL) return NONE_TEXT; List_t graphemes = {}; Table_t unique_clusters = {}; - const uint8_t *pos = (const uint8_t*)str; - const uint8_t *end = (const uint8_t*)&str[len]; + const uint8_t *pos = (const uint8_t *)str; + const uint8_t *end = (const uint8_t *)&str[len]; // Iterate over grapheme clusters - for (const uint8_t *next; (next=u8_grapheme_next(pos, end)); pos = next) { + for (const uint8_t *next; (next = u8_grapheme_next(pos, end)); pos = next) { uint32_t buf[256]; - size_t u32_len = sizeof(buf)/sizeof(buf[0]); - uint32_t *u32s = u8_to_u32(pos, (size_t)(next-pos), buf, &u32_len); + size_t u32_len = sizeof(buf) / sizeof(buf[0]); + uint32_t *u32s = u8_to_u32(pos, (size_t)(next - pos), buf, &u32_len); uint32_t buf2[256]; - size_t u32_normlen = sizeof(buf2)/sizeof(buf2[0]); + size_t u32_normlen = sizeof(buf2) / sizeof(buf2[0]); uint32_t *u32s_normalized = u32_normalize(UNINORM_NFC, u32s, u32_len, buf2, &u32_normlen); int32_t g = get_synthetic_grapheme(u32s_normalized, (int64_t)u32_normlen); List$insert(&graphemes, &g, I(0), sizeof(int32_t)); - Table$get_or_setdefault(&unique_clusters, int32_t, uint8_t, g, (uint8_t)unique_clusters.entries.length, Table$info(&Int32$info, &Byte$info)); + Table$get_or_setdefault(&unique_clusters, int32_t, uint8_t, g, (uint8_t)unique_clusters.entries.length, + Table$info(&Int32$info, &Byte$info)); if (u32s != buf) free(u32s); if (u32s_normalized != buf2) free(u32s_normalized); if (unique_clusters.entries.length >= 256) { - return concat2_assuming_safe( - Text$from_components(graphemes, unique_clusters), - Text$from_strn((const char*)next, (size_t)(end-next))); + return concat2_assuming_safe(Text$from_components(graphemes, unique_clusters), + Text$from_strn((const char *)next, (size_t)(end - next))); } } return Text$from_components(graphemes, unique_clusters); } -public OptionalText_t Text$from_str(const char *str) -{ - return str ? Text$from_strn(str, strlen(str)) : Text(""); -} +public +OptionalText_t Text$from_str(const char *str) { return str ? Text$from_strn(str, strlen(str)) : Text(""); } -static void u8_buf_append(Text_t text, char **buf, int64_t *capacity, int64_t *i) -{ +static void u8_buf_append(Text_t text, char **buf, int64_t *capacity, int64_t *i) { switch (text.tag) { case TEXT_ASCII: { if (*i + text.length > (int64_t)*capacity) { @@ -863,7 +833,7 @@ static void u8_buf_append(Text_t text, char **buf, int64_t *capacity, int64_t *i if (graphemes[g] >= 0) { uint8_t u8_buf[64]; size_t u8_len = sizeof(u8_buf); - uint8_t *u8 = u32_to_u8((ucs4_t*)&graphemes[g], 1, u8_buf, &u8_len); + uint8_t *u8 = u32_to_u8((ucs4_t *)&graphemes[g], 1, u8_buf, &u8_len); if (u8 == NULL) fail("Invalid grapheme encountered: ", graphemes[g]); if (*i + (int64_t)u8_len > (int64_t)*capacity) { @@ -894,7 +864,7 @@ static void u8_buf_append(Text_t text, char **buf, int64_t *capacity, int64_t *i if (grapheme >= 0) { uint8_t u8_buf[64]; size_t u8_len = sizeof(u8_buf); - uint8_t *u8 = u32_to_u8((ucs4_t*)&grapheme, 1, u8_buf, &u8_len); + uint8_t *u8 = u32_to_u8((ucs4_t *)&grapheme, 1, u8_buf, &u8_len); if (u8 == NULL) fail("Invalid grapheme encountered: ", grapheme); if (*i + (int64_t)u8_len > (int64_t)*capacity) { @@ -928,8 +898,8 @@ static void u8_buf_append(Text_t text, char **buf, int64_t *capacity, int64_t *i } } -public char *Text$as_c_string(Text_t text) -{ +public +char *Text$as_c_string(Text_t text) { int64_t capacity = text.length + 1; char *buf = GC_MALLOC_ATOMIC((size_t)capacity); int64_t i = 0; @@ -943,10 +913,9 @@ public char *Text$as_c_string(Text_t text) return buf; } -PUREFUNC public uint64_t Text$hash(const void *obj, const TypeInfo_t *info) -{ +PUREFUNC public uint64_t Text$hash(const void *obj, const TypeInfo_t *info) { (void)info; - Text_t text = *(Text_t*)obj; + Text_t text = *(Text_t *)obj; siphash sh; siphashinit(&sh, sizeof(int32_t[text.length])); @@ -959,40 +928,41 @@ PUREFUNC public uint64_t Text$hash(const void *obj, const TypeInfo_t *info) const char *bytes = text.ascii; for (int64_t i = 0; i + 1 < text.length; i += 2) { tmp.chunks[0] = (int32_t)bytes[i]; - tmp.chunks[1] = (int32_t)bytes[i+1]; + tmp.chunks[1] = (int32_t)bytes[i + 1]; siphashadd64bits(&sh, tmp.whole); } - int32_t last = text.length & 0x1 ? (int32_t)bytes[text.length-1] : 0; // Odd number of graphemes + int32_t last = text.length & 0x1 ? (int32_t)bytes[text.length - 1] : 0; // Odd number of graphemes return siphashfinish_last_part(&sh, (uint64_t)last); } case TEXT_GRAPHEMES: { const int32_t *graphemes = text.graphemes; for (int64_t i = 0; i + 1 < text.length; i += 2) { tmp.chunks[0] = graphemes[i]; - tmp.chunks[1] = graphemes[i+1]; + tmp.chunks[1] = graphemes[i + 1]; siphashadd64bits(&sh, tmp.whole); } - int32_t last = text.length & 0x1 ? graphemes[text.length-1] : 0; // Odd number of graphemes + int32_t last = text.length & 0x1 ? graphemes[text.length - 1] : 0; // Odd number of graphemes return siphashfinish_last_part(&sh, (uint64_t)last); } case TEXT_BLOB: { for (int64_t i = 0; i + 1 < text.length; i += 2) { tmp.chunks[0] = text.blob.map[text.blob.bytes[i]]; - tmp.chunks[1] = text.blob.map[text.blob.bytes[i+1]]; + tmp.chunks[1] = text.blob.map[text.blob.bytes[i + 1]]; siphashadd64bits(&sh, tmp.whole); } - int32_t last = text.length & 0x1 ? text.blob.map[text.blob.bytes[text.length-1]] : 0; // Odd number of graphemes + int32_t last = + text.length & 0x1 ? text.blob.map[text.blob.bytes[text.length - 1]] : 0; // Odd number of graphemes return siphashfinish_last_part(&sh, (uint64_t)last); } case TEXT_CONCAT: { TextIter_t state = NEW_TEXT_ITER_STATE(text); for (int64_t i = 0; i + 1 < text.length; i += 2) { tmp.chunks[0] = Text$get_grapheme_fast(&state, i); - tmp.chunks[1] = Text$get_grapheme_fast(&state, i+1); + tmp.chunks[1] = Text$get_grapheme_fast(&state, i + 1); siphashadd64bits(&sh, tmp.whole); } - int32_t last = (text.length & 0x1) ? Text$get_grapheme_fast(&state, text.length-1) : 0; + int32_t last = (text.length & 0x1) ? Text$get_grapheme_fast(&state, text.length - 1) : 0; return siphashfinish_last_part(&sh, (uint64_t)last); } default: errx(1, "Invalid text"); @@ -1000,8 +970,8 @@ PUREFUNC public uint64_t Text$hash(const void *obj, const TypeInfo_t *info) return 0; } -public int32_t Text$get_grapheme_fast(TextIter_t *state, int64_t index) -{ +public +int32_t Text$get_grapheme_fast(TextIter_t *state, int64_t index) { if (index < 0) return 0; if (index >= state->stack[0].text.length) return 0; @@ -1051,18 +1021,17 @@ public int32_t Text$get_grapheme_fast(TextIter_t *state, int64_t index) return 0; } -public uint32_t Text$get_main_grapheme_fast(TextIter_t *state, int64_t index) -{ +public +uint32_t Text$get_main_grapheme_fast(TextIter_t *state, int64_t index) { int32_t g = Text$get_grapheme_fast(state, index); return (g) >= 0 ? (ucs4_t)(g) : synthetic_graphemes[-(g)-1].main_codepoint; } -PUREFUNC public int32_t Text$compare(const void *va, const void *vb, const TypeInfo_t *info) -{ +PUREFUNC public int32_t Text$compare(const void *va, const void *vb, const TypeInfo_t *info) { (void)info; if (va == vb) return 0; - const Text_t a = *(const Text_t*)va; - const Text_t b = *(const Text_t*)vb; + const Text_t a = *(const Text_t *)va; + const Text_t b = *(const Text_t *)vb; // TODO: make this smarter and more efficient int64_t len = MAX(a.length, b.length); @@ -1073,31 +1042,21 @@ PUREFUNC public int32_t Text$compare(const void *va, const void *vb, const TypeI if (ai == bi) continue; int32_t cmp; if (ai > 0 && bi > 0) { - cmp = u32_cmp((ucs4_t*)&ai, (ucs4_t*)&bi, 1); + cmp = u32_cmp((ucs4_t *)&ai, (ucs4_t *)&bi, 1); } else if (ai > 0) { - cmp = u32_cmp2( - (ucs4_t*)&ai, 1, - GRAPHEME_CODEPOINTS(bi), - NUM_GRAPHEME_CODEPOINTS(bi)); + cmp = u32_cmp2((ucs4_t *)&ai, 1, GRAPHEME_CODEPOINTS(bi), NUM_GRAPHEME_CODEPOINTS(bi)); } else if (bi > 0) { - cmp = u32_cmp2( - GRAPHEME_CODEPOINTS(ai), - NUM_GRAPHEME_CODEPOINTS(ai), - (ucs4_t*)&bi, 1); + cmp = u32_cmp2(GRAPHEME_CODEPOINTS(ai), NUM_GRAPHEME_CODEPOINTS(ai), (ucs4_t *)&bi, 1); } else { - cmp = u32_cmp2( - GRAPHEME_CODEPOINTS(ai), - NUM_GRAPHEME_CODEPOINTS(ai), - GRAPHEME_CODEPOINTS(bi), - NUM_GRAPHEME_CODEPOINTS(bi)); + cmp = u32_cmp2(GRAPHEME_CODEPOINTS(ai), NUM_GRAPHEME_CODEPOINTS(ai), GRAPHEME_CODEPOINTS(bi), + NUM_GRAPHEME_CODEPOINTS(bi)); } if (cmp != 0) return cmp; } return 0; } -bool _matches(TextIter_t *text_state, TextIter_t *target_state, int64_t pos) -{ +bool _matches(TextIter_t *text_state, TextIter_t *target_state, int64_t pos) { for (int64_t i = 0; i < target_state->stack[0].text.length; i++) { int32_t text_i = Text$get_grapheme_fast(text_state, pos + i); int32_t prefix_i = Text$get_grapheme_fast(target_state, i); @@ -1106,10 +1065,8 @@ bool _matches(TextIter_t *text_state, TextIter_t *target_state, int64_t pos) return true; } -PUREFUNC public bool Text$starts_with(Text_t text, Text_t prefix, Text_t *remainder) -{ - if (text.length < prefix.length) - return false; +PUREFUNC public bool Text$starts_with(Text_t text, Text_t prefix, Text_t *remainder) { + if (text.length < prefix.length) return false; TextIter_t text_state = NEW_TEXT_ITER_STATE(text), prefix_state = NEW_TEXT_ITER_STATE(prefix); if (_matches(&text_state, &prefix_state, 0)) { if (remainder) *remainder = Text$from(text, Int$from_int64(prefix.length + 1)); @@ -1120,10 +1077,8 @@ PUREFUNC public bool Text$starts_with(Text_t text, Text_t prefix, Text_t *remain } } -PUREFUNC public bool Text$ends_with(Text_t text, Text_t suffix, Text_t *remainder) -{ - if (text.length < suffix.length) - return false; +PUREFUNC public bool Text$ends_with(Text_t text, Text_t suffix, Text_t *remainder) { + if (text.length < suffix.length) return false; TextIter_t text_state = NEW_TEXT_ITER_STATE(text), suffix_state = NEW_TEXT_ITER_STATE(suffix); if (_matches(&text_state, &suffix_state, text.length - suffix.length)) { if (remainder) *remainder = Text$to(text, Int$from_int64(text.length - suffix.length)); @@ -1134,18 +1089,17 @@ PUREFUNC public bool Text$ends_with(Text_t text, Text_t suffix, Text_t *remainde } } -public Text_t Text$without_prefix(Text_t text, Text_t prefix) -{ +public +Text_t Text$without_prefix(Text_t text, Text_t prefix) { return Text$starts_with(text, prefix, NULL) ? Text$slice(text, I(prefix.length + 1), I(text.length)) : text; } -public Text_t Text$without_suffix(Text_t text, Text_t suffix) -{ +public +Text_t Text$without_suffix(Text_t text, Text_t suffix) { return Text$ends_with(text, suffix, NULL) ? Text$slice(text, I(1), I(text.length - suffix.length)) : text; } -static bool _has_grapheme(TextIter_t *text, int32_t g) -{ +static bool _has_grapheme(TextIter_t *text, int32_t g) { for (int64_t t = 0; t < text->stack[0].text.length; t++) { if (g == Text$get_grapheme_fast(text, t)) { return true; @@ -1154,8 +1108,8 @@ static bool _has_grapheme(TextIter_t *text, int32_t g) return false; } -public Text_t Text$trim(Text_t text, Text_t to_trim, bool left, bool right) -{ +public +Text_t Text$trim(Text_t text, Text_t to_trim, bool left, bool right) { int64_t first = 0; TextIter_t text_state = NEW_TEXT_ITER_STATE(text), trim_state = NEW_TEXT_ITER_STATE(to_trim); if (left) { @@ -1163,28 +1117,29 @@ public Text_t Text$trim(Text_t text, Text_t to_trim, bool left, bool right) first += 1; } } - int64_t last = text.length-1; + int64_t last = text.length - 1; if (right) { while (last >= first && _has_grapheme(&trim_state, Text$get_grapheme_fast(&text_state, last))) { last -= 1; } } - return (first != 0 || last != text.length-1) ? Text$slice(text, I(first+1), I(last+1)) : text; + return (first != 0 || last != text.length - 1) ? Text$slice(text, I(first + 1), I(last + 1)) : text; } -public Text_t Text$translate(Text_t text, Table_t translations) -{ +public +Text_t Text$translate(Text_t text, Table_t translations) { TextIter_t text_state = NEW_TEXT_ITER_STATE(text); Text_t result = EMPTY_TEXT; int64_t span_start = 0; List_t replacement_list = translations.entries; - for (int64_t i = 0; i < text.length; ) { + for (int64_t i = 0; i < text.length;) { for (int64_t r = 0; r < replacement_list.length; r++) { - struct { Text_t target, replacement; } *entry = replacement_list.data + r*replacement_list.stride; + struct { + Text_t target, replacement; + } *entry = replacement_list.data + r * replacement_list.stride; TextIter_t target_state = NEW_TEXT_ITER_STATE(entry->target); if (_matches(&text_state, &target_state, i)) { - if (i > span_start) - result = concat2(result, Text$slice(text, I(span_start+1), I(i))); + if (i > span_start) result = concat2(result, Text$slice(text, I(span_start + 1), I(i))); result = concat2(result, entry->replacement); i += entry->target.length; @@ -1193,22 +1148,21 @@ public Text_t Text$translate(Text_t text, Table_t translations) } } i += 1; - found_match: continue; + found_match: + continue; } - if (span_start < text.length) - result = concat2(result, Text$slice(text, I(span_start+1), I(text.length))); + if (span_start < text.length) result = concat2(result, Text$slice(text, I(span_start + 1), I(text.length))); return result; } -public Text_t Text$replace(Text_t text, Text_t target, Text_t replacement) -{ +public +Text_t Text$replace(Text_t text, Text_t target, Text_t replacement) { TextIter_t text_state = NEW_TEXT_ITER_STATE(text), target_state = NEW_TEXT_ITER_STATE(target); Text_t result = EMPTY_TEXT; int64_t span_start = 0; - for (int64_t i = 0; i < text.length; ) { + for (int64_t i = 0; i < text.length;) { if (_matches(&text_state, &target_state, i)) { - if (i > span_start) - result = concat2(result, Text$slice(text, I(span_start+1), I(i))); + if (i > span_start) result = concat2(result, Text$slice(text, I(span_start + 1), I(i))); result = concat2(result, replacement); i += target.length; @@ -1217,34 +1171,31 @@ public Text_t Text$replace(Text_t text, Text_t target, Text_t replacement) i += 1; } } - if (span_start < text.length) - result = concat2(result, Text$slice(text, I(span_start+1), I(text.length))); + if (span_start < text.length) result = concat2(result, Text$slice(text, I(span_start + 1), I(text.length))); return result; } -public PUREFUNC bool Text$has(Text_t text, Text_t target) -{ +public +PUREFUNC bool Text$has(Text_t text, Text_t target) { TextIter_t text_state = NEW_TEXT_ITER_STATE(text), target_state = NEW_TEXT_ITER_STATE(target); for (int64_t i = 0; i < text.length; i++) { - if (_matches(&text_state, &target_state, i)) - return true; + if (_matches(&text_state, &target_state, i)) return true; } return false; } -public List_t Text$split(Text_t text, Text_t delimiters) -{ - if (delimiters.length == 0) - return Text$clusters(text); +public +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 = {}; - for (int64_t i = 0; i < text.length; ) { + 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)) { span_len += 1; } - Text_t slice = Text$slice(text, I(i+1), I(i+span_len)); + Text_t slice = Text$slice(text, I(i + 1), I(i + span_len)); List$insert(&splits, &slice, I(0), sizeof(slice)); i += span_len + delimiters.length; if (i == text.length) { @@ -1255,20 +1206,20 @@ public List_t Text$split(Text_t text, Text_t delimiters) return splits; } -public List_t Text$split_any(Text_t text, Text_t delimiters) -{ - if (delimiters.length == 0) - return List(text); +public +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 = {}; - for (int64_t i = 0; i < text.length; ) { + for (int64_t i = 0; i < text.length;) { int64_t span_len = 0; - while (i + span_len < text.length && !_has_grapheme(&delim_state, Text$get_grapheme_fast(&text_state, i + span_len))) { + while (i + span_len < text.length + && !_has_grapheme(&delim_state, Text$get_grapheme_fast(&text_state, i + span_len))) { span_len += 1; } bool trailing_delim = i + span_len < text.length; - Text_t slice = Text$slice(text, I(i+1), I(i+span_len)); + Text_t slice = Text$slice(text, I(i + 1), I(i + span_len)); List$insert(&splits, &slice, I(0), sizeof(slice)); i += span_len + 1; while (i < text.length && _has_grapheme(&delim_state, Text$get_grapheme_fast(&text_state, i))) { @@ -1288,8 +1239,7 @@ typedef struct { Text_t delimiter; } split_iter_state_t; -static OptionalText_t next_split(split_iter_state_t *state) -{ +static OptionalText_t next_split(split_iter_state_t *state) { Text_t text = state->state.stack[0].text; if (state->i >= text.length) { if (state->delimiter.length > 0 && state->i == text.length) { // special case @@ -1310,21 +1260,20 @@ static OptionalText_t next_split(split_iter_state_t *state) while (i + span_len < text.length && !_matches(&state->state, &delim_state, i + span_len)) { span_len += 1; } - Text_t slice = Text$slice(text, I(i+1), I(i+span_len)); + Text_t slice = Text$slice(text, I(i + 1), I(i + span_len)); state->i = i + span_len + state->delimiter.length; return slice; } -public Closure_t Text$by_split(Text_t text, Text_t delimiter) -{ +public +Closure_t Text$by_split(Text_t text, Text_t delimiter) { return (Closure_t){ - .fn=(void*)next_split, - .userdata=new(split_iter_state_t, .state=NEW_TEXT_ITER_STATE(text), .i=0, .delimiter=delimiter), + .fn = (void *)next_split, + .userdata = new (split_iter_state_t, .state = NEW_TEXT_ITER_STATE(text), .i = 0, .delimiter = delimiter), }; } -static OptionalText_t next_split_any(split_iter_state_t *state) -{ +static OptionalText_t next_split_any(split_iter_state_t *state) { Text_t text = state->state.stack[0].text; if (state->i >= text.length) { if (state->delimiter.length > 0 && state->i == text.length) { // special case @@ -1335,7 +1284,7 @@ static OptionalText_t next_split_any(split_iter_state_t *state) } if (state->delimiter.length == 0) { // special case - Text_t ret = Text$cluster(text, I(state->i+1)); + Text_t ret = Text$cluster(text, I(state->i + 1)); state->i += 1; return ret; } @@ -1343,10 +1292,11 @@ static OptionalText_t next_split_any(split_iter_state_t *state) TextIter_t delim_state = NEW_TEXT_ITER_STATE(state->delimiter); int64_t i = state->i; int64_t span_len = 0; - while (i + span_len < text.length && !_has_grapheme(&delim_state, Text$get_grapheme_fast(&state->state, i + span_len))) { + while (i + span_len < text.length + && !_has_grapheme(&delim_state, Text$get_grapheme_fast(&state->state, i + span_len))) { span_len += 1; } - Text_t slice = Text$slice(text, I(i+1), I(i+span_len)); + Text_t slice = Text$slice(text, I(i + 1), I(i + span_len)); i += span_len + 1; while (i < text.length && _has_grapheme(&delim_state, Text$get_grapheme_fast(&state->state, i))) { i += 1; @@ -1355,18 +1305,16 @@ static OptionalText_t next_split_any(split_iter_state_t *state) return slice; } -public Closure_t Text$by_split_any(Text_t text, Text_t delimiters) -{ +public +Closure_t Text$by_split_any(Text_t text, Text_t delimiters) { return (Closure_t){ - .fn=(void*)next_split_any, - .userdata=new(split_iter_state_t, .state=NEW_TEXT_ITER_STATE(text), .i=0, .delimiter=delimiters), + .fn = (void *)next_split_any, + .userdata = new (split_iter_state_t, .state = NEW_TEXT_ITER_STATE(text), .i = 0, .delimiter = delimiters), }; } -PUREFUNC public bool Text$equal_values(Text_t a, Text_t b) -{ - if (a.length != b.length) - return false; +PUREFUNC public bool Text$equal_values(Text_t a, Text_t b) { + if (a.length != b.length) return false; int64_t len = a.length; TextIter_t a_state = NEW_TEXT_ITER_STATE(a), b_state = NEW_TEXT_ITER_STATE(b); // TODO: make this smarter and more efficient @@ -1378,17 +1326,14 @@ PUREFUNC public bool Text$equal_values(Text_t a, Text_t b) return true; } -PUREFUNC public bool Text$equal(const void *a, const void *b, const TypeInfo_t *info) -{ +PUREFUNC public bool Text$equal(const void *a, const void *b, const TypeInfo_t *info) { (void)info; if (a == b) return true; - return Text$equal_values(*(Text_t*)a, *(Text_t*)b); + return Text$equal_values(*(Text_t *)a, *(Text_t *)b); } -PUREFUNC public bool Text$equal_ignoring_case(Text_t a, Text_t b, Text_t language) -{ - if (a.length != b.length) - return false; +PUREFUNC public bool Text$equal_ignoring_case(Text_t a, Text_t b, Text_t language) { + if (a.length != b.length) return false; int64_t len = a.length; TextIter_t a_state = NEW_TEXT_ITER_STATE(a), b_state = NEW_TEXT_ITER_STATE(b); const char *uc_language = Text$as_c_string(language); @@ -1396,76 +1341,79 @@ PUREFUNC public bool Text$equal_ignoring_case(Text_t a, Text_t b, Text_t languag int32_t ai = Text$get_grapheme_fast(&a_state, i); int32_t bi = Text$get_grapheme_fast(&b_state, i); if (ai != bi) { - const ucs4_t *a_codepoints = ai >= 0 ? (ucs4_t*)&ai : GRAPHEME_CODEPOINTS(ai); + const ucs4_t *a_codepoints = ai >= 0 ? (ucs4_t *)&ai : GRAPHEME_CODEPOINTS(ai); int64_t a_len = ai >= 0 ? 1 : NUM_GRAPHEME_CODEPOINTS(ai); - const ucs4_t *b_codepoints = bi >= 0 ? (ucs4_t*)&bi : GRAPHEME_CODEPOINTS(bi); + const ucs4_t *b_codepoints = bi >= 0 ? (ucs4_t *)&bi : GRAPHEME_CODEPOINTS(bi); int64_t b_len = bi >= 0 ? 1 : NUM_GRAPHEME_CODEPOINTS(bi); int cmp = 0; (void)u32_casecmp(a_codepoints, (size_t)a_len, b_codepoints, (size_t)b_len, uc_language, UNINORM_NFC, &cmp); - if (cmp != 0) - return false; + if (cmp != 0) return false; } } return true; } -public Text_t Text$upper(Text_t text, Text_t language) -{ +public +Text_t Text$upper(Text_t text, Text_t language) { if (text.length == 0) return text; List_t codepoints = Text$utf32_codepoints(text); const char *uc_language = Text$as_c_string(language); size_t out_len = 0; ucs4_t *upper = u32_toupper(codepoints.data, (size_t)codepoints.length, uc_language, UNINORM_NFC, NULL, &out_len); - Text_t ret = Text$from_codepoints((List_t){.data=upper, .length=(int64_t)out_len, .stride=sizeof(int32_t)}); + Text_t ret = Text$from_codepoints((List_t){.data = upper, .length = (int64_t)out_len, .stride = sizeof(int32_t)}); return ret; } -public Text_t Text$lower(Text_t text, Text_t language) -{ +public +Text_t Text$lower(Text_t text, Text_t language) { if (text.length == 0) return text; List_t codepoints = Text$utf32_codepoints(text); const char *uc_language = Text$as_c_string(language); size_t out_len = 0; ucs4_t *lower = u32_tolower(codepoints.data, (size_t)codepoints.length, uc_language, UNINORM_NFC, NULL, &out_len); - Text_t ret = Text$from_codepoints((List_t){.data=lower, .length=(int64_t)out_len, .stride=sizeof(int32_t)}); + Text_t ret = Text$from_codepoints((List_t){.data = lower, .length = (int64_t)out_len, .stride = sizeof(int32_t)}); return ret; } -public Text_t Text$title(Text_t text, Text_t language) -{ +public +Text_t Text$title(Text_t text, Text_t language) { if (text.length == 0) return text; List_t codepoints = Text$utf32_codepoints(text); const char *uc_language = Text$as_c_string(language); size_t out_len = 0; ucs4_t *title = u32_totitle(codepoints.data, (size_t)codepoints.length, uc_language, UNINORM_NFC, NULL, &out_len); - Text_t ret = Text$from_codepoints((List_t){.data=title, .length=(int64_t)out_len, .stride=sizeof(int32_t)}); + Text_t ret = Text$from_codepoints((List_t){.data = title, .length = (int64_t)out_len, .stride = sizeof(int32_t)}); return ret; } -public Text_t Text$quoted(Text_t text, bool colorize, Text_t quotation_mark) -{ - if (quotation_mark.length != 1) - fail("Invalid quote text: ", quotation_mark, " (must have length == 1)"); +public +Text_t Text$quoted(Text_t text, bool colorize, Text_t quotation_mark) { + if (quotation_mark.length != 1) fail("Invalid quote text: ", quotation_mark, " (must have length == 1)"); Text_t ret = colorize ? Text("\x1b[35m") : EMPTY_TEXT; - if (!Text$equal_values(quotation_mark, Text("\"")) && !Text$equal_values(quotation_mark, Text("'")) && !Text$equal_values(quotation_mark, Text("`"))) + if (!Text$equal_values(quotation_mark, Text("\"")) && !Text$equal_values(quotation_mark, Text("'")) + && !Text$equal_values(quotation_mark, Text("`"))) ret = concat2_assuming_safe(ret, Text("$")); ret = concat2_assuming_safe(ret, quotation_mark); int32_t quote_char = Text$get_grapheme(quotation_mark, 0); -#define flush_unquoted() ({ \ - if (unquoted_span > 0) { \ - ret = concat2_assuming_safe(ret, Text$slice(text, I(i-unquoted_span+1), I(i))); \ - unquoted_span = 0; \ - } }) -#define add_escaped(str) ({ \ - flush_unquoted(); \ - if (colorize) ret = concat2_assuming_safe(ret, Text("\x1b[34;1m")); \ - ret = concat2_assuming_safe(ret, Text("\\" str)); \ - if (colorize) ret = concat2_assuming_safe(ret, Text("\x1b[0;35m")); }) +#define flush_unquoted() \ + ({ \ + if (unquoted_span > 0) { \ + ret = concat2_assuming_safe(ret, Text$slice(text, I(i - unquoted_span + 1), I(i))); \ + unquoted_span = 0; \ + } \ + }) +#define add_escaped(str) \ + ({ \ + flush_unquoted(); \ + if (colorize) ret = concat2_assuming_safe(ret, Text("\x1b[34;1m")); \ + ret = concat2_assuming_safe(ret, Text("\\" str)); \ + if (colorize) ret = concat2_assuming_safe(ret, Text("\x1b[0;35m")); \ + }) TextIter_t state = NEW_TEXT_ITER_STATE(text); int64_t unquoted_span = 0; int64_t i = 0; @@ -1488,8 +1436,10 @@ public Text_t Text$quoted(Text_t text, bool colorize, Text_t quotation_mark) add_escaped("$"); break; } - case '\x00' ... '\x06': case '\x0E' ... '\x1A': - case '\x1C' ... '\x1F': case '\x7F' ... '\x7F': { + case '\x00' ... '\x06': + case '\x0E' ... '\x1A': + case '\x1C' ... '\x1F': + case '\x7F' ... '\x7F': { flush_unquoted(); if (colorize) ret = concat2_assuming_safe(ret, Text("\x1b[34;1m")); ret = concat2_assuming_safe(ret, Text("\\x")); @@ -1499,8 +1449,7 @@ public Text_t Text$quoted(Text_t text, bool colorize, Text_t quotation_mark) '\0', }; ret = concat2_assuming_safe(ret, Text$from_strn(tmp, 2)); - if (colorize) - ret = concat2_assuming_safe(ret, Text("\x1b[0;35m")); + if (colorize) ret = concat2_assuming_safe(ret, Text("\x1b[0;35m")); break; } default: { @@ -1522,21 +1471,19 @@ public Text_t Text$quoted(Text_t text, bool colorize, Text_t quotation_mark) #undef flush_unquoted ret = concat2_assuming_safe(ret, quotation_mark); - if (colorize) - ret = concat2_assuming_safe(ret, Text("\x1b[m")); + if (colorize) ret = concat2_assuming_safe(ret, Text("\x1b[m")); return ret; } -public Text_t Text$as_text(const void *vtext, bool colorize, const TypeInfo_t *info) -{ +public +Text_t Text$as_text(const void *vtext, bool colorize, const TypeInfo_t *info) { (void)info; if (!vtext) return info && info->TextInfo.lang ? Text$from_str(info->TextInfo.lang) : Text("Text"); - Text_t text = *(Text_t*)vtext; + Text_t text = *(Text_t *)vtext; // Figure out the best quotation mark to use: - bool has_double_quote = false, has_backtick = false, - has_single_quote = false, needs_escapes = false; + bool has_double_quote = false, has_backtick = false, has_single_quote = false, needs_escapes = false; TextIter_t state = NEW_TEXT_ITER_STATE(text); for (int64_t i = 0; i < text.length; i++) { int32_t g = Text$get_grapheme_fast(&state, i); @@ -1554,39 +1501,33 @@ public Text_t Text$as_text(const void *vtext, bool colorize, const TypeInfo_t *i // needing to escape them by using single quotes, but only if we don't have // single quotes or need to escape anything else (because single quotes // don't have interpolation): - if (has_double_quote && !has_single_quote) - quote = Text("'"); + if (has_double_quote && !has_single_quote) quote = Text("'"); // If there is a double quote, but no backtick, we can save a bit of // escaping by using backtick instead of double quote: - else if (has_double_quote && has_single_quote && !has_backtick && !needs_escapes) - quote = Text("`"); + else if (has_double_quote && has_single_quote && !has_backtick && !needs_escapes) quote = Text("`"); // Otherwise fall back to double quotes as the default quoting style: - else - quote = Text("\""); + else quote = Text("\""); Text_t as_text = Text$quoted(text, colorize, quote); if (info && info->TextInfo.lang && info != &Text$info) - as_text = Text$concat( - colorize ? Text("\x1b[1m$") : Text("$"), - Text$from_str(info->TextInfo.lang), - colorize ? Text("\x1b[0m") : Text(""), - as_text); + as_text = Text$concat(colorize ? Text("\x1b[1m$") : Text("$"), Text$from_str(info->TextInfo.lang), + colorize ? Text("\x1b[0m") : Text(""), as_text); return as_text; } -public Text_t Text$join(Text_t glue, List_t pieces) -{ +public +Text_t Text$join(Text_t glue, List_t pieces) { if (pieces.length == 0) return EMPTY_TEXT; - Text_t result = *(Text_t*)pieces.data; + Text_t result = *(Text_t *)pieces.data; for (int64_t i = 1; i < pieces.length; i++) { - result = Text$concat(result, glue, *(Text_t*)(pieces.data + i*pieces.stride)); + result = Text$concat(result, glue, *(Text_t *)(pieces.data + i * pieces.stride)); } return result; } -public List_t Text$clusters(Text_t text) -{ +public +List_t Text$clusters(Text_t text) { List_t clusters = {}; for (int64_t i = 1; i <= text.length; i++) { Text_t cluster = Text$slice(text, I(i), I(i)); @@ -1595,9 +1536,9 @@ public List_t Text$clusters(Text_t text) return clusters; } -public List_t Text$utf32_codepoints(Text_t text) -{ - List_t codepoints = {.atomic=1}; +public +List_t Text$utf32_codepoints(Text_t text) { + List_t codepoints = {.atomic = 1}; 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); @@ -1613,24 +1554,23 @@ public List_t Text$utf32_codepoints(Text_t text) return codepoints; } -public List_t Text$utf8_bytes(Text_t text) -{ +public +List_t Text$utf8_bytes(Text_t text) { const char *str = Text$as_c_string(text); - return (List_t){.length=(int64_t)strlen(str), .stride=1, .atomic=1, .data=(void*)str}; + return (List_t){.length = (int64_t)strlen(str), .stride = 1, .atomic = 1, .data = (void *)str}; } -static INLINE const char *codepoint_name(ucs4_t c) -{ +static INLINE const char *codepoint_name(ucs4_t c) { char *name = GC_MALLOC_ATOMIC(UNINAME_MAX); char *found_name = unicode_character_name(c, name); if (found_name) return found_name; const uc_block_t *block = uc_block(c); assert(block); - return String(block->name, "-", hex(c, .no_prefix=true, .uppercase=true)); + return String(block->name, "-", hex(c, .no_prefix = true, .uppercase = true)); } -public List_t Text$codepoint_names(Text_t text) -{ +public +List_t Text$codepoint_names(Text_t text) { List_t names = {}; TextIter_t state = NEW_TEXT_ITER_STATE(text); for (int64_t i = 0; i < text.length; i++) { @@ -1650,81 +1590,78 @@ public List_t Text$codepoint_names(Text_t text) return names; } -public Text_t Text$from_codepoints(List_t codepoints) -{ - if (codepoints.stride != sizeof(uint32_t)) - List$compact(&codepoints, sizeof(uint32_t)); +public +Text_t Text$from_codepoints(List_t codepoints) { + if (codepoints.stride != sizeof(uint32_t)) List$compact(&codepoints, sizeof(uint32_t)); List_t graphemes = {}; Table_t unique_clusters = {}; - const uint32_t *pos = (const uint32_t*)codepoints.data; - const uint32_t *end = (const uint32_t*)&pos[codepoints.length]; + const uint32_t *pos = (const uint32_t *)codepoints.data; + const uint32_t *end = (const uint32_t *)&pos[codepoints.length]; // Iterate over grapheme clusters - for (const uint32_t *next; (next=u32_grapheme_next(pos, end)); pos = next) { + for (const uint32_t *next; (next = u32_grapheme_next(pos, end)); pos = next) { // Buffer for normalized cluster: uint32_t buf[256]; - size_t u32_normlen = sizeof(buf)/sizeof(buf[0]); - uint32_t *u32s_normalized = u32_normalize(UNINORM_NFC, pos, (size_t)(next-pos), buf, &u32_normlen); + size_t u32_normlen = sizeof(buf) / sizeof(buf[0]); + uint32_t *u32s_normalized = u32_normalize(UNINORM_NFC, pos, (size_t)(next - pos), buf, &u32_normlen); int32_t g = get_synthetic_grapheme(u32s_normalized, (int64_t)u32_normlen); List$insert(&graphemes, &g, I(0), sizeof(int32_t)); - Table$get_or_setdefault( - &unique_clusters, int32_t, uint8_t, g, (uint8_t)unique_clusters.entries.length, - Table$info(&Int32$info, &Byte$info)); + Table$get_or_setdefault(&unique_clusters, int32_t, uint8_t, g, (uint8_t)unique_clusters.entries.length, + Table$info(&Int32$info, &Byte$info)); if (u32s_normalized != buf) free(u32s_normalized); if (unique_clusters.entries.length == 256) { List_t remaining_codepoints = { - .length=(int64_t)(end-next), - .data=(void*)next, - .stride=sizeof(int32_t), + .length = (int64_t)(end - next), + .data = (void *)next, + .stride = sizeof(int32_t), }; - return concat2_assuming_safe(Text$from_components(graphemes, unique_clusters), Text$from_codepoints(remaining_codepoints)); + return concat2_assuming_safe(Text$from_components(graphemes, unique_clusters), + Text$from_codepoints(remaining_codepoints)); } } return Text$from_components(graphemes, unique_clusters); } -public OptionalText_t Text$from_codepoint_names(List_t codepoint_names) -{ +public +OptionalText_t Text$from_codepoint_names(List_t codepoint_names) { List_t codepoints = {}; for (int64_t i = 0; i < codepoint_names.length; i++) { - Text_t *name = ((Text_t*)(codepoint_names.data + i*codepoint_names.stride)); + 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); - if (codepoint == UNINAME_INVALID) - return NONE_TEXT; + if (codepoint == UNINAME_INVALID) return NONE_TEXT; List$insert(&codepoints, &codepoint, I_small(0), sizeof(ucs4_t)); } return Text$from_codepoints(codepoints); } -public OptionalText_t Text$from_bytes(List_t bytes) -{ - if (bytes.stride != sizeof(int8_t)) - List$compact(&bytes, sizeof(int8_t)); +public +OptionalText_t Text$from_bytes(List_t bytes) { + if (bytes.stride != sizeof(int8_t)) List$compact(&bytes, sizeof(int8_t)); return Text$from_strn(bytes.data, (size_t)bytes.length); } -public List_t Text$lines(Text_t text) -{ +public +List_t Text$lines(Text_t text) { List_t lines = {}; TextIter_t state = NEW_TEXT_ITER_STATE(text); for (int64_t i = 0, line_start = 0; i < 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)); + Text_t line = Text$slice(text, I(line_start + 1), I(i)); List$insert(&lines, &line, I_small(0), sizeof(Text_t)); i += 1; // skip one extra for CR line_start = i + 1; } else if (grapheme == '\n') { // newline - Text_t line = Text$slice(text, I(line_start+1), I(i)); + Text_t line = Text$slice(text, I(line_start + 1), I(i)); List$insert(&lines, &line, I_small(0), sizeof(Text_t)); line_start = i + 1; - } else if (i == text.length-1 && line_start != i) { // last line - Text_t line = Text$slice(text, I(line_start+1), I(i+1)); + } else if (i == text.length - 1 && line_start != i) { // last line + Text_t line = Text$slice(text, I(line_start + 1), I(i + 1)); List$insert(&lines, &line, I_small(0), sizeof(Text_t)); } } @@ -1736,21 +1673,20 @@ typedef struct { int64_t i; } line_iter_state_t; -static OptionalText_t next_line(line_iter_state_t *state) -{ +static OptionalText_t next_line(line_iter_state_t *state) { Text_t text = state->state.stack[0].text; for (int64_t i = state->i; i < text.length; i++) { int32_t grapheme = Text$get_grapheme_fast(&state->state, i); if (grapheme == '\r' && Text$get_grapheme_fast(&state->state, i + 1) == '\n') { // CRLF - Text_t line = Text$slice(text, I(state->i+1), I(i)); + Text_t line = Text$slice(text, I(state->i + 1), I(i)); state->i = i + 2; // skip one extra for CR return line; } else if (grapheme == '\n') { // newline - Text_t line = Text$slice(text, I(state->i+1), I(i)); + Text_t line = Text$slice(text, I(state->i + 1), I(i)); state->i = i + 1; return line; - } else if (i == text.length-1 && state->i != i) { // last line - Text_t line = Text$slice(text, I(state->i+1), I(i+1)); + } else if (i == text.length - 1 && state->i != i) { // last line + Text_t line = Text$slice(text, I(state->i + 1), I(i + 1)); state->i = i + 1; return line; } @@ -1758,81 +1694,75 @@ static OptionalText_t next_line(line_iter_state_t *state) return NONE_TEXT; } -public Closure_t Text$by_line(Text_t text) -{ +public +Closure_t Text$by_line(Text_t text) { return (Closure_t){ - .fn=(void*)next_line, - .userdata=new(line_iter_state_t, .state=NEW_TEXT_ITER_STATE(text), .i=0), + .fn = (void *)next_line, + .userdata = new (line_iter_state_t, .state = NEW_TEXT_ITER_STATE(text), .i = 0), }; } -PUREFUNC public bool Text$is_none(const void *t, const TypeInfo_t *info) -{ +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)->length < 0; } -public Int_t Text$memory_size(Text_t text) -{ +public +Int_t Text$memory_size(Text_t text) { switch (text.tag) { - case TEXT_ASCII: - return Int$from_int64((int64_t)sizeof(Text_t) + (int64_t)sizeof(char[text.length])); - case TEXT_GRAPHEMES: - return Int$from_int64((int64_t)sizeof(Text_t) + (int64_t)sizeof(int32_t[text.length])); + case TEXT_ASCII: return Int$from_int64((int64_t)sizeof(Text_t) + (int64_t)sizeof(char[text.length])); + case TEXT_GRAPHEMES: return Int$from_int64((int64_t)sizeof(Text_t) + (int64_t)sizeof(int32_t[text.length])); case TEXT_BLOB: - return Int$from_int64((int64_t)sizeof(Text_t) + (int64_t)((void*)text.blob.bytes - (void*)text.blob.map) + (int64_t)sizeof(uint8_t[text.length])); + return Int$from_int64((int64_t)sizeof(Text_t) + (int64_t)((void *)text.blob.bytes - (void *)text.blob.map) + + (int64_t)sizeof(uint8_t[text.length])); case TEXT_CONCAT: - return Int$plus( - Int$from_int64((int64_t)sizeof(Text_t)), - Int$plus(Text$memory_size(*text.left), Text$memory_size(*text.right))); + return Int$plus(Int$from_int64((int64_t)sizeof(Text_t)), + Int$plus(Text$memory_size(*text.left), Text$memory_size(*text.right))); default: errx(1, "Invalid text tag: %d", text.tag); } } -public Text_t Text$layout(Text_t text) -{ +public +Text_t Text$layout(Text_t text) { switch (text.tag) { - case TEXT_ASCII: - return Texts(Text("ASCII("), Int64$as_text((int64_t[1]){text.length}, false, NULL), Text(")")); + case TEXT_ASCII: return Texts(Text("ASCII("), Int64$as_text((int64_t[1]){text.length}, false, NULL), Text(")")); case TEXT_GRAPHEMES: return Texts(Text("Graphemes("), Int64$as_text((int64_t[1]){text.length}, false, NULL), Text(")")); - case TEXT_BLOB: - return Texts(Text("Blob("), Int64$as_text((int64_t[1]){text.length}, false, NULL), Text(")")); + case TEXT_BLOB: return Texts(Text("Blob("), Int64$as_text((int64_t[1]){text.length}, false, NULL), Text(")")); case TEXT_CONCAT: return Texts(Text("Concat("), Text$layout(*text.left), Text(", "), Text$layout(*text.right), Text(")")); default: errx(1, "Invalid text tag: %d", text.tag); } } -public void Text$serialize(const void *obj, FILE *out, Table_t *pointers, const TypeInfo_t *info) -{ +public +void Text$serialize(const void *obj, FILE *out, Table_t *pointers, const TypeInfo_t *info) { (void)info; - const char *str = Text$as_c_string(*(Text_t*)obj); + const char *str = Text$as_c_string(*(Text_t *)obj); int64_t len = (int64_t)strlen(str); Int64$serialize(&len, out, pointers, &Int64$info); fwrite(str, sizeof(char), (size_t)len, out); } -public void Text$deserialize(FILE *in, void *out, List_t *pointers, const TypeInfo_t *info) -{ +public +void Text$deserialize(FILE *in, void *out, List_t *pointers, const TypeInfo_t *info) { (void)info; int64_t len = 0; Int64$deserialize(in, &len, pointers, &Int64$info); - if (len < 0) - fail("Cannot deserialize text with a negative length!"); - char *buf = GC_MALLOC_ATOMIC((size_t)len+1); - if (fread(buf, sizeof(char), (size_t)len, in) != (size_t)len) - fail("Not enough data in stream to deserialize"); - buf[len+1] = '\0'; - *(Text_t*)out = Text$from_strn(buf, (size_t)len); -} - -public const TypeInfo_t Text$info = { - .size=sizeof(Text_t), - .align=__alignof__(Text_t), - .tag=TextInfo, - .TextInfo={.lang="Text"}, - .metamethods=Text$metamethods, + if (len < 0) fail("Cannot deserialize text with a negative length!"); + char *buf = GC_MALLOC_ATOMIC((size_t)len + 1); + if (fread(buf, sizeof(char), (size_t)len, in) != (size_t)len) fail("Not enough data in stream to deserialize"); + buf[len + 1] = '\0'; + *(Text_t *)out = Text$from_strn(buf, (size_t)len); +} + +public +const TypeInfo_t Text$info = { + .size = sizeof(Text_t), + .align = __alignof__(Text_t), + .tag = TextInfo, + .TextInfo = {.lang = "Text"}, + .metamethods = Text$metamethods, }; // vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0 diff --git a/src/stdlib/text.h b/src/stdlib/text.h index cb3f1b90..6bedcb60 100644 --- a/src/stdlib/text.h +++ b/src/stdlib/text.h @@ -21,22 +21,20 @@ typedef struct { int64_t stack_index; } TextIter_t; -#define NEW_TEXT_ITER_STATE(t) (TextIter_t){.stack={{t, 0}}, .stack_index=0} +#define NEW_TEXT_ITER_STATE(t) (TextIter_t){.stack = {{t, 0}}, .stack_index = 0} -#define Text(str) ((Text_t){.length=sizeof(str)-1, .tag=TEXT_ASCII, .ascii="" str}) +#define Text(str) ((Text_t){.length = sizeof(str) - 1, .tag = TEXT_ASCII, .ascii = "" str}) static inline Text_t Text_from_str_literal(const char *str) { - return (Text_t){.length=strlen(str), .tag=TEXT_ASCII, .ascii=str}; + return (Text_t){.length = strlen(str), .tag = TEXT_ASCII, .ascii = str}; } -static inline Text_t Text_from_text(Text_t t) { - return t; -} +static inline Text_t Text_from_text(Text_t t) { return t; } -#define convert_to_text(x) _Generic(x, Text_t: Text_from_text, char*: Text$from_str, const char*: Text$from_str)(x) +#define convert_to_text(x) _Generic(x, Text_t: Text_from_text, char *: Text$from_str, const char *: Text$from_str)(x) Text_t Text$_concat(int n, Text_t items[n]); -#define Text$concat(...) Text$_concat(sizeof((Text_t[]){__VA_ARGS__})/sizeof(Text_t), (Text_t[]){__VA_ARGS__}) +#define Text$concat(...) Text$_concat(sizeof((Text_t[]){__VA_ARGS__}) / sizeof(Text_t), (Text_t[]){__VA_ARGS__}) #define Texts(...) Text$concat(MAP_LIST(convert_to_text, __VA_ARGS__)) // int Text$print(FILE *stream, Text_t t); Text_t Text$slice(Text_t text, Int_t first_int, Int_t last_int); @@ -46,12 +44,12 @@ Text_t Text$reversed(Text_t text); Text_t Text$cluster(Text_t text, Int_t index_int); 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*); -PUREFUNC int32_t Text$compare(const void *va, const void *vb, const TypeInfo_t*); -PUREFUNC bool Text$equal(const void *a, const void *b, const TypeInfo_t*); +PUREFUNC uint64_t Text$hash(const void *text, const TypeInfo_t *); +PUREFUNC int32_t Text$compare(const void *va, const void *vb, const TypeInfo_t *); +PUREFUNC bool Text$equal(const void *a, const void *b, const TypeInfo_t *); PUREFUNC bool Text$equal_values(Text_t a, Text_t b); PUREFUNC bool Text$equal_ignoring_case(Text_t a, Text_t b, Text_t language); -PUREFUNC bool Text$is_none(const void *t, const TypeInfo_t*); +PUREFUNC bool Text$is_none(const void *t, const TypeInfo_t *); Text_t Text$upper(Text_t text, Text_t language); Text_t Text$lower(Text_t text, Text_t language); Text_t Text$title(Text_t text, Text_t language); @@ -92,8 +90,7 @@ Text_t Text$layout(Text_t text); void Text$serialize(const void *obj, FILE *out, Table_t *, const TypeInfo_t *); void Text$deserialize(FILE *in, void *out, List_t *, const TypeInfo_t *); -MACROLIKE int32_t Text$get_grapheme(Text_t text, int64_t index) -{ +MACROLIKE int32_t Text$get_grapheme(Text_t text, int64_t index) { TextIter_t state = NEW_TEXT_ITER_STATE(text); return Text$get_grapheme_fast(&state, index); } @@ -101,14 +98,15 @@ MACROLIKE int32_t Text$get_grapheme(Text_t text, int64_t index) extern const TypeInfo_t Text$info; extern Text_t EMPTY_TEXT; -#define Text$metamethods { \ - .as_text=Text$as_text, \ - .hash=Text$hash, \ - .compare=Text$compare, \ - .equal=Text$equal, \ - .is_none=Text$is_none, \ - .serialize=Text$serialize, \ - .deserialize=Text$deserialize, \ -} +#define Text$metamethods \ + { \ + .as_text = Text$as_text, \ + .hash = Text$hash, \ + .compare = Text$compare, \ + .equal = Text$equal, \ + .is_none = Text$is_none, \ + .serialize = Text$serialize, \ + .deserialize = Text$deserialize, \ + } // vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0 diff --git a/src/stdlib/types.c b/src/stdlib/types.c index 0f17cb21..e64195fe 100644 --- a/src/stdlib/types.c +++ b/src/stdlib/types.c @@ -3,24 +3,21 @@ #include <gc.h> #include <sys/param.h> -#include "util.h" #include "text.h" #include "types.h" +#include "util.h" -public Text_t Type$as_text(const void *typeinfo, bool colorize, const TypeInfo_t *type) -{ +public +Text_t Type$as_text(const void *typeinfo, bool colorize, const TypeInfo_t *type) { if (!typeinfo) return Text("Type"); - if (colorize) - return Text$concat( - Text("\x1b[36;1m"), - Text$from_str(type->TypeInfoInfo.type_str), - Text("\x1b[m")); - else - return Text$from_str(type->TypeInfoInfo.type_str); + if (colorize) return Text$concat(Text("\x1b[36;1m"), Text$from_str(type->TypeInfoInfo.type_str), Text("\x1b[m")); + else return Text$from_str(type->TypeInfoInfo.type_str); } -public const TypeInfo_t Void$info = {.size=0, .align=0, .tag=StructInfo}; -public const TypeInfo_t Abort$info = {.size=0, .align=0, .tag=StructInfo}; +public +const TypeInfo_t Void$info = {.size = 0, .align = 0, .tag = StructInfo}; +public +const TypeInfo_t Abort$info = {.size = 0, .align = 0, .tag = StructInfo}; // vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0 diff --git a/src/stdlib/types.h b/src/stdlib/types.h index 60f1fcfd..a6509183 100644 --- a/src/stdlib/types.h +++ b/src/stdlib/types.h @@ -10,13 +10,13 @@ typedef struct TypeInfo_s TypeInfo_t; -typedef void (*serialize_fn_t)(const void*, FILE*, Table_t*, const TypeInfo_t*); -typedef void (*deserialize_fn_t)(FILE*, void*, List_t*, const TypeInfo_t*); -typedef bool (*is_none_fn_t)(const void*, const TypeInfo_t*); -typedef uint64_t (*hash_fn_t)(const void*, const TypeInfo_t*); -typedef int32_t (*compare_fn_t)(const void*, const void*, const TypeInfo_t*); -typedef bool (*equal_fn_t)(const void*, const void*, const TypeInfo_t*); -typedef Text_t (*as_text_fn_t)(const void*, bool, const TypeInfo_t*); +typedef void (*serialize_fn_t)(const void *, FILE *, Table_t *, const TypeInfo_t *); +typedef void (*deserialize_fn_t)(FILE *, void *, List_t *, const TypeInfo_t *); +typedef bool (*is_none_fn_t)(const void *, const TypeInfo_t *); +typedef uint64_t (*hash_fn_t)(const void *, const TypeInfo_t *); +typedef int32_t (*compare_fn_t)(const void *, const void *, const TypeInfo_t *); +typedef bool (*equal_fn_t)(const void *, const void *, const TypeInfo_t *); +typedef Text_t (*as_text_fn_t)(const void *, bool, const TypeInfo_t *); typedef struct { hash_fn_t hash; @@ -36,11 +36,22 @@ typedef struct { struct TypeInfo_s { int64_t size, align; metamethods_t metamethods; - struct { // Anonymous tagged union for convenience - enum { OpaqueInfo, StructInfo, EnumInfo, PointerInfo, TextInfo, ListInfo, TableInfo, FunctionInfo, - OptionalInfo, TypeInfoInfo } tag; + struct { // Anonymous tagged union for convenience + enum { + OpaqueInfo, + StructInfo, + EnumInfo, + PointerInfo, + TextInfo, + ListInfo, + TableInfo, + FunctionInfo, + OptionalInfo, + TypeInfoInfo + } tag; union { - struct {} OpaqueInfo; + struct { + } OpaqueInfo; struct { const char *sigil; const TypeInfo_t *pointed; @@ -72,7 +83,7 @@ struct TypeInfo_s { const char *name; NamedType_t *fields; int num_fields; - bool is_secret:1, is_opaque:1; + bool is_secret : 1, is_opaque : 1; } StructInfo; }; }; @@ -84,18 +95,22 @@ extern const TypeInfo_t Abort$info; Text_t Type$as_text(const void *typeinfo, bool colorize, const TypeInfo_t *type); -#define Type$info(typestr) &((TypeInfo_t){.size=sizeof(TypeInfo_t), .align=__alignof__(TypeInfo_t), \ - .tag=TypeInfoInfo, .TypeInfoInfo.type_str=typestr, \ - .metamethods={.serialize=cannot_serialize, .deserialize=cannot_deserialize, .as_text=Type$as_text}}) +#define Type$info(typestr) \ + &((TypeInfo_t){ \ + .size = sizeof(TypeInfo_t), \ + .align = __alignof__(TypeInfo_t), \ + .tag = TypeInfoInfo, \ + .TypeInfoInfo.type_str = typestr, \ + .metamethods = {.serialize = cannot_serialize, .deserialize = cannot_deserialize, .as_text = Type$as_text}}) -#define DEFINE_OPTIONAL_TYPE(t, unpadded_size, name) \ - typedef struct { \ - union { \ - t value; \ - struct { \ - char _padding[unpadded_size]; \ - Bool_t is_none; \ - }; \ - }; \ +#define DEFINE_OPTIONAL_TYPE(t, unpadded_size, name) \ + typedef struct { \ + union { \ + t value; \ + struct { \ + char _padding[unpadded_size]; \ + Bool_t is_none; \ + }; \ + }; \ } name // vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0 diff --git a/src/stdlib/util.h b/src/stdlib/util.h index 3b00e6e9..819cecd9 100644 --- a/src/stdlib/util.h +++ b/src/stdlib/util.h @@ -3,38 +3,56 @@ // Built-in utility functions #include <assert.h> +#include <err.h> #include <gc.h> #include <stdbool.h> #include <string.h> -#include <err.h> #define streq(a, b) (((a) == NULL && (b) == NULL) || (((a) == NULL) == ((b) == NULL) && strcmp(a, b) == 0)) #define starts_with(line, prefix) (strncmp(line, prefix, strlen(prefix)) == 0) -#define ends_with(line, suffix) (strlen(line) >= strlen(suffix) && strcmp(line + strlen(line) - strlen(suffix), suffix) == 0) -#define new(t, ...) ((t*)memcpy(GC_MALLOC(sizeof(t)), &(t){__VA_ARGS__}, sizeof(t))) -#define heap(x) (__typeof(x)*)memcpy(GC_MALLOC(sizeof(x)), (__typeof(x)[1]){x}, sizeof(x)) -#define stack(x) (__typeof(x)*)((__typeof(x)[1]){x}) -#define check_initialized(var, init_var, name) *({ if (!init_var) fail("The variable " name " is being accessed before it has been initialized!"); \ - &var; }) +#define ends_with(line, suffix) \ + (strlen(line) >= strlen(suffix) && strcmp(line + strlen(line) - strlen(suffix), suffix) == 0) +#define new(t, ...) ((t *)memcpy(GC_MALLOC(sizeof(t)), &(t){__VA_ARGS__}, sizeof(t))) +#define heap(x) (__typeof(x) *)memcpy(GC_MALLOC(sizeof(x)), (__typeof(x)[1]){x}, sizeof(x)) +#define stack(x) (__typeof(x) *)((__typeof(x)[1]){x}) +#define check_initialized(var, init_var, name) \ + *({ \ + if (!init_var) fail("The variable " name " is being accessed before it has been initialized!"); \ + &var; \ + }) -#define IF_DECLARE(decl, expr, block) if (({ decl; expr ? ({ block; 1; }) : 0; })) {} +#define IF_DECLARE(decl, expr, block) \ + if (({ \ + decl; \ + expr ? ({ \ + block; \ + 1; \ + }) \ + : 0; \ + })) { \ + } -#define WHEN(type, subj, var, body) { type var = subj; switch (var.$tag) body } +#define WHEN(type, subj, var, body) \ + { \ + type var = subj; \ + switch (var.$tag) \ + body \ + } #ifndef public -#define public __attribute__ ((visibility ("default"))) +#define public __attribute__((visibility("default"))) #endif #ifndef PUREFUNC -#define PUREFUNC __attribute__ ((pure)) +#define PUREFUNC __attribute__((pure)) #endif #ifndef CONSTFUNC -#define CONSTFUNC __attribute__ ((const)) +#define CONSTFUNC __attribute__((const)) #endif #ifndef INLINE -#define INLINE inline __attribute__ ((always_inline)) +#define INLINE inline __attribute__((always_inline)) #endif #ifndef likely |
