//------------------------------------------------------------------------------ /* This file is part of Beast: https://github.com/vinniefalco/Beast Copyright 2013, Vinnie Falco Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ //============================================================================== #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