// // Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com) // Copyright (c) 2019 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) // // Official repository: https://github.com/boostorg/static_string // #ifndef BOOST_STATIC_STRING_DETAIL_STATIC_STRING_HPP #define BOOST_STATIC_STRING_DETAIL_STATIC_STRING_HPP #include #include #include #include #include namespace boost { namespace static_string { template class basic_static_string; namespace detail { template using static_string = basic_static_string>; template using static_wstring = basic_static_string>; // At minimum an integral type shall not qualify as an iterator (Agustin Berge) template using is_input_iterator = std::integral_constant::value>; // Find the smallest width integral type that can hold a value as large as N (Glen Fernandes) template using smallest_width = typename std::conditional<(N <= (std::numeric_limits::max)()), unsigned char, typename std::conditional<(N <= (std::numeric_limits::max)()), unsigned short, typename std::conditional<(N <= (std::numeric_limits::max)()), unsigned int, typename std::conditional<(N <= (std::numeric_limits::max)()), unsigned long, typename std::conditional<(N <= (std::numeric_limits::max)()), unsigned long long, void>::type>::type>::type>::type>::type; // std::is_nothrow_convertible is C++20 template void is_nothrow_convertible_helper(To) noexcept; // MSVC is unable to parse this inline, so a helper is needed template(std::declval()))> struct is_nothrow_convertible_msvc_helper { static const bool value = noexcept(is_nothrow_convertible_helper(std::declval())); }; template struct is_nothrow_convertible : std::false_type { }; template struct is_nothrow_convertible::value>::type> : std::true_type { }; // Optimization for using the smallest possible type template class static_string_base_zero { public: BOOST_STATIC_STRING_CPP11_CONSTEXPR static_string_base_zero() noexcept { }; BOOST_STATIC_STRING_CPP11_CONSTEXPR static_string_base_zero(std::size_t n) noexcept : size_(n) { } BOOST_STATIC_STRING_CPP14_CONSTEXPR CharT* data_impl() noexcept { return data_; } BOOST_STATIC_STRING_CPP14_CONSTEXPR CharT const* 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 { return size_ = n; } BOOST_STATIC_STRING_CPP14_CONSTEXPR void term_impl() noexcept { Traits::assign(data_[size_], 0); } smallest_width size_{0}; #ifdef BOOST_STATIC_STRING_ALLOW_UNINIT_MEM CharT data_[N + 1]; #else CharT data_[N + 1]{0}; #endif }; // Optimization for when the size is 0 template class static_string_base_zero<0, CharT, Traits> { public: BOOST_STATIC_STRING_CPP11_CONSTEXPR static_string_base_zero() noexcept { } BOOST_STATIC_STRING_CPP11_CONSTEXPR static_string_base_zero(std::size_t) noexcept { } // Modifying the null terminator is UB BOOST_STATIC_STRING_CPP11_CONSTEXPR CharT* 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) noexcept { return 0; } BOOST_STATIC_STRING_CPP14_CONSTEXPR void term_impl() noexcept { } private: static constexpr CharT null_{0}; }; template constexpr CharT static_string_base_zero<0, CharT, Traits>::null_; // Optimization for storing the size in the last element template class static_string_base_null { public: BOOST_STATIC_STRING_CPP14_CONSTEXPR static_string_base_null() noexcept { set_size(0); } BOOST_STATIC_STRING_CPP14_CONSTEXPR static_string_base_null(std::size_t n) noexcept { set_size(n); } BOOST_STATIC_STRING_CPP14_CONSTEXPR CharT* data_impl() noexcept { return data_; } BOOST_STATIC_STRING_CPP14_CONSTEXPR CharT const* data_impl() const noexcept { return data_; } BOOST_STATIC_STRING_CPP11_CONSTEXPR std::size_t size_impl() const noexcept { return N - data_[N]; } BOOST_STATIC_STRING_CPP14_CONSTEXPR std::size_t set_size(std::size_t n) noexcept { return data_[N] = (N - n); } BOOST_STATIC_STRING_CPP14_CONSTEXPR void term_impl() noexcept { Traits::assign(data_[size_impl()], 0); } #ifdef BOOST_STATIC_STRING_ALLOW_UNINIT_MEM CharT data_[N + 1]; #else CharT data_[N + 1]{0}; #endif }; // Decides which size optimization to use // If the size is zero, the object will have no members // Otherwise, if CharT can hold the max size of the string, store the size in the last char // Otherwise, store the size of the string using a member of the smallest type possible template using optimization_base = #ifdef BOOST_STATIC_STRING_USE_NULL_OPTIMIZATION typename std::conditional<(N <= (std::numeric_limits::max)()) && (N != 0), static_string_base_null, static_string_base_zero>::type; #else static_string_base_zero; #endif template BOOST_STATIC_STRING_CPP14_CONSTEXPR inline int lexicographical_compare( CharT const* s1, std::size_t n1, CharT const* s2, std::size_t n2) noexcept { if(n1 < n2) return Traits::compare( s1, s2, n1) <= 0 ? -1 : 1; if(n1 > n2) return Traits::compare( s1, s2, n2) >= 0 ? 1 : -1; return Traits::compare(s1, s2, n1); } template BOOST_STATIC_STRING_CPP14_CONSTEXPR inline int lexicographical_compare( basic_string_view s1, CharT const* s2, std::size_t n2) noexcept { return detail::lexicographical_compare< CharT, Traits>(s1.data(), s1.size(), s2, n2); } template BOOST_STATIC_STRING_CPP14_CONSTEXPR inline int lexicographical_compare( const basic_static_string& s1, CharT const* s2, std::size_t n2) noexcept { return detail::lexicographical_compare< CharT, Traits>(s1.data(), s1.size(), s2, n2); } template BOOST_STATIC_STRING_CPP14_CONSTEXPR inline int lexicographical_compare( basic_string_view s1, basic_string_view s2) noexcept { return detail::lexicographical_compare( s1.data(), s1.size(), s2.data(), s2.size()); } template BOOST_STATIC_STRING_CPP14_CONSTEXPR inline int lexicographical_compare( const basic_static_string& s1, const basic_static_string& s2) noexcept { return detail::lexicographical_compare( s1.data(), s1.size(), s2.data(), s2.size()); } template inline char* integer_to_string( char* str_end, Integer value, std::true_type) { if (value == 0) { Traits::assign(*--str_end, '0'); return str_end; } if (value < 0) { value = -value; for(; value > 0; value /= 10) Traits::assign(*--str_end, "0123456789"[value % 10]); Traits::assign(*--str_end, '-'); return str_end; } for (; value > 0; value /= 10) Traits::assign(*--str_end, "0123456789"[value % 10]); return str_end; } template inline char* integer_to_string( char* str_end, Integer value, std::false_type) { if (value == 0) { Traits::assign(*--str_end, '0'); return str_end; } for (; value > 0; value /= 10) Traits::assign(*--str_end, "0123456789"[value % 10]); return str_end; } template inline wchar_t* integer_to_wstring( wchar_t* str_end, Integer value, std::true_type) { if (value == 0) { Traits::assign(*--str_end, L'0'); return str_end; } if (value < 0) { value = -value; for (; value > 0; value /= 10) Traits::assign(*--str_end, L"0123456789"[value % 10]); Traits::assign(*--str_end, L'-'); return str_end; } for (; value > 0; value /= 10) Traits::assign(*--str_end, L"0123456789"[value % 10]); return str_end; } template inline wchar_t* integer_to_wstring( wchar_t* str_end, Integer value, std::false_type) { if (value == 0) { Traits::assign(*--str_end, L'0'); return str_end; } for (; value > 0; value /= 10) Traits::assign(*--str_end, L"0123456789"[value % 10]); return str_end; } template inline static_string to_static_string_int_impl(Integer value) { char buffer[N]; const auto digits_end = std::end(buffer); const auto digits_begin = integer_to_string, Integer>( digits_end, value, std::is_signed{}); return static_string(digits_begin, std::distance(digits_begin, digits_end)); } template inline static_wstring to_static_wstring_int_impl(Integer value) { wchar_t buffer[N]; const auto digits_end = std::end(buffer); const auto digits_begin = integer_to_wstring, Integer>( digits_end, value, std::is_signed{}); return static_wstring(digits_begin, std::distance(digits_begin, digits_end)); } template inline static_string to_static_string_float_impl(Floating value) { char buffer[N + 1]; std::sprintf(buffer, "%f", value); return static_string(buffer); } template inline static_wstring to_static_wstring_float_impl(Floating value) { wchar_t buffer[N + 1]; std::swprintf(buffer, N + 1, L"%f", value); return static_wstring(buffer); } template< typename Traits, typename CharT, typename ForwardIterator> inline ForwardIterator find_not_of( ForwardIterator first, ForwardIterator last, const CharT* str, std::size_t n) noexcept { for (; first != last; ++first) if (!Traits::find(str, n, *first)) return first; return last; } } // detail } // static_string } // boost #endif