diff --git a/docs/byterator.adoc b/docs/byterator.adoc index eabb992..f986ea1 100644 --- a/docs/byterator.adoc +++ b/docs/byterator.adoc @@ -63,18 +63,22 @@ auto value = i.readu16(); ---- auto v8 = i.peeku8(); // read value without advancing v8 = i.readu8(); // read and advance +i.advanceu8(); // advance only i.writeu8(v8); // write and advance auto v16 = i.peeku16(); // read value without advancing v16 = i.readu16(); // read and advance +i.advanceu16(); // advance only i.writeu16(v16); // write and advance auto v32 = i.peeku32(); // read value without advancing v32 = i.readu32(); // read and advance +i.advanceu32(); // advance only i.writeu32(v32); // write and advance auto v64 = i.peeku64(); // read value without advancing v64 = i.readu64(); // read and advance +i.advanceu64(); // advance only i.writeu64(v64); // write and advance ---- diff --git a/include/stdx/byterator.hpp b/include/stdx/byterator.hpp index e06208b..4bb1f38 100644 --- a/include/stdx/byterator.hpp +++ b/include/stdx/byterator.hpp @@ -2,6 +2,7 @@ #include #include +#include #include #include @@ -27,11 +28,13 @@ constexpr auto iterator_value_type() -> decltype(*std::declval::pointer>()); template -using iterator_value_t = decltype(iterator_value_type()); +using iterator_value_t = + std::remove_reference_t())>; } // namespace detail template class byterator { - using byte_t = std::remove_reference_t>; + using byte_t = + stdx::conditional_t, std::byte const, std::byte>; byte_t *ptr; [[nodiscard]] friend constexpr auto operator==(byterator const &x, @@ -189,6 +192,10 @@ template class byterator { ptr -= d; return *this; } + constexpr auto advance(difference_type d) -> byterator & { + ptr += d; + return *this; + } [[nodiscard]] friend constexpr auto operator+(byterator i, difference_type d) @@ -228,11 +235,15 @@ template class byterator { return static_cast(v); } + template auto advance() -> decltype(auto) { + return advance(sizeof(V)); + } + template , int> = 0> [[nodiscard]] auto read() -> R { R ret = peek(); - ptr += sizeof(V); + advance(); return ret; } @@ -242,12 +253,15 @@ template class byterator { auto write(V &&v) -> void { using R = remove_cvref_t; std::memcpy(ptr, std::addressof(v), sizeof(R)); - ptr += sizeof(R); + advance(); } template [[nodiscard]] auto peeku8() { return peek(); } + template auto advanceu8() -> decltype(auto) { + return advance(); + } template [[nodiscard]] auto readu8() { return read(); } @@ -258,6 +272,9 @@ template class byterator { template [[nodiscard]] auto peeku16() { return peek(); } + template auto advanceu16() -> decltype(auto) { + return advance(); + } template [[nodiscard]] auto readu16() { return read(); } @@ -268,6 +285,9 @@ template class byterator { template [[nodiscard]] auto peeku32() { return peek(); } + template auto advanceu32() -> decltype(auto) { + return advance(); + } template [[nodiscard]] auto readu32() { return read(); } @@ -278,6 +298,9 @@ template class byterator { template [[nodiscard]] auto peeku64() { return peek(); } + template auto advanceu64() -> decltype(auto) { + return advance(); + } template [[nodiscard]] auto readu64() { return read(); } diff --git a/test/byterator.cpp b/test/byterator.cpp index 23d86de..06b53b9 100644 --- a/test/byterator.cpp +++ b/test/byterator.cpp @@ -77,6 +77,22 @@ TEST_CASE("random access arithmetic", "[byterator]") { CHECK((i == b)); } +TEST_CASE("advance", "[byterator]") { + auto const a = std::array{stdx::to_be(0x0102), + stdx::to_be(0x0304)}; + auto const b = stdx::byterator{std::begin(a)}; + auto i = b; + CHECK((i + 1 != b)); + i.advance(); + CHECK((i == b + 1)); + CHECK(i - b == 1); + CHECK((i - 1 == b)); + i.advance(-1); + CHECK((i == b)); + static_assert(std::is_same_v &>); +} + TEST_CASE("equality comparable", "[byterator]") { auto const a = std::array{1, 2, 3, 4}; auto x = stdx::byterator{std::begin(a)}; @@ -142,6 +158,15 @@ TEST_CASE("peek uint8_t", "[byterator]") { CHECK((i == std::begin(a))); } +TEST_CASE("advance uint8_t", "[byterator]") { + auto const a = std::array{stdx::to_be(0x0102), + stdx::to_be(0x0304)}; + auto i = stdx::byterator{std::begin(a)}; + auto j = std::next(i); + i.advanceu8(); + CHECK((i == j)); +} + TEST_CASE("read uint8_t", "[byterator]") { auto const a = std::array{stdx::to_be(0x0102), stdx::to_be(0x0304)}; @@ -171,6 +196,15 @@ TEST_CASE("peek uint16_t", "[byterator]") { CHECK((i == std::begin(a))); } +TEST_CASE("advance uint16_t", "[byterator]") { + auto const a = std::array{stdx::to_be(0x0102), + stdx::to_be(0x0304)}; + auto i = stdx::byterator{std::begin(a)}; + auto j = i + 2; + i.advanceu16(); + CHECK((i == j)); +} + TEST_CASE("read uint16_t", "[byterator]") { auto const a = std::array{stdx::to_be(0x0102), stdx::to_be(0x0304)}; @@ -200,6 +234,14 @@ TEST_CASE("peek uint32_t", "[byterator]") { CHECK((i == std::begin(a))); } +TEST_CASE("advance uint32_t", "[byterator]") { + auto const a = std::array{stdx::to_be(0x0102), + stdx::to_be(0x0304)}; + auto i = stdx::byterator{std::begin(a)}; + i.advanceu32(); + CHECK((i == std::end(a))); +} + TEST_CASE("read uint32_t", "[byterator]") { auto const a = std::array{stdx::to_be(0x0102), stdx::to_be(0x0304)}; @@ -229,6 +271,15 @@ TEST_CASE("peek uint64_t", "[byterator]") { CHECK((i == std::begin(a))); } +TEST_CASE("advance uint64_t", "[byterator]") { + auto const a = std::array{ + stdx::to_be(0x0102), stdx::to_be(0x0304), + stdx::to_be(0x0506), stdx::to_be(0x0708)}; + auto i = stdx::byterator{std::begin(a)}; + i.advanceu64(); + CHECK((i == std::end(a))); +} + TEST_CASE("read uint64_t", "[byterator]") { auto const a = std::array{ stdx::to_be(0x0102), stdx::to_be(0x0304), @@ -264,6 +315,15 @@ TEST_CASE("peek enum", "[byterator]") { CHECK(i.peek() == E::A); } +TEST_CASE("advance enum", "[byterator]") { + auto const a = std::array{stdx::to_be(0x0102), + stdx::to_be(0x0304)}; + auto i = stdx::byterator{std::begin(a)}; + auto j = std::next(i); + i.advance(); + CHECK(i == j); +} + TEST_CASE("read enum", "[byterator]") { auto const a = std::array{stdx::to_be(0x0102), stdx::to_be(0x0304)};