From 62cc1ed5a74545bd8959bb9f8c6882f92766fcf8 Mon Sep 17 00:00:00 2001 From: Eugene Gershnik Date: Fri, 27 May 2022 03:28:31 -0700 Subject: [PATCH 1/4] Allowing generic unix storage on Windows too --- doc/Windows.md | 3 ++ lib/inc/sys_string/impl/platform.h | 13 +++++++- .../impl/platforms/windows_generic.h | 30 +++++++++---------- test/CMakeLists.txt | 1 + 4 files changed, 31 insertions(+), 16 deletions(-) diff --git a/doc/Windows.md b/doc/Windows.md index 9c1c40e..4dcc012 100644 --- a/doc/Windows.md +++ b/doc/Windows.md @@ -3,6 +3,9 @@ On Windows there isn't a single, universally used system string type. Win32 API uses plain `wchar_t *`, traditional OLE/COM relies on `BSTR`, while newer C++/WinRT uses `HSTRING`. To target your specific scenario `sys_string` can be configured at compile time to use either of these types of storage. If no configuration flags are specified the default storage is plain `wchar_t *`. +Additionally, some programs rely on Unix compatibility APIs exclusively and, for those, Windows platform also supports "generic Unix" storage which stores `char *` and is meant to interoperate with plain Unix API. +It can be selected via `#define SYS_STRING_USE_GENERIC 1` and is described under [Linux](Linux.md). + Being the lowest-common denominator, zero-cost conversions to `const wchar_t *` are available in all configurations. Conversions supported by each storage type are described below. diff --git a/lib/inc/sys_string/impl/platform.h b/lib/inc/sys_string/impl/platform.h index 0d1cb81..5242879 100644 --- a/lib/inc/sys_string/impl/platform.h +++ b/lib/inc/sys_string/impl/platform.h @@ -66,6 +66,7 @@ #include #include #include + #include #if SYS_STRING_WIN_BSTR @@ -87,7 +88,7 @@ #define SYS_STRING_STATIC SYS_STRING_STATIC_HSTRING - #else + #elif SYS_STRING_USE_GENERIC namespace sysstr { @@ -97,6 +98,16 @@ #define SYS_STRING_STATIC SYS_STRING_STATIC_GENERIC + #else + + namespace sysstr + { + using sys_string = sys_string_win_generic; + using sys_string_builder = sys_string_win_generic_builder; + } + + #define SYS_STRING_STATIC SYS_STRING_STATIC_WIN_GENERIC + #endif #elif defined(__linux__) diff --git a/lib/inc/sys_string/impl/platforms/windows_generic.h b/lib/inc/sys_string/impl/platforms/windows_generic.h index a24e5a0..3637a27 100644 --- a/lib/inc/sys_string/impl/platforms/windows_generic.h +++ b/lib/inc/sys_string/impl/platforms/windows_generic.h @@ -15,7 +15,7 @@ namespace sysstr::util { - struct generic_traits + struct win_generic_traits { using storage_type = char16_t; using size_type = size_t; @@ -25,20 +25,20 @@ namespace sysstr::util }; template - using generic_static_buffer = generic::static_buffer; - using generic_dynamic_buffer = generic::dynamic_buffer; + using win_generic_static_buffer = generic::static_buffer; + using win_generic_dynamic_buffer = generic::dynamic_buffer; - using generic_buffer = generic::buffer; + using win_generic_buffer = generic::buffer; - using generic_builder_impl = generic::buffer_builder; + using win_generic_builder_impl = generic::buffer_builder; - using generic_char_access = generic::char_access; + using win_generic_char_access = generic::char_access; } namespace sysstr { - class generic_storage: private util::generic::storage + class win_generic_storage: private util::generic::storage { friend util::generic_char_access; private: @@ -92,13 +92,13 @@ namespace sysstr::util template<> template<> inline - generic_char_access::char_access(const sys_string_t & src) noexcept: + win_generic_char_access::char_access(const sys_string_t & src) noexcept: char_access(src.m_buffer) {} template<> inline - sys_string_t build(generic_builder_impl & builder) noexcept + sys_string_t build(win_generic_builder_impl & builder) noexcept { return sys_string_t(convert_to_string(builder)); } @@ -108,27 +108,27 @@ namespace sysstr { template<> inline - sys_string_t::sys_string_t(const char_access::cursor & src, size_type length): + sys_string_t::sys_string_t(const char_access::cursor & src, size_type length): sys_string_t(src.iterator(), length) {} template<> inline - sys_string_t::sys_string_t(const char_access::reverse_cursor & src, size_type length): + sys_string_t::sys_string_t(const char_access::reverse_cursor & src, size_type length): sys_string_t(src.iterator() - length, length) {} template<> inline - sys_string_t::sys_string_t(const char_access::iterator & first, const char_access::iterator & last): + sys_string_t::sys_string_t(const char_access::iterator & first, const char_access::iterator & last): sys_string_t(first, last - first) {} - using sys_string_generic = sys_string_t; - using sys_string_generic_builder = sys_string_builder_t; + using sys_string_win_generic = sys_string_t; + using sys_string_win_generic_builder = sys_string_builder_t; } -#define SYS_STRING_STATIC_GENERIC(x) ([] () noexcept -> ::sysstr::sys_string_generic { \ +#define SYS_STRING_STATIC_WIN_GENERIC(x) ([] () noexcept -> ::sysstr::sys_string_generic { \ constexpr ::size_t size = sizeof(u##x) / sizeof(char16_t); \ static const ::sysstr::util::generic_static_buffer sbuf{0, true, u##x}; \ ::sysstr::util::generic_buffer buf((::sysstr::util::generic_dynamic_buffer *)&sbuf, size - 1, 0); \ diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index a8cbf86..f8102ce 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -31,6 +31,7 @@ if (WIN32) bstr hstring win_gen + unix_gen ) elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Darwin") From bab6db3ce6f6558adc9690ffea5d792c108d2ca8 Mon Sep 17 00:00:00 2001 From: gershnik Date: Fri, 27 May 2022 05:10:31 -0700 Subject: [PATCH 2/4] Fixing issues --- .../sys_string/impl/platforms/unix_generic.h | 7 +++ .../impl/platforms/windows_generic.h | 50 +++++++++---------- test/test_windows.cpp | 22 +++++++- 3 files changed, 52 insertions(+), 27 deletions(-) diff --git a/lib/inc/sys_string/impl/platforms/unix_generic.h b/lib/inc/sys_string/impl/platforms/unix_generic.h index 1ba9f9b..7d18104 100644 --- a/lib/inc/sys_string/impl/platforms/unix_generic.h +++ b/lib/inc/sys_string/impl/platforms/unix_generic.h @@ -58,6 +58,13 @@ namespace sysstr public: using super::super; +#ifdef _MSC_VER + template + generic_storage(const Char * str, size_t len, std::enable_if_t> * = nullptr): + super(str, len) + {} +#endif + protected: ~generic_storage() noexcept = default; generic_storage(const generic_storage & src) noexcept = default; diff --git a/lib/inc/sys_string/impl/platforms/windows_generic.h b/lib/inc/sys_string/impl/platforms/windows_generic.h index 3637a27..b0bf0b0 100644 --- a/lib/inc/sys_string/impl/platforms/windows_generic.h +++ b/lib/inc/sys_string/impl/platforms/windows_generic.h @@ -25,48 +25,48 @@ namespace sysstr::util }; template - using win_generic_static_buffer = generic::static_buffer; - using win_generic_dynamic_buffer = generic::dynamic_buffer; + using win_generic_static_buffer = generic::static_buffer; + using win_generic_dynamic_buffer = generic::dynamic_buffer; - using win_generic_buffer = generic::buffer; + using win_generic_buffer = generic::buffer; - using win_generic_builder_impl = generic::buffer_builder; + using win_generic_builder_impl = generic::buffer_builder; - using win_generic_char_access = generic::char_access; + using win_generic_char_access = generic::char_access; } namespace sysstr { - class win_generic_storage: private util::generic::storage + class win_generic_storage: private util::generic::storage { - friend util::generic_char_access; + friend util::win_generic_char_access; private: - using super = util::generic::storage; + using super = util::generic::storage; public: using super::size_type; using super::storage_type; - using hash_type = util::generic_traits::hash_type; - using char_access = util::generic_char_access; - using builder_impl = util::generic_builder_impl; + using hash_type = util::win_generic_traits::hash_type; + using char_access = util::win_generic_char_access; + using builder_impl = util::win_generic_builder_impl; - static constexpr auto max_size = util::generic_traits::max_size; + static constexpr auto max_size = util::win_generic_traits::max_size; public: using super::super; template - generic_storage(const Char * str, size_t len, std::enable_if_t> * = nullptr): + win_generic_storage(const Char * str, size_t len, std::enable_if_t> * = nullptr): super(str, len) {} protected: - ~generic_storage() noexcept = default; - generic_storage(const generic_storage & src) noexcept = default; - generic_storage(generic_storage && src) noexcept = default; - generic_storage & operator=(const generic_storage & rhs) noexcept = default; - generic_storage & operator=(generic_storage && rhs) noexcept = default; + ~win_generic_storage() noexcept = default; + win_generic_storage(const win_generic_storage & src) noexcept = default; + win_generic_storage(win_generic_storage && src) noexcept = default; + win_generic_storage & operator=(const win_generic_storage & rhs) noexcept = default; + win_generic_storage & operator=(win_generic_storage && rhs) noexcept = default; public: using super::data; @@ -92,15 +92,15 @@ namespace sysstr::util template<> template<> inline - win_generic_char_access::char_access(const sys_string_t & src) noexcept: + win_generic_char_access::char_access(const sys_string_t & src) noexcept: char_access(src.m_buffer) {} template<> inline - sys_string_t build(win_generic_builder_impl & builder) noexcept + sys_string_t build(win_generic_builder_impl & builder) noexcept { - return sys_string_t(convert_to_string(builder)); + return sys_string_t(convert_to_string(builder)); } } @@ -128,11 +128,11 @@ namespace sysstr using sys_string_win_generic_builder = sys_string_builder_t; } -#define SYS_STRING_STATIC_WIN_GENERIC(x) ([] () noexcept -> ::sysstr::sys_string_generic { \ +#define SYS_STRING_STATIC_WIN_GENERIC(x) ([] () noexcept -> ::sysstr::sys_string_win_generic { \ constexpr ::size_t size = sizeof(u##x) / sizeof(char16_t); \ - static const ::sysstr::util::generic_static_buffer sbuf{0, true, u##x}; \ - ::sysstr::util::generic_buffer buf((::sysstr::util::generic_dynamic_buffer *)&sbuf, size - 1, 0); \ - return *reinterpret_cast<::sysstr::sys_string_generic *>(&buf); \ + static const ::sysstr::util::win_generic_static_buffer sbuf{0, true, u##x}; \ + ::sysstr::util::win_generic_buffer buf((::sysstr::util::win_generic_dynamic_buffer *)&sbuf, size - 1, 0); \ + return *reinterpret_cast<::sysstr::sys_string_win_generic *>(&buf); \ }()) diff --git a/test/test_windows.cpp b/test/test_windows.cpp index 1947b01..6d5e122 100644 --- a/test/test_windows.cpp +++ b/test/test_windows.cpp @@ -7,7 +7,6 @@ // #include - #include "catch.hpp" using namespace sysstr; @@ -111,6 +110,25 @@ using namespace sysstr; WindowsDeleteString(hstr); } +#elif SYS_STRING_USE_GENERIC + + TEST_CASE( "Windows Conversions", "[windows]") { + + REQUIRE(sys_string().c_str()); + CHECK(strcmp(sys_string().c_str(), "") == 0); + + REQUIRE(S("").c_str()); + CHECK(strcmp(S("").c_str(), "") == 0); + + REQUIRE(sys_string("").c_str()); + CHECK(strcmp(sys_string("").c_str(), "") == 0); + + REQUIRE(sys_string((const char*)nullptr).c_str()); + CHECK(strcmp(sys_string((const char*)nullptr).c_str(), "") == 0); + + CHECK(strcmp(sys_string("a水𐀀𝄞bcå🤢").c_str(), "a水𐀀𝄞bcå🤢") == 0); + } + #else TEST_CASE( "Windows Conversions", "[windows]") { @@ -130,4 +148,4 @@ using namespace sysstr; CHECK(wcscmp(sys_string(L"a水𐀀𝄞bcå🤢").w_str(), L"a水𐀀𝄞bcå🤢") == 0); } -#endif \ No newline at end of file +#endif From 5409e11c27eebbde8646b1ca76e8479c1f7d0925 Mon Sep 17 00:00:00 2001 From: Eugene Gershnik Date: Mon, 6 Jun 2022 07:21:28 -0700 Subject: [PATCH 3/4] Adding FreeBSD support --- lib/inc/sys_string/impl/platform.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/inc/sys_string/impl/platform.h b/lib/inc/sys_string/impl/platform.h index 5242879..19f71a7 100644 --- a/lib/inc/sys_string/impl/platform.h +++ b/lib/inc/sys_string/impl/platform.h @@ -110,7 +110,7 @@ #endif -#elif defined(__linux__) +#elif defined(__linux__) || defined(__FreeBSD__) #include From 1344b59f833c5328f0e955f5091d39f7a18b029c Mon Sep 17 00:00:00 2001 From: Eugene Gershnik Date: Thu, 9 Jun 2022 05:18:16 -0700 Subject: [PATCH 4/4] Removing debug output during Unicode tables generation --- lib/scripts/genmappings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/scripts/genmappings.py b/lib/scripts/genmappings.py index 578e980..25b2791 100644 --- a/lib/scripts/genmappings.py +++ b/lib/scripts/genmappings.py @@ -227,7 +227,7 @@ def make_whitespaces(): read_ucd_file(datadir/'DerivedCoreProperties.txt', parse_derived_properties) prop_builder.generate() -print(f'{prop_builder.block_size}: {len(prop_builder.stage1)}, {len(prop_builder.blocks)}, {len(prop_builder.stage1) + len(prop_builder.blocks) * prop_builder.block_size // prop_builder.count_per_byte}') +#print(f'{prop_builder.block_size}: {len(prop_builder.stage1)}, {len(prop_builder.blocks)}, {len(prop_builder.stage1) + len(prop_builder.blocks) * prop_builder.block_size // prop_builder.count_per_byte}') write_file(cppfile, f'''//THIS FILE IS GENERATED. PLEASE DO NOT EDIT DIRECTLY