From b4ff206c24f44e5dbc2dea14d25bfbaf945dbc75 Mon Sep 17 00:00:00 2001 From: Anna Gringauze Date: Wed, 3 Feb 2016 19:04:39 -0800 Subject: [PATCH 1/3] Added zstring_span and removed zstring_builder to support legacy strings --- include/string_span.h | 67 +++++++++++++-------- tests/string_span_tests.cpp | 114 ++++++++++++++++++++++++++++++++++++ 2 files changed, 156 insertions(+), 25 deletions(-) diff --git a/include/string_span.h b/include/string_span.h index ecbee7c..3840d55 100644 --- a/include/string_span.h +++ b/include/string_span.h @@ -71,17 +71,21 @@ namespace gsl // type system for these types that will not either incur significant runtime costs or // (sometimes needlessly) break existing programs when introduced. // -template -using czstring = const char*; + +template +using basic_zstring = CharT*; template -using cwzstring = const wchar_t*; +using czstring = basic_zstring; template -using zstring = char*; +using cwzstring = basic_zstring; template -using wzstring = wchar_t*; +using zstring = basic_zstring; + +template +using wzstring = basic_zstring; // // ensure_sentinel() @@ -521,43 +525,56 @@ inline std::wstring to_string(wstring_span<> view) #endif +// zero-terminated string span, used to convert +// zero-terminated spans to legacy strings template -class basic_zstring_builder +class basic_zstring_span { public: - using impl_type = span; - using string_span_type = basic_string_span; using value_type = CharT; - using pointer = CharT*; - using size_type = typename string_span_type::size_type; - using iterator = typename string_span_type::iterator; + using const_value_type = std::add_const_t; - basic_zstring_builder(CharT* data, size_type length) : sv_(data, length) {} + using pointer = std::add_pointer_t; + using const_pointer = std::add_pointer_t; - template - basic_zstring_builder(CharT(&arr)[Size]) : sv_(arr) {} + using zstring_type = basic_zstring; + using const_zstring_type = basic_zstring; - pointer data() const { return sv_.data(); } - string_span_type view() const { return sv_; } + using impl_type = span; + using string_span_type = basic_string_span; - size_type length() const { return sv_.length(); } + constexpr basic_zstring_span(impl_type span) noexcept + : sp_(span) + { + // expects a zero-terminated span + Expects(span[span.size() - 1] == '\0'); + } - pointer assume0() const { return data(); } - string_span_type ensure_z() const { return gsl::ensure_z(sv_); } + constexpr bool empty() const noexcept { return sp_.size() == 0; } - iterator begin() const { return sv_.begin(); } - iterator end() const { return sv_.end(); } + constexpr string_span_type as_string_span() const noexcept { return sp_.first(sp_.size()-1); } + + constexpr string_span_type ensure_z() const noexcept { return gsl::ensure_z(sp_); } + + constexpr const_zstring_type assume_z() const noexcept { return sp_.data(); } private: - impl_type sv_; + impl_type sp_; }; template -using zstring_builder = basic_zstring_builder; +using zstring_span = basic_zstring_span; template -using wzstring_builder = basic_zstring_builder; -} +using wzstring_span = basic_zstring_span; + +template +using czstring_span = basic_zstring_span; + +template +using cwzstring_span = basic_zstring_span; + +} // namespace GSL // operator == template CreateTempName(string_span<> span) + { + Expects(span.size() > 1); + + int last = 0; + if (span.size() > 4) + { + span[0] = 't'; + span[1] = 'm'; + span[2] = 'p'; + last = 3; + } + span[last] = '\0'; + + auto ret = span.subspan(0, 4); + return ret; + } + + TEST(zstring) + { + + // create zspan from zero terminated string + { + char buf[1]; + buf[0] = '\0'; + + zstring_span<> zspan({ buf, 1 }); + + CHECK(strlen(zspan.assume_z()) == 0); + CHECK(zspan.as_string_span().size() == 0); + CHECK(zspan.ensure_z().size() == 0); + } + + // create zspan from non-zero terminated string + { + char buf[1]; + buf[0] = 'a'; + + auto workaround_macro = [&]() { zstring_span<> zspan({ buf, 1 }); }; + CHECK_THROW(workaround_macro(), fail_fast); + } + + // usage scenario: create zero-terminated temp file name and pass to a legacy API + { + char buf[10]; + + auto name = CreateTempName({ buf, 10 }); + if (!name.empty()) + { + czstring<> str = name.assume_z(); + CHECK(strlen(str) == 3); + CHECK(*(str+3) == '\0'); + } + } + + } + + cwzstring_span<> CreateTempNameW(wstring_span<> span) + { + Expects(span.size() > 1); + + int last = 0; + if (span.size() > 4) + { + span[0] = L't'; + span[1] = L'm'; + span[2] = L'p'; + last = 3; + } + span[last] = L'\0'; + + auto ret = span.subspan(0, 4); + return ret; + } + + TEST(wzstring) + { + + // create zspan from zero terminated string + { + wchar_t buf[1]; + buf[0] = L'\0'; + + wzstring_span<> zspan({ buf, 1 }); + + CHECK(wcsnlen(zspan.assume_z(), 1) == 0); + CHECK(zspan.as_string_span().size() == 0); + CHECK(zspan.ensure_z().size() == 0); + } + + // create zspan from non-zero terminated string + { + wchar_t buf[1]; + buf[0] = L'a'; + + auto workaround_macro = [&]() { wzstring_span<> zspan({ buf, 1 }); }; + CHECK_THROW(workaround_macro(), fail_fast); + } + + // usage scenario: create zero-terminated temp file name and pass to a legacy API + { + wchar_t buf[10]; + + auto name = CreateTempNameW({ buf, 10 }); + if (!name.empty()) + { + cwzstring<> str = name.assume_z(); + CHECK(wcsnlen(str, 10) == 3); + CHECK(*(str + 3) == L'\0'); + } + } + + } } int main(int, const char *[]) From ed906e7aaebdbd2fccf234b13c9f3e01cf6fde44 Mon Sep 17 00:00:00 2001 From: Anna Gringauze Date: Sat, 6 Feb 2016 10:46:40 -0800 Subject: [PATCH 2/3] Addressed CR comments --- include/string_span.h | 40 +++++++++++++++++++++++++++++++++------- 1 file changed, 33 insertions(+), 7 deletions(-) diff --git a/include/string_span.h b/include/string_span.h index 3840d55..786e055 100644 --- a/include/string_span.h +++ b/include/string_span.h @@ -527,7 +527,7 @@ inline std::wstring to_string(wstring_span<> view) // zero-terminated string span, used to convert // zero-terminated spans to legacy strings -template +template class basic_zstring_span { public: @@ -544,22 +544,48 @@ public: using string_span_type = basic_string_span; constexpr basic_zstring_span(impl_type span) noexcept - : sp_(span) + : span_(span) { // expects a zero-terminated span Expects(span[span.size() - 1] == '\0'); } - constexpr bool empty() const noexcept { return sp_.size() == 0; } + // copy + constexpr basic_zstring_span(const basic_zstring_span& other) = default; - constexpr string_span_type as_string_span() const noexcept { return sp_.first(sp_.size()-1); } + // move +#ifndef GSL_MSVC_NO_DEFAULT_MOVE_CTOR + constexpr basic_zstring_span(basic_zstring_span&& other) = default; +#else + constexpr basic_zstring_span(basic_zstring_span&& other) + : span_(std::move(other.span_)) + {} +#endif - constexpr string_span_type ensure_z() const noexcept { return gsl::ensure_z(sp_); } + // assign + constexpr basic_zstring_span& operator=(const basic_zstring_span& other) = default; - constexpr const_zstring_type assume_z() const noexcept { return sp_.data(); } + // move assign +#ifndef GSL_MSVC_NO_DEFAULT_MOVE_CTOR + constexpr basic_zstring_span& operator=(basic_zstring_span&& other) = default; +#else + constexpr basic_zstring_span& operator=(basic_zstring_span&& other) + { + span_ = std::move(other.span_); + return *this; + } +#endif + + constexpr bool empty() const noexcept { return span_.size() == 0; } + + constexpr string_span_type as_string_span() const noexcept { return span_.first(span_.size()-1); } + + constexpr string_span_type ensure_z() const noexcept { return gsl::ensure_z(span_); } + + constexpr const_zstring_type assume_z() const noexcept { return span_.data(); } private: - impl_type sp_; + impl_type span_; }; template From 45f2bdb486ea64afdb7b3045179514291ec1607d Mon Sep 17 00:00:00 2001 From: Anna Gringauze Date: Sat, 6 Feb 2016 21:37:17 +0000 Subject: [PATCH 3/3] Fixed compilation issues with gcc and clang --- include/string_span.h | 8 ++++---- tests/string_span_tests.cpp | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/include/string_span.h b/include/string_span.h index 786e055..46bf2d4 100644 --- a/include/string_span.h +++ b/include/string_span.h @@ -588,16 +588,16 @@ private: impl_type span_; }; -template +template using zstring_span = basic_zstring_span; -template +template using wzstring_span = basic_zstring_span; -template +template using czstring_span = basic_zstring_span; -template +template using cwzstring_span = basic_zstring_span; } // namespace GSL diff --git a/tests/string_span_tests.cpp b/tests/string_span_tests.cpp index 6abdcb9..28d7353 100644 --- a/tests/string_span_tests.cpp +++ b/tests/string_span_tests.cpp @@ -846,7 +846,7 @@ SUITE(string_span_tests) span[last] = '\0'; auto ret = span.subspan(0, 4); - return ret; + return{ ret }; } TEST(zstring) @@ -903,7 +903,7 @@ SUITE(string_span_tests) span[last] = L'\0'; auto ret = span.subspan(0, 4); - return ret; + return{ ret }; } TEST(wzstring)