diff --git a/include/rngxx.h b/include/rngxx.h index b152d50..4177723 100644 --- a/include/rngxx.h +++ b/include/rngxx.h @@ -68,7 +68,7 @@ struct rng_next_opt { uint32_t _padding : 24; } ty; // 32 bits :/ union { - uint32_t array_size; //TODO: Implement next for arrays + uint32_t array_size; } ex; // 32 bits. fills hole }; @@ -90,6 +90,8 @@ int rng_raw(rng_t* engine, void* restrict output, struct rng_next_opt opt); void rng_next_bin(rng_t* engine, unsigned char* restrict output, size_t n); void* rng_next_ty(rng_t* engine, void* restrict output, enum rng_next_type ty, enum rng_next_flag flags); +void* rng_next_tya(rng_t* engine, void* restrict output, enum rng_next_type ty, enum rng_next_flag flags, uint32_t sz); +void* rng_next_tyab(rng_t* engine, void* restrict output, enum rng_next_type ty, enum rng_next_flag flags, uint32_t sz, const void* pmin, const void* pmax); void* rng_next_tyb(rng_t* engine, void* restrict output, enum rng_next_type ty, enum rng_next_flag flags, const void* pmin, const void* pmax); rng_dyn_ctor_ref rng_ctor_ref(const char* name); @@ -112,6 +114,14 @@ _rng__always_inline T rng_next_ ## name (rng_t* engine, const T* min, const T* m T output; \ rng_next_tyb(engine, &output, RNG_TY_ ## N, RNG_TYQ_ ## S, min, max); \ return output; \ +} \ +_rng__always_inline T* rng_nexta_ ## name(uint32_t len; rng_t* engine, T output[restrict len], uint32_t len, const T* min, const T* max) \ +{ \ + return rng_next_tyab(engine, output, RNG_TY_ ## N, RNG_TYQ_ ## S, len, min, max); \ +} \ +_rng__always_inline T* rng_nextam_ ## name(rng_t* engine, uint32_t len, const T* min, const T* max) \ +{ \ + return rng_next_tyab(engine, NULL, RNG_TY_ ## N, RNG_TYQ_ ## S, len, min, max); \ } #define _NEXT_TYPED(T, N, S) _NEXT_TYPED_(T, T, N, S) @@ -133,6 +143,14 @@ _rng__always_inline rng_bool_t rng_next_bool(rng_t* engine) rng_next_tyb(engine, &output, RNG_TY_BOOL, 0, NULL, NULL); return output & 1; } +_rng__always_inline rng_bool_t* rng_nexta_bool(uint32_t len; rng_t* engine, rng_bool_t output[restrict len], uint32_t len) +{ + return rng_next_tyab(engine, output, RNG_TY_BOOL, 0, len, NULL, NULL); +} +_rng__always_inline rng_bool_t* rng_nextam_bool(rng_t* engine, uint32_t len) +{ + return rng_next_tyab(engine, NULL, RNG_TY_BOOL, 0, len, NULL, NULL); +} #undef NEXT_TYPED_INT #undef _NEXT_TYPED diff --git a/src/capi-bridge.cpp b/src/capi-bridge.cpp index eb2d7d4..428619e 100644 --- a/src/capi-bridge.cpp +++ b/src/capi-bridge.cpp @@ -29,11 +29,27 @@ namespace bridge _export(internal) return engine.next(); } + template + inline void rep_ptr(void* vptr, size_t n, auto lambda) + { + T* ptr = reinterpret_cast(vptr); + if(!n) lambda(ptr); + else while( n --> 0 ) lambda(ptr++); + } + template inline void next_typed_into(Random& engine, void* restrict output, const void* minp = nullptr, const void* maxp = nullptr) { *reinterpret_cast(output) = next_typed(engine, minp, maxp); } + template + inline void next_typed_into_n(Random& engine, void* restrict output, size_t rep = 0, const void* minp = nullptr, const void* maxp = nullptr) + { + if(!rep) return next_typed_into(engine, output, minp, maxp); + T* restrict ro = reinterpret_cast(output); + while( rep --> 0 ) + next_typed_into(engine, reinterpret_cast(ro++), minp, maxp); + } inline void nblob(Random& engine, unsigned char* restrict output, size_t es, size_t l) { @@ -47,7 +63,7 @@ namespace bridge _export(internal) { switch(ty) { - case RNG_TY_BOOL: return alignof(bool); + case RNG_TY_BOOL: return alignof(rng_bool_t); case RNG_TY_INT8: return alignof(i8); case RNG_TY_INT16: return alignof(i16); @@ -64,7 +80,7 @@ namespace bridge _export(internal) { switch(ty) { - case RNG_TY_BOOL: return sizeof(bool); + case RNG_TY_BOOL: return sizeof(rng_bool_t); case RNG_TY_INT8: return sizeof(i8); case RNG_TY_INT16: return sizeof(i16); @@ -81,11 +97,14 @@ namespace bridge _export(internal) constexpr inline bool ty_signed(rng_next_flag f) { return ! (f & RNG_TYQ_UNSIGNED); } constexpr inline bool ty_signed(const rng_next_tyq& qt) { return ty_signed(qt.mod); } + constexpr inline bool ty_hasflag(rng_next_flag hay, rng_next_flag nee) { return !!(hay & nee); } + constexpr inline bool ty_hasflag(const rng_next_tyq& q, rng_next_flag nee) { return ty_hasflag(q.mod, nee); } + template inline auto next_fun_of(const rng_next_tyq& ty) { - if(ty_signed(ty)) return &next_typed_into; - else return &next_typed_into; + if(ty_signed(ty)) return &next_typed_into_n; //ty.hasflag(ty, RNG_TYQ_ARRAY) ? &next_typed_into_n : &next_typed_into; + else return &next_typed_into_n; //ty.hasflag(ty, RNG_TYQ_ARRAY) ? &next_typed_into_n : &next_typed_into; } auto dc_lookup(const char* name) @@ -126,25 +145,30 @@ extern "C" { return 1; } + const size_t array = bridge::ty_hasflag(opt->ty, RNG_TYQ_ARRAY) + ? static_cast(opt->ex.array_size) + : 0; switch(opt->ty.type) { case RNG_TY_BLOB: bridge::nblob(*engine, reinterpret_cast(output), opt->bound.len); break; #define INTTY(bits) case RNG_TY_INT ## bits: \ - bridge::next_fun_of(opt->ty)(*engine, output, opt->bound.range.pmin, opt->bound.range.pmax); break + bridge::next_fun_of(opt->ty)(*engine, output, array, opt->bound.range.pmin, opt->bound.range.pmax); break INTTY(8); INTTY(16); INTTY(32); INTTY(64); #undef INTTY case RNG_TY_F32: - bridge::next_typed_into(*engine, output, opt->bound.range.pmin, opt->bound.range.pmax); + bridge::next_typed_into_n(*engine, output, array, opt->bound.range.pmin, opt->bound.range.pmax); break; case RNG_TY_F64: - bridge::next_typed_into(*engine, output, opt->bound.range.pmin, opt->bound.range.pmax); + bridge::next_typed_into_n(*engine, output, array, opt->bound.range.pmin, opt->bound.range.pmax); break; case RNG_TY_BOOL: - *reinterpret_cast(output) = bridge::next_typed(*engine, output) ? 1 : 0; + bridge::rep_ptr(output, array, [&](rng_bool_t* restrict output) { + *output = bridge::next_typed(*engine) ? 1 : 0; + }); break; default: return 0; } diff --git a/src/capi.c b/src/capi.c index 91ad3f0..5d2a0a0 100644 --- a/src/capi.c +++ b/src/capi.c @@ -45,6 +45,37 @@ static void* m_alloc_for(enum rng_next_type ty) return NULL; } +static void* m_alloc_array(enum rng_next_type ty, size_t ars) +{ + size_t s, a; + switch( RNG_IMPL(m_allocsz_for)(ty, &s, &a) ) + { + case 2: // size 0, align nonzero + case 0: break; + case 1: return calloc(ars, s); + case 3: return aligned_alloc(a, s * ars); + } + return NULL; +} + +void* rng_next_tyab(rng_t* engine, void* restrict output, enum rng_next_type ty, enum rng_next_flag flags, uint32_t sz, const void* pmin, const void* pmax) +{ + if(!sz) return output; + if(! (output = output ?: m_alloc_array(ty, (size_t)sz)) ) return NULL; + + RNG_IMPL(mnext)(engine, output, &(struct rng_next_opt){ + .bound.range = { pmin, pmax }, + .ty = { + .type = ty, + .mod = flags | (sz > 1 ? RNG_TYQ_ARRAY : 0 ), + }, + .ex = { + .array_size = sz, + }, + }); + return output; + +} void* rng_next_tyb(rng_t* engine, void* restrict output, enum rng_next_type ty, enum rng_next_flag flags, const void* pmin, const void* pmax) { if(! ( output = output ?: m_alloc_for(ty)) ) return NULL; @@ -58,6 +89,7 @@ void* rng_next_tyb(rng_t* engine, void* restrict output, enum rng_next_type ty, .type = ty, .mod = flags, }, + .ex = {0}, }); return output; @@ -68,6 +100,12 @@ void* rng_next_ty(rng_t* engine, void* restrict output, enum rng_next_type ty, e return rng_next_tyb(engine, output, ty, flags, NULL, NULL); } +void* rng_next_tya(rng_t* engine, void* restrict output, enum rng_next_type ty, enum rng_next_flag flags, uint32_t sz) +{ + if(!sz) return output; + return rng_next_tyab(engine, output, ty, flags, sz, NULL, NULL); +} + rng_t* rng_new_named(const char* name, const void* seed) { return RNG_IMPL(dynctor_trycall)(name, seed); diff --git a/src/test/main.c b/src/test/main.c index ab70296..3337081 100644 --- a/src/test/main.c +++ b/src/test/main.c @@ -46,6 +46,27 @@ int main() printf("%ld\n", rng_next_i64(engine, NULL, NULL)); printf("%lf\n", rng_next_f64(engine, TREF(1.0), TREF(100.0))); printf("%d\n", rng_next_bool(engine)); + + + rng_bool_t* array = rng_nextam_bool(engine, 100); + if(!array) { + fprintf(stderr, "failed to allocate for array\n"); + return 1; + } + for(int i=0;i<100;i++) + printf("%d ", array[i]); + printf("\n"); free(array); + + int ints[100]; + if(!rng_nexta_i32(engine, ints, 100, NULL, TREF(100))) { + fprintf(stderr, "failed to compute int array\n"); + return 1; + } + + for(size_t i=0;i