Chris@16: /* Chris@16: Copyright (c) Marshall Clow 2012-2012. Chris@16: Chris@16: Distributed under the Boost Software License, Version 1.0. (See accompanying Chris@16: file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) Chris@16: Chris@16: For more information, see http://www.boost.org Chris@16: Chris@16: Based on the StringRef implementation in LLVM (http://llvm.org) and Chris@16: N3422 by Jeffrey Yasskin Chris@16: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3442.html Chris@16: Chris@16: */ Chris@16: Chris@16: #ifndef BOOST_STRING_REF_HPP Chris@16: #define BOOST_STRING_REF_HPP Chris@16: Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: Chris@16: namespace boost { Chris@16: Chris@16: namespace detail { Chris@16: // A helper functor because sometimes we don't have lambdas Chris@16: template Chris@16: class string_ref_traits_eq { Chris@16: public: Chris@16: string_ref_traits_eq ( charT ch ) : ch_(ch) {} Chris@16: bool operator () ( charT val ) const { return traits::eq ( ch_, val ); } Chris@16: charT ch_; Chris@16: }; Chris@16: } Chris@16: Chris@16: template Chris@16: class basic_string_ref { Chris@16: public: Chris@16: // types Chris@16: typedef charT value_type; Chris@16: typedef const charT* pointer; Chris@16: typedef const charT& reference; Chris@16: typedef const charT& const_reference; Chris@16: typedef pointer const_iterator; // impl-defined Chris@16: typedef const_iterator iterator; Chris@16: typedef std::reverse_iterator const_reverse_iterator; Chris@16: typedef const_reverse_iterator reverse_iterator; Chris@16: typedef std::size_t size_type; Chris@16: typedef std::ptrdiff_t difference_type; Chris@16: static BOOST_CONSTEXPR_OR_CONST size_type npos = size_type(-1); Chris@16: Chris@16: // construct/copy Chris@16: BOOST_CONSTEXPR basic_string_ref () Chris@16: : ptr_(NULL), len_(0) {} Chris@16: Chris@16: BOOST_CONSTEXPR basic_string_ref (const basic_string_ref &rhs) Chris@16: : ptr_(rhs.ptr_), len_(rhs.len_) {} Chris@16: Chris@16: basic_string_ref& operator=(const basic_string_ref &rhs) { Chris@16: ptr_ = rhs.ptr_; Chris@16: len_ = rhs.len_; Chris@16: return *this; Chris@16: } Chris@16: Chris@16: basic_string_ref(const charT* str) Chris@16: : ptr_(str), len_(traits::length(str)) {} Chris@16: Chris@16: template Chris@16: basic_string_ref(const std::basic_string& str) Chris@16: : ptr_(str.data()), len_(str.length()) {} Chris@16: Chris@16: BOOST_CONSTEXPR basic_string_ref(const charT* str, size_type len) Chris@16: : ptr_(str), len_(len) {} Chris@16: Chris@16: #ifndef BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS Chris@16: template Chris@16: explicit operator std::basic_string() const { Chris@16: return std::basic_string ( ptr_, len_ ); Chris@16: } Chris@16: #endif Chris@16: Chris@16: std::basic_string to_string () const { Chris@16: return std::basic_string ( ptr_, len_ ); Chris@16: } Chris@16: Chris@16: // iterators Chris@16: BOOST_CONSTEXPR const_iterator begin() const { return ptr_; } Chris@16: BOOST_CONSTEXPR const_iterator cbegin() const { return ptr_; } Chris@16: BOOST_CONSTEXPR const_iterator end() const { return ptr_ + len_; } Chris@16: BOOST_CONSTEXPR const_iterator cend() const { return ptr_ + len_; } Chris@16: const_reverse_iterator rbegin() const { return const_reverse_iterator (end()); } Chris@16: const_reverse_iterator crbegin() const { return const_reverse_iterator (end()); } Chris@16: const_reverse_iterator rend() const { return const_reverse_iterator (begin()); } Chris@16: const_reverse_iterator crend() const { return const_reverse_iterator (begin()); } Chris@16: Chris@16: // capacity Chris@16: BOOST_CONSTEXPR size_type size() const { return len_; } Chris@16: BOOST_CONSTEXPR size_type length() const { return len_; } Chris@16: BOOST_CONSTEXPR size_type max_size() const { return len_; } Chris@16: BOOST_CONSTEXPR bool empty() const { return len_ == 0; } Chris@16: Chris@16: // element access Chris@16: BOOST_CONSTEXPR const charT& operator[](size_type pos) const { return ptr_[pos]; } Chris@16: Chris@16: const charT& at(size_t pos) const { Chris@16: if ( pos >= len_ ) Chris@16: BOOST_THROW_EXCEPTION( std::out_of_range ( "boost::string_ref::at" ) ); Chris@16: return ptr_[pos]; Chris@16: } Chris@16: Chris@16: BOOST_CONSTEXPR const charT& front() const { return ptr_[0]; } Chris@16: BOOST_CONSTEXPR const charT& back() const { return ptr_[len_-1]; } Chris@16: BOOST_CONSTEXPR const charT* data() const { return ptr_; } Chris@16: Chris@16: // modifiers Chris@16: void clear() { len_ = 0; } Chris@16: void remove_prefix(size_type n) { Chris@16: if ( n > len_ ) Chris@16: n = len_; Chris@16: ptr_ += n; Chris@16: len_ -= n; Chris@16: } Chris@16: Chris@16: void remove_suffix(size_type n) { Chris@16: if ( n > len_ ) Chris@16: n = len_; Chris@16: len_ -= n; Chris@16: } Chris@16: Chris@16: Chris@16: // basic_string_ref string operations Chris@16: basic_string_ref substr(size_type pos, size_type n=npos) const { Chris@16: if ( pos > size()) Chris@16: BOOST_THROW_EXCEPTION( std::out_of_range ( "string_ref::substr" ) ); Chris@16: if ( n == npos || pos + n > size()) Chris@16: n = size () - pos; Chris@16: return basic_string_ref ( data() + pos, n ); Chris@16: } Chris@16: Chris@16: int compare(basic_string_ref x) const { Chris@16: const int cmp = traits::compare ( ptr_, x.ptr_, (std::min)(len_, x.len_)); Chris@16: return cmp != 0 ? cmp : ( len_ == x.len_ ? 0 : len_ < x.len_ ? -1 : 1 ); Chris@16: } Chris@16: Chris@16: bool starts_with(charT c) const { return !empty() && traits::eq ( c, front()); } Chris@16: bool starts_with(basic_string_ref x) const { Chris@16: return len_ >= x.len_ && traits::compare ( ptr_, x.ptr_, x.len_ ) == 0; Chris@16: } Chris@16: Chris@16: bool ends_with(charT c) const { return !empty() && traits::eq ( c, back()); } Chris@16: bool ends_with(basic_string_ref x) const { Chris@16: return len_ >= x.len_ && traits::compare ( ptr_ + len_ - x.len_, x.ptr_, x.len_ ) == 0; Chris@16: } Chris@16: Chris@16: size_type find(basic_string_ref s) const { Chris@16: const_iterator iter = std::search ( this->cbegin (), this->cend (), Chris@16: s.cbegin (), s.cend (), traits::eq ); Chris@16: return iter == this->cend () ? npos : std::distance ( this->cbegin (), iter ); Chris@16: } Chris@16: Chris@16: size_type find(charT c) const { Chris@16: const_iterator iter = std::find_if ( this->cbegin (), this->cend (), Chris@16: detail::string_ref_traits_eq ( c )); Chris@16: return iter == this->cend () ? npos : std::distance ( this->cbegin (), iter ); Chris@16: } Chris@16: Chris@16: size_type rfind(basic_string_ref s) const { Chris@16: const_reverse_iterator iter = std::search ( this->crbegin (), this->crend (), Chris@16: s.crbegin (), s.crend (), traits::eq ); Chris@16: return iter == this->crend () ? npos : reverse_distance ( this->crbegin (), iter ); Chris@16: } Chris@16: Chris@16: size_type rfind(charT c) const { Chris@16: const_reverse_iterator iter = std::find_if ( this->crbegin (), this->crend (), Chris@16: detail::string_ref_traits_eq ( c )); Chris@16: return iter == this->crend () ? npos : reverse_distance ( this->crbegin (), iter ); Chris@16: } Chris@16: Chris@16: size_type find_first_of(charT c) const { return find (c); } Chris@16: size_type find_last_of (charT c) const { return rfind (c); } Chris@16: Chris@16: size_type find_first_of(basic_string_ref s) const { Chris@16: const_iterator iter = std::find_first_of Chris@16: ( this->cbegin (), this->cend (), s.cbegin (), s.cend (), traits::eq ); Chris@16: return iter == this->cend () ? npos : std::distance ( this->cbegin (), iter ); Chris@16: } Chris@16: Chris@16: size_type find_last_of(basic_string_ref s) const { Chris@16: const_reverse_iterator iter = std::find_first_of Chris@16: ( this->crbegin (), this->crend (), s.cbegin (), s.cend (), traits::eq ); Chris@16: return iter == this->crend () ? npos : reverse_distance ( this->crbegin (), iter); Chris@16: } Chris@16: Chris@16: size_type find_first_not_of(basic_string_ref s) const { Chris@16: const_iterator iter = find_not_of ( this->cbegin (), this->cend (), s ); Chris@16: return iter == this->cend () ? npos : std::distance ( this->cbegin (), iter ); Chris@16: } Chris@16: Chris@16: size_type find_first_not_of(charT c) const { Chris@16: for ( const_iterator iter = this->cbegin (); iter != this->cend (); ++iter ) Chris@16: if ( !traits::eq ( c, *iter )) Chris@16: return std::distance ( this->cbegin (), iter ); Chris@16: return npos; Chris@16: } Chris@16: Chris@16: size_type find_last_not_of(basic_string_ref s) const { Chris@16: const_reverse_iterator iter = find_not_of ( this->crbegin (), this->crend (), s ); Chris@16: return iter == this->crend () ? npos : reverse_distance ( this->crbegin (), iter ); Chris@16: } Chris@16: Chris@16: size_type find_last_not_of(charT c) const { Chris@16: for ( const_reverse_iterator iter = this->crbegin (); iter != this->crend (); ++iter ) Chris@16: if ( !traits::eq ( c, *iter )) Chris@16: return reverse_distance ( this->crbegin (), iter ); Chris@16: return npos; Chris@16: } Chris@16: Chris@16: private: Chris@16: template Chris@16: size_type reverse_distance ( r_iter first, r_iter last ) const { Chris@16: return len_ - 1 - std::distance ( first, last ); Chris@16: } Chris@16: Chris@16: template Chris@16: Iterator find_not_of ( Iterator first, Iterator last, basic_string_ref s ) const { Chris@16: for ( ; first != last ; ++first ) Chris@16: if ( 0 == traits::find ( s.ptr_, s.len_, *first )) Chris@16: return first; Chris@16: return last; Chris@16: } Chris@16: Chris@16: Chris@16: Chris@16: const charT *ptr_; Chris@16: std::size_t len_; Chris@16: }; Chris@16: Chris@16: Chris@16: // Comparison operators Chris@16: // Equality Chris@16: template Chris@16: inline bool operator==(basic_string_ref x, basic_string_ref y) { Chris@16: if ( x.size () != y.size ()) return false; Chris@16: return x.compare(y) == 0; Chris@16: } Chris@16: Chris@16: template Chris@16: inline bool operator==(basic_string_ref x, const std::basic_string & y) { Chris@16: return x == basic_string_ref(y); Chris@16: } Chris@16: Chris@16: template Chris@16: inline bool operator==(const std::basic_string & x, basic_string_ref y) { Chris@16: return basic_string_ref(x) == y; Chris@16: } Chris@16: Chris@16: template Chris@16: inline bool operator==(basic_string_ref x, const charT * y) { Chris@16: return x == basic_string_ref(y); Chris@16: } Chris@16: Chris@16: template Chris@16: inline bool operator==(const charT * x, basic_string_ref y) { Chris@16: return basic_string_ref(x) == y; Chris@16: } Chris@16: Chris@16: // Inequality Chris@16: template Chris@16: inline bool operator!=(basic_string_ref x, basic_string_ref y) { Chris@16: if ( x.size () != y.size ()) return true; Chris@16: return x.compare(y) != 0; Chris@16: } Chris@16: Chris@16: template Chris@16: inline bool operator!=(basic_string_ref x, const std::basic_string & y) { Chris@16: return x != basic_string_ref(y); Chris@16: } Chris@16: Chris@16: template Chris@16: inline bool operator!=(const std::basic_string & x, basic_string_ref y) { Chris@16: return basic_string_ref(x) != y; Chris@16: } Chris@16: Chris@16: template Chris@16: inline bool operator!=(basic_string_ref x, const charT * y) { Chris@16: return x != basic_string_ref(y); Chris@16: } Chris@16: Chris@16: template Chris@16: inline bool operator!=(const charT * x, basic_string_ref y) { Chris@16: return basic_string_ref(x) != y; Chris@16: } Chris@16: Chris@16: // Less than Chris@16: template Chris@16: inline bool operator<(basic_string_ref x, basic_string_ref y) { Chris@16: return x.compare(y) < 0; Chris@16: } Chris@16: Chris@16: template Chris@16: inline bool operator<(basic_string_ref x, const std::basic_string & y) { Chris@16: return x < basic_string_ref(y); Chris@16: } Chris@16: Chris@16: template Chris@16: inline bool operator<(const std::basic_string & x, basic_string_ref y) { Chris@16: return basic_string_ref(x) < y; Chris@16: } Chris@16: Chris@16: template Chris@16: inline bool operator<(basic_string_ref x, const charT * y) { Chris@16: return x < basic_string_ref(y); Chris@16: } Chris@16: Chris@16: template Chris@16: inline bool operator<(const charT * x, basic_string_ref y) { Chris@16: return basic_string_ref(x) < y; Chris@16: } Chris@16: Chris@16: // Greater than Chris@16: template Chris@16: inline bool operator>(basic_string_ref x, basic_string_ref y) { Chris@16: return x.compare(y) > 0; Chris@16: } Chris@16: Chris@16: template Chris@16: inline bool operator>(basic_string_ref x, const std::basic_string & y) { Chris@16: return x > basic_string_ref(y); Chris@16: } Chris@16: Chris@16: template Chris@16: inline bool operator>(const std::basic_string & x, basic_string_ref y) { Chris@16: return basic_string_ref(x) > y; Chris@16: } Chris@16: Chris@16: template Chris@16: inline bool operator>(basic_string_ref x, const charT * y) { Chris@16: return x > basic_string_ref(y); Chris@16: } Chris@16: Chris@16: template Chris@16: inline bool operator>(const charT * x, basic_string_ref y) { Chris@16: return basic_string_ref(x) > y; Chris@16: } Chris@16: Chris@16: // Less than or equal to Chris@16: template Chris@16: inline bool operator<=(basic_string_ref x, basic_string_ref y) { Chris@16: return x.compare(y) <= 0; Chris@16: } Chris@16: Chris@16: template Chris@16: inline bool operator<=(basic_string_ref x, const std::basic_string & y) { Chris@16: return x <= basic_string_ref(y); Chris@16: } Chris@16: Chris@16: template Chris@16: inline bool operator<=(const std::basic_string & x, basic_string_ref y) { Chris@16: return basic_string_ref(x) <= y; Chris@16: } Chris@16: Chris@16: template Chris@16: inline bool operator<=(basic_string_ref x, const charT * y) { Chris@16: return x <= basic_string_ref(y); Chris@16: } Chris@16: Chris@16: template Chris@16: inline bool operator<=(const charT * x, basic_string_ref y) { Chris@16: return basic_string_ref(x) <= y; Chris@16: } Chris@16: Chris@16: // Greater than or equal to Chris@16: template Chris@16: inline bool operator>=(basic_string_ref x, basic_string_ref y) { Chris@16: return x.compare(y) >= 0; Chris@16: } Chris@16: Chris@16: template Chris@16: inline bool operator>=(basic_string_ref x, const std::basic_string & y) { Chris@16: return x >= basic_string_ref(y); Chris@16: } Chris@16: Chris@16: template Chris@16: inline bool operator>=(const std::basic_string & x, basic_string_ref y) { Chris@16: return basic_string_ref(x) >= y; Chris@16: } Chris@16: Chris@16: template Chris@16: inline bool operator>=(basic_string_ref x, const charT * y) { Chris@16: return x >= basic_string_ref(y); Chris@16: } Chris@16: Chris@16: template Chris@16: inline bool operator>=(const charT * x, basic_string_ref y) { Chris@16: return basic_string_ref(x) >= y; Chris@16: } Chris@16: Chris@16: namespace detail { Chris@16: Chris@16: template Chris@16: inline void insert_fill_chars(std::basic_ostream& os, std::size_t n) { Chris@16: enum { chunk_size = 8 }; Chris@16: charT fill_chars[chunk_size]; Chris@16: std::fill_n(fill_chars, static_cast< std::size_t >(chunk_size), os.fill()); Chris@16: for (; n >= chunk_size && os.good(); n -= chunk_size) Chris@16: os.write(fill_chars, static_cast< std::size_t >(chunk_size)); Chris@16: if (n > 0 && os.good()) Chris@16: os.write(fill_chars, n); Chris@16: } Chris@16: Chris@16: template Chris@16: void insert_aligned(std::basic_ostream& os, const basic_string_ref& str) { Chris@16: const std::size_t size = str.size(); Chris@16: const std::size_t alignment_size = static_cast< std::size_t >(os.width()) - size; Chris@16: const bool align_left = (os.flags() & std::basic_ostream::adjustfield) == std::basic_ostream::left; Chris@16: if (!align_left) { Chris@16: detail::insert_fill_chars(os, alignment_size); Chris@16: if (os.good()) Chris@16: os.write(str.data(), size); Chris@16: } Chris@16: else { Chris@16: os.write(str.data(), size); Chris@16: if (os.good()) Chris@16: detail::insert_fill_chars(os, alignment_size); Chris@16: } Chris@16: } Chris@16: Chris@16: } // namespace detail Chris@16: Chris@16: // Inserter Chris@16: template Chris@16: inline std::basic_ostream& Chris@16: operator<<(std::basic_ostream& os, const basic_string_ref& str) { Chris@16: if (os.good()) { Chris@16: const std::size_t size = str.size(); Chris@16: const std::size_t w = static_cast< std::size_t >(os.width()); Chris@16: if (w <= size) Chris@16: os.write(str.data(), size); Chris@16: else Chris@16: detail::insert_aligned(os, str); Chris@16: os.width(0); Chris@16: } Chris@16: return os; Chris@16: } Chris@16: Chris@16: #if 0 Chris@16: // numeric conversions Chris@16: // Chris@16: // These are short-term implementations. Chris@16: // In a production environment, I would rather avoid the copying. Chris@16: // Chris@16: inline int stoi (string_ref str, size_t* idx=0, int base=10) { Chris@16: return std::stoi ( std::string(str), idx, base ); Chris@16: } Chris@16: Chris@16: inline long stol (string_ref str, size_t* idx=0, int base=10) { Chris@16: return std::stol ( std::string(str), idx, base ); Chris@16: } Chris@16: Chris@16: inline unsigned long stoul (string_ref str, size_t* idx=0, int base=10) { Chris@16: return std::stoul ( std::string(str), idx, base ); Chris@16: } Chris@16: Chris@16: inline long long stoll (string_ref str, size_t* idx=0, int base=10) { Chris@16: return std::stoll ( std::string(str), idx, base ); Chris@16: } Chris@16: Chris@16: inline unsigned long long stoull (string_ref str, size_t* idx=0, int base=10) { Chris@16: return std::stoull ( std::string(str), idx, base ); Chris@16: } Chris@16: Chris@16: inline float stof (string_ref str, size_t* idx=0) { Chris@16: return std::stof ( std::string(str), idx ); Chris@16: } Chris@16: Chris@16: inline double stod (string_ref str, size_t* idx=0) { Chris@16: return std::stod ( std::string(str), idx ); Chris@16: } Chris@16: Chris@16: inline long double stold (string_ref str, size_t* idx=0) { Chris@16: return std::stold ( std::string(str), idx ); Chris@16: } Chris@16: Chris@16: inline int stoi (wstring_ref str, size_t* idx=0, int base=10) { Chris@16: return std::stoi ( std::wstring(str), idx, base ); Chris@16: } Chris@16: Chris@16: inline long stol (wstring_ref str, size_t* idx=0, int base=10) { Chris@16: return std::stol ( std::wstring(str), idx, base ); Chris@16: } Chris@16: Chris@16: inline unsigned long stoul (wstring_ref str, size_t* idx=0, int base=10) { Chris@16: return std::stoul ( std::wstring(str), idx, base ); Chris@16: } Chris@16: Chris@16: inline long long stoll (wstring_ref str, size_t* idx=0, int base=10) { Chris@16: return std::stoll ( std::wstring(str), idx, base ); Chris@16: } Chris@16: Chris@16: inline unsigned long long stoull (wstring_ref str, size_t* idx=0, int base=10) { Chris@16: return std::stoull ( std::wstring(str), idx, base ); Chris@16: } Chris@16: Chris@16: inline float stof (wstring_ref str, size_t* idx=0) { Chris@16: return std::stof ( std::wstring(str), idx ); Chris@16: } Chris@16: Chris@16: inline double stod (wstring_ref str, size_t* idx=0) { Chris@16: return std::stod ( std::wstring(str), idx ); Chris@16: } Chris@16: Chris@16: inline long double stold (wstring_ref str, size_t* idx=0) { Chris@16: return std::stold ( std::wstring(str), idx ); Chris@16: } Chris@16: #endif Chris@16: Chris@16: } Chris@16: Chris@16: #if 0 Chris@16: namespace std { Chris@16: // Hashing Chris@16: template<> struct hash; Chris@16: template<> struct hash; Chris@16: template<> struct hash; Chris@16: template<> struct hash; Chris@16: } Chris@16: #endif Chris@16: Chris@16: #endif