// // Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef BEAST_WEBSOCKET_STATIC_STRING_HPP #define BEAST_WEBSOCKET_STATIC_STRING_HPP #include #include #include #include #include namespace beast { /** A string with a fixed-size storage area. These objects behave like `std::string` except that the storage is not dynamically allocated but rather fixed in size. These strings offer performance advantages when a protocol imposes a natural small upper limit on the size of a value. @note The stored string is always null-terminated. */ template< std::size_t N, class CharT = char, class Traits = std::char_traits> class static_string { template friend class static_string; std::size_t n_; std::array s_; public: using traits_type = Traits; using value_type = typename Traits::char_type; using size_type = std::size_t; using difference_type = std::ptrdiff_t; using pointer = value_type*; using reference = value_type&; using const_pointer = value_type const*; using const_reference = value_type const&; using iterator = value_type*; using const_iterator = value_type const*; using reverse_iterator = std::reverse_iterator; using const_reverse_iterator = std::reverse_iterator; /** Default constructor. The string is initially empty, and null terminated. */ static_string(); /// Copy constructor. static_string(static_string const& s); /// Copy constructor. template static_string(static_string const& s); /// Copy assignment. static_string& operator=(static_string const& s); /// Copy assignment. template static_string& operator=(static_string const& s); /// Construct from string literal. template static_string(const CharT (&s)[M]); /// Assign from string literal. template static_string& operator=(const CharT (&s)[M]); /// Access specified character with bounds checking. reference at(size_type pos); /// Access specified character with bounds checking. const_reference at(size_type pos) const; /// Access specified character. reference operator[](size_type pos) { return s_[pos]; } /// Access specified character. const_reference operator[](size_type pos) const { return s_[pos]; } /// Accesses the first character. CharT& front() { return s_[0]; } /// Accesses the first character. CharT const& front() const { return s_[0]; } /// Accesses the last character. CharT& back() { return s_[n_-1]; } /// Accesses the last character. CharT const& back() const { return s_[n_-1]; } /// Returns a pointer to the first character of a string. CharT* data() { return &s_[0]; } /// Returns a pointer to the first character of a string. CharT const* data() const { return &s_[0]; } /// Returns a non-modifiable standard C character array version of the string. CharT const* c_str() const { return &s_[0]; } /// Returns an iterator to the beginning. iterator begin() { return &s_[0]; } /// Returns an iterator to the beginning. const_iterator begin() const { return &s_[0]; } /// Returns an iterator to the beginning. const_iterator cbegin() const { return &s_[0]; } /// Returns an iterator to the end. iterator end() { return &s_[n_]; } /// Returns an iterator to the end. const_iterator end() const { return &s_[n_]; } /// Returns an iterator to the end. const_iterator cend() const { return &s_[n_]; } /// Returns a reverse iterator to the beginning. reverse_iterator rbegin() { return reverse_iterator{end()}; } /// Returns a reverse iterator to the beginning. const_reverse_iterator rbegin() const { return const_reverse_iterator{cend()}; } /// Returns a reverse iterator to the beginning. const_reverse_iterator crbegin() const { return const_reverse_iterator{cend()}; } /// Returns a reverse iterator to the end. reverse_iterator rend() { return reverse_iterator{begin()}; } /// Returns a reverse iterator to the end. const_reverse_iterator rend() const { return const_reverse_iterator{cbegin()}; } /// Returns a reverse iterator to the end. const_reverse_iterator crend() const { return const_reverse_iterator{cbegin()}; } /// Returns `true` if the string is empty. bool empty() const { return n_ == 0; } /// Returns the number of characters, excluding the null terminator. size_type size() const { return n_; } /// Returns the maximum number of characters that can be stored, excluding the null terminator. size_type constexpr max_size() const { return N; } /// Returns the number of characters that can be held in currently allocated storage. size_type capacity() const { return N; } /// Clears the contents. void clear() { resize(0); } /** Changes the number of characters stored. @note No value-initialization is performed. */ void resize(std::size_t n); /** Changes the number of characters stored. If the resulting string is larger, the new characters are initialized to the value of `c`. */ void resize(std::size_t n, CharT c); /// Compare two character sequences. template int compare(static_string const& rhs) const; /// Return the characters as a `basic_string`. std::basic_string to_string() const { return std::basic_string< CharT, Traits>{&s_[0], n_}; } private: void assign(CharT const* s); }; template static_string:: static_string() : n_(0) { s_[0] = 0; } template static_string:: static_string(static_string const& s) : n_(s.n_) { Traits::copy(&s_[0], &s.s_[0], n_ + 1); } template template static_string:: static_string(static_string const& s) { if(s.size() > N) throw std::length_error("static_string overflow"); n_ = s.size(); Traits::copy(&s_[0], &s.s_[0], n_ + 1); } template auto static_string:: operator=(static_string const& s) -> static_string& { n_ = s.n_; Traits::copy(&s_[0], &s.s_[0], n_ + 1); return *this; } template template auto static_string:: operator=(static_string const& s) -> static_string& { if(s.size() > N) throw std::length_error("static_string overflow"); n_ = s.size(); Traits::copy(&s_[0], &s.s_[0], n_ + 1); return *this; } template template static_string:: static_string(const CharT (&s)[M]) : n_(M-1) { static_assert(M-1 <= N, "static_string overflow"); Traits::copy(&s_[0], &s[0], M); } template template auto static_string:: operator=(const CharT (&s)[M]) -> static_string& { static_assert(M-1 <= N, "static_string overflow"); n_ = M-1; Traits::copy(&s_[0], &s[0], M); return *this; } template auto static_string:: at(size_type pos) -> reference { if(pos >= n_) throw std::out_of_range("static_string::at"); return s_[pos]; } template auto static_string:: at(size_type pos) const -> const_reference { if(pos >= n_) throw std::out_of_range("static_string::at"); return s_[pos]; } template void static_string:: resize(std::size_t n) { if(n > N) throw std::length_error("static_string overflow"); n_ = n; s_[n_] = 0; } template void static_string:: resize(std::size_t n, CharT c) { if(n > N) throw std::length_error("static_string overflow"); if(n > n_) Traits::assign(&s_[n_], n - n_, c); n_ = n; s_[n_] = 0; } template template int static_string:: compare(static_string const& rhs) const { if(size() < rhs.size()) { auto const v = Traits::compare( data(), rhs.data(), size()); if(v == 0) return -1; return v; } else if(size() > rhs.size()) { auto const v = Traits::compare( data(), rhs.data(), rhs.size()); if(v == 0) return 1; return v; } return Traits::compare(data(), rhs.data(), size()); } template void static_string:: assign(CharT const* s) { auto const n = Traits::length(s); if(n > N) throw std::out_of_range("too large"); n_ = n; Traits::copy(&s_[0], s, n_ + 1); } namespace detail { template int compare( static_string const& lhs, const CharT (&s)[M]) { if(lhs.size() < M-1) { auto const v = Traits::compare( lhs.data(), &s[0], lhs.size()); if(v == 0) return -1; return v; } else if(lhs.size() > M-1) { auto const v = Traits::compare( lhs.data(), &s[0], M-1); if(v == 0) return 1; return v; } return Traits::compare(lhs.data(), &s[0], lhs.size()); } template inline int compare( const CharT (&s)[M], static_string const& rhs) { return -compare(rhs, s); } } // detail #if ! GENERATING_DOCS template bool operator==( static_string const& lhs, static_string const& rhs) { return lhs.compare(rhs) == 0; } template bool operator!=( static_string const& lhs, static_string const& rhs) { return lhs.compare(rhs) != 0; } template bool operator<( static_string const& lhs, static_string const& rhs) { return lhs.compare(rhs) < 0; } template bool operator<=( static_string const& lhs, static_string const& rhs) { return lhs.compare(rhs) <= 0; } template bool operator>( static_string const& lhs, static_string const& rhs) { return lhs.compare(rhs) > 0; } template bool operator>=( static_string const& lhs, static_string const& rhs) { return lhs.compare(rhs) >= 0; } //--- template bool operator==( const CharT (&s)[N], static_string const& rhs) { return detail::compare(s, rhs) == 0; } template bool operator==( static_string const& lhs, const CharT (&s)[M]) { return detail::compare(lhs, s) == 0; } template bool operator!=( const CharT (&s)[N], static_string const& rhs) { return detail::compare(s, rhs) != 0; } template bool operator!=( static_string const& lhs, const CharT (&s)[M]) { return detail::compare(lhs, s) != 0; } template bool operator<( const CharT (&s)[N], static_string const& rhs) { return detail::compare(s, rhs) < 0; } template bool operator<( static_string const& lhs, const CharT (&s)[M]) { return detail::compare(lhs, s) < 0; } template bool operator<=( const CharT (&s)[N], static_string const& rhs) { return detail::compare(s, rhs) <= 0; } template bool operator<=( static_string const& lhs, const CharT (&s)[M]) { return detail::compare(lhs, s) <= 0; } template bool operator>( const CharT (&s)[N], static_string const& rhs) { return detail::compare(s, rhs) > 0; } template bool operator>( static_string const& lhs, const CharT (&s)[M]) { return detail::compare(lhs, s) > 0; } template bool operator>=( const CharT (&s)[N], static_string const& rhs) { return detail::compare(s, rhs) >= 0; } template bool operator>=( static_string const& lhs, const CharT (&s)[M]) { return detail::compare(lhs, s) >= 0; } #endif } // beast #endif