-
Notifications
You must be signed in to change notification settings - Fork 547
[CXX-2625] Bring our very own string_view (plus: Some iterators + ranges backports) #1062
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[CXX-2625] Bring our very own string_view (plus: Some iterators + ranges backports) #1062
Conversation
31f5c29 to
f2bb2fb
Compare
kevinAlbs
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Impressive.
src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/type_traits.hpp
Outdated
Show resolved
Hide resolved
src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/string_view.hpp
Outdated
Show resolved
Hide resolved
src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/string_view.hpp
Outdated
Show resolved
Hide resolved
src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/string_view.hpp
Outdated
Show resolved
Hide resolved
src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/string_view.hpp
Outdated
Show resolved
Hide resolved
src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/string_view.hpp
Outdated
Show resolved
Hide resolved
src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/string_view.hpp
Outdated
Show resolved
Hide resolved
src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/string_view.hpp
Outdated
Show resolved
Hide resolved
| using self_type = basic_string_view; | ||
|
|
||
| /** | ||
| * @brief If R is a type for which we want to permit implicit conversion, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| * @brief If R is a type for which we want to permit implicit conversion, | |
| * @brief If S is a type for which we want to permit implicit conversion, |
src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/string_view.hpp
Outdated
Show resolved
Hide resolved
src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/string_view.hpp
Outdated
Show resolved
Hide resolved
src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/string_view.hpp
Outdated
Show resolved
Hide resolved
src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/string_view.hpp
Outdated
Show resolved
Hide resolved
src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/string_view.hpp
Outdated
Show resolved
Hide resolved
eramongodb
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for your hard work on this PR. A couple suggestions remaining; otherwise, LGTM. 👍
| } // namespace v_noabi | ||
| } // namespace bsoncxx | ||
|
|
||
| BSONCXX_POP_WARNINGS(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| BSONCXX_POP_WARNINGS(); | |
| BSONCXX_POP_WARNINGS(); | |
Spacing.
| constexpr basic_string_view(const basic_string_view&) noexcept = default; | ||
| bsoncxx_cxx14_constexpr basic_string_view& operator=(const basic_string_view&) noexcept = | ||
| default; | ||
|
|
||
| /// Default copy/move/assign/destroy |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| constexpr basic_string_view(const basic_string_view&) noexcept = default; | |
| bsoncxx_cxx14_constexpr basic_string_view& operator=(const basic_string_view&) noexcept = | |
| default; | |
| /// Default copy/move/assign/destroy | |
| constexpr basic_string_view(const basic_string_view&) noexcept = default; | |
| bsoncxx_cxx14_constexpr basic_string_view& operator=(const basic_string_view&) noexcept = | |
| default; |
Fix(?) spacing by separating the copy special member functions from the default ctor + remove a stray comment.
| * | ||
| * @param n The number of characters to remove from the beginning. Must be less than size() | ||
| */ | ||
| bsoncxx_cxx14_constexpr void remove_prefix(size_type n) noexcept { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| bsoncxx_cxx14_constexpr void remove_prefix(size_type n) noexcept { | |
| bsoncxx_cxx14_constexpr void remove_prefix(size_type n) { |
Stray noexcept.
| * | ||
| * @throws std::out_of_range if pos > size() | ||
| */ | ||
| bsoncxx_cxx14_constexpr size_type copy(pointer dest, size_type count, size_type pos = 0) const { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| bsoncxx_cxx14_constexpr size_type copy(pointer dest, size_type count, size_type pos = 0) const { | |
| size_type copy(pointer dest, size_type count, size_type pos = 0) const { |
Not yet addressed.
| bsoncxx_cxx14_constexpr size_type find(basic_string_view infix, | ||
| size_type pos = 0) const noexcept { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| bsoncxx_cxx14_constexpr size_type find(basic_string_view infix, | |
| size_type pos = 0) const noexcept { | |
| bsoncxx_cxx14_constexpr size_type find(basic_string_view infix, size_type pos = 0) const | |
| noexcept { |
ClangFormat.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Newer clang-format wants to break this line differently. Pain.
| bsoncxx_cxx14_constexpr size_type rfind(basic_string_view infix, | ||
| size_type pos = npos) const noexcept { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| bsoncxx_cxx14_constexpr size_type rfind(basic_string_view infix, | |
| size_type pos = npos) const noexcept { | |
| bsoncxx_cxx14_constexpr size_type rfind(basic_string_view infix, size_type pos = npos) const | |
| noexcept { |
ClangFormat.
| constexpr size_type find_last_not_of(basic_string_view set, | ||
| size_type pos = npos) const noexcept { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| constexpr size_type find_last_not_of(basic_string_view set, | |
| size_type pos = npos) const noexcept { | |
| constexpr size_type find_last_not_of(basic_string_view set, size_type pos = npos) const | |
| noexcept { |
ClangFormat.
Refer: CXX-2625
This changeset replaces our usage of external string_view implementations with a single custom implementation, and includes several smaller supporting library components and general code cleanup. The commits have been carefully organized to represent the iteration process taken while developing this changeset, and should be reviewable in isolation, rather than requiring the entire 1.8k line change be reviewed in whole. For reader's benefit, the changes are summarized here as well, in commit order.
Change Summaries
Utility macro:
bsoncxx_returns(...)This macro is a shorthand for
(The trailing
static_assertforces usage to be followed by a semicolon, and prevents clang-format from being confused.)It is used like this:
Besides being easier to read and write, this ensures that: The
noexcept,-> decltypeandreturnexpressions are all equivalent and correct with respect to each other. Placing the return expression in thenoexceptanddecltypespecifier causes semantically invalid code to introduce a substitution failure context rather than a hard error, which is especially helpful when doing SFINAE trickery.decay_copyandrankTheEdit:decay_copyinvocable object is an implementation of the C++23auto(...)expression, previously known as the exposition-onlydecay-copy(...)It decays its argument and invokes the appropriate move/copy constructor thereof in-situ. This is especially useful withbsoncxx_returns, in order to eliminate reference-returning operations.decay_copywas removed as YAGNI. May come back someday, if useful.The
rank<N>struct template is simply a class template which inherits fromrank<N-1>, except forrank<0>, which inherits from nothing. This is used in later changes to create ordering between ambiguous overloads using tag dispatch. A candidate conversion fromrank<10>torank<2>is "preferrable" to a conversion fromrank<10>torank<1>.Operator Utilities in
operators.hppThe code in
operators.hppis not strictly based on and C++ feature and is used to provide simpler implementation of operator overloading in thestring_viewimplementation (and eventually theoptional<T>implementation). Potentially this could be spread to other types which provide overloaded operators to eliminate existing boilerplate.struct detail::is_equality_comparable<T, U>trait template detects whetherconst T&andconst U&are comparable using the==and!=operators.struct detail::equal_toimplements a callable object likestd::equal_to<void>. If given to argumentslandrthat satisfyis_equality_comparable, it returnsl == r.class detail::equality_operatorsis a mixin base class that provides ADL-only (hiddenfriend)implementations ofoperator==(x, y)andoperator!=(x, y)if-and-only-if there exists a valid ADL-visibletag_invoke(detail::equal_to{}, x, y)implementation.class detail::strong_orderingis based on the C++20std::strong_orderingclass. This changeset does not introduce the other ordering types, as this is all we need forstring_view. To simulate C++inlinevariables, the[[gnu::weak]]and__declspec(selectany)attributes are used for thestrong_orderingconstants.compare_three_wayimplements thestd::compare_three_wayinvocable object from C++20. This will be the first usage ofrank<N>. Invoking this object ascompare_three_way{}(l, r)does the first of the following:tag_invoke(compare_three_way{}, l, r)is valid, returns that value asstrong_orderingl < ris valid andl == ris valid:1. If
l < r, returnsstrong_ordering::less2. Otherwise,
l == rreturnstrong_ordering::equal3. Otherwise, returns
strong_ordering::greater.operator()is ill-formed with a substitution error.class detail::ordering_operatorsis a mixin base class that provides all ofoperator<,operator>,operator<=andoperator>=as ADL-only hiddenfriendfunctions based ontag_invoke(compare_three_way{}, lhs, rhs).C++20 Iterators
To support some niceties of C++20/23 additions to
string_view, a detour was made for some iterator (and ranges) backports.pointer_traitsandto_address. These are utilities simply for converting an iterator into a raw pointer to the referred-to object.to_address_tanddereference_tare not part of a standard, but are useful withis_detected.is_dereferencableis a traits template detects an object to which we can apply unary operator*which returns a non-voidexpression.iter_value_t,iter_reference_t, anditer_difference_tall come from C++20 to obtain the value type, reference type, and difference type of an iterator-like object, respectively.is_weakly_incrementableis a trait template based on theweakly_incrementableC++20 concept, and the basis for detecting iterators.is_iteratoris a trait template that detects whether a type is usable as an iterator.contiguous_iterator_tagis a C++20 iterators concept tag that extendsrandom_access_iterator_tag.iterator_concept_tis not part of C++20, but is useful for obtaining the iterator category. It is not possible to infercontiguous_iterator_tag, but it is extremely useful to know it if its available. Unless C++20 support is enabled, only raw pointers will returncontiguous_iterator_tag.is_{input,forward,bidirection,random_access,contiguous}_iteratorare rough trait templates that detect an iterator type based on the result ofiterator_concept_t. They do not implement the full iterator checks of the C++20 concepts.is_sentinel_for<S, I>trait template detects whetherSis a valid sentinel type forI.is_sized_sentinel_for<S, I>extendsis_sentinel_for<S, I>to require that taking the difference betweenSandIreturns a value convertible toiter_difference_t<I>.Detour: Preprocessor Macros
This is a bit of an aside change to add some "probably useful" macros to clean up some conditional compilation and diagnostic control.
bsoncxx_concatconcatenates tokens, andbsoncxx_stringifyturns tokens into a string literal.bsoncxx_if_msvc,bsoncxx_if_gcc,bsoncxx_if_clang, andbsoncxx_if_gnu_likeare function-like macros that expand to their arguments if-and-only-if we are compiling for the respective compiler.bsoncxx_pragma(...)is a function-like port of MSVC__pragma. It accepts a token soup, which is then evaluated as a preprocessor#pragmaat the use site.bsoncxx_push_warnings()/bsoncxx_pop_warnings()is equivalent to the appropriate compiler pragma to push/pop the diagnostics settings at the use site.bsoncxx_disable_warning(Spec)disables warnings for a certain compiler (See macro code comment).A Little C++20 Ranges, as a Treat
A very small bit of C++20 ranges and the range-algorithms were backported, plus some additional utilities. This was finicky to get working on VS 2015, but doable. The following features are available in the
bsoncxx::detailnamespace:begin(),end(),size(),ssize(), anddata()invocable objects.iterator_t,sentinel_t,range_size_t,range_difference_t,range_data_t,range_value_t, andrange_concept_talias templates.is_range<R>trait template detectsiterator_t<R>andsentinel_t<R>is_contiguous_range<R>is not strictly equivalent to thecontiguous_rangeconcept, but suites our needs. It requires a validdata(R)andsize(R).subrange<>class template for creating ranges from iterator pairs.unreachable_sentinelfor unbounded views.advance,next,equal,find,find_if, andsearch. Also:not_fnanddefault_searcher.make_reversed_view,equal_to_any_of, andequal_to_value.The algorithms differ from std-ranges in that the iterator-only overloads are omitted, instead all require a range and are bounds-checked. To use a "zero overhead" unchecked algorithms, use a a
subrangewithunreachable_sentinel.The Actual
string_viewFinally, the actual
stdx::basic_string_viewclass template. It builds upon all of the previous additions and allows us to stop using mnmlstc-core and Boost for our string-viewing needs.The
basic_string_viewclass template is not equal to the C++23 implementation, but provides most of the same functionality.std::vector<char>,std::array<char>, etc. This is anexplicitconversion.std::string, as well asstd::string_viewitself. It detects "string-like" based on the presence of a.c_str()method.nullptr_tis explicitly deleted (from C++23).begin(),cbegin(),rbegin(), andcrbegin()are defined, as well as the correspondingend()soperator[]and all non-throwing access functions that specify UB for out-of-bounds access include an assertion with a useful error message rather than a strict terminations, done using_assert_inbounds(). This method is defined inline so that assertion condition is visible to the inliner without requiring LTO, while the actual diagnostic+termination function is implemented out-of-line to reduce code size.starts_withandends_withare included.contains.find-etc members are included.operators.hppusingtag_invoke. Only two functions make all six operators!