From a44e11efc5250742f8dda34b981f9811e76ac282 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rimas=20Misevi=C4=8Dius?= Date: Fri, 25 Oct 2024 22:03:31 +0300 Subject: [PATCH 1/3] Check in str_arg_char if StrT has size() member Before it was checked StrT has length() member. This allows other containers (e.g. std::vector) to be used as input. --- include/upa/str_arg.h | 16 ++++++++-------- test/test-str_arg.cpp | 6 ++++++ 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/include/upa/str_arg.h b/include/upa/str_arg.h index 829b6fb..0868461 100644 --- a/include/upa/str_arg.h +++ b/include/upa/str_arg.h @@ -131,19 +131,19 @@ namespace detail { template auto test_data(long) -> void; - // test class T has length() member + // test class T has size() member template - auto test_length(int) -> decltype(std::declval().length()); + auto test_size(int) -> decltype(std::declval().size()); template - auto test_length(long) -> void; + auto test_size(long) -> void; // T::data() return type (void - if no such member) template using data_member_t = decltype(detail::test_data(0)); - // T::length() return type (void - if no such member) + // T::size() return type (void - if no such member) template - using length_member_t = decltype(detail::test_length(0)); + using size_member_t = decltype(detail::test_size(0)); } // namespace detail @@ -162,16 +162,16 @@ struct str_arg_char : std::remove_cv { } }; -// String that has data() and length() members +// String that has data() and size() members template struct str_arg_char : std::enable_if< std::is_pointer_v> && - is_size_type_v>, + is_size_type_v>, remove_cvptr_t>> { template static str_arg to_str_arg(const STR& str) { - return { str.data(), str.length() }; + return { str.data(), str.size() }; } }; diff --git a/test/test-str_arg.cpp b/test/test-str_arg.cpp index 7c094d4..a5d603d 100644 --- a/test/test-str_arg.cpp +++ b/test/test-str_arg.cpp @@ -9,6 +9,8 @@ #include "upa/str_arg.h" //#include "doctest-main.h" +#include +#include // Function to test @@ -86,6 +88,10 @@ inline void test_char() { procfn(upa::str_arg{ cptr, cptr + N }); procfn(upa::str_arg{ vptr, vptr + N }); + // has data() and size() members + procfn(std::array{ '1', '2', '3'}); + procfn(std::vector{ '1', '2', '3'}); + // std::basic_string const std::basic_string str{ arr }; procfn(str); From 020055721be742b49bdf0ecfab8dde4df759f997 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rimas=20Misevi=C4=8Dius?= Date: Sat, 26 Oct 2024 22:55:31 +0300 Subject: [PATCH 2/3] Add support for strings convertible to std::basic_string_view --- include/upa/str_arg.h | 139 +++++++++++++++++++++++++++++---------- include/upa/url_for_qt.h | 11 +++- test/test-str_arg.cpp | 17 ++++- 3 files changed, 128 insertions(+), 39 deletions(-) diff --git a/include/upa/str_arg.h b/include/upa/str_arg.h index 0868461..5c19a3e 100644 --- a/include/upa/str_arg.h +++ b/include/upa/str_arg.h @@ -122,56 +122,123 @@ class str_arg { template using remove_cvptr_t = std::remove_cv_t>; +template +using remove_cvref_t = std::remove_cv_t>; + namespace detail { - // See: https://stackoverflow.com/a/9154394 - - // test class T has data() member - template - auto test_data(int) -> decltype(std::declval().data()); - template - auto test_data(long) -> void; - - // test class T has size() member - template - auto test_size(int) -> decltype(std::declval().size()); - template - auto test_size(long) -> void; - - // T::data() return type (void - if no such member) - template - using data_member_t = decltype(detail::test_data(0)); - - // T::size() return type (void - if no such member) - template - using size_member_t = decltype(detail::test_size(0)); + +// See: https://stackoverflow.com/a/9154394 + +// test class T has data() member +template +auto test_data(int) -> decltype(std::declval().data()); +template +auto test_data(long) -> void; + +// test class T has size() member +template +auto test_size(int) -> decltype(std::declval().size()); +template +auto test_size(long) -> void; + +// T::data() return type (void - if no such member) +template +using data_member_t = decltype(detail::test_data(0)); + +// T::size() return type (void - if no such member) +template +using size_member_t = decltype(detail::test_size(0)); + +// Check that StrT has data() and size() members of supported types + +template +constexpr bool has_data_and_size_v = + std::is_pointer_v> && + is_char_type_v>> && + is_size_type_v>; + +// Check StrT is convertible to std::basic_string_view + +template +constexpr bool convertible_to_string_view_v = + std::is_convertible_v> && + !has_data_and_size_v && + !std::is_same_v; + +// Common class for converting input to str_arg + +template +struct str_arg_char_common { + using type = CharT; + static str_arg to_str_arg(ArgT str) { + return { str.data(), str.size() }; + } +}; + +// Default str_arg_char implementation + +template +struct str_arg_char_default {}; + +// StrT has data() and size() members +template +struct str_arg_char_default>> + : str_arg_char_common< + remove_cvptr_t>, + remove_cvref_t const&> {}; + +// StrT is convertible to std::basic_string_view +template +struct str_arg_char_default>> + : str_arg_char_common> {}; + +#ifdef __cpp_char8_t +template +struct str_arg_char_default>> + : str_arg_char_common> {}; +#endif + +template +struct str_arg_char_default>> + : str_arg_char_common> {}; + +template +struct str_arg_char_default>> + : str_arg_char_common> {}; + +template +struct str_arg_char_default>> + : str_arg_char_common> {}; + } // namespace detail // Requirements for string arguments template -struct str_arg_char {}; +struct str_arg_char : detail::str_arg_char_default {}; // Null terminated string template -struct str_arg_char : std::remove_cv { - - template - static str_arg to_str_arg(const T* s) { +struct str_arg_char>>> { + using type = remove_cvref_t; + static str_arg to_str_arg(const type* s) { return s; } }; -// String that has data() and size() members -template -struct str_arg_char : std::enable_if< - std::is_pointer_v> && - is_size_type_v>, - remove_cvptr_t>> { - - template - static str_arg to_str_arg(const STR& str) { - return { str.data(), str.size() }; +// str_arg input +template +struct str_arg_char> { + using type = CharT; + static str_arg to_str_arg(str_arg s) { + return s; } }; diff --git a/include/upa/url_for_qt.h b/include/upa/url_for_qt.h index f461252..4f5afba 100644 --- a/include/upa/url_for_qt.h +++ b/include/upa/url_for_qt.h @@ -10,12 +10,17 @@ #define UPA_URL_FOR_QT_H #include "url.h" // IWYU pragma: export -#include #if __has_include() # include #else # include #endif + +// As of version 6.7, Qt string classes are convertible to +// std::basic_string_view, and such strings are supported in the +// str_arg.h file. +#if QT_VERSION < QT_VERSION_CHECK(6, 7, 0) +#include #if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0) # include #endif @@ -32,7 +37,7 @@ struct str_arg_char_for_qt { using type = CharT; static str_arg to_str_arg(const StrT& str) { - return { reinterpret_cast(str.data()), str.length() }; + return { reinterpret_cast(str.data()), str.size() }; } }; @@ -54,4 +59,6 @@ struct str_arg_char : } // namespace upa +#endif // QT_VERSION < QT_VERSION_CHECK(6, 7, 0) + #endif // UPA_URL_FOR_QT_H diff --git a/test/test-str_arg.cpp b/test/test-str_arg.cpp index a5d603d..3886c09 100644 --- a/test/test-str_arg.cpp +++ b/test/test-str_arg.cpp @@ -21,6 +21,20 @@ inline std::size_t procfn(StrT&& str) { return std::distance(inp.begin(), inp.end()); } +// Custom string class convertible to std::basic_string_view + +template +class ConvertibleString { +public: + ConvertibleString(const CharT* data, std::size_t length) + : data_(data), length_(length) {} + operator std::basic_string_view() const noexcept { + return { data_, length_ }; + } +private: + const CharT* data_ = nullptr; + std::size_t length_ = 0; +}; // Custom string class and it's specialization @@ -97,7 +111,8 @@ inline void test_char() { procfn(str); procfn(std::basic_string{ arr }); - // custom string + // custom strings + procfn(ConvertibleString{cptr, N}); procfn(CustomString{cptr, N}); } From a4b63b27a4c9f73c5abce77ba70e027a4c04b903 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rimas=20Misevi=C4=8Dius?= Date: Sun, 27 Oct 2024 08:43:47 +0200 Subject: [PATCH 3/3] Improve ATL/MFC string input support for C++17 Add support for any strings derived from CSimpleStringT when using C++17 compilers. --- include/upa/str_arg.h | 6 ++++++ include/upa/url_for_atl.h | 21 +++++++++------------ 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/include/upa/str_arg.h b/include/upa/str_arg.h index 5c19a3e..509918f 100644 --- a/include/upa/str_arg.h +++ b/include/upa/str_arg.h @@ -49,6 +49,12 @@ constexpr bool is_size_type_v = std::is_convertible_v || std::is_convertible_v; +// See: https://en.cppreference.com/w/cpp/concepts/derived_from +template +constexpr bool is_derived_from_v = + std::is_base_of_v && + std::is_convertible_v; + // string args helper class diff --git a/include/upa/url_for_atl.h b/include/upa/url_for_atl.h index 9b08dbf..03e6a42 100644 --- a/include/upa/url_for_atl.h +++ b/include/upa/url_for_atl.h @@ -14,7 +14,7 @@ #ifdef UPA_CPP_20 # include #else -# include +# include #endif namespace upa { @@ -43,17 +43,14 @@ struct str_arg_char : public str_arg_char_for_atl {}; #else // UPA_CPP_20 -template -struct str_arg_char> : - public str_arg_char_for_atl> {}; - -template -struct str_arg_char> : - public str_arg_char_for_atl> {}; - -template -struct str_arg_char> : - public str_arg_char_for_atl> {}; +// CStringT and CFixedStringT are derived from CSimpleStringT +template +struct str_arg_char> || + is_derived_from_v> || + is_derived_from_v> || + is_derived_from_v> + >> : public str_arg_char_for_atl {}; #endif // UPA_CPP_20