From 2458a2b96921e808e8534bb2cbf1c1d2adbce0d6 Mon Sep 17 00:00:00 2001 From: Avril Date: Sat, 14 Jan 2023 04:03:35 +0000 Subject: [PATCH] Added skeleton for new RNG type: Lorenz Attractor. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fortune for shuffle3's current commit: Future small blessing − 末小吉 --- include/error.h | 36 +++++++++++++ include/rng.h | 21 ++++++-- include/rng/frng.hpp | 1 + include/rng/impl.hpp | 9 +++- include/rng/lorenz.hpp | 2 + include/rng/xoroshiro128plus.hpp | 10 ++-- src/rng.cpp | 91 ++++++++++++++++++++++++++++---- 7 files changed, 151 insertions(+), 19 deletions(-) create mode 100644 include/error.h create mode 100644 include/rng/lorenz.hpp diff --git a/include/error.h b/include/error.h new file mode 100644 index 0000000..63f5fb8 --- /dev/null +++ b/include/error.h @@ -0,0 +1,36 @@ +#ifndef _ERROR_H +#define _ERROR_H + +#ifndef $PASTE +# define $_PASTE(x,y) x ## y +# define $PASTE(x,y) $_PASTE(x,y) +#endif + +#ifdef __cplusplus +extern "C" { +#endif + + +#ifdef __cplusplus +} + +constexpr inline bool is_noexcept= +#if __cpp_exceptions +#define EXCEPT 1 +//#define try try +//#define catch(...) catch(__VA_ARGS__) + false +#else +#define EXCEPT 0 +#define NOEXCEPT +//#define catch(...) __try {} catch(__VA_ARGS__) +//#define try if constexpr(!is_noexcept) +//#define throw (void)0 + true +#endif + ; + + +#endif + +#endif /* _ERROR_H */ diff --git a/include/rng.h b/include/rng.h index 4a19152..e63143a 100644 --- a/include/rng.h +++ b/include/rng.h @@ -4,6 +4,7 @@ #include "shuffle3.h" #ifdef __cplusplus +#include "rng/impl.hpp" extern "C" { #endif @@ -11,8 +12,12 @@ enum rng_kind { RNG_KIND_FRNG, RNG_KIND_DRNG, RNG_KIND_XORNG, + RNG_KIND_LORENZ, }; +typedef long double rng_st_lorenz_t; +typedef _Complex long double rng_lorenz_t; + typedef struct rng_init { enum rng_kind kind; @@ -25,7 +30,12 @@ typedef struct rng_init } drng; struct { uint64_t state[2]; - } xorng; + } xorng; + struct { + rng_lorenz_t point; + const rng_st_lorenz_t (* _UNIQUE state)[5]; + uint64_t iter; + } lorenz; } init; } rng_init_opt; @@ -38,14 +48,15 @@ void rng_free(rng_t ptr); // Tests extern void rng_test(); -extern void rng_test_spec(rng_t rng); +extern void rng_test_spec(rng_t rng) __attribute__((nonnull(1))); #ifdef __cplusplus } // RNG interfaces -#include -#include -#include +#include "rng/xoroshiro128plus.hpp" +#include "rng/frng.hpp" +#include "rng/drng.hpp" +#include "rng/lorenz.hpp" namespace rng { void test_algo(RNG&& rng); diff --git a/include/rng/frng.hpp b/include/rng/frng.hpp index 4b9c3f0..e82db25 100644 --- a/include/rng/frng.hpp +++ b/include/rng/frng.hpp @@ -34,6 +34,7 @@ namespace rng inline constexpr frng(const std::array& ar) : state(ar){P} inline constexpr frng(std::array&& ar) : state(ar){P} inline constexpr frng(const double (&ar)[2]) : state({ar[0], ar[1]}) {P} + constexpr virtual ~frng() = default; #undef P inline constexpr double next_double() override { return sample(); } inline constexpr float next_float() override { return (float)sample(); } diff --git a/include/rng/impl.hpp b/include/rng/impl.hpp index aa20b77..684f7ef 100644 --- a/include/rng/impl.hpp +++ b/include/rng/impl.hpp @@ -6,6 +6,8 @@ /// Base class for RNG impls struct RNG { + constexpr RNG() noexcept = default; + virtual unsigned char byte(); virtual void bytes(unsigned char* ptr, std::size_t len); @@ -29,7 +31,12 @@ struct RNG { inline virtual float next_float() { return (float)sample(); } inline virtual double next_double() { return sample(); } - virtual ~RNG() = default; + constexpr virtual ~RNG() = default; + + //explicit operator rng_t() const noexcept; + //friend operator RNG*(rng_t) noexcept; protected: virtual double sample() = 0; +//private: + //struct rng_impl* _UNIQUE _held = nullptr; }; diff --git a/include/rng/lorenz.hpp b/include/rng/lorenz.hpp new file mode 100644 index 0000000..3f59c93 --- /dev/null +++ b/include/rng/lorenz.hpp @@ -0,0 +1,2 @@ +#pragma once + diff --git a/include/rng/xoroshiro128plus.hpp b/include/rng/xoroshiro128plus.hpp index d0dddc1..493b0a6 100644 --- a/include/rng/xoroshiro128plus.hpp +++ b/include/rng/xoroshiro128plus.hpp @@ -9,10 +9,11 @@ namespace rng { using State = std::array; #define P D_dprintf("xorng: seeded with (%lu, %lu)", state[0], state[1]); - inline constexpr xoroshiro128plus(std::uint64_t s0, std::uint64_t s1) : state({s0, s1}){P} - inline constexpr xoroshiro128plus(std::array&& ar) : state(ar){P} - inline constexpr xoroshiro128plus(const std::array& ar) : state(ar){P} - inline constexpr xoroshiro128plus(const std::uint64_t (&ar)[2]) : state({ar[0], ar[1]}){P} + inline constexpr xoroshiro128plus(std::uint64_t s0, std::uint64_t s1) : RNG(), state({s0, s1}){P} + inline constexpr xoroshiro128plus(std::array&& ar) : RNG(), state(ar){P} + inline constexpr xoroshiro128plus(const std::array& ar) : RNG(), state(ar){P} + inline constexpr xoroshiro128plus(const std::uint64_t (&ar)[2]) : RNG(), state({ar[0], ar[1]}){P} + inline virtual ~xoroshiro128plus() {} #undef P std::uint64_t next_ulong(); using RNG::next_long; @@ -25,5 +26,6 @@ namespace rng private: State state; }; + static_assert(std::derived_from, "Wtf???"); } diff --git a/src/rng.cpp b/src/rng.cpp index e6d1a58..32e41f6 100644 --- a/src/rng.cpp +++ b/src/rng.cpp @@ -1,8 +1,53 @@ +#include + #include #include +#include #include +#include +#include + + +//#define IMPORT_ONE(NS, NAME) using NAME = NS :: NAME + +//IMPORT_ONE(std, ssize_t); + +template +static inline To* offset_ptr(T* ptr, ssize_t by) noexcept +{ + return reinterpret_cast(reinterpret_cast(ptr)+by); +} +/* +template +offset_ptr(auto* p, std::ssize_t by) -> offset_ptr; +template +offset_ptr(auto* p, std::ssize_t by) -> offset_ptr; +*/ +#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(offset_ptr(ptr, -static_cast(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(static_cast(this)->_held); +} +#endif + inline unsigned char RNG::byte() { return (unsigned char)next_int(255); @@ -48,14 +93,21 @@ std::int64_t RNG::next_long() } #include -#include namespace { // C interface 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 (ptr); } static inline RNG& extract_ref(rng_t rng) { return *extract_ptr(rng); } + template T> + static inline rng_t wrap_ptr(T* ptr) noexcept + { + if(__builtin_expect(!ptr, false)) return nullptr; + return reinterpret_cast(static_cast(ptr)); + } template static inline T* extract_downcast_ptr(rng_t rng) { @@ -64,29 +116,50 @@ namespace { // C interface extern "C" { - rng_t rng_new(rng_init_opt opt) { switch(opt.kind) { - case RNG_KIND_FRNG: return (rng_t) new rng::frng(opt.init.frng.state); - case RNG_KIND_DRNG: return (rng_t) new rng::drng(opt.init.drng.state); - case RNG_KIND_XORNG: return (rng_t) new rng::xoroshiro128plus(opt.init.xorng.state); + case RNG_KIND_FRNG: return wrap_ptr( new rng::frng(opt.init.frng.state) ); + case RNG_KIND_DRNG: return wrap_ptr( new rng::drng(opt.init.drng.state) ); + case RNG_KIND_XORNG: return wrap_ptr( new rng::xoroshiro128plus(opt.init.xorng.state) ); + //case RNG_KIND_LORENX: return static_cast( new rng::lorenzAttractor(opt.init.lorenz); ); default: panic("Unknown RNG init opt: %d", opt.kind); + __builtin_unreachable(); } return nullptr; } void rng_free(rng_t rng) { - RNG* ptr = (RNG*)rng; + RNG* ptr = extract_ptr(rng); delete ptr; } + [[gnu::nonnull(1)]] void rng_test_spec(rng_t rng) { - cout << "rng_test_spec:" << endl; - rng::test_algo(std::move(extract_ref(rng))); + auto& ref = 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); } } }