The OpenD Programming Language

1 /++
2 $(SCRIPT inhibitQuickIndex = 1;)
3 Uniform random engines.
4 
5 $(B Sections:)
6         $(LINK2 #Convenience, Convenience)
7 • $(LINK2 #Entropy, Entropy)
8 • $(LINK2 #ThreadLocal, Thread-Local)
9 • $(LINK2 #Traits, Traits)
10 • $(LINK2 #CInterface, C Interface)
11 
12 $(BOOKTABLE
13 
14 $(LEADINGROW <a id="Convenience"></a>Convenience)
15 $(TR
16     $(RROW Random, Default random number _engine))
17     $(RROW rne, Per-thread uniquely-seeded instance of default `Random`. Requires $(LINK2 https://en.wikipedia.org/wiki/Thread-local_storage, TLS).)
18 
19 $(LEADINGROW <a id="Entropy"></a>Entropy)
20 $(TR
21     $(RROW unpredictableSeed, Seed of `size_t` using system entropy. May use `unpredictableSeed!UIntType` for unsigned integers of different sizes.)
22     $(RROW genRandomNonBlocking, Fills a buffer with system entropy, returning number of bytes copied or negative number on error)
23     $(RROW genRandomBlocking, Fills a buffer with system entropy, possibly waiting if the system believes it has insufficient entropy. Returns 0 on success.))
24 
25 $(LEADINGROW <a id="ThreadLocal"></a>Thread-Local (when $(LINK2 https://en.wikipedia.org/wiki/Thread-local_storage, TLS) enabled))
26 $(TR
27     $(TR $(TDNW $(LREF threadLocal)`!(Engine)`) $(TD Per-thread uniquely-seeded instance of any specified `Engine`. Requires $(LINK2 https://en.wikipedia.org/wiki/Thread-local_storage, TLS).))
28     $(TR $(TDNW $(LREF threadLocalPtr)`!(Engine)`) $(TD `@safe` pointer to `threadLocal!Engine`. Always initializes before return. $(I Warning: do not share between threads!)))
29     $(TR $(TDNW $(LREF threadLocalInitialized)`!(Engine)`) $(TD Explicitly manipulate "is seeded" flag for thread-local instance. Not needed by most library users.))
30     $(TR $(TDNW $(LREF setThreadLocalSeed)`!(Engine, A...)`) $(TD Initialize thread-local `Engine` with a known seed rather than a random seed.))
31     )
32 
33 $(LEADINGROW <a id="Traits"></a>Traits)
34 $(TR
35     $(RROW EngineReturnType, Get return type of random number _engine's `opCall()`)
36     $(RROW isRandomEngine, Check if is random number _engine)
37     $(RROW isSaturatedRandomEngine, Check if random number _engine `G` such that `G.max == EngineReturnType!(G).max`)
38     $(RROW preferHighBits, Are the high bits of the _engine's output known to have better statistical properties than the low bits?))
39 
40 $(LEADINGROW <a id="CInterface"></a>C Interface)
41     $(RROW mir_random_engine_ctor, Perform any necessary setup. Automatically called by DRuntime.)
42     $(RROW mir_random_engine_dtor, Release any resources. Automatically called by DRuntime.)
43     $(RROW mir_random_genRandomNonBlocking, External name for $(LREF genRandomNonBlocking))
44     $(RROW mir_random_genRandomBlocking, External name for $(LREF genRandomBlocking))
45 )
46 
47 Copyright: Ilya Yaroshenko 2016-.
48 License:  $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
49 Authors: Ilya Yaroshenko
50 
51 Macros:
52     T2=$(TR $(TDNW $(LREF $1)) $(TD $+))
53     RROW = $(TR $(TDNW $(LREF $1)) $(TD $+))
54 +/
55 module mir.random.engine;
56 
57 version (OSX)
58     version = Darwin;
59 else version (iOS)
60     version = Darwin;
61 else version (TVOS)
62     version = Darwin;
63 else version (WatchOS)
64     version = Darwin;
65 
66 // A secure arc4random implementation that uses some modern algorithm rather
67 // than ARC4 may be used synonymously with non-blocking system entropy.
68 version (CRuntime_Bionic)
69     version = SecureARC4Random; // ChaCha20
70 version (Darwin)
71     version = SecureARC4Random; // AES
72 version (OpenBSD)
73     version = SecureARC4Random; // ChaCha20
74 version (NetBSD)
75     version = SecureARC4Random; // ChaCha20
76 
77 // A legacy arc4random should not be used when cryptographic security
78 // is required but may used for `unpredictableSeed`.
79 version (CRuntime_UClibc)
80     version = LegacyARC4Random; // ARC4
81 version (FreeBSD)
82     version = LegacyARC4Random; // ARC4
83 version (DragonFlyBSD)
84     version = LegacyARC4Random; // ARC4
85 version (BSD)
86     version = LegacyARC4Random; // Unknown implementation
87 
88 version (SecureARC4Random)
89     version = AnyARC4Random;
90 version (LegacyARC4Random)
91     version = AnyARC4Random;
92 
93 version (D_betterC)
94     private enum bool THREAD_LOCAL_STORAGE_AVAILABLE = false;
95 else
96     private enum bool THREAD_LOCAL_STORAGE_AVAILABLE = __traits(compiles, { static size_t x = 0; });
97 
98 import std.traits;
99 
100 import mir.random.engine.mersenne_twister;
101 
102 /++
103 Like `std.traits.ReturnType!T` but it works even if
104 T.opCall is a function template.
105 +/
106 template EngineReturnType(T)
107 {
108     import std.traits : ReturnType;
109     static if (is(ReturnType!T))
110         alias EngineReturnType = ReturnType!T;
111     else
112         alias EngineReturnType = typeof(T.init());
113 }
114 
115 /++
116 Test if T is a random engine.
117 A type should define `enum isRandomEngine = true;` to be a random engine.
118 +/
119 template isRandomEngine(T)
120 {
121     static if (is(typeof(T.isRandomEngine) : bool) && is(typeof(T.init())))
122     {
123         private alias R = typeof(T.init());
124         static if (T.isRandomEngine && isUnsigned!R)
125             enum isRandomEngine = is(typeof({
126                 enum max = T.max;
127                 static assert(is(typeof(T.max) == R));
128                 }));
129         else enum isRandomEngine = false;
130     }
131     else enum isRandomEngine = false;
132 }
133 
134 /++
135 Test if T is a saturated random-bit generator.
136 A random number generator is saturated if `T.max == ReturnType!T.max`.
137 A type should define `enum isRandomEngine = true;` to be a random engine.
138 +/
139 template isSaturatedRandomEngine(T)
140 {
141     static if (isRandomEngine!T)
142         enum isSaturatedRandomEngine = T.max == EngineReturnType!T.max;
143     else
144         enum isSaturatedRandomEngine = false;
145 }
146 
147 /++
148 Are the high bits of the engine's output known to have
149 better statistical properties than the low bits of the
150 output? This property is set by checking the value of
151 an optional enum named `preferHighBits`. If the property
152 is missing it is treated as false.
153 
154 This should be specified as true for:
155 <ul>
156 <li>linear congruential generators with power-of-2 modulus</li>
157 <li>xorshift+ family</li>
158 <li>xorshift* family</li>
159 <li>in principle any generator whose final operation is something like
160 multiplication or addition in which the high bits depend on the low bits
161 but the low bits are unaffected by the high bits.</li>
162 </ul>
163 +/
164 template preferHighBits(G)
165     if (isSaturatedRandomEngine!G)
166 {
167     static if (__traits(compiles, { enum bool e = G.preferHighBits; }))
168         private enum bool preferHighBits = G.preferHighBits;
169     else
170         private enum bool preferHighBits = false;
171 }
172 
173 /*
174  * Marker indicating it's safe to construct from void
175  * (i.e. the constructor doesn't depend on the struct
176  * being in an initially valid state).
177  * Either checks an explicit flag `_isVoidInitOkay`
178  * or tests to make sure that the structure contains
179  * nothing that looks like a pointer or an index into
180  * an array. Also ensures that there is not an elaborate
181  * destructor since it could be called when the struct
182  * is in an invalid state.
183  * Non-public because we don't want to commit to this
184  * design.
185  */
186 package template _isVoidInitOkay(G) if (isRandomEngine!G && is(G == struct))
187 {
188     static if (is(typeof(G._isVoidInitOkay) : bool))
189         enum bool _isVoidInitOkay = G._isVoidInitOkay;
190     else static if (!hasNested!G && !hasElaborateDestructor!G)
191     {
192         import std.meta : allSatisfy;
193         static if (allSatisfy!(isScalarType, FieldTypeTuple!G))
194             //All members are scalars.
195             enum bool _isVoidInitOkay = true;
196         else static if (FieldTypeTuple!(G).length == 1 && isStaticArray!(FieldTypeTuple!(G)[0]))
197             //Only has one member which is a static array of scalars.
198             enum bool _isVoidInitOkay = isScalarType!(typeof(FieldTypeTuple!(G)[0].init[0]));
199         else
200             enum bool _isVoidInitOkay = false;
201     }
202     else
203         enum bool _isVoidInitOkay = false;
204 }
205 @nogc nothrow pure @safe version(mir_random_test)
206 {
207     import mir.random.engine.mersenne_twister: Mt19937, Mt19937_64;
208     //Ensure that this property is set for the Mersenne Twister,
209     //whose internal state is huge enough for this to potentially
210     //matter:
211     static assert(_isVoidInitOkay!Mt19937);
212     static assert(_isVoidInitOkay!Mt19937_64);
213     //Check that the property is set for a moderately-sized PRNG.
214     import mir.random.engine.xorshift: Xorshift1024StarPhi;
215     static assert(_isVoidInitOkay!Xorshift1024StarPhi);
216     //Check that PRNGs not explicitly marked as void-init safe
217     //can be inferred as such if they only have scalar fields.
218     import mir.random.engine.pcg: pcg32, pcg32_oneseq;
219     import mir.random.engine.splitmix: SplitMix64;
220     static assert(_isVoidInitOkay!pcg32);
221     static assert(_isVoidInitOkay!pcg32_oneseq);
222     static assert(_isVoidInitOkay!SplitMix64);
223     //Check that PRNGs not explicitly marked as void-init safe
224     //can be inferred as such if their only field is a static
225     //array of scalars.
226     import mir.random.engine.xorshift: Xorshift128, Xoroshiro128Plus;
227     static assert(_isVoidInitOkay!Xorshift128);
228     static assert(_isVoidInitOkay!Xoroshiro128Plus);
229 }
230 
231 version (D_Ddoc)
232 {
233     /++
234     A "good" seed for initializing random number engines. Initializing
235     with $(D_PARAM unpredictableSeed) makes engines generate different
236     random number sequences every run.
237 
238     Returns:
239     A single unsigned integer seed value, different on each successive call
240     +/
241     pragma(inline, true)
242     @property size_t unpredictableSeed() @trusted nothrow @nogc
243     {
244         return unpredictableSeed!size_t;
245     }
246 }
247 
248 /// ditto
249 pragma(inline, true)
250 @property T unpredictableSeed(T = size_t)() @trusted nothrow @nogc
251     if (isUnsigned!T)
252 {
253     import mir.utility: _expect;
254     T seed = void;
255     version (AnyARC4Random)
256     {
257         // If we just need 32 bits it's faster to call arc4random()
258         // than arc4random_buf(&seed, seed.sizeof).
259         static if (T.sizeof <= uint.sizeof)
260             seed = cast(T) arc4random();
261         else
262             arc4random_buf(&seed, seed.sizeof);
263     }
264     else if (_expect(genRandomNonBlocking(&seed, seed.sizeof) != T.sizeof, false))
265     {
266         // fallback to old time/thread-based implementation in case of errors
267         seed = cast(T) fallbackSeed();
268     }
269     return seed;
270 }
271 
272 // Old name of `unpredictableSeedOf!T`. Undocumented but
273 // defined so existing code using mir.random won't break.
274 deprecated("Use unpredictableSeed!T instead of unpredictableSeedOf!T")
275 public alias unpredictableSeedOf(T) = unpredictableSeed!T;
276 
277 version (mir_random_test) @nogc nothrow @safe unittest
278 {
279     // Check unpredictableSeed syntax works with or without parentheses.
280     auto a = unpredictableSeed;
281     auto b = unpredictableSeed!uint;
282     auto c = unpredictableSeed!ulong;
283     static assert(is(typeof(a) == size_t));
284     static assert(is(typeof(b) == uint));
285     static assert(is(typeof(c) == ulong));
286 
287     auto d = unpredictableSeed();
288     auto f = unpredictableSeed!uint();
289     auto g = unpredictableSeed!ulong();
290     static assert(is(typeof(d) == size_t));
291     static assert(is(typeof(f) == uint));
292     static assert(is(typeof(g) == ulong));
293 }
294 
295 // Is llvm_readcyclecounter supported on this platform?
296 // We need to whitelist platforms where it is known to work because if it
297 // isn't supported it will compile but always return 0.
298 // https://llvm.org/docs/LangRef.html#llvm-readcyclecounter-intrinsic
299 version(LDC)
300 {
301     // The only architectures the documentation says are supported are
302     // x86 and Alpha. x86 uses RDTSC and Alpha uses RPCC.
303     version(X86_64) version = LLVMReadCycleCounter;
304     // Do *not* support 32-bit x86 because some x86 processors don't
305     // support `rdtsc` and because on x86 (but not x86-64) Linux
306     // `prctl` can disable a process's ability to use `rdtsc`.
307     else version(Alpha) version = LLVMReadCycleCounter;
308 }
309 
310 
311 pragma(inline, false)
312 private ulong fallbackSeed()()
313 {
314     // fallback to old time/thread-based implementation in case of errors
315     version(LLVMReadCycleCounter)
316     {
317         import ldc.intrinsics : llvm_readcyclecounter;
318         ulong ticks = llvm_readcyclecounter();
319     }
320     else version(D_InlineAsm_X86_64)
321     {
322         // RDTSC takes around 22 clock cycles.
323         ulong ticks = void;
324         asm @nogc nothrow
325         {
326             rdtsc;
327             shl RDX, 32;
328             xor RDX, RAX;
329             mov ticks, RDX;
330         }
331     }
332     //else version(D_InlineAsm_X86)
333     //{
334     //    // We don't use `rdtsc` with version(D_InlineAsm_X86) because
335     //    // some x86 processors don't support `rdtsc` and because on
336     //    // x86 (but not x86-64) Linux `prctl` can disable a process's
337     //    // ability to use `rdtsc`.
338     //    static assert(0);
339     //}
340     else version(Windows)
341     {
342         import core.sys.windows.winbase : QueryPerformanceCounter;
343         ulong ticks = void;
344         QueryPerformanceCounter(cast(long*)&ticks);
345     }
346     else version(Darwin)
347     {
348         import core.time : mach_absolute_time;
349         ulong ticks = mach_absolute_time();
350     }
351     else version(Posix)
352     {
353         import core.sys.posix.time : clock_gettime, CLOCK_MONOTONIC, timespec;
354         timespec ts = void;
355         const tserr = clock_gettime(CLOCK_MONOTONIC, &ts);
356         // Should never fail. Only allowed arror codes are
357         // EINVAL if the 1st argument is an invalid clock ID and
358         // EFAULT if the 2nd argument is an invalid address.
359         assert(tserr == 0, "Call to clock_gettime failed.");
360         ulong ticks = (cast(ulong) ts.tv_sec << 32) ^ ts.tv_nsec;
361     }
362     version(Posix)
363     {
364         import core.sys.posix.unistd : getpid;
365         import core.sys.posix.pthread : pthread_self;
366         auto pid = cast(uint) getpid;
367         auto tid = cast(uint) pthread_self();
368     }
369     else
370     version(Windows)
371     {
372         import core.sys.windows.winbase : GetCurrentProcessId, GetCurrentThreadId;
373         auto pid = cast(uint) GetCurrentProcessId;
374         auto tid = cast(uint) GetCurrentThreadId;
375     }
376     ulong k = ((cast(ulong)pid << 32) ^ tid) + ticks;
377     k ^= k >> 33;
378     k *= 0xff51afd7ed558ccd;
379     k ^= k >> 33;
380     k *= 0xc4ceb9fe1a85ec53;
381     k ^= k >> 33;
382     return k;
383 }
384 
385 ///
386 @safe version(mir_random_test) unittest
387 {
388     auto rnd = Random(unpredictableSeed);
389     auto n = rnd();
390     static assert(is(typeof(n) == size_t));
391 }
392 
393 /++
394 The "default", "favorite", "suggested" random number generator type on
395 the current platform. It is an alias for one of the
396 generators. You may want to use it if (1) you need to generate some
397 nice random numbers, and (2) you don't care for the minutiae of the
398 method being used.
399 +/
400 static if (is(size_t == uint))
401     alias Random = Mt19937;
402 else
403     alias Random = Mt19937_64;
404 
405 ///
406 version(mir_random_test) unittest
407 {
408     import std.traits;
409     static assert(isSaturatedRandomEngine!Random);
410     static assert(is(EngineReturnType!Random == size_t));
411 }
412 
413 static if (THREAD_LOCAL_STORAGE_AVAILABLE)
414 {
415     /++
416     Thread-local instance of the default $(LREF Random) allocated and seeded independently
417     for each thread. Requires $(LINK2 https://en.wikipedia.org/wiki/Thread-local_storage, TLS).
418     +/
419     alias rne = threadLocal!Random;
420     ///
421     @nogc nothrow @safe version(mir_random_test) unittest
422     {
423         import mir.random;
424         import std.complex;
425 
426         auto c = complex(rne.rand!real, rne.rand!real);
427 
428         int[10] array;
429         foreach (ref e; array)
430             e = rne.rand!int;
431         auto picked = array[rne.randIndex(array.length)];
432     }
433 
434     private static struct TL(Engine)
435         if (isSaturatedRandomEngine!Engine && is(Engine == struct))
436     {
437         static bool initialized;
438         static if (_isVoidInitOkay!Engine)
439             static Engine engine = void;
440         else static if (__traits(compiles, { Engine defaultConstructed; }))
441             static Engine engine;
442         else
443             static Engine engine = Engine.init;
444 
445         static if (is(ucent) && is(typeof((ucent t) => Engine(t))))
446             alias seed_t = ucent;
447         else static if (is(typeof((ulong t) => Engine(t))))
448             alias seed_t = ulong;
449         else static if (is(typeof((uint t) => Engine(t))))
450             alias seed_t = uint;
451         else
452             alias seed_t = EngineReturnType!Engine;
453 
454         pragma(inline, false) // Usually called only once per thread.
455         private static void reseed()
456         {
457             engine.__ctor(unpredictableSeed!(seed_t));
458             initialized = true;
459         }
460     }
461     /++
462     `threadLocal!Engine` returns a reference to a thread-local instance of
463     the specified random number generator allocated and seeded uniquely
464     for each thread. Requires $(LINK2 https://en.wikipedia.org/wiki/Thread-local_storage, TLS).
465 
466     `threadLocalPtr!Engine` is a pointer to the area of thread-local
467     storage used by `threadLocal!Engine`. This function is provided because
468     the compiler can infer it is `@safe`, unlike `&(threadLocal!Engine)`.
469     Like `threadLocal!Engine` this function will auto-initialize the engine.
470     $(I Do not share pointers returned by threadLocalPtr between
471     threads!)
472 
473     `threadLocalInitialized!Engine` is a low-level way to explicitly change
474     the "initialized" flag used by `threadLocal!Engine` to determine whether
475     the Engine needs to be seeded. Setting this to `false` gives a way of
476     forcing the next call to `threadLocal!Engine` to reseed. In general this
477     is unnecessary but there are some specialized use cases where users have
478     requested this ability.
479     +/
480     @property ref Engine threadLocal(Engine)()
481         if (isSaturatedRandomEngine!Engine && is(Engine == struct))
482     {
483         version (DigitalMars)
484             pragma(inline);//DMD may fail to inline this.
485         else
486             pragma(inline, true);
487         import mir.utility: _expect;
488         if (_expect(!TL!Engine.initialized, false))
489         {
490             TL!Engine.reseed();
491         }
492         return TL!Engine.engine;
493     }
494     /// ditto
495     @property Engine* threadLocalPtr(Engine)()
496         if (isSaturatedRandomEngine!Engine && is(Engine == struct))
497     {
498         version (DigitalMars)
499             pragma(inline);//DMD may fail to inline this.
500         else
501             pragma(inline, true);
502         import mir.utility: _expect;
503         if (_expect(!TL!Engine.initialized, false))
504         {
505             TL!Engine.reseed();
506         }
507         return &TL!Engine.engine;
508     }
509     /// ditto
510     @property ref bool threadLocalInitialized(Engine)()
511         if (isSaturatedRandomEngine!Engine && is(Engine == struct))
512     {
513         version (DigitalMars)
514             pragma(inline);//DMD may fail to inline this.
515         else
516             pragma(inline, true);
517         return TL!Engine.initialized;
518     }
519     ///
520     @nogc nothrow @safe version(mir_random_test) unittest
521     {
522         import mir.random;
523         import mir.random.engine.xorshift;
524 
525         alias gen = threadLocal!Xorshift1024StarPhi;
526         double x = gen.rand!double;
527         size_t i = gen.randIndex(100u);
528         ulong a = gen.rand!ulong;
529     }
530     ///
531     @nogc nothrow @safe version(mir_random_test) unittest
532     {
533         import mir.random;
534         //If you need a pointer to the engine, getting it like this is @safe:
535         Random* ptr = threadLocalPtr!Random;
536     }
537     ///
538     @nogc nothrow @safe version(mir_random_test) unittest
539     {
540         import mir.random;
541         import mir.random.engine.xorshift;
542         //If you need to mark the engine as uninitialized to force a reseed,
543         //you can do it like this:
544         threadLocalInitialized!Xorshift1024StarPhi = false;
545     }
546     ///
547     @nogc nothrow @safe version(mir_random_test) unittest
548     {
549         import mir.random;
550         import mir.random.engine.mersenne_twister;
551         //You can mark the engine as already initialized to skip
552         //automatic seeding then initialize it yourself, for instance
553         //if you want to use a known seed rather than a random one.
554         threadLocalInitialized!Mt19937 = true;
555         immutable uint[4] customSeed = [0x123, 0x234, 0x345, 0x456];
556         threadLocal!Mt19937.__ctor(customSeed);
557         foreach(_; 0..999)
558             threadLocal!Mt19937.rand!uint;
559         assert(3460025646u == threadLocal!Mt19937.rand!uint);
560     }
561     ///
562     @nogc nothrow @safe version(mir_random_test) unittest
563     {
564         import mir.random;
565         import mir.random.engine.xorshift;
566 
567         alias gen = threadLocal!Xorshift1024StarPhi;
568 
569         //If you want to you can call the generator's opCall instead of using
570         //rand!T but it is somewhat clunky because of the ambiguity of
571         //@property syntax: () looks like optional function parentheses.
572         static assert(!__traits(compiles, {ulong x0 = gen();}));//<-- Won't work
573         static assert(is(typeof(gen()) == Xorshift1024StarPhi));//<-- because the type is this.
574         ulong x1 = gen.opCall();//<-- This works though.
575         ulong x2 = gen()();//<-- This also works.
576 
577         //But instead of any of those you should really just use gen.rand!T.
578         ulong x3 = gen.rand!ulong;
579     }
580 //    ///
581 //    @nogc nothrow pure @safe version(mir_random_test) unittest
582 //    {
583 //        //If you want something like Phobos std.random.rndGen and
584 //        //don't care about the specific algorithm you can do this:
585 //        alias rndGen = threadLocal!Random;
586 //    }
587 
588     @nogc nothrow @system version(mir_random_test) unittest
589     {
590         //Verify Returns same instance every time per thread.
591         import mir.random;
592         import mir.random.engine.xorshift;
593 
594         Xorshift1024StarPhi* addr = &(threadLocal!Xorshift1024StarPhi());
595         Xorshift1024StarPhi* sameAddr = &(threadLocal!Xorshift1024StarPhi());
596         assert(addr is sameAddr);
597         assert(sameAddr is threadLocalPtr!Xorshift1024StarPhi);
598     }
599 
600     /++
601     Sets or resets the _seed of `threadLocal!Engine` using the given arguments.
602     It is not necessary to call this except if you wish to ensure the
603     PRNG uses a known _seed.
604     +/
605     void setThreadLocalSeed(Engine, A...)(auto ref A seed)
606         if (isSaturatedRandomEngine!Engine && is(Engine == struct)
607             && A.length >= 1 && is(typeof((ref A a) => Engine(a))))
608     {
609         TL!Engine.initialized = true;
610         TL!Engine.engine.__ctor(seed);
611     }
612     ///
613     @nogc nothrow @system version(mir_random_test) unittest
614     {
615         import mir.random;
616 
617         alias rnd = threadLocal!Random;
618 
619         setThreadLocalSeed!Random(123);
620         immutable float x = rnd.rand!float;
621 
622         assert(x != rnd.rand!float);
623 
624         setThreadLocalSeed!Random(123);
625         immutable float y = rnd.rand!float;
626 
627         assert(x == y);
628     }
629 }
630 else
631 {
632     static assert(!THREAD_LOCAL_STORAGE_AVAILABLE);
633 
634     @property ref Random rne()()
635     {
636         static assert(0, "Thread-local storage not available!");
637     }
638 
639     template threadLocal(T)
640     {
641         static assert(0, "Thread-local storage not available!");
642     }
643 
644     template threadLocalPtr(T)
645     {
646         static assert(0, "Thread-local storage not available!");
647     }
648 
649     template threadLocalInitialized(T)
650     {
651         static assert(0, "Thread-local storage not available!");
652     }
653 
654     template setThreadLocalSeed(T, A...)
655     {
656         static assert(0, "Thread-local storage not available!");
657     }
658 }
659 
660 version(linux)
661 {
662     import mir.linux._asm.unistd;
663     enum bool LINUX_NR_GETRANDOM = (__traits(compiles, {enum e = NR_getrandom;}));
664     //If X86_64 or X86 are missing there is a problem with the library.
665     static if (!LINUX_NR_GETRANDOM)
666     {
667         version (X86_64)
668             static assert(0, "Missing linux syscall constants!");
669         version (X86)
670             static assert(0, "Missing linux syscall constants!");
671     }
672 }
673 else
674     enum bool LINUX_NR_GETRANDOM = false;
675 
676 static if (LINUX_NR_GETRANDOM)
677 {
678     // getrandom was introduced in Linux 3.17
679     private __gshared bool getRandomFailedENOSYS = false;
680 
681     private extern(C) int syscall(size_t ident, size_t n, size_t arg1, size_t arg2) @nogc nothrow;
682 
683     /*
684      * Flags for getrandom(2)
685      *
686      * GRND_NONBLOCK    Don't block and return EAGAIN instead
687      * GRND_RANDOM      Use the /dev/random pool instead of /dev/urandom
688      */
689     private enum GRND_NONBLOCK = 0x0001;
690     private enum GRND_RANDOM = 0x0002;
691 
692     private enum GETRANDOM = NR_getrandom;
693 
694     /*
695         http://man7.org/linux/man-pages/man2/getrandom.2.html
696         If the urandom source has been initialized, reads of up to 256 bytes
697         will always return as many bytes as requested and will not be
698         interrupted by signals.  No such guarantees apply for larger buffer
699         sizes.
700     */
701     private ptrdiff_t genRandomImplSysBlocking()(scope void* ptr, size_t len) @nogc nothrow @system
702     {
703         while (len > 0)
704         {
705             auto res = syscall(GETRANDOM, cast(size_t) ptr, len, 0);
706             if (res >= 0)
707             {
708                 len -= res;
709                 ptr += res;
710             }
711             else
712             {
713                 return res;
714             }
715         }
716         return 0;
717     }
718 
719     /*
720     *   If the GRND_NONBLOCK flag is set, then
721     *   getrandom() does not block in these cases, but instead
722     *   immediately returns -1 with errno set to EAGAIN.
723     */
724     private ptrdiff_t genRandomImplSysNonBlocking()(scope void* ptr, size_t len) @nogc nothrow @system
725     {
726         return syscall(GETRANDOM, cast(size_t) ptr, len, GRND_NONBLOCK);
727     }
728 }
729 
730 version(AnyARC4Random)
731 extern(C) private @nogc nothrow
732 {
733     void arc4random_buf(scope void* buf, size_t nbytes) @system;
734     uint arc4random() @trusted;
735 }
736 
737 version(Darwin)
738 {
739     //On Darwin /dev/random is identical to /dev/urandom (neither blocks
740     //when there is low system entropy) so there is no point mucking
741     //about with file descriptors. Just use arc4random_buf for both.
742 }
743 else version(Posix)
744 {
745     import core.stdc.stdio : fclose, feof, ferror, fopen, fread;
746     alias IOType = typeof(fopen("a", "b"));
747     private __gshared IOType fdRandom;
748     version (SecureARC4Random)
749     {
750         //Don't need /dev/urandom if we have arc4random_buf.
751     }
752     else
753         private __gshared IOType fdURandom;
754 
755 
756     /* The /dev/random device is a legacy interface which dates back to a
757        time where the cryptographic primitives used in the implementation of
758        /dev/urandom were not widely trusted.  It will return random bytes
759        only within the estimated number of bits of fresh noise in the
760        entropy pool, blocking if necessary.  /dev/random is suitable for
761        applications that need high quality randomness, and can afford
762        indeterminate delays.
763 
764        When the entropy pool is empty, reads from /dev/random will block
765        until additional environmental noise is gathered.
766     */
767     private ptrdiff_t genRandomImplFileBlocking()(scope void* ptr, size_t len) @nogc nothrow @system
768     {
769         if (fdRandom is null)
770         {
771             fdRandom = fopen("/dev/random", "r");
772             if (fdRandom is null)
773                 return -1;
774         }
775 
776         while (len > 0)
777         {
778             auto res = fread(ptr, 1, len, fdRandom);
779             len -= res;
780             ptr += res;
781             // check for possible permanent errors
782             if (len != 0)
783             {
784                 if (fdRandom.ferror)
785                     return -1;
786 
787                 if (fdRandom.feof)
788                     return -1;
789             }
790         }
791 
792         return 0;
793     }
794 }
795 
796 version (SecureARC4Random)
797 {
798     //Don't need /dev/urandom if we have arc4random_buf.
799 }
800 else version(Posix)
801 {
802     /**
803        When read, the /dev/urandom device returns random bytes using a
804        pseudorandom number generator seeded from the entropy pool.  Reads
805        from this device do not block (i.e., the CPU is not yielded), but can
806        incur an appreciable delay when requesting large amounts of data.
807        When read during early boot time, /dev/urandom may return data prior
808        to the entropy pool being initialized.
809     */
810     private ptrdiff_t genRandomImplFileNonBlocking()(scope void* ptr, size_t len) @nogc nothrow @system
811     {
812         if (fdURandom is null)
813         {
814             fdURandom = fopen("/dev/urandom", "r");
815             if (fdURandom is null)
816                 return -1;
817         }
818 
819         auto res = fread(ptr, 1, len, fdURandom);
820         // check for possible errors
821         if (res != len)
822         {
823             if (fdURandom.ferror)
824                 return -1;
825 
826             if (fdURandom.feof)
827                 return -1;
828         }
829         return res;
830     }
831 }
832 
833 version(Windows)
834 {
835     // the wincrypt headers in druntime are broken for x64!
836     private alias ULONG_PTR = size_t; // uint in druntime
837     private alias BOOL = bool;
838     private alias DWORD = uint;
839     private alias LPCWSTR = wchar*;
840     private alias PBYTE = ubyte*;
841     private alias HCRYPTPROV = ULONG_PTR;
842     private alias LPCSTR = const(char)*;
843 
844     private extern(Windows) BOOL CryptGenRandom(HCRYPTPROV, DWORD, PBYTE) @nogc @safe nothrow;
845     private extern(Windows) BOOL CryptAcquireContextA(HCRYPTPROV*, LPCSTR, LPCSTR, DWORD, DWORD) @nogc nothrow;
846     private extern(Windows) BOOL CryptAcquireContextW(HCRYPTPROV*, LPCWSTR, LPCWSTR, DWORD, DWORD) @nogc nothrow;
847     private extern(Windows) BOOL CryptReleaseContext(HCRYPTPROV, ULONG_PTR) @nogc nothrow;
848 
849     private __gshared ULONG_PTR hProvider;
850 
851     private auto initGetRandom()() @nogc @trusted nothrow
852     {
853         import core.sys.windows.winbase : GetLastError;
854         import core.sys.windows.winerror : NTE_BAD_KEYSET;
855         import core.sys.windows.wincrypt : PROV_RSA_FULL, CRYPT_NEWKEYSET, CRYPT_VERIFYCONTEXT, CRYPT_SILENT;
856 
857         // https://msdn.microsoft.com/en-us/library/windows/desktop/aa379886(v=vs.85).aspx
858         // For performance reasons, we recommend that you set the pszContainer
859         // parameter to NULL and the dwFlags parameter to CRYPT_VERIFYCONTEXT
860         // in all situations where you do not require a persisted key.
861         // CRYPT_SILENT is intended for use with applications for which the UI cannot be displayed by the CSP.
862         if (!CryptAcquireContextW(&hProvider, null, null, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
863         {
864             if (GetLastError() == NTE_BAD_KEYSET)
865             {
866                 // Attempt to create default container
867                 if (!CryptAcquireContextA(&hProvider, null, null, PROV_RSA_FULL, CRYPT_NEWKEYSET | CRYPT_SILENT))
868                     return 1;
869             }
870             else
871             {
872                 return 1;
873             }
874         }
875 
876         return 0;
877     }
878 }
879 
880 /++
881 Constructs the mir random seed generators.
882 This constructor needs to be called once $(I before)
883 other calls in `mir.random.engine`.
884 
885 Automatically called by DRuntime.
886 +/
887 extern(C) void mir_random_engine_ctor() @system nothrow @nogc
888 {
889     version(Windows)
890     {
891         if (hProvider == 0)
892             initGetRandom;
893     }
894 }
895 
896 /++
897 Destructs the mir random seed generators.
898 
899 Automatically called by DRuntime.
900 +/
901 extern(C) void mir_random_engine_dtor() @system nothrow @nogc
902 {
903     version(Windows)
904     {
905         if (hProvider > 0)
906             CryptReleaseContext(hProvider, 0);
907     }
908     else
909     version(Darwin)
910     {
911 
912     }
913     else
914     version(Posix)
915     {
916         if (fdRandom !is null)
917             fdRandom.fclose;
918 
919         version (SecureARC4Random)
920         {
921             //Don't need /dev/urandom if we have arc4random_buf.
922         }
923         else if (fdURandom !is null)
924             fdURandom.fclose;
925     }
926 }
927 
928 
929 version(D_BetterC)
930 {
931     pragma(crt_constructor)
932     extern(C) void mir_random_engine_ctor_() @system nothrow @nogc
933     {
934         mir_random_engine_ctor();
935     }
936 
937     pragma(crt_destructor)
938     extern(C) void mir_random_engine_dtor_() @system nothrow @nogc
939     {
940         mir_random_engine_dtor();
941     }
942 }
943 else
944 {
945     /// Automatically calls the extern(C) module constructor
946     shared static this()
947     {
948         mir_random_engine_ctor();
949     }
950 
951     /// Automatically calls the extern(C) module destructor
952     shared static ~this()
953     {
954         mir_random_engine_dtor();
955     }
956 }
957 
958 /++
959 Fills a buffer with random data.
960 If not enough entropy has been gathered, it will block.
961 
962 Note that on Mac OS X this method will never block.
963 
964 Params:
965     ptr = pointer to the buffer to fill
966     len = length of the buffer (in bytes)
967 
968 Returns:
969     A non-zero integer if an error occurred.
970 +/
971 extern(C) ptrdiff_t mir_random_genRandomBlocking(scope void* ptr , size_t len) @nogc nothrow @system
972 {
973     version(Windows)
974     {
975         static if (DWORD.max >= size_t.max)
976             while(!CryptGenRandom(hProvider, len, cast(PBYTE) ptr)) {}
977         else
978             while (len != 0)
979             {
980                 import mir.utility : min;
981                 const n = min(DWORD.max, len);
982                 if (CryptGenRandom(hProvider, cast(DWORD) n, cast(PBYTE) ptr))
983                 {
984                     len -= n;
985                 }
986             }
987         return 0;
988     }
989     else version (Darwin)
990     {
991         arc4random_buf(ptr, len);
992         return 0;
993     }
994     else
995     {
996         static if (LINUX_NR_GETRANDOM)
997         if (!getRandomFailedENOSYS) // harmless data race
998         {
999             import core.stdc.errno;
1000             ptrdiff_t result = genRandomImplSysBlocking(ptr, len);
1001             if (result >= 0)
1002                 return result;
1003             if (errno != ENOSYS)
1004                 return result;
1005             getRandomFailedENOSYS = true; // harmless data race
1006         }
1007         return genRandomImplFileBlocking(ptr, len);
1008     }
1009 }
1010 
1011 /// ditto
1012 alias genRandomBlocking = mir_random_genRandomBlocking;
1013 
1014 /// ditto
1015 ptrdiff_t genRandomBlocking()(scope ubyte[] buffer) @nogc nothrow @trusted
1016 {
1017     pragma(inline, true);
1018     return mir_random_genRandomBlocking(buffer.ptr, buffer.length);
1019 }
1020 
1021 ///
1022 @safe nothrow version(mir_random_test) unittest
1023 {
1024     ubyte[] buf = new ubyte[10];
1025     genRandomBlocking(buf);
1026 
1027     int sum;
1028     foreach (b; buf)
1029         sum += b;
1030 
1031     assert(sum > 0, "Only zero points generated");
1032 }
1033 
1034 @nogc nothrow @safe version(mir_random_test) unittest
1035 {
1036     ubyte[10] buf;
1037     genRandomBlocking(buf);
1038 
1039     int sum;
1040     foreach (b; buf)
1041         sum += b;
1042 
1043     assert(sum > 0, "Only zero points generated");
1044 }
1045 
1046 /++
1047 Fills a buffer with random data.
1048 If not enough entropy has been gathered, it won't block.
1049 Hence the error code should be inspected.
1050 
1051 On Linux >= 3.17 genRandomNonBlocking is guaranteed to succeed for 256 bytes and
1052 fewer.
1053 
1054 On Mac OS X, OpenBSD, and NetBSD genRandomNonBlocking is guaranteed to
1055 succeed for any number of bytes.
1056 
1057 Params:
1058     buffer = the buffer to fill
1059     len = length of the buffer (in bytes)
1060 
1061 Returns:
1062     The number of bytes filled - a negative number if an error occurred
1063 +/
1064 extern(C) size_t mir_random_genRandomNonBlocking(scope void* ptr, size_t len) @nogc nothrow @system
1065 {
1066     version(Windows)
1067     {
1068         static if (DWORD.max < size_t.max)
1069             if (len > DWORD.max)
1070                 len = DWORD.max;
1071         if (!CryptGenRandom(hProvider, cast(DWORD) len, cast(PBYTE) ptr))
1072             return -1;
1073         return len;
1074     }
1075     else version(SecureARC4Random)
1076     {
1077         arc4random_buf(ptr, len);
1078         return len;
1079     }
1080     else
1081     {
1082         static if (LINUX_NR_GETRANDOM)
1083         if (!getRandomFailedENOSYS) // harmless data race
1084         {
1085             import core.stdc.errno;
1086             ptrdiff_t result = genRandomImplSysNonBlocking(ptr, len);
1087             if (result >= 0)
1088                 return result;
1089             if (errno != ENOSYS)
1090                 return result;
1091             getRandomFailedENOSYS = true; // harmless data race
1092         }
1093         return genRandomImplFileNonBlocking(ptr, len);
1094     }
1095 }
1096 /// ditto
1097 alias genRandomNonBlocking = mir_random_genRandomNonBlocking;
1098 /// ditto
1099 size_t genRandomNonBlocking()(scope ubyte[] buffer) @nogc nothrow @trusted
1100 {
1101     pragma(inline, true);
1102     return mir_random_genRandomNonBlocking(buffer.ptr, buffer.length);
1103 }
1104 
1105 ///
1106 @safe nothrow version(mir_random_test) unittest
1107 {
1108     ubyte[] buf = new ubyte[10];
1109     genRandomNonBlocking(buf);
1110 
1111     int sum;
1112     foreach (b; buf)
1113         sum += b;
1114 
1115     assert(sum > 0, "Only zero points generated");
1116 }
1117 
1118 @nogc nothrow @safe
1119 version(mir_random_test) unittest
1120 {
1121     ubyte[10] buf;
1122     genRandomNonBlocking(buf);
1123 
1124     int sum;
1125     foreach (b; buf)
1126         sum += b;
1127 
1128     assert(sum > 0, "Only zero points generated");
1129 }