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