diff --git a/include/libimp/dataof.h b/include/libimp/dataof.h new file mode 100644 index 0000000..a2d9049 --- /dev/null +++ b/include/libimp/dataof.h @@ -0,0 +1,92 @@ +/** + * \file libimp/dataof.h + * \author mutouyun (orz@orzz.org) + * \brief Returns the data pointer of the given range + * \date 2023-05-27 + */ +#pragma once + +#include // std::declval, std::true_type, std::false_type +#include // std::size_t + +#include "libimp/def.h" +#include "libimp/generic.h" + +LIBIMP_NAMESPACE_BEG_ + +/** + * \see https://en.cppreference.com/w/cpp/iterator/data +*/ + +namespace detail_dataof { + +template +struct trait_has_data { +private: + template + static std::true_type check(decltype(std::declval().data())*); + template + static std::false_type check(...); +public: + using type = decltype(check(nullptr)); + constexpr static auto value = type::value; +}; + +template +struct trait_has_Data { +private: + template + static std::true_type check(decltype(std::declval().Data())*); + template + static std::false_type check(...); +public: + using type = decltype(check(nullptr)); + constexpr static auto value = type::value; +}; + +template ::value + , bool = trait_has_Data::value> +struct trait; + +template +struct trait { + constexpr static T const *dataof(T const (&arr)[N]) noexcept { + return arr; + } + constexpr static T *dataof(T (&arr)[N]) noexcept { + return arr; + } +}; + +template +struct trait { + template + constexpr static auto dataof(T &&c) noexcept(noexcept(c.data())) { + return std::forward(c).data(); + } +}; + +template +struct trait { + template + constexpr static auto dataof(T &&c) noexcept(noexcept(c.Data())) { + return std::forward(c).Data(); + } +}; + +template +struct trait { + template + constexpr static T const *dataof(std::initializer_list il) noexcept { + return il.begin(); + } +}; + +} // namespace detail_dataof + +template >>> +constexpr auto dataof(T &&c) noexcept(noexcept(R::dataof(std::forward(c)))) { + return R::dataof(std::forward(c)); +} + +LIBIMP_NAMESPACE_END_ diff --git a/test/imp/test_imp_utility.cpp b/test/imp/test_imp_utility.cpp index 93b0257..b504482 100644 --- a/test/imp/test_imp_utility.cpp +++ b/test/imp/test_imp_utility.cpp @@ -8,6 +8,7 @@ #include "libimp/construct.h" #include "libimp/pimpl.h" #include "libimp/countof.h" +#include "libimp/dataof.h" #include "libimp/horrible_cast.h" #include "libimp/detect_plat.h" #include "libimp/generic.h" @@ -100,9 +101,27 @@ TEST(utility, countof) { std::vector vec {1, 2, 3, 4, 5}; int arr[] {7, 6, 5, 4, 3, 2, 1}; + auto il = {9, 7, 6, 4, 3, 1, 5}; EXPECT_EQ(imp::countof(sv) , sv.Size()); EXPECT_EQ(imp::countof(vec), vec.size()); EXPECT_EQ(imp::countof(arr), sizeof(arr) / sizeof(arr[0])); + EXPECT_EQ(imp::countof(il) , il.size()); +} + +TEST(utility, dataof) { + struct { + constexpr int *Data() const noexcept { return (int *)this; } + } sv; + EXPECT_FALSE(imp::detail_dataof::trait_has_data::value); + EXPECT_TRUE (imp::detail_dataof::trait_has_Data::value); + + std::vector vec {1, 2, 3, 4, 5}; + int arr[] {7, 6, 5, 4, 3, 2, 1}; + auto il = {9, 7, 6, 4, 3, 1, 5}; + EXPECT_EQ(imp::dataof(sv) , sv.Data()); + EXPECT_EQ(imp::dataof(vec), vec.data()); + EXPECT_EQ(imp::dataof(arr), arr); + EXPECT_EQ(imp::dataof(il) , il.begin()); } TEST(utility, horrible_cast) {