/*************************************************************************** * Copyright (c) Sylvain Corlay and Johan Mabille and Wolf Vollprecht * * Copyright (c) QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * * The full license is in the file LICENSE, distributed with this software. * ****************************************************************************/ #ifndef XTL_BASIC_FIXED_STRING_HPP #define XTL_BASIC_FIXED_STRING_HPP #include #include #include #include #include #include #include #include #include #include #ifdef __CLING__ #include #endif #include "xhash.hpp" #include "xtl_config.hpp" namespace xtl { namespace string_policy { template struct silent_error; template struct throwing_error; } /*********************** * xbasic_fixed_string * ***********************/ enum storage_options { buffer = 1 << 0, pointer = 1 << 1, store_size = 1 << 2, is_const = 1 << 3 }; template class EP = string_policy::silent_error, class TR = std::char_traits> class xbasic_fixed_string; template class EP, class TR> std::basic_ostream& operator<<(std::basic_ostream& os, const xbasic_fixed_string& str); template class EP, class TR> std::basic_istream& operator>>(std::basic_istream& is, xbasic_fixed_string& str); template using xbasic_string_view = xbasic_fixed_string; namespace detail { template struct select_storage; template struct fixed_small_string_storage_impl; template struct fixed_small_string_storage_impl { static_assert(N <= (1u << (8 * sizeof(T))), "small string"); fixed_small_string_storage_impl() { set_size(0); } fixed_small_string_storage_impl(T ptr[N], std::size_t size) : m_buffer(ptr) { m_buffer[N - 1] = N - size; } T* buffer() { return m_buffer; } const T* buffer() const { return m_buffer; } std::size_t size() const { // Don't use std::make_unsinged_t here, this should remain C++11 compatible using unsigned_type = typename std::make_unsigned::type; return N - reinterpret_cast(m_buffer)[N - 1]; } void set_size(std::size_t sz) { assert(sz < N && "setting a small size"); // Don't use std::make_unsinged_t here, this should remain C++11 compatible using unsigned_type = typename std::make_unsigned::type; reinterpret_cast(m_buffer)[N - 1] = static_cast(N - sz); m_buffer[sz] = '\0'; } void adjust_size(std::ptrdiff_t val) { assert(size() + val >= 0 && "adjusting to positive size"); set_size(static_cast(static_cast(size()) + val)); } T m_buffer[N]; }; template struct fixed_string_storage_impl { fixed_string_storage_impl() = default; fixed_string_storage_impl(T ptr, std::size_t size) : m_buffer(ptr), m_size(size) { } T& buffer() { return m_buffer; } const T& buffer() const { return m_buffer; } std::size_t size() const { return m_size; } void set_size(std::size_t sz) { m_size = sz; m_buffer[sz] = '\0'; } void adjust_size(std::ptrdiff_t val) { m_size += std::size_t(val); m_buffer[m_size] = '\0'; } T m_buffer; std::size_t m_size; }; template struct fixed_string_external_storage_impl { fixed_string_external_storage_impl() = default; fixed_string_external_storage_impl(T ptr, std::ptrdiff_t/*size*/) { m_buffer = ptr; } T& buffer() { return m_buffer; } const T& buffer() const { return m_buffer; } void set_size(std::size_t sz) { m_buffer[sz] = '\0'; } void adjust_size(std::ptrdiff_t val) { m_buffer[size() + val] = '\0'; } std::size_t size() const { return std::strlen(m_buffer); } T m_buffer; }; template struct select_fixed_storage { using type = fixed_string_storage_impl; }; template struct select_fixed_storage { using type = fixed_small_string_storage_impl; }; template <> struct select_storage { template using type = typename select_fixed_storage::type; }; template <> struct select_storage { template using type = fixed_string_external_storage_impl; }; } template class EP, class TR> class xbasic_fixed_string { public: using traits_type = TR; using value_type = CT; using size_type = std::size_t; using difference_type = std::ptrdiff_t; using storage_type = typename detail::select_storage::template type; using reference = value_type&; using const_reference = const value_type&; using pointer = value_type*; using const_pointer = const value_type*; using iterator = pointer; using const_iterator = const_pointer; using reverse_iterator = std::reverse_iterator; using const_reverse_iterator = std::reverse_iterator; static const size_type npos; using self_type = xbasic_fixed_string; using initializer_type = std::initializer_list; using string_type = std::basic_string; using error_policy = EP; xbasic_fixed_string(); explicit xbasic_fixed_string(size_type count, value_type ch); explicit xbasic_fixed_string(const self_type& other, size_type pos, size_type count = npos); explicit xbasic_fixed_string(const string_type& other); explicit xbasic_fixed_string(const string_type& other, size_type pos, size_type count = npos); xbasic_fixed_string(const_pointer s, size_type count); xbasic_fixed_string(const_pointer s); xbasic_fixed_string(initializer_type ilist); template xbasic_fixed_string(InputIt first, InputIt last); operator string_type() const; ~xbasic_fixed_string() = default; xbasic_fixed_string(const self_type&) = default; xbasic_fixed_string(self_type&&) = default; self_type& operator=(const self_type&) = default; self_type& operator=(self_type&&) = default; self_type& operator=(const_pointer s); self_type& operator=(value_type ch); self_type& operator=(initializer_type ilist); self_type& operator=(const string_type& str); self_type& assign(size_type count, value_type ch); self_type& assign(const self_type& other, size_type pos, size_type count = npos); self_type& assign(const_pointer s, size_type count); self_type& assign(const_pointer s); self_type& assign(initializer_type ilist); template self_type& assign(InputIt first, InputIt last); self_type& assign(const self_type& rhs); self_type& assign(self_type&& rhs); self_type& assign(const string_type& str); self_type& assign(const string_type& other, size_type pos, size_type count = npos); reference at(size_type pos); const_reference at(size_type pos) const; reference operator[](size_type pos); const_reference operator[](size_type pos) const; reference front(); const_reference front() const; reference back(); const_reference back() const; pointer data() noexcept; const_pointer data() const noexcept; const_pointer c_str() const noexcept; iterator begin() noexcept; iterator end() noexcept; const_iterator begin() const noexcept; const_iterator end() const noexcept; const_iterator cbegin() const noexcept; const_iterator cend() const noexcept; reverse_iterator rbegin() noexcept; reverse_iterator rend() noexcept; const_reverse_iterator rbegin() const noexcept; const_reverse_iterator rend() const noexcept; const_reverse_iterator crbegin() const noexcept; const_reverse_iterator crend() const noexcept; bool empty() const noexcept; size_type size() const noexcept; size_type length() const noexcept; size_type max_size() const noexcept; void clear() noexcept; void push_back(value_type ch); void pop_back(); self_type substr(size_type pos = 0, size_type count = npos) const; size_type copy(pointer dest, size_type count, size_type pos = 0) const; void resize(size_type count); void resize(size_type count, value_type ch); void swap(self_type& rhs) noexcept; self_type& insert(size_type index, size_type count, value_type ch); self_type& insert(size_type index, const_pointer s); self_type& insert(size_type index, const_pointer s, size_type count); self_type& insert(size_type index, const self_type& str); self_type& insert(size_type index, const self_type& str, size_type index_str, size_type count = npos); self_type& insert(size_type index, const string_type& str); self_type& insert(size_type index, const string_type& str, size_type index_str, size_type count = npos); iterator insert(const_iterator pos, value_type ch); iterator insert(const_iterator pos, size_type count, value_type ch); iterator insert(const_iterator pos, initializer_type ilist); template iterator insert(const_iterator pos, InputIt first, InputIt last); self_type& erase(size_type index = 0, size_type count = npos); iterator erase(const_iterator position); iterator erase(const_iterator first, const_iterator last); self_type& append(size_type count, value_type ch); self_type& append(const self_type& str); self_type& append(const self_type& str, size_type pos, size_type count = npos); self_type& append(const string_type& str); self_type& append(const string_type& str, size_type pos, size_type count = npos); self_type& append(const_pointer s, size_type count); self_type& append(const_pointer s); self_type& append(initializer_type ilist); template self_type& append(InputIt first, InputIt last); self_type& operator+=(const self_type& str); self_type& operator+=(const string_type& str); self_type& operator+=(value_type ch); self_type& operator+=(const_pointer s); self_type& operator+=(initializer_type ilist); int compare(const self_type& str) const noexcept; int compare(size_type pos1, size_type count1, const self_type& str) const; int compare(size_type pos1, size_type count1, const self_type& str, size_type pos2, size_type count2 = npos) const; int compare(const string_type& str) const noexcept; int compare(size_type pos1, size_type count1, const string_type& str) const; int compare(size_type pos1, size_type count1, const string_type& str, size_type pos2, size_type count2 = npos) const; int compare(const_pointer s) const noexcept; int compare(size_type pos1, size_type count1, const_pointer s) const; int compare(size_type pos1, size_type count1, const_pointer s, size_type count2) const; self_type& replace(size_type pos, size_type count, const self_type& str); self_type& replace(const_iterator first, const_iterator last, const self_type& str); self_type& replace(size_type pos1, size_type count1, const self_type& str, size_type pos2, size_type count2 = npos); self_type& replace(size_type pos, size_type count, const string_type& str); self_type& replace(const_iterator first, const_iterator last, const string_type& str); self_type& replace(size_type pos1, size_type count1, const string_type& str, size_type pos2, size_type count2 = npos); self_type& replace(size_type pos, size_type count, const_pointer cstr, size_type count2); self_type& replace(const_iterator first, const_iterator last, const_pointer cstr, size_type count2); self_type& replace(size_type pos, size_type count, const_pointer cstr); self_type& replace(const_iterator first, const_iterator last, const_pointer cstr); self_type& replace(size_type pos, size_type count, size_type count2, value_type ch); self_type& replace(const_iterator first, const_iterator last, size_type count2, value_type ch); self_type& replace(const_iterator first, const_iterator last, initializer_type ilist); template self_type& replace(const_iterator first, const_iterator last, InputIt first2, InputIt last2); size_type find(const self_type& str, size_type pos = 0) const noexcept; size_type find(const string_type& str, size_type pos = 0) const noexcept; size_type find(const_pointer s, size_type pos, size_type count) const; size_type find(const_pointer s, size_type pos = 0) const; size_type find(value_type ch, size_type pos = 0) const; size_type rfind(const self_type& str, size_type pos = npos) const noexcept; size_type rfind(const string_type& str, size_type pos = npos) const noexcept; size_type rfind(const_pointer s, size_type pos, size_type count) const; size_type rfind(const_pointer s, size_type pos = npos) const; size_type rfind(value_type ch, size_type pos = npos) const; size_type find_first_of(const self_type& str, size_type pos = 0) const noexcept; size_type find_first_of(const string_type& str, size_type pos = 0) const noexcept; size_type find_first_of(const_pointer s, size_type pos, size_type count) const; size_type find_first_of(const_pointer s, size_type pos = 0) const; size_type find_first_of(value_type ch, size_type pos = 0) const; size_type find_first_not_of(const self_type& str, size_type pos = 0) const noexcept; size_type find_first_not_of(const string_type& str, size_type pos = 0) const noexcept; size_type find_first_not_of(const_pointer s, size_type pos, size_type count) const; size_type find_first_not_of(const_pointer s, size_type pos = 0) const; size_type find_first_not_of(value_type ch, size_type pos = 0) const; size_type find_last_of(const self_type& str, size_type pos = 0) const noexcept; size_type find_last_of(const string_type& str, size_type pos = 0) const noexcept; size_type find_last_of(const_pointer s, size_type pos, size_type count) const; size_type find_last_of(const_pointer s, size_type pos = 0) const; size_type find_last_of(value_type ch, size_type pos = 0) const; size_type find_last_not_of(const self_type& str, size_type pos = npos) const noexcept; size_type find_last_not_of(const string_type& str, size_type pos = npos) const noexcept; size_type find_last_not_of(const_pointer s, size_type pos, size_type count) const; size_type find_last_not_of(const_pointer s, size_type pos = npos) const; size_type find_last_not_of(value_type ch, size_type pos = npos) const; private: int compare_impl(const_pointer s1, size_type count1, const_pointer s2, size_type count2) const noexcept; void update_null_termination() noexcept; void check_index(size_type pos, size_type size, const char* what) const; void check_index_strict(size_type pos, size_type size, const char* what) const; storage_type m_storage; }; template class EP, class TR> const typename xbasic_fixed_string::size_type xbasic_fixed_string::npos = std::basic_string::npos; template using xfixed_string = xbasic_fixed_string; template using xwfixed_string = xbasic_fixed_string; template using xu16fixed_string = xbasic_fixed_string; template using xu32fixed_string = xbasic_fixed_string; /************************** * Concatenation operator * **************************/ template class EP, class TR> xbasic_fixed_string operator+(const xbasic_fixed_string& lhs, const xbasic_fixed_string& rhs); template class EP, class TR> xbasic_fixed_string operator+(const xbasic_fixed_string& lhs, const CT* rhs); template class EP, class TR> xbasic_fixed_string operator+(const xbasic_fixed_string& lhs, CT rhs); template class EP, class TR> xbasic_fixed_string operator+(const CT* lhs, const xbasic_fixed_string& rhs); template class EP, class TR> xbasic_fixed_string operator+(CT lhs, const xbasic_fixed_string& rhs); template class EP, class TR> xbasic_fixed_string operator+(const xbasic_fixed_string&& lhs, const xbasic_fixed_string& rhs); template class EP, class TR> xbasic_fixed_string operator+(const xbasic_fixed_string& lhs, const xbasic_fixed_string&& rhs); template class EP, class TR> xbasic_fixed_string operator+(const xbasic_fixed_string&& lhs, const xbasic_fixed_string&& rhs); template class EP, class TR> xbasic_fixed_string operator+(const xbasic_fixed_string&& lhs, const CT* rhs); template class EP, class TR> xbasic_fixed_string operator+(const xbasic_fixed_string&& lhs, CT rhs); template class EP, class TR> xbasic_fixed_string operator+(const CT* lhs, const xbasic_fixed_string&& rhs); template class EP, class TR> xbasic_fixed_string operator+(CT lhs, const xbasic_fixed_string&& rhs); /************************ * Comparison operators * ************************/ template class EP, class TR> bool operator==(const xbasic_fixed_string& lhs, const xbasic_fixed_string& rhs) noexcept; template class EP, class TR> bool operator==(const xbasic_fixed_string& lhs, const CT* rhs) noexcept; template class EP, class TR> bool operator==(const CT* lhs, const xbasic_fixed_string& rhs) noexcept; template class EP, class TR> bool operator==(const xbasic_fixed_string& lhs, const std::basic_string& rhs) noexcept; template class EP, class TR> bool operator==(const std::basic_string& lhs, const xbasic_fixed_string& rhs) noexcept; template class EP, class TR> bool operator!=(const xbasic_fixed_string& lhs, const xbasic_fixed_string& rhs) noexcept; template class EP, class TR> bool operator!=(const xbasic_fixed_string& lhs, const CT* rhs) noexcept; template class EP, class TR> bool operator!=(const CT* lhs, const xbasic_fixed_string& rhs) noexcept; template class EP, class TR> bool operator!=(const xbasic_fixed_string& lhs, const std::basic_string& rhs) noexcept; template class EP, class TR> bool operator!=(const std::basic_string& lhs, const xbasic_fixed_string& rhs) noexcept; template class EP, class TR> bool operator<(const xbasic_fixed_string& lhs, const xbasic_fixed_string& rhs) noexcept; template class EP, class TR> bool operator<(const xbasic_fixed_string& lhs, const CT* rhs) noexcept; template class EP, class TR> bool operator<(const CT* lhs, const xbasic_fixed_string& rhs) noexcept; template class EP, class TR> bool operator<(const xbasic_fixed_string& lhs, const std::basic_string& rhs) noexcept; template class EP, class TR> bool operator<(const std::basic_string& lhs, const xbasic_fixed_string& rhs) noexcept; template class EP, class TR> bool operator<=(const xbasic_fixed_string& lhs, const xbasic_fixed_string& rhs) noexcept; template class EP, class TR> bool operator<=(const xbasic_fixed_string& lhs, const CT* rhs) noexcept; template class EP, class TR> bool operator<=(const CT* lhs, const xbasic_fixed_string& rhs) noexcept; template class EP, class TR> bool operator<=(const xbasic_fixed_string& lhs, const std::basic_string& rhs) noexcept; template class EP, class TR> bool operator<=(const std::basic_string& lhs, const xbasic_fixed_string& rhs) noexcept; template class EP, class TR> bool operator>(const xbasic_fixed_string& lhs, const xbasic_fixed_string& rhs) noexcept; template class EP, class TR> bool operator>(const xbasic_fixed_string& lhs, const CT* rhs) noexcept; template class EP, class TR> bool operator>(const CT* lhs, const xbasic_fixed_string& rhs) noexcept; template class EP, class TR> bool operator>(const xbasic_fixed_string& lhs, const std::basic_string& rhs) noexcept; template class EP, class TR> bool operator>(const std::basic_string& lhs, const xbasic_fixed_string& rhs) noexcept; template class EP, class TR> bool operator>=(const xbasic_fixed_string& lhs, const xbasic_fixed_string& rhs) noexcept; template class EP, class TR> bool operator>=(const xbasic_fixed_string& lhs, const CT* rhs) noexcept; template class EP, class TR> bool operator>=(const CT* lhs, const xbasic_fixed_string& rhs) noexcept; template class EP, class TR> bool operator>=(const xbasic_fixed_string& lhs, const std::basic_string& rhs) noexcept; template class EP, class TR> bool operator>=(const std::basic_string& lhs, const xbasic_fixed_string& rhs) noexcept; template class EP, class TR> void swap(xbasic_fixed_string& lhs, xbasic_fixed_string& rhs); /****************************** * Input / output declaration * ******************************/ template class EP, class TR> std::basic_istream& getline(std::basic_istream& input, xbasic_fixed_string& str, CT delim); template class EP, class TR> std::basic_istream& getline(std::basic_istream&& input, xbasic_fixed_string& str, CT delim); template class EP, class TR> std::basic_istream& getline(std::basic_istream& input, xbasic_fixed_string& str); template class EP, class TR> std::basic_istream& getline(std::basic_istream&& input, xbasic_fixed_string& str); } // namespace xtl namespace std { template class EP, class TR> struct hash<::xtl::xbasic_fixed_string> { using argument_type = ::xtl::xbasic_fixed_string; using result_type = std::size_t; inline result_type operator()(const argument_type& arg) const { return ::xtl::hash_bytes(arg.data(), arg.size(), static_cast(0xc70f6907UL)); } }; } // namespace std namespace xtl { /******************************** * xbasic_fixed_string policies * ********************************/ namespace string_policy { template struct silent_error { inline static std::size_t check_size(std::size_t size) { return size; } inline static std::size_t check_add(std::size_t size1, std::size_t size2) { return size1 + size2; } }; template struct throwing_error { inline static std::size_t check_size(std::size_t size) { if (size > N) { std::ostringstream oss; oss << "Invalid size (" << size << ") for xbasic_fixed_string - maximal size: " << N; #if defined(XTL_NO_EXCEPTIONS) std::fprintf(stderr, "%s\n", oss.str().c_str()); std::terminate(); #else throw std::length_error(oss.str()); #endif } return size; } inline static std::size_t check_add(std::size_t size1, std::size_t size2) { return check_size(size1 + size2); } }; } // string_policy /************************************** * xbasic_fixed_string implementation * **************************************/ /**************** * Constructors * ****************/ template class EP, class TR> inline xbasic_fixed_string::xbasic_fixed_string() : m_storage() { } template class EP, class TR> inline xbasic_fixed_string::xbasic_fixed_string(size_type count, value_type ch) : m_storage() { assign(count, ch); } template class EP, class TR> inline xbasic_fixed_string::xbasic_fixed_string(const self_type& other, size_type pos, size_type count) : m_storage() { assign(other, pos, count); } template class EP, class TR> inline xbasic_fixed_string::xbasic_fixed_string(const string_type& other) : m_storage() { assign(other); } template class EP, class TR> inline xbasic_fixed_string::xbasic_fixed_string(const string_type& other, size_type pos, size_type count) : m_storage() { assign(other, pos, count); } template class EP, class TR> inline xbasic_fixed_string::xbasic_fixed_string(const_pointer s, size_type count) : m_storage() { assign(s, count); } template class EP, class TR> inline xbasic_fixed_string::xbasic_fixed_string(const_pointer s) : m_storage() { assign(s); } template class EP, class TR> inline xbasic_fixed_string::xbasic_fixed_string(initializer_type ilist) : m_storage() { assign(ilist); } template class EP, class TR> template inline xbasic_fixed_string::xbasic_fixed_string(InputIt first, InputIt last) : m_storage() { assign(first, last); } template class EP, class TR> inline xbasic_fixed_string::operator string_type() const { return string_type(data()); } /************** * Assignment * **************/ template class EP, class TR> inline auto xbasic_fixed_string::operator=(const_pointer s) -> self_type& { return assign(s); } template class EP, class TR> inline auto xbasic_fixed_string::operator=(value_type ch) -> self_type& { return assign(size_type(1), ch); } template class EP, class TR> inline auto xbasic_fixed_string::operator=(initializer_type ilist) -> self_type& { return assign(ilist); } template class EP, class TR> inline auto xbasic_fixed_string::operator=(const string_type& str) -> self_type& { return assign(str); } template class EP, class TR> inline auto xbasic_fixed_string::assign(size_type count, value_type ch) -> self_type& { m_storage.set_size(error_policy::check_size(count)); traits_type::assign(data(), count, ch); return *this; } template class EP, class TR> inline auto xbasic_fixed_string::assign(const self_type& other, size_type pos, size_type count) -> self_type& { check_index_strict(pos, other.size(), "xbasic_fixed_string::assign"); size_type copy_count = std::min(other.size() - pos, count); m_storage.set_size(error_policy::check_size(copy_count)); traits_type::copy(data(), other.data() + pos, copy_count); return *this; } template class EP, class TR> inline auto xbasic_fixed_string::assign(const_pointer s, size_type count) -> self_type& { m_storage.set_size(error_policy::check_size(count)); traits_type::copy(data(), s, count); return *this; } template class EP, class TR> inline auto xbasic_fixed_string::assign(const_pointer s) -> self_type& { std::size_t ssize = traits_type::length(s); return assign(s, ssize); } template class EP, class TR> inline auto xbasic_fixed_string::assign(initializer_type ilist) -> self_type& { return assign(ilist.begin(), ilist.end()); } template class EP, class TR> template inline auto xbasic_fixed_string::assign(InputIt first, InputIt last) -> self_type& { m_storage.set_size(error_policy::check_size(static_cast(std::distance(first, last)))); std::copy(first, last, data()); return *this; } template class EP, class TR> inline auto xbasic_fixed_string::assign(const self_type& rhs) -> self_type& { if (this != &rhs) { m_storage.set_size(rhs.size()); traits_type::copy(data(), rhs.data(), rhs.size()); } return *this; } template class EP, class TR> inline auto xbasic_fixed_string::assign(self_type&& rhs) -> self_type& { if (this != &rhs) { m_storage.set_size(rhs.size()); traits_type::copy(data(), rhs.data(), rhs.size()); } return *this; } template class EP, class TR> inline auto xbasic_fixed_string::assign(const string_type& other) -> self_type& { return assign(other.c_str()); } template class EP, class TR> inline auto xbasic_fixed_string::assign(const string_type& other, size_type pos, size_type count) -> self_type& { return assign(other.c_str() + pos, std::min(count, other.size() - pos)); } /****************** * Element access * ******************/ template class EP, class TR> inline auto xbasic_fixed_string::at(size_type pos) -> reference { check_index(pos, size(), "basic_fixed_string::at"); return this->operator[](pos); } template class EP, class TR> inline auto xbasic_fixed_string::at(size_type pos) const -> const_reference { check_index(pos, size(), "basic_fixed_string::at"); return this->operator[](pos); } template class EP, class TR> inline auto xbasic_fixed_string::operator[](size_type pos) -> reference { return data()[pos]; } template class EP, class TR> inline auto xbasic_fixed_string::operator[](size_type pos) const -> const_reference { return data()[pos]; } template class EP, class TR> inline auto xbasic_fixed_string::front() -> reference { return this->operator[](0); } template class EP, class TR> inline auto xbasic_fixed_string::front() const -> const_reference { return this->operator[](0); } template class EP, class TR> inline auto xbasic_fixed_string::back() -> reference { return this->operator[](size() - 1); } template class EP, class TR> inline auto xbasic_fixed_string::back() const -> const_reference { return this->operator[](size() - 1); } template class EP, class TR> inline auto xbasic_fixed_string::data() noexcept -> pointer { return m_storage.buffer(); } template class EP, class TR> inline auto xbasic_fixed_string::data() const noexcept -> const_pointer { return m_storage.buffer(); } template class EP, class TR> inline auto xbasic_fixed_string::c_str() const noexcept -> const_pointer { return m_storage.buffer(); } /************* * Iterators * *************/ template class EP, class TR> inline auto xbasic_fixed_string::begin() noexcept -> iterator { return data(); } template class EP, class TR> inline auto xbasic_fixed_string::end() noexcept -> iterator { return data() + size(); } template class EP, class TR> inline auto xbasic_fixed_string::begin() const noexcept -> const_iterator { return cbegin(); } template class EP, class TR> inline auto xbasic_fixed_string::end() const noexcept -> const_iterator { return cend(); } template class EP, class TR> inline auto xbasic_fixed_string::cbegin() const noexcept -> const_iterator { return data(); } template class EP, class TR> inline auto xbasic_fixed_string::cend() const noexcept -> const_iterator { return data() + size(); } template class EP, class TR> inline auto xbasic_fixed_string::rbegin() noexcept -> reverse_iterator { return reverse_iterator(end()); } template class EP, class TR> inline auto xbasic_fixed_string::rend() noexcept -> reverse_iterator { return reverse_iterator(begin()); } template class EP, class TR> inline auto xbasic_fixed_string::rbegin() const noexcept -> const_reverse_iterator { return const_reverse_iterator(end()); } template class EP, class TR> inline auto xbasic_fixed_string::rend() const noexcept -> const_reverse_iterator { return const_reverse_iterator(begin()); } template class EP, class TR> inline auto xbasic_fixed_string::crbegin() const noexcept -> const_reverse_iterator { return const_reverse_iterator(end()); } template class EP, class TR> inline auto xbasic_fixed_string::crend() const noexcept -> const_reverse_iterator { return const_reverse_iterator(begin()); } /************ * Capacity * ************/ template class EP, class TR> inline bool xbasic_fixed_string::empty() const noexcept { return size() == 0; } template class EP, class TR> inline auto xbasic_fixed_string::size() const noexcept -> size_type { return m_storage.size(); } template class EP, class TR> inline auto xbasic_fixed_string::length() const noexcept -> size_type { return m_storage.size(); } template class EP, class TR> inline auto xbasic_fixed_string::max_size() const noexcept -> size_type { return N; } /************** * Operations * **************/ template class EP, class TR> inline void xbasic_fixed_string::clear() noexcept { m_storage.set_size(0); } template class EP, class TR> inline void xbasic_fixed_string::push_back(value_type ch) { error_policy::check_add(size(), size_type(1)); data()[size()] = ch; m_storage.adjust_size(+1); } template class EP, class TR> inline void xbasic_fixed_string::pop_back() { m_storage.adjust_size(-1); } template class EP, class TR> inline auto xbasic_fixed_string::substr(size_type pos, size_type count) const -> self_type { return self_type(*this, pos, count); } template class EP, class TR> inline auto xbasic_fixed_string::copy(pointer dest, size_type count, size_type pos) const -> size_type { check_index_strict(pos, size(), "xbasic_fixed_string::copy"); size_type nb_copied = std::min(count, size() - pos); traits_type::copy(dest, data() + pos, nb_copied); return nb_copied; } template class EP, class TR> inline void xbasic_fixed_string::resize(size_type count) { resize(count, value_type(' ')); // need to initialize with some value != \0 } template class EP, class TR> inline void xbasic_fixed_string::resize(size_type count, value_type ch) { size_type old_size = size(); m_storage.set_size(error_policy::check_size(count)); if (old_size < size()) { traits_type::assign(data() + old_size, size() - old_size, ch); } } template class EP, class TR> inline void xbasic_fixed_string::swap(self_type& rhs) noexcept { self_type tmp(std::move(rhs)); rhs = std::move(*this); *this = std::move(tmp); } /********** * insert * **********/ template class EP, class TR> auto xbasic_fixed_string::insert(size_type index, size_type count, value_type ch) -> self_type& { check_index_strict(index, size(), "xbasic_fixed_string::insert"); size_type old_size = size(); m_storage.set_size(error_policy::check_add(size(), count)); std::copy_backward(data() + index, data() + old_size, end()); traits_type::assign(data() + index, count, ch); return *this; } template class EP, class TR> inline auto xbasic_fixed_string::insert(size_type index, const_pointer s) -> self_type& { return insert(index, s, traits_type::length(s)); } template class EP, class TR> auto xbasic_fixed_string::insert(size_type index, const_pointer s, size_type count) -> self_type& { check_index_strict(index, size(), "xbasic_fixed_string::insert"); size_type old_size = size(); m_storage.set_size(error_policy::check_add(size(), count)); std::copy_backward(data() + index, data() + old_size, end()); traits_type::copy(data() + index, s, count); return *this; } template class EP, class TR> inline auto xbasic_fixed_string::insert(size_type index, const self_type& str) -> self_type& { return insert(index, str.data(), str.size()); } template class EP, class TR> inline auto xbasic_fixed_string::insert(size_type index, const self_type& str, size_type index_str, size_type count) -> self_type& { check_index_strict(index_str, str.size(), "xbasic_fixed_string::insert"); return insert(index, str.data() + index_str, std::min(count, str.size() - index_str)); } template class EP, class TR> inline auto xbasic_fixed_string::insert(size_type index, const string_type& str) -> self_type& { return insert(index, str.c_str(), str.size()); } template class EP, class TR> inline auto xbasic_fixed_string::insert(size_type index, const string_type& str, size_type index_str, size_type count) -> self_type& { check_index_strict(index_str, str.size(), "xbasic_fixed_string::insert"); return insert(index, str.c_str() + index_str, std::min(count, str.size() - index_str)); } template class EP, class TR> inline auto xbasic_fixed_string::insert(const_iterator pos, value_type ch) -> iterator { return insert(pos, size_type(1), ch); } template class EP, class TR> inline auto xbasic_fixed_string::insert(const_iterator pos, size_type count, value_type ch) -> iterator { if (cbegin() <= pos && pos < cend()) { size_type index = static_cast(pos - cbegin()); insert(index, count, ch); return const_cast(pos); } return end(); } template class EP, class TR> inline auto xbasic_fixed_string::insert(const_iterator pos, initializer_type ilist) -> iterator { return insert(pos, ilist.begin(), ilist.end()); } template class EP, class TR> template auto xbasic_fixed_string::insert(const_iterator pos, InputIt first, InputIt last) -> iterator { if (cbegin() <= pos && pos < cend()) { size_type index = static_cast(pos - cbegin()); size_type count = static_cast(std::distance(first, last)); size_type old_size = size(); m_storage.set_size(error_policy::check_add(size(), count)); std::copy_backward(data() + index, data() + old_size, end()); std::copy(first, last, data() + index); return begin() + index; } return end(); } /********* * erase * *********/ template class EP, class TR> auto xbasic_fixed_string::erase(size_type index, size_type count) -> self_type& { check_index_strict(index, size(), "xbasic_fixed_string::erase"); size_type erase_count = std::min(count, size() - index); // cannot use traits_type::copy because of overlapping std::copy(data() + index + erase_count, data() + size(), data() + index); m_storage.adjust_size(-static_cast(erase_count)); return *this; } template class EP, class TR> inline auto xbasic_fixed_string::erase(const_iterator position) -> iterator { return erase(position, position + 1); } template class EP, class TR> auto xbasic_fixed_string::erase(const_iterator first, const_iterator last) -> iterator { if (cbegin() <= first && first < cend()) { const_iterator adapted_last = std::min(last, cend()); size_type erase_count = static_cast(adapted_last - first); // cannot use traits_type::copy because of overlapping std::copy(adapted_last, cend(), iterator(first)); m_storage.adjust_size(-static_cast(erase_count)); return const_cast(first); } return end(); } /********** * append * **********/ template class EP, class TR> inline auto xbasic_fixed_string::append(size_type count, value_type ch) -> self_type& { size_type old_size = m_storage.size(); m_storage.set_size(error_policy::check_add(size(), count)); traits_type::assign(data() + old_size, count, ch); return *this; } template class EP, class TR> inline auto xbasic_fixed_string::append(const self_type& str) -> self_type& { return append(str.data(), str.size()); } template class EP, class TR> inline auto xbasic_fixed_string::append(const self_type& str, size_type pos, size_type count) -> self_type& { check_index_strict(pos, str.size(), "xbasic_fixed_string::append"); return append(str.data() + pos, std::min(count, str.size() - pos)); } template class EP, class TR> inline auto xbasic_fixed_string::append(const string_type& str) -> self_type& { return append(str.c_str(), str.size()); } template class EP, class TR> inline auto xbasic_fixed_string::append(const string_type& str, size_type pos, size_type count) -> self_type& { check_index_strict(pos, str.size(), "xbasic_fixed_string::append"); return append(str.c_str() + pos, std::min(count, str.size() - pos)); } template class EP, class TR> inline auto xbasic_fixed_string::append(const_pointer s, size_type count) -> self_type& { size_type old_size = m_storage.size(); m_storage.set_size(error_policy::check_add(size(), count)); traits_type::copy(data() + old_size, s, count); return *this; } template class EP, class TR> inline auto xbasic_fixed_string::append(const_pointer s) -> self_type& { return append(s, traits_type::length(s)); } template class EP, class TR> inline auto xbasic_fixed_string::append(initializer_type ilist) -> self_type& { return append(ilist.begin(), ilist.end()); } template class EP, class TR> template inline auto xbasic_fixed_string::append(InputIt first, InputIt last) -> self_type& { size_type count = static_cast(std::distance(first, last)); size_type old_size = m_storage.size(); m_storage.set_size(error_policy::check_add(size(), count)); std::copy(first, last, data() + old_size); return *this; } template class EP, class TR> inline auto xbasic_fixed_string::operator+=(const self_type& str) -> self_type& { return append(str); } template class EP, class TR> inline auto xbasic_fixed_string::operator+=(const string_type& str) -> self_type& { return append(str); } template class EP, class TR> inline auto xbasic_fixed_string::operator+=(value_type ch) -> self_type& { return append(size_type(1), ch); } template class EP, class TR> inline auto xbasic_fixed_string::operator+=(const_pointer s) -> self_type& { return append(s); } template class EP, class TR> inline auto xbasic_fixed_string::operator+=(initializer_type ilist) -> self_type& { return append(ilist); } /*********** * compare * ***********/ template class EP, class TR> inline int xbasic_fixed_string::compare(const self_type& str) const noexcept { return compare_impl(data(), size(), str.data(), str.size()); } template class EP, class TR> inline int xbasic_fixed_string::compare(size_type pos1, size_type count1, const self_type& str) const { check_index_strict(pos1, size(), "xbasic_fixed_string::compare"); return compare_impl(data() + pos1, std::min(count1, size() - pos1), str.data(), str.size()); } template class EP, class TR> inline int xbasic_fixed_string::compare(size_type pos1, size_type count1, const self_type& str, size_type pos2, size_type count2) const { check_index_strict(pos1, size(), "xbasic_fixed_string::compare"); check_index_strict(pos2, str.size(), "xbasic_fixed_string::compare"); return compare_impl(data() + pos1, std::min(count1, size() - pos1), str.data() + pos2, std::min(count2, str.size() - pos2)); } template class EP, class TR> inline int xbasic_fixed_string::compare(const string_type& str) const noexcept { return compare_impl(data(), size(), str.data(), str.size()); } template class EP, class TR> inline int xbasic_fixed_string::compare(size_type pos1, size_type count1, const string_type& str) const { check_index_strict(pos1, size(), "xbasic_fixed_string::compare"); return compare_impl(data() + pos1, std::min(count1, size() - pos1), str.data(), str.size()); } template class EP, class TR> inline int xbasic_fixed_string::compare(size_type pos1, size_type count1, const string_type& str, size_type pos2, size_type count2) const { check_index_strict(pos1, size(), "xbasic_fixed_string::compare"); check_index_strict(pos2, str.size(), "xbasic_fixed_string::compare"); return compare_impl(data() + pos1, std::min(count1, size() - pos1), str.data() + pos2, std::min(count2, str.size() - pos2)); } template class EP, class TR> inline int xbasic_fixed_string::compare(const_pointer s) const noexcept { return compare_impl(data(), size(), s, traits_type::length(s)); } template class EP, class TR> int xbasic_fixed_string::compare(size_type pos1, size_type count1, const_pointer s) const { return compare(pos1, count1, s, traits_type::length(s)); } template class EP, class TR> int xbasic_fixed_string::compare(size_type pos1, size_type count1, const_pointer s, size_type count2) const { check_index_strict(pos1, size(), "xbasic_fixed_string::compare"); return compare_impl(data() + pos1, std::min(count1, size() - pos1), s, count2); } /*********** * replace * ***********/ template class EP, class TR> inline auto xbasic_fixed_string::replace(size_type pos, size_type count, const self_type& str) -> self_type& { return replace(pos, count, str.data(), str.size()); } template class EP, class TR> inline auto xbasic_fixed_string::replace(const_iterator first, const_iterator last, const self_type& str) -> self_type& { return replace(first, last, str.data(), str.size()); } template class EP, class TR> inline auto xbasic_fixed_string::replace(size_type pos1, size_type count1, const self_type& str, size_type pos2, size_type count2) -> self_type& { check_index_strict(pos2, str.size(), "xbasic_fixed_string::replace"); return replace(pos1, count1, str.data() + pos2, std::min(count2, str.size() - pos2)); } template class EP, class TR> inline auto xbasic_fixed_string::replace(size_type pos, size_type count, const string_type& str) -> self_type& { return replace(pos, count, str.data(), str.size()); } template class EP, class TR> inline auto xbasic_fixed_string::replace(const_iterator first, const_iterator last, const string_type& str) -> self_type& { return replace(first, last, str.data(), str.size()); } template class EP, class TR> inline auto xbasic_fixed_string::replace(size_type pos1, size_type count1, const string_type& str, size_type pos2, size_type count2) -> self_type& { check_index_strict(pos2, str.size(), "xbasic_fixed_string::replace"); return replace(pos1, count1, str.data() + pos2, std::min(count2, str.size() - pos2)); } template class EP, class TR> auto xbasic_fixed_string::replace(size_type pos, size_type count, const_pointer cstr, size_type count2) -> self_type& { check_index_strict(pos, size(), "xbasic_fixed_string::replace"); size_type erase_count = std::min(count, size() - pos); size_type new_size = error_policy::check_add(size() - erase_count, count2); if (erase_count > count2) { traits_type::copy(data() + pos, cstr, count2); std::copy(cbegin() + pos + erase_count, cend(), data() + pos + count2); m_storage.set_size(new_size); } else if (erase_count < count2) { std::copy_backward(cbegin() + pos + erase_count, cend(), data() + new_size); traits_type::copy(data() + pos, cstr, count2); m_storage.set_size(new_size); } else { traits_type::copy(data() + pos, cstr, count2); } return *this; } template class EP, class TR> inline auto xbasic_fixed_string::replace(const_iterator first, const_iterator last, const_pointer cstr, size_type count2) -> self_type& { if (cbegin() <= first && first < last && last <= cend()) { size_type pos = static_cast(first - cbegin()); size_type count = static_cast(last - first); return replace(pos, count, cstr, count2); } return *this; } template class EP, class TR> inline auto xbasic_fixed_string::replace(size_type pos, size_type count, const_pointer cstr) -> self_type& { return replace(pos, count, cstr, traits_type::length(cstr)); } template class EP, class TR> inline auto xbasic_fixed_string::replace(const_iterator first, const_iterator last, const_pointer cstr) -> self_type& { return replace(first, last, cstr, traits_type::length(cstr)); } template class EP, class TR> inline auto xbasic_fixed_string::replace(size_type pos, size_type count, size_type count2, value_type ch) -> self_type& { check_index_strict(pos, size(), "xbasic_fixed_string::replace"); size_type erase_count = std::min(count, size() - pos); size_type new_size = error_policy::check_add(size() - erase_count, count2); if (erase_count > count2) { traits_type::assign(data() + pos, count2, ch); std::copy(cbegin() + pos + erase_count, cend(), data() + pos + count2); m_storage.set_size(new_size); } else if (erase_count < count2) { std::copy_backward(cbegin() + pos + erase_count, cend(), data() + new_size); traits_type::assign(data() + pos, count2, ch); m_storage.set_size(new_size); } else { traits_type::assign(data() + pos, count2, ch); } return *this; } template class EP, class TR> inline auto xbasic_fixed_string::replace(const_iterator first, const_iterator last, size_type count2, value_type ch) -> self_type& { if (cbegin() <= first && first < last && last <= cend()) { size_type pos = static_cast(first - cbegin()); size_type count = static_cast(last - first); return replace(pos, count, count2, ch); } return *this; } template class EP, class TR> inline auto xbasic_fixed_string::replace(const_iterator first, const_iterator last, initializer_type ilist) -> self_type& { return replace(first, last, ilist.begin(), ilist.end()); } template class EP, class TR> template inline auto xbasic_fixed_string::replace(const_iterator first, const_iterator last, InputIt first2, InputIt last2) -> self_type& { if (cbegin() <= first && first < last && last <= cend()) { size_type pos = static_cast(first - cbegin()); size_type erase_count = static_cast(last - first); size_type count2 = static_cast(std::distance(first2, last2)); size_type new_size = error_policy::check_add(size() - erase_count, count2); if (erase_count > count2) { std::copy(first2, last2, data() + pos); std::copy(cbegin() + pos + erase_count, cend(), data() + pos + count2); m_storage.set_size(new_size); } else if (erase_count < count2) { std::copy_backward(cbegin() + pos + erase_count, cend(), data() + new_size); std::copy(first2, last2, data() + pos); m_storage.set_size(new_size); } else { std::copy(first2, last2, data() + pos); } } return *this; } /******** * find * ********/ template class EP, class TR> inline auto xbasic_fixed_string::find(const self_type& str, size_type pos) const noexcept -> size_type { return find(str.data(), pos, str.size()); } template class EP, class TR> inline auto xbasic_fixed_string::find(const string_type& str, size_type pos) const noexcept -> size_type { return find(str.data(), pos, str.size()); } template class EP, class TR> auto xbasic_fixed_string::find(const_pointer s, size_type pos, size_type count) const -> size_type { if (count == size_type(0) && pos <= size()) { return pos; } size_type nm; if (pos < size() && count <= (nm = size() - pos)) { const_pointer uptr, vptr; for (nm -= count - 1, vptr = data() + pos; (uptr = traits_type::find(vptr, nm, *s)) != 0; nm -= size_type(uptr - vptr) + 1ul, vptr = uptr + 1ul) { if (traits_type::compare(uptr, s, count) == 0) { return size_type(uptr - data()); } } } return npos; } template class EP, class TR> inline auto xbasic_fixed_string::find(const_pointer s, size_type pos) const -> size_type { return find(s, pos, traits_type::length(s)); } template class EP, class TR> inline auto xbasic_fixed_string::find(value_type ch, size_type pos) const -> size_type { return find((const_pointer)(&ch), pos, size_type(1)); } /********* * rfind * *********/ template class EP, class TR> inline auto xbasic_fixed_string::rfind(const self_type& str, size_type pos) const noexcept -> size_type { return rfind(str.data(), pos, str.size()); } template class EP, class TR> inline auto xbasic_fixed_string::rfind(const string_type& str, size_type pos) const noexcept -> size_type { return rfind(str.data(), pos, str.size()); } template class EP, class TR> auto xbasic_fixed_string::rfind(const_pointer s, size_type pos, size_type count) const -> size_type { if (count == 0) { return std::min(pos, size()); } if (count <= size()) { const_pointer uptr = data() + std::min(pos, size() - count); for (;; --uptr) { if (traits_type::eq(*uptr, *s) && traits_type::compare(uptr, s, count) == 0) { return size_type(uptr - data()); } else if (uptr == data()) { break; } } } return npos; } template class EP, class TR> inline auto xbasic_fixed_string::rfind(const_pointer s, size_type pos) const -> size_type { return rfind(s, pos, traits_type::length(s)); } template class EP, class TR> inline auto xbasic_fixed_string::rfind(value_type ch, size_type pos) const -> size_type { return rfind((const_pointer)(&ch), pos, size_type(1)); } /***************** * find_first_of * *****************/ template class EP, class TR> inline auto xbasic_fixed_string::find_first_of(const self_type& str, size_type pos) const noexcept -> size_type { return find_first_of(str.data(), pos, str.size()); } template class EP, class TR> inline auto xbasic_fixed_string::find_first_of(const string_type& str, size_type pos) const noexcept -> size_type { return find_first_of(str.data(), pos, str.size()); } template class EP, class TR> auto xbasic_fixed_string::find_first_of(const_pointer s, size_type pos, size_type count) const -> size_type { if (size_type(0) < count && pos < size()) { const_pointer vptr = data() + size(); for (const_pointer uptr = data() + pos; uptr < vptr; ++uptr) { if (traits_type::find(s, count, *uptr) != 0) { return size_type(uptr - data()); } } } return npos; } template class EP, class TR> inline auto xbasic_fixed_string::find_first_of(const_pointer s, size_type pos) const -> size_type { return find_first_of(s, pos, traits_type::length(s)); } template class EP, class TR> inline auto xbasic_fixed_string::find_first_of(value_type ch, size_type pos) const -> size_type { return find_first_of((const_pointer)(&ch), pos, size_type(1)); } /********************* * find_first_not_of * *********************/ template class EP, class TR> inline auto xbasic_fixed_string::find_first_not_of(const self_type& str, size_type pos) const noexcept -> size_type { return find_first_not_of(str.data(), pos, str.size()); } template class EP, class TR> inline auto xbasic_fixed_string::find_first_not_of(const string_type& str, size_type pos) const noexcept -> size_type { return find_first_not_of(str.data(), pos, str.size()); } template class EP, class TR> auto xbasic_fixed_string::find_first_not_of(const_pointer s, size_type pos, size_type count) const -> size_type { if (pos < size()) { const_pointer vptr = data() + size(); for (const_pointer uptr = data() + pos; uptr < vptr; ++uptr) { if (traits_type::find(s, count, *uptr) == 0) { return size_type(uptr - data()); } } } return npos; } template class EP, class TR> inline auto xbasic_fixed_string::find_first_not_of(const_pointer s, size_type pos) const -> size_type { return find_first_not_of(s, pos, traits_type::length(s)); } template class EP, class TR> inline auto xbasic_fixed_string::find_first_not_of(value_type ch, size_type pos) const -> size_type { return find_first_not_of((const_pointer)(&ch), pos, size_type(1)); } /**************** * find_last_of * ****************/ template class EP, class TR> inline auto xbasic_fixed_string::find_last_of(const self_type& str, size_type pos) const noexcept -> size_type { return find_last_of(str.data(), pos, str.size()); } template class EP, class TR> inline auto xbasic_fixed_string::find_last_of(const string_type& str, size_type pos) const noexcept -> size_type { return find_last_of(str.data(), pos, str.size()); } template class EP, class TR> auto xbasic_fixed_string::find_last_of(const_pointer s, size_type pos, size_type count) const -> size_type { if (size_type(0) < count && size_type(0) < size()) { const_pointer uptr = data() + std::min(pos, size() - 1); for (;; --uptr) { if (traits_type::find(s, count, *uptr) != 0) { return size_type(uptr - data()); } else if (uptr == data()) { break; } } } return npos; } template class EP, class TR> inline auto xbasic_fixed_string::find_last_of(const_pointer s, size_type pos) const -> size_type { return find_last_of(s, pos, traits_type::length(s)); } template class EP, class TR> inline auto xbasic_fixed_string::find_last_of(value_type ch, size_type pos) const -> size_type { return find_last_of((const_pointer)(&ch), pos, size_type(1)); } /******************** * find_last_not_of * ********************/ template class EP, class TR> inline auto xbasic_fixed_string::find_last_not_of(const self_type& str, size_type pos) const noexcept -> size_type { return find_last_not_of(str.data(), pos, str.size()); } template class EP, class TR> inline auto xbasic_fixed_string::find_last_not_of(const string_type& str, size_type pos) const noexcept -> size_type { return find_last_not_of(str.data(), pos, str.size()); } template class EP, class TR> auto xbasic_fixed_string::find_last_not_of(const_pointer s, size_type pos, size_type count) const -> size_type { if (size_type(0) < size()) { const_pointer uptr = data() + std::min(pos, size() - 1); for (;; --uptr) { if (traits_type::find(s, count, *uptr) == 0) { return size_type(uptr - data()); } else if (uptr == data()) { break; } } } return npos; } template class EP, class TR> inline auto xbasic_fixed_string::find_last_not_of(const_pointer s, size_type pos) const -> size_type { return find_last_not_of(s, pos, traits_type::length(s)); } template class EP, class TR> inline auto xbasic_fixed_string::find_last_not_of(value_type ch, size_type pos) const -> size_type { return find_last_not_of((const_pointer)(&ch), pos, size_type(1)); } /******************* * Private methods * *******************/ template class EP, class TR> int xbasic_fixed_string::compare_impl(const_pointer s1, size_type count1, const_pointer s2, size_type count2) const noexcept { size_type rlen = std::min(count1, count2); int res = traits_type::compare(s1, s2, rlen); if (res == 0) { return count1 < count2 ? -1 : (count1 > count2 ? 1 : 0); } else { return res; } } template class EP, class TR> inline void xbasic_fixed_string::update_null_termination() noexcept { data()[size()] = '\0'; } template class EP, class TR> void xbasic_fixed_string::check_index(size_type pos, size_type size, const char* what) const { if (pos >= size) { #if defined(XTL_NO_EXCEPTIONS) std::fprintf(stderr, "%s\n", what); std::terminate(); #else throw std::out_of_range(what); #endif } } template class EP, class TR> void xbasic_fixed_string::check_index_strict(size_type pos, size_type size, const char* what) const { check_index(pos, size + 1, what); } /************************** * Concatenation operator * **************************/ template class EP, class TR> inline xbasic_fixed_string operator+(const xbasic_fixed_string& lhs, const xbasic_fixed_string& rhs) { xbasic_fixed_string res(lhs); return res += rhs; } template class EP, class TR> inline xbasic_fixed_string operator+(const xbasic_fixed_string& lhs, const CT* rhs) { xbasic_fixed_string res(lhs); return res += rhs; } template class EP, class TR> inline xbasic_fixed_string operator+(const xbasic_fixed_string& lhs, CT rhs) { xbasic_fixed_string res(lhs); return res += rhs; } template class EP, class TR> inline xbasic_fixed_string operator+(const CT* lhs, const xbasic_fixed_string& rhs) { xbasic_fixed_string res(lhs); return res += rhs; } template class EP, class TR> inline xbasic_fixed_string operator+(CT lhs, const xbasic_fixed_string& rhs) { using size_type = typename xbasic_fixed_string::size_type; xbasic_fixed_string res(size_type(1), lhs); return res += rhs; } template class EP, class TR> inline xbasic_fixed_string operator+(const xbasic_fixed_string&& lhs, const xbasic_fixed_string& rhs) { xbasic_fixed_string res(std::move(lhs)); return res += rhs; } template class EP, class TR> inline xbasic_fixed_string operator+(const xbasic_fixed_string& lhs, const xbasic_fixed_string&& rhs) { xbasic_fixed_string res(lhs); return res += std::move(rhs); } template class EP, class TR> inline xbasic_fixed_string operator+(const xbasic_fixed_string&& lhs, const xbasic_fixed_string&& rhs) { xbasic_fixed_string res(std::move(lhs)); return res += std::move(rhs); } template class EP, class TR> inline xbasic_fixed_string operator+(const xbasic_fixed_string&& lhs, const CT* rhs) { xbasic_fixed_string res(std::move(lhs)); return res += rhs; } template class EP, class TR> inline xbasic_fixed_string operator+(const xbasic_fixed_string&& lhs, CT rhs) { xbasic_fixed_string res(std::move(lhs)); return res += rhs; } template class EP, class TR> inline xbasic_fixed_string operator+(const CT* lhs, const xbasic_fixed_string&& rhs) { xbasic_fixed_string res(lhs); return res += std::move(rhs); } template class EP, class TR> inline xbasic_fixed_string operator+(CT lhs, const xbasic_fixed_string&& rhs) { using size_type = typename xbasic_fixed_string::size_type; xbasic_fixed_string res(size_type(1), lhs); return res += std::move(rhs); } /************************ * Comparison operators * ************************/ template class EP, class TR> inline bool operator==(const xbasic_fixed_string& lhs, const xbasic_fixed_string& rhs) noexcept { return lhs.compare(rhs) == 0; } template class EP, class TR> inline bool operator==(const xbasic_fixed_string& lhs, const CT* rhs) noexcept { return lhs.compare(rhs) == 0; } template class EP, class TR> inline bool operator==(const CT* lhs, const xbasic_fixed_string& rhs) noexcept { return rhs == lhs; } template class EP, class TR> inline bool operator==(const xbasic_fixed_string& lhs, const std::basic_string& rhs) noexcept { return lhs == rhs.c_str(); } template class EP, class TR> inline bool operator==(const std::basic_string& lhs, const xbasic_fixed_string& rhs) noexcept { return lhs.c_str() == rhs; } template class EP, class TR> inline bool operator!=(const xbasic_fixed_string& lhs, const xbasic_fixed_string& rhs) noexcept { return lhs.compare(rhs) != 0; } template class EP, class TR> inline bool operator!=(const xbasic_fixed_string& lhs, const CT* rhs) noexcept { return lhs.compare(rhs) != 0; } template class EP, class TR> inline bool operator!=(const CT* lhs, const xbasic_fixed_string& rhs) noexcept { return rhs != lhs; } template class EP, class TR> inline bool operator!=(const xbasic_fixed_string& lhs, const std::basic_string& rhs) noexcept { return lhs != rhs.c_str(); } template class EP, class TR> inline bool operator!=(const std::basic_string& lhs, const xbasic_fixed_string& rhs) noexcept { return lhs.c_str() != rhs; } template class EP, class TR> inline bool operator<(const xbasic_fixed_string& lhs, const xbasic_fixed_string& rhs) noexcept { return lhs.compare(rhs) < 0; } template class EP, class TR> inline bool operator<(const xbasic_fixed_string& lhs, const CT* rhs) noexcept { return lhs.compare(rhs) < 0; } template class EP, class TR> inline bool operator<(const CT* lhs, const xbasic_fixed_string& rhs) noexcept { return rhs > lhs; } template class EP, class TR> inline bool operator<(const xbasic_fixed_string& lhs, const std::basic_string& rhs) noexcept { return lhs < rhs.c_str(); } template class EP, class TR> inline bool operator<(const std::basic_string& lhs, const xbasic_fixed_string& rhs) noexcept { return lhs.c_str() < rhs; } template class EP, class TR> inline bool operator<=(const xbasic_fixed_string& lhs, const xbasic_fixed_string& rhs) noexcept { return lhs.compare(rhs) <= 0; } template class EP, class TR> inline bool operator<=(const xbasic_fixed_string& lhs, const CT* rhs) noexcept { return lhs.compare(rhs) <= 0; } template class EP, class TR> inline bool operator<=(const CT* lhs, const xbasic_fixed_string& rhs) noexcept { return rhs >= lhs; } template class EP, class TR> inline bool operator<=(const xbasic_fixed_string& lhs, const std::basic_string& rhs) noexcept { return lhs <= rhs.c_str(); } template class EP, class TR> inline bool operator<=(const std::basic_string& lhs, const xbasic_fixed_string& rhs) noexcept { return lhs.c_str() <= rhs; } template class EP, class TR> inline bool operator>(const xbasic_fixed_string& lhs, const xbasic_fixed_string& rhs) noexcept { return lhs.compare(rhs) > 0; } template class EP, class TR> inline bool operator>(const xbasic_fixed_string& lhs, const CT* rhs) noexcept { return lhs.compare(rhs) > 0; } template class EP, class TR> inline bool operator>(const CT* lhs, const xbasic_fixed_string& rhs) noexcept { return rhs < lhs; } template class EP, class TR> inline bool operator>(const xbasic_fixed_string& lhs, const std::basic_string& rhs) noexcept { return lhs > rhs.c_str(); } template class EP, class TR> inline bool operator>(const std::basic_string& lhs, const xbasic_fixed_string& rhs) noexcept { return lhs.c_str() > rhs; } template class EP, class TR> inline bool operator>=(const xbasic_fixed_string& lhs, const xbasic_fixed_string& rhs) noexcept { return lhs.compare(rhs) >= 0; } template class EP, class TR> inline bool operator>=(const xbasic_fixed_string& lhs, const CT* rhs) noexcept { return lhs.compare(rhs) >= 0; } template class EP, class TR> inline bool operator>=(const CT* lhs, const xbasic_fixed_string& rhs) noexcept { return rhs <= lhs; } template class EP, class TR> inline bool operator>=(const xbasic_fixed_string& lhs, const std::basic_string& rhs) noexcept { return lhs >= rhs.c_str(); } template class EP, class TR> inline bool operator>=(const std::basic_string& lhs, const xbasic_fixed_string& rhs) noexcept { return lhs.c_str() >= rhs; } template class EP, class TR> inline void swap(xbasic_fixed_string& lhs, xbasic_fixed_string& rhs) { lhs.swap(rhs); } /****************** * Input / output * ******************/ template class EP, class TR> inline std::basic_ostream& operator<<(std::basic_ostream& os, const xbasic_fixed_string& str) { os << str.c_str(); return os; } #ifdef __CLING__ template class EP, class TR> nlohmann::json mime_bundle_repr(const xbasic_fixed_string& str) { auto bundle = nlohmann::json::object(); bundle["text/plain"] = str.c_str(); return bundle; } #endif template class EP, class TR> inline std::basic_istream& operator>>(std::basic_istream& is, xbasic_fixed_string& str) { // Not optimal std::string tmp; is >> tmp; str = tmp.c_str(); return is; } template class EP, class TR> inline std::basic_istream& getline(std::basic_istream& input, xbasic_fixed_string& str, CT delim) { std::string tmp; auto& ret = std::getline(input, tmp, delim); str = tmp; return ret; } template class EP, class TR> inline std::basic_istream& getline(std::basic_istream&& input, xbasic_fixed_string& str, CT delim) { std::string tmp; auto& ret = std::getline(std::move(input), tmp, delim); str = tmp; return ret; } template class EP, class TR> inline std::basic_istream& getline(std::basic_istream& input, xbasic_fixed_string& str) { std::string tmp; auto& ret = std::getline(input, tmp); str = tmp; return ret; } template class EP, class TR> inline std::basic_istream& getline(std::basic_istream&& input, xbasic_fixed_string& str) { std::string tmp; auto& ret = std::getline(std::move(input), tmp); str = tmp; return ret; } } #endif // xtl