diff options
author | Anna Gringauze <annagrin@microsoft.com> | 2016-02-04 06:04:39 +0300 |
---|---|---|
committer | Anna Gringauze <annagrin@microsoft.com> | 2016-02-04 06:30:34 +0300 |
commit | b4ff206c24f44e5dbc2dea14d25bfbaf945dbc75 (patch) | |
tree | 03044caa49126d94ccf321cdffcc721b98d0a18d | |
parent | 6b82ac3d9c944727793469482849ee9f8f16f7b6 (diff) |
Added zstring_span and removed zstring_builder to support legacy strings
-rw-r--r-- | include/string_span.h | 65 | ||||
-rw-r--r-- | tests/string_span_tests.cpp | 114 |
2 files changed, 155 insertions, 24 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<typename CharT, std::ptrdiff_t Extent = dynamic_range> +using basic_zstring = CharT*; + template<std::ptrdiff_t Extent = dynamic_range> -using czstring = const char*; +using czstring = basic_zstring<const char, Extent>; template<std::ptrdiff_t Extent = dynamic_range> -using cwzstring = const wchar_t*; +using cwzstring = basic_zstring<const wchar_t, Extent>; template<std::ptrdiff_t Extent = dynamic_range> -using zstring = char*; +using zstring = basic_zstring<char, Extent>; template<std::ptrdiff_t Extent = dynamic_range> -using wzstring = wchar_t*; +using wzstring = basic_zstring<wchar_t, Extent>; // // 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<typename CharT, size_t Extent = dynamic_range> -class basic_zstring_builder +class basic_zstring_span { public: - using impl_type = span<CharT, Extent>; - using string_span_type = basic_string_span<CharT, Extent>; 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<CharT>; + + using pointer = std::add_pointer_t<value_type>; + using const_pointer = std::add_pointer_t<const_value_type>; - basic_zstring_builder(CharT* data, size_type length) : sv_(data, length) {} + using zstring_type = basic_zstring<value_type, Extent>; + using const_zstring_type = basic_zstring<const_value_type, Extent>; - template<size_t Size> - basic_zstring_builder(CharT(&arr)[Size]) : sv_(arr) {} + using impl_type = span<value_type, Extent>; + using string_span_type = basic_string_span<value_type, Extent>; + + constexpr basic_zstring_span(impl_type span) noexcept + : sp_(span) + { + // expects a zero-terminated span + Expects(span[span.size() - 1] == '\0'); + } - pointer data() const { return sv_.data(); } - string_span_type view() const { return sv_; } + constexpr bool empty() const noexcept { return sp_.size() == 0; } - size_type length() const { return sv_.length(); } + constexpr string_span_type as_string_span() const noexcept { return sp_.first(sp_.size()-1); } - pointer assume0() const { return data(); } - string_span_type ensure_z() const { return gsl::ensure_z(sv_); } + constexpr string_span_type ensure_z() const noexcept { return gsl::ensure_z(sp_); } - iterator begin() const { return sv_.begin(); } - iterator end() const { return sv_.end(); } + constexpr const_zstring_type assume_z() const noexcept { return sp_.data(); } private: - impl_type sv_; + impl_type sp_; }; template <size_t Max = dynamic_range> -using zstring_builder = basic_zstring_builder<char, Max>; +using zstring_span = basic_zstring_span<char, Max>; template <size_t Max = dynamic_range> -using wzstring_builder = basic_zstring_builder<wchar_t, Max>; -} +using wzstring_span = basic_zstring_span<wchar_t, Max>; + +template <size_t Max = dynamic_range> +using czstring_span = basic_zstring_span<const char, Max>; + +template <size_t Max = dynamic_range> +using cwzstring_span = basic_zstring_span<const wchar_t, Max>; + +} // namespace GSL // operator == template <typename CharT, std::ptrdiff_t Extent = gsl::dynamic_range, typename T, diff --git a/tests/string_span_tests.cpp b/tests/string_span_tests.cpp index 88d125a..6abdcb9 100644 --- a/tests/string_span_tests.cpp +++ b/tests/string_span_tests.cpp @@ -830,6 +830,120 @@ SUITE(string_span_tests) CHECK(wspan.length() == 5); #endif } + + czstring_span<> 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 *[]) |