From eb85069b669e754836b9d4587ba03d3af1a5e975 Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Sun, 26 Mar 2023 00:27:45 +0100 Subject: development branch for 4.2 Removed uses of c_auto and c_with in documentation examples and code examples. Still using c_defer a few places. Renamed c11/fmt.h to c11/print.h. Some additions in ccommon.h, e.g. c_const_cast(T, x). Improved docs. --- include/c11/fmt.h | 272 ------------------------------------------------ include/c11/print.h | 272 ++++++++++++++++++++++++++++++++++++++++++++++++ include/stc/ccommon.h | 29 ++---- include/stc/priv/raii.h | 27 +++++ 4 files changed, 306 insertions(+), 294 deletions(-) delete mode 100644 include/c11/fmt.h create mode 100644 include/c11/print.h create mode 100644 include/stc/priv/raii.h (limited to 'include') diff --git a/include/c11/fmt.h b/include/c11/fmt.h deleted file mode 100644 index 193520b1..00000000 --- a/include/c11/fmt.h +++ /dev/null @@ -1,272 +0,0 @@ -#ifndef FMT_H_INCLUDED -#define FMT_H_INCLUDED -/* -VER 2.0: NEW API: - -void fmt_print(fmt, ...); -void fmt_println(fmt, ...); -void fmt_printd(dest, fmt, ...); -void fmt_destroy(fmt_buffer* buf); - - 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 - format string - {} 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 %). - -* 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. -* (c) operamint, 2022, MIT License. ------------------------------------------------------------------------------------ -#include "c11/fmt.h" - -int main() { - const double pi = 3.141592653589793; - const size_t x = 1234567890; - const char* string = "Hello world"; - const wchar_t* wstr = L"The whole"; - const char z = 'z'; - _Bool flag = 1; - unsigned char r = 123, g = 214, b = 90, w = 110; - char buffer[64]; - - fmt_print("Color: ({} {} {}), {}\n", r, g, b, flag); - fmt_println("Wide: {}, {}", wstr, L"wide world"); - fmt_println("{:10} {:10} {:10.2f}", 42ull, 43, pi); - fmt_println("{:>10} {:>10} {:>10}", z, z, w); - fmt_printd(stdout, "{:10} {:10} {:10}\n", "Hello", "Mad", "World"); - fmt_printd(stderr, "100%: {:<20} {:.*} {}\n", string, 4, pi, x); - fmt_printd(buffer, "Precision: {} {:.10} {}", string, pi, x); - fmt_println("{}", buffer); - fmt_println("Vector: ({}, {}, {})", 3.2, 3.3, pi); - - fmt_buffer out[1] = {{.stream=1}}; - fmt_printd(out, "{} {}", "Pi is:", pi); - fmt_print("{}, len={}, cap={}\n", out->data, out->len, out->cap); - fmt_printd(out, "{} {}", ", Pi squared is:", pi*pi); - fmt_print("{}, len={}, cap={}\n", out->data, out->len, out->cap); - fmt_destroy(out); -} -*/ -#include -#include -#include - -#define fmt_OVERLOAD(name, ...) \ - fmt_JOIN(name, fmt_NUMARGS(__VA_ARGS__))(__VA_ARGS__) -#define fmt_CONCAT(a, b) a ## b -#define fmt_JOIN(a, b) fmt_CONCAT(a, b) -#define fmt_EXPAND(...) __VA_ARGS__ -#define fmt_NUMARGS(...) _fmt_APPLY_ARG_N((__VA_ARGS__, _fmt_RSEQ_N)) - -#define _fmt_APPLY_ARG_N(args) fmt_EXPAND(_fmt_ARG_N args) -#define _fmt_RSEQ_N 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 -#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 -# define fmt_OK(exp) (void)(exp) -#else -# define fmt_OK(exp) assert(exp) -#endif - -typedef struct { - char* data; - intptr_t cap, len; - _Bool stream; -} fmt_buffer; - -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, ...); - -#ifndef FMT_MAX -#define FMT_MAX 256 -#endif - -#ifndef FMT_NOSHORTS -#define print(...) fmt_printd(stdout, __VA_ARGS__) -#define println(...) fmt_printd((fmt_buffer*)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_printd(...) fmt_OVERLOAD(fmt_printd, __VA_ARGS__) - -/* Primary function. */ -#define fmt_printd2(to, fmt) \ - do { char _fs[FMT_MAX]; int _n = _fmt_parse(_fs, 0, fmt); \ - fmt_OK(_n == 0); _fmt_fn(to)(to, fmt); } while (0) -#define fmt_printd3(to, fmt, c) \ - do { char _fs[FMT_MAX]; int _n = _fmt_parse(_fs, 1, fmt, _fc(c)); \ - fmt_OK(_n == 1); _fmt_fn(to)(to, _fs, c); } while (0) -#define fmt_printd4(to, fmt, c, d) \ - do { char _fs[FMT_MAX]; int _n = _fmt_parse(_fs, 2, fmt, _fc(c), _fc(d)); \ - fmt_OK(_n == 2); _fmt_fn(to)(to, _fs, c, d); } while (0) -#define fmt_printd5(to, fmt, c, d, e) \ - do { char _fs[FMT_MAX]; int _n = _fmt_parse(_fs, 3, fmt, _fc(c), _fc(d), _fc(e)); \ - fmt_OK(_n == 3); _fmt_fn(to)(to, _fs, c, d, e); } while (0) -#define fmt_printd6(to, fmt, c, d, e, f) \ - do { char _fs[FMT_MAX]; int _n = _fmt_parse(_fs, 4, fmt, _fc(c), _fc(d), _fc(e), _fc(f)); \ - fmt_OK(_n == 4); _fmt_fn(to)(to, _fs, c, d, e, f); } while (0) -#define fmt_printd7(to, fmt, c, d, e, f, g) \ - do { char _fs[FMT_MAX]; int _n = _fmt_parse(_fs, 5, fmt, _fc(c), _fc(d), _fc(e), _fc(f), _fc(g)); \ - fmt_OK(_n == 5); _fmt_fn(to)(to, _fs, c, d, e, f, g); } while (0) -#define fmt_printd8(to, fmt, c, d, e, f, g, h) \ - do { char _fs[FMT_MAX]; int _n = _fmt_parse(_fs, 6, fmt, _fc(c), _fc(d), _fc(e), _fc(f), _fc(g), _fc(h)); \ - fmt_OK(_n == 6); _fmt_fn(to)(to, _fs, c, d, e, f, g, h); } while (0) -#define fmt_printd9(to, fmt, c, d, e, f, g, h, i) \ - do { char _fs[FMT_MAX]; int _n = _fmt_parse(_fs, 7, fmt, _fc(c), _fc(d), _fc(e), _fc(f), _fc(g), _fc(h), _fc(i)); \ - fmt_OK(_n == 7); _fmt_fn(to)(to, _fs, c, d, e, f, g, h, i); } while (0) -#define fmt_printd10(to, fmt, c, d, e, f, g, h, i, j) \ - do { char _fs[FMT_MAX]; int _n = _fmt_parse(_fs, 8, fmt, _fc(c), _fc(d), _fc(e), _fc(f), _fc(g), _fc(h), \ - _fc(i), _fc(j)); \ - fmt_OK(_n == 8); _fmt_fn(to)(to, _fs, c, d, e, f, g, h, i, j); } while (0) -#define fmt_printd11(to, fmt, c, d, e, f, g, h, i, j, k) \ - do { char _fs[FMT_MAX]; int _n = _fmt_parse(_fs, 9, fmt, _fc(c), _fc(d), _fc(e), _fc(f), _fc(g), _fc(h), \ - _fc(i), _fc(j), _fc(k)); \ - fmt_OK(_n == 9); _fmt_fn(to)(to, _fs, c, d, e, f, g, h, i, j, k); } while (0) -#define fmt_printd12(to, fmt, c, d, e, f, g, h, i, j, k, m) \ - do { char _fs[FMT_MAX]; int _n = _fmt_parse(_fs, 10, fmt, _fc(c), _fc(d), _fc(e), _fc(f), _fc(g), _fc(h), \ - _fc(i), _fc(j), _fc(k), _fc(m)); \ - fmt_OK(_n == 10); _fmt_fn(to)(to, _fs, c, d, e, f, g, h, i, j, k, m); } while (0) -#define fmt_printd13(to, fmt, c, d, e, f, g, h, i, j, k, m, n) \ - do { char _fs[FMT_MAX]; int _n = _fmt_parse(_fs, 11, fmt, _fc(c), _fc(d), _fc(e), _fc(f), _fc(g), _fc(h), \ - _fc(i), _fc(j), _fc(k), _fc(m), _fc(n)); \ - fmt_OK(_n == 11); _fmt_fn(to)(to, _fs, c, d, e, f, g, h, i, j, k, m, n); } while (0) -#define fmt_printd14(to, fmt, c, d, e, f, g, h, i, j, k, m, n, o) \ - do { char _fs[FMT_MAX]; int _n = _fmt_parse(_fs, 12, fmt, _fc(c), _fc(d), _fc(e), _fc(f), _fc(g), _fc(h), \ - _fc(i), _fc(j), _fc(k), _fc(m), _fc(n), _fc(o)); \ - fmt_OK(_n == 12); _fmt_fn(to)(to, _fs, c, d, e, f, g, h, i, j, k, m, n, o); } while (0) - -#define _fmt_fn(x) _Generic ((x), \ - FILE*: fprintf, \ - char*: sprintf, \ - fmt_buffer*: _fmt_bprint) - -#if defined(_MSC_VER) && !defined(__clang__) -# define _signed_char_hhd -#else -# define _signed_char_hhd signed char: "hhd", -#endif - -#define _fc(x) _Generic (x, \ - _Bool: "d", \ - unsigned char: "hhu", \ - _signed_char_hhd \ - char: "c", \ - short: "hd", \ - unsigned short: "hu", \ - int: "d", \ - unsigned: "u", \ - long: "ld", \ - unsigned long: "lu", \ - long long: "lld", \ - unsigned long long: "llu", \ - float: "g", \ - double: "@g", \ - long double: "@Lg", \ - char*: "s", \ - wchar_t*: "ls", \ - void*: "p", \ - const char*: "s", \ - const wchar_t*: "ls", \ - const void*: "p") - -#if defined FMT_IMPLEMENT || !(defined FMT_HEADER || defined FMT_IMPLEMENT) - -#include -#include -#include - -FMT_API void fmt_destroy(fmt_buffer* buf) { - free(buf->data); -} - -FMT_API void _fmt_bprint(fmt_buffer* buf, const char* fmt, ...) { - va_list args, args2; - va_start(args, fmt); - if (buf == 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); - } - vsprintf(buf->data + pos, fmt, args2); - done2: va_end(args2); - done1: va_end(args); -} - -FMT_API int _fmt_parse(char* p, int nargs, const char *fmt, ...) { - char *arg, *p0, ch; - int n = 0, empty; - va_list args; - va_start(args, fmt); - do { - switch ((ch = *fmt)) { - case '%': - *p++ = '%'; - break; - case '}': - if (*++fmt == '}') break; /* ok */ - n = 99; - continue; - case '{': - if (*++fmt == '{') break; /* ok */ - if (++n > nargs) continue; - if (*fmt != ':' && *fmt != '}') n = 99; - fmt += (*fmt == ':'); - empty = *fmt == '}'; - arg = va_arg(args, char *); - *p++ = '%', p0 = p; - while (1) switch (*fmt) { - case '\0': n = 99; /* nobreak */ - case '}': goto done; - case '<': *p++ = '-', ++fmt; break; - case '>': p0 = NULL; /* nobreak */ - case '-': ++fmt; break; - case '*': if (++n <= nargs) arg = va_arg(args, char *); /* nobreak */ - default: *p++ = *fmt++; - } - done: - switch (*arg) { - case 'g': if (empty) memcpy(p, ".8", 2), p += 2; break; - case '@': ++arg; if (empty) memcpy(p, ".16", 3), p += 3; break; - } - if (!strchr("csdioxXufFeEaAgGnp", fmt[-1])) - while (*arg) *p++ = *arg++; - if (p0 && (p[-1] == 's' || p[-1] == 'c')) /* left-align str */ - memmove(p0 + 1, p0, (size_t)(p++ - p0)), *p0 = '-'; - fmt += *fmt == '}'; - continue; - } - *p++ = *fmt++; - } while (ch); - va_end(args); - return n; -} -#endif -#endif diff --git a/include/c11/print.h b/include/c11/print.h new file mode 100644 index 00000000..1302d9cc --- /dev/null +++ b/include/c11/print.h @@ -0,0 +1,272 @@ +#ifndef FMT_H_INCLUDED +#define FMT_H_INCLUDED +/* +VER 2.0: NEW API: + +void fmt_print(fmt, ...); +void fmt_println(fmt, ...); +void fmt_printd(dest, fmt, ...); +void fmt_destroy(fmt_buffer* buf); + + 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 - format string + {} 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 %). + +* 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. +* (c) operamint, 2022, MIT License. +----------------------------------------------------------------------------------- +#include "c11/print.h" + +int main() { + const double pi = 3.141592653589793; + const size_t x = 1234567890; + const char* string = "Hello world"; + const wchar_t* wstr = L"The whole"; + const char z = 'z'; + _Bool flag = 1; + unsigned char r = 123, g = 214, b = 90, w = 110; + char buffer[64]; + + fmt_print("Color: ({} {} {}), {}\n", r, g, b, flag); + fmt_println("Wide: {}, {}", wstr, L"wide world"); + fmt_println("{:10} {:10} {:10.2f}", 42ull, 43, pi); + fmt_println("{:>10} {:>10} {:>10}", z, z, w); + fmt_printd(stdout, "{:10} {:10} {:10}\n", "Hello", "Mad", "World"); + fmt_printd(stderr, "100%: {:<20} {:.*} {}\n", string, 4, pi, x); + fmt_printd(buffer, "Precision: {} {:.10} {}", string, pi, x); + fmt_println("{}", buffer); + fmt_println("Vector: ({}, {}, {})", 3.2, 3.3, pi); + + fmt_buffer out[1] = {{.stream=1}}; + fmt_printd(out, "{} {}", "Pi is:", pi); + fmt_print("{}, len={}, cap={}\n", out->data, out->len, out->cap); + fmt_printd(out, "{} {}", ", Pi squared is:", pi*pi); + fmt_print("{}, len={}, cap={}\n", out->data, out->len, out->cap); + fmt_destroy(out); +} +*/ +#include +#include +#include + +#define fmt_OVERLOAD(name, ...) \ + fmt_JOIN(name, fmt_NUMARGS(__VA_ARGS__))(__VA_ARGS__) +#define fmt_CONCAT(a, b) a ## b +#define fmt_JOIN(a, b) fmt_CONCAT(a, b) +#define fmt_EXPAND(...) __VA_ARGS__ +#define fmt_NUMARGS(...) _fmt_APPLY_ARG_N((__VA_ARGS__, _fmt_RSEQ_N)) + +#define _fmt_APPLY_ARG_N(args) fmt_EXPAND(_fmt_ARG_N args) +#define _fmt_RSEQ_N 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 +#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 +# define fmt_OK(exp) (void)(exp) +#else +# define fmt_OK(exp) assert(exp) +#endif + +typedef struct { + char* data; + intptr_t cap, len; + _Bool stream; +} fmt_buffer; + +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, ...); + +#ifndef FMT_MAX +#define FMT_MAX 256 +#endif + +#ifndef FMT_NOSHORTS +#define print(...) fmt_printd(stdout, __VA_ARGS__) +#define println(...) fmt_printd((fmt_buffer*)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_printd(...) fmt_OVERLOAD(fmt_printd, __VA_ARGS__) + +/* Primary function. */ +#define fmt_printd2(to, fmt) \ + do { char _fs[FMT_MAX]; int _n = _fmt_parse(_fs, 0, fmt); \ + fmt_OK(_n == 0); _fmt_fn(to)(to, fmt); } while (0) +#define fmt_printd3(to, fmt, c) \ + do { char _fs[FMT_MAX]; int _n = _fmt_parse(_fs, 1, fmt, _fc(c)); \ + fmt_OK(_n == 1); _fmt_fn(to)(to, _fs, c); } while (0) +#define fmt_printd4(to, fmt, c, d) \ + do { char _fs[FMT_MAX]; int _n = _fmt_parse(_fs, 2, fmt, _fc(c), _fc(d)); \ + fmt_OK(_n == 2); _fmt_fn(to)(to, _fs, c, d); } while (0) +#define fmt_printd5(to, fmt, c, d, e) \ + do { char _fs[FMT_MAX]; int _n = _fmt_parse(_fs, 3, fmt, _fc(c), _fc(d), _fc(e)); \ + fmt_OK(_n == 3); _fmt_fn(to)(to, _fs, c, d, e); } while (0) +#define fmt_printd6(to, fmt, c, d, e, f) \ + do { char _fs[FMT_MAX]; int _n = _fmt_parse(_fs, 4, fmt, _fc(c), _fc(d), _fc(e), _fc(f)); \ + fmt_OK(_n == 4); _fmt_fn(to)(to, _fs, c, d, e, f); } while (0) +#define fmt_printd7(to, fmt, c, d, e, f, g) \ + do { char _fs[FMT_MAX]; int _n = _fmt_parse(_fs, 5, fmt, _fc(c), _fc(d), _fc(e), _fc(f), _fc(g)); \ + fmt_OK(_n == 5); _fmt_fn(to)(to, _fs, c, d, e, f, g); } while (0) +#define fmt_printd8(to, fmt, c, d, e, f, g, h) \ + do { char _fs[FMT_MAX]; int _n = _fmt_parse(_fs, 6, fmt, _fc(c), _fc(d), _fc(e), _fc(f), _fc(g), _fc(h)); \ + fmt_OK(_n == 6); _fmt_fn(to)(to, _fs, c, d, e, f, g, h); } while (0) +#define fmt_printd9(to, fmt, c, d, e, f, g, h, i) \ + do { char _fs[FMT_MAX]; int _n = _fmt_parse(_fs, 7, fmt, _fc(c), _fc(d), _fc(e), _fc(f), _fc(g), _fc(h), _fc(i)); \ + fmt_OK(_n == 7); _fmt_fn(to)(to, _fs, c, d, e, f, g, h, i); } while (0) +#define fmt_printd10(to, fmt, c, d, e, f, g, h, i, j) \ + do { char _fs[FMT_MAX]; int _n = _fmt_parse(_fs, 8, fmt, _fc(c), _fc(d), _fc(e), _fc(f), _fc(g), _fc(h), \ + _fc(i), _fc(j)); \ + fmt_OK(_n == 8); _fmt_fn(to)(to, _fs, c, d, e, f, g, h, i, j); } while (0) +#define fmt_printd11(to, fmt, c, d, e, f, g, h, i, j, k) \ + do { char _fs[FMT_MAX]; int _n = _fmt_parse(_fs, 9, fmt, _fc(c), _fc(d), _fc(e), _fc(f), _fc(g), _fc(h), \ + _fc(i), _fc(j), _fc(k)); \ + fmt_OK(_n == 9); _fmt_fn(to)(to, _fs, c, d, e, f, g, h, i, j, k); } while (0) +#define fmt_printd12(to, fmt, c, d, e, f, g, h, i, j, k, m) \ + do { char _fs[FMT_MAX]; int _n = _fmt_parse(_fs, 10, fmt, _fc(c), _fc(d), _fc(e), _fc(f), _fc(g), _fc(h), \ + _fc(i), _fc(j), _fc(k), _fc(m)); \ + fmt_OK(_n == 10); _fmt_fn(to)(to, _fs, c, d, e, f, g, h, i, j, k, m); } while (0) +#define fmt_printd13(to, fmt, c, d, e, f, g, h, i, j, k, m, n) \ + do { char _fs[FMT_MAX]; int _n = _fmt_parse(_fs, 11, fmt, _fc(c), _fc(d), _fc(e), _fc(f), _fc(g), _fc(h), \ + _fc(i), _fc(j), _fc(k), _fc(m), _fc(n)); \ + fmt_OK(_n == 11); _fmt_fn(to)(to, _fs, c, d, e, f, g, h, i, j, k, m, n); } while (0) +#define fmt_printd14(to, fmt, c, d, e, f, g, h, i, j, k, m, n, o) \ + do { char _fs[FMT_MAX]; int _n = _fmt_parse(_fs, 12, fmt, _fc(c), _fc(d), _fc(e), _fc(f), _fc(g), _fc(h), \ + _fc(i), _fc(j), _fc(k), _fc(m), _fc(n), _fc(o)); \ + fmt_OK(_n == 12); _fmt_fn(to)(to, _fs, c, d, e, f, g, h, i, j, k, m, n, o); } while (0) + +#define _fmt_fn(x) _Generic ((x), \ + FILE*: fprintf, \ + char*: sprintf, \ + fmt_buffer*: _fmt_bprint) + +#if defined(_MSC_VER) && !defined(__clang__) +# define _signed_char_hhd +#else +# define _signed_char_hhd signed char: "hhd", +#endif + +#define _fc(x) _Generic (x, \ + _Bool: "d", \ + unsigned char: "hhu", \ + _signed_char_hhd \ + char: "c", \ + short: "hd", \ + unsigned short: "hu", \ + int: "d", \ + unsigned: "u", \ + long: "ld", \ + unsigned long: "lu", \ + long long: "lld", \ + unsigned long long: "llu", \ + float: "g", \ + double: "@g", \ + long double: "@Lg", \ + char*: "s", \ + wchar_t*: "ls", \ + void*: "p", \ + const char*: "s", \ + const wchar_t*: "ls", \ + const void*: "p") + +#if defined FMT_IMPLEMENT || !(defined FMT_HEADER || defined FMT_IMPLEMENT) + +#include +#include +#include + +FMT_API void fmt_destroy(fmt_buffer* buf) { + free(buf->data); +} + +FMT_API void _fmt_bprint(fmt_buffer* buf, const char* fmt, ...) { + va_list args, args2; + va_start(args, fmt); + if (buf == 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); + } + vsprintf(buf->data + pos, fmt, args2); + done2: va_end(args2); + done1: va_end(args); +} + +FMT_API int _fmt_parse(char* p, int nargs, const char *fmt, ...) { + char *arg, *p0, ch; + int n = 0, empty; + va_list args; + va_start(args, fmt); + do { + switch ((ch = *fmt)) { + case '%': + *p++ = '%'; + break; + case '}': + if (*++fmt == '}') break; /* ok */ + n = 99; + continue; + case '{': + if (*++fmt == '{') break; /* ok */ + if (++n > nargs) continue; + if (*fmt != ':' && *fmt != '}') n = 99; + fmt += (*fmt == ':'); + empty = *fmt == '}'; + arg = va_arg(args, char *); + *p++ = '%', p0 = p; + while (1) switch (*fmt) { + case '\0': n = 99; /* nobreak */ + case '}': goto done; + case '<': *p++ = '-', ++fmt; break; + case '>': p0 = NULL; /* nobreak */ + case '-': ++fmt; break; + case '*': if (++n <= nargs) arg = va_arg(args, char *); /* nobreak */ + default: *p++ = *fmt++; + } + done: + switch (*arg) { + case 'g': if (empty) memcpy(p, ".8", 2), p += 2; break; + case '@': ++arg; if (empty) memcpy(p, ".16", 3), p += 3; break; + } + if (!strchr("csdioxXufFeEaAgGnp", fmt[-1])) + while (*arg) *p++ = *arg++; + if (p0 && (p[-1] == 's' || p[-1] == 'c')) /* left-align str */ + memmove(p0 + 1, p0, (size_t)(p++ - p0)), *p0 = '-'; + fmt += *fmt == '}'; + continue; + } + *p++ = *fmt++; + } while (ch); + va_end(args); + return n; +} +#endif +#endif diff --git a/include/stc/ccommon.h b/include/stc/ccommon.h index b822b9f8..5e163875 100644 --- a/include/stc/ccommon.h +++ b/include/stc/ccommon.h @@ -30,6 +30,7 @@ #include #include #include "priv/altnames.h" +#include "priv/raii.h" #define c_NPOS INTPTR_MAX #define c_ZI PRIiPTR @@ -81,7 +82,8 @@ #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_container_of(p, T, m) ((T*)((char*)(p) + 0*sizeof((p) == &((T*)0)->m) - offsetof(T, m))) +#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_swap(T, xp, yp) do { T *_xp = xp, *_yp = yp, \ _tv = *_xp; *_xp = *_yp; *_yp = _tv; } while (0) #define c_sizeof (intptr_t)sizeof @@ -123,7 +125,10 @@ #define c_arraylen(a) (intptr_t)(sizeof(a)/sizeof 0[a]) #define c_litstrlen(literal) (c_sizeof("" literal) - 1) +// 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)) @@ -132,7 +137,6 @@ typedef const char* crawstr; #define c_sv_2(str, n) (c_LITERAL(csview){str, n}) #define c_SV(sv) (int)(sv).size, (sv).str // print csview: use format "%.*s" -#define c_PAIR(ref) (ref)->first, (ref)->second #define c_ROTL(x, k) (x << (k) | x >> (8*sizeof(x) - (k))) STC_INLINE uint64_t cfasthash(const void* key, intptr_t len) { @@ -195,6 +199,7 @@ STC_INLINE char* cstrnstrn(const char *str, const char *needle, #define c_forrange_4(i, start, stop, step) \ for (long long i=start, _inc=step, _end=(long long)(stop) - (_inc > 0) \ ; (_inc > 0) ^ (i > _end); i += _inc) + #ifndef __cplusplus #define c_forlist(it, T, ...) \ for (struct {T* ref; int size, index;} \ @@ -207,26 +212,6 @@ STC_INLINE char* cstrnstrn(const char *str, const char *needle, it = {._il=__VA_ARGS__, .data=it._il.begin(), .ref=it.data, .size=it._il.size()} \ ; it.index < it.size; ++it.ref, ++it.index) #endif -#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_defer(...) for (int _i = 1; _i; _i = 0, __VA_ARGS__) - -#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))) #define c_drop(C, ...) \ do { c_forlist (_i, C*, {__VA_ARGS__}) C##_drop(*_i.ref); } while(0) diff --git a/include/stc/priv/raii.h b/include/stc/priv/raii.h new file mode 100644 index 00000000..bb41e0d1 --- /dev/null +++ b/include/stc/priv/raii.h @@ -0,0 +1,27 @@ +#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))) -- cgit v1.2.3 From ede39bc98a758674485796174ea860515ec281e6 Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Sun, 26 Mar 2023 22:33:45 +0200 Subject: Remove more c_with, c_auto --- include/stc/algo/filter.h | 30 +++++++-------- include/stc/cbits.h | 40 +++++++++---------- include/stc/cmap.h | 28 +++++++------- include/stc/csmap.h | 28 +++++++------- misc/examples/books.c | 97 +++++++++++++++++++++++------------------------ misc/examples/splitstr.c | 8 ++-- misc/tests/cregex_test.c | 25 ++++++------ src/checkauto.l | 6 +-- 8 files changed, 130 insertions(+), 132 deletions(-) (limited to 'include') diff --git a/include/stc/algo/filter.h b/include/stc/algo/filter.h index 7729799f..111d3273 100644 --- a/include/stc/algo/filter.h +++ b/include/stc/algo/filter.h @@ -24,24 +24,24 @@ #include #define i_val int #include -#include +#include int main() { - c_with (cstack_int stk = c_make(cstack_int, {1, 2, 3, 4, 5, 6, 7, 8, 9}), - cstack_int_drop(&stk)) - { - c_foreach (i, cstack_int, stk) - printf(" %d", *i.ref); - puts(""); - - c_forfilter (i, cstack_int, stk, - c_flt_skipwhile(i, *i.ref < 3) && - (*i.ref & 1) == 0 && // even only - c_flt_take(i, 2)) // break after 2 - printf(" %d", *i.ref); - puts(""); - } + cstack_int stk = c_make(cstack_int, {1, 2, 3, 4, 5, 6, 7, 8, 9}); + + c_foreach (i, cstack_int, stk) + printf(" %d", *i.ref); + puts(""); + + c_forfilter (i, cstack_int, stk, + c_flt_skipwhile(i, *i.ref < 3) && + (*i.ref & 1) == 0 && // even only + c_flt_take(i, 2)) // break after 2 + printf(" %d", *i.ref); + puts(""); + + cstack_int_drop(&stk); } */ #ifndef STC_FILTER_H_INCLUDED diff --git a/include/stc/cbits.h b/include/stc/cbits.h index fa0da665..826df847 100644 --- a/include/stc/cbits.h +++ b/include/stc/cbits.h @@ -27,26 +27,26 @@ Similar to boost::dynamic_bitset / std::bitset #include "cbits.h" int main() { - c_with (cbits bset = cbits_with_size(23, true), cbits_drop(&bset)) - { - cbits_reset(&bset, 9); - cbits_resize(&bset, 43, false); - - printf("%4zu: ", cbits_size(&bset)); - c_forrange (i, cbits_size(&bset)) - printf("%d", cbits_at(&bset, i)); - puts(""); - cbits_set(&bset, 28); - cbits_resize(&bset, 77, true); - cbits_resize(&bset, 93, false); - cbits_resize(&bset, 102, true); - cbits_set_value(&bset, 99, false); - - printf("%4zu: ", cbits_size(&bset)); - c_forrange (i, cbits_size(&bset)) - printf("%d", cbits_at(&bset, i)); - puts(""); - } + cbits bset = cbits_with_size(23, true); + cbits_reset(&bset, 9); + cbits_resize(&bset, 43, false); + + printf("%4zu: ", cbits_size(&bset)); + c_forrange (i, cbits_size(&bset)) + printf("%d", cbits_at(&bset, i)); + puts(""); + cbits_set(&bset, 28); + cbits_resize(&bset, 77, true); + cbits_resize(&bset, 93, false); + cbits_resize(&bset, 102, true); + cbits_set_value(&bset, 99, false); + + printf("%4zu: ", cbits_size(&bset)); + c_forrange (i, cbits_size(&bset)) + printf("%d", cbits_at(&bset, i)); + puts(""); + + cbits_drop(&bset); } */ #ifndef CBITS_H_INCLUDED diff --git a/include/stc/cmap.h b/include/stc/cmap.h index d9081ae0..402038cb 100644 --- a/include/stc/cmap.h +++ b/include/stc/cmap.h @@ -31,20 +31,20 @@ #include int main(void) { - c_with (cmap_ichar m = cmap_ichar_init(), cmap_ichar_drop(&m)) - { - cmap_ichar_emplace(&m, 5, 'a'); - cmap_ichar_emplace(&m, 8, 'b'); - cmap_ichar_emplace(&m, 12, 'c'); - - cmap_ichar_value* v = cmap_ichar_get(&m, 10); // NULL - char val = *cmap_ichar_at(&m, 5); // 'a' - cmap_ichar_emplace_or_assign(&m, 5, 'd'); // update - cmap_ichar_erase(&m, 8); - - c_foreach (i, cmap_ichar, m) - printf("map %d: %c\n", i.ref->first, i.ref->second); - } + cmap_ichar m = {0}; + cmap_ichar_emplace(&m, 5, 'a'); + cmap_ichar_emplace(&m, 8, 'b'); + cmap_ichar_emplace(&m, 12, 'c'); + + cmap_ichar_value* v = cmap_ichar_get(&m, 10); // NULL + char val = *cmap_ichar_at(&m, 5); // 'a' + cmap_ichar_emplace_or_assign(&m, 5, 'd'); // update + cmap_ichar_erase(&m, 8); + + c_foreach (i, cmap_ichar, m) + printf("map %d: %c\n", i.ref->first, i.ref->second); + + cmap_ichar_drop(&m); } */ #include "ccommon.h" diff --git a/include/stc/csmap.h b/include/stc/csmap.h index 0f72ca2d..2b1910e9 100644 --- a/include/stc/csmap.h +++ b/include/stc/csmap.h @@ -32,20 +32,20 @@ #include int main(void) { - c_with (csmap_sx m = csmap_sx_init(), csmap_sx_drop(&m)) - { - csmap_sx_emplace(&m, "Testing one", 1.234); - csmap_sx_emplace(&m, "Testing two", 12.34); - csmap_sx_emplace(&m, "Testing three", 123.4); - - csmap_sx_value *v = csmap_sx_get(&m, "Testing five"); // NULL - double num = *csmap_sx_at(&m, "Testing one"); - csmap_sx_emplace_or_assign(&m, "Testing three", 1000.0); // update - csmap_sx_erase(&m, "Testing two"); - - c_foreach (i, csmap_sx, m) - printf("map %s: %g\n", cstr_str(&i.ref->first), i.ref->second); - } + csmap_sx m = {0}; + csmap_sx_emplace(&m, "Testing one", 1.234); + csmap_sx_emplace(&m, "Testing two", 12.34); + csmap_sx_emplace(&m, "Testing three", 123.4); + + csmap_sx_value *v = csmap_sx_get(&m, "Testing five"); // NULL + double num = *csmap_sx_at(&m, "Testing one"); + csmap_sx_emplace_or_assign(&m, "Testing three", 1000.0); // update + csmap_sx_erase(&m, "Testing two"); + + c_foreach (i, csmap_sx, m) + printf("map %s: %g\n", cstr_str(&i.ref->first), i.ref->second); + + csmap_sx_drop(&m); } */ #ifdef STC_CSMAP_V1 diff --git a/misc/examples/books.c b/misc/examples/books.c index e43c0bc3..40fe877f 100644 --- a/misc/examples/books.c +++ b/misc/examples/books.c @@ -9,54 +9,53 @@ int main() { cmap_str book_reviews = {0}; - c_defer( - cmap_str_drop(&book_reviews) - ){ - // Review some books. - cmap_str_emplace(&book_reviews, - "Adventures of Huckleberry Finn", - "My favorite book." - ); - cmap_str_emplace(&book_reviews, - "Grimms' Fairy Tales", - "Masterpiece." - ); - cmap_str_emplace(&book_reviews, - "Pride and Prejudice", - "Very enjoyable" - ); - cmap_str_insert(&book_reviews, - cstr_lit("The Adventures of Sherlock Holmes"), - cstr_lit("Eye lyked it alot.") - ); - - // Check for a specific one. - // When collections store owned values (String), they can still be - // queried using references (&str). - if (cmap_str_contains(&book_reviews, "Les Misérables")) { - printf("We've got %" c_ZI " reviews, but Les Misérables ain't one.", - cmap_str_size(&book_reviews)); - } - - // oops, this review has a lot of spelling mistakes, let's delete it. - cmap_str_erase(&book_reviews, "The Adventures of Sherlock Holmes"); - - // Look up the values associated with some keys. - const char* to_find[] = {"Pride and Prejudice", "Alice's Adventure in Wonderland"}; - c_forrange (i, c_ARRAYLEN(to_find)) { - const cmap_str_value* b = cmap_str_get(&book_reviews, to_find[i]); - if (b) - printf("%s: %s\n", cstr_str(&b->first), cstr_str(&b->second)); - else - printf("%s is unreviewed.\n", to_find[i]); - } - - // Look up the value for a key (will panic if the key is not found). - printf("Review for Jane: %s\n", cstr_str(cmap_str_at(&book_reviews, "Pride and Prejudice"))); - - // Iterate over everything. - c_forpair (book, review, cmap_str, book_reviews) { - printf("%s: \"%s\"\n", cstr_str(_.book), cstr_str(_.review)); - } + + // Review some books. + cmap_str_emplace(&book_reviews, + "Adventures of Huckleberry Finn", + "My favorite book." + ); + cmap_str_emplace(&book_reviews, + "Grimms' Fairy Tales", + "Masterpiece." + ); + cmap_str_emplace(&book_reviews, + "Pride and Prejudice", + "Very enjoyable" + ); + cmap_str_insert(&book_reviews, + cstr_lit("The Adventures of Sherlock Holmes"), + cstr_lit("Eye lyked it alot.") + ); + + // Check for a specific one. + // When collections store owned values (String), they can still be + // queried using references (&str). + if (cmap_str_contains(&book_reviews, "Les Misérables")) { + printf("We've got %" c_ZI " reviews, but Les Misérables ain't one.", + cmap_str_size(&book_reviews)); + } + + // oops, this review has a lot of spelling mistakes, let's delete it. + cmap_str_erase(&book_reviews, "The Adventures of Sherlock Holmes"); + + // Look up the values associated with some keys. + const char* to_find[] = {"Pride and Prejudice", "Alice's Adventure in Wonderland"}; + c_forrange (i, c_ARRAYLEN(to_find)) { + const cmap_str_value* b = cmap_str_get(&book_reviews, to_find[i]); + if (b) + printf("%s: %s\n", cstr_str(&b->first), cstr_str(&b->second)); + else + printf("%s is unreviewed.\n", to_find[i]); } + + // Look up the value for a key (will panic if the key is not found). + printf("Review for Jane: %s\n", cstr_str(cmap_str_at(&book_reviews, "Pride and Prejudice"))); + + // Iterate over everything. + c_forpair (book, review, cmap_str, book_reviews) { + printf("%s: \"%s\"\n", cstr_str(_.book), cstr_str(_.review)); + } + + cmap_str_drop(&book_reviews); } diff --git a/misc/examples/splitstr.c b/misc/examples/splitstr.c index 5bf02d42..bf90b5d4 100644 --- a/misc/examples/splitstr.c +++ b/misc/examples/splitstr.c @@ -10,10 +10,10 @@ int main() c_fortoken (i, "Hello World C99!", " ") printf("'%.*s'\n", c_SV(i.token)); - puts("\nSplit with c_formatch (regex):"); - c_with (cregex re = cregex_from("[^ ]+"), cregex_drop(&re)) - c_formatch (i, &re, " Hello World C99! ") - printf("'%.*s'\n", c_SV(i.match[0])); + cregex re = cregex_from("[^ ]+"); + c_formatch (i, &re, " Hello World C99! ") + printf("'%.*s'\n", c_SV(i.match[0])); + cregex_drop(&re); } diff --git a/misc/tests/cregex_test.c b/misc/tests/cregex_test.c index b3cc9f0a..aa4b2a65 100644 --- a/misc/tests/cregex_test.c +++ b/misc/tests/cregex_test.c @@ -248,8 +248,12 @@ CTEST(cregex, replace) { const char* pattern = "\\b(\\d\\d\\d\\d)-(1[0-2]|0[1-9])-(3[01]|[12][0-9]|0[1-9])\\b"; const char* input = "start date: 2015-12-31, end date: 2022-02-28"; - - c_auto (cstr, str) { + cstr str = {0}; + cregex re = {0}; + c_defer( + cstr_drop(&str), + cregex_drop(&re) + ){ // replace with a fixed string, extended all-in-one call: cstr_take(&str, cregex_replace_pattern(pattern, input, "YYYY-MM-DD")); ASSERT_STREQ(cstr_str(&str), "start date: YYYY-MM-DD, end date: YYYY-MM-DD"); @@ -267,16 +271,15 @@ CTEST(cregex, replace) ASSERT_STREQ(cstr_str(&str), "52 ${apples} ${and} 31 ${mangoes}"); // Compile RE separately - c_with (cregex re = cregex_from(pattern), cregex_drop(&re)) { - ASSERT_EQ(cregex_captures(&re), 4); + re = cregex_from(pattern); + ASSERT_EQ(cregex_captures(&re), 4); - // European date format. - cstr_take(&str, cregex_replace(&re, input, "$3.$2.$1")); - ASSERT_STREQ(cstr_str(&str), "start date: 31.12.2015, end date: 28.02.2022"); + // European date format. + cstr_take(&str, cregex_replace(&re, input, "$3.$2.$1")); + ASSERT_STREQ(cstr_str(&str), "start date: 31.12.2015, end date: 28.02.2022"); - // Strip out everything but the matches - cstr_take(&str, cregex_replace_sv(&re, csview_from(input), "$3.$2.$1;", 0, NULL, CREG_R_STRIP)); - ASSERT_STREQ(cstr_str(&str), "31.12.2015;28.02.2022;"); - } + // Strip out everything but the matches + cstr_take(&str, cregex_replace_sv(&re, csview_from(input), "$3.$2.$1;", 0, NULL, CREG_R_STRIP)); + ASSERT_STREQ(cstr_str(&str), "31.12.2015;28.02.2022;"); } } diff --git a/src/checkauto.l b/src/checkauto.l index 349da70b..a8f14abb 100644 --- a/src/checkauto.l +++ b/src/checkauto.l @@ -41,13 +41,9 @@ for | while | switch { block_type |= LOOP; state = BRACES; } do { block_type |= LOOP; state = BRACESDONE; } -c_with | -c_scope | c_defer | -c_auto | -c_with | c_scope | -c_defer | +c_with | c_auto { block_type = AUTO; state = BRACES; } \( { if (state == BRACES) ++braces_lev; } \) { if (state == BRACES && --braces_lev == 0) { -- cgit v1.2.3 From 26cd0a73422cdbcd4998170e179fa0f3ce48e9a5 Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Mon, 27 Mar 2023 20:17:57 +0200 Subject: Some missing files. --- README.md | 98 ++++++++++++++++++----------------------------- docs/ccommon_api.md | 14 ++++--- docs/cpque_api.md | 2 +- include/stc/algo/crange.h | 4 +- include/stc/cspan.h | 8 ++-- src/utf8code.c | 2 +- 6 files changed, 55 insertions(+), 73 deletions(-) (limited to 'include') diff --git a/README.md b/README.md index 8d816bc6..75a5357e 100644 --- a/README.md +++ b/README.md @@ -165,13 +165,13 @@ int main(void) Floats_sort(&nums); - c_foreach (i, Floats, nums) // Alternative way to iterate nums. + c_foreach (i, Floats, nums) // Alternative and recommended way to iterate nums. printf(" %g", *i.ref); // i.ref is a pointer to the current element. Floats_drop(&nums); // cleanup memory } ``` -To switch to a different container type is easy when using `c_foreach`: +Switching to a different container type is easy: ```c #define i_type Floats #define i_val float @@ -185,7 +185,7 @@ int main() Floats_push(&nums, 40.f); // print the sorted numbers - c_foreach (i, Floats, nums) + c_foreach (i, Floats, nums) // c_foreach works with any container printf(" %g", *i.ref); Floats_drop(&nums); @@ -197,21 +197,22 @@ only works for integral types. *Alternatively, `#define i_opt c_no_cmp` to disab Let's make a vector of vectors that can be cloned. All of its element vectors will be destroyed when destroying the Vec2D. ```c +#include + #define i_type Vec #define i_val float #include -#include #define i_type Vec2D -#define i_valclass Vec // Use i_valclass when element type has "member" functions Vec_clone(), Vec_drop() and Vec_cmp(). -#define i_opt c_no_cmp // Disable search/sort for Vec2D because Vec_cmp() is not defined. +#define i_valclass Vec // Use i_valclass when the element type has "member" functions _clone(), _drop() and _cmp(). +#define i_opt c_no_cmp // However, disable search/sort for Vec2D because Vec_cmp() is not defined. #include int main(void) { Vec* v; Vec2D vec = {0}; // All containers in STC can be initialized with {0}. - v = Vec2D_push(&vec, Vec_init()); // Returns a pointer to the new element in vec. + v = Vec2D_push(&vec, Vec_init()); // push() returns a pointer to the new element in vec. Vec_push(v, 10.f); Vec_push(v, 20.f); @@ -228,84 +229,69 @@ int main(void) c_drop(Vec2D, &vec, &clone); // Cleanup all (6) vectors. } ``` -Here is an example of using six different container types: +Here is an example of using four different container types: ```c #include -#include - -struct Point { float x, y; }; #define i_key int #include // cset_int: unordered set +struct Point { float x, y; }; +// Define cvec_pnt with a less-comparison function for Point. #define i_val struct Point -// Define a i_less template parameter (alternative to i_cmp) for Point. #define i_less(a, b) a->x < b->x || (a->x == b->x && a->y < b->y) #define i_tag pnt #include // cvec_pnt: vector of struct Point -#define i_val int -#include // cdeq_int: deque of int - #define i_val int #include // clist_int: singly linked list -#define i_val int -#include // cstack_int - #define i_key int #define i_val int #include // csmap_int: sorted map int => int int main(void) { - // Define six empty containers + // Define four empty containers cset_int set = {0}; cvec_pnt vec = {0}; - cdeq_int deq = {0}; clist_int lst = {0}; - cstack_int stk = {0}; csmap_int map = {0}; - c_defer( // Drop the containers after the scope is executed + c_defer( // Drop the containers at scope exit cset_int_drop(&set), cvec_pnt_drop(&vec), - cdeq_int_drop(&deq), clist_int_drop(&lst), - cstack_int_drop(&stk), csmap_int_drop(&map) ){ - int nums[4] = {10, 20, 30, 40}; - struct Point pts[4] = { {10, 1}, {20, 2}, {30, 3}, {40, 4} }; - int pairs[4][2] = { {20, 2}, {10, 1}, {30, 3}, {40, 4} }; + enum{N = 5}; + int nums[N] = {10, 20, 30, 40, 50}; + struct Point pts[N] = { {10, 1}, {20, 2}, {30, 3}, {40, 4}, {50, 5} }; + int pairs[N][2] = { {20, 2}, {10, 1}, {30, 3}, {40, 4}, {50, 5} }; // Add some elements to each container - for (int i = 0; i < 4; ++i) { + for (int i = 0; i < N; ++i) { cset_int_insert(&set, nums[i]); cvec_pnt_push(&vec, pts[i]); - cdeq_int_push_back(&deq, nums[i]); clist_int_push_back(&lst, nums[i]); - cstack_int_push(&stk, nums[i]); csmap_int_insert(&map, pairs[i][0], pairs[i][1]); } - // Find an element in each container (except cstack) + // Find an element in each container cset_int_iter i1 = cset_int_find(&set, 20); cvec_pnt_iter i2 = cvec_pnt_find(&vec, (struct Point){20, 2}); - cdeq_int_iter i3 = cdeq_int_find(&deq, 20); - clist_int_iter i4 = clist_int_find(&lst, 20); - csmap_int_iter i5 = csmap_int_find(&map, 20); + clist_int_iter i3 = clist_int_find(&lst, 20); + csmap_int_iter i4 = csmap_int_find(&map, 20); - printf("\nFound: %d, (%g, %g), %d, %d, [%d: %d]\n", - *i1.ref, i2.ref->x, i2.ref->y, *i3.ref, - *i4.ref, i5.ref->first, i5.ref->second); + printf("\nFound: %d, (%g, %g), %d, [%d: %d]\n", + *i1.ref, i2.ref->x, i2.ref->y, *i3.ref, + i4.ref->first, i4.ref->second); // Erase all the elements found cset_int_erase_at(&set, i1); cvec_pnt_erase_at(&vec, i2); - cdeq_int_erase_at(&deq, i3); - clist_int_erase_at(&lst, i4); - csmap_int_erase_at(&map, i5); + clist_int_erase_at(&lst, i3); + csmap_int_erase_at(&map, i4); printf("After erasing the elements found:"); printf("\n set:"); @@ -316,18 +302,10 @@ int main(void) c_foreach (i, cvec_pnt, vec) printf(" (%g, %g)", i.ref->x, i.ref->y); - printf("\n deq:"); - c_foreach (i, cdeq_int, deq) - printf(" %d", *i.ref); - printf("\n lst:"); c_foreach (i, clist_int, lst) printf(" %d", *i.ref); - printf("\n stk:"); - c_foreach (i, cstack_int, stk) - printf(" %d", *i.ref); - printf("\n map:"); c_foreach (i, csmap_int, map) printf(" [%d: %d]", i.ref->first, i.ref->second); @@ -337,14 +315,12 @@ int main(void) Output ``` -Found: 20, (20, 2), 20, 20, [20: 2] -After erasing elements found: - set: 10 30 40 - vec: (10, 1) (30, 3) (40, 4) - deq: 5 10 30 - lst: 5 10 30 - stk: 10 20 30 40 - map: [10: 1] [30: 3] [40: 4] +Found: 20, (20, 2), 20, [20: 2] +After erasing the elements found: + set: 40 10 30 50 + vec: (10, 1) (30, 3) (40, 4) (50, 5) + lst: 10 30 40 50 + map: [10: 1] [30: 3] [40: 4] [50: 5] ``` Installation @@ -480,12 +456,12 @@ cvec_str vec = {0}; cstr s = cstr_lit("a string literal"); const char* hello = "Hello"; -cvec_str_push_back(&vec, cstr_from(hello); // construct and add string from const char* -cvec_str_push_back(&vec, cstr_clone(s)); // clone and append a cstr +cvec_str_push(&vec, cstr_from(hello); // make a cstr from const char* and move it onto vec +cvec_str_push(&vec, cstr_clone(s)); // make a cstr clone and move it onto vec -cvec_str_emplace_back(&vec, "Yay, literal"); // internally constructs cstr from const char* -cvec_str_emplace_back(&vec, cstr_clone(s)); // <-- COMPILE ERROR: expects const char* -cvec_str_emplace_back(&vec, cstr_str(&s)); // Ok: const char* input type. +cvec_str_emplace(&vec, "Yay, literal"); // internally make a cstr from const char* +cvec_str_emplace(&vec, cstr_clone(s)); // <-- COMPILE ERROR: expects const char* +cvec_str_emplace(&vec, cstr_str(&s)); // Ok: const char* input type. cstr_drop(&s) cvec_str_drop(&vec); diff --git a/docs/ccommon_api.md b/docs/ccommon_api.md index 010ea204..53ba096a 100644 --- a/docs/ccommon_api.md +++ b/docs/ccommon_api.md @@ -113,8 +113,10 @@ int main() { isPrime(*i.ref) && c_flt_skip(i, 24) && c_flt_count(i) % 15 == 1 && - c_flt_take(i, 10)) + c_flt_take(i, 10) + ){ printf(" %lld", *i.ref); + } puts(""); } // out: 1171 1283 1409 1493 1607 1721 1847 1973 2081 2203 @@ -126,7 +128,7 @@ Note that `c_flt_take()` and `c_flt_takewhile()`breaks the loop on false. ### crange A number sequence generator type, similar to [boost::irange](https://www.boost.org/doc/libs/release/libs/range/doc/html/range/reference/ranges/irange.html). The **crange_value** type is `long long`. Below *start*, *stop*, and *step* are of type *crange_value*: ```c -crange& crange_obj(...) // create a compound literal crange object +crange& crange_object(...) // create a compound literal crange object crange crange_make(stop); // will generate 0, 1, ..., stop-1 crange crange_make(start, stop); // will generate start, start+1, ... stop-1 crange crange_make(start, stop, step); // will generate start, start+step, ... upto-not-including stop @@ -144,10 +146,12 @@ c_forfilter (i, crange, r1, isPrime(*i.ref)) // 2. The 11 first primes: printf("2"); -c_forfilter (i, crange, crange_obj(3, INT64_MAX, 2), - isPrime(*i.ref) && - c_flt_take(10)) +c_forfilter (i, crange, crange_object(3, INT64_MAX, 2), + isPrime(*i.ref) && + c_flt_take(10) +){ printf(" %lld", *i.ref); +} // 2 3 5 7 11 13 17 19 23 29 31 ``` ## Algorithms diff --git a/docs/cpque_api.md b/docs/cpque_api.md index b3a1a9ec..134a920f 100644 --- a/docs/cpque_api.md +++ b/docs/cpque_api.md @@ -84,7 +84,7 @@ int main() // Add some negative ones. int nums[] = {-231, -32, -873, -4, -343}; - c_forrange (i, c_ARRAYLEN(nums)) + c_forrange (i, c_arraylen(nums)) cpque_i_push(&heap, nums[i]); // Extract and display the fifty smallest. diff --git a/include/stc/algo/crange.h b/include/stc/algo/crange.h index ca06c258..91ffdd56 100644 --- a/include/stc/algo/crange.h +++ b/include/stc/algo/crange.h @@ -34,7 +34,7 @@ int main() // use a temporary crange object. int a = 100, b = INT32_MAX; - c_forfilter (i, crange, crange_obj(a, b, 8), + c_forfilter (i, crange, crange_object(a, b, 8), c_flt_skip(i, 10) && c_flt_take(i, 3)) printf(" %lld", *i.ref); @@ -46,7 +46,7 @@ int main() #include -#define crange_obj(...) \ +#define crange_object(...) \ (*(crange[]){crange_make(__VA_ARGS__)}) typedef long long crange_value; diff --git a/include/stc/cspan.h b/include/stc/cspan.h index d5482200..ac3e9206 100644 --- a/include/stc/cspan.h +++ b/include/stc/cspan.h @@ -48,10 +48,12 @@ int demo2() { puts(""); c_forfilter (i, Intspan, span, - c_flt_skipwhile(i, *i.ref < 25) && - (*i.ref & 1) == 0 && // even only - c_flt_take(i, 2)) // break after 2 + c_flt_skipwhile(i, *i.ref < 25) && + (*i.ref & 1) == 0 && // even only + c_flt_take(i, 2) // break after 2 + ){ printf(" %d", *i.ref); + } puts(""); } */ diff --git a/src/utf8code.c b/src/utf8code.c index ecfdd24d..496f5eef 100644 --- a/src/utf8code.c +++ b/src/utf8code.c @@ -142,7 +142,7 @@ bool utf8_isalpha(uint32_t c) { static int16_t groups[] = {U8G_Latin, U8G_Nl, U8G_Greek, U8G_Cyrillic, U8G_Han, U8G_Devanagari, U8G_Arabic}; if (c < 128) return isalpha((int)c) != 0; - for (int j=0; j < c_ARRAYLEN(groups); ++j) + for (int j=0; j < c_arraylen(groups); ++j) if (utf8_isgroup(groups[j], c)) return true; return false; -- cgit v1.2.3 From 59d74d181e44dd05a8570b42fc6284745e225664 Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Tue, 28 Mar 2023 19:29:05 +0200 Subject: Example changes. Added crand.h possible replacement for crandom.h --- docs/ccommon_api.md | 2 +- include/stc/crand.h | 194 +++++++++++++++++++++++++++++++++++++++++++++++++ misc/examples/gauss2.c | 11 +-- misc/examples/prime.c | 5 +- misc/examples/shape.c | 19 ++--- 5 files changed, 211 insertions(+), 20 deletions(-) create mode 100644 include/stc/crand.h (limited to 'include') diff --git a/docs/ccommon_api.md b/docs/ccommon_api.md index 53ba096a..46966fd9 100644 --- a/docs/ccommon_api.md +++ b/docs/ccommon_api.md @@ -92,7 +92,7 @@ Iterate containers with stop-criteria and chained range filtering. | `c_flt_skipwhile(it, predicate)` | Skip items until predicate is false | | `c_flt_takewhile(it, predicate)` | Take items until predicate is false | | `c_flt_count(it)` | Increment current and return value | -| `c_flt_last(it)` | Get value of last count/skip/take | +| `c_flt_last(it)` | Get value of last count/skip*/take* | ```c // Example: #include diff --git a/include/stc/crand.h b/include/stc/crand.h new file mode 100644 index 00000000..4ebc402d --- /dev/null +++ b/include/stc/crand.h @@ -0,0 +1,194 @@ +/* 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 CRAND_H_INCLUDED +#define CRAND_H_INCLUDED +/* +// crand: Pseudo-random number generator +#include "stc/crand.h" + +int main() { + uint64_t seed = 123456789; + crand_t rng = crand_from(seed); + crand_unif_t dist1 = crand_unif_from(1, 6); + crandf_unif_t dist2 = crandf_unif_from(1.0, 10.0); + crandf_norm_t dist3 = crandf_norm_from(1.0, 10.0); + + uint64_t i = crand_r(&rng); + int64_t iu = crand_unif(&rng, &dist1); + double xu = crandf_unif(&rng, &dist2); + double xn = crandf_norm(&rng, &dist3); +} +*/ +#include +#include + +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 crandf_unif { double lower, range; } crandf_unif_t; +typedef struct crandf_norm { double mean, stddev, next; int has_next; } crandf_norm_t; + +/* PRNG crand_t. + * 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. + * crand_t 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 crand_t PRNGs */ +STC_API void csrand(uint64_t seed); +STC_API uint64_t crand(void); +STC_API double crandf(void); + +/* Init crand_t prng with a seed */ +STC_API crand_t crand_from(uint64_t seed); + +/* Unbiased bounded uniform distribution. range [low, high] */ +STC_API crand_unif_t crand_unif_from(int64_t low, int64_t high); +STC_API int64_t crand_unif(crand_t* rng, crand_unif_t* dist); + +/* Normal distribution PRNG */ +STC_API double crandf_norm(crand_t* rng, crandf_norm_t* dist); + + +/* Main crand_t prng */ +STC_INLINE uint64_t crand_r(crand_t* rng) { + enum {LR=24, RS=11, LS=3}; uint64_t *s = rng->state; + const uint64_t out = (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))) + out; + return out; +} + +/* Float64 random number in range [0.0, 1.0). */ +STC_INLINE double crandf_r(crand_t* rng) { + union {uint64_t i; double f;} u = {0x3FF0000000000000U | (crand_r(rng) >> 12)}; + return u.f - 1.0; +} + +/* Float64 uniform distributed RNG, range [low, high). */ +STC_INLINE double crandf_unif(crand_t* rng, crandf_unif_t* dist) { + return crandf_r(rng)*dist->range + dist->lower; +} + +/* Init uniform distributed float64 RNG, range [low, high). */ +STC_INLINE crandf_unif_t crandf_unif_from(double low, double high) { + return c_LITERAL(crandf_unif_t){low, high - low}; +} + +/* Marsaglia polar method for gaussian/normal distribution, float64. */ +STC_INLINE crandf_norm_t crandf_norm_from(double mean, double stddev) { + return c_LITERAL(crandf_norm_t){mean, stddev, 0.0, 0}; +} + +/* -------------------------- IMPLEMENTATION ------------------------- */ +#if defined(i_implement) + +/* Global random() */ +static crand_t crand_global = {{ + 0x26aa069ea2fb1a4d, 0x70c72c95cd592d04, + 0x504f333d3aa0b359, 0x9e3779b97f4a7c15, + 0x6a09e667a754166b +}}; + +STC_DEF void csrand(uint64_t seed) { + crand_global = crand_from(seed); +} + +STC_DEF uint64_t crand(void) { + return crand_r(&crand_global); +} + +STC_DEF double crandf(void) { + return crandf_r(&crand_global); +} + +/* rng.state[4] must be odd */ +STC_DEF crand_t crand_from(uint64_t seed) { + crand_t rng = {{seed + 0x26aa069ea2fb1a4d, + seed*0x9e3779b97f4a7c15 + 0x70c72c95cd592d04, + seed + 0x504f333d3aa0b359, + seed*0x6a09e667a754166b, seed<<1 | 1}}; + return rng; +} + +/* Init unbiased uniform uint RNG with bounds [low, high] */ +STC_DEF crand_unif_t crand_unif_from(int64_t low, int64_t high) { + crand_unif_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 + #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 crand_unif(crand_t* rng, crand_unif_t* d) { +#ifdef c_umul128 + uint64_t lo, hi; + do { c_umul128(crand_r(rng), d->range, &lo, &hi); } while (lo < d->threshold); + return d->lower + (int64_t)hi; +#else + uint64_t x, r; + do { x = crand_r(rng); r = x % d->range; } while (x - r > -d->range); + return d->lower + r; +#endif +} + +/* Normal distribution PRNG */ +STC_DEF double crandf_norm(crand_t* rng, crandf_norm_t* dist) { + double u1, u2, s, m; + if (dist->has_next++ & 1) + return dist->next * dist->stddev + dist->mean; + do { + u1 = 2.0 * crandf_r(rng) - 1.0; + u2 = 2.0 * crandf_r(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/misc/examples/gauss2.c b/misc/examples/gauss2.c index be514c12..ce29f786 100644 --- a/misc/examples/gauss2.c +++ b/misc/examples/gauss2.c @@ -11,14 +11,15 @@ int main() { - enum {N = 10000000}; - const double Mean = -12.0, StdDev = 6.0, Scale = 74; + enum {N = 5000000}; + uint64_t seed = (uint64_t)time(NULL); + stc64_t rng = stc64_new(seed); + const float Mean = round(stc64_randf(&rng)*98.f - 49.f), StdDev = stc64_randf(&rng)*10.f + 1.f, Scale = 74.f; printf("Demo of gaussian / normal distribution of %d random samples\n", N); + printf("Mean %f, StdDev %f\n", Mean, StdDev); // Setup random engine with normal distribution. - uint64_t seed = (uint64_t)time(NULL); - stc64_t rng = stc64_new(seed); stc64_normalf_t dist = stc64_normalf_new(Mean, StdDev); // Create and init histogram map with defered destruct @@ -32,7 +33,7 @@ int main() // Print the gaussian bar chart c_forpair (index, count, csmap_int, hist) { - int n = (int)((float)*_.count * StdDev * Scale * 2.5f / (float)N); + int n = (int)round((float)*_.count * StdDev * Scale * 2.5f / (float)N); if (n > 0) { cstr_resize(&bar, n, '*'); printf("%4d %s\n", *_.index, cstr_str(&bar)); diff --git a/misc/examples/prime.c b/misc/examples/prime.c index 9ffb2f53..34d64f10 100644 --- a/misc/examples/prime.c +++ b/misc/examples/prime.c @@ -42,9 +42,8 @@ int main(void) puts("\n"); puts("Show the last 50 primes using a temporary crange generator:"); - crange R = crange_make(n - 1, 0, -2); - c_forfilter (i, crange, R, - cbits_test(&primes, *i.ref>>1) && + c_forfilter (i, crange, crange_object(n - 1, 0, -2), + cbits_test(&primes, *i.ref/2) && c_flt_take(i, 50) ){ printf("%lld ", *i.ref); diff --git a/misc/examples/shape.c b/misc/examples/shape.c index e24f7fd7..d7116039 100644 --- a/misc/examples/shape.c +++ b/misc/examples/shape.c @@ -4,7 +4,7 @@ #include #include -#define c_dyn_cast(T, s) \ +#define DYN_CAST(T, s) \ (&T##_api == (s)->api ? (T*)(s) : (T*)0) // Shape definition @@ -53,15 +53,14 @@ typedef struct { extern struct ShapeAPI Triangle_api; -Triangle Triangle_from(Point a, Point b, Point c) -{ - Triangle t = {.shape={.api=&Triangle_api}, .p={a, b, c}}; +Triangle Triangle_from(Point a, Point b, Point c) { + Triangle t = {{&Triangle_api}, {a, b, c}}; return t; } static void Triangle_draw(const Shape* shape) { - const Triangle* self = c_dyn_cast(Triangle, shape); + const Triangle* self = DYN_CAST(Triangle, shape); printf("Triangle : (%g,%g), (%g,%g), (%g,%g)\n", self->p[0].x, self->p[0].y, self->p[1].x, self->p[1].y, @@ -88,9 +87,8 @@ typedef struct { extern struct ShapeAPI Polygon_api; -Polygon Polygon_init(void) -{ - Polygon p = {.shape={.api=&Polygon_api}, .points=PointVec_init()}; +Polygon Polygon_init(void) { + Polygon p = {{&Polygon_api}, {0}}; return p; } @@ -101,15 +99,14 @@ void Polygon_addPoint(Polygon* self, Point p) static void Polygon_drop(Shape* shape) { - Polygon* self = c_dyn_cast(Polygon, shape); + Polygon* self = DYN_CAST(Polygon, shape); printf("poly destructed\n"); PointVec_drop(&self->points); - Shape_drop(shape); } static void Polygon_draw(const Shape* shape) { - const Polygon* self = c_dyn_cast(Polygon, shape); + const Polygon* self = DYN_CAST(Polygon, shape); printf("Polygon :"); c_foreach (i, PointVec, self->points) printf(" (%g,%g)", i.ref->x, i.ref->y); -- cgit v1.2.3 From 97d205f7ba096a9872afbce5e696a8806d7b72d1 Mon Sep 17 00:00:00 2001 From: Tyge Lovset Date: Wed, 29 Mar 2023 08:45:28 +0200 Subject: Removed i_less_functor, i_cmp_functor, i_eq_functor and i_hash_functor: not needed. Simplified cvec_X_eq() and cdeq_X_eq() --- docs/cmap_api.md | 4 +--- docs/cpque_api.md | 1 - docs/cset_api.md | 2 -- docs/csmap_api.md | 1 - docs/csset_api.md | 1 - include/stc/cdeq.h | 5 ++--- include/stc/cmap.h | 14 +++----------- include/stc/cpque.h | 10 +++------- include/stc/csmap.h | 18 +++++++----------- include/stc/cvec.h | 5 ++--- misc/examples/functor.c | 8 ++++---- 11 files changed, 22 insertions(+), 47 deletions(-) (limited to 'include') diff --git a/docs/cmap_api.md b/docs/cmap_api.md index 71e00265..8749bd09 100644 --- a/docs/cmap_api.md +++ b/docs/cmap_api.md @@ -36,9 +36,7 @@ See the c++ class [std::unordered_map](https://en.cppreference.com/w/cpp/contain #define i_valto // convertion func i_val* => i_valraw #define i_tag // alternative typename: cmap_{i_tag}. i_tag defaults to i_val -#define i_hash_functor // advanced, see examples/functor.c for similar usage. -#define i_eq_functor // advanced, see examples/functor.c for similar usage. -#define i_ssize // internal; default int32_t. If defined, table expand 2x (else 1.5x) +#define i_ssize // internal; default int32_t. If defined, table expand 2x (else 1.5x) #include ``` `X` should be replaced by the value of `i_tag` in all of the following documentation. diff --git a/docs/cpque_api.md b/docs/cpque_api.md index 134a920f..1396dc1f 100644 --- a/docs/cpque_api.md +++ b/docs/cpque_api.md @@ -18,7 +18,6 @@ See the c++ class [std::priority_queue](https://en.cppreference.com/w/cpp/contai #define i_valfrom // convertion func i_valraw => i_val #define i_valto // convertion func i_val* => i_valraw. -#define i_less_functor // takes self as first argument. See examples/functor.c for usage. #define i_tag // alternative typename: cpque_{i_tag}. i_tag defaults to i_val #include ``` diff --git a/docs/cset_api.md b/docs/cset_api.md index a0af357f..db9fb802 100644 --- a/docs/cset_api.md +++ b/docs/cset_api.md @@ -19,8 +19,6 @@ A **cset** is an associative container that contains a set of unique objects of #define i_keyto // convertion func i_key* => i_keyraw - defaults to plain copy #define i_tag // alternative typename: cmap_{i_tag}. i_tag defaults to i_val -#define i_hash_functor // advanced, see examples/functor.c for similar usage. -#define i_eq_functor // advanced, see examples/functor.c for similar usage. #define i_ssize // default int32_t. If defined, table expand 2x (else 1.5x) #include ``` diff --git a/docs/csmap_api.md b/docs/csmap_api.md index da0e6915..0eff8c26 100644 --- a/docs/csmap_api.md +++ b/docs/csmap_api.md @@ -33,7 +33,6 @@ See the c++ class [std::map](https://en.cppreference.com/w/cpp/container/map) fo #define i_valto // convertion func i_val* => i_valraw #define i_tag // alternative typename: csmap_{i_tag}. i_tag defaults to i_val -#define i_cmp_functor // advanced, see examples/functor.c for similar usage. #define i_ssize // internal size rep. defaults to int32_t #include ``` diff --git a/docs/csset_api.md b/docs/csset_api.md index 0989fd9b..1869327c 100644 --- a/docs/csset_api.md +++ b/docs/csset_api.md @@ -18,7 +18,6 @@ See the c++ class [std::set](https://en.cppreference.com/w/cpp/container/set) fo #define i_keyfrom // convertion func i_keyraw => i_key - defaults to plain copy #define i_keyto // convertion func i_key* => i_keyraw - defaults to plain copy -#define i_cmp_functor // advanced, see examples/functor.c for similar usage. #define i_tag // alternative typename: csset_{i_tag}. i_tag defaults to i_val #define i_ssize // defaults to int32_t #include diff --git a/include/stc/cdeq.h b/include/stc/cdeq.h index c4f84a1b..09c0a7f8 100644 --- a/include/stc/cdeq.h +++ b/include/stc/cdeq.h @@ -198,9 +198,8 @@ _cx_memb(_get_mut)(_cx_self* self, _cx_raw raw) STC_INLINE bool _cx_memb(_eq)(const _cx_self* x, const _cx_self* y) { if (x->_len != y->_len) return false; - _cx_iter i = _cx_memb(_begin)(x), j = _cx_memb(_begin)(y); - for (; i.ref; _cx_memb(_next)(&i), _cx_memb(_next)(&j)) { - const _cx_raw _rx = i_keyto(i.ref), _ry = i_keyto(j.ref); + for (intptr_t i = 0; i < x->_len; ++i) { + const _cx_raw _rx = i_keyto(x->data+i), _ry = i_keyto(y->data+i); if (!(i_eq((&_rx), (&_ry)))) return false; } return true; diff --git a/include/stc/cmap.h b/include/stc/cmap.h index 402038cb..c840523f 100644 --- a/include/stc/cmap.h +++ b/include/stc/cmap.h @@ -82,12 +82,6 @@ typedef struct { int64_t idx; uint8_t hx; } chash_bucket_t; #define _i_size i_ssize #endif #include "priv/template.h" -#ifndef i_hash_functor - #define i_hash_functor(self, x) i_hash(x) -#endif -#ifndef i_eq_functor - #define i_eq_functor(self, x, y) i_eq(x, y) -#endif #if !c_option(c_is_forward) _cx_deftypes(_c_chash_types, _cx_self, i_key, i_val, i_ssize, _i_MAP_ONLY, _i_SET_ONLY); #endif @@ -371,14 +365,14 @@ STC_DEF void _cx_memb(_clear)(_cx_self* self) { STC_DEF chash_bucket_t _cx_memb(_bucket_)(const _cx_self* self, const _cx_rawkey* rkeyptr) { - const uint64_t _hash = i_hash_functor(self, 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_rawkey _raw = i_keyto(_i_keyref(self->table + b.idx)); - if (i_eq_functor(self, (&_raw), rkeyptr)) + if (i_eq((&_raw), rkeyptr)) break; } if (++b.idx == _cap) @@ -469,7 +463,7 @@ _cx_memb(_erase_entry)(_cx_self* self, _cx_value* _val) { if (! _hashx[j]) break; const _cx_rawkey _raw = i_keyto(_i_keyref(_slot + j)); - k = (i_ssize)c_PASTE(fastrange_,_i_expandby)(i_hash_functor(self, (&_raw)), (uint64_t)_cap); + 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; } @@ -479,8 +473,6 @@ _cx_memb(_erase_entry)(_cx_self* self, _cx_value* _val) { #endif // i_implement #undef i_max_load_factor -#undef i_hash_functor -#undef i_eq_functor #undef _i_size #undef _i_isset #undef _i_ismap diff --git a/include/stc/cpque.h b/include/stc/cpque.h index 4955f2e0..00eaa49e 100644 --- a/include/stc/cpque.h +++ b/include/stc/cpque.h @@ -32,9 +32,6 @@ #endif #include "priv/template.h" -#ifndef i_less_functor - #define i_less_functor(self, x, y) i_less(x, y) -#endif #if !c_option(c_is_forward) _cx_deftypes(_c_cpque_types, _cx_self, i_key); #endif @@ -120,8 +117,8 @@ STC_DEF void _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_functor(self, (&arr[c]), (&arr[c + (c < n)])); - if (!(i_less_functor(self, (&arr[r]), (&arr[c])))) return; + c += i_less((&arr[c]), (&arr[c + (c < n)])); + if (!(i_less((&arr[r]), (&arr[c])))) return; t = arr[r], arr[r] = arr[c], arr[r = c] = t; } } @@ -156,12 +153,11 @@ _cx_memb(_push)(_cx_self* self, _cx_value value) { _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_functor(self, (&arr[c/2]), (&value))); c /= 2) + for (; c > 1 && (i_less((&arr[c/2]), (&value))); c /= 2) arr[c] = arr[c/2]; arr[c] = value; } #endif #define CPQUE_H_INCLUDED -#undef i_less_functor #include "priv/template.h" diff --git a/include/stc/csmap.h b/include/stc/csmap.h index 2b1910e9..50593ba3 100644 --- a/include/stc/csmap.h +++ b/include/stc/csmap.h @@ -80,9 +80,6 @@ int main(void) { #define _i_size i_ssize #endif #include "priv/template.h" -#ifndef i_cmp_functor - #define i_cmp_functor(self, x, y) i_cmp(x, y) -#endif #if !c_option(c_is_forward) _cx_deftypes(_c_aatree_types, _cx_self, i_key, i_val, i_ssize, _i_MAP_ONLY, _i_SET_ONLY); #endif @@ -222,12 +219,12 @@ _cx_memb(_advance)(_cx_iter it, size_t n) { } STC_INLINE bool -_cx_memb(_eq)(const _cx_self* m1, const _cx_self* m2) { - if (_cx_memb(_size)(m1) != _cx_memb(_size)(m2)) return false; - _cx_iter i = _cx_memb(_begin)(m1), j = _cx_memb(_begin)(m2); +_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_rawkey _rx = i_keyto(_i_keyref(i.ref)), _ry = i_keyto(_i_keyref(j.ref)); - if ((i_cmp_functor(m1, (&_rx), (&_ry))) != 0) return false; + if (!(i_eq((&_rx), (&_ry)))) return false; } return true; } @@ -357,7 +354,7 @@ _cx_memb(_find_it)(const _cx_self* self, _cx_rawkey rkey, _cx_iter* out) { out->_top = 0; while (tn) { int c; const _cx_rawkey _raw = i_keyto(_i_keyref(&d[tn].value)); - if ((c = i_cmp_functor(self, (&_raw), (&rkey))) < 0) + if ((c = i_cmp((&_raw), (&rkey))) < 0) tn = d[tn].link[1]; else if (c > 0) { out->_st[out->_top++] = tn; tn = d[tn].link[0]; } @@ -425,7 +422,7 @@ _cx_memb(_insert_entry_i_)(_cx_self* self, i_ssize tn, const _cx_rawkey* rkey, _ while (tx) { up[top++] = tx; const _cx_rawkey _raw = i_keyto(_i_keyref(&d[tx].value)); - if (!(c = i_cmp_functor(self, (&_raw), rkey))) + if (!(c = i_cmp((&_raw), rkey))) { _res->ref = &d[tx].value; return tn; } dir = (c < 0); tx = d[tx].link[dir]; @@ -464,7 +461,7 @@ _cx_memb(_erase_r_)(_cx_self *self, i_ssize tn, const _cx_rawkey* rkey, int *era if (tn == 0) return 0; _cx_rawkey raw = i_keyto(_i_keyref(&d[tn].value)); - i_ssize tx; int c = i_cmp_functor(self, (&raw), rkey); + i_ssize 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); else { @@ -594,7 +591,6 @@ _cx_memb(_drop)(_cx_self* self) { } #endif // i_implement -#undef i_cmp_functor #undef _i_size #undef _i_isset #undef _i_ismap diff --git a/include/stc/cvec.h b/include/stc/cvec.h index 91cdb25c..8f35e5fc 100644 --- a/include/stc/cvec.h +++ b/include/stc/cvec.h @@ -236,9 +236,8 @@ _cx_memb(_get_mut)(const _cx_self* self, _cx_raw raw) STC_INLINE bool _cx_memb(_eq)(const _cx_self* x, const _cx_self* y) { if (x->_len != y->_len) return false; - _cx_iter i = _cx_memb(_begin)(x), j = _cx_memb(_begin)(y); - for (; i.ref; _cx_memb(_next)(&i), _cx_memb(_next)(&j)) { - const _cx_raw _rx = i_keyto(i.ref), _ry = i_keyto(j.ref); + for (intptr_t i = 0; i < x->_len; ++i) { + const _cx_raw _rx = i_keyto(x->data+i), _ry = i_keyto(y->data+i); if (!(i_eq((&_rx), (&_ry)))) return false; } return true; diff --git a/misc/examples/functor.c b/misc/examples/functor.c index f37e41d5..f8074c3a 100644 --- a/misc/examples/functor.c +++ b/misc/examples/functor.c @@ -1,9 +1,9 @@ // Implements c++ example: https://en.cppreference.com/w/cpp/container/priority_queue // Example of per-instance less-function on a single priority queue type // -// Note: i_less_functor: available for cpque types only -// i_cmp_functor: available for csmap and csset types only -// i_hash_functor/i_eq_functor: available for cmap and cset types only +// Note: i_less: has self for cpque types only +// i_cmp: has self for csmap and csset types only +// i_hash/i_eq: has self for cmap and cset types only #include #include @@ -23,7 +23,7 @@ struct { #define i_type ipque #define i_val int #define i_opt c_is_forward // needed to avoid re-type-define container type -#define i_less_functor(self, x, y) c_container_of(self, IPQueue, Q)->less(x, y) +#define i_less(x, y) c_container_of(self, IPQueue, Q)->less(x, y) #include void print_queue(const char* name, IPQueue q) { -- cgit v1.2.3 From 9a88ddd9cbf4c33664de258bcb5bcef6a746149a Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Wed, 29 Mar 2023 18:23:54 +0200 Subject: Some optimizations in hash func. --- include/stc/ccommon.h | 22 +++---- include/stc/crand.h | 105 +++++++++++++++------------------- misc/benchmarks/shootout_hashmaps.cpp | 1 + 3 files changed, 58 insertions(+), 70 deletions(-) (limited to 'include') diff --git a/include/stc/ccommon.h b/include/stc/ccommon.h index 5e163875..362b09ce 100644 --- a/include/stc/ccommon.h +++ b/include/stc/ccommon.h @@ -140,20 +140,20 @@ typedef const char* crawstr; #define c_ROTL(x, k) (x << (k) | x >> (8*sizeof(x) - (k))) STC_INLINE uint64_t cfasthash(const void* key, intptr_t len) { - const uint8_t *x = (const uint8_t*) key; - uint64_t u8, h = 1; intptr_t n = len >> 3; - uint32_t u4; + uint32_t u4; uint64_t u8; + switch (len) { + case 8: memcpy(&u8, key, 8); return u8*0xc6a4a7935bd1e99d; + case 4: memcpy(&u4, key, 4); return u4*0xc6a4a7935bd1e99d; + case 0: return 1; + } + const uint8_t *x = (const uint8_t*)key; + uint64_t h = *x, n = (uint64_t)len >> 3; + len &= 7; while (n--) { memcpy(&u8, x, 8), x += 8; - h += (c_ROTL(u8, 26) ^ u8)*0xc6a4a7935bd1e99d; - } - switch (len &= 7) { - case 0: return h; - case 4: memcpy(&u4, x, 4); - return h + u4*0xc6a4a7935bd1e99d; + h += u8*0xc6a4a7935bd1e99d; } - h += *x++; - while (--len) h = (h << 10) - h + *x++; + while (len--) h = (h << 10) - h - *x++; return c_ROTL(h, 26) ^ h; } diff --git a/include/stc/crand.h b/include/stc/crand.h index 4ebc402d..f46f2bd5 100644 --- a/include/stc/crand.h +++ b/include/stc/crand.h @@ -30,15 +30,13 @@ int main() { uint64_t seed = 123456789; - crand_t rng = crand_from(seed); - crand_unif_t dist1 = crand_unif_from(1, 6); - crandf_unif_t dist2 = crandf_unif_from(1.0, 10.0); - crandf_norm_t dist3 = crandf_norm_from(1.0, 10.0); + 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); - uint64_t i = crand_r(&rng); + uint64_t i = crand_u64(&rng); int64_t iu = crand_unif(&rng, &dist1); - double xu = crandf_unif(&rng, &dist2); - double xn = crandf_norm(&rng, &dist3); + double xn = crand_norm(&rng, &dist3); } */ #include @@ -46,8 +44,7 @@ int main() { 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 crandf_unif { double lower, range; } crandf_unif_t; -typedef struct crandf_norm { double mean, stddev, next; int has_next; } crandf_norm_t; +typedef struct crand_norm { double mean, stddev, next; int has_next; } crand_norm_t; /* PRNG crand_t. * Very fast PRNG suited for parallel usage with Weyl-sequence parameter. @@ -61,23 +58,25 @@ typedef struct crandf_norm { double mean, stddev, next; int has_next; } crandf_n */ /* Global crand_t PRNGs */ -STC_API void csrand(uint64_t seed); +STC_API void csrand(uint64_t seed); STC_API uint64_t crand(void); -STC_API double crandf(void); +STC_API double crandf(void); /* Init crand_t prng with a seed */ -STC_API crand_t crand_from(uint64_t seed); +STC_API crand_t crand_init(uint64_t seed); /* Unbiased bounded uniform distribution. range [low, high] */ -STC_API crand_unif_t crand_unif_from(int64_t low, int64_t 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); -/* Normal distribution PRNG */ -STC_API double crandf_norm(crand_t* rng, crandf_norm_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_API double crand_norm(crand_t* rng, crand_norm_t* dist); /* Main crand_t prng */ -STC_INLINE uint64_t crand_r(crand_t* rng) { +STC_INLINE uint64_t crand_u64(crand_t* rng) { enum {LR=24, RS=11, LS=3}; uint64_t *s = rng->state; const uint64_t out = (s[0] ^ (s[3] += s[4])) + s[1]; s[0] = s[1] ^ (s[1] >> RS); @@ -87,26 +86,11 @@ STC_INLINE uint64_t crand_r(crand_t* rng) { } /* Float64 random number in range [0.0, 1.0). */ -STC_INLINE double crandf_r(crand_t* rng) { - union {uint64_t i; double f;} u = {0x3FF0000000000000U | (crand_r(rng) >> 12)}; +STC_INLINE double crand_f64(crand_t* rng) { + union {uint64_t i; double f;} u = {0x3FF0000000000000U | (crand_u64(rng) >> 12)}; return u.f - 1.0; } -/* Float64 uniform distributed RNG, range [low, high). */ -STC_INLINE double crandf_unif(crand_t* rng, crandf_unif_t* dist) { - return crandf_r(rng)*dist->range + dist->lower; -} - -/* Init uniform distributed float64 RNG, range [low, high). */ -STC_INLINE crandf_unif_t crandf_unif_from(double low, double high) { - return c_LITERAL(crandf_unif_t){low, high - low}; -} - -/* Marsaglia polar method for gaussian/normal distribution, float64. */ -STC_INLINE crandf_norm_t crandf_norm_from(double mean, double stddev) { - return c_LITERAL(crandf_norm_t){mean, stddev, 0.0, 0}; -} - /* -------------------------- IMPLEMENTATION ------------------------- */ #if defined(i_implement) @@ -117,29 +101,34 @@ static crand_t crand_global = {{ 0x6a09e667a754166b }}; -STC_DEF void csrand(uint64_t seed) { - crand_global = crand_from(seed); -} +STC_DEF void csrand(uint64_t seed) + { crand_global = crand_init(seed); } -STC_DEF uint64_t crand(void) { - return crand_r(&crand_global); -} +STC_DEF uint64_t crand(void) + { return crand_u64(&crand_global); } + +STC_DEF double crandf(void) + { return crand_f64(&crand_global); } -STC_DEF double crandf(void) { - return crandf_r(&crand_global); +STC_INLINE uint64_t splitmix64(uint64_t s[1]) { + uint64_t z = (s[0] += 0x9e3779b97f4a7c15); + z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9; + z = (z ^ (z >> 27)) * 0x94d049bb133111eb; + return z ^ (z >> 31); } -/* rng.state[4] must be odd */ -STC_DEF crand_t crand_from(uint64_t seed) { +STC_DEF crand_t crand_init(uint64_t seed) { + /* rng.state[4] must be odd */ crand_t rng = {{seed + 0x26aa069ea2fb1a4d, seed*0x9e3779b97f4a7c15 + 0x70c72c95cd592d04, seed + 0x504f333d3aa0b359, - seed*0x6a09e667a754166b, seed<<1 | 1}}; + seed, seed<<1 | 1}}; + crand_u64(&rng); return rng; } /* Init unbiased uniform uint RNG with bounds [low, high] */ -STC_DEF crand_unif_t crand_unif_from(int64_t low, int64_t 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)}; dist.threshold = (uint64_t)(0 - dist.range) % dist.range; return dist; @@ -157,32 +146,30 @@ STC_DEF crand_unif_t crand_unif_from(int64_t low, int64_t high) { asm("mulq %3" : "=a"(*(lo)), "=d"(*(hi)) : "a"(a), "rm"(b)) #endif -/* Int uniform distributed RNG, range [low, high]. */ +/* Int64 uniform distributed RNG, range [low, high]. */ STC_DEF int64_t crand_unif(crand_t* rng, crand_unif_t* d) { -#ifdef c_umul128 uint64_t lo, hi; - do { c_umul128(crand_r(rng), d->range, &lo, &hi); } while (lo < d->threshold); - return d->lower + (int64_t)hi; +#ifdef c_umul128 + do { c_umul128(crand_u64(rng), d->range, &lo, &hi); } while (lo < d->threshold); #else - uint64_t x, r; - do { x = crand_r(rng); r = x % d->range; } while (x - r > -d->range); - return d->lower + r; + do { lo = crand_u64(rng); hi = lo % d->range; } while (lo - hi > -d->range); #endif + return d->lower + (int64_t)hi; } -/* Normal distribution PRNG */ -STC_DEF double crandf_norm(crand_t* rng, crandf_norm_t* dist) { +/* Normal distribution PRNG. Marsaglia polar method */ +STC_DEF double crand_norm(crand_t* rng, crand_norm_t* dist) { double u1, u2, s, m; if (dist->has_next++ & 1) - return dist->next * dist->stddev + dist->mean; + return dist->next*dist->stddev + dist->mean; do { - u1 = 2.0 * crandf_r(rng) - 1.0; - u2 = 2.0 * crandf_r(rng) - 1.0; + u1 = 2.0 * crand_f64(rng) - 1.0; + u2 = 2.0 * crand_f64(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; + dist->next = u2*m; + return (u1*m)*dist->stddev + dist->mean; } #endif diff --git a/misc/benchmarks/shootout_hashmaps.cpp b/misc/benchmarks/shootout_hashmaps.cpp index 39ad1786..947a35b4 100644 --- a/misc/benchmarks/shootout_hashmaps.cpp +++ b/misc/benchmarks/shootout_hashmaps.cpp @@ -35,6 +35,7 @@ KHASH_MAP_INIT_INT64(ii, IValue) // cmap template expansion #define i_key IKey #define i_val IValue +#define i_ssize int32_t // enable 2^K buckets like the rest. #define i_tag ii #define i_max_load_factor MAX_LOAD_FACTOR / 100.0f #include -- cgit v1.2.3 From 32df5677c9906661e91aad294e45a258e2eaab18 Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Thu, 30 Mar 2023 08:11:29 +0200 Subject: removed unneeded code --- include/stc/crand.h | 7 ------- 1 file changed, 7 deletions(-) (limited to 'include') diff --git a/include/stc/crand.h b/include/stc/crand.h index f46f2bd5..191d578a 100644 --- a/include/stc/crand.h +++ b/include/stc/crand.h @@ -110,13 +110,6 @@ STC_DEF uint64_t crand(void) STC_DEF double crandf(void) { return crand_f64(&crand_global); } -STC_INLINE uint64_t splitmix64(uint64_t s[1]) { - uint64_t z = (s[0] += 0x9e3779b97f4a7c15); - z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9; - z = (z ^ (z >> 27)) * 0x94d049bb133111eb; - return z ^ (z >> 31); -} - STC_DEF crand_t crand_init(uint64_t seed) { /* rng.state[4] must be odd */ crand_t rng = {{seed + 0x26aa069ea2fb1a4d, -- cgit v1.2.3 From a0a290645828c88597efce80f6b0f5a958cefa89 Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Thu, 30 Mar 2023 17:59:08 +0200 Subject: Added crand.h - Alternative API to crandom.h, which will be deprecated. --- README.md | 6 +-- docs/cpque_api.md | 8 +-- docs/crandom_api.md | 45 ++++++++--------- include/stc/clist.h | 4 +- include/stc/cqueue.h | 10 ++-- misc/benchmarks/picobench/picobench_cmap.cpp | 68 ++++++++++++------------- misc/benchmarks/picobench/picobench_csmap.cpp | 72 +++++++++++++-------------- misc/benchmarks/plotbench/cdeq_benchmark.cpp | 30 +++++------ misc/benchmarks/plotbench/clist_benchmark.cpp | 26 +++++----- misc/benchmarks/plotbench/cmap_benchmark.cpp | 34 ++++++------- misc/benchmarks/plotbench/cpque_benchmark.cpp | 32 ++++++------ misc/benchmarks/plotbench/csmap_benchmark.cpp | 34 ++++++------- misc/benchmarks/plotbench/cvec_benchmark.cpp | 22 ++++---- misc/benchmarks/shootout_hashmaps.cpp | 8 +-- misc/benchmarks/various/cbits_benchmark.cpp | 14 +++--- misc/benchmarks/various/prng_bench.cpp | 6 +-- misc/benchmarks/various/sso_bench.cpp | 14 +++--- misc/examples/birthday.c | 10 ++-- misc/examples/gauss2.c | 10 ++-- misc/examples/list.c | 7 ++- misc/examples/new_queue.c | 10 ++-- misc/examples/priority.c | 10 ++-- misc/examples/queue.c | 12 ++--- misc/examples/random.c | 16 +++--- 24 files changed, 249 insertions(+), 259 deletions(-) (limited to 'include') diff --git a/README.md b/README.md index 75a5357e..b5f9ceb7 100644 --- a/README.md +++ b/README.md @@ -60,7 +60,7 @@ Others ------ - [***ccommon*** - Generic safe macros and algorithms](docs/ccommon_api.md) - [***cregex*** - Regular expressions (extended from Rob Pike's regexp9)](docs/cregex_api.md) -- [***crandom*** - A novel very fast *PRNG* named **stc64**](docs/crandom_api.md) +- [***crand*** - A novel very fast *PRNG* named **stc64**](docs/crandom_api.md) - [***coption*** - getopt() alike command line args parser](docs/coption_api.md) Highlights @@ -343,7 +343,7 @@ once and if needed. Currently, define `i_extern` before including **clist** for It is possible to generate single headers by executing the python script `src/singleheader.py header-file > single`. Conveniently, `src\libstc.c` implements non-templated functions as shared symbols for **cstr**, **csview**, -**cbits** and **crandom**. When building in shared mode (-DSTC_HEADER), you may include this file in your project, +**cbits** and **crand**. When building in shared mode (-DSTC_HEADER), you may include this file in your project, or define your own as descibed above. ```c // stc_libs.c @@ -592,7 +592,7 @@ STC is generally very memory efficient. Type sizes: - Allows for `i_key*` template parameters instead of `i_val*` for all containers, not only for **cset** and **csset**. - Optimized *c_default_hash()*. Therefore *c_hash32()* and *c_hash64()* are removed (same speed). - Added *.._push()* and *.._emplace()* function to all containers to allow for more generic coding. -- Renamed global PRNGs *stc64_random()* and *stc64_srandom()* to *crandom()* and *csrandom()*. +- Renamed global PRNGs *stc64_random()* and *stc64_srandom()* to *crand()* and *csrand()*. - Added some examples and benchmarks for SSO and heterogenous lookup comparison with c++20 (string_bench_*.cpp). ## Brief summary of changes from version 2.x to 3.0 diff --git a/docs/cpque_api.md b/docs/cpque_api.md index 1396dc1f..962ee162 100644 --- a/docs/cpque_api.md +++ b/docs/cpque_api.md @@ -60,7 +60,7 @@ i_val cpque_X_value_clone(i_val value); ## Example ```c -#include +#include #include #define i_val int64_t @@ -71,15 +71,15 @@ i_val cpque_X_value_clone(i_val value); int main() { intptr_t N = 10000000; - stc64_t rng = stc64_new(1234); - stc64_uniform_t dist = stc64_uniform_new(0, N * 10); + crand_t rng = crand_init(1234); + crand_unif_t dist = crand_unif_init(0, N * 10); // Define heap cpque_i heap = {0}; // Push ten million random numbers to priority queue. c_forrange (N) - cpque_i_push(&heap, stc64_uniform(&rng, &dist)); + cpque_i_push(&heap, crand_unif(&rng, &dist)); // Add some negative ones. int nums[] = {-231, -32, -873, -4, -343}; diff --git a/docs/crandom_api.md b/docs/crandom_api.md index e69cc539..7281b2d7 100644 --- a/docs/crandom_api.md +++ b/docs/crandom_api.md @@ -1,4 +1,4 @@ -# STC [crandom](../include/stc/crandom.h): Pseudo Random Number Generator +# STC [crand](../include/stc/crand.h): Pseudo Random Number Generator ![Random](pics/random.jpg) This features a *64-bit PRNG* named **stc64**, and can generate bounded uniform and normal @@ -33,45 +33,40 @@ xoshiro and pcg (Vigna/O'Neill) PRNGs: https://www.pcg-random.org/posts/on-vigna ## Header file -All crandom definitions and prototypes are available by including a single header file. +All crand definitions and prototypes are available by including a single header file. ```c -#include +#include ``` ## Methods ```c -void csrandom(uint64_t seed); // seed global stc64 prng -uint64_t crandom(void); // global stc64_rand(rng) -double crandomf(void); // global stc64_randf(rng) +void csrand(uint64_t seed); // seed global stc64 prng +uint64_t crand(void); // global crand_u64(rng) +double crandf(void); // global crand_f64(rng) -stc64_t stc64_new(uint64_t seed); // stc64_init(s) is deprecated -stc64_t stc64_with_seq(uint64_t seed, uint64_t seq); // with unique stream +crand_t crand_init(uint64_t seed); // stc64_init(s) is deprecated +uint64_t crand_u64(crand_t* rng); // range [0, 2^64 - 1] +double crand_f64(crand_t* rng); // range [0.0, 1.0) -uint64_t stc64_rand(stc64_t* rng); // range [0, 2^64 - 1] -double stc64_randf(stc64_t* rng); // range [0.0, 1.0) +crand_unif_t crand_unif_init(int64_t low, int64_t high); // uniform-distribution +int64_t crand_unif(crand_t* rng, crand_unif_t* dist); // range [low, high] -stc64_uniform_t stc64_uniform_new(int64_t low, int64_t high); // uniform-distribution -int64_t stc64_uniform(stc64_t* rng, stc64_uniform_t* dist); // range [low, high] -stc64_uniformf_t stc64_uniformf_new(double lowf, double highf); -double stc64_uniformf(stc64_t* rng, stc64_uniformf_t* dist); // range [lowf, highf) - -stc64_normalf_t stc64_normalf_new(double mean, double stddev); // normal-distribution -double stc64_normalf(stc64_t* rng, stc64_normalf_t* dist); +crand_norm_t crand_norm_init(double mean, double stddev); // normal-distribution +double crand_norm(crand_t* rng, crand_norm_t* dist); ``` ## Types | Name | Type definition | Used to represent... | |:-------------------|:------------------------------------------|:-----------------------------| -| `stc64_t` | `struct {uint64_t state[4];}` | The PRNG engine type | -| `stc64_uniform_t` | `struct {int64_t lower; uint64_t range;}` | Integer uniform distribution | -| `stc64_uniformf_t` | `struct {double lower, range;}` | Real number uniform distr. | -| `stc64_normalf_t` | `struct {double mean, stddev;}` | Normal distribution type | +| `crand_t` | `struct {uint64_t state[4];}` | The PRNG engine type | +| `crand_unif_t` | `struct {int64_t lower; uint64_t range;}` | Integer uniform distribution | +| `crand_norm_t` | `struct {double mean, stddev;}` | Normal distribution type | ## Example ```c #include -#include +#include #include // Declare int -> int sorted map. Uses typetag 'i' for ints. @@ -89,13 +84,13 @@ int main() // Setup random engine with normal distribution. uint64_t seed = time(NULL); - stc64_t rng = stc64_new(seed); - stc64_normalf_t dist = stc64_normalf_new(Mean, StdDev); + crand_t rng = crand_init(seed); + crand_norm_t dist = crand_norm_init(Mean, StdDev); // Create histogram map csmap_i mhist = csmap_i_init(); c_forrange (N) { - int index = (int) round( stc64_normalf(&rng, &dist) ); + int index = (int)round(crand_norm(&rng, &dist)); csmap_i_emplace(&mhist, index, 0).ref->second += 1; } diff --git a/include/stc/clist.h b/include/stc/clist.h index eb72b888..fa26fd65 100644 --- a/include/stc/clist.h +++ b/include/stc/clist.h @@ -26,7 +26,7 @@ it also support both push_back() and push_front(), unlike std::forward_list: #include - #include + #include #define i_key int64_t #define i_tag ix @@ -38,7 +38,7 @@ { int n; for (int i = 0; i < 1000000; ++i) // one million - clist_ix_push_back(&list, crandom() >> 32); + clist_ix_push_back(&list, crand() >> 32); n = 0; c_foreach (i, clist_ix, list) if (++n % 10000 == 0) printf("%8d: %10zu\n", n, *i.ref); diff --git a/include/stc/cqueue.h b/include/stc/cqueue.h index 67909f8e..1934305a 100644 --- a/include/stc/cqueue.h +++ b/include/stc/cqueue.h @@ -22,7 +22,7 @@ */ // STC queue /* -#include +#include #include #define i_key int @@ -30,19 +30,19 @@ int main() { int n = 10000000; - stc64_t rng = stc64_new(1234); - stc64_uniform_t dist = stc64_uniform_new(0, n); + 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; i0; --i) { - int r = stc64_uniform(&rng, &dist); + int r = crand_unif(&rng, &dist); if (r & 1) ++n, cqueue_int_push(&Q, r); else diff --git a/misc/benchmarks/picobench/picobench_cmap.cpp b/misc/benchmarks/picobench/picobench_cmap.cpp index 3ffba5b9..bccbe70c 100644 --- a/misc/benchmarks/picobench/picobench_cmap.cpp +++ b/misc/benchmarks/picobench/picobench_cmap.cpp @@ -1,5 +1,5 @@ #define i_static -#include +#include #define i_static #include #include @@ -54,36 +54,36 @@ static void ins_and_erase_i(picobench::state& s) { MapInt map; map.max_load_factor((int)MaxLoadFactor100 / 100.0); - csrandom(seed); + csrand(seed); picobench::scope scope(s); c_forrange (s.iterations()) - map[crandom()]; + map[crand()]; map.clear(); - csrandom(seed); + csrand(seed); c_forrange (s.iterations()) - map[crandom()]; - csrandom(seed); + map[crand()]; + csrand(seed); c_forrange (s.iterations()) - map.erase(crandom()); + map.erase(crand()); s.set_result(map.size()); } /* static void ins_and_erase_cmap_i(picobench::state& s) { cmap_i map = cmap_i_init(); - csrandom(seed); + csrand(seed); picobench::scope scope(s); c_forrange (s.iterations()) - cmap_i_insert(&map, crandom(), 0); + cmap_i_insert(&map, crand(), 0); cmap_i_clear(&map); - csrandom(seed); + csrand(seed); c_forrange (s.iterations()) - cmap_i_insert(&map, crandom(), 0); - csrandom(seed); + cmap_i_insert(&map, crand(), 0); + csrand(seed); c_forrange (s.iterations()) - cmap_i_erase(&map, crandom()); + cmap_i_erase(&map, crand()); s.set_result(cmap_i_size(&map)); cmap_i_drop(&map); } @@ -91,18 +91,18 @@ static void ins_and_erase_cmap_i(picobench::state& s) static void ins_and_erase_cmap_x(picobench::state& s) { cmap_x map = cmap_x_init(); - csrandom(seed); + csrand(seed); picobench::scope scope(s); c_forrange (s.iterations()) - cmap_x_insert(&map, crandom(), 0); + cmap_x_insert(&map, crand(), 0); cmap_x_clear(&map); - csrandom(seed); + csrand(seed); c_forrange (s.iterations()) - cmap_x_insert(&map, crandom(), 0); - csrandom(seed); + cmap_x_insert(&map, crand(), 0); + csrand(seed); c_forrange (s.iterations()) - cmap_x_erase(&map, crandom()); + cmap_x_erase(&map, crand()); s.set_result(cmap_x_size(&map)); cmap_x_drop(&map); } @@ -124,11 +124,11 @@ static void ins_and_access_i(picobench::state& s) size_t result = 0; MapInt map; map.max_load_factor((int)MaxLoadFactor100 / 100.0); - csrandom(seed); + csrand(seed); picobench::scope scope(s); c_forrange (N1) - result += ++map[crandom() & mask]; + result += ++map[crand() & mask]; s.set_result(result); } @@ -137,11 +137,11 @@ static void ins_and_access_cmap_i(picobench::state& s) uint64_t mask = (1ull << s.arg()) - 1; size_t result = 0; cmap_i map = cmap_i_init(); - csrandom(seed); + csrand(seed); picobench::scope scope(s); c_forrange (N1) - result += ++cmap_i_insert(&map, crandom() & mask, 0).ref->second; + result += ++cmap_i_insert(&map, crand() & mask, 0).ref->second; s.set_result(result); cmap_i_drop(&map); } @@ -158,7 +158,7 @@ PICOBENCH_SUITE("Map3"); static void randomize(char* str, size_t len) { for (size_t k=0; k < len; ++k) { - union {uint64_t i; char c[8];} r = {.i = crandom()}; + union {uint64_t i; char c[8];} r = {.i = crand()}; for (unsigned i=0; i<8 && ksecond; } // reset rng back to inital state - csrandom(seed); + csrand(seed); // measure erase then iterate whole map c_forrange (n, s.iterations()) { - cmap_x_erase(&map, crandom()); + cmap_x_erase(&map, crand()); if (!(n & K)) c_foreach (i, cmap_x, map) result += i.ref->second; } diff --git a/misc/benchmarks/picobench/picobench_csmap.cpp b/misc/benchmarks/picobench/picobench_csmap.cpp index 5caab6cc..a6a97b14 100644 --- a/misc/benchmarks/picobench/picobench_csmap.cpp +++ b/misc/benchmarks/picobench/picobench_csmap.cpp @@ -1,6 +1,6 @@ #include #define i_static -#include +#include #define i_static #include #include @@ -71,20 +71,20 @@ template static void insert_i(picobench::state& s) { MapInt map; - csrandom(seed); + csrand(seed); picobench::scope scope(s); c_forrange (n, s.iterations()) - map.emplace(crandom() & 0xfffffff, n); + map.emplace(crand() & 0xfffffff, n); s.set_result(map.size()); } static void insert_csmap_i(picobench::state& s) { csmap_i map = csmap_i_init(); - csrandom(seed); + csrand(seed); picobench::scope scope(s); c_forrange (n, s.iterations()) - csmap_i_insert(&map, crandom() & 0xfffffff, n); + csmap_i_insert(&map, crand() & 0xfffffff, n); s.set_result(csmap_i_size(&map)); csmap_i_drop(&map); } @@ -103,21 +103,21 @@ static void ins_and_erase_i(picobench::state& s) size_t result = 0; uint64_t mask = (1ull << s.arg()) - 1; MapInt map; - csrandom(seed); + csrand(seed); picobench::scope scope(s); c_forrange (i, s.iterations()) - map.emplace(crandom() & mask, i); + map.emplace(crand() & mask, i); result = map.size(); map.clear(); - csrandom(seed); + csrand(seed); c_forrange (i, s.iterations()) - map[crandom() & mask] = i; + map[crand() & mask] = i; - csrandom(seed); + csrand(seed); c_forrange (s.iterations()) - map.erase(crandom() & mask); + map.erase(crand() & mask); s.set_result(result); } @@ -126,21 +126,21 @@ static void ins_and_erase_csmap_i(picobench::state& s) size_t result = 0; uint64_t mask = (1ull << s.arg()) - 1; csmap_i map = csmap_i_init(); - csrandom(seed); + csrand(seed); picobench::scope scope(s); c_forrange (i, s.iterations()) - csmap_i_insert(&map, crandom() & mask, i); + csmap_i_insert(&map, crand() & mask, i); result = csmap_i_size(&map); csmap_i_clear(&map); - csrandom(seed); + csrand(seed); c_forrange (i, s.iterations()) - csmap_i_insert_or_assign(&map, crandom() & mask, i); + csmap_i_insert_or_assign(&map, crand() & mask, i); - csrandom(seed); + csrand(seed); c_forrange (s.iterations()) - csmap_i_erase(&map, crandom() & mask); + csmap_i_erase(&map, crand() & mask); s.set_result(result); csmap_i_drop(&map); } @@ -158,12 +158,12 @@ static void ins_and_access_i(picobench::state& s) uint64_t mask = (1ull << s.arg()) - 1; size_t result = 0; MapInt map; - csrandom(seed); + csrand(seed); picobench::scope scope(s); c_forrange (s.iterations()) { - result += ++map[crandom() & mask]; - auto it = map.find(crandom() & mask); + result += ++map[crand() & mask]; + auto it = map.find(crand() & mask); if (it != map.end()) map.erase(it->first); } s.set_result(result + map.size()); @@ -174,12 +174,12 @@ static void ins_and_access_csmap_i(picobench::state& s) uint64_t mask = (1ull << s.arg()) - 1; size_t result = 0; csmap_i map = csmap_i_init(); - csrandom(seed); + csrand(seed); picobench::scope scope(s); c_forrange (s.iterations()) { - result += ++csmap_i_insert(&map, crandom() & mask, 0).ref->second; - const csmap_i_value* val = csmap_i_get(&map, crandom() & mask); + result += ++csmap_i_insert(&map, crand() & mask, 0).ref->second; + const csmap_i_value* val = csmap_i_get(&map, crand() & mask); if (val) csmap_i_erase(&map, val->first); } s.set_result(result + csmap_i_size(&map)); @@ -194,7 +194,7 @@ PICOBENCH(ins_and_access_csmap_i).P; PICOBENCH_SUITE("Map4"); static void randomize(char* str, int len) { - union {uint64_t i; char c[8];} r = {.i = crandom()}; + union {uint64_t i; char c[8];} r = {.i = crand()}; for (int i = len - 7, j = 0; i < len; ++j, ++i) str[i] = (r.c[j] & 63) + 48; } @@ -207,12 +207,12 @@ static void ins_and_access_s(picobench::state& s) MapStr map; picobench::scope scope(s); - csrandom(seed); + csrand(seed); c_forrange (s.iterations()) { randomize(&str[0], str.size()); map.emplace(str, str); } - csrandom(seed); + csrand(seed); c_forrange (s.iterations()) { randomize(&str[0], str.size()); result += map.erase(str); @@ -228,12 +228,12 @@ static void ins_and_access_csmap_s(picobench::state& s) csmap_str map = csmap_str_init(); picobench::scope scope(s); - csrandom(seed); + csrand(seed); c_forrange (s.iterations()) { randomize(buf, s.arg()); csmap_str_emplace(&map, buf, buf); } - csrandom(seed); + csrand(seed); c_forrange (s.iterations()) { randomize(buf, s.arg()); result += csmap_str_erase(&map, buf); @@ -262,22 +262,22 @@ static void iterate_x(picobench::state& s) uint64_t K = (1ull << s.arg()) - 1; picobench::scope scope(s); - csrandom(seed); + csrand(seed); size_t result = 0; // measure insert then iterate whole map c_forrange (n, s.iterations()) { - map[crandom()] = n; + map[crand()] = n; if (!(n & K)) for (auto const& keyVal : map) result += keyVal.second; } // reset rng back to inital state - csrandom(seed); + csrand(seed); // measure erase then iterate whole map c_forrange (n, s.iterations()) { - map.erase(crandom()); + map.erase(crand()); if (!(n & K)) for (auto const& keyVal : map) result += keyVal.second; } @@ -290,22 +290,22 @@ static void iterate_csmap_x(picobench::state& s) uint64_t K = (1ull << s.arg()) - 1; picobench::scope scope(s); - csrandom(seed); + csrand(seed); size_t result = 0; // measure insert then iterate whole map c_forrange (n, s.iterations()) { - csmap_x_insert_or_assign(&map, crandom(), n); + csmap_x_insert_or_assign(&map, crand(), n); if (!(n & K)) c_foreach (i, csmap_x, map) result += i.ref->second; } // reset rng back to inital state - csrandom(seed); + csrand(seed); // measure erase then iterate whole map c_forrange (n, s.iterations()) { - csmap_x_erase(&map, crandom()); + csmap_x_erase(&map, crand()); if (!(n & K)) c_foreach (i, csmap_x, map) result += i.ref->second; } diff --git a/misc/benchmarks/plotbench/cdeq_benchmark.cpp b/misc/benchmarks/plotbench/cdeq_benchmark.cpp index 1259cc07..a8399ea8 100644 --- a/misc/benchmarks/plotbench/cdeq_benchmark.cpp +++ b/misc/benchmarks/plotbench/cdeq_benchmark.cpp @@ -1,7 +1,7 @@ #include #include #define i_static -#include +#include #ifdef __cplusplus #include @@ -28,10 +28,10 @@ Sample test_std_deque() { { s.test[INSERT].t1 = clock(); container con; - csrandom(seed); - c_forrange (N/3) con.push_front(crandom() & mask1); - c_forrange (N/3) {con.push_back(crandom() & mask1); con.pop_front();} - c_forrange (N/3) con.push_back(crandom() & mask1); + csrand(seed); + c_forrange (N/3) con.push_front(crand() & mask1); + c_forrange (N/3) {con.push_back(crand() & mask1); con.pop_front();} + c_forrange (N/3) con.push_back(crand() & mask1); s.test[INSERT].t2 = clock(); s.test[INSERT].sum = con.size(); s.test[ERASE].t1 = clock(); @@ -40,13 +40,13 @@ Sample test_std_deque() { s.test[ERASE].sum = con.size(); }{ container con; - csrandom(seed); - c_forrange (N) con.push_back(crandom() & mask2); + csrand(seed); + c_forrange (N) con.push_back(crand() & mask2); s.test[FIND].t1 = clock(); size_t sum = 0; // Iteration - not inherent find - skipping //container::iterator it; - //c_forrange (S) if ((it = std::find(con.begin(), con.end(), crandom() & mask2)) != con.end()) sum += *it; + //c_forrange (S) if ((it = std::find(con.begin(), con.end(), crand() & mask2)) != con.end()) sum += *it; s.test[FIND].t2 = clock(); s.test[FIND].sum = sum; s.test[ITER].t1 = clock(); @@ -72,10 +72,10 @@ Sample test_stc_deque() { s.test[INSERT].t1 = clock(); container con = cdeq_x_init(); //cdeq_x_reserve(&con, N); - csrandom(seed); - c_forrange (N/3) cdeq_x_push_front(&con, crandom() & mask1); - c_forrange (N/3) {cdeq_x_push_back(&con, crandom() & mask1); cdeq_x_pop_front(&con);} - c_forrange (N/3) cdeq_x_push_back(&con, crandom() & mask1); + csrand(seed); + c_forrange (N/3) cdeq_x_push_front(&con, crand() & mask1); + c_forrange (N/3) {cdeq_x_push_back(&con, crand() & mask1); cdeq_x_pop_front(&con);} + c_forrange (N/3) cdeq_x_push_back(&con, crand() & mask1); s.test[INSERT].t2 = clock(); s.test[INSERT].sum = cdeq_x_size(&con); s.test[ERASE].t1 = clock(); @@ -84,13 +84,13 @@ Sample test_stc_deque() { s.test[ERASE].sum = cdeq_x_size(&con); cdeq_x_drop(&con); }{ - csrandom(seed); + csrand(seed); container con = cdeq_x_init(); - c_forrange (N) cdeq_x_push_back(&con, crandom() & mask2); + c_forrange (N) cdeq_x_push_back(&con, crand() & mask2); s.test[FIND].t1 = clock(); size_t sum = 0; //cdeq_x_iter it, end = cdeq_x_end(&con); - //c_forrange (S) if ((it = cdeq_x_find(&con, crandom() & mask2)).ref != end.ref) sum += *it.ref; + //c_forrange (S) if ((it = cdeq_x_find(&con, crand() & mask2)).ref != end.ref) sum += *it.ref; s.test[FIND].t2 = clock(); s.test[FIND].sum = sum; s.test[ITER].t1 = clock(); diff --git a/misc/benchmarks/plotbench/clist_benchmark.cpp b/misc/benchmarks/plotbench/clist_benchmark.cpp index 04c8e8cd..46bd2793 100644 --- a/misc/benchmarks/plotbench/clist_benchmark.cpp +++ b/misc/benchmarks/plotbench/clist_benchmark.cpp @@ -1,7 +1,7 @@ #include #include #define i_static -#include +#include #ifdef __cplusplus #include @@ -28,9 +28,9 @@ Sample test_std_forward_list() { { s.test[INSERT].t1 = clock(); container con; - csrandom(seed); - c_forrange (N/2) con.push_front(crandom() & mask1); - c_forrange (N/2) con.push_front(crandom() & mask1); + csrand(seed); + c_forrange (N/2) con.push_front(crand() & mask1); + c_forrange (N/2) con.push_front(crand() & mask1); s.test[INSERT].t2 = clock(); s.test[INSERT].sum = 0; s.test[ERASE].t1 = clock(); @@ -39,13 +39,13 @@ Sample test_std_forward_list() { s.test[ERASE].sum = 0; }{ container con; - csrandom(seed); - c_forrange (N) con.push_front(crandom() & mask2); + csrand(seed); + c_forrange (N) con.push_front(crand() & mask2); s.test[FIND].t1 = clock(); size_t sum = 0; container::iterator it; // Iteration - not inherent find - skipping - //c_forrange (S) if ((it = std::find(con.begin(), con.end(), crandom() & mask2)) != con.end()) sum += *it; + //c_forrange (S) if ((it = std::find(con.begin(), con.end(), crand() & mask2)) != con.end()) sum += *it; s.test[FIND].t2 = clock(); s.test[FIND].sum = sum; s.test[ITER].t1 = clock(); @@ -70,9 +70,9 @@ Sample test_stc_forward_list() { { s.test[INSERT].t1 = clock(); container con = clist_x_init(); - csrandom(seed); - c_forrange (N/2) clist_x_push_front(&con, crandom() & mask1); - c_forrange (N/2) clist_x_push_back(&con, crandom() & mask1); + csrand(seed); + c_forrange (N/2) clist_x_push_front(&con, crand() & mask1); + c_forrange (N/2) clist_x_push_back(&con, crand() & mask1); s.test[INSERT].t2 = clock(); s.test[INSERT].sum = 0; s.test[ERASE].t1 = clock(); @@ -81,13 +81,13 @@ Sample test_stc_forward_list() { s.test[ERASE].sum = 0; clist_x_drop(&con); }{ - csrandom(seed); + csrand(seed); container con = clist_x_init(); - c_forrange (N) clist_x_push_front(&con, crandom() & mask2); + c_forrange (N) clist_x_push_front(&con, crand() & mask2); s.test[FIND].t1 = clock(); size_t sum = 0; //clist_x_iter it, end = clist_x_end(&con); - //c_forrange (S) if ((it = clist_x_find(&con, crandom() & mask2)).ref != end.ref) sum += *it.ref; + //c_forrange (S) if ((it = clist_x_find(&con, crand() & mask2)).ref != end.ref) sum += *it.ref; s.test[FIND].t2 = clock(); s.test[FIND].sum = sum; s.test[ITER].t1 = clock(); diff --git a/misc/benchmarks/plotbench/cmap_benchmark.cpp b/misc/benchmarks/plotbench/cmap_benchmark.cpp index 7a8f29d2..0582d162 100644 --- a/misc/benchmarks/plotbench/cmap_benchmark.cpp +++ b/misc/benchmarks/plotbench/cmap_benchmark.cpp @@ -1,7 +1,7 @@ #include #include #define i_static -#include +#include #ifdef __cplusplus #include @@ -26,28 +26,28 @@ Sample test_std_unordered_map() { typedef std::unordered_map container; Sample s = {"std,unordered_map"}; { - csrandom(seed); + csrand(seed); s.test[INSERT].t1 = clock(); container con; - c_forrange (i, N/2) con.emplace(crandom() & mask1, i); + c_forrange (i, N/2) con.emplace(crand() & mask1, i); c_forrange (i, N/2) con.emplace(i, i); s.test[INSERT].t2 = clock(); s.test[INSERT].sum = con.size(); - csrandom(seed); + csrand(seed); s.test[ERASE].t1 = clock(); - c_forrange (N) con.erase(crandom() & mask1); + c_forrange (N) con.erase(crand() & mask1); s.test[ERASE].t2 = clock(); s.test[ERASE].sum = con.size(); }{ container con; - csrandom(seed); - c_forrange (i, N/2) con.emplace(crandom() & mask1, i); + csrand(seed); + c_forrange (i, N/2) con.emplace(crand() & mask1, i); c_forrange (i, N/2) con.emplace(i, i); - csrandom(seed); + csrand(seed); s.test[FIND].t1 = clock(); size_t sum = 0; container::iterator it; - c_forrange (N) if ((it = con.find(crandom() & mask1)) != con.end()) sum += it->second; + c_forrange (N) if ((it = con.find(crand() & mask1)) != con.end()) sum += it->second; s.test[FIND].t2 = clock(); s.test[FIND].sum = sum; s.test[ITER].t1 = clock(); @@ -70,30 +70,30 @@ Sample test_stc_unordered_map() { typedef cmap_x container; Sample s = {"STC,unordered_map"}; { - csrandom(seed); + csrand(seed); s.test[INSERT].t1 = clock(); container con = cmap_x_init(); - c_forrange (i, N/2) cmap_x_insert(&con, crandom() & mask1, i); + c_forrange (i, N/2) cmap_x_insert(&con, crand() & mask1, i); c_forrange (i, N/2) cmap_x_insert(&con, i, i); s.test[INSERT].t2 = clock(); s.test[INSERT].sum = cmap_x_size(&con); - csrandom(seed); + csrand(seed); s.test[ERASE].t1 = clock(); - c_forrange (N) cmap_x_erase(&con, crandom() & mask1); + c_forrange (N) cmap_x_erase(&con, crand() & mask1); s.test[ERASE].t2 = clock(); s.test[ERASE].sum = cmap_x_size(&con); cmap_x_drop(&con); }{ container con = cmap_x_init(); - csrandom(seed); - c_forrange (i, N/2) cmap_x_insert(&con, crandom() & mask1, i); + csrand(seed); + c_forrange (i, N/2) cmap_x_insert(&con, crand() & mask1, i); c_forrange (i, N/2) cmap_x_insert(&con, i, i); - csrandom(seed); + csrand(seed); s.test[FIND].t1 = clock(); size_t sum = 0; const cmap_x_value* val; c_forrange (N) - if ((val = cmap_x_get(&con, crandom() & mask1))) + if ((val = cmap_x_get(&con, crand() & mask1))) sum += val->second; s.test[FIND].t2 = clock(); s.test[FIND].sum = sum; diff --git a/misc/benchmarks/plotbench/cpque_benchmark.cpp b/misc/benchmarks/plotbench/cpque_benchmark.cpp index a729c09f..da092b7f 100644 --- a/misc/benchmarks/plotbench/cpque_benchmark.cpp +++ b/misc/benchmarks/plotbench/cpque_benchmark.cpp @@ -1,7 +1,7 @@ #include #include #define i_static -#include +#include #define i_val float #define i_cmp -c_default_cmp @@ -11,19 +11,17 @@ #include static const uint32_t seed = 1234; +static const int N = 10000000; void std_test() { - stc64_t rng; - int N = 10000000; - std::priority_queue, std::greater> pq; - rng = stc64_new(seed); + csrand(seed); clock_t start = clock(); c_forrange (i, N) - pq.push((float) stc64_randf(&rng)*100000); + pq.push((float) crandf()*100000.0); - printf("Built priority queue: %f secs\n", (clock() - start) / (float) CLOCKS_PER_SEC); + printf("Built priority queue: %f secs\n", (float)(clock() - start)/(float)CLOCKS_PER_SEC); printf("%g ", pq.top()); start = clock(); @@ -31,32 +29,30 @@ void std_test() pq.pop(); } - printf("\npopped PQ: %f secs\n\n", (clock() - start) / (float) CLOCKS_PER_SEC); + printf("\npopped PQ: %f secs\n\n", (float)(clock() - start)/(float)CLOCKS_PER_SEC); } void stc_test() { - stc64_t rng; - int N = 10000000, M = 10; + int N = 10000000; c_auto (cpque_f, pq) { - rng = stc64_new(seed); + csrand(seed); clock_t start = clock(); - c_forrange (i, N) - cpque_f_push(&pq, (float) stc64_randf(&rng)*100000); + c_forrange (i, N) { + cpque_f_push(&pq, (float) crandf()*100000); + } - printf("Built priority queue: %f secs\n", (clock() - start) / (float) CLOCKS_PER_SEC); + printf("Built priority queue: %f secs\n", (float)(clock() - start)/(float)CLOCKS_PER_SEC); printf("%g ", *cpque_f_top(&pq)); - c_forrange (i, M) { + start = clock(); + c_forrange (i, N) { cpque_f_pop(&pq); } - start = clock(); - c_forrange (i, M, N) - cpque_f_pop(&pq); printf("\npopped PQ: %f secs\n", (clock() - start) / (float) CLOCKS_PER_SEC); } } diff --git a/misc/benchmarks/plotbench/csmap_benchmark.cpp b/misc/benchmarks/plotbench/csmap_benchmark.cpp index 46bd695c..da3fc9cc 100644 --- a/misc/benchmarks/plotbench/csmap_benchmark.cpp +++ b/misc/benchmarks/plotbench/csmap_benchmark.cpp @@ -1,7 +1,7 @@ #include #include #define i_static -#include +#include #ifdef __cplusplus #include @@ -26,28 +26,28 @@ Sample test_std_map() { typedef std::map container; Sample s = {"std,map"}; { - csrandom(seed); + csrand(seed); s.test[INSERT].t1 = clock(); container con; - c_forrange (i, N/2) con.emplace(crandom() & mask1, i); + c_forrange (i, N/2) con.emplace(crand() & mask1, i); c_forrange (i, N/2) con.emplace(i, i); s.test[INSERT].t2 = clock(); s.test[INSERT].sum = con.size(); - csrandom(seed); + csrand(seed); s.test[ERASE].t1 = clock(); - c_forrange (N) con.erase(crandom() & mask1); + c_forrange (N) con.erase(crand() & mask1); s.test[ERASE].t2 = clock(); s.test[ERASE].sum = con.size(); }{ container con; - csrandom(seed); - c_forrange (i, N/2) con.emplace(crandom() & mask1, i); + csrand(seed); + c_forrange (i, N/2) con.emplace(crand() & mask1, i); c_forrange (i, N/2) con.emplace(i, i); - csrandom(seed); + csrand(seed); s.test[FIND].t1 = clock(); size_t sum = 0; container::iterator it; - c_forrange (N) if ((it = con.find(crandom() & mask1)) != con.end()) sum += it->second; + c_forrange (N) if ((it = con.find(crand() & mask1)) != con.end()) sum += it->second; s.test[FIND].t2 = clock(); s.test[FIND].sum = sum; s.test[ITER].t1 = clock(); @@ -71,30 +71,30 @@ Sample test_stc_map() { typedef csmap_x container; Sample s = {"STC,map"}; { - csrandom(seed); + csrand(seed); s.test[INSERT].t1 = clock(); container con = csmap_x_init(); - c_forrange (i, N/2) csmap_x_insert(&con, crandom() & mask1, i); + c_forrange (i, N/2) csmap_x_insert(&con, crand() & mask1, i); c_forrange (i, N/2) csmap_x_insert(&con, i, i); s.test[INSERT].t2 = clock(); s.test[INSERT].sum = csmap_x_size(&con); - csrandom(seed); + csrand(seed); s.test[ERASE].t1 = clock(); - c_forrange (N) csmap_x_erase(&con, crandom() & mask1); + c_forrange (N) csmap_x_erase(&con, crand() & mask1); s.test[ERASE].t2 = clock(); s.test[ERASE].sum = csmap_x_size(&con); csmap_x_drop(&con); }{ container con = csmap_x_init(); - csrandom(seed); - c_forrange (i, N/2) csmap_x_insert(&con, crandom() & mask1, i); + csrand(seed); + c_forrange (i, N/2) csmap_x_insert(&con, crand() & mask1, i); c_forrange (i, N/2) csmap_x_insert(&con, i, i); - csrandom(seed); + csrand(seed); s.test[FIND].t1 = clock(); size_t sum = 0; const csmap_x_value* val; c_forrange (N) - if ((val = csmap_x_get(&con, crandom() & mask1))) + if ((val = csmap_x_get(&con, crand() & mask1))) sum += val->second; s.test[FIND].t2 = clock(); s.test[FIND].sum = sum; diff --git a/misc/benchmarks/plotbench/cvec_benchmark.cpp b/misc/benchmarks/plotbench/cvec_benchmark.cpp index fe7e09fb..b605f4e6 100644 --- a/misc/benchmarks/plotbench/cvec_benchmark.cpp +++ b/misc/benchmarks/plotbench/cvec_benchmark.cpp @@ -1,7 +1,7 @@ #include #include #define i_static -#include +#include #ifdef __cplusplus #include @@ -28,8 +28,8 @@ Sample test_std_vector() { { s.test[INSERT].t1 = clock(); container con; - csrandom(seed); - c_forrange (N) con.push_back(crandom() & mask1); + csrand(seed); + c_forrange (N) con.push_back(crand() & mask1); s.test[INSERT].t2 = clock(); s.test[INSERT].sum = con.size(); s.test[ERASE].t1 = clock(); @@ -38,13 +38,13 @@ Sample test_std_vector() { s.test[ERASE].sum = con.size(); }{ container con; - csrandom(seed); - c_forrange (N) con.push_back(crandom() & mask2); + csrand(seed); + c_forrange (N) con.push_back(crand() & mask2); s.test[FIND].t1 = clock(); size_t sum = 0; //container::iterator it; // Iteration - not inherent find - skipping - //c_forrange (S) if ((it = std::find(con.begin(), con.end(), crandom() & mask2)) != con.end()) sum += *it; + //c_forrange (S) if ((it = std::find(con.begin(), con.end(), crand() & mask2)) != con.end()) sum += *it; s.test[FIND].t2 = clock(); s.test[FIND].sum = sum; s.test[ITER].t1 = clock(); @@ -70,8 +70,8 @@ Sample test_stc_vector() { { s.test[INSERT].t1 = clock(); container con = cvec_x_init(); - csrandom(seed); - c_forrange (N) cvec_x_push_back(&con, crandom() & mask1); + csrand(seed); + c_forrange (N) cvec_x_push_back(&con, crand() & mask1); s.test[INSERT].t2 = clock(); s.test[INSERT].sum = cvec_x_size(&con); s.test[ERASE].t1 = clock(); @@ -80,13 +80,13 @@ Sample test_stc_vector() { s.test[ERASE].sum = cvec_x_size(&con); cvec_x_drop(&con); }{ - csrandom(seed); + csrand(seed); container con = cvec_x_init(); - c_forrange (N) cvec_x_push_back(&con, crandom() & mask2); + c_forrange (N) cvec_x_push_back(&con, crand() & mask2); s.test[FIND].t1 = clock(); size_t sum = 0; //cvec_x_iter it, end = cvec_x_end(&con); - //c_forrange (S) if ((it = cvec_x_find(&con, crandom() & mask2)).ref != end.ref) sum += *it.ref; + //c_forrange (S) if ((it = cvec_x_find(&con, crand() & mask2)).ref != end.ref) sum += *it.ref; s.test[FIND].t2 = clock(); s.test[FIND].sum = sum; s.test[ITER].t1 = clock(); diff --git a/misc/benchmarks/shootout_hashmaps.cpp b/misc/benchmarks/shootout_hashmaps.cpp index 947a35b4..bae9a42b 100644 --- a/misc/benchmarks/shootout_hashmaps.cpp +++ b/misc/benchmarks/shootout_hashmaps.cpp @@ -1,6 +1,6 @@ #include #include -#include +#include #define MAX_LOAD_FACTOR 85 @@ -40,8 +40,8 @@ KHASH_MAP_INIT_INT64(ii, IValue) #define i_max_load_factor MAX_LOAD_FACTOR / 100.0f #include -#define SEED(s) rng = stc64_new(s) -#define RAND(N) (stc64_rand(&rng) & (((uint64_t)1 << N) - 1)) +#define SEED(s) rng = crand_init(s) +#define RAND(N) (crand_u64(&rng) & (((uint64_t)1 << N) - 1)) #define CMAP_SETUP(X, Key, Value) cmap_##X map = cmap_##X##_init() #define CMAP_PUT(X, key, val) cmap_##X##_insert_or_assign(&map, key, val).ref->second @@ -314,7 +314,7 @@ int main(int argc, char* argv[]) unsigned keybits = argc >= 3 ? atoi(argv[2]) : DEFAULT_KEYBITS; unsigned n = n_mill * 1000000; unsigned N1 = n, N2 = n, N3 = n, N4 = n, N5 = n; - stc64_t rng; + crand_t rng; size_t seed = 123456; // time(NULL); printf("\nUnordered hash map shootout\n"); diff --git a/misc/benchmarks/various/cbits_benchmark.cpp b/misc/benchmarks/various/cbits_benchmark.cpp index dd709db1..1764f556 100644 --- a/misc/benchmarks/various/cbits_benchmark.cpp +++ b/misc/benchmarks/various/cbits_benchmark.cpp @@ -5,7 +5,7 @@ enum{ N=1<<22 }; // 4.2 mill. #define i_static -#include +#include #define i_type cbits #define i_len N #include @@ -39,12 +39,12 @@ int main(int argc, char **argv) one_sec_delay(); total = 0; - csrandom(seed); + csrand(seed); current_time = get_time_in_ms(); c_forrange (40 * N) { - uint64_t r = crandom(); + uint64_t r = crand(); bools[r & (N-1)] = r & 1<<29; } @@ -66,13 +66,13 @@ int main(int argc, char **argv) one_sec_delay(); total = 0; - csrandom(seed); + csrand(seed); current_time = get_time_in_ms(); bitset bits; c_forrange (40 * N) { - uint64_t r = crandom(); + uint64_t r = crand(); bits[r & (N-1)] = r & 1<<29; } @@ -92,13 +92,13 @@ int main(int argc, char **argv) one_sec_delay(); total = 0; - csrandom(seed); + csrand(seed); current_time = get_time_in_ms(); cbits bits2 = cbits_with_size(N, false); c_forrange (40 * N) { - uint64_t r = crandom(); + uint64_t r = crand(); cbits_set_value(&bits2, r & (N-1), r & 1<<29); } diff --git a/misc/benchmarks/various/prng_bench.cpp b/misc/benchmarks/various/prng_bench.cpp index be07f799..234e3805 100644 --- a/misc/benchmarks/various/prng_bench.cpp +++ b/misc/benchmarks/various/prng_bench.cpp @@ -2,7 +2,7 @@ #include #include #include -#include +#include static inline uint64_t rotl64(const uint64_t x, const int k) { return (x << k) | (x >> (64 - k)); } @@ -124,7 +124,7 @@ int main(void) { enum {N = 500000000}; uint16_t* recipient = new uint16_t[N]; - static stc64_t rng; + static crand_t rng; init_state(rng.state, 12345123); std::mt19937 mt(12345123); @@ -187,7 +187,7 @@ int main(void) beg = clock(); for (size_t i = 0; i < N; i++) - recipient[i] = stc64_rand(&rng); + recipient[i] = crand_u64(&rng); end = clock(); cout << "stc64:\t\t" << (float(end - beg) / CLOCKS_PER_SEC) diff --git a/misc/benchmarks/various/sso_bench.cpp b/misc/benchmarks/various/sso_bench.cpp index 0fffef7a..993ff1bb 100644 --- a/misc/benchmarks/various/sso_bench.cpp +++ b/misc/benchmarks/various/sso_bench.cpp @@ -2,7 +2,7 @@ #include #include -#include +#include #include #define i_type StcVec @@ -30,7 +30,7 @@ static inline std::string randomString_STD(int strsize) { char* p = &s[0]; union { uint64_t u8; uint8_t b[8]; } r; for (int i = 0; i < strsize; ++i) { - if ((i & 7) == 0) r.u8 = crandom() & 0x3f3f3f3f3f3f3f3f; + if ((i & 7) == 0) r.u8 = crand() & 0x3f3f3f3f3f3f3f3f; p[i] = CHARS[r.b[i & 7]]; } return s; @@ -41,7 +41,7 @@ static inline cstr randomString_STC(int strsize) { char* p = cstr_data(&s); union { uint64_t u8; uint8_t b[8]; } r; for (int i = 0; i < strsize; ++i) { - if ((i & 7) == 0) r.u8 = crandom() & 0x3f3f3f3f3f3f3f3f; + if ((i & 7) == 0) r.u8 = crand() & 0x3f3f3f3f3f3f3f3f; p[i] = CHARS[r.b[i & 7]]; } return s; @@ -85,7 +85,7 @@ int main() { // VECTOR WITH STRINGS - csrandom(seed); + csrand(seed); sum = 0, n = 0; std::cerr << "\nstrsize\tmsecs\tstd::vector, size=" << BENCHMARK_SIZE << "\n"; for (int strsize = 1; strsize <= MAX_STRING_SIZE; strsize += 2) { @@ -95,7 +95,7 @@ int main() { } std::cout << "Avg:\t" << sum/n << '\n'; - csrandom(seed); + csrand(seed); sum = 0, n = 0; std::cerr << "\nstrsize\tmsecs\tcvec, size=" << BENCHMARK_SIZE << "\n"; for (int strsize = 1; strsize <= MAX_STRING_SIZE; strsize += 2) { @@ -108,7 +108,7 @@ int main() { // SORTED SET WITH STRINGS - csrandom(seed); + csrand(seed); sum = 0, n = 0; std::cerr << "\nstrsize\tmsecs\tstd::set, size=" << BENCHMARK_SIZE/16 << "\n"; for (int strsize = 1; strsize <= MAX_STRING_SIZE; strsize += 2) { @@ -118,7 +118,7 @@ int main() { } std::cout << "Avg:\t" << sum/n << '\n'; - csrandom(seed); + csrand(seed); sum = 0, n = 0; std::cerr << "\nstrsize\tmsecs\tcsset, size=" << BENCHMARK_SIZE/16 << "\n"; for (int strsize = 1; strsize <= MAX_STRING_SIZE; strsize += 2) { diff --git a/misc/examples/birthday.c b/misc/examples/birthday.c index 2b52cc48..c301128a 100644 --- a/misc/examples/birthday.c +++ b/misc/examples/birthday.c @@ -1,7 +1,7 @@ #include #include #include -#include +#include #define i_tag ic #define i_key uint64_t @@ -17,11 +17,11 @@ static void test_repeats(void) const static uint64_t mask = (1ull << BITS) - 1; printf("birthday paradox: value range: 2^%d, testing repeats of 2^%d values\n", BITS, BITS_TEST); - stc64_t rng = stc64_new(seed); + crand_t rng = crand_init(seed); cmap_ic m = cmap_ic_with_capacity(N); c_forrange (i, N) { - uint64_t k = stc64_rand(&rng) & mask; + uint64_t k = crand_u64(&rng) & mask; int v = cmap_ic_insert(&m, k, 0).ref->second += 1; if (v > 1) printf("repeated value %" PRIu64 " (%d) at 2^%d\n", k, v, (int)log2((double)i)); @@ -38,12 +38,12 @@ void test_distribution(void) { enum {BITS = 26}; printf("distribution test: 2^%d values\n", BITS); - stc64_t rng = stc64_new(seed); + crand_t rng = crand_init(seed); const size_t N = 1ull << BITS ; cmap_x map = {0}; c_forrange (N) { - uint64_t k = stc64_rand(&rng); + uint64_t k = crand_u64(&rng); cmap_x_insert(&map, k & 0xf, 0).ref->second += 1; } diff --git a/misc/examples/gauss2.c b/misc/examples/gauss2.c index 7fede5aa..df709d03 100644 --- a/misc/examples/gauss2.c +++ b/misc/examples/gauss2.c @@ -1,7 +1,7 @@ #include #include -#include +#include #include // Declare int -> int sorted map. @@ -13,21 +13,21 @@ int main() { enum {N = 5000000}; uint64_t seed = (uint64_t)time(NULL); - stc64_t rng = stc64_new(seed); - const double Mean = round(stc64_randf(&rng)*98.f - 49.f), StdDev = stc64_randf(&rng)*10.f + 1.f, Scale = 74.f; + crand_t rng = crand_init(seed); + const double Mean = round(crand_f64(&rng)*98.f - 49.f), StdDev = crand_f64(&rng)*10.f + 1.f, Scale = 74.f; printf("Demo of gaussian / normal distribution of %d random samples\n", N); printf("Mean %f, StdDev %f\n", Mean, StdDev); // Setup random engine with normal distribution. - stc64_normalf_t dist = stc64_normalf_new(Mean, StdDev); + crand_norm_t dist = crand_norm_init(Mean, StdDev); // Create and init histogram map with defered destruct csmap_int hist = {0}; cstr bar = {0}; c_forrange (N) { - int index = (int)round( stc64_normalf(&rng, &dist) ); + int index = (int)round(crand_norm(&rng, &dist)); csmap_int_insert(&hist, index, 0).ref->second += 1; } diff --git a/misc/examples/list.c b/misc/examples/list.c index 9f0b2504..eb81067d 100644 --- a/misc/examples/list.c +++ b/misc/examples/list.c @@ -1,7 +1,7 @@ #include #include #include -#include +#include #define i_type DList #define i_val double @@ -11,11 +11,10 @@ int main() { const int n = 3000000; DList list = {0}; - stc64_t rng = stc64_new(1234567); - stc64_uniformf_t dist = stc64_uniformf_new(100.0f, n); + crand_t rng = crand_init(1234567); int m = 0; c_forrange (n) - DList_push_back(&list, stc64_uniformf(&rng, &dist)), ++m; + DList_push_back(&list, crand_f64(&rng)*n + 100), ++m; double sum = 0.0; printf("sumarize %d:\n", m); diff --git a/misc/examples/new_queue.c b/misc/examples/new_queue.c index f7887ffb..044e44cb 100644 --- a/misc/examples/new_queue.c +++ b/misc/examples/new_queue.c @@ -1,4 +1,4 @@ -#include +#include #include #include #include @@ -22,20 +22,20 @@ int point_cmp(const Point* a, const Point* b) { int main() { int n = 50000000; - stc64_t rng = stc64_new((uint64_t)time(NULL)); - stc64_uniform_t dist = stc64_uniform_new(0, n); + crand_t rng = crand_init((uint64_t)time(NULL)); + crand_unif_t dist = crand_unif_init(0, n); IQ Q = {0}; // Push 50'000'000 random numbers onto the queue. c_forrange (n) - IQ_push(&Q, (int)stc64_uniform(&rng, &dist)); + IQ_push(&Q, (int)crand_unif(&rng, &dist)); // Push or pop on the queue 50 million times printf("befor: size %" c_ZI ", capacity %" c_ZI "\n", IQ_size(&Q), IQ_capacity(&Q)); c_forrange (n) { - int r = (int)stc64_uniform(&rng, &dist); + int r = (int)crand_unif(&rng, &dist); if (r & 3) IQ_push(&Q, r); else diff --git a/misc/examples/priority.c b/misc/examples/priority.c index d3d0283e..95dd3183 100644 --- a/misc/examples/priority.c +++ b/misc/examples/priority.c @@ -1,7 +1,7 @@ #include #include -#include +#include #define i_val int64_t #define i_cmp -c_default_cmp // min-heap (increasing values) @@ -10,22 +10,22 @@ int main() { intptr_t N = 10000000; - stc64_t rng = stc64_new((uint64_t)time(NULL)); - stc64_uniform_t dist = stc64_uniform_new(0, N * 10); + crand_t rng = crand_init((uint64_t)time(NULL)); + crand_unif_t dist = crand_unif_init(0, N * 10); cpque_i heap = {0}; // Push ten million random numbers to priority queue printf("Push %" c_ZI " numbers\n", N); c_forrange (N) - cpque_i_push(&heap, stc64_uniform(&rng, &dist)); + cpque_i_push(&heap, crand_unif(&rng, &dist)); // push some negative numbers too. c_forlist (i, int, {-231, -32, -873, -4, -343}) cpque_i_push(&heap, *i.ref); c_forrange (N) - cpque_i_push(&heap, stc64_uniform(&rng, &dist)); + cpque_i_push(&heap, crand_unif(&rng, &dist)); puts("Extract the hundred smallest."); c_forrange (100) { diff --git a/misc/examples/queue.c b/misc/examples/queue.c index 0f387d52..83c18d09 100644 --- a/misc/examples/queue.c +++ b/misc/examples/queue.c @@ -1,4 +1,4 @@ -#include +#include #include #define i_val int @@ -7,20 +7,20 @@ int main() { int n = 100000000; - stc64_uniform_t dist; - stc64_t rng = stc64_new(1234); - dist = stc64_uniform_new(0, n); + crand_unif_t dist; + crand_t rng = crand_init(1234); + dist = crand_unif_init(0, n); cqueue_i queue = {0}; // Push ten million random numbers onto the queue. c_forrange (n) - cqueue_i_push(&queue, (int)stc64_uniform(&rng, &dist)); + cqueue_i_push(&queue, (int)crand_unif(&rng, &dist)); // Push or pop on the queue ten million times printf("%d\n", n); c_forrange (n) { // forrange uses initial n only. - int r = (int)stc64_uniform(&rng, &dist); + int r = (int)crand_unif(&rng, &dist); if (r & 1) ++n, cqueue_i_push(&queue, r); else diff --git a/misc/examples/random.c b/misc/examples/random.c index e27279a0..ea9c483e 100644 --- a/misc/examples/random.c +++ b/misc/examples/random.c @@ -1,12 +1,12 @@ #include #include -#include +#include int main() { const size_t N = 1000000000; const uint64_t seed = (uint64_t)time(NULL), range = 1000000; - stc64_t rng = stc64_new(seed); + crand_t rng = crand_init(seed); int64_t sum; clock_t diff, before; @@ -15,28 +15,28 @@ int main() sum = 0; before = clock(); c_forrange (N) { - sum += (uint32_t)stc64_rand(&rng); + sum += (uint32_t)crand_u64(&rng); } diff = clock() - before; printf("full range\t\t: %f secs, %" c_ZI ", avg: %f\n", (float)diff / CLOCKS_PER_SEC, N, (float)sum / (float)N); - stc64_uniform_t dist1 = stc64_uniform_new(0, range); - rng = stc64_new(seed); + crand_unif_t dist1 = crand_unif_init(0, range); + rng = crand_init(seed); sum = 0; before = clock(); c_forrange (N) { - sum += stc64_uniform(&rng, &dist1); // unbiased + sum += crand_unif(&rng, &dist1); // unbiased } diff = clock() - before; printf("unbiased 0-%" PRIu64 "\t: %f secs, %" c_ZI ", avg: %f\n", range, (float)diff/CLOCKS_PER_SEC, N, (float)sum / (float)N); sum = 0; - rng = stc64_new(seed); + rng = crand_init(seed); before = clock(); c_forrange (N) { - sum += (int64_t)(stc64_rand(&rng) % (range + 1)); // biased + sum += (int64_t)(crand_u64(&rng) % (range + 1)); // biased } diff = clock() - before; printf("biased 0-%" PRIu64 " \t: %f secs, %" c_ZI ", avg: %f\n", -- cgit v1.2.3 From 4f1d00baf916ceaa27b1a29a80117abdb662d656 Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Fri, 31 Mar 2023 14:00:13 +0200 Subject: Small change in crand_u64(). Use - instead of ^ in result. --- include/stc/crand.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/include/stc/crand.h b/include/stc/crand.h index 191d578a..122c1f21 100644 --- a/include/stc/crand.h +++ b/include/stc/crand.h @@ -77,12 +77,12 @@ STC_API double crand_norm(crand_t* rng, crand_norm_t* dist); /* Main crand_t prng */ STC_INLINE uint64_t crand_u64(crand_t* rng) { - enum {LR=24, RS=11, LS=3}; uint64_t *s = rng->state; - const uint64_t out = (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))) + out; - return out; + uint64_t *s = rng->state; + const uint64_t result = s[0] + s[1] - (s[3] += s[4]); + s[0] = s[1] ^ (s[1] >> 11); + s[1] = s[2] + (s[2] << 3); + s[2] = ((s[2] << 24) | (s[2] >> (64 - 24))) + result; + return result; } /* Float64 random number in range [0.0, 1.0). */ -- cgit v1.2.3 From 56c394ede691143a32d53f4094df37dc49dc0a29 Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Fri, 31 Mar 2023 18:58:36 +0200 Subject: Change in crand. --- include/stc/crand.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'include') diff --git a/include/stc/crand.h b/include/stc/crand.h index 122c1f21..a1b7250d 100644 --- a/include/stc/crand.h +++ b/include/stc/crand.h @@ -78,7 +78,7 @@ STC_API double crand_norm(crand_t* rng, crand_norm_t* dist); /* Main crand_t prng */ STC_INLINE uint64_t crand_u64(crand_t* rng) { uint64_t *s = rng->state; - const uint64_t result = s[0] + s[1] - (s[3] += s[4]); + const uint64_t result = (s[0] ^ (s[3] += s[4])) + s[1]; s[0] = s[1] ^ (s[1] >> 11); s[1] = s[2] + (s[2] << 3); s[2] = ((s[2] << 24) | (s[2] >> (64 - 24))) + result; @@ -111,12 +111,12 @@ STC_DEF double crandf(void) { return crand_f64(&crand_global); } STC_DEF crand_t crand_init(uint64_t seed) { - /* rng.state[4] must be odd */ - crand_t rng = {{seed + 0x26aa069ea2fb1a4d, - seed*0x9e3779b97f4a7c15 + 0x70c72c95cd592d04, - seed + 0x504f333d3aa0b359, - seed, seed<<1 | 1}}; - crand_u64(&rng); + crand_t rng; uint64_t* s = rng.state; + 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; return rng; } -- cgit v1.2.3 From 5693ae9ae0d1a18627ba540e0240da010b282296 Mon Sep 17 00:00:00 2001 From: Tyge Lovset Date: Fri, 31 Mar 2023 22:08:07 +0200 Subject: Added stc/extend.h: A generalized way to type-safely extend a container with new members which can be accessed from the template parameters. See examples/functor.c --- README.md | 2 +- include/stc/carc.h | 18 ++++++------- include/stc/cbox.h | 18 ++++++------- include/stc/cdeq.h | 10 +++---- include/stc/clist.h | 6 ++--- include/stc/cmap.h | 10 +++---- include/stc/cpque.h | 2 +- include/stc/csmap.h | 2 +- include/stc/cstack.h | 2 +- include/stc/cvec.h | 12 ++++----- include/stc/extend.h | 65 +++++++++++++++++++++++++++++++++++++++++++++ include/stc/priv/template.h | 4 +++ misc/examples/functor.c | 47 +++++++++++++------------------- misc/examples/new_list.c | 4 +-- misc/examples/new_map.c | 2 +- misc/examples/new_queue.c | 2 +- misc/examples/new_smap.c | 2 +- misc/examples/new_vec.c | 4 +-- 18 files changed, 135 insertions(+), 77 deletions(-) create mode 100644 include/stc/extend.h (limited to 'include') diff --git a/README.md b/README.md index b5f9ceb7..3f985b7a 100644 --- a/README.md +++ b/README.md @@ -518,7 +518,7 @@ typedef struct Dataset { ... // Implementation -#define i_opt c_is_forward // flag that the container was forward declared. +#define i_is_forward // flag that the container was forward declared. #define i_val struct Point #define i_tag pnt #include diff --git a/include/stc/carc.h b/include/stc/carc.h index 02bbaf52..5d38d2e7 100644 --- a/include/stc/carc.h +++ b/include/stc/carc.h @@ -90,7 +90,7 @@ typedef i_keyraw _cx_raw; #define _i_atomic_inc(v) (void)(++*(v)) #define _i_atomic_dec_and_test(v) !(--*(v)) #endif -#if !c_option(c_is_forward) +#ifndef i_is_forward _cx_deftypes(_c_carc_types, _cx_self, i_key); #endif struct _cx_memb(_rep_) { catomic_long counter; i_key value; }; @@ -177,8 +177,8 @@ STC_INLINE void _cx_memb(_assign)(_cx_self* self, _cx_self ptr) { 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* x, const _cx_self* y) { - _cx_raw rx = i_keyto(x->get), ry = i_keyto(y->get); +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 @@ -187,24 +187,24 @@ STC_INLINE int _cx_memb(_cmp)(const _cx_self* x, const _cx_self* y) { 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* x, const _cx_self* y) { - _cx_raw rx = i_keyto(x->get), ry = i_keyto(y->get); +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* x, const _cx_self* y) - { return _cx_memb(_cmp)(x, y) == 0; } +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); } -STC_INLINE uint64_t _cx_memb(_hash)(const _cx_self* x) - { _cx_raw rx = i_keyto(x->get); 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 #undef _i_eq diff --git a/include/stc/cbox.h b/include/stc/cbox.h index 641fcbfc..6cc86c6f 100644 --- a/include/stc/cbox.h +++ b/include/stc/cbox.h @@ -76,7 +76,7 @@ int main() { #include "priv/template.h" typedef i_keyraw _cx_raw; -#if !c_option(c_is_forward) +#ifndef i_is_forward _cx_deftypes(_c_cbox_types, _cx_self, i_key); #endif @@ -163,8 +163,8 @@ STC_INLINE void _cx_memb(_assign)(_cx_self* self, _cx_self* moved) { 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* x, const _cx_self* y) { - _cx_raw rx = i_keyto(x->get), ry = i_keyto(y->get); +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 @@ -173,24 +173,24 @@ STC_INLINE int _cx_memb(_cmp)(const _cx_self* x, const _cx_self* y) { 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* x, const _cx_self* y) { - _cx_raw rx = i_keyto(x->get), ry = i_keyto(y->get); +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* x, const _cx_self* y) - { return _cx_memb(_cmp)(x, y) == 0; } +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); } -STC_INLINE uint64_t _cx_memb(_hash)(const _cx_self* x) - { _cx_raw rx = i_keyto(x->get); 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 #undef _i_eq diff --git a/include/stc/cdeq.h b/include/stc/cdeq.h index 09c0a7f8..a032722b 100644 --- a/include/stc/cdeq.h +++ b/include/stc/cdeq.h @@ -36,7 +36,7 @@ #endif #include "priv/template.h" -#if !c_option(c_is_forward) +#ifndef i_is_forward _cx_deftypes(_c_cdeq_types, _cx_self, i_key); #endif typedef i_keyraw _cx_raw; @@ -196,10 +196,10 @@ _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* x, const _cx_self* y) { - if (x->_len != y->_len) return false; - for (intptr_t i = 0; i < x->_len; ++i) { - const _cx_raw _rx = i_keyto(x->data+i), _ry = i_keyto(y->data+i); +_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; diff --git a/include/stc/clist.h b/include/stc/clist.h index fa26fd65..ca02ae3c 100644 --- a/include/stc/clist.h +++ b/include/stc/clist.h @@ -82,7 +82,7 @@ #endif #include "priv/template.h" -#if !c_option(c_is_forward) +#ifndef i_is_forward _cx_deftypes(_c_clist_types, _cx_self, i_key); #endif _cx_deftypes(_c_clist_complete_types, _cx_self, dummy); @@ -204,8 +204,8 @@ _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* x, const _cx_self* y) { - _cx_iter i = _cx_memb(_begin)(x), j = _cx_memb(_begin)(y); +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; diff --git a/include/stc/cmap.h b/include/stc/cmap.h index c840523f..437a5982 100644 --- a/include/stc/cmap.h +++ b/include/stc/cmap.h @@ -82,7 +82,7 @@ typedef struct { int64_t idx; uint8_t hx; } chash_bucket_t; #define _i_size i_ssize #endif #include "priv/template.h" -#if !c_option(c_is_forward) +#ifndef i_is_forward _cx_deftypes(_c_chash_types, _cx_self, i_key, i_val, i_ssize, _i_MAP_ONLY, _i_SET_ONLY); #endif @@ -277,11 +277,11 @@ _cx_memb(_erase_at)(_cx_self* self, _cx_iter it) { } STC_INLINE bool -_cx_memb(_eq)(const _cx_self* m1, const _cx_self* m2) { - if (_cx_memb(_size)(m1) != _cx_memb(_size)(m2)) return false; - for (_cx_iter i = _cx_memb(_begin)(m1); 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_rawkey _raw = i_keyto(_i_keyref(i.ref)); - if (!_cx_memb(_contains)(m2, _raw)) return false; + if (!_cx_memb(_contains)(other, _raw)) return false; } return true; } diff --git a/include/stc/cpque.h b/include/stc/cpque.h index 00eaa49e..f3ca7081 100644 --- a/include/stc/cpque.h +++ b/include/stc/cpque.h @@ -32,7 +32,7 @@ #endif #include "priv/template.h" -#if !c_option(c_is_forward) +#ifndef i_is_forward _cx_deftypes(_c_cpque_types, _cx_self, i_key); #endif typedef i_keyraw _cx_raw; diff --git a/include/stc/csmap.h b/include/stc/csmap.h index 50593ba3..d0a877c4 100644 --- a/include/stc/csmap.h +++ b/include/stc/csmap.h @@ -80,7 +80,7 @@ int main(void) { #define _i_size i_ssize #endif #include "priv/template.h" -#if !c_option(c_is_forward) +#ifndef i_is_forward _cx_deftypes(_c_aatree_types, _cx_self, i_key, i_val, i_ssize, _i_MAP_ONLY, _i_SET_ONLY); #endif diff --git a/include/stc/cstack.h b/include/stc/cstack.h index f0c930e5..0f855dc9 100644 --- a/include/stc/cstack.h +++ b/include/stc/cstack.h @@ -33,7 +33,7 @@ #endif #include "priv/template.h" -#if !c_option(c_is_forward) +#ifndef i_is_forward #ifdef i_capacity #define i_no_clone _cx_deftypes(_c_cstack_fixed, _cx_self, i_key, i_capacity); diff --git a/include/stc/cvec.h b/include/stc/cvec.h index 8f35e5fc..4fe5ddab 100644 --- a/include/stc/cvec.h +++ b/include/stc/cvec.h @@ -39,7 +39,7 @@ struct MyStruct { #include #define i_key int -#define i_opt c_is_forward // forward declared +#define i_is_forward // forward declared #define i_tag i32 #include @@ -73,7 +73,7 @@ int main() { #endif #include "priv/template.h" -#if !c_option(c_is_forward) +#ifndef i_is_forward _cx_deftypes(_c_cvec_types, _cx_self, i_key); #endif typedef i_keyraw _cx_raw; @@ -234,10 +234,10 @@ _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* x, const _cx_self* y) { - if (x->_len != y->_len) return false; - for (intptr_t i = 0; i < x->_len; ++i) { - const _cx_raw _rx = i_keyto(x->data+i), _ry = i_keyto(y->data+i); +_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; diff --git a/include/stc/extend.h b/include/stc/extend.h new file mode 100644 index 00000000..a3efe02d --- /dev/null +++ b/include/stc/extend.h @@ -0,0 +1,65 @@ +/* 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 +#include + +#ifdef i_key_str + #define _i_key cstr +#elif defined i_keyclass + #define _i_key i_keyclass +#elif defined i_keyboxed + #define _i_key i_keyboxed +#elif defined i_key + #define _i_key i_key +#endif + +#ifdef i_val_str + #define _i_val cstr +#elif defined i_valclass + #define _i_val i_valclass +#elif defined i_valboxed + #define _i_val i_valboxed +#elif defined i_val + #define _i_val i_val +#endif + +#ifdef _i_key + c_PASTE(forward_, i_con)(i_type, _i_key, _i_val); +#else + c_PASTE(forward_, i_con)(i_type, _i_val); +#endif + +typedef struct { + i_ext; + i_type get; +} c_PASTE(i_type, Ext); + +#define c_getcon(cptr) c_container_of(cptr, _cx_memb(Ext), get) + +#define i_is_forward +#define _i_inc +#include _i_inc +#undef _i_inc +#undef _i_key +#undef _i_val +#undef i_con \ No newline at end of file diff --git a/include/stc/priv/template.h b/include/stc/priv/template.h index e352f488..d9e38dba 100644 --- a/include/stc/priv/template.h +++ b/include/stc/priv/template.h @@ -96,6 +96,9 @@ #endif #endif +#if c_option(c_is_forward) + #define i_is_forward +#endif #if c_option(c_no_cmp) #define i_no_cmp #endif @@ -341,6 +344,7 @@ #undef i_no_hash #undef i_no_clone #undef i_no_emplace +#undef i_is_forward #undef _i_prefix #undef _i_expandby diff --git a/misc/examples/functor.c b/misc/examples/functor.c index f8074c3a..45158cd1 100644 --- a/misc/examples/functor.c +++ b/misc/examples/functor.c @@ -6,35 +6,24 @@ // i_hash/i_eq: has self for cmap and cset types only #include -#include -#include -#include -#include -// predeclare -forward_cpque(ipque, int); - -struct { - ipque Q; - bool (*less)(const int*, const int*); -} typedef IPQueue; - - -#define i_type ipque +#define i_type IPQue #define i_val int -#define i_opt c_is_forward // needed to avoid re-type-define container type -#define i_less(x, y) c_container_of(self, IPQueue, Q)->less(x, y) -#include +#define i_ext bool (*less)(const int*, const int*) +#define i_less(x, y) c_getcon(self)->less(x, y) +#define i_con cpque +#include -void print_queue(const char* name, IPQueue q) { +void print_queue(const char* name, IPQueExt q) { // NB: make a clone because there is no way to traverse // priority_queue's content without erasing the queue. - IPQueue copy = {ipque_clone(q.Q), q.less}; + IPQueExt copy = {q.less, IPQue_clone(q.get)}; - for (printf("%s: \t", name); !ipque_empty(©.Q); ipque_pop(©.Q)) - printf("%d ", *ipque_top(©.Q)); + for (printf("%s: \t", name); !IPQue_empty(©.get); IPQue_pop(©.get)) + printf("%d ", *IPQue_top(©.get)); puts(""); - ipque_drop(©.Q); + + IPQue_drop(©.get); } static bool int_less(const int* x, const int* y) { return *x < *y; } @@ -49,21 +38,21 @@ int main() printf("%d ", data[i]); puts(""); - IPQueue q1 = {ipque_init(), int_less}; // Max priority queue - IPQueue minq1 = {ipque_init(), int_greater}; // Min priority queue - IPQueue q5 = {ipque_init(), int_lambda}; // Using lambda to compare elements. + IPQueExt q1 = {int_less}; // Max priority queue + IPQueExt minq1 = {int_greater}; // Min priority queue + IPQueExt q5 = {int_lambda}; // Using lambda to compare elements. c_forrange (i, n) - ipque_push(&q1.Q, data[i]); + IPQue_push(&q1.get, data[i]); print_queue("q1", q1); c_forrange (i, n) - ipque_push(&minq1.Q, data[i]); + IPQue_push(&minq1.get, data[i]); print_queue("minq1", minq1); c_forrange (i, n) - ipque_push(&q5.Q, data[i]); + IPQue_push(&q5.get, data[i]); print_queue("q5", q5); - c_drop(ipque, &q1.Q, &minq1.Q, &q5.Q); + c_drop(IPQue, &q1.get, &minq1.get, &q5.get); } diff --git a/misc/examples/new_list.c b/misc/examples/new_list.c index eae4b8f5..8b291d34 100644 --- a/misc/examples/new_list.c +++ b/misc/examples/new_list.c @@ -11,7 +11,7 @@ typedef struct { #define i_val int #define i_tag i32 -#define i_opt c_is_forward +#define i_is_forward #include typedef struct Point { int x, y; } Point; @@ -22,7 +22,7 @@ int point_cmp(const Point* a, const Point* b) { #define i_val Point #define i_cmp point_cmp -#define i_opt c_is_forward +#define i_is_forward #define i_tag pnt #include diff --git a/misc/examples/new_map.c b/misc/examples/new_map.c index 4b02c46a..3a4f934d 100644 --- a/misc/examples/new_map.c +++ b/misc/examples/new_map.c @@ -26,7 +26,7 @@ int point_cmp(const Point* a, const Point* b) { #define i_val int #define i_cmp point_cmp #define i_hash c_default_hash -#define i_opt c_is_forward +#define i_is_forward #define i_tag pnt #include diff --git a/misc/examples/new_queue.c b/misc/examples/new_queue.c index 044e44cb..916f4dbc 100644 --- a/misc/examples/new_queue.c +++ b/misc/examples/new_queue.c @@ -12,7 +12,7 @@ int point_cmp(const Point* a, const Point* b) { } #define i_val Point #define i_cmp point_cmp -#define i_opt c_is_forward +#define i_is_forward #define i_tag pnt #include diff --git a/misc/examples/new_smap.c b/misc/examples/new_smap.c index d85d5c75..d8245b8b 100644 --- a/misc/examples/new_smap.c +++ b/misc/examples/new_smap.c @@ -20,7 +20,7 @@ int point_cmp(const Point* a, const Point* b) { #define i_key Point #define i_val int #define i_cmp point_cmp -#define i_opt c_is_forward +#define i_is_forward #include // cstr => cstr map diff --git a/misc/examples/new_vec.c b/misc/examples/new_vec.c index 988b78d9..df443b7f 100644 --- a/misc/examples/new_vec.c +++ b/misc/examples/new_vec.c @@ -10,7 +10,7 @@ struct MyStruct { } typedef MyStruct; #define i_val int -#define i_opt c_is_forward +#define i_is_forward #define i_tag i32 #include @@ -18,7 +18,7 @@ typedef struct Point { int x, y; } Point; #define i_val Point #define i_less(a, b) a->x < b->x || (a->x == b->x && a->y < b->y) -#define i_opt c_is_forward +#define i_is_forward #define i_tag pnt #include -- cgit v1.2.3 From b81d7e44bd84a3c8513980a71a06d939f44af16b Mon Sep 17 00:00:00 2001 From: Tyge Lovset Date: Sat, 1 Apr 2023 21:19:26 +0200 Subject: Update of stc/extend.h --- include/stc/extend.h | 5 +++-- include/stc/priv/template.h | 8 +++----- misc/examples/functor.c | 2 +- 3 files changed, 7 insertions(+), 8 deletions(-) (limited to 'include') diff --git a/include/stc/extend.h b/include/stc/extend.h index a3efe02d..a8cb5f5b 100644 --- a/include/stc/extend.h +++ b/include/stc/extend.h @@ -50,7 +50,7 @@ #endif typedef struct { - i_ext; + i_extend; i_type get; } c_PASTE(i_type, Ext); @@ -62,4 +62,5 @@ typedef struct { #undef _i_inc #undef _i_key #undef _i_val -#undef i_con \ No newline at end of file +#undef i_con +#undef i_extend diff --git a/include/stc/priv/template.h b/include/stc/priv/template.h index d9e38dba..5ea0cf4f 100644 --- a/include/stc/priv/template.h +++ b/include/stc/priv/template.h @@ -25,7 +25,7 @@ #ifndef STC_TEMPLATE_H_INCLUDED #define STC_TEMPLATE_H_INCLUDED - #define _cx_self c_PASTE(_i_prefix, i_tag) + #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) @@ -38,10 +38,8 @@ #define _cx_node _cx_memb(_node) #endif -#ifdef i_type - #define i_tag i_type - #undef _i_prefix - #define _i_prefix +#ifndef i_type + #define i_type c_PASTE(_i_prefix, i_tag) #endif #ifndef i_ssize diff --git a/misc/examples/functor.c b/misc/examples/functor.c index 45158cd1..7cc770d0 100644 --- a/misc/examples/functor.c +++ b/misc/examples/functor.c @@ -9,7 +9,7 @@ #define i_type IPQue #define i_val int -#define i_ext bool (*less)(const int*, const int*) +#define i_extend bool (*less)(const int*, const int*) #define i_less(x, y) c_getcon(self)->less(x, y) #define i_con cpque #include -- cgit v1.2.3 From 4abc7fe5bae28b7765d448ca8210548a9f0fa287 Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Sun, 2 Apr 2023 22:13:48 +0200 Subject: Renamed c_flt_last(i) => c_flt_n(i) in algo/filter.h --- docs/ccommon_api.md | 16 ++++++++-------- include/stc/algo/filter.h | 2 +- misc/examples/list.c | 4 ++-- misc/examples/prime.c | 2 +- 4 files changed, 12 insertions(+), 12 deletions(-) (limited to 'include') diff --git a/docs/ccommon_api.md b/docs/ccommon_api.md index 46966fd9..164abafe 100644 --- a/docs/ccommon_api.md +++ b/docs/ccommon_api.md @@ -85,14 +85,14 @@ Iterate containers with stop-criteria and chained range filtering. | `c_forfilter (it, ctype, container, filter)` | Filter out items in chain with && | | `c_forfilter_it (it, ctype, startit, filter)` | Filter from startit position | -| Built-in filter | Description | -|:----------------------------------|:-------------------------------------| -| `c_flt_skip(it, numItems)` | Skip numItems (inc count) | -| `c_flt_take(it, numItems)` | Take numItems (inc count) | -| `c_flt_skipwhile(it, predicate)` | Skip items until predicate is false | -| `c_flt_takewhile(it, predicate)` | Take items until predicate is false | -| `c_flt_count(it)` | Increment current and return value | -| `c_flt_last(it)` | Get value of last count/skip*/take* | +| Built-in filter | Description | +|:----------------------------------|:----------------------------------------| +| `c_flt_skip(it, numItems)` | Skip numItems (inc count) | +| `c_flt_take(it, numItems)` | Take numItems (inc count) | +| `c_flt_skipwhile(it, predicate)` | Skip items until predicate is false | +| `c_flt_takewhile(it, predicate)` | Take items until predicate is false | +| `c_flt_count(it)` | Increment current and return count | +| `c_flt_n(it)` | Return n items passed count/skip*/take* | ```c // Example: #include diff --git a/include/stc/algo/filter.h b/include/stc/algo/filter.h index 111d3273..d0687561 100644 --- a/include/stc/algo/filter.h +++ b/include/stc/algo/filter.h @@ -56,7 +56,7 @@ int main() #define c_flt_take(i, n) _flt_take(&(i).b, n) #define c_flt_takewhile(i, pred) _flt_takewhile(&(i).b, pred) #define c_flt_count(i) ++(i).b.s1[(i).b.s1top++] -#define c_flt_last(i) (i).b.s1[(i).b.s1top - 1] +#define c_flt_n(i) (i).b.s1[(i).b.s1top - 1] #define c_forfilter(i, C, cnt, filter) \ c_forfilter_it(i, C, C##_begin(&cnt), filter) diff --git a/misc/examples/list.c b/misc/examples/list.c index eb81067d..620c2037 100644 --- a/misc/examples/list.c +++ b/misc/examples/list.c @@ -23,14 +23,14 @@ int main() { printf("sum %f\n\n", sum); c_forfilter (i, DList, list, c_flt_take(i, 10)) - printf("%8d: %10f\n", c_flt_last(i), *i.ref); + printf("%8d: %10f\n", c_flt_n(i), *i.ref); puts("sort"); DList_sort(&list); // qsort O(n*log n) puts("sorted"); c_forfilter (i, DList, list, c_flt_take(i, 10)) - printf("%8d: %10f\n", c_flt_last(i), *i.ref); + printf("%8d: %10f\n", c_flt_n(i), *i.ref); puts(""); DList_drop(&list); diff --git a/misc/examples/prime.c b/misc/examples/prime.c index 34d64f10..d78f3ad3 100644 --- a/misc/examples/prime.c +++ b/misc/examples/prime.c @@ -47,7 +47,7 @@ int main(void) c_flt_take(i, 50) ){ printf("%lld ", *i.ref); - if (c_flt_last(i) % 10 == 0) puts(""); + if (c_flt_n(i) % 10 == 0) puts(""); } cbits_drop(&primes); -- cgit v1.2.3 From e88b655ca8cf28d357f5088c205857954ad269e2 Mon Sep 17 00:00:00 2001 From: Tyge Lovset Date: Mon, 3 Apr 2023 07:35:39 +0200 Subject: Renamed c_flt_n() => c_flt_getcount(), and c_flt_count() => c_flt_counter(). --- docs/ccommon_api.md | 24 ++++++++++++------------ include/stc/algo/filter.h | 6 +++--- misc/examples/list.c | 4 ++-- misc/examples/prime.c | 2 +- 4 files changed, 18 insertions(+), 18 deletions(-) (limited to 'include') diff --git a/docs/ccommon_api.md b/docs/ccommon_api.md index 164abafe..6a0b4ee7 100644 --- a/docs/ccommon_api.md +++ b/docs/ccommon_api.md @@ -85,14 +85,14 @@ Iterate containers with stop-criteria and chained range filtering. | `c_forfilter (it, ctype, container, filter)` | Filter out items in chain with && | | `c_forfilter_it (it, ctype, startit, filter)` | Filter from startit position | -| Built-in filter | Description | -|:----------------------------------|:----------------------------------------| -| `c_flt_skip(it, numItems)` | Skip numItems (inc count) | -| `c_flt_take(it, numItems)` | Take numItems (inc count) | -| `c_flt_skipwhile(it, predicate)` | Skip items until predicate is false | -| `c_flt_takewhile(it, predicate)` | Take items until predicate is false | -| `c_flt_count(it)` | Increment current and return count | -| `c_flt_n(it)` | Return n items passed count/skip*/take* | +| Built-in filter | Description | +|:----------------------------------|:-------------------------------------------| +| `c_flt_skip(it, numItems)` | Skip numItems (inc count) | +| `c_flt_take(it, numItems)` | Take numItems (inc count) | +| `c_flt_skipwhile(it, predicate)` | Skip items until predicate is false | +| `c_flt_takewhile(it, predicate)` | Take items until predicate is false | +| `c_flt_counter(it)` | Increment current and return count | +| `c_flt_getcount(it)` | Number of items passed skip*/take*/counter | ```c // Example: #include @@ -110,9 +110,9 @@ int main() { crange R = crange_make(1001, INT32_MAX, 2); c_forfilter (i, crange, R, - isPrime(*i.ref) && - c_flt_skip(i, 24) && - c_flt_count(i) % 15 == 1 && + isPrime(*i.ref) && + c_flt_skip(i, 24) && + c_flt_counter(i) % 15 == 1 && c_flt_take(i, 10) ){ printf(" %lld", *i.ref); @@ -121,7 +121,7 @@ int main() { } // out: 1171 1283 1409 1493 1607 1721 1847 1973 2081 2203 ``` -Note that `c_flt_take()` and `c_flt_takewhile()`breaks the loop on false. +Note that `c_flt_take()` and `c_flt_takewhile()` breaks the loop on false. ## Generators diff --git a/include/stc/algo/filter.h b/include/stc/algo/filter.h index d0687561..e133577c 100644 --- a/include/stc/algo/filter.h +++ b/include/stc/algo/filter.h @@ -51,12 +51,12 @@ int main() // c_forfilter: -#define c_flt_skip(i, n) (c_flt_count(i) > (n)) +#define c_flt_skip(i, n) (c_flt_counter(i) > (n)) #define c_flt_skipwhile(i, pred) ((i).b.s2[(i).b.s2top++] |= !(pred)) #define c_flt_take(i, n) _flt_take(&(i).b, n) #define c_flt_takewhile(i, pred) _flt_takewhile(&(i).b, pred) -#define c_flt_count(i) ++(i).b.s1[(i).b.s1top++] -#define c_flt_n(i) (i).b.s1[(i).b.s1top - 1] +#define c_flt_counter(i) ++(i).b.s1[(i).b.s1top++] +#define c_flt_getcount(i) (i).b.s1[(i).b.s1top - 1] #define c_forfilter(i, C, cnt, filter) \ c_forfilter_it(i, C, C##_begin(&cnt), filter) diff --git a/misc/examples/list.c b/misc/examples/list.c index 620c2037..363d7fec 100644 --- a/misc/examples/list.c +++ b/misc/examples/list.c @@ -23,14 +23,14 @@ int main() { printf("sum %f\n\n", sum); c_forfilter (i, DList, list, c_flt_take(i, 10)) - printf("%8d: %10f\n", c_flt_n(i), *i.ref); + printf("%8d: %10f\n", c_flt_getcount(i), *i.ref); puts("sort"); DList_sort(&list); // qsort O(n*log n) puts("sorted"); c_forfilter (i, DList, list, c_flt_take(i, 10)) - printf("%8d: %10f\n", c_flt_n(i), *i.ref); + printf("%8d: %10f\n", c_flt_getcount(i), *i.ref); puts(""); DList_drop(&list); diff --git a/misc/examples/prime.c b/misc/examples/prime.c index d78f3ad3..a576a85c 100644 --- a/misc/examples/prime.c +++ b/misc/examples/prime.c @@ -47,7 +47,7 @@ int main(void) c_flt_take(i, 50) ){ printf("%lld ", *i.ref); - if (c_flt_n(i) % 10 == 0) puts(""); + if (c_flt_getcount(i) % 10 == 0) puts(""); } cbits_drop(&primes); -- cgit v1.2.3 From a3dc31d5393d051ad4dacb314452d3c6ec8a74b7 Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Mon, 3 Apr 2023 12:43:50 +0200 Subject: Split priv/template.h in two files to make mksingle.sh work. --- include/stc/algo/csort.h | 6 ++-- include/stc/carc.h | 2 +- include/stc/cbox.h | 2 +- include/stc/cdeq.h | 2 +- include/stc/clist.h | 2 +- include/stc/cmap.h | 2 +- include/stc/cpque.h | 2 +- include/stc/csmap.h | 6 +--- include/stc/cstack.h | 2 +- include/stc/cvec.h | 2 +- include/stc/priv/altnames.h | 3 -- include/stc/priv/template.h | 64 ++--------------------------------- include/stc/priv/untemplate.h | 78 +++++++++++++++++++++++++++++++++++++++++++ misc/examples/forfilter.c | 16 ++++----- 14 files changed, 99 insertions(+), 90 deletions(-) create mode 100644 include/stc/priv/untemplate.h (limited to 'include') diff --git a/include/stc/algo/csort.h b/include/stc/algo/csort.h index c452064f..02ac4e34 100644 --- a/include/stc/algo/csort.h +++ b/include/stc/algo/csort.h @@ -20,8 +20,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -#include -#include +#include "../ccommon.h" +#include "../priv/template.h" /* Generic Quicksort in C, performs as fast as c++ std::sort(). template params: @@ -86,4 +86,4 @@ static inline void c_PASTE(cqsort_, i_tag)(i_val arr[], intptr_t lo, intptr_t hi static inline void c_PASTE(csort_, i_tag)(i_val arr[], intptr_t n) { c_PASTE(cqsort_, i_tag)(arr, 0, n - 1); } -#include +#include "../priv/untemplate.h" diff --git a/include/stc/carc.h b/include/stc/carc.h index 5d38d2e7..16d3a2d4 100644 --- a/include/stc/carc.h +++ b/include/stc/carc.h @@ -210,4 +210,4 @@ STC_INLINE uint64_t _cx_memb(_hash)(const _cx_self* self) #undef _i_eq #undef _i_atomic_inc #undef _i_atomic_dec_and_test -#include "priv/template.h" +#include "priv/untemplate.h" diff --git a/include/stc/cbox.h b/include/stc/cbox.h index 6cc86c6f..4d2cb1f1 100644 --- a/include/stc/cbox.h +++ b/include/stc/cbox.h @@ -194,4 +194,4 @@ STC_INLINE uint64_t _cx_memb(_hash)(const _cx_self* self) #endif #undef _i_eq -#include "priv/template.h" +#include "priv/untemplate.h" diff --git a/include/stc/cdeq.h b/include/stc/cdeq.h index a032722b..ef1700f5 100644 --- a/include/stc/cdeq.h +++ b/include/stc/cdeq.h @@ -442,5 +442,5 @@ _cx_memb(_value_cmp)(const _cx_value* x, const _cx_value* y) { #endif // !c_no_cmp #endif // !_i_queue #endif // IMPLEMENTATION -#include "priv/template.h" #define CDEQ_H_INCLUDED +#include "priv/untemplate.h" diff --git a/include/stc/clist.h b/include/stc/clist.h index ca02ae3c..6e6b6d45 100644 --- a/include/stc/clist.h +++ b/include/stc/clist.h @@ -404,4 +404,4 @@ STC_DEF bool _cx_memb(_sort_with)(_cx_self* self, int(*cmp)(const _cx_value*, co #endif // !c_no_cmp #endif // i_implement #define CLIST_H_INCLUDED -#include "priv/template.h" +#include "priv/untemplate.h" diff --git a/include/stc/cmap.h b/include/stc/cmap.h index 437a5982..1976738d 100644 --- a/include/stc/cmap.h +++ b/include/stc/cmap.h @@ -481,4 +481,4 @@ _cx_memb(_erase_entry)(_cx_self* self, _cx_value* _val) { #undef _i_MAP_ONLY #undef _i_SET_ONLY #define CMAP_H_INCLUDED -#include "priv/template.h" +#include "priv/untemplate.h" diff --git a/include/stc/cpque.h b/include/stc/cpque.h index f3ca7081..023c9d27 100644 --- a/include/stc/cpque.h +++ b/include/stc/cpque.h @@ -160,4 +160,4 @@ _cx_memb(_push)(_cx_self* self, _cx_value value) { #endif #define CPQUE_H_INCLUDED -#include "priv/template.h" +#include "priv/untemplate.h" diff --git a/include/stc/csmap.h b/include/stc/csmap.h index d0a877c4..716c1bfe 100644 --- a/include/stc/csmap.h +++ b/include/stc/csmap.h @@ -48,9 +48,6 @@ int main(void) { csmap_sx_drop(&m); } */ -#ifdef STC_CSMAP_V1 -#include "alt/csmap.h" -#else #include "ccommon.h" #ifndef CSMAP_H_INCLUDED @@ -598,5 +595,4 @@ _cx_memb(_drop)(_cx_self* self) { #undef _i_MAP_ONLY #undef _i_SET_ONLY #define CSMAP_H_INCLUDED -#include "priv/template.h" -#endif // !STC_CSMAP_V1 +#include "priv/untemplate.h" diff --git a/include/stc/cstack.h b/include/stc/cstack.h index 0f855dc9..1fc3f377 100644 --- a/include/stc/cstack.h +++ b/include/stc/cstack.h @@ -189,4 +189,4 @@ STC_INLINE void _cx_memb(_next)(_cx_iter* it) STC_INLINE _cx_iter _cx_memb(_advance)(_cx_iter it, size_t n) { if ((it.ref += n) >= it.end) it.ref = NULL ; return it; } -#include "priv/template.h" +#include "priv/untemplate.h" diff --git a/include/stc/cvec.h b/include/stc/cvec.h index 4fe5ddab..e257f85a 100644 --- a/include/stc/cvec.h +++ b/include/stc/cvec.h @@ -438,4 +438,4 @@ STC_DEF int _cx_memb(_value_cmp)(const _cx_value* x, const _cx_value* y) { #endif // !c_no_cmp #endif // i_implement #define CVEC_H_INCLUDED -#include "priv/template.h" +#include "priv/untemplate.h" diff --git a/include/stc/priv/altnames.h b/include/stc/priv/altnames.h index 8fa326f1..723b6a66 100644 --- a/include/stc/priv/altnames.h +++ b/include/stc/priv/altnames.h @@ -32,6 +32,3 @@ #define c_WITH c_with #define c_SCOPE c_scope #define c_DEFER c_defer -#define c_NEW c_new -#define c_ARRAYLEN c_arraylen -#define c_ARGSV c_SV // [deprecated] diff --git a/include/stc/priv/template.h b/include/stc/priv/template.h index 5ea0cf4f..250a3dda 100644 --- a/include/stc/priv/template.h +++ b/include/stc/priv/template.h @@ -20,7 +20,9 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -#ifndef _i_template +#ifdef _i_template + #error template.h already included +#endif #define _i_template #ifndef STC_TEMPLATE_H_INCLUDED @@ -290,63 +292,3 @@ #ifndef _i_has_from #define i_no_emplace #endif - -#else // ============================================================ - -#undef i_type -#undef i_tag -#undef i_imp -#undef i_opt -#undef i_less -#undef i_cmp -#undef i_eq -#undef i_hash -#undef i_rawclass -#undef i_capacity -#undef i_ssize - -#undef i_val -#undef i_val_str -#undef i_val_ssv -#undef i_valboxed -#undef i_valclass -#undef i_valraw -#undef i_valclone -#undef i_valfrom -#undef i_valto -#undef i_valdrop - -#undef i_key -#undef i_key_str -#undef i_key_ssv -#undef i_keyboxed -#undef i_keyclass -#undef i_keyraw -#undef i_keyclone -#undef i_keyfrom -#undef i_keyto -#undef i_keydrop - -#undef i_header -#undef i_implement -#undef i_static -#undef i_extern - -#undef i_allocator -#undef i_malloc -#undef i_calloc -#undef i_realloc -#undef i_free - -#undef i_no_cmp -#undef i_no_hash -#undef i_no_clone -#undef i_no_emplace -#undef i_is_forward - -#undef _i_prefix -#undef _i_expandby -#undef _i_has_from -#undef _i_has_eq -#undef _i_template -#endif diff --git a/include/stc/priv/untemplate.h b/include/stc/priv/untemplate.h new file mode 100644 index 00000000..27c6a890 --- /dev/null +++ b/include/stc/priv/untemplate.h @@ -0,0 +1,78 @@ +/* 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. + */ +#undef i_type +#undef i_tag +#undef i_imp +#undef i_opt +#undef i_less +#undef i_cmp +#undef i_eq +#undef i_hash +#undef i_rawclass +#undef i_capacity +#undef i_ssize + +#undef i_val +#undef i_val_str +#undef i_val_ssv +#undef i_valboxed +#undef i_valclass +#undef i_valraw +#undef i_valclone +#undef i_valfrom +#undef i_valto +#undef i_valdrop + +#undef i_key +#undef i_key_str +#undef i_key_ssv +#undef i_keyboxed +#undef i_keyclass +#undef i_keyraw +#undef i_keyclone +#undef i_keyfrom +#undef i_keyto +#undef i_keydrop + +#undef i_header +#undef i_implement +#undef i_static +#undef i_extern + +#undef i_allocator +#undef i_malloc +#undef i_calloc +#undef i_realloc +#undef i_free + +#undef i_no_cmp +#undef i_no_hash +#undef i_no_clone +#undef i_no_emplace +#undef i_is_forward + +#undef _i_prefix +#undef _i_expandby +#undef _i_has_from +#undef _i_has_eq +#undef _i_template diff --git a/misc/examples/forfilter.c b/misc/examples/forfilter.c index 0d72bd1b..daea68b9 100644 --- a/misc/examples/forfilter.c +++ b/misc/examples/forfilter.c @@ -9,10 +9,6 @@ #define i_val int #include -#define i_type SVec -#define i_valclass csview -#include - // filters and transforms: #define flt_skipValue(i, x) (*i.ref != (x)) #define flt_isEven(i) ((*i.ref & 1) == 0) @@ -55,11 +51,9 @@ fn main() { println!("{:?}", vector); // Print result } */ - void demo2(void) { IVec vector = {0}; - c_forfilter (x, crange, crange_object(INT64_MAX), c_flt_skipwhile(x, *x.ref != 11) && (*x.ref % 2) != 0 && @@ -67,11 +61,9 @@ void demo2(void) ){ IVec_push(&vector, (int)(*x.ref * *x.ref)); } + c_foreach (x, IVec, vector) printf(" %d", *x.ref); - c_foreach (x, IVec, vector) - printf(" %d", *x.ref); puts(""); - IVec_drop(&vector); } @@ -88,6 +80,10 @@ fn main() { println!("{:?}", words_containing_i); } */ +#define i_type SVec +#define i_valclass csview +#include + void demo3(void) { const char* sentence = "This is a sentence in C99."; @@ -102,8 +98,8 @@ void demo3(void) c_foreach (w, SVec, words_containing_i) printf(" %.*s", c_SV(*w.ref)); - puts(""); + puts(""); c_drop(SVec, &words, &words_containing_i); } -- cgit v1.2.3 From 2ad41420a973a3f1bd1ca47ab0f61b8f59ab9e66 Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Wed, 5 Apr 2023 14:44:31 +0200 Subject: Internal: renamed untemplate.h to template2.h --- include/c11/print.h | 31 +++++++++-------- include/stc/algo/csort.h | 2 +- include/stc/carc.h | 2 +- include/stc/cbox.h | 2 +- include/stc/cdeq.h | 2 +- include/stc/clist.h | 2 +- include/stc/cmap.h | 2 +- include/stc/cpque.h | 2 +- include/stc/csmap.h | 2 +- include/stc/cstack.h | 2 +- include/stc/cvec.h | 2 +- include/stc/priv/template2.h | 78 +++++++++++++++++++++++++++++++++++++++++++ include/stc/priv/untemplate.h | 78 ------------------------------------------- misc/examples/triples.c | 10 +++--- 14 files changed, 110 insertions(+), 107 deletions(-) create mode 100644 include/stc/priv/template2.h delete mode 100644 include/stc/priv/untemplate.h (limited to 'include') diff --git a/include/c11/print.h b/include/c11/print.h index 1302d9cc..7c155875 100644 --- a/include/c11/print.h +++ b/include/c11/print.h @@ -1,7 +1,10 @@ #ifndef FMT_H_INCLUDED #define FMT_H_INCLUDED /* -VER 2.0: NEW API: +VER 2.1: NEW API: +void print(fmt, ...); +void println(fmt, ...); +void printd(dest, fmt, ...); void fmt_print(fmt, ...); void fmt_println(fmt, ...); @@ -40,21 +43,21 @@ int main() { unsigned char r = 123, g = 214, b = 90, w = 110; char buffer[64]; - fmt_print("Color: ({} {} {}), {}\n", r, g, b, flag); - fmt_println("Wide: {}, {}", wstr, L"wide world"); - fmt_println("{:10} {:10} {:10.2f}", 42ull, 43, pi); - fmt_println("{:>10} {:>10} {:>10}", z, z, w); - fmt_printd(stdout, "{:10} {:10} {:10}\n", "Hello", "Mad", "World"); - fmt_printd(stderr, "100%: {:<20} {:.*} {}\n", string, 4, pi, x); - fmt_printd(buffer, "Precision: {} {:.10} {}", string, pi, x); - fmt_println("{}", buffer); - fmt_println("Vector: ({}, {}, {})", 3.2, 3.3, pi); + print("Color: ({} {} {}), {}\n", r, g, b, flag); + println("Wide: {}, {}", wstr, L"wide world"); + println("{:10} {:10} {:10.2f}", 42ull, 43, pi); + println("{:>10} {:>10} {:>10}", z, z, w); + 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_buffer out[1] = {{.stream=1}}; - fmt_printd(out, "{} {}", "Pi is:", pi); - fmt_print("{}, len={}, cap={}\n", out->data, out->len, out->cap); - fmt_printd(out, "{} {}", ", Pi squared is:", pi*pi); - fmt_print("{}, len={}, cap={}\n", out->data, out->len, out->cap); + 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); } */ diff --git a/include/stc/algo/csort.h b/include/stc/algo/csort.h index 02ac4e34..53fe9fcc 100644 --- a/include/stc/algo/csort.h +++ b/include/stc/algo/csort.h @@ -86,4 +86,4 @@ static inline void c_PASTE(cqsort_, i_tag)(i_val arr[], intptr_t lo, intptr_t hi 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/untemplate.h" +#include "../priv/template2.h" diff --git a/include/stc/carc.h b/include/stc/carc.h index 16d3a2d4..8ef80b12 100644 --- a/include/stc/carc.h +++ b/include/stc/carc.h @@ -210,4 +210,4 @@ STC_INLINE uint64_t _cx_memb(_hash)(const _cx_self* self) #undef _i_eq #undef _i_atomic_inc #undef _i_atomic_dec_and_test -#include "priv/untemplate.h" +#include "priv/template2.h" diff --git a/include/stc/cbox.h b/include/stc/cbox.h index 4d2cb1f1..ca88fc66 100644 --- a/include/stc/cbox.h +++ b/include/stc/cbox.h @@ -194,4 +194,4 @@ STC_INLINE uint64_t _cx_memb(_hash)(const _cx_self* self) #endif #undef _i_eq -#include "priv/untemplate.h" +#include "priv/template2.h" diff --git a/include/stc/cdeq.h b/include/stc/cdeq.h index ef1700f5..ff6e744f 100644 --- a/include/stc/cdeq.h +++ b/include/stc/cdeq.h @@ -443,4 +443,4 @@ _cx_memb(_value_cmp)(const _cx_value* x, const _cx_value* y) { #endif // !_i_queue #endif // IMPLEMENTATION #define CDEQ_H_INCLUDED -#include "priv/untemplate.h" +#include "priv/template2.h" diff --git a/include/stc/clist.h b/include/stc/clist.h index 6e6b6d45..f7fb4152 100644 --- a/include/stc/clist.h +++ b/include/stc/clist.h @@ -404,4 +404,4 @@ STC_DEF bool _cx_memb(_sort_with)(_cx_self* self, int(*cmp)(const _cx_value*, co #endif // !c_no_cmp #endif // i_implement #define CLIST_H_INCLUDED -#include "priv/untemplate.h" +#include "priv/template2.h" diff --git a/include/stc/cmap.h b/include/stc/cmap.h index 1976738d..9a503367 100644 --- a/include/stc/cmap.h +++ b/include/stc/cmap.h @@ -481,4 +481,4 @@ _cx_memb(_erase_entry)(_cx_self* self, _cx_value* _val) { #undef _i_MAP_ONLY #undef _i_SET_ONLY #define CMAP_H_INCLUDED -#include "priv/untemplate.h" +#include "priv/template2.h" diff --git a/include/stc/cpque.h b/include/stc/cpque.h index 023c9d27..b95b5020 100644 --- a/include/stc/cpque.h +++ b/include/stc/cpque.h @@ -160,4 +160,4 @@ _cx_memb(_push)(_cx_self* self, _cx_value value) { #endif #define CPQUE_H_INCLUDED -#include "priv/untemplate.h" +#include "priv/template2.h" diff --git a/include/stc/csmap.h b/include/stc/csmap.h index 716c1bfe..22607196 100644 --- a/include/stc/csmap.h +++ b/include/stc/csmap.h @@ -595,4 +595,4 @@ _cx_memb(_drop)(_cx_self* self) { #undef _i_MAP_ONLY #undef _i_SET_ONLY #define CSMAP_H_INCLUDED -#include "priv/untemplate.h" +#include "priv/template2.h" diff --git a/include/stc/cstack.h b/include/stc/cstack.h index 1fc3f377..c2792358 100644 --- a/include/stc/cstack.h +++ b/include/stc/cstack.h @@ -189,4 +189,4 @@ STC_INLINE void _cx_memb(_next)(_cx_iter* it) STC_INLINE _cx_iter _cx_memb(_advance)(_cx_iter it, size_t n) { if ((it.ref += n) >= it.end) it.ref = NULL ; return it; } -#include "priv/untemplate.h" +#include "priv/template2.h" diff --git a/include/stc/cvec.h b/include/stc/cvec.h index e257f85a..a1aa74b2 100644 --- a/include/stc/cvec.h +++ b/include/stc/cvec.h @@ -438,4 +438,4 @@ STC_DEF int _cx_memb(_value_cmp)(const _cx_value* x, const _cx_value* y) { #endif // !c_no_cmp #endif // i_implement #define CVEC_H_INCLUDED -#include "priv/untemplate.h" +#include "priv/template2.h" diff --git a/include/stc/priv/template2.h b/include/stc/priv/template2.h new file mode 100644 index 00000000..27c6a890 --- /dev/null +++ b/include/stc/priv/template2.h @@ -0,0 +1,78 @@ +/* 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. + */ +#undef i_type +#undef i_tag +#undef i_imp +#undef i_opt +#undef i_less +#undef i_cmp +#undef i_eq +#undef i_hash +#undef i_rawclass +#undef i_capacity +#undef i_ssize + +#undef i_val +#undef i_val_str +#undef i_val_ssv +#undef i_valboxed +#undef i_valclass +#undef i_valraw +#undef i_valclone +#undef i_valfrom +#undef i_valto +#undef i_valdrop + +#undef i_key +#undef i_key_str +#undef i_key_ssv +#undef i_keyboxed +#undef i_keyclass +#undef i_keyraw +#undef i_keyclone +#undef i_keyfrom +#undef i_keyto +#undef i_keydrop + +#undef i_header +#undef i_implement +#undef i_static +#undef i_extern + +#undef i_allocator +#undef i_malloc +#undef i_calloc +#undef i_realloc +#undef i_free + +#undef i_no_cmp +#undef i_no_hash +#undef i_no_clone +#undef i_no_emplace +#undef i_is_forward + +#undef _i_prefix +#undef _i_expandby +#undef _i_has_from +#undef _i_has_eq +#undef _i_template diff --git a/include/stc/priv/untemplate.h b/include/stc/priv/untemplate.h deleted file mode 100644 index 27c6a890..00000000 --- a/include/stc/priv/untemplate.h +++ /dev/null @@ -1,78 +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. - */ -#undef i_type -#undef i_tag -#undef i_imp -#undef i_opt -#undef i_less -#undef i_cmp -#undef i_eq -#undef i_hash -#undef i_rawclass -#undef i_capacity -#undef i_ssize - -#undef i_val -#undef i_val_str -#undef i_val_ssv -#undef i_valboxed -#undef i_valclass -#undef i_valraw -#undef i_valclone -#undef i_valfrom -#undef i_valto -#undef i_valdrop - -#undef i_key -#undef i_key_str -#undef i_key_ssv -#undef i_keyboxed -#undef i_keyclass -#undef i_keyraw -#undef i_keyclone -#undef i_keyfrom -#undef i_keyto -#undef i_keydrop - -#undef i_header -#undef i_implement -#undef i_static -#undef i_extern - -#undef i_allocator -#undef i_malloc -#undef i_calloc -#undef i_realloc -#undef i_free - -#undef i_no_cmp -#undef i_no_hash -#undef i_no_clone -#undef i_no_emplace -#undef i_is_forward - -#undef _i_prefix -#undef _i_expandby -#undef _i_has_from -#undef _i_has_eq -#undef _i_template diff --git a/misc/examples/triples.c b/misc/examples/triples.c index aac7967a..520bf012 100644 --- a/misc/examples/triples.c +++ b/misc/examples/triples.c @@ -4,12 +4,12 @@ #include void triples_vanilla(int n) { - for (int i = 5, c = 1;; ++c) { + for (int c = 5; n; ++c) { for (int a = 1; a < c; ++a) { for (int b = a + 1; b < c; ++b) { if ((int64_t)a*a + (int64_t)b*b == (int64_t)c*c) { - if (i++ == n) goto done; printf("{%d, %d, %d}\n", a, b, c); + if (--n == 0) goto done; } } } @@ -25,12 +25,12 @@ struct triples { bool triples_next(struct triples* I) { cco_begin(I); - for (I->c = 5;; ++I->c) { + for (I->c = 5; I->n; ++I->c) { for (I->a = 1; I->a < I->c; ++I->a) { for (I->b = I->a + 1; I->b < I->c; ++I->b) { if ((int64_t)I->a*I->a + (int64_t)I->b*I->b == (int64_t)I->c*I->c) { - if (I->n-- == 0) cco_return; cco_yield(true); + if (--I->n == 0) cco_return; } } } @@ -61,7 +61,7 @@ int main() while (triples_next(&t)) { if (gcd(t.a, t.b) > 1) continue; - if (t.c < 1000) + if (t.c < 100) printf("%d: {%d, %d, %d}\n", ++n, t.a, t.b, t.c); else cco_stop(&t); -- cgit v1.2.3 From 13eb85e05a88633454df7b62b80737fcc9d12238 Mon Sep 17 00:00:00 2001 From: Tyge Lovset Date: Fri, 7 Apr 2023 13:33:06 +0200 Subject: Massive documentation update/improvements. Reduced benchmarks/plotbench repetition/sizes. --- README.md | 295 ++++++++++++++++---------- docs/ccommon_api.md | 191 ++++++++++++----- include/stc/algo/coroutine.h | 10 +- misc/benchmarks/plotbench/cdeq_benchmark.cpp | 4 +- misc/benchmarks/plotbench/clist_benchmark.cpp | 4 +- misc/benchmarks/plotbench/cmap_benchmark.cpp | 6 +- misc/benchmarks/plotbench/cpque_benchmark.cpp | 4 +- misc/benchmarks/plotbench/csmap_benchmark.cpp | 4 +- misc/benchmarks/plotbench/cvec_benchmark.cpp | 2 +- misc/benchmarks/plotbench/plot.py | 2 +- misc/benchmarks/plotbench/run_all.bat | 4 +- misc/benchmarks/plotbench/run_clang.sh | 2 +- misc/benchmarks/plotbench/run_gcc.sh | 4 +- misc/benchmarks/plotbench/run_vc.bat | 3 +- 14 files changed, 347 insertions(+), 188 deletions(-) (limited to 'include') diff --git a/README.md b/README.md index 3f985b7a..224e7cb3 100644 --- a/README.md +++ b/README.md @@ -3,39 +3,16 @@ STC - Smart Template Containers for C ===================================== -News: Version 4.2 Released (2023-03-26) ------------------------------------------------- -I am happy to finally announce a new release! Major changes: -- A new exciting [**cspan**](docs/cspan_api.md) single/multi-dimensional array view (with numpy-like slicing). -- Signed sizes and indices for all containers. See C++ Core Guidelines by Stroustrup/Sutter: [ES.100](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#es100-dont-mix-signed-and-unsigned-arithmetic), [ES.102](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#es102-use-signed-types-for-arithmetic), [ES.106](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#es106-dont-try-to-avoid-negative-values-by-using-unsigned), and [ES.107](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#es107-dont-use-unsigned-for-subscripts-prefer-gslindex). -- Customizable allocator [per templated container type](https://github.com/tylov/STC/discussions/44#discussioncomment-4891925). -- Updates on **cregex** with several [new unicode character classes](docs/cregex_api.md#regex-cheatsheet). -- Algorithms: - - [crange](docs/ccommon_api.md#crange) - similar to [boost::irange](https://www.boost.org/doc/libs/release/libs/range/doc/html/range/reference/ranges/irange.html) integer range generator. - - [c_forfilter](docs/ccommon_api.md#c_forfilter) - ranges-like view filtering. - - [csort](include/stc/algo/csort.h) - [fast quicksort](misc/benchmarks/various/csort_bench.c) with custom inline comparison. -- Renamed `c_ARGSV()` => `c_SV()`: **csview** print arg. Note `c_sv()` is shorthand for *csview_from()*. -- Support for [uppercase flow-control](include/stc/priv/altnames.h) macro names in ccommon.h. -- Some API changes in **cregex** and **cstr**. -- Create single header container versions with python script. -- [Previous changes for version 4](#version-4). - -Introduction ------------- -STC is a *modern*, *ergonomic*, *type-safe*, *very fast* and *compact* container library for C99. -The API has similarities with c++ STL, but is more uniform across the containers and takes inspiration from Rust -and Python as well. It is an advantage to know how these containers work in other languages, like Java, C# or C++, -but it's not required. +### [Version 4.2](#version-history) -This library allows you to manage both trivial to very complex data in a wide variety of containers -without the need for boilerplate code. You may specify element-cloning, -comparison, -destruction and -more on complex container hierarchies without resorting to cumbersome function pointers with type casting. -Usage with trivial data types is simple to use compared to most generic container libraries for C because -of its type safety with an intuitive and consistent API. - -The library is mature and well tested, so you may use it in projects. However, minor breaking API changes may -still happen. The main development of this project is finished, but I will handle PRs with bugs and improvements -in the future, and do minor modifications. +--- +Description +----------- +STC is a *modern*, *fully typesafe*, *fast* and *compact* container and algorithm library for C99. +The API naming is similar to C++ STL, but it takes inspiration from Rust and Python as well. +The library let you store and manage trivial and highly complex data in a variety of +containers with ease. It is optimized for speed, usage ergonomics, consistency, +and it creates small binaries. Containers ---------- @@ -56,31 +33,75 @@ Containers - [***cdeq*** - **std::deque** alike type](docs/cdeq_api.md) - [***cvec*** - **std::vector** alike type](docs/cvec_api.md) -Others ------- -- [***ccommon*** - Generic safe macros and algorithms](docs/ccommon_api.md) -- [***cregex*** - Regular expressions (extended from Rob Pike's regexp9)](docs/cregex_api.md) -- [***crand*** - A novel very fast *PRNG* named **stc64**](docs/crandom_api.md) -- [***coption*** - getopt() alike command line args parser](docs/coption_api.md) - -Highlights ----------- -- **No boilerplate** - With STC, no boilerplate code is needed to setup containers either with simple built-in types or containers with complex element types, which requires cleanup. Only specify what is needed, e.g. compare-, clone-, drop- functions, and leave the rest as defaults. +Algorithms +---------- +- [***common*** Generic container algorithms](docs/ccommon_api.md#algorithms) +- [***filter*** - Ranges-like filtering](docs/ccommon_api.md#c_forfilter) +- [***coroutine*** - Tiny, fast and portable coroutine implementation](docs/ccommon_api.md#coroutines) +- [***cregex*** - Regular expressions based on Rob Pike's regexp9](docs/cregex_api.md) +- [***crange*** - Generalized iota integer generator](docs/ccommon_api.md#crange) +- [***crand*** - A novel very fast *PRNG* based on ***sfc64***](docs/crandom_api.md) +- [***coption*** - A ***getopt***-alike command line argument parser](docs/coption_api.md) + +--- +List of contents +----------------- +- [Highlights](#highlights) +- [STC is unique!](#stc-is-unique) +- [Performance](#performance) +- [STC naming conventions](#stc-naming-conventions) +- [Usage](#usage) +- [Installation](#installation) +- [Specifying template parameters](#specifying-template-parameters) +- [The *emplace* methods](#the-emplace-methods) +- [The *erase* methods](#the-erase-methods) +- [User-defined container type name](#user-defined-container-type-name) +- [Forward declarations](#forward-declarations) +- [Per-container-instance customization](#per-container-instance-customization) +- [Memory efficiency](#memory-efficiency) + +--- +## Highlights + +- **No boilerplate code** - Minimal code is needed to setup containers with any element type. Specify only what is needed, e.g. ***cmp***- and/or ***clone***-, ***drop***- functions, and leave the rest as defaults. - **Fully type safe** - Because of templating, it avoids error-prone casting of container types and elements back and forth from the containers. - **User friendly** - Just include the headers and you are good. The API and functionality is very close to c++ STL, and is fully listed in the docs. -- **Templates** - Use `#define i_{arg}` to specify container template arguments. There are templates for element-*type*, -*comparison*, -*destruction*, -*cloning*, -*conversion types*, and more. -- **Unparalleled performance** - Some containers are much faster than the c++ STL containers, the rest are about equal in speed. -- **Fully memory managed** - All containers will destruct keys/values via destructor defined as macro parameters before including the container header. Also, smart pointers are supported and can be stored in containers, see ***carc*** and ***cbox***. -- **Uniform, easy-to-learn API** - Methods to ***construct***, ***initialize***, ***iterate*** and ***destruct*** have uniform and intuitive usage across the various containers. -- **No signed/unsigned mixing** - Unsigned sizes and indices mixed with signed in comparisons and calculations is asking for trouble. STC uses only signed numbers in the API. -- **Small footprint** - Small source code and generated executables. The executable from the example below using ***six different*** container types is only ***19 Kb in size*** compiled with gcc -O3 -s on Linux. +- **Unparalleled performance** - Maps and sets are much faster than the C++ STL containers, the remaining are similar in speed. +- **Fully memory managed** - All containers will destruct keys/values via destructor (defined as macro parameters before including the container header). Also, smart pointers are supported and can be stored in containers, see ***carc*** and ***cbox***. +- **Uniform, easy-to-learn API** - Uniform and intuitive method/type names and usage across the various containers. +- **No signed/unsigned mixing** - Unsigned sizes and indices mixed with signed in comparisons and calculations is asking for trouble. STC uses only signed numbers in the API for this reason. +- **Small footprint** - Small source code and generated executables. The executable from the example below using *four different* container types is only ***19 Kb in size*** compiled with gcc -O3 -s on Linux. - **Dual mode compilation** - By default it is a simple header-only library with inline and static methods only, but you can easily switch to create a traditional library with shared symbols, without changing existing source files. See the Installation section. - **No callback functions** - All passed template argument functions/macros are directly called from the implementation, no slow callbacks which requires storage. - **Compiles with C++ and C99** - C code can be compiled with C++ (container element types must be POD). - **Forward declaration** - Templated containers may be forward declared without including the full API/implementation. See documentation below. -Performance ------------ +--- +## STC is unique! + +1. ***Centralized analysis of template parameters***. The analyser assigns values to all +non-specified template parameters (based on the specified ones) using meta-programming, +so that you don't have to! You may specify a set of "standard" template parameters for each container, +but as a minimum *only one is required*: `i_val` (+ `i_key` for maps). In this case STC assumes +that the elements are of basic types. For more complex types, additional template parameters must be given. +2. ***Alternative insert/lookup type***. You may specify an alternative type to use for lookup in +containers. E.g., containers with STC string elements (**cstr**) uses `const char*` as lookup type, +so construction of a `cstr` (which may allocate memory) for the lookup *is not needed*. Hence, the alt. lookup +key does not need to be destroyed after use, as it is normally a POD type. Finally, the alternative +lookup type may be passed to an ***emplace***-function. E.g. instead of calling +`cvec_str_push(&vec, cstr_from("Hello"))`, you may call `cvec_str_emplace(&vec, "Hello")`, +which is functionally identical, but more convenient. +3. ***Standardized container iterators***. All containers can be iterated in the same manner, and all use the +same element access syntax. E.g.: + - `c_foreach (it, MyInts, myints) *it.ref += 42;` works for any container defined as + `MyInts` with `int` elements. + - `c_foreach (it, MyInts, it1, it2) *it.ref += 42;` iterates from `it1` up to `it2`. + +--- +## Performance + +STC is a fast and memory efficient library, and code compiles very fast: + ![Benchmark](misc/benchmarks/pics/benchmark.gif) Benchmark notes: @@ -92,8 +113,9 @@ Benchmark notes: - **deque**: *insert*: n/3 push_front(), n/3 push_back()+pop_front(), n/3 push_back(). - **map and unordered map**: *insert*: n/2 random numbers, n/2 sequential numbers. *erase*: n/2 keys in the map, n/2 random keys. -STC conventions ---------------- +--- +## STC naming conventions + - Container names are prefixed by `c`, e.g. `cvec`, `cstr`. - Public STC macros are prefixed by `c_`, e.g. `c_foreach`, `c_make`. - Template parameter macros are prefixed by `i_`, e.g. `i_val`, `i_type`. @@ -103,8 +125,7 @@ STC conventions - Con_value - Con_raw - Con_iter - - Con_ssize -- Common function names for a container type Con: +- Some common function names: - Con_init() - Con_reserve(&con, capacity) - Con_drop(&con) @@ -113,7 +134,6 @@ STC conventions - Con_clone(con) - Con_push(&con, value) - Con_emplace(&con, rawval) - - Con_put_n(&con, rawval[], n) - Con_erase_at(&con, iter) - Con_front(&con) - Con_back(&con) @@ -122,40 +142,21 @@ STC conventions - Con_next(&iter) - Con_advance(iter, n) -Some standout features of STC ------------------------------ -1. ***Centralized analysis of template arguments***. Assigns good defaults to non-specified templates. -You may specify a number of "standard" template arguments for each container, but as minimum only one is -required (two for maps). In the latter case, STC assumes the elements are basic types. For more complex types, -additional template arguments should be defined. -2. ***General "heterogeneous lookup"-like feature***. Allows specification of an alternative type to use -for lookup in containers. E.g. for containers with string type (**cstr**) elements, `const char*` is used -as lookup type. It will then use the input `const char*` directly when comparing with the string data in the -container. This avoids the construction of a new `cstr` (which possible allocates memory) for the lookup. -Finally, destruction of the lookup key (i.e. string literal) after usage is not needed (or allowed), which -is convenient in C. A great ergonomic feature is that the alternative lookup type can also be used when adding -entries into containers through using the *emplace*-functions. E.g. `cvec_str_emplace_back(&vec, "Hello")`. -3. ***Standardized container iterators***. All container can be iterated in similar manner, and uses the -same element access syntax. E.g.: - - `c_foreach (it, IntContainer, container) printf(" %d", *it.ref);` will work for -every type of container defined as `IntContainer` with `int` elements. Also the form: - - `c_foreach (it, IntContainer, it1, it2)` -may be used to iterate from `it1` up to `it2`. - -Usage ------ -The usage of the containers is similar to the c++ standard containers in STL, so it should be easy if you -are familiar with them. All containers are generic/templated, except for **cstr** and **cbits**. -No casting is used, so containers are type-safe like templates in c++. A basic usage example: +--- +## Usage +The functionality of STC containers is similar to C++ STL standard containers. All containers except for a few, +like **cstr** and **cbits** are generic/templated. No type casting is done, so containers are type-safe like +templated types in C++. However, the specification of template parameters are naturally different. Here is +a basic usage example: ```c -#define i_type Floats // Container type name; if not defined, it would be cvec_float +#define i_type Floats // Container type name; unless defined name would be cvec_float #define i_val float // Container element type #include // "instantiate" the desired container type #include int main(void) { - Floats nums = Floats_init(); + Floats nums = {0}; Floats_push(&nums, 30.f); Floats_push(&nums, 10.f); Floats_push(&nums, 20.f); @@ -165,13 +166,13 @@ int main(void) Floats_sort(&nums); - c_foreach (i, Floats, nums) // Alternative and recommended way to iterate nums. - printf(" %g", *i.ref); // i.ref is a pointer to the current element. + c_foreach (i, Floats, nums) // Alternative and recommended way to iterate nums. + printf(" %g", *i.ref); // i.ref is a pointer to the current element. Floats_drop(&nums); // cleanup memory } ``` -Switching to a different container type is easy: +You may switch to a different container type, e.g. a sorted set (csset): ```c #define i_type Floats #define i_val float @@ -180,12 +181,12 @@ Switching to a different container type is easy: int main() { - Floats nums = c_make(Floats, {30.f, 10.f, 20.f}); // Initialize with a list of floats. + Floats nums = c_make(Floats, {30.f, 10.f, 20.f}); // Initialize nums with a list of floats. Floats_push(&nums, 50.f); Floats_push(&nums, 40.f); - // print the sorted numbers - c_foreach (i, Floats, nums) // c_foreach works with any container + // already sorted, print the numbers + c_foreach (i, Floats, nums) printf(" %g", *i.ref); Floats_drop(&nums); @@ -204,7 +205,7 @@ Let's make a vector of vectors that can be cloned. All of its element vectors wi #include #define i_type Vec2D -#define i_valclass Vec // Use i_valclass when the element type has "member" functions _clone(), _drop() and _cmp(). +#define i_valclass Vec // Use i_valclass when element type has "members" _clone(), _drop() and _cmp(). #define i_opt c_no_cmp // However, disable search/sort for Vec2D because Vec_cmp() is not defined. #include @@ -229,7 +230,7 @@ int main(void) c_drop(Vec2D, &vec, &clone); // Cleanup all (6) vectors. } ``` -Here is an example of using four different container types: +This example uses four different container types: ```c #include @@ -322,9 +323,9 @@ After erasing the elements found: lst: 10 30 40 50 map: [10: 1] [30: 3] [40: 4] [50: 5] ``` +--- +## Installation -Installation ------------- Because it is headers-only, headers can simply be included in your program. By default, functions are static (some inlined). You may add the *include* folder to the **CPATH** environment variable to let GCC, Clang, and TinyC locate the headers. @@ -368,9 +369,9 @@ or define your own as descibed above. #define i_tag pnt #include // clist_pnt ``` +--- +## Specifying template parameters -Specifying template parameters ------------------------------- Each templated type requires one `#include`, even if it's the same container base type, as described earlier. The template parameters are given by a `#define i_xxxx` statement, where *xxxx* is the parameter name. The list of template parameters: @@ -420,8 +421,9 @@ NB: Do not use when defining carc/cbox types themselves. - Instead of defining `i_*clone`, you may define *i_opt c_no_clone* to disable *clone* functionality. - For `i_keyclass`, if *i_keyraw* is defined along with it, *i_keyfrom* may also be defined to enable the *emplace*-functions. NB: the signature for ***cmp***, ***eq***, and ***hash*** uses *i_keyraw* as input. -The *emplace* versus non-emplace container methods --------------------------------------------------- +--- +## The *emplace* methods + STC, like c++ STL, has two sets of methods for adding elements to containers. One set begins with **emplace**, e.g. *cvec_X_emplace_back()*. This is an ergonimic alternative to *cvec_X_push_back()* when dealing non-trivial container elements, e.g. strings, shared pointers or @@ -492,8 +494,9 @@ it = cmap_str_find(&map, "Hello"); Apart from strings, maps and sets are normally used with trivial value types. However, the last example on the **cmap** page demonstrates how to specify a map with non-trivial keys. -Erase methods -------------- +--- +## The *erase* methods + | Name | Description | Container | |:--------------------------|:-----------------------------|:--------------------------------------------| | erase() | key based | csmap, csset, cmap, cset, cstr | @@ -502,8 +505,23 @@ Erase methods | erase_n() | index based | cvec, cdeq, cstr | | remove() | remove all matching values | clist | -Forward declaring containers ----------------------------- +--- +## User-defined container type name + +Define `i_type` instead of `i_tag`: +```c +#define i_type MyVec +#define i_val int +#include + +myvec vec = MyVec_init(); +MyVec_push_back(&vec, 1); +... +``` + +--- +## Forward declarations + It is possible to forward declare containers. This is useful when a container is part of a struct, but still not expose or include the full implementation / API of the container. ```c @@ -516,7 +534,6 @@ typedef struct Dataset { cstack_pnt colors; } Dataset; -... // Implementation #define i_is_forward // flag that the container was forward declared. #define i_val struct Point @@ -524,22 +541,57 @@ typedef struct Dataset { #include ``` -User-defined container type name --------------------------------- -Define `i_type` instead of `i_tag`: +--- +## Per-container-instance customization +Sometimes it is useful to extend a container type to hold extra data, e.g. a comparison +or allocator function pointer or some context that the function pointers can use. Most +libraries solve this by adding an opaque pointer (void*) or some function pointer(s) into +the data structure for the user to manage. This solution has a few disadvantages, e.g. the +pointers are not typesafe, and they take up space when not needed. STC solves this by letting +the user create a container wrapper struct where both the container and extra data fields can +be stored. The template parameters may then access the extra data using the "container_of" +technique. + +The example below shows how to customize containers to work with PostgreSQL memory management. +It adds a MemoryContext to each container by defining the `i_extend` template parameter followed +the by inclusion of ``. ```c -#define i_type MyVec +// stcpgs.h +#define pgs_malloc(sz) MemoryContextAlloc(c_getcon(self)->memctx, sz) +#define pgs_calloc(n, sz) MemoryContextAllocZero(c_getcon(self)->memctx, (n)*(sz)) +#define pgs_realloc(p, sz) (p ? repalloc(p, sz) : pgs_malloc(sz)) +#define pgs_free(p) (p ? pfree(p) : (void)0) // pfree/repalloc does not accept NULL. + +#define i_allocator pgs +#define i_no_clone +#define i_extend MemoryContext memctx +#include +``` +Define both `i_type` and `i_con` (the container type) before including the custom header: +```c +#define i_type IMap +#define i_key int #define i_val int -#include +#define i_con csmap +#include "stcpgs.h" -myvec vec = MyVec_init(); -MyVec_push_back(&vec, 1); -... +// Note the wrapper struct type is IMapExt. IMap is accessed by .get +void maptest() +{ + IMapExt map = {.memctx=CurrentMemoryContext}; + c_forrange (i, 1, 16) + IMap_insert(&map.get, i*i, i); + + c_foreach (i, IMap, map.get) + printf("%d:%d ", i.ref->first, i.ref->second); + + IMap_drop(&map.get); +} ``` +--- +## Memory efficiency -Memory efficiency ------------------ -STC is generally very memory efficient. Type sizes: +STC is generally very memory efficient. Memory usage for the different containers: - **cstr**, **cvec**, **cstack**, **cpque**: 1 pointer, 2 intptr_t + memory for elements. - **csview**, 1 pointer, 1 intptr_t. Does not own data! - **cspan**, 1 pointer and 2 \* dimension \* int32_t. Does not own data! @@ -550,7 +602,24 @@ STC is generally very memory efficient. Type sizes: - **carc**: Type size: 1 pointer, 1 long for the reference counter + memory for the shared element. - **cbox**: Type size: 1 pointer + memory for the pointed-to element. -# Version 4 +--- +# Version History + +## Version 4.1.1 +I am happy to finally announce a new release! Major changes: +- A new exciting [**cspan**](docs/cspan_api.md) single/multi-dimensional array view (with numpy-like slicing). +- Signed sizes and indices for all containers. See C++ Core Guidelines by Stroustrup/Sutter: [ES.100](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#es100-dont-mix-signed-and-unsigned-arithmetic), [ES.102](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#es102-use-signed-types-for-arithmetic), [ES.106](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#es106-dont-try-to-avoid-negative-values-by-using-unsigned), and [ES.107](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#es107-dont-use-unsigned-for-subscripts-prefer-gslindex). +- Customizable allocator [per templated container type](https://github.com/tylov/STC/discussions/44#discussioncomment-4891925). +- Updates on **cregex** with several [new unicode character classes](docs/cregex_api.md#regex-cheatsheet). +- Algorithms: + - [crange](docs/ccommon_api.md#crange) - similar to [boost::irange](https://www.boost.org/doc/libs/release/libs/range/doc/html/range/reference/ranges/irange.html) integer range generator. + - [c_forfilter](docs/ccommon_api.md#c_forfilter) - ranges-like view filtering. + - [csort](include/stc/algo/csort.h) - [fast quicksort](misc/benchmarks/various/csort_bench.c) with custom inline comparison. +- Renamed `c_ARGSV()` => `c_SV()`: **csview** print arg. Note `c_sv()` is shorthand for *csview_from()*. +- Support for [uppercase flow-control](include/stc/priv/altnames.h) macro names in ccommon.h. +- Some API changes in **cregex** and **cstr**. +- Create single header container versions with python script. + ## API changes summary V4.0 - Added **cregex** with documentation - powerful regular expressions. diff --git a/docs/ccommon_api.md b/docs/ccommon_api.md index 6a0b4ee7..af27bd1d 100644 --- a/docs/ccommon_api.md +++ b/docs/ccommon_api.md @@ -95,8 +95,7 @@ Iterate containers with stop-criteria and chained range filtering. | `c_flt_getcount(it)` | Number of items passed skip*/take*/counter | ```c // Example: -#include -#include +#include #include bool isPrime(long long i) { @@ -105,21 +104,21 @@ bool isPrime(long long i) { return true; } int main() { - // Get 10 prime numbers starting from 1000. - // Skip the first 24 primes, then select every 15th prime. - crange R = crange_make(1001, INT32_MAX, 2); + // Get 10 prime numbers starting from 1000. Skip the first 15 primes, + // then select every 25th prime (including the initial). + crange R = crange_make(1001, INT64_MAX, 2); // 1001, 1003, ... c_forfilter (i, crange, R, isPrime(*i.ref) && - c_flt_skip(i, 24) && - c_flt_counter(i) % 15 == 1 && + c_flt_skip(i, 15) && + c_flt_counter(i) % 25 == 1 && c_flt_take(i, 10) ){ printf(" %lld", *i.ref); } puts(""); } -// out: 1171 1283 1409 1493 1607 1721 1847 1973 2081 2203 +// out: 1097 1289 1481 1637 1861 2039 2243 2417 2657 2803 ``` Note that `c_flt_take()` and `c_flt_takewhile()` breaks the loop on false. @@ -144,7 +143,7 @@ c_forfilter (i, crange, r1, isPrime(*i.ref)) printf(" %lld", *i.ref); // 2 3 5 7 11 13 17 19 23 29 31 -// 2. The 11 first primes: +// 2. The first 11 primes: printf("2"); c_forfilter (i, crange, crange_object(3, INT64_MAX, 2), isPrime(*i.ref) && @@ -160,7 +159,9 @@ c_forfilter (i, crange, crange_object(3, INT64_MAX, 2), - *c_make(C, {...})*: Make any container from an initializer list. Example: ```c -#define i_val_str // cstr value type +#define i_val_str // owned cstr string value type +//#define i_valclass crawstr // non-owning const char* values with strcmp/cstrhash +//#define i_val const char* // non-owning const char* values with pointer cmp/hash. #include #define i_key int @@ -216,12 +217,13 @@ c_swap(cmap_int, &map1, &map2); c_drop(cvec_i, &vec1, &vec2, &vec3); // Type-safe casting a from const (pointer): -const char* cs = "Hello"; +const char cs[] = "Hello"; char* s = c_const_cast(char*, cs); // OK int* ip = c_const_cast(int*, cs); // issues a warning! ``` ### General predefined template parameter functions + ```c int c_default_cmp(const Type*, const Type*); Type c_default_clone(Type val); // simple copy @@ -244,8 +246,97 @@ int array[] = {1, 2, 3, 4}; intptr_t n = c_arraylen(array); ``` -## Scope macros (RAII) -### c_auto, c_with, c_scope, c_defer +--- +## Coroutines +This is an improved implementation of Simon Tatham's classic C code, which utilizes +the *Duff's device* trick. However, Tatham's implementation is not typesafe, +and it always allocates the coroutine's internal state dynamically. Also, +it does not let the coroutine do self-cleanup on early finish, i.e. it +just frees the dynamically allocated memory. + +In this implementation a coroutine may have any signature, but it should +take some struct pointer as parameter, which must contain the member `int cco_state;` +The struct should normally store all the *local* variables to be used in the +coroutine. It can also store input and output data if desired. + +The coroutine example below generates Pythagorian triples, but the main user-loop +skips the triples which are upscaled version of smaller ones, by checking +the gcd() function, and breaks when diagonal length >= 100: +```c +#include + +struct triples { + int n; // input: max number of triples to be generated. + int a, b, c; + int cco_state; // required member +}; + +bool triples_next(struct triples* I) { // coroutine + cco_begin(I); + for (I->c = 5; I->n; ++I->c) { + for (I->a = 1; I->a < I->c; ++I->a) { + for (I->b = I->a + 1; I->b < I->c; ++I->b) { + if ((int64_t)I->a*I->a + (int64_t)I->b*I->b == (int64_t)I->c*I->c) { + cco_yield(true); + if (--I->n == 0) cco_return; + } + } + } + } + cco_final: // required label + puts("done"); + cco_end(false); +} + +int gcd(int a, int b) { // greatest common denominator + while (b) { + int t = a % b; + a = b; + b = t; + } + return a; +} + +int main() +{ + puts("\nCoroutine triples:"); + struct triples t = {INT32_MAX}; + int n = 0; + + while (triples_next(&t)) { + // Skip triples with GCD(a,b) > 1 + if (gcd(t.a, t.b) > 1) + continue; + + // Stop when c >= 100 + if (t.c < 100) + printf("%d: {%d, %d, %d}\n", ++n, t.a, t.b, t.c); + else + cco_stop(&t); // make sure coroutine cleanup is done + } +} +``` +### Coroutine API +**Note**: `cco_yield()` may not be called inside a `switch` statement. Use `if-else-if` constructs instead. + +| | Function / operator | Description | +|:----------|:-------------------------------------|:----------------------------------------| +| | `cco_final:` | Obligatory label in coroutine | +| | `cco_return;` | Early return from the coroutine | +| `bool` | `cco_suspended(ctx)` | Is coroutine in suspended state? | +| `bool` | `cco_alive(ctx)` | Is coroutine still alive? | +| `void` | `cco_begin(ctx)` | Begin coroutine block | +| `rettype` | `cco_end(retval)` | End coroutine block with return value | +| `rettype` | `cco_end()` | End coroutine block with (void) | +| `rettype` | `cco_yield(retval)` | Yield a value | +| `rettype` | `cco_yield(corocall2, ctx2, retval)` | Yield from another coroutine and return val | +| `rettype` | `cco_yield(corocall2, ctx2)` | Yield from another coroutine (void) | +| | From the caller side: | | +| `void` | `cco_stop(ctx)` | Next call of coroutine returns `cco_end()` | +| `void` | `cco_reset(ctx)` | Reset state to initial (for reuse) | + +--- +## RAII scope macros General ***defer*** mechanics for resource acquisition. These macros allows you to specify the freeing of the resources at the point where the acquisition takes place. The **checkauto** utility described below, ensures that the `c_auto*` macros are used correctly. @@ -258,57 +349,54 @@ The **checkauto** utility described below, ensures that the `c_auto*` macros are | `c_with (Type var=init, drop)` | Declare `var`. Defer `drop...` to end of scope | | `c_with (Type var=init, pred, drop)` | Adds a predicate in order to exit early if init failed | | `c_auto (Type, var1,...,var4)` | `c_with (Type var1=Type_init(), Type_drop(&var1))` ... | -| `continue` | Exit a block above without memory leaks | +| `continue` | Exit a defer-block without resource leak | -For multiple variables, use either multiple **c_with** in sequence, or declare variable outside -scope and use **c_scope**. For convenience, **c_auto** support up to 4 variables. ```c -// `c_with` is similar to python `with`: it declares and can drop a variable after going out of scope. -bool ok = false; -c_with (uint8_t* buf = malloc(BUF_SIZE), buf != NULL, free(buf)) -c_with (FILE* fp = fopen(fname, "rb"), fp != NULL, fclose(fp)) +// `c_defer` executes the expression(s) when leaving scope. +cstr s1 = cstr_lit("Hello"), s2 = cstr_lit("world"); +c_defer (cstr_drop(&s1), cstr_drop(&s2)) { - int n = fread(buf, 1, BUF_SIZE, fp); - if (n <= 0) continue; // auto cleanup! NB do not break or return here. - ... - ok = true; + printf("%s %s\n", cstr_str(&s1), cstr_str(&s2)); } -return ok; -// `c_auto` automatically initialize and destruct up to 4 variables: -c_auto (cstr, s1, s2) +// `c_scope` syntactically "binds" initialization and defer. +static pthread_mutex_t mut; +c_scope (pthread_mutex_lock(&mut), pthread_mutex_unlock(&mut)) { - cstr_append(&s1, "Hello"); - cstr_append(&s1, " world"); - - cstr_append(&s2, "Cool"); - cstr_append(&s2, " stuff"); - - printf("%s %s\n", cstr_str(&s1), cstr_str(&s2)); + /* Do syncronized work. */ } -// `c_with` is a general variant of `c_auto`: +// `c_with` is similar to python `with`: declare a variable and defer the drop call. c_with (cstr str = cstr_lit("Hello"), cstr_drop(&str)) { cstr_append(&str, " world"); printf("%s\n", cstr_str(&str)); } -// `c_scope` is like `c_with` but works with an already declared variable. -static pthread_mutex_t mut; -c_scope (pthread_mutex_lock(&mut), pthread_mutex_unlock(&mut)) +// `c_auto` automatically initialize and drops up to 4 variables: +c_auto (cstr, s1, s2) { - /* Do syncronized work. */ + cstr_append(&s1, "Hello"); + cstr_append(&s1, " world"); + cstr_append(&s2, "Cool"); + cstr_append(&s2, " stuff"); + printf("%s %s\n", cstr_str(&s1), cstr_str(&s2)); } - -// `c_defer` executes the expressions when leaving scope. Prefer c_with or c_scope. -cstr s1 = cstr_lit("Hello"), s2 = cstr_lit("world"); -c_defer (cstr_drop(&s1), cstr_drop(&s2)) +``` +**Example 1**: Use multiple **c_with** in sequence: +```c +bool ok = false; +c_with (uint8_t* buf = malloc(BUF_SIZE), buf != NULL, free(buf)) +c_with (FILE* fp = fopen(fname, "rb"), fp != NULL, fclose(fp)) { - printf("%s %s\n", cstr_str(&s1), cstr_str(&s2)); + int n = fread(buf, 1, BUF_SIZE, fp); + if (n <= 0) continue; // auto cleanup! NB do not break or return here. + ... + ok = true; } +return ok; ``` -**Example**: Load each line of a text file into a vector of strings: +**Example 2**: Load each line of a text file into a vector of strings: ```c #include #include @@ -319,20 +407,19 @@ c_defer (cstr_drop(&s1), cstr_drop(&s2)) // receiver should check errno variable cvec_str readFile(const char* name) { - cvec_str vec = cvec_str_init(); // returned - + cvec_str vec = {0}; // returned c_with (FILE* fp = fopen(name, "r"), fp != NULL, fclose(fp)) - c_with (cstr line = cstr_NULL, cstr_drop(&line)) + c_with (cstr line = {0}, cstr_drop(&line)) while (cstr_getline(&line, fp)) - cvec_str_emplace_back(&vec, cstr_str(&line)); + cvec_str_emplace(&vec, cstr_str(&line)); return vec; } int main() { - c_with (cvec_str x = readFile(__FILE__), cvec_str_drop(&x)) - c_foreach (i, cvec_str, x) - printf("%s\n", cstr_str(i.ref)); + c_with (cvec_str vec = readFile(__FILE__), cvec_str_drop(&vec)) + c_foreach (i, cvec_str, vec) + printf("| %s\n", cstr_str(i.ref)); } ``` diff --git a/include/stc/algo/coroutine.h b/include/stc/algo/coroutine.h index d29b2cef..b0ecd6b7 100644 --- a/include/stc/algo/coroutine.h +++ b/include/stc/algo/coroutine.h @@ -83,16 +83,16 @@ enum { case __LINE__:; \ } while (0) -#define cco_yield_2(corocall, ctx) \ - cco_yield_3(corocall, ctx,) +#define cco_yield_2(corocall2, ctx2) \ + cco_yield_3(corocall2, ctx2, ) -#define cco_yield_3(corocall, ctx, retval) \ +#define cco_yield_3(corocall2, ctx2, retval) \ do { \ *_state = __LINE__; \ do { \ - corocall; if (cco_suspended(ctx)) return retval; \ + corocall2; if (cco_suspended(ctx2)) return retval; \ case __LINE__:; \ - } while (cco_alive(ctx)); \ + } while (cco_alive(ctx2)); \ } while (0) #define cco_final \ diff --git a/misc/benchmarks/plotbench/cdeq_benchmark.cpp b/misc/benchmarks/plotbench/cdeq_benchmark.cpp index a8399ea8..bb0e28c8 100644 --- a/misc/benchmarks/plotbench/cdeq_benchmark.cpp +++ b/misc/benchmarks/plotbench/cdeq_benchmark.cpp @@ -12,7 +12,7 @@ enum {INSERT, ERASE, FIND, ITER, DESTRUCT, N_TESTS}; const char* operations[] = {"insert", "erase", "find", "iter", "destruct"}; typedef struct { time_t t1, t2; uint64_t sum; float fac; } Range; typedef struct { const char* name; Range test[N_TESTS]; } Sample; -enum {SAMPLES = 2, N = 100000000, S = 0x3ffc, R = 4}; +enum {SAMPLES = 2, N = 50000000, S = 0x3ffc, R = 4}; uint64_t seed = 1, mask1 = 0xfffffff, mask2 = 0xffff; static float secs(Range s) { return (float)(s.t2 - s.t1) / CLOCKS_PER_SEC; } @@ -122,7 +122,7 @@ int main(int argc, char* argv[]) bool header = (argc > 2 && argv[2][0] == '1'); float std_sum = 0, stc_sum = 0; - c_forrange (j, N_TESTS) { + c_forrange (j, N_TESTS) { std_sum += secs(std_s[0].test[j]); stc_sum += secs(stc_s[0].test[j]); } diff --git a/misc/benchmarks/plotbench/clist_benchmark.cpp b/misc/benchmarks/plotbench/clist_benchmark.cpp index 46bd2793..01bfbf83 100644 --- a/misc/benchmarks/plotbench/clist_benchmark.cpp +++ b/misc/benchmarks/plotbench/clist_benchmark.cpp @@ -12,7 +12,7 @@ enum {INSERT, ERASE, FIND, ITER, DESTRUCT, N_TESTS}; const char* operations[] = {"insert", "erase", "find", "iter", "destruct"}; typedef struct { time_t t1, t2; uint64_t sum; float fac; } Range; typedef struct { const char* name; Range test[N_TESTS]; } Sample; -enum {SAMPLES = 2, N = 50000000, S = 0x3ffc, R = 4}; +enum {SAMPLES = 2, N = 10000000, S = 0x3ffc, R = 4}; uint64_t seed = 1, mask1 = 0xfffffff, mask2 = 0xffff; static float secs(Range s) { return (float)(s.t2 - s.t1) / CLOCKS_PER_SEC; } @@ -132,4 +132,4 @@ int main(int argc, char* argv[]) c_forrange (j, N_TESTS) printf("%s,%s n:%d,%s,%.3f,%.3f\n", comp, stc_s[0].name, N, operations[j], secs(stc_s[0].test[j]), secs(std_s[0].test[j]) ? secs(stc_s[0].test[j])/secs(std_s[0].test[j]) : 1.0f); printf("%s,%s n:%d,%s,%.3f,%.3f\n", comp, stc_s[0].name, N, "total", stc_sum, stc_sum/std_sum); -} \ No newline at end of file +} diff --git a/misc/benchmarks/plotbench/cmap_benchmark.cpp b/misc/benchmarks/plotbench/cmap_benchmark.cpp index 0582d162..6b2edbd7 100644 --- a/misc/benchmarks/plotbench/cmap_benchmark.cpp +++ b/misc/benchmarks/plotbench/cmap_benchmark.cpp @@ -11,7 +11,7 @@ enum {INSERT, ERASE, FIND, ITER, DESTRUCT, N_TESTS}; const char* operations[] = {"insert", "erase", "find", "iter", "destruct"}; typedef struct { time_t t1, t2; uint64_t sum; float fac; } Range; typedef struct { const char* name; Range test[N_TESTS]; } Sample; -enum {SAMPLES = 2, N = 8000000, R = 4}; +enum {SAMPLES = 2, N = 2000000, R = 4}; uint64_t seed = 1, mask1 = 0xffffffff; static float secs(Range s) { return (float)(s.t2 - s.t1) / CLOCKS_PER_SEC; } @@ -92,7 +92,7 @@ Sample test_stc_unordered_map() { s.test[FIND].t1 = clock(); size_t sum = 0; const cmap_x_value* val; - c_forrange (N) + c_forrange (N) if ((val = cmap_x_get(&con, crand() & mask1))) sum += val->second; s.test[FIND].t2 = clock(); @@ -139,4 +139,4 @@ int main(int argc, char* argv[]) c_forrange (j, N_TESTS) printf("%s,%s n:%d,%s,%.3f,%.3f\n", comp, stc_s[0].name, N, operations[j], secs(stc_s[0].test[j]), secs(std_s[0].test[j]) ? secs(stc_s[0].test[j])/secs(std_s[0].test[j]) : 1.0f); printf("%s,%s n:%d,%s,%.3f,%.3f\n", comp, stc_s[0].name, N, "total", stc_sum, stc_sum/std_sum); -} \ No newline at end of file +} diff --git a/misc/benchmarks/plotbench/cpque_benchmark.cpp b/misc/benchmarks/plotbench/cpque_benchmark.cpp index da092b7f..2d4c7a28 100644 --- a/misc/benchmarks/plotbench/cpque_benchmark.cpp +++ b/misc/benchmarks/plotbench/cpque_benchmark.cpp @@ -11,7 +11,7 @@ #include static const uint32_t seed = 1234; -static const int N = 10000000; +static const int N = 2500000; void std_test() { @@ -47,7 +47,7 @@ void stc_test() printf("Built priority queue: %f secs\n", (float)(clock() - start)/(float)CLOCKS_PER_SEC); printf("%g ", *cpque_f_top(&pq)); - + start = clock(); c_forrange (i, N) { cpque_f_pop(&pq); diff --git a/misc/benchmarks/plotbench/csmap_benchmark.cpp b/misc/benchmarks/plotbench/csmap_benchmark.cpp index da3fc9cc..60f2db49 100644 --- a/misc/benchmarks/plotbench/csmap_benchmark.cpp +++ b/misc/benchmarks/plotbench/csmap_benchmark.cpp @@ -11,7 +11,7 @@ enum {INSERT, ERASE, FIND, ITER, DESTRUCT, N_TESTS}; const char* operations[] = {"insert", "erase", "find", "iter", "destruct"}; typedef struct { time_t t1, t2; uint64_t sum; float fac; } Range; typedef struct { const char* name; Range test[N_TESTS]; } Sample; -enum {SAMPLES = 2, N = 4000000, R = 4}; +enum {SAMPLES = 2, N = 1000000, R = 4}; uint64_t seed = 1, mask1 = 0xfffffff; static float secs(Range s) { return (float)(s.t2 - s.t1) / CLOCKS_PER_SEC; } @@ -93,7 +93,7 @@ Sample test_stc_map() { s.test[FIND].t1 = clock(); size_t sum = 0; const csmap_x_value* val; - c_forrange (N) + c_forrange (N) if ((val = csmap_x_get(&con, crand() & mask1))) sum += val->second; s.test[FIND].t2 = clock(); diff --git a/misc/benchmarks/plotbench/cvec_benchmark.cpp b/misc/benchmarks/plotbench/cvec_benchmark.cpp index b605f4e6..c488a01c 100644 --- a/misc/benchmarks/plotbench/cvec_benchmark.cpp +++ b/misc/benchmarks/plotbench/cvec_benchmark.cpp @@ -12,7 +12,7 @@ enum {INSERT, ERASE, FIND, ITER, DESTRUCT, N_TESTS}; const char* operations[] = {"insert", "erase", "find", "iter", "destruct"}; typedef struct { time_t t1, t2; uint64_t sum; float fac; } Range; typedef struct { const char* name; Range test[N_TESTS]; } Sample; -enum {SAMPLES = 2, N = 150000000, S = 0x3ffc, R = 4}; +enum {SAMPLES = 2, N = 80000000, S = 0x3ffc, R = 4}; uint64_t seed = 1, mask1 = 0xfffffff, mask2 = 0xffff; static float secs(Range s) { return (float)(s.t2 - s.t1) / CLOCKS_PER_SEC; } diff --git a/misc/benchmarks/plotbench/plot.py b/misc/benchmarks/plotbench/plot.py index fa538285..0ba92264 100644 --- a/misc/benchmarks/plotbench/plot.py +++ b/misc/benchmarks/plotbench/plot.py @@ -4,7 +4,7 @@ import pandas as pd import matplotlib.pyplot as plt #sns.set_theme(style="whitegrid") -comp = ['All compilers', 'Mingw-g++-10.30', 'Win-Clang-12', 'VC-19.28'] +comp = ['All compilers', 'Mingw-g++-11.3.0', 'Win-Clang-14.0.1', 'VC-19.28'] n = int(sys.argv[1]) if len(sys.argv) > 1 else 0 file = sys.argv[2] if len(sys.argv) > 2 else 'plot_win.csv' df = pd.read_csv(file) diff --git a/misc/benchmarks/plotbench/run_all.bat b/misc/benchmarks/plotbench/run_all.bat index 2edd0a1e..98913a50 100644 --- a/misc/benchmarks/plotbench/run_all.bat +++ b/misc/benchmarks/plotbench/run_all.bat @@ -1,5 +1,7 @@ set out=plot_win.csv echo Compiler,Library,C,Method,Seconds,Ratio> %out% +echo gcc sh run_gcc.sh >> %out% +echo clang sh run_clang.sh >> %out% -call run_vc.bat >> %out% +REM call run_vc.bat >> %out% diff --git a/misc/benchmarks/plotbench/run_clang.sh b/misc/benchmarks/plotbench/run_clang.sh index ae19486e..096e71be 100644 --- a/misc/benchmarks/plotbench/run_clang.sh +++ b/misc/benchmarks/plotbench/run_clang.sh @@ -6,7 +6,7 @@ clang++ -I../include -O3 -o cmap_benchmark$exe cmap_benchmark.cpp clang++ -I../include -O3 -o csmap_benchmark$exe csmap_benchmark.cpp clang++ -I../include -O3 -o cvec_benchmark$exe cvec_benchmark.cpp -c='Win-Clang-12' +c='Win-Clang-14.0.1' ./cdeq_benchmark$exe $c ./clist_benchmark$exe $c ./cmap_benchmark$exe $c diff --git a/misc/benchmarks/plotbench/run_gcc.sh b/misc/benchmarks/plotbench/run_gcc.sh index 6a6472c0..5249ed1e 100644 --- a/misc/benchmarks/plotbench/run_gcc.sh +++ b/misc/benchmarks/plotbench/run_gcc.sh @@ -4,9 +4,9 @@ g++ -I../include -O3 -o cmap_benchmark cmap_benchmark.cpp g++ -I../include -O3 -o csmap_benchmark csmap_benchmark.cpp g++ -I../include -O3 -o cvec_benchmark cvec_benchmark.cpp -c='Mingw-g++-10.30' +c='Mingw-g++-11.3.0' ./cdeq_benchmark $c ./clist_benchmark $c ./cmap_benchmark $c ./csmap_benchmark $c -./cvec_benchmark $c \ No newline at end of file +./cvec_benchmark $c diff --git a/misc/benchmarks/plotbench/run_vc.bat b/misc/benchmarks/plotbench/run_vc.bat index 3dca925b..dc4938f8 100644 --- a/misc/benchmarks/plotbench/run_vc.bat +++ b/misc/benchmarks/plotbench/run_vc.bat @@ -1,3 +1,4 @@ + @echo off if "%VSINSTALLDIR%"=="" call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars64.bat" >nul cl.exe -nologo -EHsc -std:c++latest -I../include -O2 cdeq_benchmark.cpp >nul @@ -12,4 +13,4 @@ cdeq_benchmark.exe %c% clist_benchmark.exe %c% cmap_benchmark.exe %c% csmap_benchmark.exe %c% -cvec_benchmark.exe %c% \ No newline at end of file +cvec_benchmark.exe %c% -- cgit v1.2.3 From 701b7af4aaf9fe3965c656c500d9200dd7c4831d Mon Sep 17 00:00:00 2001 From: Tyge Lovset Date: Fri, 7 Apr 2023 22:51:45 +0200 Subject: More docs updating. --- README.md | 67 +++++++-------- docs/ccommon_api.md | 208 +++++++++++++++++++++++++---------------------- include/stc/ccommon.h | 2 +- include/stc/extend.h | 2 +- misc/examples/forloops.c | 2 +- misc/examples/functor.c | 2 +- 6 files changed, 148 insertions(+), 135 deletions(-) (limited to 'include') diff --git a/README.md b/README.md index 224e7cb3..6f07f8ff 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ STC - Smart Template Containers for C ===================================== -### [Version 4.2](#version-history) +### [Version 4.2 RC](#version-history) --- Description @@ -35,13 +35,13 @@ Containers Algorithms ---------- -- [***common*** Generic container algorithms](docs/ccommon_api.md#algorithms) -- [***filter*** - Ranges-like filtering](docs/ccommon_api.md#c_forfilter) -- [***coroutine*** - Tiny, fast and portable coroutine implementation](docs/ccommon_api.md#coroutines) -- [***cregex*** - Regular expressions based on Rob Pike's regexp9](docs/cregex_api.md) -- [***crange*** - Generalized iota integer generator](docs/ccommon_api.md#crange) -- [***crand*** - A novel very fast *PRNG* based on ***sfc64***](docs/crandom_api.md) -- [***coption*** - A ***getopt***-alike command line argument parser](docs/coption_api.md) +- [***Ranged for-loops*** - c_foreach, c_forpair, c_forlist](docs/ccommon_api.md#ranged-for-loops) +- [***Range algorithms*** - c_forrange, crange, c_forfilter](docs/ccommon_api.md#range-algorithms) +- [***Generic algorithms*** - c_make, c_find_if, c_erase_if, etc.](docs/ccommon_api.md#generic-algorithms) +- [***Coroutines*** - Simon Tatham's coroutines done right](docs/ccommon_api.md#coroutines) +- [***Regular expressions*** - modernized Rob Pike's Plan-9 regexp](docs/cregex_api.md) +- [***Random numbers*** - a novel very fast *PRNG* based on *SFC64*](docs/crandom_api.md) +- [***Command line argument parser*** - similar to *getopt()*](docs/coption_api.md) --- List of contents @@ -49,7 +49,7 @@ List of contents - [Highlights](#highlights) - [STC is unique!](#stc-is-unique) - [Performance](#performance) -- [STC naming conventions](#stc-naming-conventions) +- [Naming conventions](#naming-conventions) - [Usage](#usage) - [Installation](#installation) - [Specifying template parameters](#specifying-template-parameters) @@ -57,19 +57,19 @@ List of contents - [The *erase* methods](#the-erase-methods) - [User-defined container type name](#user-defined-container-type-name) - [Forward declarations](#forward-declarations) -- [Per-container-instance customization](#per-container-instance-customization) +- [Per container-instance customization](#per-container-instance-customization) - [Memory efficiency](#memory-efficiency) --- ## Highlights -- **No boilerplate code** - Minimal code is needed to setup containers with any element type. Specify only what is needed, e.g. ***cmp***- and/or ***clone***-, ***drop***- functions, and leave the rest as defaults. +- **No boilerplate code** - Specify only the required template parameters, e.g. ***cmp***- and/or ***clone***-, ***drop***- functions, and leave the rest as defaults. - **Fully type safe** - Because of templating, it avoids error-prone casting of container types and elements back and forth from the containers. -- **User friendly** - Just include the headers and you are good. The API and functionality is very close to c++ STL, and is fully listed in the docs. +- **User friendly** - Just include the headers and you are good. The API and functionality is very close to c++ STL and is fully listed in the docs. - **Unparalleled performance** - Maps and sets are much faster than the C++ STL containers, the remaining are similar in speed. -- **Fully memory managed** - All containers will destruct keys/values via destructor (defined as macro parameters before including the container header). Also, smart pointers are supported and can be stored in containers, see ***carc*** and ***cbox***. -- **Uniform, easy-to-learn API** - Uniform and intuitive method/type names and usage across the various containers. -- **No signed/unsigned mixing** - Unsigned sizes and indices mixed with signed in comparisons and calculations is asking for trouble. STC uses only signed numbers in the API for this reason. +- **Fully memory managed** - Containers destructs keys/values via default or user supplied drop function. They may be cloned if element types are clonable. Also, smart pointers are supported and can be stored in containers. See ***carc*** and ***cbox***. +- **Uniform, easy-to-learn API** - Intuitive method/type names and uniform usage across the various containers. +- **No signed/unsigned mixing** - Unsigned sizes and indices mixed with signed for comparison and calculation is asking for trouble. STC only uses signed numbers in the API for this reason. - **Small footprint** - Small source code and generated executables. The executable from the example below using *four different* container types is only ***19 Kb in size*** compiled with gcc -O3 -s on Linux. - **Dual mode compilation** - By default it is a simple header-only library with inline and static methods only, but you can easily switch to create a traditional library with shared symbols, without changing existing source files. See the Installation section. - **No callback functions** - All passed template argument functions/macros are directly called from the implementation, no slow callbacks which requires storage. @@ -87,7 +87,8 @@ that the elements are of basic types. For more complex types, additional templat 2. ***Alternative insert/lookup type***. You may specify an alternative type to use for lookup in containers. E.g., containers with STC string elements (**cstr**) uses `const char*` as lookup type, so construction of a `cstr` (which may allocate memory) for the lookup *is not needed*. Hence, the alt. lookup -key does not need to be destroyed after use, as it is normally a POD type. Finally, the alternative +key does not need to be destroyed after use as it is normally a POD type. Finally, the alternative +key does not need to be destroyed after use as it is normally a POD type. Finally, the alternative lookup type may be passed to an ***emplace***-function. E.g. instead of calling `cvec_str_push(&vec, cstr_from("Hello"))`, you may call `cvec_str_emplace(&vec, "Hello")`, which is functionally identical, but more convenient. @@ -100,7 +101,7 @@ same element access syntax. E.g.: --- ## Performance -STC is a fast and memory efficient library, and code compiles very fast: +STC is a fast and memory efficient library, and code compiles fast: ![Benchmark](misc/benchmarks/pics/benchmark.gif) @@ -114,7 +115,7 @@ Benchmark notes: - **map and unordered map**: *insert*: n/2 random numbers, n/2 sequential numbers. *erase*: n/2 keys in the map, n/2 random keys. --- -## STC naming conventions +## Naming conventions - Container names are prefixed by `c`, e.g. `cvec`, `cstr`. - Public STC macros are prefixed by `c_`, e.g. `c_foreach`, `c_make`. @@ -144,10 +145,10 @@ Benchmark notes: --- ## Usage -The functionality of STC containers is similar to C++ STL standard containers. All containers except for a few, +STC containers have similar functionality to C++ STL standard containers. All containers except for a few, like **cstr** and **cbits** are generic/templated. No type casting is done, so containers are type-safe like -templated types in C++. However, the specification of template parameters are naturally different. Here is -a basic usage example: +templated types in C++. However, the specification of template parameters are naturally different. In STC, +you specify template parameters by `#define` before including the container: ```c #define i_type Floats // Container type name; unless defined name would be cvec_float #define i_val float // Container element type @@ -166,7 +167,7 @@ int main(void) Floats_sort(&nums); - c_foreach (i, Floats, nums) // Alternative and recommended way to iterate nums. + c_foreach (i, Floats, nums) // Alternative and recommended way to iterate. printf(" %g", *i.ref); // i.ref is a pointer to the current element. Floats_drop(&nums); // cleanup memory @@ -181,7 +182,7 @@ You may switch to a different container type, e.g. a sorted set (csset): int main() { - Floats nums = c_make(Floats, {30.f, 10.f, 20.f}); // Initialize nums with a list of floats. + Floats nums = c_make(Floats, {30.f, 10.f, 20.f}); // Initialize with a list of floats. Floats_push(&nums, 50.f); Floats_push(&nums, 40.f); @@ -192,11 +193,11 @@ int main() Floats_drop(&nums); } ``` -For user-defined struct elements, `i_cmp` compare function should be defined, as the default `<` and `==` +For user-defined struct elements, `i_cmp` compare function should be defined as the default `<` and `==` only works for integral types. *Alternatively, `#define i_opt c_no_cmp` to disable sorting and searching*. Similarily, if an element destructor `i_valdrop` is defined, `i_valclone` function is required. *Alternatively `#define i_opt c_no_clone` to disable container cloning.* -Let's make a vector of vectors that can be cloned. All of its element vectors will be destroyed when destroying the Vec2D. +Let's make a vector of vectors, which can be cloned. All of its element vectors will be destroyed when destroying the Vec2D. ```c #include @@ -206,7 +207,7 @@ Let's make a vector of vectors that can be cloned. All of its element vectors wi #define i_type Vec2D #define i_valclass Vec // Use i_valclass when element type has "members" _clone(), _drop() and _cmp(). -#define i_opt c_no_cmp // However, disable search/sort for Vec2D because Vec_cmp() is not defined. +#define i_opt c_no_cmp // Disable cmp (search/sort) for Vec2D because Vec_cmp() is not defined. #include int main(void) @@ -542,11 +543,11 @@ typedef struct Dataset { ``` --- -## Per-container-instance customization -Sometimes it is useful to extend a container type to hold extra data, e.g. a comparison -or allocator function pointer or some context that the function pointers can use. Most -libraries solve this by adding an opaque pointer (void*) or some function pointer(s) into -the data structure for the user to manage. This solution has a few disadvantages, e.g. the +## Per container-instance customization +Sometimes it is useful to extend a container type to store extra data, e.g. a comparison +or allocator function pointer or a context which the function pointers can use. Most +libraries solve this by adding an opaque pointer (void*) or function pointer(s) into +the data structure for the user to manage. This solution has a few disadvantages: the pointers are not typesafe, and they take up space when not needed. STC solves this by letting the user create a container wrapper struct where both the container and extra data fields can be stored. The template parameters may then access the extra data using the "container_of" @@ -564,10 +565,10 @@ the by inclusion of ``. #define i_allocator pgs #define i_no_clone -#define i_extend MemoryContext memctx +#define i_extend MemoryContext memctx; #include ``` -Define both `i_type` and `i_con` (the container type) before including the custom header: +To use it, define both `i_type` and `i_con` (the container type) before including the custom header: ```c #define i_type IMap #define i_key int diff --git a/docs/ccommon_api.md b/docs/ccommon_api.md index af27bd1d..21eaf884 100644 --- a/docs/ccommon_api.md +++ b/docs/ccommon_api.md @@ -2,16 +2,17 @@ The following macros are recommended to use, and they safe/have no side-effects. -## Loop abstraction macros +--- +## Ranged for-loops -### c_foreach, c_foreach_r, c_forpair +### c_foreach, c_foreach_rv, c_forpair -| Usage | Description | -|:-----------------------------------------|:----------------------------------------| -| `c_foreach (it, ctype, container)` | Iteratate all elements | -| `c_foreach (it, ctype, it1, it2)` | Iterate the range [it1, it2) | -| `c_foreach_r (it, ctype, container)` | Iteratate in reverse (cstack,cvec,cdeq) | -| `c_forpair (key, val, ctype, container)` | Iterate with structured binding | +| Usage | Description | +|:-----------------------------------------|:------------------------------------------| +| `c_foreach (it, ctype, container)` | Iteratate all elements | +| `c_foreach (it, ctype, it1, it2)` | Iterate the range [it1, it2) | +| `c_foreach_rv (it, ctype, container)` | Iteratate in reverse (cstack, cvec, cdeq) | +| `c_forpair (key, val, ctype, container)` | Iterate with structured binding | ```c #define i_key int @@ -40,6 +41,25 @@ c_forpair (id, count, csmap_ii, map) // (3 2) (5 4) (7 3) (12 5) (23 1) ``` +### c_forlist +Iterate compound literal array elements. Additional to `i.ref`, you can access `i.data`, `i.size`, and `i.index` of the input list/element. +```c +// apply multiple push_backs +c_forlist (i, int, {1, 2, 3}) + cvec_i_push_back(&vec, *i.ref); + +// insert in existing map +c_forlist (i, cmap_ii_raw, { {4, 5}, {6, 7} }) + cmap_ii_insert(&map, i.ref->first, i.ref->second); + +// string literals pushed to a stack of cstr: +c_forlist (i, const char*, {"Hello", "crazy", "world"}) + cstack_str_emplace(&stk, *i.ref); +``` + +--- +## Range algorithms + ### c_forrange Abstraction for iterating sequence of integers. Like python's **for** *i* **in** *range()* loop. @@ -61,24 +81,38 @@ c_forrange (i, 30, 0, -5) printf(" %lld", i); // 30 25 20 15 10 5 ``` -### c_forlist -Iterate compound literal array elements. Additional to `i.ref`, you can access `i.data`, `i.size`, and `i.index` of the input list/element. +### crange +A number sequence generator type, similar to [boost::irange](https://www.boost.org/doc/libs/release/libs/range/doc/html/range/reference/ranges/irange.html). The **crange_value** type is `long long`. Below *start*, *stop*, and *step* are of type *crange_value*: ```c -// apply multiple push_backs -c_forlist (i, int, {1, 2, 3}) - cvec_i_push_back(&vec, *i.ref); +crange& crange_object(...) // create a compound literal crange object +crange crange_make(stop); // will generate 0, 1, ..., stop-1 +crange crange_make(start, stop); // will generate start, start+1, ... stop-1 +crange crange_make(start, stop, step); // will generate start, start+step, ... upto-not-including stop + // note that step may be negative. +crange_iter crange_begin(crange* self); +crange_iter crange_end(crange* self); +void crange_next(crange_iter* it); -// insert in existing map -c_forlist (i, cmap_ii_raw, { {4, 5}, {6, 7} }) - cmap_ii_insert(&map, i.ref->first, i.ref->second); +// 1. All primes less than 32: +crange r1 = crange_make(3, 32, 2); +printf("2"); // first prime +c_forfilter (i, crange, r1, isPrime(*i.ref)) + printf(" %lld", *i.ref); +// 2 3 5 7 11 13 17 19 23 29 31 -// string literals pushed to a stack of cstr: -c_forlist (i, const char*, {"Hello", "crazy", "world"}) - cstack_str_emplace(&stk, *i.ref); +// 2. The first 11 primes: +printf("2"); +c_forfilter (i, crange, crange_object(3, INT64_MAX, 2), + isPrime(*i.ref) && + c_flt_take(10) +){ + printf(" %lld", *i.ref); +} +// 2 3 5 7 11 13 17 19 23 29 31 ``` ### c_forfilter -Iterate containers with stop-criteria and chained range filtering. +Iterate a container/range with chained range filtering. | Usage | Description | |:----------------------------------------------------|:---------------------------------------| @@ -122,46 +156,14 @@ int main() { ``` Note that `c_flt_take()` and `c_flt_takewhile()` breaks the loop on false. -## Generators - -### crange -A number sequence generator type, similar to [boost::irange](https://www.boost.org/doc/libs/release/libs/range/doc/html/range/reference/ranges/irange.html). The **crange_value** type is `long long`. Below *start*, *stop*, and *step* are of type *crange_value*: -```c -crange& crange_object(...) // create a compound literal crange object -crange crange_make(stop); // will generate 0, 1, ..., stop-1 -crange crange_make(start, stop); // will generate start, start+1, ... stop-1 -crange crange_make(start, stop, step); // will generate start, start+step, ... upto-not-including stop - // note that step may be negative. -crange_iter crange_begin(crange* self); -crange_iter crange_end(crange* self); -void crange_next(crange_iter* it); - -// 1. All primes less than 32: -crange r1 = crange_make(3, 32, 2); -printf("2"); // first prime -c_forfilter (i, crange, r1, isPrime(*i.ref)) - printf(" %lld", *i.ref); -// 2 3 5 7 11 13 17 19 23 29 31 - -// 2. The first 11 primes: -printf("2"); -c_forfilter (i, crange, crange_object(3, INT64_MAX, 2), - isPrime(*i.ref) && - c_flt_take(10) -){ - printf(" %lld", *i.ref); -} -// 2 3 5 7 11 13 17 19 23 29 31 -``` -## Algorithms +--- +## Generic algorithms -### c_make, c_new, c_delete +### c_make, c_drop -- *c_make(C, {...})*: Make any container from an initializer list. Example: +Make any container from an initializer list: ```c -#define i_val_str // owned cstr string value type -//#define i_valclass crawstr // non-owning const char* values with strcmp/cstrhash -//#define i_val const char* // non-owning const char* values with pointer cmp/hash. +#define i_val_str // owned cstr string value type #include #define i_key int @@ -170,26 +172,21 @@ c_forfilter (i, crange, crange_object(3, INT64_MAX, 2), ... // Initializes with const char*, internally converted to cstr! cset_str myset = c_make(cset_str, {"This", "is", "the", "story"}); +cset_str myset2 = c_clone(myset); int x = 7, y = 8; cmap_int mymap = c_make(cmap_int, { {1, 2}, {3, 4}, {5, 6}, {x, y} }); ``` - -- ***c_new(Type)***: Allocate *and init* a new object on the heap -- ***c_delete(Type, ptr)***: Drop *and free* an object allocated on the heap +Drop multiple containers of the same type: ```c -#include - -cstr *stringptr = c_new(cstr, cstr_from("Hello")); -printf("%s\n", cstr_str(stringptr)); -c_delete(cstr, stringptr); +c_drop(cset_str, &myset, &myset2); ``` ### c_find_if, c_erase_if, c_eraseremove_if Find or erase linearily in containers using a predicate -- For *c_find_if (iter, C, c, pred)*, ***iter*** must be declared outside/prior to call. -- Use *c_erase_if (iter, C, c, pred)* with **clist**, **cmap**, **cset**, **csmap**, and **csset**. -- Use *c_eraseremove_if (iter, C, c, pred)* with **cstack**, **cvec**, **cdeq**, and **cqueue**. +- For `c_find_if(iter, C, c, pred)`, ***iter*** is in/out and must be declared prior to call. +- Use `c_erase_if(iter, C, c, pred)` with **clist**, **cmap**, **cset**, **csmap**, and **csset**. +- Use `c_eraseremove_if(iter, C, c, pred)` with **cstack**, **cvec**, **cdeq**, and **cqueue**. ```c // Search vec for first value > 2: cvec_i_iter i; @@ -208,51 +205,66 @@ if (it.ref) cmap_str_erase_at(&map, it); c_erase_if(i, csmap_str, map, cstr_contains(i.ref, "hello")); ``` -### c_swap, c_drop, c_const_cast +### c_new, c_delete + +- `c_new(Type, val)` - Allocate *and init* a new object on the heap +- `c_delete(Type, ptr)` - Drop *and free* an object allocated on the heap. NULL is OK. +```c +#include + +cstr *str_p = c_new(cstr, cstr_from("Hello")); +printf("%s\n", cstr_str(str_p)); +c_delete(cstr, str_p); +``` + +### c_malloc, c_calloc, c_realloc, c_free +Memory allocator wrappers that uses signed sizes. + +### c_arraylen +Return number of elements in an array. array must not be a pointer! +```c +int array[] = {1, 2, 3, 4}; +intptr_t n = c_arraylen(array); +``` + +### c_swap, c_const_cast ```c // Safe macro for swapping internals of two objects of same type: c_swap(cmap_int, &map1, &map2); -// Drop multiple containers of same type: -c_drop(cvec_i, &vec1, &vec2, &vec3); - // Type-safe casting a from const (pointer): const char cs[] = "Hello"; char* s = c_const_cast(char*, cs); // OK int* ip = c_const_cast(int*, cs); // issues a warning! ``` -### General predefined template parameter functions +### Predefined template parameter functions +**crawstr** - Non-owned `const char*` "class" element type: `#define i_valclass crawstr` ```c -int c_default_cmp(const Type*, const Type*); -Type c_default_clone(Type val); // simple copy -Type c_default_toraw(const Type* val); // dereference val -void c_default_drop(Type* val); // does nothing - typedef const char* crawstr; int crawstr_cmp(const crawstr* x, const crawstr* y); bool crawstr_eq(const crawstr* x, const crawstr* y); uint64_t crawstr_hash(const crawstr* x); ``` - -### c_malloc, c_calloc, c_realloc, c_free: customizable allocators -Memory allocator wrappers that uses signed sizes. - -### c_arraylen -Return number of elements in an array. array must not be a pointer! +Default implementations ```c -int array[] = {1, 2, 3, 4}; -intptr_t n = c_arraylen(array); +int c_default_cmp(const Type*, const Type*); // <=> +bool c_default_less(const Type*, const Type*); // < +bool c_default_eq(const Type*, const Type*); // == +uint64_t c_default_hash(const Type*); +Type c_default_clone(Type val); // return val +Type c_default_toraw(const Type* p); // return *p +void c_default_drop(Type* p); // does nothing ``` --- ## Coroutines This is an improved implementation of Simon Tatham's classic C code, which utilizes the *Duff's device* trick. However, Tatham's implementation is not typesafe, -and it always allocates the coroutine's internal state dynamically. Also, -it does not let the coroutine do self-cleanup on early finish, i.e. it -just frees the dynamically allocated memory. +and it always allocates the coroutine's internal state dynamically. But most crucially, +it does not let the coroutine do self-cleanup on early finish - i.e. it +only frees the initial dynamically allocated memory. In this implementation a coroutine may have any signature, but it should take some struct pointer as parameter, which must contain the member `int cco_state;` @@ -260,8 +272,8 @@ The struct should normally store all the *local* variables to be used in the coroutine. It can also store input and output data if desired. The coroutine example below generates Pythagorian triples, but the main user-loop -skips the triples which are upscaled version of smaller ones, by checking -the gcd() function, and breaks when diagonal length >= 100: +skips the triples which are upscaled version of smaller ones by checking +the gcd() function, and breaks when the diagonal size >= 100: ```c #include @@ -271,14 +283,14 @@ struct triples { int cco_state; // required member }; -bool triples_next(struct triples* I) { // coroutine - cco_begin(I); - for (I->c = 5; I->n; ++I->c) { - for (I->a = 1; I->a < I->c; ++I->a) { - for (I->b = I->a + 1; I->b < I->c; ++I->b) { - if ((int64_t)I->a*I->a + (int64_t)I->b*I->b == (int64_t)I->c*I->c) { +bool triples_next(struct triples* i) { // coroutine + cco_begin(i); + for (i->c = 5; i->n; ++i->c) { + for (i->a = 1; i->a < i->c; ++i->a) { + for (i->b = i->a + 1; i->b < i->c; ++i->b) { + if ((int64_t)i->a*i->a + (int64_t)i->b*i->b == (int64_t)i->c*i->c) { cco_yield(true); - if (--I->n == 0) cco_return; + if (--i->n == 0) cco_return; } } } diff --git a/include/stc/ccommon.h b/include/stc/ccommon.h index 362b09ce..24ad59f9 100644 --- a/include/stc/ccommon.h +++ b/include/stc/ccommon.h @@ -182,7 +182,7 @@ 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_r(it, C, cnt) \ +#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) diff --git a/include/stc/extend.h b/include/stc/extend.h index a8cb5f5b..cbfc4a12 100644 --- a/include/stc/extend.h +++ b/include/stc/extend.h @@ -50,7 +50,7 @@ #endif typedef struct { - i_extend; + i_extend i_type get; } c_PASTE(i_type, Ext); diff --git a/misc/examples/forloops.c b/misc/examples/forloops.c index 82126456..1fc00614 100644 --- a/misc/examples/forloops.c +++ b/misc/examples/forloops.c @@ -42,7 +42,7 @@ int main() printf(" %d", *i.ref); puts("\n\nc_foreach_r: reverse"); - c_foreach_r (i, IVec, vec) + c_foreach_rv (i, IVec, vec) printf(" %d", *i.ref); puts("\n\nc_foreach in map:"); diff --git a/misc/examples/functor.c b/misc/examples/functor.c index 7cc770d0..7417080b 100644 --- a/misc/examples/functor.c +++ b/misc/examples/functor.c @@ -9,7 +9,7 @@ #define i_type IPQue #define i_val int -#define i_extend bool (*less)(const int*, const int*) +#define i_extend bool (*less)(const int*, const int*); #define i_less(x, y) c_getcon(self)->less(x, y) #define i_con cpque #include -- cgit v1.2.3 From d92ffe3da29b3352c90b2d356e395914ba5b3f52 Mon Sep 17 00:00:00 2001 From: Tyge Lovset Date: Sat, 8 Apr 2023 11:02:39 +0200 Subject: More docs updates, and a change in stc/extend.h. --- README.md | 51 +++++++++++++++++++++++++++-------------------- docs/ccommon_api.md | 33 +++++++++++++++--------------- include/stc/algo/crange.h | 4 ++-- include/stc/ccommon.h | 3 ++- include/stc/extend.h | 4 ++-- misc/examples/forfilter.c | 2 +- misc/examples/functor.c | 10 +++++----- misc/examples/prime.c | 2 +- 8 files changed, 59 insertions(+), 50 deletions(-) (limited to 'include') diff --git a/README.md b/README.md index 6f07f8ff..220349b3 100644 --- a/README.md +++ b/README.md @@ -8,11 +8,10 @@ STC - Smart Template Containers for C --- Description ----------- -STC is a *modern*, *fully typesafe*, *fast* and *compact* container and algorithm library for C99. +STC is a *modern*, *typesafe*, *fast* and *compact* container and algorithms library for C99. The API naming is similar to C++ STL, but it takes inspiration from Rust and Python as well. -The library let you store and manage trivial and highly complex data in a variety of -containers with ease. It is optimized for speed, usage ergonomics, consistency, -and it creates small binaries. +The library handles everything from trivial to highly complex data using *templates*, and it +supports a variety of containers. Containers ---------- @@ -80,18 +79,18 @@ List of contents ## STC is unique! 1. ***Centralized analysis of template parameters***. The analyser assigns values to all -non-specified template parameters (based on the specified ones) using meta-programming, -so that you don't have to! You may specify a set of "standard" template parameters for each container, -but as a minimum *only one is required*: `i_val` (+ `i_key` for maps). In this case STC assumes -that the elements are of basic types. For more complex types, additional template parameters must be given. -2. ***Alternative insert/lookup type***. You may specify an alternative type to use for lookup in -containers. E.g., containers with STC string elements (**cstr**) uses `const char*` as lookup type, -so construction of a `cstr` (which may allocate memory) for the lookup *is not needed*. Hence, the alt. lookup -key does not need to be destroyed after use as it is normally a POD type. Finally, the alternative -key does not need to be destroyed after use as it is normally a POD type. Finally, the alternative -lookup type may be passed to an ***emplace***-function. E.g. instead of calling -`cvec_str_push(&vec, cstr_from("Hello"))`, you may call `cvec_str_emplace(&vec, "Hello")`, -which is functionally identical, but more convenient. +non-specified template parameters (based on the specified ones) using meta-programming, so +that you don't have to! You may specify a set of "standard" template parameters for each +container, but as a minimum *only one is required*: `i_val` (+ `i_key` for maps). In this +case, STC assumes that the elements are of basic types. For non-trivial types, additional +template parameters must be given. +2. ***Alternative insert/lookup type***. You may specify an alternative type to use for +lookup in containers. E.g., containers with STC string elements (**cstr**) uses `const char*` +as lookup type, so constructing a `cstr` (which may allocate memory) for the lookup +*is not needed*. Hence, the alternative lookup key does not need to be destroyed after use, +as it is normally a POD type. Finally, the key may be passed to an ***emplace***-function. +So instead of calling e.g. `cvec_str_push(&vec, cstr_from("Hello"))`, you may call +`cvec_str_emplace(&vec, "Hello")`, which is functionally identical, but more convenient. 3. ***Standardized container iterators***. All containers can be iterated in the same manner, and all use the same element access syntax. E.g.: - `c_foreach (it, MyInts, myints) *it.ref += 42;` works for any container defined as @@ -146,9 +145,9 @@ Benchmark notes: --- ## Usage STC containers have similar functionality to C++ STL standard containers. All containers except for a few, -like **cstr** and **cbits** are generic/templated. No type casting is done, so containers are type-safe like -templated types in C++. However, the specification of template parameters are naturally different. In STC, -you specify template parameters by `#define` before including the container: +like **cstr** and **cbits** are generic/templated. No type casting is used, so containers are type-safe like +templated types in C++. However, to specify template parameters with STC, you define them as macros prior to +including the container: ```c #define i_type Floats // Container type name; unless defined name would be cvec_float #define i_val float // Container element type @@ -576,10 +575,10 @@ To use it, define both `i_type` and `i_con` (the container type) before includin #define i_con csmap #include "stcpgs.h" -// Note the wrapper struct type is IMapExt. IMap is accessed by .get +// Note the wrapper struct type is IMap_ext. IMap is accessed by .get void maptest() { - IMapExt map = {.memctx=CurrentMemoryContext}; + IMap_ext map = {.memctx=CurrentMemoryContext}; c_forrange (i, 1, 16) IMap_insert(&map.get, i*i, i); @@ -605,9 +604,17 @@ STC is generally very memory efficient. Memory usage for the different container --- # Version History +## Version 4.2 +- Much improved documentation +- Added Coroutines + documentation +- Added `c_const_cast()` typesafe macro. +- Renamed c_foreach_r => `c_foreach_rv` +- Renamed c_flt_count(i) => `c_flt_counter(i)` +- Renamed c_flt_last(i) => `c_flt_getcount(i)` +- Removed c_PAIR ## Version 4.1.1 -I am happy to finally announce a new release! Major changes: +Major changes: - A new exciting [**cspan**](docs/cspan_api.md) single/multi-dimensional array view (with numpy-like slicing). - Signed sizes and indices for all containers. See C++ Core Guidelines by Stroustrup/Sutter: [ES.100](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#es100-dont-mix-signed-and-unsigned-arithmetic), [ES.102](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#es102-use-signed-types-for-arithmetic), [ES.106](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#es106-dont-try-to-avoid-negative-values-by-using-unsigned), and [ES.107](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#es107-dont-use-unsigned-for-subscripts-prefer-gslindex). - Customizable allocator [per templated container type](https://github.com/tylov/STC/discussions/44#discussioncomment-4891925). diff --git a/docs/ccommon_api.md b/docs/ccommon_api.md index 21eaf884..90191e40 100644 --- a/docs/ccommon_api.md +++ b/docs/ccommon_api.md @@ -84,7 +84,7 @@ c_forrange (i, 30, 0, -5) printf(" %lld", i); ### crange A number sequence generator type, similar to [boost::irange](https://www.boost.org/doc/libs/release/libs/range/doc/html/range/reference/ranges/irange.html). The **crange_value** type is `long long`. Below *start*, *stop*, and *step* are of type *crange_value*: ```c -crange& crange_object(...) // create a compound literal crange object +crange& crange_obj(...) // create a compound literal crange object crange crange_make(stop); // will generate 0, 1, ..., stop-1 crange crange_make(start, stop); // will generate start, start+1, ... stop-1 crange crange_make(start, stop, step); // will generate start, start+step, ... upto-not-including stop @@ -102,7 +102,7 @@ c_forfilter (i, crange, r1, isPrime(*i.ref)) // 2. The first 11 primes: printf("2"); -c_forfilter (i, crange, crange_object(3, INT64_MAX, 2), +c_forfilter (i, crange, crange_obj(3, INT64_MAX, 2), isPrime(*i.ref) && c_flt_take(10) ){ @@ -260,22 +260,23 @@ void c_default_drop(Type* p); // does nothing --- ## Coroutines -This is an improved implementation of Simon Tatham's classic C code, which utilizes -the *Duff's device* trick. However, Tatham's implementation is not typesafe, -and it always allocates the coroutine's internal state dynamically. But most crucially, +This is a much improved implementation of +[Simon Tatham's coroutines](https://www.chiark.greenend.org.uk/~sgtatham/coroutines.html), +which utilizes the *Duff's device* trick. Tatham's implementation is not typesafe, +and it always allocates the coroutine's internal state dynamically. But crucially, it does not let the coroutine do self-cleanup on early finish - i.e. it only frees the initial dynamically allocated memory. -In this implementation a coroutine may have any signature, but it should -take some struct pointer as parameter, which must contain the member `int cco_state;` +In this implementation, a coroutine may have any signature, but it should +take a struct pointer as parameter, which must contain the member `int cco_state;` The struct should normally store all the *local* variables to be used in the coroutine. It can also store input and output data if desired. -The coroutine example below generates Pythagorian triples, but the main user-loop -skips the triples which are upscaled version of smaller ones by checking -the gcd() function, and breaks when the diagonal size >= 100: +The coroutine example below generates Pythagorian triples, but the calling loop +skips the triples which are upscaled version of smaller ones, by checking +the gcd() function. It also ensures that it stops when the diagonal size >= 100: ```c -#include +#include struct triples { int n; // input: max number of triples to be generated. @@ -311,8 +312,7 @@ int gcd(int a, int b) { // greatest common denominator int main() { - puts("\nCoroutine triples:"); - struct triples t = {INT32_MAX}; + struct triples t = {.n=INT32_MAX}; int n = 0; while (triples_next(&t)) { @@ -324,12 +324,13 @@ int main() if (t.c < 100) printf("%d: {%d, %d, %d}\n", ++n, t.a, t.b, t.c); else - cco_stop(&t); // make sure coroutine cleanup is done + cco_stop(&t); // cleanup in next coroutine call/resume } } ``` ### Coroutine API -**Note**: `cco_yield()` may not be called inside a `switch` statement. Use `if-else-if` constructs instead. +**Note**: *cco_yield()* may not be called inside a `switch` statement. Use `if-else-if` constructs instead. +To resume the coroutine from where it was suspended with *cco_yield()*, simply call the coroutine again. | | Function / operator | Description | |:----------|:-------------------------------------|:----------------------------------------| @@ -340,7 +341,7 @@ int main() | `void` | `cco_begin(ctx)` | Begin coroutine block | | `rettype` | `cco_end(retval)` | End coroutine block with return value | | `rettype` | `cco_end()` | End coroutine block with (void) | -| `rettype` | `cco_yield(retval)` | Yield a value | +| `rettype` | `cco_yield(retval)` | Return a value and suspend execution | | `rettype` | `cco_yield(corocall2, ctx2, retval)` | Yield from another coroutine and return val | | `rettype` | `cco_yield(corocall2, ctx2)` | Yield from another coroutine (void) | | | From the caller side: | | diff --git a/include/stc/algo/crange.h b/include/stc/algo/crange.h index 91ffdd56..ca06c258 100644 --- a/include/stc/algo/crange.h +++ b/include/stc/algo/crange.h @@ -34,7 +34,7 @@ int main() // use a temporary crange object. int a = 100, b = INT32_MAX; - c_forfilter (i, crange, crange_object(a, b, 8), + c_forfilter (i, crange, crange_obj(a, b, 8), c_flt_skip(i, 10) && c_flt_take(i, 3)) printf(" %lld", *i.ref); @@ -46,7 +46,7 @@ int main() #include -#define crange_object(...) \ +#define crange_obj(...) \ (*(crange[]){crange_make(__VA_ARGS__)}) typedef long long crange_value; diff --git a/include/stc/ccommon.h b/include/stc/ccommon.h index 24ad59f9..1a2b3c3f 100644 --- a/include/stc/ccommon.h +++ b/include/stc/ccommon.h @@ -122,8 +122,9 @@ #define c_make(C, ...) \ C##_from_n((C##_raw[])__VA_ARGS__, c_sizeof((C##_raw[])__VA_ARGS__)/c_sizeof(C##_raw)) -#define c_arraylen(a) (intptr_t)(sizeof(a)/sizeof 0[a]) #define c_litstrlen(literal) (c_sizeof("" literal) - 1) +#define c_arraylen(a) (c_ARRAYLEN(a) + c_static_assert(sizeof(a) != sizeof(uintptr_t))) +#define c_ARRAYLEN(a) (intptr_t)(sizeof(a)/sizeof 0[a]) // Non-owning c-string typedef const char* crawstr; diff --git a/include/stc/extend.h b/include/stc/extend.h index cbfc4a12..66b3ebd1 100644 --- a/include/stc/extend.h +++ b/include/stc/extend.h @@ -52,9 +52,9 @@ typedef struct { i_extend i_type get; -} c_PASTE(i_type, Ext); +} c_PASTE(i_type, _ext); -#define c_getcon(cptr) c_container_of(cptr, _cx_memb(Ext), get) +#define c_getcon(cptr) c_container_of(cptr, _cx_memb(_ext), get) #define i_is_forward #define _i_inc diff --git a/misc/examples/forfilter.c b/misc/examples/forfilter.c index daea68b9..fbb7280f 100644 --- a/misc/examples/forfilter.c +++ b/misc/examples/forfilter.c @@ -54,7 +54,7 @@ fn main() { void demo2(void) { IVec vector = {0}; - c_forfilter (x, crange, crange_object(INT64_MAX), + c_forfilter (x, crange, crange_obj(INT64_MAX), c_flt_skipwhile(x, *x.ref != 11) && (*x.ref % 2) != 0 && c_flt_take(x, 5) diff --git a/misc/examples/functor.c b/misc/examples/functor.c index 7417080b..c0a4f8e8 100644 --- a/misc/examples/functor.c +++ b/misc/examples/functor.c @@ -14,10 +14,10 @@ #define i_con cpque #include -void print_queue(const char* name, IPQueExt q) { +void print_queue(const char* name, IPQue_ext q) { // NB: make a clone because there is no way to traverse // priority_queue's content without erasing the queue. - IPQueExt copy = {q.less, IPQue_clone(q.get)}; + IPQue_ext copy = {q.less, IPQue_clone(q.get)}; for (printf("%s: \t", name); !IPQue_empty(©.get); IPQue_pop(©.get)) printf("%d ", *IPQue_top(©.get)); @@ -38,9 +38,9 @@ int main() printf("%d ", data[i]); puts(""); - IPQueExt q1 = {int_less}; // Max priority queue - IPQueExt minq1 = {int_greater}; // Min priority queue - IPQueExt q5 = {int_lambda}; // Using lambda to compare elements. + IPQue_ext q1 = {int_less}; // Max priority queue + IPQue_ext minq1 = {int_greater}; // Min priority queue + IPQue_ext q5 = {int_lambda}; // Using lambda to compare elements. c_forrange (i, n) IPQue_push(&q1.get, data[i]); diff --git a/misc/examples/prime.c b/misc/examples/prime.c index a576a85c..d0887353 100644 --- a/misc/examples/prime.c +++ b/misc/examples/prime.c @@ -42,7 +42,7 @@ int main(void) puts("\n"); puts("Show the last 50 primes using a temporary crange generator:"); - c_forfilter (i, crange, crange_object(n - 1, 0, -2), + c_forfilter (i, crange, crange_obj(n - 1, 0, -2), cbits_test(&primes, *i.ref/2) && c_flt_take(i, 50) ){ -- cgit v1.2.3 From 2f64fae1f2f041ad3aec4a2388975297075fef42 Mon Sep 17 00:00:00 2001 From: Tyge Lovset Date: Sat, 8 Apr 2023 12:07:29 +0200 Subject: Using "unsafe" c_ARRAYLEN(), because sizeof(shape) may be equal to sizeof pointer. --- include/stc/cspan.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/stc/cspan.h b/include/stc/cspan.h index ac3e9206..ce3c33ce 100644 --- a/include/stc/cspan.h +++ b/include/stc/cspan.h @@ -129,10 +129,10 @@ typedef struct { int32_t d[6]; } cspan_idx6; {.data=(container)->data, .shape={(int32_t)(container)->_len}} #define cspan_from_array(array) \ - {.data=(array) + c_static_assert(sizeof(array) != sizeof(void*)), .shape={c_arraylen(array)}} + {.data=(array) + c_static_assert(sizeof(array) != sizeof(void*)), .shape={c_ARRAYLEN(array)}} #define cspan_size(self) _cspan_size((self)->shape, cspan_rank(self)) -#define cspan_rank(self) c_arraylen((self)->shape) +#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 -- cgit v1.2.3 From 6426ac05eb8c4dc1ab22aae2eb4139f9671981b7 Mon Sep 17 00:00:00 2001 From: Tyge Lovset Date: Sat, 8 Apr 2023 22:30:46 +0200 Subject: Reverted c_arraylen(), removed c_ARRAYLEN() --- README.md | 3 +++ include/stc/ccommon.h | 3 +-- include/stc/cspan.h | 4 ++-- 3 files changed, 6 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/README.md b/README.md index 220349b3..4be378a0 100644 --- a/README.md +++ b/README.md @@ -608,9 +608,12 @@ STC is generally very memory efficient. Memory usage for the different container - Much improved documentation - Added Coroutines + documentation - Added `c_const_cast()` typesafe macro. +- Added crand.h header: new API for crandom.h, which is deprecated. - Renamed c_foreach_r => `c_foreach_rv` - Renamed c_flt_count(i) => `c_flt_counter(i)` - Renamed c_flt_last(i) => `c_flt_getcount(i)` +- Renamed c_ARRAYLEN() => c_arraylen() +- Renamed deprecated c_ARGSV => c_SV - Removed c_PAIR ## Version 4.1.1 diff --git a/include/stc/ccommon.h b/include/stc/ccommon.h index 1a2b3c3f..d5508807 100644 --- a/include/stc/ccommon.h +++ b/include/stc/ccommon.h @@ -123,8 +123,7 @@ 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) (c_ARRAYLEN(a) + c_static_assert(sizeof(a) != sizeof(uintptr_t))) -#define c_ARRAYLEN(a) (intptr_t)(sizeof(a)/sizeof 0[a]) +#define c_arraylen(a) (intptr_t)(sizeof(a)/sizeof 0[a]) // Non-owning c-string typedef const char* crawstr; diff --git a/include/stc/cspan.h b/include/stc/cspan.h index ce3c33ce..ac3e9206 100644 --- a/include/stc/cspan.h +++ b/include/stc/cspan.h @@ -129,10 +129,10 @@ typedef struct { int32_t d[6]; } cspan_idx6; {.data=(container)->data, .shape={(int32_t)(container)->_len}} #define cspan_from_array(array) \ - {.data=(array) + c_static_assert(sizeof(array) != sizeof(void*)), .shape={c_ARRAYLEN(array)}} + {.data=(array) + c_static_assert(sizeof(array) != sizeof(void*)), .shape={c_arraylen(array)}} #define cspan_size(self) _cspan_size((self)->shape, cspan_rank(self)) -#define cspan_rank(self) c_ARRAYLEN((self)->shape) +#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 -- cgit v1.2.3