ALib C++ Library
Library Version: 2402 R1
Documentation generated by doxygen
Loading...
Searching...
No Matches
ac.hpp
Go to the documentation of this file.
1/** ************************************************************************************************
2 * \file
3 * This header file is part of module \alib_bitbuffer of the \aliblong.
4 *
5 * \emoji :copyright: 2013-2024 A-Worx GmbH, Germany.
6 * Published under \ref mainpage_license "Boost Software License".
7 **************************************************************************************************/
8#ifndef HPP_AWORX_ALIB_BITBUFFER_AC_V1
9#define HPP_AWORX_ALIB_BITBUFFER_AC_V1
10
11#if !defined (HPP_AWORX_ALIB_BITBUFFER)
13#endif
14
15ALIB_ASSERT_MODULE(BITBUFFER)
17
18#if !defined (HPP_ALIB_ENUMS_UNDERLYING_INTEGRAL)
20#endif
21#if !defined(HPP_ALIB_ENUMS_BW_IT_CONVERSION)
23#endif
24#if !defined(HPP_ALIB_ENUMS_SERIALIZATION)
26#endif
27
28#if ALIB_TIME && !defined (HPP_ALIB_TIME_TICKS)
29# include "alib/time/ticks.hpp"
30#endif
31
32#if !defined(ALIB_DEBUG_ARRAY_COMPRESSION)
33# define ALIB_DEBUG_ARRAY_COMPRESSION ALIB_DEBUG
34#elif !ALIB_DEBUG && ALIB_DEBUG_ARRAY_COMPRESSION
35# undef ALIB_DEBUG_ARRAY_COMPRESSION
36# define ALIB_DEBUG_ARRAY_COMPRESSION 0
37# pragma message "Symbol ALIB_DEBUG_ARRAY_COMPRESSION set (from outside!) while ALIB_DEBUG is not. The symbol got disabled."
38#endif
39
40namespace alib { namespace bitbuffer {
41
42/**
43 * This sub-namespace of \alib_bitbuffer provides algorithms to compress integral arrays.
44 * Classes \alib{bitbuffer;ac_v1::ArrayCompressor} and \alib{bitbuffer;ac_v1::HuffmanEncoder} implement
45 * some data formats defined on bit-streams, which, in future versions of \alib, may be changed.
46 * With such future changes, theses classes will be published in a next enumerated namespace,
47 * parallel to this one.<br>
48 * This approach will allow software to read existing datasets from files (explicitly using
49 * older versions of the classes by selecting them via the namespace) and convert the data to the
50 * new binary format.
51 *
52 * Type aliases \ref alib::ArrayCompressor, \ref alib::HuffmanEncoder and
53 * \ref alib::HuffmanDecoder will always refer to the latest version.
54 *
55 * \note Currently, there is no other version of the class available.
56 */
57namespace ac_v1 {
58
59
60/**
61 * This class provides several algorithms to compress arrays of integral data and encode them
62 * in \alib{bitbuffer;BitBuffer} objects.
63 * Besides a standard \https{Huffman compression,en.wikipedia.org/wiki/Huffman_coding}, different
64 * simple approaches are "tested" and the best compression algorithm is then chosen.
65 * The general assumption of the approaches (besides the <em>Huffman coding</em>) is that the
66 * data contains "signal data", which is either
67 * - sparsely filled,
68 * - has incremental values, or
69 * - has just values of a certain smaller range.
70 * Also combinations of these attributes are matched. Such data is often found in real-world
71 * applications and may be compressed much better than the generic \e Huffman approach may achieve.
72 */
74{
75 public:
76 static constexpr int QtyAlgorithms= 6; ///< The number of algorithms implemented.
77
78 /**
79 * Helper class that allows access the array data. The design goal for introducing
80 * this class (instead of providing array references in the interface methods) is
81 * to allow a minimum of flexibility in respect to the data provision, while not using
82 * callback functions (or virtual methods) to access each single array element.<p>
83 * The approach implemented here, allows the array value to be a single attribute
84 * residing in an array of structs.
85 * For this, besides a base pointer to the first value and the length of the array,
86 * the distance between two values within the array of structs (or classes) has
87 * to be given.
88 *
89 * By nature, to do this, basic pointer manipulation is needed, which imposes the need
90 * using <c>char*</c> values internally, which are casted back to the source type
91 * with setters/getters.<br>
92 * Consequently, templated constructors are given, which accept array types to
93 * restrict such pointer conversion within the type.
94 *
95 * \note
96 * In the case an application uses a more complex data scheme for storing array
97 * data to be compressed, which are not accessible with this simple mechanism,
98 * such data has to be written into temporary arrays before compression.
99 *
100 * Besides this, this accessor type, provides a transparent inline conversion of
101 * signed integer values to its unsigned counterparts by performing
102 * <em>"zig zag encoding"</em>.
103 *
104 * \tparam TIntegral The integral array type.
105 */
106 template <typename TIntegral>
107 class Array
108 {
109 public:
110 /** The unsigned version of template type \c TIntegral. */
111 using TUI = typename std::make_unsigned<TIntegral>::type;
112
113 private:
114 char* firstVal; ///< Pointer to the first array value
115 size_t distance; ///< The distance in memory between two array values
116 size_t len; ///< The length of the array
117
118 public:
119 TUI min; ///< Maximum value (when zig-zag encoded)
120 TUI max; ///< Maximum value (when zig-zag encoded)
121 TUI maxInc; ///< Maximum increase between two adjacent values.
122 TUI maxDec; ///< Maximum decrease between two adjacent values.
123 TUI minInc; ///< Minimum increase between two adjacent values.
124 TUI minDec; ///< Minimum decrease between two adjacent values.
125
126 #if !defined(ALIB_DOX) && ALIB_DEBUG_ARRAY_COMPRESSION
127 bool dbgIsCheckRead= false;
128 #endif
129
130 public:
131 /**
132 * This constructor may (and must only) be used when the data is stored in simple
133 * arrays, hence when the data is not nested in an array of structs.
134 * @param arrayStart Pointer to the first value of the array.
135 * @param length The length of the array
136 */
137 Array( const TIntegral* arrayStart, size_t length )
138 : len(length)
139 {
140 firstVal= const_cast<char*>(
141 reinterpret_cast<const char*>(arrayStart) );
142 distance= sizeof(TUI);
143
144 // set min > max to indicate that this was not calculated, yet.
145 min= (std::numeric_limits<TUI>::max)();
146 max= (std::numeric_limits<TUI>::min)();
147 }
148
149 /**
150 * This constructor takes the first and the second array value as pointers.
151 * The second is used to "assume" (!) the distance in memory between each value.
152 * \attention If the assumption of such basic memory layout is wrong,
153 * array values have to be copied to a temporary memory that satisfies
154 * this rule.
155 * @param firstValue Pointer to the first value of the array.
156 * @param secondValue Pointer to the second value of the array
157 * @param length The length of the array
158 */
159 Array( const TIntegral& firstValue, const TIntegral& secondValue, size_t length )
160 : len(length)
161 {
162 firstVal= const_cast<char*>(
163 reinterpret_cast<const char*>(&firstValue) );
164 distance= size_t( reinterpret_cast<const char*>(&secondValue)
165 - reinterpret_cast<const char*>(&firstValue)) ;
166
167 // set min > max to indicate that this was not calculated, yet.
168 min= (std::numeric_limits<TUI>::max)();
169 max= (std::numeric_limits<TUI>::min)();
170 }
171
172 public:
173 /**
174 * Returns the constant array length, given on construction.
175 * @return The length of the array to compress/decompress
176 */
178 {
179 return len;
180 }
181
182 /**
183 * Returns the value at the given index as an unsigned integer value (for arrays of
184 * signed values, zig-zag encoding is performed)
185 * @param idx The index of the value in the array to retrieve.
186 * @return An unsigned representation of the value at the given \p index.
187 */
188 ALIB_FORCE_INLINE TUI get(size_t idx) const
189 {
190 ALIB_ASSERT_ERROR( idx < len, "BITBUFFER/AC", "Array compression: Index out of bounds" )
191
193 if constexpr ( std::is_unsigned<TIntegral>::value )
194 return *(reinterpret_cast<TUI*>(firstVal + idx * distance));
195 else
196 {
197 TIntegral val= *(reinterpret_cast<TIntegral*>(firstVal + idx * distance));
198 return val >= 0 ? TUI( val << 1 )
199 : TUI( ((-val - 1) << 1) | 1 );
200 }
202 }
203
204 /**
205 * Writes the given value at the given idx as an unsigned integer value (for arrays
206 * of signed values, zig-zag encoding is performed)
207 * @param idx The index of the value in the array to set.
208 * @param value The value to set.
209 */
211 void set(size_t idx, TUI value)
212 {
214 #if ALIB_DEBUG_ARRAY_COMPRESSION
215 TUI oldVal= 0;
216 if( dbgIsCheckRead )
217 oldVal= *reinterpret_cast<TUI*>(firstVal + idx * distance );
218 #endif
219
220 ALIB_ASSERT_ERROR( idx < len, "BITBUFFER/AC", "Array compression: Index out of bounds" )
221
222 if constexpr ( std::is_unsigned<TIntegral>::value )
223 *(reinterpret_cast<TIntegral*>(firstVal + idx * distance))= TIntegral(value);
224 else
225 {
226 *(reinterpret_cast<TIntegral*>(firstVal + idx * distance)) =
227 (value & 1) == 0 ? TIntegral( value >> 1)
228 : -( TIntegral( value >> 1) + 1 );
229 }
230
231 #if ALIB_DEBUG_ARRAY_COMPRESSION
232 if( dbgIsCheckRead )
233 ALIB_ASSERT_ERROR( oldVal== *(reinterpret_cast<TUI*>(firstVal + idx * distance )),
234 "BITBUFFER/AC", "Error reading back compressed array data" )
235 #endif
237 }
238
239 /**
240 * Loops over the data and stores minimum and maximum values as well as minimum
241 * and maximum value distances.
242 */
244 {
245 // already done?
246 if( max >= min )
247 return;
248
249 maxInc= 0;
250 maxDec= 0;
251
252 // zero-length array
253 if( !len )
254 {
255 minInc= 0;
256 minDec= 0;
257 return;
258 }
259 maxInc= 0;
260 maxDec= 0;
261 minInc= (std::numeric_limits<TUI>::max)();
262 minDec= (std::numeric_limits<TUI>::max)();
263
264 TUI prevVal= get(0);
265 min= (std::min)( min, prevVal );
266 max= (std::max)( max, prevVal );
267
268 for(size_t i= 1; i < len; ++i)
269 {
270 TUI val= get(i);
271 min= (std::min)( min, val );
272 max= (std::max)( max, val );
273
274 if(val >= prevVal)
275 {
276 minInc= (std::min)( minInc, TUI( val - prevVal) );
277 maxInc= (std::max)( maxInc, TUI( val - prevVal) );
278 }
279 else
280 {
281 minDec= (std::min)( minDec, TUI( prevVal - val) );
282 maxDec= (std::max)( maxDec, TUI( prevVal - val) );
283 }
284
285 prevVal= val;
286 }
287
288 // correct minDec, if no negative distance was found.
289 if( maxDec == 0 )
290 minDec = 0;
291 }
292 }; // internal class Array
293 /**
294 * This enumeration denotes the different algorithms provided for compression.
295 *
296 * \note
297 * With the inclusion of \alib_enums in the \alibdist, this enum is defined to
298 * be \ref alib_enums_arithmetic "bitwise".<p>
299 * \note
300 * With the inclusion of at least one
301 * \ref alib_manual_modules_dependencies "\"ALib Camp\"" in the \alibdist, this
302 * enum is furthermore \ref alib_basecamp_resources_details_data "resourced" and values
303 * are appendable to class \alib{strings;TAString<TChar>;AString} and logable with \alox.
304 */
305 enum class Algorithm
306 {
307 /** No compression method selected. */
308 NONE = 0,
309
310 /** All compression methods selected. */
311 ALL = (1<< QtyAlgorithms) - 1,
312
313 /** Stores the data as integer values, which includes a simple sort of possible
314 * compression as documented with
315 * \alib{bitbuffer;BitWriter::Write<TIntegral>(TIntegral)}. */
316 Uncompressed = 1,
317
318 /** Stores the differences between the minimum and maximum value found. */
319 MinMax = 2,
320
321 /** Writes '1' if next value is equal to previous, '0' plus next value otherwise. */
322 Sparse = 4,
323
324 /** Writes the number of following equal or non equal values. */
325 VerySparse = 8,
326
327 /** Only distances of the values are written. */
328 Incremental = 16,
329
330 /** Huffman encoding (byte based). */
331 Huffman = 32,
332
333 END_OF_ENUM = 64,
334 };
335
336 /**
337 * Statistic struct to collect information about the performance of different array
338 * compression approaches.
339 * \note While other \alib module provide similar information only in debug compilations of
340 * the library, the optional mechanics to collect statistics on array compression
341 * (based on this struct) are likewise included in the release version.
342 */
344 {
345 #if ALIB_TIME
346 /** The overall compression time of each algorithm. */
347 Ticks::Duration writeTimes [QtyAlgorithms] ={};
348
349 /** The overall decompression time of each algorithm. */
350 Ticks::Duration readTimes [QtyAlgorithms] ={};
351
352 /** The number of decompression time of each algorithm. */
354 #endif
355
356 /** A counter for the number of times each algorithm was chosen for compression by
357 * providing the shortest encoding. The values sum up to field #qtyCompressions. */
359
360 /** For each algorithm, the sum of resulting bytes of all compressions performed. */
362
363 /** For each algorithm, the sum of resulting bytes of those compressions where the
364 * corresponding algorithm performed best. The values sum up to the overall
365 * effective compression length. */
367
368 /** For each algorithm, the sum of original bytes of those compressions where the
369 * corresponding algorithm performed best. The values sum up to the overall
370 * uncompressed size given with sumUncompressed.*/
372
373 /** The overall given array data to compress. */
375
376 /** The number of executed compressions. */
378
379
380 /**
381 * Adds another statistic object to this one.
382 * @param other The statistics to add to this one.
383 * @return A reference to this object.
384 */
386 {
387 for( int algoNo= 0; algoNo < QtyAlgorithms ; ++algoNo )
388 {
390 #if ALIB_TIME
391 writeTimes [algoNo]+= other.writeTimes [algoNo];
392 readTimes [algoNo]+= other.readTimes [algoNo];
393 qtyReads [algoNo]+= other.qtyReads [algoNo];
394 #endif
395 qtyWins [algoNo]+= other.qtyWins [algoNo];
396 sumCompressed [algoNo]+= other.sumCompressed [algoNo];
397 sumCompressedWon [algoNo]+= other.sumCompressedWon [algoNo];
398 sumUnCompressedWon[algoNo]+= other.sumUnCompressedWon[algoNo];
400 }
403 return *this;
404 }
405
406
407 #if ALIB_CAMP
408 /**
409 * Writes compression statistics to the given string buffer.
410 * \par Availability
411 * This method is included only if module \alib_basecamp is included in the
412 * \alibdist.
413 *
414 * @param result A string buffer to collect the dump results.
415 * @param headline A headline to integrate into the result table.
416 * @param printTotals Determines if a summary line with summed up values should be
417 * written.
418 */
420 void Print( AString& result, const String& headline, bool printTotals);
421 #endif
422 };
423
424
425 /** Deleted default constructor (this class can not be created) */
426 ArrayCompressor() = delete;
427
428
429// clang 14.0.6 (as of today 221216) falsely reports:
430// "warning: '@tparam' command used in a comment that is not attached to a template declaration
431#if !defined(ALIB_DOX)
433#endif
434 /**
435 * Compresses the given array and writes the data into the given bit writer.
436 * Each algorithm included in parameter \p algorithmsToTry are executed and finally that
437 * one with the best compression result is chosen. Prior to the usage data, some bits that
438 * determine the chosen algorithm are written, to enable method #Decompress
439 * to deserialize the data.
440 *
441 * To gain efficiency, the number of probed algorithms can be narrowed by setting a
442 * corresponding mask in \p algorithmsToTry. However, in many use case scenarios, the
443 * execution time is a less critical design factor than the compression factor reached.
444 * The decompression speed is solely dependent on the algorithm finally chosen, not on
445 * the number of algorithms tested on compression.
446 *
447 * \attention
448 * If only one algorithm is specified in parameter \p algorithmsToTry, then no
449 * meta-information about the algorithm chosen is written. Consequently, when reading
450 * back the data using #Decompress, the same single algorithm has to be provided.
451 *
452 * @tparam TValue The integral type of array data to compress.
453 * @param bitWriter A bit writer to compress the data to.
454 * @param data The array to compress.
455 * @param algorithmsToTry The set of algorithms to be tried on compression for best
456 * efficiency.<br>
457 * Defaults to \ref Algorithm::ALL.
458 * @param statistics Pointer a struct to collect statistics for the efficiency of array
459 * compression related to given user data. If set, methods #Compress and
460 * #Decompress will measure execution performance and compression rates
461 * for each algorithm. With that, a software may collect information about
462 * which algorithm is most efficient for typical datasets found and
463 * a programmer may, based on such heuristics decide to exclude certain
464 * algorithms not efficient in a use case.
465 * @return A pair of value containing the resulting size in bits and the algorithm
466 * chosen.
467 */
468
469 template <typename TValue>
470 static
471 std::pair<size_t, Algorithm> Compress ( BitWriter& bitWriter,
472 Array<TValue>& data,
473 Algorithm algorithmsToTry = Algorithm::ALL,
474 Statistics* statistics = nullptr
475 );
476
477
478 /**
479 * Decompresses an integral array from the given bit reader, which previously was encoded
480 * with methods #Compress.
481 * The integral data type has to be the same as with encoding.
482 * \attention
483 * If compression was performed with specifying only one algorithm in parameter
484 * \p algorithmsToTry, then the same algorithm has to be exclusively set on decompression,
485 * because in this case no meta information about the compression algorithm is stored
486 * in the bit stream.
487 * @tparam TValue The integral type of array data to decompress.
488 * @param bitReader A bit reader to read the data from.
489 * @param data The array to decompress data to.
490 * @param algorithm The algorithm to use for read back. Must only be given, in case
491 * that compression was performed using a single algorithm of choice.
492 * Defaults to \ref Algorithm::ALL.
493 * @param statistics An optional statistics record to store the measured de-compression
494 * time. See method #Compress for more information.
495 */
496 template <typename TValue>
497 static
498 void Decompress( BitReader& bitReader,
499 Array<TValue>& data,
500 Algorithm algorithm = Algorithm::ALL,
501 Statistics* statistics = nullptr);
502
504
505}; // class ArrayCompressor
506
507}}} // namespace [alib::bitbuffer::ac_v1]
508
509#if ALIB_ENUMS && !defined(ALIB_DOX)
513 alib::bitbuffer::ac_v1::ArrayCompressor::Algorithm::END_OF_ENUM )
514#endif
515
516
517#define HPP_ALIB_MONOMEM_DETAIL_ARRAY_COMPRESSION_ALLOW
519#undef HPP_ALIB_MONOMEM_DETAIL_ARRAY_COMPRESSION_ALLOW
520
521
522
523namespace alib { namespace bitbuffer { namespace ac_v1 {
524
525template <typename TValue>
526std::pair<size_t, ArrayCompressor::Algorithm> ArrayCompressor::Compress(
527 BitWriter& bw,
528 Array<TValue>& data,
529 Algorithm algorithmsToTry,
530 Statistics* statistics )
531{
532 ALIB_ASSERT_ERROR( data.length() * bitsof(TValue) < bw.RemainingSize(), "BITBUFFER/AC",
533 "BitBuffer is smaller than uncompressed data."
534 " No buffer overflow checks are performed during compression." )
535 ALIB_ASSERT_WARNING( data.length() * bitsof(TValue) * 2 < bw.RemainingSize(), "BITBUFFER/AC",
536 "BitBuffer remaining size should be twice as large as uncompressed data."
537 " No buffer overflow checks are performed during compression." )
538
539 auto initialBufferState= bw.GetIndex();
540 auto initialBufferFill = bw.Usage();
541 int multipleAlgorithms= CountElements(algorithmsToTry) > 1;
542 ALIB_ASSERT_ERROR(UnderlyingIntegral(algorithmsToTry) != 0, "BITBUFFER/AC", "No algorithms to check given" )
543
544 auto bestAlgo = ArrayCompressor::Algorithm::NONE;
545 auto bestAlgoNo= (std::numeric_limits<int>::max)();
546 auto lastAlgo = ArrayCompressor::Algorithm::NONE;
547 auto leastBits = (std::numeric_limits<size_t>::max)();
548
549 bool isFirstAlgo = true;
550 int algoNo= -1;
552 {
553 algoNo++;
554
555 // included in write (test)?
556 if ( !HasBits(algorithmsToTry, algo ) )
557 continue;
558 if(!isFirstAlgo)
559 {
560 bw.Reset(initialBufferState);
561 }
562 isFirstAlgo= false;
563
564 // write algo number
565 if( multipleAlgorithms )
566 bw.Write<3>( algoNo );
567 #if ALIB_TIME
568 Ticks tm;
569 #endif
571 switch( lastAlgo= algo )
572 {
573 case Algorithm::Uncompressed: writeUncompressed(bw, data); break;
574 case Algorithm::MinMax: writeMinMax (bw, data); break;
575 case Algorithm::Sparse: writeSparse (bw, data); break;
576 case Algorithm::VerySparse: writeVerySparse (bw, data); break;
577 case Algorithm::Incremental: writeIncremental (bw, data); break;
578 case Algorithm::Huffman: writeHuffman (bw, data); break;
579 default: ALIB_ERROR("BITBUFFER/AC", "Internal error: Unknown compression algorithm number read") break;
580 }
582 auto bufferFill= bw.Usage();
583
584 if( statistics )
585 {
587 #if ALIB_TIME
588 statistics->writeTimes [algoNo]+= tm.Age();
589 #endif
590 statistics->sumCompressed[algoNo]+= (bufferFill - initialBufferFill)/8;
592 }
593
594 ALIB_ASSERT_ERROR( bufferFill > initialBufferFill, "BITBUFFER/AC", "Array compression: Nothing written")
595 if( leastBits > bufferFill - initialBufferFill )
596 {
597 leastBits= bufferFill - initialBufferFill;
598 bestAlgo = algo;
599 bestAlgoNo= algoNo;
600 }
601
602 // DEBUG-Test: Read back values right away and check for equal data
603 #if ALIB_DEBUG_ARRAY_COMPRESSION
604 {
605 bw.Flush();
606 BitReader br(bw.GetBuffer(), initialBufferState);
607 if( multipleAlgorithms )
608 {
609 auto readBackAlgo= Algorithm( 1 << br.Read<3>() );
610 ALIB_ASSERT_ERROR( readBackAlgo == algo, "BITBUFFER/AC",
611 "Wrong algorithm id was read back. This must never happen." )
612 }
613
614 data.dbgIsCheckRead= true;
615
617 switch( algo )
618 {
619 case Algorithm::Uncompressed: readUncompressed(br, data ); break;
620 case Algorithm::MinMax: readMinMax (br, data ); break;
621 case Algorithm::Sparse: readSparse (br, data ); break;
622 case Algorithm::VerySparse: readVerySparse (br, data ); break;
623 case Algorithm::Incremental: readIncremental (br, data ); break;
624 case Algorithm::Huffman: readHuffman (br, data ); break;
625 default: ALIB_ERROR("Internal error: Unknown compression algorithm number read") break;
626 }
628
629 data.dbgIsCheckRead= false;
630 }
631 #endif
632
633 if( !multipleAlgorithms )
634 break;
635 } // loop over algorithms
636
637 if( statistics )
638 {
640 statistics->qtyCompressions++;
641 statistics->sumUncompressed+= data.length() * sizeof(TValue);
642 statistics->qtyWins [bestAlgoNo]++;
643 statistics->sumCompressedWon [bestAlgoNo]+= leastBits/8;
644 statistics->sumUnCompressedWon[bestAlgoNo]+= data.length() * sizeof(TValue);
646 }
647
648
649 // write with best algorithm found (if this was not the last one anyhow)
650 if( multipleAlgorithms && (bestAlgo != lastAlgo) )
651 {
652 bw.Reset( initialBufferState );
653 bw.Write<3>( bestAlgoNo );
655 switch( bestAlgo )
656 {
657 case Algorithm::Uncompressed: writeUncompressed(bw, data); break;
658 case Algorithm::MinMax: writeMinMax (bw, data); break;
659 case Algorithm::Sparse: writeSparse (bw, data); break;
660 case Algorithm::VerySparse: writeVerySparse (bw, data); break;
661 case Algorithm::Incremental: writeIncremental (bw, data); break;
662 case Algorithm::Huffman: writeHuffman (bw, data); break;
663 default: ALIB_ERROR("BITBUFFER/AC", "Internal error: Unknown compression algorithm number read") break;
664 }
666 }
667
668 bw.Flush();
669 return std::make_pair( leastBits, bestAlgo );
670}
671
672template <typename TValue>
674 Array<TValue>& data,
675 Algorithm algorithmsToTry,
676 Statistics* statistics )
677{
678 ALIB_ASSERT_ERROR(UnderlyingIntegral(algorithmsToTry) != 0, "BITBUFFER/AC",
679 "No algorithms to check given" )
680 bool multipleAlgorithms= CountElements(algorithmsToTry) > 1;
681
682#if ALIB_TIME
683 Ticks tm;
684#endif
685 auto algo= multipleAlgorithms ? Algorithm( 1 << br.Read<3>() )
686 : algorithmsToTry;
688 switch( algo )
689 {
690 case Algorithm::Uncompressed: readUncompressed(br, data ); break;
691 case Algorithm::MinMax: readMinMax (br, data ); break;
692 case Algorithm::Sparse: readSparse (br, data ); break;
693 case Algorithm::VerySparse: readVerySparse (br, data ); break;
694 case Algorithm::Incremental: readIncremental (br, data ); break;
695 case Algorithm::Huffman: readHuffman (br, data ); break;
696 default: ALIB_ERROR("Internal error: Unknown compression algorithm number read") break;
697 }
699
700 if( statistics )
701 {
703 #if ALIB_TIME
704 auto algoNo= ToSequentialEnumeration( algo );
705 statistics->readTimes[algoNo]+= tm.Age();
706 statistics->qtyReads [algoNo]++;
707 #endif
709 }
710}
711
712
713}}} // namespace [alib::bitbuffer::ac_v1]
714
715#endif // HPP_AWORX_ALIB_BITBUFFER_AC_V1
uinteger RemainingSize() const
BitBufferBase & GetBuffer() const
BitBufferBase::Index GetIndex() const
void Write(TIntegral value)
typename std::make_unsigned< TIntegral >::type TUI
Definition ac.hpp:111
TUI minDec
Minimum decrease between two adjacent values.
Definition ac.hpp:124
TUI minInc
Minimum increase between two adjacent values.
Definition ac.hpp:123
Array(const TIntegral &firstValue, const TIntegral &secondValue, size_t length)
Definition ac.hpp:159
TUI maxInc
Maximum increase between two adjacent values.
Definition ac.hpp:121
TUI maxDec
Maximum decrease between two adjacent values.
Definition ac.hpp:122
ALIB_FORCE_INLINE size_t length() const
Definition ac.hpp:177
size_t distance
The distance in memory between two array values.
Definition ac.hpp:115
size_t len
The length of the array.
Definition ac.hpp:116
ALIB_FORCE_INLINE TUI get(size_t idx) const
Definition ac.hpp:188
char * firstVal
Pointer to the first array value.
Definition ac.hpp:114
Array(const TIntegral *arrayStart, size_t length)
Definition ac.hpp:137
TUI min
Maximum value (when zig-zag encoded)
Definition ac.hpp:119
TUI max
Maximum value (when zig-zag encoded)
Definition ac.hpp:120
ALIB_FORCE_INLINE void set(size_t idx, TUI value)
Definition ac.hpp:211
static std::pair< size_t, Algorithm > Compress(BitWriter &bitWriter, Array< TValue > &data, Algorithm algorithmsToTry=Algorithm::ALL, Statistics *statistics=nullptr)
Definition ac.hpp:526
static void Decompress(BitReader &bitReader, Array< TValue > &data, Algorithm algorithm=Algorithm::ALL, Statistics *statistics=nullptr)
Definition ac.hpp:673
static constexpr int QtyAlgorithms
The number of algorithms implemented.
Definition ac.hpp:76
#define bitsof(type)
Definition bits.hpp:52
#define ALIB_ASSERT_MODULE(modulename)
Definition alib.hpp:190
#define ALIB_ENUMS_MAKE_BITWISE(TEnum)
Definition bitwise.hpp:120
#define ALIB_WARNINGS_RESTORE
Definition alib.hpp:715
#define ALIB_FORCE_INLINE
Definition alib.hpp:549
#define ALIB_ENUMS_ASSIGN_RECORD(TEnum, TRecord)
Definition records.hpp:752
#define ALIB_API
Definition alib.hpp:538
#define ALIB_ENUMS_MAKE_ITERABLE(TEnum, StopElement)
Definition iterable.hpp:114
#define ALIB_ERROR(...)
Definition alib.hpp:980
#define ALIB_WARNINGS_IGNORE_DOCS
Definition alib.hpp:702
#define ALIB_WARNINGS_ALLOW_SPARSE_ENUM_SWITCH
Definition alib.hpp:669
#define ALIB_ASSERT_ERROR(cond,...)
Definition alib.hpp:984
#define ALIB_WARNINGS_ALLOW_UNSAFE_BUFFER_USAGE
Definition alib.hpp:644
#define ALIB_ASSERT_WARNING(cond,...)
Definition alib.hpp:985
void writeHuffman(BitWriter &bw, ArrayCompressor::Array< TI > &data)
Definition acalgos.inl:29
void readSparse(BitReader &br, ArrayCompressor::Array< TI > &data)
Definition acalgos.inl:222
void writeSparse(BitWriter &bw, ArrayCompressor::Array< TI > &data)
Definition acalgos.inl:194
void readUncompressed(BitReader &br, ArrayCompressor::Array< TI > &data)
Definition acalgos.inl:130
void readIncremental(BitReader &br, ArrayCompressor::Array< TI > &data)
Definition acalgos.inl:427
void writeIncremental(BitWriter &bw, ArrayCompressor::Array< TI > &data)
Definition acalgos.inl:374
void readVerySparse(BitReader &br, ArrayCompressor::Array< TI > &data)
Definition acalgos.inl:336
void readMinMax(BitReader &br, ArrayCompressor::Array< TI > &data)
Definition acalgos.inl:171
void writeUncompressed(BitWriter &bw, ArrayCompressor::Array< TI > &data)
Definition acalgos.inl:114
void writeMinMax(BitWriter &bw, ArrayCompressor::Array< TI > &data)
Definition acalgos.inl:144
void writeVerySparse(BitWriter &bw, ArrayCompressor::Array< TI > &data)
Definition acalgos.inl:241
void readHuffman(BitReader &br, ArrayCompressor::Array< TI > &data)
Definition acalgos.inl:81
Definition alib.cpp:57
Ticks::Duration writeTimes[QtyAlgorithms]
Definition ac.hpp:347
Statistics & operator+=(const Statistics &other)
Definition ac.hpp:385
Ticks::Duration readTimes[QtyAlgorithms]
Definition ac.hpp:350
ALIB_API void Print(AString &result, const String &headline, bool printTotals)
Definition ac.cpp:23