[dynamic; N]T proof of concept: fixed capacity dynamic array (akin to small_array.Small_Array(N, T))

This commit is contained in:
gingerBill
2026-03-11 16:46:33 +00:00
parent 143a8762a0
commit f1dbe9c242
25 changed files with 677 additions and 61 deletions

View File

@@ -248,6 +248,12 @@ struct TypeNamed {
}) \
TYPE_KIND(Slice, struct { Type *elem; }) \
TYPE_KIND(DynamicArray, struct { Type *elem; }) \
TYPE_KIND(FixedCapacityDynamicArray, struct { \
i64 capacity; \
Type *generic_capacity; \
Type *elem; \
i64 padding_needed; /*-1 if unknown*/ \
}) \
TYPE_KIND(Map, struct { \
Type *key; \
Type *value; \
@@ -378,6 +384,7 @@ enum Typeid_Kind : u8 {
Typeid_Matrix,
Typeid_SoaPointer,
Typeid_Bit_Field,
Typeid_Fixed_Capacity_Dynamic_Array,
Typeid__COUNT
@@ -698,6 +705,7 @@ gb_global Type *t_type_info_simd_vector = nullptr;
gb_global Type *t_type_info_matrix = nullptr;
gb_global Type *t_type_info_soa_pointer = nullptr;
gb_global Type *t_type_info_bit_field = nullptr;
gb_global Type *t_type_info_fixed_capacity_dynamic_array = nullptr;
gb_global Type *t_type_info_named_ptr = nullptr;
gb_global Type *t_type_info_integer_ptr = nullptr;
@@ -726,6 +734,7 @@ gb_global Type *t_type_info_simd_vector_ptr = nullptr;
gb_global Type *t_type_info_matrix_ptr = nullptr;
gb_global Type *t_type_info_soa_pointer_ptr = nullptr;
gb_global Type *t_type_info_bit_field_ptr = nullptr;
gb_global Type *t_type_info_fixed_capacity_dynamic_array_ptr = nullptr;
gb_global Type *t_allocator = nullptr;
gb_global Type *t_allocator_ptr = nullptr;
@@ -1094,6 +1103,23 @@ gb_internal Type *alloc_type_dynamic_array(Type *elem) {
return t;
}
gb_internal Type *alloc_type_fixed_capacity_dynamic_array(Type *elem, i64 capacity, Type *generic_capacity = nullptr) {
if (generic_capacity != nullptr) {
Type *t = alloc_type(Type_FixedCapacityDynamicArray);
t->FixedCapacityDynamicArray.elem = elem;
t->FixedCapacityDynamicArray.capacity = capacity;
t->FixedCapacityDynamicArray.generic_capacity = generic_capacity;
t->FixedCapacityDynamicArray.padding_needed = 0;
return t;
}
Type *t = alloc_type(Type_FixedCapacityDynamicArray);
t->FixedCapacityDynamicArray.elem = elem;
t->FixedCapacityDynamicArray.capacity = capacity;
t->FixedCapacityDynamicArray.padding_needed = 0;
return t;
}
gb_internal Type *alloc_type_struct() {
Type *t = alloc_type(Type_Struct);
@@ -1658,6 +1684,11 @@ gb_internal bool is_type_dynamic_array(Type *t) {
if (t == nullptr) { return false; }
return t->kind == Type_DynamicArray;
}
gb_internal bool is_type_fixed_capacity_dynamic_array(Type *t) {
t = base_type(t);
if (t == nullptr) { return false; }
return t->kind == Type_FixedCapacityDynamicArray;
}
gb_internal bool is_type_slice(Type *t) {
t = base_type(t);
if (t == nullptr) { return false; }
@@ -1687,6 +1718,8 @@ gb_internal Type *base_array_type(Type *t) {
return bt->EnumeratedArray.elem;
} else if (is_type_simd_vector(bt)) {
return bt->SimdVector.elem;
} else if (is_type_fixed_capacity_dynamic_array(bt)) {
return bt->FixedCapacityDynamicArray.elem;
} else if (is_type_matrix(bt)) {
return bt->Matrix.elem;
}
@@ -1702,6 +1735,8 @@ gb_internal Type *base_any_array_type(Type *t) {
return bt->Slice.elem;
} else if (is_type_dynamic_array(bt)) {
return bt->DynamicArray.elem;
} else if (is_type_fixed_capacity_dynamic_array(bt)) {
return bt->FixedCapacityDynamicArray.elem;
} else if (is_type_enumerated_array(bt)) {
return bt->EnumeratedArray.elem;
} else if (is_type_simd_vector(bt)) {
@@ -2234,6 +2269,7 @@ gb_internal bool is_type_indexable(Type *t) {
case Type_Array:
case Type_Slice:
case Type_DynamicArray:
case Type_FixedCapacityDynamicArray:
case Type_Map:
return true;
case Type_MultiPointer:
@@ -2254,6 +2290,7 @@ gb_internal bool is_type_sliceable(Type *t) {
case Type_Array:
case Type_Slice:
case Type_DynamicArray:
case Type_FixedCapacityDynamicArray:
return true;
case Type_EnumeratedArray:
return false;
@@ -2394,6 +2431,11 @@ gb_internal bool is_type_polymorphic(Type *t, bool or_specialized=false) {
return is_type_polymorphic(t->SimdVector.elem, or_specialized);
case Type_DynamicArray:
return is_type_polymorphic(t->DynamicArray.elem, or_specialized);
case Type_FixedCapacityDynamicArray:
if (t->FixedCapacityDynamicArray.generic_capacity != nullptr) {
return true;
}
return is_type_polymorphic(t->FixedCapacityDynamicArray.elem, or_specialized);
case Type_Slice:
return is_type_polymorphic(t->Slice.elem, or_specialized);
@@ -2515,6 +2557,11 @@ gb_internal bool type_has_nil(Type *t) {
case Type_DynamicArray:
case Type_Map:
return true;
case Type_FixedCapacityDynamicArray:
// TODO(bill): should it have `nil`?
return false;
case Type_Union:
return t->Union.kind != UnionType_no_nil;
case Type_Struct:
@@ -2642,6 +2689,9 @@ gb_internal bool is_type_comparable(Type *t) {
case Type_Matrix:
return is_type_comparable(t->Matrix.elem);
case Type_FixedCapacityDynamicArray:
return false;
case Type_BitSet:
return true;
@@ -2688,6 +2738,10 @@ gb_internal bool is_type_simple_compare(Type *t) {
case Type_EnumeratedArray:
return is_type_simple_compare(t->EnumeratedArray.elem);
case Type_FixedCapacityDynamicArray:
return false;
// return is_type_simple_compare(t->FixedCapacityDynamicArray.elem);
case Type_Basic:
if (t->Basic.flags & BasicFlag_SimpleCompare) {
return true;
@@ -2758,6 +2812,10 @@ gb_internal bool is_type_nearly_simple_compare(Type *t) {
case Type_EnumeratedArray:
return is_type_nearly_simple_compare(t->EnumeratedArray.elem);
case Type_FixedCapacityDynamicArray:
return false;
// return is_type_nearly_simple_compare(t->FixedCapacityDynamicArray.elem);
case Type_Basic:
if (t->Basic.flags & (BasicFlag_SimpleCompare|BasicFlag_Numeric)) {
return true;
@@ -2838,6 +2896,7 @@ gb_internal bool is_type_load_safe(Type *type) {
case Type_DynamicArray:
case Type_Proc:
case Type_SoaPointer:
case Type_FixedCapacityDynamicArray:
return false;
case Type_Enum:
@@ -3047,6 +3106,10 @@ gb_internal bool are_types_identical_internal(Type *x, Type *y, bool check_tuple
case Type_DynamicArray:
return are_types_identical(x->DynamicArray.elem, y->DynamicArray.elem);
case Type_FixedCapacityDynamicArray:
return (x->FixedCapacityDynamicArray.capacity == y->FixedCapacityDynamicArray.capacity) &&
are_types_identical(x->FixedCapacityDynamicArray.elem, y->FixedCapacityDynamicArray.elem);
case Type_Slice:
return are_types_identical(x->Slice.elem, y->Slice.elem);
@@ -4144,9 +4207,22 @@ gb_internal i64 type_align_of_internal(Type *t, TypePath *path) {
}
case Type_DynamicArray:
// data, count, capacity, allocator
// data, len, cap, allocator
return build_context.int_size;
case Type_FixedCapacityDynamicArray:
// data, len
{
Type *elem = t->FixedCapacityDynamicArray.elem;
bool pop = type_path_push(path, elem);
if (path->failure) {
return FAILURE_ALIGNMENT;
}
i64 align = type_align_of_internal(elem, path);
if (pop) type_path_pop(path);
return gb_max(build_context.int_size, align);
}
case Type_Slice:
return build_context.int_size;
@@ -4419,6 +4495,34 @@ gb_internal i64 type_size_of_internal(Type *t, TypePath *path) {
// data + len + cap + allocator(procedure+data)
return 3*build_context.int_size + 2*build_context.ptr_size;
case Type_FixedCapacityDynamicArray:
{
// data + len
i64 capacity = t->FixedCapacityDynamicArray.capacity;
Type *elem = t->FixedCapacityDynamicArray.elem;
i64 align = type_align_of_internal(elem, path);
if (path->failure) {
return FAILURE_SIZE;
}
align = gb_max(build_context.int_size, align);
i64 size = type_size_of(elem);
size *= capacity;
i64 old_size = size;
size = align_formula(size, build_context.int_size);
i64 padding = size - old_size;
if (t->FixedCapacityDynamicArray.padding_needed >= 0) {
GB_ASSERT(t->FixedCapacityDynamicArray.padding_needed == padding);
}
t->FixedCapacityDynamicArray.padding_needed = padding;
size += 1*build_context.int_size;
size = align_formula(size, align);
return size;
}
case Type_Map:
/*
struct {
@@ -4644,6 +4748,23 @@ gb_internal i64 type_offset_of(Type *t, i64 index, Type **field_type_) {
return 3*build_context.int_size; // allocator
}
break;
case Type_FixedCapacityDynamicArray:
switch (index) {
case 0:
if (field_type_) *field_type_ = alloc_type_array(t->FixedCapacityDynamicArray.elem, t->FixedCapacityDynamicArray.capacity);
return 0; // data
case 1: // len
if (field_type_) *field_type_ = t_int;
{
i64 offset = 0;
offset = type_size_of(alloc_type_array(t->FixedCapacityDynamicArray.elem, t->FixedCapacityDynamicArray.capacity));
offset = align_formula(offset, build_context.int_size);
return offset;
}
}
break;
case Type_Union:
if (!is_type_union_maybe_pointer(t)) {
/* i64 s = */ type_size_of(t);
@@ -4711,6 +4832,12 @@ gb_internal i64 type_offset_of_from_selection(Type *type, Selection sel) {
case 3: t = t_allocator; break;
}
break;
case Type_FixedCapacityDynamicArray:
switch (index) {
case 0: t = alloc_type_array(t->FixedCapacityDynamicArray.elem, t->FixedCapacityDynamicArray.capacity); break;
case 1: t = t_int; break;
}
break;
}
}
}
@@ -4970,6 +5097,15 @@ gb_internal Type *type_internal_index(Type *t, isize index) {
default: GB_PANIC("invalid raw dynamic array index");
};
}
case Type_FixedCapacityDynamicArray:
{
switch (index) {
case 0: t = alloc_type_array(t->FixedCapacityDynamicArray.elem, t->FixedCapacityDynamicArray.capacity); break;
case 1: return t_int;
default: GB_PANIC("invalid raw fixed capacity dynamic array index");
};
}
case Type_Struct:
return get_struct_field_type(bt, index);
case Type_Union:
@@ -5068,6 +5204,13 @@ gb_internal gbString write_type_to_string(gbString str, Type *type, bool shortha
str = write_type_to_string(str, type->DynamicArray.elem, shorthand, allow_polymorphic);
break;
case Type_FixedCapacityDynamicArray:
str = gb_string_appendc(str, "[dynamic; ");
str = gb_string_appendc(str, gb_bprintf("%lld", cast(long long)type->FixedCapacityDynamicArray.capacity));
str = gb_string_appendc(str, "]");
str = write_type_to_string(str, type->FixedCapacityDynamicArray.elem, shorthand, allow_polymorphic);
break;
case Type_Enum:
str = gb_string_appendc(str, "enum");
if (type->Enum.base_type != nullptr) {