diff --git a/.gitignore b/.gitignore index 74f33d3..9006ccd 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,15 @@ bin/ bin64/ +build/ # Because of CMake and VS2017 Win32/ x64/ .vs/ -out/ \ No newline at end of file +out/ + +# VS CMake settings +/CMakeSettings.json +# CMake presets +/CMakePresets.json +/CMakeUserPresets.json diff --git a/include/boost/static_string/static_string.hpp b/include/boost/static_string/static_string.hpp index fce1ddb..78463b8 100644 --- a/include/boost/static_string/static_string.hpp +++ b/include/boost/static_string/static_string.hpp @@ -310,103 +310,125 @@ copy_with_traits( template class static_string_base { -private: + using derived_type = basic_static_string; + friend derived_type; + using size_type = smallest_width; using value_type = typename Traits::char_type; using pointer = value_type*; using const_pointer = const value_type*; -public: - BOOST_STATIC_STRING_CPP11_CONSTEXPR - static_string_base() noexcept { }; - - BOOST_STATIC_STRING_CPP14_CONSTEXPR - pointer - data_impl() noexcept - { - return data_; - } - - BOOST_STATIC_STRING_CPP14_CONSTEXPR - const_pointer - data_impl() const noexcept - { - return data_; - } - - BOOST_STATIC_STRING_CPP11_CONSTEXPR - std::size_t - size_impl() const noexcept - { - return size_; - } - BOOST_STATIC_STRING_CPP14_CONSTEXPR - std::size_t - set_size(std::size_t n) noexcept + struct size { - // Functions that set size will throw - // if the new size would exceed max_size() - // therefore we can guarantee that this will - // not lose data. - return size_ = size_type(n); - } - - BOOST_STATIC_STRING_CPP14_CONSTEXPR - void - term_impl() noexcept - { - Traits::assign(data_[size_], value_type()); - } - - size_type size_ = 0; - - value_type data_[N + 1]{}; + class basic_static_string + { + friend derived_type; + + BOOST_STATIC_STRING_CPP11_CONSTEXPR + size_type + size_impl() const noexcept + { + return size; + } + + BOOST_STATIC_STRING_CPP14_CONSTEXPR + size_type + size_impl(std::size_t n) noexcept + { + // Functions that set size will throw + // if the new size would exceed max_size() + // therefore we can guarantee that this will + // not lose data. + return size = static_cast(n); + } + + public: + size_type size = 0; + }; + }; + + struct data + { + class basic_static_string + { + friend derived_type; + + BOOST_STATIC_STRING_CPP14_CONSTEXPR + pointer + data_impl() noexcept + { + return data; + } + + BOOST_STATIC_STRING_CPP11_CONSTEXPR + const_pointer + data_impl() const noexcept + { + return data; + } + + public: + value_type data[N + 1]{}; + }; + }; }; // Optimization for when the size is 0 template class static_string_base<0, CharT, Traits> { -private: + using derived_type = basic_static_string<0, CharT, Traits>; + friend derived_type; + + using size_type = std::size_t; using value_type = typename Traits::char_type; using pointer = value_type*; -public: - BOOST_STATIC_STRING_CPP11_CONSTEXPR - static_string_base() noexcept { } - // Modifying the null terminator is UB - BOOST_STATIC_STRING_CPP11_CONSTEXPR - pointer - data_impl() const noexcept - { - return const_cast(&null_); - } - - BOOST_STATIC_STRING_CPP11_CONSTEXPR - std::size_t - size_impl() const noexcept - { - return 0; - } - - BOOST_STATIC_STRING_CPP11_CONSTEXPR - std::size_t - set_size(std::size_t) const noexcept + struct size { - return 0; - } - - BOOST_STATIC_STRING_CPP14_CONSTEXPR - void - term_impl() const noexcept { } - -private: - static constexpr const value_type null_{}; + class basic_static_string + { + friend derived_type; + + BOOST_STATIC_STRING_CPP11_CONSTEXPR + size_type + size_impl() const noexcept + { + return 0; + } + + BOOST_STATIC_STRING_CPP11_CONSTEXPR + size_type + size_impl(std::size_t) const noexcept + { + return 0; + } + }; + }; + + struct data + { + class basic_static_string + { + friend derived_type; + + BOOST_STATIC_STRING_CPP11_CONSTEXPR + pointer + data_impl() const noexcept + { + return const_cast(&data); + } + + public: + static constexpr value_type data{}; + }; + }; }; // This is only needed in C++14 and lower. // see http://eel.is/c++draft/depr.static.constexpr #ifndef BOOST_STATIC_STRING_CPP17 +#if 0 template constexpr const @@ -415,6 +437,13 @@ static_string_base<0, CharT, Traits>:: null_; #endif +template +constexpr +typename static_string_base<0, CharT, Traits>::value_type +static_string_base<0, CharT, Traits>::data::basic_static_string::data; +#endif + + template BOOST_STATIC_STRING_CPP14_CONSTEXPR inline @@ -919,7 +948,11 @@ template> class basic_static_string #ifndef BOOST_STATIC_STRING_DOCS - : private detail::static_string_base + // : public detail::static_string_base + : public detail::static_string_base< + N, CharT, Traits>::size::basic_static_string + , public detail::static_string_base< + N, CharT, Traits>::data::basic_static_string #endif { private: @@ -2211,7 +2244,7 @@ class basic_static_string void clear() noexcept { - this->set_size(0); + this->size_impl(0); term(); } @@ -2803,7 +2836,7 @@ class basic_static_string pop_back() noexcept { BOOST_STATIC_STRING_ASSERT(!empty()); - this->set_size(size() - 1); + this->size_impl(size() - 1); term(); } @@ -2979,7 +3012,7 @@ class basic_static_string InputIterator first, InputIterator last) { - this->set_size(size() + read_back(true, first, last)); + this->size_impl(size() + read_back(true, first, last)); return term(); } @@ -5431,11 +5464,22 @@ class basic_static_string } private: + BOOST_STATIC_STRING_CPP14_CONSTEXPR + void term_impl(std::true_type) noexcept + { + traits_type::assign(data()[size()], value_type()); + } + + BOOST_STATIC_STRING_CPP14_CONSTEXPR + void term_impl(std::false_type) noexcept + { + } + BOOST_STATIC_STRING_CPP14_CONSTEXPR basic_static_string& term() noexcept { - this->term_impl(); + term_impl(std::integral_constant()); return *this; } @@ -5443,7 +5487,7 @@ class basic_static_string basic_static_string& assign_char(value_type ch, std::true_type) noexcept { - this->set_size(1); + this->size_impl(1); traits_type::assign(data()[0], ch); return term(); } @@ -5517,7 +5561,7 @@ class basic_static_string const_pointer s, size_type count) noexcept { - this->set_size(count); + this->size_impl(count); traits_type::copy(data(), s, size() + 1); return *this; } @@ -6434,7 +6478,7 @@ assign( if (count > max_size()) detail::throw_exception( "count > max_size()"); - this->set_size(count); + this->size_impl(count); traits_type::assign(data(), size(), ch); return term(); } @@ -6451,7 +6495,7 @@ assign( if (count > max_size()) detail::throw_exception( "count > max_size()"); - this->set_size(count); + this->size_impl(count); traits_type::move(data(), s, size()); return term(); } @@ -6473,13 +6517,13 @@ assign( { if (i >= max_size()) { - this->set_size(i); + this->size_impl(i); term(); detail::throw_exception("n > max_size()"); } traits_type::assign(*ptr, *first); } - this->set_size(ptr - data()); + this->size_impl(ptr - data()); return term(); } @@ -6501,7 +6545,7 @@ insert( const auto index = pos - curr_data; traits_type::move(&curr_data[index + count], &curr_data[index], curr_size - index + 1); traits_type::assign(&curr_data[index], count, ch); - this->set_size(curr_size + count); + this->size_impl(curr_size + count); return &curr_data[index]; } @@ -6554,7 +6598,7 @@ insert( traits_type::copy(dest, src, count); } } - this->set_size(curr_size + count); + this->size_impl(curr_size + count); return curr_data + index; } @@ -6578,7 +6622,7 @@ insert( const auto count = read_back(false, first, last); const std::size_t index = pos - curr_data; std::rotate(&curr_data[index], &curr_data[curr_size + 1], &curr_data[curr_size + count + 1]); - this->set_size(curr_size + count); + this->size_impl(curr_size + count); return curr_data + index; } @@ -6594,7 +6638,7 @@ erase( const auto curr_data = data(); const std::size_t index = first - curr_data; traits_type::move(&curr_data[index], last, (end() - last) + 1); - this->set_size(size() - std::size_t(last - first)); + this->size_impl(size() - std::size_t(last - first)); return curr_data + index; } @@ -6610,7 +6654,7 @@ push_back( detail::throw_exception( "curr_size >= max_size()"); traits_type::assign(data()[curr_size], ch); - this->set_size(curr_size + 1); + this->size_impl(curr_size + 1); term(); } @@ -6628,7 +6672,7 @@ append( detail::throw_exception( "count > max_size() - size()"); traits_type::assign(end(), count, ch); - this->set_size(curr_size + count); + this->size_impl(curr_size + count); return term(); } @@ -6646,7 +6690,7 @@ append( detail::throw_exception( "count > max_size() - size()"); traits_type::copy(end(), s, count); - this->set_size(curr_size + count); + this->size_impl(curr_size + count); return term(); } @@ -6662,7 +6706,7 @@ resize(size_type n, value_type c) const auto curr_size = size(); if(n > curr_size) traits_type::assign(data() + curr_size, n - curr_size, c); - this->set_size(n); + this->size_impl(n); term(); } @@ -6674,9 +6718,9 @@ swap(basic_static_string& s) noexcept { const auto curr_size = size(); basic_static_string tmp(s); - s.set_size(curr_size); + s.size_impl(curr_size); traits_type::copy(&s.data()[0], data(), curr_size + 1); - this->set_size(tmp.size()); + this->size_impl(tmp.size()); traits_type::copy(data(), tmp.data(), size() + 1); } @@ -6695,10 +6739,8 @@ swap(basic_static_string& s) detail::throw_exception( "s.size() > max_size()"); basic_static_string tmp(s); - s.set_size(curr_size); - traits_type::copy(&s.data()[0], data(), curr_size + 1); - this->set_size(tmp.size()); - traits_type::copy(data(), &tmp.data()[0], size() + 1); + s.assign_unchecked(data(), curr_size); + assign_unchecked(tmp.data(), tmp.size()); } template @@ -6721,7 +6763,7 @@ replace( const auto pos = i1 - curr_data; traits_type::move(&curr_data[pos + n], i2, (end() - i2) + 1); traits_type::assign(&curr_data[pos], n, c); - this->set_size((curr_size - n1) + n); + this->size_impl((curr_size - n1) + n); return *this; } @@ -6782,7 +6824,7 @@ replace( traits_type::move(&curr_data[pos + n2], &curr_data[pos + n1], curr_size - pos - n1 + 1); } } - this->set_size((curr_size - n1) + n2); + this->size_impl((curr_size - n1) + n2); return *this; } @@ -6814,7 +6856,7 @@ replace( // Move everything from the end of the splice point to the end of the rotated string to // the begining of the splice point traits_type::move(&curr_data[pos + n2], &curr_data[pos + n2 + n1], ((curr_size - n1) + n2) - pos); - this->set_size((curr_size - n1) + n2); + this->size_impl((curr_size - n1) + n2); return *this; } @@ -6986,7 +7028,7 @@ replace_unchecked( "replaced string exceeds max_size()"); traits_type::move(&curr_data[pos + n2], i2, (end() - i2) + 1); traits_type::copy(&curr_data[pos], s, n2); - this->set_size((curr_size - n1) + n2); + this->size_impl((curr_size - n1) + n2); return *this; } @@ -7008,7 +7050,7 @@ insert_unchecked( const std::size_t index = pos - curr_data; traits_type::move(&curr_data[index + count], pos, (end() - pos) + 1); traits_type::copy(&curr_data[index], s, count); - this->set_size(curr_size + count); + this->size_impl(curr_size + count); return curr_data + index; } diff --git a/test/compile_fail.hpp b/test/compile_fail.hpp index d0d0dfd..03510f1 100644 --- a/test/compile_fail.hpp +++ b/test/compile_fail.hpp @@ -4,16 +4,6 @@ namespace boost { namespace static_strings { -static_assert(std::is_base_of< - detail::static_string_base<0, char, std::char_traits>, - static_string<0>>::value, - "the zero size optimization shall be used for N = 0"); - -static_assert(std::is_base_of< - detail::static_string_base<(std::numeric_limits::max)() + 1, char, std::char_traits>, - static_string<(std::numeric_limits::max)() + 1>>::value, - "the minimum size type optimization shall be used for N > 0"); - static_assert(!detail::is_input_iterator::value, "is_input_iterator is incorrect"); static_assert(!detail::is_input_iterator::value, "is_input_iterator is incorrect"); static_assert(detail::is_input_iterator::value, "is_input_iterator is incorrect"); diff --git a/test/constexpr_tests.hpp b/test/constexpr_tests.hpp index 9b2e83c..ad8402e 100644 --- a/test/constexpr_tests.hpp +++ b/test/constexpr_tests.hpp @@ -22,38 +22,74 @@ struct cxper_char_traits using int_type = int; using state_type = std::mbstate_t; - static constexpr void assign(char_type& a, const char_type& b) noexcept { a = b; } - static constexpr bool eq(char_type a, char_type b) noexcept { return a == b; } - static constexpr bool lt(char_type a, char_type b) noexcept { return a < b; } + static constexpr void assign(char_type& a, const char_type& b) noexcept + { + a = b; + } + + static constexpr bool eq(char_type a, char_type b) noexcept + { + return a == b; + } + + static constexpr bool lt(char_type a, char_type b) noexcept + { + return a < b; + } + + static constexpr int compare(const char_type* a, const char_type* b, std::size_t n) + { + for (; n--; ++a, ++b) + { + if(lt(*a, *b)) + return 1; + else if(lt(*b, *a)) + return -1; + } + return 0; + } - static constexpr int compare(const char_type*, const char_type*, std::size_t) { return 0; } static constexpr std::size_t length(const char_type* s) { - std::size_t n = 0; - while (*(s++)); - return n; + auto ptr = s; + while (!eq(*ptr, char_type())) + ++ptr; + return ptr - s; } - static constexpr const char_type* find(const char_type*, std::size_t, const char_type&){ return 0; } + + static constexpr const char_type* find(const char_type* s, std::size_t n, const char_type& ch) + { + for (; n--; ++s) + { + if (eq(*s, ch)) + return s; + } + return nullptr; + } + static constexpr char_type* move(char_type* dest, const char_type* src, std::size_t n) { - const auto temp = dest; - while (n--) - *(dest++) = *(src++); - return temp; + if (detail::ptr_in_range(src, src + n, dest)) + { + while (n--) + assign(dest[n], src[n]); + return dest; + } + return copy(dest, src, n); } + static constexpr char_type* copy(char_type* dest, const char_type* src, std::size_t n) { - const auto temp = dest; - while (n--) - *(dest++) = *(src++); - return temp; + for (auto ptr = dest; n--;) + assign(*ptr++, *src++); + return dest; } + static constexpr char_type* assign(char_type* dest, std::size_t n, char_type ch) { - const auto temp = dest; - while (n--) - *(dest++) = ch; - return temp; + for (auto ptr = dest; n--;) + assign(*ptr++, ch); + return dest; } }; #else @@ -605,5 +641,28 @@ testConstantEvaluation() cstatic_string().empty(); #endif } + +#ifdef BOOST_STATIC_STRING_CPP20 + +template X> +struct nttp_primary +{ + static constexpr bool value = false; +}; + +template<> +struct nttp_primary<"test string"> +{ + static constexpr bool value = true; +}; + +static_assert(!nttp_primary<"random string">::value, + "structural equality broken"); + +static_assert(nttp_primary<"test string">::value, + "structural equality broken"); + +#endif + } // static_strings } // boost \ No newline at end of file