Added name-based runtime engine lookup.

This is opt-in for any children of `Random`, the macro `RNGXX_APPLY_CTOR(namespace, class_name, seed_type)` in `internal/init.hpp` enables this lookup.

Non-internal implementors of Random can use this API also. This provides a dynamic way to load user-defined subclasses of Random at runtime.

A symbol-based lookup may be added in the future.

Version bumped.

Fortune for rngxx's current commit: Future curse − 末凶
iter
Avril 3 years ago
parent ebc16f5638
commit 4b988ba83b

@ -4,7 +4,7 @@ PROJECT=rngxx
AUTHOR=Avril (Flanchan) <flanchan@cumallover.me> AUTHOR=Avril (Flanchan) <flanchan@cumallover.me>
VERSION_MAJOR=0 VERSION_MAJOR=0
VERSION_MINOR=2 VERSION_MINOR=3
VERSION=$(VERSION_MAJOR).$(VERSION_MINOR) VERSION=$(VERSION_MAJOR).$(VERSION_MINOR)
ifeq ($(PREFIX),) ifeq ($(PREFIX),)

@ -67,16 +67,26 @@ struct rng_next_opt {
typedef __typeof( ((struct rng_next_opt*)NULL)->ty ) rng_next_tyq; // Qualified type 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 #ifndef _RNGXX_IMPL_ONLY_TYPES
// -- C API functions -- (C++ NO compat) // -- C API functions -- (C++ NO compat)
int rng_raw(rng_t* engine, void* restrict output, struct rng_next_opt opt); 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_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_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); 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]); rng_t* rng_new(enum rng_kind kind, const u64 seed[static restrict 1]);
void rng_free(rng_t* rng); void rng_free(rng_t* rng);

@ -40,4 +40,5 @@ namespace rng
explicit crand(_opaque* raw); explicit crand(_opaque* raw);
i64 _sample_int(); i64 _sample_int();
}; };
} }

@ -0,0 +1,32 @@
#pragma once
#include <utility>
#include <functional>
#include <string>
#include <stdexcept>
#include "common.h"
#include <rngxx.hpp>
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<Random* (const void*)>& apply_raw(std::string_view name, std::function<Random* (const void*)> fn) noexcept;
template<typename T, typename _Ptr = void>
inline auto apply(std::string_view name, auto&& lam)
{
return apply_raw(name, [lam](const void* seed) -> Random* {
return static_cast<Random*>(lam(reinterpret_cast<const _Ptr*>(seed)));
});
}
std::function<Random* (const void*)>& 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<ns::T, TSeed>(#T, [](const TSeed* ptr) { return new ns::T(*ptr); })

@ -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" // 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 <cstdio>
#include <rngxx.hpp> #include <rngxx.hpp>
#include <rngxx/crand.h> #include <rngxx/crand.h>
#include <init.hpp>
#include "capi-bridge.h" #include "capi-bridge.h"
template<typename T, typename... Args> template<typename T, typename... Args>
@ -84,9 +87,26 @@ namespace bridge _export(internal)
if(ty_signed(ty)) return &next_typed_into<S>; if(ty_signed(ty)) return &next_typed_into<S>;
else return &next_typed_into<U>; else return &next_typed_into<U>;
} }
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<std::remove_reference_t<decltype(init::get(""))>*>( 0 ); //auto deduction fails here?
}
}
} }
extern "C" { extern "C" {
// Internal bridge members // Internal bridge members
_export(internal) _export(internal)
rng_t* RNG_IMPL(mkdriver)(rng_kind kind, const u64* restrict seed) rng_t* RNG_IMPL(mkdriver)(rng_kind kind, const u64* restrict seed)
@ -145,4 +165,40 @@ extern "C" {
{ {
delete rng; 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<decltype(bridge::dc_lookup(""))>(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<rng_dyn_ctor*>(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<rng_ctor_fn>();
if(fun) return *fun;
}
}
return nullptr;
}
} }

@ -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); 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 #ifdef __cplusplus
} }
#endif #endif

@ -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); 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);
}

@ -0,0 +1,41 @@
#include <unordered_map>
#include <string>
#include <init.hpp>
using ctor_map = std::unordered_map<std::string_view, std::function<Random* (const void*)>>;
static ctor_map* INIT_MAP=nullptr;
namespace rng::init
{
const std::function<Random* (const void*)>& apply_raw(std::string_view name, std::function<Random* (const void*)> fn) noexcept
{
if(!INIT_MAP) INIT_MAP = new ctor_map();
auto& map = *INIT_MAP;
map[name] = std::move(fn);
return map[name];
}
std::function<Random* (const void*)>& 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;
}
}
}
}

@ -7,6 +7,7 @@
#include <rngxx.hpp> #include <rngxx.hpp>
#include <mem.h> #include <mem.h>
#include <init.hpp>
#include <rngxx/crand.h> #include <rngxx/crand.h>
#include "crand.h" #include "crand.h"
@ -70,3 +71,4 @@ namespace rng
} }
RNGXX_APPLY_CTOR(rng, crand, u64);

@ -16,9 +16,32 @@ static int next(rng_t* rng, const int* min, const int* max)
} }
#define TREF(x) ( (const __typeof(x)[]){ (x) } ) #define TREF(x) ( (const __typeof(x)[]){ (x) } )
int main() 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("%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("%ld\n", rng_next_i64(engine, NULL, NULL));
printf("%lf\n", rng_next_f64(engine, TREF(1.0), TREF(100.0))); printf("%lf\n", rng_next_f64(engine, TREF(1.0), TREF(100.0)));

Loading…
Cancel
Save