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.
146 lines
4.1 KiB
146 lines
4.1 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 <rngxx.hpp>
|
|
#include <rngxx/crand.h>
|
|
|
|
#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, f32, f64, 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(minp) return engine.next(*reinterpret_cast<const T*>(minp), engine.max_for<T>());
|
|
}
|
|
return engine.next<T>();
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
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(bool);
|
|
|
|
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(bool);
|
|
|
|
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); }
|
|
|
|
template<typename S, typename U>
|
|
inline auto next_fun_of(const rng_next_tyq& ty)
|
|
{
|
|
if(ty_signed(ty)) return &next_typed_into<S>;
|
|
else return &next_typed_into<U>;
|
|
}
|
|
}
|
|
|
|
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]);
|
|
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;
|
|
}
|
|
|
|
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, 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<f32>(*engine, output);
|
|
break;
|
|
case RNG_TY_F64:
|
|
bridge::next_typed_into<f64>(*engine, output);
|
|
break;
|
|
case RNG_TY_BOOL:
|
|
*reinterpret_cast<rng_bool_t*>(output) = bridge::next_typed<bool>(*engine, output) ? 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;
|
|
}
|
|
}
|