Change things up to use type params for all array and table methods
This commit is contained in:
parent
1dcfbdc5c7
commit
7355b2f7fe
@ -17,11 +17,17 @@
|
||||
|
||||
extern const void *SSS_HASH_VECTOR;
|
||||
|
||||
static inline size_t get_item_size(const TypeInfo *info)
|
||||
{
|
||||
return info->ArrayInfo.item->size;
|
||||
}
|
||||
|
||||
// Replace the array's .data pointer with a new pointer to a copy of the
|
||||
// data that is compacted and has a stride of exactly `item_size`
|
||||
public void Array_compact(array_t *arr, int64_t item_size)
|
||||
public void Array__compact(array_t *arr, const TypeInfo *type)
|
||||
{
|
||||
void *copy = NULL;
|
||||
int64_t item_size = get_item_size(type);
|
||||
if (arr->length > 0) {
|
||||
copy = arr->atomic ? GC_MALLOC_ATOMIC(arr->length * item_size) : GC_MALLOC(arr->length * item_size);
|
||||
if ((int64_t)arr->stride == item_size) {
|
||||
@ -41,13 +47,14 @@ public void Array_compact(array_t *arr, int64_t item_size)
|
||||
};
|
||||
}
|
||||
|
||||
public void Array_insert(array_t *arr, const void *item, int64_t index, int64_t item_size)
|
||||
public void Array__insert(array_t *arr, const void *item, int64_t index, const TypeInfo *type)
|
||||
{
|
||||
if (index < 1) index = arr->length - index + 1;
|
||||
|
||||
if (index < 1) index = 1;
|
||||
else if (index > (int64_t)arr->length + 1) index = (int64_t)arr->length + 1;
|
||||
|
||||
int64_t item_size = get_item_size(type);
|
||||
if (!arr->data) {
|
||||
arr->free = 4;
|
||||
arr->data = arr->atomic ? GC_MALLOC_ATOMIC(arr->free * item_size) : GC_MALLOC(arr->free * item_size);
|
||||
@ -64,7 +71,7 @@ public void Array_insert(array_t *arr, const void *item, int64_t index, int64_t
|
||||
arr->stride = item_size;
|
||||
} else {
|
||||
if (arr->copy_on_write)
|
||||
Array_compact(arr, item_size);
|
||||
Array__compact(arr, type);
|
||||
|
||||
if (index != arr->length+1)
|
||||
memmove((void*)arr->data + index*item_size, arr->data + (index-1)*item_size, (arr->length - index)*item_size);
|
||||
@ -75,13 +82,14 @@ public void Array_insert(array_t *arr, const void *item, int64_t index, int64_t
|
||||
memcpy((void*)arr->data + (index-1)*item_size, item, item_size);
|
||||
}
|
||||
|
||||
public void Array_insert_all(array_t *arr, array_t to_insert, int64_t index, int64_t item_size)
|
||||
public void Array__insert_all(array_t *arr, array_t to_insert, int64_t index, const TypeInfo *type)
|
||||
{
|
||||
if (index < 1) index = arr->length - index + 1;
|
||||
|
||||
if (index < 1) index = 1;
|
||||
else if (index > (int64_t)arr->length + 1) index = (int64_t)arr->length + 1;
|
||||
|
||||
int64_t item_size = get_item_size(type);
|
||||
if (!arr->data) {
|
||||
arr->free = to_insert.length;
|
||||
arr->data = arr->atomic ? GC_MALLOC_ATOMIC(item_size*arr->free) : GC_MALLOC(item_size*arr->free);
|
||||
@ -96,7 +104,7 @@ public void Array_insert_all(array_t *arr, array_t to_insert, int64_t index, int
|
||||
arr->copy_on_write = 0;
|
||||
} else {
|
||||
if (arr->copy_on_write)
|
||||
Array_compact(arr, item_size);
|
||||
Array__compact(arr, type);
|
||||
|
||||
if (index != arr->length+1)
|
||||
memmove((void*)arr->data + index*item_size, arr->data + (index-1)*item_size, (arr->length - index + to_insert.length-1)*item_size);
|
||||
@ -107,7 +115,7 @@ public void Array_insert_all(array_t *arr, array_t to_insert, int64_t index, int
|
||||
memcpy((void*)arr->data + (index-1 + i)*item_size, to_insert.data + i*to_insert.stride, item_size);
|
||||
}
|
||||
|
||||
public void Array_remove(array_t *arr, int64_t index, int64_t count, int64_t item_size)
|
||||
public void Array__remove(array_t *arr, int64_t index, int64_t count, const TypeInfo *type)
|
||||
{
|
||||
if (index < 1) index = arr->length - index + 1;
|
||||
|
||||
@ -118,6 +126,7 @@ public void Array_remove(array_t *arr, int64_t index, int64_t count, int64_t ite
|
||||
|
||||
// TODO: optimize arr.remove(1) by just updating the .data and .length values
|
||||
|
||||
int64_t item_size = get_item_size(type);
|
||||
if (index + count > arr->length) {
|
||||
if (arr->free >= 0)
|
||||
arr->free += count;
|
||||
@ -139,7 +148,7 @@ public void Array_remove(array_t *arr, int64_t index, int64_t count, int64_t ite
|
||||
arr->length -= count;
|
||||
}
|
||||
|
||||
public void Array_sort(array_t *arr, const TypeInfo *type)
|
||||
public void Array__sort(array_t *arr, const TypeInfo *type)
|
||||
{
|
||||
const TypeInfo *item_type = type->ArrayInfo.item;
|
||||
int64_t item_size = item_type->size;
|
||||
@ -147,15 +156,16 @@ public void Array_sort(array_t *arr, const TypeInfo *type)
|
||||
item_size += item_type->align - (item_size % item_type->align); // padding
|
||||
|
||||
if (arr->copy_on_write || (int64_t)arr->stride != item_size)
|
||||
Array_compact(arr, item_size);
|
||||
Array__compact(arr, type);
|
||||
|
||||
qsort_r(arr->data, arr->length, item_size, (void*)generic_compare, (void*)item_type);
|
||||
}
|
||||
|
||||
public void Array_shuffle(array_t *arr, int64_t item_size)
|
||||
public void Array__shuffle(array_t *arr, const TypeInfo *type)
|
||||
{
|
||||
int64_t item_size = get_item_size(type);
|
||||
if (arr->copy_on_write || (int64_t)arr->stride != item_size)
|
||||
Array_compact(arr, item_size);
|
||||
Array__compact(arr, type);
|
||||
|
||||
char tmp[item_size];
|
||||
for (int64_t i = arr->length-1; i > 1; i--) {
|
||||
@ -166,11 +176,8 @@ public void Array_shuffle(array_t *arr, int64_t item_size)
|
||||
}
|
||||
}
|
||||
|
||||
public array_t Array_slice(array_t *array, int64_t first, int64_t stride, int64_t length, bool readonly, const TypeInfo *type)
|
||||
public array_t Array__slice(array_t *array, int64_t first, int64_t stride, int64_t length, bool readonly, const TypeInfo *type)
|
||||
{
|
||||
TypeInfo *item = type->ArrayInfo.item;
|
||||
int64_t item_size = item->size;
|
||||
|
||||
if (stride > INT16_MAX)
|
||||
stride = INT16_MAX;
|
||||
else if (stride < INT16_MIN)
|
||||
@ -214,6 +221,7 @@ public array_t Array_slice(array_t *array, int64_t first, int64_t stride, int64_
|
||||
// never do modifictions
|
||||
array->copy_on_write = !readonly;
|
||||
|
||||
int64_t item_size = get_item_size(type);
|
||||
return (array_t){
|
||||
.atomic=array->atomic,
|
||||
.data=array->data + item_size*(first-1),
|
||||
@ -223,7 +231,7 @@ public array_t Array_slice(array_t *array, int64_t first, int64_t stride, int64_
|
||||
};
|
||||
}
|
||||
|
||||
public bool Array_contains(array_t array, void *item, const TypeInfo *type)
|
||||
public bool Array__contains(array_t array, void *item, const TypeInfo *type)
|
||||
{
|
||||
TypeInfo *item_type = type->ArrayInfo.item;
|
||||
for (int64_t i = 0; i < array.length; i++)
|
||||
@ -232,12 +240,13 @@ public bool Array_contains(array_t array, void *item, const TypeInfo *type)
|
||||
return false;
|
||||
}
|
||||
|
||||
public void Array_clear(array_t *array)
|
||||
public void Array__clear(array_t *array, const TypeInfo *type)
|
||||
{
|
||||
(void)type;
|
||||
*array = (array_t){.data=0, .length=0};
|
||||
}
|
||||
|
||||
public int32_t Array_compare(const array_t *x, const array_t *y, const TypeInfo *type)
|
||||
public int32_t Array__compare(const array_t *x, const array_t *y, const TypeInfo *type)
|
||||
{
|
||||
// Early out for arrays with the same data, e.g. two copies of the same array:
|
||||
if (x->data == y->data && x->stride == y->stride)
|
||||
@ -264,12 +273,12 @@ public int32_t Array_compare(const array_t *x, const array_t *y, const TypeInfo
|
||||
return (x->length > y->length) - (x->length < y->length);
|
||||
}
|
||||
|
||||
public bool Array_equal(const array_t *x, const array_t *y, const TypeInfo *type)
|
||||
public bool Array__equal(const array_t *x, const array_t *y, const TypeInfo *type)
|
||||
{
|
||||
return (Array_compare(x, y, type) == 0);
|
||||
return (Array__compare(x, y, type) == 0);
|
||||
}
|
||||
|
||||
public CORD Array_cord(const array_t *arr, bool colorize, const TypeInfo *type)
|
||||
public CORD Array__cord(const array_t *arr, bool colorize, const TypeInfo *type)
|
||||
{
|
||||
if (!arr)
|
||||
return CORD_all("[", generic_as_str(NULL, false, type->ArrayInfo.item), "]");
|
||||
@ -286,7 +295,7 @@ public CORD Array_cord(const array_t *arr, bool colorize, const TypeInfo *type)
|
||||
return c;
|
||||
}
|
||||
|
||||
public uint32_t Array_hash(const array_t *arr, const TypeInfo *type)
|
||||
public uint32_t Array__hash(const array_t *arr, const TypeInfo *type)
|
||||
{
|
||||
// Array hash is calculated as a rolling, compacting hash of the length of the array, followed by
|
||||
// the hashes of its items (or the items themselves if they're small plain data)
|
||||
|
@ -7,40 +7,18 @@
|
||||
#include "functions.h"
|
||||
#include "types.h"
|
||||
|
||||
void Array_insert(array_t *arr, const void *item, int64_t index, int64_t item_size);
|
||||
void Array_insert_all(array_t *arr, array_t to_insert, int64_t index, int64_t item_size);
|
||||
void Array_remove(array_t *arr, int64_t index, int64_t count, int64_t item_size);
|
||||
void Array_sort(array_t *arr, const TypeInfo *type);
|
||||
void Array_shuffle(array_t *arr, int64_t item_size);
|
||||
void Array_clear(array_t *array);
|
||||
void Array_compact(array_t *arr, int64_t item_size);
|
||||
bool Array_contains(array_t array, void *item, const TypeInfo *type);
|
||||
array_t Array_slice(array_t *array, int64_t first, int64_t stride, int64_t length, bool readonly, const TypeInfo *type);
|
||||
uint32_t Array_hash(const array_t *arr, const TypeInfo *type);
|
||||
int32_t Array_compare(const array_t *x, const array_t *y, const TypeInfo *type);
|
||||
bool Array_equal(const array_t *x, const array_t *y, const TypeInfo *type);
|
||||
CORD Array_as_str(const array_t *arr, bool colorize, const TypeInfo *type);
|
||||
|
||||
// Due to some C language weirdness, the type of "foo" is inferred to be `char[3]` instead of `const char*`
|
||||
// This is a hacky workaround to ensure that __typeof("foo") => `const char *`
|
||||
#define FIX_STR_LITERAL(s) _Generic(((void)0, s), char*: (const char*)s, default: s)
|
||||
|
||||
#define ARRAY_OF(t) t**
|
||||
#define EMPTY_ARRAY(t) (t**)new(array_t)
|
||||
#define LENGTH(arr) (((array_t*)(arr))->length)
|
||||
#define ARRAY(x, ...) (__typeof(FIX_STR_LITERAL(x))**)new(array_t, \
|
||||
.data=memcpy(GC_MALLOC(sizeof((__typeof(FIX_STR_LITERAL(x))[]){x, __VA_ARGS__})), (__typeof(FIX_STR_LITERAL(x))[]){x, __VA_ARGS__}, \
|
||||
sizeof((__typeof(FIX_STR_LITERAL(x))[]){x, __VA_ARGS__})), \
|
||||
.length=(sizeof((__typeof(FIX_STR_LITERAL(x))[]){x, __VA_ARGS__})) / sizeof(FIX_STR_LITERAL(x)), \
|
||||
.stride=sizeof(FIX_STR_LITERAL(x)))
|
||||
#define STATIC_ARRAY(x, ...) ((array_t){ \
|
||||
.data=(__typeof(FIX_STR_LITERAL(x))[]){x, __VA_ARGS__}, \
|
||||
.length=(sizeof((__typeof(FIX_STR_LITERAL(x))[]){x, __VA_ARGS__})) / sizeof(FIX_STR_LITERAL(x)), \
|
||||
.stride=sizeof(FIX_STR_LITERAL(x))})
|
||||
#define foreach(arr, var, last) for (__typeof(arr[0]) var = arr[0], last = ith_addr(arr, LENGTH(arr)-1); var && var <= last; var = ((void*)var) + ((array_t*)(arr))->stride)
|
||||
#define ith_addr(arr, i) ((__typeof(arr[0]))(((array_t*)(arr))->data + (i)*((array_t*)(arr))->stride))
|
||||
#define ith(arr, i) (*ith_addr(arr,i))
|
||||
#define append(arr, obj) Array_insert((array_t*)(arr), (__typeof((arr)[0][0])[]){obj}, 0, sizeof((arr)[0][0]))
|
||||
#define remove(arr, i) Array_remove((array_t*)(arr), (i)+1, 1, sizeof(arr[0][0]))
|
||||
void Array__insert(array_t *arr, const void *item, int64_t index, const TypeInfo *type);
|
||||
void Array__insert_all(array_t *arr, array_t to_insert, int64_t index, const TypeInfo *type);
|
||||
void Array__remove(array_t *arr, int64_t index, int64_t count, const TypeInfo *type);
|
||||
void Array__sort(array_t *arr, const TypeInfo *type);
|
||||
void Array__shuffle(array_t *arr, const TypeInfo *type);
|
||||
void Array__clear(array_t *array, const TypeInfo *type);
|
||||
void Array__compact(array_t *arr, const TypeInfo *type);
|
||||
bool Array__contains(array_t array, void *item, const TypeInfo *type);
|
||||
array_t Array__slice(array_t *array, int64_t first, int64_t stride, int64_t length, bool readonly, const TypeInfo *type);
|
||||
uint32_t Array__hash(const array_t *arr, const TypeInfo *type);
|
||||
int32_t Array__compare(const array_t *x, const array_t *y, const TypeInfo *type);
|
||||
bool Array__equal(const array_t *x, const array_t *y, const TypeInfo *type);
|
||||
CORD Array__as_str(const array_t *arr, bool colorize, const TypeInfo *type);
|
||||
|
||||
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
|
||||
|
@ -31,8 +31,8 @@ public void fail(const char *fmt, ...)
|
||||
public uint32_t generic_hash(const void *obj, const TypeInfo *type)
|
||||
{
|
||||
switch (type->tag) {
|
||||
case PointerInfo: return Pointer__hash(obj, type);
|
||||
case ArrayInfo: return Array_hash(obj, type);
|
||||
case PointerInfo: case FunctionInfo: return Pointer__hash(obj, type);
|
||||
case ArrayInfo: return Array__hash(obj, type);
|
||||
case TableInfo: return Table_hash(obj, type);
|
||||
case CustomInfo:
|
||||
if (!type->CustomInfo.hash)
|
||||
@ -50,8 +50,8 @@ public uint32_t generic_hash(const void *obj, const TypeInfo *type)
|
||||
public int32_t generic_compare(const void *x, const void *y, const TypeInfo *type)
|
||||
{
|
||||
switch (type->tag) {
|
||||
case PointerInfo: return Pointer__compare(x, y, type);
|
||||
case ArrayInfo: return Array_compare(x, y, type);
|
||||
case PointerInfo: case FunctionInfo: return Pointer__compare(x, y, type);
|
||||
case ArrayInfo: return Array__compare(x, y, type);
|
||||
case TableInfo: return Table_compare(x, y, type);
|
||||
case CustomInfo:
|
||||
if (!type->CustomInfo.compare)
|
||||
@ -66,8 +66,8 @@ public int32_t generic_compare(const void *x, const void *y, const TypeInfo *typ
|
||||
public bool generic_equal(const void *x, const void *y, const TypeInfo *type)
|
||||
{
|
||||
switch (type->tag) {
|
||||
case PointerInfo: return Pointer__equal(x, y, type);
|
||||
case ArrayInfo: return Array_equal(x, y, type);
|
||||
case PointerInfo: case FunctionInfo: return Pointer__equal(x, y, type);
|
||||
case ArrayInfo: return Array__equal(x, y, type);
|
||||
case TableInfo: return Table_equal(x, y, type);
|
||||
case CustomInfo:
|
||||
if (!type->CustomInfo.equal)
|
||||
@ -83,7 +83,8 @@ public CORD generic_as_str(const void *obj, bool colorize, const TypeInfo *type)
|
||||
{
|
||||
switch (type->tag) {
|
||||
case PointerInfo: return Pointer__cord(obj, colorize, type);
|
||||
case ArrayInfo: return Array_as_str(obj, colorize, type);
|
||||
case FunctionInfo: return Func__as_str(obj, colorize, type);
|
||||
case ArrayInfo: return Array__as_str(obj, colorize, type);
|
||||
case TableInfo: return Table_as_str(obj, colorize, type);
|
||||
case TypeInfoInfo: return Type__as_str(obj, colorize, type);
|
||||
case CustomInfo:
|
||||
|
@ -37,11 +37,10 @@
|
||||
// Helper accessors for type functions/values:
|
||||
#define HASH_KEY(t, k) (generic_hash((k), type->TableInfo.key) % ((t)->bucket_info->count))
|
||||
#define EQUAL_KEYS(x, y) (generic_equal((x), (y), type->TableInfo.key))
|
||||
#define ENTRY_SIZE (type->TableInfo.entry_size)
|
||||
#define VALUE_OFFSET (type->TableInfo.value_offset)
|
||||
#define END_OF_CHAIN UINT32_MAX
|
||||
|
||||
#define GET_ENTRY(t, i) ((t)->entries.data + (t)->entries.stride*(i))
|
||||
#define ENTRY_TYPE(type) (&(TypeInfo){.size=entry_size(type), .align=entry_align(type), .tag=OpaqueInfo})
|
||||
|
||||
extern const void *SSS_HASH_VECTOR;
|
||||
|
||||
@ -59,10 +58,34 @@ TypeInfo StrToVoidStarTable_type = {
|
||||
.size=sizeof(table_t),
|
||||
.align=alignof(table_t),
|
||||
.tag=TableInfo,
|
||||
.TableInfo={.key=&Str_type.type, .value=&MemoryPointer_typeinfo,
|
||||
.entry_size=16, .value_offset=8},
|
||||
.TableInfo={.key=&Str_type.type, .value=&MemoryPointer_typeinfo},
|
||||
};
|
||||
|
||||
static inline size_t entry_size(const TypeInfo *info)
|
||||
{
|
||||
size_t size = info->TableInfo.key->size;
|
||||
if (info->TableInfo.value->align > 1 && size % info->TableInfo.value->align)
|
||||
size += info->TableInfo.value->align - (size % info->TableInfo.value->align); // padding
|
||||
size += info->TableInfo.value->size;
|
||||
if (info->TableInfo.key->align > 1 && size % info->TableInfo.key->align)
|
||||
size += info->TableInfo.key->align - (size % info->TableInfo.key->align); // padding
|
||||
return size;
|
||||
}
|
||||
|
||||
static inline size_t entry_align(const TypeInfo *info)
|
||||
{
|
||||
return MAX(info->TableInfo.key->align, info->TableInfo.value->align);
|
||||
}
|
||||
|
||||
static inline size_t value_offset(const TypeInfo *info)
|
||||
{
|
||||
size_t offset = info->TableInfo.key->size;
|
||||
if (info->TableInfo.value->align > 1 && offset % info->TableInfo.value->align)
|
||||
offset += info->TableInfo.value->align - (offset % info->TableInfo.value->align); // padding
|
||||
return offset;
|
||||
}
|
||||
|
||||
|
||||
static inline void hshow(const table_t *t)
|
||||
{
|
||||
hdebug("{");
|
||||
@ -79,7 +102,7 @@ static inline void hshow(const table_t *t)
|
||||
static void maybe_copy_on_write(table_t *t, const TypeInfo *type)
|
||||
{
|
||||
if (t->entries.copy_on_write) {
|
||||
Array_compact(&t->entries, type->TableInfo.entry_size);
|
||||
Array__compact(&t->entries, ENTRY_TYPE(type));
|
||||
}
|
||||
|
||||
if (t->bucket_info && t->bucket_info->copy_on_write) {
|
||||
@ -110,7 +133,7 @@ public void *Table_get_raw(const table_t *t, const void *key, const TypeInfo *ty
|
||||
void *entry = GET_ENTRY(t, buckets[i].index);
|
||||
if (EQUAL_KEYS(entry, key)) {
|
||||
hdebug("Found key!\n");
|
||||
return entry + VALUE_OFFSET;
|
||||
return entry + value_offset(type);
|
||||
}
|
||||
if (buckets[i].next_bucket == END_OF_CHAIN)
|
||||
break;
|
||||
@ -250,18 +273,18 @@ public void *Table_reserve(table_t *t, const void *key, const void *value, const
|
||||
|
||||
maybe_copy_on_write(t, type);
|
||||
|
||||
char buf[ENTRY_SIZE] = {};
|
||||
char buf[entry_size(type)] = {};
|
||||
memcpy(buf, key, key_size);
|
||||
if (value && value_size > 0)
|
||||
memcpy(buf + VALUE_OFFSET, value, value_size);
|
||||
memcpy(buf + value_offset(type), value, value_size);
|
||||
else
|
||||
memset(buf + VALUE_OFFSET, 0, value_size);
|
||||
Array_insert(&t->entries, buf, 0, ENTRY_SIZE);
|
||||
memset(buf + value_offset(type), 0, value_size);
|
||||
Array__insert(&t->entries, buf, 0, ENTRY_TYPE(type));
|
||||
|
||||
int64_t entry_index = t->entries.length-1;
|
||||
void *entry = GET_ENTRY(t, entry_index);
|
||||
Table_set_bucket(t, entry, entry_index, type);
|
||||
return entry + VALUE_OFFSET;
|
||||
return entry + value_offset(type);
|
||||
}
|
||||
|
||||
public void Table_set(table_t *t, const void *key, const void *value, const TypeInfo *type)
|
||||
@ -336,13 +359,13 @@ public void Table_remove(table_t *t, const void *key, const TypeInfo *type)
|
||||
|
||||
// Clobber the entry being removed (in the middle of the array) with
|
||||
// the last entry:
|
||||
memcpy(GET_ENTRY(t, bucket->index), GET_ENTRY(t, last_entry), ENTRY_SIZE);
|
||||
memcpy(GET_ENTRY(t, bucket->index), GET_ENTRY(t, last_entry), entry_size(type));
|
||||
}
|
||||
|
||||
// Last entry is being removed, so clear it out to be safe:
|
||||
memset(GET_ENTRY(t, last_entry), 0, ENTRY_SIZE);
|
||||
memset(GET_ENTRY(t, last_entry), 0, entry_size(type));
|
||||
|
||||
Array_remove(&t->entries, t->entries.length, 1, ENTRY_SIZE);
|
||||
Array__remove(&t->entries, t->entries.length, 1, ENTRY_TYPE(type));
|
||||
|
||||
int64_t bucket_to_clear;
|
||||
if (prev) { // Middle (or end) of a chain
|
||||
@ -392,7 +415,7 @@ public bool Table_equal(const table_t *x, const table_t *y, const TypeInfo *type
|
||||
const TypeInfo *value_type = type->TableInfo.value;
|
||||
for (int64_t i = 0, length = Table_length(x); i < length; i++) {
|
||||
void *x_key = GET_ENTRY(x, i);
|
||||
void *x_value = x_key + VALUE_OFFSET;
|
||||
void *x_value = x_key + value_offset(type);
|
||||
void *y_value = Table_get_raw(y, x_key, type);
|
||||
if (!y_value)
|
||||
return false;
|
||||
@ -421,15 +444,15 @@ public int32_t Table_compare(const table_t *x, const table_t *y, const TypeInfo
|
||||
return (x->entries.length > y->entries.length) - (x->entries.length < y->entries.length);
|
||||
|
||||
array_t x_entries = x->entries, y_entries = y->entries;
|
||||
Array_sort(&x_entries, table.key);
|
||||
Array_sort(&y_entries, table.key);
|
||||
Array__sort(&x_entries, table.key);
|
||||
Array__sort(&y_entries, table.key);
|
||||
for (int64_t i = 0; i < x_entries.length; i++) {
|
||||
void *x_key = x_entries.data + x_entries.stride * i;
|
||||
void *y_key = y_entries.data + y_entries.stride * i;
|
||||
int32_t diff = generic_compare(x_key, y_key, table.key);
|
||||
if (diff != 0) return diff;
|
||||
void *x_value = x_key + table.value_offset;
|
||||
void *y_value = y_key + table.value_offset;
|
||||
void *x_value = x_key + value_offset(type);
|
||||
void *y_value = y_key + value_offset(type);
|
||||
diff = generic_compare(x_value, y_value, table.value);
|
||||
if (diff != 0) return diff;
|
||||
}
|
||||
@ -457,13 +480,13 @@ public uint32_t Table_hash(const table_t *t, const TypeInfo *type)
|
||||
// hash(#t, xor(hash(k) for k in t.keys), xor(hash(v) for v in t.values), hash(t.fallback), hash(t.default))
|
||||
// Where fallback and default hash to zero if absent
|
||||
auto table = type->TableInfo;
|
||||
int64_t value_offset = table.value_offset;
|
||||
int64_t val_off = value_offset(type);
|
||||
|
||||
uint32_t key_hashes = 0, value_hashes = 0, fallback_hash = 0, default_hash = 0;
|
||||
for (int64_t i = 0, length = Table_length(t); i < length; i++) {
|
||||
void *entry = GET_ENTRY(t, i);
|
||||
key_hashes ^= generic_hash(entry, table.key);
|
||||
value_hashes ^= generic_hash(entry + value_offset, table.value);
|
||||
value_hashes ^= generic_hash(entry + val_off, table.value);
|
||||
}
|
||||
|
||||
if (t->fallback)
|
||||
@ -492,7 +515,7 @@ public CORD Table_as_str(const table_t *t, bool colorize, const TypeInfo *type)
|
||||
if (!t)
|
||||
return CORD_all("{", generic_as_str(NULL, false, table.key), "=>", generic_as_str(NULL, false, table.value), "}");
|
||||
|
||||
int64_t value_offset = table.value_offset;
|
||||
int64_t val_off = value_offset(type);
|
||||
CORD c = "{";
|
||||
for (int64_t i = 0, length = Table_length(t); i < length; i++) {
|
||||
if (i > 0)
|
||||
@ -500,7 +523,7 @@ public CORD Table_as_str(const table_t *t, bool colorize, const TypeInfo *type)
|
||||
void *entry = GET_ENTRY(t, i);
|
||||
c = CORD_cat(c, generic_as_str(entry, colorize, table.key));
|
||||
c = CORD_cat(c, "=>");
|
||||
c = CORD_cat(c, generic_as_str(entry + value_offset, colorize, table.value));
|
||||
c = CORD_cat(c, generic_as_str(entry + val_off, colorize, table.value));
|
||||
}
|
||||
|
||||
if (t->fallback) {
|
||||
|
@ -47,8 +47,8 @@ public struct {
|
||||
public CORD Func__as_str(const void *fn, bool colorize, const TypeInfo *type)
|
||||
{
|
||||
(void)fn;
|
||||
CORD c = type->TypeInfoInfo.type_str;
|
||||
if (colorize)
|
||||
CORD c = type->FunctionInfo.type_str;
|
||||
if (fn && colorize)
|
||||
CORD_sprintf(&c, "\x1b[32;1m%r\x1b[m", c);
|
||||
return c;
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ typedef CORD (*str_fn_t)(const void*, bool, const struct TypeInfo*);
|
||||
typedef struct TypeInfo {
|
||||
int64_t size, align;
|
||||
struct { // Anonymous tagged union for convenience
|
||||
enum { CustomInfo, PointerInfo, ArrayInfo, TableInfo, TypeInfoInfo, } tag;
|
||||
enum { CustomInfo, PointerInfo, ArrayInfo, TableInfo, FunctionInfo, TypeInfoInfo, OpaqueInfo, } tag;
|
||||
union {
|
||||
struct {
|
||||
equal_fn_t equal;
|
||||
@ -32,15 +32,19 @@ typedef struct TypeInfo {
|
||||
} ArrayInfo;
|
||||
struct {
|
||||
struct TypeInfo *key, *value;
|
||||
int64_t entry_size, value_offset;
|
||||
} TableInfo;
|
||||
struct {
|
||||
const char *type_str;
|
||||
} FunctionInfo;
|
||||
struct {
|
||||
const char *type_str;
|
||||
} TypeInfoInfo;
|
||||
struct {} OpaqueInfo;
|
||||
};
|
||||
};
|
||||
} TypeInfo;
|
||||
|
||||
CORD Type__as_str(const void *typeinfo, bool colorize, const TypeInfo *type);
|
||||
CORD Func__as_str(const void *fn, bool colorize, const TypeInfo *type);
|
||||
|
||||
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
|
||||
|
56
compile.c
56
compile.c
@ -414,17 +414,49 @@ CORD compile(env_t *env, ast_t *ast)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// CORD compile_type_info(env_t *env, type_t *t)
|
||||
// {
|
||||
// switch (t->tag) {
|
||||
// case BoolType: return "&Bool$Info";
|
||||
// case IntType: return CORD_asprintf("&Int%ld$Info", Match(t, IntType)->bits);
|
||||
// case NumType: return CORD_asprintf("&Num%ld$Info", Match(t, NumType)->bits);
|
||||
// case StringType: return CORD_all("&", Match(t, StringType)->dsl ? Match(t, StringType)->dsl : "Str", "$Info");
|
||||
// case StructType: return CORD_all("&", Match(t, StructType)->name, "$Info");
|
||||
// case EnumType: return CORD_all("&", Match(t, EnumType)->name, "$Info");
|
||||
// case ArrayType: return CORD_all("&((TypeInfo){", Match(t, EnumType)->name, "$Info");
|
||||
// }
|
||||
// }
|
||||
CORD compile_type_info(env_t *env, type_t *t)
|
||||
{
|
||||
switch (t->tag) {
|
||||
case BoolType: return "&Bool_type";
|
||||
case IntType: return CORD_asprintf("&Int%ld_type", Match(t, IntType)->bits);
|
||||
case NumType: return CORD_asprintf("&Num%ld_type", Match(t, NumType)->bits);
|
||||
case StringType: return CORD_all("&", Match(t, StringType)->dsl ? Match(t, StringType)->dsl : "Str", "_type");
|
||||
case StructType: return CORD_all("&", Match(t, StructType)->name, "_type");
|
||||
case EnumType: return CORD_all("&", Match(t, EnumType)->name, "_type");
|
||||
case ArrayType: {
|
||||
type_t *item_t = Match(t, ArrayType)->item_type;
|
||||
return CORD_asprintf(
|
||||
"&((TypeInfo){.size=%zu, .align=%zu, .tag=ArrayInfo, .ArrayInfo.item=%r})",
|
||||
sizeof(array_t), alignof(array_t),
|
||||
compile_type_info(env, item_t));
|
||||
}
|
||||
case TableType: {
|
||||
type_t *key_type = Match(t, TableType)->key_type;
|
||||
type_t *value_type = Match(t, TableType)->value_type;
|
||||
return CORD_asprintf(
|
||||
"&((TypeInfo){.size=%zu, .align=%zu, .tag=TableInfo, .TableInfo.key=%r, .TableInfo.value=%r})",
|
||||
sizeof(table_t), alignof(table_t),
|
||||
compile_type_info(env, key_type),
|
||||
compile_type_info(env, value_type));
|
||||
}
|
||||
case PointerType: {
|
||||
auto ptr = Match(t, PointerType);
|
||||
CORD sigil = ptr->is_stack ? "&" : (ptr->is_optional ? "?" : "@");
|
||||
if (ptr->is_readonly) sigil = CORD_cat(sigil, "(readonly)");
|
||||
return CORD_asprintf(
|
||||
"&((TypeInfo){.size=%zu, .align=%zu, .tag=PointerInfo, .PointerInfo.sigil=\"%r\", .PointerInfo.pointed=%r})",
|
||||
sizeof(void*), alignof(void*),
|
||||
sigil, compile_type_info(env, ptr->pointed));
|
||||
}
|
||||
case FunctionType: {
|
||||
return CORD_asprintf("&((TypeInfo){.size=%zu, .align=%zu, .tag=FunctionInfo, .FunctionInfo.type_str=\"%r\"})",
|
||||
sizeof(void*), alignof(void*), type_to_cord(t));
|
||||
}
|
||||
case ClosureType: {
|
||||
errx(1, "No typeinfo for closures yet");
|
||||
}
|
||||
default: errx(1, "No such typeinfo");
|
||||
}
|
||||
}
|
||||
|
||||
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
|
||||
|
@ -51,10 +51,7 @@ env_t *new_compilation_unit(void)
|
||||
table_t namespace;
|
||||
} global_types[] = {
|
||||
{"Bool", Type(BoolType), "Bool_t", "Bool", {}},
|
||||
{"Int", Type(IntType, .bits=64), "Int_t", "Int", Table_from_entries(*(array_t*)ARRAY(
|
||||
new(ns_entry_t, "min", {"Int.min", Type(IntType, .bits=64)}),
|
||||
new(ns_entry_t, "max", {"Int.max", Type(IntType, .bits=64)}),
|
||||
), &StrToVoidStarTable_type)},
|
||||
{"Int", Type(IntType, .bits=64), "Int_t", "Int", {}},
|
||||
};
|
||||
|
||||
for (size_t i = 0; i < sizeof(global_types)/sizeof(global_types[0]); i++) {
|
||||
|
38
typecheck.c
38
typecheck.c
@ -74,24 +74,6 @@ type_t *parse_type_ast(env_t *env, type_ast_t *ast)
|
||||
code_err(ast, "I don't know how to get this type");
|
||||
}
|
||||
|
||||
type_t *get_iter_type(env_t *env, ast_t *iter)
|
||||
{
|
||||
type_t *iter_t = get_type(env, iter);
|
||||
for (;;) {
|
||||
if (iter_t->tag == PointerType) iter_t = Match(iter_t, PointerType)->pointed;
|
||||
// else if (iter_t->tag == VariantType) iter_t = Match(iter_t, VariantType)->variant_of;
|
||||
else break;
|
||||
}
|
||||
type_t *value_t = value_type(iter_t);
|
||||
switch (value_t->tag) {
|
||||
case ArrayType: return Match(value_t, ArrayType)->item_type;
|
||||
case TableType: return table_entry_type(value_t);
|
||||
default:
|
||||
code_err(iter, "I don't know how to iterate over %T values like this", iter_t);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
type_t *get_math_type(env_t *env, ast_t *ast, type_t *lhs_t, type_t *rhs_t)
|
||||
{
|
||||
(void)env;
|
||||
@ -218,8 +200,8 @@ type_t *get_type(env_t *env, ast_t *ast)
|
||||
type_t *merged = item_type ? type_or_type(item_type, t2) : t2;
|
||||
if (!merged)
|
||||
code_err(item->ast,
|
||||
"This array item has type %s, which is different from earlier array items which have type %s",
|
||||
type_to_string(t2), type_to_string(item_type));
|
||||
"This array item has type %T, which is different from earlier array items which have type %T",
|
||||
t2, item_type);
|
||||
item_type = merged;
|
||||
}
|
||||
} else {
|
||||
@ -244,16 +226,16 @@ type_t *get_type(env_t *env, ast_t *ast)
|
||||
type_t *key_merged = key_type ? type_or_type(key_type, key_t) : key_t;
|
||||
if (!key_merged)
|
||||
code_err(table_entry->key,
|
||||
"This table entry has type %s, which is different from earlier table entries which have type %s",
|
||||
type_to_string(key_t), type_to_string(key_type));
|
||||
"This table entry has type %T, which is different from earlier table entries which have type %T",
|
||||
key_t, key_type);
|
||||
key_type = key_merged;
|
||||
|
||||
type_t *value_t = get_type(env, table_entry->value);
|
||||
type_t *val_merged = value_type ? type_or_type(value_type, value_t) : value_t;
|
||||
if (!val_merged)
|
||||
code_err(table_entry->value,
|
||||
"This table entry has type %s, which is different from earlier table entries which have type %s",
|
||||
type_to_string(value_t), type_to_string(value_type));
|
||||
"This table entry has type %T, which is different from earlier table entries which have type %T",
|
||||
value_t, value_type);
|
||||
value_type = val_merged;
|
||||
}
|
||||
}
|
||||
@ -316,9 +298,9 @@ type_t *get_type(env_t *env, ast_t *ast)
|
||||
}
|
||||
case Block: {
|
||||
auto block = Match(ast, Block);
|
||||
if (LENGTH(block->statements) == 0)
|
||||
return Type(VoidType);
|
||||
ast_list_t *last = block->statements;
|
||||
if (!last)
|
||||
return Type(VoidType);
|
||||
while (last->next)
|
||||
last = last->next;
|
||||
|
||||
@ -503,8 +485,8 @@ type_t *get_type(env_t *env, ast_t *ast)
|
||||
type_t *t_either = type_or_type(true_t, false_t);
|
||||
if (!t_either)
|
||||
code_err(if_->else_body,
|
||||
"I was expecting this block to have a %s value (based on earlier clauses), but it actually has a %s value.",
|
||||
type_to_string(true_t), type_to_string(false_t));
|
||||
"I was expecting this block to have a %T value (based on earlier clauses), but it actually has a %T value.",
|
||||
true_t, false_t);
|
||||
return t_either;
|
||||
} else {
|
||||
return Type(VoidType);
|
||||
|
@ -14,6 +14,5 @@ type_t *get_math_type(env_t *env, ast_t *ast, type_t *lhs_t, type_t *rhs_t);
|
||||
bool is_discardable(env_t *env, ast_t *ast);
|
||||
type_t *get_namespace_type(env_t *env, ast_t *namespace_ast, type_t *type);
|
||||
type_t *get_file_type(env_t *env, const char *path);
|
||||
type_t *get_iter_type(env_t *env, ast_t *iter);
|
||||
|
||||
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
|
||||
|
27
types.c
27
types.c
@ -8,7 +8,7 @@
|
||||
#include "types.h"
|
||||
#include "util.h"
|
||||
|
||||
static CORD type_to_cord(type_t *t) {
|
||||
CORD type_to_cord(type_t *t) {
|
||||
switch (t->tag) {
|
||||
case UnknownType: return "???";
|
||||
case AbortType: return "Abort";
|
||||
@ -127,16 +127,12 @@ int printf_type(FILE *stream, const struct printf_info *info, const void *const
|
||||
return CORD_put(type_to_cord(t), stream);
|
||||
}
|
||||
|
||||
const char *type_to_string(type_t *t) {
|
||||
return CORD_to_const_char_star(type_to_cord(t));
|
||||
}
|
||||
|
||||
bool type_eq(type_t *a, type_t *b)
|
||||
{
|
||||
if (a == b) return true;
|
||||
if (a->tag != b->tag) return false;
|
||||
if (a->tag == PlaceholderType) return a == b;
|
||||
return streq(type_to_string(a), type_to_string(b));
|
||||
return (CORD_cmp(type_to_cord(a), type_to_cord(b)) == 0);
|
||||
}
|
||||
|
||||
bool type_is_a(type_t *t, type_t *req)
|
||||
@ -431,25 +427,6 @@ bool can_have_cycles(type_t *t)
|
||||
return _can_have_cycles(t, &seen);
|
||||
}
|
||||
|
||||
type_t *table_entry_type(type_t *table_type)
|
||||
{
|
||||
static table_t cache = {0};
|
||||
arg_t *fields = new(
|
||||
arg_t, .name="key",
|
||||
.type=Match(table_type, TableType)->key_type);
|
||||
fields->next = new(
|
||||
arg_t, .name="value",
|
||||
.type=Match(table_type, TableType)->value_type);
|
||||
type_t *t = Type(StructType, .fields=fields);
|
||||
type_t *cached = Table_str_get(&cache, type_to_string(t));
|
||||
if (cached) {
|
||||
return cached;
|
||||
} else {
|
||||
Table_str_set(&cache, type_to_string(t), t);
|
||||
return t;
|
||||
}
|
||||
}
|
||||
|
||||
type_t *replace_type(type_t *t, type_t *target, type_t *replacement)
|
||||
{
|
||||
if (type_eq(t, target))
|
||||
|
5
types.h
5
types.h
@ -99,9 +99,7 @@ struct type_s {
|
||||
|
||||
int printf_pointer_size(const struct printf_info *info, size_t n, int argtypes[n], int size[n]);
|
||||
int printf_type(FILE *stream, const struct printf_info *info, const void *const args[]);
|
||||
const char *type_to_string_concise(type_t *t);
|
||||
const char *type_to_typeof_string(type_t *t);
|
||||
const char *type_to_string(type_t *t);
|
||||
CORD type_to_cord(type_t *t);
|
||||
bool type_eq(type_t *a, type_t *b);
|
||||
bool type_is_a(type_t *t, type_t *req);
|
||||
type_t *type_or_type(type_t *a, type_t *b);
|
||||
@ -114,7 +112,6 @@ bool has_stack_memory(type_t *t);
|
||||
bool can_promote(type_t *actual, type_t *needed);
|
||||
bool can_leave_uninitialized(type_t *t);
|
||||
bool can_have_cycles(type_t *t);
|
||||
type_t *table_entry_type(type_t *table_t);
|
||||
type_t *replace_type(type_t *t, type_t *target, type_t *replacement);
|
||||
size_t type_size(type_t *t);
|
||||
size_t type_align(type_t *t);
|
||||
|
Loading…
Reference in New Issue
Block a user