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 	this(R r) {
18 		_front = r.front;
19 		_diff = r.forwardDifference.array; /+ TODO: Can we make msgpack pack r.forwardDifference without .array +/
20 	}
21 private:
22 	typeof(R.init.front) _front; // First element
23 	typeof(R.init.forwardDifference.array) _diff; // The Difference
24 }
25 
26 /** Instantiator for $(D ForwardDifferenceCode).
27  */
28 auto encodeForwardDifference(R)(R r) if (isInputRange!R) {
29 	return ForwardDifferenceCode!R(r); /+ TODO: Use named parts? +/
30 }
31 
32 // version = use_msgpack;
33 
34 unittest {
35 	import std.range: dropOne;
36 	import core.exception: AssertError;
37 	import std.exception: assertThrown;
38 	version (use_msgpack) import msgpack;
39 
40 	assertThrown!AssertError([1].dropOne.encodeForwardDifference_alt);
41 
42 	auto x = [1, int.min, 22, 0, int.max, -1100];
43 
44 	auto fdp = x.encodeForwardDifference;
45 
46 	version (use_msgpack) {
47 		alias FDP = typeof(fdp);
48 
49 		auto raw = fdp.pack;
50 		auto raw2 = raw.dup;
51 
52 		FDP fdp_;				   // restored
53 		aw.unpack(fdp_);		   // restore it
54 		assert(fdp == fdp_);
55 
56 		auto fdp__ = raw2.unpack!FDP; // restore it (alternatively)
57 		assert(fdp == fdp__);
58 	}
59 }
60 
61 /** Alternative. */
62 auto encodeForwardDifference_alt(R)(R r) if (isInputRange!R) {
63 	import std.typecons: tuple;
64 	return tuple(r.front, r.forwardDifference);
65 }
66 /** Alternative. */
67 auto decodeForwardDifference_alt(E, R)(Tuple!(E, R) x)
68 if (isInputRange!R &&
69 		is(ElementType!R == typeof(E - E))) {
70 	/* TODO: Extract as ForwardSum */
71 	auto diffs = x[1]; // differences
72 	immutable n = diffs.array.length;
73 	auto y = new E[1 + n]; /+ TODO: Remove array and keep extra length argument in forwardDifference +/
74 	y[0] = x[0];
75 	auto a = diffs.array;
76 	foreach (ix; 0..n) {
77 		y[ix + 1] = y[ix] + a[ix];
78 	}
79 	return y;
80 }
81 
82 unittest {
83 	auto x = [1, int.min, 22, 0, int.max, -1100];
84 	// in memory pack and unpack
85 	auto pfd = x.encodeForwardDifference_alt;
86 	assert(x == pfd.decodeForwardDifference_alt);
87 }