# include <tuple>
# include <functional>
# include <bit>
# include <cfloat>
# 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 ) ;
map . access ( mm : : Access : : Random , true ) ;
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 ( std : : bit_cast < std : : uint64_t > ( long_l ) , std : : bit_cast < 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 ( std : : bit_cast < std : : uint64_t > ( long_l ) , std : : bit_cast < 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 )
{
//TODO: Use libcow's `cow_create_fd()`/`Cow::Cow(fd, size)` to try to map `ifile`
// Then, clone it, and use the `Fake` to do the shuffling on, and write the data to `ofile`.
// If `ifile` cannot be mapped, create a shim `Cow(size(ifile))`, `sendfile()/copy_file_range()/splice()` `ifile` into the shim memory fd, and use that (do *not* clone it to a Fake,)
// Then, perform the shuffling on the original `Cow`, and `sendfile()/copy_file_range()/splice()` the `ifile` file memory descriptor used for the `Cow` into `ofile`, and then destroy the `Cow`, **make sure to `msync()` the Cow'd range before the copy**.
mm : : vmap imap ; //{ifile};
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 ;
}