1 /* 2 Copyright (c) Marshall Clow 2012-2015. 3 Copyright (c) Glen Joseph Fernandes 2019 ([email protected]) 4 5 Distributed under the Boost Software License, Version 1.0. (See accompanying 6 file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 7 8 For more information, see http://www.boost.org 9 10 Based on the StringRef implementation in LLVM (http://llvm.org) and 11 N3422 by Jeffrey Yasskin 12 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3442.html 13 14 */ 15 16 #ifndef BOOST_STRING_REF_HPP 17 #define BOOST_STRING_REF_HPP 18 19 #include <boost/config.hpp> 20 #include <boost/detail/workaround.hpp> 21 #include <boost/io/ostream_put.hpp> 22 #include <boost/utility/string_ref_fwd.hpp> 23 #include <boost/throw_exception.hpp> 24 25 #include <cstddef> 26 #include <stdexcept> 27 #include <algorithm> 28 #include <iterator> 29 #include <string> 30 #include <iosfwd> 31 32 #if defined(BOOST_NO_CXX11_DEFAULTED_FUNCTIONS) || (defined(BOOST_GCC) && ((BOOST_GCC+0) / 100) <= 406) 33 // GCC 4.6 cannot handle a defaulted function with noexcept specifier 34 #define BOOST_STRING_REF_NO_CXX11_DEFAULTED_NOEXCEPT_FUNCTIONS 35 #endif 36 37 namespace boost { 38 39 namespace detail { 40 // A helper functor because sometimes we don't have lambdas 41 template <typename charT, typename traits> 42 class string_ref_traits_eq { 43 public: string_ref_traits_eq(charT ch)44 string_ref_traits_eq ( charT ch ) : ch_(ch) {} operator ()(charT val) const45 bool operator () ( charT val ) const { return traits::eq ( ch_, val ); } 46 charT ch_; 47 }; 48 } 49 50 template<typename charT, typename traits> 51 class basic_string_ref { 52 public: 53 // types 54 typedef charT value_type; 55 typedef const charT* pointer; 56 typedef const charT& reference; 57 typedef const charT& const_reference; 58 typedef pointer const_iterator; // impl-defined 59 typedef const_iterator iterator; 60 typedef std::reverse_iterator<const_iterator> const_reverse_iterator; 61 typedef const_reverse_iterator reverse_iterator; 62 typedef std::size_t size_type; 63 typedef std::ptrdiff_t difference_type; 64 static BOOST_CONSTEXPR_OR_CONST size_type npos = size_type(-1); 65 66 // construct/copy basic_string_ref()67 BOOST_CONSTEXPR basic_string_ref () BOOST_NOEXCEPT 68 : ptr_(NULL), len_(0) {} 69 70 // by defaulting these functions, basic_string_ref becomes 71 // trivially copy/move constructible. 72 BOOST_CONSTEXPR basic_string_ref (const basic_string_ref &rhs) BOOST_NOEXCEPT 73 #ifndef BOOST_STRING_REF_NO_CXX11_DEFAULTED_NOEXCEPT_FUNCTIONS 74 = default; 75 #else 76 : ptr_(rhs.ptr_), len_(rhs.len_) {} 77 #endif 78 79 basic_string_ref& operator=(const basic_string_ref &rhs) BOOST_NOEXCEPT 80 #ifndef BOOST_STRING_REF_NO_CXX11_DEFAULTED_NOEXCEPT_FUNCTIONS 81 = default; 82 #else 83 { 84 ptr_ = rhs.ptr_; 85 len_ = rhs.len_; 86 return *this; 87 } 88 #endif 89 basic_string_ref(const charT * str)90 basic_string_ref(const charT* str) BOOST_NOEXCEPT 91 : ptr_(str), len_(traits::length(str)) {} 92 93 template<typename Allocator> basic_string_ref(const std::basic_string<charT,traits,Allocator> & str)94 basic_string_ref(const std::basic_string<charT, traits, Allocator>& str) 95 : ptr_(str.data()), len_(str.length()) {} 96 97 // #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && !defined(BOOST_NO_CXX11_DELETED_FUNCTIONS) 98 // // Constructing a string_ref from a temporary string is a bad idea 99 // template<typename Allocator> 100 // basic_string_ref( std::basic_string<charT, traits, Allocator>&&) 101 // = delete; 102 // #endif 103 basic_string_ref(const charT * str,size_type len)104 BOOST_CONSTEXPR basic_string_ref(const charT* str, size_type len) BOOST_NOEXCEPT 105 : ptr_(str), len_(len) {} 106 107 #ifndef BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS 108 template<typename Allocator> operator std::basic_string<charT,traits,Allocator>() const109 explicit operator std::basic_string<charT, traits, Allocator>() const { 110 return std::basic_string<charT, traits, Allocator> ( begin(), end()); 111 } 112 #endif 113 to_string() const114 std::basic_string<charT, traits> to_string () const { 115 return std::basic_string<charT, traits> ( begin(), end()); 116 } 117 118 // iterators begin() const119 BOOST_CONSTEXPR const_iterator begin() const { return ptr_; } cbegin() const120 BOOST_CONSTEXPR const_iterator cbegin() const { return ptr_; } end() const121 BOOST_CONSTEXPR const_iterator end() const { return ptr_ + len_; } cend() const122 BOOST_CONSTEXPR const_iterator cend() const { return ptr_ + len_; } rbegin() const123 const_reverse_iterator rbegin() const { return const_reverse_iterator (end()); } crbegin() const124 const_reverse_iterator crbegin() const { return const_reverse_iterator (end()); } rend() const125 const_reverse_iterator rend() const { return const_reverse_iterator (begin()); } crend() const126 const_reverse_iterator crend() const { return const_reverse_iterator (begin()); } 127 128 // capacity size() const129 BOOST_CONSTEXPR size_type size() const { return len_; } length() const130 BOOST_CONSTEXPR size_type length() const { return len_; } max_size() const131 BOOST_CONSTEXPR size_type max_size() const { return len_; } empty() const132 BOOST_CONSTEXPR bool empty() const { return len_ == 0; } 133 134 // element access operator [](size_type pos) const135 BOOST_CONSTEXPR const charT& operator[](size_type pos) const { return ptr_[pos]; } 136 at(size_t pos) const137 const charT& at(size_t pos) const { 138 if ( pos >= len_ ) 139 BOOST_THROW_EXCEPTION( std::out_of_range ( "boost::string_ref::at" ) ); 140 return ptr_[pos]; 141 } 142 front() const143 BOOST_CONSTEXPR const charT& front() const { return ptr_[0]; } back() const144 BOOST_CONSTEXPR const charT& back() const { return ptr_[len_-1]; } data() const145 BOOST_CONSTEXPR const charT* data() const { return ptr_; } 146 147 // modifiers clear()148 void clear() { len_ = 0; } remove_prefix(size_type n)149 void remove_prefix(size_type n) { 150 if ( n > len_ ) 151 n = len_; 152 ptr_ += n; 153 len_ -= n; 154 } 155 remove_suffix(size_type n)156 void remove_suffix(size_type n) { 157 if ( n > len_ ) 158 n = len_; 159 len_ -= n; 160 } 161 162 163 // basic_string_ref string operations substr(size_type pos,size_type n=npos) const164 basic_string_ref substr(size_type pos, size_type n=npos) const { 165 if ( pos > size()) 166 BOOST_THROW_EXCEPTION( std::out_of_range ( "string_ref::substr" ) ); 167 return basic_string_ref(data() + pos, (std::min)(size() - pos, n)); 168 } 169 compare(basic_string_ref x) const170 int compare(basic_string_ref x) const { 171 const int cmp = traits::compare ( ptr_, x.ptr_, (std::min)(len_, x.len_)); 172 return cmp != 0 ? cmp : ( len_ == x.len_ ? 0 : len_ < x.len_ ? -1 : 1 ); 173 } 174 starts_with(charT c) const175 bool starts_with(charT c) const { return !empty() && traits::eq ( c, front()); } starts_with(basic_string_ref x) const176 bool starts_with(basic_string_ref x) const { 177 return len_ >= x.len_ && traits::compare ( ptr_, x.ptr_, x.len_ ) == 0; 178 } 179 ends_with(charT c) const180 bool ends_with(charT c) const { return !empty() && traits::eq ( c, back()); } ends_with(basic_string_ref x) const181 bool ends_with(basic_string_ref x) const { 182 return len_ >= x.len_ && traits::compare ( ptr_ + len_ - x.len_, x.ptr_, x.len_ ) == 0; 183 } 184 find(basic_string_ref s) const185 size_type find(basic_string_ref s) const { 186 if (s.empty()) return 0; 187 const_iterator iter = std::search ( this->cbegin (), this->cend (), 188 s.cbegin (), s.cend (), traits::eq ); 189 return iter == this->cend () ? npos : std::distance ( this->cbegin (), iter ); 190 } 191 find(charT c) const192 size_type find(charT c) const { 193 const_iterator iter = std::find_if ( this->cbegin (), this->cend (), 194 detail::string_ref_traits_eq<charT, traits> ( c )); 195 return iter == this->cend () ? npos : std::distance ( this->cbegin (), iter ); 196 } 197 rfind(basic_string_ref s) const198 size_type rfind(basic_string_ref s) const { 199 if (s.empty()) return 0; 200 const_reverse_iterator iter = std::search ( this->crbegin (), this->crend (), 201 s.crbegin (), s.crend (), traits::eq ); 202 return iter == this->crend () ? npos : (std::distance(iter, this->crend()) - s.size()); 203 } 204 rfind(charT c) const205 size_type rfind(charT c) const { 206 const_reverse_iterator iter = std::find_if ( this->crbegin (), this->crend (), 207 detail::string_ref_traits_eq<charT, traits> ( c )); 208 return iter == this->crend () ? npos : (this->size() - 1 - std::distance(this->crbegin(), iter)); 209 } 210 find_first_of(charT c) const211 size_type find_first_of(charT c) const { return find (c); } find_last_of(charT c) const212 size_type find_last_of (charT c) const { return rfind (c); } 213 find_first_of(basic_string_ref s) const214 size_type find_first_of(basic_string_ref s) const { 215 const_iterator iter = std::find_first_of 216 ( this->cbegin (), this->cend (), s.cbegin (), s.cend (), traits::eq ); 217 return iter == this->cend () ? npos : std::distance ( this->cbegin (), iter ); 218 } 219 find_last_of(basic_string_ref s) const220 size_type find_last_of(basic_string_ref s) const { 221 const_reverse_iterator iter = std::find_first_of 222 ( this->crbegin (), this->crend (), s.cbegin (), s.cend (), traits::eq ); 223 return iter == this->crend () ? npos : (this->size() - 1 - std::distance(this->crbegin(), iter)); 224 } 225 find_first_not_of(basic_string_ref s) const226 size_type find_first_not_of(basic_string_ref s) const { 227 const_iterator iter = find_not_of ( this->cbegin (), this->cend (), s ); 228 return iter == this->cend () ? npos : std::distance ( this->cbegin (), iter ); 229 } 230 find_first_not_of(charT c) const231 size_type find_first_not_of(charT c) const { 232 for ( const_iterator iter = this->cbegin (); iter != this->cend (); ++iter ) 233 if ( !traits::eq ( c, *iter )) 234 return std::distance ( this->cbegin (), iter ); 235 return npos; 236 } 237 find_last_not_of(basic_string_ref s) const238 size_type find_last_not_of(basic_string_ref s) const { 239 const_reverse_iterator iter = find_not_of ( this->crbegin (), this->crend (), s ); 240 return iter == this->crend () ? npos : (this->size() - 1 - std::distance(this->crbegin(), iter)); 241 } 242 find_last_not_of(charT c) const243 size_type find_last_not_of(charT c) const { 244 for ( const_reverse_iterator iter = this->crbegin (); iter != this->crend (); ++iter ) 245 if ( !traits::eq ( c, *iter )) 246 return this->size() - 1 - std::distance(this->crbegin(), iter); 247 return npos; 248 } 249 250 private: 251 252 template <typename Iterator> find_not_of(Iterator first,Iterator last,basic_string_ref s) const253 Iterator find_not_of ( Iterator first, Iterator last, basic_string_ref s ) const { 254 for ( ; first != last ; ++first ) 255 if ( 0 == traits::find ( s.ptr_, s.len_, *first )) 256 return first; 257 return last; 258 } 259 260 261 262 const charT *ptr_; 263 std::size_t len_; 264 }; 265 266 267 // Comparison operators 268 // Equality 269 template<typename charT, typename traits> operator ==(basic_string_ref<charT,traits> x,basic_string_ref<charT,traits> y)270 inline bool operator==(basic_string_ref<charT, traits> x, basic_string_ref<charT, traits> y) { 271 if ( x.size () != y.size ()) return false; 272 return x.compare(y) == 0; 273 } 274 275 template<typename charT, typename traits, typename Allocator> operator ==(basic_string_ref<charT,traits> x,const std::basic_string<charT,traits,Allocator> & y)276 inline bool operator==(basic_string_ref<charT, traits> x, const std::basic_string<charT, traits, Allocator> & y) { 277 return x == basic_string_ref<charT, traits>(y); 278 } 279 280 template<typename charT, typename traits, typename Allocator> operator ==(const std::basic_string<charT,traits,Allocator> & x,basic_string_ref<charT,traits> y)281 inline bool operator==(const std::basic_string<charT, traits, Allocator> & x, basic_string_ref<charT, traits> y) { 282 return basic_string_ref<charT, traits>(x) == y; 283 } 284 285 template<typename charT, typename traits> operator ==(basic_string_ref<charT,traits> x,const charT * y)286 inline bool operator==(basic_string_ref<charT, traits> x, const charT * y) { 287 return x == basic_string_ref<charT, traits>(y); 288 } 289 290 template<typename charT, typename traits> operator ==(const charT * x,basic_string_ref<charT,traits> y)291 inline bool operator==(const charT * x, basic_string_ref<charT, traits> y) { 292 return basic_string_ref<charT, traits>(x) == y; 293 } 294 295 // Inequality 296 template<typename charT, typename traits> operator !=(basic_string_ref<charT,traits> x,basic_string_ref<charT,traits> y)297 inline bool operator!=(basic_string_ref<charT, traits> x, basic_string_ref<charT, traits> y) { 298 if ( x.size () != y.size ()) return true; 299 return x.compare(y) != 0; 300 } 301 302 template<typename charT, typename traits, typename Allocator> operator !=(basic_string_ref<charT,traits> x,const std::basic_string<charT,traits,Allocator> & y)303 inline bool operator!=(basic_string_ref<charT, traits> x, const std::basic_string<charT, traits, Allocator> & y) { 304 return x != basic_string_ref<charT, traits>(y); 305 } 306 307 template<typename charT, typename traits, typename Allocator> operator !=(const std::basic_string<charT,traits,Allocator> & x,basic_string_ref<charT,traits> y)308 inline bool operator!=(const std::basic_string<charT, traits, Allocator> & x, basic_string_ref<charT, traits> y) { 309 return basic_string_ref<charT, traits>(x) != y; 310 } 311 312 template<typename charT, typename traits> operator !=(basic_string_ref<charT,traits> x,const charT * y)313 inline bool operator!=(basic_string_ref<charT, traits> x, const charT * y) { 314 return x != basic_string_ref<charT, traits>(y); 315 } 316 317 template<typename charT, typename traits> operator !=(const charT * x,basic_string_ref<charT,traits> y)318 inline bool operator!=(const charT * x, basic_string_ref<charT, traits> y) { 319 return basic_string_ref<charT, traits>(x) != y; 320 } 321 322 // Less than 323 template<typename charT, typename traits> operator <(basic_string_ref<charT,traits> x,basic_string_ref<charT,traits> y)324 inline bool operator<(basic_string_ref<charT, traits> x, basic_string_ref<charT, traits> y) { 325 return x.compare(y) < 0; 326 } 327 328 template<typename charT, typename traits, typename Allocator> operator <(basic_string_ref<charT,traits> x,const std::basic_string<charT,traits,Allocator> & y)329 inline bool operator<(basic_string_ref<charT, traits> x, const std::basic_string<charT, traits, Allocator> & y) { 330 return x < basic_string_ref<charT, traits>(y); 331 } 332 333 template<typename charT, typename traits, typename Allocator> operator <(const std::basic_string<charT,traits,Allocator> & x,basic_string_ref<charT,traits> y)334 inline bool operator<(const std::basic_string<charT, traits, Allocator> & x, basic_string_ref<charT, traits> y) { 335 return basic_string_ref<charT, traits>(x) < y; 336 } 337 338 template<typename charT, typename traits> operator <(basic_string_ref<charT,traits> x,const charT * y)339 inline bool operator<(basic_string_ref<charT, traits> x, const charT * y) { 340 return x < basic_string_ref<charT, traits>(y); 341 } 342 343 template<typename charT, typename traits> operator <(const charT * x,basic_string_ref<charT,traits> y)344 inline bool operator<(const charT * x, basic_string_ref<charT, traits> y) { 345 return basic_string_ref<charT, traits>(x) < y; 346 } 347 348 // Greater than 349 template<typename charT, typename traits> operator >(basic_string_ref<charT,traits> x,basic_string_ref<charT,traits> y)350 inline bool operator>(basic_string_ref<charT, traits> x, basic_string_ref<charT, traits> y) { 351 return x.compare(y) > 0; 352 } 353 354 template<typename charT, typename traits, typename Allocator> operator >(basic_string_ref<charT,traits> x,const std::basic_string<charT,traits,Allocator> & y)355 inline bool operator>(basic_string_ref<charT, traits> x, const std::basic_string<charT, traits, Allocator> & y) { 356 return x > basic_string_ref<charT, traits>(y); 357 } 358 359 template<typename charT, typename traits, typename Allocator> operator >(const std::basic_string<charT,traits,Allocator> & x,basic_string_ref<charT,traits> y)360 inline bool operator>(const std::basic_string<charT, traits, Allocator> & x, basic_string_ref<charT, traits> y) { 361 return basic_string_ref<charT, traits>(x) > y; 362 } 363 364 template<typename charT, typename traits> operator >(basic_string_ref<charT,traits> x,const charT * y)365 inline bool operator>(basic_string_ref<charT, traits> x, const charT * y) { 366 return x > basic_string_ref<charT, traits>(y); 367 } 368 369 template<typename charT, typename traits> operator >(const charT * x,basic_string_ref<charT,traits> y)370 inline bool operator>(const charT * x, basic_string_ref<charT, traits> y) { 371 return basic_string_ref<charT, traits>(x) > y; 372 } 373 374 // Less than or equal to 375 template<typename charT, typename traits> operator <=(basic_string_ref<charT,traits> x,basic_string_ref<charT,traits> y)376 inline bool operator<=(basic_string_ref<charT, traits> x, basic_string_ref<charT, traits> y) { 377 return x.compare(y) <= 0; 378 } 379 380 template<typename charT, typename traits, typename Allocator> operator <=(basic_string_ref<charT,traits> x,const std::basic_string<charT,traits,Allocator> & y)381 inline bool operator<=(basic_string_ref<charT, traits> x, const std::basic_string<charT, traits, Allocator> & y) { 382 return x <= basic_string_ref<charT, traits>(y); 383 } 384 385 template<typename charT, typename traits, typename Allocator> operator <=(const std::basic_string<charT,traits,Allocator> & x,basic_string_ref<charT,traits> y)386 inline bool operator<=(const std::basic_string<charT, traits, Allocator> & x, basic_string_ref<charT, traits> y) { 387 return basic_string_ref<charT, traits>(x) <= y; 388 } 389 390 template<typename charT, typename traits> operator <=(basic_string_ref<charT,traits> x,const charT * y)391 inline bool operator<=(basic_string_ref<charT, traits> x, const charT * y) { 392 return x <= basic_string_ref<charT, traits>(y); 393 } 394 395 template<typename charT, typename traits> operator <=(const charT * x,basic_string_ref<charT,traits> y)396 inline bool operator<=(const charT * x, basic_string_ref<charT, traits> y) { 397 return basic_string_ref<charT, traits>(x) <= y; 398 } 399 400 // Greater than or equal to 401 template<typename charT, typename traits> operator >=(basic_string_ref<charT,traits> x,basic_string_ref<charT,traits> y)402 inline bool operator>=(basic_string_ref<charT, traits> x, basic_string_ref<charT, traits> y) { 403 return x.compare(y) >= 0; 404 } 405 406 template<typename charT, typename traits, typename Allocator> operator >=(basic_string_ref<charT,traits> x,const std::basic_string<charT,traits,Allocator> & y)407 inline bool operator>=(basic_string_ref<charT, traits> x, const std::basic_string<charT, traits, Allocator> & y) { 408 return x >= basic_string_ref<charT, traits>(y); 409 } 410 411 template<typename charT, typename traits, typename Allocator> operator >=(const std::basic_string<charT,traits,Allocator> & x,basic_string_ref<charT,traits> y)412 inline bool operator>=(const std::basic_string<charT, traits, Allocator> & x, basic_string_ref<charT, traits> y) { 413 return basic_string_ref<charT, traits>(x) >= y; 414 } 415 416 template<typename charT, typename traits> operator >=(basic_string_ref<charT,traits> x,const charT * y)417 inline bool operator>=(basic_string_ref<charT, traits> x, const charT * y) { 418 return x >= basic_string_ref<charT, traits>(y); 419 } 420 421 template<typename charT, typename traits> operator >=(const charT * x,basic_string_ref<charT,traits> y)422 inline bool operator>=(const charT * x, basic_string_ref<charT, traits> y) { 423 return basic_string_ref<charT, traits>(x) >= y; 424 } 425 426 // Inserter 427 template<class charT, class traits> 428 inline std::basic_ostream<charT, traits>& operator <<(std::basic_ostream<charT,traits> & os,const basic_string_ref<charT,traits> & str)429 operator<<(std::basic_ostream<charT, traits>& os, const basic_string_ref<charT,traits>& str) { 430 return boost::io::ostream_put(os, str.data(), str.size()); 431 } 432 433 #if 0 434 // numeric conversions 435 // 436 // These are short-term implementations. 437 // In a production environment, I would rather avoid the copying. 438 // 439 inline int stoi (string_ref str, size_t* idx=0, int base=10) { 440 return std::stoi ( std::string(str), idx, base ); 441 } 442 443 inline long stol (string_ref str, size_t* idx=0, int base=10) { 444 return std::stol ( std::string(str), idx, base ); 445 } 446 447 inline unsigned long stoul (string_ref str, size_t* idx=0, int base=10) { 448 return std::stoul ( std::string(str), idx, base ); 449 } 450 451 inline long long stoll (string_ref str, size_t* idx=0, int base=10) { 452 return std::stoll ( std::string(str), idx, base ); 453 } 454 455 inline unsigned long long stoull (string_ref str, size_t* idx=0, int base=10) { 456 return std::stoull ( std::string(str), idx, base ); 457 } 458 459 inline float stof (string_ref str, size_t* idx=0) { 460 return std::stof ( std::string(str), idx ); 461 } 462 463 inline double stod (string_ref str, size_t* idx=0) { 464 return std::stod ( std::string(str), idx ); 465 } 466 467 inline long double stold (string_ref str, size_t* idx=0) { 468 return std::stold ( std::string(str), idx ); 469 } 470 471 inline int stoi (wstring_ref str, size_t* idx=0, int base=10) { 472 return std::stoi ( std::wstring(str), idx, base ); 473 } 474 475 inline long stol (wstring_ref str, size_t* idx=0, int base=10) { 476 return std::stol ( std::wstring(str), idx, base ); 477 } 478 479 inline unsigned long stoul (wstring_ref str, size_t* idx=0, int base=10) { 480 return std::stoul ( std::wstring(str), idx, base ); 481 } 482 483 inline long long stoll (wstring_ref str, size_t* idx=0, int base=10) { 484 return std::stoll ( std::wstring(str), idx, base ); 485 } 486 487 inline unsigned long long stoull (wstring_ref str, size_t* idx=0, int base=10) { 488 return std::stoull ( std::wstring(str), idx, base ); 489 } 490 491 inline float stof (wstring_ref str, size_t* idx=0) { 492 return std::stof ( std::wstring(str), idx ); 493 } 494 495 inline double stod (wstring_ref str, size_t* idx=0) { 496 return std::stod ( std::wstring(str), idx ); 497 } 498 499 inline long double stold (wstring_ref str, size_t* idx=0) { 500 return std::stold ( std::wstring(str), idx ); 501 } 502 #endif 503 504 } 505 506 #if 0 507 namespace std { 508 // Hashing 509 template<> struct hash<boost::string_ref>; 510 template<> struct hash<boost::u16string_ref>; 511 template<> struct hash<boost::u32string_ref>; 512 template<> struct hash<boost::wstring_ref>; 513 } 514 #endif 515 516 #endif 517