Deprecate Where
and change channel API to use a boolean front
value
This commit is contained in:
parent
5f0b099e14
commit
5feecff9d9
2
Makefile
2
Makefile
@ -25,7 +25,7 @@ O=-Og
|
||||
CFLAGS=$(CCONFIG) $(EXTRA) $(CWARN) $(G) $(O) $(OSFLAGS)
|
||||
LDLIBS=-lgc -lcord -lreadline -lm -lunistring -lgmp -ldl
|
||||
BUILTIN_OBJS=builtins/array.o builtins/bool.o builtins/channel.o builtins/nums.o builtins/functions.o builtins/integers.o \
|
||||
builtins/pointer.o builtins/memory.o builtins/text.o builtins/thread.o builtins/where.o builtins/c_string.o builtins/table.o \
|
||||
builtins/pointer.o builtins/memory.o builtins/text.o builtins/thread.o builtins/c_string.o builtins/table.o \
|
||||
builtins/types.o builtins/util.o builtins/files.o builtins/range.o
|
||||
TESTS=$(patsubst %.tm,%.tm.testresult,$(wildcard test/*.tm))
|
||||
|
||||
|
@ -18,11 +18,10 @@
|
||||
#include "text.h"
|
||||
#include "types.h"
|
||||
#include "util.h"
|
||||
#include "where.h"
|
||||
|
||||
public channel_t *Channel$new(Int_t max_size)
|
||||
{
|
||||
if (Int$compare_value(max_size, I(0)) <= 0)
|
||||
if (Int$compare_value(max_size, I_small(0)) <= 0)
|
||||
fail("Cannot create a channel with a size less than one: %ld", max_size);
|
||||
channel_t *channel = new(channel_t);
|
||||
channel->items = (array_t){};
|
||||
@ -32,22 +31,22 @@ public channel_t *Channel$new(Int_t max_size)
|
||||
return channel;
|
||||
}
|
||||
|
||||
public void Channel$give(channel_t *channel, const void *item, Where_t where, int64_t padded_item_size)
|
||||
public void Channel$give(channel_t *channel, const void *item, bool front, 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);
|
||||
Int_t index = (where.tag == $tag$Where$Start) ? I(1) : I(0);
|
||||
Int_t index = front ? I_small(1) : I_small(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, Where_t where, int64_t padded_item_size)
|
||||
public void Channel$give_all(channel_t *channel, array_t to_give, bool front, 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);
|
||||
Int_t index = front ? I_small(1) : I_small(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)
|
||||
@ -61,24 +60,24 @@ public void Channel$give_all(channel_t *channel, array_t to_give, Where_t where,
|
||||
(void)pthread_cond_signal(&channel->cond);
|
||||
}
|
||||
|
||||
public void Channel$get(channel_t *channel, void *out, Where_t where, int64_t item_size, int64_t padded_item_size)
|
||||
public void Channel$get(channel_t *channel, void *out, bool front, 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);
|
||||
Int_t index = (where.tag == $tag$Where$End) ? I(0) : I(1);
|
||||
Array$remove_at(&channel->items, index, I(1), padded_item_size);
|
||||
memcpy(out, channel->items.data + channel->items.stride * (front ? 0 : channel->items.length-1), item_size);
|
||||
Int_t index = front ? I_small(1) : Int64_to_Int(channel->items.length);
|
||||
Array$remove_at(&channel->items, index, I_small(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, Where_t where, int64_t item_size)
|
||||
public void Channel$peek(channel_t *channel, void *out, bool front, int64_t item_size)
|
||||
{
|
||||
(void)pthread_mutex_lock(&channel->mutex);
|
||||
while (channel->items.length == 0)
|
||||
pthread_cond_wait(&channel->cond, &channel->mutex);
|
||||
int64_t index = (where.tag == $tag$Where$End) ? channel->items.length-1 : 0;
|
||||
int64_t index = front ? 0 : channel->items.length-1;
|
||||
memcpy(out, channel->items.data + channel->items.stride*index, item_size);
|
||||
(void)pthread_mutex_unlock(&channel->mutex);
|
||||
(void)pthread_cond_signal(&channel->cond);
|
||||
|
@ -8,18 +8,17 @@
|
||||
#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, 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$give(channel_t *channel, const void *item, bool front, int64_t padded_item_size);
|
||||
#define Channel$give_value(channel, item, front, padded_item_size) \
|
||||
({ __typeof(item) _item = item; Channel$give(channel, &_item, front, padded_item_size); })
|
||||
void Channel$give_all(channel_t *channel, array_t to_give, bool front, int64_t padded_item_size);
|
||||
void Channel$get(channel_t *channel, void *out, bool front, int64_t item_size, int64_t padded_item_size);
|
||||
#define Channel$get_value(channel, front, t, padded_item_size) \
|
||||
({ t _val; Channel$get(channel, &_val, front, sizeof(t), padded_item_size); _val; })
|
||||
void Channel$peek(channel_t *channel, void *out, bool front, int64_t item_size);
|
||||
#define Channel$peek_value(channel, front, t) ({ t _val; Channel$peek(channel, &_val, front, sizeof(t)); _val; })
|
||||
void Channel$clear(channel_t *channel);
|
||||
array_t Channel$view(channel_t *channel);
|
||||
uint64_t Channel$hash(const channel_t **channel, const TypeInfo *type);
|
||||
|
@ -10,7 +10,6 @@
|
||||
#include "datatypes.h"
|
||||
#include "integers.h"
|
||||
#include "types.h"
|
||||
#include "where.h"
|
||||
|
||||
int printf_text(FILE *stream, const struct printf_info *info, const void *const args[]);
|
||||
int printf_text_size(const struct printf_info *info, size_t n, int argtypes[n], int sizes[n]);
|
||||
|
@ -1,37 +0,0 @@
|
||||
// A type called "Where" that is an enum for "Anywhere", "Start", or "End"
|
||||
// Mainly used for text methods
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "text.h"
|
||||
#include "types.h"
|
||||
#include "util.h"
|
||||
#include "where.h"
|
||||
|
||||
static Text_t Where$as_text(Where_t *obj, bool use_color)
|
||||
{
|
||||
if (!obj)
|
||||
return Text$from_str("Where");
|
||||
switch (obj->tag) {
|
||||
case $tag$Where$Anywhere:
|
||||
return Text$from_str(use_color ? "\x1b[36;1mWhere.Anywhere\x1b[m" : "Where.Anywhere");
|
||||
case $tag$Where$Start:
|
||||
return Text$from_str(use_color ? "\x1b[36;1mWhere.Start\x1b[m" : "Where.Start");
|
||||
case $tag$Where$End:
|
||||
return Text$from_str(use_color ? "\x1b[36;1mWhere.End\x1b[m" : "Where.End");
|
||||
default:
|
||||
return (Text_t){.length=0};
|
||||
}
|
||||
}
|
||||
|
||||
public const Where_t Where$tagged$Anywhere = {$tag$Where$Anywhere};
|
||||
public const Where_t Where$tagged$Start = {$tag$Where$Start};
|
||||
public const Where_t Where$tagged$End = {$tag$Where$End};
|
||||
public const TypeInfo Where$Anywhere = {0, 0, {.tag=EmptyStruct, .EmptyStruct.name="Anywhere"}};
|
||||
public const TypeInfo Where$Start = {0, 0, {.tag=EmptyStruct, .EmptyStruct.name="Start"}};
|
||||
public const TypeInfo Where$End = {0, 0, {.tag=EmptyStruct, .EmptyStruct.name="End"}};
|
||||
public const TypeInfo Where = {sizeof(Where_t), __alignof__(Where_t),
|
||||
{.tag=CustomInfo, .CustomInfo={.as_text=(void*)Where$as_text}}};
|
||||
|
||||
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
|
@ -1,37 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
// Type info and methods for Where datatype (Anywhere, Start, or End enum)
|
||||
// Mainly used for text methods.
|
||||
|
||||
#include <gc/cord.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "types.h"
|
||||
|
||||
typedef struct Where_s Where_t;
|
||||
extern const TypeInfo Where;
|
||||
typedef struct Where$Anywhere_s Where$Anywhere_t;
|
||||
extern const TypeInfo Where$Anywhere;
|
||||
typedef struct Where$Start_s Where$Start_t;
|
||||
extern const TypeInfo Where$Start;
|
||||
typedef struct Where$End_s Where$End_t;
|
||||
extern const TypeInfo Where$End;
|
||||
|
||||
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;
|
||||
union {
|
||||
Where$Anywhere_t Anywhere;
|
||||
Where$Start_t Start;
|
||||
Where$End_t End;
|
||||
};
|
||||
};
|
||||
|
||||
extern const Where_t Where$tagged$Anywhere;
|
||||
extern const Where_t Where$tagged$Start;
|
||||
extern const Where_t Where$tagged$End;
|
||||
|
||||
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
|
14
compile.c
14
compile.c
@ -2404,28 +2404,26 @@ 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"));
|
||||
arg_t *front_default_end = new(arg_t, .name="front", .type=Type(BoolType), .default_val=FakeAST(Bool, false));
|
||||
arg_t *front_default_start = new(arg_t, .name="front", .type=Type(BoolType), .default_val=FakeAST(Bool, true));
|
||||
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, .next=where_default_end);
|
||||
arg_t *arg_spec = new(arg_t, .name="item", .type=item_t, .next=front_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), .next=where_default_end);
|
||||
arg_t *arg_spec = new(arg_t, .name="to_give", .type=Type(ArrayType, .item_type=item_t), .next=front_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);
|
||||
arg_t *arg_spec = where_default_start;
|
||||
arg_t *arg_spec = front_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);
|
||||
arg_t *arg_spec = where_default_start;
|
||||
arg_t *arg_spec = front_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")) {
|
||||
|
@ -31,15 +31,14 @@ Adds an item to the channel.
|
||||
|
||||
**Usage:**
|
||||
```markdown
|
||||
give(channel:|T|, item: T, where: Where = Where.End) -> Void
|
||||
give(channel:|T|, item: T, front: Bool = no) -> 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`.
|
||||
- `front`: Whether to put the item at the front of the channel (as opposed to the back).
|
||||
|
||||
**Returns:**
|
||||
Nothing.
|
||||
@ -58,15 +57,14 @@ Adds multiple items to the channel.
|
||||
|
||||
**Usage:**
|
||||
```markdown
|
||||
give_all(channel:|T|, items: [T], where: Where = Where.End) -> Void
|
||||
give_all(channel:|T|, items: [T], front: Bool = no) -> 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`.
|
||||
- `front`: Whether to put the item at the front of the channel (as opposed to the back).
|
||||
|
||||
**Returns:**
|
||||
Nothing.
|
||||
@ -85,14 +83,13 @@ Removes and returns an item from the channel. If the channel is empty, it waits
|
||||
|
||||
**Usage:**
|
||||
```markdown
|
||||
get(channel:|T|, where: Where = Where.Start) -> T
|
||||
get(channel:|T|, front: Bool = yes) -> 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`.
|
||||
- `front`: Whether to put the item at the front of the channel (as opposed to the back).
|
||||
|
||||
**Returns:**
|
||||
The item removed from the channel.
|
||||
@ -113,14 +110,13 @@ it. If the channel is empty, it waits until an item is available.
|
||||
|
||||
**Usage:**
|
||||
```markdown
|
||||
peek(channel:|T|, where: Where = Where.Start) -> T
|
||||
peek(channel:|T|, front: Bool = yes) -> 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`.
|
||||
- `front`: Whether to put the item at the front of the channel (as opposed to the back).
|
||||
|
||||
**Returns:**
|
||||
The item removed from the channel.
|
||||
|
27
docs/text.md
27
docs/text.md
@ -270,7 +270,7 @@ Text.find(pattern:Text, start=1, length=!&Int64?)->Int
|
||||
Text.find_all(pattern:Text)->[Text]
|
||||
Text.split(pattern:Text)->[Text]
|
||||
Text.replace(pattern:Text, replacement:Text)->[Text]
|
||||
Text.has(pattern:Text, where=Where.Anywhere)->Bool
|
||||
Text.has(pattern:Text)->Bool
|
||||
```
|
||||
|
||||
See [Text Functions](#Text-Functions) for the full API documentation.
|
||||
@ -345,31 +345,6 @@ many repetitions you want by putting a number or range of numbers first using
|
||||
[..0-1 question mark]
|
||||
```
|
||||
|
||||
## Some Examples
|
||||
|
||||
URL query string parameters:
|
||||
|
||||
```
|
||||
text := "example.com/page?a=b&c=d"
|
||||
>> text:find(before=$Pat`?`, $Pat`[..]`):split($Pat`&`)
|
||||
= ["a=b", "c=d"]
|
||||
```
|
||||
|
||||
Remove or get file extension:
|
||||
|
||||
```
|
||||
filename := "foo.txt"
|
||||
>> filename:without($Pat`.[:id:]`, where=End)
|
||||
= "foo"
|
||||
|
||||
>> filename:find(before=$Pat`.`, $Pat`[:id:][:end:]`)
|
||||
= MatchResult.Success(match="txt")
|
||||
|
||||
>> filename := "foo.tar.gz"
|
||||
>> ".":join(filename:split($Pat`.`):from(2))
|
||||
= "tar.gz"
|
||||
```
|
||||
|
||||
# Text Functions
|
||||
|
||||
## `as_c_string`
|
||||
|
@ -11,7 +11,6 @@
|
||||
|
||||
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)
|
||||
@ -47,20 +46,6 @@ env_t *new_compilation_unit(CORD *libname)
|
||||
const char *name, *code, *type_str;
|
||||
} ns_entry_t;
|
||||
|
||||
{
|
||||
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 = 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"));
|
||||
}
|
||||
|
||||
{
|
||||
env_t *range_env = namespace_env(env, "Range");
|
||||
RANGE_TYPE = Type(
|
||||
@ -241,7 +226,6 @@ env_t *new_compilation_unit(CORD *libname)
|
||||
#undef F2
|
||||
#undef F
|
||||
#undef C
|
||||
{"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"},
|
||||
@ -264,7 +248,6 @@ env_t *new_compilation_unit(CORD *libname)
|
||||
{"split", "Text$split", "func(text:Text, pattern='')->[Text]"},
|
||||
{"slice", "Text$slice", "func(text:Text, from=1, to=-1)->Text"},
|
||||
{"title", "Text$title", "func(text:Text)->Text"},
|
||||
{"trimmed", "Text$trimmed", "func(text:Text, trim=\" {\\n\\r\\t}\", where=Where.Anywhere)->Text"},
|
||||
{"upper", "Text$upper", "func(text:Text)->Text"},
|
||||
{"utf32_codepoints", "Text$utf32_codepoints", "func(text:Text)->[Int32]"},
|
||||
{"utf8_bytes", "Text$utf8_bytes", "func(text:Text)->[Int8]"},
|
||||
|
@ -81,6 +81,5 @@ 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
|
||||
|
@ -11,10 +11,10 @@ func main():
|
||||
= [10, 20, 30]
|
||||
>> channel:peek()
|
||||
= 10
|
||||
>> channel:peek(End)
|
||||
>> channel:peek(front=no)
|
||||
= 30
|
||||
|
||||
>> channel:give(-10, Start)
|
||||
>> channel:give(-10, front=yes)
|
||||
>> channel:view()
|
||||
= [-10, 10, 20, 30]
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user