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