MongoDB C++ Driver 4.2.0
Loading...
Searching...
No Matches
string_view.hpp
Go to the documentation of this file.
1// Copyright 2009-present 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
18
20
21#if defined(BSONCXX_POLY_USE_STD)
22
23#include <string_view>
24
25namespace bsoncxx {
26namespace v1 {
27namespace stdx {
28
29using std::basic_string_view;
30using std::string_view;
31
32} // namespace stdx
33} // namespace v1
34} // namespace bsoncxx
35
36#elif defined(BSONCXX_POLY_USE_IMPLS)
37
40
41#include <algorithm>
42#include <cstddef>
43#include <functional>
44#include <iterator>
45#include <limits>
46#include <ostream>
47#include <stdexcept>
48#include <string>
49#include <utility>
50
51namespace bsoncxx {
52namespace v1 {
53namespace stdx {
54
55template <typename Char, typename Traits = std::char_traits<Char>>
56class basic_string_view : bsoncxx::detail::equality_operators, bsoncxx::detail::ordering_operators {
57 public:
58 using pointer = Char*;
59 using const_pointer = Char const*;
60 using size_type = std::size_t;
61 using difference_type = std::ptrdiff_t;
62 using value_type = Char;
63
64 // Constant sentinel value to represent an impossible/invalid string position.
65 static constexpr size_type npos = static_cast<size_type>(-1);
66
67 private:
68 // Pointer to the beginning of the string being viewed.
69 const_pointer _begin = nullptr;
70 // The size of the array that is being viewed via `_begin`.
71 size_type _size = 0;
72
73 public:
74 using traits_type = Traits;
75 using reference = Char&;
76 using const_reference = Char const&;
77 using const_iterator = const_pointer;
78 using iterator = const_iterator;
79 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
80 using reverse_iterator = const_reverse_iterator;
81
82 constexpr basic_string_view() noexcept = default;
83 constexpr basic_string_view(basic_string_view const&) noexcept = default;
84 BSONCXX_PRIVATE_CONSTEXPR_CXX14 basic_string_view& operator=(basic_string_view const&) noexcept = default;
85
86 constexpr basic_string_view(const_pointer s, size_type count) : _begin(s), _size(count) {}
87
88 constexpr basic_string_view(const_pointer s) : _begin(s), _size(traits_type::length(s)) {}
89
90 template <typename Alloc>
91 constexpr basic_string_view(std::basic_string<value_type, traits_type, Alloc> const& str) noexcept
92 : _begin(str.data()), _size(str.size()) {}
93
94#if defined(__cpp_lib_string_view)
95 constexpr basic_string_view(std::basic_string_view<value_type, traits_type> sv) noexcept
96 : _begin(sv.data()), _size(sv.size()) {}
97#endif
98
99 basic_string_view(std::nullptr_t) = delete;
100
101 constexpr const_iterator begin() const noexcept {
102 return const_iterator(_begin);
103 }
104 constexpr const_iterator end() const noexcept {
105 return begin() + size();
106 }
107 constexpr const_iterator cbegin() const noexcept {
108 return begin();
109 }
110 constexpr const_iterator cend() const noexcept {
111 return end();
112 }
113
114 constexpr const_reverse_iterator rbegin() const noexcept {
115 return const_reverse_iterator{end()};
116 }
117
118 constexpr const_reverse_iterator rend() const noexcept {
119 return const_reverse_iterator{begin()};
120 }
121
122 constexpr const_reverse_iterator crbegin() const noexcept {
123 return const_reverse_iterator{cend()};
124 }
125
126 constexpr const_reverse_iterator crend() const noexcept {
127 return const_reverse_iterator{crbegin()};
128 }
129
130 constexpr const_reference operator[](size_type offset) const {
131 return _begin[offset];
132 }
133
134 BSONCXX_PRIVATE_CONSTEXPR_CXX14 const_reference at(size_type pos) const {
135 if (pos >= size()) {
136 throw std::out_of_range{"bsoncxx::stdx::basic_string_view::at()"};
137 }
138 return _begin[pos];
139 }
140
141 constexpr const_reference front() const {
142 return (*this)[0];
143 }
144
145 constexpr const_reference back() const {
146 return (*this)[size() - 1];
147 }
148
149 constexpr const_pointer data() const noexcept {
150 return _begin;
151 }
152
153 constexpr size_type size() const noexcept {
154 return _size;
155 }
156
157 constexpr size_type length() const noexcept {
158 return size();
159 }
160
161 constexpr bool empty() const noexcept {
162 return size() == 0;
163 }
164
165 constexpr size_type max_size() const noexcept {
166 return static_cast<size_type>(std::numeric_limits<difference_type>::max());
167 }
168
169 BSONCXX_PRIVATE_CONSTEXPR_CXX14 void remove_prefix(size_type n) {
170 _begin += n;
171 _size -= n;
172 }
173
174 BSONCXX_PRIVATE_CONSTEXPR_CXX14 void remove_suffix(size_type n) {
175 _size -= n;
176 }
177
178 BSONCXX_PRIVATE_CONSTEXPR_CXX14 void swap(basic_string_view& other) {
179 std::swap(_begin, other._begin);
180 std::swap(_size, other._size);
181 }
182
183 size_type copy(pointer dest, size_type count, size_type pos = 0) const {
184 if (pos > size()) {
185 throw std::out_of_range{"bsoncxx::stdx::basic_string_view::substr()"};
186 }
187 count = (std::min)(count, size() - pos);
188 Traits::copy(dest, data() + pos, count);
189 return count;
190 }
191
192 BSONCXX_PRIVATE_CONSTEXPR_CXX14 basic_string_view substr(size_type pos = 0, size_type count = npos) const {
193 if (pos > size()) {
194 throw std::out_of_range{"bsoncxx::stdx::basic_string_view::substr()"};
195 }
196 return basic_string_view(_begin + pos, (std::min)(count, size() - pos));
197 }
198
199 constexpr int compare(basic_string_view other) const noexcept {
200 // Another level of indirection to support restricted C++11 constexpr.
201 return _compare2(Traits::compare(data(), other.data(), (std::min)(size(), other.size())), other);
202 }
203
204 constexpr int compare(const_pointer cstr) const {
205 return compare(basic_string_view(cstr));
206 }
207
208 constexpr int compare(size_type pos1, size_type count1, basic_string_view other) const {
209 return substr(pos1, count1).compare(other);
210 }
211
212 constexpr int compare(size_type pos1, size_type count1, const_pointer cstr) const {
213 return compare(pos1, count1, basic_string_view(cstr));
214 }
215
216 constexpr int compare(size_type pos1, size_type count1, basic_string_view other, size_type pos2, size_type count2)
217 const {
218 return substr(pos1, count1).compare(other.substr(pos2, count2));
219 }
220
221 constexpr int compare(size_type pos1, size_type count1, const_pointer str, size_type count2) const {
222 return substr(pos1, count1).compare(basic_string_view(str, count2));
223 }
224
225 BSONCXX_PRIVATE_CONSTEXPR_CXX14 size_type find(basic_string_view infix, size_type pos = 0) const noexcept {
226 if (pos > size()) {
227 return npos;
228 }
229 basic_string_view sub = this->substr(pos);
230 if (infix.empty()) {
231 // The empty string is always "present" at the beginning of any string.
232 return pos;
233 }
234 const_iterator found = std::search(sub.begin(), sub.end(), infix.begin(), infix.end());
235 if (found == sub.end()) {
236 return npos;
237 }
238 return static_cast<size_type>(found - begin());
239 }
240
241 BSONCXX_PRIVATE_CONSTEXPR_CXX14 size_type rfind(basic_string_view infix, size_type pos = npos) const noexcept {
242 // Calc the endpos where searching should begin, which includes the infix size.
243 size_type const substr_size = pos != npos ? pos + infix.size() : pos;
244 if (infix.empty()) {
245 return (std::min)(pos, size());
246 }
247 basic_string_view searched = this->substr(0, substr_size);
248 auto f = std::search(searched.rbegin(), searched.rend(), infix.rbegin(), infix.rend());
249 if (f == searched.rend()) {
250 return npos;
251 }
252 return static_cast<size_type>(rend() - f) - infix.size();
253 }
254
255 constexpr size_type find_first_of(basic_string_view set, size_type pos = 0) const noexcept {
256 return _find_if(pos, [&](value_type chr) { return set.find(chr) != npos; });
257 }
258
259 constexpr size_type find_last_of(basic_string_view set, size_type pos = npos) const noexcept {
260 return _rfind_if(pos, [&](value_type chr) { return set.find(chr) != npos; });
261 }
262
263 constexpr size_type find_first_not_of(basic_string_view set, size_type pos = 0) const noexcept {
264 return _find_if(pos, [&](value_type chr) { return set.find(chr) == npos; });
265 }
266
267 constexpr size_type find_last_not_of(basic_string_view set, size_type pos = npos) const noexcept {
268 return _rfind_if(pos, [&](value_type chr) { return set.find(chr) == npos; });
269 }
270
271#pragma push_macro("DECL_FINDERS")
272#undef DECL_FINDERS
273#define DECL_FINDERS(Name, DefaultPos) \
274 constexpr size_type Name(value_type chr, size_type pos = DefaultPos) const noexcept { \
275 return Name(basic_string_view(&chr, 1), pos); \
276 } \
277 constexpr size_type Name(const_pointer cstr, size_type pos, size_type count) const { \
278 return Name(basic_string_view(cstr, count), pos); \
279 } \
280 constexpr size_type Name(const_pointer cstr, size_type pos = DefaultPos) const { \
281 return Name(basic_string_view(cstr), pos); \
282 } \
283 BSONCXX_PRIVATE_FORCE_SEMICOLON
284
285 DECL_FINDERS(find, 0);
286 DECL_FINDERS(rfind, npos);
287 DECL_FINDERS(find_first_of, 0);
288 DECL_FINDERS(find_last_of, npos);
289 DECL_FINDERS(find_first_not_of, 0);
290 DECL_FINDERS(find_last_not_of, npos);
291#pragma pop_macro("DECL_FINDERS")
292
293 // Explicit-conversion to a std::basic_string.
294 template <typename Allocator>
295 explicit operator std::basic_string<Char, Traits, Allocator>() const {
296 return std::basic_string<Char, Traits, Allocator>(data(), size());
297 }
298
299#if defined(__cpp_lib_string_view)
300 explicit operator std::basic_string_view<value_type, traits_type>() const noexcept {
301 return std::basic_string_view<value_type, traits_type>(data(), size());
302 }
303#endif
304
305 private:
306 // Additional level-of-indirection for constexpr compare().
307 constexpr int _compare2(int diff, basic_string_view other) const noexcept {
308 // "diff" is the diff according to Traits::cmp
309 return diff ? diff : static_cast<int>(size() - other.size());
310 }
311
312 // Implementation of equality comparison.
313 constexpr friend bool
314 tag_invoke(bsoncxx::detail::equal_to, basic_string_view left, basic_string_view right) noexcept {
315 return left.size() == right.size() && left.compare(right) == 0;
316 }
317
318 // Implementation of a three-way-comparison.
319 constexpr friend bsoncxx::detail::strong_ordering
320 tag_invoke(bsoncxx::detail::compare_three_way cmp, basic_string_view left, basic_string_view right) noexcept {
321 return cmp(left.compare(right), 0);
322 }
323
324 friend std::basic_ostream<Char, Traits>& operator<<(std::basic_ostream<Char, Traits>& out, basic_string_view self) {
325 out << std::basic_string<Char, Traits>(self);
326 return out;
327 }
328
329 // Find the first in-bounds index I in [pos, size()) where the given predicate
330 // returns true for substr(I). If no index exists, returns npos.
331 template <typename F>
332 BSONCXX_PRIVATE_CONSTEXPR_CXX14 size_type _find_if(size_type pos, F pred) const noexcept {
333 auto const sub = substr(pos);
334 iterator const found = std::find_if(sub.begin(), sub.end(), pred);
335 if (found == end()) {
336 return npos;
337 }
338 return static_cast<size_type>(found - begin());
339 }
340
341 // Find the LAST index I in [0, pos] where the given predicate returns true for
342 // substr(0, I). If no such index exists, returns npos.
343 template <typename F>
344 BSONCXX_PRIVATE_CONSTEXPR_CXX14 size_type _rfind_if(size_type pos, F pred) const noexcept {
345 // Adjust 'pos' for an inclusive range in substr()
346 auto const rpos = pos == npos ? npos : pos + 1;
347 // The substring that will be searched:
348 auto const prefix = substr(0, rpos);
349 const_reverse_iterator const found = std::find_if(prefix.rbegin(), prefix.rend(), pred);
350 if (found == rend()) {
351 return npos;
352 }
353 // Adjust by 1 to account for reversed-ness
354 return static_cast<size_type>(rend() - found) - 1u;
355 }
356};
357
358// Required to define this here for compatibility with C++14 and older. Can be removed in C++17 or
359// newer.
360template <typename C, typename Tr>
361constexpr std::size_t basic_string_view<C, Tr>::npos;
362
363using string_view = basic_string_view<char>;
364
365} // namespace stdx
366} // namespace v1
367} // namespace bsoncxx
368
369namespace std {
370
371template <typename CharT, typename Traits>
372struct hash<bsoncxx::v1::stdx::basic_string_view<CharT, Traits>> : private std::hash<std::basic_string<CharT, Traits>> {
373 std::size_t operator()(bsoncxx::v1::stdx::basic_string_view<CharT, Traits> const& str) const {
374 return std::hash<std::basic_string<CharT, Traits>>::operator()(
375 std::basic_string<CharT, Traits>(str.data(), str.size()));
376 }
377};
378
379} // namespace std
380
381#else
382#error "Cannot find a valid polyfill for string_view"
383#endif
384
386
398
399#if defined(BSONCXX_PRIVATE_DOXYGEN_PREPROCESSOR)
400
401namespace bsoncxx {
402namespace v1 {
403namespace stdx {
404
412class string_view {};
413
414} // namespace stdx
415} // namespace v1
416} // namespace bsoncxx
417
418#endif // defined(BSONCXX_PRIVATE_DOXYGEN_PREPROCESSOR)
Provides macros describing the bsoncxx library configuration.
For internal use only!
The bsoncxx v1 macro guard postlude header.
The bsoncxx v1 macro guard prelude header.
A polyfill for std::string_view.
Definition string_view.hpp:412
For internal use only!
Declares C++17 standard library polyfills.
Declares entities whose ABI stability is guaranteed for documented symbols.
@ bsoncxx
From the bsoncxx library.
Definition exception.hpp:39
The top-level namespace within which all bsoncxx library entities are declared.