From 9e07c6adc7a0616eec40e78024a8501ec7d96559 Mon Sep 17 00:00:00 2001 From: Bruce Hill Date: Sun, 18 Aug 2024 23:31:36 -0400 Subject: [PATCH] Add Channel:peek() --- api/channels.md | 26 ++++++++++++++++++++++++++ builtins/channel.c | 10 ++++++++++ builtins/channel.h | 2 ++ compile.c | 4 ++++ test/threads.tm | 5 ++++- typecheck.c | 1 + 6 files changed, 47 insertions(+), 1 deletion(-) diff --git a/api/channels.md b/api/channels.md index dbb6707..ca7ce17 100644 --- a/api/channels.md +++ b/api/channels.md @@ -91,6 +91,32 @@ get(channel:|T|) -> T **Returns:** The item removed from the channel. +**Example:** +```markdown +>> channel:peek() += "Hello" +``` + +--- + +### `peek` + +**Description:** +Returns the next item that will come out of the channel, but without removing +it. If the channel is empty, it waits until an item is available. + +**Usage:** +```markdown +peek(channel:|T|) -> T +``` + +**Parameters:** + +- `channel`: The channel from which to remove an item. + +**Returns:** +The item removed from the channel. + **Example:** ```markdown >> channel:get() diff --git a/builtins/channel.c b/builtins/channel.c index f47a0b1..9360bcf 100644 --- a/builtins/channel.c +++ b/builtins/channel.c @@ -68,6 +68,16 @@ public void Channel$get(channel_t *channel, void *out, int64_t item_size, int64_ (void)pthread_cond_signal(&channel->cond); } +public void Channel$peek(channel_t *channel, void *out, int64_t item_size) +{ + (void)pthread_mutex_lock(&channel->mutex); + while (channel->items.length == 0) + pthread_cond_wait(&channel->cond, &channel->mutex); + memcpy(out, channel->items.data, item_size); + (void)pthread_mutex_unlock(&channel->mutex); + (void)pthread_cond_signal(&channel->cond); +} + public array_t Channel$view(channel_t *channel) { (void)pthread_mutex_lock(&channel->mutex); diff --git a/builtins/channel.h b/builtins/channel.h index 3b2d2c1..b828237 100644 --- a/builtins/channel.h +++ b/builtins/channel.h @@ -15,6 +15,8 @@ void Channel$give(channel_t *channel, const void *item, int64_t padded_item_size void Channel$give_all(channel_t *channel, array_t to_give, int64_t padded_item_size); void Channel$get(channel_t *channel, void *out, int64_t item_size, int64_t padded_item_size); #define Channel$get_value(channel, t, padded_item_size) ({ t _val; Channel$get(channel, &_val, sizeof(t), padded_item_size); _val; }) +void Channel$peek(channel_t *channel, void *out, int64_t item_size); +#define Channel$peek_value(channel, t) ({ t _val; Channel$peek(channel, &_val, sizeof(t)); _val; }) void Channel$clear(channel_t *channel); array_t Channel$view(channel_t *channel); uint32_t Channel$hash(const channel_t **channel, const TypeInfo *type); diff --git a/compile.c b/compile.c index 08b5693..477913c 100644 --- a/compile.c +++ b/compile.c @@ -2377,6 +2377,10 @@ CORD compile(env_t *env, ast_t *ast) CORD self = compile_to_pointer_depth(env, call->self, 0, false); (void)compile_arguments(env, ast, NULL, call->args); return CORD_all("Channel$get_value(", self, ", ", compile_type(item_t), ", ", padded_item_size, ")"); + } else if (streq(call->name, "peek")) { + CORD self = compile_to_pointer_depth(env, call->self, 0, false); + (void)compile_arguments(env, ast, NULL, call->args); + return CORD_all("Channel$peek_value(", self, ", ", compile_type(item_t), ")"); } else if (streq(call->name, "clear")) { CORD self = compile_to_pointer_depth(env, call->self, 0, false); (void)compile_arguments(env, ast, NULL, call->args); diff --git a/test/threads.tm b/test/threads.tm index e8d83f4..f7acd01 100644 --- a/test/threads.tm +++ b/test/threads.tm @@ -2,6 +2,10 @@ enum Job(Increment(x:Int), Decrement(x:Int)) func main(): jobs := |:Job; max_size=2| + >> jobs:give(Increment(5)) + >> jobs:peek() + = Job.Increment(x=5) + results := |:Int; max_size| >> thread := Thread.new(func(): //! In another thread! @@ -13,7 +17,6 @@ func main(): >> results:give(x-1) ) - >> jobs:give(Increment(5)) >> jobs:give(Decrement(100)) >> jobs:give(Decrement(100)) >> jobs:give(Decrement(100)) diff --git a/typecheck.c b/typecheck.c index 805f83e..2fb8556 100644 --- a/typecheck.c +++ b/typecheck.c @@ -774,6 +774,7 @@ type_t *get_type(env_t *env, ast_t *ast) else if (streq(call->name, "get")) return Match(self_value_t, ChannelType)->item_type; else if (streq(call->name, "give")) return Type(VoidType); else if (streq(call->name, "give_all")) return Type(VoidType); + else if (streq(call->name, "peek")) return Match(self_value_t, ChannelType)->item_type; else if (streq(call->name, "view")) return Type(ArrayType, .item_type=Match(self_value_t, ChannelType)->item_type); else code_err(ast, "There is no '%s' method for arrays", call->name); }