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