mirror of
				https://github.com/pocketpy/pocketpy
				synced 2025-10-31 08:50:17 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			2437 lines
		
	
	
		
			98 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			2437 lines
		
	
	
		
			98 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /***************************************************************************
 | |
| * 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 <cstddef>
 | |
| #include <exception>
 | |
| #include <functional>
 | |
| #include <iterator>
 | |
| #include <sstream>
 | |
| #include <stdexcept>
 | |
| #include <string>
 | |
| #include <cassert>
 | |
| #include <algorithm>
 | |
| #include <type_traits>
 | |
| 
 | |
| #ifdef __CLING__
 | |
| #include <nlohmann/json.hpp>
 | |
| #endif
 | |
| 
 | |
| #include "xhash.hpp"
 | |
| #include "xtl_config.hpp"
 | |
| 
 | |
| namespace xtl
 | |
| {
 | |
| 
 | |
|     namespace string_policy
 | |
|     {
 | |
|         template <std::size_t>
 | |
|         struct silent_error;
 | |
| 
 | |
|         template <std::size_t>
 | |
|         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 CT, std::size_t N = 55, int ST = buffer | store_size, template <std::size_t> class EP = string_policy::silent_error, class TR = std::char_traits<CT>>
 | |
|     class xbasic_fixed_string;
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     std::basic_ostream<CT, TR>& operator<<(std::basic_ostream<CT, TR>& os,
 | |
|                                            const xbasic_fixed_string<CT, N, ST, EP, TR>& str);
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     std::basic_istream<CT, TR>& operator>>(std::basic_istream<CT, TR>& is,
 | |
|                                            xbasic_fixed_string<CT, N, ST, EP, TR>& str);
 | |
| 
 | |
|     template <class CT>
 | |
|     using xbasic_string_view = xbasic_fixed_string<const CT, 0, pointer | store_size | is_const>;
 | |
| 
 | |
|     namespace detail
 | |
|     {
 | |
|         template <int selector>
 | |
|         struct select_storage;
 | |
| 
 | |
|         template <typename T>
 | |
|         struct fixed_small_string_storage_impl;
 | |
| 
 | |
|         template <class T, std::size_t N>
 | |
|         struct fixed_small_string_storage_impl<T[N]>
 | |
|         {
 | |
|             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<T>::type;
 | |
|                 return N - reinterpret_cast<unsigned_type const*>(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<T>::type;
 | |
|                 reinterpret_cast<unsigned_type*>(m_buffer)[N - 1] = static_cast<unsigned_type>(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<std::size_t>(static_cast<std::ptrdiff_t>(size()) + val));
 | |
|             }
 | |
| 
 | |
|             T m_buffer[N];
 | |
|         };
 | |
| 
 | |
|         template <class T>
 | |
|         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 <class T>
 | |
|         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 <class T, bool Small>
 | |
|         struct select_fixed_storage {
 | |
|           using type = fixed_string_storage_impl<T>;
 | |
|         };
 | |
| 
 | |
|         template <class T>
 | |
|         struct select_fixed_storage<T, true> {
 | |
|           using type = fixed_small_string_storage_impl<T>;
 | |
|         };
 | |
| 
 | |
|         template <>
 | |
|         struct select_storage<buffer | store_size>
 | |
|         {
 | |
|             template <class T, std::size_t N>
 | |
|             using type = typename select_fixed_storage<T[N + 1], N < (1u << (8 * sizeof(T)))>::type;
 | |
|         };
 | |
| 
 | |
|         template <>
 | |
|         struct select_storage<buffer>
 | |
|         {
 | |
|             template <class T, std::size_t N>
 | |
|             using type = fixed_string_external_storage_impl<T[N + 1]>;
 | |
|         };
 | |
|     }
 | |
| 
 | |
|     template <class CT,
 | |
|               std::size_t N,
 | |
|               int ST,
 | |
|               template <std::size_t> 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<ST>::template type<CT, N>;
 | |
| 
 | |
|         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<iterator>;
 | |
|         using const_reverse_iterator = std::reverse_iterator<const_iterator>;
 | |
| 
 | |
| 
 | |
|         static const size_type npos;
 | |
| 
 | |
|         using self_type = xbasic_fixed_string;
 | |
|         using initializer_type = std::initializer_list<value_type>;
 | |
|         using string_type = std::basic_string<value_type, traits_type>;
 | |
| 
 | |
|         using error_policy = EP<N>;
 | |
| 
 | |
|         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 <class InputIt>
 | |
|         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 <class InputIt>
 | |
|         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 <class InputIt>
 | |
|         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 <class InputIt>
 | |
|         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 <class InputIt>
 | |
|         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 CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     const typename xbasic_fixed_string<CT, N, ST, EP, TR>::size_type xbasic_fixed_string<CT, N, ST, EP, TR>::npos
 | |
|         = std::basic_string<value_type, traits_type>::npos;
 | |
| 
 | |
|     template <std::size_t N>
 | |
|     using xfixed_string = xbasic_fixed_string<char, N>;
 | |
| 
 | |
|     template <std::size_t N>
 | |
|     using xwfixed_string = xbasic_fixed_string<wchar_t, N>;
 | |
| 
 | |
|     template <std::size_t N>
 | |
|     using xu16fixed_string = xbasic_fixed_string<char16_t, N>;
 | |
| 
 | |
|     template <std::size_t N>
 | |
|     using xu32fixed_string = xbasic_fixed_string<char32_t, N>;
 | |
| 
 | |
|     /**************************
 | |
|      * Concatenation operator *
 | |
|      **************************/
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     xbasic_fixed_string<CT, N, ST, EP, TR>
 | |
|     operator+(const xbasic_fixed_string<CT, N, ST, EP, TR>& lhs,
 | |
|               const xbasic_fixed_string<CT, N, ST, EP, TR>& rhs);
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     xbasic_fixed_string<CT, N, ST, EP, TR>
 | |
|     operator+(const xbasic_fixed_string<CT, N, ST, EP, TR>& lhs,
 | |
|               const CT* rhs);
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     xbasic_fixed_string<CT, N, ST, EP, TR>
 | |
|     operator+(const xbasic_fixed_string<CT, N, ST, EP, TR>& lhs,
 | |
|               CT rhs);
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     xbasic_fixed_string<CT, N, ST, EP, TR>
 | |
|     operator+(const CT* lhs,
 | |
|               const xbasic_fixed_string<CT, N, ST, EP, TR>& rhs);
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     xbasic_fixed_string<CT, N, ST, EP, TR>
 | |
|     operator+(CT lhs,
 | |
|               const xbasic_fixed_string<CT, N, ST, EP, TR>& rhs);
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     xbasic_fixed_string<CT, N, ST, EP, TR>
 | |
|     operator+(const xbasic_fixed_string<CT, N, ST, EP, TR>&& lhs,
 | |
|               const xbasic_fixed_string<CT, N, ST, EP, TR>& rhs);
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     xbasic_fixed_string<CT, N, ST, EP, TR>
 | |
|     operator+(const xbasic_fixed_string<CT, N, ST, EP, TR>& lhs,
 | |
|               const xbasic_fixed_string<CT, N, ST, EP, TR>&& rhs);
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     xbasic_fixed_string<CT, N, ST, EP, TR>
 | |
|     operator+(const xbasic_fixed_string<CT, N, ST, EP, TR>&& lhs,
 | |
|               const xbasic_fixed_string<CT, N, ST, EP, TR>&& rhs);
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     xbasic_fixed_string<CT, N, ST, EP, TR>
 | |
|     operator+(const xbasic_fixed_string<CT, N, ST, EP, TR>&& lhs,
 | |
|               const CT* rhs);
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     xbasic_fixed_string<CT, N, ST, EP, TR>
 | |
|     operator+(const xbasic_fixed_string<CT, N, ST, EP, TR>&& lhs,
 | |
|               CT rhs);
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     xbasic_fixed_string<CT, N, ST, EP, TR>
 | |
|     operator+(const CT* lhs,
 | |
|               const xbasic_fixed_string<CT, N, ST, EP, TR>&& rhs);
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     xbasic_fixed_string<CT, N, ST, EP, TR>
 | |
|     operator+(CT lhs,
 | |
|               const xbasic_fixed_string<CT, N, ST, EP, TR>&& rhs);
 | |
| 
 | |
|     /************************
 | |
|      * Comparison operators *
 | |
|      ************************/
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     bool operator==(const xbasic_fixed_string<CT, N, ST, EP, TR>& lhs,
 | |
|                     const xbasic_fixed_string<CT, N, ST, EP, TR>& rhs) noexcept;
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     bool operator==(const xbasic_fixed_string<CT, N, ST, EP, TR>& lhs,
 | |
|                     const CT* rhs) noexcept;
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     bool operator==(const CT* lhs,
 | |
|                     const xbasic_fixed_string<CT, N, ST, EP, TR>& rhs) noexcept;
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     bool operator==(const xbasic_fixed_string<CT, N, ST, EP, TR>& lhs,
 | |
|                     const std::basic_string<CT, TR>& rhs) noexcept;
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     bool operator==(const std::basic_string<CT, TR>& lhs,
 | |
|                     const xbasic_fixed_string<CT, N, ST, EP, TR>& rhs) noexcept;
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     bool operator!=(const xbasic_fixed_string<CT, N, ST, EP, TR>& lhs,
 | |
|                     const xbasic_fixed_string<CT, N, ST, EP, TR>& rhs) noexcept;
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     bool operator!=(const xbasic_fixed_string<CT, N, ST, EP, TR>& lhs,
 | |
|                     const CT* rhs) noexcept;
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     bool operator!=(const CT* lhs,
 | |
|                     const xbasic_fixed_string<CT, N, ST, EP, TR>& rhs) noexcept;
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     bool operator!=(const xbasic_fixed_string<CT, N, ST, EP, TR>& lhs,
 | |
|                     const std::basic_string<CT, TR>& rhs) noexcept;
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     bool operator!=(const std::basic_string<CT, TR>& lhs,
 | |
|                     const xbasic_fixed_string<CT, N, ST, EP, TR>& rhs) noexcept;
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     bool operator<(const xbasic_fixed_string<CT, N, ST, EP, TR>& lhs,
 | |
|                    const xbasic_fixed_string<CT, N, ST, EP, TR>& rhs) noexcept;
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     bool operator<(const xbasic_fixed_string<CT, N, ST, EP, TR>& lhs,
 | |
|                    const CT* rhs) noexcept;
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     bool operator<(const CT* lhs,
 | |
|                    const xbasic_fixed_string<CT, N, ST, EP, TR>& rhs) noexcept;
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     bool operator<(const xbasic_fixed_string<CT, N, ST, EP, TR>& lhs,
 | |
|                    const std::basic_string<CT, TR>& rhs) noexcept;
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     bool operator<(const std::basic_string<CT, TR>& lhs,
 | |
|                    const xbasic_fixed_string<CT, N, ST, EP, TR>& rhs) noexcept;
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     bool operator<=(const xbasic_fixed_string<CT, N, ST, EP, TR>& lhs,
 | |
|                     const xbasic_fixed_string<CT, N, ST, EP, TR>& rhs) noexcept;
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     bool operator<=(const xbasic_fixed_string<CT, N, ST, EP, TR>& lhs,
 | |
|                     const CT* rhs) noexcept;
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     bool operator<=(const CT* lhs,
 | |
|                     const xbasic_fixed_string<CT, N, ST, EP, TR>& rhs) noexcept;
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     bool operator<=(const xbasic_fixed_string<CT, N, ST, EP, TR>& lhs,
 | |
|                     const std::basic_string<CT, TR>& rhs) noexcept;
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     bool operator<=(const std::basic_string<CT, TR>& lhs,
 | |
|                     const xbasic_fixed_string<CT, N, ST, EP, TR>& rhs) noexcept;
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     bool operator>(const xbasic_fixed_string<CT, N, ST, EP, TR>& lhs,
 | |
|                    const xbasic_fixed_string<CT, N, ST, EP, TR>& rhs) noexcept;
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     bool operator>(const xbasic_fixed_string<CT, N, ST, EP, TR>& lhs,
 | |
|                    const CT* rhs) noexcept;
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     bool operator>(const CT* lhs,
 | |
|                    const xbasic_fixed_string<CT, N, ST, EP, TR>& rhs) noexcept;
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     bool operator>(const xbasic_fixed_string<CT, N, ST, EP, TR>& lhs,
 | |
|                    const std::basic_string<CT, TR>& rhs) noexcept;
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     bool operator>(const std::basic_string<CT, TR>& lhs,
 | |
|                    const xbasic_fixed_string<CT, N, ST, EP, TR>& rhs) noexcept;
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     bool operator>=(const xbasic_fixed_string<CT, N, ST, EP, TR>& lhs,
 | |
|                     const xbasic_fixed_string<CT, N, ST, EP, TR>& rhs) noexcept;
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     bool operator>=(const xbasic_fixed_string<CT, N, ST, EP, TR>& lhs,
 | |
|                     const CT* rhs) noexcept;
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     bool operator>=(const CT* lhs,
 | |
|                     const xbasic_fixed_string<CT, N, ST, EP, TR>& rhs) noexcept;
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     bool operator>=(const xbasic_fixed_string<CT, N, ST, EP, TR>& lhs,
 | |
|                     const std::basic_string<CT, TR>& rhs) noexcept;
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     bool operator>=(const std::basic_string<CT, TR>& lhs,
 | |
|                     const xbasic_fixed_string<CT, N, ST, EP, TR>& rhs) noexcept;
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     void swap(xbasic_fixed_string<CT, N, ST, EP, TR>& lhs,
 | |
|               xbasic_fixed_string<CT, N, ST, EP, TR>& rhs);
 | |
| 
 | |
|     /******************************
 | |
|      * Input / output declaration *
 | |
|      ******************************/
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     std::basic_istream<CT, TR>& getline(std::basic_istream<CT, TR>& input,
 | |
|                                         xbasic_fixed_string<CT, N, ST, EP, TR>& str,
 | |
|                                         CT delim);
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     std::basic_istream<CT, TR>& getline(std::basic_istream<CT, TR>&& input,
 | |
|                                         xbasic_fixed_string<CT, N, ST, EP, TR>& str,
 | |
|                                         CT delim);
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     std::basic_istream<CT, TR>& getline(std::basic_istream<CT, TR>& input,
 | |
|                                         xbasic_fixed_string<CT, N, ST, EP, TR>& str);
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     std::basic_istream<CT, TR>& getline(std::basic_istream<CT, TR>&& input,
 | |
|                                         xbasic_fixed_string<CT, N, ST, EP, TR>& str);
 | |
| 
 | |
| }  // namespace xtl
 | |
| 
 | |
| namespace std
 | |
| {
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     struct hash<::xtl::xbasic_fixed_string<CT, N, ST, EP, TR>>
 | |
|     {
 | |
|         using argument_type = ::xtl::xbasic_fixed_string<CT, N, ST, EP, TR>;
 | |
|         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<std::size_t>(0xc70f6907UL));
 | |
|         }
 | |
|     };
 | |
| }  // namespace std
 | |
| 
 | |
| namespace xtl
 | |
| {
 | |
|     /********************************
 | |
|      * xbasic_fixed_string policies *
 | |
|      ********************************/
 | |
| 
 | |
|     namespace string_policy
 | |
|     {
 | |
|         template <std::size_t N>
 | |
|         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 <std::size_t N>
 | |
|         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 CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline xbasic_fixed_string<CT, N, ST, EP, TR>::xbasic_fixed_string()
 | |
|         : m_storage()
 | |
|     {
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline xbasic_fixed_string<CT, N, ST, EP, TR>::xbasic_fixed_string(size_type count, value_type ch)
 | |
|         : m_storage()
 | |
|     {
 | |
|         assign(count, ch);
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline xbasic_fixed_string<CT, N, ST, EP, TR>::xbasic_fixed_string(const self_type& other,
 | |
|                                                                    size_type pos,
 | |
|                                                                    size_type count)
 | |
|         : m_storage()
 | |
|     {
 | |
|         assign(other, pos, count);
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline xbasic_fixed_string<CT, N, ST, EP, TR>::xbasic_fixed_string(const string_type& other)
 | |
|         : m_storage()
 | |
|     {
 | |
|         assign(other);
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline xbasic_fixed_string<CT, N, ST, EP, TR>::xbasic_fixed_string(const string_type& other,
 | |
|                                                                    size_type pos,
 | |
|                                                                    size_type count)
 | |
|         : m_storage()
 | |
|     {
 | |
|         assign(other, pos, count);
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline xbasic_fixed_string<CT, N, ST, EP, TR>::xbasic_fixed_string(const_pointer s, size_type count)
 | |
|         : m_storage()
 | |
|     {
 | |
|         assign(s, count);
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline xbasic_fixed_string<CT, N, ST, EP, TR>::xbasic_fixed_string(const_pointer s)
 | |
|         : m_storage()
 | |
|     {
 | |
|         assign(s);
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline xbasic_fixed_string<CT, N, ST, EP, TR>::xbasic_fixed_string(initializer_type ilist)
 | |
|         : m_storage()
 | |
|     {
 | |
|         assign(ilist);
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     template <class InputIt>
 | |
|     inline xbasic_fixed_string<CT, N, ST, EP, TR>::xbasic_fixed_string(InputIt first, InputIt last)
 | |
|         : m_storage()
 | |
|     {
 | |
|         assign(first, last);
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline xbasic_fixed_string<CT, N, ST, EP, TR>::operator string_type() const
 | |
|     {
 | |
|         return string_type(data());
 | |
|     }
 | |
| 
 | |
|     /**************
 | |
|      * Assignment *
 | |
|      **************/
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::operator=(const_pointer s) -> self_type&
 | |
|     {
 | |
|         return assign(s);
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::operator=(value_type ch) -> self_type&
 | |
|     {
 | |
|         return assign(size_type(1), ch);
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::operator=(initializer_type ilist) -> self_type&
 | |
|     {
 | |
|         return assign(ilist);
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::operator=(const string_type& str) -> self_type&
 | |
|     {
 | |
|         return assign(str);
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::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 CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::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 CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::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 CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::assign(const_pointer s) -> self_type&
 | |
|     {
 | |
|         std::size_t ssize = traits_type::length(s);
 | |
|         return assign(s, ssize);
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::assign(initializer_type ilist) -> self_type&
 | |
|     {
 | |
|         return assign(ilist.begin(), ilist.end());
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     template <class InputIt>
 | |
|     inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::assign(InputIt first, InputIt last) -> self_type&
 | |
|     {
 | |
|         m_storage.set_size(error_policy::check_size(static_cast<size_type>(std::distance(first, last))));
 | |
|         std::copy(first, last, data());
 | |
|         return *this;
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::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 CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::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 CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::assign(const string_type& other) -> self_type&
 | |
|     {
 | |
|         return assign(other.c_str());
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::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 CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::at(size_type pos) -> reference
 | |
|     {
 | |
|         check_index(pos, size(), "basic_fixed_string::at");
 | |
|         return this->operator[](pos);
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::at(size_type pos) const -> const_reference
 | |
|     {
 | |
|         check_index(pos, size(), "basic_fixed_string::at");
 | |
|         return this->operator[](pos);
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::operator[](size_type pos) -> reference
 | |
|     {
 | |
|         return data()[pos];
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::operator[](size_type pos) const -> const_reference
 | |
|     {
 | |
|         return data()[pos];
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::front() -> reference
 | |
|     {
 | |
|         return this->operator[](0);
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::front() const -> const_reference
 | |
|     {
 | |
|         return this->operator[](0);
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::back() -> reference
 | |
|     {
 | |
|         return this->operator[](size() - 1);
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::back() const -> const_reference
 | |
|     {
 | |
|         return this->operator[](size() - 1);
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::data() noexcept -> pointer
 | |
|     {
 | |
|         return m_storage.buffer();
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::data() const noexcept -> const_pointer
 | |
|     {
 | |
|         return m_storage.buffer();
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::c_str() const noexcept -> const_pointer
 | |
|     {
 | |
|         return m_storage.buffer();
 | |
|     }
 | |
| 
 | |
|     /*************
 | |
|      * Iterators *
 | |
|      *************/
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::begin() noexcept -> iterator
 | |
|     {
 | |
|         return data();
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::end() noexcept -> iterator
 | |
|     {
 | |
|         return data() + size();
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::begin() const noexcept -> const_iterator
 | |
|     {
 | |
|         return cbegin();
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::end() const noexcept -> const_iterator
 | |
|     {
 | |
|         return cend();
 | |
|     }
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::cbegin() const noexcept -> const_iterator
 | |
|     {
 | |
|         return data();
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::cend() const noexcept -> const_iterator
 | |
|     {
 | |
|         return data() + size();
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::rbegin() noexcept -> reverse_iterator
 | |
|     {
 | |
|         return reverse_iterator(end());
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::rend() noexcept -> reverse_iterator
 | |
|     {
 | |
|         return reverse_iterator(begin());
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::rbegin() const noexcept -> const_reverse_iterator
 | |
|     {
 | |
|         return const_reverse_iterator(end());
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::rend() const noexcept -> const_reverse_iterator
 | |
|     {
 | |
|         return const_reverse_iterator(begin());
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::crbegin() const noexcept -> const_reverse_iterator
 | |
|     {
 | |
|         return const_reverse_iterator(end());
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::crend() const noexcept -> const_reverse_iterator
 | |
|     {
 | |
|         return const_reverse_iterator(begin());
 | |
|     }
 | |
| 
 | |
|     /************
 | |
|      * Capacity *
 | |
|      ************/
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline bool xbasic_fixed_string<CT, N, ST, EP, TR>::empty() const noexcept
 | |
|     {
 | |
|         return size() == 0;
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::size() const noexcept -> size_type
 | |
|     {
 | |
|         return m_storage.size();
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::length() const noexcept -> size_type
 | |
|     {
 | |
|         return m_storage.size();
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::max_size() const noexcept -> size_type
 | |
|     {
 | |
|         return N;
 | |
|     }
 | |
| 
 | |
|     /**************
 | |
|      * Operations *
 | |
|      **************/
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline void xbasic_fixed_string<CT, N, ST, EP, TR>::clear() noexcept
 | |
|     {
 | |
|         m_storage.set_size(0);
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline void xbasic_fixed_string<CT, N, ST, EP, TR>::push_back(value_type ch)
 | |
|     {
 | |
|         error_policy::check_add(size(), size_type(1));
 | |
|         data()[size()] = ch;
 | |
|         m_storage.adjust_size(+1);
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline void xbasic_fixed_string<CT, N, ST, EP, TR>::pop_back()
 | |
|     {
 | |
|         m_storage.adjust_size(-1);
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::substr(size_type pos, size_type count) const -> self_type
 | |
|     {
 | |
|         return self_type(*this, pos, count);
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::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 CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline void xbasic_fixed_string<CT, N, ST, EP, TR>::resize(size_type count)
 | |
|     {
 | |
|         resize(count, value_type(' '));  // need to initialize with some value != \0
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline void xbasic_fixed_string<CT, N, ST, EP, TR>::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 CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline void xbasic_fixed_string<CT, N, ST, EP, TR>::swap(self_type& rhs) noexcept
 | |
|     {
 | |
|         self_type tmp(std::move(rhs));
 | |
|         rhs = std::move(*this);
 | |
|         *this = std::move(tmp);
 | |
|     }
 | |
| 
 | |
|     /**********
 | |
|      * insert *
 | |
|      **********/
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     auto xbasic_fixed_string<CT, N, ST, EP, TR>::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 CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::insert(size_type index, const_pointer s) -> self_type&
 | |
|     {
 | |
|         return insert(index, s, traits_type::length(s));
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     auto xbasic_fixed_string<CT, N, ST, EP, TR>::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 CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::insert(size_type index, const self_type& str) -> self_type&
 | |
|     {
 | |
|         return insert(index, str.data(), str.size());
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::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 CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::insert(size_type index, const string_type& str) -> self_type&
 | |
|     {
 | |
|         return insert(index, str.c_str(), str.size());
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::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 CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::insert(const_iterator pos, value_type ch) -> iterator
 | |
|     {
 | |
|         return insert(pos, size_type(1), ch);
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::insert(const_iterator pos, size_type count, value_type ch) -> iterator
 | |
|     {
 | |
|         if (cbegin() <= pos && pos < cend())
 | |
|         {
 | |
|             size_type index = static_cast<size_type>(pos - cbegin());
 | |
|             insert(index, count, ch);
 | |
|             return const_cast<iterator>(pos);
 | |
|         }
 | |
|         return end();
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::insert(const_iterator pos, initializer_type ilist) -> iterator
 | |
|     {
 | |
|         return insert(pos, ilist.begin(), ilist.end());
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     template <class InputIt>
 | |
|     auto xbasic_fixed_string<CT, N, ST, EP, TR>::insert(const_iterator pos, InputIt first, InputIt last) -> iterator
 | |
|     {
 | |
|         if (cbegin() <= pos && pos < cend())
 | |
|         {
 | |
|             size_type index = static_cast<size_type>(pos - cbegin());
 | |
|             size_type count = static_cast<size_type>(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 CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     auto xbasic_fixed_string<CT, N, ST, EP, TR>::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<std::ptrdiff_t>(erase_count));
 | |
|         return *this;
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::erase(const_iterator position) -> iterator
 | |
|     {
 | |
|         return erase(position, position + 1);
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     auto xbasic_fixed_string<CT, N, ST, EP, TR>::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<size_type>(adapted_last - first);
 | |
|             // cannot use traits_type::copy because of overlapping
 | |
|             std::copy(adapted_last, cend(), iterator(first));
 | |
|             m_storage.adjust_size(-static_cast<std::ptrdiff_t>(erase_count));
 | |
|             return const_cast<iterator>(first);
 | |
|         }
 | |
|         return end();
 | |
|     }
 | |
| 
 | |
|     /**********
 | |
|      * append *
 | |
|      **********/
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::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 CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::append(const self_type& str) -> self_type&
 | |
|     {
 | |
|         return append(str.data(), str.size());
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::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 CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::append(const string_type& str) -> self_type&
 | |
|     {
 | |
|         return append(str.c_str(), str.size());
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::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 CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::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 CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::append(const_pointer s) -> self_type&
 | |
|     {
 | |
|         return append(s, traits_type::length(s));
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::append(initializer_type ilist) -> self_type&
 | |
|     {
 | |
|         return append(ilist.begin(), ilist.end());
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     template <class InputIt>
 | |
|     inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::append(InputIt first, InputIt last) -> self_type&
 | |
|     {
 | |
|         size_type count = static_cast<size_type>(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 CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::operator+=(const self_type& str) -> self_type&
 | |
|     {
 | |
|         return append(str);
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::operator+=(const string_type& str) -> self_type&
 | |
|     {
 | |
|         return append(str);
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::operator+=(value_type ch) -> self_type&
 | |
|     {
 | |
|         return append(size_type(1), ch);
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::operator+=(const_pointer s) -> self_type&
 | |
|     {
 | |
|         return append(s);
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::operator+=(initializer_type ilist) -> self_type&
 | |
|     {
 | |
|         return append(ilist);
 | |
|     }
 | |
| 
 | |
|     /***********
 | |
|      * compare *
 | |
|      ***********/
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline int xbasic_fixed_string<CT, N, ST, EP, TR>::compare(const self_type& str) const noexcept
 | |
|     {
 | |
|         return compare_impl(data(), size(), str.data(), str.size());
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline int xbasic_fixed_string<CT, N, ST, EP, TR>::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 CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline int xbasic_fixed_string<CT, N, ST, EP, TR>::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 CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline int xbasic_fixed_string<CT, N, ST, EP, TR>::compare(const string_type& str) const noexcept
 | |
|     {
 | |
|         return compare_impl(data(), size(), str.data(), str.size());
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline int xbasic_fixed_string<CT, N, ST, EP, TR>::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 CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline int xbasic_fixed_string<CT, N, ST, EP, TR>::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 CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline int xbasic_fixed_string<CT, N, ST, EP, TR>::compare(const_pointer s) const noexcept
 | |
|     {
 | |
|         return compare_impl(data(), size(), s, traits_type::length(s));
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     int xbasic_fixed_string<CT, N, ST, EP, TR>::compare(size_type pos1, size_type count1, const_pointer s) const
 | |
|     {
 | |
|         return compare(pos1, count1, s, traits_type::length(s));
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     int xbasic_fixed_string<CT, N, ST, EP, TR>::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 CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::replace(size_type pos, size_type count, const self_type& str) -> self_type&
 | |
|     {
 | |
|         return replace(pos, count, str.data(), str.size());
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::replace(const_iterator first, const_iterator last,
 | |
|                                                             const self_type& str) -> self_type&
 | |
|     {
 | |
|         return replace(first, last, str.data(), str.size());
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::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 CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::replace(size_type pos, size_type count, const string_type& str) -> self_type&
 | |
|     {
 | |
|         return replace(pos, count, str.data(), str.size());
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::replace(const_iterator first, const_iterator last,
 | |
|                                                             const string_type& str) -> self_type&
 | |
|     {
 | |
|         return replace(first, last, str.data(), str.size());
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::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 CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     auto xbasic_fixed_string<CT, N, ST, EP, TR>::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 CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::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<size_type>(first - cbegin());
 | |
|             size_type count = static_cast<size_type>(last - first);
 | |
|             return replace(pos, count, cstr, count2);
 | |
|         }
 | |
|         return *this;
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::replace(size_type pos, size_type count,
 | |
|                                                             const_pointer cstr) -> self_type&
 | |
|     {
 | |
|         return replace(pos, count, cstr, traits_type::length(cstr));
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::replace(const_iterator first, const_iterator last,
 | |
|                                                             const_pointer cstr) -> self_type&
 | |
|     {
 | |
|         return replace(first, last, cstr, traits_type::length(cstr));
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::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 CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::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<size_type>(first - cbegin());
 | |
|             size_type count = static_cast<size_type>(last - first);
 | |
|             return replace(pos, count, count2, ch);
 | |
|         }
 | |
|         return *this;
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::replace(const_iterator first, const_iterator last,
 | |
|                                                             initializer_type ilist) -> self_type&
 | |
|     {
 | |
|         return replace(first, last, ilist.begin(), ilist.end());
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     template <class InputIt>
 | |
|     inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::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<size_type>(first - cbegin());
 | |
|             size_type erase_count = static_cast<size_type>(last - first);
 | |
|             size_type count2 = static_cast<size_type>(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 CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::find(const self_type& str, size_type pos) const noexcept -> size_type
 | |
|     {
 | |
|         return find(str.data(), pos, str.size());
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::find(const string_type& str, size_type pos) const noexcept -> size_type
 | |
|     {
 | |
|         return find(str.data(), pos, str.size());
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     auto xbasic_fixed_string<CT, N, ST, EP, TR>::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 CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::find(const_pointer s, size_type pos) const -> size_type
 | |
|     {
 | |
|         return find(s, pos, traits_type::length(s));
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::find(value_type ch, size_type pos) const -> size_type
 | |
|     {
 | |
|         return find((const_pointer)(&ch), pos, size_type(1));
 | |
|     }
 | |
| 
 | |
|     /*********
 | |
|      * rfind *
 | |
|      *********/
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::rfind(const self_type& str, size_type pos) const noexcept -> size_type
 | |
|     {
 | |
|         return rfind(str.data(), pos, str.size());
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::rfind(const string_type& str, size_type pos) const noexcept -> size_type
 | |
|     {
 | |
|         return rfind(str.data(), pos, str.size());
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     auto xbasic_fixed_string<CT, N, ST, EP, TR>::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 CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::rfind(const_pointer s, size_type pos) const -> size_type
 | |
|     {
 | |
|         return rfind(s, pos, traits_type::length(s));
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::rfind(value_type ch, size_type pos) const -> size_type
 | |
|     {
 | |
|         return rfind((const_pointer)(&ch), pos, size_type(1));
 | |
|     }
 | |
| 
 | |
|     /*****************
 | |
|      * find_first_of *
 | |
|      *****************/
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::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 CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::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 CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     auto xbasic_fixed_string<CT, N, ST, EP, TR>::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 CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::find_first_of(const_pointer s, size_type pos) const -> size_type
 | |
|     {
 | |
|         return find_first_of(s, pos, traits_type::length(s));
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::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 CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::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 CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::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 CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     auto xbasic_fixed_string<CT, N, ST, EP, TR>::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 CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::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 CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::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 CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::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 CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::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 CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     auto xbasic_fixed_string<CT, N, ST, EP, TR>::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 CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::find_last_of(const_pointer s, size_type pos) const -> size_type
 | |
|     {
 | |
|         return find_last_of(s, pos, traits_type::length(s));
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::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 CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::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 CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::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 CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     auto xbasic_fixed_string<CT, N, ST, EP, TR>::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 CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::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 CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::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 CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     int xbasic_fixed_string<CT, N, ST, EP, TR>::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 CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline void xbasic_fixed_string<CT, N, ST, EP, TR>::update_null_termination() noexcept
 | |
|     {
 | |
|         data()[size()] = '\0';
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     void xbasic_fixed_string<CT, N, ST, EP, TR>::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 CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     void xbasic_fixed_string<CT, N, ST, EP, TR>::check_index_strict(size_type pos, size_type size, const char* what) const
 | |
|     {
 | |
|         check_index(pos, size + 1, what);
 | |
|     }
 | |
| 
 | |
|     /**************************
 | |
|      * Concatenation operator *
 | |
|      **************************/
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline xbasic_fixed_string<CT, N, ST, EP, TR>
 | |
|     operator+(const xbasic_fixed_string<CT, N, ST, EP, TR>& lhs,
 | |
|               const xbasic_fixed_string<CT, N, ST, EP, TR>& rhs)
 | |
|     {
 | |
|         xbasic_fixed_string<CT, N, ST, EP, TR> res(lhs);
 | |
|         return res += rhs;
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline xbasic_fixed_string<CT, N, ST, EP, TR>
 | |
|     operator+(const xbasic_fixed_string<CT, N, ST, EP, TR>& lhs,
 | |
|               const CT* rhs)
 | |
|     {
 | |
|         xbasic_fixed_string<CT, N, ST, EP, TR> res(lhs);
 | |
|         return res += rhs;
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline xbasic_fixed_string<CT, N, ST, EP, TR>
 | |
|     operator+(const xbasic_fixed_string<CT, N, ST, EP, TR>& lhs,
 | |
|               CT rhs)
 | |
|     {
 | |
|         xbasic_fixed_string<CT, N, ST, EP, TR> res(lhs);
 | |
|         return res += rhs;
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline xbasic_fixed_string<CT, N, ST, EP, TR>
 | |
|     operator+(const CT* lhs,
 | |
|               const xbasic_fixed_string<CT, N, ST, EP, TR>& rhs)
 | |
|     {
 | |
|         xbasic_fixed_string<CT, N, ST, EP, TR> res(lhs);
 | |
|         return res += rhs;
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline xbasic_fixed_string<CT, N, ST, EP, TR>
 | |
|     operator+(CT lhs,
 | |
|               const xbasic_fixed_string<CT, N, ST, EP, TR>& rhs)
 | |
|     {
 | |
|         using size_type = typename xbasic_fixed_string<CT, N, ST, EP, TR>::size_type;
 | |
|         xbasic_fixed_string<CT, N, ST, EP, TR> res(size_type(1), lhs);
 | |
|         return res += rhs;
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline xbasic_fixed_string<CT, N, ST, EP, TR>
 | |
|     operator+(const xbasic_fixed_string<CT, N, ST, EP, TR>&& lhs,
 | |
|               const xbasic_fixed_string<CT, N, ST, EP, TR>& rhs)
 | |
|     {
 | |
|         xbasic_fixed_string<CT, N, ST, EP, TR> res(std::move(lhs));
 | |
|         return res += rhs;
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline xbasic_fixed_string<CT, N, ST, EP, TR>
 | |
|     operator+(const xbasic_fixed_string<CT, N, ST, EP, TR>& lhs,
 | |
|               const xbasic_fixed_string<CT, N, ST, EP, TR>&& rhs)
 | |
|     {
 | |
|         xbasic_fixed_string<CT, N, ST, EP, TR> res(lhs);
 | |
|         return res += std::move(rhs);
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline xbasic_fixed_string<CT, N, ST, EP, TR>
 | |
|     operator+(const xbasic_fixed_string<CT, N, ST, EP, TR>&& lhs,
 | |
|               const xbasic_fixed_string<CT, N, ST, EP, TR>&& rhs)
 | |
|     {
 | |
|         xbasic_fixed_string<CT, N, ST, EP, TR> res(std::move(lhs));
 | |
|         return res += std::move(rhs);
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline xbasic_fixed_string<CT, N, ST, EP, TR>
 | |
|     operator+(const xbasic_fixed_string<CT, N, ST, EP, TR>&& lhs,
 | |
|               const CT* rhs)
 | |
|     {
 | |
|         xbasic_fixed_string<CT, N, ST, EP, TR> res(std::move(lhs));
 | |
|         return res += rhs;
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline xbasic_fixed_string<CT, N, ST, EP, TR>
 | |
|     operator+(const xbasic_fixed_string<CT, N, ST, EP, TR>&& lhs,
 | |
|               CT rhs)
 | |
|     {
 | |
|         xbasic_fixed_string<CT, N, ST, EP, TR> res(std::move(lhs));
 | |
|         return res += rhs;
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline xbasic_fixed_string<CT, N, ST, EP, TR>
 | |
|     operator+(const CT* lhs,
 | |
|               const xbasic_fixed_string<CT, N, ST, EP, TR>&& rhs)
 | |
|     {
 | |
|         xbasic_fixed_string<CT, N, ST, EP, TR> res(lhs);
 | |
|         return res += std::move(rhs);
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline xbasic_fixed_string<CT, N, ST, EP, TR>
 | |
|     operator+(CT lhs,
 | |
|               const xbasic_fixed_string<CT, N, ST, EP, TR>&& rhs)
 | |
|     {
 | |
|         using size_type = typename xbasic_fixed_string<CT, N, ST, EP, TR>::size_type;
 | |
|         xbasic_fixed_string<CT, N, ST, EP, TR> res(size_type(1), lhs);
 | |
|         return res += std::move(rhs);
 | |
|     }
 | |
| 
 | |
|     /************************
 | |
|     * Comparison operators *
 | |
|     ************************/
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline bool operator==(const xbasic_fixed_string<CT, N, ST, EP, TR>& lhs,
 | |
|                            const xbasic_fixed_string<CT, N, ST, EP, TR>& rhs) noexcept
 | |
|     {
 | |
|         return lhs.compare(rhs) == 0;
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline bool operator==(const xbasic_fixed_string<CT, N, ST, EP, TR>& lhs,
 | |
|                            const CT* rhs) noexcept
 | |
|     {
 | |
|         return lhs.compare(rhs) == 0;
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline bool operator==(const CT* lhs,
 | |
|                            const xbasic_fixed_string<CT, N, ST, EP, TR>& rhs) noexcept
 | |
|     {
 | |
|         return rhs == lhs;
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline bool operator==(const xbasic_fixed_string<CT, N, ST, EP, TR>& lhs,
 | |
|                            const std::basic_string<CT, TR>& rhs) noexcept
 | |
|     {
 | |
|         return lhs == rhs.c_str();
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline bool operator==(const std::basic_string<CT, TR>& lhs,
 | |
|                            const xbasic_fixed_string<CT, N, ST, EP, TR>& rhs) noexcept
 | |
|     {
 | |
|         return lhs.c_str() == rhs;
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline bool operator!=(const xbasic_fixed_string<CT, N, ST, EP, TR>& lhs,
 | |
|                            const xbasic_fixed_string<CT, N, ST, EP, TR>& rhs) noexcept
 | |
|     {
 | |
|         return lhs.compare(rhs) != 0;
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline bool operator!=(const xbasic_fixed_string<CT, N, ST, EP, TR>& lhs,
 | |
|                            const CT* rhs) noexcept
 | |
|     {
 | |
|         return lhs.compare(rhs) != 0;
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline bool operator!=(const CT* lhs,
 | |
|                            const xbasic_fixed_string<CT, N, ST, EP, TR>& rhs) noexcept
 | |
|     {
 | |
|         return rhs != lhs;
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline bool operator!=(const xbasic_fixed_string<CT, N, ST, EP, TR>& lhs,
 | |
|                            const std::basic_string<CT, TR>& rhs) noexcept
 | |
|     {
 | |
|         return lhs != rhs.c_str();
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline bool operator!=(const std::basic_string<CT, TR>& lhs,
 | |
|                            const xbasic_fixed_string<CT, N, ST, EP, TR>& rhs) noexcept
 | |
|     {
 | |
|         return lhs.c_str() != rhs;
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline bool operator<(const xbasic_fixed_string<CT, N, ST, EP, TR>& lhs,
 | |
|                           const xbasic_fixed_string<CT, N, ST, EP, TR>& rhs) noexcept
 | |
|     {
 | |
|         return lhs.compare(rhs) < 0;
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline bool operator<(const xbasic_fixed_string<CT, N, ST, EP, TR>& lhs,
 | |
|                           const CT* rhs) noexcept
 | |
|     {
 | |
|         return lhs.compare(rhs) < 0;
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline bool operator<(const CT* lhs,
 | |
|                           const xbasic_fixed_string<CT, N, ST, EP, TR>& rhs) noexcept
 | |
|     {
 | |
|         return rhs > lhs;
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline bool operator<(const xbasic_fixed_string<CT, N, ST, EP, TR>& lhs,
 | |
|                           const std::basic_string<CT, TR>& rhs) noexcept
 | |
|     {
 | |
|         return lhs < rhs.c_str();
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline bool operator<(const std::basic_string<CT, TR>& lhs,
 | |
|                           const xbasic_fixed_string<CT, N, ST, EP, TR>& rhs) noexcept
 | |
|     {
 | |
|         return lhs.c_str() < rhs;
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline bool operator<=(const xbasic_fixed_string<CT, N, ST, EP, TR>& lhs,
 | |
|                            const xbasic_fixed_string<CT, N, ST, EP, TR>& rhs) noexcept
 | |
|     {
 | |
|         return lhs.compare(rhs) <= 0;
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline bool operator<=(const xbasic_fixed_string<CT, N, ST, EP, TR>& lhs,
 | |
|                            const CT* rhs) noexcept
 | |
|     {
 | |
|         return lhs.compare(rhs) <= 0;
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline bool operator<=(const CT* lhs,
 | |
|                            const xbasic_fixed_string<CT, N, ST, EP, TR>& rhs) noexcept
 | |
|     {
 | |
|         return rhs >= lhs;
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline bool operator<=(const xbasic_fixed_string<CT, N, ST, EP, TR>& lhs,
 | |
|                            const std::basic_string<CT, TR>& rhs) noexcept
 | |
|     {
 | |
|         return lhs <= rhs.c_str();
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline bool operator<=(const std::basic_string<CT, TR>& lhs,
 | |
|                            const xbasic_fixed_string<CT, N, ST, EP, TR>& rhs) noexcept
 | |
|     {
 | |
|         return lhs.c_str() <= rhs;
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline bool operator>(const xbasic_fixed_string<CT, N, ST, EP, TR>& lhs,
 | |
|                           const xbasic_fixed_string<CT, N, ST, EP, TR>& rhs) noexcept
 | |
|     {
 | |
|         return lhs.compare(rhs) > 0;
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline bool operator>(const xbasic_fixed_string<CT, N, ST, EP, TR>& lhs,
 | |
|                           const CT* rhs) noexcept
 | |
|     {
 | |
|         return lhs.compare(rhs) > 0;
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline bool operator>(const CT* lhs,
 | |
|                           const xbasic_fixed_string<CT, N, ST, EP, TR>& rhs) noexcept
 | |
|     {
 | |
|         return rhs < lhs;
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline bool operator>(const xbasic_fixed_string<CT, N, ST, EP, TR>& lhs,
 | |
|                           const std::basic_string<CT, TR>& rhs) noexcept
 | |
|     {
 | |
|         return lhs > rhs.c_str();
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline bool operator>(const std::basic_string<CT, TR>& lhs,
 | |
|                           const xbasic_fixed_string<CT, N, ST, EP, TR>& rhs) noexcept
 | |
|     {
 | |
|         return lhs.c_str() > rhs;
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline bool operator>=(const xbasic_fixed_string<CT, N, ST, EP, TR>& lhs,
 | |
|                            const xbasic_fixed_string<CT, N, ST, EP, TR>& rhs) noexcept
 | |
|     {
 | |
|         return lhs.compare(rhs) >= 0;
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline bool operator>=(const xbasic_fixed_string<CT, N, ST, EP, TR>& lhs,
 | |
|                            const CT* rhs) noexcept
 | |
|     {
 | |
|         return lhs.compare(rhs) >= 0;
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline bool operator>=(const CT* lhs,
 | |
|                            const xbasic_fixed_string<CT, N, ST, EP, TR>& rhs) noexcept
 | |
|     {
 | |
|         return rhs <= lhs;
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline bool operator>=(const xbasic_fixed_string<CT, N, ST, EP, TR>& lhs,
 | |
|                            const std::basic_string<CT, TR>& rhs) noexcept
 | |
|     {
 | |
|         return lhs >= rhs.c_str();
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline bool operator>=(const std::basic_string<CT, TR>& lhs,
 | |
|                            const xbasic_fixed_string<CT, N, ST, EP, TR>& rhs) noexcept
 | |
|     {
 | |
|         return lhs.c_str() >= rhs;
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline void swap(xbasic_fixed_string<CT, N, ST, EP, TR>& lhs, xbasic_fixed_string<CT, N, ST, EP, TR>& rhs)
 | |
|     {
 | |
|         lhs.swap(rhs);
 | |
|     }
 | |
| 
 | |
|     /******************
 | |
|      * Input / output *
 | |
|      ******************/
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline std::basic_ostream<CT, TR>& operator<<(std::basic_ostream<CT, TR>& os,
 | |
|                                                   const xbasic_fixed_string<CT, N, ST, EP, TR>& str)
 | |
|     {
 | |
|         os << str.c_str();
 | |
|         return os;
 | |
|     }
 | |
| 
 | |
| #ifdef __CLING__
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     nlohmann::json mime_bundle_repr(const xbasic_fixed_string<CT, N, ST, EP, TR>& str)
 | |
|     {
 | |
|         auto bundle = nlohmann::json::object();
 | |
|         bundle["text/plain"] = str.c_str();
 | |
|         return bundle;
 | |
|     }
 | |
| #endif
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline std::basic_istream<CT, TR>& operator>>(std::basic_istream<CT, TR>& is,
 | |
|                                                   xbasic_fixed_string<CT, N, ST, EP, TR>& str)
 | |
|     {
 | |
|         // Not optimal
 | |
|         std::string tmp;
 | |
|         is >> tmp;
 | |
|         str = tmp.c_str();
 | |
|         return is;
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline std::basic_istream<CT, TR>& getline(std::basic_istream<CT, TR>& input,
 | |
|                                                xbasic_fixed_string<CT, N, ST, EP, TR>& str,
 | |
|                                                CT delim)
 | |
|     {
 | |
|         std::string tmp;
 | |
|         auto& ret = std::getline(input, tmp, delim);
 | |
|         str = tmp;
 | |
|         return ret;
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline std::basic_istream<CT, TR>& getline(std::basic_istream<CT, TR>&& input,
 | |
|                                                xbasic_fixed_string<CT, N, ST, EP, TR>& str,
 | |
|                                                CT delim)
 | |
|     {
 | |
|         std::string tmp;
 | |
|         auto& ret = std::getline(std::move(input), tmp, delim);
 | |
|         str = tmp;
 | |
|         return ret;
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline std::basic_istream<CT, TR>& getline(std::basic_istream<CT, TR>& input,
 | |
|                                                xbasic_fixed_string<CT, N, ST, EP, TR>& str)
 | |
|     {
 | |
|         std::string tmp;
 | |
|         auto& ret = std::getline(input, tmp);
 | |
|         str = tmp;
 | |
|         return ret;
 | |
|     }
 | |
| 
 | |
|     template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
 | |
|     inline std::basic_istream<CT, TR>& getline(std::basic_istream<CT, TR>&& input,
 | |
|                                                xbasic_fixed_string<CT, N, ST, EP, TR>& str)
 | |
|     {
 | |
|         std::string tmp;
 | |
|         auto& ret = std::getline(std::move(input), tmp);
 | |
|         str = tmp;
 | |
|         return ret;
 | |
|     }
 | |
| }
 | |
| 
 | |
| #endif  // xtl
 |