From 8df0cc41c95e6c01d9c4c0fd1f57fbe96f40bbe7 Mon Sep 17 00:00:00 2001 From: Bruce Hill Date: Tue, 31 Dec 2024 15:57:13 -0500 Subject: [PATCH] Array:heap_pop() now returns an optional value --- compile.c | 3 ++- docs/arrays.md | 8 ++++---- stdlib/arrays.h | 10 +++++++--- typecheck.c | 2 +- 4 files changed, 14 insertions(+), 9 deletions(-) diff --git a/compile.c b/compile.c index 2cc3284..373762c 100644 --- a/compile.c +++ b/compile.c @@ -2963,7 +2963,8 @@ CORD compile(env_t *env, ast_t *ast) .type=Type(ClosureType, .fn=fn_t)); arg_t *arg_spec = new(arg_t, .name="by", .type=Type(ClosureType, .fn=fn_t), .default_val=default_cmp); CORD arg_code = compile_arguments(env, ast, arg_spec, call->args); - return CORD_all("Array$heap_pop_value(", self, ", ", arg_code, ", ", padded_item_size, ", ", compile_type(item_t), ")"); + return CORD_all("Array$heap_pop_value(", self, ", ", arg_code, ", ", compile_type(item_t), ", _, ", + promote_to_optional(item_t, "_"), ", ", compile_none(item_t), ", ", padded_item_size, ")"); } else if (streq(call->name, "binary_search")) { self = compile_to_pointer_depth(env, call->self, 0, call->args != NULL); type_t *item_ptr = Type(PointerType, .pointed=item_t, .is_stack=true); diff --git a/docs/arrays.md b/docs/arrays.md index 3bb15bd..7cae399 100644 --- a/docs/arrays.md +++ b/docs/arrays.md @@ -456,12 +456,12 @@ func has(arr: [T] -> Bool) ### `heap_pop` **Description:** -Removes and returns the top element of a heap. By default, this is the -*minimum* value in the heap. +Removes and returns the top element of a heap or `none` if the array is empty. +By default, this is the *minimum* value in the heap. **Signature:** ```tomo -func heap_pop(arr: @[T], by: func(x,y:&T->Int32) = T.compare -> T) +func heap_pop(arr: @[T], by: func(x,y:&T->Int32) = T.compare -> T?) ``` **Parameters:** @@ -471,7 +471,7 @@ func heap_pop(arr: @[T], by: func(x,y:&T->Int32) = T.compare -> T) default comparison function for the item type will be used. **Returns:** -The removed top element of the heap. +The removed top element of the heap or `none` if the array is empty. **Example:** ```tomo diff --git a/stdlib/arrays.h b/stdlib/arrays.h index f8921e0..cf1f088 100644 --- a/stdlib/arrays.h +++ b/stdlib/arrays.h @@ -107,9 +107,13 @@ void Array$heapify(Array_t *heap, Closure_t comparison, int64_t padded_item_size void Array$heap_push(Array_t *heap, const void *item, Closure_t comparison, int64_t padded_item_size); #define Array$heap_push_value(heap, _value, comparison, padded_item_size) ({ __typeof(_value) value = _value; Array$heap_push(heap, &value, comparison, padded_item_size); }) void Array$heap_pop(Array_t *heap, Closure_t comparison, int64_t padded_item_size); -#define Array$heap_pop_value(heap, comparison, padded_item_size, type) \ - ({ Array_t *_heap = heap; if (_heap->length == 0) fail("Attempt to pop from an empty array"); \ - type value = *(type*)_heap->data; Array$heap_pop(_heap, comparison, padded_item_size); value; }) +#define Array$heap_pop_value(heap, comparison, type, nonnone_var, nonnone_expr, none_expr, padded_item_size) \ + ({ Array_t *_heap = heap; \ + (_heap->length > 0) ? ({ \ + type nonnone_var = *(type*)_heap->data; \ + Array$heap_pop(_heap, comparison, padded_item_size); \ + nonnone_expr; \ + }) : none_expr; }) Int_t Array$binary_search(Array_t array, void *target, Closure_t comparison); #define Array$binary_search_value(array, target, comparison) \ ({ __typeof(target) _target = target; Array$binary_search(array, &_target, comparison); }) diff --git a/typecheck.c b/typecheck.c index afbc8df..f6a75ac 100644 --- a/typecheck.c +++ b/typecheck.c @@ -824,7 +824,7 @@ type_t *get_type(env_t *env, ast_t *ast) else if (streq(call->name, "first")) return Type(OptionalType, .type=INT_TYPE); else if (streq(call->name, "from")) return self_value_t; else if (streq(call->name, "has")) return Type(BoolType); - else if (streq(call->name, "heap_pop")) return item_type; + else if (streq(call->name, "heap_pop")) return Type(OptionalType, .type=item_type); else if (streq(call->name, "heap_push")) return Type(VoidType); else if (streq(call->name, "heapify")) return Type(VoidType); else if (streq(call->name, "insert")) return Type(VoidType);