C API added

(testing needed)

Fortune for rngxx's current commit: Half blessing − 半吉
capi
Avril 3 years ago
parent ed1f1d5f03
commit 29187574be
Signed by: flanchan
GPG Key ID: 284488987C31F630

@ -28,14 +28,15 @@ OPT_FLAGS?= $(addprefix -march=,$(TARGET_CPU)) -fgraphite -fopenmp -floop-parall
CXX_OPT_FLAGS?= $(OPT_FLAGS) CXX_OPT_FLAGS?= $(OPT_FLAGS)
# Static analyzer currently generates false positives for C++, enable it only for C # Static analyzer currently generates false positives for C++, enable it only for C
CFLAGS += $(COMMON_FLAGS) --std=gnu17 -fanalyzer CFLAGS += $(COMMON_FLAGS) --std=gnu17
#-fanalyzer
CXXFLAGS += $(COMMON_FLAGS) --std=gnu++20 -felide-constructors CXXFLAGS += $(COMMON_FLAGS) --std=gnu++20 -felide-constructors
LDFLAGS += LDFLAGS +=
STRIP=strip STRIP=strip
RELEASE_COMMON_FLAGS+= -Werror RELEASE_COMMON_FLAGS+= -Werror
DEBUG_COMMON_FLAGS+= -fanalyzer DEBUG_COMMON_FLAGS+=
ifneq ($(TARGET_SPEC_FLAGS),no) ifneq ($(TARGET_SPEC_FLAGS),no)
RELEASE_CFLAGS?= -O3 -flto $(OPT_FLAGS) RELEASE_CFLAGS?= -O3 -flto $(OPT_FLAGS)

@ -31,9 +31,13 @@ enum rng_next_flag {
RNG_TYQ_CHAOS = 1 << 1, RNG_TYQ_CHAOS = 1 << 1,
}; // 2 bits }; // 2 bits
typedef int rng_bool_t;
enum rng_next_type { enum rng_next_type {
RNG_TY_BLOB = 0, RNG_TY_BLOB = 0,
RNG_TY_BOOL, // Expects type `rng_bool_t`.
RNG_TY_INT8, RNG_TY_INT8,
RNG_TY_INT16, RNG_TY_INT16,
RNG_TY_INT32, RNG_TY_INT32,
@ -65,8 +69,15 @@ typedef __typeof( ((struct rng_next_opt*)NULL)->ty ) rng_next_tyq; // Qualified
// -- // -- // -- // --
#ifndef _RNGXX_IMPL_ONLY_TYPES #ifndef _RNGXX_IMPL_ONLY_TYPES
// -- C API functions -- (C++ NO compat) // -- C API functions -- (C++ NO compat)
rng_t* rng_new(enum rng_kind kind, u64 seed[static restrict 1]); 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);
//TODO: Specialised `rng_next` functions
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);
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);
// -- // -- // -- // --

@ -159,8 +159,16 @@ struct Random
return std::bit_cast<T>(arr); return std::bit_cast<T>(arr);
} }
template<typename T>
inline T next(T min, T max);
template<typename T>
inline T next(T max);
template<typename T> template<typename T>
inline iterator<T> iter() { return iterator(*this); } //TODO: An iterator that yields `next<T>()` forever. inline iterator<T> iter() { return iterator(*this); } //TODO: An iterator that yields `next<T>()` forever.
template<typename T>
constexpr inline T max_for() const;
protected: protected:
//TODO: Should we have _min_* functions too? or just continue to use 0 as the lower bound for next_*(..max)? I think use 0... //TODO: Should we have _min_* functions too? or just continue to use 0 as the lower bound for next_*(..max)? I think use 0...
#define MAX(T, M) constexpr inline virtual T _max_ ## T() const { return M; } #define MAX(T, M) constexpr inline virtual T _max_ ## T() const { return M; }
@ -170,7 +178,8 @@ protected:
MAXX(32) MAXX(32)
MAXX(64) MAXX(64)
#undef MAXX #undef MAXX
#undef MAX #undef MAX
protected:
//constexpr inline virtual i8 _max() const { return 100; } // use limits.h stuff instead. //constexpr inline virtual i8 _max() const { return 100; } // use limits.h stuff instead.
// Vectorised versions of `next_bytes()`. These will fall back to that if they are not overriden, but if the implementation has a more efficient way of generating 4/8 bytes of random data it should override these. // Vectorised versions of `next_bytes()`. These will fall back to that if they are not overriden, but if the implementation has a more efficient way of generating 4/8 bytes of random data it should override these.
@ -205,14 +214,24 @@ protected:
} }
} }
}; };
#define DEFT(T) template<> inline T Random::next< T >() { return next_ ## T(); }
#define DEFTT(n) DEFT(i ## n) DEFT(u ## n) #define DEFTT(n) DEFT(i ## n) DEFT(u ## n)
DEFT(bool) #define DEFT(T) template<> inline T Random::max_for< T >() const { return _max_ ## T(); }
DEFTT(8) #define DEF \
DEFTT(16) DEFTT(8) \
DEFTT(32) DEFTT(16) \
DEFTT(64) DEFTT(32) \
DEFTT(64) \
//DEFTT(128) //DEFTT(128)
DEF
#undef DEFT
#define DEFT(T) template<> inline T Random::next< T >() { return next_ ## T(); } \
template<> inline T Random::next< T >(T min, T max) { return next_ ## T(min, max); } \
template<> inline T Random::next< T >(T max) { return next_ ## T(max); }
template<> inline bool Random::next<bool>() { return next_bool(); }
template<> inline f64 Random::next<f64>() { return next_f64(); }
template<> inline f32 Random::next<f32>() { return next_f32(); }
DEF
#undef DEF
#undef DEFTT #undef DEFTT
#undef DEFT #undef DEFT

@ -5,29 +5,88 @@
#include "capi-bridge.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) namespace bridge _export(internal)
{ {
void nblob(Random& restrict engine, unsigned char* restrict output, size_t es, size_t l) 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) size_t len = es * l; // full length (bytes)
engine.next_bytes(output, len);
} }
inline void nblob(Random& restrict engine, unsigned char* restrict output, size_t len) { nblob(engine, output, 1, 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) constexpr inline size_t ty_sizeof(rng_next_type ty)
{ {
//TODO: 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(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_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" { extern "C" {
// Internal bridge members // Internal bridge members
_export(internal) _export(internal)
rng_t* RNG_IMPL(mkdriver)(rng_kind kind, u64* restrict seed) rng_t* RNG_IMPL(mkdriver)(rng_kind kind, const u64* restrict seed)
{ {
switch(kind) switch(kind)
{ {
@ -37,22 +96,47 @@ extern "C" {
} }
} }
_export(internal) _export(internal)
int RNG_IMPL(mnext)(rng_t* restrict engine, void* restrict output, const rng_next_opt* restrict opt) int RNG_IMPL(mnext)(rng_t* engine, void* restrict output, const rng_next_opt* restrict opt)
{ {
if(opt->ty.mod & RNG_TYQ_CHAOS) { if(opt->ty.mod & RNG_TYQ_CHAOS) {
bridge::nblob(*engine, reinterpret_cast<unsigned char*>(output), bridge::ty_sizeof(opt->ty.type), opt->bound.len); bridge::nblob(*engine, reinterpret_cast<unsigned char*>(output), bridge::ty_sizeof(opt->ty.type));
return 1; return 1;
} }
switch(opt->ty.type) switch(opt->ty.type)
{ {
case RNG_TY_BLOB: bridge::nblob(*engine, reinterpret_cast<unsigned char*>(output), opt->bound.len); break; case RNG_TY_BLOB: bridge::nblob(*engine, reinterpret_cast<unsigned char*>(output), opt->bound.len); break;
//TODO: Rest of types
#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; default: return 0;
} }
return 1; 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 // Direct C interface members
void rng_free(rng_t* rng) void rng_free(rng_t* rng)
{ {

@ -16,8 +16,10 @@
extern "C" { extern "C" {
#endif #endif
rng_t* RNG_IMPL(mkdriver)(enum rng_kind kind, u64* restrict seed) _export(internal); rng_t* RNG_IMPL(mkdriver)(enum rng_kind kind, const u64* restrict seed) _export(internal);
int RNG_IMPL(mnext)(rng_t* restrict engine, void* restrict output, const struct rng_next_opt* restrict opt) _export(internal); int RNG_IMPL(mnext)(rng_t* engine, void* restrict output, const struct rng_next_opt* restrict opt) _export(internal);
int RNG_IMPL(m_allocsz_for)(enum rng_next_type ty, size_t* restrict size, size_t* restrict align) _export(internal);
#ifdef __cplusplus #ifdef __cplusplus
} }

@ -13,13 +13,57 @@
if(UNLIKELY(_nn__expr == NULL)) { fprintf(stderr, "fatal (unexpected null pointer): " __VA_ARGS__); abort(); } \ if(UNLIKELY(_nn__expr == NULL)) { fprintf(stderr, "fatal (unexpected null pointer): " __VA_ARGS__); abort(); } \
_nn__expr; }) _nn__expr; })
rng_t* rng_new(enum rng_kind kind, u64 seed[static restrict 1]) rng_t* rng_new(enum rng_kind kind, const u64 seed[static restrict 1])
{ {
return assert_not_null(RNG_IMPL(mkdriver) (kind, &seed[0]), "invalid kind %d", (int)kind); return assert_not_null(RNG_IMPL(mkdriver) (kind, &seed[0]), "invalid kind %d", (int)kind);
} }
// void rng_free() - direct bridge // void rng_free() - direct bridge
int rng_next(rng_t* restrict engine, void* restrict output, struct rng_next_opt opt) int rng_raw(rng_t* engine, void* restrict output, struct rng_next_opt opt)
{ {
return RNG_IMPL(mnext)(engine, output, &opt); return RNG_IMPL(mnext)(engine, output, &opt);
} }
void rng_next_bin(rng_t* engine, unsigned char* restrict output, size_t n)
{
RNG_IMPL(mnext)(engine, (void* restrict)output, &(struct rng_next_opt){
.bound.len = n,
.ty.type = RNG_TY_BLOB,
});
}
static void* m_alloc_for(enum rng_next_type ty)
{
size_t s, a;
switch( RNG_IMPL(m_allocsz_for)(ty, &s, &a) )
{
case 2: // size 0, align nonzero
case 0: break;
case 1: return malloc(s);
case 3: return aligned_alloc(a, s);
}
return NULL;
}
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)
{
if(! ( output = output ?: m_alloc_for(ty)) ) return NULL;
RNG_IMPL(mnext)(engine, output, &(struct rng_next_opt){
.bound.range = {
.pmin = pmin,
.pmax = pmax,
},
.ty = {
.type = ty,
.mod = flags,
},
});
return output;
}
void* rng_next_ty(rng_t* engine, void* restrict output, enum rng_next_type ty, enum rng_next_flag flags)
{
return rng_next_tyb(engine, output, ty, flags, NULL, NULL);
}

Loading…
Cancel
Save