MongoDB C++ Driver  mongocxx-3.10.2
All Classes Namespaces Functions Typedefs Enumerations Enumerator Friends Pages
string_view.hpp
1 // Copyright 2023 MongoDB Inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #pragma once
16 
17 #include <bsoncxx/config/prelude.hpp>
18 
19 #if defined(BSONCXX_POLY_USE_MNMLSTC)
20 
21 #include <core/string.hpp>
22 
23 namespace bsoncxx {
24 namespace v_noabi {
25 namespace stdx {
26 
27 using ::core::basic_string_view;
28 using ::core::string_view;
29 
30 } // namespace stdx
31 } // namespace v_noabi
32 } // namespace bsoncxx
33 
34 #elif defined(BSONCXX_POLY_USE_BOOST)
35 
36 #include <boost/version.hpp>
37 
38 #if BOOST_VERSION >= 106100
39 
40 #include <boost/utility/string_view.hpp>
41 
42 namespace bsoncxx {
43 namespace v_noabi {
44 namespace stdx {
45 
46 using ::boost::basic_string_view;
47 using ::boost::string_view;
48 
49 } // namespace stdx
50 } // namespace v_noabi
51 } // namespace bsoncxx
52 
53 #else
54 
55 #include <boost/utility/string_ref.hpp>
56 
57 namespace bsoncxx {
58 namespace v_noabi {
59 namespace stdx {
60 
61 template <typename charT, typename traits = std::char_traits<charT>>
62 using basic_string_view = ::boost::basic_string_ref<charT, traits>;
63 using string_view = ::boost::string_ref;
64 
65 } // namespace stdx
66 } // namespace v_noabi
67 } // namespace bsoncxx
68 
69 #endif
70 
71 #elif defined(BSONCXX_POLY_USE_STD_EXPERIMENTAL)
72 
73 #include <experimental/string_view>
74 
75 namespace bsoncxx {
76 namespace v_noabi {
77 namespace stdx {
78 
79 using ::std::experimental::basic_string_view;
80 using ::std::experimental::string_view;
81 
82 } // namespace stdx
83 } // namespace v_noabi
84 } // namespace bsoncxx
85 
86 #elif defined(BSONCXX_POLY_USE_STD)
87 
88 #include <string_view>
89 
90 namespace bsoncxx {
91 namespace v_noabi {
92 namespace stdx {
93 
94 using ::std::basic_string_view;
95 using ::std::string_view;
96 
97 } // namespace stdx
98 } // namespace v_noabi
99 } // namespace bsoncxx
100 
101 #elif defined(BSONCXX_POLY_USE_IMPLS)
102 
103 #include <algorithm>
104 #include <cstddef>
105 #include <ios>
106 #include <limits>
107 #include <stdexcept>
108 #include <string>
109 #include <utility>
110 
111 #include <bsoncxx/stdx/operators.hpp>
112 #include <bsoncxx/stdx/type_traits.hpp>
113 
114 namespace bsoncxx {
115 namespace v_noabi {
116 namespace stdx {
117 
121 template <typename Char, typename Traits = std::char_traits<Char>>
122 class basic_string_view : bsoncxx::detail::equality_operators, bsoncxx::detail::ordering_operators {
123  public:
124  // Pointer to (non-const) character type
125  using pointer = Char*;
126  // Pointer to const-character type
127  using const_pointer = const Char*;
128  // Type representing the size of a string
129  using size_type = std::size_t;
130  // Type representing the offset within a string
131  using difference_type = std::ptrdiff_t;
132  // The type of the string character
133  using value_type = Char;
134 
135  // Constant sentinel value to represent an impossible/invalid string position
136  static constexpr size_type npos = static_cast<size_type>(-1);
137 
138  private:
139  // Pointer to the beginning of the string being viewed
140  const_pointer _begin = nullptr;
141  // The size of the array that is being viewed via `_begin`
142  size_type _size = 0;
143 
144  public:
145  using traits_type = Traits;
146  using reference = Char&;
147  using const_reference = const Char&;
148  using const_iterator = const_pointer;
149  using iterator = const_iterator;
150  using const_reverse_iterator = std::reverse_iterator<const_iterator>;
151  using reverse_iterator = const_reverse_iterator;
152 
156  constexpr basic_string_view() noexcept = default;
157  constexpr basic_string_view(const basic_string_view&) noexcept = default;
158  bsoncxx_cxx14_constexpr basic_string_view& operator=(const basic_string_view&) noexcept =
159  default;
160 
165  constexpr basic_string_view(const_pointer s, size_type count) : _begin(s), _size(count) {}
166 
172  constexpr basic_string_view(const_pointer s) : _begin(s), _size(traits_type::length(s)) {}
173 
180  template <typename Alloc>
181  constexpr basic_string_view(
182  const std::basic_string<value_type, traits_type, Alloc>& str) noexcept
183  : _begin(str.data()), _size(str.size()) {}
184 
185 #if __cpp_lib_string_view
186  constexpr basic_string_view(std::basic_string_view<value_type, traits_type> sv) noexcept
187  : _begin(sv.data()), _size(sv.size()) {}
188 #endif
189 
190  // Construction from a null pointer is deleted
191  basic_string_view(std::nullptr_t) = delete;
192 
193  constexpr const_iterator begin() const noexcept {
194  return const_iterator(_begin);
195  }
196  constexpr const_iterator end() const noexcept {
197  return begin() + size();
198  }
199  constexpr const_iterator cbegin() const noexcept {
200  return begin();
201  }
202  constexpr const_iterator cend() const noexcept {
203  return end();
204  }
205 
206  constexpr const_reverse_iterator rbegin() const noexcept {
207  return const_reverse_iterator{end()};
208  }
209 
210  constexpr const_reverse_iterator rend() const noexcept {
211  return const_reverse_iterator{begin()};
212  }
213 
214  constexpr const_reverse_iterator crbegin() const noexcept {
215  return const_reverse_iterator{cend()};
216  }
217 
218  constexpr const_reverse_iterator crend() const noexcept {
219  return const_reverse_iterator{crbegin()};
220  }
221 
228  constexpr const_reference operator[](size_type offset) const {
229  return _begin[offset];
230  }
231 
238  bsoncxx_cxx14_constexpr const_reference at(size_type pos) const {
239  if (pos >= size()) {
240  throw std::out_of_range{"bsoncxx::stdx::basic_string_view::at()"};
241  }
242  return _begin[pos];
243  }
245  constexpr const_reference front() const {
246  return (*this)[0];
247  }
249  constexpr const_reference back() const {
250  return (*this)[size() - 1];
251  }
252 
254  constexpr const_pointer data() const noexcept {
255  return _begin;
256  }
258  constexpr size_type size() const noexcept {
259  return _size;
260  }
262  constexpr size_type length() const noexcept {
263  return size();
264  }
266  constexpr bool empty() const noexcept {
267  return size() == 0;
268  }
270  constexpr size_type max_size() const noexcept {
271  return static_cast<size_type>(std::numeric_limits<difference_type>::max());
272  }
273 
279  bsoncxx_cxx14_constexpr void remove_prefix(size_type n) {
280  _begin += n;
281  _size -= n;
282  }
283 
289  bsoncxx_cxx14_constexpr void remove_suffix(size_type n) {
290  _size -= n;
291  }
292 
296  bsoncxx_cxx14_constexpr void swap(basic_string_view& other) {
297  std::swap(_begin, other._begin);
298  std::swap(_size, other._size);
299  }
300 
312  size_type copy(pointer dest, size_type count, size_type pos = 0) const {
313  if (pos > size()) {
314  throw std::out_of_range{"bsoncxx::stdx::basic_string_view::substr()"};
315  }
316  count = (std::min)(count, size() - pos);
317  Traits::copy(dest, data() + pos, count);
318  return count;
319  }
320 
330  bsoncxx_cxx14_constexpr basic_string_view substr(size_type pos = 0,
331  size_type count = npos) const {
332  if (pos > size()) {
333  throw std::out_of_range{"bsoncxx::stdx::basic_string_view::substr()"};
334  }
335  return basic_string_view(_begin + pos, (std::min)(count, size() - pos));
336  }
337 
346  constexpr int compare(basic_string_view other) const noexcept {
347  // Another level of indirection to support restricted C++11 constexpr
348  return _compare2(Traits::compare(data(), other.data(), (std::min)(size(), other.size())),
349  other);
350  }
351 
357  constexpr int compare(const_pointer cstr) const {
358  return compare(basic_string_view(cstr));
359  }
360 
366  constexpr int compare(size_type pos1, size_type count1, basic_string_view other) const {
367  return substr(pos1, count1).compare(other);
368  }
369 
375  constexpr int compare(size_type pos1, size_type count1, const_pointer cstr) const {
376  return compare(pos1, count1, basic_string_view(cstr));
377  }
378 
384  constexpr int compare(size_type pos1,
385  size_type count1,
386  basic_string_view other,
387  size_type pos2,
388  size_type count2) const {
389  return substr(pos1, count1).compare(other.substr(pos2, count2));
390  }
391 
397  constexpr int compare(size_type pos1,
398  size_type count1,
399  const_pointer str,
400  size_type count2) const {
401  return substr(pos1, count1).compare(basic_string_view(str, count2));
402  }
403 
408  bsoncxx_cxx14_constexpr size_type find(basic_string_view infix, size_type pos = 0) const
409  noexcept {
410  if (pos > size()) {
411  return npos;
412  }
413  basic_string_view sub = this->substr(pos);
414  if (infix.empty()) {
415  // The empty string is always "present" at the beginning of any string
416  return pos;
417  }
418  const_iterator found = std::search(sub.begin(), sub.end(), infix.begin(), infix.end());
419  if (found == sub.end()) {
420  return npos;
421  }
422  return static_cast<size_type>(found - begin());
423  }
424 
429  bsoncxx_cxx14_constexpr size_type rfind(basic_string_view infix, size_type pos = npos) const
430  noexcept {
431  // Calc the endpos where searching should begin, which includes the infix size
432  const size_type substr_size = pos != npos ? pos + infix.size() : pos;
433  if (infix.empty()) {
434  return (std::min)(pos, size());
435  }
436  basic_string_view searched = this->substr(0, substr_size);
437  auto f = std::search(searched.rbegin(), searched.rend(), infix.rbegin(), infix.rend());
438  if (f == searched.rend()) {
439  return npos;
440  }
441  return static_cast<size_type>(rend() - f) - infix.size();
442  }
443 
448  constexpr size_type find_first_of(basic_string_view set, size_type pos = 0) const noexcept {
449  return _find_if(pos, [&](value_type chr) { return set.find(chr) != npos; });
450  }
451 
456  constexpr size_type find_last_of(basic_string_view set, size_type pos = npos) const noexcept {
457  return _rfind_if(pos, [&](value_type chr) { return set.find(chr) != npos; });
458  }
459 
464  constexpr size_type find_first_not_of(basic_string_view set, size_type pos = 0) const noexcept {
465  return _find_if(pos, [&](value_type chr) { return set.find(chr) == npos; });
466  }
467 
472  constexpr size_type find_last_not_of(basic_string_view set, size_type pos = npos) const
473  noexcept {
474  return _rfind_if(pos, [&](value_type chr) { return set.find(chr) == npos; });
475  }
476 
477 #pragma push_macro("DECL_FINDERS")
478 #undef DECL_FINDERS
479 #define DECL_FINDERS(Name, DefaultPos) \
480  constexpr size_type Name(value_type chr, size_type pos = DefaultPos) const noexcept { \
481  return Name(basic_string_view(&chr, 1), pos); \
482  } \
483  constexpr size_type Name(const_pointer cstr, size_type pos, size_type count) const { \
484  return Name(basic_string_view(cstr, count), pos); \
485  } \
486  constexpr size_type Name(const_pointer cstr, size_type pos = DefaultPos) const { \
487  return Name(basic_string_view(cstr), pos); \
488  } \
489  BSONCXX_FORCE_SEMICOLON
490  DECL_FINDERS(find, 0);
491  DECL_FINDERS(rfind, npos);
492  DECL_FINDERS(find_first_of, 0);
493  DECL_FINDERS(find_last_of, npos);
494  DECL_FINDERS(find_first_not_of, 0);
495  DECL_FINDERS(find_last_not_of, npos);
496 #pragma pop_macro("DECL_FINDERS")
497 
501  template <typename Allocator>
502  explicit operator std::basic_string<Char, Traits, Allocator>() const {
503  return std::basic_string<Char, Traits, Allocator>(data(), size());
504  }
505 
506 #if __cpp_lib_string_view
507  explicit operator std::basic_string_view<value_type, traits_type>() const noexcept {
508  return std::basic_string_view<value_type, traits_type>(data(), size());
509  }
510 #endif
511 
512  private:
513  // Additional level-of-indirection for constexpr compare()
514  constexpr int _compare2(int diff, basic_string_view other) const noexcept {
515  // "diff" is the diff according to Traits::cmp
516  return diff ? diff : static_cast<int>(size() - other.size());
517  }
518 
519  // Implementation of equality comparison
520  constexpr friend bool tag_invoke(bsoncxx::detail::equal_to,
521  basic_string_view left,
522  basic_string_view right) noexcept {
523  return left.size() == right.size() && left.compare(right) == 0;
524  }
525 
526  // Implementation of a three-way-comparison
527  constexpr friend bsoncxx::detail::strong_ordering tag_invoke(
528  bsoncxx::detail::compare_three_way cmp,
529  basic_string_view left,
530  basic_string_view right) noexcept {
531  return cmp(left.compare(right), 0);
532  }
533 
534  friend std::basic_ostream<Char, Traits>& operator<<(std::basic_ostream<Char, Traits>& out,
535  basic_string_view self) {
536  out << std::basic_string<Char, Traits>(self);
537  return out;
538  }
539 
540  // Find the first in-bounds index I in [pos, size()) where the given predicate
541  // returns true for substr(I). If no index exists, returns npos
542  template <typename F>
543  bsoncxx_cxx14_constexpr size_type _find_if(size_type pos, F pred) const noexcept {
544  const auto sub = substr(pos);
545  const iterator found = std::find_if(sub.begin(), sub.end(), pred);
546  if (found == end()) {
547  return npos;
548  }
549  return static_cast<size_type>(found - begin());
550  }
551 
552  // Find the LAST index I in [0, pos] where the given predicate returns true for
553  // substr(0, I). If no such index exists, returns npos.
554  template <typename F>
555  bsoncxx_cxx14_constexpr size_type _rfind_if(size_type pos, F pred) const noexcept {
556  // Adjust 'pos' for an inclusive range in substr()
557  const auto rpos = pos == npos ? npos : pos + 1;
558  // The substring that will be searched:
559  const auto prefix = substr(0, rpos);
560  const const_reverse_iterator found = std::find_if(prefix.rbegin(), prefix.rend(), pred);
561  if (found == rend()) {
562  return npos;
563  }
564  // Adjust by 1 to account for reversed-ness
565  return static_cast<size_type>(rend() - found) - 1u;
566  }
567 };
568 
569 // Required to define this here for C++≤14 compatibility. Can be removed in C++≥17
570 template <typename C, typename Tr>
571 const std::size_t basic_string_view<C, Tr>::npos;
572 
573 using string_view = basic_string_view<char>;
574 
575 } // namespace stdx
576 } // namespace v_noabi
577 } // namespace bsoncxx
578 
579 namespace std {
580 
581 template <typename CharT, typename Traits>
582 struct hash<bsoncxx::v_noabi::stdx::basic_string_view<CharT, Traits>>
583  : private std::hash<std::basic_string<CharT, Traits>> {
584  std::size_t operator()(
585  const bsoncxx::v_noabi::stdx::basic_string_view<CharT, Traits>& str) const {
586  return std::hash<std::basic_string<CharT, Traits>>::operator()(
587  std::basic_string<CharT, Traits>(str.data(), str.size()));
588  }
589 };
590 
591 } // namespace std
592 
593 #else
594 #error "Cannot find a valid polyfill for string_view"
595 #endif
596 
597 #include <bsoncxx/config/postlude.hpp>
598 
599 namespace bsoncxx {
600 namespace stdx {
601 
602 using ::bsoncxx::v_noabi::stdx::basic_string_view;
603 using ::bsoncxx::v_noabi::stdx::string_view;
604 
605 } // namespace stdx
606 } // namespace bsoncxx
The top-level namespace for bsoncxx library entities.
Definition: element-fwd.hpp:19