Update channel API to take a Where parameter

This commit is contained in:
Bruce Hill 2024-08-18 23:59:13 -04:00
parent 9e07c6adc7
commit 8363d53bd2
10 changed files with 85 additions and 44 deletions

View File

@ -31,13 +31,15 @@ Adds an item to the channel.
**Usage:**
```markdown
give(channel:|T|, item: T) -> Void
give(channel:|T|, item: T, where: Where = Where.End) -> Void
```
**Parameters:**
- `channel`: The channel to which the item will be added.
- `item`: The item to add to the channel.
- `where`: Where to put the item (at the `Start` or `End` of the queue).
`Anywhere` defaults to `End`.
**Returns:**
Nothing.
@ -56,13 +58,15 @@ Adds multiple items to the channel.
**Usage:**
```markdown
give_all(channel:|T|, items: [T]) -> Void
give_all(channel:|T|, items: [T], where: Where = Where.End) -> Void
```
**Parameters:**
- `channel`: The channel to which the items will be added.
- `items`: The array of items to add to the channel.
- `where`: Where to put the items (at the `Start` or `End` of the queue).
`Anywhere` defaults to `End`.
**Returns:**
Nothing.
@ -81,12 +85,14 @@ Removes and returns an item from the channel. If the channel is empty, it waits
**Usage:**
```markdown
get(channel:|T|) -> T
get(channel:|T|, where: Where = Where.Start) -> T
```
**Parameters:**
- `channel`: The channel from which to remove an item.
- `where`: Where to get the item from (from the `Start` or `End` of the queue).
`Anywhere` defaults to `Start`.
**Returns:**
The item removed from the channel.
@ -107,12 +113,14 @@ it. If the channel is empty, it waits until an item is available.
**Usage:**
```markdown
peek(channel:|T|) -> T
peek(channel:|T|, where: Where = Where.Start) -> T
```
**Parameters:**
- `channel`: The channel from which to remove an item.
- `where`: Which end of the channel to peek from (the `Start` or `End`).
`Anywhere` defaults to `Start`.
**Returns:**
The item removed from the channel.

View File

@ -17,6 +17,7 @@
#include "integers.h"
#include "types.h"
#include "util.h"
#include "where.h"
public channel_t *Channel$new(Int_t max_size)
{
@ -30,50 +31,54 @@ public channel_t *Channel$new(Int_t max_size)
return channel;
}
public void Channel$give(channel_t *channel, const void *item, int64_t padded_item_size)
public void Channel$give(channel_t *channel, const void *item, Where_t where, int64_t padded_item_size)
{
(void)pthread_mutex_lock(&channel->mutex);
while (channel->items.length >= channel->max_size)
pthread_cond_wait(&channel->cond, &channel->mutex);
Array$insert(&channel->items, item, I(0), padded_item_size);
Int_t index = (where.tag == $tag$Where$Start) ? I(1) : I(0);
Array$insert(&channel->items, item, index, padded_item_size);
(void)pthread_mutex_unlock(&channel->mutex);
(void)pthread_cond_signal(&channel->cond);
}
public void Channel$give_all(channel_t *channel, array_t to_give, int64_t padded_item_size)
public void Channel$give_all(channel_t *channel, array_t to_give, Where_t where, int64_t padded_item_size)
{
if (to_give.length == 0) return;
(void)pthread_mutex_lock(&channel->mutex);
Int_t index = (where.tag == $tag$Where$Start) ? I(1) : I(0);
if (channel->items.length + to_give.length >= channel->max_size) {
for (int64_t i = 0; i < to_give.length; i++) {
while (channel->items.length >= channel->max_size)
pthread_cond_wait(&channel->cond, &channel->mutex);
Array$insert(&channel->items, to_give.data + i*to_give.stride, I(0), padded_item_size);
Array$insert(&channel->items, to_give.data + i*to_give.stride, index, padded_item_size);
}
} else {
Array$insert_all(&channel->items, to_give, I(0), padded_item_size);
Array$insert_all(&channel->items, to_give, index, padded_item_size);
}
(void)pthread_mutex_unlock(&channel->mutex);
(void)pthread_cond_signal(&channel->cond);
}
public void Channel$get(channel_t *channel, void *out, int64_t item_size, int64_t padded_item_size)
public void Channel$get(channel_t *channel, void *out, Where_t where, int64_t item_size, int64_t padded_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);
Array$remove_at(&channel->items, I(1), I(1), padded_item_size);
Int_t index = (where.tag == $tag$Where$End) ? I(0) : I(1);
Array$remove_at(&channel->items, index, I(1), padded_item_size);
(void)pthread_mutex_unlock(&channel->mutex);
(void)pthread_cond_signal(&channel->cond);
}
public void Channel$peek(channel_t *channel, void *out, int64_t item_size)
public void Channel$peek(channel_t *channel, void *out, Where_t where, 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);
int64_t index = (where.tag == $tag$Where$End) ? channel->items.length-1 : 0;
memcpy(out, channel->items.data + channel->items.stride*index, item_size);
(void)pthread_mutex_unlock(&channel->mutex);
(void)pthread_cond_signal(&channel->cond);
}

View File

@ -8,15 +8,18 @@
#include "datatypes.h"
#include "types.h"
#include "util.h"
#include "where.h"
channel_t *Channel$new(Int_t max_size);
void Channel$give(channel_t *channel, const void *item, int64_t padded_item_size);
#define Channel$give_value(channel, item, padded_item_size) ({ __typeof(item) _item = item; Channel$give(channel, &_item, 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$give(channel_t *channel, const void *item, Where_t where, int64_t padded_item_size);
#define Channel$give_value(channel, item, where, padded_item_size) \
({ __typeof(item) _item = item; Channel$give(channel, &_item, where, padded_item_size); })
void Channel$give_all(channel_t *channel, array_t to_give, Where_t where, int64_t padded_item_size);
void Channel$get(channel_t *channel, void *out, Where_t where, int64_t item_size, int64_t padded_item_size);
#define Channel$get_value(channel, where, t, padded_item_size) \
({ t _val; Channel$get(channel, &_val, where, sizeof(t), padded_item_size); _val; })
void Channel$peek(channel_t *channel, void *out, Where_t where, int64_t item_size);
#define Channel$peek_value(channel, where, t) ({ t _val; Channel$peek(channel, &_val, where, 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);

View File

@ -171,12 +171,12 @@ public bool Text$has(CORD str, CORD target, Where_t where)
if (target_norm_len > str_norm_len) return false;
bool ret;
if (where.$tag == $tag$Where$Start) {
if (where.tag == $tag$Where$Start) {
ret = (u8_strncmp(str_normalized, target_normalized, target_norm_len-1) == 0);
} else if (where.$tag == $tag$Where$End) {
} else if (where.tag == $tag$Where$End) {
ret = (u8_strcmp(str_normalized + str_norm_len - target_norm_len, target_normalized) == 0);
} else {
assert(where.$tag == $tag$Where$Anywhere);
assert(where.tag == $tag$Where$Anywhere);
ret = (u8_strstr(str_normalized, target_normalized) != NULL);
}
@ -191,11 +191,11 @@ public CORD Text$without(CORD str, CORD target, Where_t where)
size_t target_len = CORD_len(target);
size_t str_len = CORD_len(str);
if (where.$tag == $tag$Where$Start) {
if (where.tag == $tag$Where$Start) {
if (CORD_ncmp(str, 0, target, 0, target_len) == 0)
return CORD_substr(str, target_len, str_len - target_len);
return str;
} else if (where.$tag == $tag$Where$End) {
} else if (where.tag == $tag$Where$End) {
if (CORD_ncmp(str, str_len-target_len, target, 0, target_len) == 0)
return CORD_substr(str, 0, str_len - target_len);
return str;
@ -222,10 +222,10 @@ public CORD Text$trimmed(CORD str, CORD skip, Where_t where)
const uint8_t *ustr = (const uint8_t*)CORD_to_const_char_star(str);
const uint8_t *uskip = (const uint8_t*)CORD_to_const_char_star(skip);
// TODO: implement proper reverse iteration with u8_prev()
if (where.$tag == $tag$Where$Start) {
if (where.tag == $tag$Where$Start) {
size_t span = u8_strspn(ustr, uskip);
return (CORD)ustr + span;
} else if (where.$tag == $tag$Where$End) {
} else if (where.tag == $tag$Where$End) {
size_t len = u8_strlen(ustr);
const uint8_t *back = ustr + len;
size_t back_span = 0;

View File

@ -31,7 +31,7 @@ static CORD Where$as_text(Where_t *obj, bool use_color)
{
if (!obj)
return "Where";
switch (obj->$tag) {
switch (obj->tag) {
case $tag$Where$Anywhere:
return use_color ? "\x1b[36;1mWhere.Anywhere\x1b[m" : "Where.Anywhere";
case $tag$Where$Start:

View File

@ -22,7 +22,7 @@ struct Where$Anywhere_s {};
struct Where$Start_s {};
struct Where$End_s {};
struct Where_s {
enum { $tag$Where$Anywhere = 0, $tag$Where$Start = 1, $tag$Where$End = 2 } $tag;
enum { $tag$Where$Anywhere = 0, $tag$Where$Start = 1, $tag$Where$End = 2 } tag;
union {
Where$Anywhere_t Anywhere;
Where$Start_t Start;

View File

@ -2363,24 +2363,30 @@ CORD compile(env_t *env, ast_t *ast)
case ChannelType: {
type_t *item_t = Match(self_value_t, ChannelType)->item_type;
CORD padded_item_size = CORD_asprintf("%ld", padded_type_size(item_t));
arg_t *where_default_end = new(arg_t, .name="where", .type=WHERE_TYPE,
.default_val=FakeAST(FieldAccess, .fielded=FakeAST(Var, "Where"), .field="End"));
arg_t *where_default_start = new(arg_t, .name="where", .type=WHERE_TYPE,
.default_val=FakeAST(FieldAccess, .fielded=FakeAST(Var, "Where"), .field="Start"));
if (streq(call->name, "give")) {
CORD self = compile_to_pointer_depth(env, call->self, 0, false);
arg_t *arg_spec = new(arg_t, .name="item", .type=item_t);
arg_t *arg_spec = new(arg_t, .name="item", .type=item_t, .next=where_default_end);
return CORD_all("Channel$give_value(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ",
padded_item_size, ")");
} else if (streq(call->name, "give_all")) {
CORD self = compile_to_pointer_depth(env, call->self, 0, false);
arg_t *arg_spec = new(arg_t, .name="to_give", .type=Type(ArrayType, .item_type=item_t));
arg_t *arg_spec = new(arg_t, .name="to_give", .type=Type(ArrayType, .item_type=item_t), .next=where_default_end);
return CORD_all("Channel$give_all(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ",
padded_item_size, ")");
} else if (streq(call->name, "get")) {
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, ")");
arg_t *arg_spec = where_default_start;
return CORD_all("Channel$get_value(", self, ", ", compile_arguments(env, ast, arg_spec, call->args),
", ", 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), ")");
arg_t *arg_spec = where_default_start;
return CORD_all("Channel$peek_value(", self, ", ", compile_arguments(env, ast, arg_spec, call->args),
", ", 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);

View File

@ -11,6 +11,7 @@
type_t *TEXT_TYPE = NULL;
type_t *RANGE_TYPE = NULL;
type_t *WHERE_TYPE = NULL;
public type_t *THREAD_TYPE = NULL;
env_t *new_compilation_unit(CORD *libname)
@ -45,19 +46,18 @@ env_t *new_compilation_unit(CORD *libname)
const char *name, *code, *type_str;
} ns_entry_t;
type_t *where;
{
env_t *where_env = namespace_env(env, "Where");
type_t *anywhere = Type(StructType, .name="Anywhere");
type_t *start = Type(StructType, .name="Start");
type_t *end = Type(StructType, .name="End");
where = Type(EnumType, .name="Where", .env=where_env,
.tags=new(tag_t, .name="Anywhere", .tag_value=0, .type=anywhere,
.next=new(tag_t, .name="Start", .tag_value=0, .type=start,
.next=new(tag_t, .name="End", .tag_value=0, .type=end))));
set_binding(where_env, "Anywhere", new(binding_t, .type=where, .code="Where$tagged$Anywhere"));
set_binding(where_env, "Start", new(binding_t, .type=where, .code="Where$tagged$Start"));
set_binding(where_env, "End", new(binding_t, .type=where, .code="Where$tagged$End"));
WHERE_TYPE = Type(EnumType, .name="Where", .env=where_env,
.tags=new(tag_t, .name="Anywhere", .tag_value=0, .type=anywhere,
.next=new(tag_t, .name="Start", .tag_value=0, .type=start,
.next=new(tag_t, .name="End", .tag_value=0, .type=end))));
set_binding(where_env, "Anywhere", new(binding_t, .type=WHERE_TYPE, .code="Where$tagged$Anywhere"));
set_binding(where_env, "Start", new(binding_t, .type=WHERE_TYPE, .code="Where$tagged$Start"));
set_binding(where_env, "End", new(binding_t, .type=WHERE_TYPE, .code="Where$tagged$End"));
}
{
@ -240,7 +240,7 @@ env_t *new_compilation_unit(CORD *libname)
#undef F2
#undef F
#undef C
{"Where", where, "Where_t", "Where", {}},
{"Where", WHERE_TYPE, "Where_t", "Where", {}},
{"Range", RANGE_TYPE, "Range_t", "Range", TypedArray(ns_entry_t,
{"reversed", "Range$reversed", "func(range:Range)->Range"},
{"by", "Range$by", "func(range:Range, step:Int)->Range"},

View File

@ -77,5 +77,6 @@ binding_t *get_namespace_binding(env_t *env, ast_t *self, const char *name);
extern type_t *TEXT_TYPE;
extern type_t *RANGE_TYPE;
extern type_t *THREAD_TYPE;
extern type_t *WHERE_TYPE;
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0

View File

@ -1,6 +1,24 @@
enum Job(Increment(x:Int), Decrement(x:Int))
func main():
do:
>> channel := |:Int|
>> channel:give(10)
>> channel:give(20)
>> channel:give(30)
>> channel:view()
= [10, 20, 30]
>> channel:peek()
= 10
>> channel:peek(End)
= 30
>> channel:give(-10, Start)
>> channel:view()
= [-10, 10, 20, 30]
jobs := |:Job; max_size=2|
>> jobs:give(Increment(5))
>> jobs:peek()