Add method for array:remove_item(item) and rename

array:remove(index)->array:remove_at(index) to avoid confusion. Also
hook up array:has()
This commit is contained in:
Bruce Hill 2024-08-15 02:39:35 -04:00
parent ed1667cb37
commit 66ae30ac29
6 changed files with 74 additions and 38 deletions

View File

@ -157,7 +157,7 @@ public void Array$insert_all(array_t *arr, array_t to_insert, Int_t int_index, i
}
}
public void Array$remove(array_t *arr, Int_t int_index, Int_t int_count, int64_t padded_item_size)
public void Array$remove_at(array_t *arr, Int_t int_index, Int_t int_count, int64_t padded_item_size)
{
int64_t index = Int_to_Int64(int_index, false);
if (index < 1) index = arr->length + index + 1;
@ -192,6 +192,25 @@ public void Array$remove(array_t *arr, Int_t int_index, Int_t int_count, int64_t
if (arr->length == 0) arr->data = NULL;
}
public void Array$remove_item(array_t *arr, void *item, Int_t max_removals, const TypeInfo *type)
{
int64_t padded_item_size = get_padded_item_size(type);
const Int_t ZERO = (Int_t){.small=(0<<2)|1};
const Int_t ONE = (Int_t){.small=(1<<2)|1};
const TypeInfo *item_type = type->ArrayInfo.item;
for (int64_t i = 0; i < arr->length; ) {
if (max_removals.small == ZERO.small) // zero
break;
if (generic_equal(item, arr->data + i*arr->stride, item_type)) {
Array$remove_at(arr, I(i+1), ONE, padded_item_size);
max_removals = Int$minus(max_removals, ONE);
} else {
i++;
}
}
}
public void Array$sort(array_t *arr, closure_t comparison, int64_t padded_item_size)
{
if (arr->data_refcount != 0 || (int64_t)arr->stride != padded_item_size)
@ -442,12 +461,13 @@ public array_t Array$concat(array_t x, array_t y, int64_t padded_item_size)
};
}
public bool Array$contains(array_t array, void *item, const TypeInfo *type)
public bool Array$has(array_t array, void *item, const TypeInfo *type)
{
const TypeInfo *item_type = type->ArrayInfo.item;
for (int64_t i = 0; i < array.length; i++)
for (int64_t i = 0; i < array.length; i++) {
if (generic_equal(array.data + i*array.stride, item, item_type))
return true;
}
return false;
}

View File

@ -58,7 +58,9 @@
#define Array$insert_value(arr, item_expr, index, padded_item_size) ({ __typeof(item_expr) item = item_expr; Array$insert(arr, &item, index, padded_item_size); })
void Array$insert(array_t *arr, const void *item, Int_t index, int64_t padded_item_size);
void Array$insert_all(array_t *arr, array_t to_insert, Int_t index, int64_t padded_item_size);
void Array$remove(array_t *arr, Int_t index, Int_t count, int64_t padded_item_size);
void Array$remove_at(array_t *arr, Int_t index, Int_t count, int64_t padded_item_size);
void Array$remove_item(array_t *arr, void *item, Int_t max_removals, const TypeInfo *type);
#define Array$remove_item_value(arr, item_expr, max, type) ({ __typeof(item_expr) item = item_expr; Array$remove_item(arr, &item, max, type); })
void Array$sort(array_t *arr, closure_t comparison, int64_t padded_item_size);
array_t Array$sorted(array_t arr, closure_t comparison, int64_t padded_item_size);
void Array$shuffle(array_t *arr, int64_t padded_item_size);
@ -69,7 +71,8 @@ array_t Array$sample(array_t arr, Int_t n, array_t weights, int64_t padded_item_
table_t Array$counts(array_t arr, const TypeInfo *type);
void Array$clear(array_t *array);
void Array$compact(array_t *arr, int64_t padded_item_size);
bool Array$contains(array_t array, void *item, const TypeInfo *type);
bool Array$has(array_t array, void *item, const TypeInfo *type);
#define Array$has_value(arr, item_expr, type) ({ __typeof(item_expr) item = item_expr; Array$has(arr, &item, type); })
array_t Array$from(array_t array, Int_t first);
array_t Array$to(array_t array, Int_t last);
array_t Array$by(array_t array, Int_t stride, int64_t padded_item_size);

View File

@ -63,7 +63,7 @@ public void Channel$pop(channel_t *channel, void *out, int64_t item_size, int64_
while (channel->items.length == 0)
pthread_cond_wait(&channel->cond, &channel->mutex);
memcpy(out, channel->items.data, item_size);
Array$remove(&channel->items, I(1), I(1), padded_item_size);
Array$remove_at(&channel->items, I(1), I(1), padded_item_size);
(void)pthread_mutex_unlock(&channel->mutex);
(void)pthread_cond_signal(&channel->cond);
}

View File

@ -350,7 +350,7 @@ public void Table$remove(table_t *t, const void *key, const TypeInfo *type)
// Last entry is being removed, so clear it out to be safe:
memset(GET_ENTRY(*t, last_entry), 0, entry_size(type));
Array$remove(&t->entries, I(t->entries.length), I(1), entry_size(type));
Array$remove_at(&t->entries, I(t->entries.length), I(1), entry_size(type));
int64_t bucket_to_clear;
if (prev) { // Middle (or end) of a chain

View File

@ -2101,16 +2101,27 @@ CORD compile(env_t *env, ast_t *ast)
.next=new(arg_t, .name="at", .type=INT_TYPE, .default_val=FakeAST(Int, .str="0", .bits=0)));
return CORD_all("Array$insert_all(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ",
padded_item_size, ")");
} else if (streq(call->name, "remove")) {
} else if (streq(call->name, "remove_at")) {
CORD self = compile_to_pointer_depth(env, call->self, 1, false);
arg_t *arg_spec = new(arg_t, .name="index", .type=INT_TYPE, .default_val=FakeAST(Int, .str="-1", .bits=0),
.next=new(arg_t, .name="count", .type=INT_TYPE, .default_val=FakeAST(Int, .str="1", .bits=0)));
return CORD_all("Array$remove(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ",
return CORD_all("Array$remove_at(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ",
padded_item_size, ")");
} else if (streq(call->name, "remove_item")) {
CORD self = compile_to_pointer_depth(env, call->self, 1, false);
arg_t *arg_spec = new(arg_t, .name="item", .type=item_t,
.next=new(arg_t, .name="max_count", .type=INT_TYPE, .default_val=FakeAST(Int, .str="-1", .bits=0)));
return CORD_all("Array$remove_item_value(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ",
compile_type_info(env, self_value_t), ")");
} else if (streq(call->name, "random")) {
CORD self = compile_to_pointer_depth(env, call->self, 0, false);
(void)compile_arguments(env, ast, NULL, call->args);
return CORD_all("Array$random_value(", self, ", ", compile_type(item_t), ")");
} else if (streq(call->name, "has")) {
CORD self = compile_to_pointer_depth(env, call->self, 0, false);
arg_t *arg_spec = new(arg_t, .name="item", .type=item_t);
return CORD_all("Array$has_value(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ",
compile_type_info(env, self_value_t), ")");
} else if (streq(call->name, "sample")) {
CORD self = compile_to_pointer_depth(env, call->self, 0, false);
arg_t *arg_spec = new(arg_t, .name="count", .type=INT_TYPE,

View File

@ -710,58 +710,60 @@ type_t *get_type(env_t *env, ast_t *ast)
type_t *self_value_t = value_type(get_type(env, call->self));
switch (self_value_t->tag) {
case ArrayType: {
if (streq(call->name, "insert")) return Type(VoidType);
if (streq(call->name, "binary_search")) return INT_TYPE;
else if (streq(call->name, "by")) return self_value_t;
else if (streq(call->name, "clear")) return Type(VoidType);
else if (streq(call->name, "counts")) return Type(TableType, .key_type=Match(self_value_t, ArrayType)->item_type, .value_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 Match(self_value_t, ArrayType)->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);
else if (streq(call->name, "insert_all")) return Type(VoidType);
else if (streq(call->name, "remove")) return Type(VoidType);
else if (streq(call->name, "sort")) return Type(VoidType);
else if (streq(call->name, "sorted")) return self_value_t;
else if (streq(call->name, "random")) return Match(self_value_t, ArrayType)->item_type;
else if (streq(call->name, "remove_at")) return Type(VoidType);
else if (streq(call->name, "remove_item")) return Type(VoidType);
else if (streq(call->name, "reversed")) return self_value_t;
else if (streq(call->name, "sample")) return self_value_t;
else if (streq(call->name, "shuffle")) return Type(VoidType);
else if (streq(call->name, "shuffled")) return self_value_t;
else if (streq(call->name, "random")) return Match(self_value_t, ArrayType)->item_type;
else if (streq(call->name, "sample")) return self_value_t;
else if (streq(call->name, "clear")) return Type(VoidType);
else if (streq(call->name, "from")) return self_value_t;
else if (streq(call->name, "sort")) return Type(VoidType);
else if (streq(call->name, "sorted")) return self_value_t;
else if (streq(call->name, "to")) return self_value_t;
else if (streq(call->name, "by")) return self_value_t;
else if (streq(call->name, "reversed")) return self_value_t;
else if (streq(call->name, "unique")) return Type(SetType, .item_type=Match(self_value_t, ArrayType)->item_type);
else if (streq(call->name, "counts")) return Type(TableType, .key_type=Match(self_value_t, ArrayType)->item_type, .value_type=INT_TYPE);
else if (streq(call->name, "heapify")) return Type(VoidType);
else if (streq(call->name, "heap_push")) return Type(VoidType);
else if (streq(call->name, "heap_pop")) return Match(self_value_t, ArrayType)->item_type;
else if (streq(call->name, "binary_search")) return INT_TYPE;
else code_err(ast, "There is no '%s' method for arrays", call->name);
}
case SetType: {
if (streq(call->name, "add")) return Type(VoidType);
else if (streq(call->name, "has")) return Type(BoolType);
else if (streq(call->name, "add_all")) return Type(VoidType);
else if (streq(call->name, "remove")) return Type(VoidType);
else if (streq(call->name, "remove_all")) return Type(VoidType);
else if (streq(call->name, "clear")) return Type(VoidType);
else if (streq(call->name, "with")) return self_value_t;
else if (streq(call->name, "overlap")) return self_value_t;
else if (streq(call->name, "without")) return self_value_t;
else if (streq(call->name, "has")) return Type(BoolType);
else if (streq(call->name, "is_subset_of")) return Type(BoolType);
else if (streq(call->name, "is_superset_of")) return Type(BoolType);
else if (streq(call->name, "overlap")) return self_value_t;
else if (streq(call->name, "remove")) return Type(VoidType);
else if (streq(call->name, "remove_all")) return Type(VoidType);
else if (streq(call->name, "with")) return self_value_t;
else if (streq(call->name, "without")) return self_value_t;
else code_err(ast, "There is no '%s' method for sets", call->name);
}
case ChannelType: {
if (streq(call->name, "push")) return Type(VoidType);
else if (streq(call->name, "push_all")) return Type(VoidType);
if (streq(call->name, "clear")) return Type(VoidType);
else if (streq(call->name, "pop")) return Match(self_value_t, ChannelType)->item_type;
else if (streq(call->name, "clear")) return Type(VoidType);
else if (streq(call->name, "push")) return Type(VoidType);
else if (streq(call->name, "push_all")) return Type(VoidType);
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);
}
case TableType: {
auto table = Match(self_value_t, TableType);
if (streq(call->name, "get")) return table->value_type;
else if (streq(call->name, "has")) return Type(BoolType);
else if (streq(call->name, "set")) return Type(VoidType);
else if (streq(call->name, "bump")) return Type(VoidType);
else if (streq(call->name, "remove")) return Type(VoidType);
if (streq(call->name, "bump")) return Type(VoidType);
else if (streq(call->name, "clear")) return Type(VoidType);
else if (streq(call->name, "get")) return table->value_type;
else if (streq(call->name, "has")) return Type(BoolType);
else if (streq(call->name, "remove")) return Type(VoidType);
else if (streq(call->name, "set")) return Type(VoidType);
else if (streq(call->name, "sorted")) return self_value_t;
else code_err(ast, "There is no '%s' method for tables", call->name);
}