2017-05-26 04:48:44 +08:00
/*
* IRandom . h
*
* This source file is part of the FoundationDB open source project
*
* Copyright 2013 - 2018 Apple Inc . and the FoundationDB project authors
2018-02-22 02:25:11 +08:00
*
2017-05-26 04:48:44 +08:00
* Licensed under the Apache License , Version 2.0 ( the " License " ) ;
* you may not use this file except in compliance with the License .
* You may obtain a copy of the License at
2018-02-22 02:25:11 +08:00
*
2017-05-26 04:48:44 +08:00
* http : //www.apache.org/licenses/LICENSE-2.0
2018-02-22 02:25:11 +08:00
*
2017-05-26 04:48:44 +08:00
* Unless required by applicable law or agreed to in writing , software
* distributed under the License is distributed on an " AS IS " BASIS ,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied .
* See the License for the specific language governing permissions and
* limitations under the License .
*/
# ifndef FLOW_IRANDOM_H
# define FLOW_IRANDOM_H
# pragma once
2018-10-20 01:30:13 +08:00
# include "flow/Platform.h"
2019-01-31 05:53:23 +08:00
# include "flow/FileIdentifier.h"
2019-01-29 11:38:13 +08:00
# include "flow/ObjectSerializerTraits.h"
2019-05-24 09:51:59 +08:00
# include "flow/FastRef.h"
2017-05-26 04:48:44 +08:00
# include <stdint.h>
# if (defined(__APPLE__))
# include <ext/hash_map>
# else
# include <unordered_map>
# endif
2019-02-05 13:25:10 +08:00
# include <functional>
2017-05-26 04:48:44 +08:00
2020-04-04 02:18:06 +08:00
// Until we move to C++20, we'll need something to take the place of operator<=>.
// This is as good a place as any, I guess.
template < typename T >
typename std : : enable_if < std : : is_integral < T > : : value , int > : : type compare ( T l , T r ) {
const int gt = l > r ;
const int lt = l < r ;
return gt - lt ;
// GCC also emits branchless code for the following, but the above performs
// slightly better in benchmarks as of this writing.
// return l < r ? -1 : l == r ? 0 : 1;
}
template < typename T , typename U >
typename std : : enable_if < ! std : : is_integral < T > : : value , int > : : type compare ( T const & l , U const & r ) {
return l . compare ( r ) ;
}
template < class K , class V >
int compare ( std : : pair < K , V > const & l , std : : pair < K , V > const & r ) {
if ( int cmp = compare ( l . first , r . first ) ) {
return cmp ;
}
return compare ( l . second , r . second ) ;
}
2017-05-26 04:48:44 +08:00
class UID {
uint64_t part [ 2 ] ;
public :
2019-01-31 05:53:23 +08:00
constexpr static FileIdentifier file_identifier = 15597147 ;
2017-05-26 04:48:44 +08:00
UID ( ) { part [ 0 ] = part [ 1 ] = 0 ; }
UID ( uint64_t a , uint64_t b ) { part [ 0 ] = a ; part [ 1 ] = b ; }
std : : string toString ( ) const ;
std : : string shortString ( ) const ;
bool isValid ( ) const { return part [ 0 ] | | part [ 1 ] ; }
2020-05-08 06:50:40 +08:00
int compare ( const UID & r ) const {
2020-04-04 02:18:06 +08:00
if ( int cmp = : : compare ( part [ 0 ] , r . part [ 0 ] ) ) {
return cmp ;
}
return : : compare ( part [ 1 ] , r . part [ 1 ] ) ;
}
2017-05-26 04:48:44 +08:00
bool operator = = ( const UID & r ) const { return part [ 0 ] = = r . part [ 0 ] & & part [ 1 ] = = r . part [ 1 ] ; }
bool operator ! = ( const UID & r ) const { return part [ 0 ] ! = r . part [ 0 ] | | part [ 1 ] ! = r . part [ 1 ] ; }
bool operator < ( const UID & r ) const { return part [ 0 ] < r . part [ 0 ] | | ( part [ 0 ] = = r . part [ 0 ] & & part [ 1 ] < r . part [ 1 ] ) ; }
2020-07-11 05:37:47 +08:00
bool operator > ( const UID & r ) const { return r < * this ; }
bool operator < = ( const UID & r ) const { return ! ( * this > r ) ; }
bool operator > = ( const UID & r ) const { return ! ( * this < r ) ; }
2017-05-26 04:48:44 +08:00
uint64_t hash ( ) const { return first ( ) ; }
uint64_t first ( ) const { return part [ 0 ] ; }
uint64_t second ( ) const { return part [ 1 ] ; }
static UID fromString ( std : : string const & ) ;
template < class Ar >
void serialize_unversioned ( Ar & ar ) { // Changing this serialization format will affect key definitions, so can't simply be versioned!
2018-12-29 02:49:26 +08:00
serializer ( ar , part [ 0 ] , part [ 1 ] ) ;
2017-05-26 04:48:44 +08:00
}
} ;
template < class Ar > void load ( Ar & ar , UID & uid ) { uid . serialize_unversioned ( ar ) ; }
template < class Ar > void save ( Ar & ar , UID const & uid ) { const_cast < UID & > ( uid ) . serialize_unversioned ( ar ) ; }
2019-01-29 11:38:13 +08:00
template < >
struct scalar_traits < UID > : std : : true_type {
constexpr static size_t size = sizeof ( uint64_t [ 2 ] ) ;
2019-07-16 03:58:31 +08:00
template < class Context >
static void save ( uint8_t * out , const UID & uid , Context & ) {
2019-01-29 11:38:13 +08:00
uint64_t * outI = reinterpret_cast < uint64_t * > ( out ) ;
outI [ 0 ] = uid . first ( ) ;
outI [ 1 ] = uid . second ( ) ;
}
template < class Context >
static void load ( const uint8_t * i , UID & out , Context & context ) {
const uint64_t * in = reinterpret_cast < const uint64_t * > ( i ) ;
out = UID ( in [ 0 ] , in [ 1 ] ) ;
}
} ;
2017-05-26 04:48:44 +08:00
namespace std {
template < >
2019-02-05 13:25:10 +08:00
class hash < UID > {
2017-05-26 04:48:44 +08:00
public :
size_t operator ( ) ( UID const & u ) const { return u . hash ( ) ; }
} ;
}
class IRandom {
public :
2019-02-14 07:11:53 +08:00
virtual double random01 ( ) = 0 ; // return random value in [0, 1]
2017-05-26 04:48:44 +08:00
virtual int randomInt ( int min , int maxPlusOne ) = 0 ;
virtual int64_t randomInt64 ( int64_t min , int64_t maxPlusOne ) = 0 ;
virtual uint32_t randomUInt32 ( ) = 0 ;
virtual UID randomUniqueID ( ) = 0 ;
virtual char randomAlphaNumeric ( ) = 0 ;
virtual std : : string randomAlphaNumeric ( int length ) = 0 ;
2019-03-04 04:57:43 +08:00
virtual uint32_t randomSkewedUInt32 ( uint32_t min , uint32_t maxPlusOne ) = 0 ;
2017-05-26 04:48:44 +08:00
virtual uint64_t peek ( ) const = 0 ; // returns something that is probably different for different random states. Deterministic (and idempotent) for a deterministic generator.
2019-05-24 09:51:59 +08:00
virtual void addref ( ) = 0 ;
virtual void delref ( ) = 0 ;
2017-05-26 04:48:44 +08:00
// The following functions have fixed implementations for now:
template < class C >
decltype ( ( fake < const C > ( ) [ 0 ] ) ) randomChoice ( const C & c ) { return c [ randomInt ( 0 , ( int ) c . size ( ) ) ] ; }
template < class C >
void randomShuffle ( C & container ) {
int s = ( int ) container . size ( ) ;
2018-08-02 09:09:54 +08:00
for ( int i = 0 ; i < s ; i + + ) {
int j = randomInt ( i , s ) ;
if ( i ! = j ) {
std : : swap ( container [ i ] , container [ j ] ) ;
}
}
2017-05-26 04:48:44 +08:00
}
bool coinflip ( ) { return ( this - > random01 ( ) < 0.5 ) ; }
} ;
extern FILE * randLog ;
2019-05-11 05:01:52 +08:00
// Sets the seed for the deterministic random number generator on the current thread
void setThreadLocalDeterministicRandomSeed ( uint32_t seed ) ;
// Returns the random number generator that can be seeded. This generator should only
// be used in contexts where the choice to call it is deterministic.
2019-06-05 04:40:48 +08:00
//
// This generator is only deterministic if given a seed using setThreadLocalDeterministicRandomSeed
2019-05-24 09:51:59 +08:00
Reference < IRandom > deterministicRandom ( ) ;
2019-05-11 05:01:52 +08:00
// A random number generator that cannot be manually seeded and may be called in
// non-deterministic contexts.
2019-05-24 09:51:59 +08:00
Reference < IRandom > nondeterministicRandom ( ) ;
2019-05-11 05:01:52 +08:00
2017-05-26 04:48:44 +08:00
# endif