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..19f71a7 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,9 +98,19 @@ #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__) +#elif defined(__linux__) || defined(__FreeBSD__) #include 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 a24e5a0..b0bf0b0 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,48 +25,48 @@ 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; + 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 - 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)); + return sys_string_t(convert_to_string(builder)); } } @@ -108,31 +108,31 @@ 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_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/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 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") 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