Initial commit
This commit is contained in:
118
stc/sys/crange.h
Normal file
118
stc/sys/crange.h
Normal file
@@ -0,0 +1,118 @@
|
||||
/* MIT License
|
||||
*
|
||||
* Copyright (c) 2025 Tyge Løvset
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
/*
|
||||
#include <stdio.h>
|
||||
#include <stc/algorithm.h>
|
||||
|
||||
int main(void)
|
||||
{
|
||||
crange r1 = crange_make(80, 90);
|
||||
for (c_each(i, crange, r1))
|
||||
printf(" %d", *i.ref);
|
||||
puts("");
|
||||
|
||||
c_filter(crange, c_iota(100, INT_MAX, 10), true
|
||||
&& c_flt_skip(25)
|
||||
&& c_flt_take(3)
|
||||
&& printf(" %d", *value)
|
||||
);
|
||||
puts("");
|
||||
}
|
||||
*/
|
||||
// IWYU pragma: private, include "stc/algorithm.h"
|
||||
#ifndef STC_CRANGE_H_INCLUDED
|
||||
#define STC_CRANGE_H_INCLUDED
|
||||
|
||||
#include "../priv/linkage.h"
|
||||
#include "../common.h"
|
||||
|
||||
// crange: isize range -----
|
||||
|
||||
typedef isize crange_value;
|
||||
typedef struct { crange_value start, end, step, value; } crange;
|
||||
typedef struct { crange_value *ref, end, step; } crange_iter;
|
||||
|
||||
STC_INLINE crange crange_make_3(crange_value start, crange_value stop, crange_value step)
|
||||
{ crange r = {start, stop - (step > 0), step}; return r; }
|
||||
|
||||
#define crange_make(...) c_MACRO_OVERLOAD(crange_make, __VA_ARGS__)
|
||||
#define crange_make_1(stop) crange_make_3(0, stop, 1) // NB! arg is stop
|
||||
#define crange_make_2(start, stop) crange_make_3(start, stop, 1)
|
||||
|
||||
STC_INLINE crange_iter crange_begin(crange* self) {
|
||||
self->value = self->start;
|
||||
crange_iter it = {&self->value, self->end, self->step};
|
||||
return it;
|
||||
}
|
||||
|
||||
STC_INLINE void crange_next(crange_iter* it) {
|
||||
if ((it->step > 0) == ((*it->ref += it->step) > it->end))
|
||||
it->ref = NULL;
|
||||
}
|
||||
|
||||
STC_INLINE crange_iter crange_advance(crange_iter it, size_t n) {
|
||||
if ((it.step > 0) == ((*it.ref += it.step*(isize)n) > it.end))
|
||||
it.ref = NULL;
|
||||
return it;
|
||||
}
|
||||
|
||||
// iota: c++-like std::iota, use in iterations on-the-fly -----
|
||||
// Note: c_iota() does not compile with c++, crange does.
|
||||
#define c_iota(...) c_MACRO_OVERLOAD(c_iota, __VA_ARGS__)
|
||||
#define c_iota_1(start) c_iota_3(start, INTPTR_MAX, 1) // NB! arg is start.
|
||||
#define c_iota_2(start, stop) c_iota_3(start, stop, 1)
|
||||
#define c_iota_3(start, stop, step) ((crange[]){crange_make_3(start, stop, step)})[0]
|
||||
|
||||
|
||||
// crange32 -----
|
||||
|
||||
typedef int32_t crange32_value;
|
||||
typedef struct { crange32_value start, end, step, value; } crange32;
|
||||
typedef struct { crange32_value *ref, end, step; } crange32_iter;
|
||||
|
||||
STC_INLINE crange32 crange32_make_3(crange32_value start, crange32_value stop, crange32_value step)
|
||||
{ crange32 r = {start, stop - (step > 0), step}; return r; }
|
||||
|
||||
#define crange32_make(...) c_MACRO_OVERLOAD(crange32_make, __VA_ARGS__)
|
||||
#define crange32_make_1(stop) crange32_make_3(0, stop, 1) // NB! arg is stop
|
||||
#define crange32_make_2(start, stop) crange32_make_3(start, stop, 1)
|
||||
|
||||
STC_INLINE crange32_iter crange32_begin(crange32* self) {
|
||||
self->value = self->start;
|
||||
crange32_iter it = {&self->value, self->end, self->step};
|
||||
return it;
|
||||
}
|
||||
|
||||
STC_INLINE void crange32_next(crange32_iter* it) {
|
||||
if ((it->step > 0) == ((*it->ref += it->step) > it->end))
|
||||
it->ref = NULL;
|
||||
}
|
||||
|
||||
STC_INLINE crange32_iter crange32_advance(crange32_iter it, uint32_t n) {
|
||||
if ((it.step > 0) == ((*it.ref += it.step*(int32_t)n) > it.end))
|
||||
it.ref = NULL;
|
||||
return it;
|
||||
}
|
||||
|
||||
#include "../priv/linkage2.h"
|
||||
#endif // STC_CRANGE_H_INCLUDE
|
||||
185
stc/sys/filter.h
Normal file
185
stc/sys/filter.h
Normal file
@@ -0,0 +1,185 @@
|
||||
/* MIT License
|
||||
*
|
||||
* Copyright (c) 2025 Tyge Løvset
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
/*
|
||||
#include <stdio.h>
|
||||
#define T Vec, int
|
||||
#include <stc/cstack.h>
|
||||
#include <stc/algorithm.h>
|
||||
|
||||
int main(void)
|
||||
{
|
||||
Vec vec = c_make(Vec, {1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 9, 10, 11, 12, 5});
|
||||
|
||||
c_filter(Vec, vec, true
|
||||
&& c_flt_skipwhile(*value < 3) // skip leading values < 3
|
||||
&& (*value & 1) == 1 // then use odd values only
|
||||
&& c_flt_map(*value * 2) // multiply by 2
|
||||
&& c_flt_takewhile(*value < 20) // stop if mapped *value >= 20
|
||||
&& printf(" %d", *value) // print value
|
||||
);
|
||||
// 6 10 14 2 6 18
|
||||
puts("");
|
||||
Vec_drop(&vec);
|
||||
}
|
||||
*/
|
||||
// IWYU pragma: private, include "stc/algorithm.h"
|
||||
#ifndef STC_FILTER_H_INCLUDED
|
||||
#define STC_FILTER_H_INCLUDED
|
||||
|
||||
#include "../common.h"
|
||||
|
||||
// ------- c_filter --------
|
||||
#define c_flt_take(n) _flt_take(&fltbase, n)
|
||||
#define c_flt_skip(n) (c_flt_counter() > (n))
|
||||
#define c_flt_takewhile(pred) _flt_takewhile(&fltbase, pred)
|
||||
#define c_flt_skipwhile(pred) (fltbase.sb[fltbase.sb_top++] |= !(pred))
|
||||
#define c_flt_counter() (++fltbase.sn[++fltbase.sn_top])
|
||||
#define c_flt_getcount() (fltbase.sn[fltbase.sn_top])
|
||||
#define c_flt_map(expr) (_mapped = (expr), value = &_mapped)
|
||||
#define c_flt_src _it.ref
|
||||
|
||||
#define c_filter(C, cnt, pred) \
|
||||
_c_filter(C, C##_begin(&cnt), _, pred)
|
||||
|
||||
#define c_filter_from(C, start, pred) \
|
||||
_c_filter(C, start, _, pred)
|
||||
|
||||
#define c_filter_reverse(C, cnt, pred) \
|
||||
_c_filter(C, C##_rbegin(&cnt), _r, pred)
|
||||
|
||||
#define c_filter_reverse_from(C, start, pred) \
|
||||
_c_filter(C, start, _r, pred)
|
||||
|
||||
#define _c_filter(C, start, rev, pred) do { \
|
||||
struct _flt_base fltbase = {0}; \
|
||||
C##_iter _it = start; \
|
||||
C##_value *value = _it.ref, _mapped = {0}; \
|
||||
for ((void)_mapped ; !fltbase.done & (_it.ref != NULL) ; \
|
||||
C##rev##next(&_it), value = _it.ref, fltbase.sn_top=0, fltbase.sb_top=0) \
|
||||
(void)(pred); \
|
||||
} while (0)
|
||||
|
||||
// ------- c_filter_zip --------
|
||||
#define c_filter_zip(...) c_MACRO_OVERLOAD(c_filter_zip, __VA_ARGS__)
|
||||
#define c_filter_zip_4(C, cnt1, cnt2, pred) \
|
||||
c_filter_zip_5(C, cnt1, C, cnt2, pred)
|
||||
#define c_filter_zip_5(C1, cnt1, C2, cnt2, pred) \
|
||||
_c_filter_zip(C1, C1##_begin(&cnt1), C2, C2##_begin(&cnt2), _, pred)
|
||||
|
||||
#define c_filter_reverse_zip(...) c_MACRO_OVERLOAD(c_filter_reverse_zip, __VA_ARGS__)
|
||||
#define c_filter_reverse_zip_4(C, cnt1, cnt2, pred) \
|
||||
c_filter_reverse_zip_5(C, cnt1, C, cnt2, pred)
|
||||
#define c_filter_reverse_zip_5(C1, cnt1, C2, cnt2, pred) \
|
||||
_c_filter_zip(C1, C1##_rbegin(&cnt1), C2, C2##_rbegin(&cnt2), _r, pred)
|
||||
|
||||
#define c_filter_pairwise(C, cnt, pred) \
|
||||
_c_filter_zip(C, C##_begin(&cnt), C, C##_advance(_it1, 1), _, pred)
|
||||
|
||||
#define c_flt_map1(expr) (_mapped1 = (expr), value1 = &_mapped1)
|
||||
#define c_flt_map2(expr) (_mapped2 = (expr), value2 = &_mapped2)
|
||||
#define c_flt_src1 _it1.ref
|
||||
#define c_flt_src2 _it2.ref
|
||||
|
||||
#define _c_filter_zip(C1, start1, C2, start2, rev, pred) do { \
|
||||
struct _flt_base fltbase = {0}; \
|
||||
C1##_iter _it1 = start1; \
|
||||
C2##_iter _it2 = start2; \
|
||||
C1##_value* value1 = _it1.ref, _mapped1; (void)_mapped1; \
|
||||
C2##_value* value2 = _it2.ref, _mapped2; (void)_mapped2; \
|
||||
for (; !fltbase.done & (_it1.ref != NULL) & (_it2.ref != NULL); \
|
||||
C1##rev##next(&_it1), value1 = _it1.ref, C2##rev##next(&_it2), value2 = _it2.ref, \
|
||||
fltbase.sn_top=0, fltbase.sb_top=0) \
|
||||
(void)(pred); \
|
||||
} while (0)
|
||||
|
||||
// ------- c_ffilter --------
|
||||
// c_ffilter allows to execute imperative statements for each element
|
||||
// in a for-loop, e.g., calling nested generic statements instead
|
||||
// of defining a function/expression for it:
|
||||
/*
|
||||
Vec vec = ..., vec2 = ...;
|
||||
for (c_ffilter(i, Vec, vec, true
|
||||
&& c_fflt_skipwhile(i, *i.ref < 3) // skip leading values < 3
|
||||
&& (*i.ref & 1) == 1 // then use odd values only
|
||||
&& c_fflt_map(i, *i.ref * 2) // multiply by 2
|
||||
&& c_fflt_takewhile(i, *i.ref < 20) // stop if mapped *i.ref >= 20
|
||||
)){
|
||||
c_eraseremove_if(Vec, &vec2, *value == *i.ref);
|
||||
}
|
||||
*/
|
||||
#define c_fflt_take(i, n) _flt_take(&i.base, n)
|
||||
#define c_fflt_skip(i, n) (c_fflt_counter(i) > (n))
|
||||
#define c_fflt_takewhile(i, pred) _flt_takewhile(&i.base, pred)
|
||||
#define c_fflt_skipwhile(i, pred) (i.base.sb[i.base.sb_top++] |= !(pred))
|
||||
#define c_fflt_counter(i) (++i.base.sn[++i.base.sn_top])
|
||||
#define c_fflt_getcount(i) (i.base.sn[i.base.sn_top])
|
||||
#define c_fflt_map(i, expr) (i.mapped = (expr), i.ref = &i.mapped)
|
||||
#define c_fflt_src(i) i.iter.ref
|
||||
|
||||
#define c_forfilter(...) for (c_ffilter(__VA_ARGS__))
|
||||
#define c_forfilter_from(...) for (c_ffilter_from(__VA_ARGS__))
|
||||
#define c_forfilter_reverse(...) for (c_ffilter_reverse(__VA_ARGS__))
|
||||
#define c_forfilter_reverse_from(...) for (c_ffilter_reverse_from(__VA_ARGS__))
|
||||
|
||||
#define c_ffilter(i, C, cnt, pred) \
|
||||
_c_ffilter(i, C, C##_begin(&cnt), _, pred)
|
||||
|
||||
#define c_ffilter_from(i, C, start, pred) \
|
||||
_c_ffilter(i, C, start, _, pred)
|
||||
|
||||
#define c_ffilter_reverse(i, C, cnt,pred) \
|
||||
_c_ffilter(i, C, C##_rbegin(&cnt), _r, pred)
|
||||
|
||||
#define c_ffilter_reverse_from(i, C, start, pred) \
|
||||
_c_ffilter(i, C, start, _r, pred)
|
||||
|
||||
#define _c_ffilter(i, C, start, rev, pred) \
|
||||
struct {C##_iter iter; C##_value *ref, mapped; struct _flt_base base;} \
|
||||
i = {.iter=start, .ref=i.iter.ref} ; !i.base.done & (i.iter.ref != NULL) ; \
|
||||
C##rev##next(&i.iter), i.ref = i.iter.ref, i.base.sn_top=0, i.base.sb_top=0) \
|
||||
if (!(pred)) ; else if (1
|
||||
|
||||
// ------------------------ private -------------------------
|
||||
#ifndef c_NFILTERS
|
||||
#define c_NFILTERS 20
|
||||
#endif
|
||||
|
||||
struct _flt_base {
|
||||
uint8_t sn_top, sb_top;
|
||||
bool done, sb[c_NFILTERS];
|
||||
uint32_t sn[c_NFILTERS];
|
||||
};
|
||||
|
||||
static inline bool _flt_take(struct _flt_base* base, uint32_t n) {
|
||||
uint32_t k = ++base->sn[++base->sn_top];
|
||||
base->done |= (k >= n);
|
||||
return n > 0;
|
||||
}
|
||||
|
||||
static inline bool _flt_takewhile(struct _flt_base* base, bool pred) {
|
||||
bool skip = (base->sb[base->sb_top++] |= !pred);
|
||||
base->done |= skip;
|
||||
return !skip;
|
||||
}
|
||||
|
||||
#endif // STC_FILTER_H_INCLUDED
|
||||
5
stc/sys/finalize.h
Normal file
5
stc/sys/finalize.h
Normal file
@@ -0,0 +1,5 @@
|
||||
#ifndef i_extend
|
||||
#include "../priv/linkage2.h"
|
||||
#include "../priv/template2.h"
|
||||
#endif
|
||||
#undef i_extend
|
||||
171
stc/sys/sumtype.h
Normal file
171
stc/sys/sumtype.h
Normal file
@@ -0,0 +1,171 @@
|
||||
/* MIT License
|
||||
*
|
||||
* Copyright (c) 2025 Tyge Løvset
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
/*
|
||||
// https://stackoverflow.com/questions/70935435/how-to-create-variants-in-rust
|
||||
#include <stdio.h>
|
||||
#include <stc/cstr.h>
|
||||
#include <stc/algorithm.h>
|
||||
|
||||
c_sumtype (Action,
|
||||
(ActionSpeak, cstr),
|
||||
(ActionQuit, bool),
|
||||
(ActionRunFunc, struct {
|
||||
int32_t (*func)(int32_t, int32_t);
|
||||
int32_t v1, v2;
|
||||
})
|
||||
);
|
||||
|
||||
void Action_drop(Action* self) {
|
||||
if (c_is(self, ActionSpeak, s))
|
||||
cstr_drop(s);
|
||||
}
|
||||
|
||||
void action(Action* action) {
|
||||
c_when (action) {
|
||||
c_is(ActionSpeak, s) {
|
||||
printf("Asked to speak: %s\n", cstr_str(s));
|
||||
}
|
||||
c_is(ActionQuit) {
|
||||
printf("Asked to quit!\n");
|
||||
}
|
||||
c_is(ActionRunFunc, r) {
|
||||
int32_t res = r->func(r->v1, r->v2);
|
||||
printf("v1: %d, v2: %d, res: %d\n", r->v1, r->v2, res);
|
||||
}
|
||||
c_otherwise assert(!"no match");
|
||||
}
|
||||
}
|
||||
|
||||
int32_t add(int32_t a, int32_t b) {
|
||||
return a + b;
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
Action act1 = c_variant(ActionSpeak, cstr_from("Hello"));
|
||||
Action act2 = c_variant(ActionQuit, 1);
|
||||
Action act3 = c_variant(ActionRunFunc, {add, 5, 6});
|
||||
|
||||
action(&act1);
|
||||
action(&act2);
|
||||
action(&act3);
|
||||
|
||||
c_drop(Action, &act1, &act2, &act3);
|
||||
}
|
||||
*/
|
||||
#ifndef STC_SUMTYPE_H_INCLUDED
|
||||
#define STC_SUMTYPE_H_INCLUDED
|
||||
|
||||
#include "../common.h"
|
||||
|
||||
#define _c_EMPTY()
|
||||
#define _c_LOOP_INDIRECTION() c_LOOP
|
||||
#define _c_LOOP_END_1 ,_c_LOOP1
|
||||
#define _c_LOOP0(f,T,x,...) f c_EXPAND((T, c_EXPAND x)) _c_LOOP_INDIRECTION _c_EMPTY()()(f,T,__VA_ARGS__)
|
||||
#define _c_LOOP1(...)
|
||||
#define _c_CHECK(x,...) c_TUPLE_AT_1(__VA_ARGS__,x,)
|
||||
#define _c_E0(...) __VA_ARGS__
|
||||
#define _c_E1(...) _c_E0(_c_E0(_c_E0(_c_E0(_c_E0(_c_E0(__VA_ARGS__))))))
|
||||
#define _c_E2(...) _c_E1(_c_E1(_c_E1(_c_E1(_c_E1(_c_E1(__VA_ARGS__))))))
|
||||
#define c_EVAL(...) _c_E2(_c_E2(_c_E2(__VA_ARGS__))) // currently supports up to 130 variants
|
||||
#define c_LOOP(f,T,x,...) _c_CHECK(_c_LOOP0, c_JOIN(_c_LOOP_END_, c_NUMARGS(c_EXPAND x)))(f,T,x,__VA_ARGS__)
|
||||
|
||||
|
||||
#define _c_enum_1(x,...) (x=__LINE__*1000, __VA_ARGS__)
|
||||
#define _c_vartuple_tag(T, Tag, ...) Tag,
|
||||
#define _c_vartuple_type(T, Tag, ...) typedef __VA_ARGS__ Tag##_type; typedef T Tag##_sumtype;
|
||||
#define _c_vartuple_var(T, Tag, ...) struct { enum enum_##T tag; Tag##_type get; } Tag;
|
||||
|
||||
#define c_sumtype(T, ...) \
|
||||
typedef union T T; \
|
||||
enum enum_##T { c_EVAL(c_LOOP(_c_vartuple_tag, T, _c_enum_1 __VA_ARGS__, (0),)) }; \
|
||||
c_EVAL(c_LOOP(_c_vartuple_type, T, __VA_ARGS__, (0),)) \
|
||||
union T { \
|
||||
struct { enum enum_##T tag; } _any_; \
|
||||
c_EVAL(c_LOOP(_c_vartuple_var, T, __VA_ARGS__, (0),)) \
|
||||
}
|
||||
|
||||
#if defined STC_HAS_TYPEOF && STC_HAS_TYPEOF
|
||||
#define c_when(varptr) \
|
||||
for (__typeof__(varptr) _vp1 = (varptr); _vp1; _vp1 = NULL) \
|
||||
switch (_vp1->_any_.tag)
|
||||
|
||||
#define c_is_2(Tag, x) \
|
||||
break; case Tag: \
|
||||
for (__typeof__(_vp1->Tag.get)* x = &_vp1->Tag.get; x; x = NULL)
|
||||
|
||||
#define c_is_3(varptr, Tag, x) \
|
||||
false) ; else for (__typeof__(varptr) _vp2 = (varptr); _vp2; _vp2 = NULL) \
|
||||
if (c_is_variant(_vp2, Tag)) \
|
||||
for (__typeof__(_vp2->Tag.get) *x = &_vp2->Tag.get; x; x = NULL
|
||||
#else
|
||||
typedef union { struct { int tag; } _any_; } _c_any_variant;
|
||||
#define c_when(varptr) \
|
||||
for (_c_any_variant* _vp1 = (_c_any_variant *)(varptr); \
|
||||
_vp1; _vp1 = NULL, (void)sizeof((varptr)->_any_.tag)) \
|
||||
switch (_vp1->_any_.tag)
|
||||
|
||||
#define c_is_2(Tag, x) \
|
||||
break; case Tag: \
|
||||
for (Tag##_type *x = &((Tag##_sumtype *)_vp1)->Tag.get; x; x = NULL)
|
||||
|
||||
#define c_is_3(varptr, Tag, x) \
|
||||
false) ; else for (Tag##_sumtype* _vp2 = c_const_cast(Tag##_sumtype*, varptr); _vp2; _vp2 = NULL) \
|
||||
if (c_is_variant(_vp2, Tag)) \
|
||||
for (Tag##_type *x = &_vp2->Tag.get; x; x = NULL
|
||||
#endif
|
||||
|
||||
// Handling multiple tags with different payloads:
|
||||
#define c_is(...) c_MACRO_OVERLOAD(c_is, __VA_ARGS__)
|
||||
#define c_is_1(Tag) \
|
||||
break; case Tag:
|
||||
|
||||
#define c_or_is(Tag) \
|
||||
; case Tag:
|
||||
|
||||
// Type checked multiple tags with same payload:
|
||||
#define c_is_same(...) c_MACRO_OVERLOAD(c_is_same, __VA_ARGS__)
|
||||
#define _c_chk(Tag1, Tag2) \
|
||||
case 1 ? Tag1 : sizeof((Tag1##_type*)0 == (Tag2##_type*)0):
|
||||
#define c_is_same_2(Tag1, Tag2) \
|
||||
break; _c_chk(Tag1, Tag2) case Tag2:
|
||||
#define c_is_same_3(Tag1, Tag2, Tag3) \
|
||||
break; _c_chk(Tag1, Tag2) _c_chk(Tag2, Tag3) case Tag3:
|
||||
#define c_is_same_4(Tag1, Tag2, Tag3, Tag4) \
|
||||
break; _c_chk(Tag1, Tag2) _c_chk(Tag2, Tag3) _c_chk(Tag3, Tag4) case Tag4:
|
||||
|
||||
#define c_otherwise \
|
||||
break; default:
|
||||
|
||||
#define c_variant(Tag, ...) \
|
||||
(c_literal(Tag##_sumtype){.Tag={.tag=Tag, .get=__VA_ARGS__}})
|
||||
|
||||
#define c_is_variant(varptr, Tag) \
|
||||
((varptr)->Tag.tag == Tag)
|
||||
|
||||
#define c_get_if(varptr, Tag) \
|
||||
(c_is_variant(varptr, Tag) ? &(varptr)->Tag.get : NULL)
|
||||
|
||||
#define c_variant_index(varptr) \
|
||||
((int)(varptr)->_any_.tag)
|
||||
|
||||
#endif // STC_SUMTYPE_H_INCLUDED
|
||||
188
stc/sys/utility.h
Normal file
188
stc/sys/utility.h
Normal file
@@ -0,0 +1,188 @@
|
||||
/* MIT License
|
||||
*
|
||||
* Copyright (c) 2025 Tyge Løvset
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
// IWYU pragma: private, include "stc/algorithm.h"
|
||||
#ifndef STC_UTILITY_H_INCLUDED
|
||||
#define STC_UTILITY_H_INCLUDED
|
||||
|
||||
// --------------------------------
|
||||
// c_find_if, c_find_reverse_if
|
||||
// --------------------------------
|
||||
|
||||
#define c_find_if(...) c_MACRO_OVERLOAD(c_find_if, __VA_ARGS__)
|
||||
#define c_find_if_4(C, cnt, outit_ptr, pred) \
|
||||
_c_find(C, C##_begin(&cnt), NULL, _, outit_ptr, pred)
|
||||
|
||||
#define c_find_if_5(C, start, finish, outit_ptr, pred) \
|
||||
_c_find(C, start, (finish).ref, _, outit_ptr, pred)
|
||||
|
||||
#define c_find_reverse_if(...) c_MACRO_OVERLOAD(c_find_reverse_if, __VA_ARGS__)
|
||||
#define c_find_reverse_if_4(C, cnt, outit_ptr, pred) \
|
||||
_c_find(C, C##_rbegin(&cnt), NULL, _r, outit_ptr, pred)
|
||||
|
||||
#define c_find_reverse_if_5(C, rstart, rfinish, outit_ptr, pred) \
|
||||
_c_find(C, rstart, (rfinish).ref, _r, outit_ptr, pred)
|
||||
|
||||
// private
|
||||
#define _c_find(C, start, endref, rev, outit_ptr, pred) do { \
|
||||
C##_iter* _out = outit_ptr; \
|
||||
const C##_value *value, *_endref = endref; \
|
||||
for (*_out = start; (value = _out->ref) != _endref; C##rev##next(_out)) \
|
||||
if (pred) goto c_JOIN(findif_, __LINE__); \
|
||||
_out->ref = NULL; c_JOIN(findif_, __LINE__):; \
|
||||
} while (0)
|
||||
|
||||
// --------------------------------
|
||||
// c_reverse
|
||||
// --------------------------------
|
||||
|
||||
#define c_reverse_array(array, n) do { \
|
||||
typedef struct { char d[sizeof 0[array]]; } _etype; \
|
||||
_etype* _arr = (_etype *)(array); \
|
||||
for (isize _i = 0, _j = (n) - 1; _i < _j; ++_i, --_j) \
|
||||
c_swap(_arr + _i, _arr + _j); \
|
||||
} while (0)
|
||||
|
||||
// Compiles with vec, stack, and deque, and cspan container types:
|
||||
#define c_reverse(CntType, self) do { \
|
||||
CntType* _self = self; \
|
||||
for (isize _i = 0, _j = CntType##_size(_self) - 1; _i < _j; ++_i, --_j) \
|
||||
c_swap(CntType##_at_mut(_self, _i), CntType##_at_mut(_self, _j)); \
|
||||
} while (0)
|
||||
|
||||
// --------------------------------
|
||||
// c_erase_if
|
||||
// --------------------------------
|
||||
|
||||
// Use with: list, hashmap, hashset, sortedmap, sortedset:
|
||||
#define c_erase_if(C, cnt_ptr, pred) do { \
|
||||
C* _cnt = cnt_ptr; \
|
||||
const C##_value* value; \
|
||||
for (C##_iter _it = C##_begin(_cnt); (value = _it.ref); ) { \
|
||||
if (pred) _it = C##_erase_at(_cnt, _it); \
|
||||
else C##_next(&_it); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
// --------------------------------
|
||||
// c_eraseremove_if
|
||||
// --------------------------------
|
||||
|
||||
// Use with: stack, vec, deque, queue:
|
||||
#define c_eraseremove_if(C, cnt_ptr, pred) do { \
|
||||
C* _cnt = cnt_ptr; \
|
||||
isize _n = 0; \
|
||||
const C##_value* value; \
|
||||
C##_iter _i, _it = C##_begin(_cnt); \
|
||||
while ((value = _it.ref) && !(pred)) \
|
||||
C##_next(&_it); \
|
||||
for (_i = _it; (value = _it.ref); C##_next(&_it)) { \
|
||||
if (pred) C##_value_drop(_cnt, _it.ref), ++_n; \
|
||||
else *_i.ref = *_it.ref, C##_next(&_i); \
|
||||
} \
|
||||
C##_adjust_end_(_cnt, -_n); \
|
||||
} while (0)
|
||||
|
||||
// --------------------------------
|
||||
// c_copy_to, c_copy_if
|
||||
// --------------------------------
|
||||
|
||||
#define c_copy_to(...) c_MACRO_OVERLOAD(c_copy_to, __VA_ARGS__)
|
||||
#define c_copy_to_3(C, outcnt_ptr, cnt) \
|
||||
_c_copy_if(C, outcnt_ptr, _, C, cnt, true)
|
||||
|
||||
#define c_copy_to_4(C_out, outcnt_ptr, C, cnt) \
|
||||
_c_copy_if(C_out, outcnt_ptr, _, C, cnt, true)
|
||||
|
||||
#define c_copy_if(...) c_MACRO_OVERLOAD(c_copy_if, __VA_ARGS__)
|
||||
#define c_copy_if_4(C, outcnt_ptr, cnt, pred) \
|
||||
_c_copy_if(C, outcnt_ptr, _, C, cnt, pred)
|
||||
|
||||
#define c_copy_if_5(C_out, outcnt_ptr, C, cnt, pred) \
|
||||
_c_copy_if(C_out, outcnt_ptr, _, C, cnt, pred)
|
||||
|
||||
// private
|
||||
#define _c_copy_if(C_out, outcnt_ptr, rev, C, cnt, pred) do { \
|
||||
C_out *_out = outcnt_ptr; \
|
||||
C _cnt = cnt; \
|
||||
const C##_value* value; \
|
||||
for (C##_iter _it = C##rev##begin(&_cnt); (value = _it.ref); C##rev##next(&_it)) \
|
||||
if (pred) C_out##_push(_out, C_out##_value_clone(_out, *_it.ref)); \
|
||||
} while (0)
|
||||
|
||||
// --------------------------------
|
||||
// c_all_of, c_any_of, c_none_of
|
||||
// --------------------------------
|
||||
|
||||
#define c_all_of(C, cnt, outbool_ptr, pred) do { \
|
||||
C##_iter _it; \
|
||||
c_find_if_4(C, cnt, &_it, !(pred)); \
|
||||
*(outbool_ptr) = _it.ref == NULL; \
|
||||
} while (0)
|
||||
|
||||
#define c_any_of(C, cnt, outbool_ptr, pred) do { \
|
||||
C##_iter _it; \
|
||||
c_find_if_4(C, cnt, &_it, pred); \
|
||||
*(outbool_ptr) = _it.ref != NULL; \
|
||||
} while (0)
|
||||
|
||||
#define c_none_of(C, cnt, outbool_ptr, pred) do { \
|
||||
C##_iter _it; \
|
||||
c_find_if_4(C, cnt, &_it, pred); \
|
||||
*(outbool_ptr) = _it.ref == NULL; \
|
||||
} while (0)
|
||||
|
||||
// --------------------------------
|
||||
// c_min, c_max, c_min_n, c_max_n
|
||||
// --------------------------------
|
||||
#define _c_minmax_call(fn, T, ...) \
|
||||
fn(c_make_array(T, {__VA_ARGS__}), c_sizeof((T[]){__VA_ARGS__})/c_sizeof(T))
|
||||
|
||||
#define c_min(...) _c_minmax_call(c_min_n, isize, __VA_ARGS__)
|
||||
#define c_umin(...) _c_minmax_call(c_umin_n, size_t, __VA_ARGS__)
|
||||
#define c_min32(...) _c_minmax_call(c_min32_n, int32_t, __VA_ARGS__)
|
||||
#define c_fmin(...) _c_minmax_call(c_fmin_n, float, __VA_ARGS__)
|
||||
#define c_dmin(...) _c_minmax_call(c_dmin_n, double, __VA_ARGS__)
|
||||
#define c_max(...) _c_minmax_call(c_max_n, isize, __VA_ARGS__)
|
||||
#define c_umax(...) _c_minmax_call(c_umax_n, size_t, __VA_ARGS__)
|
||||
#define c_max32(...) _c_minmax_call(c_max32_n, int32_t, __VA_ARGS__)
|
||||
#define c_fmax(...) _c_minmax_call(c_fmax_n, float, __VA_ARGS__)
|
||||
#define c_dmax(...) _c_minmax_call(c_dmax_n, double, __VA_ARGS__)
|
||||
|
||||
#define _c_minmax_def(fn, T, opr) \
|
||||
static inline T fn(const T a[], isize n) { \
|
||||
T x = a[0]; \
|
||||
for (isize i = 1; i < n; ++i) if (a[i] opr x) x = a[i]; \
|
||||
return x; \
|
||||
}
|
||||
_c_minmax_def(c_min32_n, int32_t, <)
|
||||
_c_minmax_def(c_min_n, isize, <)
|
||||
_c_minmax_def(c_umin_n, size_t, <)
|
||||
_c_minmax_def(c_fmin_n, float, <)
|
||||
_c_minmax_def(c_dmin_n, double, <)
|
||||
_c_minmax_def(c_max32_n, int32_t, >)
|
||||
_c_minmax_def(c_max_n, isize, >)
|
||||
_c_minmax_def(c_umax_n, size_t, >)
|
||||
_c_minmax_def(c_fmax_n, float, >)
|
||||
_c_minmax_def(c_dmax_n, double, >)
|
||||
|
||||
#endif // STC_UTILITY_H_INCLUDED
|
||||
Reference in New Issue
Block a user