CX Framework
Cross-platform C utility framework
Loading...
Searching...
No Matches
sarray.h
Go to the documentation of this file.
1#pragma once
7
41
42#include <cx/cx.h>
43#include <cx/debug/assert.h>
44#include <cx/debug/dbgtypes.h>
46
47CX_C_BEGIN
48
49#define sarrayref(typ) sa_##typ
50#define sarrayhdl(typ) sa_##typ*
51
73
80#define saDeclareType(name, typ) \
81 typedef union sa_##name { \
82 _nv_sarray* _debug; \
83 void* _is_sarray; \
84 void* _is_sarray_##name; \
85 typ* a; \
86 } sa_##name
87
93#define saDeclare(name) saDeclareType(name, name)
94
100#define saDeclarePtr(name) saDeclareType(name, name*)
101
105#define saInitNone { .a = 0 }
106
107// Pre-declared common sarray types
108typedef sa_ref sa_opaque;
109saDeclare(int8);
110saDeclare(int16);
111saDeclare(int32);
112saDeclare(int64);
113saDeclare(intptr);
114saDeclare(uint8);
115saDeclare(uint16);
116saDeclare(uint32);
117saDeclare(uint64);
118saDeclare(uintptr);
119saDeclare(bool);
120saDeclareType(size, size_t);
121saDeclare(float32);
122saDeclare(float64);
123saDeclareType(ptr, void*);
124saDeclare(string);
125// strref doesn't make sense in an sarray
126saDeclareType(object, ObjInst*);
127saDeclareType(suid, SUID);
129saDeclareType(sarray, sa_ref);
130saDeclare(hashtable);
131saDeclare(closure);
132
133// SArray header structure
134//
135// Internal structure containing array metadata. Access through helper macros.
136typedef struct SArrayHeader {
137 // sarray header begins here
138 stype elemtype;
139 int32 count;
140 int32 capacity;
141 uint32 flags; // high 8 bits = growth
142 void* data[1];
143} SArrayHeader;
144
147 SA_Ref = 0x0010,
148 SA_Sorted = 0x0020,
149 SA_AutoShrink = 0x0040,
150};
151
152// Growth rate strategies for array expansion
153enum SARRAY_GROW_ENUM {
154 SA_GROW_Auto,
155
156 // Dynamic growth rates (transition from high to lower growth as size increases)
157 SA_GROW_Normal,
158 SA_GROW_Aggressive,
159 SA_GROW_Slow,
160
161 // Fixed growth rates
162 SA_GROW_100,
163 SA_GROW_50,
164 SA_GROW_25,
165
166 SA_GROW_Minimal,
167};
168
173 SA_Unique = 0x00010000,
174
177 SA_Fast = 0x00020000,
178
181 SA_Inexact = 0x00100000,
182
183 // Internal use only - do not use directly
184 SAINT_Consume = 0x10000000,
185};
186
187#define SA_GROW_MASK (0xff000000)
188
229#define SA_Grow(rate) (((uint32)SA_GROW_##rate) << 24)
230
231// Internal macro - extracts growth settings from flags
232#define SA_GET_GROW(flags) ((flags) >> 24)
233
234#define SARRAY_HDRSIZE (offsetof(SArrayHeader, data))
235#define SARRAY_HDR(ref) ((SArrayHeader*)(((uintptr)((ref).a)) - SARRAY_HDRSIZE))
236#define SAREF(r) (unused_noeval(&((r)._is_sarray)), *(sa_ref*)(&(r)))
237#define SAHANDLE(h) ((sahandle)(unused_noeval((h != NULL) && &((h)->_is_sarray)), (h)))
238
239_Ret_notnull_ _meta_inline SArrayHeader* _saHdr(_In_ sa_ref ref)
240{
241 return SARRAY_HDR(ref);
242}
243
250#define saSize(ref) ((ref)._is_sarray ? _saHdr(SAREF(ref))->count : 0)
251
258#define saCapacity(ref) ((ref)._is_sarray ? _saHdr(SAREF(ref))->capacity : 0)
259
266#define saElemSize(ref) ((ref)._is_sarray ? stGetSize(_saHdr(SAREF(ref))->elemtype) : 0)
267
274#define saElemType(ref) ((ref)._is_sarray ? _saHdr(SAREF(ref))->elemtype : 0)
275
282#define saValid(ref) ((ref).a)
283
285
290
291_Success_(!canfail || return) _When_(canfail, _Check_return_) _At_(out->a, _Post_notnull_) bool
292_saInit(_Out_ sahandle out, stype elemtype, int32 capacity, bool canfail, flags_t flags);
293
315#define saInit(out, type, capacity, ...) \
316 _saInit(SAHANDLE(out), stType(type), capacity, false, opt_flags(__VA_ARGS__))
317
327#define saTryInit(out, type, capacity, ...) \
328 _saInit(SAHANDLE(out), stType(type), capacity, true, opt_flags(__VA_ARGS__))
329
330_At_(handle->a, _Pre_maybenull_ _Post_null_) void _saDestroy(_Inout_ sahandle handle);
331
345#define saDestroy(handle) _saDestroy(SAHANDLE(handle))
346
347_When_(canfail, _Check_return_) _At_(handle->a, _Pre_notnull_ _Post_notnull_) bool _saReserve(_Inout_ sahandle handle, int32 capacity, bool canfail);
348
364#define saReserve(handle, capacity) _saReserve(SAHANDLE(handle), capacity, true)
365
366_At_(handle->a, _Pre_notnull_ _Post_notnull_) void _saShrink(_Inout_ sahandle handle, int32 capacity);
367
385#define saShrink(handle, capacity) _saShrink(SAHANDLE(handle), capacity)
386
387_At_(handle->a, _Pre_notnull_ _Post_notnull_) void _saSetSize(_Inout_ sahandle handle, int32 size);
388
403#define saSetSize(handle, size) _saSetSize(SAHANDLE(handle), size)
404
405_At_(handle->a, _Pre_maybenull_) void _saClear(_Inout_ sahandle handle);
406
420#define saClear(handle) _saClear(SAHANDLE(handle))
421
423
428
429#define _sa_Consume_Arg_ \
430 _When_(flags& SAINT_Consume, _Pre_notnull_ _Post_invalid_) \
431 _When_(!(flags & SAINT_Consume), _Inout_)
432_At_(handle->a, _Pre_maybenull_ _Post_notnull_) int32 _saPush(_Inout_ sahandle handle, stype elemtype, _In_ stgeneric elem,
433 flags_t flags);
434_At_(handle->a, _Pre_maybenull_ _Post_notnull_) int32 _saPushPtr(_Inout_ sahandle handle, stype elemtype,
435 _sa_Consume_Arg_ stgeneric* elem, flags_t flags);
436
460#define saPush(handle, type, elem, ...) \
461 _saPush(SAHANDLE(handle), stCheckedArg(type, elem), opt_flags(__VA_ARGS__))
462
486#define saPushC(handle, type, elem, ...) \
487 _saPushPtr(SAHANDLE(handle), \
488 stCheckedPtrArg(type, elem), \
489 opt_flags(__VA_ARGS__) | SAINT_Consume)
490
491_Ret_opt_valid_ _At_(handle->a, _Pre_maybenull_) void* _saPopPtr(_Inout_ sahandle handle, int32 idx);
492
510#define saPopPtr(handle) _saPopPtr(SAHANDLE(handle), -1)
511
527#define saPopPtrI(handle, idx) _saPopPtr(SAHANDLE(handle), idx)
528
529_At_(ref.a, _Pre_notnull_) int32 _saFind(_In_ sa_ref ref, _In_ stgeneric elem, flags_t flags);
530_At_(ref.a, _Pre_maybenull_) _meta_inline int32
531_saFindChecked(_In_ sa_ref ref, stype elemtype, _In_ stgeneric elem, flags_t flags)
532{
533 if (!ref.a)
534 return -1;
535 devAssert(stEq(saElemType(ref), elemtype));
536 return _saFind(ref, elem, flags);
537}
538
561#define saFind(ref, type, elem, ...) \
562 _saFindChecked(SAREF(ref), stCheckedArg(type, elem), opt_flags(__VA_ARGS__))
563
564_At_(handle->a, _Pre_notnull_ _Post_notnull_) bool _saFindRemove(_Inout_ sahandle handle, _In_ stgeneric elem, flags_t flags);
565_At_(handle->a, _Pre_maybenull_) _meta_inline bool
566_saFindRemoveChecked(_Inout_ sahandle handle, stype elemtype, _In_ stgeneric elem, flags_t flags)
567{
568 if (!handle->a)
569 return false;
570 devAssert(stEq(saElemType(*handle), elemtype));
571 return _saFindRemove(handle, elem, flags);
572}
573
594#define saFindRemove(handle, type, elem, ...) \
595 _saFindRemoveChecked(SAHANDLE(handle), stCheckedArg(type, elem), opt_flags(__VA_ARGS__))
596
597_At_(handle->a, _Pre_notnull_ _Post_notnull_) int32 _saInsert(_Inout_ sahandle handle, int32 idx, _In_ stgeneric elem);
598_At_(handle->a, _Pre_notnull_ _Post_notnull_) _meta_inline int32
599_saInsertChecked(_Inout_ sahandle handle, int32 idx, stype elemtype, _In_ stgeneric elem)
600{
601 devAssert(handle->_is_sarray);
602 devAssert(stEq(saElemType(*handle), elemtype));
603 return _saInsert(handle, idx, elem);
604}
605
628#define saInsert(handle, idx, type, elem) \
629 _saInsertChecked(SAHANDLE(handle), idx, stCheckedArg(type, elem))
630
631_At_(handle->a, _Pre_notnull_ _Post_notnull_) bool _saExtract(_Inout_ sahandle handle, int32 idx, _Inout_opt_ stgeneric* elem,
632 flags_t flags);
633
634_At_(handle->a, _Pre_maybenull_) _meta_inline bool
635_saExtractChecked(_Inout_ sahandle handle, int32 idx, stype elemtype,
636 _stCopyDest_Anno_opt_(elemtype) stgeneric* elem, flags_t flags)
637{
638 if (!handle->a)
639 return false;
640 devAssert(elemtype == stType(none) || stEq(saElemType(*handle), elemtype));
641 return _saExtract(handle, idx, elem, flags);
642}
643
667#define saExtract(handle, idx, type, elem_copy_out, ...) \
668 _saExtractChecked(SAHANDLE(handle), \
669 idx, \
670 stCheckedPtrArg(type, elem_copy_out), \
671 opt_flags(__VA_ARGS__))
672
690#define saRemove(handle, idx, ...) \
691 _saExtractChecked(SAHANDLE(handle), idx, stType(none), NULL, opt_flags(__VA_ARGS__))
692
693_At_(handle->a, _Pre_maybenull_) void _saSort(_Inout_ sahandle handle, bool keep);
694
714#define saSort(handle, keep) _saSort(SAHANDLE(handle), keep)
715
730typedef intptr (*saCmpFunc)(stype st,
731 _In_ stgeneric gen1,
732 _In_ stgeneric gen2,
733 flags_t flags,
734 _In_opt_ void* ctx);
735
736_At_(handle->a, _Pre_maybenull_) void _saSortCustom(_Inout_ sahandle handle,
737 _In_ saCmpFunc cmp,
738 _In_opt_ void* ctx,
739 flags_t flags);
740
775#define saSortCustom(handle, cmp, ctx, ...) \
776 _saSortCustom(SAHANDLE(handle), cmp, ctx, opt_flags(__VA_ARGS__))
777
779
783
784_At_(out->a, _When_(ref.a, _Post_notnull_) ) void _saSlice(_Out_ sahandle out, _In_ sa_ref ref, int32 start, int32 end);
785
806#define saSlice(out, src, start, end) _saSlice(SAHANDLE(out), SAREF(src), start, end)
807
825#define saClone(out, src) _saSlice(SAHANDLE(out), SAREF(src), 0, 0)
826
827_At_(out->a, _Post_maybenull_) void _saMerge(_Out_ sahandle out, int n, _In_ sa_ref* refs, flags_t flags);
828
846#define saMerge(out, ...) \
847 _saMerge(SAHANDLE(out), \
848 sizeof((sa_ref[]) { __VA_ARGS__ }) / sizeof(sa_ref), \
849 (sa_ref[]) { __VA_ARGS__ }, \
850 0)
851
869#define saMergeF(out, flags, ...) \
870 _saMerge(SAHANDLE(out), \
871 sizeof((sa_ref[]) { __VA_ARGS__ }) / sizeof(sa_ref), \
872 (sa_ref[]) { __VA_ARGS__ }, \
873 flags)
874
877
878CX_C_END
879
880#ifdef __cplusplus
881// C++ needs a different initializer syntax
882#undef saInitNone
883#define saInitNone \
884 { }
885
886// C++ replacements for the compound-literal-based saMerge/saMergeF.
887//
888// The C versions build a temporary sa_ref[] via an array compound literal, which
889// C++ does not support. Instead, collect the source arrays into a local sa_ref[]
890// through a variadic template.
891template <typename... SAs> _meta_inline void _cxSaMerge(sahandle out, flags_t flags, SAs... arrs)
892{
893 static_assert(sizeof...(SAs) > 0, "saMerge requires at least one source array");
894 sa_ref refs[] = { *(sa_ref*)&arrs... };
895 _saMerge(out, (int)(sizeof...(SAs)), refs, flags);
896}
897#undef saMerge
898#undef saMergeF
899#define saMerge(out, ...) _cxSaMerge(SAHANDLE(out), 0, __VA_ARGS__)
900#define saMergeF(out, flags, ...) _cxSaMerge(SAHANDLE(out), flags, __VA_ARGS__)
901#endif
Runtime assertion macros and failure handling.
#define saDeclare(name)
Definition sarray.h:93
#define saElemType(ref)
Definition sarray.h:274
#define saDeclareType(name, typ)
Definition sarray.h:80
SARRAY_CREATE_FLAGS_ENUM
Creation flags for sarray initialization.
Definition sarray.h:146
SARRAY_FUNC_FLAGS_ENUM
Operation flags for sarray functions.
Definition sarray.h:170
@ SA_Ref
Array references data without copying/destroying (pointer types only)
Definition sarray.h:147
@ SA_Sorted
Maintain sorted order with O(log n) search and O(n) insert.
Definition sarray.h:148
@ SA_AutoShrink
Automatically release memory when array shrinks.
Definition sarray.h:149
@ SA_Fast
Definition sarray.h:177
@ SA_Inexact
Definition sarray.h:181
@ SA_Unique
Definition sarray.h:173
intptr(* saCmpFunc)(stype st, stgeneric gen1, stgeneric gen2, flags_t flags, void *ctx)
Definition sarray.h:730
#define devAssert(expr)
Definition assert.h:140
#define stvar(typen, val)
Definition stvar.h:162
bool stEq(stype s1, stype s2)
Definition stype.h:1785
#define stType(name)
Definition stype.h:972
128-bit sortable unique identifier
Definition suid.h:47
Macros for suppressing compiler warnings.