commit
07cd0c252d
@ -0,0 +1 @@
|
|||||||
|
Complete rewrite using `mmap` et al. Maybe in Rust of C++ idk
|
@ -0,0 +1,73 @@
|
|||||||
|
SRC_C = $(wildcard src/*.c)
|
||||||
|
SRC_CXX = $(wildcard src/*.cpp)
|
||||||
|
SRC_CXX+= $(wildcard src/rng/*.cpp)
|
||||||
|
|
||||||
|
INCLUDE = include
|
||||||
|
|
||||||
|
PROJECT=shuffle3
|
||||||
|
|
||||||
|
COMMON_FLAGS = -Wall -pedantic $(addprefix -I,$(INCLUDE)) -fno-strict-aliasing
|
||||||
|
|
||||||
|
OPT_FLAGS?= -march=native -fgraphite -fopenmp -floop-parallelize-all -ftree-parallelize-loops=4 \
|
||||||
|
-floop-interchange -ftree-loop-distribution -floop-strip-mine -floop-block \
|
||||||
|
-fno-stack-check
|
||||||
|
|
||||||
|
CXX_OPT_FLAGS?= $(OPT_FLAGS) -felide-constructors
|
||||||
|
|
||||||
|
CFLAGS += $(COMMON_FLAGS) --std=gnu11
|
||||||
|
CXXFLAGS += $(COMMON_FLAGS) --std=gnu++20 -fno-exceptions
|
||||||
|
LDFLAGS += -lfmt
|
||||||
|
|
||||||
|
STRIP=strip
|
||||||
|
|
||||||
|
RELEASE_CFLAGS?= -O3 -flto $(OPT_FLAGS)
|
||||||
|
RELEASE_CXXFLAGS?= -O3 -flto $(CXX_OPT_FLAGS)
|
||||||
|
RELEASE_LDFLAGS?= -O3 -flto
|
||||||
|
|
||||||
|
DEBUG_CFLAGS?= -O0 -g -DDEBUG
|
||||||
|
DEBUG_CXXFLAGS?= $(DEBUG_CFLAGS)
|
||||||
|
DEBUG_LDFLAGS?=
|
||||||
|
|
||||||
|
# Objects
|
||||||
|
|
||||||
|
OBJ_C = $(addprefix obj/c/,$(SRC_C:.c=.o))
|
||||||
|
OBJ_CXX = $(addprefix obj/cxx/,$(SRC_CXX:.cpp=.o))
|
||||||
|
OBJ = $(OBJ_C) $(OBJ_CXX)
|
||||||
|
|
||||||
|
# Phonies
|
||||||
|
|
||||||
|
.PHONY: release
|
||||||
|
release: | dirs $(PROJECT)-release
|
||||||
|
|
||||||
|
.PHONY: debug
|
||||||
|
debug: | dirs $(PROJECT)-debug
|
||||||
|
|
||||||
|
# Targets
|
||||||
|
|
||||||
|
dirs:
|
||||||
|
@mkdir -p obj/c{,xx}/src
|
||||||
|
@mkdir -p obj/cxx/src/rng
|
||||||
|
|
||||||
|
obj/c/%.o: %.c
|
||||||
|
$(CC) -c $< $(CFLAGS) -o $@ $(LDFLAGS)
|
||||||
|
|
||||||
|
obj/cxx/%.o: %.cpp
|
||||||
|
$(CXX) -c $< $(CXXFLAGS) -o $@ $(LDFLAGS)
|
||||||
|
|
||||||
|
|
||||||
|
$(PROJECT)-release: CFLAGS+= $(RELEASE_CFLAGS)
|
||||||
|
$(PROJECT)-release: CXXFLAGS += $(RELEASE_CXXFLAGS)
|
||||||
|
$(PROJECT)-release: LDFLAGS += $(RELEASE_LDFLAGS)
|
||||||
|
$(PROJECT)-release: $(OBJ)
|
||||||
|
$(CXX) $^ $(CXXFLAGS) -o $@ $(LDFLAGS)
|
||||||
|
$(STRIP) $@
|
||||||
|
|
||||||
|
$(PROJECT)-debug: CFLAGS+= $(DEBUG_CFLAGS)
|
||||||
|
$(PROJECT)-debug: CXXFLAGS += $(DEBUG_CXXFLAGS)
|
||||||
|
$(PROJECT)-debug: LDFLAGS += $(DEBUG_LDFLAGS)
|
||||||
|
$(PROJECT)-debug: $(OBJ)
|
||||||
|
$(CXX) $^ $(CXXFLAGS) -o $@ $(LDFLAGS)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf obj
|
||||||
|
rm -f $(PROJECT)-{release,debug}
|
@ -0,0 +1,35 @@
|
|||||||
|
* shuffle3-lean
|
||||||
|
Redegisn/upgrade of =shuffle3=
|
||||||
|
|
||||||
|
* Goals
|
||||||
|
- [X] Functioning in-place shuffle/unshuffle
|
||||||
|
- [X] Shuffle
|
||||||
|
- [X] Unshuffle
|
||||||
|
- [X] Usable in-place s/us from command line
|
||||||
|
- [X] Shuffle
|
||||||
|
- [X] Unshuffle
|
||||||
|
- [ ] Functioning out-of-place/in-memory shuffle/unshuffle
|
||||||
|
- [ ] Shuffle
|
||||||
|
- [ ] Unshuffle
|
||||||
|
- [ ] Usable out-of-place s/us from command line
|
||||||
|
- [ ] Shuffle
|
||||||
|
- [ ] Unshuffle
|
||||||
|
|
||||||
|
** NO compatibility with =shuffle3=
|
||||||
|
=shuffle3='s ~drng~ PRNG algorithm uses an outdated global state backend. We don't want to reuse this.
|
||||||
|
As a result, output from =shuffle3= and =shuffle3-lean= is different.
|
||||||
|
|
||||||
|
* Improvements
|
||||||
|
- *~70-80x* speedup from shuffle3 1.0
|
||||||
|
- Huge reduction in syscalls
|
||||||
|
- Takes advantage of the kernel's fs cache
|
||||||
|
- Can properly handle large files without core dumping
|
||||||
|
- Doesn't dump huge amounts of trash onto each stack frame
|
||||||
|
|
||||||
|
* Todo
|
||||||
|
- [X] impl rng
|
||||||
|
- [X] impl shuffling
|
||||||
|
- [ ] impl out-of-place shuffling
|
||||||
|
- [-] arg parsing and dispatch
|
||||||
|
- [X] simple parsing
|
||||||
|
- [ ] complex parsing
|
@ -0,0 +1,28 @@
|
|||||||
|
// https://stackoverflow.com/a/30304782
|
||||||
|
|
||||||
|
#ifndef _COLORS_
|
||||||
|
#define _COLORS_
|
||||||
|
|
||||||
|
/* FOREGROUND */
|
||||||
|
#define RST "\x1B[0m"
|
||||||
|
#define KRED "\x1B[31m"
|
||||||
|
#define KGRN "\x1B[32m"
|
||||||
|
#define KYEL "\x1B[33m"
|
||||||
|
#define KBLU "\x1B[34m"
|
||||||
|
#define KMAG "\x1B[35m"
|
||||||
|
#define KCYN "\x1B[36m"
|
||||||
|
#define KWHT "\x1B[37m"
|
||||||
|
|
||||||
|
#define FRED(x) KRED x RST
|
||||||
|
#define FGRN(x) KGRN x RST
|
||||||
|
#define FYEL(x) KYEL x RST
|
||||||
|
#define FBLU(x) KBLU x RST
|
||||||
|
#define FMAG(x) KMAG x RST
|
||||||
|
#define FCYN(x) KCYN x RST
|
||||||
|
#define FWHT(x) KWHT x RST
|
||||||
|
|
||||||
|
#define BOLD(x) "\x1B[1m" x RST
|
||||||
|
#define UNDL(x) "\x1B[4m" x RST
|
||||||
|
|
||||||
|
#endif /* _COLORS_ */
|
||||||
|
|
@ -0,0 +1,43 @@
|
|||||||
|
#ifndef _DEBUG_H
|
||||||
|
#define _DEBUG_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct debuginfo {
|
||||||
|
const char* file;
|
||||||
|
const char* function;
|
||||||
|
int line;
|
||||||
|
};
|
||||||
|
|
||||||
|
void _do_dprintf(struct debuginfo di, const char* fmt, ...);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C++" {
|
||||||
|
#include <utility>
|
||||||
|
template<typename... Args>
|
||||||
|
inline void _real_dprintf(const char* file, const char* function, int line, const char* fmt, Args&&... args)
|
||||||
|
{
|
||||||
|
#ifdef DEBUG
|
||||||
|
debuginfo i = { file, function, line };
|
||||||
|
_do_dprintf(i, fmt, std::forward<Args>(args)...);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#define D_dprintf(fmt, ...) _real_dprintf(__FILE__, __func__, __LINE__, fmt __VA_OPT__(,) __VA_ARGS__)
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
#define D_dprintf(fmt, ...) _do_dprintf( (struct debuginfo){.file = __FILE__, .function = __func__, .line = __LINE__}, fmt __VA_OPT__(,) __VA_ARGS__)
|
||||||
|
#else
|
||||||
|
static inline void _do__nothing(const char* fmt, ...) {}
|
||||||
|
#define D_dprintf(fmt, ...) _do__nothing(fmt __VA_OPT__(,) __VA_ARGS__) //(fmt __VA_OPT__(,) __VA_ARGS__, (void)0)
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* _DEBUG_H */
|
@ -0,0 +1,74 @@
|
|||||||
|
#ifndef _MAP_H
|
||||||
|
#define _MAP_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#define restrict __restrict__
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
typedef struct mmap {
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
void* ptr;
|
||||||
|
size_t len;
|
||||||
|
} mmap_t;
|
||||||
|
|
||||||
|
int open_and_map(const char* file, mmap_t* restrict ptr);
|
||||||
|
int unmap_and_close(mmap_t map);
|
||||||
|
|
||||||
|
typedef void* (*map_cb)(mmap_t map, void* user);
|
||||||
|
void* map_and_then(const char* file, map_cb callback, void* user);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#include <panic.h>
|
||||||
|
#include "reinterpret.h"
|
||||||
|
#include <cstdint>
|
||||||
|
namespace mm {
|
||||||
|
struct mmap {
|
||||||
|
inline static mmap_t create_raw(const char* file)
|
||||||
|
{
|
||||||
|
mmap_t map;
|
||||||
|
if (!open_and_map(file, &map)) panic("Failed to map file");
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline mmap(mmap_t raw) :inner(raw){}
|
||||||
|
inline mmap(const char* file)
|
||||||
|
: inner(create_raw(file)) {}
|
||||||
|
|
||||||
|
inline mmap(mmap&& move) : inner(move.inner)
|
||||||
|
{
|
||||||
|
auto other = const_cast<mmap_t*>(&move.inner);
|
||||||
|
other->ptr = nullptr;
|
||||||
|
}
|
||||||
|
inline mmap(const mmap& copt) = delete;
|
||||||
|
|
||||||
|
inline ~mmap()
|
||||||
|
{
|
||||||
|
if (inner.ptr) {
|
||||||
|
::unmap_and_close(inner);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const span<const unsigned char> as_span() const { return span(as_ptr(), size()); }
|
||||||
|
inline span<unsigned char> as_span() { return span(as_ptr(), size()); }
|
||||||
|
|
||||||
|
inline const std::uint8_t* as_ptr() const { return (const std::uint8_t*)inner.ptr; }
|
||||||
|
inline std::uint8_t* as_ptr() { return (std::uint8_t*)inner.ptr; }
|
||||||
|
|
||||||
|
inline std::size_t size() const { return inner.len; }
|
||||||
|
|
||||||
|
inline int as_fd() const { return inner.fd; }
|
||||||
|
inline const mmap_t& as_raw() const { return inner; }
|
||||||
|
private:
|
||||||
|
const mmap_t inner;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef restrict
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* _MAP_H */
|
@ -0,0 +1,35 @@
|
|||||||
|
#ifndef _PANIC_H
|
||||||
|
#define _PANIC_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct panicinfo {
|
||||||
|
const char* file;
|
||||||
|
const char* function;
|
||||||
|
int line;
|
||||||
|
};
|
||||||
|
|
||||||
|
void _do_panic(struct panicinfo pi, const char* fmt, ...) __attribute__((noreturn));
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C++" {
|
||||||
|
#include <utility>
|
||||||
|
template<typename... Args>
|
||||||
|
__attribute__((noreturn)) inline void _real_panic(const char* file, const char* function, int line, const char* fmt, Args&&... args)
|
||||||
|
{
|
||||||
|
panicinfo i = { file, function, line };
|
||||||
|
_do_panic(i, fmt, std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
#define panic(fmt, ...) _real_panic(__FILE__, __func__, __LINE__, fmt __VA_OPT__(,) __VA_ARGS__)
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#define panic(fmt, ...) _do_panic( (struct panicinfo){.file = __FILE__, .function = __func__, .line = __LINE__}, fmt __VA_OPT__(,) __VA_ARGS__)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
@ -0,0 +1 @@
|
|||||||
|
reinterpret.hpp
|
@ -0,0 +1,61 @@
|
|||||||
|
#ifndef _REINTERPRET_H
|
||||||
|
#define _REINTERPRET_H
|
||||||
|
|
||||||
|
#include <panic.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
#define restrict __restrict__
|
||||||
|
#include <cstddef>
|
||||||
|
#include <cstdint>
|
||||||
|
#else
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
template<typename T>
|
||||||
|
struct span {
|
||||||
|
inline span(T* ptr, std::size_t len) : ptr(ptr), len(len) {}
|
||||||
|
|
||||||
|
template<typename U>
|
||||||
|
inline span<U> reinterpret() const
|
||||||
|
{
|
||||||
|
auto bytes = size_bytes();
|
||||||
|
//if (len_b % sizeof(U) != 0) panic("Cannot reinterpret T to U due to unmatch sizing constraints.");
|
||||||
|
|
||||||
|
return span<U>((U*)ptr, bytes / sizeof(U));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const T& operator[](std::size_t i) const
|
||||||
|
{
|
||||||
|
if (i >= len) panic("Out of bounds access: %lu >= %lu", i, len);
|
||||||
|
return ptr[i];
|
||||||
|
}
|
||||||
|
inline T& operator[](std::size_t i)
|
||||||
|
{
|
||||||
|
if (i >= len) panic("Out of bounds access: %lu >= %lu", i, len);
|
||||||
|
return ptr[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const T* as_ptr() const { return ptr; }
|
||||||
|
inline T* as_ptr() { return ptr; }
|
||||||
|
|
||||||
|
inline const T* operator&() const { return as_ptr(); }
|
||||||
|
inline T* operator&() { return as_ptr(); }
|
||||||
|
|
||||||
|
inline std::size_t size_bytes() const { return len * sizeof(T); }
|
||||||
|
inline std::size_t size() const { return len; }
|
||||||
|
private:
|
||||||
|
T* const ptr;
|
||||||
|
const std::size_t len;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
uint64_t* bytes_to_long(uint8_t* ptr, size_t ptr_sz, size_t* restrict nsize);
|
||||||
|
float* bytes_to_float(uint8_t* ptr, size_t ptr_sz, size_t* restrict nsize);
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* _REINTERPRET_H */
|
@ -0,0 +1,59 @@
|
|||||||
|
#ifndef _RNG_H
|
||||||
|
#define _RNG_H
|
||||||
|
|
||||||
|
#include "shuffle3.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
enum rng_kind {
|
||||||
|
RNG_KIND_FRNG,
|
||||||
|
RNG_KIND_DRNG,
|
||||||
|
RNG_KIND_XORNG,
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct rng_init
|
||||||
|
{
|
||||||
|
enum rng_kind kind;
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
double state[2];
|
||||||
|
} frng;
|
||||||
|
struct {
|
||||||
|
int32_t state;
|
||||||
|
} drng;
|
||||||
|
struct {
|
||||||
|
uint64_t state[2];
|
||||||
|
} xorng;
|
||||||
|
} init;
|
||||||
|
|
||||||
|
} rng_init_opt;
|
||||||
|
|
||||||
|
typedef struct rng_impl* _UNIQUE rng_t;
|
||||||
|
|
||||||
|
rng_t rng_new(rng_init_opt kind);
|
||||||
|
#define RNG_INIT(_kind,...) ((rng_init_opt){.kind=(_kind), .init.__VA_ARGS__ })
|
||||||
|
void rng_free(rng_t ptr);
|
||||||
|
|
||||||
|
// Tests
|
||||||
|
extern void rng_test();
|
||||||
|
extern void rng_test_spec(rng_t rng);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
// RNG interfaces
|
||||||
|
#include <rng/frng.hpp>
|
||||||
|
#include <rng/drng.hpp>
|
||||||
|
#include <rng/xoroshiro128plus.hpp>
|
||||||
|
|
||||||
|
namespace rng {
|
||||||
|
void test_algo(RNG&& rng);
|
||||||
|
|
||||||
|
template<class R,
|
||||||
|
typename std::enable_if<std::is_base_of<RNG, R>::value>::value __fuck>
|
||||||
|
inline void test_algo(R&& rng) { test_algo(static_cast<RNG&&>(rng)); }
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* _RNG_H */
|
@ -0,0 +1,22 @@
|
|||||||
|
|
||||||
|
#include "impl.hpp"
|
||||||
|
#include <debug.h>
|
||||||
|
namespace rng
|
||||||
|
{
|
||||||
|
struct drng : public RNG
|
||||||
|
{
|
||||||
|
inline drng(std::uint32_t seed) : state(seed){
|
||||||
|
D_dprintf("drng: seeded with %u", seed);
|
||||||
|
//dprintf(" dummy run sample: %f", sample());
|
||||||
|
}
|
||||||
|
inline drng() : drng(1){}
|
||||||
|
|
||||||
|
static drng from_time();
|
||||||
|
|
||||||
|
int rand();
|
||||||
|
protected:
|
||||||
|
double sample() override;
|
||||||
|
private:
|
||||||
|
std::uint32_t state;
|
||||||
|
};
|
||||||
|
}
|
@ -0,0 +1,66 @@
|
|||||||
|
|
||||||
|
#include "impl.hpp"
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
#include <debug.h>
|
||||||
|
|
||||||
|
namespace rng
|
||||||
|
{
|
||||||
|
struct frng : public RNG
|
||||||
|
{
|
||||||
|
template<std::size_t N>
|
||||||
|
static constexpr inline double dot(const std::array<double, N>& v, const std::array<double, N>& u)
|
||||||
|
{
|
||||||
|
double res=0;
|
||||||
|
for(std::size_t i=0;i<N;i++)
|
||||||
|
{
|
||||||
|
res += v[i] * u[i];
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline constexpr double fract(double x)
|
||||||
|
{
|
||||||
|
return x - floor(x);
|
||||||
|
}
|
||||||
|
static inline constexpr double sample_double(const std::array<double, 2>& state)
|
||||||
|
{
|
||||||
|
const constexpr std::array<double, 2> vec2 = { 12.9898, 78.223 };
|
||||||
|
return fract(sin(dot(state, vec2)) * 43758.5453);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define P D_dprintf("frng: seeded with (%f, %f)", state[0], state[1]);
|
||||||
|
inline constexpr frng(double s1, double s2) : state({s1, s2}){P}
|
||||||
|
inline constexpr frng(const std::array<double, 2>& ar) : state(ar){P}
|
||||||
|
inline constexpr frng(std::array<double, 2>&& ar) : state(ar){P}
|
||||||
|
inline constexpr frng(const double (&ar)[2]) : state({ar[0], ar[1]}) {P}
|
||||||
|
#undef P
|
||||||
|
inline constexpr double next_double() override { return sample(); }
|
||||||
|
inline constexpr float next_float() override { return (float)sample(); }
|
||||||
|
protected:
|
||||||
|
inline constexpr double sample() override
|
||||||
|
{
|
||||||
|
double res = sample_double(state);
|
||||||
|
update_state(state, res);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
std::array<double, 2> state;
|
||||||
|
static inline constexpr void update_state(std::array<double, 2>& state, double r)
|
||||||
|
{
|
||||||
|
float v1 = (float)state[0];
|
||||||
|
float v2 = (float)state[1];
|
||||||
|
|
||||||
|
std::array<double, 2> nvec = {
|
||||||
|
r,
|
||||||
|
(double)v2,
|
||||||
|
};
|
||||||
|
|
||||||
|
state[0] = sample_double(nvec);
|
||||||
|
|
||||||
|
nvec[1] = (double)v1;
|
||||||
|
state[1] = sample_double(nvec);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,35 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <vector>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
/// Base class for RNG impls
|
||||||
|
struct RNG {
|
||||||
|
virtual unsigned char byte();
|
||||||
|
virtual void bytes(unsigned char* ptr, std::size_t len);
|
||||||
|
|
||||||
|
template<std::size_t N>
|
||||||
|
inline void bytes(unsigned char (&arr)[N]) { return bytes(arr, N); }
|
||||||
|
template<std::size_t N>
|
||||||
|
inline void bytes(std::array<unsigned char, N>& array) { return bytes(&array[0], N); }
|
||||||
|
inline void bytes(std::vector<unsigned char>& vec) { return bytes(&vec[0], vec.size()); }
|
||||||
|
|
||||||
|
bool chance();
|
||||||
|
virtual bool chance(double chance);
|
||||||
|
|
||||||
|
virtual std::int32_t next_int();
|
||||||
|
inline std::int32_t next_int(std::int32_t max) { return next_int(0, max); }
|
||||||
|
std::int32_t next_int(std::int32_t min, std::int32_t max);
|
||||||
|
|
||||||
|
virtual std::int64_t next_long();
|
||||||
|
inline std::int64_t next_long(std::int64_t max) { return next_long(0, max); }
|
||||||
|
std::int64_t next_long(std::int64_t min, std::int64_t max);
|
||||||
|
|
||||||
|
inline virtual float next_float() { return (float)sample(); }
|
||||||
|
inline virtual double next_double() { return sample(); }
|
||||||
|
|
||||||
|
virtual ~RNG() = default;
|
||||||
|
protected:
|
||||||
|
virtual double sample() = 0;
|
||||||
|
};
|
@ -0,0 +1,29 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "impl.hpp"
|
||||||
|
#include <debug.h>
|
||||||
|
|
||||||
|
namespace rng
|
||||||
|
{
|
||||||
|
struct xoroshiro128plus : public RNG
|
||||||
|
{
|
||||||
|
using State = std::array<std::uint64_t, 2>;
|
||||||
|
#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<std::uint64_t, 2>&& ar) : state(ar){P}
|
||||||
|
inline constexpr xoroshiro128plus(const std::array<std::uint64_t, 2>& ar) : state(ar){P}
|
||||||
|
inline constexpr xoroshiro128plus(const std::uint64_t (&ar)[2]) : state({ar[0], ar[1]}){P}
|
||||||
|
#undef P
|
||||||
|
std::uint64_t next_ulong();
|
||||||
|
using RNG::next_long;
|
||||||
|
std::int64_t next_long() override;
|
||||||
|
|
||||||
|
void jump();
|
||||||
|
void long_jump();
|
||||||
|
protected:
|
||||||
|
double sample() override;
|
||||||
|
private:
|
||||||
|
State state;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,38 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <rng.h>
|
||||||
|
#include <reinterpret.h>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <fmt/format.h>
|
||||||
|
|
||||||
|
namespace rng {
|
||||||
|
template<typename T, typename R>
|
||||||
|
inline void shuffle(R& rng, span<T> span)
|
||||||
|
{
|
||||||
|
if(!span.size()) return;
|
||||||
|
fmt::print(" -> shuffling {} objects...", span.size());
|
||||||
|
for(std::size_t i=span.size()-1;i>0;i--)
|
||||||
|
{
|
||||||
|
auto j = rng.next_long(i);
|
||||||
|
std::swap(span[i], span[j]);
|
||||||
|
}
|
||||||
|
fmt::print(" OK\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T, typename R>
|
||||||
|
inline void unshuffle(R& rng, span<T> span)
|
||||||
|
{
|
||||||
|
if(!span.size()) return;
|
||||||
|
std::vector<std::size_t> rng_values(span.size());
|
||||||
|
|
||||||
|
fmt::print(" -> unshuffling {} objects...", span.size());
|
||||||
|
for(std::size_t i=span.size()-1;i>0;i--)
|
||||||
|
rng_values.push_back(rng.next_long(i));
|
||||||
|
|
||||||
|
for(std::size_t i=1;i<span.size();i++) {
|
||||||
|
std::swap(span[i], span[rng_values.back()]);
|
||||||
|
rng_values.pop_back();
|
||||||
|
}
|
||||||
|
fmt::print(" OK\n");
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,30 @@
|
|||||||
|
#ifndef _SHUFFLE3_H
|
||||||
|
#define _SHUFFLE3_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
#define _UNIQUE __restrict
|
||||||
|
extern "C" {
|
||||||
|
#else
|
||||||
|
#define _UNIQUE restrict
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
#define _FORCE_INLINE __attribute__((gnu_inline)) static inline
|
||||||
|
#else
|
||||||
|
#define _FORCE_INLINE __attribute__((gnu_inline)) extern inline
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
#ifdef DEBUG
|
||||||
|
#define dprintf(fmt, ...) printf("[dbg @" __FILE__ "->%s:%d] " fmt "\n", __func__, __LINE__ __VA_OPT__(,) __VA_ARGS__)
|
||||||
|
#else
|
||||||
|
#define dprintf(fmt, ...)
|
||||||
|
#endif
|
||||||
|
*/
|
||||||
|
extern const char* _prog_name;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* _SHUFFLE3_H */
|
@ -0,0 +1,52 @@
|
|||||||
|
#ifndef _WORK_H
|
||||||
|
#define _WORK_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
enum work_buffer_opts {
|
||||||
|
WORK_BO_CPIP=0, // Copy then run in place on output file (default)
|
||||||
|
WORK_BO_BUFFERED=1, // Read whole input into memory then perform
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct _work_args {
|
||||||
|
enum {
|
||||||
|
OP_SHUFFLE_IP, // Shuffle in place
|
||||||
|
OP_SHUFFLE_OP, // Shuffle out of place
|
||||||
|
|
||||||
|
OP_UNSHUFFLE_IP, // Unshuffle in place
|
||||||
|
OP_UNSHUFFLE_OP, // Unshuffle out of place
|
||||||
|
|
||||||
|
OP_HELP, // Print help then exit
|
||||||
|
} op;
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
const char* file;
|
||||||
|
} op_shuffle_ip;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
enum work_buffer_opts buffered;
|
||||||
|
const char* ifile;
|
||||||
|
const char* ofile;
|
||||||
|
} op_shuffle_op;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
const char* file;
|
||||||
|
} op_unshuffle_ip;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
enum work_buffer_opts buffered;
|
||||||
|
const char* ifile;
|
||||||
|
const char* ofile;
|
||||||
|
} op_unshuffle_op;
|
||||||
|
} data;
|
||||||
|
} work_args_t;
|
||||||
|
|
||||||
|
int do_work(const work_args_t args);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* _WORK_H */
|
@ -0,0 +1,19 @@
|
|||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
#include <debug.h>
|
||||||
|
|
||||||
|
#include <colours.h>
|
||||||
|
|
||||||
|
void _do_dprintf(struct debuginfo info, const char* fmt, ...)
|
||||||
|
{
|
||||||
|
#ifdef DEBUG
|
||||||
|
va_list li;
|
||||||
|
va_start(li, fmt);
|
||||||
|
fprintf(stderr, "["FGRN("dbg")" " FYEL("@") BOLD("%s") "->" FWHT("%s") ":" FYEL("%d") "]: ", info.file, info.function,info.line);
|
||||||
|
vfprintf(stderr, fmt, li);
|
||||||
|
fprintf(stderr, "\n");
|
||||||
|
va_end(li);
|
||||||
|
#endif
|
||||||
|
}
|
@ -0,0 +1,78 @@
|
|||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
|
||||||
|
#include <shuffle3.h>
|
||||||
|
#include <panic.h>
|
||||||
|
#include <reinterpret.h>
|
||||||
|
#include <map.h>
|
||||||
|
#include <rng.h>
|
||||||
|
#include <work.h>
|
||||||
|
|
||||||
|
#include <debug.h>
|
||||||
|
|
||||||
|
#define noreturn __attribute__((noreturn)) void
|
||||||
|
|
||||||
|
_Static_assert(sizeof(float)==sizeof(uint32_t), "float is not 32 bits");
|
||||||
|
|
||||||
|
const char* _prog_name;
|
||||||
|
|
||||||
|
noreturn help_then_exit()
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Try passing `-h`\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void usage()
|
||||||
|
{
|
||||||
|
printf( "shuffle3 - 3 pass binary shuffler\n"
|
||||||
|
"Usage: %s -s <file>\n"
|
||||||
|
"Usage: %s -u <file>\n", _prog_name, _prog_name);
|
||||||
|
printf("\nOPTIONS:\n"
|
||||||
|
" -s\tShuffle file in place\n"
|
||||||
|
" -u\tUnshuffle file in place\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char** argv)
|
||||||
|
{
|
||||||
|
_prog_name = argv[0];
|
||||||
|
|
||||||
|
work_args_t parsed;
|
||||||
|
|
||||||
|
if( !argv[1] || *(argv[1]) != '-') help_then_exit();
|
||||||
|
|
||||||
|
D_dprintf("Parsing `%c'", argv[1][1]);
|
||||||
|
switch(argv[1][1])
|
||||||
|
{
|
||||||
|
case 's':
|
||||||
|
parsed.op = OP_SHUFFLE_IP;
|
||||||
|
if(!(parsed.data.op_shuffle_ip.file = argv[2]))
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Error: -s expected file argument.\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
D_dprintf("parsed.op = %d", OP_SHUFFLE_IP);
|
||||||
|
break;
|
||||||
|
case 'u':
|
||||||
|
parsed.op = OP_UNSHUFFLE_IP;
|
||||||
|
if(!(parsed.data.op_unshuffle_ip.file = argv[2]))
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Error: -u expected file argument.\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
D_dprintf("parsed.op = %d", OP_UNSHUFFLE_IP);
|
||||||
|
break;
|
||||||
|
case 'h':
|
||||||
|
usage();
|
||||||
|
return 0;
|
||||||
|
default:
|
||||||
|
fprintf(stderr, "Error: unknown argument `%s'\n\n", argv[1]);
|
||||||
|
help_then_exit();
|
||||||
|
panic("Unreachable");
|
||||||
|
}
|
||||||
|
|
||||||
|
return do_work(parsed);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,56 @@
|
|||||||
|
#define _GNU_SOURCE
|
||||||
|
#include<stdio.h>
|
||||||
|
#include<stdlib.h>
|
||||||
|
#include<string.h>
|
||||||
|
#include<unistd.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include<sys/mman.h>
|
||||||
|
#include<fcntl.h>
|
||||||
|
|
||||||
|
#define FILEMODE S_IRWXU | S_IRGRP | S_IROTH
|
||||||
|
|
||||||
|
#include <map.h>
|
||||||
|
|
||||||
|
int open_and_map(const char* file, mmap_t* restrict ptr)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
struct stat st;
|
||||||
|
if ((fd = open(file, O_RDWR, FILEMODE)) < 0) {
|
||||||
|
perror("Failed to open file");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fstat(fd, &st) < 0) {
|
||||||
|
perror("Failed to stat file");
|
||||||
|
close(fd);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
register struct mmap map = { .fd = fd, .ptr = NULL, .len = st.st_size };
|
||||||
|
|
||||||
|
if ((map.ptr = mmap(NULL, map.len, PROT_READ | PROT_WRITE, MAP_SHARED,fd, 0)) == MAP_FAILED) {
|
||||||
|
perror("mmap() failed");
|
||||||
|
close(fd);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
*ptr = map;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int unmap_and_close(mmap_t map)
|
||||||
|
{
|
||||||
|
register int rval=1;
|
||||||
|
if (munmap(map.ptr, map.len) < 0) {
|
||||||
|
perror("munmap() failed");
|
||||||
|
rval=0;
|
||||||
|
}
|
||||||
|
if (close(map.fd) <0) {
|
||||||
|
perror("Failed to close fd");
|
||||||
|
rval=0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rval;
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
|
||||||
|
#include <shuffle3.h>
|
||||||
|
#include <reinterpret.hpp>
|
||||||
|
#include <map.h>
|
||||||
|
|
||||||
|
|
||||||
|
extern "C" void* map_and_then(const char* file, map_cb callback, void* user)
|
||||||
|
{
|
||||||
|
mm::mmap map(file);
|
||||||
|
return callback(map.as_raw(), user);
|
||||||
|
}
|
@ -0,0 +1,18 @@
|
|||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
#include <panic.h>
|
||||||
|
|
||||||
|
#include <colours.h>
|
||||||
|
|
||||||
|
__attribute__((noreturn)) void _do_panic(struct panicinfo info, const char* fmt, ...)
|
||||||
|
{
|
||||||
|
va_list li;
|
||||||
|
va_start(li, fmt);
|
||||||
|
fprintf(stderr, BOLD(UNDL(FRED("[!]"))) " (" BOLD("%s") "->" BOLD(FRED("%s")) ":" FYEL("%d") ") " BOLD(FRED("fatal error")) ": ", info.file, info.function, info.line);
|
||||||
|
vfprintf(stderr, fmt, li);
|
||||||
|
fprintf(stderr, "\n");
|
||||||
|
va_end(li);
|
||||||
|
abort();
|
||||||
|
}
|
@ -0,0 +1,22 @@
|
|||||||
|
#include <shuffle3.h>
|
||||||
|
#include <reinterpret.hpp>
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
static inline T* bytes_to_t(std::uint8_t* ptr, std::size_t ptr_sz, std::size_t* restrict nsize)
|
||||||
|
{
|
||||||
|
span<uint8_t> bytes(ptr, ptr_sz);
|
||||||
|
auto tout = bytes.reinterpret<T>();
|
||||||
|
*nsize = tout.size();
|
||||||
|
return tout.as_ptr();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
uint64_t* bytes_to_long(uint8_t* ptr, size_t ptr_sz, size_t* restrict nsize)
|
||||||
|
{
|
||||||
|
return bytes_to_t<uint64_t>(ptr, ptr_sz, nsize);
|
||||||
|
}
|
||||||
|
float* bytes_to_float(uint8_t* ptr, size_t ptr_sz, size_t* restrict nsize)
|
||||||
|
{
|
||||||
|
return bytes_to_t<float>(ptr, ptr_sz, nsize);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,92 @@
|
|||||||
|
#include <iostream>
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
#include <rng/impl.hpp>
|
||||||
|
|
||||||
|
inline unsigned char RNG::byte()
|
||||||
|
{
|
||||||
|
return (unsigned char)next_int(255);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RNG::bytes(unsigned char* ptr, std::size_t len)
|
||||||
|
{
|
||||||
|
for(std::size_t i=0;i<len;i++)
|
||||||
|
{
|
||||||
|
ptr[i] = byte();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RNG::chance()
|
||||||
|
{
|
||||||
|
return chance(.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RNG::chance(double d)
|
||||||
|
{
|
||||||
|
if (d<=0) return false;
|
||||||
|
return sample() <= d;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::int32_t RNG::next_int(std::int32_t min, std::int32_t max)
|
||||||
|
{
|
||||||
|
return (std::int32_t)floor(sample() * (double)(max-min))+min;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::int32_t RNG::next_int()
|
||||||
|
{
|
||||||
|
return (chance() ? 1 : -1) * (std::int32_t)floor(sample() * (double)INT32_MAX);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::int64_t RNG::next_long(std::int64_t min, std::int64_t max)
|
||||||
|
{
|
||||||
|
return (std::int64_t)floor(sample() * (double)(max-min))+min;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::int64_t RNG::next_long()
|
||||||
|
{
|
||||||
|
return (chance() ? 1l : -1l) * (std::int64_t)floor(sample() * (double)INT64_MAX);
|
||||||
|
}
|
||||||
|
|
||||||
|
#include <rng.h>
|
||||||
|
#include <panic.h>
|
||||||
|
namespace { // C interface
|
||||||
|
using namespace std;
|
||||||
|
#define extract_ptr(ptr) ((RNG*)(ptr))
|
||||||
|
static inline RNG& extract_ref(rng_t rng)
|
||||||
|
{
|
||||||
|
return *extract_ptr(rng);
|
||||||
|
}
|
||||||
|
template<typename T>
|
||||||
|
static inline T* extract_downcast_ptr(rng_t rng)
|
||||||
|
{
|
||||||
|
return dynamic_cast<T*>(extract_ptr(rng));
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
default: panic("Unknown RNG init opt: %d", opt.kind);
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rng_free(rng_t rng)
|
||||||
|
{
|
||||||
|
RNG* ptr = (RNG*)rng;
|
||||||
|
delete ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rng_test_spec(rng_t rng)
|
||||||
|
{
|
||||||
|
cout << "rng_test_spec:" << endl;
|
||||||
|
rng::test_algo(std::move(extract_ref(rng)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
#include <cstdlib>
|
||||||
|
#include <ctime>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include <rng/drng.hpp>
|
||||||
|
|
||||||
|
namespace rng
|
||||||
|
{
|
||||||
|
drng drng::from_time() { return drng(time(NULL)); }
|
||||||
|
|
||||||
|
int drng::rand()
|
||||||
|
{
|
||||||
|
return rand_r(&state);
|
||||||
|
}
|
||||||
|
|
||||||
|
double drng::sample()
|
||||||
|
{
|
||||||
|
int val = rand_r(&state);
|
||||||
|
return (double)val / (double)RAND_MAX;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,3 @@
|
|||||||
|
#include <rng/impl.hpp>
|
||||||
|
#include <rng/frng.hpp>
|
||||||
|
#include <iostream>
|
@ -0,0 +1,37 @@
|
|||||||
|
#include <iostream>
|
||||||
|
#include <rng.h>
|
||||||
|
|
||||||
|
namespace rng {
|
||||||
|
void test_algo(RNG&& rng)
|
||||||
|
{
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
for(int i=0;i<10;i++) {
|
||||||
|
double d = rng.next_double();
|
||||||
|
long l = rng.next_long(-10, 10);
|
||||||
|
|
||||||
|
std::array<bool, 10> ar;
|
||||||
|
for(auto& i : ar) i = rng.chance();
|
||||||
|
|
||||||
|
cout << "\t(Sampled: " << d;
|
||||||
|
cout << ", Long: " << l;
|
||||||
|
cout << ", Bools: [ ";
|
||||||
|
for(const auto& i : ar) cout << i << " ";
|
||||||
|
cout << "])" << endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" void rng_test()
|
||||||
|
{
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
cout << "frng:" << endl;
|
||||||
|
rng::test_algo(rng::frng(1.0, 1.2));
|
||||||
|
|
||||||
|
cout << "drng:" << endl;
|
||||||
|
rng::test_algo(rng::drng(10));
|
||||||
|
|
||||||
|
cout << "xoroshiro128+:" << endl;
|
||||||
|
rng::test_algo(rng::xoroshiro128plus(100ul, 200ul));
|
||||||
|
}
|
@ -0,0 +1,86 @@
|
|||||||
|
#include <rng/xoroshiro128plus.hpp>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
using u64 = std::uint64_t;
|
||||||
|
|
||||||
|
#define XO xoroshiro128plus
|
||||||
|
|
||||||
|
static inline constexpr u64 rotl(u64 x, int k)
|
||||||
|
{
|
||||||
|
return (x << k) | (x >> (64 - k));
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace rng
|
||||||
|
{
|
||||||
|
inline constexpr u64 next(XO::State& s)
|
||||||
|
{
|
||||||
|
u64 s0 = s[0];
|
||||||
|
u64 s1 = s[1];
|
||||||
|
u64 result = s0 + s1;
|
||||||
|
|
||||||
|
s1 ^= s0;
|
||||||
|
s[0] = rotl(s0, 24) ^ s1 ^ (s1 << 16);
|
||||||
|
s[1] = rotl(s1, 37);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
inline constexpr void xo_jump(XO::State& s)
|
||||||
|
{
|
||||||
|
constexpr const std::uint64_t JUMP[] = { 0xdf900294d8f554a5, 0x170865df4b3201fc };
|
||||||
|
|
||||||
|
std::uint64_t s0 = 0;
|
||||||
|
std::uint64_t s1 = 0;
|
||||||
|
for(u64 i = 0; i < sizeof JUMP / sizeof *JUMP; i++)
|
||||||
|
for(int b = 0; b < 64; b++) {
|
||||||
|
if (JUMP[i] & UINT64_C(1) << b) {
|
||||||
|
s0 ^= s[0];
|
||||||
|
s1 ^= s[1];
|
||||||
|
}
|
||||||
|
next(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
s[0] = s0;
|
||||||
|
s[1] = s1;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline constexpr void xo_long_jump(XO::State& s)
|
||||||
|
{
|
||||||
|
constexpr const uint64_t LONG_JUMP[] = { 0xd2a98b26625eee7b, 0xdddf9b1090aa7ac1 };
|
||||||
|
|
||||||
|
std::uint64_t s0 = 0;
|
||||||
|
std::uint64_t s1 = 0;
|
||||||
|
for(u64 i = 0; i < sizeof LONG_JUMP / sizeof *LONG_JUMP; i++)
|
||||||
|
for(int b = 0; b < 64; b++) {
|
||||||
|
if (LONG_JUMP[i] & UINT64_C(1) << b) {
|
||||||
|
s0 ^= s[0];
|
||||||
|
s1 ^= s[1];
|
||||||
|
}
|
||||||
|
next(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
s[0] = s0;
|
||||||
|
s[1] = s1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void XO::jump() { xo_jump(state); }
|
||||||
|
void XO::long_jump() { xo_long_jump(state); }
|
||||||
|
|
||||||
|
std::uint64_t XO::next_ulong()
|
||||||
|
{
|
||||||
|
return next(state);
|
||||||
|
}
|
||||||
|
std:: int64_t XO::next_long()
|
||||||
|
{
|
||||||
|
const u64 v = next_ulong();
|
||||||
|
static_assert(sizeof(v) == sizeof(decltype(next_long())));
|
||||||
|
|
||||||
|
return *(const std::int64_t*)&v;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
double XO::sample()
|
||||||
|
{
|
||||||
|
return (next(state) & ((INT64_C(1) << 53) - 1)) * (1.00 / (INT64_C(1) << 53));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,129 @@
|
|||||||
|
#include <tuple>
|
||||||
|
#include <functional>
|
||||||
|
#include <cfloat>
|
||||||
|
|
||||||
|
#include <fmt/format.h>
|
||||||
|
|
||||||
|
#include <shuffle3.h>
|
||||||
|
#include <panic.h>
|
||||||
|
#include <map.h>
|
||||||
|
#include <reinterpret.h>
|
||||||
|
#include <shuffle.hpp>
|
||||||
|
|
||||||
|
#include <work.h>
|
||||||
|
#include <debug.h>
|
||||||
|
|
||||||
|
template<typename T, typename Fn>
|
||||||
|
std::tuple<T, T> minmax_t(const span<T>& array, Fn keep)
|
||||||
|
{
|
||||||
|
T highest;
|
||||||
|
T lowest;
|
||||||
|
bool init=false;
|
||||||
|
D_dprintf("minmax_t: %p (%lu)", array.as_ptr(), array.size());
|
||||||
|
for(std::size_t i=0;i<array.size();i++)
|
||||||
|
{
|
||||||
|
if(!keep(array[i])) continue;
|
||||||
|
|
||||||
|
auto item = array[i];
|
||||||
|
if(!init) {
|
||||||
|
init = true;
|
||||||
|
lowest = highest = item;
|
||||||
|
}
|
||||||
|
else if(item < lowest) lowest = item;
|
||||||
|
else if(item > highest) highest = item;
|
||||||
|
}
|
||||||
|
//fmt::print("MMX {}, {}\n", lowest, highest);
|
||||||
|
return {lowest, highest};
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
inline std::tuple<T, T> minmax_t(const span<T>& array)
|
||||||
|
{
|
||||||
|
return minmax_t(array, [](T _val) { return true; });
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace work
|
||||||
|
{
|
||||||
|
/// Shuffle or unshuffle in place
|
||||||
|
template<bool unshuffle>
|
||||||
|
int xshuffle_ip(const char* file)
|
||||||
|
{
|
||||||
|
mm::mmap map(file);
|
||||||
|
|
||||||
|
if constexpr(unshuffle)
|
||||||
|
{
|
||||||
|
auto [byte_l, byte_h] = minmax_t(map.as_span().reinterpret<std::int8_t>());
|
||||||
|
D_dprintf("MMX res (s8): %d -- %d", byte_l, byte_h);
|
||||||
|
rng::drng drng((std::int32_t) ((0xfffa << 16) | (byte_l<<7) | byte_h ));
|
||||||
|
rng::unshuffle(drng, map.as_span());
|
||||||
|
|
||||||
|
auto [float_l, float_h] = minmax_t(map.as_span().reinterpret<float>(), [](float f) -> bool { return !( (f!=f) || f < -FLT_MAX || f > FLT_MAX); });
|
||||||
|
D_dprintf("MMX res (f32): %f -- %f", float_l, float_h);
|
||||||
|
rng::frng frng(float_l, float_h);
|
||||||
|
rng::unshuffle(frng, map.as_span().reinterpret<float>());
|
||||||
|
|
||||||
|
auto [long_l, long_h] = minmax_t(map.as_span().reinterpret<std::int64_t>());
|
||||||
|
D_dprintf("MMX res (u64): %ld -- %ld", long_l, long_h);
|
||||||
|
rng::xoroshiro128plus xorng(*(const std::uint64_t*)&long_l, *(const std::uint64_t*)&long_h);
|
||||||
|
rng::unshuffle(xorng, map.as_span().reinterpret<std::int64_t>());
|
||||||
|
} else {
|
||||||
|
auto [long_l, long_h] = minmax_t(map.as_span().reinterpret<std::int64_t>());
|
||||||
|
D_dprintf("MMX res (u64): %ld -- %ld", long_l, long_h);
|
||||||
|
rng::xoroshiro128plus xorng(*(const std::uint64_t*)&long_l, *(const std::uint64_t*)&long_h);
|
||||||
|
rng::shuffle(xorng, map.as_span().reinterpret<std::int64_t>());
|
||||||
|
|
||||||
|
auto [float_l, float_h] = minmax_t(map.as_span().reinterpret<float>(), [](float f) -> bool { return !( (f!=f) || f < -FLT_MAX || f > FLT_MAX); });
|
||||||
|
D_dprintf("MMX res (f32): %f -- %f", float_l, float_h);
|
||||||
|
rng::frng frng(float_l, float_h);
|
||||||
|
rng::shuffle(frng, map.as_span().reinterpret<float>());
|
||||||
|
|
||||||
|
auto [byte_l, byte_h] = minmax_t(map.as_span().reinterpret<std::int8_t>());
|
||||||
|
D_dprintf("MMX res (s8): %d -- %d", byte_l, byte_h);
|
||||||
|
rng::drng drng((std::int32_t) ((0xfffa << 16) | (byte_l<<7) | byte_h ));
|
||||||
|
rng::shuffle(drng, map.as_span());
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Shuffle or unshuffle out of place
|
||||||
|
template<bool unshuffle>
|
||||||
|
int xshuffle_op(const char* ifile, const char* ofile, bool is_buffered)
|
||||||
|
{
|
||||||
|
|
||||||
|
if constexpr(unshuffle)
|
||||||
|
{
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
}
|
||||||
|
panic("Unimplemented");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int help()
|
||||||
|
{
|
||||||
|
//Print help then exit
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" int do_work(const work_args_t args)
|
||||||
|
{
|
||||||
|
using A = decltype(args.op);
|
||||||
|
switch (args.op) {
|
||||||
|
case A::OP_SHUFFLE_IP: return work::xshuffle_ip<false >(args.data.op_shuffle_ip.file);
|
||||||
|
case A::OP_SHUFFLE_OP: return work::xshuffle_op<false >(args.data.op_shuffle_op.ifile,
|
||||||
|
args.data.op_shuffle_op.ofile,
|
||||||
|
args.data.op_shuffle_op.buffered == WORK_BO_BUFFERED);
|
||||||
|
case A::OP_UNSHUFFLE_IP: return work::xshuffle_ip<true >(args.data.op_unshuffle_ip.file);
|
||||||
|
case A::OP_UNSHUFFLE_OP: return work::xshuffle_op<true>(args.data.op_unshuffle_op.ifile,
|
||||||
|
args.data.op_unshuffle_op.ofile,
|
||||||
|
args.data.op_unshuffle_op.buffered == WORK_BO_BUFFERED);
|
||||||
|
case A::OP_HELP: return help();
|
||||||
|
|
||||||
|
default: panic("Unknown op %d", (int)args.op);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
Reference in new issue