diff options
Diffstat (limited to 'include/stc')
| -rw-r--r-- | include/stc/algo/crange.h | 13 | ||||
| -rw-r--r-- | include/stc/algo/filter.h | 16 | ||||
| -rw-r--r-- | include/stc/algo/sort.h | 2 | ||||
| -rw-r--r-- | include/stc/algorithm.h (renamed from include/stc/calgo.h) | 1 | ||||
| -rw-r--r-- | include/stc/ccommon.h | 6 | ||||
| -rw-r--r-- | include/stc/cdeq.h | 19 | ||||
| -rw-r--r-- | include/stc/coroutine.h (renamed from include/stc/algo/coroutine.h) | 100 | ||||
| -rw-r--r-- | include/stc/cqueue.h | 206 | ||||
| -rw-r--r-- | include/stc/crand.h | 43 | ||||
| -rw-r--r-- | include/stc/cspan.h | 12 | ||||
| -rw-r--r-- | include/stc/cstr.h | 34 | ||||
| -rw-r--r-- | include/stc/priv/cqueue_hdr.h | 117 | ||||
| -rw-r--r-- | include/stc/priv/cqueue_imp.h | 129 | ||||
| -rw-r--r-- | include/stc/priv/template.h | 8 | ||||
| -rw-r--r-- | include/stc/priv/template2.h | 2 |
15 files changed, 395 insertions, 313 deletions
diff --git a/include/stc/algo/crange.h b/include/stc/algo/crange.h index 03162a2d..faeda162 100644 --- a/include/stc/algo/crange.h +++ b/include/stc/algo/crange.h @@ -27,14 +27,14 @@ int main(void) { - crange r1 = crange_make(80, 90); + crange r1 = crange_init(80, 90); c_foreach (i, crange, r1) printf(" %lld", *i.ref); puts(""); // use a temporary crange object. int a = 100, b = INT32_MAX; - crange r2 = crange_make(a, b, 8); + crange r2 = crange_init(a, b, 8); c_forfilter (i, crange, r2, c_flt_skip(i, 10) && c_flt_take(i, 3)) @@ -51,11 +51,12 @@ typedef long long crange_value; typedef struct { crange_value start, end, step, value; } crange; typedef struct { crange_value *ref, end, step; } crange_iter; -#define crange_make(...) c_MACRO_OVERLOAD(crange_make, __VA_ARGS__) -#define crange_make_1(stop) crange_make_3(0, stop, 1) -#define crange_make_2(start, stop) crange_make_3(start, stop, 1) +#define crange_make crange_init // [deprecated] +#define crange_init(...) c_MACRO_OVERLOAD(crange_init, __VA_ARGS__) +#define crange_init_1(stop) crange_init_3(0, stop, 1) +#define crange_init_2(start, stop) crange_init_3(start, stop, 1) -STC_INLINE crange crange_make_3(crange_value start, crange_value stop, crange_value step) +STC_INLINE crange crange_init_3(crange_value start, crange_value stop, crange_value step) { crange r = {start, stop - (step > 0), step}; return r; } STC_INLINE crange_iter crange_begin(crange* self) diff --git a/include/stc/algo/filter.h b/include/stc/algo/filter.h index 4a227927..1a62c3e1 100644 --- a/include/stc/algo/filter.h +++ b/include/stc/algo/filter.h @@ -85,6 +85,21 @@ int main(void) if (it.ref == _endref) it.ref = NULL; \ } while (0) +#define c_all_of(boolptr, it, C, cnt, pred) do { \ + C##_iter it; \ + c_find_if_4(it, C, cnt, !(pred)); \ + *(boolptr) = it.ref == NULL; \ +} while (0) +#define c_any_of(boolptr, it, C, cnt, pred) do { \ + C##_iter it; \ + c_find_if_4(it, C, cnt, pred); \ + *(boolptr) = it.ref != NULL; \ +} while (0) +#define c_none_of(boolptr, it, C, cnt, pred) do { \ + C##_iter it; \ + c_find_if_4(it, C, cnt, pred); \ + *(boolptr) = it.ref == NULL; \ +} while (0) // Use with: clist, cmap, cset, csmap, csset: #define c_erase_if(it, C, cnt, pred) do { \ @@ -95,7 +110,6 @@ int main(void) } \ } while (0) - // Use with: cstack, cvec, cdeq, cqueue: #define c_eraseremove_if(it, C, cnt, pred) do { \ C* _cnt = &cnt; \ diff --git a/include/stc/algo/sort.h b/include/stc/algo/sort.h index 06d7395f..86c9b9f1 100644 --- a/include/stc/algo/sort.h +++ b/include/stc/algo/sort.h @@ -70,7 +70,7 @@ int main(void) { #ifndef i_tag #define i_tag i_key #endif - #define i_type c_PASTE(i_tag, array) + #define i_type c_PASTE(i_tag, s) typedef i_key i_type; #endif #ifndef i_at diff --git a/include/stc/calgo.h b/include/stc/algorithm.h index 63ef97b9..cf3ab328 100644 --- a/include/stc/calgo.h +++ b/include/stc/algorithm.h @@ -4,6 +4,5 @@ #include "algo/raii.h" #include "algo/crange.h" #include "algo/filter.h" -#include "algo/coroutine.h" #endif diff --git a/include/stc/ccommon.h b/include/stc/ccommon.h index 1f9ea80d..77f754fa 100644 --- a/include/stc/ccommon.h +++ b/include/stc/ccommon.h @@ -69,7 +69,7 @@ typedef long long _llong; #define c_new(T, ...) ((T*)memcpy(malloc(sizeof(T)), ((T[]){__VA_ARGS__}), sizeof(T))) #define c_LITERAL(T) (T) #endif -#define c_new_n(T, n) ((T*)malloc(sizeof(T)*(n))) +#define c_new_n(T, n) ((T*)malloc(sizeof(T)*(size_t)(n))) #define c_malloc(sz) malloc(c_i2u(sz)) #define c_calloc(n, sz) calloc(c_i2u(n), c_i2u(sz)) #define c_realloc(p, sz) realloc(p, c_i2u(sz)) @@ -191,10 +191,6 @@ STC_INLINE intptr_t cnextpow2(intptr_t n) { for (C##_iter it = start, *_endref = (C##_iter*)(finish).ref \ ; it.ref != (C##_value*)_endref; C##_next(&it)) -#define c_foreach_rv(it, C, cnt) \ - for (C##_iter it = {.ref=C##_end(&cnt).end - 1, .end=(cnt).data - 1} \ - ; it.ref != it.end; --it.ref) - #define c_forpair(key, val, C, cnt) /* structured binding */ \ for (struct {C##_iter it; const C##_key* key; C##_mapped* val;} _ = {.it=C##_begin(&cnt)} \ ; _.it.ref && (_.key = &_.it.ref->first, _.val = &_.it.ref->second) \ diff --git a/include/stc/cdeq.h b/include/stc/cdeq.h index 056ef005..9892f6f1 100644 --- a/include/stc/cdeq.h +++ b/include/stc/cdeq.h @@ -20,16 +20,19 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ +#include "priv/linkage.h" + +#ifndef CDEQ_H_INCLUDED +#include "ccommon.h" +#include "forward.h" +#include <stdlib.h> +#include <string.h> +#endif // CDEQ_H_INCLUDED + #define _i_prefix cdeq_ #define _pop _pop_front #define _pull _pull_front -#ifdef i_more - #include "cqueue.h" - #define i_more -#else - #define i_more - #include "cqueue.h" -#endif +#include "priv/cqueue_hdr.h" #undef _pop STC_API _cx_value* _cx_MEMB(_push_front)(_cx_Self* self, i_key value); @@ -122,6 +125,8 @@ _cx_MEMB(_get_mut)(_cx_Self* self, _cx_raw raw) /* -------------------------- IMPLEMENTATION ------------------------- */ #if defined(i_implement) || defined(i_static) +#include "priv/cqueue_imp.h" + STC_DEF _cx_value* _cx_MEMB(_push_front)(_cx_Self* self, i_key value) { intptr_t start = (self->start - 1) & self->capmask; diff --git a/include/stc/algo/coroutine.h b/include/stc/coroutine.h index 3a5382f3..42905744 100644 --- a/include/stc/algo/coroutine.h +++ b/include/stc/coroutine.h @@ -24,7 +24,7 @@ #define STC_COROUTINE_INCLUDED /* #include <stdio.h> -#include <stc/algo/coroutine.h> +#include <stc/coroutine.h> struct iterpair { int max_x, max_y; @@ -56,7 +56,7 @@ int main(void) { return 0; } */ -#include "../ccommon.h" +#include "ccommon.h" enum { CCO_STATE_CLEANUP = -1, @@ -64,9 +64,8 @@ enum { }; typedef enum { CCO_DONE = 0, - CCO_YIELD = 1, - CCO_AWAIT = 2, - CCO_ERROR = -1, + CCO_AWAIT = 1<<0, + CCO_YIELD = 1<<1, } cco_result; #define cco_initial(co) ((co)->cco_state == 0) @@ -74,7 +73,7 @@ typedef enum { #define cco_done(co) ((co)->cco_state == CCO_STATE_DONE) #define cco_routine(co) \ - for (int *_state = &(co)->cco_state; *_state != CCO_STATE_DONE; *_state = CCO_STATE_DONE) \ + for (int* _state = &(co)->cco_state; *_state != CCO_STATE_DONE; *_state = CCO_STATE_DONE) \ _resume: switch (*_state) case 0: // thanks, @liigo! #define cco_yield() cco_yield_v(CCO_YIELD) @@ -84,26 +83,27 @@ typedef enum { case __LINE__:; \ } while (0) -#define cco_await(promise) cco_await_v_2(promise, CCO_AWAIT) -#define cco_await_v(...) c_MACRO_OVERLOAD(cco_await_v, __VA_ARGS__) -#define cco_await_v_1(promise) cco_await_v_2(promise, ) -#define cco_await_v_2(promise, ret) \ +#define cco_await(promise) cco_await_and_return(promise, CCO_AWAIT) +#define cco_await_v(promise) cco_await_and_return(promise, ) +#define cco_await_and_return(promise, ret) \ do { \ *_state = __LINE__; \ case __LINE__: if (!(promise)) {return ret; goto _resume;} \ } while (0) -/* cco_await_on(): assumes coroutine returns a cco_result value (int) */ -#define cco_await_on(corocall) \ +/* cco_call_await(): assumes coroutine returns a cco_result value (int) */ +#define cco_call_await(...) c_MACRO_OVERLOAD(cco_call_await, __VA_ARGS__) +#define cco_call_await_1(corocall) cco_call_await_2(corocall, CCO_DONE) +#define cco_call_await_2(corocall, resultbits) \ do { \ *_state = __LINE__; \ - case __LINE__: { int _r = corocall; if (_r != CCO_DONE) {return _r; goto _resume;} } \ + case __LINE__: { int _r = corocall; if (!(_r & ~(resultbits))) {return _r; goto _resume;} } \ } while (0) -/* cco_block_on(): assumes coroutine returns a cco_result value (int) */ -#define cco_block_on(...) c_MACRO_OVERLOAD(cco_block_on, __VA_ARGS__) -#define cco_block_on_1(corocall) while ((corocall) != CCO_DONE) -#define cco_block_on_2(corocall, result) while ((*(result) = (corocall)) != CCO_DONE) +/* cco_call_blocking(): assumes coroutine returns a cco_result value (int) */ +#define cco_call_blocking(...) c_MACRO_OVERLOAD(cco_call_blocking, __VA_ARGS__) +#define cco_call_blocking_1(corocall) while ((corocall) != CCO_DONE) +#define cco_call_blocking_2(corocall, result) while ((*(result) = (corocall)) != CCO_DONE) #define cco_cleanup \ *_state = CCO_STATE_CLEANUP; case CCO_STATE_CLEANUP @@ -132,26 +132,44 @@ typedef enum { (void)((co)->cco_state = 0) /* - * Closure (optional) + * Tasks (optional) */ -#define cco_closure(Name, ...) \ +struct cco_runtime; + +#define cco_task_struct(Name, ...) \ struct Name { \ - int (*cco_fn)(struct Name*); \ - int cco_state; \ + int (*cco_func)(struct Name*, struct cco_runtime*); \ + int cco_state, cco_expect; \ __VA_ARGS__ \ } -typedef struct cco_base { - int (*cco_fn)(struct cco_base*); - int cco_state; -} cco_base; +typedef cco_task_struct(cco_task, /**/) cco_task; + +typedef struct cco_runtime { + int result, top; cco_task* stack[]; +} cco_runtime; + +#define cco_cast_task(task) \ + ((cco_task *)(task) + 0*sizeof((task)->cco_func(task, (cco_runtime*)0) + ((int*)0 == &(task)->cco_state))) + +#define cco_task_resume(task, rt) \ + (task)->cco_func(task, rt) -#define cco_resume(closure) \ - (closure)->cco_fn(closure) +#define cco_task_await(...) c_MACRO_OVERLOAD(cco_task_await, __VA_ARGS__) +#define cco_task_await_2(task, rt) cco_task_await_3(task, rt, CCO_DONE) +#define cco_task_await_3(task, rt, resultbits) \ + do { \ + cco_runtime* _rt = rt; \ + (_rt->stack[++_rt->top] = cco_cast_task(task))->cco_expect = (resultbits); \ + cco_yield_v(CCO_AWAIT); \ + } while (0) -#define cco_cast(closure) \ - ((cco_base *)(closure) + 0*sizeof((cco_resume(closure), (int*)0 == &(closure)->cco_state))) +#define cco_task_blocking(...) c_MACRO_OVERLOAD(cco_task_blocking, __VA_ARGS__) +#define cco_task_blocking_1(task) cco_task_blocking_3(task, _rt, 16) +#define cco_task_blocking_3(task, rt, STACKDEPTH) \ + for (struct { int result, top; cco_task* stack[STACKDEPTH]; } rt = {.stack={cco_cast_task(task)}}; \ + (((rt.result = cco_task_resume(rt.stack[rt.top], (cco_runtime*)&rt)) & ~rt.stack[rt.top]->cco_expect) || --rt.top >= 0); ) /* * Semaphore @@ -159,12 +177,11 @@ typedef struct cco_base { typedef struct { intptr_t count; } cco_sem; -#define cco_sem_await(sem) cco_sem_await_v_2(sem, CCO_AWAIT) -#define cco_sem_await_v(...) c_MACRO_OVERLOAD(cco_sem_await_v, __VA_ARGS__) -#define cco_sem_await_v_1(sem) cco_sem_await_v_2(sem, ) -#define cco_sem_await_v_2(sem, ret) \ +#define cco_sem_await(sem) cco_sem_await_and_return(sem, CCO_AWAIT) +#define cco_sem_await_v(sem) cco_sem_await_and_return(sem, ) +#define cco_sem_await_and_return(sem, ret) \ do { \ - cco_await_v_2((sem)->count > 0, ret); \ + cco_await_and_return((sem)->count > 0, ret); \ --(sem)->count; \ } while (0) @@ -178,17 +195,22 @@ typedef struct { intptr_t count; } cco_sem; #ifdef _WIN32 #ifdef __cplusplus - #define _c_LINKC extern "C" __declspec(dllimport) + #define _c_LINKC extern "C" __declspec(dllimport) + #else + #define _c_LINKC __declspec(dllimport) + #endif + #if 1 // _WIN32_WINNT < _WIN32_WINNT_WIN8 || defined __TINYC__ + #define _c_getsystime GetSystemTimeAsFileTime #else - #define _c_LINKC __declspec(dllimport) + #define _c_getsystime GetSystemTimePreciseAsFileTime #endif struct _FILETIME; - _c_LINKC void GetSystemTimePreciseAsFileTime(struct _FILETIME*); + _c_LINKC void _c_getsystime(struct _FILETIME*); _c_LINKC void Sleep(unsigned long); static inline double cco_time(void) { /* seconds since epoch */ unsigned long long quad; /* 64-bit value representing 1/10th usecs since Jan 1 1601, 00:00 UTC */ - GetSystemTimePreciseAsFileTime((struct _FILETIME*)&quad); + _c_getsystime((struct _FILETIME*)&quad); return (double)(quad - 116444736000000000ULL)*1e-7; /* time diff Jan 1 1601-Jan 1 1970 in 1/10th usecs */ } @@ -219,7 +241,7 @@ typedef struct { double interval, start; } cco_timer; #define cco_timer_await_v_3(tm, sec, ret) \ do { \ cco_timer_start(tm, sec); \ - cco_await_v_2(cco_timer_expired(tm), ret); \ + cco_await_and_return(cco_timer_expired(tm), ret); \ } while (0) static inline void cco_timer_start(cco_timer* tm, double sec) { diff --git a/include/stc/cqueue.h b/include/stc/cqueue.h index 5d38ca89..8a609b96 100644 --- a/include/stc/cqueue.h +++ b/include/stc/cqueue.h @@ -32,211 +32,11 @@ #ifndef _i_prefix #define _i_prefix cqueue_ #endif -#include "priv/template.h" - -#ifndef i_is_forward -_cx_DEFTYPES(_c_cdeq_types, _cx_Self, i_key); -#endif -typedef i_keyraw _cx_raw; - -STC_API _cx_Self _cx_MEMB(_with_capacity)(const intptr_t n); -STC_API bool _cx_MEMB(_reserve)(_cx_Self* self, const intptr_t n); -STC_API void _cx_MEMB(_clear)(_cx_Self* self); -STC_API void _cx_MEMB(_drop)(_cx_Self* self); -STC_API _cx_value* _cx_MEMB(_push)(_cx_Self* self, i_key value); // push_back -STC_API void _cx_MEMB(_shrink_to_fit)(_cx_Self *self); -STC_API _cx_iter _cx_MEMB(_advance)(_cx_iter it, intptr_t n); - -#define _cdeq_toidx(self, pos) (((pos) - (self)->start) & (self)->capmask) -#define _cdeq_topos(self, idx) (((self)->start + (idx)) & (self)->capmask) - -STC_INLINE _cx_Self _cx_MEMB(_init)(void) - { _cx_Self cx = {0}; return cx; } -STC_INLINE void _cx_MEMB(_put_n)(_cx_Self* self, const _cx_raw* raw, intptr_t n) - { while (n--) _cx_MEMB(_push)(self, i_keyfrom(*raw++)); } -STC_INLINE _cx_Self _cx_MEMB(_from_n)(const _cx_raw* raw, intptr_t n) - { _cx_Self cx = {0}; _cx_MEMB(_put_n)(&cx, raw, n); return cx; } -STC_INLINE void _cx_MEMB(_value_drop)(_cx_value* val) { i_keydrop(val); } - -#if !defined i_no_emplace -STC_INLINE _cx_value* _cx_MEMB(_emplace)(_cx_Self* self, _cx_raw raw) - { return _cx_MEMB(_push)(self, i_keyfrom(raw)); } -#endif - -#if defined _i_has_eq || defined _i_has_cmp -STC_API bool _cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other); -#endif - -#if !defined i_no_clone -STC_API _cx_Self _cx_MEMB(_clone)(_cx_Self cx); -STC_INLINE i_key _cx_MEMB(_value_clone)(i_key val) - { return i_keyclone(val); } -#endif // !i_no_clone -STC_INLINE intptr_t _cx_MEMB(_size)(const _cx_Self* self) - { return _cdeq_toidx(self, self->end); } -STC_INLINE intptr_t _cx_MEMB(_capacity)(const _cx_Self* self) - { return self->capmask; } -STC_INLINE bool _cx_MEMB(_empty)(const _cx_Self* self) - { return self->start == self->end; } -STC_INLINE _cx_raw _cx_MEMB(_value_toraw)(const _cx_value* pval) - { return i_keyto(pval); } - -STC_INLINE _cx_value* _cx_MEMB(_front)(const _cx_Self* self) - { return self->data + self->start; } - -STC_INLINE _cx_value* _cx_MEMB(_back)(const _cx_Self* self) - { return self->data + ((self->end - 1) & self->capmask); } - -STC_INLINE void _cx_MEMB(_pop)(_cx_Self* self) { // pop_front - c_assert(!_cx_MEMB(_empty)(self)); - i_keydrop((self->data + self->start)); - self->start = (self->start + 1) & self->capmask; -} - -STC_INLINE _cx_value _cx_MEMB(_pull)(_cx_Self* self) { // move front out of queue - c_assert(!_cx_MEMB(_empty)(self)); - intptr_t s = self->start; - self->start = (s + 1) & self->capmask; - return self->data[s]; -} - -STC_INLINE void _cx_MEMB(_copy)(_cx_Self* self, const _cx_Self* other) { - if (self->data == other->data) return; - _cx_MEMB(_drop)(self); - *self = _cx_MEMB(_clone)(*other); -} - -STC_INLINE _cx_iter _cx_MEMB(_begin)(const _cx_Self* self) { - return c_LITERAL(_cx_iter){ - _cx_MEMB(_empty)(self) ? NULL : self->data + self->start, - self->start, self - }; -} - -STC_INLINE _cx_iter _cx_MEMB(_end)(const _cx_Self* self) - { return c_LITERAL(_cx_iter){.pos=self->end, ._s=self}; } - -STC_INLINE void _cx_MEMB(_next)(_cx_iter* it) { - if (it->pos != it->_s->capmask) { ++it->ref; ++it->pos; } - else { it->ref -= it->pos; it->pos = 0; } - if (it->pos == it->_s->end) it->ref = NULL; -} - -STC_INLINE intptr_t _cx_MEMB(_index)(const _cx_Self* self, _cx_iter it) - { return _cdeq_toidx(self, it.pos); } - -STC_INLINE void _cx_MEMB(_adjust_end_)(_cx_Self* self, intptr_t n) - { self->end = (self->end + n) & self->capmask; } +#include "priv/cqueue_hdr.h" /* -------------------------- IMPLEMENTATION ------------------------- */ #if defined(i_implement) || defined(i_static) - -STC_DEF _cx_iter _cx_MEMB(_advance)(_cx_iter it, intptr_t n) { - intptr_t len = _cx_MEMB(_size)(it._s); - intptr_t pos = it.pos, idx = _cdeq_toidx(it._s, pos); - it.pos = (pos + n) & it._s->capmask; - it.ref += it.pos - pos; - if (!c_LTu(idx + n, len)) it.ref = NULL; - return it; -} - -STC_DEF void -_cx_MEMB(_clear)(_cx_Self* self) { - c_foreach (i, _cx_Self, *self) - { i_keydrop(i.ref); } - self->start = 0, self->end = 0; -} - -STC_DEF void -_cx_MEMB(_drop)(_cx_Self* self) { - _cx_MEMB(_clear)(self); - i_free(self->data); -} - -STC_DEF _cx_Self -_cx_MEMB(_with_capacity)(const intptr_t n) { - _cx_Self cx = {0}; - _cx_MEMB(_reserve)(&cx, n); - return cx; -} - -STC_DEF bool -_cx_MEMB(_reserve)(_cx_Self* self, const intptr_t n) { - if (n <= self->capmask) - return true; - intptr_t oldcap = self->capmask + 1, newcap = cnextpow2(n + 1); - _cx_value* d = (_cx_value *)i_realloc(self->data, newcap*c_sizeof *self->data); - if (!d) - return false; - intptr_t head = oldcap - self->start; - if (self->start <= self->end) - ; - else if (head < self->end) { - self->start = newcap - head; - c_memmove(d + self->start, d + oldcap - head, head*c_sizeof *d); - } else { - c_memmove(d + oldcap, d, self->end*c_sizeof *d); - self->end += oldcap; - } - self->capmask = newcap - 1; - self->data = d; - return true; -} - -STC_DEF _cx_value* -_cx_MEMB(_push)(_cx_Self* self, i_key value) { // push_back - intptr_t end = (self->end + 1) & self->capmask; - if (end == self->start) { // full - _cx_MEMB(_reserve)(self, self->capmask + 3); // => 2x expand - end = (self->end + 1) & self->capmask; - } - _cx_value *v = self->data + self->end; - self->end = end; - *v = value; - return v; -} - -STC_DEF void -_cx_MEMB(_shrink_to_fit)(_cx_Self *self) { - intptr_t sz = _cx_MEMB(_size)(self), j = 0; - if (sz > self->capmask/2) - return; - _cx_Self out = _cx_MEMB(_with_capacity)(sz); - if (!out.data) - return; - c_foreach (i, _cx_Self, *self) - out.data[j++] = *i.ref; - out.end = sz; - i_free(self->data); - *self = out; -} - -#if !defined i_no_clone -STC_DEF _cx_Self -_cx_MEMB(_clone)(_cx_Self cx) { - intptr_t sz = _cx_MEMB(_size)(&cx), j = 0; - _cx_Self out = _cx_MEMB(_with_capacity)(sz); - if (out.data) - c_foreach (i, _cx_Self, cx) - out.data[j++] = i_keyclone((*i.ref)); - out.end = sz; - return out; -} -#endif // i_no_clone - -#if defined _i_has_eq || defined _i_has_cmp -STC_DEF bool -_cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other) { - if (_cx_MEMB(_size)(self) != _cx_MEMB(_size)(other)) return false; - for (_cx_iter i = _cx_MEMB(_begin)(self), j = _cx_MEMB(_begin)(other); - i.ref; _cx_MEMB(_next)(&i), _cx_MEMB(_next)(&j)) - { - const _cx_raw _rx = i_keyto(i.ref), _ry = i_keyto(j.ref); - if (!(i_eq((&_rx), (&_ry)))) return false; - } - return true; -} -#endif +#include "priv/cqueue_imp.h" #endif // IMPLEMENTATION -#include "priv/template2.h" #define CQUEUE_H_INCLUDED +#include "priv/template2.h" diff --git a/include/stc/crand.h b/include/stc/crand.h index 0a6aa9e0..32722762 100644 --- a/include/stc/crand.h +++ b/include/stc/crand.h @@ -32,20 +32,20 @@ int main(void) { uint64_t seed = 123456789; crand_t rng = crand_init(seed); - crand_unif_t dist1 = crand_unif_init(1, 6); - crand_norm_t dist3 = crand_norm_init(1.0, 10.0); + crand_uniform_t dist1 = crand_uniform_init(1, 6); + crand_normal_t dist3 = crand_normal_init(1.0, 10.0); uint64_t i = crand_u64(&rng); - int64_t iu = crand_unif(&rng, &dist1); - double xn = crand_norm(&rng, &dist3); + int64_t iu = crand_uniform(&rng, &dist1); + double xn = crand_normal(&rng, &dist3); } */ #include <string.h> #include <math.h> typedef struct crand { uint64_t state[5]; } crand_t; -typedef struct crand_unif { int64_t lower; uint64_t range, threshold; } crand_unif_t; -typedef struct crand_norm { double mean, stddev, next; int has_next; } crand_norm_t; +typedef struct crand_uniform { int64_t lower; uint64_t range, threshold; } crand_uniform_t; +typedef struct crand_normal { double mean, stddev, next; int has_next; } crand_normal_t; /* PRNG crand_t. * Very fast PRNG suited for parallel usage with Weyl-sequence parameter. @@ -67,14 +67,14 @@ STC_API double crandf(void); STC_API crand_t crand_init(uint64_t seed); /* Unbiased bounded uniform distribution. range [low, high] */ -STC_API crand_unif_t crand_unif_init(int64_t low, int64_t high); -STC_API int64_t crand_unif(crand_t* rng, crand_unif_t* dist); +STC_API crand_uniform_t crand_uniform_init(int64_t low, int64_t high); +STC_API int64_t crand_uniform(crand_t* rng, crand_uniform_t* dist); /* Normal/gaussian distribution. */ -STC_INLINE crand_norm_t crand_norm_init(double mean, double stddev) - { crand_norm_t r = {mean, stddev, 0.0, 0}; return r; } +STC_INLINE crand_normal_t crand_normal_init(double mean, double stddev) + { crand_normal_t r = {mean, stddev, 0.0, 0}; return r; } -STC_API double crand_norm(crand_t* rng, crand_norm_t* dist); +STC_API double crand_normal(crand_t* rng, crand_normal_t* dist); /* Main crand_t prng */ STC_INLINE uint64_t crand_u64(crand_t* rng) { @@ -95,11 +95,10 @@ STC_INLINE double crand_f64(crand_t* rng) { /* -------------------------- IMPLEMENTATION ------------------------- */ #if defined(i_implement) || defined(i_static) -/* Global random() */ -static crand_t crand_global = {{ - 0x26aa069ea2fb1a4d, 0x70c72c95cd592d04, - 0x504f333d3aa0b359, 0x9e3779b97f4a7c15, - 0x6a09e667a754166b +/* Global random seed */ +static crand_t crand_global = {{ // csrand(0) + 0x9e3779b97f4a7c15, 0x6f68261b57e7a770, + 0xe220a838bf5c9dde, 0x7c17d1800457b1ba, 0x1, }}; STC_DEF void csrand(uint64_t seed) @@ -116,20 +115,20 @@ STC_DEF crand_t crand_init(uint64_t seed) { s[0] = seed + 0x9e3779b97f4a7c15; s[1] = (s[0] ^ (s[0] >> 30))*0xbf58476d1ce4e5b9; s[2] = (s[1] ^ (s[1] >> 27))*0x94d049bb133111eb; - s[3] = (s[2] ^ (s[2] >> 31)); - s[4] = ((seed + 0x6aa069ea2fb1a4d) << 1) | 1; + s[3] = s[0] ^ s[2] ^ (s[2] >> 31); + s[4] = (seed << 1) | 1; return rng; } /* Init unbiased uniform uint RNG with bounds [low, high] */ -STC_DEF crand_unif_t crand_unif_init(int64_t low, int64_t high) { - crand_unif_t dist = {low, (uint64_t) (high - low + 1)}; +STC_DEF crand_uniform_t crand_uniform_init(int64_t low, int64_t high) { + crand_uniform_t dist = {low, (uint64_t) (high - low + 1)}; dist.threshold = (uint64_t)(0 - dist.range) % dist.range; return dist; } /* Int64 uniform distributed RNG, range [low, high]. */ -STC_DEF int64_t crand_unif(crand_t* rng, crand_unif_t* d) { +STC_DEF int64_t crand_uniform(crand_t* rng, crand_uniform_t* d) { uint64_t lo, hi; #ifdef c_umul128 do { c_umul128(crand_u64(rng), d->range, &lo, &hi); } while (lo < d->threshold); @@ -140,7 +139,7 @@ STC_DEF int64_t crand_unif(crand_t* rng, crand_unif_t* d) { } /* Normal distribution PRNG. Marsaglia polar method */ -STC_DEF double crand_norm(crand_t* rng, crand_norm_t* dist) { +STC_DEF double crand_normal(crand_t* rng, crand_normal_t* dist) { double u1, u2, s, m; if (dist->has_next++ & 1) return dist->next*dist->stddev + dist->mean; diff --git a/include/stc/cspan.h b/include/stc/cspan.h index dcb02961..08045010 100644 --- a/include/stc/cspan.h +++ b/include/stc/cspan.h @@ -80,19 +80,19 @@ int demo2() { STC_INLINE Self Self##_from_n(Self##_raw* raw, const intptr_t n) { \ return (Self){.data=raw, .shape={(int32_t)n}}; \ } \ - STC_INLINE Self Self##_slice_(Self##_value* v, const int32_t shape[], const int32_t stri[], \ + STC_INLINE Self Self##_slice_(Self##_value* d, const int32_t shape[], const int32_t stri[], \ const int rank, const int32_t a[][2]) { \ - Self s; s.data = v; int outrank; \ - s.data += _cspan_slice(s.shape, s.stride.d, &outrank, shape, stri, rank, a); \ + Self s; int outrank; \ + s.data = d + _cspan_slice(s.shape, s.stride.d, &outrank, shape, stri, rank, a); \ c_assert(outrank == RANK); \ return s; \ } \ STC_INLINE Self##_iter Self##_begin(const Self* self) { \ - Self##_iter it = {.ref=self->data, .pos={0}, ._s=self}; \ + Self##_iter it = {.ref=self->data, ._s=self}; \ return it; \ } \ STC_INLINE Self##_iter Self##_end(const Self* self) { \ - Self##_iter it = {.ref=NULL}; \ + Self##_iter it = {0}; \ return it; \ } \ STC_INLINE void Self##_next(Self##_iter* it) { \ @@ -120,7 +120,7 @@ using_cspan_tuple(7); using_cspan_tuple(8); #define cspan_init(SpanType, ...) \ {.data=(SpanType##_value[])__VA_ARGS__, .shape={sizeof((SpanType##_value[])__VA_ARGS__)/sizeof(SpanType##_value)}, .stride={.d={1}}} -/* create a cspan from a cvec, cstack, cdeq, cqueue, or cpque (heap) */ +/* create a cspan from a cvec, cstack, or cpque (heap) */ #define cspan_from(container) \ {.data=(container)->data, .shape={(int32_t)(container)->_len}, .stride={.d={1}}} diff --git a/include/stc/cstr.h b/include/stc/cstr.h index 17943ad5..2648e267 100644 --- a/include/stc/cstr.h +++ b/include/stc/cstr.h @@ -170,14 +170,14 @@ STC_INLINE intptr_t cstr_capacity(const cstr* self) // utf8 methods defined in/depending on src/utf8code.c: -STC_API cstr cstr_casefold_sv(csview sv); -STC_API cstr cstr_tolower_sv(csview sv); -STC_API cstr cstr_toupper_sv(csview sv); -STC_API cstr cstr_tolower(const char* str); -STC_API cstr cstr_toupper(const char* str); -STC_API void cstr_lowercase(cstr* self); -STC_API void cstr_uppercase(cstr* self); -STC_API bool cstr_valid_utf8(const cstr* self); +extern cstr cstr_casefold_sv(csview sv); +extern cstr cstr_tolower_sv(csview sv); +extern cstr cstr_toupper_sv(csview sv); +extern cstr cstr_tolower(const char* str); +extern cstr cstr_toupper(const char* str); +extern void cstr_lowercase(cstr* self); +extern void cstr_uppercase(cstr* self); +extern bool cstr_valid_utf8(const cstr* self); // other utf8 @@ -394,7 +394,7 @@ fn_tocase[] = {{tolower, utf8_casefold}, {tolower, utf8_tolower}, {toupper, utf8_toupper}}; -STC_DEF cstr cstr_tocase(csview sv, int k) { +static cstr cstr_tocase(csview sv, int k) { cstr out = cstr_init(); char *buf = cstr_reserve(&out, sv.size*3/2); const char *end = sv.str + sv.size; @@ -415,28 +415,28 @@ STC_DEF cstr cstr_tocase(csview sv, int k) { return out; } -STC_DEF cstr cstr_casefold_sv(csview sv) +cstr cstr_casefold_sv(csview sv) { return cstr_tocase(sv, 0); } -STC_DEF cstr cstr_tolower_sv(csview sv) +cstr cstr_tolower_sv(csview sv) { return cstr_tocase(sv, 1); } -STC_DEF cstr cstr_toupper_sv(csview sv) +cstr cstr_toupper_sv(csview sv) { return cstr_tocase(sv, 2); } -STC_DEF cstr cstr_tolower(const char* str) +cstr cstr_tolower(const char* str) { return cstr_tolower_sv(c_sv(str, c_strlen(str))); } -STC_DEF cstr cstr_toupper(const char* str) +cstr cstr_toupper(const char* str) { return cstr_toupper_sv(c_sv(str, c_strlen(str))); } -STC_DEF void cstr_lowercase(cstr* self) +void cstr_lowercase(cstr* self) { cstr_take(self, cstr_tolower_sv(cstr_sv(self))); } -STC_DEF void cstr_uppercase(cstr* self) +void cstr_uppercase(cstr* self) { cstr_take(self, cstr_toupper_sv(cstr_sv(self))); } -STC_DEF bool cstr_valid_utf8(const cstr* self) +bool cstr_valid_utf8(const cstr* self) { return utf8_valid(cstr_str(self)); } #endif // i_import diff --git a/include/stc/priv/cqueue_hdr.h b/include/stc/priv/cqueue_hdr.h new file mode 100644 index 00000000..90539f36 --- /dev/null +++ b/include/stc/priv/cqueue_hdr.h @@ -0,0 +1,117 @@ +/* MIT License + * + * Copyright (c) 2023 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 "template.h" +#ifndef i_is_forward +_cx_DEFTYPES(_c_cdeq_types, _cx_Self, i_key); +#endif +typedef i_keyraw _cx_raw; + +STC_API _cx_Self _cx_MEMB(_with_capacity)(const intptr_t n); +STC_API bool _cx_MEMB(_reserve)(_cx_Self* self, const intptr_t n); +STC_API void _cx_MEMB(_clear)(_cx_Self* self); +STC_API void _cx_MEMB(_drop)(_cx_Self* self); +STC_API _cx_value* _cx_MEMB(_push)(_cx_Self* self, i_key value); // push_back +STC_API void _cx_MEMB(_shrink_to_fit)(_cx_Self *self); +STC_API _cx_iter _cx_MEMB(_advance)(_cx_iter it, intptr_t n); + +#define _cdeq_toidx(self, pos) (((pos) - (self)->start) & (self)->capmask) +#define _cdeq_topos(self, idx) (((self)->start + (idx)) & (self)->capmask) + +STC_INLINE _cx_Self _cx_MEMB(_init)(void) + { _cx_Self cx = {0}; return cx; } +STC_INLINE void _cx_MEMB(_put_n)(_cx_Self* self, const _cx_raw* raw, intptr_t n) + { while (n--) _cx_MEMB(_push)(self, i_keyfrom(*raw++)); } +STC_INLINE _cx_Self _cx_MEMB(_from_n)(const _cx_raw* raw, intptr_t n) + { _cx_Self cx = {0}; _cx_MEMB(_put_n)(&cx, raw, n); return cx; } +STC_INLINE void _cx_MEMB(_value_drop)(_cx_value* val) { i_keydrop(val); } + +#if !defined i_no_emplace +STC_INLINE _cx_value* _cx_MEMB(_emplace)(_cx_Self* self, _cx_raw raw) + { return _cx_MEMB(_push)(self, i_keyfrom(raw)); } +#endif + +#if defined _i_has_eq || defined _i_has_cmp +STC_API bool _cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other); +#endif + +#if !defined i_no_clone +STC_API _cx_Self _cx_MEMB(_clone)(_cx_Self cx); +STC_INLINE i_key _cx_MEMB(_value_clone)(i_key val) + { return i_keyclone(val); } +#endif // !i_no_clone +STC_INLINE intptr_t _cx_MEMB(_size)(const _cx_Self* self) + { return _cdeq_toidx(self, self->end); } +STC_INLINE intptr_t _cx_MEMB(_capacity)(const _cx_Self* self) + { return self->capmask; } +STC_INLINE bool _cx_MEMB(_empty)(const _cx_Self* self) + { return self->start == self->end; } +STC_INLINE _cx_raw _cx_MEMB(_value_toraw)(const _cx_value* pval) + { return i_keyto(pval); } + +STC_INLINE _cx_value* _cx_MEMB(_front)(const _cx_Self* self) + { return self->data + self->start; } + +STC_INLINE _cx_value* _cx_MEMB(_back)(const _cx_Self* self) + { return self->data + ((self->end - 1) & self->capmask); } + +STC_INLINE void _cx_MEMB(_pop)(_cx_Self* self) { // pop_front + c_assert(!_cx_MEMB(_empty)(self)); + i_keydrop((self->data + self->start)); + self->start = (self->start + 1) & self->capmask; +} + +STC_INLINE _cx_value _cx_MEMB(_pull)(_cx_Self* self) { // move front out of queue + c_assert(!_cx_MEMB(_empty)(self)); + intptr_t s = self->start; + self->start = (s + 1) & self->capmask; + return self->data[s]; +} + +STC_INLINE void _cx_MEMB(_copy)(_cx_Self* self, const _cx_Self* other) { + if (self->data == other->data) return; + _cx_MEMB(_drop)(self); + *self = _cx_MEMB(_clone)(*other); +} + +STC_INLINE _cx_iter _cx_MEMB(_begin)(const _cx_Self* self) { + return c_LITERAL(_cx_iter){ + _cx_MEMB(_empty)(self) ? NULL : self->data + self->start, + self->start, self + }; +} + +STC_INLINE _cx_iter _cx_MEMB(_end)(const _cx_Self* self) + { return c_LITERAL(_cx_iter){.pos=self->end, ._s=self}; } + +STC_INLINE void _cx_MEMB(_next)(_cx_iter* it) { + if (it->pos != it->_s->capmask) { ++it->ref; ++it->pos; } + else { it->ref -= it->pos; it->pos = 0; } + if (it->pos == it->_s->end) it->ref = NULL; +} + +STC_INLINE intptr_t _cx_MEMB(_index)(const _cx_Self* self, _cx_iter it) + { return _cdeq_toidx(self, it.pos); } + +STC_INLINE void _cx_MEMB(_adjust_end_)(_cx_Self* self, intptr_t n) + { self->end = (self->end + n) & self->capmask; } diff --git a/include/stc/priv/cqueue_imp.h b/include/stc/priv/cqueue_imp.h new file mode 100644 index 00000000..2ad9c811 --- /dev/null +++ b/include/stc/priv/cqueue_imp.h @@ -0,0 +1,129 @@ +/* MIT License + * + * Copyright (c) 2023 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. + */ + +STC_DEF _cx_iter _cx_MEMB(_advance)(_cx_iter it, intptr_t n) { + intptr_t len = _cx_MEMB(_size)(it._s); + intptr_t pos = it.pos, idx = _cdeq_toidx(it._s, pos); + it.pos = (pos + n) & it._s->capmask; + it.ref += it.pos - pos; + if (!c_LTu(idx + n, len)) it.ref = NULL; + return it; +} + +STC_DEF void +_cx_MEMB(_clear)(_cx_Self* self) { + c_foreach (i, _cx_Self, *self) + { i_keydrop(i.ref); } + self->start = 0, self->end = 0; +} + +STC_DEF void +_cx_MEMB(_drop)(_cx_Self* self) { + _cx_MEMB(_clear)(self); + i_free(self->data); +} + +STC_DEF _cx_Self +_cx_MEMB(_with_capacity)(const intptr_t n) { + _cx_Self cx = {0}; + _cx_MEMB(_reserve)(&cx, n); + return cx; +} + +STC_DEF bool +_cx_MEMB(_reserve)(_cx_Self* self, const intptr_t n) { + if (n <= self->capmask) + return true; + intptr_t oldcap = self->capmask + 1, newcap = cnextpow2(n + 1); + _cx_value* d = (_cx_value *)i_realloc(self->data, newcap*c_sizeof *self->data); + if (!d) + return false; + intptr_t head = oldcap - self->start; + if (self->start <= self->end) + ; + else if (head < self->end) { + self->start = newcap - head; + c_memmove(d + self->start, d + oldcap - head, head*c_sizeof *d); + } else { + c_memmove(d + oldcap, d, self->end*c_sizeof *d); + self->end += oldcap; + } + self->capmask = newcap - 1; + self->data = d; + return true; +} + +STC_DEF _cx_value* +_cx_MEMB(_push)(_cx_Self* self, i_key value) { // push_back + intptr_t end = (self->end + 1) & self->capmask; + if (end == self->start) { // full + _cx_MEMB(_reserve)(self, self->capmask + 3); // => 2x expand + end = (self->end + 1) & self->capmask; + } + _cx_value *v = self->data + self->end; + self->end = end; + *v = value; + return v; +} + +STC_DEF void +_cx_MEMB(_shrink_to_fit)(_cx_Self *self) { + intptr_t sz = _cx_MEMB(_size)(self), j = 0; + if (sz > self->capmask/2) + return; + _cx_Self out = _cx_MEMB(_with_capacity)(sz); + if (!out.data) + return; + c_foreach (i, _cx_Self, *self) + out.data[j++] = *i.ref; + out.end = sz; + i_free(self->data); + *self = out; +} + +#if !defined i_no_clone +STC_DEF _cx_Self +_cx_MEMB(_clone)(_cx_Self cx) { + intptr_t sz = _cx_MEMB(_size)(&cx), j = 0; + _cx_Self out = _cx_MEMB(_with_capacity)(sz); + if (out.data) + c_foreach (i, _cx_Self, cx) + out.data[j++] = i_keyclone((*i.ref)); + out.end = sz; + return out; +} +#endif // i_no_clone + +#if defined _i_has_eq || defined _i_has_cmp +STC_DEF bool +_cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other) { + if (_cx_MEMB(_size)(self) != _cx_MEMB(_size)(other)) return false; + for (_cx_iter i = _cx_MEMB(_begin)(self), j = _cx_MEMB(_begin)(other); + i.ref; _cx_MEMB(_next)(&i), _cx_MEMB(_next)(&j)) + { + const _cx_raw _rx = i_keyto(i.ref), _ry = i_keyto(j.ref); + if (!(i_eq((&_rx), (&_ry)))) return false; + } + return true; +} +#endif diff --git a/include/stc/priv/template.h b/include/stc/priv/template.h index 30ed5732..ccdce718 100644 --- a/include/stc/priv/template.h +++ b/include/stc/priv/template.h @@ -103,7 +103,7 @@ #define i_no_emplace #endif #if c_option(c_native_cmp) - #define i_native_cmp + #define i_cmp_native #endif #if c_option(c_no_clone) || defined _i_carc #define i_no_clone @@ -203,10 +203,10 @@ #endif #ifndef i_no_cmp - #if defined i_cmp || defined i_less || defined i_native_cmp + #if defined i_cmp || defined i_less || defined i_cmp_native #define _i_has_cmp #endif - #if defined i_eq || defined i_native_cmp + #if defined i_eq || defined i_cmp_native #define _i_has_eq #endif @@ -228,7 +228,7 @@ #endif #endif -#if !defined i_hash && (!(defined _i_cbox || defined _i_carc) || defined i_native_cmp) +#if !defined i_hash && (!(defined _i_cbox || defined _i_carc) || defined i_cmp_native) #define i_hash c_default_hash #endif diff --git a/include/stc/priv/template2.h b/include/stc/priv/template2.h index def5d01e..351defde 100644 --- a/include/stc/priv/template2.h +++ b/include/stc/priv/template2.h @@ -67,7 +67,7 @@ #undef i_realloc #undef i_free -#undef i_native_cmp +#undef i_cmp_native #undef i_no_cmp #undef i_no_hash #undef i_no_clone |
