|
|
@ -1,8 +1,53 @@
|
|
|
|
|
|
|
|
#include <stdexcept>
|
|
|
|
|
|
|
|
|
|
|
|
#include <iostream>
|
|
|
|
#include <iostream>
|
|
|
|
#include <cmath>
|
|
|
|
#include <cmath>
|
|
|
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
|
|
|
|
|
|
|
|
#include <rng/impl.hpp>
|
|
|
|
#include <rng/impl.hpp>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include <error.h>
|
|
|
|
|
|
|
|
#include <panic.h>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//#define IMPORT_ONE(NS, NAME) using NAME = NS :: NAME
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//IMPORT_ONE(std, ssize_t);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
template<typename To, typename T, typename Unit=unsigned char>
|
|
|
|
|
|
|
|
static inline To* offset_ptr(T* ptr, ssize_t by) noexcept
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
return reinterpret_cast<To*>(reinterpret_cast<Unit*>(ptr)+by);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
|
|
template<typename To, typename Unit>
|
|
|
|
|
|
|
|
offset_ptr(auto* p, std::ssize_t by) -> offset_ptr<To, decltype(p), Unit>;
|
|
|
|
|
|
|
|
template<typename To>
|
|
|
|
|
|
|
|
offset_ptr(auto* p, std::ssize_t by) -> offset_ptr<To, decltype(p)>;
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifdef FT_PT_OPERATORS
|
|
|
|
|
|
|
|
inline operator RNG*(rng_t ptr) noexcept
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
if(__builtin_expect(!ptr, false)) return nullptr;
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
|
|
|
|
RNG* op =
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
|
|
|
return
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
reinterpret_cast<RNG*>(offset_ptr<RNG>(ptr, -static_cast<ssize_t>(offsetof(RNG, _held))));
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
|
|
|
|
if(__builtin_expect(!op, false)) return nullptr;
|
|
|
|
|
|
|
|
if(__builtin_expect(op->_held, false)) panic("Invalid rng_t -> RNG conversion");
|
|
|
|
|
|
|
|
return ptr;
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
RNG::operator rng_t() const noexcept
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
return reinterpret_cast<rng_t>(static_cast<RNG*>(this)->_held);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
inline unsigned char RNG::byte()
|
|
|
|
inline unsigned char RNG::byte()
|
|
|
|
{
|
|
|
|
{
|
|
|
|
return (unsigned char)next_int(255);
|
|
|
|
return (unsigned char)next_int(255);
|
|
|
@ -48,14 +93,21 @@ std::int64_t RNG::next_long()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#include <rng.h>
|
|
|
|
#include <rng.h>
|
|
|
|
#include <panic.h>
|
|
|
|
|
|
|
|
namespace { // C interface
|
|
|
|
namespace { // C interface
|
|
|
|
using namespace std;
|
|
|
|
using namespace std;
|
|
|
|
#define extract_ptr(ptr) ((RNG*)(ptr))
|
|
|
|
[[gnu::always_inline, gnu::gnu_inline]]
|
|
|
|
|
|
|
|
static inline RNG* extract_ptr(rng_t ptr)
|
|
|
|
|
|
|
|
{ return reinterpret_cast<RNG*> (ptr); }
|
|
|
|
static inline RNG& extract_ref(rng_t rng)
|
|
|
|
static inline RNG& extract_ref(rng_t rng)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
return *extract_ptr(rng);
|
|
|
|
return *extract_ptr(rng);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
template<std::derived_from<RNG> T>
|
|
|
|
|
|
|
|
static inline rng_t wrap_ptr(T* ptr) noexcept
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
if(__builtin_expect(!ptr, false)) return nullptr;
|
|
|
|
|
|
|
|
return reinterpret_cast<rng_t>(static_cast<RNG*>(ptr));
|
|
|
|
|
|
|
|
}
|
|
|
|
template<typename T>
|
|
|
|
template<typename T>
|
|
|
|
static inline T* extract_downcast_ptr(rng_t rng)
|
|
|
|
static inline T* extract_downcast_ptr(rng_t rng)
|
|
|
|
{
|
|
|
|
{
|
|
|
@ -64,29 +116,50 @@ namespace { // C interface
|
|
|
|
|
|
|
|
|
|
|
|
extern "C"
|
|
|
|
extern "C"
|
|
|
|
{
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
rng_t rng_new(rng_init_opt opt)
|
|
|
|
rng_t rng_new(rng_init_opt opt)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
switch(opt.kind)
|
|
|
|
switch(opt.kind)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
case RNG_KIND_FRNG: return (rng_t) new rng::frng(opt.init.frng.state);
|
|
|
|
case RNG_KIND_FRNG: return wrap_ptr( new rng::frng(opt.init.frng.state) );
|
|
|
|
case RNG_KIND_DRNG: return (rng_t) new rng::drng(opt.init.drng.state);
|
|
|
|
case RNG_KIND_DRNG: return wrap_ptr( new rng::drng(opt.init.drng.state) );
|
|
|
|
case RNG_KIND_XORNG: return (rng_t) new rng::xoroshiro128plus(opt.init.xorng.state);
|
|
|
|
case RNG_KIND_XORNG: return wrap_ptr( new rng::xoroshiro128plus(opt.init.xorng.state) );
|
|
|
|
|
|
|
|
//case RNG_KIND_LORENX: return static_cast<rng_t>( new rng::lorenzAttractor(opt.init.lorenz); );
|
|
|
|
default: panic("Unknown RNG init opt: %d", opt.kind);
|
|
|
|
default: panic("Unknown RNG init opt: %d", opt.kind);
|
|
|
|
|
|
|
|
__builtin_unreachable();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nullptr;
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void rng_free(rng_t rng)
|
|
|
|
void rng_free(rng_t rng)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
RNG* ptr = (RNG*)rng;
|
|
|
|
RNG* ptr = extract_ptr(rng);
|
|
|
|
delete ptr;
|
|
|
|
delete ptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
[[gnu::nonnull(1)]]
|
|
|
|
void rng_test_spec(rng_t rng)
|
|
|
|
void rng_test_spec(rng_t rng)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
cout << "rng_test_spec:" << endl;
|
|
|
|
auto& ref = extract_ref(rng);
|
|
|
|
rng::test_algo(std::move(extract_ref(rng)));
|
|
|
|
cout << "rng_test_spec (" << typeid(ref).name() << ")..." << std::flush;
|
|
|
|
|
|
|
|
if constexpr(!is_noexcept) {
|
|
|
|
|
|
|
|
#if EXCEPT
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
|
|
rng::test_algo(std::move(ref));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
catch(const std::exception& except) {
|
|
|
|
|
|
|
|
cout << "\r\r\r\tERROR: " << (except.what() ?: typeid(except).name()) << endl;
|
|
|
|
|
|
|
|
rng_free(rng);
|
|
|
|
|
|
|
|
throw;
|
|
|
|
|
|
|
|
} catch(...) {
|
|
|
|
|
|
|
|
cout << "\r\r\r\tERROR" << endl;
|
|
|
|
|
|
|
|
rng_free(rng);
|
|
|
|
|
|
|
|
throw;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
} else rng::test_algo(std::move(ref));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
cout << "\r\r\r\tOK" << endl;
|
|
|
|
|
|
|
|
rng_free(rng);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|