string_view.h 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729
  1. #pragma once
  2. #include <c10/macros/Macros.h>
  3. #include <c10/util/C++17.h>
  4. #include <c10/util/reverse_iterator.h>
  5. #include <algorithm>
  6. #include <cstring>
  7. #include <limits>
  8. #include <stdexcept>
  9. #include <string>
  10. #if __cpp_lib_string_view
  11. #include <string_view>
  12. #define C10_HAS_STD_STRING_VIEW() 1
  13. #define C10_HAS_STD_EXPERIMENTAL_STRING_VIEW() 0
  14. #elif defined(__has_include)
  15. #if __has_include(<experimental/string_view>)
  16. // libc++ 7.0 has experimental/string_view but it's just a #error
  17. #if !defined(_LIBCPP_VERSION) || (_LIBCPP_VERSION < 7000)
  18. #include <experimental/string_view>
  19. #endif
  20. #if __cpp_lib_experimental_string_view
  21. #define C10_HAS_STD_STRING_VIEW() 0
  22. #define C10_HAS_STD_EXPERIMENTAL_STRING_VIEW() 1
  23. #endif
  24. #endif
  25. #endif
  26. #ifndef C10_HAS_STD_STRING_VIEW
  27. #define C10_HAS_STD_STRING_VIEW() 0
  28. #endif
  29. #ifndef C10_HAS_STD_EXPERIMENTAL_STRING_VIEW
  30. #define C10_HAS_STD_EXPERIMENTAL_STRING_VIEW() 0
  31. #endif
  32. C10_CLANG_DIAGNOSTIC_PUSH()
  33. #if C10_CLANG_HAS_WARNING("-Wdeprecated")
  34. C10_CLANG_DIAGNOSTIC_IGNORE("-Wdeprecated")
  35. #endif
  36. namespace c10 {
  37. /**
  38. * Reimplementation of std::string_view for C++11.
  39. * Implemented following the interface definition in
  40. * https://en.cppreference.com/w/cpp/string/basic_string_view
  41. * See there for the API documentation.
  42. *
  43. * Difference: We don't have a Traits template parameter because
  44. * std::char_traits isn't constexpr and we'd have to reimplement
  45. * std::char_traits if we wanted to use it with our constexpr basic_string_view.
  46. */
  47. template <class CharT>
  48. class basic_string_view final {
  49. public:
  50. using value_type = CharT;
  51. using pointer = CharT*;
  52. using const_pointer = const CharT*;
  53. using reference = CharT&;
  54. using const_reference = const CharT&;
  55. using const_iterator = const CharT*;
  56. using iterator = const_iterator;
  57. using const_reverse_iterator = c10::reverse_iterator<const_iterator>;
  58. using reverse_iterator = const_reverse_iterator;
  59. using size_type = std::size_t;
  60. using difference_type = std::ptrdiff_t;
  61. static constexpr size_type npos = size_type(-1);
  62. constexpr basic_string_view() noexcept : begin_(nullptr), size_(0) {}
  63. explicit constexpr basic_string_view(const_pointer str, size_type count)
  64. : begin_(str), size_(count) {}
  65. /* implicit */ constexpr basic_string_view(const_pointer str)
  66. : basic_string_view(str, strlen_(str)) {}
  67. /* implicit */ basic_string_view(const ::std::basic_string<CharT>& str)
  68. : basic_string_view(str.data(), str.size()) {}
  69. constexpr basic_string_view(const basic_string_view&) noexcept = default;
  70. constexpr basic_string_view& operator=(
  71. const basic_string_view& rhs) noexcept {
  72. begin_ = rhs.begin_;
  73. size_ = rhs.size_;
  74. return *this;
  75. }
  76. explicit operator ::std::basic_string<CharT>() const {
  77. return ::std::basic_string<CharT>(data(), size());
  78. }
  79. constexpr const_iterator begin() const noexcept {
  80. return cbegin();
  81. }
  82. constexpr const_iterator cbegin() const noexcept {
  83. return begin_;
  84. }
  85. constexpr const_iterator end() const noexcept {
  86. return cend();
  87. }
  88. constexpr const_iterator cend() const noexcept {
  89. return begin_ + size_;
  90. }
  91. constexpr const_reverse_iterator rbegin() const noexcept {
  92. return crbegin();
  93. }
  94. constexpr const_reverse_iterator crbegin() const noexcept {
  95. return const_reverse_iterator(this->end());
  96. }
  97. constexpr const_reverse_iterator rend() const noexcept {
  98. return crend();
  99. }
  100. constexpr const_reverse_iterator crend() const noexcept {
  101. return const_reverse_iterator(this->begin());
  102. }
  103. friend constexpr const_iterator begin(basic_string_view sv) noexcept {
  104. return sv.begin();
  105. }
  106. friend constexpr const_iterator end(basic_string_view sv) noexcept {
  107. return sv.end();
  108. }
  109. constexpr const_reference operator[](size_type pos) const {
  110. // TODO: split out
  111. return at_(pos);
  112. }
  113. constexpr const_reference at(size_type pos) const {
  114. #if !defined( \
  115. __CUDA_ARCH__) // CUDA doesn't like std::out_of_range in device code
  116. return C10_UNLIKELY(pos >= size_)
  117. ? (throw std::out_of_range(
  118. "string_view::operator[] or string_view::at() out of range. Index: " +
  119. c10::guts::to_string(pos) +
  120. ", size: " + c10::guts::to_string(size())),
  121. at_(0))
  122. : at_(pos);
  123. #else
  124. return at_(pos);
  125. #endif
  126. }
  127. constexpr const_reference front() const {
  128. return *begin_;
  129. }
  130. constexpr const_reference back() const {
  131. return *(begin_ + size_ - 1);
  132. }
  133. constexpr const_pointer data() const noexcept {
  134. return begin_;
  135. }
  136. constexpr size_type size() const noexcept {
  137. return size_;
  138. }
  139. constexpr size_type length() const noexcept {
  140. return size();
  141. }
  142. constexpr size_type max_size() const noexcept {
  143. return std::numeric_limits<difference_type>::max();
  144. }
  145. C10_NODISCARD constexpr bool empty() const noexcept {
  146. return size() == 0;
  147. }
  148. constexpr void remove_prefix(size_type n) {
  149. if (n > size()) {
  150. throw std::out_of_range(
  151. "basic_string_view::remove_prefix: out of range. PrefixLength: " +
  152. c10::guts::to_string(n) + ", size: " + c10::guts::to_string(size()));
  153. }
  154. begin_ += n;
  155. size_ -= n;
  156. }
  157. constexpr void remove_suffix(size_type n) {
  158. if (n > size()) {
  159. throw std::out_of_range(
  160. "basic_string_view::remove_suffix: out of range. SuffixLength: " +
  161. c10::guts::to_string(n) + ", size: " + c10::guts::to_string(size()));
  162. }
  163. size_ -= n;
  164. }
  165. constexpr void swap(basic_string_view& sv) noexcept {
  166. auto tmp = *this;
  167. *this = sv;
  168. sv = tmp;
  169. }
  170. size_type copy(pointer dest, size_type count, size_type pos = 0) const {
  171. if (pos > size_) {
  172. throw std::out_of_range(
  173. "basic_string_view::copy: out of range. Index: " +
  174. c10::guts::to_string(pos) +
  175. ", size: " + c10::guts::to_string(size()));
  176. }
  177. size_type copy_length = guts::min(count, size_ - pos);
  178. for (auto iter = begin() + pos, end = iter + copy_length; iter != end;) {
  179. *(dest++) = *(iter++);
  180. }
  181. return copy_length;
  182. }
  183. constexpr basic_string_view substr(size_type pos = 0, size_type count = npos)
  184. const {
  185. #if !defined( \
  186. __CUDA_ARCH__) // CUDA doesn't like std::out_of_range in device code
  187. return (pos > size_)
  188. ? (throw std::out_of_range(
  189. "basic_string_view::substr parameter out of bounds. Index: " +
  190. c10::guts::to_string(pos) +
  191. ", size: " + c10::guts::to_string(size())),
  192. substr_())
  193. : substr_(pos, count);
  194. #else
  195. return substr_(pos, count);
  196. #endif
  197. }
  198. constexpr int compare(basic_string_view rhs) const noexcept {
  199. #if __cpp_constexpr >= 201304
  200. // if we are in C++14, write it iteratively. This is faster.
  201. for (size_t i = 0, end = guts::min(size(), rhs.size()); i < end; ++i) {
  202. if (at_(i) < rhs.at_(i)) {
  203. return -1;
  204. } else if (at_(i) > rhs.at_(i)) {
  205. return 1;
  206. }
  207. }
  208. if (size() < rhs.size()) {
  209. return -1;
  210. } else if (size() > rhs.size()) {
  211. return 1;
  212. }
  213. return 0;
  214. #else
  215. // if we are in C++11, we need to do it recursively because of constexpr
  216. // restrictions.
  217. return (size() == 0 && rhs.size() == 0) ? 0
  218. : (size() == 0) ? -1
  219. : (rhs.size() == 0) ? 1
  220. : (front() < rhs.front()) ? -1
  221. : (front() > rhs.front()) ? 1
  222. : substr_(1).compare(rhs.substr_(1));
  223. #endif
  224. }
  225. constexpr int compare(size_type pos1, size_type count1, basic_string_view v)
  226. const {
  227. return substr(pos1, count1).compare(v);
  228. }
  229. constexpr int compare(
  230. size_type pos1,
  231. size_type count1,
  232. basic_string_view v,
  233. size_type pos2,
  234. size_type count2) const {
  235. return substr(pos1, count1).compare(v.substr(pos2, count2));
  236. }
  237. constexpr int compare(const_pointer s) const {
  238. return compare(basic_string_view(s));
  239. }
  240. constexpr int compare(size_type pos1, size_type count1, const_pointer s)
  241. const {
  242. return substr(pos1, count1).compare(basic_string_view(s));
  243. }
  244. constexpr int compare(
  245. size_type pos1,
  246. size_type count1,
  247. const_pointer s,
  248. size_type count2) const {
  249. return substr(pos1, count1).compare(basic_string_view(s, count2));
  250. }
  251. friend constexpr bool operator==(
  252. basic_string_view lhs,
  253. basic_string_view rhs) noexcept {
  254. return lhs.equals_(rhs);
  255. }
  256. friend constexpr bool operator!=(
  257. basic_string_view lhs,
  258. basic_string_view rhs) noexcept {
  259. return !(lhs == rhs);
  260. }
  261. friend constexpr bool operator<(
  262. basic_string_view lhs,
  263. basic_string_view rhs) noexcept {
  264. return lhs.compare(rhs) < 0;
  265. }
  266. friend constexpr bool operator>=(
  267. basic_string_view lhs,
  268. basic_string_view rhs) noexcept {
  269. return !(lhs < rhs);
  270. }
  271. friend constexpr bool operator>(
  272. basic_string_view lhs,
  273. basic_string_view rhs) noexcept {
  274. return rhs < lhs;
  275. }
  276. friend constexpr bool operator<=(
  277. basic_string_view lhs,
  278. basic_string_view rhs) noexcept {
  279. return !(lhs > rhs);
  280. }
  281. constexpr bool starts_with(basic_string_view prefix) const noexcept {
  282. return (prefix.size() > size()) ? false
  283. : prefix.equals_(substr_(0, prefix.size()));
  284. }
  285. constexpr bool starts_with(CharT prefix) const noexcept {
  286. return !empty() && prefix == front();
  287. }
  288. constexpr bool starts_with(const_pointer prefix) const {
  289. return starts_with(basic_string_view(prefix));
  290. }
  291. constexpr bool ends_with(basic_string_view suffix) const noexcept {
  292. return (suffix.size() > size())
  293. ? false
  294. : suffix.equals_(substr_(size() - suffix.size(), suffix.size()));
  295. }
  296. constexpr bool ends_with(CharT suffix) const noexcept {
  297. return !empty() && suffix == back();
  298. }
  299. constexpr bool ends_with(const_pointer suffix) const {
  300. return ends_with(basic_string_view(suffix));
  301. }
  302. constexpr size_type find(basic_string_view v, size_type pos = 0)
  303. const noexcept {
  304. #if __cpp_constexpr >= 201304
  305. // if we are in C++14, write it iteratively. This is faster.
  306. if (v.size() == 0) {
  307. return pos <= size() ? pos : npos;
  308. }
  309. if (pos + v.size() <= size()) {
  310. for (size_type cur = pos, end = size() - v.size(); cur <= end; ++cur) {
  311. if (v.at_(0) == at_(cur) &&
  312. v.substr_(1).equals_(substr_(cur + 1, v.size() - 1))) {
  313. return cur;
  314. }
  315. }
  316. }
  317. return npos;
  318. #else
  319. // if we are in C++11, we need to do it recursively because of constexpr
  320. // restrictions.
  321. return (v.size() == 0) ? (pos <= size() ? pos : npos)
  322. : (pos + v.size() > size()) ? npos
  323. : (v.at_(0) == at_(pos) &&
  324. v.substr_(1).equals_(substr_(pos + 1, v.size() - 1)))
  325. ? pos
  326. : find(v, pos + 1);
  327. #endif
  328. }
  329. constexpr size_type find(CharT ch, size_type pos = 0) const noexcept {
  330. return find_first_if_(pos, charIsEqual_{ch});
  331. }
  332. constexpr size_type find(const_pointer s, size_type pos, size_type count)
  333. const {
  334. return find(basic_string_view(s, count), pos);
  335. }
  336. constexpr size_type find(const_pointer s, size_type pos = 0) const {
  337. return find(basic_string_view(s), pos);
  338. }
  339. constexpr size_type rfind(basic_string_view v, size_type pos = npos)
  340. const noexcept {
  341. #if __cpp_constexpr >= 201304
  342. // if we are in C++14, write it iteratively. This is faster.
  343. if (v.size() == 0) {
  344. return pos <= size() ? pos : size();
  345. }
  346. if (v.size() <= size()) {
  347. pos = guts::min(size() - v.size(), pos);
  348. do {
  349. if (v.at_(0) == at_(pos) &&
  350. v.substr_(1).equals_(substr_(pos + 1, v.size() - 1))) {
  351. return pos;
  352. }
  353. } while (pos-- > 0);
  354. }
  355. return npos;
  356. #else
  357. // if we are in C++11, we need to do it recursively because of constexpr
  358. // restrictions.
  359. return (v.size() == 0) ? (pos <= size() ? pos : size())
  360. : (v.size() > size()) ? npos
  361. : (size() - v.size() < pos) ? rfind(v, size() - v.size())
  362. : (v.at_(0) == at_(pos) &&
  363. v.substr_(1).equals_(substr_(pos + 1, v.size() - 1)))
  364. ? pos
  365. : (pos == 0) ? npos
  366. : rfind(v, pos - 1);
  367. #endif
  368. }
  369. constexpr size_type rfind(CharT ch, size_type pos = npos) const noexcept {
  370. return find_last_if_(pos, charIsEqual_{ch});
  371. }
  372. constexpr size_type rfind(const_pointer s, size_type pos, size_type count)
  373. const {
  374. return rfind(basic_string_view(s, count), pos);
  375. }
  376. constexpr size_type rfind(const_pointer s, size_type pos = npos) const {
  377. return rfind(basic_string_view(s), pos);
  378. }
  379. constexpr size_type find_first_of(basic_string_view v, size_type pos = 0)
  380. const noexcept {
  381. return find_first_if_(pos, stringViewContainsChar_{v});
  382. }
  383. constexpr size_type find_first_of(CharT ch, size_type pos = 0)
  384. const noexcept {
  385. return find_first_if_(pos, charIsEqual_{ch});
  386. }
  387. constexpr size_type find_first_of(
  388. const_pointer s,
  389. size_type pos,
  390. size_type count) const {
  391. return find_first_of(basic_string_view(s, count), pos);
  392. }
  393. constexpr size_type find_first_of(const_pointer s, size_type pos = 0) const {
  394. return find_first_of(basic_string_view(s), pos);
  395. }
  396. constexpr size_type find_last_of(basic_string_view v, size_type pos = npos)
  397. const noexcept {
  398. return find_last_if_(pos, stringViewContainsChar_{v});
  399. }
  400. constexpr size_type find_last_of(CharT ch, size_type pos = npos)
  401. const noexcept {
  402. return find_last_if_(pos, charIsEqual_{ch});
  403. }
  404. constexpr size_type find_last_of(
  405. const_pointer s,
  406. size_type pos,
  407. size_type count) const {
  408. return find_last_of(basic_string_view(s, count), pos);
  409. }
  410. constexpr size_type find_last_of(const_pointer s, size_type pos = npos)
  411. const {
  412. return find_last_of(basic_string_view(s), pos);
  413. }
  414. constexpr size_type find_first_not_of(basic_string_view v, size_type pos = 0)
  415. const noexcept {
  416. return find_first_if_(pos, stringViewDoesNotContainChar_{v});
  417. }
  418. constexpr size_type find_first_not_of(CharT ch, size_type pos = 0)
  419. const noexcept {
  420. return find_first_if_(pos, charIsNotEqual_{ch});
  421. }
  422. constexpr size_type find_first_not_of(
  423. const_pointer s,
  424. size_type pos,
  425. size_type count) const {
  426. return find_first_not_of(basic_string_view(s, count), pos);
  427. }
  428. constexpr size_type find_first_not_of(const_pointer s, size_type pos = 0)
  429. const {
  430. return find_first_not_of(basic_string_view(s), pos);
  431. }
  432. constexpr size_type find_last_not_of(
  433. basic_string_view v,
  434. size_type pos = npos) const noexcept {
  435. return find_last_if_(pos, stringViewDoesNotContainChar_{v});
  436. }
  437. constexpr size_type find_last_not_of(CharT ch, size_type pos = npos)
  438. const noexcept {
  439. return find_last_if_(pos, charIsNotEqual_{ch});
  440. }
  441. constexpr size_type find_last_not_of(
  442. const_pointer s,
  443. size_type pos,
  444. size_type count) const {
  445. return find_last_not_of(basic_string_view(s, count), pos);
  446. }
  447. constexpr size_type find_last_not_of(const_pointer s, size_type pos = npos)
  448. const {
  449. return find_last_not_of(basic_string_view(s), pos);
  450. }
  451. private:
  452. static constexpr size_type strlen_(const_pointer str) noexcept {
  453. #if __cpp_constexpr >= 201304
  454. // if we are in C++14, write it iteratively. This is faster.
  455. const_pointer current = str;
  456. while (*current != '\0') {
  457. ++current;
  458. }
  459. return current - str;
  460. #else
  461. // if we are in C++11, we need to do it recursively because of constexpr
  462. // restrictions.
  463. return (*str == '\0') ? 0 : 1 + strlen_(str + 1);
  464. #endif
  465. }
  466. constexpr const_reference at_(size_type pos) const noexcept {
  467. return *(begin_ + pos);
  468. }
  469. constexpr basic_string_view substr_(size_type pos = 0, size_type count = npos)
  470. const {
  471. return basic_string_view{begin_ + pos, guts::min(count, size() - pos)};
  472. }
  473. template <class Condition>
  474. constexpr size_type find_first_if_(size_type pos, Condition&& condition)
  475. const noexcept {
  476. #if __cpp_constexpr >= 201304
  477. // if we are in C++14, write it iteratively. This is faster.
  478. if (pos + 1 <= size()) {
  479. for (size_type cur = pos; cur < size(); ++cur) {
  480. if (condition(at_(cur))) {
  481. return cur;
  482. }
  483. }
  484. }
  485. return npos;
  486. #else
  487. // if we are in C++11, we need to do it recursively because of constexpr
  488. // restrictions.
  489. return (pos + 1 > size()) ? npos
  490. : condition(at_(pos))
  491. ? pos
  492. : find_first_if_(pos + 1, std::forward<Condition>(condition));
  493. #endif
  494. }
  495. template <class Condition>
  496. constexpr size_type find_last_if_(size_type pos, Condition&& condition)
  497. const noexcept {
  498. #if __cpp_constexpr >= 201304
  499. // if we are in C++14, write it iteratively. This is faster.
  500. if (size() > 0) {
  501. pos = guts::min(size() - 1, pos);
  502. do {
  503. if (condition(at_(pos))) {
  504. return pos;
  505. }
  506. } while (pos-- > 0);
  507. }
  508. return npos;
  509. #else
  510. // if we are in C++11, we need to do it recursively because of constexpr
  511. // restrictions.
  512. return (size() == 0) ? npos
  513. : (pos >= size())
  514. ? find_last_if_(size() - 1, std::forward<Condition>(condition))
  515. : condition(at_(pos)) ? pos
  516. : (pos == 0)
  517. ? npos
  518. : find_last_if_(pos - 1, std::forward<Condition>(condition));
  519. #endif
  520. }
  521. constexpr bool equals_(basic_string_view rhs) const {
  522. // We don't use string_view::compare() here but implement it manually
  523. // because only looking at equality allows for more optimized code.
  524. #if defined(__GNUC__) && !defined(__CUDACC__)
  525. return size() == rhs.size() &&
  526. 0 == __builtin_memcmp(data(), rhs.data(), size());
  527. #elif __cpp_constexpr >= 201304
  528. // if we are in C++14, write it iteratively. This is faster than the
  529. // recursive C++11 implementation below.
  530. if (size() != rhs.size()) {
  531. return false;
  532. }
  533. // Yes, memcmp would be laster than this loop, but memcmp isn't constexpr
  534. // and I didn't feel like implementing a constexpr memcmp variant.
  535. // TODO At some point this should probably be done, including tricks
  536. // like comparing one machine word instead of a byte per iteration.
  537. for (typename basic_string_view<CharT>::size_type pos = 0; pos < size();
  538. ++pos) {
  539. if (at_(pos) != rhs.at_(pos)) {
  540. return false;
  541. }
  542. }
  543. return true;
  544. #else
  545. // if we are in C++11, we need to do it recursively because of constexpr
  546. // restrictions.
  547. return (size() != rhs.size()) ? false
  548. : (size() == 0) ? true
  549. : (front() != rhs.front()) ? false
  550. : (substr_(1).equals_(rhs.substr_(1)));
  551. #endif
  552. }
  553. struct charIsEqual_ final {
  554. CharT expected;
  555. constexpr bool operator()(CharT actual) const noexcept {
  556. return expected == actual;
  557. }
  558. };
  559. struct charIsNotEqual_ final {
  560. CharT expected;
  561. constexpr bool operator()(CharT actual) const noexcept {
  562. return expected != actual;
  563. }
  564. };
  565. struct stringViewContainsChar_ final {
  566. basic_string_view expected;
  567. constexpr bool operator()(CharT ch) const noexcept {
  568. return npos != expected.find(ch);
  569. }
  570. };
  571. struct stringViewDoesNotContainChar_ final {
  572. basic_string_view expected;
  573. constexpr bool operator()(CharT ch) const noexcept {
  574. return npos == expected.find(ch);
  575. }
  576. };
  577. const_pointer begin_;
  578. size_type size_{};
  579. };
  580. template <class CharT>
  581. const typename basic_string_view<CharT>::size_type
  582. basic_string_view<CharT>::npos;
  583. template <class CharT>
  584. inline std::basic_ostream<CharT>& operator<<(
  585. std::basic_ostream<CharT>& stream,
  586. basic_string_view<CharT> sv) {
  587. // The rules for operator<< are quite complex, so lets defer to the
  588. // STL implementation. The std::string fallback might be a bit
  589. // slower, but is better than getting it wrong.
  590. #if C10_HAS_STD_STRING_VIEW()
  591. using std_string_type = ::std::basic_string_view<CharT>;
  592. #elif C10_HAS_STD_EXPERIMENTAL_STRING_VIEW()
  593. using std_string_type = ::std::experimental::basic_string_view<CharT>;
  594. #else
  595. using std_string_type = ::std::basic_string<CharT>;
  596. #endif
  597. return stream << std_string_type(sv.data(), sv.size());
  598. }
  599. template <class CharT>
  600. constexpr inline void swap(
  601. basic_string_view<CharT>& lhs,
  602. basic_string_view<CharT>& rhs) {
  603. lhs.swap(rhs);
  604. }
  605. using string_view = basic_string_view<char>;
  606. } // namespace c10
  607. namespace std {
  608. template <class CharT>
  609. struct hash<::c10::basic_string_view<CharT>> {
  610. size_t operator()(::c10::basic_string_view<CharT> x) const {
  611. // The standard says that std""string_view hashing must do the same as
  612. // std::string hashing but leaves the details of std::string hashing
  613. // up to the implementer. So, to be conformant, we need to re-use and
  614. // existing STL type's hash function. The std::string fallback is probably
  615. // slow but the only way to be conformant.
  616. #if C10_HAS_STD_STRING_VIEW()
  617. using std_string_type = ::std::basic_string_view<CharT>;
  618. #elif C10_HAS_STD_EXPERIMENTAL_STRING_VIEW()
  619. using std_string_type = ::std::experimental::basic_string_view<CharT>;
  620. #else
  621. using std_string_type = ::std::basic_string<CharT>;
  622. #endif
  623. return ::std::hash<std_string_type>{}(std_string_type(x.data(), x.size()));
  624. }
  625. };
  626. } // namespace std
  627. C10_CLANG_DIAGNOSTIC_POP()