-
Notifications
You must be signed in to change notification settings - Fork 543
[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
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
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. 👍
@@ -679,6 +674,7 @@ BSONCXX_INLINE bool operator==(const b_maxkey&, const b_maxkey&) { | |||
} // 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_assert
forces 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
,-> decltype
andreturn
expressions are all equivalent and correct with respect to each other. Placing the return expression in thenoexcept
anddecltype
specifier causes semantically invalid code to introduce a substitution failure context rather than a hard error, which is especially helpful when doing SFINAE trickery.decay_copy
andrank
TheEdit:decay_copy
invocable 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_copy
was 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.hpp
The code in
operators.hpp
is not strictly based on and C++ feature and is used to provide simpler implementation of operator overloading in thestring_view
implementation (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_to
implements a callable object likestd::equal_to<void>
. If given to argumentsl
andr
that satisfyis_equality_comparable
, it returnsl == r
.class detail::equality_operators
is 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_ordering
is based on the C++20std::strong_ordering
class. This changeset does not introduce the other ordering types, as this is all we need forstring_view
. To simulate C++inline
variables, the[[gnu::weak]]
and__declspec(selectany)
attributes are used for thestrong_ordering
constants.compare_three_way
implements thestd::compare_three_way
invocable 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_ordering
l < r
is valid andl == r
is valid:1. If
l < r
, returnsstrong_ordering::less
2. Otherwise,
l == r
returnstrong_ordering::equal
3. Otherwise, returns
strong_ordering::greater
.operator()
is ill-formed with a substitution error.class detail::ordering_operators
is a mixin base class that provides all ofoperator<
,operator>
,operator<=
andoperator>=
as ADL-only hiddenfriend
functions 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_traits
andto_address
. These are utilities simply for converting an iterator into a raw pointer to the referred-to object.to_address_t
anddereference_t
are not part of a standard, but are useful withis_detected
.is_dereferencable
is a traits template detects an object to which we can apply unary operator*
which returns a non-void
expression.iter_value_t
,iter_reference_t
, anditer_difference_t
all come from C++20 to obtain the value type, reference type, and difference type of an iterator-like object, respectively.is_weakly_incrementable
is a trait template based on theweakly_incrementable
C++20 concept, and the basis for detecting iterators.is_iterator
is a trait template that detects whether a type is usable as an iterator.contiguous_iterator_tag
is a C++20 iterators concept tag that extendsrandom_access_iterator_tag
.iterator_concept_t
is 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}_iterator
are 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 whetherS
is a valid sentinel type forI
.is_sized_sentinel_for<S, I>
extendsis_sentinel_for<S, I>
to require that taking the difference betweenS
andI
returns 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_concat
concatenates tokens, andbsoncxx_stringify
turns tokens into a string literal.bsoncxx_if_msvc
,bsoncxx_if_gcc
,bsoncxx_if_clang
, andbsoncxx_if_gnu_like
are 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#pragma
at 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::detail
namespace: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_t
alias templates.is_range<R>
trait template detectsiterator_t<R>
andsentinel_t<R>
is_contiguous_range<R>
is not strictly equivalent to thecontiguous_range
concept, but suites our needs. It requires a validdata(R)
andsize(R)
.subrange<>
class template for creating ranges from iterator pairs.unreachable_sentinel
for unbounded views.advance
,next
,equal
,find
,find_if
, andsearch
. Also:not_fn
anddefault_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
subrange
withunreachable_sentinel
.The Actual
string_view
Finally, the actual
stdx::basic_string_view
class 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_view
class 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 anexplicit
conversion.std::string
, as well asstd::string_view
itself. It detects "string-like" based on the presence of a.c_str()
method.nullptr_t
is 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_with
andends_with
are included.contains
.find
-etc members are included.operators.hpp
usingtag_invoke
. Only two functions make all six operators!