1 /** Data sampling, typically randomly.
2  *
3  * Test: dmd -version=show -preview=dip1000 -preview=in -vcolumns -d -I.. -i -debug -g -checkaction=context -allinst -unittest -main -run sampling.d
4  */
5 module nxt.sampling;
6 
7 alias Offset = size_t;
8 alias Length = size_t;
9 
10 /** Span.
11  * TODO: Relate|Unite with `nxt.limits.Limits`.
12  */
13 struct Span {
14 	Offset offset = 0;
15 	Length length = 1;
16 }
17 
18 @safe pure nothrow @nogc unittest {
19 	Span x;
20 	assert(x == Span.init);
21 }
22 
23 /++ Format (flags) of sampling. +/
24 struct Format {
25 	/// Array length span.
26 	Span arrayLengthSpan = Span(0,3);
27 	/++ Field recursion depth span for recursive aggregate type with unbounded
28 		depth like `std.json.JSONValue`. +/
29 	Span fieldDepth = Span(Length.min, 3);
30 }
31 
32 import std.random : Random;
33 
34 /++ Returns: A random sample of the type `T`.
35     TODO: Use direct field setting for T only when __traits(isPOD, T) is true
36           otherwise use __traits(getOverloads, T, "__ctor").
37 	Test on `std.json.JSONValue`.
38  +/
39 auto sample(T)(ref Random rnd, in Format fmt = Format.init) {
40 	static if (is(T == U[], U)) { // isArray
41 		import std.random : uniform;
42 		T t;
43 		t.length = uniform(fmt.arrayLengthSpan.offset, fmt.arrayLengthSpan.length, rnd);
44 		foreach (ref e; t)
45 			e = rnd.sample!(U);
46 		return t;
47 	} else static if (is(T == struct)) {
48 		import std.traits : FieldNameTuple;
49 		T t; /+ TODO: = void +/
50 		foreach (mn; FieldNameTuple!T)
51 			__traits(getMember, t, mn) = rnd.sample!(typeof(__traits(getMember, t, mn)))(fmt);
52 		return t;
53 	} else {
54 		import std.random : uniform;
55 		return uniform!(T);
56 	}
57 }
58 
59 /// scalar
60 @safe unittest {
61     auto rnd = Random(42);
62 	auto s = rnd.sample!ubyte;
63 }
64 
65 /// char[]
66 @safe unittest {
67     auto rnd = Random(42);
68 	foreach (_; 0 .. 100) {
69 		auto s = rnd.sample!(char[])(Format(arrayLengthSpan: Span(0,10)));
70 		// dbg(s);
71 	}
72 }
73 
74 /// struct
75 @safe unittest {
76     auto rnd = Random(42);
77 	struct S { byte x, y;}
78 	struct T { short a, b; ushort c, d; S s; }
79 	struct U { int a, b; uint c, d; T t; int[] ia; }
80 	auto s = rnd.sample!U;
81 	// dbg(s);
82 }
83 
84 version (unittest) {
85 	import nxt.debugio;
86 }