Embedded Template Library 1.0
Loading...
Searching...
No Matches
bit_stream.h
Go to the documentation of this file.
1
2
3/******************************************************************************
4The MIT License(MIT)
5Embedded Template Library.
6https://github.com/ETLCPP/etl
7https://www.etlcpp.com
8Copyright(c) 2018 John Wellbelove
9Permission is hereby granted, free of charge, to any person obtaining a copy
10of this software and associated documentation files(the "Software"), to deal
11in the Software without restriction, including without limitation the rights
12to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
13copies of the Software, and to permit persons to whom the Software is
14furnished to do so, subject to the following conditions :
15The above copyright notice and this permission notice shall be included in all
16copies or substantial portions of the Software.
17THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
20AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23SOFTWARE.
24******************************************************************************/
25
26#ifndef ETL_BIT_STREAM_INCLUDED
27#define ETL_BIT_STREAM_INCLUDED
28
29#include "platform.h"
30#include "algorithm.h"
31#include "binary.h"
32#include "delegate.h"
33#include "endianness.h"
34#include "enum_type.h"
35#include "error_handler.h"
36#include "exception.h"
37#include "integral_limits.h"
38#include "iterator.h"
39#include "memory.h"
40#include "nullptr.h"
41#include "optional.h"
42#include "span.h"
43#include "type_traits.h"
44
45#include <limits.h>
46#include <stdint.h>
47
48#include "private/minmax_push.h"
49
50namespace etl
51{
52 //***************************************************************************
57 //***************************************************************************
58 struct bit_order
59 {
65
67 ETL_ENUM_TYPE(lsb_first, "lsb_first")
68 ETL_ENUM_TYPE(msb_first, "msb_first")
69 ETL_END_ENUM_TYPE
70 };
71
72 //***************************************************************************
75 //***************************************************************************
77 {
78 public:
79
80 typedef const unsigned char* const_iterator;
81
82 //***************************************************************************
84 //***************************************************************************
86 : pdata(ETL_NULLPTR)
87 , length_chars(0U)
88 {
89 restart();
90 }
91
92 //***************************************************************************
94 //***************************************************************************
95 bit_stream(void* begin_, void* end_)
96 : pdata(reinterpret_cast<unsigned char*>(begin_))
97 , length_chars(static_cast<size_t>(etl::distance(reinterpret_cast<unsigned char*>(begin_), reinterpret_cast<unsigned char*>(end_))))
98 {
99 restart();
100 }
101
102 //***************************************************************************
104 //***************************************************************************
105 bit_stream(void* begin_, size_t length_)
106 : pdata(reinterpret_cast<unsigned char*>(begin_))
107 , length_chars(length_)
108 {
109 restart();
110 }
111
112 //***************************************************************************
114 //***************************************************************************
115 void set_stream(void* begin_, size_t length_)
116 {
117 pdata = reinterpret_cast<unsigned char*>(begin_);
118 length_chars = length_;
119 restart();
120 }
121
122 //***************************************************************************
124 //***************************************************************************
125 void set_stream(void* begin_, void* end_)
126 {
127 set_stream(begin_, static_cast<size_t>(etl::distance(reinterpret_cast<unsigned char*>(begin_), reinterpret_cast<unsigned char*>(end_))));
128 }
129
130 //***************************************************************************
132 //***************************************************************************
133 void restart()
134 {
135 bits_available_in_char = CHAR_BIT;
136 char_index = 0U;
137 bits_available = CHAR_BIT * length_chars;
138 }
139
140 //***************************************************************************
142 //***************************************************************************
143 bool at_end() const
144 {
145 return (bits_available == 0U);
146 }
147
148 //***************************************************************************
150 //***************************************************************************
151 bool put(bool value)
152 {
153 bool success = false;
154
155 if (pdata != ETL_NULLPTR)
156 {
157 if (bits_available > 0)
158 {
159 unsigned char chunk = value ? 1 : 0;
160 put_integral(uint32_t(chunk), 1);
161 success = true;
162 }
163 }
164
165 return success;
166 }
167
168 //***************************************************************************
170 //***************************************************************************
171 template <typename T>
172 typename etl::enable_if<etl::is_integral<T>::value, bool>::type put(T value, uint_least8_t nbits = CHAR_BIT * sizeof(T))
173 {
174 return put_integral(static_cast<uint32_t>(value), nbits);
175 }
176
177#if ETL_USING_64BIT_TYPES
178 //***************************************************************************
180 //***************************************************************************
181 bool put(int64_t value, uint_least8_t nbits = CHAR_BIT * sizeof(int64_t))
182 {
183 return put_integral(uint64_t(value), nbits);
184 }
185
186 //***************************************************************************
188 //***************************************************************************
189 bool put(uint64_t value, uint_least8_t nbits = CHAR_BIT * sizeof(uint64_t))
190 {
191 return put_integral(value, nbits);
192 }
193#endif
194
195 //***************************************************************************
197 //***************************************************************************
198 template <typename T>
199 typename etl::enable_if<etl::is_floating_point<T>::value, bool>::type put(T value)
200 {
201 bool success = true;
202
203 unsigned char data[sizeof(T)];
204 to_bytes(value, data);
205
206 for (size_t i = 0UL; i < sizeof(T); ++i)
207 {
208 if (!put_integral(uint32_t(data[i]), CHAR_BIT))
209 {
210 success = false;
211 }
212 }
213
214 return success;
215 }
216
217 //***************************************************************************
219 //***************************************************************************
220 bool get(bool& value)
221 {
222 bool success = false;
223
224 if (pdata != ETL_NULLPTR)
225 {
226 // Do we have enough bits?
227 if (bits_available > 0U)
228 {
229 value = get_bit();
230 success = true;
231 }
232 }
233
234 return success;
235 }
236
237 //***************************************************************************
239 //***************************************************************************
240 template <typename T>
241 typename etl::enable_if<etl::is_integral<T>::value, bool>::type get(T& value, uint_least8_t nbits = CHAR_BIT * sizeof(T))
242 {
243 bool success = false;
244 uint_least8_t bits = nbits;
245
246 if (pdata != ETL_NULLPTR)
247 {
248 // Do we have enough bits?
249 if (bits_available >= nbits)
250 {
251 value = 0;
252
253 // Get the bits from the stream.
254 while (nbits != 0)
255 {
256 unsigned char mask_width = static_cast<unsigned char>(etl::min(nbits, bits_available_in_char));
257
258 typedef typename etl::make_unsigned<T>::type chunk_t;
259 chunk_t chunk = get_chunk(mask_width);
260
261 nbits -= mask_width;
262 value |= static_cast<T>(chunk << nbits);
263 }
264
265 success = true;
266 }
267 }
268
269 // Sign extend if signed type and not already full bit width.
270 if (etl::is_signed<T>::value && (bits != (CHAR_BIT * sizeof(T))))
271 {
272 typedef typename etl::make_signed<T>::type ST;
273 value = static_cast<T>(etl::sign_extend<ST, ST>(static_cast<ST>(value), bits));
274 }
275
276 return success;
277 }
278
279 //***************************************************************************
281 //***************************************************************************
282 template <typename T>
283 typename etl::enable_if<etl::is_floating_point<T>::value, bool>::type get(T& value)
284 {
285 bool success = false;
286
287 if (pdata != ETL_NULLPTR)
288 {
289 uint_least8_t nbits = CHAR_BIT * sizeof(T);
290
291 // Do we have enough bits?
292 if (bits_available >= nbits)
293 {
294 // Temporary storage.
296
297 for (size_t i = 0UL; i < sizeof(T); ++i)
298 {
299 get(data.raw[i], CHAR_BIT);
300 }
301
302 from_bytes(reinterpret_cast<const unsigned char*>(data.raw), value);
303
304 success = true;
305 }
306 }
307
308 return success;
309 }
310
311 //***************************************************************************
313 //***************************************************************************
314 size_t size() const
315 {
316 size_t s = char_index;
317
318 // Current byte is used?
319 if (bits_available_in_char != CHAR_BIT)
320 {
321 ++s;
322 }
323
324 return s;
325 }
326
327 //***************************************************************************
329 //***************************************************************************
330 size_t bits() const
331 {
332 return (length_chars * CHAR_BIT) - bits_available;
333 }
334
335 //***************************************************************************
337 //***************************************************************************
338 const_iterator begin() const
339 {
340 return pdata;
341 }
342
343 //***************************************************************************
345 //***************************************************************************
346 const_iterator end() const
347 {
348 return pdata + size();
349 }
350
351 private:
352
353 //***************************************************************************
355 //***************************************************************************
356 bool put_integral(uint32_t value, uint_least8_t nbits)
357 {
358 bool success = false;
359
360 if (pdata != ETL_NULLPTR)
361 {
362 // Do we have enough bits?
363 if (bits_available >= nbits)
364 {
365 // Send the bits to the stream.
366 while (nbits != 0)
367 {
368 unsigned char mask_width = static_cast<unsigned char>(etl::min(nbits, bits_available_in_char));
369 nbits -= mask_width;
370 uint32_t mask = ((1U << mask_width) - 1U) << nbits;
371 // uint32_t mask = ((uint32_t(1U) << mask_width) - 1U) << nbits;
372
373 // Normalise the chunk to the low bits (>> nbits), then left-align
374 // it within the bits still free in the current char.
375 // Chunks are never larger than one char.
376 uint32_t chunk = ((value & mask) >> nbits) << (bits_available_in_char - mask_width);
377
378 put_chunk(static_cast<unsigned char>(chunk), mask_width);
379 }
380
381 success = true;
382 }
383 }
384
385 return success;
386 }
387
388#if ETL_USING_64BIT_TYPES
389 //***************************************************************************
391 //***************************************************************************
392 bool put_integral(uint64_t value, uint_least8_t nbits)
393 {
394 bool success = false;
395
396 if (pdata != ETL_NULLPTR)
397 {
398 // Do we have enough bits?
399 if (bits_available >= nbits)
400 {
401 // Send the bits to the stream.
402 while (nbits != 0)
403 {
404 unsigned char mask_width = static_cast<unsigned char>(etl::min(nbits, bits_available_in_char));
405 nbits -= mask_width;
406 uint64_t mask = ((uint64_t(1U) << mask_width) - 1U) << nbits;
407
408 // Normalise the chunk to the low bits (>> nbits), then left-align
409 // it within the bits still free in the current char.
410 // Chunks are never larger than one char.
411 uint64_t chunk = ((value & mask) >> nbits) << (bits_available_in_char - mask_width);
412
413 put_chunk(static_cast<unsigned char>(chunk), mask_width);
414 }
415
416 success = true;
417 }
418 }
419
420 return success;
421 }
422#endif
423
424 //***************************************************************************
426 //***************************************************************************
427 void put_chunk(unsigned char chunk, unsigned char nbits)
428 {
429 // Clear if new byte.
430 if (bits_available_in_char == 8U)
431 {
432 pdata[char_index] = 0U;
433 }
434
435 pdata[char_index] |= chunk;
436 step(nbits);
437 }
438
439 //***************************************************************************
441 //***************************************************************************
442 unsigned char get_chunk(unsigned char nbits)
443 {
444 unsigned char value = static_cast<unsigned char>(pdata[char_index]);
445
446 value >>= (bits_available_in_char - nbits);
447
448 unsigned char mask;
449
450 if (nbits == CHAR_BIT)
451 {
452 mask = etl::integral_limits<unsigned char>::max;
453 }
454 else
455 {
456 mask = static_cast<unsigned char>((1U << nbits) - 1);
457 }
458
459 value &= mask;
460
461 step(nbits);
462
463 return value;
464 }
465
466 //***************************************************************************
468 //***************************************************************************
469 bool get_bit()
470 {
471 bool result = (static_cast<unsigned char>(pdata[char_index]) & (1U << (bits_available_in_char - 1U))) != 0U;
472
473 step(1U);
474
475 return result;
476 }
477
478 //***************************************************************************
480 //***************************************************************************
481 template <typename T>
482 void from_bytes(const unsigned char* data, T& value)
483 {
484 etl::uninitialized_buffer_of<T, 1U> temp;
485
486 // Network to host.
487 if (etl::endianness::value() == etl::endian::little)
488 {
489 etl::reverse_copy(data, data + sizeof(T), reinterpret_cast<unsigned char*>(temp.raw));
490 }
491 else
492 {
493 etl::copy(data, data + sizeof(T), reinterpret_cast<unsigned char*>(temp.raw));
494 }
495
496 value = *reinterpret_cast<T*>(temp.raw);
497 }
498
499 //***************************************************************************
501 //***************************************************************************
502 template <typename T>
503 void to_bytes(T value, unsigned char* data)
504 {
505 unsigned char* pf = reinterpret_cast<unsigned char*>(&value);
506
507 // Host to network.
508 if (etl::endianness::value() == etl::endian::little)
509 {
510 etl::reverse_copy(pf, pf + sizeof(T), data);
511 }
512 else
513 {
514 etl::copy(pf, pf + sizeof(T), data);
515 }
516 }
517
518 //***************************************************************************
521 //***************************************************************************
522 void step(unsigned char nbits)
523 {
524 bits_available_in_char -= nbits;
525
526 if (bits_available_in_char == 0)
527 {
528 ++char_index;
529 bits_available_in_char = 8;
530 }
531
532 bits_available -= nbits;
533 }
534
535 unsigned char* pdata;
536 size_t length_chars;
537 unsigned char bits_available_in_char;
539 size_t char_index;
540 size_t bits_available;
542 };
543
544 //***************************************************************************
546 //***************************************************************************
548 {
549 public:
550
551 typedef char value_type;
552 typedef value_type* iterator;
553 typedef const value_type* const_iterator;
554 typedef etl::span<value_type> callback_parameter_type;
555 typedef etl::delegate<void(callback_parameter_type)> callback_type;
556
557 //***************************************************************************
559 //***************************************************************************
560 template <size_t Length>
561 bit_stream_writer(const etl::span<char, Length>& span_, etl::bit_order bit_order_, callback_type callback_ = callback_type(),
562 etl::endian byte_order_ = etl::endian::big)
563 : pdata(span_.begin())
564 , length_chars(span_.size_bytes())
565 , bit_order(bit_order_)
566 , byte_order(byte_order_)
567 , callback(callback_)
568 {
569 restart();
570 }
571
572 //***************************************************************************
574 //***************************************************************************
575 template <size_t Length>
576 bit_stream_writer(const etl::span<unsigned char, Length>& span_, etl::bit_order bit_order_, callback_type callback_ = callback_type(),
577 etl::endian byte_order_ = etl::endian::big)
578 : pdata(reinterpret_cast<char*>(span_.begin()))
579 , length_chars(span_.size_bytes())
580 , bit_order(bit_order_)
581 , byte_order(byte_order_)
582 , callback(callback_)
583 {
584 restart();
585 }
586
587 //***************************************************************************
589 //***************************************************************************
590 bit_stream_writer(void* begin_, void* end_, etl::bit_order bit_order_, callback_type callback_ = callback_type(),
591 etl::endian byte_order_ = etl::endian::big)
592 : pdata(reinterpret_cast<char*>(begin_))
593 , length_chars(static_cast<size_t>(etl::distance(reinterpret_cast<unsigned char*>(begin_), reinterpret_cast<unsigned char*>(end_))))
594 , bit_order(bit_order_)
595 , byte_order(byte_order_)
596 , callback(callback_)
597 {
598 restart();
599 }
600
601 //***************************************************************************
603 //***************************************************************************
604 bit_stream_writer(void* begin_, size_t length_chars_, etl::bit_order bit_order_, callback_type callback_ = callback_type(),
605 etl::endian byte_order_ = etl::endian::big)
606 : pdata(reinterpret_cast<char*>(begin_))
607 , length_chars(length_chars_)
608 , bit_order(bit_order_)
609 , byte_order(byte_order_)
610 , callback(callback_)
611 {
612 restart();
613 }
614
615 //***************************************************************************
617 //***************************************************************************
618 void restart()
619 {
620 bits_available_in_char = CHAR_BIT;
621 char_index = 0U;
622 bits_available = capacity_bits();
623 }
624
625 //***************************************************************************
627 //***************************************************************************
628 size_t capacity_bytes() const
629 {
630 return length_chars;
631 }
632
633 //***************************************************************************
635 //***************************************************************************
636 size_t capacity_bits() const
637 {
638 return length_chars * CHAR_BIT;
639 }
640
641 //***************************************************************************
643 //***************************************************************************
644 bool empty() const
645 {
646 return (available_bits() == capacity_bits());
647 }
648
649 //***************************************************************************
651 //***************************************************************************
652 bool full() const
653 {
654 return (available_bits() == 0U);
655 }
656
657 //***************************************************************************
659 //***************************************************************************
660 void write_unchecked(bool value)
661 {
662 unsigned char chunk = value ? 1 : 0;
663 write_data<unsigned char>(chunk, 1);
664 }
665
666 //***************************************************************************
668 //***************************************************************************
669 bool write(bool value)
670 {
671 bool success = (available<1U>() > 0U);
672
673 if (success)
674 {
675 write_unchecked(value);
676 }
677
678 return success;
679 }
680
681 //***************************************************************************
683 //***************************************************************************
684 template <typename T>
685 typename etl::enable_if<etl::is_integral<T>::value, void>::type write_unchecked(T value, uint_least8_t nbits = CHAR_BIT * sizeof(T))
686 {
687 typedef typename etl::unsigned_type<T>::type unsigned_t;
688
689 write_data<unsigned_t>(static_cast<unsigned_t>(value), nbits);
690 }
691
692 //***************************************************************************
694 //***************************************************************************
695 template <typename T>
696 typename etl::enable_if<etl::is_integral<T>::value, bool>::type write(T value, uint_least8_t nbits = CHAR_BIT * sizeof(T))
697 {
698 bool success = (available(nbits) > 0U);
699
700 if (success)
701 {
702 write_unchecked(value, nbits);
703 }
704
705 return success;
706 }
707
708 //***************************************************************************
712 //***************************************************************************
713 bool skip(size_t nbits)
714 {
715 bool success = (nbits <= available_bits());
716
717 if (success)
718 {
719 while (nbits > bits_available_in_char)
720 {
721 step(bits_available_in_char);
722 nbits -= bits_available_in_char;
723 }
724
725 if (nbits != 0U)
726 {
727 step(static_cast<unsigned char>(nbits));
728 }
729 }
730
731 return success;
732 }
733
734 //***************************************************************************
736 //***************************************************************************
737 size_t size_bytes() const
738 {
739 size_t s = char_index;
740
741 // Is the current byte partially used?
742 if (bits_available_in_char != CHAR_BIT)
743 {
744 ++s;
745 }
746
747 return s;
748 }
749
750 //***************************************************************************
752 //***************************************************************************
753 size_t size_bits() const
754 {
755 return capacity_bits() - available_bits();
756 }
757
758 //***************************************************************************
761 //***************************************************************************
762 template <size_t Nbits>
763 size_t available() const
764 {
765 return bits_available / Nbits;
766 }
767
768 //***************************************************************************
771 //***************************************************************************
772 template <typename T>
773 size_t available() const
774 {
776 }
777
778 //***************************************************************************
781 //***************************************************************************
782 size_t available(size_t nbits) const
783 {
784 return bits_available / nbits;
785 }
786
787 //***************************************************************************
789 //***************************************************************************
790 size_t available_bits() const
791 {
792 return bits_available;
793 }
794
795 //***************************************************************************
797 //***************************************************************************
798 iterator begin()
799 {
800 return pdata;
801 }
802
803 //***************************************************************************
805 //***************************************************************************
806 const_iterator begin() const
807 {
808 return pdata;
809 }
810
811 //***************************************************************************
813 //***************************************************************************
814 const_iterator cbegin() const
815 {
816 return pdata;
817 }
818
819 //***************************************************************************
821 //***************************************************************************
822 iterator end()
823 {
824 return pdata + size_bytes();
825 }
826
827 //***************************************************************************
829 //***************************************************************************
830 const_iterator end() const
831 {
832 return pdata + size_bytes();
833 }
834
835 //***************************************************************************
837 //***************************************************************************
838 const_iterator cend() const
839 {
840 return pdata + size_bytes();
841 }
842
843 //***************************************************************************
845 //***************************************************************************
847 {
848 return etl::span<char>(pdata, pdata + size_bytes());
849 }
850
851 //***************************************************************************
853 //***************************************************************************
855 {
856 return etl::span<const char>(pdata, pdata + size_bytes());
857 }
858
859 //***************************************************************************
861 //***************************************************************************
863 {
864 return etl::span<char>(pdata, pdata + length_chars);
865 }
866
867 //***************************************************************************
869 //***************************************************************************
871 {
872 return etl::span<const char>(pdata, pdata + length_chars);
873 }
874
875 //***************************************************************************
877 //***************************************************************************
878 void flush()
879 {
880 if (callback.is_valid())
881 {
882 if (bits_available_in_char != 0U)
883 {
884 char_index = 1U; // Indicate that the first char is actually 'full'.
885 flush_full_bytes();
886 }
887
888 restart();
889 }
890 }
891
892 //***************************************************************************
894 //***************************************************************************
895 void set_callback(callback_type callback_)
896 {
897 callback = callback_;
898 }
899
900 //***************************************************************************
902 //***************************************************************************
903 callback_type get_callback() const
904 {
905 return callback;
906 }
907
908 private:
909
910 //***************************************************************************
913 //***************************************************************************
914 template <typename T>
915 void write_data(T value, uint_least8_t nbits)
916 {
917 ETL_ASSERT(nbits <= (CHAR_BIT * sizeof(T)), ETL_ERROR_GENERIC("bit_stream_writer::write_data: nbits too large"));
918
919 // Apply the byte order (endianness).
920 // Only meaningful when writing the full width of the type.
921 if ((byte_order == etl::endian::little) && (nbits == (CHAR_BIT * sizeof(T))))
922 {
923 value = etl::reverse_bytes(value);
924 }
925
926 // Apply the bit order.
927 if (bit_order == etl::bit_order::lsb_first)
928 {
929 value = etl::reverse_bits(value);
930 value = value >> ((CHAR_BIT * sizeof(T)) - nbits);
931 }
932
933 // Send the bits to the stream.
934 while (nbits != 0)
935 {
936 unsigned char mask_width = static_cast<unsigned char>(etl::min(nbits, bits_available_in_char));
937 nbits -= mask_width;
938 T mask = ((T(1U) << mask_width) - 1U) << nbits;
939
940 // Normalise the chunk to the low bits (>> nbits), then left-align
941 // it within the bits still free in the current char.
942 // Chunks are never larger than one char.
943 T chunk = ((value & mask) >> nbits) << (bits_available_in_char - mask_width);
944
945 write_chunk(static_cast<char>(chunk), mask_width);
946 }
947
948 if (callback.is_valid())
949 {
950 flush_full_bytes();
951 }
952 }
953
954 //***************************************************************************
956 //***************************************************************************
957 void write_chunk(char chunk, unsigned char nbits)
958 {
959 // Clear if new byte.
960 if (bits_available_in_char == CHAR_BIT)
961 {
962 pdata[char_index] = 0U;
963 }
964
965 pdata[char_index] |= chunk;
966 step(nbits);
967 }
968
969 //***************************************************************************
972 //***************************************************************************
973 void flush_full_bytes()
974 {
975 // Is the first byte fully filled?
976 if (char_index > 0U)
977 {
978 callback(callback_parameter_type(pdata, pdata + char_index));
979
980 bits_available = CHAR_BIT * length_chars;
981
982 if (bits_available_in_char != 0U)
983 {
984 // Move a partially filled last byte to the start of the buffer.
985 pdata[0] = pdata[char_index];
986 bits_available -= (CHAR_BIT - bits_available_in_char);
987 }
988
989 char_index = 0U;
990 }
991 }
992
993 //***************************************************************************
996 //***************************************************************************
997 void step(unsigned char nbits)
998 {
999 bits_available_in_char -= nbits;
1000
1001 if (bits_available_in_char == 0)
1002 {
1003 ++char_index;
1004 bits_available_in_char = CHAR_BIT;
1005 }
1006
1007 bits_available -= nbits;
1008 }
1009
1010 char* const pdata;
1011 const size_t length_chars;
1012 const etl::bit_order bit_order;
1013 const etl::endian byte_order;
1014 unsigned char bits_available_in_char;
1016 size_t char_index;
1017 size_t bits_available;
1019 callback_type callback;
1020 };
1021
1022 //***************************************************************************
1025 //***************************************************************************
1026 inline void write_unchecked(etl::bit_stream_writer& stream, bool value)
1027 {
1028 stream.write_unchecked(value);
1029 }
1030
1031 //***************************************************************************
1034 //***************************************************************************
1035 inline bool write(etl::bit_stream_writer& stream, bool value)
1036 {
1037 return stream.write(value);
1038 }
1039
1040 //***************************************************************************
1044 //***************************************************************************
1045 template <typename T>
1046 typename etl::enable_if<etl::is_integral<T>::value, void>::type write_unchecked(etl::bit_stream_writer& stream, const T& value,
1047 uint_least8_t nbits = CHAR_BIT * sizeof(T))
1048 {
1049 stream.write_unchecked(value, nbits);
1050 }
1051
1052 //***************************************************************************
1056 //***************************************************************************
1057 template <typename T>
1058 typename etl::enable_if<etl::is_integral<T>::value, bool>::type write(etl::bit_stream_writer& stream, const T& value,
1059 uint_least8_t nbits = CHAR_BIT * sizeof(T))
1060 {
1061 return stream.write(value, nbits);
1062 }
1063
1064 //***************************************************************************
1066 //***************************************************************************
1068 {
1069 public:
1070
1071 typedef char value_type;
1072 typedef const char* const_iterator;
1073
1074 //***************************************************************************
1076 //***************************************************************************
1077 template <size_t Length>
1078 bit_stream_reader(const etl::span<char, Length>& span_, etl::bit_order bit_order_, etl::endian byte_order_ = etl::endian::big)
1079 : pdata(span_.begin())
1080 , length_chars(span_.size_bytes())
1081 , bit_order(bit_order_)
1082 , byte_order(byte_order_)
1083 {
1084 restart();
1085 }
1086
1087 //***************************************************************************
1089 //***************************************************************************
1090 template <size_t Length>
1091 bit_stream_reader(const etl::span<unsigned char, Length>& span_, etl::bit_order bit_order_, etl::endian byte_order_ = etl::endian::big)
1092 : pdata(reinterpret_cast<const char*>(span_.begin()))
1093 , length_chars(span_.size_bytes())
1094 , bit_order(bit_order_)
1095 , byte_order(byte_order_)
1096 {
1097 restart();
1098 }
1099
1100 //***************************************************************************
1102 //***************************************************************************
1103 template <size_t Length>
1104 bit_stream_reader(const etl::span<const char, Length>& span_, etl::bit_order bit_order_, etl::endian byte_order_ = etl::endian::big)
1105 : pdata(span_.begin())
1106 , length_chars(span_.size_bytes())
1107 , bit_order(bit_order_)
1108 , byte_order(byte_order_)
1109 {
1110 restart();
1111 }
1112
1113 //***************************************************************************
1115 //***************************************************************************
1116 template <size_t Length>
1117 bit_stream_reader(const etl::span<const unsigned char, Length>& span_, etl::bit_order bit_order_, etl::endian byte_order_ = etl::endian::big)
1118 : pdata(reinterpret_cast<const char*>(span_.begin()))
1119 , length_chars(span_.size_bytes())
1120 , bit_order(bit_order_)
1121 , byte_order(byte_order_)
1122 {
1123 restart();
1124 }
1125
1126 //***************************************************************************
1128 //***************************************************************************
1129 bit_stream_reader(const void* begin_, const void* end_, etl::bit_order bit_order_, etl::endian byte_order_ = etl::endian::big)
1130 : pdata(reinterpret_cast<const char*>(begin_))
1131 , length_chars(static_cast<size_t>(etl::distance(reinterpret_cast<const char*>(begin_), reinterpret_cast<const char*>(end_))))
1132 , bit_order(bit_order_)
1133 , byte_order(byte_order_)
1134 {
1135 restart();
1136 }
1137
1138 //***************************************************************************
1140 //***************************************************************************
1141 bit_stream_reader(const void* begin_, size_t length_, etl::bit_order bit_order_, etl::endian byte_order_ = etl::endian::big)
1142 : pdata(reinterpret_cast<const char*>(begin_))
1143 , length_chars(length_)
1144 , bit_order(bit_order_)
1145 , byte_order(byte_order_)
1146 {
1147 restart();
1148 }
1149
1150 //***************************************************************************
1152 //***************************************************************************
1153 void restart()
1154 {
1155 bits_available_in_char = CHAR_BIT;
1156 char_index = 0U;
1157 bits_available = CHAR_BIT * length_chars;
1158 }
1159
1160 //***************************************************************************
1162 //***************************************************************************
1163 template <typename T>
1164 typename etl::enable_if<etl::is_same<bool, T>::value, bool>::type read_unchecked()
1165 {
1166 return get_bit();
1167 }
1168
1169 //***************************************************************************
1171 //***************************************************************************
1172 template <typename T>
1173 typename etl::enable_if<etl::is_same<bool, T>::value, etl::optional<bool> >::type read()
1174 {
1175 etl::optional<bool> result;
1176
1177 if (bits_available > 0U)
1178 {
1179 result = read_unchecked<bool>();
1180 }
1181
1182 return result;
1183 }
1184
1185 //***************************************************************************
1187 //***************************************************************************
1188 template <typename T>
1189 typename etl::enable_if< etl::is_integral<T>::value && !etl::is_same<bool, T>::value, T>::type read_unchecked(uint_least8_t nbits = CHAR_BIT
1190 * sizeof(T))
1191 {
1192 typedef typename etl::unsigned_type<T>::type unsigned_t;
1193
1194 T value = static_cast<T>(read_value<unsigned_t>(nbits, etl::is_signed<T>::value));
1195
1196 return static_cast<T>(value);
1197 }
1198
1199 //***************************************************************************
1201 //***************************************************************************
1202 template <typename T>
1203 typename etl::enable_if<etl::is_integral<T>::value && !etl::is_same<bool, T>::value, etl::optional<T> >::type
1204 read(uint_least8_t nbits = CHAR_BIT * sizeof(T))
1205 {
1206 etl::optional<T> result;
1207
1208 // Do we have enough bits?
1209 if (bits_available >= nbits)
1210 {
1211 result = read_unchecked<T>(nbits);
1212 }
1213
1214 return result;
1215 }
1216
1217 //***************************************************************************
1219 //***************************************************************************
1220 size_t size_bytes() const
1221 {
1222 return length_chars;
1223 }
1224
1225 //***************************************************************************
1227 //***************************************************************************
1228 size_t size_bits() const
1229 {
1230 return length_chars * CHAR_BIT;
1231 }
1232
1233 //***************************************************************************
1235 //***************************************************************************
1236 const_iterator begin() const
1237 {
1238 return pdata;
1239 }
1240
1241 //***************************************************************************
1243 //***************************************************************************
1244 const_iterator cbegin() const
1245 {
1246 return pdata;
1247 }
1248
1249 //***************************************************************************
1251 //***************************************************************************
1252 const_iterator end() const
1253 {
1254 return pdata + size_bytes();
1255 }
1256
1257 //***************************************************************************
1259 //***************************************************************************
1260 const_iterator cend() const
1261 {
1262 return pdata + size_bytes();
1263 }
1264
1265 //***************************************************************************
1267 //***************************************************************************
1269 {
1270 return etl::span<const char>(pdata, pdata + length_chars);
1271 }
1272
1273 //***************************************************************************
1277 //***************************************************************************
1278 bool skip(size_t nbits)
1279 {
1280 bool success = (nbits <= bits_available);
1281
1282 if (success)
1283 {
1284 while (nbits > bits_available_in_char)
1285 {
1286 nbits -= bits_available_in_char;
1287 step(bits_available_in_char);
1288 }
1289
1290 if (nbits != 0U)
1291 {
1292 step(static_cast<unsigned char>(nbits));
1293 }
1294 }
1295
1296 return success;
1297 }
1298
1299 private:
1300
1301 //***************************************************************************
1304 //***************************************************************************
1305 template <typename T>
1306 T read_value(uint_least8_t nbits, bool is_signed)
1307 {
1308 ETL_ASSERT(nbits <= (CHAR_BIT * sizeof(T)), ETL_ERROR_GENERIC("bit_stream_reader::read_value: nbits too large"));
1309
1310 T value = 0;
1311 uint_least8_t bits = nbits;
1312
1313 // Get the bits from the stream.
1314 while (nbits != 0)
1315 {
1316 unsigned char mask_width = static_cast<unsigned char>(etl::min(nbits, bits_available_in_char));
1317
1318 T chunk = get_chunk(mask_width);
1319
1320 nbits -= mask_width;
1321 value |= static_cast<T>(chunk << nbits);
1322 }
1323
1324 if (bit_order == etl::bit_order::lsb_first)
1325 {
1326 value = value << ((CHAR_BIT * sizeof(T)) - bits);
1327 value = etl::reverse_bits(value);
1328 }
1329
1330 // Apply the byte order (endianness).
1331 // Only meaningful when reading the full width of the type.
1332 if ((byte_order == etl::endian::little) && (bits == (CHAR_BIT * sizeof(T))))
1333 {
1334 value = etl::reverse_bytes(value);
1335 }
1336
1337 if (is_signed && (bits != (CHAR_BIT * sizeof(T))))
1338 {
1339 value = etl::sign_extend<T, T>(value, bits);
1340 }
1341
1342 return value;
1343 }
1344
1345 //***************************************************************************
1347 //***************************************************************************
1348 unsigned char get_chunk(unsigned char nbits)
1349 {
1350 unsigned char value = static_cast<unsigned char>(pdata[char_index]);
1351 value >>= (bits_available_in_char - nbits);
1352
1353 unsigned char mask;
1354
1355 if (nbits == CHAR_BIT)
1356 {
1357 mask = etl::integral_limits<unsigned char>::max;
1358 }
1359 else
1360 {
1361 mask = static_cast<unsigned char>((1U << nbits) - 1);
1362 }
1363
1364 value &= mask;
1365
1366 step(nbits);
1367
1368 return value;
1369 }
1370
1371 //***************************************************************************
1373 //***************************************************************************
1374 bool get_bit()
1375 {
1376 bool result = (static_cast<unsigned char>(pdata[char_index]) & (1U << (bits_available_in_char - 1U))) != 0U;
1377
1378 step(1U);
1379
1380 return result;
1381 }
1382
1383 //***************************************************************************
1386 //***************************************************************************
1387 void step(unsigned char nbits)
1388 {
1389 bits_available_in_char -= nbits;
1390
1391 if (bits_available_in_char == 0)
1392 {
1393 ++char_index;
1394 bits_available_in_char = 8;
1395 }
1396
1397 bits_available -= nbits;
1398 }
1399
1400 const char* pdata;
1401 size_t length_chars;
1402 const etl::bit_order bit_order;
1403 const etl::endian byte_order;
1404 unsigned char bits_available_in_char;
1406 size_t char_index;
1407 size_t bits_available;
1409 };
1410
1411 //***************************************************************************
1413 //***************************************************************************
1414 template <typename T>
1416 {
1417 return stream.read_unchecked<T>();
1418 }
1419
1420 template <typename T>
1421 T read_unchecked(etl::bit_stream_reader& stream, uint_least8_t nbits)
1422 {
1423 return stream.read_unchecked<T>(nbits);
1424 }
1425
1426 //***************************************************************************
1428 //***************************************************************************
1429 template <typename T>
1431 {
1432 return stream.read<T>();
1433 }
1434
1435 template <typename T>
1436 etl::optional<T> read(etl::bit_stream_reader& stream, uint_least8_t nbits)
1437 {
1438 return stream.read<T>(nbits);
1439 }
1440
1441 //***************************************************************************
1443 //***************************************************************************
1444 template <>
1446 {
1447 return stream.read_unchecked<bool>();
1448 }
1449
1450 //***************************************************************************
1452 //***************************************************************************
1453 template <>
1455 {
1456 return stream.read<bool>();
1457 }
1458} // namespace etl
1459
1460#include "private/minmax_pop.h"
1461
1462#endif
Reads bit streams.
Definition bit_stream.h:1068
etl::enable_if< etl::is_same< bool, T >::value, etl::optional< bool > >::type read()
For bool types.
Definition bit_stream.h:1173
const_iterator end() const
Returns end of the stream.
Definition bit_stream.h:1252
const_iterator cend() const
Returns end of the stream.
Definition bit_stream.h:1260
bit_stream_reader(const etl::span< char, Length > &span_, etl::bit_order bit_order_, etl::endian byte_order_=etl::endian::big)
Construct from span.
Definition bit_stream.h:1078
size_t size_bits() const
Returns the number of bits in the stream buffer.
Definition bit_stream.h:1228
etl::enable_if< etl::is_integral< T >::value &&!etl::is_same< bool, T >::value, T >::type read_unchecked(uint_least8_t nbits=CHAR_BIT *sizeof(T))
For integral types.
Definition bit_stream.h:1189
bool skip(size_t nbits)
Definition bit_stream.h:1278
bit_stream_reader(const etl::span< const unsigned char, Length > &span_, etl::bit_order bit_order_, etl::endian byte_order_=etl::endian::big)
Construct from span.
Definition bit_stream.h:1117
etl::enable_if< etl::is_integral< T >::value &&!etl::is_same< bool, T >::value, etl::optional< T > >::type read(uint_least8_t nbits=CHAR_BIT *sizeof(T))
For integral types.
Definition bit_stream.h:1204
void restart()
Sets the indexes back to the beginning of the stream.
Definition bit_stream.h:1153
bit_stream_reader(const etl::span< const char, Length > &span_, etl::bit_order bit_order_, etl::endian byte_order_=etl::endian::big)
Construct from span.
Definition bit_stream.h:1104
bit_stream_reader(const etl::span< unsigned char, Length > &span_, etl::bit_order bit_order_, etl::endian byte_order_=etl::endian::big)
Construct from span.
Definition bit_stream.h:1091
bit_stream_reader(const void *begin_, const void *end_, etl::bit_order bit_order_, etl::endian byte_order_=etl::endian::big)
Construct from range.
Definition bit_stream.h:1129
bit_stream_reader(const void *begin_, size_t length_, etl::bit_order bit_order_, etl::endian byte_order_=etl::endian::big)
Construct from begin and length.
Definition bit_stream.h:1141
const_iterator cbegin() const
Returns start of the stream.
Definition bit_stream.h:1244
etl::enable_if< etl::is_same< bool, T >::value, bool >::type read_unchecked()
For bool types.
Definition bit_stream.h:1164
etl::span< const char > data() const
Returns a span of whole the stream.
Definition bit_stream.h:1268
const_iterator begin() const
Returns start of the stream.
Definition bit_stream.h:1236
size_t size_bytes() const
Returns the number of bytes in the stream buffer.
Definition bit_stream.h:1220
Writes bits streams.
Definition bit_stream.h:548
etl::enable_if< etl::is_integral< T >::value, bool >::type write(T value, uint_least8_t nbits=CHAR_BIT *sizeof(T))
For integral types.
Definition bit_stream.h:696
size_t size_bytes() const
Returns the number of bytes used in the stream.
Definition bit_stream.h:737
etl::enable_if< etl::is_integral< T >::value, void >::type write_unchecked(T value, uint_least8_t nbits=CHAR_BIT *sizeof(T))
For integral types.
Definition bit_stream.h:685
etl::span< const char > used_data() const
Returns a span of the used portion of the stream.
Definition bit_stream.h:854
bool write(bool value)
Writes a boolean to the stream.
Definition bit_stream.h:669
size_t size_bits() const
Returns the number of bits used in the stream.
Definition bit_stream.h:753
size_t available_bits() const
The number of bits left in the stream.
Definition bit_stream.h:790
const_iterator cend() const
Returns end of the stream.
Definition bit_stream.h:838
bit_stream_writer(void *begin_, void *end_, etl::bit_order bit_order_, callback_type callback_=callback_type(), etl::endian byte_order_=etl::endian::big)
Construct from range.
Definition bit_stream.h:590
callback_type get_callback() const
Gets the function to call after every write.
Definition bit_stream.h:903
bool empty() const
Returns true if the bitsteam indexes have been reset.
Definition bit_stream.h:644
bit_stream_writer(void *begin_, size_t length_chars_, etl::bit_order bit_order_, callback_type callback_=callback_type(), etl::endian byte_order_=etl::endian::big)
Construct from begin and length.
Definition bit_stream.h:604
iterator end()
Returns end of the stream.
Definition bit_stream.h:822
void set_callback(callback_type callback_)
Sets the function to call after every write.
Definition bit_stream.h:895
size_t available() const
Definition bit_stream.h:763
etl::span< char > data()
Returns a span of whole the stream.
Definition bit_stream.h:862
bool full() const
Returns true if the bitsteam indexes have reached the end.
Definition bit_stream.h:652
bool skip(size_t nbits)
Definition bit_stream.h:713
size_t capacity_bits() const
Returns the maximum capacity in bits.
Definition bit_stream.h:636
etl::span< char > used_data()
Returns a span of the used portion of the stream.
Definition bit_stream.h:846
bit_stream_writer(const etl::span< char, Length > &span_, etl::bit_order bit_order_, callback_type callback_=callback_type(), etl::endian byte_order_=etl::endian::big)
Construct from span.
Definition bit_stream.h:561
size_t capacity_bytes() const
Returns the maximum capacity in bytes.
Definition bit_stream.h:628
etl::span< const char > data() const
Returns a span of whole the stream.
Definition bit_stream.h:870
void restart()
Sets the indexes back to the beginning of the stream.
Definition bit_stream.h:618
void write_unchecked(bool value)
Writes a boolean to the stream.
Definition bit_stream.h:660
void flush()
Flush the last byte, if partially filled, to the callback, if valid.
Definition bit_stream.h:878
const_iterator cbegin() const
Returns start of the stream.
Definition bit_stream.h:814
size_t available(size_t nbits) const
Definition bit_stream.h:782
const_iterator end() const
Returns end of the stream.
Definition bit_stream.h:830
const_iterator begin() const
Returns start of the stream.
Definition bit_stream.h:806
iterator begin()
Returns start of the stream.
Definition bit_stream.h:798
bit_stream_writer(const etl::span< unsigned char, Length > &span_, etl::bit_order bit_order_, callback_type callback_=callback_type(), etl::endian byte_order_=etl::endian::big)
Construct from span.
Definition bit_stream.h:576
etl::enable_if< etl::is_integral< T >::value, bool >::type get(T &value, uint_least8_t nbits=CHAR_BIT *sizeof(T))
For integral types.
Definition bit_stream.h:241
etl::enable_if< etl::is_integral< T >::value, bool >::type put(T value, uint_least8_t nbits=CHAR_BIT *sizeof(T))
For integral types.
Definition bit_stream.h:172
bool put(int64_t value, uint_least8_t nbits=CHAR_BIT *sizeof(int64_t))
For 64bit integral types.
Definition bit_stream.h:181
etl::enable_if< etl::is_floating_point< T >::value, bool >::type put(T value)
For floating point types.
Definition bit_stream.h:199
void restart()
Sets the indexes back to the beginning of the stream.
Definition bit_stream.h:133
size_t size() const
Returns the number of bytes used in the stream.
Definition bit_stream.h:314
size_t bits() const
Returns the number of bits used in the stream.
Definition bit_stream.h:330
bit_stream(void *begin_, void *end_)
Construct from range.
Definition bit_stream.h:95
bool put(uint64_t value, uint_least8_t nbits=CHAR_BIT *sizeof(uint64_t))
For 64bit integral types.
Definition bit_stream.h:189
bit_stream(void *begin_, size_t length_)
Construct from begin and length.
Definition bit_stream.h:105
etl::enable_if< etl::is_floating_point< T >::value, bool >::type get(T &value)
For floating point types.
Definition bit_stream.h:283
bool at_end() const
Returns true if the bitsteam indexes have reached the end.
Definition bit_stream.h:143
bool put(bool value)
Writes a boolean to the stream.
Definition bit_stream.h:151
bit_stream()
Default constructor.
Definition bit_stream.h:85
bool get(bool &value)
For bool types.
Definition bit_stream.h:220
void set_stream(void *begin_, size_t length_)
Construct from begin and length.
Definition bit_stream.h:115
void set_stream(void *begin_, void *end_)
Construct from range.
Definition bit_stream.h:125
const_iterator end() const
Returns end of the stream.
Definition bit_stream.h:346
const_iterator begin() const
Returns start of the stream.
Definition bit_stream.h:338
Declaration.
Definition delegate_cpp03.h:191
Span - Fixed Extent.
Definition span.h:208
Definition memory.h:3153
ETL_CONSTEXPR14 etl::enable_if< etl::is_integral< T >::value &&etl::is_unsigned< T >::value &&(etl::integral_limits< T >::bits==16U), T >::type reverse_bits(T value)
Definition binary.h:542
ETL_CONSTEXPR14 etl::enable_if< etl::is_integral< T >::value &&etl::is_unsigned< T >::value &&(etl::integral_limits< T >::bits==16U), T >::type reverse_bytes(T value)
Definition binary.h:745
ETL_CONSTEXPR14 TReturn sign_extend(TValue value)
Definition binary.h:273
Definition endianness.h:100
#define ETL_ASSERT(b, e)
Definition error_handler.h:511
Definition optional.h:1238
#define ETL_DECLARE_ENUM_TYPE(TypeName, ValueType)
Definition enum_type.h:90
Definition absolute.h:40
ETL_CONSTEXPR TContainer::pointer data(TContainer &container)
Definition iterator.h:1470
bool read_unchecked< bool >(etl::bit_stream_reader &stream)
Read an unchecked bool from a stream.
Definition bit_stream.h:1445
etl::optional< T > read(etl::bit_stream_reader &stream)
Read a checked type from a stream.
Definition bit_stream.h:1430
void write_unchecked(etl::bit_stream_writer &stream, bool value)
Definition bit_stream.h:1026
ETL_CONSTEXPR TContainer::size_type size(const TContainer &container)
Definition iterator.h:1434
T & get(array< T, Size > &a)
Definition array.h:1158
etl::optional< bool > read< bool >(etl::bit_stream_reader &stream)
Read a bool from a stream.
Definition bit_stream.h:1454
T read_unchecked(etl::bit_stream_reader &stream)
Read an unchecked type from a stream.
Definition bit_stream.h:1415
bool write(etl::bit_stream_writer &stream, bool value)
Definition bit_stream.h:1035
Definition bit_stream.h:59
enum_type
Definition bit_stream.h:61
@ lsb_first
Least significant bit first.
Definition bit_stream.h:62
@ msb_first
Most significant bit first.
Definition bit_stream.h:63
is_signed
Definition type_traits.h:458