summaryrefslogtreecommitdiffhomepage
path: root/include
diff options
context:
space:
mode:
Diffstat (limited to 'include')
-rw-r--r--include/c11/fmt.h (renamed from include/c11/print.h)119
-rw-r--r--include/stc/algo/coroutine.h117
-rw-r--r--include/stc/algo/crange.h25
-rw-r--r--include/stc/algo/csort.h89
-rw-r--r--include/stc/algo/filter.h35
-rw-r--r--include/stc/algo/raii.h51
-rw-r--r--include/stc/algo/sort.h123
-rw-r--r--include/stc/algorithm.h (renamed from include/stc/calgo.h)2
-rw-r--r--include/stc/carc.h147
-rw-r--r--include/stc/cbits.h104
-rw-r--r--include/stc/cbox.h132
-rw-r--r--include/stc/ccommon.h180
-rw-r--r--include/stc/cdeq.h459
-rw-r--r--include/stc/clist.h239
-rw-r--r--include/stc/cmap.h458
-rw-r--r--include/stc/coroutine.h288
-rw-r--r--include/stc/cpque.h97
-rw-r--r--include/stc/cqueue.h51
-rw-r--r--include/stc/crand.h65
-rw-r--r--include/stc/crandom.h197
-rw-r--r--include/stc/crawstr.h108
-rw-r--r--include/stc/cregex.h37
-rw-r--r--include/stc/cset.h3
-rw-r--r--include/stc/csmap.h423
-rw-r--r--include/stc/cspan.h262
-rw-r--r--include/stc/csset.h3
-rw-r--r--include/stc/cstack.h138
-rw-r--r--include/stc/cstr.h217
-rw-r--r--include/stc/csview.h146
-rw-r--r--include/stc/cvec.h332
-rw-r--r--include/stc/extend.h17
-rw-r--r--include/stc/forward.h79
-rw-r--r--include/stc/priv/cqueue_hdr.h116
-rw-r--r--include/stc/priv/cqueue_imp.h129
-rw-r--r--include/stc/priv/linkage.h (renamed from include/stc/priv/altnames.h)30
-rw-r--r--include/stc/priv/raii.h27
-rw-r--r--include/stc/priv/template.h132
-rw-r--r--include/stc/priv/template2.h14
-rw-r--r--include/stc/utf8.h43
39 files changed, 2732 insertions, 2502 deletions
diff --git a/include/c11/print.h b/include/c11/fmt.h
index 7c155875..7787bdb0 100644
--- a/include/c11/print.h
+++ b/include/c11/fmt.h
@@ -1,39 +1,39 @@
#ifndef FMT_H_INCLUDED
#define FMT_H_INCLUDED
/*
-VER 2.1: NEW API:
-void print(fmt, ...);
-void println(fmt, ...);
-void printd(dest, fmt, ...);
-
+VER 2.2: NEW API:
void fmt_print(fmt, ...);
void fmt_println(fmt, ...);
void fmt_printd(dest, fmt, ...);
-void fmt_destroy(fmt_buffer* buf);
+const char* fmt_tm(fmt, struct tm* tp);
+void fmt_close(fmt_stream* ss);
dest - destination, one of:
FILE* fp Write to a file
char* strbuf Write to a pre-allocated string buffer
- fmt_buffer* buf Auto realloc the needed memory (safe).
- Set buf->stream=1 for stream-mode.
- Call fmt_destroy(buf) after usage.
+ fmt_stream* ss Write to a string-stream (auto allocated).
+ Set ss->overwrite=1 for overwrite-mode.
+ Call fmt_close(ss) after usage.
- fmt - format string
+ fmt - format string (const char*)
{} Auto-detected format. If :MOD is not specified,
float will use ".8g" format, and double ".16g".
- {:MOD} Format modifiers: < left align (replaces -), default for char*, char.
- > right align, default for numbers.
- Other than that MOD can be normal printf format modifiers.
- {{, }} Print chars {, and }. (note: a single % prints %).
+ {:MODS} Format modifiers: '<' left align (replaces '-'). Default for char* and char.
+ '>' right align. Default for numbers.
+ Other than that MODS can be regular printf() format modifiers.
+ {{ }} % Print the '{', '}', and '%' characters.
* C11 or higher required.
* MAX 255 chars fmt string by default. MAX 12 arguments after fmt string.
-* Static linking by default, shared symbols by defining FMT_HEADER / FMT_IMPLEMENT.
+* Define FMT_IMPLEMENT, STC_IMPLEMENT or i_implement prior to #include in one translation unit.
+* Define FMT_SHORTS to add print(), println() and printd() macros, without fmt_ prefix.
* (c) operamint, 2022, MIT License.
-----------------------------------------------------------------------------------
-#include "c11/print.h"
+#define FMT_IMPLEMENT
+#define FMT_SHORTS
+#include "c11/fmt.h"
-int main() {
+int main(void) {
const double pi = 3.141592653589793;
const size_t x = 1234567890;
const char* string = "Hello world";
@@ -50,19 +50,26 @@ int main() {
printd(stdout, "{:10} {:10} {:10}\n", "Hello", "Mad", "World");
printd(stderr, "100%: {:<20} {:.*} {}\n", string, 4, pi, x);
printd(buffer, "Precision: {} {:.10} {}", string, pi, x);
- println("{}", buffer);
- println("Vector: ({}, {}, {})", 3.2, 3.3, pi);
+ fmt_println("{}", buffer);
+ fmt_println("Vector: ({}, {}, {})", 3.2, 3.3, pi);
- fmt_buffer out[1] = {{.stream=1}};
- printd(out, "{} {}", "Pi is:", pi);
- print("{}, len={}, cap={}\n", out->data, out->len, out->cap);
- printd(out, "{} {}", ", Pi squared is:", pi*pi);
- print("{}, len={}, cap={}\n", out->data, out->len, out->cap);
- fmt_destroy(out);
+ fmt_stream ss[1] = {0};
+ printd(ss, "{} {}", "Pi is:", pi);
+ print("{}, len={}, cap={}\n", ss->data, ss->len, ss->cap);
+ printd(ss, "{} {}", ", Pi squared is:", pi*pi);
+ print("{}, len={}, cap={}\n", ss->data, ss->len, ss->cap);
+ fmt_close(ss);
+
+ time_t now = time(NULL);
+ struct tm t1 = *localtime(&now), t2 = t1;
+ t2.tm_year += 2;
+ fmt_print("Dates:\n {}\n {}\n", fmt_tm("%Y-%m-%d %X %Z", &t1),
+ fmt_tm("%Y-%m-%d %X %Z", &t2));
}
*/
#include <stdio.h>
#include <stdint.h>
+#include <stddef.h>
#include <assert.h>
#define fmt_OVERLOAD(name, ...) \
@@ -77,12 +84,7 @@ int main() {
#define _fmt_ARG_N(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, \
_14, _15, _16, N, ...) N
-#if defined FMT_HEADER || defined FMT_IMPLEMENT
-# define FMT_API
-#else
-# define FMT_API static inline
-#endif
-#if defined FMT_NDEBUG || defined NDEBUG
+#if defined FMT_NDEBUG || defined STC_NDEBUG || defined NDEBUG
# define fmt_OK(exp) (void)(exp)
#else
# define fmt_OK(exp) assert(exp)
@@ -91,25 +93,27 @@ int main() {
typedef struct {
char* data;
intptr_t cap, len;
- _Bool stream;
-} fmt_buffer;
+ _Bool overwrite;
+} fmt_stream;
-FMT_API void fmt_destroy(fmt_buffer* buf);
-FMT_API int _fmt_parse(char* p, int nargs, const char *fmt, ...);
-FMT_API void _fmt_bprint(fmt_buffer*, const char* fmt, ...);
+struct tm; /* Max 2 usages. Buffer = 64 chars. */
+const char* fmt_tm(const char *fmt, const struct tm *tp);
+void fmt_close(fmt_stream* ss);
+int _fmt_parse(char* p, int nargs, const char *fmt, ...);
+void _fmt_bprint(fmt_stream*, const char* fmt, ...);
#ifndef FMT_MAX
-#define FMT_MAX 256
+#define FMT_MAX 128
#endif
-#ifndef FMT_NOSHORTS
+#ifdef FMT_SHORTS
#define print(...) fmt_printd(stdout, __VA_ARGS__)
-#define println(...) fmt_printd((fmt_buffer*)0, __VA_ARGS__)
+#define println(...) fmt_printd((fmt_stream*)0, __VA_ARGS__)
#define printd fmt_printd
#endif
#define fmt_print(...) fmt_printd(stdout, __VA_ARGS__)
-#define fmt_println(...) fmt_printd((fmt_buffer*)0, __VA_ARGS__)
+#define fmt_println(...) fmt_printd((fmt_stream*)0, __VA_ARGS__)
#define fmt_printd(...) fmt_OVERLOAD(fmt_printd, __VA_ARGS__)
/* Primary function. */
@@ -161,7 +165,7 @@ FMT_API void _fmt_bprint(fmt_buffer*, const char* fmt, ...);
#define _fmt_fn(x) _Generic ((x), \
FILE*: fprintf, \
char*: sprintf, \
- fmt_buffer*: _fmt_bprint)
+ fmt_stream*: _fmt_bprint)
#if defined(_MSC_VER) && !defined(__clang__)
# define _signed_char_hhd
@@ -192,38 +196,46 @@ FMT_API void _fmt_bprint(fmt_buffer*, const char* fmt, ...);
const wchar_t*: "ls", \
const void*: "p")
-#if defined FMT_IMPLEMENT || !(defined FMT_HEADER || defined FMT_IMPLEMENT)
+#if defined FMT_IMPLEMENT || defined STC_IMPLEMENT || defined i_implement
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
+#include <time.h>
+
+void fmt_close(fmt_stream* ss) {
+ free(ss->data);
+}
-FMT_API void fmt_destroy(fmt_buffer* buf) {
- free(buf->data);
+const char* fmt_tm(const char *fmt, const struct tm *tp) {
+ static char buf[2][64];
+ static int i;
+ strftime(buf[(i = !i)], sizeof buf[0], fmt, tp);
+ return buf[i];
}
-FMT_API void _fmt_bprint(fmt_buffer* buf, const char* fmt, ...) {
+void _fmt_bprint(fmt_stream* ss, const char* fmt, ...) {
va_list args, args2;
va_start(args, fmt);
- if (buf == NULL) {
+ if (ss == NULL) {
vprintf(fmt, args); putchar('\n');
goto done1;
}
va_copy(args2, args);
const int n = vsnprintf(NULL, 0U, fmt, args);
if (n < 0) goto done2;
- const intptr_t pos = buf->stream ? buf->len : 0;
- buf->len = pos + n;
- if (buf->len > buf->cap) {
- buf->cap = buf->len + buf->cap/2;
- buf->data = (char*)realloc(buf->data, (size_t)buf->cap + 1U);
+ const intptr_t pos = ss->overwrite ? 0 : ss->len;
+ ss->len = pos + n;
+ if (ss->len > ss->cap) {
+ ss->cap = ss->len + ss->cap/2;
+ ss->data = (char*)realloc(ss->data, (size_t)ss->cap + 1U);
}
- vsprintf(buf->data + pos, fmt, args2);
+ vsprintf(ss->data + pos, fmt, args2);
done2: va_end(args2);
done1: va_end(args);
}
-FMT_API int _fmt_parse(char* p, int nargs, const char *fmt, ...) {
+int _fmt_parse(char* p, int nargs, const char *fmt, ...) {
char *arg, *p0, ch;
int n = 0, empty;
va_list args;
@@ -273,3 +285,4 @@ FMT_API int _fmt_parse(char* p, int nargs, const char *fmt, ...) {
}
#endif
#endif
+#undef i_implement
diff --git a/include/stc/algo/coroutine.h b/include/stc/algo/coroutine.h
deleted file mode 100644
index b0ecd6b7..00000000
--- a/include/stc/algo/coroutine.h
+++ /dev/null
@@ -1,117 +0,0 @@
-/* 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.
- */
-#ifndef STC_COROUTINE_INCLUDED
-#define STC_COROUTINE_INCLUDED
-/*
-#include <stdio.h>
-#include <stc/algo/coroutine.h>
-
-struct iterate {
- int max_x, max_y;
- int x, y;
- int cco_state; // required member
-};
-
-bool iterate(struct iterate* I) {
- cco_begin(I);
- for (I->x = 0; I->x < I->max_x; I->x++)
- for (I->y = 0; I->y < I->max_y; I->y++)
- cco_yield(true);
-
- cco_final:
- puts("final");
- cco_end(false);
-}
-
-int main(void) {
- struct iterate it = {.max_x=3, .max_y=3};
- int n = 0;
- while (iterate(&it))
- {
- printf("%d %d\n", it.x, it.y);
- // example of early stop:
- if (++n == 20) cco_stop(&it); // signal to stop at next
- }
- return 0;
-}
-*/
-#include <stc/ccommon.h>
-
-enum {
- cco_state_final = -1,
- cco_state_done = -2,
-};
-
-#define cco_suspended(ctx) ((ctx)->cco_state > 0)
-#define cco_alive(ctx) ((ctx)->cco_state != cco_state_done)
-
-#define cco_begin(ctx) \
- int *_state = &(ctx)->cco_state; \
- switch (*_state) { \
- case 0:
-
-#define cco_end(retval) \
- *_state = cco_state_done; break; \
- case -99: goto _cco_final_; \
- } \
- return retval
-
-#define cco_yield(...) c_MACRO_OVERLOAD(cco_yield, __VA_ARGS__)
-#define cco_yield_1(retval) \
- do { \
- *_state = __LINE__; return retval; \
- case __LINE__:; \
- } while (0)
-
-#define cco_yield_2(corocall2, ctx2) \
- cco_yield_3(corocall2, ctx2, )
-
-#define cco_yield_3(corocall2, ctx2, retval) \
- do { \
- *_state = __LINE__; \
- do { \
- corocall2; if (cco_suspended(ctx2)) return retval; \
- case __LINE__:; \
- } while (cco_alive(ctx2)); \
- } while (0)
-
-#define cco_final \
- case cco_state_final: \
- _cco_final_
-
-#define cco_return \
- goto _cco_final_
-
-#define cco_stop(ctx) \
- do { \
- int* _state = &(ctx)->cco_state; \
- if (*_state > 0) *_state = cco_state_final; \
- } while (0)
-
-#define cco_reset(ctx) \
- do { \
- int* _state = &(ctx)->cco_state; \
- if (*_state == cco_state_done) *_state = 0; \
- } while (0)
-
-#endif
diff --git a/include/stc/algo/crange.h b/include/stc/algo/crange.h
index ca06c258..faeda162 100644
--- a/include/stc/algo/crange.h
+++ b/include/stc/algo/crange.h
@@ -25,16 +25,17 @@
#include <stc/algo/filter.h>
#include <stc/algo/crange.h>
-int main()
+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;
- c_forfilter (i, crange, crange_obj(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))
printf(" %lld", *i.ref);
@@ -44,29 +45,27 @@ int main()
#ifndef STC_CRANGE_H_INCLUDED
#define STC_CRANGE_H_INCLUDED
-#include <stc/ccommon.h>
-
-#define crange_obj(...) \
- (*(crange[]){crange_make(__VA_ARGS__)})
+#include "../ccommon.h"
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)
{ self->value = self->start; crange_iter it = {&self->value, self->end, self->step}; return it; }
-STC_INLINE crange_iter crange_end(crange* self)
+STC_INLINE crange_iter crange_end(crange* self)
{ crange_iter it = {NULL}; return it; }
-STC_INLINE void crange_next(crange_iter* it)
+STC_INLINE void crange_next(crange_iter* it)
{ *it->ref += it->step; if ((it->step > 0) == (*it->ref > it->end)) it->ref = NULL; }
#endif
diff --git a/include/stc/algo/csort.h b/include/stc/algo/csort.h
deleted file mode 100644
index 53fe9fcc..00000000
--- a/include/stc/algo/csort.h
+++ /dev/null
@@ -1,89 +0,0 @@
-/* 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 "../ccommon.h"
-#include "../priv/template.h"
-
-/* Generic Quicksort in C, performs as fast as c++ std::sort().
-template params:
-#define i_val - value type [required]
-#define i_less - less function. default: *x < *y
-#define i_tag NAME - define csort_NAME(). default {i_val}
-
-// test:
-#include <stdio.h>
-#define i_val int
-#include <stc/algo/csort.h>
-
-int main() {
- int arr[] = {23, 321, 5434, 25, 245, 1, 654, 33, 543, 21};
-
- csort_int(arr, c_arraylen(arr));
-
- for (int i = 0; i < c_arraylen(arr); i++)
- printf(" %d", arr[i]);
- puts("");
-}
-*/
-
-typedef i_val c_PASTE(c_CONCAT(csort_, i_tag), _value);
-
-static inline void c_PASTE(cisort_, i_tag)(i_val arr[], intptr_t lo, intptr_t hi) {
- for (intptr_t j = lo, i = lo + 1; i <= hi; j = i, ++i) {
- i_val key = arr[i];
- while (j >= 0 && (i_less((&key), (&arr[j])))) {
- arr[j + 1] = arr[j];
- --j;
- }
- arr[j + 1] = key;
- }
-}
-
-static inline void c_PASTE(cqsort_, i_tag)(i_val arr[], intptr_t lo, intptr_t hi) {
- intptr_t i = lo, j;
- while (lo < hi) {
- i_val pivot = arr[lo + (hi - lo)*7/16];
- j = hi;
-
- while (i <= j) {
- while (i_less((&arr[i]), (&pivot))) ++i;
- while (i_less((&pivot), (&arr[j]))) --j;
- if (i <= j) {
- c_swap(i_val, arr+i, arr+j);
- ++i; --j;
- }
- }
- if (j - lo > hi - i) {
- c_swap(intptr_t, &lo, &i);
- c_swap(intptr_t, &hi, &j);
- }
-
- if (j - lo > 64) c_PASTE(cqsort_, i_tag)(arr, lo, j);
- else if (j > lo) c_PASTE(cisort_, i_tag)(arr, lo, j);
- lo = i;
- }
-}
-
-static inline void c_PASTE(csort_, i_tag)(i_val arr[], intptr_t n)
- { c_PASTE(cqsort_, i_tag)(arr, 0, n - 1); }
-
-#include "../priv/template2.h"
diff --git a/include/stc/algo/filter.h b/include/stc/algo/filter.h
index e133577c..320cd50d 100644
--- a/include/stc/algo/filter.h
+++ b/include/stc/algo/filter.h
@@ -24,11 +24,11 @@
#include <stdio.h>
#define i_val int
#include <stc/cstack.h>
-#include <stc/calgo.h>
+#include <stc/algorithm.h>
-int main()
+int main(void)
{
- cstack_int stk = c_make(cstack_int, {1, 2, 3, 4, 5, 6, 7, 8, 9});
+ cstack_int stk = c_init(cstack_int, {1, 2, 3, 4, 5, 6, 7, 8, 9});
c_foreach (i, cstack_int, stk)
printf(" %d", *i.ref);
@@ -47,7 +47,7 @@ int main()
#ifndef STC_FILTER_H_INCLUDED
#define STC_FILTER_H_INCLUDED
-#include <stc/ccommon.h>
+#include "../ccommon.h"
// c_forfilter:
@@ -85,29 +85,42 @@ int main()
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 { \
C* _cnt = &cnt; \
- intptr_t _index = 0; \
- for (C##_iter it = C##_begin(_cnt); it.ref; ++_index) { \
+ for (C##_iter it = C##_begin(_cnt); it.ref; ) { \
if (pred) it = C##_erase_at(_cnt, it); \
else C##_next(&it); \
} \
} while (0)
-
// Use with: cstack, cvec, cdeq, cqueue:
#define c_eraseremove_if(it, C, cnt, pred) do { \
C* _cnt = &cnt; \
- intptr_t _n = 0, _index = 0; \
+ intptr_t _n = 0; \
C##_iter it = C##_begin(_cnt), _i; \
while (it.ref && !(pred)) \
- C##_next(&it), ++_index; \
- for (_i = it; it.ref; C##_next(&it), ++_index) \
+ C##_next(&it); \
+ for (_i = it; it.ref; C##_next(&it)) \
if (pred) C##_value_drop(it.ref), ++_n; \
else *_i.ref = *it.ref, C##_next(&_i); \
- _cnt->_len -= _n; \
+ C##_adjust_end_(_cnt, -_n); \
} while (0)
// ------------------------ private -------------------------
diff --git a/include/stc/algo/raii.h b/include/stc/algo/raii.h
new file mode 100644
index 00000000..584f5c59
--- /dev/null
+++ b/include/stc/algo/raii.h
@@ -0,0 +1,51 @@
+/* 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.
+*/
+#ifndef STC_RAII_INCLUDED
+#define STC_RAII_INCLUDED
+
+#define c_with(...) c_MACRO_OVERLOAD(c_with, __VA_ARGS__)
+#define c_with_2(declvar, drop) \
+ for (declvar, *_i, **_ip = &_i; _ip; _ip = 0, drop)
+#define c_with_3(declvar, pred, drop) \
+ for (declvar, *_i, **_ip = &_i; _ip && (pred); _ip = 0, drop)
+
+#define c_scope(...) c_MACRO_OVERLOAD(c_scope, __VA_ARGS__)
+#define c_scope_2(init, drop) \
+ for (int _i = (init, 1); _i; _i = 0, drop)
+#define c_scope_3(init, pred, drop) \
+ for (int _i = (init, 1); _i && (pred); _i = 0, drop)
+
+#define c_auto(...) c_MACRO_OVERLOAD(c_auto, __VA_ARGS__)
+#define c_auto_2(C, a) \
+ c_with_2(C a = C##_init(), C##_drop(&a))
+#define c_auto_3(C, a, b) \
+ c_with_2(c_EXPAND(C a = C##_init(), b = C##_init()), \
+ (C##_drop(&b), C##_drop(&a)))
+#define c_auto_4(C, a, b, c) \
+ c_with_2(c_EXPAND(C a = C##_init(), b = C##_init(), c = C##_init()), \
+ (C##_drop(&c), C##_drop(&b), C##_drop(&a)))
+#define c_auto_5(C, a, b, c, d) \
+ c_with_2(c_EXPAND(C a = C##_init(), b = C##_init(), c = C##_init(), d = C##_init()), \
+ (C##_drop(&d), C##_drop(&c), C##_drop(&b), C##_drop(&a)))
+
+#endif
diff --git a/include/stc/algo/sort.h b/include/stc/algo/sort.h
new file mode 100644
index 00000000..86c9b9f1
--- /dev/null
+++ b/include/stc/algo/sort.h
@@ -0,0 +1,123 @@
+/* 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.
+ */
+/* Generic Quicksort in C, performs as fast as c++ std::sort().
+template params:
+#define i_key - value type [required]
+#define i_less - less function. default: *x < *y
+#define i_type name - define {{name}}_sort_n(), else {{i_key}}array_sort_n().
+
+// ex1:
+#include <stdio.h>
+#define i_key int
+#include <stc/algo/sort.h>
+
+int main(void) {
+ int nums[] = {23, 321, 5434, 25, 245, 1, 654, 33, 543, 21};
+
+ intarray_sort_n(nums, c_arraylen(nums));
+
+ for (int i = 0; i < c_arraylen(nums); i++)
+ printf(" %d", nums[i]);
+ puts("");
+}
+
+// ex2:
+#define i_key int
+#define i_type IDeq
+#define i_more // retain input template params to be reused by sort.h
+#include <stc/cdeq.h>
+#include <stc/algo/sort.h>
+
+int main(void) {
+ IDeq nums = c_init(IDeq, {5434, 25, 245, 1, 654, 33, 543, 21});
+ IDeq_push_front(&nums, 23);
+ IDeq_push_front(&nums, 321);
+
+ IDeq_sort_n(&nums, IDeq_size(&nums));
+
+ c_foreach (i, IDeq, nums)
+ printf(" %d", *i.ref);
+ IDeq_drop(&nums);
+}
+*/
+#include "../ccommon.h"
+
+#if !defined i_key && defined i_val
+ #define i_key i_val
+#endif
+#ifndef i_type
+ #define i_at(arr, idx) (&arr[idx])
+ #ifndef i_tag
+ #define i_tag i_key
+ #endif
+ #define i_type c_PASTE(i_tag, s)
+ typedef i_key i_type;
+#endif
+#ifndef i_at
+ #define i_at(arr, idx) _cx_MEMB(_at_mut)(arr, idx)
+#endif
+#include "../priv/template.h"
+
+
+static inline void _cx_MEMB(_insertsort_ij)(_cx_Self* arr, intptr_t lo, intptr_t hi) {
+ for (intptr_t j = lo, i = lo + 1; i <= hi; j = i, ++i) {
+ i_key key = *i_at(arr, i);
+ while (j >= 0 && (i_less((&key), i_at(arr, j)))) {
+ *i_at(arr, j + 1) = *i_at(arr, j);
+ --j;
+ }
+ *i_at(arr, j + 1) = key;
+ }
+}
+
+static inline void _cx_MEMB(_sort_ij)(_cx_Self* arr, intptr_t lo, intptr_t hi) {
+ intptr_t i = lo, j;
+ while (lo < hi) {
+ i_key pivot = *i_at(arr, lo + (hi - lo)*7/16);
+ j = hi;
+
+ while (i <= j) {
+ while (i_less(i_at(arr, i), (&pivot))) ++i;
+ while (i_less((&pivot), i_at(arr, j))) --j;
+ if (i <= j) {
+ c_swap(i_key, i_at(arr, i), i_at(arr, j));
+ ++i; --j;
+ }
+ }
+ if (j - lo > hi - i) {
+ c_swap(intptr_t, &lo, &i);
+ c_swap(intptr_t, &hi, &j);
+ }
+
+ if (j - lo > 64) _cx_MEMB(_sort_ij)(arr, lo, j);
+ else if (j > lo) _cx_MEMB(_insertsort_ij)(arr, lo, j);
+ lo = i;
+ }
+}
+
+static inline void _cx_MEMB(_sort_n)(_cx_Self* arr, intptr_t len) {
+ _cx_MEMB(_sort_ij)(arr, 0, len - 1);
+}
+
+#include "../priv/template2.h"
+#undef i_at
diff --git a/include/stc/calgo.h b/include/stc/algorithm.h
index 21e73faf..cf3ab328 100644
--- a/include/stc/calgo.h
+++ b/include/stc/algorithm.h
@@ -1,8 +1,8 @@
#ifndef STC_CALGO_INCLUDED
#define STC_CALGO_INCLUDED
+#include "algo/raii.h"
#include "algo/crange.h"
#include "algo/filter.h"
-#include "algo/coroutine.h"
#endif
diff --git a/include/stc/carc.h b/include/stc/carc.h
index 8ef80b12..b617e1ca 100644
--- a/include/stc/carc.h
+++ b/include/stc/carc.h
@@ -22,6 +22,7 @@
*/
/* carc: atomic reference counted shared_ptr
+#define i_implement
#include <stc/cstr.h>
typedef struct { cstr name, last; } Person;
@@ -29,6 +30,11 @@ typedef struct { cstr name, last; } Person;
Person Person_make(const char* name, const char* last) {
return (Person){.name = cstr_from(name), .last = cstr_from(last)};
}
+Person Person_clone(Person p) {
+ p.name = cstr_clone(p.name);
+ p.last = cstr_clone(p.last);
+ return p;
+}
void Person_drop(Person* p) {
printf("drop: %s %s\n", cstr_str(&p->name), cstr_str(&p->last));
cstr_drop(&p->name);
@@ -36,11 +42,10 @@ void Person_drop(Person* p) {
}
#define i_type ArcPers
-#define i_key Person
-#define i_keydrop Person_drop
+#define i_valclass Person // clone, drop, cmp, hash
#include <stc/carc.h>
-int main() {
+int main(void) {
ArcPers p = ArcPers_from(Person_make("John", "Smiths"));
ArcPers q = ArcPers_clone(p); // share the pointer
@@ -48,10 +53,11 @@ int main() {
c_drop(ArcPers, &p, &q);
}
*/
-#include "ccommon.h"
+#include "priv/linkage.h"
#ifndef CARC_H_INCLUDED
#define CARC_H_INCLUDED
+#include "ccommon.h"
#include "forward.h"
#include <stdlib.h>
@@ -71,19 +77,18 @@ int main() {
#define c_atomic_dec_and_test(v) (atomic_fetch_sub(v, 1) == 1)
#endif
-#define carc_NULL {NULL, NULL}
+#define carc_null {0}
#endif // CARC_H_INCLUDED
-#ifndef _i_prefix
#define _i_prefix carc_
-#endif
-#ifdef i_eq
-#define _i_eq
-#endif
+#define _i_carc
#include "priv/template.h"
typedef i_keyraw _cx_raw;
-#if !c_option(c_no_atomic)
+#if c_option(c_no_atomic)
+ #define i_no_atomic
+#endif
+#if !defined i_no_atomic
#define _i_atomic_inc(v) c_atomic_inc(v)
#define _i_atomic_dec_and_test(v) c_atomic_dec_and_test(v)
#else
@@ -91,123 +96,127 @@ typedef i_keyraw _cx_raw;
#define _i_atomic_dec_and_test(v) !(--*(v))
#endif
#ifndef i_is_forward
-_cx_deftypes(_c_carc_types, _cx_self, i_key);
+_cx_DEFTYPES(_c_carc_types, _cx_Self, i_key);
#endif
-struct _cx_memb(_rep_) { catomic_long counter; i_key value; };
+struct _cx_MEMB(_rep_) { catomic_long counter; i_key value; };
-STC_INLINE _cx_self _cx_memb(_init)(void)
- { return c_LITERAL(_cx_self){NULL, NULL}; }
+STC_INLINE _cx_Self _cx_MEMB(_init)(void)
+ { return c_LITERAL(_cx_Self){NULL, NULL}; }
-STC_INLINE long _cx_memb(_use_count)(const _cx_self* self)
+STC_INLINE long _cx_MEMB(_use_count)(const _cx_Self* self)
{ return self->use_count ? *self->use_count : 0; }
-STC_INLINE _cx_self _cx_memb(_from_ptr)(_cx_value* p) {
- _cx_self ptr = {p};
+STC_INLINE _cx_Self _cx_MEMB(_from_ptr)(_cx_value* p) {
+ _cx_Self ptr = {p};
if (p)
*(ptr.use_count = _i_alloc(catomic_long)) = 1;
return ptr;
}
// c++: std::make_shared<_cx_value>(val)
-STC_INLINE _cx_self _cx_memb(_make)(_cx_value val) {
- _cx_self ptr;
- struct _cx_memb(_rep_)* rep = _i_alloc(struct _cx_memb(_rep_));
+STC_INLINE _cx_Self _cx_MEMB(_make)(_cx_value val) {
+ _cx_Self ptr;
+ struct _cx_MEMB(_rep_)* rep = _i_alloc(struct _cx_MEMB(_rep_));
*(ptr.use_count = &rep->counter) = 1;
*(ptr.get = &rep->value) = val;
return ptr;
}
-STC_INLINE _cx_raw _cx_memb(_toraw)(const _cx_self* self)
+STC_INLINE _cx_raw _cx_MEMB(_toraw)(const _cx_Self* self)
{ return i_keyto(self->get); }
-STC_INLINE _cx_self _cx_memb(_move)(_cx_self* self) {
- _cx_self ptr = *self;
+STC_INLINE _cx_Self _cx_MEMB(_move)(_cx_Self* self) {
+ _cx_Self ptr = *self;
self->get = NULL, self->use_count = NULL;
return ptr;
}
-STC_INLINE void _cx_memb(_drop)(_cx_self* self) {
+STC_INLINE void _cx_MEMB(_drop)(_cx_Self* self) {
if (self->use_count && _i_atomic_dec_and_test(self->use_count)) {
i_keydrop(self->get);
- if ((char *)self->get != (char *)self->use_count + offsetof(struct _cx_memb(_rep_), value))
+ if ((char *)self->get != (char *)self->use_count + offsetof(struct _cx_MEMB(_rep_), value))
i_free(self->get);
i_free((long*)self->use_count);
}
}
-STC_INLINE void _cx_memb(_reset)(_cx_self* self) {
- _cx_memb(_drop)(self);
+STC_INLINE void _cx_MEMB(_reset)(_cx_Self* self) {
+ _cx_MEMB(_drop)(self);
self->use_count = NULL, self->get = NULL;
}
-STC_INLINE void _cx_memb(_reset_to)(_cx_self* self, _cx_value* p) {
- _cx_memb(_drop)(self);
- *self = _cx_memb(_from_ptr)(p);
+STC_INLINE void _cx_MEMB(_reset_to)(_cx_Self* self, _cx_value* p) {
+ _cx_MEMB(_drop)(self);
+ *self = _cx_MEMB(_from_ptr)(p);
}
#ifndef i_no_emplace
-STC_INLINE _cx_self _cx_memb(_from)(_cx_raw raw)
- { return _cx_memb(_make)(i_keyfrom(raw)); }
+STC_INLINE _cx_Self _cx_MEMB(_from)(_cx_raw raw)
+ { return _cx_MEMB(_make)(i_keyfrom(raw)); }
#else
-STC_INLINE _cx_self _cx_memb(_from)(_cx_value val)
- { return _cx_memb(_make)(val); }
+STC_INLINE _cx_Self _cx_MEMB(_from)(_cx_value val)
+ { return _cx_MEMB(_make)(val); }
#endif
// does not use i_keyclone, so OK to always define.
-STC_INLINE _cx_self _cx_memb(_clone)(_cx_self ptr) {
+STC_INLINE _cx_Self _cx_MEMB(_clone)(_cx_Self ptr) {
if (ptr.use_count)
_i_atomic_inc(ptr.use_count);
return ptr;
}
// take ownership of unowned
-STC_INLINE void _cx_memb(_take)(_cx_self* self, _cx_self unowned) {
- _cx_memb(_drop)(self);
+STC_INLINE void _cx_MEMB(_take)(_cx_Self* self, _cx_Self unowned) {
+ _cx_MEMB(_drop)(self);
*self = unowned;
}
// share ownership with ptr
-STC_INLINE void _cx_memb(_assign)(_cx_self* self, _cx_self ptr) {
+STC_INLINE void _cx_MEMB(_assign)(_cx_Self* self, _cx_Self ptr) {
if (ptr.use_count)
_i_atomic_inc(ptr.use_count);
- _cx_memb(_drop)(self);
+ _cx_MEMB(_drop)(self);
*self = ptr;
}
-#ifndef i_no_cmp
-STC_INLINE int _cx_memb(_raw_cmp)(const _cx_raw* rx, const _cx_raw* ry)
- { return i_cmp(rx, ry); }
+#if defined i_use_cmp
+ STC_INLINE int _cx_MEMB(_raw_cmp)(const _cx_raw* rx, const _cx_raw* ry)
+ { return i_cmp(rx, ry); }
-STC_INLINE int _cx_memb(_cmp)(const _cx_self* self, const _cx_self* other) {
- _cx_raw rx = i_keyto(self->get), ry = i_keyto(other->get);
- return i_cmp((&rx), (&ry));
-}
-#endif
+ STC_INLINE int _cx_MEMB(_cmp)(const _cx_Self* self, const _cx_Self* other) {
+ _cx_raw rx = i_keyto(self->get), ry = i_keyto(other->get);
+ return i_cmp((&rx), (&ry));
+ }
-#ifdef _i_eq
-STC_INLINE bool _cx_memb(_raw_eq)(const _cx_raw* rx, const _cx_raw* ry)
- { return i_eq(rx, ry); }
+ STC_INLINE bool _cx_MEMB(_raw_eq)(const _cx_raw* rx, const _cx_raw* ry)
+ { return i_eq(rx, ry); }
-STC_INLINE bool _cx_memb(_eq)(const _cx_self* self, const _cx_self* other) {
- _cx_raw rx = i_keyto(self->get), ry = i_keyto(other->get);
- return i_eq((&rx), (&ry));
-}
-#elif !defined i_no_cmp
-STC_INLINE bool _cx_memb(_raw_eq)(const _cx_raw* rx, const _cx_raw* ry)
- { return i_cmp(rx, ry) == 0; }
+ STC_INLINE bool _cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other) {
+ _cx_raw rx = i_keyto(self->get), ry = i_keyto(other->get);
+ return i_eq((&rx), (&ry));
+ }
-STC_INLINE bool _cx_memb(_eq)(const _cx_self* self, const _cx_self* other)
- { return _cx_memb(_cmp)(self, other) == 0; }
-#endif
+ #ifndef i_no_hash
+ STC_INLINE uint64_t _cx_MEMB(_raw_hash)(const _cx_raw* rx)
+ { return i_hash(rx); }
-#ifndef i_no_hash
-STC_INLINE uint64_t _cx_memb(_raw_hash)(const _cx_raw* rx)
- { return i_hash(rx); }
+ STC_INLINE uint64_t _cx_MEMB(_hash)(const _cx_Self* self)
+ { _cx_raw rx = i_keyto(self->get); return i_hash((&rx)); }
+ #endif // i_no_hash
-STC_INLINE uint64_t _cx_memb(_hash)(const _cx_self* self)
- { _cx_raw rx = i_keyto(self->get); return i_hash((&rx)); }
-#endif
+#else
-#undef _i_eq
+ STC_INLINE int _cx_MEMB(_cmp)(const _cx_Self* self, const _cx_Self* other) {
+ return c_default_cmp(&self->get, &other->get);
+ }
+ STC_INLINE bool _cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other) {
+ return self->get == other->get;
+ }
+ STC_INLINE uint64_t _cx_MEMB(_hash)(const _cx_Self* self)
+ { return c_default_hash(&self->get); }
+#endif // i_use_cmp
+
+#include "priv/template2.h"
+#undef i_no_atomic
#undef _i_atomic_inc
#undef _i_atomic_dec_and_test
-#include "priv/template2.h"
+#undef _i_carc
diff --git a/include/stc/cbits.h b/include/stc/cbits.h
index 826df847..3b5785d3 100644
--- a/include/stc/cbits.h
+++ b/include/stc/cbits.h
@@ -26,12 +26,12 @@ Similar to boost::dynamic_bitset / std::bitset
#include <stdio.h>
#include "cbits.h"
-int main() {
+int main(void) {
cbits bset = cbits_with_size(23, true);
cbits_reset(&bset, 9);
cbits_resize(&bset, 43, false);
- printf("%4zu: ", cbits_size(&bset));
+ printf("%4lld: ", cbits_size(&bset));
c_forrange (i, cbits_size(&bset))
printf("%d", cbits_at(&bset, i));
puts("");
@@ -41,7 +41,7 @@ int main() {
cbits_resize(&bset, 102, true);
cbits_set_value(&bset, 99, false);
- printf("%4zu: ", cbits_size(&bset));
+ printf("%4lld: ", cbits_size(&bset));
c_forrange (i, cbits_size(&bset))
printf("%d", cbits_at(&bset, i));
puts("");
@@ -54,11 +54,8 @@ int main() {
#include <stdlib.h>
#include <string.h>
-#ifndef i_ssize
-#define i_ssize intptr_t
-#endif
#define _cbits_bit(i) ((uint64_t)1 << ((i) & 63))
-#define _cbits_words(n) (i_ssize)(((n) + 63)>>6)
+#define _cbits_words(n) (_llong)(((n) + 63)>>6)
#define _cbits_bytes(n) (_cbits_words(n) * c_sizeof(uint64_t))
#if defined(__GNUC__)
@@ -80,23 +77,23 @@ int main() {
}
#endif
-STC_INLINE i_ssize _cbits_count(const uint64_t* set, const i_ssize sz) {
- const i_ssize n = sz>>6;
- i_ssize count = 0;
- for (i_ssize i = 0; i < n; ++i)
+STC_INLINE _llong _cbits_count(const uint64_t* set, const _llong sz) {
+ const _llong n = sz>>6;
+ _llong count = 0;
+ for (_llong i = 0; i < n; ++i)
count += cpopcount64(set[i]);
if (sz & 63)
count += cpopcount64(set[n] & (_cbits_bit(sz) - 1));
return count;
}
-STC_INLINE char* _cbits_to_str(const uint64_t* set, const i_ssize sz,
- char* out, i_ssize start, i_ssize stop) {
+STC_INLINE char* _cbits_to_str(const uint64_t* set, const _llong sz,
+ char* out, _llong start, _llong stop) {
if (stop > sz) stop = sz;
- assert(start <= stop);
+ c_assert(start <= stop);
c_memset(out, '0', stop - start);
- for (i_ssize i = start; i < stop; ++i)
+ for (_llong i = start; i < stop; ++i)
if ((set[i>>6] & _cbits_bit(i)) != 0)
out[i - start] = '1';
out[stop - start] = '\0';
@@ -104,8 +101,8 @@ STC_INLINE char* _cbits_to_str(const uint64_t* set, const i_ssize sz,
}
#define _cbits_OPR(OPR, VAL) \
- const i_ssize n = sz>>6; \
- for (i_ssize i = 0; i < n; ++i) \
+ const _llong n = sz>>6; \
+ for (_llong i = 0; i < n; ++i) \
if ((set[i] OPR other[i]) != VAL) \
return false; \
if (!(sz & 63)) \
@@ -113,10 +110,10 @@ STC_INLINE char* _cbits_to_str(const uint64_t* set, const i_ssize sz,
const uint64_t i = (uint64_t)n, m = _cbits_bit(sz) - 1; \
return ((set[i] OPR other[i]) & m) == (VAL & m)
-STC_INLINE bool _cbits_subset_of(const uint64_t* set, const uint64_t* other, const i_ssize sz)
+STC_INLINE bool _cbits_subset_of(const uint64_t* set, const uint64_t* other, const _llong sz)
{ _cbits_OPR(|, set[i]); }
-STC_INLINE bool _cbits_disjoint(const uint64_t* set, const uint64_t* other, const i_ssize sz)
+STC_INLINE bool _cbits_disjoint(const uint64_t* set, const uint64_t* other, const _llong sz)
{ _cbits_OPR(&, 0); }
#endif // CBITS_H_INCLUDED
@@ -125,15 +122,14 @@ STC_INLINE bool _cbits_disjoint(const uint64_t* set, const uint64_t* other, cons
#if !defined i_capacity // DYNAMIC SIZE BITARRAY
-#define _i_assert(x) assert(x)
+#define _i_assert(x) c_assert(x)
#define i_type cbits
-struct { uint64_t *data64; i_ssize _size; } typedef i_type;
+typedef struct { uint64_t *data64; _llong _size; } i_type;
STC_INLINE cbits cbits_init(void) { return c_LITERAL(cbits){NULL}; }
-STC_INLINE void cbits_create(cbits* self) { self->data64 = NULL; self->_size = 0; }
STC_INLINE void cbits_drop(cbits* self) { c_free(self->data64); }
-STC_INLINE i_ssize cbits_size(const cbits* self) { return self->_size; }
+STC_INLINE _llong cbits_size(const cbits* self) { return self->_size; }
STC_INLINE cbits* cbits_take(cbits* self, cbits other) {
if (self->data64 != other.data64) {
@@ -144,7 +140,7 @@ STC_INLINE cbits* cbits_take(cbits* self, cbits other) {
}
STC_INLINE cbits cbits_clone(cbits other) {
- const i_ssize bytes = _cbits_bytes(other._size);
+ const _llong bytes = _cbits_bytes(other._size);
cbits set = {(uint64_t *)c_memcpy(c_malloc(bytes), other.data64, bytes), other._size};
return set;
}
@@ -158,16 +154,16 @@ STC_INLINE cbits* cbits_copy(cbits* self, const cbits* other) {
return self;
}
-STC_INLINE void cbits_resize(cbits* self, const i_ssize size, const bool value) {
- const i_ssize new_n = _cbits_words(size), osize = self->_size, old_n = _cbits_words(osize);
+STC_INLINE void cbits_resize(cbits* self, const _llong size, const bool value) {
+ const _llong new_n = _cbits_words(size), osize = self->_size, old_n = _cbits_words(osize);
self->data64 = (uint64_t *)c_realloc(self->data64, new_n*8);
self->_size = size;
if (new_n >= old_n) {
c_memset(self->data64 + old_n, -(int)value, (new_n - old_n)*8);
if (old_n > 0) {
- uint64_t m = _cbits_bit(osize) - 1; /* mask */
- value ? (self->data64[old_n - 1] |= ~m)
- : (self->data64[old_n - 1] &= m);
+ uint64_t mask = _cbits_bit(osize) - 1;
+ if (value) self->data64[old_n - 1] |= ~mask;
+ else self->data64[old_n - 1] &= mask;
}
}
}
@@ -181,13 +177,13 @@ STC_INLINE cbits cbits_move(cbits* self) {
return tmp;
}
-STC_INLINE cbits cbits_with_size(const i_ssize size, const bool value) {
+STC_INLINE cbits cbits_with_size(const _llong size, const bool value) {
cbits set = {(uint64_t *)c_malloc(_cbits_bytes(size)), size};
cbits_set_all(&set, value);
return set;
}
-STC_INLINE cbits cbits_with_pattern(const i_ssize size, const uint64_t pattern) {
+STC_INLINE cbits cbits_with_pattern(const _llong size, const uint64_t pattern) {
cbits set = {(uint64_t *)c_malloc(_cbits_bytes(size)), size};
cbits_set_pattern(&set, pattern);
return set;
@@ -200,12 +196,11 @@ STC_INLINE cbits cbits_with_pattern(const i_ssize size, const uint64_t pattern)
#define i_type c_PASTE(cbits, i_capacity)
#endif
-struct { uint64_t data64[(i_capacity - 1)/64 + 1]; } typedef i_type;
+typedef struct { uint64_t data64[(i_capacity - 1)/64 + 1]; } i_type;
-STC_INLINE i_type _i_memb(_init)(void) { return c_LITERAL(i_type){0}; }
-STC_INLINE void _i_memb(_create)(i_type* self) {}
+STC_INLINE void _i_memb(_init)(i_type* self) { memset(self->data64, 0, i_capacity*8); }
STC_INLINE void _i_memb(_drop)(i_type* self) {}
-STC_INLINE i_ssize _i_memb(_size)(const i_type* self) { return i_capacity; }
+STC_INLINE _llong _i_memb(_size)(const i_type* self) { return i_capacity; }
STC_INLINE i_type _i_memb(_move)(i_type* self) { return *self; }
STC_INLINE i_type* _i_memb(_take)(i_type* self, i_type other)
@@ -216,18 +211,18 @@ STC_INLINE i_type _i_memb(_clone)(i_type other)
STC_INLINE i_type* _i_memb(_copy)(i_type* self, const i_type* other)
{ *self = *other; return self; }
-
+
STC_INLINE void _i_memb(_set_all)(i_type *self, const bool value);
STC_INLINE void _i_memb(_set_pattern)(i_type *self, const uint64_t pattern);
-STC_INLINE i_type _i_memb(_with_size)(const i_ssize size, const bool value) {
- assert(size <= i_capacity);
+STC_INLINE i_type _i_memb(_with_size)(const _llong size, const bool value) {
+ c_assert(size <= i_capacity);
i_type set; _i_memb(_set_all)(&set, value);
return set;
}
-STC_INLINE i_type _i_memb(_with_pattern)(const i_ssize size, const uint64_t pattern) {
- assert(size <= i_capacity);
+STC_INLINE i_type _i_memb(_with_pattern)(const _llong size, const uint64_t pattern) {
+ c_assert(size <= i_capacity);
i_type set; _i_memb(_set_pattern)(&set, pattern);
return set;
}
@@ -239,36 +234,36 @@ STC_INLINE void _i_memb(_set_all)(i_type *self, const bool value)
{ c_memset(self->data64, value? ~0 : 0, _cbits_bytes(_i_memb(_size)(self))); }
STC_INLINE void _i_memb(_set_pattern)(i_type *self, const uint64_t pattern) {
- i_ssize n = _cbits_words(_i_memb(_size)(self));
+ _llong n = _cbits_words(_i_memb(_size)(self));
while (n--) self->data64[n] = pattern;
}
-STC_INLINE bool _i_memb(_test)(const i_type* self, const i_ssize i)
+STC_INLINE bool _i_memb(_test)(const i_type* self, const _llong i)
{ return (self->data64[i>>6] & _cbits_bit(i)) != 0; }
-STC_INLINE bool _i_memb(_at)(const i_type* self, const i_ssize i)
+STC_INLINE bool _i_memb(_at)(const i_type* self, const _llong i)
{ return (self->data64[i>>6] & _cbits_bit(i)) != 0; }
-STC_INLINE void _i_memb(_set)(i_type *self, const i_ssize i)
+STC_INLINE void _i_memb(_set)(i_type *self, const _llong i)
{ self->data64[i>>6] |= _cbits_bit(i); }
-STC_INLINE void _i_memb(_reset)(i_type *self, const i_ssize i)
+STC_INLINE void _i_memb(_reset)(i_type *self, const _llong i)
{ self->data64[i>>6] &= ~_cbits_bit(i); }
-STC_INLINE void _i_memb(_set_value)(i_type *self, const i_ssize i, const bool b) {
+STC_INLINE void _i_memb(_set_value)(i_type *self, const _llong i, const bool b) {
self->data64[i>>6] ^= ((uint64_t)-(int)b ^ self->data64[i>>6]) & _cbits_bit(i);
}
-STC_INLINE void _i_memb(_flip)(i_type *self, const i_ssize i)
+STC_INLINE void _i_memb(_flip)(i_type *self, const _llong i)
{ self->data64[i>>6] ^= _cbits_bit(i); }
STC_INLINE void _i_memb(_flip_all)(i_type *self) {
- i_ssize n = _cbits_words(_i_memb(_size)(self));
+ _llong n = _cbits_words(_i_memb(_size)(self));
while (n--) self->data64[n] ^= ~(uint64_t)0;
}
STC_INLINE i_type _i_memb(_from)(const char* str) {
- int64_t n = c_strlen(str);
+ _llong n = c_strlen(str);
i_type set = _i_memb(_with_size)(n, false);
while (n--) if (str[n] == '1') _i_memb(_set)(&set, n);
return set;
@@ -277,26 +272,26 @@ STC_INLINE i_type _i_memb(_from)(const char* str) {
/* Intersection */
STC_INLINE void _i_memb(_intersect)(i_type *self, const i_type* other) {
_i_assert(self->_size == other->_size);
- i_ssize n = _cbits_words(_i_memb(_size)(self));
+ _llong n = _cbits_words(_i_memb(_size)(self));
while (n--) self->data64[n] &= other->data64[n];
}
/* Union */
STC_INLINE void _i_memb(_union)(i_type *self, const i_type* other) {
_i_assert(self->_size == other->_size);
- i_ssize n = _cbits_words(_i_memb(_size)(self));
+ _llong n = _cbits_words(_i_memb(_size)(self));
while (n--) self->data64[n] |= other->data64[n];
}
/* Exclusive disjunction */
STC_INLINE void _i_memb(_xor)(i_type *self, const i_type* other) {
_i_assert(self->_size == other->_size);
- i_ssize n = _cbits_words(_i_memb(_size)(self));
+ _llong n = _cbits_words(_i_memb(_size)(self));
while (n--) self->data64[n] ^= other->data64[n];
}
-STC_INLINE int64_t _i_memb(_count)(const i_type* self)
+STC_INLINE _llong _i_memb(_count)(const i_type* self)
{ return _cbits_count(self->data64, _i_memb(_size)(self)); }
-STC_INLINE char* _i_memb(_to_str)(const i_type* self, char* out, int64_t start, int64_t stop)
+STC_INLINE char* _i_memb(_to_str)(const i_type* self, char* out, _llong start, _llong stop)
{ return _cbits_to_str(self->data64, _i_memb(_size)(self), out, start, stop); }
STC_INLINE bool _i_memb(_subset_of)(const i_type* self, const i_type* other) {
@@ -312,7 +307,6 @@ STC_INLINE bool _i_memb(_disjoint)(const i_type* self, const i_type* other) {
#pragma GCC diagnostic pop
#endif
#define CBITS_H_INCLUDED
-#undef _i_size
#undef _i_memb
#undef _i_assert
#undef i_capacity
diff --git a/include/stc/cbox.h b/include/stc/cbox.h
index ca88fc66..55ce9711 100644
--- a/include/stc/cbox.h
+++ b/include/stc/cbox.h
@@ -23,7 +23,9 @@
*/
/* cbox: heap allocated boxed type
+#define i_implement
#include <stc/cstr.h>
+#include <stc/algo/raii.h> // c_auto
typedef struct { cstr name, email; } Person;
@@ -40,11 +42,11 @@ void Person_drop(Person* p) {
c_drop(cstr, &p->name, &p->email);
}
-#define i_keyclass Person // bind Person clone+drop fn's
#define i_type PBox
+#define i_valclass Person // bind Person clone+drop fn's
#include <stc/cbox.h>
-int main() {
+int main(void) {
c_auto (PBox, p, q)
{
p = PBox_from(Person_from("John Smiths", "[email protected]"));
@@ -56,142 +58,142 @@ int main() {
}
}
*/
-#include "ccommon.h"
+#include "priv/linkage.h"
#ifndef CBOX_H_INCLUDED
#define CBOX_H_INCLUDED
+#include "ccommon.h"
#include "forward.h"
#include <stdlib.h>
#include <string.h>
-#define cbox_NULL {NULL}
+#define cbox_null {0}
#endif // CBOX_H_INCLUDED
-#ifndef _i_prefix
#define _i_prefix cbox_
-#endif
-#ifdef i_eq
-#define _i_eq
-#endif
+#define _i_cbox
#include "priv/template.h"
typedef i_keyraw _cx_raw;
#ifndef i_is_forward
-_cx_deftypes(_c_cbox_types, _cx_self, i_key);
+_cx_DEFTYPES(_c_cbox_types, _cx_Self, i_key);
#endif
// constructors (take ownership)
-STC_INLINE _cx_self _cx_memb(_init)(void)
- { return c_LITERAL(_cx_self){NULL}; }
+STC_INLINE _cx_Self _cx_MEMB(_init)(void)
+ { return c_LITERAL(_cx_Self){NULL}; }
-STC_INLINE long _cx_memb(_use_count)(const _cx_self* self)
+STC_INLINE long _cx_MEMB(_use_count)(const _cx_Self* self)
{ return (long)(self->get != NULL); }
-STC_INLINE _cx_self _cx_memb(_from_ptr)(_cx_value* p)
- { return c_LITERAL(_cx_self){p}; }
+STC_INLINE _cx_Self _cx_MEMB(_from_ptr)(_cx_value* p)
+ { return c_LITERAL(_cx_Self){p}; }
// c++: std::make_unique<i_key>(val)
-STC_INLINE _cx_self _cx_memb(_make)(_cx_value val) {
- _cx_self ptr = {_i_alloc(_cx_value)};
+STC_INLINE _cx_Self _cx_MEMB(_make)(_cx_value val) {
+ _cx_Self ptr = {_i_alloc(_cx_value)};
*ptr.get = val; return ptr;
}
-STC_INLINE _cx_raw _cx_memb(_toraw)(const _cx_self* self)
+STC_INLINE _cx_raw _cx_MEMB(_toraw)(const _cx_Self* self)
{ return i_keyto(self->get); }
// destructor
-STC_INLINE void _cx_memb(_drop)(_cx_self* self) {
+STC_INLINE void _cx_MEMB(_drop)(_cx_Self* self) {
if (self->get) {
i_keydrop(self->get);
i_free(self->get);
}
}
-STC_INLINE _cx_self _cx_memb(_move)(_cx_self* self) {
- _cx_self ptr = *self;
+STC_INLINE _cx_Self _cx_MEMB(_move)(_cx_Self* self) {
+ _cx_Self ptr = *self;
self->get = NULL;
return ptr;
}
-STC_INLINE _cx_value* _cx_memb(_release)(_cx_self* self)
- { return _cx_memb(_move)(self).get; }
+STC_INLINE _cx_value* _cx_MEMB(_release)(_cx_Self* self)
+ { return _cx_MEMB(_move)(self).get; }
-STC_INLINE void _cx_memb(_reset)(_cx_self* self) {
- _cx_memb(_drop)(self);
+STC_INLINE void _cx_MEMB(_reset)(_cx_Self* self) {
+ _cx_MEMB(_drop)(self);
self->get = NULL;
}
// take ownership of p
-STC_INLINE void _cx_memb(_reset_to)(_cx_self* self, _cx_value* p) {
- _cx_memb(_drop)(self);
+STC_INLINE void _cx_MEMB(_reset_to)(_cx_Self* self, _cx_value* p) {
+ _cx_MEMB(_drop)(self);
self->get = p;
}
#ifndef i_no_emplace
-STC_INLINE _cx_self _cx_memb(_from)(_cx_raw raw)
- { return _cx_memb(_make)(i_keyfrom(raw)); }
+STC_INLINE _cx_Self _cx_MEMB(_from)(_cx_raw raw)
+ { return _cx_MEMB(_make)(i_keyfrom(raw)); }
#else
-STC_INLINE _cx_self _cx_memb(_from)(_cx_value val)
- { return _cx_memb(_make)(val); }
+STC_INLINE _cx_Self _cx_MEMB(_from)(_cx_value val)
+ { return _cx_MEMB(_make)(val); }
#endif
#if !defined i_no_clone
- STC_INLINE _cx_self _cx_memb(_clone)(_cx_self other) {
+ STC_INLINE _cx_Self _cx_MEMB(_clone)(_cx_Self other) {
if (!other.get)
return other;
- _cx_self out = {_i_alloc(i_key)};
+ _cx_Self out = {_i_alloc(i_key)};
*out.get = i_keyclone((*other.get));
return out;
}
#endif // !i_no_clone
// take ownership of unowned
-STC_INLINE void _cx_memb(_take)(_cx_self* self, _cx_self unowned) {
- _cx_memb(_drop)(self);
+STC_INLINE void _cx_MEMB(_take)(_cx_Self* self, _cx_Self unowned) {
+ _cx_MEMB(_drop)(self);
*self = unowned;
}
// transfer ownership from moved; set moved to NULL
-STC_INLINE void _cx_memb(_assign)(_cx_self* self, _cx_self* moved) {
+STC_INLINE void _cx_MEMB(_assign)(_cx_Self* self, _cx_Self* moved) {
if (moved->get == self->get)
return;
- _cx_memb(_drop)(self);
+ _cx_MEMB(_drop)(self);
*self = *moved;
moved->get = NULL;
}
-#ifndef i_no_cmp
-STC_INLINE int _cx_memb(_raw_cmp)(const _cx_raw* rx, const _cx_raw* ry)
- { return i_cmp(rx, ry); }
+#if defined i_use_cmp
+ STC_INLINE int _cx_MEMB(_raw_cmp)(const _cx_raw* rx, const _cx_raw* ry)
+ { return i_cmp(rx, ry); }
-STC_INLINE int _cx_memb(_cmp)(const _cx_self* self, const _cx_self* other) {
- _cx_raw rx = i_keyto(self->get), ry = i_keyto(other->get);
- return i_cmp((&rx), (&ry));
-}
-#endif
+ STC_INLINE int _cx_MEMB(_cmp)(const _cx_Self* self, const _cx_Self* other) {
+ _cx_raw rx = i_keyto(self->get), ry = i_keyto(other->get);
+ return i_cmp((&rx), (&ry));
+ }
-#ifdef _i_eq
-STC_INLINE bool _cx_memb(_raw_eq)(const _cx_raw* rx, const _cx_raw* ry)
- { return i_eq(rx, ry); }
+ STC_INLINE bool _cx_MEMB(_raw_eq)(const _cx_raw* rx, const _cx_raw* ry)
+ { return i_eq(rx, ry); }
-STC_INLINE bool _cx_memb(_eq)(const _cx_self* self, const _cx_self* other) {
- _cx_raw rx = i_keyto(self->get), ry = i_keyto(other->get);
- return i_eq((&rx), (&ry));
-}
-#elif !defined i_no_cmp
-STC_INLINE bool _cx_memb(_raw_eq)(const _cx_raw* rx, const _cx_raw* ry)
- { return i_cmp(rx, ry) == 0; }
+ STC_INLINE bool _cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other) {
+ _cx_raw rx = i_keyto(self->get), ry = i_keyto(other->get);
+ return i_eq((&rx), (&ry));
+ }
-STC_INLINE bool _cx_memb(_eq)(const _cx_self* self, const _cx_self* other)
- { return _cx_memb(_cmp)(self, other) == 0; }
-#endif
+ #ifndef i_no_hash
+ STC_INLINE uint64_t _cx_MEMB(_raw_hash)(const _cx_raw* rx)
+ { return i_hash(rx); }
-#ifndef i_no_hash
-STC_INLINE uint64_t _cx_memb(_raw_hash)(const _cx_raw* rx)
- { return i_hash(rx); }
+ STC_INLINE uint64_t _cx_MEMB(_hash)(const _cx_Self* self)
+ { _cx_raw rx = i_keyto(self->get); return i_hash((&rx)); }
+ #endif // i_no_hash
-STC_INLINE uint64_t _cx_memb(_hash)(const _cx_self* self)
- { _cx_raw rx = i_keyto(self->get); return i_hash((&rx)); }
-#endif
+#else
+
+ STC_INLINE int _cx_MEMB(_cmp)(const _cx_Self* self, const _cx_Self* other) {
+ return c_default_cmp(&self->get, &other->get);
+ }
+ STC_INLINE bool _cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other) {
+ return self->get == other->get;
+ }
+ STC_INLINE uint64_t _cx_MEMB(_hash)(const _cx_Self* self)
+ { return c_default_hash(&self->get); }
+#endif // i_use_cmp
-#undef _i_eq
#include "priv/template2.h"
+#undef _i_cbox
diff --git a/include/stc/ccommon.h b/include/stc/ccommon.h
index d5508807..0a8c439a 100644
--- a/include/stc/ccommon.h
+++ b/include/stc/ccommon.h
@@ -29,17 +29,11 @@
#include <stdbool.h>
#include <string.h>
#include <assert.h>
-#include "priv/altnames.h"
-#include "priv/raii.h"
+typedef long long _llong;
#define c_NPOS INTPTR_MAX
#define c_ZI PRIiPTR
#define c_ZU PRIuPTR
-#if defined STC_NDEBUG || defined NDEBUG
- #define c_ASSERT(expr) (void)(0)
-#else
- #define c_ASSERT(expr) assert(expr)
-#endif
#if defined(_MSC_VER)
#pragma warning(disable: 4116 4996) // unnamed type definition in parentheses
@@ -63,7 +57,7 @@
#define _c_ARG_N(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, \
_14, _15, _16, N, ...) N
-#ifdef __cplusplus
+#ifdef __cplusplus
#include <new>
#define _i_alloc(T) static_cast<T*>(i_malloc(c_sizeof(T)))
#define _i_new(T, ...) new (_i_alloc(T)) T(__VA_ARGS__)
@@ -71,39 +65,45 @@
#define c_LITERAL(T) T
#else
#define _i_alloc(T) ((T*)i_malloc(c_sizeof(T)))
- #define _i_new(T, ...) ((T*)memcpy(_i_alloc(T), (T[]){__VA_ARGS__}, sizeof(T)))
- #define c_new(T, ...) ((T*)memcpy(malloc(sizeof(T)), (T[]){__VA_ARGS__}, sizeof(T)))
+ #define _i_new(T, ...) ((T*)memcpy(_i_alloc(T), ((T[]){__VA_ARGS__}), sizeof(T)))
+ #define c_new(T, ...) ((T*)memcpy(malloc(sizeof(T)), ((T[]){__VA_ARGS__}), sizeof(T)))
#define c_LITERAL(T) (T)
#endif
-#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))
+#define c_new_n(T, n) ((T*)malloc(sizeof(T)*c_i2u_size(n)))
+#define c_malloc(sz) malloc(c_i2u_size(sz))
+#define c_calloc(n, sz) calloc(c_i2u_size(n), c_i2u_size(sz))
+#define c_realloc(p, sz) realloc(p, c_i2u_size(sz))
#define c_free(p) free(p)
#define c_delete(T, ptr) do { T *_tp = ptr; T##_drop(_tp); free(_tp); } while (0)
-#define c_static_assert(b) ((int)(0*sizeof(int[(b) ? 1 : -1])))
+#define c_static_assert(expr) (1 ? 0 : (int)sizeof(int[(expr) ? 1 : -1]))
+#if defined STC_NDEBUG || defined NDEBUG
+ #define c_assert(expr) ((void)0)
+#else
+ #define c_assert(expr) assert(expr)
+#endif
#define c_container_of(p, C, m) ((C*)((char*)(1 ? (p) : &((C*)0)->m) - offsetof(C, m)))
-#define c_const_cast(T, p) ((T)(p) + 0*sizeof((T)0 == (p)))
+#define c_const_cast(T, p) ((T)(1 ? (p) : (T)0))
#define c_swap(T, xp, yp) do { T *_xp = xp, *_yp = yp, \
_tv = *_xp; *_xp = *_yp; *_yp = _tv; } while (0)
+// use with gcc -Wconversion
#define c_sizeof (intptr_t)sizeof
#define c_strlen(s) (intptr_t)strlen(s)
-#define c_strncmp(a, b, ilen) strncmp(a, b, c_i2u(ilen))
-#define c_memcpy(d, s, ilen) memcpy(d, s, c_i2u(ilen))
-#define c_memmove(d, s, ilen) memmove(d, s, c_i2u(ilen))
-#define c_memset(d, val, ilen) memset(d, val, c_i2u(ilen))
-#define c_memcmp(a, b, ilen) memcmp(a, b, c_i2u(ilen))
-
-#define c_u2i(u) ((intptr_t)((u) + 0*sizeof((u) == 1U)))
-#define c_i2u(i) ((size_t)(i) + 0*sizeof((i) == 1))
-#define c_LTu(a, b) ((size_t)(a) < (size_t)(b))
+#define c_strncmp(a, b, ilen) strncmp(a, b, c_i2u_size(ilen))
+#define c_memcpy(d, s, ilen) memcpy(d, s, c_i2u_size(ilen))
+#define c_memmove(d, s, ilen) memmove(d, s, c_i2u_size(ilen))
+#define c_memset(d, val, ilen) memset(d, val, c_i2u_size(ilen))
+#define c_memcmp(a, b, ilen) memcmp(a, b, c_i2u_size(ilen))
+#define c_u2i_size(u) (intptr_t)(1 ? (u) : (size_t)1)
+#define c_i2u_size(i) (size_t)(1 ? (i) : -1)
+#define c_less_unsigned(a, b) ((size_t)(a) < (size_t)(b))
// x and y are i_keyraw* type, defaults to i_key*:
#define c_default_cmp(x, y) (c_default_less(y, x) - c_default_less(x, y))
#define c_default_less(x, y) (*(x) < *(y))
#define c_default_eq(x, y) (*(x) == *(y))
#define c_memcmp_eq(x, y) (memcmp(x, y, sizeof *(x)) == 0)
-#define c_default_hash(x) cfasthash(x, c_sizeof(*(x)))
+#define c_default_hash(x) stc_hash(x, c_sizeof(*(x)))
#define c_default_clone(v) (v)
#define c_default_toraw(vp) (*(vp))
@@ -114,32 +114,31 @@
#define c_no_atomic (1<<1)
#define c_no_clone (1<<2)
#define c_no_emplace (1<<3)
-#define c_no_cmp (1<<4)
-#define c_no_hash (1<<5)
-
+#define c_no_hash (1<<4)
+#define c_use_cmp (1<<5)
/* Function macros and others */
-#define c_make(C, ...) \
- C##_from_n((C##_raw[])__VA_ARGS__, c_sizeof((C##_raw[])__VA_ARGS__)/c_sizeof(C##_raw))
-
#define c_litstrlen(literal) (c_sizeof("" literal) - 1)
#define c_arraylen(a) (intptr_t)(sizeof(a)/sizeof 0[a])
-// Non-owning c-string
-typedef const char* crawstr;
-#define crawstr_clone(s) (s)
-#define crawstr_drop(p) ((void)p)
-#define crawstr_cmp(xp, yp) strcmp(*(xp), *(yp))
-#define crawstr_hash(p) cstrhash(*(p))
+// Non-owning c-string "class"
+typedef const char* ccharptr;
+#define ccharptr_cmp(xp, yp) strcmp(*(xp), *(yp))
+#define ccharptr_hash(p) stc_strhash(*(p))
+#define ccharptr_clone(s) (s)
+#define ccharptr_drop(p) ((void)p)
#define c_sv(...) c_MACRO_OVERLOAD(c_sv, __VA_ARGS__)
-#define c_sv_1(lit) c_sv_2(lit, c_litstrlen(lit))
+#define c_sv_1(literal) c_sv_2(literal, c_litstrlen(literal))
#define c_sv_2(str, n) (c_LITERAL(csview){str, n})
+#define c_SV(sv) (int)(sv).size, (sv).buf // printf("%.*s\n", c_SV(sv));
+
+#define c_rs(literal) c_rs_2(literal, c_litstrlen(literal))
+#define c_rs_2(str, n) (c_LITERAL(crawstr){str, n})
-#define c_SV(sv) (int)(sv).size, (sv).str // print csview: use format "%.*s"
#define c_ROTL(x, k) (x << (k) | x >> (8*sizeof(x) - (k)))
-STC_INLINE uint64_t cfasthash(const void* key, intptr_t len) {
+STC_INLINE uint64_t stc_hash(const void* key, intptr_t len) {
uint32_t u4; uint64_t u8;
switch (len) {
case 8: memcpy(&u8, key, 8); return u8*0xc6a4a7935bd1e99d;
@@ -147,21 +146,21 @@ STC_INLINE uint64_t cfasthash(const void* key, intptr_t len) {
case 0: return 1;
}
const uint8_t *x = (const uint8_t*)key;
- uint64_t h = *x, n = (uint64_t)len >> 3;
+ uint64_t h = (uint64_t)*x << 7, n = (uint64_t)len >> 3;
len &= 7;
while (n--) {
memcpy(&u8, x, 8), x += 8;
- h += u8*0xc6a4a7935bd1e99d;
+ h = (h ^ u8)*0xc6a4a7935bd1e99d;
}
- while (len--) h = (h << 10) - h - *x++;
- return c_ROTL(h, 26) ^ h;
+ while (len--) h = (h ^ *x++)*0x100000001b3;
+ return h ^ c_ROTL(h, 26);
}
-STC_INLINE uint64_t cstrhash(const char *str)
- { return cfasthash(str, c_strlen(str)); }
+STC_INLINE uint64_t stc_strhash(const char *str)
+ { return stc_hash(str, c_strlen(str)); }
-STC_INLINE char* cstrnstrn(const char *str, const char *needle,
- intptr_t slen, const intptr_t nlen) {
+STC_INLINE char* stc_strnstrn(const char *str, intptr_t slen,
+ const char *needle, intptr_t nlen) {
if (!nlen) return (char *)str;
if (nlen > slen) return NULL;
slen -= nlen;
@@ -173,6 +172,16 @@ STC_INLINE char* cstrnstrn(const char *str, const char *needle,
return NULL;
}
+STC_INLINE intptr_t stc_nextpow2(intptr_t n) {
+ n--;
+ n |= n >> 1, n |= n >> 2;
+ n |= n >> 4, n |= n >> 8;
+ n |= n >> 16;
+ #if INTPTR_MAX == INT64_MAX
+ n |= n >> 32;
+ #endif
+ return n + 1;
+}
/* Control block macros */
#define c_foreach(...) c_MACRO_OVERLOAD(c_foreach, __VA_ARGS__)
@@ -182,57 +191,56 @@ STC_INLINE char* cstrnstrn(const char *str, const char *needle,
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) \
; C##_next(&_.it))
-#define c_forrange(...) c_MACRO_OVERLOAD(c_forrange, __VA_ARGS__)
-#define c_forrange_1(stop) c_forrange_3(_c_i, 0, stop)
-#define c_forrange_2(i, stop) c_forrange_3(i, 0, stop)
-#define c_forrange_3(i, start, stop) \
- for (long long i=start, _end=(long long)(stop); i < _end; ++i)
-#define c_forrange_4(i, start, stop, step) \
- for (long long i=start, _inc=step, _end=(long long)(stop) - (_inc > 0) \
+#define c_forrange(...) c_for(long long, __VA_ARGS__)
+#define c_for(...) c_MACRO_OVERLOAD(c_for, __VA_ARGS__)
+#define c_for_2(T, stop) c_for_4(T, _c_i, 0, stop)
+#define c_for_3(T, i, stop) c_for_4(T, i, 0, stop)
+#define c_for_4(T, i, start, stop) \
+ for (T i=start, _end=stop; i < _end; ++i)
+#define c_for_5(T, i, start, stop, step) \
+ for (T i=start, _inc=step, _end=(T)(stop) - (_inc > 0) \
; (_inc > 0) ^ (i > _end); i += _inc)
#ifndef __cplusplus
+ #define c_init(C, ...) \
+ C##_from_n((C##_raw[])__VA_ARGS__, c_sizeof((C##_raw[])__VA_ARGS__)/c_sizeof(C##_raw))
#define c_forlist(it, T, ...) \
- for (struct {T* ref; int size, index;} \
- it = {.ref=(T[])__VA_ARGS__, .size=(int)(sizeof((T[])__VA_ARGS__)/sizeof(T))} \
- ; it.index < it.size; ++it.ref, ++it.index)
+ for (struct {T* ref; int size, index;} \
+ it = {.ref=(T[])__VA_ARGS__, .size=(int)(sizeof((T[])__VA_ARGS__)/sizeof(T))} \
+ ; it.index < it.size; ++it.ref, ++it.index)
#else
- #include <initializer_list>
- #define c_forlist(it, T, ...) \
- for (struct {std::initializer_list<T> _il; std::initializer_list<T>::iterator data, ref; size_t size, index;} \
- it = {._il=__VA_ARGS__, .data=it._il.begin(), .ref=it.data, .size=it._il.size()} \
- ; it.index < it.size; ++it.ref, ++it.index)
+ #include <initializer_list>
+ template <class C, class T>
+ inline C _from_n(C (*func)(const T[], intptr_t), std::initializer_list<T> il)
+ { return func(&*il.begin(), il.size()); }
+
+ #define c_init(C, ...) _from_n<C,C##_raw>(C##_from_n, __VA_ARGS__)
+ #define c_forlist(it, T, ...) \
+ for (struct {std::initializer_list<T> _il; std::initializer_list<T>::iterator ref; size_t size, index;} \
+ it = {._il=__VA_ARGS__, .ref=it._il.begin(), .size=it._il.size()} \
+ ; it.index < it.size; ++it.ref, ++it.index)
#endif
+#define c_defer(...) \
+ for (int _i = 1; _i; _i = 0, __VA_ARGS__)
#define c_drop(C, ...) \
do { c_forlist (_i, C*, {__VA_ARGS__}) C##_drop(*_i.ref); } while(0)
-#endif // CCOMMON_H_INCLUDED
-
-#undef STC_API
-#undef STC_DEF
-
-#if !defined(i_static) && !defined(STC_STATIC) && (defined(i_header) || defined(STC_HEADER) || \
- defined(i_implement) || defined(STC_IMPLEMENT))
- #define STC_API extern
- #define STC_DEF
-#else
- #define i_static
- #define STC_API static inline
- #define STC_DEF static inline
-#endif
-#if defined(STC_EXTERN)
- #define i_extern
-#endif
-#if defined(i_static) || defined(STC_IMPLEMENT)
- #define i_implement
+#if defined(__SIZEOF_INT128__)
+ #define c_umul128(a, b, lo, hi) \
+ do { __uint128_t _z = (__uint128_t)(a)*(b); \
+ *(lo) = (uint64_t)_z, *(hi) = (uint64_t)(_z >> 64U); } while(0)
+#elif defined(_MSC_VER) && defined(_WIN64)
+ #include <intrin.h>
+ #define c_umul128(a, b, lo, hi) ((void)(*(lo) = _umul128(a, b, hi)))
+#elif defined(__x86_64__)
+ #define c_umul128(a, b, lo, hi) \
+ asm("mulq %3" : "=a"(*(lo)), "=d"(*(hi)) : "a"(a), "rm"(b))
#endif
+
+#endif // CCOMMON_H_INCLUDED
diff --git a/include/stc/cdeq.h b/include/stc/cdeq.h
index ff6e744f..4730721c 100644
--- a/include/stc/cdeq.h
+++ b/include/stc/cdeq.h
@@ -20,427 +20,184 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
-#include "ccommon.h"
+#include "priv/linkage.h"
#ifndef CDEQ_H_INCLUDED
+#include "ccommon.h"
#include "forward.h"
#include <stdlib.h>
#include <string.h>
-
-#define _it2_ptr(it1, it2) (it1.ref && !it2.ref ? it2.end : it2.ref)
-#define _it_ptr(it) (it.ref ? it.ref : it.end)
#endif // CDEQ_H_INCLUDED
-#ifndef _i_prefix
#define _i_prefix cdeq_
-#endif
-#include "priv/template.h"
-
-#ifndef i_is_forward
-_cx_deftypes(_c_cdeq_types, _cx_self, i_key);
-#endif
-typedef i_keyraw _cx_raw;
+#define _pop _pop_front
+#define _pull _pull_front
+#include "priv/cqueue_hdr.h"
+#undef _pop
+#undef _pull
-STC_API _cx_self _cx_memb(_init)(void);
-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);
-STC_API void _cx_memb(_shrink_to_fit)(_cx_self *self);
-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_queue
-#if !defined i_no_emplace
-STC_API _cx_iter _cx_memb(_emplace_range)(_cx_self* self, _cx_value* pos,
- const _cx_raw* p1, const _cx_raw* p2);
-#endif // i_no_emplace
-
-#if !defined i_no_cmp || defined _i_has_eq
-STC_API _cx_iter _cx_memb(_find_in)(_cx_iter p1, _cx_iter p2, _cx_raw raw);
-#endif
-#ifndef i_no_cmp
-STC_API int _cx_memb(_value_cmp)(const _cx_value* x, const _cx_value* y);
-#endif
-STC_API _cx_value* _cx_memb(_push_front)(_cx_self* self, i_key value);
-STC_API _cx_iter _cx_memb(_erase_range_p)(_cx_self* self, _cx_value* p1, _cx_value* p2);
-STC_API _cx_iter _cx_memb(_insert_range)(_cx_self* self, _cx_value* pos,
- const _cx_value* p1, const _cx_value* p2);
-#endif // !_i_queue
+STC_API _cx_value* _cx_MEMB(_push_front)(_cx_Self* self, i_key value);
+STC_API _cx_iter _cx_MEMB(_insert_n)(_cx_Self* self, intptr_t idx, const _cx_value* arr, intptr_t n);
+STC_API _cx_iter _cx_MEMB(_insert_uninit)(_cx_Self* self, intptr_t idx, intptr_t n);
+STC_API void _cx_MEMB(_erase_n)(_cx_Self* self, intptr_t idx, intptr_t n);
-#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
+STC_INLINE const _cx_value*
+_cx_MEMB(_at)(const _cx_Self* self, intptr_t idx)
+ { return self->data + _cdeq_topos(self, idx); }
-#if !defined i_no_clone
-#if !defined _i_queue
-STC_API _cx_iter _cx_memb(_copy_range)(_cx_self* self, _cx_value* pos,
- const _cx_value* p1, const _cx_value* p2);
+STC_INLINE _cx_value*
+_cx_MEMB(_at_mut)(_cx_Self* self, intptr_t idx)
+ { return self->data + _cdeq_topos(self, idx); }
-STC_INLINE void _cx_memb(_copy)(_cx_self *self, const _cx_self* other) {
- if (self->data == other->data) return;
- _cx_memb(_clear)(self);
- _cx_memb(_copy_range)(self, self->data,
- other->data, other->data + other->_len);
- }
-#endif // !_i_queue
-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 self->_len; }
-STC_INLINE intptr_t _cx_memb(_capacity)(const _cx_self* self) { return self->_cap; }
-STC_INLINE bool _cx_memb(_empty)(const _cx_self* self) { return !self->_len; }
-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; }
-STC_INLINE _cx_value* _cx_memb(_back)(const _cx_self* self)
- { return self->data + self->_len - 1; }
-STC_INLINE void _cx_memb(_pop_front)(_cx_self* self) // == _pop() when _i_queue
- { i_keydrop(self->data); ++self->data; --self->_len; }
+STC_INLINE _cx_value*
+_cx_MEMB(_push_back)(_cx_Self* self, _cx_value val)
+ { return _cx_MEMB(_push)(self, val); }
-STC_INLINE _cx_iter _cx_memb(_begin)(const _cx_self* self) {
- intptr_t n = self->_len;
- return c_LITERAL(_cx_iter){n ? self->data : NULL, self->data + n};
+STC_INLINE void
+_cx_MEMB(_pop_back)(_cx_Self* self) {
+ c_assert(!_cx_MEMB(_empty)(self));
+ self->end = (self->end - 1) & self->capmask;
+ i_keydrop((self->data + self->end));
}
-STC_INLINE _cx_iter _cx_memb(_end)(const _cx_self* self)
- { return c_LITERAL(_cx_iter){NULL, self->data + self->_len}; }
-
-STC_INLINE void _cx_memb(_next)(_cx_iter* it)
- { if (++it->ref == it->end) it->ref = NULL; }
-
-STC_INLINE _cx_iter _cx_memb(_advance)(_cx_iter it, size_t n)
- { if ((it.ref += n) >= it.end) it.ref = NULL; return it; }
-
-#if !defined _i_queue
-
-STC_INLINE intptr_t _cx_memb(_index)(const _cx_self* self, _cx_iter it)
- { return (it.ref - self->data); }
-STC_INLINE void _cx_memb(_pop_back)(_cx_self* self)
- { _cx_value* p = &self->data[--self->_len]; i_keydrop(p); }
-
-STC_INLINE const _cx_value* _cx_memb(_at)(const _cx_self* self, const intptr_t idx) {
- assert(idx < self->_len); return self->data + idx;
-}
-STC_INLINE _cx_value* _cx_memb(_at_mut)(_cx_self* self, const intptr_t idx) {
- assert(idx < self->_len); return self->data + idx;
+STC_INLINE _cx_value _cx_MEMB(_pull_back)(_cx_Self* self) { // move back out of deq
+ c_assert(!_cx_MEMB(_empty)(self));
+ self->end = (self->end - 1) & self->capmask;
+ return self->data[self->end];
}
-STC_INLINE _cx_value* _cx_memb(_push_back)(_cx_self* self, i_key value) {
- return _cx_memb(_push)(self, value);
-}
STC_INLINE _cx_iter
-_cx_memb(_insert)(_cx_self* self, const intptr_t idx, i_key value) {
- return _cx_memb(_insert_range)(self, self->data + idx, &value, &value + 1);
-}
-STC_INLINE _cx_iter
-_cx_memb(_insert_n)(_cx_self* self, const intptr_t idx, const _cx_value arr[], const intptr_t n) {
- return _cx_memb(_insert_range)(self, self->data + idx, arr, arr + n);
-}
-STC_INLINE _cx_iter
-_cx_memb(_insert_at)(_cx_self* self, _cx_iter it, i_key value) {
- return _cx_memb(_insert_range)(self, _it_ptr(it), &value, &value + 1);
+_cx_MEMB(_insert_at)(_cx_Self* self, _cx_iter it, const _cx_value val) {
+ intptr_t idx = _cdeq_toidx(self, it.pos);
+ return _cx_MEMB(_insert_n)(self, idx, &val, 1);
}
STC_INLINE _cx_iter
-_cx_memb(_erase_n)(_cx_self* self, const intptr_t idx, const intptr_t n) {
- return _cx_memb(_erase_range_p)(self, self->data + idx, self->data + idx + n);
-}
-STC_INLINE _cx_iter
-_cx_memb(_erase_at)(_cx_self* self, _cx_iter it) {
- return _cx_memb(_erase_range_p)(self, it.ref, it.ref + 1);
+_cx_MEMB(_erase_at)(_cx_Self* self, _cx_iter it) {
+ _cx_MEMB(_erase_n)(self, _cdeq_toidx(self, it.pos), 1);
+ if (it.pos == self->end) it.ref = NULL;
+ return it;
}
+
STC_INLINE _cx_iter
-_cx_memb(_erase_range)(_cx_self* self, _cx_iter i1, _cx_iter i2) {
- return _cx_memb(_erase_range_p)(self, i1.ref, _it2_ptr(i1, i2));
+_cx_MEMB(_erase_range)(_cx_Self* self, _cx_iter it1, _cx_iter it2) {
+ intptr_t idx1 = _cdeq_toidx(self, it1.pos);
+ intptr_t idx2 = _cdeq_toidx(self, it2.pos);
+ _cx_MEMB(_erase_n)(self, idx1, idx2 - idx1);
+ if (it1.pos == self->end) it1.ref = NULL;
+ return it1;
}
#if !defined i_no_emplace
+STC_API _cx_iter
+_cx_MEMB(_emplace_n)(_cx_Self* self, intptr_t idx, const _cx_raw* raw, intptr_t n);
+
STC_INLINE _cx_value*
-_cx_memb(_emplace_front)(_cx_self* self, _cx_raw raw) {
- return _cx_memb(_push_front)(self, i_keyfrom(raw));
-}
+_cx_MEMB(_emplace_front)(_cx_Self* self, const _cx_raw raw)
+ { return _cx_MEMB(_push_front)(self, i_keyfrom(raw)); }
-STC_INLINE _cx_value* _cx_memb(_emplace_back)(_cx_self* self, _cx_raw raw) {
- return _cx_memb(_push)(self, i_keyfrom(raw));
-}
+STC_INLINE _cx_value*
+_cx_MEMB(_emplace_back)(_cx_Self* self, const _cx_raw raw)
+ { return _cx_MEMB(_push)(self, i_keyfrom(raw)); }
STC_INLINE _cx_iter
-_cx_memb(_emplace_n)(_cx_self* self, const intptr_t idx, const _cx_raw arr[], const intptr_t n) {
- return _cx_memb(_emplace_range)(self, self->data + idx, arr, arr + n);
-}
-STC_INLINE _cx_iter
-_cx_memb(_emplace_at)(_cx_self* self, _cx_iter it, _cx_raw raw) {
- return _cx_memb(_emplace_range)(self, _it_ptr(it), &raw, &raw + 1);
-}
-#endif // !i_no_emplace
+_cx_MEMB(_emplace_at)(_cx_Self* self, _cx_iter it, const _cx_raw raw)
+ { return _cx_MEMB(_insert_at)(self, it, i_keyfrom(raw)); }
+#endif
-#if !defined i_no_cmp || defined _i_has_eq
+#if defined _i_has_eq || defined _i_has_cmp
+STC_API _cx_iter _cx_MEMB(_find_in)(_cx_iter p1, _cx_iter p2, _cx_raw raw);
STC_INLINE _cx_iter
-_cx_memb(_find)(const _cx_self* self, _cx_raw raw) {
- return _cx_memb(_find_in)(_cx_memb(_begin)(self), _cx_memb(_end)(self), raw);
+_cx_MEMB(_find)(const _cx_Self* self, _cx_raw raw) {
+ return _cx_MEMB(_find_in)(_cx_MEMB(_begin)(self), _cx_MEMB(_end)(self), raw);
}
STC_INLINE const _cx_value*
-_cx_memb(_get)(const _cx_self* self, _cx_raw raw) {
- return _cx_memb(_find_in)(_cx_memb(_begin)(self), _cx_memb(_end)(self), raw).ref;
+_cx_MEMB(_get)(const _cx_Self* self, _cx_raw raw) {
+ return _cx_MEMB(_find_in)(_cx_MEMB(_begin)(self), _cx_MEMB(_end)(self), raw).ref;
}
STC_INLINE _cx_value*
-_cx_memb(_get_mut)(_cx_self* self, _cx_raw raw)
- { return (_cx_value *) _cx_memb(_get)(self, raw); }
-
-STC_INLINE bool
-_cx_memb(_eq)(const _cx_self* self, const _cx_self* other) {
- if (self->_len != other->_len) return false;
- for (intptr_t i = 0; i < self->_len; ++i) {
- const _cx_raw _rx = i_keyto(self->data+i), _ry = i_keyto(other->data+i);
- if (!(i_eq((&_rx), (&_ry)))) return false;
- }
- return true;
-}
+_cx_MEMB(_get_mut)(_cx_Self* self, _cx_raw raw)
+ { return (_cx_value *) _cx_MEMB(_get)(self, raw); }
#endif
-#ifndef i_no_cmp
-
-STC_INLINE void
-_cx_memb(_sort_range)(_cx_iter i1, _cx_iter i2, int(*cmp)(const _cx_value*, const _cx_value*)) {
- qsort(i1.ref, (size_t)(_it2_ptr(i1, i2) - i1.ref), sizeof *i1.ref,
- (int(*)(const void*, const void*)) cmp);
-}
-
-STC_INLINE void
-_cx_memb(_sort)(_cx_self* self) {
- _cx_memb(_sort_range)(_cx_memb(_begin)(self), _cx_memb(_end)(self), _cx_memb(_value_cmp));
-}
-#endif // !c_no_cmp
-#endif // _i_queue
/* -------------------------- IMPLEMENTATION ------------------------- */
-#if defined(i_implement)
-#define _cdeq_nfront(self) ((self)->data - (self)->_base)
-
-STC_DEF _cx_self
-_cx_memb(_init)(void) {
- _cx_self cx = {NULL};
- return cx;
-}
-
-STC_DEF void
-_cx_memb(_clear)(_cx_self* self) {
- if (self->_cap) {
- for (_cx_value *p = self->data, *q = p + self->_len; p != q; )
- { --q; i_keydrop(q); }
- self->_len = 0;
- self->data = self->_base;
- }
-}
-
-STC_DEF void
-_cx_memb(_shrink_to_fit)(_cx_self *self) {
- if (self->_len != self->_cap) {
- c_memmove(self->_base, self->data, self->_len*c_sizeof(i_key));
- _cx_value* d = (_cx_value*)i_realloc(self->_base, self->_len*c_sizeof(i_key));
- if (d) {
- self->_base = d;
- self->_cap = self->_len;
- }
- self->data = self->_base;
- }
-}
-
-STC_DEF void
-_cx_memb(_drop)(_cx_self* self) {
- if (self->_base) {
- _cx_memb(_clear)(self);
- i_free(self->_base);
- }
-}
-
-static intptr_t
-_cx_memb(_realloc_)(_cx_self* self, const intptr_t n) {
- const intptr_t cap = (intptr_t)((float)self->_len*1.7f) + n + 7;
- const intptr_t nfront = _cdeq_nfront(self);
- _cx_value* d = (_cx_value*)i_realloc(self->_base, cap*c_sizeof(i_key));
- if (!d)
- return 0;
- self->_cap = cap;
- self->_base = d;
- self->data = d + nfront;
- return cap;
-}
-
-static bool
-_cx_memb(_expand_right_half_)(_cx_self* self, const intptr_t idx, const intptr_t n) {
- const intptr_t sz = self->_len, cap = self->_cap;
- const intptr_t nfront = _cdeq_nfront(self), nback = cap - sz - nfront;
- if (nback >= n || (intptr_t)((float)sz*1.3f) + n > cap) {
- if (!_cx_memb(_realloc_)(self, n))
- return false;
- c_memmove(self->data + idx + n, self->data + idx, (sz - idx)*c_sizeof(i_key));
- } else {
-#if !defined _i_queue
- const intptr_t unused = cap - (sz + n);
- const intptr_t pos = (nfront*2 < unused) ? nfront : unused/2;
-#else
- const intptr_t pos = 0;
-#endif
- c_memmove(self->_base + pos, self->data, idx*c_sizeof(i_key));
- c_memmove(self->data + pos + idx + n, self->data + idx, (sz - idx)*c_sizeof(i_key));
- self->data = self->_base + pos;
- }
- return true;
-}
-
-STC_DEF _cx_self
-_cx_memb(_with_capacity)(const intptr_t n) {
- _cx_self cx = _cx_memb(_init)();
- _cx_memb(_expand_right_half_)(&cx, 0, n);
- return cx;
-}
+#if defined(i_implement) || defined(i_static)
-STC_DEF bool
-_cx_memb(_reserve)(_cx_self* self, const intptr_t n) {
- const intptr_t sz = self->_len;
- return n <= sz || _cx_memb(_expand_right_half_)(self, sz, n - sz);
-}
+#include "priv/cqueue_imp.h"
STC_DEF _cx_value*
-_cx_memb(_push)(_cx_self* self, i_key value) {
- if (_cdeq_nfront(self) + self->_len == self->_cap)
- _cx_memb(_expand_right_half_)(self, self->_len, 1);
- _cx_value *v = self->data + self->_len++;
+_cx_MEMB(_push_front)(_cx_Self* self, i_key value) {
+ intptr_t start = (self->start - 1) & self->capmask;
+ if (start == self->end) { // full
+ _cx_MEMB(_reserve)(self, self->capmask + 3); // => 2x expand
+ start = (self->start - 1) & self->capmask;
+ }
+ _cx_value *v = self->data + start;
+ self->start = start;
*v = value;
return v;
}
-#if !defined i_no_clone
-STC_DEF _cx_self
-_cx_memb(_clone)(_cx_self cx) {
- _cx_self out = _cx_memb(_with_capacity)(cx._len);
- if (out._base)
- for (intptr_t i = 0; i < cx._len; ++i)
- out.data[i] = i_keyclone(cx.data[i]);
- return out;
-}
-#endif
-
-#if !defined _i_queue
-
-static void
-_cx_memb(_expand_left_half_)(_cx_self* self, const intptr_t idx, const intptr_t n) {
- intptr_t cap = self->_cap;
- const intptr_t sz = self->_len;
- const intptr_t nfront = _cdeq_nfront(self), nback = cap - sz - nfront;
- if (nfront >= n) {
- self->data = (_cx_value *)c_memmove(self->data - n, self->data, idx*c_sizeof(i_key));
- } else {
- if ((intptr_t)((float)sz*1.3f) + n > cap)
- cap = _cx_memb(_realloc_)(self, n);
- const intptr_t unused = cap - (sz + n);
- const intptr_t pos = (nback*2 < unused) ? unused - nback : unused/2;
- c_memmove(self->_base + pos + idx + n, self->data + idx, (sz - idx)*c_sizeof(i_key));
- self->data = (_cx_value *)c_memmove(self->_base + pos, self->data, idx*c_sizeof(i_key));
- }
-}
-
-static _cx_iter
-_cx_memb(_insert_uninit)(_cx_self* self, _cx_value* pos, const intptr_t n) {
- if (n) {
- if (!pos) pos = self->data + self->_len;
- const intptr_t idx = (pos - self->data);
- if (idx*2 < self->_len)
- _cx_memb(_expand_left_half_)(self, idx, n);
- else
- _cx_memb(_expand_right_half_)(self, idx, n);
- self->_len += n;
- pos = self->data + idx;
- }
- return c_LITERAL(_cx_iter){pos, self->data + self->_len};
-}
-
-STC_DEF _cx_value*
-_cx_memb(_push_front)(_cx_self* self, i_key value) {
- if (self->data == self->_base)
- _cx_memb(_expand_left_half_)(self, 0, 1);
- else
- --self->data;
- ++self->_len;
- *self->data = value;
- return self->data;
+STC_DEF void
+_cx_MEMB(_erase_n)(_cx_Self* self, const intptr_t idx, const intptr_t n) {
+ const intptr_t len = _cx_MEMB(_size)(self);
+ for (intptr_t i = idx + n - 1; i >= idx; --i)
+ i_keydrop(_cx_MEMB(_at_mut)(self, i));
+ for (intptr_t i = idx, j = i + n; j < len; ++i, ++j)
+ *_cx_MEMB(_at_mut)(self, i) = *_cx_MEMB(_at)(self, j);
+ self->end = (self->end - n) & self->capmask;
}
STC_DEF _cx_iter
-_cx_memb(_insert_range)(_cx_self* self, _cx_value* pos,
- const _cx_value* p1, const _cx_value* p2) {
- _cx_iter it = _cx_memb(_insert_uninit)(self, pos, (p2 - p1));
- if (it.ref)
- c_memcpy(it.ref, p1, (p2 - p1)*c_sizeof *p1);
+_cx_MEMB(_insert_uninit)(_cx_Self* self, const intptr_t idx, const intptr_t n) {
+ const intptr_t len = _cx_MEMB(_size)(self);
+ _cx_iter it = {._s=self};
+ if (len + n > self->capmask)
+ if (!_cx_MEMB(_reserve)(self, len*5/4 + n))
+ return it;
+ it.pos = _cdeq_topos(self, idx);
+ it.ref = self->data + it.pos;
+ self->end = (self->end + n) & self->capmask;
+
+ if (it.pos < self->end) // common case because of reserve policy
+ c_memmove(it.ref + n, it.ref, (len - idx)*c_sizeof *it.ref);
+ else for (intptr_t i = len - 1, j = i + n; i >= idx; --i, --j)
+ *_cx_MEMB(_at_mut)(self, j) = *_cx_MEMB(_at)(self, i);
return it;
}
STC_DEF _cx_iter
-_cx_memb(_erase_range_p)(_cx_self* self, _cx_value* p1, _cx_value* p2) {
- assert(p1 && p2);
- intptr_t len = p2 - p1;
- _cx_value* p = p1, *end = self->data + self->_len;
- for (; p != p2; ++p)
- { i_keydrop(p); }
- c_memmove(p1, p2, (end - p2)*c_sizeof *p1);
- self->_len -= len;
- return c_LITERAL(_cx_iter){p2 == end ? NULL : p1, end - len};
-}
-
-#if !defined i_no_clone
-STC_DEF _cx_iter
-_cx_memb(_copy_range)(_cx_self* self, _cx_value* pos,
- const _cx_value* p1, const _cx_value* p2) {
- _cx_iter it = _cx_memb(_insert_uninit)(self, pos, (p2 - p1));
- if (it.ref)
- for (_cx_value* p = it.ref; p1 != p2; ++p1)
- *p++ = i_keyclone((*p1));
+_cx_MEMB(_insert_n)(_cx_Self* self, const intptr_t idx, const _cx_value* arr, const intptr_t n) {
+ _cx_iter it = _cx_MEMB(_insert_uninit)(self, idx, n);
+ for (intptr_t i = idx, j = 0; j < n; ++i, ++j)
+ *_cx_MEMB(_at_mut)(self, i) = arr[j];
return it;
}
-#endif // !i_no_clone
#if !defined i_no_emplace
STC_DEF _cx_iter
-_cx_memb(_emplace_range)(_cx_self* self, _cx_value* pos,
- const _cx_raw* p1, const _cx_raw* p2) {
- _cx_iter it = _cx_memb(_insert_uninit)(self, pos, (p2 - p1));
- if (it.ref)
- for (_cx_value* p = it.ref; p1 != p2; ++p1)
- *p++ = i_keyfrom((*p1));
+_cx_MEMB(_emplace_n)(_cx_Self* self, const intptr_t idx, const _cx_raw* raw, const intptr_t n) {
+ _cx_iter it = _cx_MEMB(_insert_uninit)(self, idx, n);
+ for (intptr_t i = idx, j = 0; j < n; ++i, ++j)
+ *_cx_MEMB(_at_mut)(self, i) = i_keyfrom(raw[j]);
return it;
}
-#endif // !i_no_emplace
+#endif
-#if !defined i_no_cmp || defined _i_has_eq
+#if defined _i_has_eq || defined _i_has_cmp
STC_DEF _cx_iter
-_cx_memb(_find_in)(_cx_iter i1, _cx_iter i2, _cx_raw raw) {
- const _cx_value* p2 = _it2_ptr(i1, i2);
- for (; i1.ref != p2; ++i1.ref) {
+_cx_MEMB(_find_in)(_cx_iter i1, _cx_iter i2, _cx_raw raw) {
+ for (; i1.pos != i2.pos; _cx_MEMB(_next)(&i1)) {
const _cx_raw r = i_keyto(i1.ref);
if (i_eq((&raw), (&r)))
- return i1;
+ break;
}
- i2.ref = NULL;
- return i2;
+ return i1;
}
#endif
-#ifndef i_no_cmp
-STC_DEF int
-_cx_memb(_value_cmp)(const _cx_value* x, const _cx_value* y) {
- const _cx_raw rx = i_keyto(x);
- const _cx_raw ry = i_keyto(y);
- return i_cmp((&rx), (&ry));
-}
-#endif // !c_no_cmp
-#endif // !_i_queue
#endif // IMPLEMENTATION
#define CDEQ_H_INCLUDED
#include "priv/template2.h"
diff --git a/include/stc/clist.h b/include/stc/clist.h
index f7fb4152..6a205c2b 100644
--- a/include/stc/clist.h
+++ b/include/stc/clist.h
@@ -32,7 +32,7 @@
#define i_tag ix
#include <stc/clist.h>
- int main()
+ int main(void)
{
c_auto (clist_ix, list)
{
@@ -51,9 +51,10 @@
}
}
*/
-#include "ccommon.h"
+#include "priv/linkage.h"
#ifndef CLIST_H_INCLUDED
+#include "ccommon.h"
#include "forward.h"
#include <stdlib.h>
#include <string.h>
@@ -77,82 +78,81 @@
#endif // CLIST_H_INCLUDED
-#ifndef _i_prefix
#define _i_prefix clist_
-#endif
#include "priv/template.h"
#ifndef i_is_forward
- _cx_deftypes(_c_clist_types, _cx_self, i_key);
+ _cx_DEFTYPES(_c_clist_types, _cx_Self, i_key);
#endif
-_cx_deftypes(_c_clist_complete_types, _cx_self, dummy);
+_cx_DEFTYPES(_c_clist_complete_types, _cx_Self, dummy);
typedef i_keyraw _cx_raw;
-STC_API void _cx_memb(_drop)(_cx_self* self);
-STC_API _cx_value* _cx_memb(_push_back)(_cx_self* self, i_key value);
-STC_API _cx_value* _cx_memb(_push_front)(_cx_self* self, i_key value);
-STC_API _cx_iter _cx_memb(_insert_at)(_cx_self* self, _cx_iter it, i_key value);
-STC_API _cx_iter _cx_memb(_erase_at)(_cx_self* self, _cx_iter it);
-STC_API _cx_iter _cx_memb(_erase_range)(_cx_self* self, _cx_iter it1, _cx_iter it2);
-#if !defined i_no_cmp || defined _i_has_eq
-STC_API _cx_iter _cx_memb(_find_in)(_cx_iter it1, _cx_iter it2, _cx_raw val);
-STC_API intptr_t _cx_memb(_remove)(_cx_self* self, _cx_raw val);
+STC_API void _cx_MEMB(_drop)(_cx_Self* self);
+STC_API _cx_value* _cx_MEMB(_push_back)(_cx_Self* self, i_key value);
+STC_API _cx_value* _cx_MEMB(_push_front)(_cx_Self* self, i_key value);
+STC_API _cx_iter _cx_MEMB(_insert_at)(_cx_Self* self, _cx_iter it, i_key value);
+STC_API _cx_iter _cx_MEMB(_erase_at)(_cx_Self* self, _cx_iter it);
+STC_API _cx_iter _cx_MEMB(_erase_range)(_cx_Self* self, _cx_iter it1, _cx_iter it2);
+#if defined _i_has_eq || defined _i_has_cmp
+STC_API _cx_iter _cx_MEMB(_find_in)(_cx_iter it1, _cx_iter it2, _cx_raw val);
+STC_API intptr_t _cx_MEMB(_remove)(_cx_Self* self, _cx_raw val);
#endif
-#ifndef i_no_cmp
-STC_API bool _cx_memb(_sort_with)(_cx_self* self, int(*cmp)(const _cx_value*, const _cx_value*));
-STC_API int _cx_memb(_sort_cmp_)(const _cx_value*, const _cx_value*);
-STC_INLINE bool _cx_memb(_sort)(_cx_self* self)
- { return _cx_memb(_sort_with)(self, _cx_memb(_sort_cmp_)); }
+#if defined _i_has_cmp
+STC_API bool _cx_MEMB(_sort_with)(_cx_Self* self, int(*cmp)(const _cx_value*, const _cx_value*));
+STC_API int _cx_MEMB(_sort_cmp_)(const _cx_value*, const _cx_value*);
+STC_INLINE bool _cx_MEMB(_sort)(_cx_Self* self)
+ { return _cx_MEMB(_sort_with)(self, _cx_MEMB(_sort_cmp_)); }
#endif
-STC_API void _cx_memb(_reverse)(_cx_self* self);
-STC_API _cx_iter _cx_memb(_splice)(_cx_self* self, _cx_iter it, _cx_self* other);
-STC_API _cx_self _cx_memb(_split_off)(_cx_self* self, _cx_iter it1, _cx_iter it2);
-STC_API _cx_value* _cx_memb(_push_back_node)(_cx_self* self, _cx_node* node);
-STC_API _cx_value* _cx_memb(_insert_after_node)(_cx_self* self, _cx_node* ref, _cx_node* node);
-STC_API _cx_node* _cx_memb(_unlink_after_node)(_cx_self* self, _cx_node* ref);
-STC_API void _cx_memb(_erase_after_node)(_cx_self* self, _cx_node* ref);
-STC_INLINE _cx_node* _cx_memb(_get_node)(_cx_value* vp) { return _clist_tonode(vp); }
-
+STC_API void _cx_MEMB(_reverse)(_cx_Self* self);
+STC_API _cx_iter _cx_MEMB(_splice)(_cx_Self* self, _cx_iter it, _cx_Self* other);
+STC_API _cx_Self _cx_MEMB(_split_off)(_cx_Self* self, _cx_iter it1, _cx_iter it2);
+STC_API _cx_value* _cx_MEMB(_push_back_node)(_cx_Self* self, _cx_node* node);
+STC_API _cx_value* _cx_MEMB(_insert_after_node)(_cx_Self* self, _cx_node* ref, _cx_node* node);
+STC_API _cx_node* _cx_MEMB(_unlink_after_node)(_cx_Self* self, _cx_node* ref);
+STC_API void _cx_MEMB(_erase_after_node)(_cx_Self* self, _cx_node* ref);
+STC_INLINE _cx_node* _cx_MEMB(_get_node)(_cx_value* pval) { return _clist_tonode(pval); }
+STC_INLINE _cx_node* _cx_MEMB(_unlink_front_node)(_cx_Self* self)
+ { return _cx_MEMB(_unlink_after_node)(self, self->last); }
#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); }
+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); }
STC_INLINE void
-_cx_memb(_copy)(_cx_self *self, const _cx_self* other) {
+_cx_MEMB(_copy)(_cx_Self *self, const _cx_Self* other) {
if (self->last == other->last) return;
- _cx_memb(_drop)(self); *self = _cx_memb(_clone)(*other);
+ _cx_MEMB(_drop)(self); *self = _cx_MEMB(_clone)(*other);
}
#endif // !i_no_clone
#if !defined i_no_emplace
-STC_INLINE _cx_value* _cx_memb(_emplace_back)(_cx_self* self, _cx_raw raw)
- { return _cx_memb(_push_back)(self, i_keyfrom(raw)); }
-STC_INLINE _cx_value* _cx_memb(_emplace_front)(_cx_self* self, _cx_raw raw)
- { return _cx_memb(_push_front)(self, i_keyfrom(raw)); }
-STC_INLINE _cx_iter _cx_memb(_emplace_at)(_cx_self* self, _cx_iter it, _cx_raw raw)
- { return _cx_memb(_insert_at)(self, it, i_keyfrom(raw)); }
-STC_INLINE _cx_value* _cx_memb(_emplace)(_cx_self* self, _cx_raw raw)
- { return _cx_memb(_push_back)(self, i_keyfrom(raw)); }
+STC_INLINE _cx_value* _cx_MEMB(_emplace_back)(_cx_Self* self, _cx_raw raw)
+ { return _cx_MEMB(_push_back)(self, i_keyfrom(raw)); }
+STC_INLINE _cx_value* _cx_MEMB(_emplace_front)(_cx_Self* self, _cx_raw raw)
+ { return _cx_MEMB(_push_front)(self, i_keyfrom(raw)); }
+STC_INLINE _cx_iter _cx_MEMB(_emplace_at)(_cx_Self* self, _cx_iter it, _cx_raw raw)
+ { return _cx_MEMB(_insert_at)(self, it, i_keyfrom(raw)); }
+STC_INLINE _cx_value* _cx_MEMB(_emplace)(_cx_Self* self, _cx_raw raw)
+ { return _cx_MEMB(_push_back)(self, i_keyfrom(raw)); }
#endif // !i_no_emplace
-STC_INLINE _cx_self _cx_memb(_init)(void) { return c_LITERAL(_cx_self){NULL}; }
-STC_INLINE void _cx_memb(_put_n)(_cx_self* self, const _cx_raw* raw, intptr_t n)
- { while (n--) _cx_memb(_push_back)(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 bool _cx_memb(_reserve)(_cx_self* self, intptr_t n) { (void)(self + n); return true; }
-STC_INLINE bool _cx_memb(_empty)(const _cx_self* self) { return self->last == NULL; }
-STC_INLINE void _cx_memb(_clear)(_cx_self* self) { _cx_memb(_drop)(self); }
-STC_INLINE _cx_value* _cx_memb(_push)(_cx_self* self, i_key value)
- { return _cx_memb(_push_back)(self, value); }
-STC_INLINE void _cx_memb(_pop_front)(_cx_self* self)
- { assert(!_cx_memb(_empty)(self)); _cx_memb(_erase_after_node)(self, self->last); }
-STC_INLINE _cx_node* _cx_memb(_unlink_node_front)(_cx_self* self)
- { return _cx_memb(_unlink_after_node)(self, self->last); }
-STC_INLINE _cx_value* _cx_memb(_front)(const _cx_self* self) { return &self->last->next->value; }
-STC_INLINE _cx_value* _cx_memb(_back)(const _cx_self* self) { return &self->last->value; }
+STC_INLINE _cx_Self _cx_MEMB(_init)(void) { return c_LITERAL(_cx_Self){NULL}; }
+STC_INLINE void _cx_MEMB(_put_n)(_cx_Self* self, const _cx_raw* raw, intptr_t n)
+ { while (n--) _cx_MEMB(_push_back)(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 bool _cx_MEMB(_reserve)(_cx_Self* self, intptr_t n) { (void)(self + n); return true; }
+STC_INLINE bool _cx_MEMB(_empty)(const _cx_Self* self) { return self->last == NULL; }
+STC_INLINE void _cx_MEMB(_clear)(_cx_Self* self) { _cx_MEMB(_drop)(self); }
+STC_INLINE _cx_value* _cx_MEMB(_push)(_cx_Self* self, i_key value)
+ { return _cx_MEMB(_push_back)(self, value); }
+STC_INLINE void _cx_MEMB(_pop_front)(_cx_Self* self)
+ { c_assert(!_cx_MEMB(_empty)(self)); _cx_MEMB(_erase_after_node)(self, self->last); }
+STC_INLINE _cx_value* _cx_MEMB(_front)(const _cx_Self* self) { return &self->last->next->value; }
+STC_INLINE _cx_value* _cx_MEMB(_back)(const _cx_Self* self) { return &self->last->value; }
+STC_INLINE _cx_raw _cx_MEMB(_value_toraw)(const _cx_value* pval) { return i_keyto(pval); }
+STC_INLINE void _cx_MEMB(_value_drop)(_cx_value* pval) { i_keydrop(pval); }
STC_INLINE intptr_t
-_cx_memb(_count)(const _cx_self* self) {
+_cx_MEMB(_count)(const _cx_Self* self) {
intptr_t n = 1; const _cx_node *node = self->last;
if (!node) return 0;
while ((node = node->next) != self->last) ++n;
@@ -160,53 +160,53 @@ _cx_memb(_count)(const _cx_self* self) {
}
STC_INLINE _cx_iter
-_cx_memb(_begin)(const _cx_self* self) {
+_cx_MEMB(_begin)(const _cx_Self* self) {
_cx_value* head = self->last ? &self->last->next->value : NULL;
return c_LITERAL(_cx_iter){head, &self->last, self->last};
}
STC_INLINE _cx_iter
-_cx_memb(_end)(const _cx_self* self)
+_cx_MEMB(_end)(const _cx_Self* self)
{ return c_LITERAL(_cx_iter){NULL}; }
STC_INLINE void
-_cx_memb(_next)(_cx_iter* it) {
+_cx_MEMB(_next)(_cx_iter* it) {
_cx_node* node = it->prev = _clist_tonode(it->ref);
it->ref = (node == *it->_last ? NULL : &node->next->value);
}
STC_INLINE _cx_iter
-_cx_memb(_advance)(_cx_iter it, size_t n) {
- while (n-- && it.ref) _cx_memb(_next)(&it);
+_cx_MEMB(_advance)(_cx_iter it, size_t n) {
+ while (n-- && it.ref) _cx_MEMB(_next)(&it);
return it;
}
STC_INLINE _cx_iter
-_cx_memb(_splice_range)(_cx_self* self, _cx_iter it,
- _cx_self* other, _cx_iter it1, _cx_iter it2) {
- _cx_self tmp = _cx_memb(_split_off)(other, it1, it2);
- return _cx_memb(_splice)(self, it, &tmp);
+_cx_MEMB(_splice_range)(_cx_Self* self, _cx_iter it,
+ _cx_Self* other, _cx_iter it1, _cx_iter it2) {
+ _cx_Self tmp = _cx_MEMB(_split_off)(other, it1, it2);
+ return _cx_MEMB(_splice)(self, it, &tmp);
}
-#if !defined i_no_cmp || defined _i_has_eq
+#if defined _i_has_eq || defined _i_has_cmp
STC_INLINE _cx_iter
-_cx_memb(_find)(const _cx_self* self, _cx_raw val) {
- return _cx_memb(_find_in)(_cx_memb(_begin)(self), _cx_memb(_end)(self), val);
+_cx_MEMB(_find)(const _cx_Self* self, _cx_raw val) {
+ return _cx_MEMB(_find_in)(_cx_MEMB(_begin)(self), _cx_MEMB(_end)(self), val);
}
STC_INLINE const _cx_value*
-_cx_memb(_get)(const _cx_self* self, _cx_raw val) {
- return _cx_memb(_find_in)(_cx_memb(_begin)(self), _cx_memb(_end)(self), val).ref;
+_cx_MEMB(_get)(const _cx_Self* self, _cx_raw val) {
+ return _cx_MEMB(_find_in)(_cx_MEMB(_begin)(self), _cx_MEMB(_end)(self), val).ref;
}
STC_INLINE _cx_value*
-_cx_memb(_get_mut)(_cx_self* self, _cx_raw val) {
- return _cx_memb(_find_in)(_cx_memb(_begin)(self), _cx_memb(_end)(self), val).ref;
+_cx_MEMB(_get_mut)(_cx_Self* self, _cx_raw val) {
+ return _cx_MEMB(_find_in)(_cx_MEMB(_begin)(self), _cx_MEMB(_end)(self), val).ref;
}
-STC_INLINE bool _cx_memb(_eq)(const _cx_self* self, const _cx_self* other) {
- _cx_iter i = _cx_memb(_begin)(self), j = _cx_memb(_begin)(other);
- for (; i.ref && j.ref; _cx_memb(_next)(&i), _cx_memb(_next)(&j)) {
+STC_INLINE bool _cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other) {
+ _cx_iter i = _cx_MEMB(_begin)(self), j = _cx_MEMB(_begin)(other);
+ for (; i.ref && j.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;
}
@@ -215,32 +215,32 @@ STC_INLINE bool _cx_memb(_eq)(const _cx_self* self, const _cx_self* other) {
#endif
// -------------------------- IMPLEMENTATION -------------------------
-#if defined(i_implement)
+#if defined(i_implement) || defined(i_static)
#if !defined i_no_clone
-STC_DEF _cx_self
-_cx_memb(_clone)(_cx_self cx) {
- _cx_self out = _cx_memb(_init)();
- c_foreach (it, _cx_self, cx)
- _cx_memb(_push_back)(&out, i_keyclone((*it.ref)));
+STC_DEF _cx_Self
+_cx_MEMB(_clone)(_cx_Self cx) {
+ _cx_Self out = _cx_MEMB(_init)();
+ c_foreach (it, _cx_Self, cx)
+ _cx_MEMB(_push_back)(&out, i_keyclone((*it.ref)));
return out;
}
#endif
STC_DEF void
-_cx_memb(_drop)(_cx_self* self) {
- while (self->last) _cx_memb(_erase_after_node)(self, self->last);
+_cx_MEMB(_drop)(_cx_Self* self) {
+ while (self->last) _cx_MEMB(_erase_after_node)(self, self->last);
}
STC_DEF _cx_value*
-_cx_memb(_push_back)(_cx_self* self, i_key value) {
+_cx_MEMB(_push_back)(_cx_Self* self, i_key value) {
_c_clist_insert_entry_after(self->last, value);
self->last = entry;
return &entry->value;
}
STC_DEF _cx_value*
-_cx_memb(_push_front)(_cx_self* self, i_key value) {
+_cx_MEMB(_push_front)(_cx_Self* self, i_key value) {
_c_clist_insert_entry_after(self->last, value);
if (!self->last)
self->last = entry;
@@ -248,14 +248,14 @@ _cx_memb(_push_front)(_cx_self* self, i_key value) {
}
STC_DEF _cx_value*
-_cx_memb(_push_back_node)(_cx_self* self, _cx_node* node) {
+_cx_MEMB(_push_back_node)(_cx_Self* self, _cx_node* node) {
_c_clist_insert_after_node(self->last, node);
self->last = node;
return &node->value;
}
STC_DEF _cx_value*
-_cx_memb(_insert_after_node)(_cx_self* self, _cx_node* ref, _cx_node* node) {
+_cx_MEMB(_insert_after_node)(_cx_Self* self, _cx_node* ref, _cx_node* node) {
_c_clist_insert_after_node(ref, node);
if (!self->last)
self->last = node;
@@ -263,7 +263,7 @@ _cx_memb(_insert_after_node)(_cx_self* self, _cx_node* ref, _cx_node* node) {
}
STC_DEF _cx_iter
-_cx_memb(_insert_at)(_cx_self* self, _cx_iter it, i_key value) {
+_cx_MEMB(_insert_at)(_cx_Self* self, _cx_iter it, i_key value) {
_cx_node* node = it.ref ? it.prev : self->last;
_c_clist_insert_entry_after(node, value);
if (!self->last || !it.ref) {
@@ -275,32 +275,32 @@ _cx_memb(_insert_at)(_cx_self* self, _cx_iter it, i_key value) {
}
STC_DEF _cx_iter
-_cx_memb(_erase_at)(_cx_self* self, _cx_iter it) {
+_cx_MEMB(_erase_at)(_cx_Self* self, _cx_iter it) {
_cx_node *node = _clist_tonode(it.ref);
it.ref = (node == self->last) ? NULL : &node->next->value;
- _cx_memb(_erase_after_node)(self, it.prev);
+ _cx_MEMB(_erase_after_node)(self, it.prev);
return it;
}
STC_DEF _cx_iter
-_cx_memb(_erase_range)(_cx_self* self, _cx_iter it1, _cx_iter it2) {
+_cx_MEMB(_erase_range)(_cx_Self* self, _cx_iter it1, _cx_iter it2) {
_cx_node *end = it2.ref ? _clist_tonode(it2.ref) : self->last->next;
if (it1.ref != it2.ref) do {
- _cx_memb(_erase_after_node)(self, it1.prev);
+ _cx_MEMB(_erase_after_node)(self, it1.prev);
if (!self->last) break;
} while (it1.prev->next != end);
return it2;
}
STC_DEF void
-_cx_memb(_erase_after_node)(_cx_self* self, _cx_node* ref) {
- _cx_node* node = _cx_memb(_unlink_after_node)(self, ref);
+_cx_MEMB(_erase_after_node)(_cx_Self* self, _cx_node* ref) {
+ _cx_node* node = _cx_MEMB(_unlink_after_node)(self, ref);
i_keydrop((&node->value));
i_free(node);
}
STC_DEF _cx_node*
-_cx_memb(_unlink_after_node)(_cx_self* self, _cx_node* ref) {
+_cx_MEMB(_unlink_after_node)(_cx_Self* self, _cx_node* ref) {
_cx_node* node = ref->next, *next = node->next;
ref->next = next;
if (node == next)
@@ -311,17 +311,17 @@ _cx_memb(_unlink_after_node)(_cx_self* self, _cx_node* ref) {
}
STC_DEF void
-_cx_memb(_reverse)(_cx_self* self) {
- _cx_self rev = {NULL};
+_cx_MEMB(_reverse)(_cx_Self* self) {
+ _cx_Self rev = {NULL};
while (self->last) {
- _cx_node* node = _cx_memb(_unlink_after_node)(self, self->last);
- _cx_memb(_insert_after_node)(&rev, rev.last, node);
+ _cx_node* node = _cx_MEMB(_unlink_after_node)(self, self->last);
+ _cx_MEMB(_insert_after_node)(&rev, rev.last, node);
}
*self = rev;
}
STC_DEF _cx_iter
-_cx_memb(_splice)(_cx_self* self, _cx_iter it, _cx_self* other) {
+_cx_MEMB(_splice)(_cx_Self* self, _cx_iter it, _cx_Self* other) {
if (!self->last)
self->last = other->last;
else if (other->last) {
@@ -335,9 +335,9 @@ _cx_memb(_splice)(_cx_self* self, _cx_iter it, _cx_self* other) {
return it;
}
-STC_DEF _cx_self
-_cx_memb(_split_off)(_cx_self* self, _cx_iter it1, _cx_iter it2) {
- _cx_self lst = {NULL};
+STC_DEF _cx_Self
+_cx_MEMB(_split_off)(_cx_Self* self, _cx_iter it1, _cx_iter it2) {
+ _cx_Self lst = {NULL};
if (it1.ref == it2.ref)
return lst;
_cx_node *p1 = it1.prev,
@@ -350,11 +350,10 @@ _cx_memb(_split_off)(_cx_self* self, _cx_iter it1, _cx_iter it2) {
return lst;
}
-#if !defined i_no_cmp || defined _i_has_eq
-
+#if defined _i_has_eq || defined _i_has_cmp
STC_DEF _cx_iter
-_cx_memb(_find_in)(_cx_iter it1, _cx_iter it2, _cx_raw val) {
- c_foreach (it, _cx_self, it1, it2) {
+_cx_MEMB(_find_in)(_cx_iter it1, _cx_iter it2, _cx_raw val) {
+ c_foreach (it, _cx_Self, it1, it2) {
_cx_raw r = i_keyto(it.ref);
if (i_eq((&r), (&val)))
return it;
@@ -363,14 +362,14 @@ _cx_memb(_find_in)(_cx_iter it1, _cx_iter it2, _cx_raw val) {
}
STC_DEF intptr_t
-_cx_memb(_remove)(_cx_self* self, _cx_raw val) {
+_cx_MEMB(_remove)(_cx_Self* self, _cx_raw val) {
intptr_t n = 0;
_cx_node *prev = self->last, *node;
if (prev) do {
node = prev->next;
_cx_raw r = i_keyto((&node->value));
if (i_eq((&r), (&val))) {
- _cx_memb(_erase_after_node)(self, prev), ++n;
+ _cx_MEMB(_erase_after_node)(self, prev), ++n;
if (!self->last) break;
} else
prev = node;
@@ -379,29 +378,29 @@ _cx_memb(_remove)(_cx_self* self, _cx_raw val) {
}
#endif
-#ifndef i_no_cmp
-STC_DEF int _cx_memb(_sort_cmp_)(const _cx_value* x, const _cx_value* y) {
+#if defined _i_has_cmp
+STC_DEF int _cx_MEMB(_sort_cmp_)(const _cx_value* x, const _cx_value* y) {
const _cx_raw a = i_keyto(x), b = i_keyto(y);
return i_cmp((&a), (&b));
}
-STC_DEF bool _cx_memb(_sort_with)(_cx_self* self, int(*cmp)(const _cx_value*, const _cx_value*)) {
- size_t len = 0, cap = 0;
+STC_DEF bool _cx_MEMB(_sort_with)(_cx_Self* self, int(*cmp)(const _cx_value*, const _cx_value*)) {
+ intptr_t len = 0, cap = 0;
_cx_value *a = NULL, *p = NULL;
_cx_iter i;
- for (i = _cx_memb(_begin)(self); i.ref; _cx_memb(_next)(&i)) {
+ for (i = _cx_MEMB(_begin)(self); i.ref; _cx_MEMB(_next)(&i)) {
if (len == cap) {
- if ((p = (_cx_value *)i_realloc(a, (cap += cap/2 + 4)*sizeof *a))) a = p;
+ if ((p = (_cx_value *)i_realloc(a, (cap += cap/2 + 4)*c_sizeof *a))) a = p;
else { i_free(a); return false; }
}
a[len++] = *i.ref;
}
- qsort(a, len, sizeof *a, (int(*)(const void*, const void*))cmp);
- for (i = _cx_memb(_begin)(self); i.ref; _cx_memb(_next)(&i), ++p)
+ qsort(a, (size_t)len, sizeof *a, (int(*)(const void*, const void*))cmp);
+ for (i = _cx_MEMB(_begin)(self); i.ref; _cx_MEMB(_next)(&i), ++p)
*i.ref = *p;
i_free(a); return true;
}
-#endif // !c_no_cmp
+#endif // _i_has_cmp
#endif // i_implement
#define CLIST_H_INCLUDED
#include "priv/template2.h"
diff --git a/include/stc/cmap.h b/include/stc/cmap.h
index 14782b71..c069fbd8 100644
--- a/include/stc/cmap.h
+++ b/include/stc/cmap.h
@@ -47,43 +47,32 @@ int main(void) {
cmap_ichar_drop(&m);
}
*/
-#include "ccommon.h"
+#include "priv/linkage.h"
#ifndef CMAP_H_INCLUDED
+#include "ccommon.h"
#include "forward.h"
#include <stdlib.h>
#include <string.h>
-typedef struct { int64_t idx; uint8_t hx; } chash_bucket_t;
+struct chash_slot { uint8_t hashx; };
#endif // CMAP_H_INCLUDED
#ifndef _i_prefix
-#define _i_prefix cmap_
-#endif
-#ifdef _i_isset
- #define _i_MAP_ONLY c_false
- #define _i_SET_ONLY c_true
- #define _i_keyref(vp) (vp)
-#else
+ #define _i_prefix cmap_
#define _i_ismap
#define _i_MAP_ONLY c_true
#define _i_SET_ONLY c_false
#define _i_keyref(vp) (&(vp)->first)
-#endif
-#define _i_ishash
-#ifndef i_max_load_factor
- #define i_max_load_factor 0.85f
-#endif
-#ifndef i_ssize
- #define i_ssize int32_t
- #define _i_size intptr_t
- #define _i_expandby 1
#else
- #define _i_expandby 2
- #define _i_size i_ssize
+ #define _i_isset
+ #define _i_MAP_ONLY c_false
+ #define _i_SET_ONLY c_true
+ #define _i_keyref(vp) (vp)
#endif
+#define _i_ishash
#include "priv/template.h"
#ifndef i_is_forward
- _cx_deftypes(_c_chash_types, _cx_self, i_key, i_val, i_ssize, _i_MAP_ONLY, _i_SET_ONLY);
+ _cx_DEFTYPES(_c_chash_types, _cx_Self, i_key, i_val, _i_MAP_ONLY, _i_SET_ONLY);
#endif
_i_MAP_ONLY( struct _cx_value {
@@ -92,61 +81,61 @@ _i_MAP_ONLY( struct _cx_value {
}; )
typedef i_keyraw _cx_keyraw;
-typedef i_valraw _cx_memb(_rmapped);
+typedef i_valraw _cx_MEMB(_rmapped);
typedef _i_SET_ONLY( i_keyraw )
_i_MAP_ONLY( struct { i_keyraw first;
i_valraw second; } )
_cx_raw;
-STC_API _cx_self _cx_memb(_with_capacity)(_i_size cap);
+STC_API _cx_Self _cx_MEMB(_with_capacity)(intptr_t cap);
#if !defined i_no_clone
-STC_API _cx_self _cx_memb(_clone)(_cx_self map);
+STC_API _cx_Self _cx_MEMB(_clone)(_cx_Self map);
#endif
-STC_API void _cx_memb(_drop)(_cx_self* self);
-STC_API void _cx_memb(_clear)(_cx_self* self);
-STC_API bool _cx_memb(_reserve)(_cx_self* self, _i_size capacity);
-STC_API chash_bucket_t _cx_memb(_bucket_)(const _cx_self* self, const _cx_keyraw* rkeyptr);
-STC_API _cx_result _cx_memb(_insert_entry_)(_cx_self* self, _cx_keyraw rkey);
-STC_API void _cx_memb(_erase_entry)(_cx_self* self, _cx_value* val);
-
-STC_INLINE _cx_self _cx_memb(_init)(void) { _cx_self map = {0}; return map; }
-STC_INLINE void _cx_memb(_shrink_to_fit)(_cx_self* self) { _cx_memb(_reserve)(self, self->size); }
-STC_INLINE float _cx_memb(_max_load_factor)(const _cx_self* self) { return (float)(i_max_load_factor); }
-STC_INLINE bool _cx_memb(_empty)(const _cx_self* map) { return !map->size; }
-STC_INLINE _i_size _cx_memb(_size)(const _cx_self* map) { return map->size; }
-STC_INLINE _i_size _cx_memb(_bucket_count)(_cx_self* map) { return map->bucket_count; }
-STC_INLINE _i_size _cx_memb(_capacity)(const _cx_self* map)
- { return (_i_size)((float)map->bucket_count * (i_max_load_factor)); }
-STC_INLINE bool _cx_memb(_contains)(const _cx_self* self, _cx_keyraw rkey)
- { return self->size && self->_hashx[_cx_memb(_bucket_)(self, &rkey).idx]; }
-
-#ifndef _i_isset
- STC_API _cx_result _cx_memb(_insert_or_assign)(_cx_self* self, i_key key, i_val mapped);
+STC_API void _cx_MEMB(_drop)(_cx_Self* self);
+STC_API void _cx_MEMB(_clear)(_cx_Self* self);
+STC_API bool _cx_MEMB(_reserve)(_cx_Self* self, intptr_t capacity);
+STC_API _cx_result _cx_MEMB(_bucket_)(const _cx_Self* self, const _cx_keyraw* rkeyptr);
+STC_API _cx_result _cx_MEMB(_insert_entry_)(_cx_Self* self, _cx_keyraw rkey);
+STC_API void _cx_MEMB(_erase_entry)(_cx_Self* self, _cx_value* val);
+STC_API float _cx_MEMB(_max_load_factor)(const _cx_Self* self);
+STC_API intptr_t _cx_MEMB(_capacity)(const _cx_Self* map);
+
+STC_INLINE _cx_Self _cx_MEMB(_init)(void) { _cx_Self map = {0}; return map; }
+STC_INLINE void _cx_MEMB(_shrink_to_fit)(_cx_Self* self) { _cx_MEMB(_reserve)(self, (intptr_t)self->size); }
+STC_INLINE bool _cx_MEMB(_empty)(const _cx_Self* map) { return !map->size; }
+STC_INLINE intptr_t _cx_MEMB(_size)(const _cx_Self* map) { return (intptr_t)map->size; }
+STC_INLINE intptr_t _cx_MEMB(_bucket_count)(_cx_Self* map) { return map->bucket_count; }
+STC_INLINE bool _cx_MEMB(_contains)(const _cx_Self* self, _cx_keyraw rkey)
+ { return self->size && !_cx_MEMB(_bucket_)(self, &rkey).inserted; }
+
+#ifdef _i_ismap
+ STC_API _cx_result _cx_MEMB(_insert_or_assign)(_cx_Self* self, i_key key, i_val mapped);
#if !defined i_no_emplace
- STC_API _cx_result _cx_memb(_emplace_or_assign)(_cx_self* self, _cx_keyraw rkey, i_valraw rmapped);
+ STC_API _cx_result _cx_MEMB(_emplace_or_assign)(_cx_Self* self, _cx_keyraw rkey, i_valraw rmapped);
#endif
STC_INLINE const _cx_mapped*
- _cx_memb(_at)(const _cx_self* self, _cx_keyraw rkey) {
- chash_bucket_t b = _cx_memb(_bucket_)(self, &rkey);
- assert(self->_hashx[b.idx]);
- return &self->table[b.idx].second;
+ _cx_MEMB(_at)(const _cx_Self* self, _cx_keyraw rkey) {
+ _cx_result b = _cx_MEMB(_bucket_)(self, &rkey);
+ c_assert(!b.inserted);
+ return &b.ref->second;
}
+
STC_INLINE _cx_mapped*
- _cx_memb(_at_mut)(_cx_self* self, _cx_keyraw rkey)
- { return (_cx_mapped*)_cx_memb(_at)(self, rkey); }
-#endif // !_i_isset
+ _cx_MEMB(_at_mut)(_cx_Self* self, _cx_keyraw rkey)
+ { return (_cx_mapped*)_cx_MEMB(_at)(self, rkey); }
+#endif // _i_ismap
#if !defined i_no_clone
-STC_INLINE void _cx_memb(_copy)(_cx_self *self, const _cx_self* other) {
- if (self->table == other->table)
+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);
+ _cx_MEMB(_drop)(self);
+ *self = _cx_MEMB(_clone)(*other);
}
STC_INLINE _cx_value
-_cx_memb(_value_clone)(_cx_value _val) {
+_cx_MEMB(_value_clone)(_cx_value _val) {
*_i_keyref(&_val) = i_keyclone((*_i_keyref(&_val)));
_i_MAP_ONLY( _val.second = i_valclone(_val.second); )
return _val;
@@ -155,31 +144,39 @@ _cx_memb(_value_clone)(_cx_value _val) {
#if !defined i_no_emplace
STC_INLINE _cx_result
-_cx_memb(_emplace)(_cx_self* self, _cx_keyraw rkey _i_MAP_ONLY(, i_valraw rmapped)) {
- _cx_result _res = _cx_memb(_insert_entry_)(self, rkey);
+_cx_MEMB(_emplace)(_cx_Self* self, _cx_keyraw rkey _i_MAP_ONLY(, i_valraw rmapped)) {
+ _cx_result _res = _cx_MEMB(_insert_entry_)(self, rkey);
if (_res.inserted) {
*_i_keyref(_res.ref) = i_keyfrom(rkey);
_i_MAP_ONLY( _res.ref->second = i_valfrom(rmapped); )
}
return _res;
}
+
+#ifdef _i_ismap
+ STC_INLINE _cx_result
+ _cx_MEMB(_emplace_key)(_cx_Self* self, _cx_keyraw rkey) {
+ _cx_result _res = _cx_MEMB(_insert_entry_)(self, rkey);
+ if (_res.inserted)
+ _res.ref->first = i_keyfrom(rkey);
+ return _res;
+ }
+#endif // _i_ismap
#endif // !i_no_emplace
-STC_INLINE _cx_raw
-_cx_memb(_value_toraw)(const _cx_value* val) {
+STC_INLINE _cx_raw _cx_MEMB(_value_toraw)(const _cx_value* val) {
return _i_SET_ONLY( i_keyto(val) )
_i_MAP_ONLY( c_LITERAL(_cx_raw){i_keyto((&val->first)), i_valto((&val->second))} );
}
-STC_INLINE void
-_cx_memb(_value_drop)(_cx_value* _val) {
+STC_INLINE void _cx_MEMB(_value_drop)(_cx_value* _val) {
i_keydrop(_i_keyref(_val));
_i_MAP_ONLY( i_valdrop((&_val->second)); )
}
STC_INLINE _cx_result
-_cx_memb(_insert)(_cx_self* self, i_key _key _i_MAP_ONLY(, i_val _mapped)) {
- _cx_result _res = _cx_memb(_insert_entry_)(self, i_keyto((&_key)));
+_cx_MEMB(_insert)(_cx_Self* self, i_key _key _i_MAP_ONLY(, i_val _mapped)) {
+ _cx_result _res = _cx_MEMB(_insert_entry_)(self, i_keyto((&_key)));
if (_res.inserted)
{ *_i_keyref(_res.ref) = _key; _i_MAP_ONLY( _res.ref->second = _mapped; )}
else
@@ -187,157 +184,150 @@ _cx_memb(_insert)(_cx_self* self, i_key _key _i_MAP_ONLY(, i_val _mapped)) {
return _res;
}
-STC_INLINE _cx_result
-_cx_memb(_push)(_cx_self* self, _cx_value _val) {
- _cx_result _res = _cx_memb(_insert_entry_)(self, i_keyto(_i_keyref(&_val)));
+STC_INLINE _cx_value* _cx_MEMB(_push)(_cx_Self* self, _cx_value _val) {
+ _cx_result _res = _cx_MEMB(_insert_entry_)(self, i_keyto(_i_keyref(&_val)));
if (_res.inserted)
*_res.ref = _val;
else
- _cx_memb(_value_drop)(&_val);
- return _res;
+ _cx_MEMB(_value_drop)(&_val);
+ return _res.ref;
}
-STC_INLINE void _cx_memb(_put_n)(_cx_self* self, const _cx_raw* raw, _i_size n) {
+STC_INLINE void _cx_MEMB(_put_n)(_cx_Self* self, const _cx_raw* raw, intptr_t n) {
while (n--)
#if defined _i_isset && defined i_no_emplace
- _cx_memb(_insert)(self, *raw++);
+ _cx_MEMB(_insert)(self, *raw++);
#elif defined _i_isset
- _cx_memb(_emplace)(self, *raw++);
+ _cx_MEMB(_emplace)(self, *raw++);
#elif defined i_no_emplace
- _cx_memb(_insert_or_assign)(self, raw->first, raw->second), ++raw;
+ _cx_MEMB(_insert_or_assign)(self, raw->first, raw->second), ++raw;
#else
- _cx_memb(_emplace_or_assign)(self, raw->first, raw->second), ++raw;
+ _cx_MEMB(_emplace_or_assign)(self, raw->first, raw->second), ++raw;
#endif
}
-STC_INLINE _cx_self _cx_memb(_from_n)(const _cx_raw* raw, _i_size n)
- { _cx_self cx = {0}; _cx_memb(_put_n)(&cx, raw, n); return cx; }
+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 _cx_iter _cx_memb(_begin)(const _cx_self* self) {
- _cx_iter it = {self->table, self->table+self->bucket_count, self->_hashx};
- if (it._hx)
- while (*it._hx == 0)
- ++it.ref, ++it._hx;
- if (it.ref == it._end) it.ref = NULL;
- return it;
-}
+STC_API _cx_iter _cx_MEMB(_begin)(const _cx_Self* self);
-STC_INLINE _cx_iter
-_cx_memb(_end)(const _cx_self* self)
+STC_INLINE _cx_iter _cx_MEMB(_end)(const _cx_Self* self)
{ return c_LITERAL(_cx_iter){NULL}; }
-STC_INLINE void
-_cx_memb(_next)(_cx_iter* it) {
- while ((++it->ref, *++it->_hx == 0)) ;
+STC_INLINE void _cx_MEMB(_next)(_cx_iter* it) {
+ while ((++it->ref, (++it->sref)->hashx == 0)) ;
if (it->ref == it->_end) it->ref = NULL;
}
-STC_INLINE _cx_iter
-_cx_memb(_advance)(_cx_iter it, size_t n) {
- while (n-- && it.ref) _cx_memb(_next)(&it);
+STC_INLINE _cx_iter _cx_MEMB(_advance)(_cx_iter it, size_t n) {
+ while (n-- && it.ref) _cx_MEMB(_next)(&it);
return it;
}
STC_INLINE _cx_iter
-_cx_memb(_find)(const _cx_self* self, _cx_keyraw rkey) {
- int64_t idx;
- if (self->size && self->_hashx[idx = _cx_memb(_bucket_)(self, &rkey).idx])
- return c_LITERAL(_cx_iter){self->table + idx,
- self->table + self->bucket_count,
- self->_hashx + idx};
- return _cx_memb(_end)(self);
+_cx_MEMB(_find)(const _cx_Self* self, _cx_keyraw rkey) {
+ _cx_result b;
+ if (self->size && !(b = _cx_MEMB(_bucket_)(self, &rkey)).inserted)
+ return c_LITERAL(_cx_iter){b.ref,
+ self->data + self->bucket_count,
+ self->slot + (b.ref - self->data)};
+ return _cx_MEMB(_end)(self);
}
STC_INLINE const _cx_value*
-_cx_memb(_get)(const _cx_self* self, _cx_keyraw rkey) {
- int64_t idx;
- if (self->size && self->_hashx[idx = _cx_memb(_bucket_)(self, &rkey).idx])
- return self->table + idx;
+_cx_MEMB(_get)(const _cx_Self* self, _cx_keyraw rkey) {
+ _cx_result b;
+ if (self->size && !(b = _cx_MEMB(_bucket_)(self, &rkey)).inserted)
+ return b.ref;
return NULL;
}
STC_INLINE _cx_value*
-_cx_memb(_get_mut)(_cx_self* self, _cx_keyraw rkey)
- { return (_cx_value*)_cx_memb(_get)(self, rkey); }
+_cx_MEMB(_get_mut)(_cx_Self* self, _cx_keyraw rkey)
+ { return (_cx_value*)_cx_MEMB(_get)(self, rkey); }
STC_INLINE int
-_cx_memb(_erase)(_cx_self* self, _cx_keyraw rkey) {
- if (self->size == 0)
- return 0;
- chash_bucket_t b = _cx_memb(_bucket_)(self, &rkey);
- return self->_hashx[b.idx] ? _cx_memb(_erase_entry)(self, self->table + b.idx), 1 : 0;
+_cx_MEMB(_erase)(_cx_Self* self, _cx_keyraw rkey) {
+ _cx_result b;
+ if (self->size && !(b = _cx_MEMB(_bucket_)(self, &rkey)).inserted)
+ { _cx_MEMB(_erase_entry)(self, b.ref); return 1; }
+ return 0;
}
STC_INLINE _cx_iter
-_cx_memb(_erase_at)(_cx_self* self, _cx_iter it) {
- _cx_memb(_erase_entry)(self, it.ref);
- if (*it._hx == 0)
- _cx_memb(_next)(&it);
+_cx_MEMB(_erase_at)(_cx_Self* self, _cx_iter it) {
+ _cx_MEMB(_erase_entry)(self, it.ref);
+ if (it.sref->hashx == 0)
+ _cx_MEMB(_next)(&it);
return it;
}
STC_INLINE 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); i.ref; _cx_memb(_next)(&i)) {
+_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); i.ref; _cx_MEMB(_next)(&i)) {
const _cx_keyraw _raw = i_keyto(_i_keyref(i.ref));
- if (!_cx_memb(_contains)(other, _raw)) return false;
+ if (!_cx_MEMB(_contains)(other, _raw)) return false;
}
return true;
}
/* -------------------------- IMPLEMENTATION ------------------------- */
-#if defined(i_implement)
+#if defined(i_implement) || defined(i_static)
+#ifndef i_max_load_factor
+ #define i_max_load_factor 0.80f
+#endif
+#define fastrange_2(x, n) (intptr_t)((x) & (size_t)((n) - 1)) // n power of 2.
-#ifndef CMAP_H_INCLUDED
-STC_INLINE int64_t fastrange_1(uint64_t x, uint64_t n)
- { return (int64_t)((uint32_t)x*n >> 32); } // n < 2^32
-
-STC_INLINE int64_t fastrange_2(uint64_t x, uint64_t n)
- { return (int64_t)(x & (n - 1)); } // n power of 2.
-
-STC_INLINE uint64_t next_power_of_2(uint64_t n) {
- n--;
- n |= n >> 1, n |= n >> 2;
- n |= n >> 4, n |= n >> 8;
- n |= n >> 16, n |= n >> 32;
- return n + 1;
+STC_DEF _cx_iter _cx_MEMB(_begin)(const _cx_Self* self) {
+ _cx_iter it = {self->data, self->data+self->bucket_count, self->slot};
+ if (it.sref)
+ while (it.sref->hashx == 0)
+ ++it.ref, ++it.sref;
+ if (it.ref == it._end) it.ref = NULL;
+ return it;
+}
+
+STC_DEF float _cx_MEMB(_max_load_factor)(const _cx_Self* self) {
+ return (float)(i_max_load_factor);
+}
+
+STC_DEF intptr_t _cx_MEMB(_capacity)(const _cx_Self* map) {
+ return (intptr_t)((float)map->bucket_count * (i_max_load_factor));
}
-#endif // CMAP_H_INCLUDED
-STC_DEF _cx_self
-_cx_memb(_with_capacity)(const _i_size cap) {
- _cx_self h = {0};
- _cx_memb(_reserve)(&h, cap);
- return h;
+STC_DEF _cx_Self _cx_MEMB(_with_capacity)(const intptr_t cap) {
+ _cx_Self map = {0};
+ _cx_MEMB(_reserve)(&map, cap);
+ return map;
}
-STC_INLINE void _cx_memb(_wipe_)(_cx_self* self) {
+STC_INLINE void _cx_MEMB(_wipe_)(_cx_Self* self) {
if (self->size == 0)
return;
- _cx_value* e = self->table, *end = e + self->bucket_count;
- uint8_t *hx = self->_hashx;
- for (; e != end; ++e)
- if (*hx++)
- _cx_memb(_value_drop)(e);
+ _cx_value* d = self->data, *_end = d + self->bucket_count;
+ struct chash_slot* s = self->slot;
+ for (; d != _end; ++d)
+ if ((s++)->hashx)
+ _cx_MEMB(_value_drop)(d);
}
-STC_DEF void _cx_memb(_drop)(_cx_self* self) {
- _cx_memb(_wipe_)(self);
- i_free(self->_hashx);
- i_free((void *) self->table);
+STC_DEF void _cx_MEMB(_drop)(_cx_Self* self) {
+ _cx_MEMB(_wipe_)(self);
+ i_free(self->slot);
+ i_free(self->data);
}
-STC_DEF void _cx_memb(_clear)(_cx_self* self) {
- _cx_memb(_wipe_)(self);
+STC_DEF void _cx_MEMB(_clear)(_cx_Self* self) {
+ _cx_MEMB(_wipe_)(self);
self->size = 0;
- c_memset(self->_hashx, 0, self->bucket_count);
+ c_memset(self->slot, 0, c_sizeof(struct chash_slot)*self->bucket_count);
}
-#ifndef _i_isset
+#ifdef _i_ismap
STC_DEF _cx_result
- _cx_memb(_insert_or_assign)(_cx_self* self, i_key _key, i_val _mapped) {
- _cx_result _res = _cx_memb(_insert_entry_)(self, i_keyto((&_key)));
+ _cx_MEMB(_insert_or_assign)(_cx_Self* self, i_key _key, i_val _mapped) {
+ _cx_result _res = _cx_MEMB(_insert_entry_)(self, i_keyto((&_key)));
_cx_mapped* _mp = _res.ref ? &_res.ref->second : &_mapped;
if (_res.inserted)
_res.ref->first = _key;
@@ -349,8 +339,8 @@ STC_DEF void _cx_memb(_clear)(_cx_self* self) {
#if !defined i_no_emplace
STC_DEF _cx_result
- _cx_memb(_emplace_or_assign)(_cx_self* self, _cx_keyraw rkey, i_valraw rmapped) {
- _cx_result _res = _cx_memb(_insert_entry_)(self, rkey);
+ _cx_MEMB(_emplace_or_assign)(_cx_Self* self, _cx_keyraw rkey, i_valraw rmapped) {
+ _cx_result _res = _cx_MEMB(_insert_entry_)(self, rkey);
if (_res.inserted)
_res.ref->first = i_keyfrom(rkey);
else {
@@ -361,119 +351,117 @@ STC_DEF void _cx_memb(_clear)(_cx_self* self) {
return _res;
}
#endif // !i_no_emplace
-#endif // !_i_isset
+#endif // _i_ismap
-STC_DEF chash_bucket_t
-_cx_memb(_bucket_)(const _cx_self* self, const _cx_keyraw* rkeyptr) {
+STC_DEF _cx_result
+_cx_MEMB(_bucket_)(const _cx_Self* self, const _cx_keyraw* rkeyptr) {
const uint64_t _hash = i_hash(rkeyptr);
- int64_t _cap = self->bucket_count;
- chash_bucket_t b = {c_PASTE(fastrange_,_i_expandby)(_hash, (uint64_t)_cap), (uint8_t)(_hash | 0x80)};
- const uint8_t* _hx = self->_hashx;
- while (_hx[b.idx]) {
- if (_hx[b.idx] == b.hx) {
- const _cx_keyraw _raw = i_keyto(_i_keyref(self->table + b.idx));
- if (i_eq((&_raw), rkeyptr))
+ intptr_t _cap = self->bucket_count;
+ intptr_t _idx = fastrange_2(_hash, _cap);
+ _cx_result b = {NULL, true, (uint8_t)(_hash | 0x80)};
+ const struct chash_slot* s = self->slot;
+ while (s[_idx].hashx) {
+ if (s[_idx].hashx == b.hashx) {
+ const _cx_keyraw _raw = i_keyto(_i_keyref(self->data + _idx));
+ if (i_eq((&_raw), rkeyptr)) {
+ b.inserted = false;
break;
+ }
}
- if (++b.idx == _cap)
- b.idx = 0;
+ if (++_idx == _cap) _idx = 0;
}
+ b.ref = self->data + _idx;
return b;
}
STC_DEF _cx_result
-_cx_memb(_insert_entry_)(_cx_self* self, _cx_keyraw rkey) {
- _cx_result res = {NULL};
- if (self->size + 2 > (i_ssize)((float)self->bucket_count * (i_max_load_factor)))
- if (!_cx_memb(_reserve)(self, self->size*3/2))
- return res;
-
- chash_bucket_t b = _cx_memb(_bucket_)(self, &rkey);
- res.ref = &self->table[b.idx];
- if ((res.inserted = !self->_hashx[b.idx])) {
- self->_hashx[b.idx] = b.hx;
+_cx_MEMB(_insert_entry_)(_cx_Self* self, _cx_keyraw rkey) {
+ if (self->size >= (intptr_t)((float)self->bucket_count * (i_max_load_factor)))
+ if (!_cx_MEMB(_reserve)(self, (intptr_t)(self->size*3/2 + 2)))
+ return c_LITERAL(_cx_result){NULL};
+
+ _cx_result b = _cx_MEMB(_bucket_)(self, &rkey);
+ if (b.inserted) {
+ self->slot[b.ref - self->data].hashx = b.hashx;
++self->size;
}
- return res;
+ return b;
}
#if !defined i_no_clone
-STC_DEF _cx_self
-_cx_memb(_clone)(_cx_self m) {
- if (m.table) {
- _cx_value *t = (_cx_value *)i_malloc(c_sizeof(_cx_value)*m.bucket_count),
- *dst = t, *m_end = m.table + m.bucket_count;
- uint8_t *h = (uint8_t *)c_memcpy(i_malloc(m.bucket_count + 1), m._hashx, m.bucket_count + 1);
- if (!(t && h))
- { i_free(t), i_free(h), t = 0, h = 0, m.bucket_count = 0; }
+STC_DEF _cx_Self
+_cx_MEMB(_clone)(_cx_Self m) {
+ if (m.data) {
+ _cx_value *d = (_cx_value *)i_malloc(c_sizeof(_cx_value)*m.bucket_count),
+ *_dst = d, *_end = m.data + m.bucket_count;
+ const intptr_t _mem = c_sizeof(struct chash_slot)*(m.bucket_count + 1);
+ struct chash_slot *s = (struct chash_slot *)c_memcpy(i_malloc(_mem), m.slot, _mem);
+ if (!(d && s))
+ { i_free(d), i_free(s), d = 0, s = 0, m.bucket_count = 0; }
else
- for (; m.table != m_end; ++m.table, ++m._hashx, ++dst)
- if (*m._hashx)
- *dst = _cx_memb(_value_clone)(*m.table);
- m.table = t, m._hashx = h;
+ for (; m.data != _end; ++m.data, ++m.slot, ++_dst)
+ if (m.slot->hashx)
+ *_dst = _cx_MEMB(_value_clone)(*m.data);
+ m.data = d, m.slot = s;
}
return m;
}
#endif
STC_DEF bool
-_cx_memb(_reserve)(_cx_self* self, const _i_size newcap) {
- const i_ssize _oldbuckets = self->bucket_count, _newcap = (i_ssize)newcap;
- if (_newcap != self->size && _newcap <= _oldbuckets)
+_cx_MEMB(_reserve)(_cx_Self* self, const intptr_t _newcap) {
+ const intptr_t _oldbucks = self->bucket_count;
+ if (_newcap != self->size && _newcap <= _oldbucks)
return true;
- i_ssize _nbuckets = (i_ssize)((float)_newcap / (i_max_load_factor)) + 4;
- #if _i_expandby == 2
- _nbuckets = (i_ssize)next_power_of_2(_nbuckets);
- #else
- _nbuckets |= 1;
- #endif
- _cx_self m = {
- (_cx_value *)i_malloc(c_sizeof(_cx_value)*_nbuckets),
- (uint8_t *)i_calloc(_nbuckets + 1, 1),
- self->size, _nbuckets,
+ intptr_t _newbucks = (intptr_t)((float)_newcap / (i_max_load_factor)) + 4;
+ _newbucks = stc_nextpow2(_newbucks);
+ _cx_Self m = {
+ (_cx_value *)i_malloc(_newbucks*c_sizeof(_cx_value)),
+ (struct chash_slot *)i_calloc(_newbucks + 1, c_sizeof(struct chash_slot)),
+ self->size, _newbucks
};
- bool ok = m.table && m._hashx;
- if (ok) { /* Rehash: */
- m._hashx[_nbuckets] = 0xff;
- const _cx_value* e = self->table;
- const uint8_t* h = self->_hashx;
- for (i_ssize i = 0; i < _oldbuckets; ++i, ++e) if (*h++) {
- _cx_keyraw r = i_keyto(_i_keyref(e));
- chash_bucket_t b = _cx_memb(_bucket_)(&m, &r);
- m.table[b.idx] = *e;
- m._hashx[b.idx] = b.hx;
+ bool ok = m.data && m.slot;
+ if (ok) { // Rehash:
+ m.slot[_newbucks].hashx = 0xff;
+ const _cx_value* d = self->data;
+ const struct chash_slot* s = self->slot;
+ for (intptr_t i = 0; i < _oldbucks; ++i, ++d) if ((s++)->hashx) {
+ _cx_keyraw r = i_keyto(_i_keyref(d));
+ _cx_result b = _cx_MEMB(_bucket_)(&m, &r);
+ m.slot[b.ref - m.data].hashx = b.hashx;
+ *b.ref = *d; // move
}
- c_swap(_cx_self, self, &m);
+ c_swap(_cx_Self, self, &m);
}
- i_free(m._hashx);
- i_free(m.table);
+ i_free(m.slot);
+ i_free(m.data);
return ok;
}
STC_DEF void
-_cx_memb(_erase_entry)(_cx_self* self, _cx_value* _val) {
- i_ssize i = (i_ssize)(_val - self->table), j = i, k;
- const i_ssize _cap = self->bucket_count;
- _cx_value* _slot = self->table;
- uint8_t* _hashx = self->_hashx;
- _cx_memb(_value_drop)(_val);
- for (;;) { /* delete without leaving tombstone */
- if (++j == _cap)
- j = 0;
- if (! _hashx[j])
+_cx_MEMB(_erase_entry)(_cx_Self* self, _cx_value* _val) {
+ _cx_value* d = self->data;
+ struct chash_slot* s = self->slot;
+ intptr_t i = _val - d, j = i, k;
+ const intptr_t _cap = self->bucket_count;
+ _cx_MEMB(_value_drop)(_val);
+ for (;;) { // delete without leaving tombstone
+ if (++j == _cap) j = 0;
+ if (! s[j].hashx)
break;
- const _cx_keyraw _raw = i_keyto(_i_keyref(_slot + j));
- k = (i_ssize)c_PASTE(fastrange_,_i_expandby)(i_hash((&_raw)), (uint64_t)_cap);
- if ((j < i) ^ (k <= i) ^ (k > j)) /* is k outside (i, j]? */
- _slot[i] = _slot[j], _hashx[i] = _hashx[j], i = j;
+ const _cx_keyraw _raw = i_keyto(_i_keyref(d + j));
+ k = fastrange_2(i_hash((&_raw)), _cap);
+ if ((j < i) ^ (k <= i) ^ (k > j)) { // is k outside (i, j]?
+ d[i] = d[j];
+ s[i] = s[j];
+ i = j;
+ }
}
- _hashx[i] = 0;
+ s[i].hashx = 0;
--self->size;
}
-
#endif // i_implement
#undef i_max_load_factor
-#undef _i_size
#undef _i_isset
#undef _i_ismap
#undef _i_ishash
diff --git a/include/stc/coroutine.h b/include/stc/coroutine.h
new file mode 100644
index 00000000..5f06e7b8
--- /dev/null
+++ b/include/stc/coroutine.h
@@ -0,0 +1,288 @@
+/* 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.
+ */
+#ifndef STC_COROUTINE_INCLUDED
+#define STC_COROUTINE_INCLUDED
+/*
+#include <stdio.h>
+#include <stc/coroutine.h>
+
+struct iterpair {
+ int max_x, max_y;
+ int x, y;
+ int cco_state; // required member
+};
+
+int iterpair(struct iterpair* I) {
+ cco_routine(I) {
+ for (I->x = 0; I->x < I->max_x; I->x++)
+ for (I->y = 0; I->y < I->max_y; I->y++)
+ cco_yield();
+
+ cco_final: // required if there is cleanup code
+ puts("final");
+ }
+ return 0; // CCO_DONE
+}
+
+int main(void) {
+ struct iterpair it = {.max_x=3, .max_y=3};
+ int n = 0;
+ while (iterpair(&it))
+ {
+ printf("%d %d\n", it.x, it.y);
+ // example of early stop:
+ if (++n == 7) cco_stop(&it); // signal to stop/finalize in next
+ }
+ return 0;
+}
+*/
+#include "ccommon.h"
+
+enum {
+ CCO_STATE_CLEANUP = -1,
+ CCO_STATE_DONE = -2,
+};
+typedef enum {
+ CCO_DONE = 0,
+ CCO_AWAIT = 1<<0,
+ CCO_YIELD = 1<<1,
+} cco_result;
+
+#define cco_initial(co) ((co)->cco_state == 0)
+#define cco_suspended(co) ((co)->cco_state > 0)
+#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) \
+ _resume: switch (*_state) case 0: // thanks, @liigo!
+
+#define cco_yield() cco_yield_v(CCO_YIELD)
+#define cco_yield_v(ret) \
+ do { \
+ *_state = __LINE__; return ret; goto _resume; \
+ case __LINE__:; \
+ } while (0)
+
+#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_call(): assumes coroutine returns a cco_result value (int) */
+#define cco_await_call(...) c_MACRO_OVERLOAD(cco_await_call, __VA_ARGS__)
+#define cco_await_call_1(corocall) cco_await_call_2(corocall, CCO_DONE)
+#define cco_await_call_2(corocall, awaitbits) \
+ do { \
+ *_state = __LINE__; \
+ case __LINE__: { int _r = corocall; if (_r & ~(awaitbits)) {return _r; goto _resume;} } \
+ } while (0)
+
+/* cco_blocking_call(): assumes coroutine returns a cco_result value (int) */
+#define cco_blocking_call(corocall) while ((corocall) != CCO_DONE)
+
+#define cco_cleanup cco_final // [deprecated]
+#define cco_final \
+ *_state = CCO_STATE_CLEANUP; case CCO_STATE_CLEANUP
+
+#define cco_return \
+ do { \
+ *_state = *_state >= 0 ? CCO_STATE_CLEANUP : CCO_STATE_DONE; \
+ goto _resume; \
+ } while (0)
+
+#define cco_yield_final() cco_yield_final_v(CCO_YIELD)
+#define cco_yield_final_v(value) \
+ do { \
+ *_state = *_state >= 0 ? CCO_STATE_CLEANUP : CCO_STATE_DONE; \
+ return value; \
+ } while (0)
+
+#define cco_stop(co) \
+ do { \
+ int* _s = &(co)->cco_state; \
+ if (*_s > 0) *_s = CCO_STATE_CLEANUP; \
+ else if (*_s == 0) *_s = CCO_STATE_DONE; \
+ } while (0)
+
+#define cco_reset(co) \
+ (void)((co)->cco_state = 0)
+
+/*
+ * Iterator (for generators)
+ * User define: Gen must be an existing typedef struct:
+ * Gen_iter Gen_begin(Gen* g); // function
+ * int Gen_next(Gen_iter* it); // coroutine
+ */
+
+#define cco_iter_struct(Gen, ...) \
+ typedef Gen Gen##_value; \
+ typedef struct Gen##_iter { \
+ Gen##_value* ref; \
+ int cco_state; \
+ __VA_ARGS__ \
+ } Gen##_iter
+
+/*
+ * Tasks
+ */
+
+struct cco_runtime;
+
+#define cco_task_struct(Task, ...) \
+ struct Task { \
+ int (*cco_func)(struct Task*, struct cco_runtime*); \
+ int cco_state, cco_expect; \
+ __VA_ARGS__ \
+ }
+
+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_resume_task(task, rt) \
+ (task)->cco_func(task, rt)
+
+#define cco_await_task(...) c_MACRO_OVERLOAD(cco_await_task, __VA_ARGS__)
+#define cco_await_task_2(task, rt) cco_await_task_3(task, rt, CCO_DONE)
+#define cco_await_task_3(task, rt, awaitbits) \
+ do { \
+ cco_runtime* _rt = rt; \
+ (_rt->stack[++_rt->top] = cco_cast_task(task))->cco_expect = (awaitbits); \
+ cco_yield_v(CCO_AWAIT); \
+ } while (0)
+
+#define cco_blocking_task(...) c_MACRO_OVERLOAD(cco_blocking_task, __VA_ARGS__)
+#define cco_blocking_task_1(task) cco_blocking_task_3(task, _rt, 16)
+#define cco_blocking_task_3(task, rt, STACKDEPTH) \
+ for (struct { int result, top; cco_task* stack[STACKDEPTH]; } rt = {.stack={cco_cast_task(task)}}; \
+ (((rt.result = cco_resume_task(rt.stack[rt.top], (cco_runtime*)&rt)) & \
+ ~rt.stack[rt.top]->cco_expect) || --rt.top >= 0); )
+
+/*
+ * Semaphore
+ */
+
+typedef struct { intptr_t count; } cco_sem;
+
+#define cco_await_sem(sem) cco_await_sem_and_return(sem, CCO_AWAIT)
+#define cco_await_sem_v(sem) cco_await_sem_and_return(sem, )
+#define cco_await_sem_and_return(sem, ret) \
+ do { \
+ cco_await_and_return((sem)->count > 0, ret); \
+ --(sem)->count; \
+ } while (0)
+
+#define cco_sem_release(sem) ++(sem)->count
+#define cco_sem_from(value) ((cco_sem){value})
+#define cco_sem_set(sem, value) ((sem)->count = value)
+
+/*
+ * Timer
+ */
+
+#ifdef _WIN32
+ #ifdef __cplusplus
+ #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_getsystime GetSystemTimePreciseAsFileTime
+ #endif
+ 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 */
+ _c_getsystime((struct _FILETIME*)&quad);
+ return (double)(quad - 116444736000000000ULL)*1e-7; /* time diff Jan 1 1601-Jan 1 1970 in 1/10th usecs */
+ }
+
+ static inline void cco_sleep(double sec) {
+ Sleep((unsigned long)(sec*1000.0));
+ }
+#else
+ #include <sys/time.h>
+ static inline double cco_time(void) { /* seconds since epoch */
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ return (double)tv.tv_sec + (double)tv.tv_usec*1e-6;
+ }
+
+ static inline void cco_sleep(double sec) {
+ struct timeval tv;
+ tv.tv_sec = (time_t)sec;
+ tv.tv_usec = (suseconds_t)((sec - (double)(long)sec)*1e6);
+ select(0, NULL, NULL, NULL, &tv);
+ }
+#endif
+
+typedef struct { double interval, start; } cco_timer;
+
+#define cco_await_timer(tm, sec) cco_await_timer_v_3(tm, sec, CCO_AWAIT)
+#define cco_await_timer_v(...) c_MACRO_OVERLOAD(cco_await_timer_v, __VA_ARGS__)
+#define cco_await_timer_v_2(tm, sec) cco_await_timer_v_3(tm, sec, )
+#define cco_await_timer_v_3(tm, sec, ret) \
+ do { \
+ cco_timer_start(tm, sec); \
+ cco_await_and_return(cco_timer_expired(tm), ret); \
+ } while (0)
+
+static inline void cco_timer_start(cco_timer* tm, double sec) {
+ tm->interval = sec;
+ tm->start = cco_time();
+}
+
+static inline cco_timer cco_timer_from(double sec) {
+ cco_timer tm = {.interval=sec, .start=cco_time()};
+ return tm;
+}
+
+static inline void cco_timer_restart(cco_timer* tm) {
+ tm->start = cco_time();
+}
+
+static inline bool cco_timer_expired(cco_timer* tm) {
+ return cco_time() - tm->start >= tm->interval;
+}
+
+static inline double cco_timer_elapsed(cco_timer* tm) {
+ return cco_time() - tm->start;
+}
+
+static inline double cco_timer_remaining(cco_timer* tm) {
+ return tm->start + tm->interval - cco_time();
+}
+
+#endif
diff --git a/include/stc/cpque.h b/include/stc/cpque.h
index b95b5020..520514ef 100644
--- a/include/stc/cpque.h
+++ b/include/stc/cpque.h
@@ -20,101 +20,100 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
-#include "ccommon.h"
+#include "priv/linkage.h"
#ifndef CPQUE_H_INCLUDED
+#include "ccommon.h"
#include <stdlib.h>
#include "forward.h"
#endif
-#ifndef _i_prefix
#define _i_prefix cpque_
-#endif
-
+#define _i_ispque
#include "priv/template.h"
#ifndef i_is_forward
- _cx_deftypes(_c_cpque_types, _cx_self, i_key);
+ _cx_DEFTYPES(_c_cpque_types, _cx_Self, i_key);
#endif
typedef i_keyraw _cx_raw;
-STC_API void _cx_memb(_make_heap)(_cx_self* self);
-STC_API void _cx_memb(_erase_at)(_cx_self* self, intptr_t idx);
-STC_API void _cx_memb(_push)(_cx_self* self, _cx_value value);
+STC_API void _cx_MEMB(_make_heap)(_cx_Self* self);
+STC_API void _cx_MEMB(_erase_at)(_cx_Self* self, intptr_t idx);
+STC_API _cx_value* _cx_MEMB(_push)(_cx_Self* self, _cx_value value);
-STC_INLINE _cx_self _cx_memb(_init)(void)
- { return c_LITERAL(_cx_self){NULL}; }
+STC_INLINE _cx_Self _cx_MEMB(_init)(void)
+ { return c_LITERAL(_cx_Self){NULL}; }
-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 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 _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 bool _cx_memb(_reserve)(_cx_self* self, const intptr_t cap) {
+STC_INLINE bool _cx_MEMB(_reserve)(_cx_Self* self, const intptr_t cap) {
if (cap != self->_len && cap <= self->_cap) return true;
_cx_value *d = (_cx_value *)i_realloc(self->data, cap*c_sizeof *d);
return d ? (self->data = d, self->_cap = cap, true) : false;
}
-STC_INLINE void _cx_memb(_shrink_to_fit)(_cx_self* self)
- { _cx_memb(_reserve)(self, self->_len); }
+STC_INLINE void _cx_MEMB(_shrink_to_fit)(_cx_Self* self)
+ { _cx_MEMB(_reserve)(self, self->_len); }
-STC_INLINE _cx_self _cx_memb(_with_capacity)(const intptr_t cap) {
- _cx_self out = {NULL}; _cx_memb(_reserve)(&out, cap);
+STC_INLINE _cx_Self _cx_MEMB(_with_capacity)(const intptr_t cap) {
+ _cx_Self out = {NULL}; _cx_MEMB(_reserve)(&out, cap);
return out;
}
-STC_INLINE _cx_self _cx_memb(_with_size)(const intptr_t size, i_key null) {
- _cx_self out = {NULL}; _cx_memb(_reserve)(&out, size);
+STC_INLINE _cx_Self _cx_MEMB(_with_size)(const intptr_t size, i_key null) {
+ _cx_Self out = {NULL}; _cx_MEMB(_reserve)(&out, size);
while (out._len < size) out.data[out._len++] = null;
return out;
}
-STC_INLINE void _cx_memb(_clear)(_cx_self* self) {
+STC_INLINE void _cx_MEMB(_clear)(_cx_Self* self) {
intptr_t i = self->_len; self->_len = 0;
while (i--) { i_keydrop((self->data + i)); }
}
-STC_INLINE void _cx_memb(_drop)(_cx_self* self)
- { _cx_memb(_clear)(self); i_free(self->data); }
+STC_INLINE void _cx_MEMB(_drop)(_cx_Self* self)
+ { _cx_MEMB(_clear)(self); i_free(self->data); }
-STC_INLINE intptr_t _cx_memb(_size)(const _cx_self* q)
+STC_INLINE intptr_t _cx_MEMB(_size)(const _cx_Self* q)
{ return q->_len; }
-STC_INLINE bool _cx_memb(_empty)(const _cx_self* q)
+STC_INLINE bool _cx_MEMB(_empty)(const _cx_Self* q)
{ return !q->_len; }
-STC_INLINE intptr_t _cx_memb(_capacity)(const _cx_self* q)
+STC_INLINE intptr_t _cx_MEMB(_capacity)(const _cx_Self* q)
{ return q->_cap; }
-STC_INLINE const _cx_value* _cx_memb(_top)(const _cx_self* self)
+STC_INLINE const _cx_value* _cx_MEMB(_top)(const _cx_Self* self)
{ return &self->data[0]; }
-STC_INLINE void _cx_memb(_pop)(_cx_self* self)
- { assert(!_cx_memb(_empty)(self)); _cx_memb(_erase_at)(self, 0); }
+STC_INLINE void _cx_MEMB(_pop)(_cx_Self* self)
+ { c_assert(!_cx_MEMB(_empty)(self)); _cx_MEMB(_erase_at)(self, 0); }
#if !defined i_no_clone
-STC_API _cx_self _cx_memb(_clone)(_cx_self q);
+STC_API _cx_Self _cx_MEMB(_clone)(_cx_Self q);
-STC_INLINE void _cx_memb(_copy)(_cx_self *self, const _cx_self* other) {
+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);
+ _cx_MEMB(_drop)(self);
+ *self = _cx_MEMB(_clone)(*other);
}
-STC_INLINE i_key _cx_memb(_value_clone)(_cx_value val)
+STC_INLINE i_key _cx_MEMB(_value_clone)(_cx_value val)
{ return i_keyclone(val); }
#endif // !i_no_clone
#if !defined i_no_emplace
-STC_INLINE void _cx_memb(_emplace)(_cx_self* self, _cx_raw raw)
- { _cx_memb(_push)(self, i_keyfrom(raw)); }
+STC_INLINE void _cx_MEMB(_emplace)(_cx_Self* self, _cx_raw raw)
+ { _cx_MEMB(_push)(self, i_keyfrom(raw)); }
#endif // !i_no_emplace
/* -------------------------- IMPLEMENTATION ------------------------- */
-#if defined(i_implement)
+#if defined(i_implement) || defined(i_static)
STC_DEF void
-_cx_memb(_sift_down_)(_cx_self* self, const intptr_t idx, const intptr_t n) {
+_cx_MEMB(_sift_down_)(_cx_Self* self, const intptr_t idx, const intptr_t n) {
_cx_value t, *arr = self->data - 1;
for (intptr_t r = idx, c = idx*2; c <= n; c *= 2) {
c += i_less((&arr[c]), (&arr[c + (c < n)]));
@@ -124,15 +123,15 @@ _cx_memb(_sift_down_)(_cx_self* self, const intptr_t idx, const intptr_t n) {
}
STC_DEF void
-_cx_memb(_make_heap)(_cx_self* self) {
+_cx_MEMB(_make_heap)(_cx_Self* self) {
intptr_t n = self->_len;
for (intptr_t k = n/2; k != 0; --k)
- _cx_memb(_sift_down_)(self, k, n);
+ _cx_MEMB(_sift_down_)(self, k, n);
}
#if !defined i_no_clone
-STC_DEF _cx_self _cx_memb(_clone)(_cx_self q) {
- _cx_self out = _cx_memb(_with_capacity)(q._len);
+STC_DEF _cx_Self _cx_MEMB(_clone)(_cx_Self q) {
+ _cx_Self out = _cx_MEMB(_with_capacity)(q._len);
for (; out._len < out._cap; ++q.data)
out.data[out._len++] = i_keyclone((*q.data));
return out;
@@ -140,24 +139,26 @@ STC_DEF _cx_self _cx_memb(_clone)(_cx_self q) {
#endif
STC_DEF void
-_cx_memb(_erase_at)(_cx_self* self, const intptr_t idx) {
+_cx_MEMB(_erase_at)(_cx_Self* self, const intptr_t idx) {
i_keydrop((self->data + idx));
const intptr_t n = --self->_len;
self->data[idx] = self->data[n];
- _cx_memb(_sift_down_)(self, idx + 1, n);
+ _cx_MEMB(_sift_down_)(self, idx + 1, n);
}
-STC_DEF void
-_cx_memb(_push)(_cx_self* self, _cx_value value) {
+STC_DEF _cx_value*
+_cx_MEMB(_push)(_cx_Self* self, _cx_value value) {
if (self->_len == self->_cap)
- _cx_memb(_reserve)(self, self->_len*3/2 + 4);
+ _cx_MEMB(_reserve)(self, self->_len*3/2 + 4);
_cx_value *arr = self->data - 1; /* base 1 */
intptr_t c = ++self->_len;
for (; c > 1 && (i_less((&arr[c/2]), (&value))); c /= 2)
arr[c] = arr[c/2];
arr[c] = value;
+ return arr + c;
}
#endif
#define CPQUE_H_INCLUDED
#include "priv/template2.h"
+#undef _i_ispque \ No newline at end of file
diff --git a/include/stc/cqueue.h b/include/stc/cqueue.h
index 1934305a..8a609b96 100644
--- a/include/stc/cqueue.h
+++ b/include/stc/cqueue.h
@@ -20,46 +20,23 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
-// STC queue
-/*
-#include <stc/crand.h>
-#include <stdio.h>
+#include "priv/linkage.h"
-#define i_key int
-#include <stc/cqueue.h>
-
-int main() {
- int n = 10000000;
- crand_t rng = crand_init(1234);
- crand_unif_t dist = crand_unif_init(0, n);
-
- c_auto (cqueue_int, Q)
- {
- // Push ten million random numbers onto the queue.
- for (int i=0; i<n; ++i)
- cqueue_int_push(&Q, crand_unif(&rng, &dist));
-
- // Push or pop on the queue ten million times
- printf("before: size, capacity: %d, %d\n", n, cqueue_int_size(&Q), cqueue_int_capacity(&Q));
- for (int i=n; i>0; --i) {
- int r = crand_unif(&rng, &dist);
- if (r & 1)
- ++n, cqueue_int_push(&Q, r);
- else
- --n, cqueue_int_pop(&Q);
- }
- printf("after: size, capacity: %d, %d\n", n, cqueue_int_size(&Q), cqueue_int_capacity(&Q));
- }
-}
-*/
+#ifndef CQUEUE_H_INCLUDED
+#include "ccommon.h"
+#include "forward.h"
+#include <stdlib.h>
+#include <string.h>
+#endif // CQUEUE_H_INCLUDED
#ifndef _i_prefix
#define _i_prefix cqueue_
#endif
-#define _i_queue
-#define _pop_front _pop
-
-#include "cdeq.h"
+#include "priv/cqueue_hdr.h"
-#undef _pop_front
-#undef _i_queue
+/* -------------------------- IMPLEMENTATION ------------------------- */
+#if defined(i_implement) || defined(i_static)
+#include "priv/cqueue_imp.h"
+#endif // IMPLEMENTATION
+#define CQUEUE_H_INCLUDED
+#include "priv/template2.h"
diff --git a/include/stc/crand.h b/include/stc/crand.h
index a1b7250d..32722762 100644
--- a/include/stc/crand.h
+++ b/include/stc/crand.h
@@ -20,31 +20,32 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
-#include "ccommon.h"
+#include "priv/linkage.h"
#ifndef CRAND_H_INCLUDED
#define CRAND_H_INCLUDED
+#include "ccommon.h"
/*
// crand: Pseudo-random number generator
#include "stc/crand.h"
-int main() {
+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.
@@ -66,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) {
@@ -92,13 +93,12 @@ STC_INLINE double crand_f64(crand_t* rng) {
}
/* -------------------------- IMPLEMENTATION ------------------------- */
-#if defined(i_implement)
+#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)
@@ -115,32 +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;
}
-#if defined(__SIZEOF_INT128__)
- #define c_umul128(a, b, lo, hi) \
- do { __uint128_t _z = (__uint128_t)(a)*(b); \
- *(lo) = (uint64_t)_z, *(hi) = (uint64_t)(_z >> 64U); } while(0)
-#elif defined(_MSC_VER) && defined(_WIN64)
- #include <intrin.h>
- #define c_umul128(a, b, lo, hi) ((void)(*(lo) = _umul128(a, b, hi)))
-#elif defined(__x86_64__)
- #define c_umul128(a, b, lo, hi) \
- asm("mulq %3" : "=a"(*(lo)), "=d"(*(hi)) : "a"(a), "rm"(b))
-#endif
-
/* 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);
@@ -151,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;
@@ -164,11 +152,10 @@ STC_DEF double crand_norm(crand_t* rng, crand_norm_t* dist) {
dist->next = u2*m;
return (u1*m)*dist->stddev + dist->mean;
}
-
#endif
#endif
#undef i_opt
#undef i_static
#undef i_header
#undef i_implement
-#undef i_extern
+#undef i_import
diff --git a/include/stc/crandom.h b/include/stc/crandom.h
deleted file mode 100644
index a9374602..00000000
--- a/include/stc/crandom.h
+++ /dev/null
@@ -1,197 +0,0 @@
-/* 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 "ccommon.h"
-
-#ifndef CRANDOM_H_INCLUDED
-#define CRANDOM_H_INCLUDED
-/*
-// crandom: Pseudo-random number generator
-#include "stc/crandom.h"
-int main() {
- uint64_t seed = 123456789;
- stc64_t rng = stc64_new(seed);
- stc64_uniform_t dist1 = stc64_uniform_new(1, 6);
- stc64_uniformf_t dist2 = stc64_uniformf_new(1.0, 10.0);
- stc64_normalf_t dist3 = stc64_normalf_new(1.0, 10.0);
-
- uint64_t i = stc64_rand(&rng);
- int64_t iu = stc64_uniform(&rng, &dist1);
- double xu = stc64_uniformf(&rng, &dist2);
- double xn = stc64_normalf(&rng, &dist3);
-}
-*/
-#include <string.h>
-#include <math.h>
-
-typedef struct stc64 { uint64_t state[5]; } stc64_t;
-typedef struct stc64_uniform { int64_t lower; uint64_t range, threshold; } stc64_uniform_t;
-typedef struct stc64_uniformf { double lower, range; } stc64_uniformf_t;
-typedef struct stc64_normalf { double mean, stddev, next; int has_next; } stc64_normalf_t;
-
-/* PRNG stc64.
- * Very fast PRNG suited for parallel usage with Weyl-sequence parameter.
- * 320-bit state, 256 bit is mutable.
- * Noticable faster than xoshiro and pcg, slighly slower than wyrand64 and
- * Romu, but these have restricted capacity for larger parallel jobs or unknown minimum periods.
- * stc64 supports 2^63 unique threads with a minimum 2^64 period lengths each.
- * Passes all statistical tests, e.g PractRand and correlation tests, i.e. interleaved
- * streams with one-bit diff state. Even the 16-bit version (LR=6, RS=5, LS=3) passes
- * PractRand to multiple TB input.
- */
-
-/* Global stc64 PRNGs */
-STC_API void csrandom(uint64_t seed);
-STC_API uint64_t crandom(void);
-STC_API double crandomf(void);
-
-/* Init stc64 prng with and without sequence number */
-STC_API stc64_t stc64_with_seq(uint64_t seed, uint64_t seq);
-STC_INLINE stc64_t stc64_new(uint64_t seed)
- { return stc64_with_seq(seed, seed + 0x3504f333d3aa0b37); }
-
-/* Unbiased bounded uniform distribution. range [low, high] */
-STC_API stc64_uniform_t stc64_uniform_new(int64_t low, int64_t high);
-STC_API int64_t stc64_uniform(stc64_t* rng, stc64_uniform_t* dist);
-
-/* Normal distribution PRNG */
-STC_API double stc64_normalf(stc64_t* rng, stc64_normalf_t* dist);
-
-
-/* Main stc64 prng */
-STC_INLINE uint64_t stc64_rand(stc64_t* rng) {
- uint64_t *s = rng->state; enum {LR=24, RS=11, LS=3};
- const uint64_t result = (s[0] ^ (s[3] += s[4])) + s[1];
- s[0] = s[1] ^ (s[1] >> RS);
- s[1] = s[2] + (s[2] << LS);
- s[2] = ((s[2] << LR) | (s[2] >> (64 - LR))) + result;
- return result;
-}
-
-/* Float64 random number in range [0.0, 1.0). */
-STC_INLINE double stc64_randf(stc64_t* rng) {
- union {uint64_t i; double f;} u = {0x3FF0000000000000ull | (stc64_rand(rng) >> 12)};
- return u.f - 1.0;
-}
-
-/* Float64 uniform distributed RNG, range [low, high). */
-STC_INLINE double stc64_uniformf(stc64_t* rng, stc64_uniformf_t* dist) {
- return stc64_randf(rng)*dist->range + dist->lower;
-}
-
-/* Init uniform distributed float64 RNG, range [low, high). */
-STC_INLINE stc64_uniformf_t stc64_uniformf_new(double low, double high) {
- return c_LITERAL(stc64_uniformf_t){low, high - low};
-}
-
-/* Marsaglia polar method for gaussian/normal distribution, float64. */
-STC_INLINE stc64_normalf_t stc64_normalf_new(double mean, double stddev) {
- return c_LITERAL(stc64_normalf_t){mean, stddev, 0.0, 0};
-}
-
-/* -------------------------- IMPLEMENTATION ------------------------- */
-#if defined(i_implement)
-
-/* Global random() */
-static stc64_t stc64_global = {{
- 0x26aa069ea2fb1a4d, 0x70c72c95cd592d04,
- 0x504f333d3aa0b359, 0x9e3779b97f4a7c15,
- 0x6a09e667a754166b
-}};
-
-STC_DEF void csrandom(uint64_t seed) {
- stc64_global = stc64_new(seed);
-}
-
-STC_DEF uint64_t crandom(void) {
- return stc64_rand(&stc64_global);
-}
-
-STC_DEF double crandomf(void) {
- return stc64_randf(&stc64_global);
-}
-
-/* rng.state[4] must be odd */
-STC_DEF stc64_t stc64_with_seq(uint64_t seed, uint64_t seq) {
- stc64_t rng = {{seed+0x26aa069ea2fb1a4d, seed+0x70c72c95cd592d04,
- seed+0x504f333d3aa0b359, seed, seq<<1 | 1}};
- for (int i = 0; i < 6; ++i) stc64_rand(&rng);
- return rng;
-}
-
-/* Init unbiased uniform uint RNG with bounds [low, high] */
-STC_DEF stc64_uniform_t stc64_uniform_new(int64_t low, int64_t high) {
- stc64_uniform_t dist = {low, (uint64_t) (high - low + 1)};
- dist.threshold = (uint64_t)(0 - dist.range) % dist.range;
- return dist;
-}
-
-#if defined(__SIZEOF_INT128__)
- #define c_umul128(a, b, lo, hi) \
- do { __uint128_t _z = (__uint128_t)(a)*(b); \
- *(lo) = (uint64_t)_z, *(hi) = (uint64_t)(_z >> 64U); } while(0)
-#elif defined(_MSC_VER) && defined(_WIN64)
- #include <intrin.h>
- #define c_umul128(a, b, lo, hi) ((void)(*(lo) = _umul128(a, b, hi)))
-#elif defined(__x86_64__)
- #define c_umul128(a, b, lo, hi) \
- asm("mulq %3" : "=a"(*(lo)), "=d"(*(hi)) : "a"(a), "rm"(b))
-#endif
-
-/* Int uniform distributed RNG, range [low, high]. */
-STC_DEF int64_t stc64_uniform(stc64_t* rng, stc64_uniform_t* d) {
-#ifdef c_umul128
- uint64_t lo, hi;
- do { c_umul128(stc64_rand(rng), d->range, &lo, &hi); } while (lo < d->threshold);
- return d->lower + (int64_t)hi;
-#else
- uint64_t x, r;
- do {
- x = stc64_rand(rng);
- r = x % d->range;
- } while (x - r > -d->range);
- return d->lower + r;
-#endif
-}
-
-/* Normal distribution PRNG */
-STC_DEF double stc64_normalf(stc64_t* rng, stc64_normalf_t* dist) {
- double u1, u2, s, m;
- if (dist->has_next++ & 1)
- return dist->next * dist->stddev + dist->mean;
- do {
- u1 = 2.0 * stc64_randf(rng) - 1.0;
- u2 = 2.0 * stc64_randf(rng) - 1.0;
- s = u1*u1 + u2*u2;
- } while (s >= 1.0 || s == 0.0);
- m = sqrt(-2.0 * log(s) / s);
- dist->next = u2 * m;
- return (u1 * m) * dist->stddev + dist->mean;
-}
-
-#endif
-#endif
-#undef i_opt
-#undef i_static
-#undef i_header
-#undef i_implement
-#undef i_extern
diff --git a/include/stc/crawstr.h b/include/stc/crawstr.h
new file mode 100644
index 00000000..9dbdb6f7
--- /dev/null
+++ b/include/stc/crawstr.h
@@ -0,0 +1,108 @@
+/* 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.
+ */
+#define _i_inc_utf8
+#include "utf8.h"
+
+#ifndef CRAWSTR_H_INCLUDED
+#define CRAWSTR_H_INCLUDED
+
+#define crawstr_init() c_rs("")
+#define crawstr_clone(rs) c_default_clone(rs)
+#define crawstr_drop(self) c_default_drop(self)
+#define crawstr_toraw(self) (self)->str
+
+STC_INLINE crawstr crawstr_from(const char* str)
+ { return c_rs_2(str, c_strlen(str)); }
+STC_INLINE void crawstr_clear(crawstr* self) { *self = c_rs(""); }
+STC_INLINE csview crawstr_sv(crawstr rs) { return c_sv_2(rs.str, rs.size); }
+
+STC_INLINE intptr_t crawstr_size(crawstr rs) { return rs.size; }
+STC_INLINE bool crawstr_empty(crawstr rs) { return rs.size == 0; }
+
+STC_INLINE bool crawstr_equals(crawstr rs, const char* str) {
+ intptr_t n = c_strlen(str);
+ return rs.size == n && !c_memcmp(rs.str, str, n);
+}
+
+STC_INLINE intptr_t crawstr_find(crawstr rs, const char* search) {
+ char* res = strstr(rs.str, search);
+ return res ? (res - rs.str) : c_NPOS;
+}
+
+STC_INLINE bool crawstr_contains(crawstr rs, const char* str)
+ { return crawstr_find(rs, str) != c_NPOS; }
+
+STC_INLINE bool crawstr_starts_with(crawstr rs, const char* str) {
+ intptr_t n = c_strlen(str);
+ return n > rs.size ? false : !c_memcmp(rs.str, str, n);
+}
+
+STC_INLINE bool crawstr_ends_with(crawstr rs, const char* str) {
+ intptr_t n = c_strlen(str);
+ return n > rs.size ? false : !c_memcmp(rs.str + rs.size - n, str, n);
+}
+
+/* utf8 iterator */
+STC_INLINE crawstr_iter crawstr_begin(const crawstr* self) {
+ if (!self->size) return c_LITERAL(crawstr_iter){.ref = NULL};
+ return c_LITERAL(crawstr_iter){.u8 = {{self->str, utf8_chr_size(self->str)}}};
+}
+STC_INLINE crawstr_iter crawstr_end(const crawstr* self) {
+ (void)self; return c_LITERAL(crawstr_iter){.ref = NULL};
+}
+STC_INLINE void crawstr_next(crawstr_iter* it) {
+ it->ref += it->chr.size;
+ it->chr.size = utf8_chr_size(it->ref);
+ if (!*it->ref) it->ref = NULL;
+}
+STC_INLINE crawstr_iter crawstr_advance(crawstr_iter it, intptr_t pos) {
+ int inc = -1;
+ if (pos > 0) pos = -pos, inc = 1;
+ while (pos && *it.ref) pos += (*(it.ref += inc) & 0xC0) != 0x80;
+ it.chr.size = utf8_chr_size(it.ref);
+ if (!*it.ref) it.ref = NULL;
+ return it;
+}
+
+/* utf8 ignore case cmp: depends on src/utf8code.c */
+STC_INLINE int crawstr_icmp(const crawstr* x, const crawstr* y)
+ { return utf8_icmp_sv(c_sv_2(x->str, x->size), c_sv_2(y->str, y->size)); }
+
+STC_INLINE int crawstr_cmp(const crawstr* x, const crawstr* y) {
+ intptr_t n = x->size < y->size ? x->size : y->size;
+ int c = c_memcmp(x->str, y->str, n);
+ return c ? c : (int)(x->size - y->size);
+}
+
+STC_INLINE bool crawstr_eq(const crawstr* x, const crawstr* y)
+ { return x->size == y->size && !c_memcmp(x->str, y->str, x->size); }
+
+STC_INLINE uint64_t crawstr_hash(const crawstr *self)
+ { return stc_hash(self->str, self->size); }
+
+#endif // CRAWSTR_H_INCLUDED
+#undef i_static
+#undef i_header
+#undef i_implement
+#undef i_import
+#undef i_opt
diff --git a/include/stc/cregex.h b/include/stc/cregex.h
index a48b4c49..c8ad6dbe 100644
--- a/include/stc/cregex.h
+++ b/include/stc/cregex.h
@@ -22,6 +22,8 @@ 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 "priv/linkage.h"
+
#ifndef CREGEX_H_INCLUDED
#define CREGEX_H_INCLUDED
/*
@@ -37,15 +39,19 @@ THE SOFTWARE.
enum {
CREG_DEFAULT = 0,
+
/* compile-flags */
- CREG_C_DOTALL = 1<<0, /* dot matches newline too */
- CREG_C_ICASE = 1<<1, /* ignore case */
+ CREG_DOTALL = 1<<0, /* dot matches newline too */
+ CREG_ICASE = 1<<1, /* ignore case */
+
/* match-flags */
- CREG_M_FULLMATCH = 1<<2, /* like start-, end-of-line anchors were in pattern: "^ ... $" */
- CREG_M_NEXT = 1<<3, /* use end of previous match[0] as start of input */
- CREG_M_STARTEND = 1<<4, /* use match[0] as start+end of input */
+ CREG_FULLMATCH = 1<<2, /* like start-, end-of-line anchors were in pattern: "^ ... $" */
+ CREG_NEXT = 1<<3, /* use end of previous match[0] as start of input */
+ CREG_STARTEND = 1<<4, /* use match[0] as start+end of input */
+
/* replace-flags */
- CREG_R_STRIP = 1<<5, /* only keep the matched strings, strip rest */
+ CREG_STRIP = 1<<5, /* only keep the matched strings, strip rest */
+
/* limits */
CREG_MAX_CLASSES = 16,
CREG_MAX_CAPTURES = 32,
@@ -53,7 +59,6 @@ enum {
typedef enum {
CREG_OK = 0,
- CREG_SUCCESS = 0, /* [deprecated] */
CREG_NOMATCH = -1,
CREG_MATCHERROR = -2,
CREG_OUTOFMEMORY = -3,
@@ -82,7 +87,7 @@ typedef struct {
#define c_formatch(it, Re, Input) \
for (cregex_iter it = {Re, Input}; \
- cregex_find_4(it.re, it.input, it.match, CREG_M_NEXT) == CREG_OK; )
+ cregex_find_4(it.re, it.input, it.match, CREG_NEXT) == CREG_OK; )
STC_INLINE cregex cregex_init(void) {
cregex re = {0};
@@ -104,7 +109,7 @@ STC_INLINE cregex cregex_from_2(const char* pattern, int cflags) {
return re;
}
-/* number of capture groups in a regex pattern including full the match capture, 0 if regex is invalid */
+/* number of capture groups in a regex pattern, excluding the full match capture (0) */
int cregex_captures(const cregex* re);
/* return CREG_OK, CREG_NOMATCH or CREG_MATCHERROR. */
@@ -116,7 +121,7 @@ int cregex_find_4(const cregex* re, const char* input, csview match[], int mflag
STC_INLINE int cregex_find_sv(const cregex* re, csview input, csview match[]) {
csview *mp = NULL;
if (match) { match[0] = input; mp = match; }
- return cregex_find(re, input.str, mp, CREG_M_STARTEND);
+ return cregex_find(re, input.buf, mp, CREG_STARTEND);
}
/* match + compile RE pattern */
@@ -136,7 +141,7 @@ STC_INLINE bool cregex_is_match(const cregex* re, const char* input)
#define cregex_replace_sv_4(pattern, input, replace, count) \
cregex_replace_sv_6(pattern, input, replace, count, NULL, CREG_DEFAULT)
cstr cregex_replace_sv_6(const cregex* re, csview input, const char* replace, int count,
- bool (*mfun)(int i, csview match, cstr* mstr), int rflags);
+ bool (*transform)(int group, csview match, cstr* result), int rflags);
/* replace input with replace using regular expression */
#define cregex_replace(...) c_MACRO_OVERLOAD(cregex_replace, __VA_ARGS__)
@@ -154,18 +159,20 @@ STC_INLINE cstr cregex_replace_4(const cregex* re, const char* input, const char
#define cregex_replace_pattern_4(pattern, input, replace, count) \
cregex_replace_pattern_6(pattern, input, replace, count, NULL, CREG_DEFAULT)
cstr cregex_replace_pattern_6(const char* pattern, const char* input, const char* replace, int count,
- bool (*mfun)(int i, csview match, cstr* mstr), int crflags);
+ bool (*transform)(int group, csview match, cstr* result), int crflags);
/* destroy regex */
void cregex_drop(cregex* re);
-
#endif // CREGEX_H_INCLUDED
-#if defined(i_extern)
+
+#if defined i_implement
# include "../../src/cregex.c"
+#endif
+#if defined i_import
# include "../../src/utf8code.c"
-# undef i_extern
#endif
#undef i_opt
#undef i_header
#undef i_static
+#undef i_import
#undef i_implement
diff --git a/include/stc/cset.h b/include/stc/cset.h
index 58cbeb3e..c89a144d 100644
--- a/include/stc/cset.h
+++ b/include/stc/cset.h
@@ -39,8 +39,5 @@ int main(void) {
}
*/
-#ifndef _i_prefix
#define _i_prefix cset_
-#endif
-#define _i_isset
#include "cmap.h"
diff --git a/include/stc/csmap.h b/include/stc/csmap.h
index ebfe8d44..d2e1d1fc 100644
--- a/include/stc/csmap.h
+++ b/include/stc/csmap.h
@@ -24,6 +24,7 @@
// Sorted/Ordered set and map - implemented as an AA-tree.
/*
#include <stdio.h>
+#define i_implement
#include <stc/cstr.h>
#define i_tag sx // Sorted map<cstr, double>
@@ -48,9 +49,10 @@ int main(void) {
csmap_sx_drop(&m);
}
*/
-#include "ccommon.h"
+#include "priv/linkage.h"
#ifndef CSMAP_H_INCLUDED
+#include "ccommon.h"
#include "forward.h"
#include <stdlib.h>
#include <string.h>
@@ -58,27 +60,20 @@ int main(void) {
#endif // CSMAP_H_INCLUDED
#ifndef _i_prefix
-#define _i_prefix csmap_
-#endif
-#ifdef _i_isset
- #define _i_MAP_ONLY c_false
- #define _i_SET_ONLY c_true
- #define _i_keyref(vp) (vp)
-#else
+ #define _i_prefix csmap_
#define _i_ismap
#define _i_MAP_ONLY c_true
#define _i_SET_ONLY c_false
#define _i_keyref(vp) (&(vp)->first)
-#endif
-#ifndef i_ssize
- #define i_ssize int32_t
- #define _i_size intptr_t
#else
- #define _i_size i_ssize
+ #define _i_isset
+ #define _i_MAP_ONLY c_false
+ #define _i_SET_ONLY c_true
+ #define _i_keyref(vp) (vp)
#endif
#include "priv/template.h"
#ifndef i_is_forward
- _cx_deftypes(_c_aatree_types, _cx_self, i_key, i_val, i_ssize, _i_MAP_ONLY, _i_SET_ONLY);
+ _cx_DEFTYPES(_c_aatree_types, _cx_Self, i_key, i_val, _i_MAP_ONLY, _i_SET_ONLY);
#endif
_i_MAP_ONLY( struct _cx_value {
@@ -86,205 +81,251 @@ _i_MAP_ONLY( struct _cx_value {
_cx_mapped second;
}; )
struct _cx_node {
- i_ssize link[2];
+ int32_t link[2];
int8_t level;
_cx_value value;
};
typedef i_keyraw _cx_keyraw;
-typedef i_valraw _cx_memb(_rmapped);
+typedef i_valraw _cx_MEMB(_rmapped);
typedef _i_SET_ONLY( i_keyraw )
_i_MAP_ONLY( struct { i_keyraw first; i_valraw second; } )
_cx_raw;
#if !defined i_no_emplace
-STC_API _cx_result _cx_memb(_emplace)(_cx_self* self, _cx_keyraw rkey _i_MAP_ONLY(, i_valraw rmapped));
+STC_API _cx_result _cx_MEMB(_emplace)(_cx_Self* self, _cx_keyraw rkey _i_MAP_ONLY(, i_valraw rmapped));
#endif // !i_no_emplace
#if !defined i_no_clone
-STC_API _cx_self _cx_memb(_clone)(_cx_self tree);
+STC_API _cx_Self _cx_MEMB(_clone)(_cx_Self tree);
#endif // !i_no_clone
-STC_API _cx_result _cx_memb(_insert)(_cx_self* self, i_key key _i_MAP_ONLY(, i_val mapped));
-STC_API _cx_result _cx_memb(_push)(_cx_self* self, _cx_value _val);
-STC_API void _cx_memb(_drop)(_cx_self* self);
-STC_API bool _cx_memb(_reserve)(_cx_self* self, _i_size cap);
-STC_API _cx_value* _cx_memb(_find_it)(const _cx_self* self, _cx_keyraw rkey, _cx_iter* out);
-STC_API _cx_iter _cx_memb(_lower_bound)(const _cx_self* self, _cx_keyraw rkey);
-STC_API _cx_value* _cx_memb(_front)(const _cx_self* self);
-STC_API _cx_value* _cx_memb(_back)(const _cx_self* self);
-STC_API int _cx_memb(_erase)(_cx_self* self, _cx_keyraw rkey);
-STC_API _cx_iter _cx_memb(_erase_at)(_cx_self* self, _cx_iter it);
-STC_API _cx_iter _cx_memb(_erase_range)(_cx_self* self, _cx_iter it1, _cx_iter it2);
-STC_API void _cx_memb(_next)(_cx_iter* it);
-
-STC_INLINE _cx_self _cx_memb(_init)(void) { _cx_self tree = {0}; return tree; }
-STC_INLINE bool _cx_memb(_empty)(const _cx_self* cx) { return cx->size == 0; }
-STC_INLINE _i_size _cx_memb(_size)(const _cx_self* cx) { return cx->size; }
-STC_INLINE _i_size _cx_memb(_capacity)(const _cx_self* cx) { return cx->cap; }
-STC_INLINE _cx_iter _cx_memb(_find)(const _cx_self* self, _cx_keyraw rkey)
- { _cx_iter it; _cx_memb(_find_it)(self, rkey, &it); return it; }
-STC_INLINE bool _cx_memb(_contains)(const _cx_self* self, _cx_keyraw rkey)
- { _cx_iter it; return _cx_memb(_find_it)(self, rkey, &it) != NULL; }
-STC_INLINE const _cx_value* _cx_memb(_get)(const _cx_self* self, _cx_keyraw rkey)
- { _cx_iter it; return _cx_memb(_find_it)(self, rkey, &it); }
-STC_INLINE _cx_value* _cx_memb(_get_mut)(_cx_self* self, _cx_keyraw rkey)
- { _cx_iter it; return _cx_memb(_find_it)(self, rkey, &it); }
-
-STC_INLINE _cx_self
-_cx_memb(_with_capacity)(const _i_size cap) {
- _cx_self tree = _cx_memb(_init)();
- _cx_memb(_reserve)(&tree, cap);
+STC_API void _cx_MEMB(_drop)(_cx_Self* self);
+STC_API bool _cx_MEMB(_reserve)(_cx_Self* self, intptr_t cap);
+STC_API _cx_value* _cx_MEMB(_find_it)(const _cx_Self* self, _cx_keyraw rkey, _cx_iter* out);
+STC_API _cx_iter _cx_MEMB(_lower_bound)(const _cx_Self* self, _cx_keyraw rkey);
+STC_API _cx_value* _cx_MEMB(_front)(const _cx_Self* self);
+STC_API _cx_value* _cx_MEMB(_back)(const _cx_Self* self);
+STC_API int _cx_MEMB(_erase)(_cx_Self* self, _cx_keyraw rkey);
+STC_API _cx_iter _cx_MEMB(_erase_at)(_cx_Self* self, _cx_iter it);
+STC_API _cx_iter _cx_MEMB(_erase_range)(_cx_Self* self, _cx_iter it1, _cx_iter it2);
+STC_API _cx_iter _cx_MEMB(_begin)(const _cx_Self* self);
+STC_API void _cx_MEMB(_next)(_cx_iter* it);
+
+STC_INLINE _cx_Self _cx_MEMB(_init)(void) { _cx_Self tree = {0}; return tree; }
+STC_INLINE bool _cx_MEMB(_empty)(const _cx_Self* cx) { return cx->size == 0; }
+STC_INLINE intptr_t _cx_MEMB(_size)(const _cx_Self* cx) { return cx->size; }
+STC_INLINE intptr_t _cx_MEMB(_capacity)(const _cx_Self* cx) { return cx->cap; }
+STC_INLINE _cx_iter _cx_MEMB(_find)(const _cx_Self* self, _cx_keyraw rkey)
+ { _cx_iter it; _cx_MEMB(_find_it)(self, rkey, &it); return it; }
+STC_INLINE bool _cx_MEMB(_contains)(const _cx_Self* self, _cx_keyraw rkey)
+ { _cx_iter it; return _cx_MEMB(_find_it)(self, rkey, &it) != NULL; }
+STC_INLINE const _cx_value* _cx_MEMB(_get)(const _cx_Self* self, _cx_keyraw rkey)
+ { _cx_iter it; return _cx_MEMB(_find_it)(self, rkey, &it); }
+STC_INLINE _cx_value* _cx_MEMB(_get_mut)(_cx_Self* self, _cx_keyraw rkey)
+ { _cx_iter it; return _cx_MEMB(_find_it)(self, rkey, &it); }
+
+STC_INLINE _cx_Self
+_cx_MEMB(_with_capacity)(const intptr_t cap) {
+ _cx_Self tree = _cx_MEMB(_init)();
+ _cx_MEMB(_reserve)(&tree, cap);
return tree;
}
STC_INLINE void
-_cx_memb(_clear)(_cx_self* self)
- { _cx_memb(_drop)(self); *self = _cx_memb(_init)(); }
+_cx_MEMB(_clear)(_cx_Self* self)
+ { _cx_MEMB(_drop)(self); *self = _cx_MEMB(_init)(); }
STC_INLINE _cx_raw
-_cx_memb(_value_toraw)(const _cx_value* val) {
+_cx_MEMB(_value_toraw)(const _cx_value* val) {
return _i_SET_ONLY( i_keyto(val) )
_i_MAP_ONLY( c_LITERAL(_cx_raw){i_keyto((&val->first)),
i_valto((&val->second))} );
}
STC_INLINE void
-_cx_memb(_value_drop)(_cx_value* val) {
+_cx_MEMB(_value_drop)(_cx_value* val) {
i_keydrop(_i_keyref(val));
_i_MAP_ONLY( i_valdrop((&val->second)); )
}
#if !defined i_no_clone
STC_INLINE _cx_value
-_cx_memb(_value_clone)(_cx_value _val) {
+_cx_MEMB(_value_clone)(_cx_value _val) {
*_i_keyref(&_val) = i_keyclone((*_i_keyref(&_val)));
_i_MAP_ONLY( _val.second = i_valclone(_val.second); )
return _val;
}
STC_INLINE void
-_cx_memb(_copy)(_cx_self *self, const _cx_self* other) {
+_cx_MEMB(_copy)(_cx_Self *self, const _cx_Self* other) {
if (self->nodes == other->nodes)
return;
- _cx_memb(_drop)(self);
- *self = _cx_memb(_clone)(*other);
+ _cx_MEMB(_drop)(self);
+ *self = _cx_MEMB(_clone)(*other);
}
STC_INLINE void
-_cx_memb(_shrink_to_fit)(_cx_self *self) {
- _cx_self tmp = _cx_memb(_clone)(*self);
- _cx_memb(_drop)(self); *self = tmp;
+_cx_MEMB(_shrink_to_fit)(_cx_Self *self) {
+ _cx_Self tmp = _cx_MEMB(_clone)(*self);
+ _cx_MEMB(_drop)(self); *self = tmp;
}
#endif // !i_no_clone
-#ifndef _i_isset
- STC_API _cx_result _cx_memb(_insert_or_assign)(_cx_self* self, i_key key, i_val mapped);
+STC_API _cx_result _cx_MEMB(_insert_entry_)(_cx_Self* self, _cx_keyraw rkey);
+
+#ifdef _i_ismap
+ STC_API _cx_result _cx_MEMB(_insert_or_assign)(_cx_Self* self, i_key key, i_val mapped);
#if !defined i_no_emplace
- STC_API _cx_result _cx_memb(_emplace_or_assign)(_cx_self* self, _cx_keyraw rkey, i_valraw rmapped);
+ STC_API _cx_result _cx_MEMB(_emplace_or_assign)(_cx_Self* self, _cx_keyraw rkey, i_valraw rmapped);
+
+ STC_INLINE _cx_result
+ _cx_MEMB(_emplace_key)(_cx_Self* self, _cx_keyraw rkey) {
+ _cx_result res = _cx_MEMB(_insert_entry_)(self, rkey);
+ if (res.inserted)
+ res.ref->first = i_keyfrom(rkey);
+ return res;
+ }
#endif
-
STC_INLINE const _cx_mapped*
- _cx_memb(_at)(const _cx_self* self, _cx_keyraw rkey)
- { _cx_iter it; return &_cx_memb(_find_it)(self, rkey, &it)->second; }
- STC_INLINE _cx_mapped*
- _cx_memb(_at_mut)(_cx_self* self, _cx_keyraw rkey)
- { _cx_iter it; return &_cx_memb(_find_it)(self, rkey, &it)->second; }
-#endif // !_i_isset
+ _cx_MEMB(_at)(const _cx_Self* self, _cx_keyraw rkey)
+ { _cx_iter it; return &_cx_MEMB(_find_it)(self, rkey, &it)->second; }
-STC_INLINE _cx_iter
-_cx_memb(_begin)(const _cx_self* self) {
- _cx_iter it;
- it.ref = NULL;
- it._d = self->nodes, it._top = 0;
- it._tn = self->root;
- if (it._tn)
- _cx_memb(_next)(&it);
- return it;
-}
+ STC_INLINE _cx_mapped*
+ _cx_MEMB(_at_mut)(_cx_Self* self, _cx_keyraw rkey)
+ { _cx_iter it; return &_cx_MEMB(_find_it)(self, rkey, &it)->second; }
+#endif // _i_ismap
STC_INLINE _cx_iter
-_cx_memb(_end)(const _cx_self* self) {
+_cx_MEMB(_end)(const _cx_Self* self) {
(void)self;
_cx_iter it; it.ref = NULL, it._top = 0, it._tn = 0;
return it;
}
STC_INLINE _cx_iter
-_cx_memb(_advance)(_cx_iter it, size_t n) {
+_cx_MEMB(_advance)(_cx_iter it, size_t n) {
while (n-- && it.ref)
- _cx_memb(_next)(&it);
+ _cx_MEMB(_next)(&it);
return it;
}
STC_INLINE bool
-_cx_memb(_eq)(const _cx_self* self, const _cx_self* other) {
- if (_cx_memb(_size)(self) != _cx_memb(_size)(other)) return false;
- _cx_iter i = _cx_memb(_begin)(self), j = _cx_memb(_begin)(other);
- for (; i.ref; _cx_memb(_next)(&i), _cx_memb(_next)(&j)) {
+_cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other) {
+ if (_cx_MEMB(_size)(self) != _cx_MEMB(_size)(other)) return false;
+ _cx_iter i = _cx_MEMB(_begin)(self), j = _cx_MEMB(_begin)(other);
+ for (; i.ref; _cx_MEMB(_next)(&i), _cx_MEMB(_next)(&j)) {
const _cx_keyraw _rx = i_keyto(_i_keyref(i.ref)), _ry = i_keyto(_i_keyref(j.ref));
if (!(i_eq((&_rx), (&_ry)))) return false;
}
return true;
}
-STC_INLINE void _cx_memb(_put_n)(_cx_self* self, const _cx_raw* raw, _i_size n) {
+STC_INLINE _cx_result
+_cx_MEMB(_insert)(_cx_Self* self, i_key _key _i_MAP_ONLY(, i_val _mapped)) {
+ _cx_result _res = _cx_MEMB(_insert_entry_)(self, i_keyto((&_key)));
+ if (_res.inserted)
+ { *_i_keyref(_res.ref) = _key; _i_MAP_ONLY( _res.ref->second = _mapped; )}
+ else
+ { i_keydrop((&_key)); _i_MAP_ONLY( i_valdrop((&_mapped)); )}
+ return _res;
+}
+
+STC_INLINE _cx_value*
+_cx_MEMB(_push)(_cx_Self* self, _cx_value _val) {
+ _cx_result _res = _cx_MEMB(_insert_entry_)(self, i_keyto(_i_keyref(&_val)));
+ if (_res.inserted)
+ *_res.ref = _val;
+ else
+ _cx_MEMB(_value_drop)(&_val);
+ return _res.ref;
+}
+
+STC_INLINE void
+_cx_MEMB(_put_n)(_cx_Self* self, const _cx_raw* raw, intptr_t n) {
while (n--)
#if defined _i_isset && defined i_no_emplace
- _cx_memb(_insert)(self, *raw++);
+ _cx_MEMB(_insert)(self, *raw++);
#elif defined _i_isset
- _cx_memb(_emplace)(self, *raw++);
+ _cx_MEMB(_emplace)(self, *raw++);
#elif defined i_no_emplace
- _cx_memb(_insert_or_assign)(self, raw->first, raw->second), ++raw;
+ _cx_MEMB(_insert_or_assign)(self, raw->first, raw->second), ++raw;
#else
- _cx_memb(_emplace_or_assign)(self, raw->first, raw->second), ++raw;
+ _cx_MEMB(_emplace_or_assign)(self, raw->first, raw->second), ++raw;
#endif
}
-STC_INLINE _cx_self _cx_memb(_from_n)(const _cx_raw* raw, _i_size n)
- { _cx_self cx = {0}; _cx_memb(_put_n)(&cx, raw, n); return cx; }
+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; }
/* -------------------------- IMPLEMENTATION ------------------------- */
-#if defined(i_implement)
+#if defined(i_implement) || defined(i_static)
+
+STC_DEF void
+_cx_MEMB(_next)(_cx_iter *it) {
+ int32_t tn = it->_tn;
+ if (it->_top || tn) {
+ while (tn) {
+ it->_st[it->_top++] = tn;
+ tn = it->_d[tn].link[0];
+ }
+ tn = it->_st[--it->_top];
+ it->_tn = it->_d[tn].link[1];
+ it->ref = &it->_d[tn].value;
+ } else
+ it->ref = NULL;
+}
+
+STC_DEF _cx_iter
+_cx_MEMB(_begin)(const _cx_Self* self) {
+ _cx_iter it;
+ it.ref = NULL;
+ it._d = self->nodes, it._top = 0;
+ it._tn = self->root;
+ if (it._tn)
+ _cx_MEMB(_next)(&it);
+ return it;
+}
STC_DEF bool
-_cx_memb(_reserve)(_cx_self* self, const _i_size cap) {
+_cx_MEMB(_reserve)(_cx_Self* self, const intptr_t cap) {
if (cap <= self->cap)
return false;
_cx_node* nodes = (_cx_node*)i_realloc(self->nodes, (cap + 1)*c_sizeof(_cx_node));
if (!nodes)
return false;
- nodes[0] = c_LITERAL(_cx_node){{0, 0}, 0};
+ nodes[0] = c_LITERAL(_cx_node){0};
self->nodes = nodes;
- self->cap = (i_ssize)cap;
+ self->cap = (int32_t)cap;
return true;
}
STC_DEF _cx_value*
-_cx_memb(_front)(const _cx_self* self) {
+_cx_MEMB(_front)(const _cx_Self* self) {
_cx_node *d = self->nodes;
- i_ssize tn = self->root;
+ int32_t tn = self->root;
while (d[tn].link[0])
tn = d[tn].link[0];
return &d[tn].value;
}
STC_DEF _cx_value*
-_cx_memb(_back)(const _cx_self* self) {
+_cx_MEMB(_back)(const _cx_Self* self) {
_cx_node *d = self->nodes;
- i_ssize tn = self->root;
+ int32_t tn = self->root;
while (d[tn].link[1])
tn = d[tn].link[1];
return &d[tn].value;
}
-static i_ssize
-_cx_memb(_new_node_)(_cx_self* self, int level) {
- i_ssize tn;
+static int32_t
+_cx_MEMB(_new_node_)(_cx_Self* self, int level) {
+ int32_t tn;
if (self->disp) {
tn = self->disp;
self->disp = self->nodes[tn].link[1];
} else {
if (self->head == self->cap)
- if (!_cx_memb(_reserve)(self, self->head*3/2 + 4))
+ if (!_cx_MEMB(_reserve)(self, self->head*3/2 + 4))
return 0;
tn = ++self->head; /* start with 1, 0 is nullnode. */
}
@@ -293,32 +334,10 @@ _cx_memb(_new_node_)(_cx_self* self, int level) {
return tn;
}
-static _cx_result _cx_memb(_insert_entry_)(_cx_self* self, _cx_keyraw rkey);
-
-STC_DEF _cx_result
-_cx_memb(_insert)(_cx_self* self, i_key _key _i_MAP_ONLY(, i_val _mapped)) {
- _cx_result _res = _cx_memb(_insert_entry_)(self, i_keyto((&_key)));
- if (_res.inserted)
- { *_i_keyref(_res.ref) = _key; _i_MAP_ONLY( _res.ref->second = _mapped; )}
- else
- { i_keydrop((&_key)); _i_MAP_ONLY( i_valdrop((&_mapped)); )}
- return _res;
-}
-
-STC_DEF _cx_result
-_cx_memb(_push)(_cx_self* self, _cx_value _val) {
- _cx_result _res = _cx_memb(_insert_entry_)(self, i_keyto(_i_keyref(&_val)));
- if (_res.inserted)
- *_res.ref = _val;
- else
- _cx_memb(_value_drop)(&_val);
- return _res;
-}
-
-#ifndef _i_isset
+#ifdef _i_ismap
STC_DEF _cx_result
- _cx_memb(_insert_or_assign)(_cx_self* self, i_key _key, i_val _mapped) {
- _cx_result _res = _cx_memb(_insert_entry_)(self, i_keyto((&_key)));
+ _cx_MEMB(_insert_or_assign)(_cx_Self* self, i_key _key, i_val _mapped) {
+ _cx_result _res = _cx_MEMB(_insert_entry_)(self, i_keyto((&_key)));
_cx_mapped* _mp = _res.ref ? &_res.ref->second : &_mapped;
if (_res.inserted)
_res.ref->first = _key;
@@ -330,8 +349,8 @@ _cx_memb(_push)(_cx_self* self, _cx_value _val) {
#if !defined i_no_emplace
STC_DEF _cx_result
- _cx_memb(_emplace_or_assign)(_cx_self* self, _cx_keyraw rkey, i_valraw rmapped) {
- _cx_result _res = _cx_memb(_insert_entry_)(self, rkey);
+ _cx_MEMB(_emplace_or_assign)(_cx_Self* self, _cx_keyraw rkey, i_valraw rmapped) {
+ _cx_result _res = _cx_MEMB(_insert_entry_)(self, rkey);
if (_res.inserted)
_res.ref->first = i_keyfrom(rkey);
else {
@@ -342,11 +361,11 @@ _cx_memb(_push)(_cx_self* self, _cx_value _val) {
return _res;
}
#endif // !i_no_emplace
-#endif // !_i_isset
+#endif // !_i_ismap
STC_DEF _cx_value*
-_cx_memb(_find_it)(const _cx_self* self, _cx_keyraw rkey, _cx_iter* out) {
- i_ssize tn = self->root;
+_cx_MEMB(_find_it)(const _cx_Self* self, _cx_keyraw rkey, _cx_iter* out) {
+ int32_t tn = self->root;
_cx_node *d = out->_d = self->nodes;
out->_top = 0;
while (tn) {
@@ -362,36 +381,21 @@ _cx_memb(_find_it)(const _cx_self* self, _cx_keyraw rkey, _cx_iter* out) {
}
STC_DEF _cx_iter
-_cx_memb(_lower_bound)(const _cx_self* self, _cx_keyraw rkey) {
+_cx_MEMB(_lower_bound)(const _cx_Self* self, _cx_keyraw rkey) {
_cx_iter it;
- _cx_memb(_find_it)(self, rkey, &it);
+ _cx_MEMB(_find_it)(self, rkey, &it);
if (!it.ref && it._top) {
- i_ssize tn = it._st[--it._top];
+ int32_t tn = it._st[--it._top];
it._tn = it._d[tn].link[1];
it.ref = &it._d[tn].value;
}
return it;
}
-STC_DEF void
-_cx_memb(_next)(_cx_iter *it) {
- i_ssize tn = it->_tn;
- if (it->_top || tn) {
- while (tn) {
- it->_st[it->_top++] = tn;
- tn = it->_d[tn].link[0];
- }
- tn = it->_st[--it->_top];
- it->_tn = it->_d[tn].link[1];
- it->ref = &it->_d[tn].value;
- } else
- it->ref = NULL;
-}
-
-STC_DEF i_ssize
-_cx_memb(_skew_)(_cx_node *d, i_ssize tn) {
+STC_DEF int32_t
+_cx_MEMB(_skew_)(_cx_node *d, int32_t tn) {
if (tn && d[d[tn].link[0]].level == d[tn].level) {
- i_ssize tmp = d[tn].link[0];
+ int32_t tmp = d[tn].link[0];
d[tn].link[0] = d[tmp].link[1];
d[tmp].link[1] = tn;
tn = tmp;
@@ -399,10 +403,10 @@ _cx_memb(_skew_)(_cx_node *d, i_ssize tn) {
return tn;
}
-STC_DEF i_ssize
-_cx_memb(_split_)(_cx_node *d, i_ssize tn) {
+STC_DEF int32_t
+_cx_MEMB(_split_)(_cx_node *d, int32_t tn) {
if (d[d[d[tn].link[1]].link[1]].level == d[tn].level) {
- i_ssize tmp = d[tn].link[1];
+ int32_t tmp = d[tn].link[1];
d[tn].link[1] = d[tmp].link[0];
d[tmp].link[0] = tn;
tn = tmp;
@@ -411,9 +415,9 @@ _cx_memb(_split_)(_cx_node *d, i_ssize tn) {
return tn;
}
-static i_ssize
-_cx_memb(_insert_entry_i_)(_cx_self* self, i_ssize tn, const _cx_keyraw* rkey, _cx_result* _res) {
- i_ssize up[64], tx = tn;
+STC_DEF int32_t
+_cx_MEMB(_insert_entry_i_)(_cx_Self* self, int32_t tn, const _cx_keyraw* rkey, _cx_result* _res) {
+ int32_t up[64], tx = tn;
_cx_node* d = self->nodes;
int c, top = 0, dir = 0;
while (tx) {
@@ -424,7 +428,7 @@ _cx_memb(_insert_entry_i_)(_cx_self* self, i_ssize tn, const _cx_keyraw* rkey, _
dir = (c < 0);
tx = d[tx].link[dir];
}
- if ((tx = _cx_memb(_new_node_)(self, 1)) == 0)
+ if ((tx = _cx_MEMB(_new_node_)(self, 1)) == 0)
return 0;
d = self->nodes;
_res->ref = &d[tx].value;
@@ -435,42 +439,42 @@ _cx_memb(_insert_entry_i_)(_cx_self* self, i_ssize tn, const _cx_keyraw* rkey, _
while (top--) {
if (top)
dir = (d[up[top - 1]].link[1] == up[top]);
- up[top] = _cx_memb(_skew_)(d, up[top]);
- up[top] = _cx_memb(_split_)(d, up[top]);
+ up[top] = _cx_MEMB(_skew_)(d, up[top]);
+ up[top] = _cx_MEMB(_split_)(d, up[top]);
if (top)
d[up[top - 1]].link[dir] = up[top];
}
return up[0];
}
-static _cx_result
-_cx_memb(_insert_entry_)(_cx_self* self, _cx_keyraw rkey) {
+STC_DEF _cx_result
+_cx_MEMB(_insert_entry_)(_cx_Self* self, _cx_keyraw rkey) {
_cx_result res = {NULL};
- i_ssize tn = _cx_memb(_insert_entry_i_)(self, self->root, &rkey, &res);
+ int32_t tn = _cx_MEMB(_insert_entry_i_)(self, self->root, &rkey, &res);
self->root = tn;
self->size += res.inserted;
return res;
}
-static i_ssize
-_cx_memb(_erase_r_)(_cx_self *self, i_ssize tn, const _cx_keyraw* rkey, int *erased) {
+STC_DEF int32_t
+_cx_MEMB(_erase_r_)(_cx_Self *self, int32_t tn, const _cx_keyraw* rkey, int *erased) {
_cx_node *d = self->nodes;
if (tn == 0)
return 0;
_cx_keyraw raw = i_keyto(_i_keyref(&d[tn].value));
- i_ssize tx; int c = i_cmp((&raw), rkey);
+ int32_t tx; int c = i_cmp((&raw), rkey);
if (c != 0)
- d[tn].link[c < 0] = _cx_memb(_erase_r_)(self, d[tn].link[c < 0], rkey, erased);
+ d[tn].link[c < 0] = _cx_MEMB(_erase_r_)(self, d[tn].link[c < 0], rkey, erased);
else {
if (!(*erased)++)
- _cx_memb(_value_drop)(&d[tn].value);
+ _cx_MEMB(_value_drop)(&d[tn].value);
if (d[tn].link[0] && d[tn].link[1]) {
tx = d[tn].link[0];
while (d[tx].link[1])
tx = d[tx].link[1];
d[tn].value = d[tx].value; /* move */
raw = i_keyto(_i_keyref(&d[tn].value));
- d[tn].link[0] = _cx_memb(_erase_r_)(self, d[tn].link[0], &raw, erased);
+ d[tn].link[0] = _cx_MEMB(_erase_r_)(self, d[tn].link[0], &raw, erased);
} else { /* unlink node */
tx = tn;
tn = d[tn].link[ d[tn].link[0] == 0 ];
@@ -483,19 +487,19 @@ _cx_memb(_erase_r_)(_cx_self *self, i_ssize tn, const _cx_keyraw* rkey, int *era
if (d[d[tn].link[0]].level < d[tn].level - 1 || d[tx].level < d[tn].level - 1) {
if (d[tx].level > --d[tn].level)
d[tx].level = d[tn].level;
- tn = _cx_memb(_skew_)(d, tn);
- tx = d[tn].link[1] = _cx_memb(_skew_)(d, d[tn].link[1]);
- d[tx].link[1] = _cx_memb(_skew_)(d, d[tx].link[1]);
- tn = _cx_memb(_split_)(d, tn);
- d[tn].link[1] = _cx_memb(_split_)(d, d[tn].link[1]);
+ tn = _cx_MEMB(_skew_)(d, tn);
+ tx = d[tn].link[1] = _cx_MEMB(_skew_)(d, d[tn].link[1]);
+ d[tx].link[1] = _cx_MEMB(_skew_)(d, d[tx].link[1]);
+ tn = _cx_MEMB(_split_)(d, tn);
+ d[tn].link[1] = _cx_MEMB(_split_)(d, d[tn].link[1]);
}
return tn;
}
STC_DEF int
-_cx_memb(_erase)(_cx_self* self, _cx_keyraw rkey) {
+_cx_MEMB(_erase)(_cx_Self* self, _cx_keyraw rkey) {
int erased = 0;
- i_ssize root = _cx_memb(_erase_r_)(self, self->root, &rkey, &erased);
+ int32_t root = _cx_MEMB(_erase_r_)(self, self->root, &rkey, &erased);
if (!erased)
return 0;
self->root = root;
@@ -504,23 +508,23 @@ _cx_memb(_erase)(_cx_self* self, _cx_keyraw rkey) {
}
STC_DEF _cx_iter
-_cx_memb(_erase_at)(_cx_self* self, _cx_iter it) {
+_cx_MEMB(_erase_at)(_cx_Self* self, _cx_iter it) {
_cx_keyraw raw = i_keyto(_i_keyref(it.ref));
- _cx_memb(_next)(&it);
+ _cx_MEMB(_next)(&it);
if (it.ref) {
_cx_keyraw nxt = i_keyto(_i_keyref(it.ref));
- _cx_memb(_erase)(self, raw);
- _cx_memb(_find_it)(self, nxt, &it);
+ _cx_MEMB(_erase)(self, raw);
+ _cx_MEMB(_find_it)(self, nxt, &it);
} else
- _cx_memb(_erase)(self, raw);
+ _cx_MEMB(_erase)(self, raw);
return it;
}
STC_DEF _cx_iter
-_cx_memb(_erase_range)(_cx_self* self, _cx_iter it1, _cx_iter it2) {
+_cx_MEMB(_erase_range)(_cx_Self* self, _cx_iter it1, _cx_iter it2) {
if (!it2.ref) {
while (it1.ref)
- it1 = _cx_memb(_erase_at)(self, it1);
+ it1 = _cx_MEMB(_erase_at)(self, it1);
return it1;
}
_cx_key k1 = *_i_keyref(it1.ref), k2 = *_i_keyref(it2.ref);
@@ -528,30 +532,30 @@ _cx_memb(_erase_range)(_cx_self* self, _cx_iter it1, _cx_iter it2) {
for (;;) {
if (memcmp(&k1, &k2, sizeof k1) == 0)
return it1;
- _cx_memb(_next)(&it1);
+ _cx_MEMB(_next)(&it1);
k1 = *_i_keyref(it1.ref);
- _cx_memb(_erase)(self, r1);
+ _cx_MEMB(_erase)(self, r1);
r1 = i_keyto((&k1));
- _cx_memb(_find_it)(self, r1, &it1);
+ _cx_MEMB(_find_it)(self, r1, &it1);
}
}
#if !defined i_no_clone
-static i_ssize
-_cx_memb(_clone_r_)(_cx_self* self, _cx_node* src, i_ssize sn) {
+STC_DEF int32_t
+_cx_MEMB(_clone_r_)(_cx_Self* self, _cx_node* src, int32_t sn) {
if (sn == 0)
return 0;
- i_ssize tx, tn = _cx_memb(_new_node_)(self, src[sn].level);
- self->nodes[tn].value = _cx_memb(_value_clone)(src[sn].value);
- tx = _cx_memb(_clone_r_)(self, src, src[sn].link[0]); self->nodes[tn].link[0] = tx;
- tx = _cx_memb(_clone_r_)(self, src, src[sn].link[1]); self->nodes[tn].link[1] = tx;
+ int32_t tx, tn = _cx_MEMB(_new_node_)(self, src[sn].level);
+ self->nodes[tn].value = _cx_MEMB(_value_clone)(src[sn].value);
+ tx = _cx_MEMB(_clone_r_)(self, src, src[sn].link[0]); self->nodes[tn].link[0] = tx;
+ tx = _cx_MEMB(_clone_r_)(self, src, src[sn].link[1]); self->nodes[tn].link[1] = tx;
return tn;
}
-STC_DEF _cx_self
-_cx_memb(_clone)(_cx_self tree) {
- _cx_self clone = _cx_memb(_with_capacity)(tree.size);
- i_ssize root = _cx_memb(_clone_r_)(&clone, tree.nodes, tree.root);
+STC_DEF _cx_Self
+_cx_MEMB(_clone)(_cx_Self tree) {
+ _cx_Self clone = _cx_MEMB(_with_capacity)(tree.size);
+ int32_t root = _cx_MEMB(_clone_r_)(&clone, tree.nodes, tree.root);
clone.root = root;
clone.size = tree.size;
return clone;
@@ -560,8 +564,8 @@ _cx_memb(_clone)(_cx_self tree) {
#if !defined i_no_emplace
STC_DEF _cx_result
-_cx_memb(_emplace)(_cx_self* self, _cx_keyraw rkey _i_MAP_ONLY(, i_valraw rmapped)) {
- _cx_result res = _cx_memb(_insert_entry_)(self, rkey);
+_cx_MEMB(_emplace)(_cx_Self* self, _cx_keyraw rkey _i_MAP_ONLY(, i_valraw rmapped)) {
+ _cx_result res = _cx_MEMB(_insert_entry_)(self, rkey);
if (res.inserted) {
*_i_keyref(res.ref) = i_keyfrom(rkey);
_i_MAP_ONLY(res.ref->second = i_valfrom(rmapped);)
@@ -571,24 +575,23 @@ _cx_memb(_emplace)(_cx_self* self, _cx_keyraw rkey _i_MAP_ONLY(, i_valraw rmappe
#endif // i_no_emplace
static void
-_cx_memb(_drop_r_)(_cx_node* d, i_ssize tn) {
+_cx_MEMB(_drop_r_)(_cx_node* d, int32_t tn) {
if (tn) {
- _cx_memb(_drop_r_)(d, d[tn].link[0]);
- _cx_memb(_drop_r_)(d, d[tn].link[1]);
- _cx_memb(_value_drop)(&d[tn].value);
+ _cx_MEMB(_drop_r_)(d, d[tn].link[0]);
+ _cx_MEMB(_drop_r_)(d, d[tn].link[1]);
+ _cx_MEMB(_value_drop)(&d[tn].value);
}
}
STC_DEF void
-_cx_memb(_drop)(_cx_self* self) {
+_cx_MEMB(_drop)(_cx_Self* self) {
if (self->cap) {
- _cx_memb(_drop_r_)(self->nodes, self->root);
+ _cx_MEMB(_drop_r_)(self->nodes, self->root);
i_free(self->nodes);
}
}
#endif // i_implement
-#undef _i_size
#undef _i_isset
#undef _i_ismap
#undef _i_keyref
diff --git a/include/stc/cspan.h b/include/stc/cspan.h
index ac3e9206..0875ed92 100644
--- a/include/stc/cspan.h
+++ b/include/stc/cspan.h
@@ -24,9 +24,9 @@
/*
#include <stdio.h>
#include <stc/cspan.h>
-#include <stc/algo/filter.h>
+#include <stc/algorithm.h>
using_cspan(Span2f, float, 2);
-using_cspan(Intspan, int, 1);
+using_cspan(Intspan, int);
int demo1() {
float raw[4*5];
@@ -60,209 +60,231 @@ int demo2() {
#ifndef STC_CSPAN_H_INCLUDED
#define STC_CSPAN_H_INCLUDED
+#include "priv/linkage.h"
#include "ccommon.h"
#define using_cspan(...) c_MACRO_OVERLOAD(using_cspan, __VA_ARGS__)
#define using_cspan_2(Self, T) \
- using_cspan_3(Self, T, 1)
+ using_cspan_3(Self, T, 1); \
+ STC_INLINE Self Self##_from_n(Self##_raw* raw, const intptr_t n) { \
+ return (Self){.data=raw, .shape={(int32_t)n}, .stride={.d={1}}}; \
+ } \
+ struct stc_nostruct
#define using_cspan_3(Self, T, RANK) \
typedef T Self##_value; typedef T Self##_raw; \
typedef struct { \
Self##_value *data; \
int32_t shape[RANK]; \
- cspan_idx##RANK stride; \
+ cspan_tuple##RANK stride; \
} Self; \
\
typedef struct { Self##_value *ref; int32_t pos[RANK]; const Self *_s; } Self##_iter; \
\
- 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[], \
- const int rank, const int32_t a[][2]) { \
- Self s = {.data=v}; int outrank; \
- s.data += _cspan_slice(s.shape, s.stride.d, &outrank, shape, stri, rank, a); \
- c_ASSERT(outrank == RANK); \
+ STC_INLINE Self Self##_slice_(Self##_value* d, const int32_t shape[], const intptr_t stri[], \
+ const int rank, const int32_t a[][3]) { \
+ 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) { \
- it->ref += _cspan_next##RANK(RANK, it->pos, it->_s->shape, it->_s->stride.d); \
- if (it->pos[0] == it->_s->shape[0]) it->ref = NULL; \
+ int done; \
+ it->ref += _cspan_next##RANK(it->pos, it->_s->shape, it->_s->stride.d, RANK, &done); \
+ if (done) it->ref = NULL; \
} \
struct stc_nostruct
-#define using_cspan2(Self, T) using_cspan_3(Self, T, 1); using_cspan_3(Self##2, T, 2)
+#define using_cspan2(Self, T) using_cspan_2(Self, T); using_cspan_3(Self##2, T, 2)
#define using_cspan3(Self, T) using_cspan2(Self, T); using_cspan_3(Self##3, T, 3)
#define using_cspan4(Self, T) using_cspan3(Self, T); using_cspan_3(Self##4, T, 4)
-typedef struct { int32_t d[1]; } cspan_idx1;
-typedef struct { int32_t d[2]; } cspan_idx2;
-typedef struct { int32_t d[3]; } cspan_idx3;
-typedef struct { int32_t d[4]; } cspan_idx4;
-typedef struct { int32_t d[5]; } cspan_idx5;
-typedef struct { int32_t d[6]; } cspan_idx6;
-#define c_END -1
-#define c_ALL 0,-1
+#define using_cspan_tuple(N) typedef struct { intptr_t d[N]; } cspan_tuple##N
+using_cspan_tuple(1); using_cspan_tuple(2);
+using_cspan_tuple(3); using_cspan_tuple(4);
+using_cspan_tuple(5); using_cspan_tuple(6);
+using_cspan_tuple(7); using_cspan_tuple(8);
-#define cspan_md(array, ...) \
- {.data=array, .shape={__VA_ARGS__}, .stride={.d={__VA_ARGS__}}}
+#define c_END -1
+#define c_ALL 0,c_END
+typedef enum {c_ROWMAJOR, c_COLMAJOR} cspan_layout;
-/* For static initialization, use cspan_make(). c_make() for non-static only. */
-#define cspan_make(SpanType, ...) \
- {.data=(SpanType##_value[])__VA_ARGS__, .shape={sizeof((SpanType##_value[])__VA_ARGS__)/sizeof(SpanType##_value)}}
+/* Use cspan_init() for static initialization only. c_init() for non-static init. */
+#define cspan_init(SpanType, ...) \
+ {.data=(SpanType##_value[])__VA_ARGS__, .shape={sizeof((SpanType##_value[])__VA_ARGS__)/sizeof(SpanType##_value)}, .stride={.d={1}}}
-#define cspan_slice(OutSpan, parent, ...) \
- OutSpan##_slice_((parent)->data, (parent)->shape, (parent)->stride.d, cspan_rank(parent) + \
- c_static_assert(cspan_rank(parent) == sizeof((int32_t[][2]){__VA_ARGS__})/sizeof(int32_t[2])), \
- (const int32_t[][2]){__VA_ARGS__})
-
-/* 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}}
+ {.data=(container)->data, .shape={(int32_t)(container)->_len}, .stride={.d={1}}}
+
+#define cspan_from_n(ptr, n) \
+ {.data=(ptr), .shape={n}, .stride={.d={1}}}
#define cspan_from_array(array) \
- {.data=(array) + c_static_assert(sizeof(array) != sizeof(void*)), .shape={c_arraylen(array)}}
+ cspan_from_n(array, c_arraylen(array))
#define cspan_size(self) _cspan_size((self)->shape, cspan_rank(self))
#define cspan_rank(self) c_arraylen((self)->shape)
-
-#define cspan_index(self, ...) c_PASTE(cspan_idx_, c_NUMARGS(__VA_ARGS__))(self, __VA_ARGS__)
-#define cspan_idx_1 cspan_idx_4
-#define cspan_idx_2 cspan_idx_4
-#define cspan_idx_3 cspan_idx_4
-#define cspan_idx_4(self, ...) \
- c_PASTE(_cspan_idx, c_NUMARGS(__VA_ARGS__))((self)->shape, (self)->stride, __VA_ARGS__) // small/fast
-#define cspan_idx_5(self, ...) \
- (_cspan_idxN(c_NUMARGS(__VA_ARGS__), (self)->shape, (self)->stride.d, (int32_t[]){__VA_ARGS__}) + \
- c_static_assert(cspan_rank(self) == c_NUMARGS(__VA_ARGS__))) // general
-#define cspan_idx_6 cspan_idx_5
-
+#define cspan_is_colmajor(self) ((self)->stride.d[0] < (self)->stride.d[cspan_rank(self) - 1])
+#define cspan_is_rowmajor(self) (!cspan_is_colmajor(self))
+#define cspan_get_layout(self) (cspan_is_colmajor(self) ? c_COLMAJOR : c_ROWMAJOR)
#define cspan_at(self, ...) ((self)->data + cspan_index(self, __VA_ARGS__))
#define cspan_front(self) ((self)->data)
#define cspan_back(self) ((self)->data + cspan_size(self) - 1)
+#define cspan_index(self, ...) \
+ (_cspan_index(c_NUMARGS(__VA_ARGS__), (self)->shape, (self)->stride.d, (const int32_t[]){__VA_ARGS__}) + \
+ c_static_assert(cspan_rank(self) == c_NUMARGS(__VA_ARGS__))) // general
-// cspan_subspanN. (N<4) Optimized, same as e.g. cspan_slice(Span3, &ms3, {off,off+count}, {c_ALL}, {c_ALL});
+// cspan_subspanX: (X <= 3) optimized. Similar to cspan_slice(Span3, &ms3, {off,off+count}, {c_ALL}, {c_ALL});
#define cspan_subspan(self, offset, count) \
- {.data=cspan_at(self, offset), .shape={count}}
+ {.data=cspan_at(self, offset), .shape={count}, .stride=(self)->stride}
#define cspan_subspan2(self, offset, count) \
- {.data=cspan_at(self, offset, 0), .shape={count, (self)->shape[1]}, .stride={(self)->stride}}
+ {.data=cspan_at(self, offset, 0), .shape={count, (self)->shape[1]}, .stride=(self)->stride}
#define cspan_subspan3(self, offset, count) \
- {.data=cspan_at(self, offset, 0, 0), .shape={count, (self)->shape[1], (self)->shape[2]}, .stride={(self)->stride}}
+ {.data=cspan_at(self, offset, 0, 0), .shape={count, (self)->shape[1], (self)->shape[2]}, .stride=(self)->stride}
-// cspan_submdN: reduce rank (N<5) Optimized, same as e.g. cspan_slice(Span2, &ms4, {x}, {y}, {c_ALL}, {c_ALL});
-#define cspan_submd4(...) c_MACRO_OVERLOAD(cspan_submd4, __VA_ARGS__)
-#define cspan_submd3(...) c_MACRO_OVERLOAD(cspan_submd3, __VA_ARGS__)
+// cspan_submd(): Reduce rank (N <= 4) Optimized, same as e.g. cspan_slice(Span2, &ms4, {x}, {y}, {c_ALL}, {c_ALL});
#define cspan_submd2(self, x) \
- {.data=cspan_at(self, x, 0), .shape={(self)->shape[1]}}
+ {.data=cspan_at(self, x, 0), .shape={(self)->shape[1]}, .stride=(cspan_tuple1){.d={(self)->stride.d[1]}}}
+#define cspan_submd3(...) c_MACRO_OVERLOAD(cspan_submd3, __VA_ARGS__)
#define cspan_submd3_2(self, x) \
{.data=cspan_at(self, x, 0, 0), .shape={(self)->shape[1], (self)->shape[2]}, \
- .stride={.d={0, (self)->stride.d[2]}}}
+ .stride=(cspan_tuple2){.d={(self)->stride.d[1], (self)->stride.d[2]}}}
#define cspan_submd3_3(self, x, y) \
- {.data=cspan_at(self, x, y, 0), .shape={(self)->shape[2]}}
+ {.data=cspan_at(self, x, y, 0), .shape={(self)->shape[2]}, .stride=(cspan_tuple1){.d={(self)->stride.d[2]}}}
+#define cspan_submd4(...) c_MACRO_OVERLOAD(cspan_submd4, __VA_ARGS__)
#define cspan_submd4_2(self, x) \
{.data=cspan_at(self, x, 0, 0, 0), .shape={(self)->shape[1], (self)->shape[2], (self)->shape[3]}, \
- .stride={.d={0, (self)->stride.d[2], (self)->stride.d[3]}}}
+ .stride=(cspan_tuple3){.d={(self)->stride.d[1], (self)->stride.d[2], (self)->stride.d[3]}}}
#define cspan_submd4_3(self, x, y) \
- {.data=cspan_at(self, x, y, 0, 0), .shape={(self)->shape[2], (self)->shape[3]}, .stride={.d={0, (self)->stride.d[3]}}}
+ {.data=cspan_at(self, x, y, 0, 0), .shape={(self)->shape[2], (self)->shape[3]}, \
+ .stride=(cspan_tuple2){.d={(self)->stride.d[2], (self)->stride.d[3]}}}
#define cspan_submd4_4(self, x, y, z) \
- {.data=cspan_at(self, x, y, z, 0), .shape={(self)->shape[3]}}
+ {.data=cspan_at(self, x, y, z, 0), .shape={(self)->shape[3]}, .stride=(cspan_tuple1){.d={(self)->stride.d[3]}}}
+
+#define cspan_md(array, ...) cspan_md_layout(c_ROWMAJOR, array, __VA_ARGS__)
+#define cspan_md_layout(layout, array, ...) \
+ {.data=array, .shape={__VA_ARGS__}, \
+ .stride=*(c_PASTE(cspan_tuple,c_NUMARGS(__VA_ARGS__))*)_cspan_shape2stride(layout, ((intptr_t[]){__VA_ARGS__}), c_NUMARGS(__VA_ARGS__))}
-// private definitions:
+#define cspan_transpose(self) \
+ _cspan_transpose((self)->shape, (self)->stride.d, cspan_rank(self))
+
+// General slicing function;
+#define cspan_slice(OutSpan, parent, ...) \
+ OutSpan##_slice_((parent)->data, (parent)->shape, (parent)->stride.d, cspan_rank(parent) + \
+ c_static_assert(cspan_rank(parent) == sizeof((int32_t[][3]){__VA_ARGS__})/sizeof(int32_t[3])), \
+ (const int32_t[][3]){__VA_ARGS__})
+
+/* ------------------- PRIVAT DEFINITIONS ------------------- */
STC_INLINE intptr_t _cspan_size(const int32_t shape[], int rank) {
intptr_t sz = shape[0];
- while (rank-- > 1) sz *= shape[rank];
+ while (--rank) sz *= shape[rank];
return sz;
}
-STC_INLINE intptr_t _cspan_idx1(const int32_t shape[1], const cspan_idx1 stri, int32_t x)
- { c_ASSERT(c_LTu(x, shape[0])); return x; }
-
-STC_INLINE intptr_t _cspan_idx2(const int32_t shape[2], const cspan_idx2 stri, int32_t x, int32_t y)
- { c_ASSERT(c_LTu(x, shape[0]) && c_LTu(y, shape[1])); return (intptr_t)stri.d[1]*x + y; }
-
-STC_INLINE intptr_t _cspan_idx3(const int32_t shape[3], const cspan_idx3 stri, int32_t x, int32_t y, int32_t z) {
- c_ASSERT(c_LTu(x, shape[0]) && c_LTu(y, shape[1]) && c_LTu(z, shape[2]));
- return (intptr_t)stri.d[2]*(stri.d[1]*x + y) + z;
+STC_INLINE void _cspan_transpose(int32_t shape[], intptr_t stride[], int rank) {
+ for (int i = 0; i < --rank; ++i) {
+ c_swap(int32_t, shape + i, shape + rank);
+ c_swap(intptr_t, stride + i, stride + rank);
+ }
}
-STC_INLINE intptr_t _cspan_idx4(const int32_t shape[4], const cspan_idx4 stri, int32_t x, int32_t y,
- int32_t z, int32_t w) {
- c_ASSERT(c_LTu(x, shape[0]) && c_LTu(y, shape[1]) && c_LTu(z, shape[2]) && c_LTu(w, shape[3]));
- return (intptr_t)stri.d[3]*(stri.d[2]*(stri.d[1]*x + y) + z) + w;
+
+STC_INLINE intptr_t _cspan_index(int rank, const int32_t shape[], const intptr_t stride[], const int32_t a[]) {
+ intptr_t off = 0;
+ while (rank--) {
+ c_assert(c_less_unsigned(a[rank], shape[rank]));
+ off += stride[rank]*a[rank];
+ }
+ return off;
}
-STC_API intptr_t _cspan_idxN(int rank, const int32_t shape[], const int32_t stri[], const int32_t a[]);
-STC_API intptr_t _cspan_next2(int rank, int32_t pos[], const int32_t shape[], const int32_t stride[]);
-#define _cspan_next1(r, pos, d, s) (++pos[0], 1)
+#define _cspan_next1(pos, shape, stride, rank, done) (*done = ++pos[0]==shape[0], stride[0])
+STC_API intptr_t
+ _cspan_next2(int32_t pos[], const int32_t shape[], const intptr_t stride[], int rank, int* done);
#define _cspan_next3 _cspan_next2
#define _cspan_next4 _cspan_next2
#define _cspan_next5 _cspan_next2
#define _cspan_next6 _cspan_next2
+#define _cspan_next7 _cspan_next2
+#define _cspan_next8 _cspan_next2
+
+STC_API intptr_t _cspan_slice(int32_t oshape[], intptr_t ostride[], int* orank,
+ const int32_t shape[], const intptr_t stride[],
+ int rank, const int32_t a[][3]);
+
+STC_API intptr_t* _cspan_shape2stride(cspan_layout layout, intptr_t shape[], int rank);
+#endif // STC_CSPAN_H_INCLUDED
-STC_API intptr_t _cspan_slice(int32_t odim[], int32_t ostri[], int* orank,
- const int32_t shape[], const int32_t stri[],
- int rank, const int32_t a[][2]);
+/* --------------------- IMPLEMENTATION --------------------- */
+#if defined(i_implement) || defined(i_static)
-/* -------------------------- IMPLEMENTATION ------------------------- */
-#if defined(i_implement)
+STC_DEF intptr_t _cspan_next2(int32_t pos[], const int32_t shape[], const intptr_t stride[], int r, int* done) {
+ intptr_t off = stride[--r];
+ ++pos[r];
-STC_DEF intptr_t _cspan_idxN(int rank, const int32_t shape[], const int32_t stri[], const int32_t a[]) {
- intptr_t off = a[0];
- c_ASSERT(c_LTu(a[0], shape[0]));
- for (int i = 1; i < rank; ++i) {
- off *= stri[i];
- off += a[i];
- c_ASSERT(c_LTu(a[i], shape[i]));
+ for (; r && pos[r] == shape[r]; --r) {
+ pos[r] = 0; ++pos[r - 1];
+ off += stride[r - 1] - stride[r]*shape[r];
}
+ *done = pos[r] == shape[r];
return off;
}
-STC_DEF intptr_t _cspan_next2(int rank, int32_t pos[], const int32_t shape[], const int32_t stride[]) {
- intptr_t off = 1, rs = 1;
- ++pos[rank - 1];
- while (--rank && pos[rank] == shape[rank]) {
- pos[rank] = 0, ++pos[rank - 1];
- const intptr_t ds = rs*shape[rank];
- rs *= stride[rank];
- off += rs - ds;
+STC_DEF intptr_t* _cspan_shape2stride(cspan_layout layout, intptr_t stride[], int rank) {
+ int i, inc;
+ if (layout == c_COLMAJOR) i = 0, inc = 1;
+ else i = rank - 1, inc = -1;
+ intptr_t k = 1, s1 = stride[i], s2;
+
+ stride[i] = 1;
+ while (--rank) {
+ i += inc;
+ s2 = stride[i];
+ stride[i] = (k *= s1);
+ s1 = s2;
}
- return off;
+ return stride;
}
-STC_DEF intptr_t _cspan_slice(int32_t odim[], int32_t ostri[], int* orank,
- const int32_t shape[], const int32_t stri[],
- int rank, const int32_t a[][2]) {
+STC_DEF intptr_t _cspan_slice(int32_t oshape[], intptr_t ostride[], int* orank,
+ const int32_t shape[], const intptr_t stride[],
+ int rank, const int32_t a[][3]) {
intptr_t off = 0;
- int i = 0, j = 0;
- int32_t t, s = 1;
+ int i = 0, oi = 0;
+ int32_t end;
+
for (; i < rank; ++i) {
- off *= stri[i];
- off += a[i][0];
- switch (a[i][1]) {
- case 0: s *= stri[i]; c_ASSERT(c_LTu(a[i][0], shape[i])); continue;
- case -1: t = shape[i]; break;
- default: t = a[i][1]; break;
+ off += stride[i]*a[i][0];
+ switch (a[i][1]) {
+ case 0: c_assert(c_less_unsigned(a[i][0], shape[i])); continue;
+ case -1: end = shape[i]; break;
+ default: end = a[i][1];
+ }
+ oshape[oi] = end - a[i][0];
+ ostride[oi] = stride[i];
+ c_assert((oshape[oi] > 0) & !c_less_unsigned(shape[i], end));
+ if (a[i][2]) {
+ ostride[oi] *= a[i][2];
+ oshape[oi] = (oshape[oi] - 1)/a[i][2] + 1;
}
- odim[j] = t - a[i][0];
- ostri[j] = s*stri[i];
- c_ASSERT(c_LTu(0, odim[j]) & !c_LTu(shape[i], t));
- s = 1; ++j;
+ ++oi;
}
- *orank = j;
+ *orank = oi;
return off;
}
-#endif
+
#endif
#undef i_opt
#undef i_header
#undef i_implement
#undef i_static
-#undef i_extern
+#undef i_import
diff --git a/include/stc/csset.h b/include/stc/csset.h
index c14d2a6a..29810c7c 100644
--- a/include/stc/csset.h
+++ b/include/stc/csset.h
@@ -42,8 +42,5 @@ int main(void) {
}
*/
-#ifndef _i_prefix
#define _i_prefix csset_
-#endif
-#define _i_isset
#include "csmap.h"
diff --git a/include/stc/cstack.h b/include/stc/cstack.h
index c2792358..8fb176e1 100644
--- a/include/stc/cstack.h
+++ b/include/stc/cstack.h
@@ -20,85 +20,79 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
-#include "ccommon.h"
+#include "priv/linkage.h"
#ifndef CSTACK_H_INCLUDED
#define CSTACK_H_INCLUDED
+#include "ccommon.h"
#include <stdlib.h>
#include "forward.h"
#endif // CSTACK_H_INCLUDED
-#ifndef _i_prefix
#define _i_prefix cstack_
-#endif
#include "priv/template.h"
#ifndef i_is_forward
#ifdef i_capacity
#define i_no_clone
- _cx_deftypes(_c_cstack_fixed, _cx_self, i_key, i_capacity);
+ _cx_DEFTYPES(_c_cstack_fixed, _cx_Self, i_key, i_capacity);
#else
- _cx_deftypes(_c_cstack_types, _cx_self, i_key);
+ _cx_DEFTYPES(_c_cstack_types, _cx_Self, i_key);
#endif
#endif
typedef i_keyraw _cx_raw;
-STC_INLINE _cx_self _cx_memb(_init)(void) {
- _cx_self cx; cx._len = 0;
-#ifndef i_capacity
- cx._cap = 0; cx.data = NULL;
-#endif
- return cx;
-}
-
#ifdef i_capacity
-STC_INLINE void _cx_memb(_create)(_cx_self* self)
+STC_INLINE void _cx_MEMB(_init)(_cx_Self* self)
{ self->_len = 0; }
#else
-STC_INLINE void _cx_memb(_create)(_cx_self* self)
- { self->_len = 0; self->_cap = 0; self->data = NULL; }
+STC_INLINE _cx_Self _cx_MEMB(_init)(void) {
+ _cx_Self out = {0};
+ return out;
+}
-STC_INLINE _cx_self _cx_memb(_with_capacity)(intptr_t cap) {
- _cx_self out = {(_cx_value *) i_malloc(cap*c_sizeof(i_key)), 0, cap};
+STC_INLINE _cx_Self _cx_MEMB(_with_capacity)(intptr_t cap) {
+ _cx_Self out = {(_cx_value *) i_malloc(cap*c_sizeof(i_key)), 0, cap};
return out;
}
-STC_INLINE _cx_self _cx_memb(_with_size)(intptr_t size, i_key null) {
- _cx_self out = {(_cx_value *) i_malloc(size*c_sizeof null), size, size};
+STC_INLINE _cx_Self _cx_MEMB(_with_size)(intptr_t size, i_key null) {
+ _cx_Self out = {(_cx_value *) i_malloc(size*c_sizeof null), size, size};
while (size) out.data[--size] = null;
return out;
}
#endif // i_capacity
-STC_INLINE void _cx_memb(_clear)(_cx_self* self) {
+STC_INLINE void _cx_MEMB(_clear)(_cx_Self* self) {
_cx_value *p = self->data + self->_len;
while (p-- != self->data) { i_keydrop(p); }
self->_len = 0;
}
-STC_INLINE void _cx_memb(_drop)(_cx_self* self) {
- _cx_memb(_clear)(self);
+STC_INLINE void _cx_MEMB(_drop)(_cx_Self* self) {
+ _cx_MEMB(_clear)(self);
#ifndef i_capacity
i_free(self->data);
#endif
}
-STC_INLINE intptr_t _cx_memb(_size)(const _cx_self* self)
+
+STC_INLINE intptr_t _cx_MEMB(_size)(const _cx_Self* self)
{ return self->_len; }
-STC_INLINE bool _cx_memb(_empty)(const _cx_self* self)
+STC_INLINE bool _cx_MEMB(_empty)(const _cx_Self* self)
{ return !self->_len; }
-STC_INLINE intptr_t _cx_memb(_capacity)(const _cx_self* self) {
+STC_INLINE intptr_t _cx_MEMB(_capacity)(const _cx_Self* self) {
#ifndef i_capacity
return self->_cap;
#else
return i_capacity;
#endif
}
-STC_INLINE void _cx_memb(_value_drop)(_cx_value* val)
+STC_INLINE void _cx_MEMB(_value_drop)(_cx_value* val)
{ i_keydrop(val); }
-STC_INLINE bool _cx_memb(_reserve)(_cx_self* self, intptr_t n) {
+STC_INLINE bool _cx_MEMB(_reserve)(_cx_Self* self, intptr_t n) {
if (n < self->_len) return true;
#ifndef i_capacity
_cx_value *t = (_cx_value *)i_realloc(self->data, n*c_sizeof *t);
@@ -107,86 +101,106 @@ STC_INLINE bool _cx_memb(_reserve)(_cx_self* self, intptr_t n) {
return false;
}
-STC_INLINE _cx_value* _cx_memb(_append_uninit)(_cx_self *self, intptr_t n) {
+STC_INLINE _cx_value* _cx_MEMB(_append_uninit)(_cx_Self *self, intptr_t n) {
intptr_t len = self->_len;
- if (!_cx_memb(_reserve)(self, len + n)) return NULL;
+ if (!_cx_MEMB(_reserve)(self, len*3/2 + n)) return NULL;
self->_len += n;
return self->data + len;
}
-STC_INLINE void _cx_memb(_shrink_to_fit)(_cx_self* self)
- { _cx_memb(_reserve)(self, self->_len); }
+STC_INLINE void _cx_MEMB(_shrink_to_fit)(_cx_Self* self)
+ { _cx_MEMB(_reserve)(self, self->_len); }
-STC_INLINE const _cx_value* _cx_memb(_top)(const _cx_self* self)
+STC_INLINE const _cx_value* _cx_MEMB(_top)(const _cx_Self* self)
{ return &self->data[self->_len - 1]; }
-STC_INLINE _cx_value* _cx_memb(_back)(const _cx_self* self)
+STC_INLINE _cx_value* _cx_MEMB(_back)(const _cx_Self* self)
{ return (_cx_value*) &self->data[self->_len - 1]; }
-STC_INLINE _cx_value* _cx_memb(_front)(const _cx_self* self)
+STC_INLINE _cx_value* _cx_MEMB(_front)(const _cx_Self* self)
{ return (_cx_value*) &self->data[0]; }
-STC_INLINE _cx_value* _cx_memb(_push)(_cx_self* self, _cx_value val) {
- if (self->_len == _cx_memb(_capacity)(self))
- if (!_cx_memb(_reserve)(self, self->_len*3/2 + 4))
+STC_INLINE _cx_value* _cx_MEMB(_push)(_cx_Self* self, _cx_value val) {
+ if (self->_len == _cx_MEMB(_capacity)(self))
+ if (!_cx_MEMB(_reserve)(self, self->_len*3/2 + 4))
return NULL;
_cx_value* vp = self->data + self->_len++;
*vp = val; return vp;
}
-STC_INLINE void _cx_memb(_pop)(_cx_self* self)
- { assert(!_cx_memb(_empty)(self)); _cx_value* p = &self->data[--self->_len]; i_keydrop(p); }
+STC_INLINE void _cx_MEMB(_pop)(_cx_Self* self)
+ { c_assert(self->_len); _cx_value* p = &self->data[--self->_len]; i_keydrop(p); }
-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_value _cx_MEMB(_pull)(_cx_Self* self)
+ { c_assert(self->_len); return self->data[--self->_len]; }
-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(_put_n)(_cx_Self* self, const _cx_raw* raw, intptr_t n)
+ { while (n--) _cx_MEMB(_push)(self, i_keyfrom(*raw++)); }
-STC_INLINE const _cx_value* _cx_memb(_at)(const _cx_self* self, intptr_t idx)
- { assert(idx < self->_len); return self->data + idx; }
-STC_INLINE _cx_value* _cx_memb(_at_mut)(_cx_self* self, intptr_t idx)
- { assert(idx < self->_len); return self->data + idx; }
+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 const _cx_value* _cx_MEMB(_at)(const _cx_Self* self, intptr_t idx)
+ { c_assert(idx < self->_len); return self->data + idx; }
+STC_INLINE _cx_value* _cx_MEMB(_at_mut)(_cx_Self* self, intptr_t idx)
+ { c_assert(idx < self->_len); return self->data + idx; }
#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)); }
+STC_INLINE _cx_value* _cx_MEMB(_emplace)(_cx_Self* self, _cx_raw raw)
+ { return _cx_MEMB(_push)(self, i_keyfrom(raw)); }
#endif // !i_no_emplace
#if !defined i_no_clone
-STC_INLINE _cx_self _cx_memb(_clone)(_cx_self v) {
- _cx_self out = {(_cx_value *)i_malloc(v._len*c_sizeof(_cx_value)), v._len, v._len};
+STC_INLINE _cx_Self _cx_MEMB(_clone)(_cx_Self v) {
+ _cx_Self out = {(_cx_value *)i_malloc(v._len*c_sizeof(_cx_value)), v._len, v._len};
if (!out.data) out._cap = 0;
else for (intptr_t i = 0; i < v._len; ++v.data)
out.data[i++] = i_keyclone((*v.data));
return out;
}
-STC_INLINE void _cx_memb(_copy)(_cx_self *self, const _cx_self* other) {
+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);
+ _cx_MEMB(_drop)(self);
+ *self = _cx_MEMB(_clone)(*other);
}
-STC_INLINE i_key _cx_memb(_value_clone)(_cx_value val)
+STC_INLINE i_key _cx_MEMB(_value_clone)(_cx_value val)
{ return i_keyclone(val); }
-STC_INLINE i_keyraw _cx_memb(_value_toraw)(const _cx_value* val)
+STC_INLINE i_keyraw _cx_MEMB(_value_toraw)(const _cx_value* val)
{ return i_keyto(val); }
#endif // !i_no_clone
-STC_INLINE _cx_iter _cx_memb(_begin)(const _cx_self* self) {
+STC_INLINE _cx_iter _cx_MEMB(_begin)(const _cx_Self* self) {
return c_LITERAL(_cx_iter){self->_len ? (_cx_value*)self->data : NULL,
- (_cx_value*)self->data + self->_len};
+ (_cx_value*)self->data + self->_len};
}
-STC_INLINE _cx_iter _cx_memb(_end)(const _cx_self* self)
+STC_INLINE _cx_iter _cx_MEMB(_end)(const _cx_Self* self)
{ return c_LITERAL(_cx_iter){NULL, (_cx_value*)self->data + self->_len}; }
-STC_INLINE void _cx_memb(_next)(_cx_iter* it)
+STC_INLINE void _cx_MEMB(_next)(_cx_iter* it)
{ if (++it->ref == it->end) it->ref = NULL; }
-STC_INLINE _cx_iter _cx_memb(_advance)(_cx_iter it, size_t n)
+STC_INLINE _cx_iter _cx_MEMB(_advance)(_cx_iter it, size_t n)
{ if ((it.ref += n) >= it.end) it.ref = NULL ; return it; }
+STC_INLINE intptr_t _cx_MEMB(_index)(const _cx_Self* self, _cx_iter it)
+ { return (it.ref - self->data); }
+
+STC_INLINE void _cx_MEMB(_adjust_end_)(_cx_Self* self, intptr_t n)
+ { self->_len += n; }
+
+#if defined _i_has_eq || defined _i_has_cmp
+STC_INLINE bool
+_cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other) {
+ if (self->_len != other->_len) return false;
+ for (intptr_t i = 0; i < self->_len; ++i) {
+ const _cx_raw _rx = i_keyto(self->data+i), _ry = i_keyto(other->data+i);
+ if (!(i_eq((&_rx), (&_ry)))) return false;
+ }
+ return true;
+}
+#endif
#include "priv/template2.h"
diff --git a/include/stc/cstr.h b/include/stc/cstr.h
index eea16bc4..5a6465ff 100644
--- a/include/stc/cstr.h
+++ b/include/stc/cstr.h
@@ -24,15 +24,13 @@
/* A string type with short string optimization in C99 with good small-string
* optimization (22 characters with 24 bytes string).
*/
+#define i_header // external linkage by default. override with i_static.
+#define _i_inc_utf8
+#include "utf8.h"
+
#ifndef CSTR_H_INCLUDED
#define CSTR_H_INCLUDED
-#if defined i_extern || defined STC_EXTERN
-# define _i_extern
-#endif
-#include "ccommon.h"
-#include "forward.h"
-#include "utf8.h"
#include <stdlib.h> /* malloc */
#include <stdarg.h>
#include <stdio.h> /* vsnprintf */
@@ -70,15 +68,17 @@ STC_API char* _cstr_internal_move(cstr* self, intptr_t pos1, intptr_t pos2);
/**************************** PUBLIC API **********************************/
#define cstr_lit(literal) cstr_from_n(literal, c_litstrlen(literal))
-#define cstr_NULL (c_LITERAL(cstr){{{0}, 0}})
+#define cstr_null (c_LITERAL(cstr){0})
#define cstr_toraw(self) cstr_str(self)
STC_API char* cstr_reserve(cstr* self, intptr_t cap);
STC_API void cstr_shrink_to_fit(cstr* self);
STC_API char* cstr_resize(cstr* self, intptr_t size, char value);
STC_API intptr_t cstr_find_at(const cstr* self, intptr_t pos, const char* search);
+STC_API intptr_t cstr_find_sv(const cstr* self, csview search);
STC_API char* cstr_assign_n(cstr* self, const char* str, intptr_t len);
STC_API char* cstr_append_n(cstr* self, const char* str, intptr_t len);
+STC_API char* cstr_append_uninit(cstr *self, intptr_t len);
STC_API bool cstr_getdelim(cstr *self, int delim, FILE *fp);
STC_API void cstr_erase(cstr* self, intptr_t pos, intptr_t len);
STC_API void cstr_u8_erase(cstr* self, intptr_t bytepos, intptr_t u8len);
@@ -90,6 +90,7 @@ STC_API cstr cstr_from_vfmt(const char* fmt, va_list args);
STC_API intptr_t cstr_append_fmt(cstr* self, const char* fmt, ...);
STC_API intptr_t cstr_printf(cstr* self, const char* fmt, ...);
STC_API cstr cstr_replace_sv(csview sv, csview search, csview repl, int32_t count);
+STC_API uint64_t cstr_hash(const cstr *self);
STC_INLINE cstr_buf cstr_buffer(cstr* s) {
return cstr_is_long(s)
@@ -97,12 +98,14 @@ STC_INLINE cstr_buf cstr_buffer(cstr* s) {
: c_LITERAL(cstr_buf){s->sml.data, cstr_s_size(s), cstr_s_cap};
}
STC_INLINE csview cstr_sv(const cstr* s) {
- return cstr_is_long(s) ? c_LITERAL(csview){s->lon.data, cstr_l_size(s)}
- : c_LITERAL(csview){s->sml.data, cstr_s_size(s)};
+ return cstr_is_long(s) ? c_sv_2(s->lon.data, cstr_l_size(s))
+ : c_sv_2(s->sml.data, cstr_s_size(s));
}
+STC_INLINE crawstr cstr_rs(const cstr* s)
+ { csview sv = cstr_sv(s); return c_rs_2(sv.buf, sv.size); }
STC_INLINE cstr cstr_init(void)
- { return cstr_NULL; }
+ { return cstr_null; }
STC_INLINE cstr cstr_from_n(const char* str, const intptr_t len) {
cstr s;
@@ -114,7 +117,10 @@ STC_INLINE cstr cstr_from(const char* str)
{ return cstr_from_n(str, c_strlen(str)); }
STC_INLINE cstr cstr_from_sv(csview sv)
- { return cstr_from_n(sv.str, sv.size); }
+ { return cstr_from_n(sv.buf, sv.size); }
+
+STC_INLINE cstr cstr_from_rs(crawstr rs)
+ { return cstr_from_n(rs.str, rs.size); }
STC_INLINE cstr cstr_with_size(const intptr_t size, const char value) {
cstr s;
@@ -137,13 +143,13 @@ STC_INLINE cstr* cstr_take(cstr* self, const cstr s) {
STC_INLINE cstr cstr_move(cstr* self) {
cstr tmp = *self;
- *self = cstr_NULL;
+ *self = cstr_null;
return tmp;
}
STC_INLINE cstr cstr_clone(cstr s) {
csview sv = cstr_sv(&s);
- return cstr_from_n(sv.str, sv.size);
+ return cstr_from_n(sv.buf, sv.size);
}
STC_INLINE void cstr_drop(cstr* self) {
@@ -173,33 +179,16 @@ STC_INLINE intptr_t cstr_capacity(const cstr* self)
// utf8 methods defined in/depending on src/utf8code.c:
-extern cstr cstr_tocase(csview sv, int k);
-
-STC_INLINE cstr cstr_casefold_sv(csview sv)
- { return cstr_tocase(sv, 0); }
-
-STC_INLINE cstr cstr_tolower_sv(csview sv)
- { return cstr_tocase(sv, 1); }
-
-STC_INLINE cstr cstr_toupper_sv(csview sv)
- { return cstr_tocase(sv, 2); }
-
-STC_INLINE cstr cstr_tolower(const char* str)
- { return cstr_tolower_sv(c_sv(str, c_strlen(str))); }
-
-STC_INLINE cstr cstr_toupper(const char* str)
- { return cstr_toupper_sv(c_sv(str, c_strlen(str))); }
-
-STC_INLINE void cstr_lowercase(cstr* self)
- { cstr_take(self, cstr_tolower_sv(cstr_sv(self))); }
-
-STC_INLINE void cstr_uppercase(cstr* self)
- { cstr_take(self, cstr_toupper_sv(cstr_sv(self))); }
-
-STC_INLINE bool cstr_valid_utf8(const cstr* self)
- { return utf8_valid(cstr_str(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
+// utf8 functions not depending on src/utf8code.c:
STC_INLINE intptr_t cstr_u8_size(const cstr* self)
{ return utf8_size(cstr_str(self)); }
@@ -216,8 +205,8 @@ STC_INLINE const char* cstr_u8_at(const cstr* self, intptr_t u8idx)
STC_INLINE csview cstr_u8_chr(const cstr* self, intptr_t u8idx) {
const char* str = cstr_str(self);
csview sv;
- sv.str = utf8_at(str, u8idx);
- sv.size = utf8_chr_size(sv.str);
+ sv.buf = utf8_at(str, u8idx);
+ sv.size = utf8_chr_size(sv.buf);
return sv;
}
@@ -225,22 +214,22 @@ STC_INLINE csview cstr_u8_chr(const cstr* self, intptr_t u8idx) {
STC_INLINE cstr_iter cstr_begin(const cstr* self) {
csview sv = cstr_sv(self);
- if (!sv.size) return c_LITERAL(cstr_iter){NULL};
- return c_LITERAL(cstr_iter){.u8 = {{sv.str, utf8_chr_size(sv.str)}}};
+ if (!sv.size) return c_LITERAL(cstr_iter){.ref = NULL};
+ return c_LITERAL(cstr_iter){.u8 = {{sv.buf, utf8_chr_size(sv.buf)}}};
}
STC_INLINE cstr_iter cstr_end(const cstr* self) {
(void)self; return c_LITERAL(cstr_iter){NULL};
}
STC_INLINE void cstr_next(cstr_iter* it) {
- it->ref += it->u8.chr.size;
- it->u8.chr.size = utf8_chr_size(it->ref);
+ it->ref += it->chr.size;
+ it->chr.size = utf8_chr_size(it->ref);
if (!*it->ref) it->ref = NULL;
}
STC_INLINE cstr_iter cstr_advance(cstr_iter it, intptr_t pos) {
int inc = -1;
if (pos > 0) pos = -pos, inc = 1;
while (pos && *it.ref) pos += (*(it.ref += inc) & 0xC0) != 0x80;
- it.u8.chr.size = utf8_chr_size(it.ref);
+ it.chr.size = utf8_chr_size(it.ref);
if (!*it.ref) it.ref = NULL;
return it;
}
@@ -249,14 +238,6 @@ STC_INLINE cstr_iter cstr_advance(cstr_iter it, intptr_t pos) {
STC_INLINE void cstr_clear(cstr* self)
{ _cstr_set_size(self, 0); }
-STC_INLINE char* cstr_append_uninit(cstr *self, intptr_t len) {
- intptr_t sz = cstr_size(self);
- char* d = cstr_reserve(self, sz + len);
- if (!d) return NULL;
- _cstr_set_size(self, sz + len);
- return d + sz;
-}
-
STC_INLINE int cstr_cmp(const cstr* s1, const cstr* s2)
{ return strcmp(cstr_str(s1), cstr_str(s2)); }
@@ -265,7 +246,7 @@ STC_INLINE int cstr_icmp(const cstr* s1, const cstr* s2)
STC_INLINE bool cstr_eq(const cstr* s1, const cstr* s2) {
csview x = cstr_sv(s1), y = cstr_sv(s2);
- return x.size == y.size && !c_memcmp(x.str, y.str, x.size);
+ return x.size == y.size && !c_memcmp(x.buf, y.buf, x.size);
}
@@ -273,7 +254,7 @@ STC_INLINE bool cstr_equals(const cstr* self, const char* str)
{ return !strcmp(cstr_str(self), str); }
STC_INLINE bool cstr_equals_sv(const cstr* self, csview sv)
- { return sv.size == cstr_size(self) && !c_memcmp(cstr_str(self), sv.str, sv.size); }
+ { return sv.size == cstr_size(self) && !c_memcmp(cstr_str(self), sv.buf, sv.size); }
STC_INLINE bool cstr_equals_s(const cstr* self, cstr s)
{ return !cstr_cmp(self, &s); }
@@ -287,8 +268,6 @@ STC_INLINE intptr_t cstr_find(const cstr* self, const char* search) {
return res ? (res - str) : c_NPOS;
}
-STC_API intptr_t cstr_find_sv(const cstr* self, csview search);
-
STC_INLINE intptr_t cstr_find_s(const cstr* self, cstr search)
{ return cstr_find(self, cstr_str(&search)); }
@@ -305,7 +284,7 @@ STC_INLINE bool cstr_contains_s(const cstr* self, cstr search)
STC_INLINE bool cstr_starts_with_sv(const cstr* self, csview sub) {
if (sub.size > cstr_size(self)) return false;
- return !c_memcmp(cstr_str(self), sub.str, sub.size);
+ return !c_memcmp(cstr_str(self), sub.buf, sub.size);
}
STC_INLINE bool cstr_starts_with(const cstr* self, const char* sub) {
@@ -327,7 +306,7 @@ STC_INLINE bool cstr_istarts_with(const cstr* self, const char* sub) {
STC_INLINE bool cstr_ends_with_sv(const cstr* self, csview sub) {
csview sv = cstr_sv(self);
if (sub.size > sv.size) return false;
- return !c_memcmp(sv.str + sv.size - sub.size, sub.str, sub.size);
+ return !c_memcmp(sv.buf + sv.size - sub.size, sub.buf, sub.size);
}
STC_INLINE bool cstr_ends_with_s(const cstr* self, cstr sub)
@@ -339,7 +318,7 @@ STC_INLINE bool cstr_ends_with(const cstr* self, const char* sub)
STC_INLINE bool cstr_iends_with(const cstr* self, const char* sub) {
csview sv = cstr_sv(self);
intptr_t n = c_strlen(sub);
- return n <= sv.size && !utf8_icmp(sv.str + sv.size - n, sub);
+ return n <= sv.size && !utf8_icmp(sv.buf + sv.size - n, sub);
}
@@ -347,11 +326,11 @@ STC_INLINE char* cstr_assign(cstr* self, const char* str)
{ return cstr_assign_n(self, str, c_strlen(str)); }
STC_INLINE char* cstr_assign_sv(cstr* self, csview sv)
- { return cstr_assign_n(self, sv.str, sv.size); }
+ { return cstr_assign_n(self, sv.buf, sv.size); }
STC_INLINE char* cstr_copy(cstr* self, cstr s) {
csview sv = cstr_sv(&s);
- return cstr_assign_n(self, sv.str, sv.size);
+ return cstr_assign_n(self, sv.buf, sv.size);
}
@@ -360,21 +339,19 @@ STC_INLINE char* cstr_push(cstr* self, const char* chr)
STC_INLINE void cstr_pop(cstr* self) {
csview sv = cstr_sv(self);
- const char* s = sv.str + sv.size;
+ const char* s = sv.buf + sv.size;
while ((*--s & 0xC0) == 0x80) ;
- _cstr_set_size(self, (s - sv.str));
+ _cstr_set_size(self, (s - sv.buf));
}
STC_INLINE char* cstr_append(cstr* self, const char* str)
{ return cstr_append_n(self, str, c_strlen(str)); }
-STC_INLINE void cstr_append_sv(cstr* self, csview sv)
- { cstr_append_n(self, sv.str, sv.size); }
+STC_INLINE char* cstr_append_sv(cstr* self, csview sv)
+ { return cstr_append_n(self, sv.buf, sv.size); }
-STC_INLINE char* cstr_append_s(cstr* self, cstr s) {
- csview sv = cstr_sv(&s);
- return cstr_append_n(self, sv.str, sv.size);
-}
+STC_INLINE char* cstr_append_s(cstr* self, cstr s)
+ { return cstr_append_sv(self, cstr_sv(&s)); }
#define cstr_replace(...) c_MACRO_OVERLOAD(cstr_replace, __VA_ARGS__)
#define cstr_replace_3(self, search, repl) cstr_replace_4(self, search, repl, INT32_MAX)
@@ -385,7 +362,7 @@ STC_INLINE void cstr_replace_4(cstr* self, const char* search, const char* repl,
STC_INLINE void cstr_replace_at_sv(cstr* self, intptr_t pos, intptr_t len, const csview repl) {
char* d = _cstr_internal_move(self, pos + len, pos + repl.size);
- c_memcpy(d + pos, repl.str, repl.size);
+ c_memcpy(d + pos, repl.buf, repl.size);
}
STC_INLINE void cstr_replace_at(cstr* self, intptr_t pos, intptr_t len, const char* repl)
@@ -404,18 +381,18 @@ STC_INLINE void cstr_insert(cstr* self, intptr_t pos, const char* str)
STC_INLINE void cstr_insert_sv(cstr* self, intptr_t pos, csview sv)
{ cstr_replace_at_sv(self, pos, 0, sv); }
-STC_INLINE void cstr_insert_s(cstr* self, intptr_t pos, cstr s) {
- csview sv = cstr_sv(&s);
- cstr_replace_at_sv(self, pos, 0, sv);
-}
-
+STC_INLINE void cstr_insert_s(cstr* self, intptr_t pos, cstr s)
+ { cstr_replace_at_sv(self, pos, 0, cstr_sv(&s)); }
STC_INLINE bool cstr_getline(cstr *self, FILE *fp)
{ return cstr_getdelim(self, '\n', fp); }
-STC_API uint64_t cstr_hash(const cstr *self);
+#endif // CSTR_H_INCLUDED
+
+/* -------------------------- UTF8 CASE CONVERSION ------------------------- */
+#if defined(i_import) && !defined(CSTR_X_INCLUDED)
+#define CSTR_X_INCLUDED
-#ifdef _i_extern
static struct {
int (*conv_asc)(int);
uint32_t (*conv_utf)(uint32_t);
@@ -424,15 +401,15 @@ fn_tocase[] = {{tolower, utf8_casefold},
{tolower, utf8_tolower},
{toupper, utf8_toupper}};
-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;
+ const char *end = sv.buf + sv.size;
uint32_t cp; intptr_t sz = 0;
utf8_decode_t d = {.state=0};
- while (sv.str < end) {
- do { utf8_decode(&d, (uint8_t)*sv.str++); } while (d.state);
+ while (sv.buf < end) {
+ do { utf8_decode(&d, (uint8_t)*sv.buf++); } while (d.state);
if (d.codep < 128)
buf[sz++] = (char)fn_tocase[k].conv_asc((int)d.codep);
else {
@@ -444,20 +421,46 @@ cstr cstr_tocase(csview sv, int k) {
cstr_shrink_to_fit(&out);
return out;
}
-#endif
+
+cstr cstr_casefold_sv(csview sv)
+ { return cstr_tocase(sv, 0); }
+
+cstr cstr_tolower_sv(csview sv)
+ { return cstr_tocase(sv, 1); }
+
+cstr cstr_toupper_sv(csview sv)
+ { return cstr_tocase(sv, 2); }
+
+cstr cstr_tolower(const char* str)
+ { return cstr_tolower_sv(c_sv(str, c_strlen(str))); }
+
+cstr cstr_toupper(const char* str)
+ { return cstr_toupper_sv(c_sv(str, c_strlen(str))); }
+
+void cstr_lowercase(cstr* self)
+ { cstr_take(self, cstr_tolower_sv(cstr_sv(self))); }
+
+void cstr_uppercase(cstr* self)
+ { cstr_take(self, cstr_toupper_sv(cstr_sv(self))); }
+
+bool cstr_valid_utf8(const cstr* self)
+ { return utf8_valid(cstr_str(self)); }
+#endif // i_import
/* -------------------------- IMPLEMENTATION ------------------------- */
-#if defined(i_implement)
+#if defined i_implement || defined i_static
+#ifndef CSTR_C_INCLUDED
+#define CSTR_C_INCLUDED
STC_DEF uint64_t cstr_hash(const cstr *self) {
csview sv = cstr_sv(self);
- return cfasthash(sv.str, sv.size);
+ return stc_hash(sv.buf, sv.size);
}
STC_DEF intptr_t cstr_find_sv(const cstr* self, csview search) {
csview sv = cstr_sv(self);
- char* res = cstrnstrn(sv.str, search.str, sv.size, search.size);
- return res ? (res - sv.str) : c_NPOS;
+ char* res = stc_strnstrn(sv.buf, sv.size, search.buf, search.size);
+ return res ? (res - sv.buf) : c_NPOS;
}
STC_DEF char* _cstr_internal_move(cstr* self, const intptr_t pos1, const intptr_t pos2) {
@@ -509,7 +512,8 @@ STC_DEF char* cstr_reserve(cstr* self, const intptr_t cap) {
if (cap > cstr_s_cap) {
char* data = (char *)c_malloc(cap + 1);
const intptr_t len = cstr_s_size(self);
- c_memcpy(data, self->sml.data, cstr_s_cap + 1);
+ /* copy full short buffer to emulate realloc() */
+ c_memcpy(data, self->sml.data, c_sizeof self->sml);
self->lon.data = data;
self->lon.size = (size_t)len;
cstr_l_set_cap(self, cap);
@@ -532,8 +536,8 @@ STC_DEF char* cstr_resize(cstr* self, const intptr_t size, const char value) {
STC_DEF intptr_t cstr_find_at(const cstr* self, const intptr_t pos, const char* search) {
csview sv = cstr_sv(self);
if (pos > sv.size) return c_NPOS;
- const char* res = strstr((char*)sv.str + pos, search);
- return res ? (res - sv.str) : c_NPOS;
+ const char* res = strstr((char*)sv.buf + pos, search);
+ return res ? (res - sv.buf) : c_NPOS;
}
STC_DEF char* cstr_assign_n(cstr* self, const char* str, const intptr_t len) {
@@ -555,6 +559,14 @@ STC_DEF char* cstr_append_n(cstr* self, const char* str, const intptr_t len) {
return r.data;
}
+STC_DEF char* cstr_append_uninit(cstr *self, intptr_t len) {
+ cstr_buf r = cstr_buffer(self);
+ if (r.size + len > r.cap && !(r.data = cstr_reserve(self, r.size*3/2 + len)))
+ return NULL;
+ _cstr_set_size(self, r.size + len);
+ return r.data + r.size;
+}
+
STC_DEF bool cstr_getdelim(cstr *self, const int delim, FILE *fp) {
int c = fgetc(fp);
if (c == EOF)
@@ -575,19 +587,18 @@ STC_DEF bool cstr_getdelim(cstr *self, const int delim, FILE *fp) {
}
}
-STC_DEF cstr
-cstr_replace_sv(csview in, csview search, csview repl, int32_t count) {
- cstr out = cstr_NULL;
+STC_DEF cstr cstr_replace_sv(csview in, csview search, csview repl, int32_t count) {
+ cstr out = cstr_null;
intptr_t from = 0; char* res;
if (!count) count = INT32_MAX;
if (search.size)
- while (count-- && (res = cstrnstrn(in.str + from, search.str, in.size - from, search.size))) {
- const intptr_t pos = (res - in.str);
- cstr_append_n(&out, in.str + from, pos - from);
- cstr_append_n(&out, repl.str, repl.size);
+ while (count-- && (res = stc_strnstrn(in.buf + from, in.size - from, search.buf, search.size))) {
+ const intptr_t pos = (res - in.buf);
+ cstr_append_n(&out, in.buf + from, pos - from);
+ cstr_append_n(&out, repl.buf, repl.size);
from = pos + search.size;
}
- cstr_append_n(&out, in.str + from, in.size - from);
+ cstr_append_n(&out, in.buf + from, in.size - from);
return out;
}
@@ -629,7 +640,7 @@ STC_DEF intptr_t cstr_vfmt(cstr* self, intptr_t start, const char* fmt, va_list
#endif
STC_DEF cstr cstr_from_fmt(const char* fmt, ...) {
- cstr s = cstr_NULL;
+ cstr s = cstr_null;
va_list args;
va_start(args, fmt);
cstr_vfmt(&s, 0, fmt, args);
@@ -663,14 +674,14 @@ STC_DEF intptr_t cstr_printf(cstr* self, const char* fmt, ...) {
va_end(args);
return n;
}
-
+#endif // CSTR_C_INCLUDED
#endif // i_implement
+
#if defined __GNUC__ && !defined __clang__
# pragma GCC diagnostic pop
#endif
-#endif // CSTR_H_INCLUDED
#undef i_opt
#undef i_header
#undef i_static
#undef i_implement
-#undef _i_extern
+#undef i_import
diff --git a/include/stc/csview.h b/include/stc/csview.h
index bba3aea3..11e42c97 100644
--- a/include/stc/csview.h
+++ b/include/stc/csview.h
@@ -20,109 +20,117 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
+#define i_header // external linkage by default. override with i_static.
+#define _i_inc_utf8
+#include "utf8.h"
+
#ifndef CSVIEW_H_INCLUDED
#define CSVIEW_H_INCLUDED
-#include "ccommon.h"
-#include "forward.h"
-#include "utf8.h"
-
-#define csview_NULL c_sv_1("")
-#define csview_init() csview_NULL
+#define csview_init() c_sv_1("")
#define csview_drop(p) c_default_drop(p)
#define csview_clone(sv) c_default_clone(sv)
-#define csview_lit(literal) c_sv_1(literal)
#define csview_from_n(str, n) c_sv_2(str, n)
-STC_API intptr_t csview_find_sv(csview sv, csview search);
+STC_API csview_iter csview_advance(csview_iter it, intptr_t pos);
+STC_API intptr_t csview_find_sv(csview sv, csview search);
+STC_API uint64_t csview_hash(const csview *self);
+STC_API csview csview_slice_ex(csview sv, intptr_t p1, intptr_t p2);
+STC_API csview csview_substr_ex(csview sv, intptr_t pos, intptr_t n);
+STC_API csview csview_token(csview sv, const char* sep, intptr_t* start);
STC_INLINE csview csview_from(const char* str)
- { return c_LITERAL(csview){str, c_strlen(str)}; }
-STC_INLINE void csview_clear(csview* self) { *self = csview_NULL; }
-
-STC_INLINE intptr_t csview_size(csview sv) { return sv.size; }
+ { return c_LITERAL(csview){str, c_strlen(str)}; }
+STC_INLINE void csview_clear(csview* self) { *self = csview_init(); }
+STC_INLINE intptr_t csview_size(csview sv) { return sv.size; }
STC_INLINE bool csview_empty(csview sv) { return sv.size == 0; }
+STC_INLINE bool csview_equals_sv(csview sv1, csview sv2)
+ { return sv1.size == sv2.size && !c_memcmp(sv1.buf, sv2.buf, sv1.size); }
+
STC_INLINE bool csview_equals(csview sv, const char* str)
- { intptr_t n = c_strlen(str); return sv.size == n && !c_memcmp(sv.str, str, n); }
+ { return csview_equals_sv(sv, c_sv_2(str, c_strlen(str))); }
STC_INLINE intptr_t csview_find(csview sv, const char* str)
- { return csview_find_sv(sv, c_sv(str, c_strlen(str))); }
+ { return csview_find_sv(sv, c_sv_2(str, c_strlen(str))); }
STC_INLINE bool csview_contains(csview sv, const char* str)
{ return csview_find(sv, str) != c_NPOS; }
STC_INLINE bool csview_starts_with(csview sv, const char* str) {
intptr_t n = c_strlen(str);
- return n > sv.size ? false : !c_memcmp(sv.str, str, n);
+ return n > sv.size ? false : !c_memcmp(sv.buf, str, n);
}
STC_INLINE bool csview_ends_with(csview sv, const char* str) {
intptr_t n = c_strlen(str);
- return n > sv.size ? false : !c_memcmp(sv.str + sv.size - n, str, n);
+ return n > sv.size ? false : !c_memcmp(sv.buf + sv.size - n, str, n);
}
STC_INLINE csview csview_substr(csview sv, intptr_t pos, intptr_t n) {
if (pos + n > sv.size) n = sv.size - pos;
- sv.str += pos, sv.size = n;
+ sv.buf += pos, sv.size = n;
return sv;
}
STC_INLINE csview csview_slice(csview sv, intptr_t p1, intptr_t p2) {
if (p2 > sv.size) p2 = sv.size;
- sv.str += p1, sv.size = p2 > p1 ? p2 - p1 : 0;
+ sv.buf += p1, sv.size = p2 > p1 ? p2 - p1 : 0;
return sv;
}
/* utf8 iterator */
STC_INLINE csview_iter csview_begin(const csview* self) {
if (!self->size) return c_LITERAL(csview_iter){NULL};
- return c_LITERAL(csview_iter){.u8 = {{self->str, utf8_chr_size(self->str)},
- self->str + self->size}};
+ return c_LITERAL(csview_iter){.u8 = {{self->buf, utf8_chr_size(self->buf)},
+ self->buf + self->size}};
}
STC_INLINE csview_iter csview_end(const csview* self) {
- return c_LITERAL(csview_iter){.u8 = {{NULL}, self->str + self->size}};
+ return c_LITERAL(csview_iter){.u8 = {{NULL}, self->buf + self->size}};
}
STC_INLINE void csview_next(csview_iter* it) {
- it->ref += it->u8.chr.size;
- it->u8.chr.size = utf8_chr_size(it->ref);
+ it->ref += it->chr.size;
+ it->chr.size = utf8_chr_size(it->ref);
if (it->ref == it->u8.end) it->ref = NULL;
}
-STC_INLINE csview_iter csview_advance(csview_iter it, intptr_t pos) {
- int inc = -1;
- if (pos > 0) pos = -pos, inc = 1;
- while (pos && it.ref != it.u8.end) pos += (*(it.ref += inc) & 0xC0) != 0x80;
- it.u8.chr.size = utf8_chr_size(it.ref);
- if (it.ref == it.u8.end) it.ref = NULL;
- return it;
-}
-
/* utf8 */
STC_INLINE intptr_t csview_u8_size(csview sv)
- { return utf8_size_n(sv.str, sv.size); }
+ { return utf8_size_n(sv.buf, sv.size); }
STC_INLINE csview csview_u8_substr(csview sv, intptr_t bytepos, intptr_t u8len) {
- sv.str += bytepos;
- sv.size = utf8_pos(sv.str, u8len);
+ sv.buf += bytepos;
+ sv.size = utf8_pos(sv.buf, u8len);
return sv;
}
STC_INLINE bool csview_valid_utf8(csview sv) // depends on src/utf8code.c
- { return utf8_valid_n(sv.str, sv.size); }
-
-STC_API csview csview_substr_ex(csview sv, intptr_t pos, intptr_t n);
-STC_API csview csview_slice_ex(csview sv, intptr_t p1, intptr_t p2);
-STC_API csview csview_token(csview sv, const char* sep, intptr_t* start);
+ { return utf8_valid_n(sv.buf, sv.size); }
#define c_fortoken_sv(it, inputsv, sep) \
for (struct { csview _inp, token, *ref; const char *_sep; intptr_t pos; } \
it = {._inp=inputsv, .token=it._inp, .ref=&it.token, ._sep=sep} \
- ; it.pos <= it._inp.size && (it.token = csview_token(it._inp, it._sep, &it.pos)).str ; )
+ ; it.pos <= it._inp.size && (it.token = csview_token(it._inp, it._sep, &it.pos)).buf ; )
#define c_fortoken(it, input, sep) \
c_fortoken_sv(it, csview_from(input), sep)
+/* ---- Container helper functions ---- */
+
+STC_INLINE int csview_cmp(const csview* x, const csview* y) {
+ intptr_t n = x->size < y->size ? x->size : y->size;
+ int c = c_memcmp(x->buf, y->buf, n);
+ return c ? c : (int)(x->size - y->size);
+}
+
+STC_INLINE int csview_icmp(const csview* x, const csview* y)
+ { return utf8_icmp_sv(*x, *y); }
+
+STC_INLINE bool csview_eq(const csview* x, const csview* y)
+ { return x->size == y->size && !c_memcmp(x->buf, y->buf, x->size); }
+
+#endif // CSVIEW_H_INCLUDED
+
/* csview interaction with cstr: */
#ifdef CSTR_H_INCLUDED
@@ -140,34 +148,29 @@ STC_INLINE csview cstr_slice_ex(const cstr* self, intptr_t p1, intptr_t p2)
STC_INLINE csview cstr_u8_substr(const cstr* self , intptr_t bytepos, intptr_t u8len)
{ return csview_u8_substr(cstr_sv(self), bytepos, u8len); }
-
#endif
-/* ---- Container helper functions ---- */
-
-STC_INLINE int csview_cmp(const csview* x, const csview* y) {
- intptr_t n = x->size < y->size ? x->size : y->size;
- int c = c_memcmp(x->str, y->str, n);
- return c ? c : (int)(x->size - y->size);
-}
-
-STC_INLINE int csview_icmp(const csview* x, const csview* y)
- { return utf8_icmp_sv(*x, *y); }
-
-STC_INLINE bool csview_eq(const csview* x, const csview* y)
- { return x->size == y->size && !c_memcmp(x->str, y->str, x->size); }
-
-STC_API uint64_t csview_hash(const csview *self);
/* -------------------------- IMPLEMENTATION ------------------------- */
-#if defined(i_implement)
+#if defined i_implement || defined i_static
+#ifndef CSVIEW_C_INCLUDED
+#define CSVIEW_C_INCLUDED
+
+STC_DEF csview_iter csview_advance(csview_iter it, intptr_t pos) {
+ int inc = -1;
+ if (pos > 0) pos = -pos, inc = 1;
+ while (pos && it.ref != it.u8.end) pos += (*(it.ref += inc) & 0xC0) != 0x80;
+ it.chr.size = utf8_chr_size(it.ref);
+ if (it.ref == it.u8.end) it.ref = NULL;
+ return it;
+}
STC_DEF intptr_t csview_find_sv(csview sv, csview search) {
- char* res = cstrnstrn(sv.str, search.str, sv.size, search.size);
- return res ? (res - sv.str) : c_NPOS;
+ char* res = stc_strnstrn(sv.buf, sv.size, search.buf, search.size);
+ return res ? (res - sv.buf) : c_NPOS;
}
STC_DEF uint64_t csview_hash(const csview *self)
- { return cfasthash(self->str, self->size); }
+ { return stc_hash(self->buf, self->size); }
STC_DEF csview csview_substr_ex(csview sv, intptr_t pos, intptr_t n) {
if (pos < 0) {
@@ -176,7 +179,7 @@ STC_DEF csview csview_substr_ex(csview sv, intptr_t pos, intptr_t n) {
}
if (pos > sv.size) pos = sv.size;
if (pos + n > sv.size) n = sv.size - pos;
- sv.str += pos, sv.size = n;
+ sv.buf += pos, sv.size = n;
return sv;
}
@@ -187,23 +190,22 @@ STC_DEF csview csview_slice_ex(csview sv, intptr_t p1, intptr_t p2) {
}
if (p2 < 0) p2 += sv.size;
if (p2 > sv.size) p2 = sv.size;
- sv.str += p1, sv.size = (p2 > p1 ? p2 - p1 : 0);
+ sv.buf += p1, sv.size = (p2 > p1 ? p2 - p1 : 0);
return sv;
}
STC_DEF csview csview_token(csview sv, const char* sep, intptr_t* start) {
intptr_t sep_size = c_strlen(sep);
- csview slice = {sv.str + *start, sv.size - *start};
- const char* res = cstrnstrn(slice.str, sep, slice.size, sep_size);
- csview tok = {slice.str, res ? (res - slice.str) : slice.size};
+ csview slice = {sv.buf + *start, sv.size - *start};
+ const char* res = stc_strnstrn(slice.buf, slice.size, sep, sep_size);
+ csview tok = {slice.buf, res ? (res - slice.buf) : slice.size};
*start += tok.size + sep_size;
return tok;
}
-
-#endif
-#endif
-#undef i_opt
+#endif // CSVIEW_C_INCLUDED
+#endif // i_implement
+#undef i_static
#undef i_header
#undef i_implement
-#undef i_static
-#undef i_extern
+#undef i_import
+#undef i_opt
diff --git a/include/stc/cvec.h b/include/stc/cvec.h
index a1aa74b2..12cd6875 100644
--- a/include/stc/cvec.h
+++ b/include/stc/cvec.h
@@ -22,6 +22,7 @@
*/
/*
+#define i_implement
#include <stc/cstr.h>
#include <stc/forward.h>
@@ -39,11 +40,11 @@ struct MyStruct {
#include <stc/cvec.h>
#define i_key int
-#define i_is_forward // forward declared
+#define i_is_forward
#define i_tag i32
#include <stc/cvec.h>
-int main() {
+int main(void) {
cvec_i32 vec = {0};
cvec_i32_push(&vec, 123);
cvec_i32_drop(&vec);
@@ -57,9 +58,10 @@ int main() {
cvec_str_drop(&svec);
}
*/
-#include "ccommon.h"
+#include "priv/linkage.h"
#ifndef CVEC_H_INCLUDED
+#include "ccommon.h"
#include "forward.h"
#include <stdlib.h>
#include <string.h>
@@ -68,173 +70,172 @@ int main() {
#define _it_ptr(it) (it.ref ? it.ref : it.end)
#endif // CVEC_H_INCLUDED
-#ifndef _i_prefix
#define _i_prefix cvec_
-#endif
#include "priv/template.h"
#ifndef i_is_forward
- _cx_deftypes(_c_cvec_types, _cx_self, i_key);
+ _cx_DEFTYPES(_c_cvec_types, _cx_Self, i_key);
#endif
typedef i_keyraw _cx_raw;
-STC_API _cx_self _cx_memb(_init)(void);
-STC_API void _cx_memb(_drop)(_cx_self* self);
-STC_API void _cx_memb(_clear)(_cx_self* self);
-STC_API bool _cx_memb(_reserve)(_cx_self* self, intptr_t cap);
-STC_API bool _cx_memb(_resize)(_cx_self* self, intptr_t size, i_key null);
-STC_API _cx_value* _cx_memb(_push)(_cx_self* self, i_key value);
-STC_API _cx_iter _cx_memb(_erase_range_p)(_cx_self* self, _cx_value* p1, _cx_value* p2);
-STC_API _cx_iter _cx_memb(_insert_range)(_cx_self* self, _cx_value* pos,
- const _cx_value* p1, const _cx_value* p2);
-STC_API _cx_iter _cx_memb(_insert_uninit)(_cx_self* self, _cx_value* pos, const intptr_t n);
-#if !defined i_no_cmp || defined _i_has_eq
-STC_API _cx_iter _cx_memb(_find_in)(_cx_iter it1, _cx_iter it2, _cx_raw raw);
+STC_API _cx_Self _cx_MEMB(_init)(void);
+STC_API void _cx_MEMB(_drop)(_cx_Self* self);
+STC_API void _cx_MEMB(_clear)(_cx_Self* self);
+STC_API bool _cx_MEMB(_reserve)(_cx_Self* self, intptr_t cap);
+STC_API bool _cx_MEMB(_resize)(_cx_Self* self, intptr_t size, i_key null);
+STC_API _cx_iter _cx_MEMB(_erase_n)(_cx_Self* self, intptr_t idx, intptr_t n);
+STC_API _cx_iter _cx_MEMB(_insert_uninit)(_cx_Self* self, intptr_t idx, intptr_t n);
+#if defined _i_has_eq || defined _i_has_cmp
+STC_API _cx_iter _cx_MEMB(_find_in)(_cx_iter it1, _cx_iter it2, _cx_raw raw);
#endif
-#ifndef i_no_cmp
-STC_API int _cx_memb(_value_cmp)(const _cx_value* x, const _cx_value* y);
-STC_API _cx_iter _cx_memb(_binary_search_in)(_cx_iter it1, _cx_iter it2, _cx_raw raw, _cx_iter* lower_bound);
+#if defined _i_has_cmp
+STC_API int _cx_MEMB(_value_cmp)(const _cx_value* x, const _cx_value* y);
+STC_API _cx_iter _cx_MEMB(_binary_search_in)(_cx_iter it1, _cx_iter it2, _cx_raw raw, _cx_iter* lower_bound);
#endif
-STC_INLINE void _cx_memb(_value_drop)(_cx_value* val) { i_keydrop(val); }
+STC_INLINE void _cx_MEMB(_value_drop)(_cx_value* val) { i_keydrop(val); }
+
+STC_INLINE _cx_value* _cx_MEMB(_push)(_cx_Self* self, i_key value) {
+ if (self->_len == self->_cap)
+ if (!_cx_MEMB(_reserve)(self, self->_len*2 + 4))
+ return NULL;
+ _cx_value *v = self->data + self->_len++;
+ *v = value;
+ return v;
+ }
#if !defined i_no_emplace
-STC_API _cx_iter _cx_memb(_emplace_range)(_cx_self* self, _cx_value* pos,
- const _cx_raw* p1, const _cx_raw* p2);
-STC_INLINE _cx_value* _cx_memb(_emplace)(_cx_self* self, _cx_raw raw)
- { return _cx_memb(_push)(self, i_keyfrom(raw)); }
-STC_INLINE _cx_value* _cx_memb(_emplace_back)(_cx_self* self, _cx_raw raw)
- { return _cx_memb(_push)(self, i_keyfrom(raw)); }
-STC_INLINE _cx_iter
-_cx_memb(_emplace_n)(_cx_self* self, const intptr_t idx, const _cx_raw arr[], const intptr_t n) {
- return _cx_memb(_emplace_range)(self, self->data + idx, arr, arr + n);
+STC_API _cx_iter
+_cx_MEMB(_emplace_n)(_cx_Self* self, intptr_t idx, const _cx_raw raw[], intptr_t n);
+
+STC_INLINE _cx_value* _cx_MEMB(_emplace)(_cx_Self* self, _cx_raw raw) {
+ return _cx_MEMB(_push)(self, i_keyfrom(raw));
}
-STC_INLINE _cx_iter
-_cx_memb(_emplace_at)(_cx_self* self, _cx_iter it, _cx_raw raw) {
- return _cx_memb(_emplace_range)(self, _it_ptr(it), &raw, &raw + 1);
+STC_INLINE _cx_value* _cx_MEMB(_emplace_back)(_cx_Self* self, _cx_raw raw) {
+ return _cx_MEMB(_push)(self, i_keyfrom(raw));
+}
+STC_INLINE _cx_iter _cx_MEMB(_emplace_at)(_cx_Self* self, _cx_iter it, _cx_raw raw) {
+ return _cx_MEMB(_emplace_n)(self, _it_ptr(it) - self->data, &raw, 1);
}
#endif // !i_no_emplace
#if !defined i_no_clone
-STC_API _cx_self _cx_memb(_clone)(_cx_self cx);
-STC_API _cx_iter _cx_memb(_copy_range)(_cx_self* self, _cx_value* pos,
- const _cx_value* p1, const _cx_value* p2);
-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 i_key _cx_memb(_value_clone)(_cx_value val)
+STC_API _cx_Self _cx_MEMB(_clone)(_cx_Self cx);
+STC_API _cx_iter _cx_MEMB(_copy_n)(_cx_Self* self, intptr_t idx, const _cx_value arr[], intptr_t n);
+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 i_key _cx_MEMB(_value_clone)(_cx_value val)
{ return i_keyclone(val); }
-STC_INLINE void _cx_memb(_copy)(_cx_self* self, const _cx_self* other) {
+STC_INLINE void _cx_MEMB(_copy)(_cx_Self* self, const _cx_Self* other) {
if (self->data == other->data) return;
- _cx_memb(_clear)(self);
- _cx_memb(_copy_range)(self, self->data, other->data,
- other->data + other->_len);
+ _cx_MEMB(_clear)(self);
+ _cx_MEMB(_copy_n)(self, 0, other->data, other->_len);
}
#endif // !i_no_clone
-STC_INLINE intptr_t _cx_memb(_size)(const _cx_self* self) { return self->_len; }
-STC_INLINE intptr_t _cx_memb(_capacity)(const _cx_self* self) { return self->_cap; }
-STC_INLINE bool _cx_memb(_empty)(const _cx_self* self) { return !self->_len; }
-STC_INLINE _cx_raw _cx_memb(_value_toraw)(const _cx_value* val) { return i_keyto(val); }
-STC_INLINE _cx_value* _cx_memb(_front)(const _cx_self* self) { return self->data; }
-STC_INLINE _cx_value* _cx_memb(_back)(const _cx_self* self)
+STC_INLINE intptr_t _cx_MEMB(_size)(const _cx_Self* self) { return self->_len; }
+STC_INLINE intptr_t _cx_MEMB(_capacity)(const _cx_Self* self) { return self->_cap; }
+STC_INLINE bool _cx_MEMB(_empty)(const _cx_Self* self) { return !self->_len; }
+STC_INLINE _cx_raw _cx_MEMB(_value_toraw)(const _cx_value* val) { return i_keyto(val); }
+STC_INLINE _cx_value* _cx_MEMB(_front)(const _cx_Self* self) { return self->data; }
+STC_INLINE _cx_value* _cx_MEMB(_back)(const _cx_Self* self)
{ return self->data + self->_len - 1; }
-STC_INLINE void _cx_memb(_pop)(_cx_self* self)
- { assert(!_cx_memb(_empty)(self)); _cx_value* p = &self->data[--self->_len]; i_keydrop(p); }
-STC_INLINE _cx_value* _cx_memb(_push_back)(_cx_self* self, i_key value)
- { return _cx_memb(_push)(self, value); }
-STC_INLINE void _cx_memb(_pop_back)(_cx_self* self) { _cx_memb(_pop)(self); }
-
-STC_INLINE _cx_self
-_cx_memb(_with_size)(const intptr_t size, i_key null) {
- _cx_self cx = _cx_memb(_init)();
- _cx_memb(_resize)(&cx, size, null);
+STC_INLINE void _cx_MEMB(_pop)(_cx_Self* self)
+ { c_assert(self->_len); _cx_value* p = &self->data[--self->_len]; i_keydrop(p); }
+STC_INLINE _cx_value _cx_MEMB(_pull)(_cx_Self* self)
+ { c_assert(self->_len); return self->data[--self->_len]; }
+STC_INLINE _cx_value* _cx_MEMB(_push_back)(_cx_Self* self, i_key value)
+ { return _cx_MEMB(_push)(self, value); }
+STC_INLINE void _cx_MEMB(_pop_back)(_cx_Self* self) { _cx_MEMB(_pop)(self); }
+
+STC_INLINE _cx_Self
+_cx_MEMB(_with_size)(const intptr_t size, i_key null) {
+ _cx_Self cx = _cx_MEMB(_init)();
+ _cx_MEMB(_resize)(&cx, size, null);
return cx;
}
-STC_INLINE _cx_self
-_cx_memb(_with_capacity)(const intptr_t cap) {
- _cx_self cx = _cx_memb(_init)();
- _cx_memb(_reserve)(&cx, cap);
+STC_INLINE _cx_Self
+_cx_MEMB(_with_capacity)(const intptr_t cap) {
+ _cx_Self cx = _cx_MEMB(_init)();
+ _cx_MEMB(_reserve)(&cx, cap);
return cx;
}
STC_INLINE void
-_cx_memb(_shrink_to_fit)(_cx_self* self) {
- _cx_memb(_reserve)(self, _cx_memb(_size)(self));
+_cx_MEMB(_shrink_to_fit)(_cx_Self* self) {
+ _cx_MEMB(_reserve)(self, _cx_MEMB(_size)(self));
}
-
-STC_INLINE _cx_iter
-_cx_memb(_insert)(_cx_self* self, const intptr_t idx, i_key value) {
- return _cx_memb(_insert_range)(self, self->data + idx, &value, &value + 1);
-}
STC_INLINE _cx_iter
-_cx_memb(_insert_n)(_cx_self* self, const intptr_t idx, const _cx_value arr[], const intptr_t n) {
- return _cx_memb(_insert_range)(self, self->data + idx, arr, arr + n);
+_cx_MEMB(_insert_n)(_cx_Self* self, const intptr_t idx, const _cx_value arr[], const intptr_t n) {
+ _cx_iter it = _cx_MEMB(_insert_uninit)(self, idx, n);
+ if (it.ref)
+ c_memcpy(it.ref, arr, n*c_sizeof *arr);
+ return it;
}
STC_INLINE _cx_iter
-_cx_memb(_insert_at)(_cx_self* self, _cx_iter it, i_key value) {
- return _cx_memb(_insert_range)(self, _it_ptr(it), &value, &value + 1);
+_cx_MEMB(_insert_at)(_cx_Self* self, _cx_iter it, const _cx_value value) {
+ return _cx_MEMB(_insert_n)(self, _it_ptr(it) - self->data, &value, 1);
}
STC_INLINE _cx_iter
-_cx_memb(_erase_n)(_cx_self* self, const intptr_t idx, const intptr_t n) {
- return _cx_memb(_erase_range_p)(self, self->data + idx, self->data + idx + n);
+_cx_MEMB(_erase_at)(_cx_Self* self, _cx_iter it) {
+ return _cx_MEMB(_erase_n)(self, it.ref - self->data, 1);
}
STC_INLINE _cx_iter
-_cx_memb(_erase_at)(_cx_self* self, _cx_iter it) {
- return _cx_memb(_erase_range_p)(self, it.ref, it.ref + 1);
-}
-STC_INLINE _cx_iter
-_cx_memb(_erase_range)(_cx_self* self, _cx_iter i1, _cx_iter i2) {
- return _cx_memb(_erase_range_p)(self, i1.ref, _it2_ptr(i1, i2));
+_cx_MEMB(_erase_range)(_cx_Self* self, _cx_iter i1, _cx_iter i2) {
+ return _cx_MEMB(_erase_n)(self, i1.ref - self->data, _it2_ptr(i1, i2) - i1.ref);
}
STC_INLINE const _cx_value*
-_cx_memb(_at)(const _cx_self* self, const intptr_t idx) {
- assert(idx < self->_len); return self->data + idx;
+_cx_MEMB(_at)(const _cx_Self* self, const intptr_t idx) {
+ c_assert(idx < self->_len); return self->data + idx;
}
STC_INLINE _cx_value*
-_cx_memb(_at_mut)(_cx_self* self, const intptr_t idx) {
- assert(idx < self->_len); return self->data + idx;
+_cx_MEMB(_at_mut)(_cx_Self* self, const intptr_t idx) {
+ c_assert(idx < self->_len); return self->data + idx;
}
-STC_INLINE _cx_iter _cx_memb(_begin)(const _cx_self* self) {
+STC_INLINE _cx_iter _cx_MEMB(_begin)(const _cx_Self* self) {
intptr_t n = self->_len;
return c_LITERAL(_cx_iter){n ? self->data : NULL, self->data + n};
}
-STC_INLINE _cx_iter _cx_memb(_end)(const _cx_self* self)
+STC_INLINE _cx_iter _cx_MEMB(_end)(const _cx_Self* self)
{ return c_LITERAL(_cx_iter){NULL, self->data + self->_len}; }
-STC_INLINE void _cx_memb(_next)(_cx_iter* it)
+STC_INLINE void _cx_MEMB(_next)(_cx_iter* it)
{ if (++it->ref == it->end) it->ref = NULL; }
-STC_INLINE _cx_iter _cx_memb(_advance)(_cx_iter it, size_t n)
+STC_INLINE _cx_iter _cx_MEMB(_advance)(_cx_iter it, size_t n)
{ if ((it.ref += n) >= it.end) it.ref = NULL; return it; }
-STC_INLINE intptr_t _cx_memb(_index)(const _cx_self* self, _cx_iter it)
+STC_INLINE intptr_t _cx_MEMB(_index)(const _cx_Self* self, _cx_iter it)
{ return (it.ref - self->data); }
-#if !defined i_no_cmp || defined _i_has_eq
+STC_INLINE void _cx_MEMB(_adjust_end_)(_cx_Self* self, intptr_t n)
+ { self->_len += n; }
+
+#if defined _i_has_eq || defined _i_has_cmp
STC_INLINE _cx_iter
-_cx_memb(_find)(const _cx_self* self, _cx_raw raw) {
- return _cx_memb(_find_in)(_cx_memb(_begin)(self), _cx_memb(_end)(self), raw);
+_cx_MEMB(_find)(const _cx_Self* self, _cx_raw raw) {
+ return _cx_MEMB(_find_in)(_cx_MEMB(_begin)(self), _cx_MEMB(_end)(self), raw);
}
STC_INLINE const _cx_value*
-_cx_memb(_get)(const _cx_self* self, _cx_raw raw) {
- return _cx_memb(_find)(self, raw).ref;
+_cx_MEMB(_get)(const _cx_Self* self, _cx_raw raw) {
+ return _cx_MEMB(_find)(self, raw).ref;
}
STC_INLINE _cx_value*
-_cx_memb(_get_mut)(const _cx_self* self, _cx_raw raw)
- { return (_cx_value*) _cx_memb(_get)(self, raw); }
+_cx_MEMB(_get_mut)(const _cx_Self* self, _cx_raw raw)
+ { return (_cx_value*) _cx_MEMB(_get)(self, raw); }
STC_INLINE bool
-_cx_memb(_eq)(const _cx_self* self, const _cx_self* other) {
+_cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other) {
if (self->_len != other->_len) return false;
for (intptr_t i = 0; i < self->_len; ++i) {
const _cx_raw _rx = i_keyto(self->data+i), _ry = i_keyto(other->data+i);
@@ -243,42 +244,42 @@ _cx_memb(_eq)(const _cx_self* self, const _cx_self* other) {
return true;
}
#endif
-#ifndef i_no_cmp
+#if defined _i_has_cmp
STC_INLINE _cx_iter
-_cx_memb(_binary_search)(const _cx_self* self, _cx_raw raw) {
+_cx_MEMB(_binary_search)(const _cx_Self* self, _cx_raw raw) {
_cx_iter lower;
- return _cx_memb(_binary_search_in)(_cx_memb(_begin)(self), _cx_memb(_end)(self), raw, &lower);
+ return _cx_MEMB(_binary_search_in)(_cx_MEMB(_begin)(self), _cx_MEMB(_end)(self), raw, &lower);
}
STC_INLINE _cx_iter
-_cx_memb(_lower_bound)(const _cx_self* self, _cx_raw raw) {
+_cx_MEMB(_lower_bound)(const _cx_Self* self, _cx_raw raw) {
_cx_iter lower;
- _cx_memb(_binary_search_in)(_cx_memb(_begin)(self), _cx_memb(_end)(self), raw, &lower);
+ _cx_MEMB(_binary_search_in)(_cx_MEMB(_begin)(self), _cx_MEMB(_end)(self), raw, &lower);
return lower;
}
STC_INLINE void
-_cx_memb(_sort_range)(_cx_iter i1, _cx_iter i2, int(*cmp)(const _cx_value*, const _cx_value*)) {
+_cx_MEMB(_sort_range)(_cx_iter i1, _cx_iter i2, int(*cmp)(const _cx_value*, const _cx_value*)) {
qsort(i1.ref, (size_t)(_it2_ptr(i1, i2) - i1.ref), sizeof(_cx_value),
(int(*)(const void*, const void*)) cmp);
}
STC_INLINE void
-_cx_memb(_sort)(_cx_self* self) {
- _cx_memb(_sort_range)(_cx_memb(_begin)(self), _cx_memb(_end)(self), _cx_memb(_value_cmp));
+_cx_MEMB(_sort)(_cx_Self* self) {
+ _cx_MEMB(_sort_range)(_cx_MEMB(_begin)(self), _cx_MEMB(_end)(self), _cx_MEMB(_value_cmp));
}
-#endif // !c_no_cmp
+#endif // _i_has_cmp
/* -------------------------- IMPLEMENTATION ------------------------- */
-#if defined(i_implement)
+#if defined(i_implement) || defined(i_static)
-STC_DEF _cx_self
-_cx_memb(_init)(void) {
- return c_LITERAL(_cx_self){NULL};
+STC_DEF _cx_Self
+_cx_MEMB(_init)(void) {
+ return c_LITERAL(_cx_Self){NULL};
}
STC_DEF void
-_cx_memb(_clear)(_cx_self* self) {
+_cx_MEMB(_clear)(_cx_Self* self) {
if (self->_cap) {
for (_cx_value *p = self->data, *q = p + self->_len; p != q; ) {
--q; i_keydrop(q);
@@ -288,15 +289,15 @@ _cx_memb(_clear)(_cx_self* self) {
}
STC_DEF void
-_cx_memb(_drop)(_cx_self* self) {
+_cx_MEMB(_drop)(_cx_Self* self) {
if (self->_cap == 0)
return;
- _cx_memb(_clear)(self);
+ _cx_MEMB(_clear)(self);
i_free(self->data);
}
STC_DEF bool
-_cx_memb(_reserve)(_cx_self* self, const intptr_t cap) {
+_cx_MEMB(_reserve)(_cx_Self* self, const intptr_t cap) {
if (cap > self->_cap || (cap && cap == self->_len)) {
_cx_value* d = (_cx_value*)i_realloc(self->data, cap*c_sizeof(i_key));
if (!d)
@@ -308,8 +309,8 @@ _cx_memb(_reserve)(_cx_self* self, const intptr_t cap) {
}
STC_DEF bool
-_cx_memb(_resize)(_cx_self* self, const intptr_t len, i_key null) {
- if (!_cx_memb(_reserve)(self, len))
+_cx_MEMB(_resize)(_cx_Self* self, const intptr_t len, i_key null) {
+ if (!_cx_MEMB(_reserve)(self, len))
return false;
const intptr_t n = self->_len;
for (intptr_t i = len; i < n; ++i)
@@ -320,86 +321,61 @@ _cx_memb(_resize)(_cx_self* self, const intptr_t len, i_key null) {
return true;
}
-STC_DEF _cx_value*
-_cx_memb(_push)(_cx_self* self, i_key value) {
- if (self->_len == self->_cap)
- if (!_cx_memb(_reserve)(self, self->_len*3/2 + 4))
- return NULL;
- _cx_value *v = self->data + self->_len++;
- *v = value;
- return v;
-}
-
STC_DEF _cx_iter
-_cx_memb(_insert_uninit)(_cx_self* self, _cx_value* pos, const intptr_t n) {
- if (n) {
- if (!pos) pos = self->data + self->_len;
- const intptr_t idx = (pos - self->data);
- if (self->_len + n > self->_cap) {
- if (!_cx_memb(_reserve)(self, self->_len*3/2 + n))
- return _cx_memb(_end)(self);
- pos = self->data + idx;
- }
- c_memmove(pos + n, pos, (self->_len - idx)*c_sizeof *pos);
- self->_len += n;
- }
+_cx_MEMB(_insert_uninit)(_cx_Self* self, const intptr_t idx, const intptr_t n) {
+ if (self->_len + n > self->_cap)
+ if (!_cx_MEMB(_reserve)(self, self->_len*5/4 + n))
+ return _cx_MEMB(_end)(self);
+
+ _cx_value* pos = self->data + idx;
+ c_memmove(pos + n, pos, (self->_len - idx)*c_sizeof *pos);
+ self->_len += n;
return c_LITERAL(_cx_iter){pos, self->data + self->_len};
}
STC_DEF _cx_iter
-_cx_memb(_insert_range)(_cx_self* self, _cx_value* pos,
- const _cx_value* p1, const _cx_value* p2) {
- _cx_iter it = _cx_memb(_insert_uninit)(self, pos, (p2 - p1));
- if (it.ref)
- c_memcpy(it.ref, p1, (p2 - p1)*c_sizeof *p1);
- return it;
-}
-
-STC_DEF _cx_iter
-_cx_memb(_erase_range_p)(_cx_self* self, _cx_value* p1, _cx_value* p2) {
- intptr_t len = (p2 - p1);
- _cx_value* p = p1, *end = self->data + self->_len;
- for (; p != p2; ++p)
+_cx_MEMB(_erase_n)(_cx_Self* self, const intptr_t idx, const intptr_t len) {
+ _cx_value* d = self->data + idx, *p = d, *end = self->data + self->_len;
+ for (intptr_t i = 0; i < len; ++i, ++p)
{ i_keydrop(p); }
- c_memmove(p1, p2, (end - p2)*c_sizeof *p1);
+ c_memmove(d, p, (end - p)*c_sizeof *d);
self->_len -= len;
- return c_LITERAL(_cx_iter){p2 == end ? NULL : p1, end - len};
+ return c_LITERAL(_cx_iter){p == end ? NULL : d, end - len};
}
#if !defined i_no_clone
-STC_DEF _cx_self
-_cx_memb(_clone)(_cx_self cx) {
- _cx_self out = _cx_memb(_init)();
- _cx_memb(_copy_range)(&out, out.data, cx.data, cx.data + cx._len);
+STC_DEF _cx_Self
+_cx_MEMB(_clone)(_cx_Self cx) {
+ _cx_Self out = _cx_MEMB(_init)();
+ _cx_MEMB(_copy_n)(&out, 0, cx.data, cx._len);
return out;
}
STC_DEF _cx_iter
-_cx_memb(_copy_range)(_cx_self* self, _cx_value* pos,
- const _cx_value* p1, const _cx_value* p2) {
- _cx_iter it = _cx_memb(_insert_uninit)(self, pos, (p2 - p1));
+_cx_MEMB(_copy_n)(_cx_Self* self, const intptr_t idx,
+ const _cx_value arr[], const intptr_t n) {
+ _cx_iter it = _cx_MEMB(_insert_uninit)(self, idx, n);
if (it.ref)
- for (_cx_value* p = it.ref; p1 != p2; ++p1)
- *p++ = i_keyclone((*p1));
+ for (_cx_value* p = it.ref, *q = p + n; p != q; ++arr)
+ *p++ = i_keyclone((*arr));
return it;
}
#endif // !i_no_clone
#if !defined i_no_emplace
STC_DEF _cx_iter
-_cx_memb(_emplace_range)(_cx_self* self, _cx_value* pos,
- const _cx_raw* p1, const _cx_raw* p2) {
- _cx_iter it = _cx_memb(_insert_uninit)(self, pos, (p2 - p1));
+_cx_MEMB(_emplace_n)(_cx_Self* self, const intptr_t idx, const _cx_raw raw[], intptr_t n) {
+ _cx_iter it = _cx_MEMB(_insert_uninit)(self, idx, n);
if (it.ref)
- for (_cx_value* p = it.ref; p1 != p2; ++p1)
- *p++ = i_keyfrom((*p1));
+ for (_cx_value* p = it.ref; n--; ++raw, ++p)
+ *p = i_keyfrom((*raw));
return it;
}
#endif // !i_no_emplace
+#if defined _i_has_eq || defined _i_has_cmp
-#if !defined i_no_cmp || defined _i_has_eq
STC_DEF _cx_iter
-_cx_memb(_find_in)(_cx_iter i1, _cx_iter i2, _cx_raw raw) {
+_cx_MEMB(_find_in)(_cx_iter i1, _cx_iter i2, _cx_raw raw) {
const _cx_value* p2 = _it2_ptr(i1, i2);
for (; i1.ref != p2; ++i1.ref) {
const _cx_raw r = i_keyto(i1.ref);
@@ -410,10 +386,10 @@ _cx_memb(_find_in)(_cx_iter i1, _cx_iter i2, _cx_raw raw) {
return i2;
}
#endif
-#ifndef i_no_cmp
+#if defined _i_has_cmp
STC_DEF _cx_iter
-_cx_memb(_binary_search_in)(_cx_iter i1, _cx_iter i2, const _cx_raw raw,
+_cx_MEMB(_binary_search_in)(_cx_iter i1, _cx_iter i2, const _cx_raw raw,
_cx_iter* lower_bound) {
_cx_value* w[2] = {i1.ref, _it2_ptr(i1, i2)};
_cx_iter mid = i1;
@@ -430,12 +406,12 @@ _cx_memb(_binary_search_in)(_cx_iter i1, _cx_iter i2, const _cx_raw raw,
i1.ref = NULL; return i1;
}
-STC_DEF int _cx_memb(_value_cmp)(const _cx_value* x, const _cx_value* y) {
+STC_DEF int _cx_MEMB(_value_cmp)(const _cx_value* x, const _cx_value* y) {
const _cx_raw rx = i_keyto(x);
const _cx_raw ry = i_keyto(y);
return i_cmp((&rx), (&ry));
}
-#endif // !c_no_cmp
+#endif // _i_has_cmp
#endif // i_implement
#define CVEC_H_INCLUDED
#include "priv/template2.h"
diff --git a/include/stc/extend.h b/include/stc/extend.h
index 66b3ebd1..52d59414 100644
--- a/include/stc/extend.h
+++ b/include/stc/extend.h
@@ -43,10 +43,12 @@
#define _i_val i_val
#endif
-#ifdef _i_key
- c_PASTE(forward_, i_con)(i_type, _i_key, _i_val);
+#if defined _i_key && defined _i_val
+ c_PASTE(forward_, i_base)(i_type, _i_key, _i_val);
+#elif defined _i_key
+ c_PASTE(forward_, i_base)(i_type, _i_key);
#else
- c_PASTE(forward_, i_con)(i_type, _i_val);
+ c_PASTE(forward_, i_base)(i_type, _i_val);
#endif
typedef struct {
@@ -54,13 +56,16 @@ typedef struct {
i_type get;
} c_PASTE(i_type, _ext);
-#define c_getcon(cptr) c_container_of(cptr, _cx_memb(_ext), get)
+#define c_extend() c_container_of(self, _cx_MEMB(_ext), get)
+// Note: i_less: c_extend() accessible for cpque types
+// i_cmp: c_extend() accessible for csmap and csset types
+// i_hash/i_eq: c_extend() accessible for cmap and cset types
#define i_is_forward
-#define _i_inc <stc/i_con.h>
+#define _i_inc <stc/i_base.h>
#include _i_inc
#undef _i_inc
#undef _i_key
#undef _i_val
-#undef i_con
+#undef i_base
#undef i_extend
diff --git a/include/stc/forward.h b/include/stc/forward.h
index 31e67e7d..2fbff034 100644
--- a/include/stc/forward.h
+++ b/include/stc/forward.h
@@ -24,35 +24,50 @@
#define STC_FORWARD_H_INCLUDED
#include <stdint.h>
+#include <stddef.h>
#define forward_carc(CX, VAL) _c_carc_types(CX, VAL)
#define forward_cbox(CX, VAL) _c_cbox_types(CX, VAL)
#define forward_cdeq(CX, VAL) _c_cdeq_types(CX, VAL)
#define forward_clist(CX, VAL) _c_clist_types(CX, VAL)
-#define forward_cmap(CX, KEY, VAL) _c_chash_types(CX, KEY, VAL, int32_t, c_true, c_false)
-#define forward_cmap64(CX, KEY, VAL) _c_chash_types(CX, KEY, VAL, int64_t, c_true, c_false)
-#define forward_cset(CX, KEY) _c_chash_types(CX, cset, KEY, KEY, int32_t, c_false, c_true)
-#define forward_cset64(CX, KEY) _c_chash_types(CX, cset, KEY, KEY, int64_t, c_false, c_true)
-#define forward_csmap(CX, KEY, VAL) _c_aatree_types(CX, KEY, VAL, int32_t, c_true, c_false)
-#define forward_csset(CX, KEY) _c_aatree_types(CX, KEY, KEY, int32_t, c_false, c_true)
+#define forward_cmap(CX, KEY, VAL) _c_chash_types(CX, KEY, VAL, c_true, c_false)
+#define forward_cset(CX, KEY) _c_chash_types(CX, cset, KEY, KEY, c_false, c_true)
+#define forward_csmap(CX, KEY, VAL) _c_aatree_types(CX, KEY, VAL, c_true, c_false)
+#define forward_csset(CX, KEY) _c_aatree_types(CX, KEY, KEY, c_false, c_true)
#define forward_cstack(CX, VAL) _c_cstack_types(CX, VAL)
#define forward_cpque(CX, VAL) _c_cpque_types(CX, VAL)
#define forward_cqueue(CX, VAL) _c_cdeq_types(CX, VAL)
#define forward_cvec(CX, VAL) _c_cvec_types(CX, VAL)
-// csview
+// csview : non-null terminated string view
typedef const char csview_value;
-typedef struct csview {
- csview_value* str;
+typedef struct csview {
+ csview_value* buf;
intptr_t size;
} csview;
-typedef union {
- csview_value* ref;
+typedef union {
+ csview_value* ref;
+ csview chr;
struct { csview chr; csview_value* end; } u8;
} csview_iter;
-// cstr
+
+// crawstr : null-terminated string view
+typedef csview_value crawstr_value;
+typedef struct crawstr {
+ crawstr_value* str;
+ intptr_t size;
+} crawstr;
+
+typedef union {
+ crawstr_value* ref;
+ csview chr;
+ struct { csview chr; } u8; // [deprecated]
+} crawstr_iter;
+
+
+// cstr : null-terminated string (short string optimized - sso)
typedef char cstr_value;
typedef struct { cstr_value* data; intptr_t size, cap; } cstr_buf;
typedef union cstr {
@@ -60,11 +75,13 @@ typedef union cstr {
struct { cstr_value* data; size_t size, ncap; } lon;
} cstr;
-typedef union {
- cstr_value* ref;
- struct { csview chr; } u8;
+typedef union {
+ cstr_value* ref;
+ csview chr;
+ struct { csview chr; } u8; // [deprecated]
} cstr_iter;
+
#define c_true(...) __VA_ARGS__
#define c_false(...)
@@ -83,12 +100,17 @@ typedef union {
#define _c_cdeq_types(SELF, VAL) \
typedef VAL SELF##_value; \
- typedef struct { SELF##_value *ref, *end; } SELF##_iter; \
\
typedef struct SELF { \
- SELF##_value *_base, *data; \
- intptr_t _len, _cap; \
- } SELF
+ SELF##_value *data; \
+ intptr_t start, end, capmask; \
+ } SELF; \
+\
+ typedef struct { \
+ SELF##_value *ref; \
+ intptr_t pos; \
+ const SELF* _s; \
+ } SELF##_iter
#define _c_clist_types(SELF, VAL) \
typedef VAL SELF##_value; \
@@ -103,10 +125,9 @@ typedef union {
SELF##_node *last; \
} SELF
-#define _c_chash_types(SELF, KEY, VAL, SZ, MAP_ONLY, SET_ONLY) \
+#define _c_chash_types(SELF, KEY, VAL, MAP_ONLY, SET_ONLY) \
typedef KEY SELF##_key; \
typedef VAL SELF##_mapped; \
- typedef SZ SELF##_ssize; \
\
typedef SET_ONLY( SELF##_key ) \
MAP_ONLY( struct SELF##_value ) \
@@ -115,23 +136,23 @@ typedef union {
typedef struct { \
SELF##_value *ref; \
bool inserted; \
+ uint8_t hashx; \
} SELF##_result; \
\
typedef struct { \
SELF##_value *ref, *_end; \
- uint8_t* _hx; \
+ struct chash_slot* sref; \
} SELF##_iter; \
\
typedef struct SELF { \
- SELF##_value* table; \
- uint8_t* _hashx; \
- SELF##_ssize size, bucket_count; \
+ SELF##_value* data; \
+ struct chash_slot* slot; \
+ intptr_t size, bucket_count; \
} SELF
-#define _c_aatree_types(SELF, KEY, VAL, SZ, MAP_ONLY, SET_ONLY) \
+#define _c_aatree_types(SELF, KEY, VAL, MAP_ONLY, SET_ONLY) \
typedef KEY SELF##_key; \
typedef VAL SELF##_mapped; \
- typedef SZ SELF##_ssize; \
typedef struct SELF##_node SELF##_node; \
\
typedef SET_ONLY( SELF##_key ) \
@@ -147,12 +168,12 @@ typedef union {
SELF##_value *ref; \
SELF##_node *_d; \
int _top; \
- SELF##_ssize _tn, _st[36]; \
+ int32_t _tn, _st[36]; \
} SELF##_iter; \
\
typedef struct SELF { \
SELF##_node *nodes; \
- SELF##_ssize root, disp, head, size, cap; \
+ int32_t root, disp, head, size, cap; \
} SELF
#define _c_cstack_fixed(SELF, VAL, CAP) \
diff --git a/include/stc/priv/cqueue_hdr.h b/include/stc/priv/cqueue_hdr.h
new file mode 100644
index 00000000..06f3bd74
--- /dev/null
+++ b/include/stc/priv/cqueue_hdr.h
@@ -0,0 +1,116 @@
+/* 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); }
+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);
+ }
+#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 _cx_iter _cx_MEMB(_begin)(const _cx_Self* self) {
+ return c_LITERAL(_cx_iter){
+ .ref=_cx_MEMB(_empty)(self) ? NULL : self->data + self->start,
+ .pos=self->start, ._s=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..65711fc0
--- /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_less_unsigned(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 = stc_nextpow2(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/altnames.h b/include/stc/priv/linkage.h
index 723b6a66..7f63f5f1 100644
--- a/include/stc/priv/altnames.h
+++ b/include/stc/priv/linkage.h
@@ -20,15 +20,21 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
-#define c_FORLIST c_forlist
-#define c_FORRANGE c_forrange
-#define c_FOREACH c_foreach
-#define c_FORPAIR c_forpair
-#define c_FORFILTER c_forfilter
-#define c_FORMATCH c_formatch
-#define c_FORTOKEN c_fortoken
-#define c_FORTOKEN_SV c_fortoken_sv
-#define c_AUTO c_auto
-#define c_WITH c_with
-#define c_SCOPE c_scope
-#define c_DEFER c_defer
+#undef STC_API
+#undef STC_DEF
+
+#ifdef i_extern // [deprecated]
+# define i_import
+#endif
+#if !defined(i_static) && !defined(STC_STATIC) && (defined(i_header) || defined(STC_HEADER) || \
+ defined(i_implement) || defined(STC_IMPLEMENT))
+ #define STC_API extern
+ #define STC_DEF
+#else
+ #define i_static
+ #define STC_API static inline
+ #define STC_DEF static inline
+#endif
+#if defined(STC_IMPLEMENT) || defined(i_import)
+ #define i_implement
+#endif
diff --git a/include/stc/priv/raii.h b/include/stc/priv/raii.h
deleted file mode 100644
index bb41e0d1..00000000
--- a/include/stc/priv/raii.h
+++ /dev/null
@@ -1,27 +0,0 @@
-#define c_defer(...) \
- for (int _i = 1; _i; _i = 0, __VA_ARGS__)
-
-#define c_with(...) c_MACRO_OVERLOAD(c_with, __VA_ARGS__)
-#define c_with_2(declvar, drop) \
- for (declvar, *_i, **_ip = &_i; _ip; _ip = 0, drop)
-#define c_with_3(declvar, pred, drop) \
- for (declvar, *_i, **_ip = &_i; _ip && (pred); _ip = 0, drop)
-
-#define c_scope(...) c_MACRO_OVERLOAD(c_scope, __VA_ARGS__)
-#define c_scope_2(init, drop) \
- for (int _i = (init, 1); _i; _i = 0, drop)
-#define c_scope_3(init, pred, drop) \
- for (int _i = (init, 1); _i && (pred); _i = 0, drop)
-
-#define c_auto(...) c_MACRO_OVERLOAD(c_auto, __VA_ARGS__)
-#define c_auto_2(C, a) \
- c_with_2(C a = C##_init(), C##_drop(&a))
-#define c_auto_3(C, a, b) \
- c_with_2(c_EXPAND(C a = C##_init(), b = C##_init()), \
- (C##_drop(&b), C##_drop(&a)))
-#define c_auto_4(C, a, b, c) \
- c_with_2(c_EXPAND(C a = C##_init(), b = C##_init(), c = C##_init()), \
- (C##_drop(&c), C##_drop(&b), C##_drop(&a)))
-#define c_auto_5(C, a, b, c, d) \
- c_with_2(c_EXPAND(C a = C##_init(), b = C##_init(), c = C##_init(), d = C##_init()), \
- (C##_drop(&d), C##_drop(&c), C##_drop(&b), C##_drop(&a)))
diff --git a/include/stc/priv/template.h b/include/stc/priv/template.h
index 16ef51af..38097a35 100644
--- a/include/stc/priv/template.h
+++ b/include/stc/priv/template.h
@@ -20,34 +20,28 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
-#ifdef _i_template
- #error template.h already included
-#endif
+#ifndef _i_template
#define _i_template
#ifndef STC_TEMPLATE_H_INCLUDED
#define STC_TEMPLATE_H_INCLUDED
- #define _cx_self i_type
- #define _cx_memb(name) c_PASTE(_cx_self, name)
- #define _cx_deftypes(macro, SELF, ...) c_EXPAND(macro(SELF, __VA_ARGS__))
- #define _cx_value _cx_memb(_value)
- #define _cx_key _cx_memb(_key)
- #define _cx_mapped _cx_memb(_mapped)
- #define _cx_raw _cx_memb(_raw)
- #define _cx_keyraw _cx_memb(_keyraw)
- #define _cx_iter _cx_memb(_iter)
- #define _cx_result _cx_memb(_result)
- #define _cx_node _cx_memb(_node)
+ #define _cx_Self i_type
+ #define _cx_MEMB(name) c_PASTE(_cx_Self, name)
+ #define _cx_DEFTYPES(macro, SELF, ...) c_EXPAND(macro(SELF, __VA_ARGS__))
+ #define _cx_value _cx_MEMB(_value)
+ #define _cx_key _cx_MEMB(_key)
+ #define _cx_mapped _cx_MEMB(_mapped)
+ #define _cx_raw _cx_MEMB(_raw)
+ #define _cx_keyraw _cx_MEMB(_keyraw)
+ #define _cx_iter _cx_MEMB(_iter)
+ #define _cx_result _cx_MEMB(_result)
+ #define _cx_node _cx_MEMB(_node)
#endif
#ifndef i_type
#define i_type c_PASTE(_i_prefix, i_tag)
#endif
-#ifndef i_ssize
- #define i_ssize intptr_t
-#endif
-
#ifndef i_allocator
#define i_allocator c
#endif
@@ -99,23 +93,22 @@
#if c_option(c_is_forward)
#define i_is_forward
#endif
-#if c_option(c_no_cmp)
- #define i_no_cmp
-#endif
#if c_option(c_no_hash)
#define i_no_hash
#endif
#if c_option(c_no_emplace)
#define i_no_emplace
#endif
-#ifdef i_eq
- #define _i_has_eq
+#if c_option(c_use_cmp) || defined _i_ismap || defined _i_isset || defined _i_ispque
+ #define i_use_cmp
+#endif
+#if c_option(c_no_clone) || defined _i_carc
+ #define i_no_clone
#endif
#if defined i_key_str
#define i_keyclass cstr
- #define i_rawclass crawstr
- #define i_keyfrom cstr_from
+ #define i_rawclass ccharptr
#ifndef i_tag
#define i_tag str
#endif
@@ -131,7 +124,7 @@
#elif defined i_keyboxed
#define i_keyclass i_keyboxed
#define i_rawclass c_PASTE(i_keyboxed, _raw)
- #ifndef i_no_cmp
+ #if defined i_use_cmp
#define i_eq c_PASTE(i_keyboxed, _raw_eq)
#endif
#endif
@@ -142,56 +135,68 @@
#define i_rawclass i_key
#endif
-#ifdef i_keyclass
+#if defined i_keyclass
#define i_key i_keyclass
#ifndef i_keyclone
#define i_keyclone c_PASTE(i_key, _clone)
#endif
- #if !defined i_keyto && defined i_keyraw
- #define i_keyto c_PASTE(i_key, _toraw)
+ #ifndef i_keydrop
+ #define i_keydrop c_PASTE(i_key, _drop)
#endif
#if !defined i_keyfrom && defined i_keyraw
#define i_keyfrom c_PASTE(i_key, _from)
#endif
- #ifndef i_keydrop
- #define i_keydrop c_PASTE(i_key, _drop)
+ #if !defined i_keyto && defined i_keyraw
+ #define i_keyto c_PASTE(i_key, _toraw)
+ #endif
+ #if !defined i_keyraw && (defined i_cmp || defined i_less || defined i_eq || defined i_hash)
+ #define i_use_cmp
#endif
#endif
-#ifdef i_rawclass
- #if !defined i_cmp && !defined i_no_cmp
+#if defined i_rawclass && defined i_use_cmp
+ #if !(defined i_cmp || defined i_less)
#define i_cmp c_PASTE(i_keyraw, _cmp)
#endif
- #if !defined i_hash && !defined i_no_hash
+ #if !(defined i_hash || defined i_no_hash)
#define i_hash c_PASTE(i_keyraw, _hash)
#endif
#endif
+#if defined i_cmp || defined i_less || defined i_use_cmp
+ #define _i_has_cmp
+#endif
+#if defined i_eq || defined i_use_cmp
+ #define _i_has_eq
+#endif
+#if !(defined i_hash || defined i_no_hash)
+ #define i_hash c_default_hash
+#endif
+
#if !defined i_key
#error "No i_key or i_val defined"
#elif defined i_keyraw ^ defined i_keyto
- #error "Both i_keyraw/valraw and i_keyto/valto must be defined, if any"
-#elif defined i_keyfrom && !defined i_keyraw
- #error "i_keyfrom/valfrom defined without i_keyraw/valraw"
+ #error "Both i_keyraw/i_valraw and i_keyto/i_valto must be defined, if any"
+#elif !defined i_no_clone && (defined i_keyclone ^ defined i_keydrop)
+ #error "Both i_keyclone/i_valclone and i_keydrop/i_valdrop must be defined, if any (unless i_no_clone defined)."
#elif defined i_from || defined i_drop
#error "i_from / i_drop not supported. Define i_keyfrom/i_valfrom and/or i_keydrop/i_valdrop instead"
+#elif defined i_keyraw && defined _i_ishash && !(defined i_hash && (defined _i_has_cmp || defined i_eq))
+ #error "For cmap/cset, both i_hash and i_eq (or i_less or i_cmp) must be defined when i_keyraw is defined."
+#elif defined i_keyraw && defined i_use_cmp && !defined _i_has_cmp
+ #error "For csmap/csset/cpque, i_cmp or i_less must be defined when i_keyraw is defined."
#endif
#ifndef i_tag
#define i_tag i_key
#endif
-#if c_option(c_no_clone)
- #define i_no_clone
-#elif !(defined i_keyclone || defined i_no_clone) && (defined i_keydrop || defined i_keyraw)
- #error i_keyclone/valclone should be defined when i_keydrop/valdrop or i_keyraw/valraw is defined
-#endif
#ifndef i_keyraw
#define i_keyraw i_key
#endif
#ifndef i_keyfrom
#define i_keyfrom c_default_clone
#else
- #define _i_has_from
+ #define i_has_emplace
#endif
#ifndef i_keyto
#define i_keyto c_default_toraw
@@ -204,32 +209,27 @@
#endif
// i_eq, i_less, i_cmp
-#if !defined i_eq && (defined i_cmp || defined i_less)
+#if !defined i_eq && defined i_cmp
#define i_eq(x, y) !(i_cmp(x, y))
#elif !defined i_eq
- #define i_eq c_default_eq
+ #define i_eq(x, y) *x == *y
#endif
-#if defined i_less && defined i_cmp
- #error "Only one of i_less and i_cmp may be defined"
-#elif !defined i_less && !defined i_cmp
- #define i_less c_default_less
-#elif !defined i_less
+#if defined i_cmp && defined i_less
+ #error "Only one of i_cmp and i_less may be defined"
+#elif defined i_cmp
#define i_less(x, y) (i_cmp(x, y)) < 0
+#elif !defined i_less
+ #define i_less(x, y) *x < *y
#endif
#ifndef i_cmp
#define i_cmp(x, y) (i_less(y, x)) - (i_less(x, y))
#endif
-#ifndef i_hash
- #define i_hash c_default_hash
-#endif
-
#if defined _i_ismap // ---- process cmap/csmap value i_val, ... ----
#ifdef i_val_str
#define i_valclass cstr
- #define i_valraw crawstr
- #define i_valfrom cstr_from
+ #define i_valraw const char*
#elif defined i_val_ssv
#define i_valclass cstr
#define i_valraw csview
@@ -245,31 +245,32 @@
#ifndef i_valclone
#define i_valclone c_PASTE(i_val, _clone)
#endif
- #if !defined i_valto && defined i_valraw
- #define i_valto c_PASTE(i_val, _toraw)
+ #ifndef i_valdrop
+ #define i_valdrop c_PASTE(i_val, _drop)
#endif
#if !defined i_valfrom && defined i_valraw
#define i_valfrom c_PASTE(i_val, _from)
#endif
- #ifndef i_valdrop
- #define i_valdrop c_PASTE(i_val, _drop)
+ #if !defined i_valto && defined i_valraw
+ #define i_valto c_PASTE(i_val, _toraw)
#endif
#endif
#ifndef i_val
#error "i_val* must be defined for maps"
+#elif defined i_valraw ^ defined i_valto
+ #error "Both i_valraw and i_valto must be defined, if any"
+#elif !defined i_no_clone && (defined i_valclone ^ defined i_valdrop)
+ #error "Both i_valclone and i_valdrop must be defined, if any"
#endif
-#if !(defined i_valclone || defined i_no_clone) && (defined i_valdrop || defined i_valraw)
- #error i_valclone should be defined when i_valdrop or i_valraw is defined
-#endif
#ifndef i_valraw
#define i_valraw i_val
#endif
#ifndef i_valfrom
#define i_valfrom c_default_clone
#else
- #define _i_has_from
+ #define i_has_emplace
#endif
#ifndef i_valto
#define i_valto c_default_toraw
@@ -289,6 +290,7 @@
#ifndef i_valraw
#define i_valraw i_keyraw
#endif
-#ifndef _i_has_from
+#ifndef i_has_emplace
#define i_no_emplace
#endif
+#endif
diff --git a/include/stc/priv/template2.h b/include/stc/priv/template2.h
index 27c6a890..44254601 100644
--- a/include/stc/priv/template2.h
+++ b/include/stc/priv/template2.h
@@ -20,6 +20,9 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
+#ifdef i_more
+#undef i_more
+#else
#undef i_type
#undef i_tag
#undef i_imp
@@ -30,7 +33,6 @@
#undef i_hash
#undef i_rawclass
#undef i_capacity
-#undef i_ssize
#undef i_val
#undef i_val_str
@@ -57,7 +59,7 @@
#undef i_header
#undef i_implement
#undef i_static
-#undef i_extern
+#undef i_import
#undef i_allocator
#undef i_malloc
@@ -65,14 +67,16 @@
#undef i_realloc
#undef i_free
-#undef i_no_cmp
+#undef i_use_cmp
#undef i_no_hash
#undef i_no_clone
#undef i_no_emplace
#undef i_is_forward
+#undef i_has_emplace
+#undef _i_has_cmp
+#undef _i_has_eq
#undef _i_prefix
#undef _i_expandby
-#undef _i_has_from
-#undef _i_has_eq
#undef _i_template
+#endif
diff --git a/include/stc/utf8.h b/include/stc/utf8.h
index a4cc3846..6d12856f 100644
--- a/include/stc/utf8.h
+++ b/include/stc/utf8.h
@@ -1,11 +1,34 @@
+/* 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 "priv/linkage.h"
+
#ifndef UTF8_H_INCLUDED
#define UTF8_H_INCLUDED
+#include "ccommon.h"
#include <ctype.h>
#include "forward.h"
-#include "ccommon.h"
-// utf8 methods defined in src/utf8code.c:
enum {
U8G_Cc, U8G_Lt, U8G_Nd, U8G_Nl,
U8G_Pc, U8G_Pd, U8G_Pf, U8G_Pi,
@@ -16,6 +39,7 @@ enum {
U8G_SIZE
};
+// utf8 methods defined in src/utf8code.c:
extern bool utf8_isgroup(int group, uint32_t c);
extern bool utf8_isalpha(uint32_t c);
extern uint32_t utf8_casefold(uint32_t c);
@@ -51,9 +75,9 @@ STC_INLINE bool utf8_isspace(uint32_t c) {
/* decode next utf8 codepoint. https://bjoern.hoehrmann.de/utf-8/decoder/dfa */
typedef struct { uint32_t state, codep; } utf8_decode_t;
+extern const uint8_t utf8_dtab[]; /* utf8code.c */
STC_INLINE uint32_t utf8_decode(utf8_decode_t* d, const uint32_t byte) {
- extern const uint8_t utf8_dtab[]; /* utf8code.c */
const uint32_t type = utf8_dtab[byte];
d->codep = d->state ? (byte & 0x3fu) | (d->codep << 6)
: (0xffU >> type) & byte;
@@ -112,9 +136,16 @@ STC_INLINE const char* utf8_at(const char *s, intptr_t index) {
STC_INLINE intptr_t utf8_pos(const char* s, intptr_t index)
{ return (intptr_t)(utf8_at(s, index) - s); }
-
#endif // UTF8_H_INCLUDED
-#if defined(i_extern)
+
+#if defined i_import || (defined i_implement && !defined _i_inc_utf8)
# include "../../src/utf8code.c"
-# undef i_extern
#endif
+#ifndef _i_inc_utf8
+#undef i_static
+#undef i_header
+#undef i_implement
+#undef i_import
+#undef i_opt
+#endif
+#undef _i_inc_utf8