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 }