Skip to content

Commit 78b5026

Browse files
committed
Add byte reader
1 parent ecb3ac3 commit 78b5026

File tree

5 files changed

+217
-0
lines changed

5 files changed

+217
-0
lines changed

components/ocs_core/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ idf_component_register(
1616
"file_stream_reader.cpp"
1717
"stream_transceiver.cpp"
1818
"byte_writer.cpp"
19+
"byte_reader.cpp"
1920

2021
REQUIRES
2122
"json"
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/*
2+
* SPDX-FileCopyrightText: 2026 Tendry Lab
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
#include <algorithm>
7+
#include <cstring>
8+
9+
#include "ocs_core/byte_reader.h"
10+
11+
namespace ocs {
12+
namespace core {
13+
14+
ByteReader::ByteReader(const uint8_t* data, size_t size)
15+
: data_(data)
16+
, size_(size) {
17+
}
18+
19+
size_t ByteReader::get_len() const {
20+
return size_ - offset_;
21+
}
22+
23+
size_t ByteReader::get_cap() const {
24+
return size_;
25+
}
26+
27+
const uint8_t* ByteReader::get_data() const {
28+
return data_ + offset_;
29+
}
30+
31+
size_t ByteReader::read(uint8_t* data, size_t size) {
32+
const size_t ret = std::min(size, get_len());
33+
34+
if (ret) {
35+
memcpy(data, get_data(), ret);
36+
offset_ += ret;
37+
}
38+
39+
return ret;
40+
}
41+
42+
} // namespace core
43+
} // namespace ocs

components/ocs_core/byte_reader.h

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/*
2+
* SPDX-FileCopyrightText: 2026 Tendry Lab
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
#pragma once
7+
8+
#include <cstddef>
9+
#include <cstdint>
10+
#include <type_traits>
11+
12+
#include "ocs_core/noncopyable.h"
13+
14+
namespace ocs {
15+
namespace core {
16+
17+
class ByteReader : private core::NonCopyable<> {
18+
public:
19+
//! Initialize.
20+
//!
21+
//! @remarks
22+
//! - @p data should be valid until ByteReader exists.
23+
ByteReader(const uint8_t* data, size_t size);
24+
25+
//! Return number of bytes left.
26+
size_t get_len() const;
27+
28+
//! Return size of the underlying array of bytes.
29+
size_t get_cap() const;
30+
31+
//! Return pointer to the underlying data.
32+
//!
33+
//! @remarks
34+
//! Offset is taken into account.
35+
const uint8_t* get_data() const;
36+
37+
//! Read @p size bytes to @p data buffer.
38+
//!
39+
//! @returns
40+
//! Number of read bytes or 0 if no bytes left.
41+
size_t read(uint8_t* data, size_t size);
42+
43+
//! Read any integral value.
44+
template <typename T> bool read(T& t) {
45+
static_assert(std::is_integral<T>::value, "require integer type");
46+
47+
if (get_len() < sizeof(t)) {
48+
return false;
49+
}
50+
51+
t = 0;
52+
53+
for (size_t n = offset_; n < offset_ + sizeof(t); ++n) {
54+
t = (t << 8) | data_[n];
55+
}
56+
57+
offset_ += sizeof(t);
58+
59+
return true;
60+
}
61+
62+
private:
63+
const uint8_t* data_ { nullptr };
64+
const size_t size_ { 0 };
65+
66+
size_t offset_ { 0 };
67+
};
68+
69+
} // namespace core
70+
} // namespace ocs

components/ocs_core/test/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ idf_component_register(
77
"test_rate_limiter.cpp"
88
"test_stream_transceiver.cpp"
99
"test_byte_writer.cpp"
10+
"test_byte_reader.cpp"
1011

1112
REQUIRES
1213
"unity"
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
/*
2+
* SPDX-FileCopyrightText: 2026 Tendry Lab
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
#include <cstring>
7+
8+
#include "unity.h"
9+
10+
#include "ocs_core/byte_reader.h"
11+
12+
namespace ocs {
13+
namespace core {
14+
15+
TEST_CASE("Byte reader: read array: whole at once", "[ocs_core], [byte_reader]") {
16+
uint8_t write_buf[42];
17+
memset(write_buf, 5, sizeof(write_buf));
18+
19+
ByteReader reader(write_buf, sizeof(write_buf));
20+
TEST_ASSERT_EQUAL(sizeof(write_buf), reader.get_len());
21+
22+
uint8_t read_buf[sizeof(write_buf)];
23+
memset(read_buf, 0, sizeof(read_buf));
24+
25+
TEST_ASSERT_EQUAL(sizeof(write_buf), reader.read(read_buf, sizeof(read_buf)));
26+
TEST_ASSERT_TRUE(memcmp(write_buf, read_buf, sizeof(write_buf)) == 0);
27+
}
28+
29+
TEST_CASE("Byte reader: read byte", "[ocs_core], [byte_reader]") {
30+
uint8_t write_buf[42];
31+
memset(write_buf, 5, sizeof(write_buf));
32+
33+
ByteReader reader(write_buf, sizeof(write_buf));
34+
TEST_ASSERT_EQUAL(sizeof(write_buf), reader.get_len());
35+
36+
for (size_t n = 0; n < sizeof(write_buf); ++n) {
37+
uint8_t byte = 0;
38+
TEST_ASSERT_TRUE(reader.read(byte));
39+
TEST_ASSERT_EQUAL(5, byte);
40+
}
41+
42+
uint8_t byte = 0;
43+
TEST_ASSERT_FALSE(reader.read(byte));
44+
}
45+
46+
TEST_CASE("Byte reader: read by offset: whole at once", "[ocs_core], [byte_reader]") {
47+
uint8_t write_buf[42];
48+
memset(write_buf, 5, sizeof(write_buf));
49+
50+
ByteReader reader(write_buf, sizeof(write_buf));
51+
TEST_ASSERT_EQUAL(sizeof(write_buf), reader.get_len());
52+
TEST_ASSERT_EQUAL_PTR(write_buf, reader.get_data());
53+
54+
uint8_t byte = 0;
55+
TEST_ASSERT_TRUE(reader.read(byte));
56+
TEST_ASSERT_EQUAL(5, byte);
57+
TEST_ASSERT_EQUAL(sizeof(write_buf) - 1, reader.get_len());
58+
59+
ByteReader off_reader(reader.get_data(), reader.get_len());
60+
TEST_ASSERT_EQUAL_PTR(write_buf + 1, off_reader.get_data());
61+
TEST_ASSERT_EQUAL(sizeof(write_buf) - 1, reader.get_len());
62+
TEST_ASSERT_TRUE(memcmp(write_buf + 1, off_reader.get_data(), off_reader.get_len())
63+
== 0);
64+
}
65+
66+
TEST_CASE("Byte reader: read by offset: read less", "[ocs_core], [byte_reader]") {
67+
uint8_t write_buf[42];
68+
memset(write_buf, 5, sizeof(write_buf));
69+
70+
ByteReader reader(write_buf, sizeof(write_buf));
71+
TEST_ASSERT_EQUAL(sizeof(write_buf), reader.get_len());
72+
73+
uint8_t byte = 0;
74+
TEST_ASSERT_TRUE(reader.read(byte));
75+
TEST_ASSERT_EQUAL(5, byte);
76+
77+
TEST_ASSERT_TRUE(reader.read(byte));
78+
TEST_ASSERT_EQUAL(5, byte);
79+
80+
TEST_ASSERT_EQUAL(sizeof(write_buf) - 2, reader.get_len());
81+
82+
uint8_t read_buf[sizeof(write_buf)];
83+
memset(read_buf, 0, sizeof(read_buf));
84+
85+
TEST_ASSERT_EQUAL(sizeof(read_buf) - 2, reader.read(read_buf, sizeof(read_buf)));
86+
TEST_ASSERT_TRUE(memcmp(write_buf + 2, read_buf, sizeof(read_buf) - 2) == 0);
87+
88+
TEST_ASSERT_FALSE(reader.read(byte));
89+
90+
ByteReader off_reader(read_buf + sizeof(read_buf) - 2, 2);
91+
92+
TEST_ASSERT_TRUE(off_reader.read(byte));
93+
TEST_ASSERT_EQUAL(0, byte);
94+
95+
TEST_ASSERT_TRUE(off_reader.read(byte));
96+
TEST_ASSERT_EQUAL(0, byte);
97+
98+
TEST_ASSERT_FALSE(off_reader.read(byte));
99+
}
100+
101+
} // namespace core
102+
} // namespace ocs

0 commit comments

Comments
 (0)