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 "type_traits.h"
31#include "nullptr.h"
32#include "endianness.h"
33#include "integral_limits.h"
34#include "binary.h"
35#include "algorithm.h"
36#include "iterator.h"
37#include "memory.h"
38#include "delegate.h"
39#include "span.h"
40#include "optional.h"
41#include "exception.h"
42#include "error_handler.h"
43
44#include <stdint.h>
45#include <limits.h>
46
47#include "private/minmax_push.h"
48
49namespace etl
50{
51 //***************************************************************************
54 //***************************************************************************
56 {
57 public:
58
59 typedef const unsigned char* const_iterator;
60
61 //***************************************************************************
63 //***************************************************************************
65 : pdata(ETL_NULLPTR)
66 , length_chars(0U)
67 {
68 restart();
69 }
70
71 //***************************************************************************
73 //***************************************************************************
74 bit_stream(void* begin_, void* end_)
75 : pdata(reinterpret_cast<unsigned char*>(begin_))
76 , length_chars(etl::distance(reinterpret_cast<unsigned char*>(begin_), reinterpret_cast<unsigned char*>(end_)))
77 {
78 restart();
79 }
80
81 //***************************************************************************
83 //***************************************************************************
84 bit_stream(void* begin_, size_t length_)
85 : pdata(reinterpret_cast<unsigned char*>(begin_))
86 , length_chars(length_)
87 {
88 restart();
89 }
90
91 //***************************************************************************
93 //***************************************************************************
94 void set_stream(void* begin_, size_t length_)
95 {
96 pdata = reinterpret_cast<unsigned char*>(begin_);
97 length_chars = length_;
98 restart();
99 }
100
101 //***************************************************************************
103 //***************************************************************************
104 void set_stream(void* begin_, void* end_)
105 {
106 set_stream(begin_, etl::distance(reinterpret_cast<unsigned char*>(begin_), reinterpret_cast<unsigned char*>(end_)));
107 }
108
109 //***************************************************************************
111 //***************************************************************************
112 void restart()
113 {
114 bits_available_in_char = CHAR_BIT;
115 char_index = 0U;
116 bits_available = CHAR_BIT * length_chars;
117 }
118
119 //***************************************************************************
121 //***************************************************************************
122 bool at_end() const
123 {
124 return (bits_available == 0U);
125 }
126
127 //***************************************************************************
129 //***************************************************************************
130 bool put(bool value)
131 {
132 bool success = false;
133
134 if (pdata != ETL_NULLPTR)
135 {
136 if (bits_available > 0)
137 {
138 unsigned char chunk = value ? 1 : 0;
139 put_integral(uint32_t(chunk), 1);
140 success = true;
141 }
142 }
143
144 return success;
145 }
146
147 //***************************************************************************
149 //***************************************************************************
150 template <typename T>
152 put(T value, uint_least8_t nbits = CHAR_BIT * sizeof(T))
153 {
154 return put_integral(static_cast<uint32_t>(value), nbits);
155 }
156
157#if ETL_USING_64BIT_TYPES
158 //***************************************************************************
160 //***************************************************************************
161 bool put(int64_t value, uint_least8_t nbits = CHAR_BIT * sizeof(int64_t))
162 {
163 return put_integral(uint64_t(value), nbits);
164 }
165
166 //***************************************************************************
168 //***************************************************************************
169 bool put(uint64_t value, uint_least8_t nbits = CHAR_BIT * sizeof(uint64_t))
170 {
171 return put_integral(value, nbits);
172 }
173#endif
174
175 //***************************************************************************
177 //***************************************************************************
178 template <typename T>
180 put(T value)
181 {
182 bool success = true;
183
184 unsigned char data[sizeof(T)];
185 to_bytes(value, data);
186
187 for (size_t i = 0UL; i < sizeof(T); ++i)
188 {
189 if (!put_integral(uint32_t(data[i]), CHAR_BIT))
190 {
191 success = false;
192 }
193 }
194
195 return success;
196 }
197
198 //***************************************************************************
200 //***************************************************************************
201 bool get(bool& value)
202 {
203 bool success = false;
204
205 if (pdata != ETL_NULLPTR)
206 {
207 // Do we have enough bits?
208 if (bits_available > 0U)
209 {
210 value = get_bit();
211 success = true;
212 }
213 }
214
215 return success;
216 }
217
218 //***************************************************************************
220 //***************************************************************************
221 template <typename T>
223 get(T& value, uint_least8_t nbits = CHAR_BIT * sizeof(T))
224 {
225 bool success = false;
226 uint_least8_t bits = nbits;
227
228 if (pdata != ETL_NULLPTR)
229 {
230 // Do we have enough bits?
231 if (bits_available >= nbits)
232 {
233 value = 0;
234
235 // Get the bits from the stream.
236 while (nbits != 0)
237 {
238 unsigned char mask_width = static_cast<unsigned char>(etl::min(nbits, bits_available_in_char));
239
240 typedef typename etl::make_unsigned<T>::type chunk_t;
241 chunk_t chunk = get_chunk(mask_width);
242
243 nbits -= mask_width;
244 value |= static_cast<T>(chunk << nbits);
245 }
246
247 success = true;
248 }
249 }
250
251 // Sign extend if signed type and not already full bit width.
252 if (etl::is_signed<T>::value && (bits != (CHAR_BIT * sizeof(T))))
253 {
254 typedef typename etl::make_signed<T>::type ST;
255 value = etl::sign_extend<ST, ST>(value, bits);
256 }
257
258 return success;
259 }
260
261 //***************************************************************************
263 //***************************************************************************
264 template <typename T>
266 get(T& value)
267 {
268 bool success = false;
269
270 if (pdata != ETL_NULLPTR)
271 {
272 uint_least8_t nbits = CHAR_BIT * sizeof(T);
273
274 // Do we have enough bits?
275 if (bits_available >= nbits)
276 {
277 // Temporary storage.
279
280 for (size_t i = 0UL; i < sizeof(T); ++i)
281 {
282 get(data.raw[i], CHAR_BIT);
283 }
284
285 from_bytes(reinterpret_cast<const unsigned char*>(data.raw), value);
286
287 success = true;
288 }
289 }
290
291 return success;
292 }
293
294 //***************************************************************************
296 //***************************************************************************
297 size_t size() const
298 {
299 size_t s = char_index;
300
301 // Current byte is used?
302 if (bits_available_in_char != CHAR_BIT)
303 {
304 ++s;
305 }
306
307 return s;
308 }
309
310 //***************************************************************************
312 //***************************************************************************
313 size_t bits() const
314 {
315 return (length_chars * CHAR_BIT) - bits_available;
316 }
317
318 //***************************************************************************
320 //***************************************************************************
321 const_iterator begin() const
322 {
323 return pdata;
324 }
325
326 //***************************************************************************
328 //***************************************************************************
329 const_iterator end() const
330 {
331 return pdata + size();
332 }
333
334 private:
335
336 //***************************************************************************
338 //***************************************************************************
339 bool put_integral(uint32_t value, uint_least8_t nbits)
340 {
341 bool success = false;
342
343 if (pdata != ETL_NULLPTR)
344 {
345 // Do we have enough bits?
346 if (bits_available >= nbits)
347 {
348 // Send the bits to the stream.
349 while (nbits != 0)
350 {
351 unsigned char mask_width = static_cast<unsigned char>(etl::min(nbits, bits_available_in_char));
352 nbits -= mask_width;
353 uint32_t mask = ((1U << mask_width) - 1U) << nbits;
354 //uint32_t mask = ((uint32_t(1U) << mask_width) - 1U) << nbits;
355
356 // Move chunk to lowest char bits.
357 // Chunks are never larger than one char.
358 uint32_t chunk = ((value & mask) >> nbits) << (bits_available_in_char - mask_width);
359
360 put_chunk(static_cast<unsigned char>(chunk), mask_width);
361 }
362
363 success = true;
364 }
365 }
366
367 return success;
368 }
369
370#if ETL_USING_64BIT_TYPES
371 //***************************************************************************
373 //***************************************************************************
374 bool put_integral(uint64_t value, uint_least8_t nbits)
375 {
376 bool success = false;
377
378 if (pdata != ETL_NULLPTR)
379 {
380 // Do we have enough bits?
381 if (bits_available >= nbits)
382 {
383 // Send the bits to the stream.
384 while (nbits != 0)
385 {
386 unsigned char mask_width = static_cast<unsigned char>(etl::min(nbits, bits_available_in_char));
387 nbits -= mask_width;
388 uint64_t mask = ((uint64_t(1U) << mask_width) - 1U) << nbits;
389
390 // Move chunk to lowest char bits.
391 // Chunks are never larger than one char.
392 uint64_t chunk = ((value & mask) >> nbits) << (bits_available_in_char - mask_width);
393
394 put_chunk(static_cast<unsigned char>(chunk), mask_width);
395 }
396
397 success = true;
398 }
399 }
400
401 return success;
402 }
403#endif
404
405 //***************************************************************************
407 //***************************************************************************
408 void put_chunk(unsigned char chunk, unsigned char nbits)
409 {
410 // Clear if new byte.
411 if (bits_available_in_char == 8U)
412 {
413 pdata[char_index] = 0U;
414 }
415
416 pdata[char_index] |= chunk;
417 step(nbits);
418 }
419
420 //***************************************************************************
422 //***************************************************************************
423 unsigned char get_chunk(unsigned char nbits)
424 {
425 unsigned char value = pdata[char_index];
426
427 value >>= (bits_available_in_char - nbits);
428
429 unsigned char mask;
430
431 if (nbits == CHAR_BIT)
432 {
433 mask = etl::integral_limits<unsigned char>::max;
434 }
435 else
436 {
437 mask = (1U << nbits) - 1;
438 }
439
440 value &= mask;
441
442 step(nbits);
443
444 return value;
445 }
446
447 //***************************************************************************
449 //***************************************************************************
450 bool get_bit()
451 {
452 bool result = (pdata[char_index] & (1U << (bits_available_in_char - 1U))) != 0U;
453
454 step(1U);
455
456 return result;
457 }
458
459 //***************************************************************************
461 //***************************************************************************
462 template <typename T>
463 void from_bytes(const unsigned char* data, T& value)
464 {
465 etl::uninitialized_buffer_of<T, 1U> temp;
466
467 // Network to host.
468 if (etl::endianness::value() == etl::endian::little)
469 {
470 etl::reverse_copy(data, data + sizeof(T), temp.raw);
471 }
472 else
473 {
474 etl::copy(data, data + sizeof(T), temp.raw);
475 }
476
477 value = *reinterpret_cast<T*>(temp.raw);
478 }
479
480 //***************************************************************************
482 //***************************************************************************
483 template <typename T>
484 void to_bytes(T value, unsigned char* data)
485 {
486 unsigned char* pf = reinterpret_cast<unsigned char*>(&value);
487
488 // Host to network.
489 if (etl::endianness::value() == etl::endian::little)
490 {
491 etl::reverse_copy(pf, pf + sizeof(T), data);
492 }
493 else
494 {
495 etl::copy(pf, pf + sizeof(T), data);
496 }
497 }
498
499 //***************************************************************************
502 //***************************************************************************
503 void step(unsigned char nbits)
504 {
505 bits_available_in_char -= nbits;
506
507 if (bits_available_in_char == 0)
508 {
509 ++char_index;
510 bits_available_in_char = 8;
511 }
512
513 bits_available -= nbits;
514 }
515
516 unsigned char *pdata;
517 size_t length_chars;
518 unsigned char bits_available_in_char;
519 size_t char_index;
520 size_t bits_available;
521 };
522
523 //***************************************************************************
525 //***************************************************************************
527 {
528 public:
529
530 typedef char value_type;
531 typedef value_type* iterator;
532 typedef const value_type* const_iterator;
533 typedef etl::span<value_type> callback_parameter_type;
534 typedef etl::delegate<void(callback_parameter_type)> callback_type;
535
536 //***************************************************************************
538 //***************************************************************************
539 template <size_t Length>
540 bit_stream_writer(const etl::span<char, Length>& span_, etl::endian stream_endianness_, callback_type callback_ = callback_type())
541 : pdata(span_.begin())
542 , length_chars(span_.size_bytes())
543 , stream_endianness(stream_endianness_)
544 , callback(callback_)
545 {
546 restart();
547 }
548
549 //***************************************************************************
551 //***************************************************************************
552 template <size_t Length>
553 bit_stream_writer(const etl::span<unsigned char, Length>& span_, etl::endian stream_endianness_, callback_type callback_ = callback_type())
554 : pdata(reinterpret_cast<char*>(span_.begin()))
555 , length_chars(span_.size_bytes())
556 , stream_endianness(stream_endianness_)
557 , callback(callback_)
558 {
559 restart();
560 }
561
562 //***************************************************************************
564 //***************************************************************************
565 bit_stream_writer(void* begin_, void* end_, etl::endian stream_endianness_, callback_type callback_ = callback_type())
566 : pdata(reinterpret_cast<char*>(begin_))
567 , length_chars(etl::distance(reinterpret_cast<unsigned char*>(begin_), reinterpret_cast<unsigned char*>(end_)))
568 , stream_endianness(stream_endianness_)
569 , callback(callback_)
570 {
571 restart();
572 }
573
574 //***************************************************************************
576 //***************************************************************************
577 bit_stream_writer(void* begin_, size_t length_chars_, etl::endian stream_endianness_, callback_type callback_ = callback_type())
578 : pdata(reinterpret_cast<char*>(begin_))
579 , length_chars(length_chars_)
580 , stream_endianness(stream_endianness_)
581 , callback(callback_)
582 {
583 restart();
584 }
585
586 //***************************************************************************
588 //***************************************************************************
589 void restart()
590 {
591 bits_available_in_char = CHAR_BIT;
592 char_index = 0U;
593 bits_available = capacity_bits();
594 }
595
596 //***************************************************************************
598 //***************************************************************************
599 size_t capacity_bytes() const
600 {
601 return length_chars;
602 }
603
604 //***************************************************************************
606 //***************************************************************************
607 size_t capacity_bits() const
608 {
609 return length_chars * CHAR_BIT;
610 }
611
612 //***************************************************************************
614 //***************************************************************************
615 bool empty() const
616 {
617 return (available_bits() == capacity_bits());
618 }
619
620 //***************************************************************************
622 //***************************************************************************
623 bool full() const
624 {
625 return (available_bits() == 0U);
626 }
627
628 //***************************************************************************
630 //***************************************************************************
631 void write_unchecked(bool value)
632 {
633 unsigned char chunk = value ? 1 : 0;
634 write_data<unsigned char>(chunk, 1);
635 }
636
637 //***************************************************************************
639 //***************************************************************************
640 bool write(bool value)
641 {
642 bool success = (available<1U>() > 0U);
643
644 if (success)
645 {
646 write_unchecked(value);
647 }
648
649 return success;
650 }
651
652 //***************************************************************************
654 //***************************************************************************
655 template <typename T>
657 write_unchecked(T value, uint_least8_t nbits = CHAR_BIT * sizeof(T))
658 {
659 typedef typename etl::unsigned_type<T>::type unsigned_t;
660
661 write_data<unsigned_t>(static_cast<unsigned_t>(value), nbits);
662 }
663
664 //***************************************************************************
666 //***************************************************************************
667 template <typename T>
669 write(T value, uint_least8_t nbits = CHAR_BIT * sizeof(T))
670 {
671 bool success = (available(nbits) > 0U);
672
673 if (success)
674 {
675 write_unchecked(value, nbits);
676 }
677
678 return success;
679 }
680
681 //***************************************************************************
685 //***************************************************************************
686 bool skip(size_t nbits)
687 {
688 bool success = (nbits <= available_bits());
689
690 if (success)
691 {
692 while (nbits > bits_available_in_char)
693 {
694 step(bits_available_in_char);
695 nbits -= bits_available_in_char;
696 }
697
698 if (nbits != 0U)
699 {
700 step(static_cast<unsigned char>(nbits));
701 }
702 }
703
704 return success;
705 }
706
707 //***************************************************************************
709 //***************************************************************************
710 size_t size_bytes() const
711 {
712 size_t s = char_index;
713
714 // Is the current byte partially used?
715 if (bits_available_in_char != CHAR_BIT)
716 {
717 ++s;
718 }
719
720 return s;
721 }
722
723 //***************************************************************************
725 //***************************************************************************
726 size_t size_bits() const
727 {
728 return capacity_bits() - available_bits();
729 }
730
731 //***************************************************************************
734 //***************************************************************************
735 template <size_t Nbits>
736 size_t available() const
737 {
738 return bits_available / Nbits;
739 }
740
741 //***************************************************************************
744 //***************************************************************************
745 template <typename T>
746 size_t available() const
747 {
749 }
750
751 //***************************************************************************
754 //***************************************************************************
755 size_t available(size_t nbits) const
756 {
757 return bits_available / nbits;
758 }
759
760 //***************************************************************************
762 //***************************************************************************
763 size_t available_bits() const
764 {
765 return bits_available;
766 }
767
768 //***************************************************************************
770 //***************************************************************************
771 iterator begin()
772 {
773 return pdata;
774 }
775
776 //***************************************************************************
778 //***************************************************************************
779 const_iterator begin() const
780 {
781 return pdata;
782 }
783
784 //***************************************************************************
786 //***************************************************************************
787 const_iterator cbegin() const
788 {
789 return pdata;
790 }
791
792 //***************************************************************************
794 //***************************************************************************
795 iterator end()
796 {
797 return pdata + size_bytes();
798 }
799
800 //***************************************************************************
802 //***************************************************************************
803 const_iterator end() const
804 {
805 return pdata + size_bytes();
806 }
807
808 //***************************************************************************
810 //***************************************************************************
811 const_iterator cend() const
812 {
813 return pdata + size_bytes();
814 }
815
816 //***************************************************************************
818 //***************************************************************************
820 {
821 return etl::span<char>(pdata, pdata + size_bytes());
822 }
823
824 //***************************************************************************
826 //***************************************************************************
828 {
829 return etl::span<const char>(pdata, pdata + size_bytes());
830 }
831
832 //***************************************************************************
834 //***************************************************************************
836 {
837 return etl::span<char>(pdata, pdata + length_chars);
838 }
839
840 //***************************************************************************
842 //***************************************************************************
844 {
845 return etl::span<const char>(pdata, pdata + length_chars);
846 }
847
848 //***************************************************************************
850 //***************************************************************************
851 void flush()
852 {
853 if (callback.is_valid())
854 {
855 if (bits_available_in_char != 0U)
856 {
857 char_index = 1U; // Indicate that the first char is actually 'full'.
858 flush_full_bytes();
859 }
860
861 restart();
862 }
863 }
864
865 //***************************************************************************
867 //***************************************************************************
868 void set_callback(callback_type callback_)
869 {
870 callback = callback_;
871 }
872
873 //***************************************************************************
875 //***************************************************************************
876 callback_type get_callback() const
877 {
878 return callback;
879 }
880
881 private:
882
883 //***************************************************************************
886 //***************************************************************************
887 template <typename T>
888 void write_data(T value, uint_least8_t nbits)
889 {
890 // Make sure that we are not writing more bits than should be available.
891 nbits = (nbits > (CHAR_BIT * sizeof(T))) ? (CHAR_BIT * sizeof(T)) : nbits;
892
893 if (stream_endianness == etl::endian::little)
894 {
895 value = etl::reverse_bits(value);
896 value = value >> ((CHAR_BIT * sizeof(T)) - nbits);
897 }
898
899 // Send the bits to the stream.
900 while (nbits != 0)
901 {
902 unsigned char mask_width = static_cast<unsigned char>(etl::min(nbits, bits_available_in_char));
903 nbits -= mask_width;
904 T mask = ((T(1U) << mask_width) - 1U) << nbits;
905
906 // Move chunk to lowest char bits.
907 // Chunks are never larger than one char.
908 T chunk = ((value & mask) >> nbits) << (bits_available_in_char - mask_width);
909
910 write_chunk(static_cast<char>(chunk), mask_width);
911 }
912
913 if (callback.is_valid())
914 {
915 flush_full_bytes();
916 }
917 }
918
919 //***************************************************************************
921 //***************************************************************************
922 void write_chunk(char chunk, unsigned char nbits)
923 {
924 // Clear if new byte.
925 if (bits_available_in_char == CHAR_BIT)
926 {
927 pdata[char_index] = 0U;
928 }
929
930 pdata[char_index] |= chunk;
931 step(nbits);
932 }
933
934 //***************************************************************************
937 //***************************************************************************
938 void flush_full_bytes()
939 {
940 // Is the first byte fully filled?
941 if (char_index > 0U)
942 {
943 callback(callback_parameter_type(pdata, pdata + char_index));
944
945 bits_available = CHAR_BIT * length_chars;
946
947 if (bits_available_in_char != 0U)
948 {
949 // Move a partially filled last byte to the start of the buffer.
950 pdata[0] = pdata[char_index];
951 bits_available -= (CHAR_BIT - bits_available_in_char);
952 }
953
954 char_index = 0U;
955 }
956 }
957
958 //***************************************************************************
961 //***************************************************************************
962 void step(unsigned char nbits)
963 {
964 bits_available_in_char -= nbits;
965
966 if (bits_available_in_char == 0)
967 {
968 ++char_index;
969 bits_available_in_char = CHAR_BIT;
970 }
971
972 bits_available -= nbits;
973 }
974
975 char* const pdata;
976 const size_t length_chars;
977 const etl::endian stream_endianness;
978 unsigned char bits_available_in_char;
979 size_t char_index;
980 size_t bits_available;
981 callback_type callback;
982 };
983
984 //***************************************************************************
987 //***************************************************************************
988 inline void write_unchecked(etl::bit_stream_writer& stream, bool value)
989 {
990 stream.write_unchecked(value);
991 }
992
993 //***************************************************************************
996 //***************************************************************************
997 inline bool write(etl::bit_stream_writer& stream, bool value)
998 {
999 return stream.write(value);
1000 }
1001
1002 //***************************************************************************
1006 //***************************************************************************
1007 template <typename T>
1008 typename etl::enable_if<etl::is_integral<T>::value, void>::type
1009 write_unchecked(etl::bit_stream_writer& stream, const T& value, uint_least8_t nbits = CHAR_BIT * sizeof(T))
1010 {
1011 stream.write_unchecked(value, nbits);
1012 }
1013
1014 //***************************************************************************
1018 //***************************************************************************
1019 template <typename T>
1020 typename etl::enable_if<etl::is_integral<T>::value, bool>::type
1021 write(etl::bit_stream_writer& stream, const T& value, uint_least8_t nbits = CHAR_BIT * sizeof(T))
1022 {
1023 return stream.write(value, nbits);
1024 }
1025
1026 //***************************************************************************
1028 //***************************************************************************
1030 {
1031 public:
1032
1033 typedef char value_type;
1034 typedef const char* const_iterator;
1035
1036 //***************************************************************************
1038 //***************************************************************************
1039 template <size_t Length>
1041 : pdata(span_.begin())
1042 , length_chars(span_.size_bytes())
1043 , stream_endianness(stream_endianness_)
1044 {
1045 restart();
1046 }
1047
1048 //***************************************************************************
1050 //***************************************************************************
1051 template <size_t Length>
1053 : pdata(reinterpret_cast<const char*>(span_.begin()))
1054 , length_chars(span_.size_bytes())
1055 , stream_endianness(stream_endianness_)
1056 {
1057 restart();
1058 }
1059
1060 //***************************************************************************
1062 //***************************************************************************
1063 template <size_t Length>
1065 : pdata(span_.begin())
1066 , length_chars(span_.size_bytes())
1067 , stream_endianness(stream_endianness_)
1068 {
1069 restart();
1070 }
1071
1072 //***************************************************************************
1074 //***************************************************************************
1075 template <size_t Length>
1077 : pdata(reinterpret_cast<const char*>(span_.begin()))
1078 , length_chars(span_.size_bytes())
1079 , stream_endianness(stream_endianness_)
1080 {
1081 restart();
1082 }
1083
1084 //***************************************************************************
1086 //***************************************************************************
1087 bit_stream_reader(const void* begin_, const void* end_, etl::endian stream_endianness_)
1088 : pdata(reinterpret_cast<const char*>(begin_))
1089 , length_chars(etl::distance(reinterpret_cast<const char*>(begin_), reinterpret_cast<const char*>(end_)))
1090 , stream_endianness(stream_endianness_)
1091 {
1092 restart();
1093 }
1094
1095 //***************************************************************************
1097 //***************************************************************************
1098 bit_stream_reader(const void* begin_, size_t length_, etl::endian stream_endianness_)
1099 : pdata(reinterpret_cast<const char*>(begin_))
1100 , length_chars(length_)
1101 , stream_endianness(stream_endianness_)
1102 {
1103 restart();
1104 }
1105
1106 //***************************************************************************
1108 //***************************************************************************
1109 void restart()
1110 {
1111 bits_available_in_char = CHAR_BIT;
1112 char_index = 0U;
1113 bits_available = CHAR_BIT * length_chars;
1114 }
1115
1116 //***************************************************************************
1118 //***************************************************************************
1119 template <typename T>
1122 {
1123 return get_bit();
1124 }
1125
1126 //***************************************************************************
1128 //***************************************************************************
1129 template <typename T>
1132 {
1133 etl::optional<bool> result;
1134
1135 if (bits_available > 0U)
1136 {
1137 result = read_unchecked<bool>();
1138 }
1139
1140 return result;
1141 }
1142
1143 //***************************************************************************
1145 //***************************************************************************
1146 template <typename T>
1148 read_unchecked(uint_least8_t nbits = CHAR_BIT * sizeof(T))
1149 {
1150 typedef typename etl::unsigned_type<T>::type unsigned_t;
1151
1152 T value = read_value<unsigned_t>(nbits, etl::is_signed<T>::value);
1153
1154 return static_cast<T>(value);
1155 }
1156
1157 //***************************************************************************
1159 //***************************************************************************
1160 template <typename T>
1162 read(uint_least8_t nbits = CHAR_BIT * sizeof(T))
1163 {
1164 etl::optional<T> result;
1165
1166 // Do we have enough bits?
1167 if (bits_available >= nbits)
1168 {
1169 result = read_unchecked<T>(nbits);
1170 }
1171
1172 return result;
1173 }
1174
1175 //***************************************************************************
1177 //***************************************************************************
1178 size_t size_bytes() const
1179 {
1180 return length_chars;
1181 }
1182
1183 //***************************************************************************
1185 //***************************************************************************
1186 size_t size_bits() const
1187 {
1188 return length_chars * CHAR_BIT;
1189 }
1190
1191 //***************************************************************************
1193 //***************************************************************************
1194 const_iterator begin() const
1195 {
1196 return pdata;
1197 }
1198
1199 //***************************************************************************
1201 //***************************************************************************
1202 const_iterator cbegin() const
1203 {
1204 return pdata;
1205 }
1206
1207 //***************************************************************************
1209 //***************************************************************************
1210 const_iterator end() const
1211 {
1212 return pdata + size_bytes();
1213 }
1214
1215 //***************************************************************************
1217 //***************************************************************************
1218 const_iterator cend() const
1219 {
1220 return pdata + size_bytes();
1221 }
1222
1223 //***************************************************************************
1225 //***************************************************************************
1227 {
1228 return etl::span<const char>(pdata, pdata + length_chars);
1229 }
1230
1231 //***************************************************************************
1235 //***************************************************************************
1236 bool skip(size_t nbits)
1237 {
1238 bool success = (nbits <= bits_available);
1239
1240 if (success)
1241 {
1242 while (nbits > bits_available_in_char)
1243 {
1244 nbits -= bits_available_in_char;
1245 step(bits_available_in_char);
1246 }
1247
1248 if (nbits != 0U)
1249 {
1250 step(static_cast<unsigned char>(nbits));
1251 }
1252 }
1253
1254 return success;
1255 }
1256
1257 private:
1258
1259 //***************************************************************************
1262 //***************************************************************************
1263 template <typename T>
1264 T read_value(uint_least8_t nbits, bool is_signed)
1265 {
1266 // Make sure that we are not reading more bits than should be available.
1267 nbits = (nbits > (CHAR_BIT * sizeof(T))) ? (CHAR_BIT * sizeof(T)) : nbits;
1268
1269 T value = 0;
1270 uint_least8_t bits = nbits;
1271
1272 // Get the bits from the stream.
1273 while (nbits != 0)
1274 {
1275 unsigned char mask_width = static_cast<unsigned char>(etl::min(nbits, bits_available_in_char));
1276
1277 T chunk = get_chunk(mask_width);
1278
1279 nbits -= mask_width;
1280 value |= static_cast<T>(chunk << nbits);
1281 }
1282
1283 if (stream_endianness == etl::endian::little)
1284 {
1285 value = value << ((CHAR_BIT * sizeof(T)) - bits);
1286 value = etl::reverse_bits(value);
1287 }
1288
1289 if (is_signed && (bits != (CHAR_BIT * sizeof(T))))
1290 {
1291 value = etl::sign_extend<T, T>(value, bits);
1292 }
1293
1294 return value;
1295 }
1296
1297 //***************************************************************************
1299 //***************************************************************************
1300 unsigned char get_chunk(unsigned char nbits)
1301 {
1302 unsigned char value = pdata[char_index];
1303 value >>= (bits_available_in_char - nbits);
1304
1305 unsigned char mask;
1306
1307 if (nbits == CHAR_BIT)
1308 {
1309 mask = etl::integral_limits<unsigned char>::max;
1310 }
1311 else
1312 {
1313 mask = (1U << nbits) - 1;
1314 }
1315
1316 value &= mask;
1317
1318 step(nbits);
1319
1320 return value;
1321 }
1322
1323 //***************************************************************************
1325 //***************************************************************************
1326 bool get_bit()
1327 {
1328 bool result = (pdata[char_index] & (1U << (bits_available_in_char - 1U))) != 0U;
1329
1330 step(1U);
1331
1332 return result;
1333 }
1334
1335 //***************************************************************************
1338 //***************************************************************************
1339 void step(unsigned char nbits)
1340 {
1341 bits_available_in_char -= nbits;
1342
1343 if (bits_available_in_char == 0)
1344 {
1345 ++char_index;
1346 bits_available_in_char = 8;
1347 }
1348
1349 bits_available -= nbits;
1350 }
1351
1352 const char* pdata;
1353 size_t length_chars;
1354 const etl::endian stream_endianness;
1355 unsigned char bits_available_in_char;
1356 size_t char_index;
1357 size_t bits_available;
1358 };
1359
1360 //***************************************************************************
1362 //***************************************************************************
1363 template <typename T>
1365 {
1366 return stream.read_unchecked<T>();
1367 }
1368
1369 template <typename T>
1370 T read_unchecked(etl::bit_stream_reader& stream, uint_least8_t nbits)
1371 {
1372 return stream.read_unchecked<T>(nbits);
1373 }
1374
1375 //***************************************************************************
1377 //***************************************************************************
1378 template <typename T>
1380 {
1381 return stream.read<T>();
1382 }
1383
1384 template <typename T>
1385 etl::optional<T> read(etl::bit_stream_reader& stream, uint_least8_t nbits)
1386 {
1387 return stream.read<T>(nbits);
1388 }
1389
1390 //***************************************************************************
1392 //***************************************************************************
1393 template <>
1395 {
1396 return stream.read_unchecked<bool>();
1397 }
1398
1399 //***************************************************************************
1401 //***************************************************************************
1402 template <>
1404 {
1405 return stream.read<bool>();
1406 }
1407}
1408
1409#include "private/minmax_pop.h"
1410
1411#endif
Reads bit streams.
Definition bit_stream.h:1030
etl::enable_if< etl::is_same< bool, T >::value, etl::optional< bool > >::type read()
For bool types.
Definition bit_stream.h:1131
const_iterator end() const
Returns end of the stream.
Definition bit_stream.h:1210
bit_stream_reader(const etl::span< const unsigned char, Length > &span_, etl::endian stream_endianness_)
Construct from span.
Definition bit_stream.h:1076
const_iterator cend() const
Returns end of the stream.
Definition bit_stream.h:1218
bit_stream_reader(const etl::span< char, Length > &span_, etl::endian stream_endianness_)
Construct from span.
Definition bit_stream.h:1040
size_t size_bits() const
Returns the number of bits in the stream buffer.
Definition bit_stream.h:1186
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:1148
bit_stream_reader(const void *begin_, size_t length_, etl::endian stream_endianness_)
Construct from begin and length.
Definition bit_stream.h:1098
bool skip(size_t nbits)
Definition bit_stream.h:1236
bit_stream_reader(const etl::span< const char, Length > &span_, etl::endian stream_endianness_)
Construct from span.
Definition bit_stream.h:1064
bit_stream_reader(const void *begin_, const void *end_, etl::endian stream_endianness_)
Construct from range.
Definition bit_stream.h:1087
bit_stream_reader(const etl::span< unsigned char, Length > &span_, etl::endian stream_endianness_)
Construct from span.
Definition bit_stream.h:1052
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:1162
void restart()
Sets the indexes back to the beginning of the stream.
Definition bit_stream.h:1109
const_iterator cbegin() const
Returns start of the stream.
Definition bit_stream.h:1202
etl::enable_if< etl::is_same< bool, T >::value, bool >::type read_unchecked()
For bool types.
Definition bit_stream.h:1121
etl::span< const char > data() const
Returns a span of whole the stream.
Definition bit_stream.h:1226
const_iterator begin() const
Returns start of the stream.
Definition bit_stream.h:1194
size_t size_bytes() const
Returns the number of bytes in the stream buffer.
Definition bit_stream.h:1178
Writes bits streams.
Definition bit_stream.h:527
bit_stream_writer(void *begin_, void *end_, etl::endian stream_endianness_, callback_type callback_=callback_type())
Construct from range.
Definition bit_stream.h:565
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:669
size_t size_bytes() const
Returns the number of bytes used in the stream.
Definition bit_stream.h:710
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:657
etl::span< const char > used_data() const
Returns a span of the used portion of the stream.
Definition bit_stream.h:827
bool write(bool value)
Writes a boolean to the stream.
Definition bit_stream.h:640
size_t size_bits() const
Returns the number of bits used in the stream.
Definition bit_stream.h:726
size_t available_bits() const
The number of bits left in the stream.
Definition bit_stream.h:763
const_iterator cend() const
Returns end of the stream.
Definition bit_stream.h:811
callback_type get_callback() const
Gets the function to call after every write.
Definition bit_stream.h:876
bool empty() const
Returns true if the bitsteam indexes have been reset.
Definition bit_stream.h:615
bit_stream_writer(void *begin_, size_t length_chars_, etl::endian stream_endianness_, callback_type callback_=callback_type())
Construct from begin and length.
Definition bit_stream.h:577
bit_stream_writer(const etl::span< unsigned char, Length > &span_, etl::endian stream_endianness_, callback_type callback_=callback_type())
Construct from span.
Definition bit_stream.h:553
bit_stream_writer(const etl::span< char, Length > &span_, etl::endian stream_endianness_, callback_type callback_=callback_type())
Construct from span.
Definition bit_stream.h:540
iterator end()
Returns end of the stream.
Definition bit_stream.h:795
void set_callback(callback_type callback_)
Sets the function to call after every write.
Definition bit_stream.h:868
size_t available() const
Definition bit_stream.h:736
etl::span< char > data()
Returns a span of whole the stream.
Definition bit_stream.h:835
bool full() const
Returns true if the bitsteam indexes have reached the end.
Definition bit_stream.h:623
bool skip(size_t nbits)
Definition bit_stream.h:686
size_t capacity_bits() const
Returns the maximum capacity in bits.
Definition bit_stream.h:607
etl::span< char > used_data()
Returns a span of the used portion of the stream.
Definition bit_stream.h:819
size_t capacity_bytes() const
Returns the maximum capacity in bytes.
Definition bit_stream.h:599
etl::span< const char > data() const
Returns a span of whole the stream.
Definition bit_stream.h:843
void restart()
Sets the indexes back to the beginning of the stream.
Definition bit_stream.h:589
void write_unchecked(bool value)
Writes a boolean to the stream.
Definition bit_stream.h:631
void flush()
Flush the last byte, if partially filled, to the callback, if valid.
Definition bit_stream.h:851
const_iterator cbegin() const
Returns start of the stream.
Definition bit_stream.h:787
size_t available(size_t nbits) const
Definition bit_stream.h:755
const_iterator end() const
Returns end of the stream.
Definition bit_stream.h:803
const_iterator begin() const
Returns start of the stream.
Definition bit_stream.h:779
iterator begin()
Returns start of the stream.
Definition bit_stream.h:771
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:223
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:152
bool put(int64_t value, uint_least8_t nbits=CHAR_BIT *sizeof(int64_t))
For 64bit integral types.
Definition bit_stream.h:161
etl::enable_if< etl::is_floating_point< T >::value, bool >::type put(T value)
For floating point types.
Definition bit_stream.h:180
void restart()
Sets the indexes back to the beginning of the stream.
Definition bit_stream.h:112
size_t size() const
Returns the number of bytes used in the stream.
Definition bit_stream.h:297
size_t bits() const
Returns the number of bits used in the stream.
Definition bit_stream.h:313
bit_stream(void *begin_, void *end_)
Construct from range.
Definition bit_stream.h:74
bool put(uint64_t value, uint_least8_t nbits=CHAR_BIT *sizeof(uint64_t))
For 64bit integral types.
Definition bit_stream.h:169
bit_stream(void *begin_, size_t length_)
Construct from begin and length.
Definition bit_stream.h:84
etl::enable_if< etl::is_floating_point< T >::value, bool >::type get(T &value)
For floating point types.
Definition bit_stream.h:266
bool at_end() const
Returns true if the bitsteam indexes have reached the end.
Definition bit_stream.h:122
bool put(bool value)
Writes a boolean to the stream.
Definition bit_stream.h:130
bit_stream()
Default constructor.
Definition bit_stream.h:64
bool get(bool &value)
For bool types.
Definition bit_stream.h:201
void set_stream(void *begin_, size_t length_)
Construct from begin and length.
Definition bit_stream.h:94
void set_stream(void *begin_, void *end_)
Construct from range.
Definition bit_stream.h:104
const_iterator end() const
Returns end of the stream.
Definition bit_stream.h:329
const_iterator begin() const
Returns start of the stream.
Definition bit_stream.h:321
Declaration.
Definition delegate_cpp03.h:191
Definition optional.h:1321
Span - Fixed Extent.
Definition span.h:138
Definition memory.h:2183
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 TReturn sign_extend(TValue value)
Definition binary.h:272
Definition endianness.h:100
enable_if
Definition type_traits_generator.h:1254
is_same
Definition type_traits_generator.h:1104
is_signed
Definition type_traits_generator.h:1074
make_signed
Definition type_traits_generator.h:1234
make_unsigned
Definition type_traits_generator.h:1244
bitset_ext
Definition absolute.h:39
bool read_unchecked< bool >(etl::bit_stream_reader &stream)
Read an unchecked bool from a stream.
Definition bit_stream.h:1394
etl::optional< T > read(etl::bit_stream_reader &stream)
Read a checked type from a stream.
Definition bit_stream.h:1379
void write_unchecked(etl::bit_stream_writer &stream, bool value)
Definition bit_stream.h:988
etl::optional< bool > read< bool >(etl::bit_stream_reader &stream)
Read a bool from a stream.
Definition bit_stream.h:1403
T read_unchecked(etl::bit_stream_reader &stream)
Read an unchecked type from a stream.
Definition bit_stream.h:1364
bool write(etl::bit_stream_writer &stream, bool value)
Definition bit_stream.h:997