tudocomp
– The TU Dortmund Compression Framework
coders/HuffmanCoder.hpp
Go to the documentation of this file.
1 #pragma once
2 
3 #include <bitset>
4 #include <numeric>
5 
6 #include <tudocomp/Env.hpp>
7 #include <tudocomp/Coder.hpp>
8 #include <tudocomp/util.hpp>
9 #include <tudocomp/Range.hpp>
10 #include <tudocomp/def.hpp>
11 
12 namespace tdc {
13 
15 namespace huff {
16 
22  template<class T>
23  len_compact_t* count_alphabet(const T& input) {
24  typedef typename std::make_unsigned<typename T::value_type>::type value_type;
25  constexpr size_t max_literal = std::numeric_limits<value_type>::max();
26  len_compact_t* C { new len_compact_t[max_literal+1] };
27  std::memset(C, 0, sizeof(len_compact_t)*(max_literal+1));
28 
29  for(const auto& c : input) {
30  DCHECK_LT(static_cast<value_type>(c), max_literal+1);
31  DCHECK_LT(C[static_cast<value_type>(c)], std::numeric_limits<len_compact_t>::max());
32  ++C[static_cast<value_type>(c)];
33  }
34  return C;
35  }
36  template<class T>
37  len_compact_t* count_alphabet_literals(T&& input) {
39  std::memset(C, 0, sizeof(len_compact_t)*(ULITERAL_MAX+1));
40 
41  while(input.has_next()) {
42  uliteral_t c = input.next().c;
43  DCHECK_LT(static_cast<uliteral_t>(c), ULITERAL_MAX+1);
44  DCHECK_LT(C[static_cast<uliteral_t>(c)], std::numeric_limits<len_compact_t>::max());
45  ++C[static_cast<uliteral_t>(c)];
46  }
47  return C;
48  }
52  inline len_t effective_alphabet_size(const len_compact_t* C) {
53  return std::count_if(C, C+ULITERAL_MAX+1, [] (const len_compact_t& i) { return i != 0u; }); // size of the effective alphabet
54  }
55 
62  inline uliteral_t* gen_effective_alphabet(const len_compact_t*const C, const size_t alphabet_size) {
63  uliteral_t* map_from_effective { new uliteral_t[alphabet_size] };
64  size_t j = 0;
65  for(size_t i = 0; i <= ULITERAL_MAX; ++i) {
66  if(C[i] == 0u) continue;
67  DCHECK_LT(j, alphabet_size);
68  map_from_effective[j++] = i;
69  }
70  DCHECK_EQ(j, alphabet_size);
71  for(size_t i = 0; i < alphabet_size; ++i) {
72 // DCHECK_NE(map_from_effective[i],0);
73  DCHECK_LE(map_from_effective[i], ULITERAL_MAX);
74  DCHECK_NE(C[map_from_effective[i]], 0u);
75  }
76  return map_from_effective;
77  }
78 
88  inline uint8_t* gen_codelengths(const len_compact_t*const C, const uliteral_t*const map_from_effective, const size_t alphabet_size) {
89  size_t A[2*alphabet_size];
90  for(size_t i=0; i < alphabet_size; i++) {
91  DVLOG(2) << "Char " << map_from_effective[i] << " : " << size_t(C[map_from_effective[i]]);
92  A[alphabet_size+i] = C[map_from_effective[i]];
93  A[i] = alphabet_size+i;
94  }
95  // build a minHeap of A[0..size)
96  auto comp = [&A] (const size_t a, const size_t b) -> bool { return A[a] > A[b];};
97  std::make_heap(&A[0], &A[alphabet_size], comp);
98  DCHECK_LE(A[A[0]], A[A[1]]);
99  assert_permutation_offset<size_t*>(A,alphabet_size,alphabet_size);
100 
101  DVLOG(2) << "A: "<<arr_to_debug_string(A,2*alphabet_size);
102 
103 
104  size_t h = alphabet_size-1;
105  //builds the Huffman tree
106  while(h > 0) {
107  std::pop_heap(A, A+h+1, comp);
108  const size_t m1 = A[h]; // first element from the heap (already popped)
109  --h;
110 
111  std::pop_heap(A, A+h+1, comp);
112  const size_t m2 = A[h]; //second min count
113  DCHECK_GT(m1,h); DCHECK_GT(m2,h);
114 
115  A[h+1] = A[m1] + A[m2]; // create a new parent node
116  A[h] = h + 1;
117  A[m1] = A[m2] = h + 1; //parent pointer
118  std::push_heap(A, A+h+1, comp);
119  }
120 
121  A[1] = 0;
122  for(size_t i = 2; i < 2*alphabet_size; ++i) {
123  A[i] = A[A[i]]+ 1;
124  }
125  // variant:
126  // for(size_t i = size; i < 2*size; ++i) {
127  // size_t d = 0;
128  // size_t r = i;
129  // while(r > 1) {
130  // ++d;
131  // r = A[r];
132  // }
133  // A[i] = d;
134  // }
135 
136  uint8_t* codelengths { new uint8_t[alphabet_size] };
137  for (size_t i=0; i < alphabet_size; i++) {
138  DCHECK_LE(A[alphabet_size+i], 64); // the latter representation allows only codewords of length at most 64 bits
139  codelengths[i] = A[alphabet_size+i];
140  DVLOG(2) << "Char " << map_from_effective[i] << " : " << codelengths[i];
141  }
142 
143  IF_PARANOID({
144  // invariants
145 
146  // check that more frequent keywords get shorter codelengthss
147  for(size_t i=0; i < alphabet_size; ++i) {
148  for(size_t j=i+1; j < alphabet_size; ++j) {
149  if(codelengths[i] > codelengths[j]) {
150  DCHECK_LE(C[map_from_effective[i]], C[map_from_effective[j]]);
151  }
152  else if(codelengths[i] < codelengths[j]) {
153  DCHECK_GE(C[map_from_effective[i]], C[map_from_effective[j]]);
154  }
155  }}
156  { // check Kraft's equality
157  const size_t& max_el = *std::max_element(A+alphabet_size,A+2*alphabet_size);
158  DCHECK_LT(max_el,63);
159  size_t sum = 0;
160  for (size_t i = 0; i < alphabet_size; ++i)
161  {
162  sum += 2ULL<<(max_el - A[alphabet_size+i]);
163  }
164  DCHECK_EQ(sum, 2ULL<<max_el);
165  }
166  })
167 
168  return codelengths;
169  }
170 
173  inline uliteral_t* gen_numl(const uint8_t*const ordered_codelengths, const size_t alphabet_size, const uint8_t longest) {
174  DCHECK_EQ(longest, *std::max_element(ordered_codelengths, ordered_codelengths+alphabet_size));
175  DCHECK_GT(longest,0);
176 
177  // numl : length l -> #codewords of length l
178  uliteral_t* numl = new uliteral_t[longest];
179  std::memset(numl,0,sizeof(uliteral_t)*longest);
180 
181  for (size_t i = 0; i < alphabet_size; ++i) {
182  DCHECK_LE(ordered_codelengths[i], longest);
183  DCHECK_GT(ordered_codelengths[i], 0);
184  ++numl[ordered_codelengths[i]-1];
185  }
186  return numl;
187  }
188 
192  inline size_t* gen_first_codes(const uliteral_t*const numl, const size_t longest) {
193  size_t* firstcode = new size_t[longest];
194  firstcode[longest-1] = 0;
195  for(size_t i = longest-1; i > 0; --i)
196  firstcode[i-1] = (firstcode[i] + numl[i])/2;
197  return firstcode;
198  }
199 
202  inline size_t* gen_codewords(const uint8_t*const ordered_codelengths, const size_t alphabet_size, const uliteral_t*const numl, const uint8_t longest) {
203  DCHECK_EQ(longest, *std::max_element(ordered_codelengths, ordered_codelengths+alphabet_size));
204  DCHECK_GT(longest,0);
205 
206  //firstcode stores the code of the first character with the specific length. It is then incremented for the later characters of the same length
207  size_t*const firstcode = gen_first_codes(numl, longest);
208 
209  size_t*const codewords = new size_t[alphabet_size];
210  for(size_t i = 0; i < alphabet_size; ++i) {
211  DCHECK_LE(ordered_codelengths[i], longest);
212  DCHECK_GT(ordered_codelengths[i], 0);
213  codewords[i] = firstcode[ordered_codelengths[i]-1]++;
214  DVLOG(2) << "codeword " << i << " : " << std::bitset<64>(codewords[i]) << ", length " << ordered_codelengths[i];
215  }
216  delete [] firstcode;
217  return codewords;
218  }
219 
220  struct huffmantable {
221  const uliteral_t* ordered_map_from_effective;
222  const size_t alphabet_size;
223 
227  const uliteral_t*const numl;
228  const uint8_t longest;
229 
230  ~huffmantable() {
231  if(ordered_map_from_effective != nullptr) delete [] ordered_map_from_effective;
232  if(numl != nullptr) delete [] numl;
233  }
234  };
235 
241  struct extended_huffmantable : public huffmantable {
242  extended_huffmantable(
243  const uliteral_t*const _ordered_map_from_effective,
244  const size_t*const _codewords,
245  const uint8_t*const _ordered_codelengths,
246  const size_t _alphabet_size,
247  const uliteral_t*const _numl,
248  const uint8_t _longest)
249  : huffmantable{_ordered_map_from_effective,_alphabet_size, _numl, _longest},
250  codewords(_codewords),
251  ordered_codelengths(_ordered_codelengths)
252  {}
253  const size_t*const codewords;
254  const uint8_t*const ordered_codelengths;
255  ~extended_huffmantable() {
256  if(codewords != nullptr) delete [] codewords;
257  if(ordered_codelengths != nullptr) delete [] ordered_codelengths;
258  }
259  };
260 
264  inline void huffmantable_encode(tdc::io::BitOStream& os, const huffmantable& table) {
265  os.write_compressed_int(table.longest);
266  for(size_t i = 0; i < table.longest; ++i) {
267  os.write_compressed_int(table.numl[i]);
268  }
269  os.write_compressed_int(table.alphabet_size);
270  for(size_t i = 0; i < table.alphabet_size; ++i) {
271  os.write_int<uliteral_t>(table.ordered_map_from_effective[i]);
272  }
273  }
274 
278  inline huffmantable huffmantable_decode(tdc::io::BitIStream& in) {
279  const uint8_t longest = in.read_compressed_int<uint8_t>();
280  uliteral_t*const numl { new uliteral_t[longest] };
281  for(size_t i = 0; i < longest; ++i) {
282  numl[i] = in.read_compressed_int<uliteral_t>();
283  }
284  const size_t alphabet_size = in.read_compressed_int<size_t>();
285  uint8_t*const ordered_map_from_effective { new uint8_t[alphabet_size] };
286  for(size_t i = 0; i < alphabet_size; ++i) {
287  ordered_map_from_effective[i] = in.read_int<uliteral_t>();
288  }
289  return { ordered_map_from_effective, alphabet_size, numl, longest };
290  }
291 
294  inline uint8_t* gen_ordered_map_to_effective(const uint8_t*const ordered_map_from_effective, const size_t alphabet_size) {
295  uint8_t* map_to_effective = new uint8_t[ULITERAL_MAX];
296  std::memset(map_to_effective, 0xff, sizeof(map_to_effective)*sizeof(uint8_t));
297  for(size_t i = 0; i < alphabet_size; ++i) {
298  map_to_effective[ordered_map_from_effective[i]] = i;
299  }
300  DVLOG(2) << "ordered_map_from_effective : " << arr_to_debug_string(ordered_map_from_effective, alphabet_size);
301  DVLOG(2) << "map_to_effective : " << arr_to_debug_string(map_to_effective, ULITERAL_MAX);
302  return map_to_effective;
303  }
304 
305 
309  inline void huffman_encode(
310  uliteral_t input,
312  const uint8_t*const ordered_codelengths,
313  const uint8_t*const ordered_map_to_effective,
314  const size_t alphabet_size,
315  const size_t*const codewords
316  ) {
317  const size_t char_value = static_cast<uliteral_t>(input);
318  const uint8_t& effective_char = ordered_map_to_effective[char_value];
319  DCHECK_LT(effective_char, alphabet_size);
320  os.write_int(codewords[effective_char], ordered_codelengths[effective_char]);
321  DVLOG(2) << " codeword " << codewords[effective_char] << " length " << int(ordered_codelengths[effective_char]);
322  }
323 
324 
328  inline void huffman_encode(
329  std::istream& input,
331  const size_t input_length,
332  const uint8_t*const ordered_map_from_effective,
333  const uint8_t*const ordered_codelengths,
334  const size_t alphabet_size,
335  const size_t*const codewords
336  ) {
337  DCHECK_GT(input_length, 0);
338 
339  const uint8_t*const ordered_map_to_effective { gen_ordered_map_to_effective(ordered_map_from_effective, alphabet_size) };
340 
341  {//now writing
342  os.write_compressed_int<size_t>(input_length);
343  char c;
344  while(input.get(c)) {
345  huffman_encode(c, os, ordered_codelengths, ordered_map_to_effective, alphabet_size, codewords);
346  }
347  }
348  delete [] ordered_map_to_effective;
349  }
350 
351 
356  inline std::unique_ptr<size_t[]> gen_prefix_sum_lengths(
357  const uint8_t*const ordered_codelengths,
358  const size_t alphabet_size,
359  const uint8_t longest) {
360  auto prefix_sum_lengths = std::make_unique<size_t[]>(longest);
361 #ifndef NDDEBUG
362  std::fill(
363  prefix_sum_lengths.get(),
364  prefix_sum_lengths.get() + longest,
365  std::numeric_limits<size_t>::max()
366  );
367 #endif
368  prefix_sum_lengths[ordered_codelengths[0]-1] = 0;
369  for(size_t i = 1; i < alphabet_size; ++i) {
370  if(ordered_codelengths[i-1] < ordered_codelengths[i])
371  prefix_sum_lengths[ordered_codelengths[i]-1] = i;
372  }
373  DVLOG(2) << "ordered_codelengths : " << arr_to_debug_string(ordered_codelengths, alphabet_size);
374  DVLOG(2) << "prefix_sum_lengths : " << arr_to_debug_string(prefix_sum_lengths.get(), longest);
375  return prefix_sum_lengths;
376  }
377  inline uliteral_t huffman_decode(
379  const uliteral_t*const ordered_map_from_effective,
380  const size_t*const prefix_sum_lengths,
381  const size_t*const firstcodes
382  ) {
383  DCHECK(!is.eof());
384  size_t value = 0;
385  uint8_t length = 0;
386  do {
387  DCHECK(!is.eof());
388  value = (value<<1) + is.read_bit();
389  ++length;
390  } while(value < firstcodes[length-1]);
391  DVLOG(2) << " codeword " << value << " length " << length;
392  --length;
393 // DCHECK_LT(prefix_sum_lengths[length]+ (value - firstcodes[length]), alphabet_size);
394  return ordered_map_from_effective[prefix_sum_lengths[length]+ (value - firstcodes[length]) ];
395 
396 
397  }
398 
399 
400  inline void huffman_decode(
402  std::ostream& output,
403  const uliteral_t*const ordered_map_from_effective,
404  const uint8_t*const ordered_codelengths,
405  const size_t alphabet_size,
406  const uliteral_t*const numl,
407  const uint8_t longest) {
408 
409  std::unique_ptr<size_t const[]> const prefix_sum_lengths { gen_prefix_sum_lengths(ordered_codelengths, alphabet_size, longest) };
410 
411  const size_t text_length = is.read_compressed_int<size_t>();
412  DCHECK_GT(text_length, 0);
413  const size_t*const firstcodes = gen_first_codes(numl, longest);
414  DVLOG(2) << "firstcodes : " << arr_to_debug_string(firstcodes, longest);
415  size_t num_chars_read = 0;
416  while(true) {
417  output << huffman_decode(is, ordered_map_from_effective, prefix_sum_lengths.get(), firstcodes);
418  ++num_chars_read;
419  if(num_chars_read == text_length) break;
420  }
421  delete [] firstcodes;
422  }
423 
426  inline uint8_t* gen_ordered_codelength(const size_t alphabet_size, const uliteral_t*const numl, const size_t longest) {
427  uint8_t* ordered_codelengths { new uint8_t[alphabet_size] };
428  for(size_t i = 0,k=0; i < longest; ++i) {
429  for(size_t j = 0; j < numl[i]; ++j) {
430  DCHECK_LT(k, alphabet_size);
431  ordered_codelengths[k++] = i+1;
432  }
433  }
434  return ordered_codelengths;
435  }
436 
442  inline extended_huffmantable gen_huffmantable(const len_compact_t*const C) {
443  const size_t alphabet_size = effective_alphabet_size(C);
444  DCHECK_GT(alphabet_size,0);
445 
446  // mapFromEffective : rank of an effective alphabet character -> input alphabet (char-range)
447  const uliteral_t*const mapFromEffective = gen_effective_alphabet(C, alphabet_size);
448 
449  const uint8_t*const codelengths = gen_codelengths(C, mapFromEffective, alphabet_size);
450  delete [] C;
451 
452  // codeword_order is a permutation (like suffix array) sorting (code_length, mapFromEffective) by code_length ascendingly (instead of mapFromEffective values)
453  size_t*const codeword_order = new size_t[alphabet_size];
454  std::iota(codeword_order,codeword_order+alphabet_size,0);
455  std::sort(codeword_order,codeword_order+alphabet_size, [&] (const uliteral_t& i, const uliteral_t& j) { return codelengths[i] < codelengths[j]; });
456 
457  const uint8_t longest = *std::max_element(codelengths, codelengths+alphabet_size);
458 
459  // the ordered variants are all sorted by the codelengths, (instead of by character values)
460  uint8_t* ordered_codelengths { new uint8_t[alphabet_size] };
461  uliteral_t*const ordered_map_from_effective { new uliteral_t[alphabet_size] };
462  for(size_t i = 0; i < alphabet_size; ++i) {
463  ordered_codelengths[i] = codelengths[codeword_order[i]];
464  ordered_map_from_effective[i] = mapFromEffective[codeword_order[i]];
465  }
466  delete [] codelengths;
467  delete [] mapFromEffective;
468  delete [] codeword_order;
469 
470  const uliteral_t*const numl = gen_numl(ordered_codelengths, alphabet_size, longest);
471  const size_t*const codewords = gen_codewords(ordered_codelengths, alphabet_size, numl, longest);
472 
473  return { ordered_map_from_effective, codewords, ordered_codelengths, alphabet_size, numl, longest };
474  }
475 
476  inline extended_huffmantable gen_huffmantable(const std::string& text) {
477  const len_compact_t*const C { count_alphabet(text) };
478  return gen_huffmantable(C);
479  }
480 
481  inline void encode(tdc::io::Input& input, tdc::io::Output& output) {
482  tdc::io::BitOStream bit_os{output};
483  View iview = input.as_view();
484  const len_compact_t*const C { count_alphabet(iview) };
485  extended_huffmantable table = gen_huffmantable(C);
486  huffmantable_encode(bit_os, table);
487  io::ViewStream view_stream(iview);
488  auto& is = view_stream.stream();
489  huffman_encode(is, bit_os, iview.size(), table.ordered_map_from_effective, table.ordered_codelengths, table.alphabet_size, table.codewords);
490  }
491 
492  inline void decode(tdc::io::Input& input, tdc::io::Output& output) {
493  tdc::io::BitIStream bit_is{input};
494  huffmantable table = huffmantable_decode(bit_is);
495  const uint8_t*const ordered_codelengths = gen_ordered_codelength(table.alphabet_size, table.numl, table.longest);
496  auto os = output.as_stream();
497  huffman_decode(
498  bit_is,
499  os,
500  table.ordered_map_from_effective,
501  ordered_codelengths,
502  table.alphabet_size,
503  table.numl,
504  table.longest);
505 
506  delete [] ordered_codelengths;
507  }
508 
509 }//ns
511 
512 class HuffmanCoder : public Algorithm {
513 public:
514  inline static Meta meta() {
515  Meta m("coder", "huff", "Canonical Huffman Coder");
516  return m;
517  }
518 
519  HuffmanCoder() = delete;
520 
521  class Encoder : public tdc::Encoder {
522  const huff::extended_huffmantable m_table;
523  const uint8_t*const ordered_map_to_effective;
524  public:
525  template<typename literals_t>
526  inline Encoder(Env&& env, std::shared_ptr<BitOStream> out, literals_t&& literals)
527  : tdc::Encoder(std::move(env), out, literals),
528  m_table{ [&] () {
529  if(tdc_likely(!literals.has_next())) return huff::extended_huffmantable { nullptr, nullptr, nullptr, 0, nullptr, 0 };
530  const len_compact_t*const C = huff::count_alphabet_literals(std::move(literals));
531  const len_t alphabet_size = huff::effective_alphabet_size(C);
532  if(tdc_unlikely(alphabet_size == 1)) {
533  delete [] C;
534  return huff::extended_huffmantable { nullptr, nullptr, nullptr, 1, nullptr, 0 };
535  }
536  return huff::gen_huffmantable(C);
537  }() }
538  , ordered_map_to_effective { m_table.codewords == nullptr ? nullptr : huff::gen_ordered_map_to_effective(m_table.ordered_map_from_effective, m_table.alphabet_size) }
539  {
540  if(tdc_unlikely(m_table.alphabet_size <= 1)) {
541  m_out->write_bit(0);
542  }
543  else {
544  m_out->write_bit(1);
545  huff::huffmantable_encode(*m_out, m_table);
546  }
547  }
548 
550  if(tdc_likely(ordered_map_to_effective != nullptr)) {
551  delete [] ordered_map_to_effective;
552  }
553  }
554 
555  template<typename literals_t>
556  inline Encoder(Env&& env, Output& out, literals_t&& literals)
557  : Encoder(std::move(env), std::make_shared<BitOStream>(out), literals) {
558  }
559 
560  using tdc::Encoder::encode; // default encoding as fallback
561 
562  template<typename value_t>
563  inline void encode(value_t v, const LiteralRange&) {
564  DCHECK_NE(m_table.alphabet_size,0);
565  if(tdc_unlikely(m_table.alphabet_size == 1))
566  m_out->write_int(static_cast<uliteral_t>(v),8*sizeof(uliteral_t));
567  else
568  huff::huffman_encode(v, *m_out, m_table.ordered_codelengths, ordered_map_to_effective, m_table.alphabet_size, m_table.codewords);
569  }
570  };
571 
572  class Decoder : public tdc::Decoder {
573  const uliteral_t* ordered_map_from_effective;
574  std::unique_ptr<size_t const[]> prefix_sum_lengths;
575  const size_t* firstcodes;
576  public:
578  if(tdc_likely(ordered_map_from_effective != nullptr)) {
579  delete [] ordered_map_from_effective;
580  delete [] firstcodes;
581  }
582  }
583 
584  inline Decoder(Env&& env, std::shared_ptr<BitIStream> in)
585  : tdc::Decoder(std::move(env), in) {
586 
587  if(tdc_unlikely(!m_in->read_bit())) {
588  ordered_map_from_effective = nullptr;
589  return;
590  }
591  huff::huffmantable table(huff::huffmantable_decode(*m_in) );
592  ordered_map_from_effective = table.ordered_map_from_effective;
593  table.ordered_map_from_effective = nullptr;
594  const uint8_t*const ordered_codelengths { huff::gen_ordered_codelength(table.alphabet_size, table.numl, table.longest) };
595  prefix_sum_lengths = huff::gen_prefix_sum_lengths(ordered_codelengths, table.alphabet_size, table.longest);
596  delete [] ordered_codelengths;
597  firstcodes = huff::gen_first_codes(table.numl, table.longest);
598  }
599 
600  inline Decoder(Env&& env, Input& in)
601  : Decoder(std::move(env), std::make_shared<BitIStream>(in)) {
602  }
603 
604  using tdc::Decoder::decode; // default decoding as fallback
605 
606  template<typename value_t>
607  inline value_t decode(const LiteralRange&) {
608  if(tdc_unlikely(ordered_map_from_effective == nullptr))
609  return m_in->read_int<uliteral_t>();
610  return huff::huffman_decode(*m_in, ordered_map_from_effective, prefix_sum_lengths.get(), firstcodes);
611  }
612  };
613 };
614 
615 
616 }//ns
617 
T read_compressed_int(size_t b=7)
Reads a compressed integer from the input.
Definition: BitIStream.hpp:175
Contains the text compression and encoding framework.
Definition: namespaces.hpp:11
Represents the range of valid tdc::uliteral_t values.
Definition: Range.hpp:90
Provides meta information about an Algorithm.
Definition: Meta.hpp:34
#define tdc_unlikely(x)
Provides a hint to the compiler that x is expected to resolve to false.
Definition: def.hpp:23
uint8_t uliteral_t
Type to represent signed single literals.
Definition: def.hpp:131
Wrapper for input streams that provides bitwise reading functionality.
Definition: BitIStream.hpp:16
Encoder(Env &&env, std::shared_ptr< BitOStream > out, literals_t &&literals)
value_t decode(const LiteralRange &)
void encode(value_t v, const LiteralRange &)
Encoder(Env &&env, Output &out, literals_t &&literals)
constexpr size_t ULITERAL_MAX
The maximum value of uliteral_t.
Definition: def.hpp:134
OutputStream as_stream() const
Creates a stream that allows for character-wise output.
#define tdc_likely(x)
Provides a hint to the compiler that x is expected to resolve to true.
Definition: def.hpp:20
Wrapper for output streams that provides bitwise writing functionality.
Definition: BitOStream.hpp:17
An abstraction layer for algorithm output.
Definition: Output.hpp:23
uint32_t len_compact_t
Type to represent an bit-compact length value.
Definition: def.hpp:103
fast_t< len_compact_t > len_t
Type to represent an length value.
Definition: def.hpp:114
void write_compressed_int(T v, size_t b=7)
Writes a compressed integer to the input.
Definition: BitOStream.hpp:151
Decoder(Env &&env, std::shared_ptr< BitIStream > in)
std::string arr_to_debug_string(const T *s, size_t length)
Builds the string representation of an array of printable values, sorrounded by square brackets ([ an...
value_t decode(const Range &r)
Decodes an arbitrary-range integer value.
Definition: Coder.hpp:127
Base for data encoders.
Definition: Coder.hpp:14
ByteView View
Definition: View.hpp:25
void write_int(T value, size_t bits=sizeof(T) *CHAR_BIT)
Writes the bit representation of an integer in MSB first order to the output.
Definition: BitOStream.hpp:98
InputView as_view() const
Provides a view on the input that allows for random access.
Definition: Input.hpp:260
bool eof() const
TODO document.
Definition: BitIStream.hpp:191
uint8_t read_bit()
Reads the next single bit from the input.
Definition: BitIStream.hpp:91
#define IF_PARANOID(x)
x is compiled only in debug builds and when the PARANOID macro is defined.
Definition: def.hpp:49
Local environment for a compression/encoding/decompression call.
void encode(value_t v, const Range &r)
Encodes an arbitrary-range integer value.
Definition: Coder.hpp:61
Base for data decoders.
Definition: Coder.hpp:87
Interface for algorithms.
Definition: Algorithm.hpp:15
T read_int(size_t amount=sizeof(T) *CHAR_BIT)
Reads the integer value of the next amount bits in MSB first order.
Definition: BitIStream.hpp:119
An abstraction layer for algorithm input.
Definition: Input.hpp:37