diff --git a/include/qoixx.hpp b/include/qoixx.hpp index f3bd8bb..e1b664f 100644 --- a/include/qoixx.hpp +++ b/include/qoixx.hpp @@ -27,6 +27,22 @@ namespace qoixx{ namespace detail{ +template +requires(sizeof(T) == 1 && !std::same_as) +struct contiguous_puller{ + static constexpr bool is_contiguous = true; + const T* t; + inline std::uint8_t pull()noexcept{ + return static_cast(*t++); + } + inline const std::uint8_t* raw_pointer()noexcept{ + return reinterpret_cast(t); + } + inline void advance(std::size_t n)noexcept{ + t += n; + } +}; + template struct default_container_operator; @@ -64,19 +80,7 @@ struct default_container_operator>{ static constexpr pusher create_pusher(target_type& t)noexcept{ return {&t}; } - struct puller{ - static constexpr bool is_contiguous = true; - const T* t; - inline std::uint8_t pull()noexcept{ - return static_cast(*t++); - } - inline const std::uint8_t* raw_pointer()noexcept{ - return reinterpret_cast(t); - } - inline void advance(std::size_t n)noexcept{ - t += n; - } - }; + using puller = contiguous_puller; static constexpr puller create_puller(const target_type& t)noexcept{ return {t.data()}; } @@ -119,19 +123,7 @@ struct default_container_operator, std::size_t>>{ static constexpr pusher create_pusher(target_type& t)noexcept{ return {&t}; } - struct puller{ - static constexpr bool is_contiguous = true; - const T* t; - inline std::uint8_t pull()noexcept{ - return static_cast(*t++); - } - inline const std::uint8_t* raw_pointer()noexcept{ - return reinterpret_cast(t); - } - inline void advance(std::size_t n)noexcept{ - t += n; - } - }; + using puller = contiguous_puller; static constexpr puller create_puller(const target_type& t)noexcept{ return {t.first.get()}; } @@ -147,19 +139,7 @@ template requires(sizeof(T) == 1) struct default_container_operator>{ using target_type = std::pair; - struct puller{ - static constexpr bool is_contiguous = true; - const T* ptr; - inline std::uint8_t pull()noexcept{ - return static_cast(*ptr++); - } - inline const std::uint8_t* raw_pointer()noexcept{ - return reinterpret_cast(ptr); - } - inline void advance(std::size_t n)noexcept{ - ptr += n; - } - }; + using puller = contiguous_puller; static constexpr puller create_puller(const target_type& t)noexcept{ return {t.first}; } diff --git a/src/test.cpp b/src/test.cpp index 978c61c..b757028 100644 --- a/src/test.cpp +++ b/src/test.cpp @@ -2,6 +2,22 @@ #define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN #include "doctest.h" +template +static bool equals(const T& t, const U& u){ + const auto t_size = qoixx::container_operator::size(t); + { + const auto u_size = qoixx::container_operator::size(u); + if(t_size != u_size) + return false; + } + auto t_puller = qoixx::container_operator::create_puller(t); + auto u_puller = qoixx::container_operator::create_puller(u); + for(std::size_t i = 0; i < t_size; ++i) + if(t_puller.pull() != u_puller.pull()) + return false; + return true; +} + TEST_CASE("3-channel image"){ constexpr qoixx::qoi::desc d{ .width = 8, @@ -34,11 +50,41 @@ TEST_CASE("3-channel image"){ const auto actual = qoixx::qoi::encode>(image, d); CHECK(actual == expected); } + SUBCASE("encode std::vector, output as std::pair, std::size_t>>"){ + const auto actual = qoixx::qoi::encode, std::size_t>>(image, d); + CHECK(equals(actual, expected)); + } + SUBCASE("encode std::pair, std::size_t>, output as std::vector"){ + auto ptr = std::make_unique(image.size()); + std::ranges::copy(image, ptr.get()); + const auto actual = qoixx::qoi::encode>(std::make_pair(std::move(ptr), image.size()), d); + CHECK(equals(actual, expected)); + } + SUBCASE("encode std::uint8_t*, output as std::vector"){ + const auto actual = qoixx::qoi::encode>(image.data(), image.size(), d); + CHECK(equals(actual, expected)); + } SUBCASE("decode std::vector, output as std::vector"){ const auto [actual, desc] = qoixx::qoi::decode>(expected); CHECK(d == desc); CHECK(actual == image); } + SUBCASE("decode std::vector, output as std::pair>"){ + const auto [actual, desc] = qoixx::qoi::decode, std::size_t>>(expected); + CHECK(d == desc); + CHECK(equals(actual, image)); + } + SUBCASE("decode std::pair, std::size_t>, output as std::vector"){ + auto ptr = std::make_unique(expected.size()); + std::ranges::copy(expected, ptr.get()); + const auto [actual, desc] = qoixx::qoi::decode>(std::make_pair(std::move(ptr), expected.size())); + CHECK(d == desc); + CHECK(equals(actual, image)); + } + SUBCASE("decode std::uint8_t*, output as std::vector"){ + const auto [actual, desc] = qoixx::qoi::decode>(expected.data(), expected.size()); + CHECK(equals(actual, image)); + } } TEST_CASE("4-channel image"){ @@ -77,9 +123,39 @@ TEST_CASE("4-channel image"){ const auto actual = qoixx::qoi::encode>(image, d); CHECK(actual == expected); } + SUBCASE("encode std::vector, output as std::pair, std::size_t>>"){ + const auto actual = qoixx::qoi::encode, std::size_t>>(image, d); + CHECK(equals(actual, expected)); + } + SUBCASE("encode std::pair, std::size_t>, output as std::vector"){ + auto ptr = std::make_unique(image.size()); + std::ranges::copy(image, ptr.get()); + const auto actual = qoixx::qoi::encode>(std::make_pair(std::move(ptr), image.size()), d); + CHECK(equals(actual, expected)); + } + SUBCASE("encode std::uint8_t*, output as std::vector"){ + const auto actual = qoixx::qoi::encode>(image.data(), image.size(), d); + CHECK(equals(actual, expected)); + } SUBCASE("decode std::vector, output as std::vector"){ const auto [actual, desc] = qoixx::qoi::decode>(expected); CHECK(d == desc); CHECK(actual == image); } + SUBCASE("decode std::vector, output as std::pair>"){ + const auto [actual, desc] = qoixx::qoi::decode, std::size_t>>(expected); + CHECK(d == desc); + CHECK(equals(actual, image)); + } + SUBCASE("decode std::pair, std::size_t>, output as std::vector"){ + auto ptr = std::make_unique(expected.size()); + std::ranges::copy(expected, ptr.get()); + const auto [actual, desc] = qoixx::qoi::decode>(std::make_pair(std::move(ptr), expected.size())); + CHECK(d == desc); + CHECK(equals(actual, image)); + } + SUBCASE("decode std::uint8_t*, output as std::vector"){ + const auto [actual, desc] = qoixx::qoi::decode>(expected.data(), expected.size()); + CHECK(equals(actual, image)); + } }