From 3b4ae670508ae5069bc3a20822b706401c005452 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rimas=20Misevi=C4=8Dius?= Date: Thu, 10 Oct 2024 22:54:53 +0300 Subject: [PATCH 1/4] Add str_arg_char specializations for ATL/MFC and Qt strings To support string input from CStringT (ATL/MFC) and QString (Qt) objects. --- .codecov.yml | 1 + include/upa/url_for_atl.h | 24 ++++++++++++++++++++++++ include/upa/url_for_qt.h | 27 +++++++++++++++++++++++++++ 3 files changed, 52 insertions(+) create mode 100644 include/upa/url_for_atl.h create mode 100644 include/upa/url_for_qt.h diff --git a/.codecov.yml b/.codecov.yml index 229246c..8778dc5 100644 --- a/.codecov.yml +++ b/.codecov.yml @@ -4,6 +4,7 @@ codecov: ignore: - "deps" - "include/upa/idna.h" + - "include/upa/url_for_*.h" - "src/idna.cpp" - "test" diff --git a/include/upa/url_for_atl.h b/include/upa/url_for_atl.h new file mode 100644 index 0000000..f3a1979 --- /dev/null +++ b/include/upa/url_for_atl.h @@ -0,0 +1,24 @@ +// Copyright 2024 Rimas Misevičius +// Distributed under the BSD-style license that can be +// found in the LICENSE file. +// +#ifndef UPA_URL_FOR_ATL_H +#define UPA_URL_FOR_ATL_H + +#include "url.h" // IWYU pragma: export +#include + +namespace upa { + +template +struct str_arg_char> { + using type = CharT; + + static str_arg to_str_arg(const ATL::CStringT& str) { + return { str.GetString(), static_cast(str.GetLength()) }; + } +}; + +} // namespace upa + +#endif // UPA_URL_FOR_ATL_H diff --git a/include/upa/url_for_qt.h b/include/upa/url_for_qt.h new file mode 100644 index 0000000..3d8597a --- /dev/null +++ b/include/upa/url_for_qt.h @@ -0,0 +1,27 @@ +// Copyright 2024 Rimas Misevičius +// Distributed under the BSD-style license that can be +// found in the LICENSE file. +// +#ifndef UPA_URL_FOR_QT_H +#define UPA_URL_FOR_QT_H + +#include "url.h" // IWYU pragma: export +#include + +namespace upa { + +template<> +struct str_arg_char { + using type = char16_t; + + static str_arg to_str_arg(const QString& str) { + return { + reinterpret_cast(str.data()), + static_cast(str.length()) + }; + } +}; + +} // namespace upa + +#endif // UPA_URL_FOR_QT_H From 5c76c89cb6a517d82dc2e7084357789c6356dc60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rimas=20Misevi=C4=8Dius?= Date: Sat, 12 Oct 2024 21:08:31 +0300 Subject: [PATCH 2/4] Add specializations for more ATL/MFC strings * CSimpleStringT, CFixedStringT * For C++20 - any string derived from CSimpleStringT --- CMakeLists.txt | 1 + include/upa/url_for_atl.h | 45 ++++++++++++++++++++++++++++++++++----- test/test-url_for_.cpp | 44 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 85 insertions(+), 5 deletions(-) create mode 100644 test/test-url_for_.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 3748187..9d5219e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -156,6 +156,7 @@ if (UPA_BUILD_TESTS) test/test-url.cpp test/test-url-port.cpp test/test-url-setters.cpp + test/test-url_for_.cpp test/test-url_host.cpp test/test-url_percent_encode.cpp test/test-url_search_params.cpp diff --git a/include/upa/url_for_atl.h b/include/upa/url_for_atl.h index f3a1979..206e6b5 100644 --- a/include/upa/url_for_atl.h +++ b/include/upa/url_for_atl.h @@ -5,20 +5,55 @@ #ifndef UPA_URL_FOR_ATL_H #define UPA_URL_FOR_ATL_H +#include "config.h" #include "url.h" // IWYU pragma: export -#include +#include +#ifdef UPA_CPP_20 +# include +#else +# include +#endif namespace upa { -template -struct str_arg_char> { - using type = CharT; +template +struct str_arg_char_for_atl { + using type = typename StrT::XCHAR; - static str_arg to_str_arg(const ATL::CStringT& str) { + static str_arg to_str_arg(const StrT& str) { return { str.GetString(), static_cast(str.GetLength()) }; } }; +#ifdef UPA_CPP_20 + +// CStringT and CFixedStringT are derived from CSimpleStringT +template +concept derived_from_CSimpleString = + std::derived_from> || + std::derived_from> || + std::derived_from> || + std::derived_from>; + +template +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> {}; + +#endif // UPA_CPP_20 + } // namespace upa #endif // UPA_URL_FOR_ATL_H diff --git a/test/test-url_for_.cpp b/test/test-url_for_.cpp new file mode 100644 index 0000000..8be19bb --- /dev/null +++ b/test/test-url_for_.cpp @@ -0,0 +1,44 @@ +// Copyright 2024 Rimas Misevičius +// Distributed under the BSD-style license that can be +// found in the LICENSE file. +// + +#include "doctest-main.h" + +#ifdef _MSC_VER +# define UPA_TEST_URL_FOR_ATL +# include "upa/url_for_atl.h" +# include +# include +# include +#endif + +#ifdef UPA_TEST_URL_FOR_ATL + +TEST_CASE("ATL::CSimpleStringA input") { + ATL::CStringA basestr; + + ATL::CSimpleStringA str_input("http://host/", basestr.GetManager()); + upa::url url{ str_input }; + CHECK(url.href() == "http://host/"); +} + +TEST_CASE("ATL::CSimpleStringW input") { + ATL::CStringW basestr; + + ATL::CSimpleStringW str_input(L"http://host/", basestr.GetManager()); + upa::url url{ str_input }; + CHECK(url.href() == "http://host/"); +} + +TEST_CASE_TEMPLATE_DEFINE("ATL string input", StrT, test_url_for_atl) { + StrT str_input("http://host/"); + upa::url url{ str_input }; + CHECK(url.href() == "http://host/"); +} + +TEST_CASE_TEMPLATE_INVOKE(test_url_for_atl, + ATL::CStringA, ATL::CFixedStringT, + ATL::CStringW, ATL::CFixedStringT); + +#endif // UPA_TEST_URL_FOR_ATL From 4ca5098ea65af41f713d4aee2b2cabf0833499c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rimas=20Misevi=C4=8Dius?= Date: Sun, 13 Oct 2024 23:45:00 +0300 Subject: [PATCH 3/4] Add specializations for more Qt strings * QStringView, QUtf8StringView * add tests --- .github/workflows/test-ubuntu.yml | 7 ++++++ CMakeLists.txt | 15 ++++++++++- include/upa/url_for_qt.h | 40 ++++++++++++++++++++++++++---- test/test-url_for_.cpp | 41 +++++++++++++++++++++++++++++++ 4 files changed, 97 insertions(+), 6 deletions(-) diff --git a/.github/workflows/test-ubuntu.yml b/.github/workflows/test-ubuntu.yml index e54f838..6c9117b 100644 --- a/.github/workflows/test-ubuntu.yml +++ b/.github/workflows/test-ubuntu.yml @@ -45,6 +45,13 @@ jobs: cxx_standard: 20 cmake_options: "" + - name: g++ C++17 Qt + os: ubuntu-24.04 + cxx_compiler: g++ + cxx_standard: 17 + cmake_options: "-DUPA_TEST_URL_FOR_QT=ON" + install: "qt6-base-dev" + - name: g++ C++17 Codecov os: ubuntu-latest cxx_compiler: g++ diff --git a/CMakeLists.txt b/CMakeLists.txt index 9d5219e..3bc6b75 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -54,6 +54,7 @@ option(UPA_INSTALL "Generate the install target." ON) # library options option(UPA_AMALGAMATED "Use amalgamated URL library source." OFF) # tests build options +option(UPA_TEST_URL_FOR_QT "Build tests with Qt strings" OFF) option(UPA_TEST_COVERAGE "Build tests with code coverage reporting" OFF) option(UPA_TEST_COVERAGE_CLANG "Build tests with Clang source-based code coverage" OFF) option(UPA_TEST_SANITIZER "Build tests with Clang sanitizer" OFF) @@ -77,6 +78,11 @@ if (UPA_BUILD_FUZZER) endif() endif() +# Tests with Qt strings +if (UPA_TEST_URL_FOR_QT) + find_package(Qt6 REQUIRED COMPONENTS Core) +endif() + # Code coverage reporting if (UPA_TEST_COVERAGE AND CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") # add flags for GCC & LLVM/Clang @@ -170,7 +176,14 @@ if (UPA_BUILD_TESTS) get_filename_component(test_name ${file} NAME_WE) add_executable(${test_name} ${file}) - target_link_libraries(${test_name} ${upa_lib_target}) + target_link_libraries(${test_name} PRIVATE ${upa_lib_target}) + + if ("${test_name}" STREQUAL "test-url_for_") + if (UPA_TEST_URL_FOR_QT) + target_compile_definitions(${test_name} PRIVATE UPA_TEST_URL_FOR_QT) + target_link_libraries(${test_name} PRIVATE Qt6::Core) + endif() + endif() add_test(NAME ${test_name} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/test diff --git a/include/upa/url_for_qt.h b/include/upa/url_for_qt.h index 3d8597a..6e49c48 100644 --- a/include/upa/url_for_qt.h +++ b/include/upa/url_for_qt.h @@ -7,21 +7,51 @@ #include "url.h" // IWYU pragma: export #include +#if defined(__has_include) && __has_include() +# include +#else +# include +#endif +#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0) +# include +#endif +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) +# include +#endif +#include // std::ptrdiff_t namespace upa { -template<> -struct str_arg_char { - using type = char16_t; +template +struct str_arg_char_for_qt { + static_assert(sizeof(typename StrT::value_type) == sizeof(CharT), + "StrT::value_type and CharT must be the same size"); + using type = CharT; - static str_arg to_str_arg(const QString& str) { + static str_arg to_str_arg(const StrT& str) { return { - reinterpret_cast(str.data()), + reinterpret_cast(str.data()), static_cast(str.length()) }; } }; +template<> +struct str_arg_char : + public str_arg_char_for_qt {}; + +#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0) +template<> +struct str_arg_char : + public str_arg_char_for_qt {}; +#endif + +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) +template<> +struct str_arg_char : + public str_arg_char_for_qt {}; +#endif + } // namespace upa #endif // UPA_URL_FOR_QT_H diff --git a/test/test-url_for_.cpp b/test/test-url_for_.cpp index 8be19bb..149a62b 100644 --- a/test/test-url_for_.cpp +++ b/test/test-url_for_.cpp @@ -13,6 +13,23 @@ # include #endif +#ifdef UPA_TEST_URL_FOR_QT +# include "upa/url_for_qt.h" +# include +# if defined(__has_include) && __has_include() +# include +# else +# include +# endif +# if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0) +# include +# endif +# if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) +# include +# endif +#endif + + #ifdef UPA_TEST_URL_FOR_ATL TEST_CASE("ATL::CSimpleStringA input") { @@ -42,3 +59,27 @@ TEST_CASE_TEMPLATE_INVOKE(test_url_for_atl, ATL::CStringW, ATL::CFixedStringT); #endif // UPA_TEST_URL_FOR_ATL + +#ifdef UPA_TEST_URL_FOR_QT + +TEST_CASE_TEMPLATE_DEFINE("Qt string input", StrT, test_url_for_qt) { + StrT str_input("http://host/"); + upa::url url{ str_input }; + CHECK(url.href() == "http://host/"); +} + +TEST_CASE_TEMPLATE_INVOKE(test_url_for_qt, QString); + +#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0) +TEST_CASE("QStringView input") { + QStringView str_input(u"http://host/"); + upa::url url{ str_input }; + CHECK(url.href() == "http://host/"); +} +#endif + +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) +TEST_CASE_TEMPLATE_INVOKE(test_url_for_qt, QUtf8StringView); +#endif + +#endif // UPA_TEST_URL_FOR_QT From 9d200baf8927cb975f88f72eaef94af13b0e8de6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rimas=20Misevi=C4=8Dius?= Date: Thu, 17 Oct 2024 19:36:40 +0300 Subject: [PATCH 4/4] Add "String input" documentation --- Doxyfile | 3 ++- README.md | 2 +- doc/string_input.md | 23 +++++++++++++++++++++++ include/upa/url_for_atl.h | 4 ++++ include/upa/url_for_qt.h | 4 ++++ 5 files changed, 34 insertions(+), 2 deletions(-) create mode 100644 doc/string_input.md diff --git a/Doxyfile b/Doxyfile index bfe097d..30b6968 100644 --- a/Doxyfile +++ b/Doxyfile @@ -970,7 +970,8 @@ INPUT = include/upa/url.h \ include/upa/url_result.h \ include/upa/url_search_params.h \ include/upa/url_percent_encode.h \ - README.md + README.md \ + doc/string_input.md # This tag can be used to specify the character encoding of the source files # that Doxygen parses. Internally Doxygen uses the UTF-8 encoding. Doxygen uses diff --git a/README.md b/README.md index cee329e..5b5282f 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ Upa URL contains features not specified in the standard: 4. Experimental URLHost class (see proposal: https://github.com/whatwg/url/pull/288): `upa::url_host` 5. The `upa::url_search_params` class has a few additional functions: `remove`, `remove_if` -For string input, the library supports UTF-8, UTF-16, UTF-32 encodings and several string types, including `std::basic_string`, `std::basic_string_view`, null-terminated strings of any char type: `char`, `char8_t`, `char16_t`, `char32_t`, or `wchar_t`. +For string input, the library supports UTF-8, UTF-16, UTF-32 encodings and several string types, including `std::basic_string`, `std::basic_string_view`, null-terminated strings of any char type: `char`, `char8_t`, `char16_t`, `char32_t`, or `wchar_t`. See ["String input"](doc/string_input.md) for more information. ## Installation diff --git a/doc/string_input.md b/doc/string_input.md new file mode 100644 index 0000000..322803c --- /dev/null +++ b/doc/string_input.md @@ -0,0 +1,23 @@ +## String input + +For string input, the library supports UTF-8, UTF-16, UTF-32 encodings and several string types, including `std::basic_string`, `std::basic_string_view`, null-terminated strings of any char type: `char`, `char8_t`, `char16_t`, `char32_t`, or `wchar_t`. + +The ATL/MFC and Qt library string types are also supported. To use them you need to include the header files listed in the table below instead of `url.h`: + +| Library | Supported string types | Include instead of `url.h` | +|-|-|-| +| ATL/MFC | `CSimpleStringT`, `CStringT`, `CFixedStringT` | `url_for_atl.h` | +| Qt | `QString`, `QStringView`, `QUtf8StringView` | `url_for_qt.h` | + +Qt example: +```cpp +#include "upa/url_for_qt.h" +#include + +int main() { + QString str{"http://example.com/"}; + upa::url url{str}; + std::cout << url.href() << '\n'; + return 0; +} +``` diff --git a/include/upa/url_for_atl.h b/include/upa/url_for_atl.h index 206e6b5..979e0a9 100644 --- a/include/upa/url_for_atl.h +++ b/include/upa/url_for_atl.h @@ -1,6 +1,10 @@ // Copyright 2024 Rimas Misevičius // Distributed under the BSD-style license that can be // found in the LICENSE file. + +// This file can be included instead of url.h to allow strings of the +// ATL/MFC classes CSimpleStringT, CStringT, CFixedStringT to be used +// as string input in the functions of this library. // #ifndef UPA_URL_FOR_ATL_H #define UPA_URL_FOR_ATL_H diff --git a/include/upa/url_for_qt.h b/include/upa/url_for_qt.h index 6e49c48..36d2eb1 100644 --- a/include/upa/url_for_qt.h +++ b/include/upa/url_for_qt.h @@ -1,6 +1,10 @@ // Copyright 2024 Rimas Misevičius // Distributed under the BSD-style license that can be // found in the LICENSE file. + +// This file can be included instead of url.h to allow strings of the +// Qt classes QString, QStringView, QUtf8StringView to be used as string +// input in the functions of this library. // #ifndef UPA_URL_FOR_QT_H #define UPA_URL_FOR_QT_H