jaulib v1.4.0-2-g788cf73
Jau Support Library (C++, Java, ..)
Loading...
Searching...
No Matches
test_bitstream01.cpp
Go to the documentation of this file.
1/*
2 * Author: Sven Gothel <sgothel@jausoft.com>
3 * Copyright (c) 2021-2025 Gothel Software e.K.
4 *
5 * SPDX-License-Identifier: MIT
6 *
7 * This Source Code Form is subject to the terms of the MIT License
8 * If a copy of the MIT was not distributed with this file,
9 * you can obtain one at https://opensource.org/license/mit/.
10 */
11
12#include <cassert>
13#include <cstddef>
14#include <cstdint>
15#include <cstdlib>
16#include <cstring>
17#include <memory>
18
19#include <jau/basic_types.hpp>
20#include <jau/bitfield.hpp>
21#include <jau/bitheap.hpp>
22#include <jau/debug.hpp>
23#include <jau/int_types.hpp>
24#include <jau/io/bit_stream.hpp>
26#include <jau/io/file_util.hpp>
27#include <jau/io/io_util.hpp>
28#include <jau/string_util.hpp>
29#include <jau/test/catch2_ext.hpp>
30
31// #include "test_httpd.hpp"
32#include "data_bitstream.hpp"
33
34extern "C" {
35#include <unistd.h>
36}
37
38using namespace jau::fractions_i64_literals;
39using jau::nsize_t;
40// using size_type = jau::io::Bitstream::size_type;
41
42TEST_CASE( "Bitstream Test 00", "[bitstream]" ) {
43 REQUIRE( true == true );
44}
45
46static jau::bitheap getBitfield(const jau::nsize_t bitCount, const jau::bit_order_t bitOrder) {
47 jau::bitheap source(bitCount);
48 std::string_view in = BitDemoData::testStringMSB64_be;
49
50 // msb 1111101011011110101011111111111011011110101011111100101011111110
51 // lsb 0111111101010011111101010111101101111111111101010111101101011111
52 //
53 // msb 11111010 11011110 10101111 11111110 11011110 10101111 11001010 11111110
54 // lsb 01111111 01010011 11110101 01111011 01111111 11110101 01111011 01011111
55 for(size_t i=0; i<bitCount; ) {
56 for(size_t j=64; i<bitCount && j-- > 0; ++i) {
57 REQUIRE(true == source.put(i, in[j] == '1'));
58 }
59 }
60 if( jau::bit_order_t::msb != bitOrder ) {
61 source.reverse();
62 }
63 return source;
64}
65
67 const nsize_t preBits, const nsize_t skipBits, const nsize_t postBits) {
68 const nsize_t bitCount = preBits + skipBits + postBits;
69 const nsize_t byteCount = (bitCount + 7) / 8;
70 jau::bitheap source = getBitfield(bitCount, dataBitOrder);
71 jau::io::Bitstream bsTest(std::make_unique<jau::io::ByteStream_SecMemory>(byteCount, jau::io::iomode_t::rw), jau::io::ioaccess_t::write);
72 fprintf(stderr, "TestStream.0: bitOrder[data %s], bits[pre %zu, skip %zu, post %zu = %zu]: %s\n",
73 jau::to_string(dataBitOrder).c_str(),
74 (size_t)preBits, (size_t)skipBits, (size_t)postBits, (size_t)bitCount, bsTest.toString().c_str());
75 std::cerr << source << "\n";
76
77 for( nsize_t i = 0; i < bitCount; i++ ) {
78 REQUIRE(true == bsTest.writeBit(source[i]) );
79 // fprintf(stderr, "TestData.1a: i %zu, %s\n", (size_t)i, bsTest.toString().c_str());
80 }
81 CHECK(preBits + skipBits + postBits == bsTest.position());
82
83 REQUIRE(true == bsTest.setAccess(jau::io::ioaccess_t::read)); // switch to input-mode, implies flush()
84 fprintf(stderr, "TestData.X: %s\n", bsTest.toString().c_str());
85 REQUIRE(0 == bsTest.seek(0));
86 BitDemoData::dumpData("TestStream.X", bsTest.byteStream());
87 return bsTest;
88}
89
90static std::string getTestStreamResultAsString(const jau::bit_order_t dataBitOrder,
91 const jau::nsize_t preBits, const jau::nsize_t skipBits, const jau::nsize_t postBits) {
92 const jau::nsize_t totalBits = preBits+postBits;
93 fprintf(stderr,"TestString: bitOrder %s, preBits %zu, skipBits %zu, postBits %zu, totalBits %zu\n",
94 jau::to_string(dataBitOrder).c_str(), (size_t)preBits, (size_t)skipBits, (size_t)postBits, (size_t)totalBits);
95
96 jau::bitheap source = getBitfield(preBits+skipBits+postBits, dataBitOrder);
97 std::cerr << source << "\n";
98 const auto [pre, preOK] = source.subbits(0, preBits);
99 const auto [post, postOK] = source.subbits(preBits+skipBits, postBits);
100 REQUIRE(true == preOK);
101 REQUIRE(true == postOK);
102
103 jau::bitheap r(preBits+postBits);
104 REQUIRE(true == r.put(0, pre));
105 REQUIRE(true == r.put(preBits, post));
106 std::cerr << "ResultExp: <" << pre << "> + <" << post << "> = <" << r << ">\n";
107 REQUIRE(totalBits == r.size());
108 return r.toString();
109}
110
111static std::string readBits(jau::io::Bitstream *copy, jau::io::Bitstream &input,
112 const nsize_t preCount, const nsize_t count) /* throws IOException */ {
113 fprintf(stderr, "ReadBits.0: count[pre %zu, actual %zu]: %s\n", (size_t)preCount, (size_t)count, input.toString().c_str());
114 if( copy ) {
115 fprintf(stderr, "ReadBits.0c: %s\n", copy->toString().c_str());
116 }
117 std::string sbRead;
118 nsize_t i = 0;
119 while( i < count ) {
120 const int bit = input.readBit();
121 if( 0 > bit ) {
122 // fprintf(stderr, "ReadBits.1: EOS: i %zu, %s\n", (size_t)i, input.toString().c_str());
123 break;
124 } else {
125 const char c = ( 0 != bit ) ? '1' : '0';
126 sbRead.insert(0, 1, c);
127 i++;
128 // fprintf(stderr, "ReadBits.1: i %zu, '%c' -> %s, %s\n", (size_t)i, c, sbRead.c_str(), input.toString().c_str());
129 REQUIRE(i+preCount == input.position());
130 if( copy ) {
131 REQUIRE(true == copy->writeBit(bit));
132 // fprintf(stderr, "ReadBits.1c: i %zu, %s\n", (size_t)i, copy->toString().c_str());
133 REQUIRE(i+preCount == copy->position());
134 }
135 }
136 }
137 fprintf(stderr, "ReadBits.2: %s\n", input.toString().c_str());
138 REQUIRE(i+preCount == input.position());
139 if( copy ) {
140 fprintf(stderr, "ReadBits.2c: %s\n", copy->toString().c_str());
141 REQUIRE(i+preCount == copy->position());
142 }
143 return sbRead;
144}
145
146static void testLinearBitsImpl(const jau::bit_order_t bitOrder, const nsize_t preBits, const nsize_t skipBits, const nsize_t postBits) {
147 const nsize_t totalBits = preBits+skipBits+postBits;
148 fprintf(stderr,"XXX TestLinearBits: bitOrder %s, preBits %zu, skipBits %zu, postBits %zu, totalBits %zu\n",
149 jau::to_string(bitOrder).c_str(), (size_t)preBits, (size_t)skipBits, (size_t)postBits, (size_t)totalBits);
150
151 // prepare bitstream
152 std::cerr << "Prepare bitstream\n";
153 jau::io::Bitstream bsTest = getTestStream(bitOrder, preBits, skipBits, postBits);
154 const std::string sTest = getTestStreamResultAsString(bitOrder, preBits, skipBits, postBits);
155
156 // init copy-bitstream
157 const nsize_t byteCount = ( totalBits + 7 ) / 8;
158 jau::io::Bitstream bsCopy(std::make_unique<jau::io::ByteStream_SecMemory>(byteCount, jau::io::iomode_t::rw), jau::io::ioaccess_t::write);
159
160 // read-bitstream .. and copy bits while reading
161 std::cerr << "Reading bitstream: <" << sTest << "> from " << bsTest << "\n";
162 {
163 const std::string sReadPre = readBits(&bsCopy, bsTest, 0, preBits);
164 REQUIRE(skipBits == bsTest.skip(skipBits));
165 REQUIRE(skipBits == bsCopy.skip(skipBits));
166
167 const std::string sReadPost = readBits(&bsCopy, bsTest, preBits+skipBits, postBits);
168 const std::string sRead = sReadPost + sReadPre;
169 std::cerr << "Read.Test: <" << sTest << "> == <" << sReadPre << "> + <" << sReadPost << "> = <" << sRead << ">\n";
170 REQUIRE(sTest == sRead);
171 REQUIRE(totalBits == bsTest.position());
172 REQUIRE(totalBits == bsCopy.position());
173 }
174
175 // read copy ..
176 REQUIRE(true == bsCopy.setImmutable()); // switch to input-mode, implies flush()
177 BitDemoData::dumpData("Copy", bsCopy.byteStream());
178 REQUIRE(0 == bsTest.seek(0));
179
180 std::cerr << "Reading copy-bitstream: " << bsCopy << "\n";
181 REQUIRE(true == bsCopy.setMark(0)); // mark at beginning
182 REQUIRE(0 == bsCopy.position());
183 {
184 const std::string sReadPre1 = readBits( nullptr, bsCopy, 0, preBits);
185 REQUIRE(skipBits == bsCopy.skip(skipBits));
186
187 const std::string sReadPost1 = readBits(nullptr, bsCopy, preBits+skipBits, postBits);
188 const std::string sRead1 = sReadPost1 + sReadPre1;
189 REQUIRE(sTest == sRead1);
190
191 REQUIRE(true == bsCopy.seekMark());
192 const std::string sReadPre2 = readBits(nullptr, bsCopy, 0, preBits);
193 REQUIRE(sReadPre1 == sReadPre2);
194 REQUIRE(skipBits == bsCopy.skip(skipBits));
195
196 const std::string sReadPost2 = readBits(nullptr, bsCopy, preBits+skipBits, postBits);
197 REQUIRE(sReadPost1 == sReadPost2);
198 const std::string sRead2 = sReadPost2 + sReadPre2;
199 REQUIRE(sTest == sRead2);
200 REQUIRE(totalBits == bsCopy.position());
201 }
202}
203
204static void testLinearBitsImpl(const jau::bit_order_t bitOrder) {
205 testLinearBitsImpl(bitOrder, 0, 0, 1);
206 testLinearBitsImpl(bitOrder, 0, 0, 3);
207 testLinearBitsImpl(bitOrder, 0, 0, 7);
208 testLinearBitsImpl(bitOrder, 0, 0, 8);
209 testLinearBitsImpl(bitOrder, 0, 0, 9);
210 testLinearBitsImpl(bitOrder, 0, 0, 20);
211 testLinearBitsImpl(bitOrder, 0, 0, 31);
212 testLinearBitsImpl(bitOrder, 0, 0, 32);
213 testLinearBitsImpl(bitOrder, 0, 0, 33);
214 testLinearBitsImpl(bitOrder, 0, 0, 63);
215 testLinearBitsImpl(bitOrder, 0, 0, 64);
216 testLinearBitsImpl(bitOrder, 0, 0, 65);
217 testLinearBitsImpl(bitOrder, 0, 0, 80);
218 testLinearBitsImpl(bitOrder, 0, 0, 127);
219 testLinearBitsImpl(bitOrder, 0, 0, 128);
220 testLinearBitsImpl(bitOrder, 0, 0, 129);
221 testLinearBitsImpl(bitOrder, 0, 0, 140);
222
223 testLinearBitsImpl(bitOrder, 3, 0, 3);
224 testLinearBitsImpl(bitOrder, 8, 0, 3);
225 testLinearBitsImpl(bitOrder, 9, 0, 3);
226
227 testLinearBitsImpl(bitOrder, 0, 1, 1);
228 testLinearBitsImpl(bitOrder, 0, 1, 3);
229 testLinearBitsImpl(bitOrder, 0, 2, 8);
230 testLinearBitsImpl(bitOrder, 0, 8, 10);
231 testLinearBitsImpl(bitOrder, 0, 12, 20);
232 testLinearBitsImpl(bitOrder, 0, 23, 9);
233
234 testLinearBitsImpl(bitOrder, 1, 1, 1);
235 testLinearBitsImpl(bitOrder, 2, 1, 3);
236 testLinearBitsImpl(bitOrder, 7, 2, 8);
237 testLinearBitsImpl(bitOrder, 8, 8, 8);
238 testLinearBitsImpl(bitOrder, 15, 12, 5);
239 testLinearBitsImpl(bitOrder, 16, 11, 5);
240}
241
242TEST_CASE( "Bitstream Test 01 LinearBitsMSBFirst", "[bitstream]" ) {
244}
245
246TEST_CASE( "Bitstream Test 02 LinearBitsLSBFirst", "[bitstream]" ) {
248}
249
250//
251//
252//
253
254static void testBulkBitsImpl(const nsize_t preBits, const nsize_t skipBits, const nsize_t postBits) /* throws IOException */ {
255 const nsize_t totalBits = preBits+skipBits+postBits;
256 fprintf(stderr,"XXX TestBulkBits: preBits %zu, skipBits %zu, postBits %zu, totalBits %zu\n",
257 (size_t)preBits, (size_t)skipBits, (size_t)postBits, (size_t)totalBits);
258
259 // prepare bitstream
260 std::cerr << "Prepare bitstream\n";
261 jau::io::Bitstream bsTest = getTestStream(jau::bit_order_t::msb, preBits, skipBits, postBits);
262 const std::string sTest = getTestStreamResultAsString(jau::bit_order_t::msb, preBits, skipBits, postBits);
263
264 // init copy-bitstream
265 const nsize_t byteCount = ( totalBits + 7 ) / 8;
266 jau::io::Bitstream bsCopy(std::make_unique<jau::io::ByteStream_SecMemory>(byteCount, jau::io::iomode_t::rw), jau::io::ioaccess_t::write);
267
268 // read-bitstream .. and copy bits while reading
269 std::cerr << "Reading bitstream: <" << sTest << "> from " << bsTest << "\n";
270 {
271 uint64_t readBitsPre;
272 REQUIRE(preBits == bsTest.readBits64(preBits, readBitsPre));
273 REQUIRE(preBits == bsCopy.writeBits64(preBits, readBitsPre));
274
275 REQUIRE(skipBits == bsTest.skip(skipBits));
276 REQUIRE(skipBits == bsCopy.skip(skipBits));
277
278 uint64_t readBitsPost;
279 REQUIRE(postBits == bsTest.readBits64(postBits, readBitsPost));
280 REQUIRE(postBits == bsCopy.writeBits64(postBits, readBitsPost));
281
282 const std::string sReadPreLo = preBits > 0 ? jau::toBitString(readBitsPre, jau::bit_order_t::msb,jau::PrefixOpt::none, preBits) : "";
283 const std::string sReadPostHi = postBits > 0 ? jau::toBitString(readBitsPost, jau::bit_order_t::msb, jau::PrefixOpt::none, postBits) : "";
284 const std::string sRead = sReadPostHi + sReadPreLo;
285 std::cerr << "Read.Test: <" << sTest << "> == <" << sReadPreLo << "> + <" << sReadPostHi << "> = <" << sRead << ">\n";
286
287 REQUIRE(sTest == sRead);
288 REQUIRE(totalBits == bsTest.position());
289 REQUIRE(totalBits == bsCopy.position());
290 }
291
292 // read copy ..
293 REQUIRE(true == bsCopy.setImmutable()); // switch to input-mode, implies flush()
294 BitDemoData::dumpData("Copy: ", bsCopy.byteStream());
295
296 std::cerr << "Reading copy-bitstream: " << bsCopy << "\n";
297 REQUIRE(true == bsCopy.setMark(0)); // mark at beginning
298 REQUIRE(0 == bsCopy.position());
299 {
300 uint64_t copyBitsPre;
301 REQUIRE(preBits == bsCopy.readBits64(preBits, copyBitsPre));
302 REQUIRE(skipBits == bsCopy.skip(skipBits));
303
304 uint64_t copyBitsPost;
305 REQUIRE(postBits == bsCopy.readBits64(postBits, copyBitsPost));
306
307 const std::string sReadPreLo = preBits > 0 ? jau::toBitString(copyBitsPre, jau::bit_order_t::msb,jau::PrefixOpt::none, preBits) : "";
308 const std::string sReadPostHi = postBits > 0 ? jau::toBitString(copyBitsPost, jau::bit_order_t::msb, jau::PrefixOpt::none, postBits) : "";
309 const std::string sRead = sReadPostHi + sReadPreLo;
310 std::cerr << "Copy.Test: <" << sTest << "> == <" << sReadPreLo << "> + <" << sReadPostHi << "> = <" << sRead << ">\n";
311
312 REQUIRE(sTest == sRead);
313 REQUIRE(totalBits == bsCopy.position());
314 }
315}
316
317TEST_CASE( "Bitstream Test 11 BulkBitsLSBFirst", "[bitstream]" ) {
318 testBulkBitsImpl(0, 0, 1);
319 testBulkBitsImpl(0, 0, 3);
320 testBulkBitsImpl(0, 0, 8);
321 testBulkBitsImpl(0, 0, 10);
322 testBulkBitsImpl(0, 0, 30);
323 testBulkBitsImpl(0, 0, 31);
324
325 testBulkBitsImpl(3, 0, 3);
326 testBulkBitsImpl(8, 0, 3);
327 testBulkBitsImpl(9, 0, 3);
328 testBulkBitsImpl(5, 0, 6);
329 testBulkBitsImpl(5, 0, 8);
330
331 testBulkBitsImpl(0, 1, 1);
332 testBulkBitsImpl(3, 6, 4);
333
334 testBulkBitsImpl(0, 1, 3);
335 testBulkBitsImpl(0, 2, 8);
336 testBulkBitsImpl(0, 8, 10);
337 testBulkBitsImpl(0, 12, 20);
338 testBulkBitsImpl(0, 23, 9);
339 testBulkBitsImpl(0, 1, 31);
340
341 testBulkBitsImpl(1, 1, 1);
342 testBulkBitsImpl(2, 1, 3);
343 testBulkBitsImpl(7, 2, 8);
344 testBulkBitsImpl(8, 8, 8);
345 testBulkBitsImpl(15, 12, 5);
346 testBulkBitsImpl(16, 11, 5);
347 testBulkBitsImpl(5, 6, 5);
348 testBulkBitsImpl(5, 6, 8);
349}
350
351TEST_CASE( "Bitstream Test 21 ErrorHandling", "[bitstream]" ) {
352 jau::io::Bitstream bsTest(std::make_unique<jau::io::ByteStream_SecMemory>(64, jau::io::iomode_t::rw), jau::io::ioaccess_t::write);
353 std::cerr << "x0 " << bsTest << "\n";
354 std::cerr << "x0 " << bsTest.byteStream() << "\n";
355
356 REQUIRE(true == bsTest.canWrite());
357 REQUIRE(-1 == bsTest.readBit());
358
359 REQUIRE(true == bsTest.setAccess(jau::io::ioaccess_t::read));
360 REQUIRE(false == bsTest.canWrite());
361 REQUIRE(false == bsTest.writeBit(1));
362
363 REQUIRE(true == bsTest.setAccess(jau::io::ioaccess_t::write));
364 REQUIRE(true == bsTest.canWrite());
365 REQUIRE(true == bsTest.writeBit(1));
366
367 REQUIRE(true == bsTest.setAccess(jau::io::ioaccess_t::read));
368 REQUIRE(false == bsTest.canWrite());
369 REQUIRE(1 == bsTest.readBit());
370}
static void dumpData(const std::string &prefix, const uint8_t *data, size_t len)
static constexpr std::string_view testStringMSB64_be
Simple dynamically heap-sized bitheap for efficient bit storage access in O(1).
Definition bitheap.hpp:49
std::string toString(size_type bitpos, size_type length, PrefixOpt prefix=PrefixOpt::none) const noexcept
Definition bitheap.hpp:450
std::pair< bitheap, bool > subbits(size_type bitpos, size_type length) const noexcept
Definition bitheap.hpp:419
constexpr size_type size() const noexcept
Returns storage size in bits.
Definition bitheap.hpp:58
constexpr bool put(size_type bitpos, bool v) noexcept
Writes the bit value v to position bitpos into this storage.
Definition bitheap.hpp:133
constexpr bitheap & reverse() noexcept
Definition bitheap.hpp:176
Versatile Bitstream implementation supporting:
size_type seek(size_type newPos) noexcept
Sets this stream's bit position.
std::string toString() const
bool setAccess(ioaccess_t access) noexcept
Changes the access-mode to write or read and resets position and cache to zero.
bool setImmutable() noexcept
Changes the write-mode to read, sets the underlying ByteStream to read-only and resets position and c...
constexpr bool canWrite() const noexcept
Returns true in case stream is in write mode, false if in read mode.
bool writeBit(uint8_t bit) noexcept
Write given bit in least-significant-bit (LSB) first order.
bool setMark(size_type readLimit) noexcept
Set markpos to current bit-position, allowing the stream to be seekMark().
ByteStream & byteStream()
Returns the used underlying ByteStream.
size_type skip(size_type n) noexcept
Skip given number of bits.
jau::nsize_t readBits64(jau::nsize_t n, data_type &r) noexcept
Read incoming bits in least-significant-bit (LSB) first order.
int readBit() noexcept
Read incoming bit in least-significant-bit (LSB) first order.
bool seekMark() noexcept
Seeks stream bit-position to markpos as set via setMark().
jau::nsize_t writeBits64(jau::nsize_t n, data_type bits) noexcept
Write given bits in least-significant-bit (LSB) first order.
size_type position() const noexcept
Returns the bit position in the stream.
@ rw
Read and write capabilities, i.e.
@ read
Read intent.
@ write
Write intend.
uint_fast32_t nsize_t
Natural 'size_t' alternative using uint_fast32_t as its natural sized type.
Definition int_types.hpp:55
std::string toBitString(const void *data, const nsize_t length, const bit_order_t bitOrder=bit_order_t::msb, const PrefixOpt prefix=PrefixOpt::prefix, size_t bit_len=0) noexcept
Produce a binary string representation of the given lsb-first byte values.
bit_order_t
Bit order type, i.e.
@ lsb
Identifier for least-significant-bit (lsb) first.
@ msb
Identifier for most-significant-bit (msb) first.
std::string to_string(const bit_order_t v) noexcept
Return std::string representation of the given bit_order_t.
static void testBulkBitsImpl(const nsize_t preBits, const nsize_t skipBits, const nsize_t postBits)
static std::string getTestStreamResultAsString(const jau::bit_order_t dataBitOrder, const jau::nsize_t preBits, const jau::nsize_t skipBits, const jau::nsize_t postBits)
static void testLinearBitsImpl(const jau::bit_order_t bitOrder, const nsize_t preBits, const nsize_t skipBits, const nsize_t postBits)
static jau::io::Bitstream getTestStream(const jau::bit_order_t dataBitOrder, const nsize_t preBits, const nsize_t skipBits, const nsize_t postBits)
static std::string readBits(jau::io::Bitstream *copy, jau::io::Bitstream &input, const nsize_t preCount, const nsize_t count)
TEST_CASE("Bitstream Test 00", "[bitstream]")
static jau::bitheap getBitfield(const jau::nsize_t bitCount, const jau::bit_order_t bitOrder)