Initial commit

This commit is contained in:
Mid
2025-08-31 16:22:38 +03:00
commit 64c21ca43a
62 changed files with 13346 additions and 0 deletions

118
stc/sys/crange.h Normal file
View 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
View 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
View 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
View 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
View 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