1 #!/usr/bin/env rdmd-unittest-module
2 
3 /** Codecs.
4     Copyright: Per Nordlöw 2018-.
5     License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0).
6     Authors: $(WEB Per Nordlöw)
7 */
8 module nxt.codec;
9 
10 import std.typecons : Tuple;
11 import std.range.primitives : front, isInputRange, ElementType;
12 import std.array : array;
13 import nxt.algorithm_ex : forwardDifference;
14 
15 /** Packing of $(D r) using a `forwardDifference`.
16     Used to pack elements of type ptrdiff, times, etc.
17  */
18 struct ForwardDifferenceCode(R) if (isInputRange!R)
19 {
20     this(R r)
21     {
22         _front = r.front;
23         _diff = r.forwardDifference.array; // TODO Can we make msgpack pack r.forwardDifference without .array
24     }
25 private:
26     typeof(R.init.front) _front; // First element
27     typeof(R.init.forwardDifference.array) _diff; // The Difference
28 }
29 
30 /** Instantiator for $(D ForwardDifferenceCode).
31  */
32 auto encodeForwardDifference(R)(R r) if (isInputRange!R)
33 {
34     return ForwardDifferenceCode!R(r); // TODO Use named parts?
35 }
36 
37 // version = use_msgpack;
38 
39 unittest
40 {
41     import std.range: dropOne;
42     import core.exception: AssertError;
43     import std.exception: assertThrown;
44     version(use_msgpack) import msgpack;
45 
46     assertThrown!AssertError([1].dropOne.encodeForwardDifference_alt);
47 
48     auto x = [1, int.min, 22, 0, int.max, -1100];
49 
50     auto fdp = x.encodeForwardDifference;
51 
52     version(use_msgpack)
53     {
54         alias FDP = typeof(fdp);
55 
56         auto raw = fdp.pack;
57         auto raw2 = raw.dup;
58 
59         FDP fdp_;                   // restored
60         aw.unpack(fdp_);           // restore it
61         assert(fdp == fdp_);
62 
63         auto fdp__ = raw2.unpack!FDP; // restore it (alternatively)
64         assert(fdp == fdp__);
65     }
66 }
67 
68 /** Alternative. */
69 auto encodeForwardDifference_alt(R)(R r) if (isInputRange!R)
70 {
71     import std.typecons: tuple;
72     return tuple(r.front, r.forwardDifference);
73 }
74 /** Alternative. */
75 auto decodeForwardDifference_alt(E, R)(Tuple!(E, R) x)
76 if (isInputRange!R &&
77         is(ElementType!R == typeof(E - E)))
78 {
79     /* TODO Extract as ForwardSum */
80     auto diffs = x[1]; // differences
81     immutable n = diffs.array.length;
82     auto y = new E[1 + n]; // TODO Remove array and keep extra length argument in forwardDifference
83     y[0] = x[0];
84     auto a = diffs.array;
85     foreach (ix; 0..n) {
86         y[ix + 1] = y[ix] + a[ix];
87     }
88     return y;
89 }
90 
91 unittest
92 {
93     auto x = [1, int.min, 22, 0, int.max, -1100];
94     // in memory pack and unpack
95     auto pfd = x.encodeForwardDifference_alt;
96     assert(x == pfd.decodeForwardDifference_alt);
97 }