CX Framework
Cross-platform C utility framework
Loading...
Searching...
No Matches
stype.h
Go to the documentation of this file.
1#pragma once
2
5
10
115
116#include <cx/debug/assert.h>
117#include <cx/platform/base.h>
118#include <cx/platform/cpp.h>
120#include <cx/utils/macros/salieri.h>
122#include <stdbool.h>
123#include <stddef.h>
124#include <stdint.h>
125#include <string.h>
126
127// extra files that can be included for specific functions
128#define STYPE_FOREACH_ALL <cx/stype/alltypes.inc>
129
130CX_C_BEGIN
131
132// do this as a typedef instead of a #define
133#undef bool
134
135// IMPORTANT NOTE!
136// Always initialize string to NULL or 0 first!
137typedef struct str_ref* _Nullable string;
138typedef const struct str_ref* _Nullable strref;
139typedef struct hashtable_ref* hashtable;
140typedef struct closure_ref* closure;
141typedef struct cchain_ref* cchain;
142typedef struct BufferHeader* Buffer;
143typedef struct ObjInst ObjInst;
144typedef struct ObjInst_WeakRef ObjInst_WeakRef;
145typedef struct SUID SUID;
146typedef struct stvar stvar;
147
148enum STYPE_CLASS_ID {
149 STCLASS_OPAQUE = 0x00,
150 STCLASS_INT = 0x10,
151 STCLASS_UINT = 0x20,
152 STCLASS_FLOAT = 0x30,
153 STCLASS_PTR = 0x40,
154 STCLASS_CX = 0xe0,
155 STCLASS_CX_CONTAINER = 0xf0,
156};
157
158#define STYPE_CLASS_MASK 0xf0
159#define STYPE_CLASS(v) ((v) & STYPE_CLASS_MASK)
160
161typedef signed char int8;
162typedef unsigned char uint8;
163typedef short int16;
164typedef unsigned short uint16;
165typedef int int32;
166typedef unsigned int uint32;
167typedef long long int64;
168typedef unsigned long long uint64;
169typedef intptr_t intptr;
170typedef uintptr_t uintptr;
171#ifndef __cplusplus
172typedef _Bool bool;
173#else
174typedef bool _Bool;
175#endif
176
177// limits for integer types
178
179#define MIN_INT8 (-0x7f - 1)
180#define MAX_INT8 0x7f
181#define MAX_UINT8 0xff
182#define MIN_INT16 (-0x7fff - 1)
183#define MAX_INT16 0x7fff
184#define MAX_UINT16 0xffff
185#define MIN_INT32 (-0x7fffffffL - 1)
186#define MAX_INT32 0x7fffffffL
187#define MAX_UINT32 0xffffffffUL
188#define MAX_INT64 0x7fffffffffffffffLL
189#define MIN_INT64 (-0x7fffffffffffffffLL - 1)
190#define MAX_UINT64 0xffffffffffffffffULL
191
192#if defined(_64BIT)
193#define MIN_INTPTR MIN_INT64
194#define MAX_INTPTR MAX_INT64
195#define MAX_UINTPTR MAX_UINT64
196#elif defined(_32BIT)
197#define MIN_INTPTR MIN_INT32
198#define MAX_INTPTR MAX_INT32
199#define MAX_UINTPTR MAX_UINT32
200#endif
201
202typedef float float32;
203typedef double float64;
204
205typedef uint32 stype;
206
207// standardize on uint32 for function call flags
208typedef uint32 flags_t;
209
210// sarrays are special because of the pointer union
211typedef union sa_ref {
212 void* _is_sarray;
213 void* a;
214} sa_ref;
215typedef union sa_ref* sahandle;
216
217// This is the type that is used for passing as a parameter by-value, containers, and
218// variants. Should be no larger than 64 bits wide, but can be smaller.
219#define SType_none void*
220#define SType_opaque void*
221#define SType_int8 int8
222#define SType_int16 int16
223#define SType_int32 int32
224#define SType_int64 int64
225#define SType_uint8 uint8
226#define SType_uint16 uint16
227#define SType_uint32 uint32
228#define SType_uint64 uint64
229#define SType_intptr intptr
230#define SType_uintptr uintptr
231#define SType_bool _Bool
232#define SType_size size_t
233#define SType_float32 float32
234#define SType_float64 float64
235#define SType_ptr void*
236#define SType_string string
237#define SType_strref strref
238#define SType_object ObjInst*
239#define SType_weakref ObjInst_WeakRef*
240#define SType_suid SUID*
241#define SType_stvar stvar*
242#define SType_sarray sa_ref
243#define SType_hashtable hashtable
244#define SType_closure closure
245#define SType_cchain cchain
246#define SType_buffer Buffer
247#define stTypeDef(name) SType_##name
248
254
268#define stTypeCast(name, v) ((SType_##name)(v))
269
283#define stPtrCast(name, v) ((SType_##name*)(v))
284
285// container that can be aliased for any type
286#define CONTAINER_TYPE(type) stTypeDef(type) st_##type
287typedef union stgeneric {
288 uint64 st_generic;
289 CONTAINER_TYPE(none);
290 CONTAINER_TYPE(opaque);
291 CONTAINER_TYPE(int8);
292 CONTAINER_TYPE(int16);
293 CONTAINER_TYPE(int32);
294 CONTAINER_TYPE(int64);
295 CONTAINER_TYPE(uint8);
296 CONTAINER_TYPE(uint16);
297 CONTAINER_TYPE(uint32);
298 CONTAINER_TYPE(uint64);
299 CONTAINER_TYPE(intptr);
300 CONTAINER_TYPE(uintptr);
301 CONTAINER_TYPE(bool);
302 CONTAINER_TYPE(size);
303 CONTAINER_TYPE(float32);
304 CONTAINER_TYPE(float64);
305 CONTAINER_TYPE(ptr);
306 CONTAINER_TYPE(string);
307 CONTAINER_TYPE(strref);
308 CONTAINER_TYPE(object);
309 CONTAINER_TYPE(weakref);
310 CONTAINER_TYPE(suid);
311 CONTAINER_TYPE(stvar);
312 CONTAINER_TYPE(sarray);
313 CONTAINER_TYPE(hashtable);
314 CONTAINER_TYPE(closure);
315 CONTAINER_TYPE(cchain);
316 CONTAINER_TYPE(buffer);
317} stgeneric;
318
319_Static_assert(sizeof(stgeneric) == sizeof(uint64), "stype container too large");
320
321#ifndef __cplusplus
322#define stgeneric(type, val) ((stgeneric) { .st_##type = stCheck(type, val) })
323#define stgeneric_unchecked(type, val) ((stgeneric) { .st_##type = (val) })
324#define stgensarray(val) stgeneric(ptr, (val)._is_sarray)
325#else
326#define stgeneric(type, val) ((stgeneric)stCheck(type, val))
327#define stgeneric_unchecked(type, val) ((stgeneric)(val))
328#define stgensarray(val) stgeneric(ptr, (val)._is_sarray)
329#endif
330
331// Compact variant structure. This is most often used for passing arrays of values that
332// the type is not known at compile time, as part of the type-safe varargs replacement
333// mechanism.
334
335typedef struct stvar {
336 stgeneric data;
337 stype type;
338} stvar;
339
340// The type that's actually used for storage in containers, etc.
341#define STStorageType_none void
342#define STStorageType_opaque void
343#define STStorageType_int8 int8
344#define STStorageType_int16 int16
345#define STStorageType_int32 int32
346#define STStorageType_int64 int64
347#define STStorageType_uint8 uint8
348#define STStorageType_uint16 uint16
349#define STStorageType_uint32 uint32
350#define STStorageType_uint64 uint64
351#define STStorageType_intptr intptr
352#define STStorageType_uintptr uintptr
353#define STStorageType_bool _Bool
354#define STStorageType_size size_t
355#define STStorageType_float32 float32
356#define STStorageType_float64 float64
357#define STStorageType_ptr void*
358#define STStorageType_string string
359#define STStorageType_strref string
360#define STStorageType_object ObjInst*
361#define STStorageType_weakref ObjInst_WeakRef*
362#define STStorageType_suid SUID
363#define STStorageType_stvar stvar
364#define STStorageType_sarray sa_ref
365#define STStorageType_hashtable hashtable
366#define STStorageType_closure closure
367#define STStorageType_cchain cchain
368#define STStorageType_buffer Buffer
369#define stStorageType(name) STStorageType_##name
370
371enum STYPE_ID {
372 // none is a special type for empty argument lists, variants, etc
373 STypeId_none = STCLASS_OPAQUE,
374 // opaque is a magic catch-all type for custom structures and such
375 STypeId_opaque = STCLASS_OPAQUE | 1,
376 // generic scalar types
377 STypeId_int8 = STCLASS_INT | 1,
378 STypeId_int16 = STCLASS_INT | 2,
379 STypeId_int32 = STCLASS_INT | 4,
380 STypeId_int64 = STCLASS_INT | 8,
381 STypeId_intptr = STCLASS_INT | sizeof(intptr), // alias for one of the other int types
382 STypeId_uint8 = STCLASS_UINT | 1,
383 STypeId_uint16 = STCLASS_UINT | 2,
384 STypeId_uint32 = STCLASS_UINT | 4,
385 STypeId_uint64 = STCLASS_UINT | 8,
386 STypeId_uintptr = STCLASS_UINT | sizeof(intptr),
387 STypeId_bool = STCLASS_UINT | 3, // fill in a gap in the ID sequence
388 STypeId_size = STCLASS_UINT | sizeof(size_t), // alias for one of the uint types
389 STypeId_float32 = STCLASS_FLOAT | 4,
390 STypeId_float64 = STCLASS_FLOAT | 8,
391 // ptr is stored similar to (u)intptr, but automatically dereferenced in ops functions
392 STypeId_ptr = STCLASS_PTR | sizeof(void*),
393 // most of the CX class are "object-like" types and use pointers as handles
394 STypeId_string = STCLASS_CX | 0,
395 STypeId_strref = STCLASS_CX | 0,
396 STypeId_object = STCLASS_CX | 1,
397 STypeId_weakref = STCLASS_CX | 2,
398 STypeId_suid = STCLASS_CX | 3, // notable exception
399 STypeId_stvar = STCLASS_CX | 4,
400 STypeId_closure = STCLASS_CX | 5,
401 STypeId_buffer = STCLASS_CX | 6,
402 STypeId_sarray = STCLASS_CX_CONTAINER | 0,
403 STypeId_hashtable = STCLASS_CX_CONTAINER | 1,
404 STypeId_cchain = STCLASS_CX_CONTAINER | 2,
405};
406
419#define stTypeId(name) STypeId_##name
420
421// The actual storage size of the type
422enum STYPE_SIZE {
423 STypeSize_none = 0,
424 // opaque is not really size 0, but filled by by macros later
425 STypeSize_opaque = 0,
426 STypeSize_int8 = sizeof(int8),
427 STypeSize_int16 = sizeof(int16),
428 STypeSize_int32 = sizeof(int32),
429 STypeSize_int64 = sizeof(int64),
430 STypeSize_intptr = sizeof(intptr),
431 STypeSize_uint8 = sizeof(int8),
432 STypeSize_uint16 = sizeof(int16),
433 STypeSize_uint32 = sizeof(int32),
434 STypeSize_uint64 = sizeof(int64),
435 STypeSize_uintptr = sizeof(uintptr),
436 STypeSize_bool = sizeof(_Bool),
437 STypeSize_size = sizeof(size_t),
438 STypeSize_float32 = sizeof(float32),
439 STypeSize_float64 = sizeof(float64),
440 STypeSize_ptr = sizeof(void*),
441 STypeSize_string = sizeof(void*),
442 STypeSize_strref = sizeof(void*),
443 STypeSize_object = sizeof(ObjInst*),
444 STypeSize_weakref = sizeof(ObjInst_WeakRef*),
445 // SUID is special because it's always passed by reference, but stored as the full 16 bytes
446 STypeSize_suid = 16,
447 STypeSize_stvar = sizeof(stvar),
448 STypeSize_sarray = sizeof(sa_ref),
449 STypeSize_hashtable = sizeof(hashtable),
450 STypeSize_closure = sizeof(closure),
451 STypeSize_cchain = sizeof(cchain),
452 STypeSize_buffer = sizeof(Buffer),
453};
454
466#define stTypeSize(name) STypeSize_##name
467
468enum STYPE_FLAGS {
469 STypeFlag_Object = (1 << 0), // "object-like" type -- pointer to managed object
470 STypeFlag_Custom = (1 << 1), // type uses custom ops
471 STypeFlag_PassPtr = (1 << 2), // type is passed by pointer rather than by value,
472 // does not apply to 'handle' style objects
473};
474#define stFlag(name) STypeFlag_##name
475
490#define stHasFlag(st, fname) ((st >> 8) & stFlag(fname))
491
492/*typedef union stype {
493 uint32 spec;
494 struct {
495 uint8 id;
496 uint8 flags;
497 uint16 size;
498 };
499} stype; */
500
507#define stGetId(st) (st & 0xff)
508
515#define stGetFlags(st) ((st >> 8) & 0xff)
516
523#define stGetSize(st) (st >> 16)
524
525#define _stype_mktype(tid, tflags, tsz) ((tid & 0xff) | (tflags & 0xff) << 8 | (tsz & 0xffff) << 16)
526
536// ignore custom flag when comparing types
537_meta_inline bool stEq(stype sta, stype stb)
538{
539 return (sta & ~_stype_mktype(0, STypeFlag_Custom, 0)) ==
540 (stb & ~_stype_mktype(0, STypeFlag_Custom, 0));
541}
542
543enum STYPE_DEFAULT_FLAGS {
544 STypeFlags_none = 0,
545 STypeFlags_opaque = stFlag(PassPtr),
546 STypeFlags_int8 = 0,
547 STypeFlags_int16 = 0,
548 STypeFlags_int32 = 0,
549 STypeFlags_int64 = 0,
550 STypeFlags_intptr = 0,
551 STypeFlags_uint8 = 0,
552 STypeFlags_uint16 = 0,
553 STypeFlags_uint32 = 0,
554 STypeFlags_uint64 = 0,
555 STypeFlags_uintptr = 0,
556 STypeFlags_bool = 0,
557 STypeFlags_size = 0,
558 STypeFlags_float32 = 0,
559 STypeFlags_float64 = 0,
560 STypeFlags_ptr = 0,
561 STypeFlags_string = stFlag(Object),
562 STypeFlags_strref = stFlag(Object),
563 STypeFlags_object = stFlag(Object),
564 STypeFlags_weakref = stFlag(Object),
565 STypeFlags_suid = stFlag(PassPtr),
566 STypeFlags_stvar = stFlag(PassPtr) | stFlag(Object),
567 STypeFlags_sarray = stFlag(Object),
568 STypeFlags_hashtable = stFlag(Object),
569 STypeFlags_closure = stFlag(Object),
570 STypeFlags_cchain = stFlag(Object),
571 STypeFlags_buffer = stFlag(Object),
572};
573
580#define stTypeFlags(name) STypeFlags_##name
581
582#define stTypeInternal(name) _stype_mktype(stTypeId(name), stTypeFlags(name), stTypeSize(name))
583#define stFullTypeInternal(name) stTypeInternal(name), 0
584_meta_inline stype _stype_mkcustom(stype base)
585{
586 base |= _stype_mktype(0, stFlag(Custom), 0);
587 return base;
588}
589
590// Static type checks
591// These types all include the marker as either the first member, or as part of
592// a union that coincides with the first member. Therefore we can take their address
593// and get the address of the parent structure that we already had (essentially a no-op)
594// while checking that they exist, thus verifying the type is correct.
595// Note the magic of the comma operator -- these prevent compilation if something is wrong,
596// but get optimized away entirely and do not emit any code.
597// The use of unused_noeval further improves this by hiding it in a conditional branch that
598// is guaranteed to not be evaluated, preventing any side effects such as function calls or
599// postfix operators.
600// The seemingly redundant (h) && portions of the expression are there solely to suppress
601// warnings from stupid compilers that don't understand it can never actually be dereferenced.
602#define saCheckType(name, h) ((sa_##name*)(unused_noeval((h) && &((h)->is_sarray_##name)), (h)))
603#define saCheck(s) (unused_noeval(&((s)._is_sarray)), (s.a))
604#define saCheckPtr(h) (unused_noeval((h != NULL) && &((h)->_is_sarray)), (h))
605#define htCheck(h) (unused_noeval((h) && &((h)->_is_hashtable)), (h))
606#define htCheckPtr(h) (unused_noeval((h) && (*h) && &((*h)->_is_hashtable)), (h))
607#define objInstCheck(o) (unused_noeval((o) && &((o)->_is_ObjInst)), (o))
608#define objInstCheckPtr(o) (unused_noeval((o != NULL) && (*o) && &((*o)->_is_ObjInst)), (o))
609#define objWeakRefCheck(o) (unused_noeval((o) && &((o)->_is_ObjInst_WeakRef)), (o))
610#define objWeakRefCheckPtr(o) (unused_noeval((o) && (*o) && &((*o)->_is_ObjInst_WeakRef)), (o))
611#define strCheck(s) (unused_noeval((s) && &((s)->_is_string)), (s))
612#define strCheckPtr(s) (unused_noeval((s != NULL) && (*s) && &((*s)->_is_string)), (s))
613#define closureCheck(c) (unused_noeval((c) && &((c)->_is_closure)), (c))
614#define closureCheckPtr(c) (unused_noeval((c != NULL) && (*c) && &((*c)->_is_closure)), (c))
615#define cchainCheck(c) (unused_noeval((c) && &((c)->_is_closure_chain)), (c))
616#define cchainCheckPtr(c) (unused_noeval((c != NULL) && (*c) && &((*c)->_is_closure_chain)), (c))
617#define bufferCheck(c) (unused_noeval((c) && &((c)->_is_buffer)), (c))
618#define bufferCheckPtr(c) (unused_noeval((c != NULL) && (*c) && &((*c)->_is_buffer)), (c))
619
620// most of these are no-ops, but some can do extra type checking
621#define STypeCheck_opaque(type, val) (val)
622#define STypeCheck_int8(type, val) (val)
623#define STypeCheck_int16(type, val) (val)
624#define STypeCheck_int32(type, val) (val)
625#define STypeCheck_int64(type, val) (val)
626#define STypeCheck_intptr(type, val) (val)
627#define STypeCheck_uint8(type, val) (val)
628#define STypeCheck_uint16(type, val) (val)
629#define STypeCheck_uint32(type, val) (val)
630#define STypeCheck_uint64(type, val) (val)
631#define STypeCheck_uintptr(type, val) (val)
632#define STypeCheck_bool(type, val) (val)
633#define STypeCheck_size(type, val) (val)
634#define STypeCheck_float32(type, val) (val)
635#define STypeCheck_float64(type, val) (val)
636#define STypeCheck_ptr(type, val) (val)
637#define STypeCheck_string(type, val) strCheck(val)
638#define STypeCheck_strref(type, val) strCheck(val)
639#define STypeCheck_object(type, val) objInstCheck(val)
640#define STypeCheck_weakref(type, val) objWeakRefCheck(val)
641#define STypeCheck_suid(type, val) (unused_noeval((((val).low), ((val).high))), (val))
642#define STypeCheck_stvar(_type, val) (unused_noeval((((val).data), ((val).type))), (val))
643#define STypeCheck_sarray(type, val) saCheck(val)
644#define STypeCheck_hashtable(type, val) htCheck(val)
645#define STypeCheck_closure(type, val) closureCheck(val)
646#define STypeCheck_cchain(type, val) cchainCheck(val)
647#define STypeCheck_buffer(type, val) bufferCheck(val)
648
669#define stCheck(type, val) STypeCheck_##type(type, val)
670
671#define STypeCheckPtr_gen(type, ptr) (unused_noeval((stTypeDef(type)*)(ptr)), ptr)
672#define STypeCheckPtr_opaque(type, ptr) (ptr)
673#define STypeCheckPtr_int8(type, ptr) (ptr)
674#define STypeCheckPtr_int16(type, ptr) (ptr)
675#define STypeCheckPtr_int32(type, ptr) (ptr)
676#define STypeCheckPtr_int64(type, ptr) (ptr)
677#define STypeCheckPtr_intptr(type, ptr) (ptr)
678#define STypeCheckPtr_uint8(type, ptr) (ptr)
679#define STypeCheckPtr_uint16(type, ptr) (ptr)
680#define STypeCheckPtr_uint32(type, ptr) (ptr)
681#define STypeCheckPtr_uint64(type, ptr) (ptr)
682#define STypeCheckPtr_uintptr(type, ptr) (ptr)
683#define STypeCheckPtr_bool(type, ptr) (ptr)
684#define STypeCheckPtr_size(type, ptr) (ptr)
685#define STypeCheckPtr_float32(type, ptr) (ptr)
686#define STypeCheckPtr_float64(type, ptr) (ptr)
687#define STypeCheckPtr_ptr(type, ptr) (ptr)
688#define STypeCheckPtr_string(type, ptr) strCheckPtr(ptr)
689#define STypeCheckPtr_strref(type, ptr) strCheckPtr(ptr)
690#define STypeCheckPtr_object(type, ptr) objInstCheckPtr(ptr)
691#define STypeCheckPtr_weakref(type, ptr) objWeakRefCheckPtr(ptr)
692#define STypeCheckPtr_suid(type, ptr) (unused_noeval((((ptr)->low), ((ptr)->high))), (ptr))
693#define STypeCheckPtr_stvar(_type, ptr) (unused_noeval((((ptr)->data), ((ptr)->type))), (ptr))
694#define STypeCheckPtr_sarray(type, ptr) saCheckPtr(ptr)
695#define STypeCheckPtr_hashtable(type, ptr) htCheckPtr(ptr)
696#define STypeCheckPtr_closure(type, ptr) closureCheckPtr(ptr)
697#define STypeCheckPtr_cchain(type, ptr) cchainCheckPtr(ptr)
698#define STypeCheckPtr_buffer(type, ptr) bufferCheckPtr(ptr)
699
710#define stCheckPtr(type, ptr) STypeCheckPtr_##type(type, ptr)
711
730// C99 compound literals are lvalues and can force the compiler to create a temporary
731// on the stack if necessary, so that we can pass pointers to arbitrary expressions
732#define stRvalAddr(type, rval) ((stStorageType(type)[1]) { rval })
733
735
736// MEGA PREPROCESSOR HACKS INCOMING
737#define stType_none stTypeInternal(none)
738// this enables the use of opaque(realtype) as type name in functions like saCreate
739#define stType_opaque(realtype) \
740 _stype_mktype(stTypeId(opaque), stTypeFlags(opaque), (uint16)sizeof(realtype))
741#define stType_int8 stTypeInternal(int8)
742#define stType_int16 stTypeInternal(int16)
743#define stType_int32 stTypeInternal(int32)
744#define stType_int64 stTypeInternal(int64)
745#define stType_intptr stTypeInternal(intptr)
746#define stType_uint8 stTypeInternal(uint8)
747#define stType_uint16 stTypeInternal(uint16)
748#define stType_uint32 stTypeInternal(uint32)
749#define stType_uint64 stTypeInternal(uint64)
750#define stType_uintptr stTypeInternal(uintptr)
751#define stType_bool stTypeInternal(bool)
752#define stType_size stTypeInternal(size)
753#define stType_float32 stTypeInternal(float32)
754#define stType_float64 stTypeInternal(float64)
755#define stType_ptr stTypeInternal(ptr)
756#define stType_string stTypeInternal(string)
757#define stType_strref stTypeInternal(strref)
758#define stType_object stTypeInternal(object)
759#define stType_weakref stTypeInternal(weakref)
760#define stType_suid stTypeInternal(suid)
761#define stType_stvar stTypeInternal(stvar)
762#define stType_sarray stTypeInternal(sarray)
763#define stType_hashtable stTypeInternal(hashtable)
764#define stType_closure stTypeInternal(closure)
765#define stType_cchain stTypeInternal(cchain)
766#define stType_buffer stTypeInternal(buffer)
767#define stType_custom(basetype) _stype_mkcustom(stType_##basetype)
768
806
822#define stType(name) stType_##name
823
824#define stFullType_none stFullTypeInternal(none)
825// and the hack for custom(basetype, ops)
826#define stFullType_opaque(realtype) \
827 _stype_mktype(stTypeId(opaque), stTypeFlags(opaque), (uint16)sizeof(realtype)), 0
828#define stFullType_int8 stFullTypeInternal(int8)
829#define stFullType_int16 stFullTypeInternal(int16)
830#define stFullType_int32 stFullTypeInternal(int32)
831#define stFullType_int64 stFullTypeInternal(int64)
832#define stFullType_intptr stFullTypeInternal(intptr)
833#define stFullType_uint8 stFullTypeInternal(uint8)
834#define stFullType_uint16 stFullTypeInternal(uint16)
835#define stFullType_uint32 stFullTypeInternal(uint32)
836#define stFullType_uint64 stFullTypeInternal(uint64)
837#define stFullType_uintptr stFullTypeInternal(uintptr)
838#define stFullType_bool stFullTypeInternal(bool)
839#define stFullType_size stFullTypeInternal(size)
840#define stFullType_float32 stFullTypeInternal(float32)
841#define stFullType_float64 stFullTypeInternal(float64)
842#define stFullType_ptr stFullTypeInternal(ptr)
843#define stFullType_string stFullTypeInternal(string)
844#define stFullType_strref stFullTypeInternal(strref)
845#define stFullType_object stFullTypeInternal(object)
846#define stFullType_weakref stFullTypeInternal(weakref)
847#define stFullType_suid stFullTypeInternal(suid)
848#define stFullType_stvar stFullTypeInternal(stvar)
849#define stFullType_sarray stFullTypeInternal(sarray)
850#define stFullType_hashtable stFullTypeInternal(hashtable)
851#define stFullType_closure stFullTypeInternal(closure)
852#define stFullType_cchain stFullTypeInternal(cchain)
853#define stFullType_buffer stFullTypeInternal(buffer)
854// this will chain evaluate macros for stuff like custom(opaque(realtype), ops)
855// it gets token pasted as _stype_mkcustom(stType_opaque(realtype), ops)
856#define stFullType_custom(basetype, ops) _stype_mkcustom(stType_##basetype), (&ops)
857
876#define stFullType(name) stFullType_##name
877
878// Macros for passing arguments by value
879
880// none ignores the value
881#define STypeArg_none(type, val) ((stgeneric) { 0 })
882// opqaue is a special case that must always be passed by pointer, and
883// the caller must supply an lvalue
884#define STypeArg_opaque(type, val) stgeneric(type, &(val))
885// but everything else gets put into a container
886#define STypeArg_int8(type, val) stgeneric(type, val)
887#define STypeArg_int16(type, val) stgeneric(type, val)
888#define STypeArg_int32(type, val) stgeneric(type, val)
889#define STypeArg_int64(type, val) stgeneric(type, val)
890#define STypeArg_intptr(type, val) stgeneric(type, val)
891#define STypeArg_uint8(type, val) stgeneric(type, val)
892#define STypeArg_uint16(type, val) stgeneric(type, val)
893#define STypeArg_uint32(type, val) stgeneric(type, val)
894#define STypeArg_uint64(type, val) stgeneric(type, val)
895#define STypeArg_uintptr(type, val) stgeneric(type, val)
896#define STypeArg_bool(type, val) stgeneric(type, val)
897#define STypeArg_size(type, val) stgeneric(type, val)
898#define STypeArg_float32(type, val) stgeneric(type, val)
899#define STypeArg_float64(type, val) stgeneric(type, val)
900#define STypeArg_ptr(type, val) stgeneric(type, val)
901#define STypeArg_string(type, val) stgeneric(type, val)
902#define STypeArg_strref(type, val) stgeneric(type, val)
903#define STypeArg_object(type, val) stgeneric(type, objInstBase(val))
904#define STypeArg_weakref(type, val) stgeneric(type, objWeakRefBase(val))
905// SUID and stvar are too big, so make a copy and pass a pointer
906#define STypeArg_suid(type, val) stgeneric_unchecked(type, stRvalAddr(type, stCheck(type, val)))
907#define STypeArg_stvar(type, val) stgeneric_unchecked(type, stRvalAddr(type, stCheck(type, val)))
908#define STypeArg_sarray(type, val) stgensarray(val)
909#define STypeArg_hashtable(type, val) stgeneric(type, val)
910#define STypeArg_closure(type, val) stgeneric(type, val)
911#define STypeArg_cchain(type, val) stgeneric(type, val)
912#define STypeArg_buffer(type, val) stgeneric(type, val)
913
937#define stArg(type, val) STypeArg_##type(type, val)
938
939// And for passing a pointer-to-pointer, mostly for functions that want to
940// consume or reallocate the object
941
942#define STypeArgPtr_none(type, val) NULL
943// opaque is already passed in as a pointer
944#define STypeArgPtr_opaque(type, val) &stgeneric(type, val)
945#define STypeArgPtr_int8(type, val) (stgeneric*)stCheckPtr(type, val)
946#define STypeArgPtr_int16(type, val) (stgeneric*)stCheckPtr(type, val)
947#define STypeArgPtr_int32(type, val) (stgeneric*)stCheckPtr(type, val)
948#define STypeArgPtr_int64(type, val) (stgeneric*)stCheckPtr(type, val)
949#define STypeArgPtr_intptr(type, val) (stgeneric*)stCheckPtr(type, val)
950#define STypeArgPtr_uint8(type, val) (stgeneric*)stCheckPtr(type, val)
951#define STypeArgPtr_uint16(type, val) (stgeneric*)stCheckPtr(type, val)
952#define STypeArgPtr_uint32(type, val) (stgeneric*)stCheckPtr(type, val)
953#define STypeArgPtr_uint64(type, val) (stgeneric*)stCheckPtr(type, val)
954#define STypeArgPtr_uintptr(type, val) (stgeneric*)stCheckPtr(type, val)
955#define STypeArgPtr_bool(type, val) (stgeneric*)stCheckPtr(type, val)
956#define STypeArgPtr_size(type, val) (stgeneric*)stCheckPtr(type, val)
957#define STypeArgPtr_float32(type, val) (stgeneric*)stCheckPtr(type, val)
958#define STypeArgPtr_float64(type, val) (stgeneric*)stCheckPtr(type, val)
959#define STypeArgPtr_ptr(type, val) (stgeneric*)stCheckPtr(type, (void**)(val))
960#define STypeArgPtr_string(type, val) (stgeneric*)stCheckPtr(type, val)
961#define STypeArgPtr_strref(type, val) (stgeneric*)stCheckPtr(type, val)
962#define STypeArgPtr_object(type, val) (stgeneric*)stCheckPtr(type, val)
963#define STypeArgPtr_weakref(type, val) (stgeneric*)stCheckPtr(type, val)
964// same for the other pass-by-pointer cases (SUID, stvar)
965#define STypeArgPtr_suid(type, val) &stgeneric_unchecked(type, stCheckPtr(type, val))
966#define STypeArgPtr_stvar(type, val) &stgeneric_unchecked(type, stCheckPtr(type, val))
967#define STypeArgPtr_sarray(type, val) (stgeneric*)stCheckPtr(type, val)
968#define STypeArgPtr_hashtable(type, val) (stgeneric*)stCheckPtr(type, val)
969#define STypeArgPtr_closure(type, val) (stgeneric*)stCheckPtr(type, val)
970#define STypeArgPtr_cchain(type, val) (stgeneric*)stCheckPtr(type, val)
971#define STypeArgPtr_buffer(type, val) (stgeneric*)stCheckPtr(type, val)
972
990#define stArgPtr(type, val) STypeArgPtr_##type(type, val)
991
992// Macros for type-checked inline metafunctions.
993// These expand to a pair of parameters for type, followed by a pointer.
994
995#define STypeCheckedArg_none(type, val) stTypeInternal(type), stArg(type, val)
996#define STypeCheckedArg_opaque(type, val) stType_opaque(val), stArg(type, val)
997#define STypeCheckedArg_int8(type, val) stTypeInternal(type), stArg(type, val)
998#define STypeCheckedArg_int16(type, val) stTypeInternal(type), stArg(type, val)
999#define STypeCheckedArg_int32(type, val) stTypeInternal(type), stArg(type, val)
1000#define STypeCheckedArg_int64(type, val) stTypeInternal(type), stArg(type, val)
1001#define STypeCheckedArg_intptr(type, val) stTypeInternal(type), stArg(type, val)
1002#define STypeCheckedArg_uint8(type, val) stTypeInternal(type), stArg(type, val)
1003#define STypeCheckedArg_uint16(type, val) stTypeInternal(type), stArg(type, val)
1004#define STypeCheckedArg_uint32(type, val) stTypeInternal(type), stArg(type, val)
1005#define STypeCheckedArg_uint64(type, val) stTypeInternal(type), stArg(type, val)
1006#define STypeCheckedArg_uintptr(type, val) stTypeInternal(type), stArg(type, val)
1007#define STypeCheckedArg_bool(type, val) stTypeInternal(type), stArg(type, val)
1008#define STypeCheckedArg_size(type, val) stTypeInternal(type), stArg(type, val)
1009#define STypeCheckedArg_float32(type, val) stTypeInternal(type), stArg(type, val)
1010#define STypeCheckedArg_float64(type, val) stTypeInternal(type), stArg(type, val)
1011#define STypeCheckedArg_ptr(type, val) stTypeInternal(type), stArg(type, val)
1012#define STypeCheckedArg_string(type, val) stTypeInternal(type), stArg(type, val)
1013#define STypeCheckedArg_strref(type, val) stTypeInternal(type), stArg(type, val)
1014#define STypeCheckedArg_object(type, val) stTypeInternal(type), stArg(type, val)
1015#define STypeCheckedArg_weakref(type, val) stTypeInternal(type), stArg(type, val)
1016#define STypeCheckedArg_suid(type, val) stTypeInternal(type), stArg(type, val)
1017#define STypeCheckedArg_stvar(type, val) stTypeInternal(type), stArg(type, val)
1018#define STypeCheckedArg_sarray(type, val) stTypeInternal(type), stArg(type, val)
1019#define STypeCheckedArg_hashtable(type, val) stTypeInternal(type), stArg(type, val)
1020#define STypeCheckedArg_closure(type, val) stTypeInternal(type), stArg(type, val)
1021#define STypeCheckedArg_cchain(type, val) stTypeInternal(type), stArg(type, val)
1022#define STypeCheckedArg_buffer(type, val) stTypeInternal(type), stArg(type, val)
1023
1044#define stCheckedArg(type, val) STypeCheckedArg_##type(type, val)
1045
1046// Type checking of pointers to types, mostly for functions that want to
1047// consume object-like variables and destroy them
1048
1049#define STypeCheckedPtrArg_none(type, val) stTypeInternal(type), stArgPtr(type, val)
1050// go the opposite direction for opaque since it's already passed in as a pointer
1051#define STypeCheckedPtrArg_opaque(type, val) stType_opaque(*val), stArgPtr(type, val)
1052#define STypeCheckedPtrArg_int8(type, val) stTypeInternal(type), stArgPtr(type, val)
1053#define STypeCheckedPtrArg_int16(type, val) stTypeInternal(type), stArgPtr(type, val)
1054#define STypeCheckedPtrArg_int32(type, val) stTypeInternal(type), stArgPtr(type, val)
1055#define STypeCheckedPtrArg_int64(type, val) stTypeInternal(type), stArgPtr(type, val)
1056#define STypeCheckedPtrArg_intptr(type, val) stTypeInternal(type), stArgPtr(type, val)
1057#define STypeCheckedPtrArg_uint8(type, val) stTypeInternal(type), stArgPtr(type, val)
1058#define STypeCheckedPtrArg_uint16(type, val) stTypeInternal(type), stArgPtr(type, val)
1059#define STypeCheckedPtrArg_uint32(type, val) stTypeInternal(type), stArgPtr(type, val)
1060#define STypeCheckedPtrArg_uint64(type, val) stTypeInternal(type), stArgPtr(type, val)
1061#define STypeCheckedPtrArg_uintptr(type, val) stTypeInternal(type), stArgPtr(type, val)
1062#define STypeCheckedPtrArg_bool(type, val) stTypeInternal(type), stArgPtr(type, val)
1063#define STypeCheckedPtrArg_size(type, val) stTypeInternal(type), stArgPtr(type, val)
1064#define STypeCheckedPtrArg_float32(type, val) stTypeInternal(type), stArgPtr(type, val)
1065#define STypeCheckedPtrArg_float64(type, val) stTypeInternal(type), stArgPtr(type, val)
1066#define STypeCheckedPtrArg_ptr(type, val) stTypeInternal(type), stArgPtr(type, val)
1067#define STypeCheckedPtrArg_string(type, val) stTypeInternal(type), stArgPtr(type, val)
1068#define STypeCheckedPtrArg_strref(type, val) stTypeInternal(type), stArgPtr(type, val)
1069#define STypeCheckedPtrArg_object(type, val) stTypeInternal(type), stArgPtr(type, val)
1070#define STypeCheckedPtrArg_weakref(type, val) stTypeInternal(type), stArgPtr(type, val)
1071#define STypeCheckedPtrArg_suid(type, val) stTypeInternal(type), stArgPtr(type, val)
1072#define STypeCheckedPtrArg_stvar(type, val) stTypeInternal(type), stArgPtr(type, val)
1073#define STypeCheckedPtrArg_sarray(type, val) stTypeInternal(type), stArgPtr(type, val)
1074#define STypeCheckedPtrArg_hashtable(type, val) stTypeInternal(type), stArgPtr(type, val)
1075#define STypeCheckedPtrArg_closure(type, val) stTypeInternal(type), stArgPtr(type, val)
1076#define STypeCheckedPtrArg_cchain(type, val) stTypeInternal(type), stArgPtr(type, val)
1077#define STypeCheckedPtrArg_buffer(type, val) stTypeInternal(type), stArgPtr(type, val)
1078
1100#define stCheckedPtrArg(type, val) STypeCheckedPtrArg_##type(type, val)
1101
1103
1107
1117
1125 ST_Equality = 0x00000002,
1126
1133 ST_Overflow = 0x00000004,
1134
1142 ST_Lossless = 0x00000008,
1143};
1144
1146
1172
1173#define _stCopyDest_Anno_(typvar) _Post_valid_ _When_(stHasFlag(typvar, PassPtr), _Pre_valid_)
1174#define _stCopyDest_Anno_opt_(typvar) _Out_opt_ _When_(stHasFlag(typvar, PassPtr), _Pre_opt_valid_)
1175
1187typedef void (*stDtorFunc)(stype st, _Pre_notnull_ _Post_invalid_ stgeneric* gen, flags_t flags);
1188
1200typedef intptr (*stCmpFunc)(stype st, _In_ stgeneric gen1, _In_ stgeneric gen2, flags_t flags);
1201
1213typedef uint32 (*stHashFunc)(stype st, _In_ stgeneric gen, flags_t flags);
1214
1230typedef void (*stCopyFunc)(stype st, _stCopyDest_Anno_(st) stgeneric* dest, _In_ stgeneric src,
1231 flags_t flags);
1232
1251typedef _Success_(return)
1252_Check_return_ bool (*stConvertFunc)(stype destst, _stCopyDest_Anno_(destst) stgeneric* dest,
1253 stype srcst, _In_ stgeneric src, flags_t flags);
1254
1255extern stDtorFunc _stDefaultDtor[256];
1256extern stCmpFunc _stDefaultCmp[256];
1257extern stHashFunc _stDefaultHash[256];
1258extern stCopyFunc _stDefaultCopy[256];
1259extern stConvertFunc _stDefaultConvert[256];
1260
1261typedef struct STypeOps {
1262 stDtorFunc dtor;
1263 stCmpFunc cmp;
1264 stHashFunc hash;
1265 stCopyFunc copy;
1266 stConvertFunc convert;
1267} STypeOps;
1268
1270
1278
1279_meta_inline stgeneric _stStoredVal(stype st, _In_ const void* storage)
1280{
1281 stgeneric ret;
1282 switch (stGetSize(st)) {
1283 case 1:
1284 ret.st_uint8 = *(uint8*)storage;
1285 break;
1286 case 2:
1287 ret.st_uint16 = *(uint16*)storage;
1288 break;
1289 case 4:
1290 ret.st_uint32 = *(uint32*)storage;
1291 break;
1292 case 8:
1293 ret.st_uint64 = *(uint64*)storage;
1294 break;
1295 default:
1296 devFatalError("Invalid small stype size");
1297 ret.st_uint64 = 0;
1298 }
1299 return ret;
1300}
1301
1319#define stStored(st, storage) \
1320 (stHasFlag(st, PassPtr) ? stgeneric(ptr, (void*)(storage)) : _stStoredVal(st, storage))
1321
1332#define stStoredPtr(st, storage) \
1333 (stHasFlag(st, PassPtr) ? &stgeneric(ptr, ((void*)(storage))) : (stgeneric*)((void*)(storage)))
1334
1345#define stGenPtr(st, gen) (stHasFlag(st, PassPtr) ? (gen).st_ptr : &(gen))
1346
1348
1356
1357// inlining these lets most of it get optimized out and specialized if the type is known at
1358// compile-time
1359
1377#define stDestroy(type, pobj, ...) \
1378 _stDestroy(stFullType(type), stArgPtr(type, pobj), opt_flags(__VA_ARGS__))
1379_meta_inline void _stDestroy(stype st, _In_opt_ STypeOps* ops,
1380 _Pre_notnull_ _Post_invalid_ stgeneric* gen, flags_t flags)
1381{
1382 // ops is mandatory for custom type
1383 devAssert(!stHasFlag(st, Custom) || ops);
1384
1385 if (ops && ops->dtor)
1386 ops->dtor(st, gen, flags);
1387 else if (_stDefaultDtor[stGetId(st)])
1388 _stDefaultDtor[stGetId(st)](st, gen, flags);
1389}
1408#define stCmp(type, obj1, obj2, ...) \
1409 _stCmp(stFullType(type), stArg(type, obj1), stArg(type, obj2), opt_flags(__VA_ARGS__))
1410_meta_inline intptr _stCmp(stype st, _In_opt_ STypeOps* ops, _In_ stgeneric gen1,
1411 _In_ stgeneric gen2, flags_t flags)
1412{
1413 // ops is mandatory for custom type
1414 devAssert(!stHasFlag(st, Custom) || ops);
1415
1416 if (ops && ops->cmp)
1417 return ops->cmp(st, gen1, gen2, flags);
1418
1419 if (_stDefaultCmp[stGetId(st)])
1420 return _stDefaultCmp[stGetId(st)](st, gen1, gen2, flags);
1421
1422 if (!stHasFlag(st, PassPtr))
1423 return memcmp(&gen1, &gen2, stGetSize(st));
1424 else
1425 return memcmp(gen1.st_ptr, gen2.st_ptr, stGetSize(st));
1426}
1427
1445#define stCopy(type, pdest, src, ...) \
1446 _stCopy(stFullType(type), stArgPtr(type, pdest), stArg(type, src), opt_flags(__VA_ARGS__))
1447_meta_inline void _stCopy(stype st, _In_opt_ STypeOps* ops, _stCopyDest_Anno_(st) stgeneric* dest,
1448 _In_ stgeneric src, flags_t flags)
1449{
1450 // ops is mandatory for custom type
1451 devAssert(!stHasFlag(st, Custom) || ops);
1452
1453 stCopyFunc defCopy = _stDefaultCopy[stGetId(st)];
1454
1455 if (ops && ops->copy)
1456 ops->copy(st, dest, src, flags);
1457 else if (defCopy)
1458 defCopy(st, dest, src, flags);
1459 else if (!stHasFlag(st, PassPtr))
1460 memcpy(dest, &src, stGetSize(st));
1461 else
1462 memcpy(dest->st_ptr, src.st_ptr, stGetSize(st));
1463}
1464
1465uint32 stHash_gen(stype st, _In_ stgeneric stgen, flags_t flags);
1466
1481#define stHash(type, obj, ...) _stHash(stFullType(type), stArg(type, obj), opt_flags(__VA_ARGS__))
1482_meta_inline uint32 _stHash(stype st, _In_opt_ STypeOps* ops, _In_ stgeneric gen, flags_t flags)
1483{
1484 // ops is mandatory for custom type
1485 devAssert(!stHasFlag(st, Custom) || ops);
1486
1487 if (ops && ops->hash)
1488 return ops->hash(st, gen, flags);
1489 else if (_stDefaultHash[stGetId(st)])
1490 return _stDefaultHash[stGetId(st)](st, gen, flags);
1491 else
1492 return stHash_gen(st, gen, flags);
1493}
1494
1517#define stConvert(desttype, pdest, srctype, src, ...) \
1518 _stConvert(stType(desttype), \
1519 stArgPtr(desttype, pdest), \
1520 stFullType(srctype), \
1521 stArg(srctype, src), \
1522 opt_flags(__VA_ARGS__))
1523_Success_(return) _Check_return_ _meta_inline bool
1524_stConvert(stype destst, _stCopyDest_Anno_(destst) stgeneric* dest, stype srcst,
1525 _In_opt_ STypeOps* srcops, _In_ stgeneric src, flags_t flags)
1526{
1527 // ops is mandatory for custom type
1528 devAssert(!stHasFlag(srcst, Custom) || srcops);
1529
1530 stConvertFunc defConvert = _stDefaultConvert[stGetId(srcst)];
1531
1532 // The *source* stype is responsible for handling conversions to other types
1533 if (srcops && srcops->convert)
1534 return srcops->convert(destst, dest, srcst, src, flags);
1535 else if (srcst == destst)
1536 return _stCopy(destst, NULL, dest, src, flags), true;
1537 else if (defConvert)
1538 return defConvert(destst, dest, srcst, src, flags);
1539 else
1540 return false; // can't convert it if we don't know how!
1541}
1542
1544
1546
1547CX_C_END
Runtime assertion macros and failure handling.
Compiler and platform detection macros.
struct closure_ref * closure
Opaque handle to a closure.
Definition closure.h:45
#define devFatalError(msg)
Definition assert.h:187
#define devAssert(expr)
Definition assert.h:138
struct hashtable_ref * hashtable
Definition hashtable.h:26
struct str_ref * string
Opaque handle to a string object.
Definition strbase.h:29
const struct str_ref * strref
Borrowed reference to a string.
Definition strbase.h:39
#define stvar(typen, val)
Definition stvar.h:153
STYPE_OPS_FLAGS
Definition stype.h:1110
@ ST_Overflow
Definition stype.h:1133
@ ST_CaseInsensitive
Definition stype.h:1116
@ ST_Equality
Definition stype.h:1125
@ ST_Lossless
Definition stype.h:1142
void(* stDtorFunc)(stype st, stgeneric *gen, flags_t flags)
Definition stype.h:1187
intptr(* stCmpFunc)(stype st, stgeneric gen1, stgeneric gen2, flags_t flags)
Definition stype.h:1200
bool(* stConvertFunc)(stype destst, _stCopyDest_Anno_(destst) stgeneric *dest, stype srcst, stgeneric src, flags_t flags)
Definition stype.h:1252
uint32(* stHashFunc)(stype st, stgeneric gen, flags_t flags)
Definition stype.h:1213
void(* stCopyFunc)(stype st, _stCopyDest_Anno_(st) stgeneric *dest, stgeneric src, flags_t flags)
Definition stype.h:1230
#define stHasFlag(st, fname)
Definition stype.h:490
#define stGetSize(st)
Definition stype.h:523
#define stGetId(st)
Definition stype.h:507
bool stEq(stype sta, stype stb)
Definition stype.h:537
Optional macro argument handling.
Copy-on-write strings with automatic memory management and rope optimization.
128-bit sortable unique identifier
Definition suid.h:47
Macros for suppressing compiler warnings.