You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
232 lines
6.7 KiB
232 lines
6.7 KiB
// 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/crand.h>
|
|
#include <rngxx/sm64.h>
|
|
|
|
#include <init.hpp>
|
|
|
|
#include "capi-bridge.h"
|
|
|
|
template<typename T, typename... Args>
|
|
static inline consteval bool is_same_any() {
|
|
return (std::is_same_v<T, Args> || ...);
|
|
}
|
|
|
|
namespace bridge _export(internal)
|
|
{
|
|
template<typename T>
|
|
inline T next_typed(Random& engine, const void* minp = nullptr, const void* maxp = nullptr)
|
|
{
|
|
if constexpr(!is_same_any<T, bool>()) {
|
|
if(minp && maxp) return engine.next(*reinterpret_cast<const T*>(minp), *reinterpret_cast<const T*>(maxp));
|
|
else if(maxp) return engine.next(*reinterpret_cast<const T*>(maxp));
|
|
else {
|
|
if constexpr(!is_same_any<T, f32, f64>())
|
|
if(minp)return engine.next(*reinterpret_cast<const T*>(minp), engine.max_for<T>());
|
|
}
|
|
}
|
|
return engine.next<T>();
|
|
}
|
|
|
|
template<typename T>
|
|
inline void rep_ptr(void* vptr, size_t n, auto lambda)
|
|
{
|
|
T* ptr = reinterpret_cast<T*>(vptr);
|
|
if(!n) lambda(ptr);
|
|
else while( n --> 0 ) lambda(ptr++);
|
|
}
|
|
|
|
template<typename T>
|
|
inline void next_typed_into(Random& engine, void* restrict output, const void* minp = nullptr, const void* maxp = nullptr)
|
|
{
|
|
*reinterpret_cast<T* restrict>(output) = next_typed<T>(engine, minp, maxp);
|
|
}
|
|
template<typename T>
|
|
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<T>(engine, output, minp, maxp);
|
|
T* restrict ro = reinterpret_cast<T*>(output);
|
|
while( rep --> 0 )
|
|
next_typed_into<T>(engine, reinterpret_cast<void*>(ro++), minp, maxp);
|
|
}
|
|
|
|
inline void nblob(Random& engine, unsigned char* restrict output, size_t es, size_t l)
|
|
{
|
|
size_t len = es * l; // full length (bytes)
|
|
|
|
engine.next_bytes(output, len);
|
|
}
|
|
inline void nblob(Random& engine, unsigned char* restrict output, size_t len) { nblob(engine, output, 1, len); }
|
|
|
|
constexpr inline size_t ty_alignof(rng_next_type ty)
|
|
{
|
|
switch(ty)
|
|
{
|
|
case RNG_TY_BOOL: return alignof(rng_bool_t);
|
|
|
|
case RNG_TY_INT8: return alignof(i8);
|
|
case RNG_TY_INT16: return alignof(i16);
|
|
case RNG_TY_INT32: return alignof(i32);
|
|
case RNG_TY_INT64: return alignof(i64);
|
|
case RNG_TY_F32: return alignof(f32);
|
|
case RNG_TY_F64: return alignof(f64);
|
|
|
|
case RNG_TY_BLOB: return 0;
|
|
default: return 0;
|
|
}
|
|
}
|
|
constexpr inline size_t ty_sizeof(rng_next_type ty)
|
|
{
|
|
switch(ty)
|
|
{
|
|
case RNG_TY_BOOL: return sizeof(rng_bool_t);
|
|
|
|
case RNG_TY_INT8: return sizeof(i8);
|
|
case RNG_TY_INT16: return sizeof(i16);
|
|
case RNG_TY_INT32: return sizeof(i32);
|
|
case RNG_TY_INT64: return sizeof(i64);
|
|
case RNG_TY_F32: return sizeof(f32);
|
|
case RNG_TY_F64: return sizeof(f64);
|
|
|
|
case RNG_TY_BLOB: return 0;
|
|
default: return 0;
|
|
}
|
|
}
|
|
|
|
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<typename S, typename U>
|
|
inline auto next_fun_of(const rng_next_tyq& ty)
|
|
{
|
|
if(ty_signed(ty)) return &next_typed_into_n<S>; //ty.hasflag(ty, RNG_TYQ_ARRAY) ? &next_typed_into_n<S> : &next_typed_into<S>;
|
|
else return &next_typed_into_n<U>; //ty.hasflag(ty, RNG_TYQ_ARRAY) ? &next_typed_into_n<U> : &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" {
|
|
|
|
// Internal bridge members
|
|
_export(internal)
|
|
rng_t* RNG_IMPL(mkdriver)(rng_kind kind, const u64* restrict seed)
|
|
{
|
|
switch(kind)
|
|
{
|
|
case RNG_KIND_CRAND:
|
|
return new rng::crand(seed[0]);
|
|
case RNG_KIND_SM64:
|
|
return new rng::sm64(seed[0]);
|
|
default: return NULL;
|
|
}
|
|
}
|
|
_export(internal)
|
|
int RNG_IMPL(mnext)(rng_t* engine, void* restrict output, const rng_next_opt* restrict opt)
|
|
{
|
|
if(opt->ty.mod & RNG_TYQ_CHAOS) {
|
|
bridge::nblob(*engine, reinterpret_cast<unsigned char*>(output), bridge::ty_sizeof(opt->ty.type));
|
|
return 1;
|
|
}
|
|
|
|
const size_t array = bridge::ty_hasflag(opt->ty, RNG_TYQ_ARRAY)
|
|
? static_cast<size_t>(opt->ex.array_size)
|
|
: 0;
|
|
switch(opt->ty.type)
|
|
{
|
|
case RNG_TY_BLOB: bridge::nblob(*engine, reinterpret_cast<unsigned char*>(output), opt->bound.len); break;
|
|
|
|
#define INTTY(bits) case RNG_TY_INT ## bits: \
|
|
bridge::next_fun_of<i ## bits, u ## bits>(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_n<f32>(*engine, output, array, opt->bound.range.pmin, opt->bound.range.pmax);
|
|
break;
|
|
case RNG_TY_F64:
|
|
bridge::next_typed_into_n<f64>(*engine, output, array, opt->bound.range.pmin, opt->bound.range.pmax);
|
|
break;
|
|
case RNG_TY_BOOL:
|
|
bridge::rep_ptr<rng_bool_t>(output, array, [&](rng_bool_t* restrict output) {
|
|
*output = bridge::next_typed<bool>(*engine) ? 1 : 0;
|
|
});
|
|
break;
|
|
default: return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
_export(internal)
|
|
int RNG_IMPL(m_allocsz_for)(enum rng_next_type ty, size_t* restrict size, size_t* restrict align)
|
|
{
|
|
int ok = 0;
|
|
if(size) ok |= ((*size = bridge::ty_sizeof(ty)) > 0) ? 1 : 0;
|
|
if(align) ok |= ((*align = bridge::ty_alignof(ty)) > 0) ? 2 : 0;
|
|
return ok;
|
|
}
|
|
|
|
// Direct C interface members
|
|
void rng_free(rng_t* 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;
|
|
}
|
|
}
|