rrudb 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.yardopts +1 -0
- data/LICENSE.txt +22 -0
- data/README.md +26 -0
- data/examples/example.rb +39 -0
- data/ext/rudb/NuDB/include/nudb/CMakeLists.txt +104 -0
- data/ext/rudb/NuDB/include/nudb/_experimental/basic_seconds_clock.hpp +200 -0
- data/ext/rudb/NuDB/include/nudb/_experimental/chrono_util.hpp +58 -0
- data/ext/rudb/NuDB/include/nudb/_experimental/test/fail_file.hpp +343 -0
- data/ext/rudb/NuDB/include/nudb/_experimental/test/temp_dir.hpp +73 -0
- data/ext/rudb/NuDB/include/nudb/_experimental/test/test_store.hpp +451 -0
- data/ext/rudb/NuDB/include/nudb/_experimental/test/xor_shift_engine.hpp +105 -0
- data/ext/rudb/NuDB/include/nudb/_experimental/util.hpp +288 -0
- data/ext/rudb/NuDB/include/nudb/basic_store.hpp +461 -0
- data/ext/rudb/NuDB/include/nudb/concepts.hpp +205 -0
- data/ext/rudb/NuDB/include/nudb/context.hpp +144 -0
- data/ext/rudb/NuDB/include/nudb/create.hpp +117 -0
- data/ext/rudb/NuDB/include/nudb/detail/arena.hpp +296 -0
- data/ext/rudb/NuDB/include/nudb/detail/bucket.hpp +473 -0
- data/ext/rudb/NuDB/include/nudb/detail/buffer.hpp +86 -0
- data/ext/rudb/NuDB/include/nudb/detail/bulkio.hpp +196 -0
- data/ext/rudb/NuDB/include/nudb/detail/cache.hpp +236 -0
- data/ext/rudb/NuDB/include/nudb/detail/endian.hpp +93 -0
- data/ext/rudb/NuDB/include/nudb/detail/field.hpp +265 -0
- data/ext/rudb/NuDB/include/nudb/detail/format.hpp +630 -0
- data/ext/rudb/NuDB/include/nudb/detail/gentex.hpp +259 -0
- data/ext/rudb/NuDB/include/nudb/detail/mutex.hpp +26 -0
- data/ext/rudb/NuDB/include/nudb/detail/pool.hpp +243 -0
- data/ext/rudb/NuDB/include/nudb/detail/store_base.hpp +45 -0
- data/ext/rudb/NuDB/include/nudb/detail/stream.hpp +149 -0
- data/ext/rudb/NuDB/include/nudb/detail/xxhash.hpp +328 -0
- data/ext/rudb/NuDB/include/nudb/error.hpp +257 -0
- data/ext/rudb/NuDB/include/nudb/file.hpp +55 -0
- data/ext/rudb/NuDB/include/nudb/impl/basic_store.ipp +785 -0
- data/ext/rudb/NuDB/include/nudb/impl/context.ipp +241 -0
- data/ext/rudb/NuDB/include/nudb/impl/create.ipp +163 -0
- data/ext/rudb/NuDB/include/nudb/impl/error.ipp +175 -0
- data/ext/rudb/NuDB/include/nudb/impl/posix_file.ipp +248 -0
- data/ext/rudb/NuDB/include/nudb/impl/recover.ipp +209 -0
- data/ext/rudb/NuDB/include/nudb/impl/rekey.ipp +248 -0
- data/ext/rudb/NuDB/include/nudb/impl/verify.ipp +634 -0
- data/ext/rudb/NuDB/include/nudb/impl/visit.ipp +96 -0
- data/ext/rudb/NuDB/include/nudb/impl/win32_file.ipp +264 -0
- data/ext/rudb/NuDB/include/nudb/native_file.hpp +76 -0
- data/ext/rudb/NuDB/include/nudb/nudb.hpp +27 -0
- data/ext/rudb/NuDB/include/nudb/posix_file.hpp +228 -0
- data/ext/rudb/NuDB/include/nudb/progress.hpp +32 -0
- data/ext/rudb/NuDB/include/nudb/recover.hpp +73 -0
- data/ext/rudb/NuDB/include/nudb/rekey.hpp +110 -0
- data/ext/rudb/NuDB/include/nudb/store.hpp +27 -0
- data/ext/rudb/NuDB/include/nudb/type_traits.hpp +63 -0
- data/ext/rudb/NuDB/include/nudb/verify.hpp +200 -0
- data/ext/rudb/NuDB/include/nudb/version.hpp +21 -0
- data/ext/rudb/NuDB/include/nudb/visit.hpp +63 -0
- data/ext/rudb/NuDB/include/nudb/win32_file.hpp +246 -0
- data/ext/rudb/NuDB/include/nudb/xxhasher.hpp +45 -0
- data/ext/rudb/extconf.rb +12 -0
- data/ext/rudb/rudb.cpp +234 -0
- data/lib/rudb/version.rb +3 -0
- data/lib/rudb.rb +1 -0
- metadata +104 -0
@@ -0,0 +1,451 @@
|
|
1
|
+
//
|
2
|
+
// Copyright (c) 2015-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
3
|
+
//
|
4
|
+
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
5
|
+
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
6
|
+
//
|
7
|
+
|
8
|
+
#ifndef NUDB_TEST_TEST_STORE_HPP
|
9
|
+
#define NUDB_TEST_TEST_STORE_HPP
|
10
|
+
|
11
|
+
#include <nudb/_experimental/util.hpp>
|
12
|
+
#include <nudb/_experimental/test/temp_dir.hpp>
|
13
|
+
#include <nudb/_experimental/test/xor_shift_engine.hpp>
|
14
|
+
#include <nudb/create.hpp>
|
15
|
+
#include <nudb/native_file.hpp>
|
16
|
+
#include <nudb/store.hpp>
|
17
|
+
#include <nudb/verify.hpp>
|
18
|
+
#include <nudb/xxhasher.hpp>
|
19
|
+
#include <iomanip>
|
20
|
+
#include <iostream>
|
21
|
+
|
22
|
+
namespace nudb {
|
23
|
+
namespace test {
|
24
|
+
|
25
|
+
template<class = void>
|
26
|
+
class Buffer_t
|
27
|
+
{
|
28
|
+
std::size_t size_ = 0;
|
29
|
+
std::size_t capacity_ = 0;
|
30
|
+
std::unique_ptr<std::uint8_t[]> p_;
|
31
|
+
|
32
|
+
public:
|
33
|
+
Buffer_t() = default;
|
34
|
+
|
35
|
+
Buffer_t(Buffer_t&& other);
|
36
|
+
|
37
|
+
Buffer_t(Buffer_t const& other);
|
38
|
+
|
39
|
+
Buffer_t& operator=(Buffer_t&& other);
|
40
|
+
|
41
|
+
Buffer_t& operator=(Buffer_t const& other);
|
42
|
+
|
43
|
+
bool
|
44
|
+
empty() const
|
45
|
+
{
|
46
|
+
return size_ == 0;
|
47
|
+
}
|
48
|
+
|
49
|
+
std::size_t
|
50
|
+
size() const
|
51
|
+
{
|
52
|
+
return size_;
|
53
|
+
}
|
54
|
+
|
55
|
+
std::uint8_t*
|
56
|
+
data()
|
57
|
+
{
|
58
|
+
return p_.get();
|
59
|
+
}
|
60
|
+
|
61
|
+
std::uint8_t const*
|
62
|
+
data() const
|
63
|
+
{
|
64
|
+
return p_.get();
|
65
|
+
}
|
66
|
+
|
67
|
+
void
|
68
|
+
clear();
|
69
|
+
|
70
|
+
void
|
71
|
+
shrink_to_fit();
|
72
|
+
|
73
|
+
std::uint8_t*
|
74
|
+
resize(std::size_t size);
|
75
|
+
|
76
|
+
std::uint8_t*
|
77
|
+
operator()(void const* data, std::size_t size);
|
78
|
+
};
|
79
|
+
|
80
|
+
template<class _>
|
81
|
+
Buffer_t<_>::
|
82
|
+
Buffer_t(Buffer_t&& other)
|
83
|
+
: size_(other.size_)
|
84
|
+
, capacity_(other.capacity_)
|
85
|
+
, p_(std::move(other.p_))
|
86
|
+
{
|
87
|
+
other.size_ = 0;
|
88
|
+
other.capacity_ = 0;
|
89
|
+
}
|
90
|
+
|
91
|
+
template<class _>
|
92
|
+
Buffer_t<_>::
|
93
|
+
Buffer_t(Buffer_t const& other)
|
94
|
+
{
|
95
|
+
if(! other.empty())
|
96
|
+
std::memcpy(resize(other.size()),
|
97
|
+
other.data(), other.size());
|
98
|
+
}
|
99
|
+
|
100
|
+
template<class _>
|
101
|
+
auto
|
102
|
+
Buffer_t<_>::
|
103
|
+
operator=(Buffer_t&& other) ->
|
104
|
+
Buffer_t&
|
105
|
+
{
|
106
|
+
if(&other != this)
|
107
|
+
{
|
108
|
+
size_ = other.size_;
|
109
|
+
capacity_ = other.capacity_;
|
110
|
+
p_ = std::move(other.p_);
|
111
|
+
other.size_ = 0;
|
112
|
+
other.capacity_ = 0;
|
113
|
+
}
|
114
|
+
return *this;
|
115
|
+
}
|
116
|
+
|
117
|
+
template<class _>
|
118
|
+
auto
|
119
|
+
Buffer_t<_>::
|
120
|
+
operator=(Buffer_t const& other) ->
|
121
|
+
Buffer_t&
|
122
|
+
{
|
123
|
+
if(&other != this)
|
124
|
+
{
|
125
|
+
if(other.empty())
|
126
|
+
size_ = 0;
|
127
|
+
else
|
128
|
+
std::memcpy(resize(other.size()),
|
129
|
+
other.data(), other.size());
|
130
|
+
}
|
131
|
+
return *this;
|
132
|
+
}
|
133
|
+
|
134
|
+
template<class _>
|
135
|
+
void
|
136
|
+
Buffer_t<_>::
|
137
|
+
clear()
|
138
|
+
{
|
139
|
+
size_ = 0;
|
140
|
+
capacity_ = 0;
|
141
|
+
p_.reset();
|
142
|
+
}
|
143
|
+
|
144
|
+
template<class _>
|
145
|
+
void
|
146
|
+
Buffer_t<_>::
|
147
|
+
shrink_to_fit()
|
148
|
+
{
|
149
|
+
if(empty() || size_ == capacity_)
|
150
|
+
return;
|
151
|
+
std::unique_ptr<std::uint8_t[]> p{
|
152
|
+
new std::uint8_t[size_]};
|
153
|
+
capacity_ = size_;
|
154
|
+
std::memcpy(p.get(), p_.get(), size_);
|
155
|
+
std::swap(p, p_);
|
156
|
+
}
|
157
|
+
|
158
|
+
template<class _>
|
159
|
+
std::uint8_t*
|
160
|
+
Buffer_t<_>::
|
161
|
+
resize(std::size_t size)
|
162
|
+
{
|
163
|
+
if(capacity_ < size)
|
164
|
+
{
|
165
|
+
p_.reset(new std::uint8_t[size]);
|
166
|
+
capacity_ = size;
|
167
|
+
}
|
168
|
+
size_ = size;
|
169
|
+
return p_.get();
|
170
|
+
}
|
171
|
+
|
172
|
+
template<class _>
|
173
|
+
std::uint8_t*
|
174
|
+
Buffer_t<_>::
|
175
|
+
operator()(void const* data, std::size_t size)
|
176
|
+
{
|
177
|
+
if(data == nullptr || size == 0)
|
178
|
+
return resize(0);
|
179
|
+
return reinterpret_cast<std::uint8_t*>(
|
180
|
+
std::memcpy(resize(size), data, size));
|
181
|
+
}
|
182
|
+
|
183
|
+
using Buffer = Buffer_t<>;
|
184
|
+
|
185
|
+
//------------------------------------------------------------------------------
|
186
|
+
|
187
|
+
/// Describes a test generated key/value pair
|
188
|
+
struct item_type
|
189
|
+
{
|
190
|
+
std::uint8_t* key;
|
191
|
+
std::uint8_t* data;
|
192
|
+
std::size_t size;
|
193
|
+
};
|
194
|
+
|
195
|
+
/// Interface to facilitate tests
|
196
|
+
template<class File>
|
197
|
+
class basic_test_store
|
198
|
+
{
|
199
|
+
using Hasher = xxhasher;
|
200
|
+
|
201
|
+
temp_dir td_;
|
202
|
+
std::uniform_int_distribution<std::size_t> sizef_;
|
203
|
+
std::function<void(error_code&)> createf_;
|
204
|
+
std::function<void(error_code&)> openf_;
|
205
|
+
Buffer buf_;
|
206
|
+
|
207
|
+
public:
|
208
|
+
path_type const dp;
|
209
|
+
path_type const kp;
|
210
|
+
path_type const lp;
|
211
|
+
std::size_t const keySize;
|
212
|
+
std::size_t const blockSize;
|
213
|
+
float const loadFactor;
|
214
|
+
static std::uint64_t constexpr appnum = 1;
|
215
|
+
static std::uint64_t constexpr salt = 42;
|
216
|
+
basic_store<xxhasher, File> db;
|
217
|
+
|
218
|
+
template<class... Args>
|
219
|
+
basic_test_store(std::size_t keySize,
|
220
|
+
std::size_t blockSize, float loadFactor,
|
221
|
+
Args&&... args);
|
222
|
+
|
223
|
+
template<class... Args>
|
224
|
+
basic_test_store(
|
225
|
+
boost::filesystem::path const& temp_dir,
|
226
|
+
std::size_t keySize, std::size_t blockSize, float loadFactor,
|
227
|
+
Args&&... args);
|
228
|
+
|
229
|
+
~basic_test_store();
|
230
|
+
|
231
|
+
item_type
|
232
|
+
operator[](std::uint64_t i);
|
233
|
+
|
234
|
+
void
|
235
|
+
create(error_code& ec);
|
236
|
+
|
237
|
+
void
|
238
|
+
open(error_code& ec);
|
239
|
+
|
240
|
+
void
|
241
|
+
close(error_code& ec)
|
242
|
+
{
|
243
|
+
db.close(ec);
|
244
|
+
}
|
245
|
+
|
246
|
+
void
|
247
|
+
erase();
|
248
|
+
|
249
|
+
private:
|
250
|
+
template<class Generator>
|
251
|
+
static
|
252
|
+
void
|
253
|
+
rngfill(
|
254
|
+
void* dest, std::size_t size, Generator& g);
|
255
|
+
};
|
256
|
+
|
257
|
+
template <class File>
|
258
|
+
template <class... Args>
|
259
|
+
basic_test_store<File>::basic_test_store(
|
260
|
+
boost::filesystem::path const& temp_dir,
|
261
|
+
std::size_t keySize_, std::size_t blockSize_,
|
262
|
+
float loadFactor_, Args&&... args)
|
263
|
+
: td_(temp_dir)
|
264
|
+
, sizef_(250, 750)
|
265
|
+
, createf_(
|
266
|
+
[this, args...](error_code& ec)
|
267
|
+
{
|
268
|
+
nudb::create<Hasher, File>(
|
269
|
+
dp, kp, lp, appnum, salt,
|
270
|
+
keySize, blockSize, loadFactor, ec,
|
271
|
+
args...);
|
272
|
+
})
|
273
|
+
, openf_(
|
274
|
+
[this, args...](error_code& ec)
|
275
|
+
{
|
276
|
+
db.open(dp, kp, lp, ec, args...);
|
277
|
+
})
|
278
|
+
, dp(td_.file("nudb.dat"))
|
279
|
+
, kp(td_.file("nudb.key"))
|
280
|
+
, lp(td_.file("nudb.log"))
|
281
|
+
, keySize(keySize_)
|
282
|
+
, blockSize(blockSize_)
|
283
|
+
, loadFactor(loadFactor_)
|
284
|
+
{
|
285
|
+
}
|
286
|
+
|
287
|
+
template <class File>
|
288
|
+
template <class... Args>
|
289
|
+
basic_test_store<File>::basic_test_store(std::size_t keySize_,
|
290
|
+
std::size_t blockSize_, float loadFactor_,
|
291
|
+
Args&&... args)
|
292
|
+
: basic_test_store(boost::filesystem::path{},
|
293
|
+
keySize_,
|
294
|
+
blockSize_,
|
295
|
+
loadFactor_,
|
296
|
+
std::forward<Args>(args)...)
|
297
|
+
{
|
298
|
+
}
|
299
|
+
|
300
|
+
template<class File>
|
301
|
+
basic_test_store<File>::
|
302
|
+
~basic_test_store()
|
303
|
+
{
|
304
|
+
erase();
|
305
|
+
}
|
306
|
+
|
307
|
+
template<class File>
|
308
|
+
auto
|
309
|
+
basic_test_store<File>::
|
310
|
+
operator[](std::uint64_t i) ->
|
311
|
+
item_type
|
312
|
+
{
|
313
|
+
xor_shift_engine g{i + 1};
|
314
|
+
item_type item;
|
315
|
+
item.size = sizef_(g);
|
316
|
+
auto const needed = keySize + item.size;
|
317
|
+
rngfill(buf_.resize(needed), needed, g);
|
318
|
+
// put key last so we can get some unaligned
|
319
|
+
// keys, this increases coverage of xxhash.
|
320
|
+
item.data = buf_.data();
|
321
|
+
item.key = buf_.data() + item.size;
|
322
|
+
return item;
|
323
|
+
}
|
324
|
+
|
325
|
+
template<class File>
|
326
|
+
void
|
327
|
+
basic_test_store<File>::
|
328
|
+
create(error_code& ec)
|
329
|
+
{
|
330
|
+
createf_(ec);
|
331
|
+
}
|
332
|
+
|
333
|
+
template<class File>
|
334
|
+
void
|
335
|
+
basic_test_store<File>::
|
336
|
+
open(error_code& ec)
|
337
|
+
{
|
338
|
+
openf_(ec);
|
339
|
+
if(ec)
|
340
|
+
return;
|
341
|
+
if(db.key_size() != keySize)
|
342
|
+
ec = error::invalid_key_size;
|
343
|
+
else if(db.block_size() != blockSize)
|
344
|
+
ec = error::invalid_block_size;
|
345
|
+
}
|
346
|
+
|
347
|
+
template<class File>
|
348
|
+
void
|
349
|
+
basic_test_store<File>::
|
350
|
+
erase()
|
351
|
+
{
|
352
|
+
erase_file(dp);
|
353
|
+
erase_file(kp);
|
354
|
+
erase_file(lp);
|
355
|
+
}
|
356
|
+
|
357
|
+
template<class File>
|
358
|
+
template<class Generator>
|
359
|
+
void
|
360
|
+
basic_test_store<File>::
|
361
|
+
rngfill(
|
362
|
+
void* dest, std::size_t size, Generator& g)
|
363
|
+
{
|
364
|
+
using result_type =
|
365
|
+
typename Generator::result_type;
|
366
|
+
while(size >= sizeof(result_type))
|
367
|
+
{
|
368
|
+
auto const v = g();
|
369
|
+
std::memcpy(dest, &v, sizeof(v));
|
370
|
+
dest = reinterpret_cast<
|
371
|
+
std::uint8_t*>(dest) + sizeof(v);
|
372
|
+
size -= sizeof(v);
|
373
|
+
}
|
374
|
+
if(size > 0)
|
375
|
+
{
|
376
|
+
auto const v = g();
|
377
|
+
std::memcpy(dest, &v, size);
|
378
|
+
}
|
379
|
+
}
|
380
|
+
|
381
|
+
using test_store = basic_test_store<native_file>;
|
382
|
+
|
383
|
+
//------------------------------------------------------------------------------
|
384
|
+
|
385
|
+
template<class T>
|
386
|
+
static
|
387
|
+
std::string
|
388
|
+
num (T t)
|
389
|
+
{
|
390
|
+
std::string s = std::to_string(t);
|
391
|
+
std::reverse(s.begin(), s.end());
|
392
|
+
std::string s2;
|
393
|
+
s2.reserve(s.size() + (s.size()+2)/3);
|
394
|
+
int n = 0;
|
395
|
+
for (auto c : s)
|
396
|
+
{
|
397
|
+
if (n == 3)
|
398
|
+
{
|
399
|
+
n = 0;
|
400
|
+
s2.insert (s2.begin(), ',');
|
401
|
+
}
|
402
|
+
++n;
|
403
|
+
s2.insert(s2.begin(), c);
|
404
|
+
}
|
405
|
+
return s2;
|
406
|
+
}
|
407
|
+
|
408
|
+
template<class = void>
|
409
|
+
std::ostream&
|
410
|
+
operator<<(std::ostream& os, verify_info const& info)
|
411
|
+
{
|
412
|
+
os <<
|
413
|
+
"avg_fetch: " << std::fixed << std::setprecision(3) << info.avg_fetch << "\n" <<
|
414
|
+
"waste: " << std::fixed << std::setprecision(3) << info.waste * 100 << "%" << "\n" <<
|
415
|
+
"overhead: " << std::fixed << std::setprecision(1) << info.overhead * 100 << "%" << "\n" <<
|
416
|
+
"actual_load: " << std::fixed << std::setprecision(0) << info.actual_load * 100 << "%" << "\n" <<
|
417
|
+
"version: " << num(info.version) << "\n" <<
|
418
|
+
"uid: " << fhex(info.uid) << "\n" <<
|
419
|
+
"appnum: " << info.appnum << "\n" <<
|
420
|
+
"key_size: " << num(info.key_size) << "\n" <<
|
421
|
+
"salt: " << fhex(info.salt) << "\n" <<
|
422
|
+
"pepper: " << fhex(info.pepper) << "\n" <<
|
423
|
+
"block_size: " << num(info.block_size) << "\n" <<
|
424
|
+
"bucket_size: " << num(info.bucket_size) << "\n" <<
|
425
|
+
"load_factor: " << std::fixed << std::setprecision(0) << info.load_factor * 100 << "%" << "\n" <<
|
426
|
+
"capacity: " << num(info.capacity) << "\n" <<
|
427
|
+
"buckets: " << num(info.buckets) << "\n" <<
|
428
|
+
"key_count: " << num(info.key_count) << "\n" <<
|
429
|
+
"value_count: " << num(info.value_count) << "\n" <<
|
430
|
+
"value_bytes: " << num(info.value_bytes) << "\n" <<
|
431
|
+
"spill_count: " << num(info.spill_count) << "\n" <<
|
432
|
+
"spill_count_tot: " << num(info.spill_count_tot) << "\n" <<
|
433
|
+
"spill_bytes: " << num(info.spill_bytes) << "\n" <<
|
434
|
+
"spill_bytes_tot: " << num(info.spill_bytes_tot) << "\n" <<
|
435
|
+
"key_file_size: " << num(info.key_file_size) << "\n" <<
|
436
|
+
"dat_file_size: " << num(info.dat_file_size) << std::endl;
|
437
|
+
|
438
|
+
std::string s;
|
439
|
+
for (size_t i = 0; i < info.hist.size(); ++i)
|
440
|
+
s += (i==0) ?
|
441
|
+
std::to_string(info.hist[i]) :
|
442
|
+
(", " + std::to_string(info.hist[i]));
|
443
|
+
os << "hist: " << s << std::endl;
|
444
|
+
return os;
|
445
|
+
}
|
446
|
+
|
447
|
+
} // test
|
448
|
+
} // nudb
|
449
|
+
|
450
|
+
#endif
|
451
|
+
|
@@ -0,0 +1,105 @@
|
|
1
|
+
//
|
2
|
+
// Copyright (c) 2015-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
3
|
+
//
|
4
|
+
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
5
|
+
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
6
|
+
//
|
7
|
+
|
8
|
+
#ifndef NUDB_TEST_XOR_SHIFT_ENGINE_HPP
|
9
|
+
#define NUDB_TEST_XOR_SHIFT_ENGINE_HPP
|
10
|
+
|
11
|
+
#include <cstdint>
|
12
|
+
#include <limits>
|
13
|
+
#include <stdexcept>
|
14
|
+
|
15
|
+
namespace nudb {
|
16
|
+
namespace test {
|
17
|
+
|
18
|
+
/** XOR-shift Generator.
|
19
|
+
|
20
|
+
Meets the requirements of UniformRandomNumberGenerator.
|
21
|
+
|
22
|
+
Simple and fast RNG based on:
|
23
|
+
http://xorshift.di.unimi.it/xorshift128plus.c
|
24
|
+
does not accept seed==0
|
25
|
+
*/
|
26
|
+
class xor_shift_engine
|
27
|
+
{
|
28
|
+
public:
|
29
|
+
using result_type = std::uint64_t;
|
30
|
+
|
31
|
+
xor_shift_engine(xor_shift_engine const&) = default;
|
32
|
+
xor_shift_engine& operator=(xor_shift_engine const&) = default;
|
33
|
+
|
34
|
+
explicit
|
35
|
+
xor_shift_engine(result_type val = 1977u)
|
36
|
+
{
|
37
|
+
seed(val);
|
38
|
+
}
|
39
|
+
|
40
|
+
void
|
41
|
+
seed(result_type seed);
|
42
|
+
|
43
|
+
result_type
|
44
|
+
operator()();
|
45
|
+
|
46
|
+
static
|
47
|
+
result_type constexpr
|
48
|
+
min()
|
49
|
+
{
|
50
|
+
return std::numeric_limits<result_type>::min();
|
51
|
+
}
|
52
|
+
|
53
|
+
static
|
54
|
+
result_type constexpr
|
55
|
+
max()
|
56
|
+
{
|
57
|
+
return std::numeric_limits<result_type>::max();
|
58
|
+
}
|
59
|
+
|
60
|
+
private:
|
61
|
+
result_type s_[2];
|
62
|
+
|
63
|
+
static
|
64
|
+
result_type
|
65
|
+
murmurhash3(result_type x);
|
66
|
+
};
|
67
|
+
|
68
|
+
inline
|
69
|
+
void
|
70
|
+
xor_shift_engine::seed(result_type seed)
|
71
|
+
{
|
72
|
+
if(seed == 0)
|
73
|
+
throw std::domain_error("invalid seed");
|
74
|
+
s_[0] = murmurhash3(seed);
|
75
|
+
s_[1] = murmurhash3(s_[0]);
|
76
|
+
}
|
77
|
+
|
78
|
+
inline
|
79
|
+
auto
|
80
|
+
xor_shift_engine::operator()() ->
|
81
|
+
result_type
|
82
|
+
{
|
83
|
+
result_type s1 = s_[0];
|
84
|
+
result_type const s0 = s_[1];
|
85
|
+
s_[0] = s0;
|
86
|
+
s1 ^= s1<< 23;
|
87
|
+
return(s_[1] =(s1 ^ s0 ^(s1 >> 17) ^(s0 >> 26))) + s0;
|
88
|
+
}
|
89
|
+
|
90
|
+
inline
|
91
|
+
auto
|
92
|
+
xor_shift_engine::murmurhash3(result_type x)
|
93
|
+
-> result_type
|
94
|
+
{
|
95
|
+
x ^= x >> 33;
|
96
|
+
x *= 0xff51afd7ed558ccdULL;
|
97
|
+
x ^= x >> 33;
|
98
|
+
x *= 0xc4ceb9fe1a85ec53ULL;
|
99
|
+
return x ^= x >> 33;
|
100
|
+
}
|
101
|
+
|
102
|
+
} // test
|
103
|
+
} // nudb
|
104
|
+
|
105
|
+
#endif
|