diff --git a/include/boost/static_string/config.hpp b/include/boost/static_string/config.hpp index 1b72f9e..7c61947 100644 --- a/include/boost/static_string/config.hpp +++ b/include/boost/static_string/config.hpp @@ -33,8 +33,15 @@ #endif // Can we use is_constant_evaluated? +// Standard version #if __cpp_lib_is_constant_evaluated >= 201811L #define BOOST_STATIC_STRING_USE_IS_CONST_EVAL +#define BOOST_STATIC_STRING_IS_CONST_EVAL std::is_constant_evaluated() +#elif defined(__clang__) && (__clang_major__ > 8) +// If we have clang version 9+, we can use the intrinsic +// While gcc also has this, we don't need it +#define BOOST_STATIC_STRING_USE_IS_CONST_EVAL +#define BOOST_STATIC_STRING_IS_CONST_EVAL __builtin_is_constant_evaluated() #endif // Can we use [[nodiscard]]? @@ -56,36 +63,35 @@ #endif #if BOOST_STATIC_STRING_STANDARD_VERSION > 201703L +#define BOOST_STATIC_STRING_CPP20 +#define BOOST_STATIC_STRING_CPP17 +#define BOOST_STATIC_STRING_CPP14 +#define BOOST_STATIC_STRING_CPP11 #define BOOST_STATIC_STRING_CPP20_CONSTEXPR constexpr #define BOOST_STATIC_STRING_CPP17_CONSTEXPR constexpr #define BOOST_STATIC_STRING_CPP14_CONSTEXPR constexpr #define BOOST_STATIC_STRING_CPP11_CONSTEXPR constexpr -#define BOOST_STATIC_STRING_CPP20_CONSTEXPR_USED -#define BOOST_STATIC_STRING_CPP17_CONSTEXPR_USED -#define BOOST_STATIC_STRING_CPP14_CONSTEXPR_USED -#define BOOST_STATIC_STRING_CPP11_CONSTEXPR_USED -#define BOOST_STATIC_STRING_ALLOW_UNINIT_MEM #elif BOOST_STATIC_STRING_STANDARD_VERSION >= 201703L +#define BOOST_STATIC_STRING_CPP17 +#define BOOST_STATIC_STRING_CPP14 +#define BOOST_STATIC_STRING_CPP11 #define BOOST_STATIC_STRING_CPP20_CONSTEXPR #define BOOST_STATIC_STRING_CPP17_CONSTEXPR constexpr #define BOOST_STATIC_STRING_CPP14_CONSTEXPR constexpr #define BOOST_STATIC_STRING_CPP11_CONSTEXPR constexpr -#define BOOST_STATIC_STRING_CPP17_CONSTEXPR_USED -#define BOOST_STATIC_STRING_CPP14_CONSTEXPR_USED -#define BOOST_STATIC_STRING_CPP11_CONSTEXPR_USED #elif BOOST_STATIC_STRING_STANDARD_VERSION >= 201402L +#define BOOST_STATIC_STRING_CPP14 +#define BOOST_STATIC_STRING_CPP11 #define BOOST_STATIC_STRING_CPP20_CONSTEXPR #define BOOST_STATIC_STRING_CPP17_CONSTEXPR #define BOOST_STATIC_STRING_CPP14_CONSTEXPR constexpr #define BOOST_STATIC_STRING_CPP11_CONSTEXPR constexpr -#define BOOST_STATIC_STRING_CPP14_CONSTEXPR_USED -#define BOOST_STATIC_STRING_CPP11_CONSTEXPR_USED #else +#define BOOST_STATIC_STRING_CPP11 #define BOOST_STATIC_STRING_CPP20_CONSTEXPR #define BOOST_STATIC_STRING_CPP17_CONSTEXPR #define BOOST_STATIC_STRING_CPP14_CONSTEXPR #define BOOST_STATIC_STRING_CPP11_CONSTEXPR constexpr -#define BOOST_STATIC_STRING_CPP11_CONSTEXPR_USED #endif #ifdef BOOST_STATIC_STRING_NO_EXCEPTIONS @@ -127,19 +133,25 @@ // Compiler bug prevents constexpr from working with clang 4.x and 5.x // if it is detected, we disable constexpr -#if (BOOST_STATIC_STRING_STANDARD_VERSION >= 201402L) && \ -(BOOST_STATIC_STRING_STANDARD_VERSION < 201703L) && \ +#if (BOOST_STATIC_STRING_STANDARD_VERSION >= 201402L && \ +BOOST_STATIC_STRING_STANDARD_VERSION < 201703L) && \ defined(__clang__) && \ ((__clang_major__ == 4) || (__clang_major__ == 5)) // This directive works on clang #warning "C++14 constexpr is not supported in clang 4.x and 5.x due to a compiler bug." -#ifdef BOOST_STATIC_STRING_CPP14_CONSTEXPR_USED -#undef BOOST_STATIC_STRING_CPP14_CONSTEXPR_USED +#ifdef BOOST_STATIC_STRING_CPP14 +#undef BOOST_STATIC_STRING_CPP14 #endif #undef BOOST_STATIC_STRING_CPP14_CONSTEXPR #define BOOST_STATIC_STRING_CPP14_CONSTEXPR #endif +//(defined(_MSVC_LANG) && BOOST_STATIC_STRING_STANDARD_VERSION < 201703L) +#if (defined(__clang__) && (__clang_major__ < 9)) || \ +(defined(_MSVC_LANG) && !defined(BOOST_STATIC_STRING_CPP20)) +#define BOOST_STATIC_STRING_NO_PTR_COMP_FUNCTIONS +#endif + #ifndef BOOST_STATIC_STRING_STANDALONE #include #include diff --git a/include/boost/static_string/static_string.hpp b/include/boost/static_string/static_string.hpp index 050c637..a995a4b 100644 --- a/include/boost/static_string/static_string.hpp +++ b/include/boost/static_string/static_string.hpp @@ -212,7 +212,7 @@ public: } smallest_width size_{0}; -#ifdef BOOST_STATIC_STRING_ALLOW_UNINIT_MEM +#ifdef BOOST_STATIC_STRING_CPP20 CharT data_[N + 1]; #else CharT data_[N + 1]{}; @@ -311,7 +311,7 @@ public: Traits::assign(data_[size_impl()], 0); } -#ifdef BOOST_STATIC_STRING_ALLOW_UNINIT_MEM +#ifdef BOOST_STATIC_STRING_CPP20 CharT data_[N + 1]; #else CharT data_[N + 1]{}; @@ -607,7 +607,32 @@ is_inside( const T* src_last, const T* ptr) { - return std::greater_equal()(ptr, src_first) && + // We want to make this usable in constant expressions as much as possible + // while retaining the guarentee that the comparison has a strict total ordering. + // We also want this to be fast. Since different compilers have differing levels + // of conformance, we will settle for the best option that is available. +#ifdef BOOST_STATIC_STRING_NO_PTR_COMP_FUNCTIONS +#ifdef BOOST_STATIC_STRING_USE_IS_CONST_EVAL + // Our second best option is to use is_constant_evaluated + // and a loop that checks for equality, since equality for + // pointer to object types is never unspecified in this case. + if (BOOST_STATIC_STRING_IS_CONST_EVAL) + { + for (; src_first != src_last; ++src_first) + if (src_first == ptr) + return true; + return false; + } +#else + // If library comparison functions don't work, then + // its almost certain that we can use the builtin + // comparison operator instead. + return ptr >= src_first && ptr <= src_last; +#endif +#endif + // Use the library comparison functions if we can't use + // is_constant_evaluated or if we don't need to. + return std::greater_equal()(ptr, src_first) && std::less_equal()(ptr, src_last); } } // detail @@ -4739,7 +4764,7 @@ BOOST_STATIC_STRING_CPP11_CONSTEXPR basic_static_string:: basic_static_string() noexcept { -#ifdef BOOST_STATIC_STRING_CPP20_CONSTEXPR_USED +#ifdef BOOST_STATIC_STRING_CPP20 term(); #endif } @@ -5316,7 +5341,7 @@ replace( n1 = (std::min)(n1, curr_size - pos); Traits::move(&curr_data[pos + n2], &curr_data[pos + n1], curr_size - pos - n1 + 1); Traits::assign(&curr_data[pos], n2, c); - this->set_size(curr_size + (n2 - n1)); + this->set_size((curr_size + n2) - n1); return *this; } @@ -5377,7 +5402,7 @@ replace( Traits::move(&curr_data[pos + n2], &curr_data[pos + n1], curr_size - pos - n1 + 1); } } - this->set_size(curr_size + (n2 - n1)); + this->set_size((curr_size + n2) - n1); return *this; } @@ -5414,7 +5439,7 @@ replace( n1 = (std::min)(n1, curr_size - pos); // Move everything from the end of the splice point to the end of the rotated string to the begining of the splice point Traits::move(&curr_data[pos + n2], &curr_data[pos + n2 + n1], (curr_size + (n2 - n1)) - pos); - this->set_size(curr_size + (n2 - n1)); + this->set_size((curr_size + n2) - n1); return *this; } @@ -5603,7 +5628,7 @@ replace_unchecked( n1 = curr_size - pos; Traits::move(&curr_data[pos + n2], &curr_data[pos + n1], curr_size - pos - n1 + 1); Traits::copy(&curr_data[pos], s, n2); - this->set_size(curr_size + (n2 - n1)); + this->set_size((curr_size + n2) - n1); return *this; } diff --git a/test/constexpr_tests.hpp b/test/constexpr_tests.hpp index 0b482c9..e3dd8d0 100644 --- a/test/constexpr_tests.hpp +++ b/test/constexpr_tests.hpp @@ -11,7 +11,7 @@ #include // char_traits aren't constexpr until c++17 -#ifdef BOOST_STATIC_STRING_CPP14_CONSTEXPR_USED +#if BOOST_STATIC_STRING_STANDARD_VERSION <= 201703L struct cxper_char_traits { using char_type = char; @@ -43,7 +43,7 @@ constexpr bool testConstantEvaluation() { -#ifdef BOOST_STATIC_STRING_CPP20_CONSTEXPR_USED +#ifdef BOOST_STATIC_STRING_CPP20 // c++20 constexpr tests cstatic_string a; cstatic_string b(1, 'a'); @@ -230,7 +230,7 @@ testConstantEvaluation() a.ends_with("a"); return true; -#elif defined(BOOST_STATIC_STRING_CPP17_CONSTEXPR_USED) +#elif defined(BOOST_STATIC_STRING_CPP17) //c++17 constexpr tests // ctors @@ -419,7 +419,7 @@ testConstantEvaluation() a.ends_with("a"); return true; -#elif defined(BOOST_STATIC_STRING_CPP14_CONSTEXPR_USED) +#elif defined(BOOST_STATIC_STRING_CPP14) // c++14 constexpr tests // ctors @@ -593,7 +593,7 @@ testConstantEvaluation() a.ends_with('a'); a.ends_with("a"); return true; -#elif defined(BOOST_STATIC_STRING_CPP11_CONSTEXPR_USED) +#elif defined(BOOST_STATIC_STRING_CPP11) // c++11 constexpr tests return cstatic_string().size() + cstatic_string().empty() + diff --git a/test/static_string.cpp b/test/static_string.cpp index 57f4f7e..e8edc2d 100644 --- a/test/static_string.cpp +++ b/test/static_string.cpp @@ -1,6 +1,6 @@ // // Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com) -// Copyright (c) 2019 Krystian Stasiowski (sdkrystian at gmail dot com) +// Copyright (c) 2019-2020 Krystian Stasiowski (sdkrystian at gmail dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)