diff --git a/include/libimp/span.h b/include/libimp/span.h index d4065b9..2e013a8 100644 --- a/include/libimp/span.h +++ b/include/libimp/span.h @@ -10,9 +10,12 @@ #include #include #include +#include +#include #include #include #include +#include #ifdef LIBIMP_CPP_20 #include #endif // LIBIMP_CPP_20 @@ -48,7 +51,8 @@ using is_inconvertible = template using is_sized_sentinel_for = - is_inconvertible() - std::declval()), std::ptrdiff_t>; + typename std::enable_if() - std::declval()), + std::ptrdiff_t>::value>::type; /// @brief Obtain the address represented by p /// without forming a reference to the object pointed to by p. @@ -202,10 +206,65 @@ public: } }; +template () == std::declval())> +bool operator==(span a, span b) noexcept { + if (a.size() != b.size()) { + return false; + } + for (std::size_t i = 0; i < a.size(); ++i) { + if (a[i] != b[i]) return false; + } + return true; +} + template ::value, std::uint8_t const, std::uint8_t>::type> auto as_bytes(span s) noexcept -> span { return {reinterpret_cast(s.data()), s.size_bytes()}; } +template +auto make_span(T *arr, std::size_t count) noexcept -> span { + return {arr, count}; +} + +template +auto make_span(T (&arr)[E]) noexcept -> span { + return {arr}; +} + +template +auto make_span(std::array const &arr) noexcept -> span { + return {arr}; +} + +template +auto make_span(std::array const &arr) noexcept -> span::type> { + return {arr}; +} + +template +auto make_span(std::vector &arr) noexcept -> span { + return {arr.data(), arr.size()}; +} + +template +auto make_span(std::vector const &arr) noexcept -> span::type> { + return {arr.data(), arr.size()}; +} + +template +auto make_span(std::initializer_list list) noexcept -> span::type> { + return {list.begin(), list.end()}; +} + +inline auto make_span(std::string &str) noexcept -> span { + return {const_cast(str.data()), str.size()}; +} + +inline auto make_span(std::string const &str) noexcept -> span { + return {str.data(), str.size()}; +} + LIBIMP_NAMESPACE_END_ diff --git a/test/test_imp_span.cpp b/test/test_imp_span.cpp index b432e3d..0c7a482 100644 --- a/test/test_imp_span.cpp +++ b/test/test_imp_span.cpp @@ -1,7 +1,56 @@ +#include +#include + #include "gtest/gtest.h" #include "libimp/span.h" +#include "libimp/countof.h" + +TEST(span, to_address) { + int *a = new int; + EXPECT_EQ(imp::detail::to_address(a), a); + std::unique_ptr b {a}; + EXPECT_EQ(imp::detail::to_address(b), a); +} TEST(span, span) { + auto test_proc = [](auto &&buf, auto &&sp) { + EXPECT_EQ(imp::countof(buf), sp.size()); + EXPECT_EQ(sizeof(buf[0]) * imp::countof(buf), sp.size_bytes()); + for (int i = 0; i < sp.size(); ++i) { + EXPECT_EQ(buf[i], sp[i]); + } + }; + { + int buf[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; + auto sp = imp::make_span(buf); + test_proc(buf, sp); + test_proc(imp::make_span({0, 1, 2}) , sp.first(3)); + test_proc(imp::make_span({6, 7, 8, 9}), sp.last(4)); + test_proc(imp::make_span({3, 4, 5, 6}), sp.subspan(3, 4)); + test_proc(imp::make_span({3, 4, 5, 6, 7, 8, 9}), sp.subspan(3)); + } + { + std::vector buf = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; + auto sp = imp::make_span(buf); + imp::span sp2 {buf.begin(), buf.end()}; + EXPECT_EQ(sp, sp2); + test_proc(buf, sp); + test_proc(imp::make_span({0, 1, 2}) , sp.first(3)); + test_proc(imp::make_span({6, 7, 8, 9}), sp.last(4)); + test_proc(imp::make_span({3, 4, 5, 6}), sp.subspan(3, 4)); + test_proc(imp::make_span({3, 4, 5, 6, 7, 8, 9}), sp.subspan(3)); + test_proc(imp::make_span((char *)sp.data(), sp.size_bytes()), imp::as_bytes(sp)); + } + { + std::string buf = "0123456789"; + auto sp = imp::make_span(buf); + // if (sp == imp::make_span({nullptr})) {} + test_proc(buf, sp); + test_proc(imp::make_span("012", 3) , sp.first(3)); + test_proc(imp::make_span("6789", 4), sp.last(4)); + test_proc(imp::make_span("3456", 4), sp.subspan(3, 4)); + test_proc(imp::make_span("3456789", 7), sp.subspan(3)); + } } \ No newline at end of file