1 
2 module markov.binary.decoder;
3 
4 import markov.chain;
5 import markov.counter;
6 import markov.serialize;
7 import markov.state;
8 
9 import std.algorithm;
10 import std.array;
11 import std.bitmanip;
12 import std.conv;
13 import std.range;
14 import std.stdio;
15 import std.traits;
16 
17 struct BinaryDecoder(T)
18 if(isDecodable!(T, ubyte[]))
19 {
20 public:
21     MarkovChain!T decode()(ubyte[] input)
22     {
23         auto range = inputRangeObject(input);
24         return decode(range);
25     }
26 
27     MarkovChain!T decode(Range)(ref Range input)
28     if(isInputRange!Range && is(ElementType!Range : ubyte))
29     {
30         return MarkovChain!(T)(decodeStates(input));
31     }
32 
33     State!T[] decodeStates(Range)(ref Range input)
34     if(isInputRange!Range && is(ElementType!Range : ubyte))
35     {
36         uint count = decodeValue!(uint)(input);
37         return iota(0, count).map!(i => decodeState(input)).array;
38     }
39 
40     State!T decodeState(Range)(ref Range input)
41     if(isInputRange!Range && is(ElementType!Range : ubyte))
42     {
43         State!T state = State!T(decodeValue!(uint)(input));
44         uint length = decodeValue!(uint)(input);
45 
46         foreach(i; 0 .. length)
47         {
48             state.set(
49                 decodeTokens(input),
50                 decodeCounter(input)
51             );
52         }
53 
54         return state;
55     }
56 
57     Counter!T decodeCounter(Range)(ref Range input)
58     if(isInputRange!Range && is(ElementType!Range : ubyte))
59     {
60         Counter!T counter;
61         uint length = decodeValue!(uint)(input);
62 
63         foreach(i; 0 .. length)
64         {
65             counter.set(
66                 decodeToken(input),
67                 decodeValue!(uint)(input)
68             );
69         }
70 
71         return counter;
72     }
73 
74 private:
75     Type decodeValue(Type, Range)(ref Range input)
76     if(isInputRange!Range && is(ElementType!Range : ubyte) && isSomeString!Type)
77     {
78         // TODO : Handle wide strings.
79         uint length = decodeValue!(uint)(input);
80         return input.take(length).map!(b => b.to!char).array.idup;
81     }
82 
83     Type decodeValue(Type, Range)(ref Range input)
84     if(isInputRange!Range && is(ElementType!Range : ubyte) && isArray!Type && !isSomeString!Type)
85     {
86         uint length = decodeValue!(uint)(input);
87         return iota(0, length).map!(i => decodeValue!(ElementType!Type)(input)).array;
88     }
89 
90     Type decodeValue(Type, Range)(ref Range input)
91     if(isInputRange!Range && is(ElementType!Range : ubyte) && isArray!Type && !isSomeString!Type)
92     {
93         ValueType!Type[KeyType!Type] data;
94         uint length = decodeValue!(uint)(input);
95 
96         foreach(i; 0 .. length)
97         {
98             data[decodeValue!(KeyType!Type)(input)] = decodeValue!(ValueType!Type)(input);
99         }
100 
101         return data;
102     }
103 
104     Type decodeValue(Type, Range)(ref Range input)
105     if(isInputRange!Range && is(ElementType!Range : ubyte) && isNumeric!Type)
106     {
107         ubyte[Type.sizeof] b = input.take(Type.sizeof).array[0 .. Type.sizeof];
108         return b.bigEndianToNative!Type;
109     }
110 
111     Type decodeValue(Type, Range)(ref Range input)
112     if(isInputRange!Range && is(ElementType!Range : ubyte) && isBoolean!Type)
113     {
114         scope(exit) input.popFront;
115         return !!input.front;
116     }
117 
118     T decodeToken(Range)(ref Range input)
119     if(isInputRange!Range && is(ElementType!Range : ubyte))
120     {
121         static if(hasDecodeProperty!(T, ubyte[]))
122         {
123             return T.decode(input.table(T.sizeof));
124         }
125         else
126         {
127             return decodeValue!(T)(input);
128         }
129     }
130 
131     T[] decodeTokens(Range)(ref Range input)
132     if(isInputRange!Range && is(ElementType!Range : ubyte))
133     {
134         uint count = decodeValue!(uint)(input);
135         return iota(0, count).map!(i => decodeToken(input)).array;
136     }
137 }
138 
139 MarkovChain!T decodeBinary(T)(ubyte[] encoded)
140 {
141     BinaryDecoder!T decoder;
142     return decoder.decode(encoded);
143 }
144 
145 MarkovChain!T decodeBinary(T, Range)(ref Range input)
146 if(isInputRange!Range && is(ElementType!Range : ubyte))
147 {
148     BinaryDecoder!T decoder;
149     return decoder.decode(input);
150 }
151 
152 MarkovChain!T decodeBinary(T)(File input)
153 {
154     static struct FileInputRange
155     {
156         ubyte[] _buffer;
157         File _file;
158 
159         this(File file)
160         {
161             _file = file;
162             _buffer = [ 0 ];
163 
164             if(!empty) popFront;
165         }
166 
167         @property
168         bool empty()
169         {
170             return _file.eof || _file.error;
171         }
172 
173         @property
174         ubyte front()
175         {
176             return _buffer.length ? _buffer[0] : 0;
177         }
178 
179         void popFront()
180         {
181             _file.rawRead(_buffer);
182         }
183     }
184 
185     BinaryDecoder!T decoder;
186     auto range = FileInputRange(input);
187 
188     return decoder.decode(range);
189 }