diff --git a/Makefile b/Makefile index ce0f814..57cfc70 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ PROJECT=rngxx AUTHOR=Avril (Flanchan) VERSION_MAJOR=0 -VERSION_MINOR=2 +VERSION_MINOR=3 VERSION=$(VERSION_MAJOR).$(VERSION_MINOR) ifeq ($(PREFIX),) diff --git a/include/rngxx.h b/include/rngxx.h index 33c0826..b5ef735 100644 --- a/include/rngxx.h +++ b/include/rngxx.h @@ -67,16 +67,26 @@ struct rng_next_opt { typedef __typeof( ((struct rng_next_opt*)NULL)->ty ) rng_next_tyq; // Qualified type +typedef rng_t* (*rng_ctor_fn)(const void*); + +typedef struct rng_dyn_ctor* rng_dyn_ctor_ref; + // -- // -- #ifndef _RNGXX_IMPL_ONLY_TYPES // -- C API functions -- (C++ NO compat) + 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_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); +rng_ctor_fn rng_ctor(const char* name) __attribute__((deprecated("many dynamic ctors will have state that cannot be expressed through a raw function pointer, and so this method will not work for them. use `rng_ctor_ref` and `rng_ctor_call` instead where possible, unless you know that the dynamic ctor is a bare function pointer."))); // Get a dynamic ctor that is a raw funciton pointer. If the ctor for this name is not a raw function pointer (if it has state), then NULL is returned. +rng_t* rng_ctor_call(rng_dyn_ctor_ref ctor, const void* seed); + +rng_t* rng_new_named(const char* name, const void* seed); rng_t* rng_new(enum rng_kind kind, const u64 seed[static restrict 1]); void rng_free(rng_t* rng); diff --git a/include/rngxx/crand.h b/include/rngxx/crand.h index 89e2914..701b5fa 100644 --- a/include/rngxx/crand.h +++ b/include/rngxx/crand.h @@ -40,4 +40,5 @@ namespace rng explicit crand(_opaque* raw); i64 _sample_int(); }; + } diff --git a/include/rngxx/internal/init.hpp b/include/rngxx/internal/init.hpp new file mode 100644 index 0000000..d1af82d --- /dev/null +++ b/include/rngxx/internal/init.hpp @@ -0,0 +1,32 @@ +#pragma once + +#include +#include +#include +#include + +#include "common.h" +#include + +namespace rng::init +{ + struct DCLookupFailed final : std::exception{ inline DCLookupFailed(const std::string_view& n) : std::exception(), name(std::move(n)){} std::string name; }; + + const std::function& apply_raw(std::string_view name, std::function fn) noexcept; + + template + inline auto apply(std::string_view name, auto&& lam) + { + return apply_raw(name, [lam](const void* seed) -> Random* { + return static_cast(lam(reinterpret_cast(seed))); + }); + } + + std::function& get(std::string_view name); +} + +#define RNGXX_DCTOR_NAME(T) _rng__init_for_ ## T +// To add to dynamic CTOR map +#define RNGXX_APPLY_CTOR(ns, T, TSeed) \ +const static auto RNGXX_DCTOR_NAME(T) = rng::init::apply(#T, [](const TSeed* ptr) { return new ns::T(*ptr); }) + diff --git a/src/capi-bridge.cpp b/src/capi-bridge.cpp index 1667cc2..eb2d7d4 100644 --- a/src/capi-bridge.cpp +++ b/src/capi-bridge.cpp @@ -1,8 +1,11 @@ // Contains the work-doing code for the C API interface, which should be exported to the C API shim in the header "capi-bridge.h" +#include #include #include +#include + #include "capi-bridge.h" template @@ -84,9 +87,26 @@ namespace bridge _export(internal) if(ty_signed(ty)) return &next_typed_into; else return &next_typed_into; } + + auto dc_lookup(const char* name) + { + namespace init = rng::init; + try { + auto& ctor = init::get(name); + return &ctor; + } catch(init::DCLookupFailed& f) { +#ifdef DEBUG + fprintf(stderr, "Lookup failed for `%s' (%s)\n", name, f.name.c_str()); +#else + (void)f; +#endif + return reinterpret_cast*>( 0 ); //auto deduction fails here? + } + } } extern "C" { + // Internal bridge members _export(internal) rng_t* RNG_IMPL(mkdriver)(rng_kind kind, const u64* restrict seed) @@ -145,4 +165,40 @@ extern "C" { { delete rng; } + + + _export(internal) + rng_t* RNG_IMPL(dynctor_trycall)(const char* name, const void* seed) + { + auto cptr = bridge::dc_lookup(name); + if(LIKELY(cptr)) return (*cptr)(seed); + else return nullptr; + } + + _export(internal) + rng_t* RNG_IMPL(dynctor_callref)(struct rng_dyn_ctor* ptr, const void* seed) + { + auto& ctor = *reinterpret_cast(ptr); + return ctor(seed); + } + + _export(internal) + rng_dyn_ctor* RNG_IMPL(dynctor_refer)(const char* name) + { + auto ctor = bridge::dc_lookup(name); + return reinterpret_cast(ctor); + } + + rng_ctor_fn rng_ctor(const char* name) + { + auto cptr = bridge::dc_lookup(name); + if(LIKELY(cptr)) { + auto& ctor = *cptr; + if(ctor) { + rng_ctor_fn* fun = ctor.target(); + if(fun) return *fun; + } + } + return nullptr; + } } diff --git a/src/capi-bridge.h b/src/capi-bridge.h index 82955a0..c0d0b54 100644 --- a/src/capi-bridge.h +++ b/src/capi-bridge.h @@ -21,6 +21,10 @@ int RNG_IMPL(mnext)(rng_t* engine, void* restrict output, const struct rng_next_ int RNG_IMPL(m_allocsz_for)(enum rng_next_type ty, size_t* restrict size, size_t* restrict align) _export(internal); +rng_t* RNG_IMPL(dynctor_trycall)(const char* name, const void* seed) _export(internal); +struct rng_dyn_ctor* RNG_IMPL(dynctor_refer)(const char* name) _export(internal); +rng_t* RNG_IMPL(dynctor_callref)(struct rng_dyn_ctor* ptr, const void* seed) _export(internal); + #ifdef __cplusplus } #endif diff --git a/src/capi.c b/src/capi.c index 0034f57..91ad3f0 100644 --- a/src/capi.c +++ b/src/capi.c @@ -67,3 +67,18 @@ 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); } + +rng_t* rng_new_named(const char* name, const void* seed) +{ + return RNG_IMPL(dynctor_trycall)(name, seed); +} + +rng_dyn_ctor_ref rng_ctor_ref(const char* name) +{ + return RNG_IMPL(dynctor_refer)(name); +} + +rng_t* rng_ctor_call(rng_dyn_ctor_ref ctor, const void* seed) +{ + return RNG_IMPL(dynctor_callref)(ctor, seed); +} diff --git a/src/init.cpp b/src/init.cpp new file mode 100644 index 0000000..b67ce2d --- /dev/null +++ b/src/init.cpp @@ -0,0 +1,41 @@ +#include +#include + +#include + +using ctor_map = std::unordered_map>; + +static ctor_map* INIT_MAP=nullptr; + +namespace rng::init +{ + const std::function& apply_raw(std::string_view name, std::function fn) noexcept + { + if(!INIT_MAP) INIT_MAP = new ctor_map(); + + auto& map = *INIT_MAP; + map[name] = std::move(fn); + return map[name]; + } + + std::function& get(std::string_view name) + { + if(UNLIKELY(!INIT_MAP)) throw DCLookupFailed ( name ); + auto& map = *INIT_MAP; + if(map.contains(name)) return map[name]; + else throw DCLookupFailed ( name ); + } + + + namespace { + __attribute__((destructor)) + static void _rng_ctor__fini() { + if(LIKELY(INIT_MAP)) { + delete INIT_MAP; + INIT_MAP = nullptr; + } + } + } +} + + diff --git a/src/rng/crand.cpp b/src/rng/crand.cpp index 54825a0..8679228 100644 --- a/src/rng/crand.cpp +++ b/src/rng/crand.cpp @@ -7,6 +7,7 @@ #include #include +#include #include #include "crand.h" @@ -70,3 +71,4 @@ namespace rng } +RNGXX_APPLY_CTOR(rng, crand, u64); diff --git a/src/test/main.c b/src/test/main.c index 20aebe8..ab70296 100644 --- a/src/test/main.c +++ b/src/test/main.c @@ -16,9 +16,32 @@ static int next(rng_t* rng, const int* min, const int* max) } #define TREF(x) ( (const __typeof(x)[]){ (x) } ) + int main() { - rng_t* engine = rng_new(RNG_KIND_CRAND, (const u64[]){ time(NULL) }); + rng_dyn_ctor_ref rcref = rng_ctor_ref("crand"); + rng_ctor_fn rctor = rng_ctor("crand"); + + rng_t* engine = NULL; + if(rctor) { + printf("constructing direct\n"); + engine = rctor(TREF((u64)time(NULL))); + } else { + printf("constructing through ref\n"); + engine = rng_ctor_call(rcref, TREF((u64)time(NULL))); + } + if(!engine) { + printf("fallback to `rng_new_named()`\n"); + engine = rng_new_named("crand", TREF((u64)time(NULL))); //rng_new(rng_kind_crand, (const u64[]){ time(null) }); + } + if(!engine) { + printf("fallback to static init\n"); + engine = rng_new(RNG_KIND_CRAND, (const u64[]){ time(NULL) }); + } + if(!engine) { + fprintf(stderr, "failed to create engine\n"); + return 1; + } printf("%d %d %d\n", next(engine, NULL, TREF(100)), next(engine, TREF(10), TREF(20)), next(engine, NULL, NULL)); printf("%ld\n", rng_next_i64(engine, NULL, NULL)); printf("%lf\n", rng_next_f64(engine, TREF(1.0), TREF(100.0)));