From 10795782c674df12fc70ea3aeeaa2f62158b6cbd Mon Sep 17 00:00:00 2001 From: Bruce Hill Date: Thu, 12 Sep 2024 13:17:53 -0400 Subject: Implement optional hashing/equality/comparisons --- builtins/functions.c | 16 +++++++++++----- builtins/optionals.c | 2 +- builtins/optionals.h | 1 + test/optionals.tm | 10 ++++++++++ 4 files changed, 23 insertions(+), 6 deletions(-) diff --git a/builtins/functions.c b/builtins/functions.c index 3c01f678..a2b17807 100644 --- a/builtins/functions.c +++ b/builtins/functions.c @@ -115,9 +115,7 @@ PUREFUNC public uint64_t generic_hash(const void *obj, const TypeInfo *type) case ArrayInfo: return Array$hash(obj, type); case ChannelInfo: return Channel$hash((Channel_t**)obj, type); case TableInfo: return Table$hash(obj, type); - case OptionalInfo: { - errx(1, "Optional hash not implemented"); - } + case OptionalInfo: return is_null(obj, type->OptionalInfo.type) ? 0 : generic_hash(obj, type->OptionalInfo.type); case EmptyStructInfo: return 0; case CustomInfo: case StructInfo: case EnumInfo: case CStringInfo: // These all share the same info if (!type->CustomInfo.hash) @@ -141,7 +139,11 @@ PUREFUNC public int32_t generic_compare(const void *x, const void *y, const Type case ChannelInfo: return Channel$compare((Channel_t**)x, (Channel_t**)y, type); case TableInfo: return Table$compare(x, y, type); case OptionalInfo: { - errx(1, "Optional compare not implemented"); + bool x_is_null = is_null(x, type->OptionalInfo.type); + bool y_is_null = is_null(y, type->OptionalInfo.type); + if (x_is_null && y_is_null) return 0; + else if (x_is_null != y_is_null) return (int32_t)y_is_null - (int32_t)x_is_null; + else return generic_compare(x, y, type->OptionalInfo.type); } case EmptyStructInfo: return 0; case CustomInfo: case StructInfo: case EnumInfo: case CStringInfo: // These all share the same info @@ -166,7 +168,11 @@ PUREFUNC public bool generic_equal(const void *x, const void *y, const TypeInfo case TableInfo: return Table$equal(x, y, type); case EmptyStructInfo: return true; case OptionalInfo: { - errx(1, "Optional equal not implemented"); + bool x_is_null = is_null(x, type->OptionalInfo.type); + bool y_is_null = is_null(y, type->OptionalInfo.type); + if (x_is_null && y_is_null) return true; + else if (x_is_null != y_is_null) return false; + else return generic_equal(x, y, type->OptionalInfo.type); } case CustomInfo: case StructInfo: case EnumInfo: case CStringInfo: // These all share the same info if (!type->CustomInfo.equal) diff --git a/builtins/optionals.c b/builtins/optionals.c index 8a1aaf99..8b890c97 100644 --- a/builtins/optionals.c +++ b/builtins/optionals.c @@ -14,7 +14,7 @@ public const Table_t NULL_TABLE = {.entries.length=-1}; public const Closure_t NULL_CLOSURE = {.fn=NULL}; public const Text_t NULL_TEXT = {.length=-1}; -static inline bool is_null(const void *obj, const TypeInfo *non_optional_type) +public PUREFUNC bool is_null(const void *obj, const TypeInfo *non_optional_type) { if (non_optional_type == &Int$info) return ((Int_t*)obj)->small == 0; diff --git a/builtins/optionals.h b/builtins/optionals.h index 10599473..5f0a407f 100644 --- a/builtins/optionals.h +++ b/builtins/optionals.h @@ -18,6 +18,7 @@ extern const Int_t NULL_INT; extern const Closure_t NULL_CLOSURE; extern const Text_t NULL_TEXT; +PUREFUNC bool is_null(const void *obj, const TypeInfo *non_optional_type); Text_t Optional$as_text(const void *obj, bool colorize, const TypeInfo *type); // vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0 diff --git a/test/optionals.tm b/test/optionals.tm index 5c18d58d..a3f33d6c 100644 --- a/test/optionals.tm +++ b/test/optionals.tm @@ -274,3 +274,13 @@ func main(): >> maybe_int(yes)! = 123 : Int + + # Test comparisons, hashing, equality: + >> (!Int == 5?) + = no + >> (5? == 5?) + = yes + >> {!Int, !Int} + = {!Int} + >> [5?, !Int, !Int, 6?]:sorted() + = [!Int, !Int, 5?, 6?] -- cgit v1.2.3