summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--examples/benchmark.c2
-rw-r--r--examples/complex.c2
-rw-r--r--examples/demos.c10
-rw-r--r--examples/geek2.c43
-rw-r--r--examples/geek3.c4
-rw-r--r--examples/geek4.c10
-rw-r--r--examples/geek5.c2
-rw-r--r--examples/inits.c2
-rw-r--r--examples/mapmap.c4
-rw-r--r--examples/words.c4
-rw-r--r--stc/clist.h2
-rw-r--r--stc/cmap.h115
-rw-r--r--stc/crandom.h5
13 files changed, 117 insertions, 88 deletions
diff --git a/examples/benchmark.c b/examples/benchmark.c
index 3ff193bc..0b9c4f10 100644
--- a/examples/benchmark.c
+++ b/examples/benchmark.c
@@ -124,7 +124,7 @@ crandom_eng64_t rng;
const size_t N1 = 10000000 * 5;
const size_t N2 = 10000000 * 5;
-const size_t N3 = 10000000 * 10;
+const size_t N3 = 10000000 * 5;
#define RR 20
int rr = RR;
diff --git a/examples/complex.c b/examples/complex.c
index cd8a6d78..08a3b505 100644
--- a/examples/complex.c
+++ b/examples/complex.c
@@ -8,7 +8,7 @@ void check_destroy(float* v) {printf("destroy %g\n", *v);}
declare_carray(f, float, check_destroy); // normally omit the last argument - float type need no destroy.
declare_clist(t2, carray2f, carray2f_destroy, c_no_compare);
declare_cmap(il, int, clist_t2, clist_t2_destroy);
-declare_cmap_str(sm, cmap_il, cmap_il_destroy);
+declare_cmap_strkey(sm, cmap_il, cmap_il_destroy);
int main() {
int xdim = 4, ydim = 6;
diff --git a/examples/demos.c b/examples/demos.c
index a3e512e5..4f5c2356 100644
--- a/examples/demos.c
+++ b/examples/demos.c
@@ -62,9 +62,9 @@ void vectordemo2()
{
printf("\nVECTORDEMO2\n");
cvec_str names = cvec_init;
- cvec_str_push_back(&names, cstr_make("Mary"));
- cvec_str_push_back(&names, cstr_make("Joe"));
- cvec_str_push_back(&names, cstr_make("Chris"));
+ cvec_str_push_back(&names, "Mary");
+ cvec_str_push_back(&names, "Joe");
+ cvec_str_push_back(&names, "Chris");
cstr_assign(&names.data[1], "Jane"); // replace Joe
printf("names[1]: %s\n", names.data[1].str);
@@ -130,7 +130,7 @@ void mapdemo1()
}
-declare_cmap_str(si, int); // Shorthand macro for the general declare_cmap expansion.
+declare_cmap_strkey(si, int); // Shorthand macro for the general declare_cmap expansion.
void mapdemo2()
{
@@ -152,7 +152,7 @@ void mapdemo2()
}
-declare_cmap_str(ss, cstr_t, cstr_destroy);
+declare_cmap_strkey(ss, cstr_t, cstr_destroy);
void mapdemo3()
{
diff --git a/examples/geek2.c b/examples/geek2.c
index 9b2785f1..6141518f 100644
--- a/examples/geek2.c
+++ b/examples/geek2.c
@@ -1,16 +1,16 @@
-#ifndef CXX
+#ifndef RUST
#include <stc/cmap.h>
#include <stc/cstr.h>
-declare_cmap_str(ss, cstr_t, cstr_destroy);
+declare_cmap_str();
declare_cset_str();
int main()
{
// Lets use an explicit type signature (which would
// be `cmap<String, String>` in this example).
- cmap_ss book_reviews = cmap_init;
+ cmap_str book_reviews = cmap_init;
cset_str set = cset_init;
cset_str_put(&set, "Hello");
cset_str_put(&set, "You");
@@ -19,50 +19,57 @@ int main()
printf("%s ", i.item->key.str); puts("");
// Review some books.
- cmap_ss_put(&book_reviews,
+ c_push(&book_reviews, cmap_str, c_items(
+ {"Adventures of Huckleberry Finn", "My favorite book."},
+ {"Grimms' Fairy Tales", "Masterpiece."},
+ {"Pride and Prejudice", "Very enjoyable."},
+ {"The Adventures of Sherlock Holmes", "Eye lyked it alot."},
+ ));
+/*
+ cmap_str_insert(&book_reviews,
"Adventures of Huckleberry Finn",
- cstr_make("My favorite book.")
+ "My favorite book."
);
- cmap_ss_put(&book_reviews,
+ cmap_str_insert(&book_reviews,
"Grimms' Fairy Tales",
- cstr_make("Masterpiece.")
+ "Masterpiece."
);
- cmap_ss_put(&book_reviews,
+ cmap_str_insert(&book_reviews,
"Pride and Prejudice",
- cstr_make("Very enjoyable.")
+ "Very enjoyable."
);
- cmap_ss_put(&book_reviews,
+ cmap_str_insert(&book_reviews,
"The Adventures of Sherlock Holmes",
- cstr_make("Eye lyked it alot.")
+ "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_ss_find(&book_reviews, "Les Misérables")) {
+ if (! cmap_str_find(&book_reviews, "Les Misérables")) {
printf("We've got %zu reviews, but Les Misérables ain't one.\n",
cmap_size(book_reviews));
}
// oops, this review has a lot of spelling mistakes, let's delete it.
- cmap_ss_erase(&book_reviews, "The Adventures of Sherlock Holmes");
+ 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", NULL};
for (const char** book = to_find; *book; ++book) {
- cmap_ss_entry_t *review = cmap_ss_find(&book_reviews, *book);
+ cmap_str_entry_t *review = cmap_str_find(&book_reviews, *book);
if (review) printf("%s: %s\n", *book, review->value.str);
else printf("%s is unreviewed.\n", *book);
}
// Look up the value for a key (will panic if the key is not found).
- printf("Review for Jane: %s\n", cmap_ss_find(&book_reviews, "Pride and Prejudice")->value.str);
+ printf("Review for Jane: %s\n", cmap_str_find(&book_reviews, "Pride and Prejudice")->value.str);
// Iterate over everything.
- c_foreach (i, cmap_ss, book_reviews) {
+ c_foreach (i, cmap_str, book_reviews) {
printf("- %s: \"%s\"\n", i.item->key.str, i.item->value.str);
}
- cmap_ss_destroy(&book_reviews);
+ cmap_str_destroy(&book_reviews);
}
#else // ======================================================
diff --git a/examples/geek3.c b/examples/geek3.c
index b8de97c8..ad2bdfa1 100644
--- a/examples/geek3.c
+++ b/examples/geek3.c
@@ -3,8 +3,8 @@
#include <stc/cmap.h>
#include <stc/cstr.h>
-declare_cmap_str(si, int);
-declare_cmap_str(ss, cstr_t, cstr_destroy);
+declare_cmap_strkey(si, int);
+declare_cmap_strkey(ss, cstr_t, cstr_destroy);
int main ()
{
diff --git a/examples/geek4.c b/examples/geek4.c
index b0a57844..a62a6fd1 100644
--- a/examples/geek4.c
+++ b/examples/geek4.c
@@ -38,7 +38,7 @@ Efficient Approach: For all the words of the first sentence, we can check if it
#include <stc/cstr.h>
declare_cvec_str();
-declare_cmap_str(sb, bool);
+declare_cmap_strkey(sb, bool);
declare_cvec(sb, cmap_sb_entry_t, cmap_sb_entry_destroy, c_no_compare);
// Function to return the count of common words
@@ -137,10 +137,10 @@ int commonWords(cvec_str S)
int main()
{
cvec_str S = cvec_init;
- cvec_str_push_back(&S, cstr_make("there is a cow"));
- cvec_str_push_back(&S, cstr_make("cow is our mother"));
- cvec_str_push_back(&S, cstr_make("cow gives us milk and milk is sweet"));
- cvec_str_push_back(&S, cstr_make("there is a boy who loves cow"));
+ cvec_str_push_back(&S, "there is a cow");
+ cvec_str_push_back(&S, "cow is our mother");
+ cvec_str_push_back(&S, "cow gives us milk and milk is sweet");
+ cvec_str_push_back(&S, "there is a boy who loves cow");
printf("%d\n", commonWords(S));
cvec_str_destroy(&S);
diff --git a/examples/geek5.c b/examples/geek5.c
index 67f5d097..a0531ad3 100644
--- a/examples/geek5.c
+++ b/examples/geek5.c
@@ -22,7 +22,7 @@ Output: 0
#include <stc/cstr.h>
declare_cvec(i, int);
-declare_cmap_str(sv, cvec_i, cvec_i_destroy);
+declare_cmap_strkey(sv, cvec_i, cvec_i_destroy);
// Function to return the number of occurrences of
diff --git a/examples/inits.c b/examples/inits.c
index 92e67b84..c55bf83f 100644
--- a/examples/inits.c
+++ b/examples/inits.c
@@ -5,7 +5,7 @@
#include <stc/clist.h>
declare_cmap(id, int, cstr_t, cstr_destroy); // Map of int -> cstr_t
-declare_cmap_str(cnt, int);
+declare_cmap_strkey(cnt, int);
typedef struct {int x, y;} ipair_t;
inline static int ipair_compare(const ipair_t* a, const ipair_t* b) {
diff --git a/examples/mapmap.c b/examples/mapmap.c
index 14ccd9a9..1f2bd4f5 100644
--- a/examples/mapmap.c
+++ b/examples/mapmap.c
@@ -8,8 +8,8 @@ static void my_str_destr(cstr_t* x) {
cstr_destroy(x);
}
-declare_cmap_str(ss, cstr_t, my_str_destr);
-declare_cmap_str(cfg, cmap_ss, cmap_ss_destroy);
+declare_cmap_strkey(ss, cstr_t, my_str_destr);
+declare_cmap_strkey(cfg, cmap_ss, cmap_ss_destroy);
int main(void) {
cmap_cfg config = cmap_init;
diff --git a/examples/words.c b/examples/words.c
index a10811c1..f8e86329 100644
--- a/examples/words.c
+++ b/examples/words.c
@@ -6,9 +6,7 @@
declare_cvec_str();
declare_clist_str();
-declare_cmap_str(si, int);
-
-typedef const char* input_t;
+declare_cmap_strkey(si, int);
int main1()
{
diff --git a/stc/clist.h b/stc/clist.h
index ecd4fde0..2dfbb2ac 100644
--- a/stc/clist.h
+++ b/stc/clist.h
@@ -119,7 +119,7 @@
clist_##tag##_insert_after_v(clist_##tag* self, clist_##tag##_iter_t pos, Value value); \
STC_INLINE void \
clist_##tag##_insert_after(clist_##tag* self, clist_##tag##_iter_t pos, RawValue rawValue) { \
- clist_##tag##_insert_after_v(self, valueFromRaw(rawValue)); \
+ clist_##tag##_insert_after_v(self, pos, valueFromRaw(rawValue)); \
} \
STC_API void \
clist_##tag##_erase_after(clist_##tag* self, clist_##tag##_iter_t pos); \
diff --git a/stc/cmap.h b/stc/cmap.h
index 1840eda6..a7488edf 100644
--- a/stc/cmap.h
+++ b/stc/cmap.h
@@ -86,7 +86,7 @@ enum {chash_HASH = 0x7f, chash_USED = 0x80};
#define declare_cmap_10(tag, Key, Value, valueDestroy, keyEqualsRaw, keyHashRaw, \
keyDestroy, RawKey, keyToRaw, keyFromRaw) \
declare_CHASH(tag, cmap, Key, Value, valueDestroy, keyEqualsRaw, keyHashRaw, \
- keyDestroy, RawKey, keyToRaw, keyFromRaw)
+ keyDestroy, RawKey, keyToRaw, keyFromRaw, Value, c_default_from_raw)
/* cset: */
#define declare_cset(...) \
@@ -105,49 +105,64 @@ enum {chash_HASH = 0x7f, chash_USED = 0x80};
#define declare_cset_8(tag, Key, keyEqualsRaw, keyHashRaw, keyDestroy, \
RawKey, keyToRaw, keyFromRaw) \
declare_CHASH(tag, cset, Key, Key, void, keyEqualsRaw, keyHashRaw, \
- keyDestroy, RawKey, keyToRaw, keyFromRaw)
+ keyDestroy, RawKey, keyToRaw, keyFromRaw, void, c_default_from_raw)
-/* cset_str, cmap_str: */
+/* cset_str, cmap_str, cmap_strkey, cmap_strval: */
#define declare_cset_str() \
- declare_CHASH_STR(str, cset, cstr_t, void)
+ declare_CHASH_strkey(str, cset, cstr_t, void)
-#define declare_cmap_str(...) \
- c_MACRO_OVERLOAD(declare_cmap_str, __VA_ARGS__)
+#define declare_cmap_str() \
+ declare_CHASH(str, cmap, cstr_t, cstr_t, cstr_destroy, cstr_equals_raw, cstr_hash_raw, \
+ cstr_destroy, const char*, cstr_to_raw, cstr_make, const char*, cstr_make)
-#define declare_cmap_str_2(tag, Value) \
- declare_CHASH_STR(tag, cmap, Value, c_default_destroy)
+#define declare_cmap_strkey(...) \
+ c_MACRO_OVERLOAD(declare_cmap_strkey, __VA_ARGS__)
-#define declare_cmap_str_3(tag, Value, ValueDestroy) \
- declare_CHASH_STR(tag, cmap, Value, ValueDestroy)
+#define declare_cmap_strkey_2(tag, Value) \
+ declare_CHASH_strkey(tag, cmap, Value, c_default_destroy)
-#define declare_CHASH_STR(tag, ctype, Value, valueDestroy) \
+#define declare_cmap_strkey_3(tag, Value, ValueDestroy) \
+ declare_CHASH_strkey(tag, cmap, Value, ValueDestroy)
+
+#define declare_cmap_strval(...) \
+ c_MACRO_OVERLOAD(declare_cmap_strval, __VA_ARGS__)
+
+#define declare_cmap_strval_2(tag, Key) \
+ declare_cmap_strval_4(tag, Key, c_default_equals, c_default_hash16)
+
+#define declare_cmap_strval_4(tag, Key, keyEquals, keyHash) \
+ declare_CHASH(tag, cmap, Key, cstr_t, cstr_destroy, keyEquals, keyHash, \
+ c_default_destroy, Key, c_default_to_raw, c_default_from_raw, const char*, cstr_make)
+
+#define declare_CHASH_strkey(tag, ctype, Value, valueDestroy) \
declare_CHASH(tag, ctype, cstr_t, Value, valueDestroy, cstr_equals_raw, cstr_hash_raw, \
- cstr_destroy, const char*, cstr_to_raw, cstr_make)
+ cstr_destroy, const char*, cstr_to_raw, cstr_make, Value, c_default_from_raw)
-#define OPT_1_cset(x)
-#define OPT_1_cmap(x) x
-#define OPT_2_cset(x, y) x
-#define OPT_2_cmap(x, y) x, y
+#define CMAP_ONLY_cset(x)
+#define CMAP_ONLY_cmap(x) x
+#define CMAP_BOTH_cset(x, y) x
+#define CMAP_BOTH_cmap(x, y) x, y
/* CHASH full: use 'void' for Value if ctype is cset */
#define declare_CHASH(tag, ctype, Key, Value, valueDestroy, keyEqualsRaw, keyHashRaw, \
- keyDestroy, RawKey, keyToRaw, keyFromRaw) \
+ keyDestroy, RawKey, keyToRaw, keyFromRaw, RawValue, valueFromRaw) \
typedef struct { \
Key key; \
- OPT_1_##ctype(Value value;) \
+ CMAP_ONLY_##ctype(Value value;) \
} ctype##_##tag##_entry_t; \
\
STC_INLINE void \
ctype##_##tag##_entry_destroy(ctype##_##tag##_entry_t* e) { \
keyDestroy(&e->key); \
- OPT_1_##ctype(valueDestroy(&e->value);) \
+ CMAP_ONLY_##ctype(valueDestroy(&e->value);) \
} \
typedef struct { \
RawKey key; \
- OPT_1_##ctype(Value value;) \
+ CMAP_ONLY_##ctype(RawValue value;) \
} ctype##_##tag##_input_t; \
\
typedef RawKey ctype##_##tag##_rawkey_t; \
+typedef RawValue ctype##_##tag##_rawvalue_t; \
\
typedef struct { \
ctype##_##tag##_entry_t* table; \
@@ -184,10 +199,34 @@ STC_API void \
ctype##_##tag##_clear(ctype##_##tag* self); \
STC_API ctype##_##tag##_entry_t* \
ctype##_##tag##_find(const ctype##_##tag* self, ctype##_##tag##_rawkey_t rawKey); \
-STC_API ctype##_##tag##_entry_t* /* like c++ std::map.insert_or_assign(): */ \
-ctype##_##tag##_put(ctype##_##tag* self, OPT_2_##ctype(ctype##_##tag##_rawkey_t rawKey, Value value)); \
-STC_API ctype##_##tag##_entry_t* /* like c++ std::map.insert(): */ \
-ctype##_##tag##_insert(ctype##_##tag* self, OPT_2_##ctype(ctype##_##tag##_rawkey_t rawKey, Value value)); \
+ \
+struct ctype##_##tag##_result {ctype##_##tag##_entry_t *entry; bool inserted;}; \
+STC_API struct ctype##_##tag##_result \
+ctype##_##tag##_insert_key(ctype##_##tag* self, ctype##_##tag##_rawkey_t rawKey); \
+ \
+STC_INLINE ctype##_##tag##_entry_t* /* like c++ std::map.insert_or_assign(): */ \
+ctype##_##tag##_put(ctype##_##tag* self, CMAP_BOTH_##ctype(ctype##_##tag##_rawkey_t rawKey, RawValue rawValue)) { \
+ struct ctype##_##tag##_result res = ctype##_##tag##_insert_key(self, rawKey); \
+ CMAP_ONLY_##ctype( if (!res.inserted) valueDestroy(&res.entry->value); \
+ res.entry->value = valueFromRaw(rawValue); ) \
+ return res.entry; \
+} \
+STC_INLINE ctype##_##tag##_entry_t* /* like c++ std::map.insert(): */ \
+ctype##_##tag##_insert(ctype##_##tag* self, CMAP_BOTH_##ctype(ctype##_##tag##_rawkey_t rawKey, RawValue rawValue)) { \
+ struct ctype##_##tag##_result res = ctype##_##tag##_insert_key(self, rawKey); \
+ CMAP_ONLY_##ctype( if (res.inserted) res.entry->value = valueFromRaw(rawValue); ) \
+ return res.entry; \
+} \
+ \
+CMAP_ONLY_##ctype( \
+STC_INLINE ctype##_##tag##_entry_t* /* cmap_put_v(key, move(value)) */ \
+ctype##_##tag##_put_v(ctype##_##tag* self, ctype##_##tag##_rawkey_t rawKey, Value value) { \
+ struct ctype##_##tag##_result res = ctype##_##tag##_insert_key(self, rawKey); \
+ if (!res.inserted) valueDestroy(&res.entry->value); \
+ res.entry->value = value; \
+ return res.entry; \
+} \
+) /* end CMAP_ONLY */ \
STC_API size_t \
ctype##_##tag##_reserve(ctype##_##tag* self, size_t size); \
STC_API bool \
@@ -203,7 +242,7 @@ STC_API uint32_t c_default_hash16(const void *data, size_t len); \
STC_API uint32_t c_default_hash32(const void* data, size_t len); \
\
implement_CHASH(tag, ctype, Key, Value, valueDestroy, keyEqualsRaw, keyHashRaw, \
- keyDestroy, RawKey, keyToRaw, keyFromRaw) \
+ keyDestroy, RawKey, keyToRaw, keyFromRaw, RawValue, valueFromRaw) \
typedef Key ctype##_##tag##_key_t; \
typedef Value ctype##_##tag##_value_t
@@ -211,7 +250,7 @@ typedef Value ctype##_##tag##_value_t
#if !defined(STC_HEADER) || defined(STC_IMPLEMENTATION)
#define implement_CHASH(tag, ctype, Key, Value, valueDestroy, keyEqualsRaw, keyHashRaw, \
- keyDestroy, RawKey, keyToRaw, keyFromRaw) \
+ keyDestroy, RawKey, keyToRaw, keyFromRaw, RawValue, valueFromRaw) \
STC_API ctype##_##tag \
ctype##_##tag##_with_capacity(size_t cap) { \
ctype##_##tag h = ctype##_init; \
@@ -220,7 +259,7 @@ ctype##_##tag##_with_capacity(size_t cap) { \
} \
STC_API void \
ctype##_##tag##_push_n(ctype##_##tag* self, const ctype##_##tag##_input_t in[], size_t size) { \
- for (size_t i=0; i<size; ++i) ctype##_##tag##_put(self, OPT_2_##ctype(in[i].key, in[i].value)); \
+ for (size_t i=0; i<size; ++i) ctype##_##tag##_put(self, CMAP_BOTH_##ctype(in[i].key, in[i].value)); \
} \
\
STC_INLINE void ctype##_##tag##_wipe_(ctype##_##tag* self) { \
@@ -273,8 +312,7 @@ STC_INLINE void ctype##_##tag##_reserve_expand(ctype##_##tag* self) { \
ctype##_##tag##_reserve(self, 5 + self->size * 3 / 2); \
} \
\
-struct ctype##_##tag##_result {ctype##_##tag##_entry_t *entry; bool inserted;}; \
-STC_INLINE struct ctype##_##tag##_result \
+STC_API struct ctype##_##tag##_result \
ctype##_##tag##_insert_key(ctype##_##tag* self, ctype##_##tag##_rawkey_t rawKey) { \
ctype##_##tag##_reserve_expand(self); \
uint32_t hx; \
@@ -288,23 +326,6 @@ ctype##_##tag##_insert_key(ctype##_##tag* self, ctype##_##tag##_rawkey_t rawKey)
return res; \
} \
\
-STC_API ctype##_##tag##_entry_t* \
-ctype##_##tag##_put(ctype##_##tag* self, OPT_2_##ctype(ctype##_##tag##_rawkey_t rawKey, Value value)) { \
- struct ctype##_##tag##_result res = ctype##_##tag##_insert_key(self, rawKey); \
- OPT_1_##ctype( \
- if (!res.inserted) valueDestroy(&res.entry->value); \
- res.entry->value = value; \
- ) \
- return res.entry; \
-} \
- \
-STC_API ctype##_##tag##_entry_t* \
-ctype##_##tag##_insert(ctype##_##tag* self, OPT_2_##ctype(ctype##_##tag##_rawkey_t rawKey, Value value)) { \
- struct ctype##_##tag##_result res = ctype##_##tag##_insert_key(self, rawKey); \
- OPT_1_##ctype( if (res.inserted) res.entry->value = value; else valueDestroy(&value); ) \
- return res.entry; \
-} \
- \
STC_API size_t \
ctype##_##tag##_reserve(ctype##_##tag* self, size_t newcap) { \
size_t oldcap = self->bucket_count; \
@@ -361,7 +382,7 @@ ctype##_##tag##_erase(ctype##_##tag* self, ctype##_##tag##_rawkey_t rawKey) { \
if (self->size == 0) \
return false; \
if (self->size < self->bucket_count * self->shrink_limit_factor && self->bucket_count * sizeof(ctype##_##tag##_entry_t) > 1024) \
- ctype##_##tag##_reserve(self, (size_t) (self->size * 1.2f / self->max_load_factor)); \
+ ctype##_##tag##_reserve(self, self->size * 6 / 5); \
uint32_t hx; \
size_t i = ctype##_##tag##_bucket(self, &rawKey, &hx); \
return ctype##_##tag##_erase_entry(self, self->table + i); \
diff --git a/stc/crandom.h b/stc/crandom.h
index a3d0b77c..f4b609b7 100644
--- a/stc/crandom.h
+++ b/stc/crandom.h
@@ -95,11 +95,14 @@ STC_INLINE crandom_distrib_i64_t crandom_uniform_i64_init(int64_t low, int64_t h
crandom_distrib_i64_t dist = {low, high - low + 1}; return dist;
}
+#if defined(_MSC_VER) && defined(_WIN64)
+#include <intrin.h>
+#endif
+
STC_INLINE int64_t crandom_uniform_i64(crandom_eng64_t* rng, crandom_distrib_i64_t dist) {
#if defined(__SIZEOF_INT128__)
return dist.offset + (int64_t) (((__uint128_t) crandom_i64(rng) * dist.range) >> 64);
#elif defined(_MSC_VER) && defined(_WIN64)
- uint64_t _umul128(uint64_t x, uint64_t y, uint64_t *hi);
uint64_t hi; _umul128(crandom_i64(rng), dist.range, &hi); return dist.offset + hi;
#else
return dist.offset + crandom_i64(rng) % dist.range; // slower