From 71f0e614be90e6bf5c20f9427f92c5b880417def Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Wed, 8 Nov 2023 14:57:51 -0700 Subject: [PATCH 01/47] Shorthand for trailing return type, noexcept, and single-return-statement --- .../v_noabi/bsoncxx/config/postlude.hpp | 3 +++ .../v_noabi/bsoncxx/config/prelude.hpp | 17 ++++++++++++++ .../v_noabi/bsoncxx/stdx/type_traits.hpp | 22 ++++++------------- 3 files changed, 27 insertions(+), 15 deletions(-) diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/config/postlude.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/config/postlude.hpp index 2d18d353f3..5c0c2e303d 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/config/postlude.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/config/postlude.hpp @@ -67,6 +67,9 @@ #undef BSONCXX_UNREACHABLE #pragma pop_macro("BSONCXX_UNREACHABLE") +#pragma pop_macro("mongo_cxx14_constexpr") +#pragma pop_macro("bsoncxx_returns") + // CXX-2769: out-of-place, but remains for backward compatibility. #ifdef BSONCXX_ENUM static_assert(false, "BSONCXX_ENUM must be undef'ed"); diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/config/prelude.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/config/prelude.hpp index b5c0432b87..13e5d2bd11 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/config/prelude.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/config/prelude.hpp @@ -90,3 +90,20 @@ /// @namespace bsoncxx::v_noabi::stdx /// Declares polyfills for C++17 forward compatibility. /// + +#pragma push_macro("mongo_cxx14_constexpr") +#if __cplusplus >= 201402L +#define mongo_cxx14_constexpr constexpr +#else +#define mongo_cxx14_constexpr inline +#endif + +#pragma push_macro("bsoncxx_returns") +/** + * @brief Add a trailing noexcept, decltype-return, and return-body to a function definition. + */ +#define bsoncxx_returns(...) \ + noexcept(noexcept(__VA_ARGS__))->decltype(__VA_ARGS__) { \ + return __VA_ARGS__; \ + } \ + static_assert(true, "") diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/type_traits.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/type_traits.hpp index b3a9a376c6..8d33244871 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/type_traits.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/type_traits.hpp @@ -344,31 +344,25 @@ using requires_not_t = requires_t>>; // Impl: invoke/is_invocable namespace impl_invoke { -#pragma push_macro("RETURNS") -#define RETURNS(...) \ - noexcept(noexcept(__VA_ARGS__))->decltype(__VA_ARGS__) { \ - return __VA_ARGS__; \ - } \ - static_assert(true, "") - template struct invoker { template constexpr static auto apply(F&& fun, Args&&... args) - RETURNS(static_cast(fun)(static_cast(args)...)); + bsoncxx_returns(static_cast(fun)(static_cast(args)...)); }; template <> struct invoker { template constexpr static auto apply(F&& fun, Self&& self, Args&&... args) - RETURNS((static_cast(self).*fun)(static_cast(args)...)); + bsoncxx_returns((static_cast(self).*fun)(static_cast(args)...)); }; template <> struct invoker { template - constexpr static auto apply(F&& fun, Self&& self) RETURNS(static_cast(self).*fun); + constexpr static auto apply(F&& fun, Self&& self) + bsoncxx_returns(static_cast(self).*fun); }; } // namespace impl_invoke @@ -383,13 +377,11 @@ static constexpr struct invoke_fn { template > constexpr auto operator()(F&& fn, Args&&... args) const - RETURNS(impl_invoke::invoker::value, - std::is_member_function_pointer::value> // - ::apply(static_cast(fn), static_cast(args)...)); + bsoncxx_returns(impl_invoke::invoker::value, + std::is_member_function_pointer::value> // + ::apply(static_cast(fn), static_cast(args)...)); } invoke; -#pragma pop_macro("RETURNS") - /** * @brief Yields the type that would result from invoking F with the given arguments. * From f5e1d021ef1ed21d8fa3a0952752ec8e031a1e08 Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Wed, 8 Nov 2023 15:31:54 -0700 Subject: [PATCH 02/47] Some additional traits: decay_copy and rank<> --- .../v_noabi/bsoncxx/stdx/type_traits.hpp | 29 +++++++++++++++++++ src/bsoncxx/test/type_traits.test.cpp | 17 +++++++++++ 2 files changed, 46 insertions(+) diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/type_traits.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/type_traits.hpp index 8d33244871..eab234e186 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/type_traits.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/type_traits.hpp @@ -34,6 +34,7 @@ DECL_ALIAS(remove_reference); DECL_ALIAS(remove_const); DECL_ALIAS(remove_volatile); DECL_ALIAS(remove_cv); +DECL_ALIAS(add_pointer); DECL_ALIAS(add_const); DECL_ALIAS(add_volatile); DECL_ALIAS(add_lvalue_reference); @@ -412,6 +413,34 @@ struct is_invocable : is_detected { template struct is_alike : std::is_same, remove_cvref_t> {}; +/** + * @brief Tag type for creating ranked overloads to force disambiguation. + * + * @tparam N The ranking of the overload. A higher value is ranked greater than + * lower values. + */ +template +struct rank : rank {}; + +template <> +struct rank<0> {}; + +struct _decay_copy_fn { + template + constexpr auto operator()(T&& arg) const + noexcept(std::is_nothrow_constructible, T&&>{}) + -> requires_t, std::is_constructible, T&&>> { + return static_cast>(static_cast(arg)); + } +}; + +/** + * @brief Perform a decay-copy on the given value. + * + * Equivalent to the C++23 `auto()` expression. + */ +static constexpr _decay_copy_fn decay_copy; + } // namespace detail } // namespace v_noabi diff --git a/src/bsoncxx/test/type_traits.test.cpp b/src/bsoncxx/test/type_traits.test.cpp index 5c3a452d91..07aa86607c 100644 --- a/src/bsoncxx/test/type_traits.test.cpp +++ b/src/bsoncxx/test/type_traits.test.cpp @@ -179,4 +179,21 @@ static_assert( value, "fail"); +struct rank_test { + template + constexpr int val(T x, bsoncxx::detail::rank<0>) const { + return x.never_instantiated(); + } + template + constexpr int val(T x, bsoncxx::detail::rank<1>) const { + return x + 30; + } + template + constexpr int operator()(T v) const { + return this->val(v, bsoncxx::detail::rank<20>{}); + } +}; + +static_assert(rank_test{}(12) == 42, "fail"); + } // namespace From f79efdb599f4811f378283a890ebff92c713fe1e Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Wed, 8 Nov 2023 15:41:34 -0700 Subject: [PATCH 03/47] New operators.hpp utilities --- src/bsoncxx/include/CMakeLists.txt | 1 + .../v_noabi/bsoncxx/stdx/operators.hpp | 165 ++++++++++++++++++ 2 files changed, 166 insertions(+) create mode 100644 src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/operators.hpp diff --git a/src/bsoncxx/include/CMakeLists.txt b/src/bsoncxx/include/CMakeLists.txt index 1f7ea4b7e3..94d92cfdcf 100644 --- a/src/bsoncxx/include/CMakeLists.txt +++ b/src/bsoncxx/include/CMakeLists.txt @@ -58,6 +58,7 @@ set_dist_list(src_bsoncxx_include_DIST bsoncxx/v_noabi/bsoncxx/oid.hpp bsoncxx/v_noabi/bsoncxx/stdx/make_unique.hpp bsoncxx/v_noabi/bsoncxx/stdx/optional.hpp + bsoncxx/v_noabi/bsoncxx/stdx/operators.hpp bsoncxx/v_noabi/bsoncxx/stdx/string_view.hpp bsoncxx/v_noabi/bsoncxx/stdx/type_traits.hpp bsoncxx/v_noabi/bsoncxx/string/to_string.hpp diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/operators.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/operators.hpp new file mode 100644 index 0000000000..82fccbbbb1 --- /dev/null +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/operators.hpp @@ -0,0 +1,165 @@ +#pragma once + +#include +#include +#include + +#include "./type_traits.hpp" + +#include + +namespace bsoncxx { +inline namespace v_noabi { +namespace detail { + +/** + * @brief Detect whether two types are equality-comparable. + * + * Requires L == R, L != R, R == L, and R != L + */ +template +struct is_equality_comparable : std::false_type {}; + +template +struct is_equality_comparable< + L, + R, + void_t>() == std::declval>()), + decltype(std::declval>() != std::declval>()), + decltype(std::declval>() == std::declval>()), + decltype(std::declval>() != std::declval>())>> + : std::true_type {}; + +/** + * @brief Callable object and tag type for equality comparison + * + */ +struct equal_to { + template + constexpr requires_t> // + operator()(L&& l, R&& r) const noexcept(noexcept(l == r)) { + return l == r; + } +}; + +/** + * @brief Derive from this class to define ADL-only operator== and operator!= on the basis of + * an ADL-only tag_invoke(equal_to, l, r) + */ +class equality_operators { + template + constexpr friend auto operator==(const Left& self, const Other& other) + bsoncxx_returns(tag_invoke(equal_to{}, self, other)); + + template + constexpr friend auto operator!=(const Left& self, const Other& other) + bsoncxx_returns(!tag_invoke(equal_to{}, self, other)); +}; + +/** + * @brief Very basic impl of C++20 std::strong_ordering + * + * We don't need other weaker orderings yet, so this is all that we have + */ +class strong_ordering { + signed char _c; + struct _construct {}; + + constexpr strong_ordering(_construct, signed char c) noexcept : _c(c) {} + + public: + static const strong_ordering less; + static const strong_ordering greater; + static const strong_ordering equivalent; + static const strong_ordering equal; + + constexpr strong_ordering(std::nullptr_t) noexcept : strong_ordering(_construct{}, 0) {} + + constexpr bool operator==(strong_ordering o) const noexcept { + return _c == o._c; + } + constexpr bool operator!=(strong_ordering o) const noexcept { + return !(*this == o); + } + +#define DEFOP(Op) \ + constexpr bool operator Op(std::nullptr_t) const noexcept { \ + return _c Op 0; \ + } \ + static_assert(true, "") + DEFOP(<); + DEFOP(>); + DEFOP(<=); + DEFOP(>=); +#undef DEFOP +}; + +#ifdef __GNUC__ +#define psuedo_inline [[gnu::weak]] +#elif defined _MSC_VER +#define psuedo_inline __declspec(selectany) +#else +#define pseudo_inline +#endif + +psuedo_inline const strong_ordering strong_ordering::less = + strong_ordering(strong_ordering::_construct{}, -1); +psuedo_inline const strong_ordering strong_ordering::greater = + strong_ordering(strong_ordering::_construct{}, 1); +psuedo_inline const strong_ordering strong_ordering::equivalent = + strong_ordering(strong_ordering::_construct{}, 0); +psuedo_inline const strong_ordering strong_ordering::equal = + strong_ordering(strong_ordering::_construct{}, 0); + +#undef psuedo_inline + +/** + * @brief Implements a three-way comparison between two objects. That is, in + * a single operation, determine whether the left operand is less-than, greater-than, + * or equal-to the right-hand operand. + */ +struct compare_three_way { + template () < std::declval()), + typename = decltype(std::declval() == std::declval())> + constexpr static strong_ordering impl(L const& l, R const& r, rank<1>) { + return (l < r) ? strong_ordering::less + : (l == r ? strong_ordering::equal // + : strong_ordering::greater); + } + + template (), std::declval(), std::declval()))> + constexpr strong_ordering impl(L const& l, R const& r, rank<2>) const { + return tag_invoke(*this, l, r); + } + + template + constexpr auto operator()(L const& l, R const& r) const + bsoncxx_returns((impl)(l, r, rank<2>{})); +}; + +/** + * @brief Inherit to define ADL-visible ordering operators based on an ADL-visible + * implementation of tag_invoke(compare_three_way, l, r) + */ +struct ordering_operators { +#define DEFOP(Oper) \ + template \ + constexpr friend auto operator Oper(const L& l, const R& r) \ + bsoncxx_returns(tag_invoke(compare_three_way{}, l, r) Oper 0) + DEFOP(<); + DEFOP(>); + DEFOP(<=); + DEFOP(>=); +#undef DEFOP +}; + +} // namespace detail +} // namespace v_noabi +} // namespace bsoncxx + +#include From ff488e386388b17927451395e7d4fba5d6cb71b2 Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Wed, 8 Nov 2023 17:44:39 -0700 Subject: [PATCH 04/47] Iterator utilities --- src/bsoncxx/include/CMakeLists.txt | 1 + .../bsoncxx/v_noabi/bsoncxx/stdx/iterator.hpp | 218 ++++++++++++++++++ .../v_noabi/bsoncxx/stdx/type_traits.hpp | 39 +++- src/bsoncxx/test/CMakeLists.txt | 2 + src/bsoncxx/test/iterator.test.cpp | 80 +++++++ 5 files changed, 336 insertions(+), 4 deletions(-) create mode 100644 src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/iterator.hpp create mode 100644 src/bsoncxx/test/iterator.test.cpp diff --git a/src/bsoncxx/include/CMakeLists.txt b/src/bsoncxx/include/CMakeLists.txt index 94d92cfdcf..12f2b05bf5 100644 --- a/src/bsoncxx/include/CMakeLists.txt +++ b/src/bsoncxx/include/CMakeLists.txt @@ -56,6 +56,7 @@ set_dist_list(src_bsoncxx_include_DIST bsoncxx/v_noabi/bsoncxx/exception/exception.hpp bsoncxx/v_noabi/bsoncxx/json.hpp bsoncxx/v_noabi/bsoncxx/oid.hpp + bsoncxx/v_noabi/bsoncxx/stdx/iterator.hpp bsoncxx/v_noabi/bsoncxx/stdx/make_unique.hpp bsoncxx/v_noabi/bsoncxx/stdx/optional.hpp bsoncxx/v_noabi/bsoncxx/stdx/operators.hpp diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/iterator.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/iterator.hpp new file mode 100644 index 0000000000..f937a6188e --- /dev/null +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/iterator.hpp @@ -0,0 +1,218 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#if defined(__has_include) +#if __has_include() +#include +#endif +#endif + +#include "./operators.hpp" +#include "./type_traits.hpp" + +#include + +namespace bsoncxx { +inline namespace v_noabi { +namespace detail { + +/** + * @brief Backport of std::pointer_traits with the addition of to_address() for pointers + */ +template +struct pointer_traits : std::pointer_traits {}; + +template +struct pointer_traits : std::pointer_traits { + using typename std::pointer_traits::pointer; + using typename std::pointer_traits::element_type; + + static constexpr pointer to_address(pointer p) noexcept { + return p; + } +}; + +struct _to_address_fn { + template + static constexpr auto impl(FancyPointer fp, rank<3>) + bsoncxx_returns(pointer_traits::to_address(fp)); + + template + static constexpr auto impl(Iterator iter, rank<2>) bsoncxx_returns(iter.operator->()); + + template + static constexpr auto impl(T* p, rank<1>) bsoncxx_returns(p); + + template + constexpr auto operator()(Iterator iter) const bsoncxx_returns((impl)(iter, rank<10>{})); +}; + +/** + * @brief Convert an iterator or pointer-like type to a raw pointer. + */ +constexpr static _to_address_fn to_address; + +/** + * @brief The type obtained by to_address() for the given object, if valid + */ +template +using to_address_t = decltype(to_address(std::declval())); + +/** + * @brief The result of applying unary operator* to the given object, if valid + */ +template +using dereference_t = decltype(*std::declval()); + +/** + * @brief Detect a type that can be dereferenced (like a pointer) and the result + * type is non-void + */ +template +struct is_dereferencable : conjunction, + // Clang supports dereferencing void*, and we can't detect + // that easily. Refuse if I is (cv-)void* + negation>>, + negation>>> {}; + +/** + * @brief Obtain the value type of the given iterator. + * + * This is only a very rough approximation for our use cases. A more thorough + * C++20 impl requiers additional traits + */ +template +using iter_value_t = + requires_t::value_type, is_dereferencable>; + +/** + * @brief Obtain the reference type of the given iterator (unless that type is `void`) + */ +template +using iter_reference_t = requires_t()), is_dereferencable>; + +/** + * @brief Obtain the difference type for the given iterator + */ +template +using iter_difference_t = typename std::iterator_traits::difference_type; + +template +struct is_weakly_incrementable : std::false_type {}; + +template +struct is_weakly_incrementable< // + Iter, + requires_t, + std::is_assignable, + is_detected, + true_t()), // + decltype(std::declval()++)>, + std::is_same()), Iter&>>> : std::true_type {}; + +/** + * @brief Detect a type that may be used as an iterator + */ +template +struct is_iterator : conjunction, + is_detected, + is_detected> {}; + +// We want contiguous_iterator_tag. We can't get the full functionality without +// stdlib support, but we can get reasonable approximation for our purposes +#if defined(__cpp_lib_ranges) +using std::contiguous_iterator_tag; +#else +struct contiguous_iterator_tag : std::random_access_iterator_tag {}; +#endif + +// Base case, use the iterator to get the actual traits from it. +template +struct ITER_TRAITS_impl { + using type = I; +}; + +// If std::iterator_traits is not "the default" (which contains no difference_type), +// then use std::iterator_traits. +template +struct ITER_TRAITS_impl::difference_type>> { + using type = std::iterator_traits; +}; + +template +using ITER_TRAITS = typename ITER_TRAITS_impl::type; + +// Get the iterator concept tag from the given iterator-like type +struct calc_iterator_concept { + struct impl { + template + static auto x(I*, rank<3>) bsoncxx_returns(contiguous_iterator_tag{}); + template + static auto x(I, rank<2>) bsoncxx_returns(typename ITER_TRAITS::iterator_concept{}); + template + static auto x(I, rank<1>) bsoncxx_returns(typename ITER_TRAITS::iterator_category{}); + }; + template + auto operator()(I) -> decltype(impl::x(I{}, rank<10>{})); +}; + +/** + * @brief Obtain the iterator concept/category tag type, if present. + * + * Without C++20 stdlib support, does not detect contiguous_iterator_tag except + * for on raw pointers. + */ +template +using iterator_concept_t = decltype(calc_iterator_concept{}(I{})); + +template +struct is_iterator_kind + : conjunction, std::is_base_of>> {}; + +template +struct is_input_iterator : is_iterator_kind {}; + +template +struct is_forwrd_iterator : is_iterator_kind {}; + +template +struct is_bidirectional_iterator : is_iterator_kind {}; + +template +struct is_random_access_iterator : is_iterator_kind {}; + +template +struct is_contiguous_iterator : is_iterator_kind {}; + +/** + * @brief Detect if the type `Sentinel` is a range sentinel for iterator `Iter` + */ +template +struct is_sentinel_for : conjunction, is_iterator> {}; + +template +using difference_t = decltype(std::declval() - std::declval()); + +/** + * @brief Detect if the type `Sentinel` is a sentinel for `Iter` and subtraction + * is defined between them. + */ +template +struct is_sized_sentinel_for + : conjunction< + is_sentinel_for, + std::is_convertible, iter_difference_t>, + std::is_convertible, iter_difference_t>> { +}; + +} // namespace detail +} // namespace v_noabi +} // namespace bsoncxx + +#include diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/type_traits.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/type_traits.hpp index eab234e186..08d458a503 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/type_traits.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/type_traits.hpp @@ -33,6 +33,7 @@ DECL_ALIAS(make_unsigned); DECL_ALIAS(remove_reference); DECL_ALIAS(remove_const); DECL_ALIAS(remove_volatile); +DECL_ALIAS(remove_pointer); DECL_ALIAS(remove_cv); DECL_ALIAS(add_pointer); DECL_ALIAS(add_const); @@ -56,13 +57,25 @@ using remove_cvref_t = remove_cv_t>; template using const_reference_t = add_lvalue_reference_t>; +// Workaround for CWG issue 1558 +template +struct _just_void_ { + using type = void; +}; /** * @brief A "do-nothing" alias template that always evaluates to void * * @tparam Ts Zero or more type arguments, all discarded */ template -using void_t = void; +using void_t = +#if defined(_MSC_VER) && _MSC_VER < 1910 + // Old MSVC requires that the type parameters actually be "used" to trigger SFINAE at caller. + // This was resolved by CWG issue 1558 + typename _just_void_::type; +#else + void; +#endif /** * @brief Alias for integral_constant @@ -95,7 +108,7 @@ std::true_type is_detected_f(mp_list*); // Failure case for is_detected. Because this function takes an elipsis, this is // less preferred than the above overload that accepts a pointer type directly. -template +template std::false_type is_detected_f(...); // Provides the detected_or impl @@ -117,6 +130,18 @@ struct detection { using f = Oper; }; +/// Workaround: MSVC 14.0 forgets whether a type resulting from the evaluation +/// of a template-template parameter to an alias template is a reference. +template +struct vc140_detection { + using type = Dflt; +}; + +template +struct vc140_detection>, Oper, Args...> { + using type = Oper; +}; + } // namespace impl_detection /** @@ -149,8 +174,14 @@ struct is_detected * @tparam Args The arguments to give to the Oper metafunction */ template -using detected_or = typename impl_detection::detection< - is_detected::value>::template f; +using detected_or = +#if defined(_MSC_VER) && _MSC_VER < 1910 + typename impl_detection::vc140_detection::type +#else + typename impl_detection::detection< + is_detected::value>::template f +#endif + ; /** * @brief If Oper evaluates to a type, yields that type. Otherwise, yields diff --git a/src/bsoncxx/test/CMakeLists.txt b/src/bsoncxx/test/CMakeLists.txt index f3c224b02e..a685f92090 100644 --- a/src/bsoncxx/test/CMakeLists.txt +++ b/src/bsoncxx/test/CMakeLists.txt @@ -39,6 +39,7 @@ add_executable(test_bson view_or_value.cpp make_unique.test.cpp type_traits.test.cpp + iterator.test.cpp ) # Common target properties for test executables. @@ -123,4 +124,5 @@ set_dist_list(src_bsoncxx_test_DIST view_or_value.cpp type_traits.test.cpp make_unique.test.cpp + iterator.test.cpp ) diff --git a/src/bsoncxx/test/iterator.test.cpp b/src/bsoncxx/test/iterator.test.cpp new file mode 100644 index 0000000000..a2c2f14e47 --- /dev/null +++ b/src/bsoncxx/test/iterator.test.cpp @@ -0,0 +1,80 @@ +#include "bsoncxx/stdx/iterator.hpp" + +#include +#include +#include +#include + +#include "bsoncxx/stdx/type_traits.hpp" +#include + +namespace { + +struct fancy_ptr { + std::string* realptr; + + constexpr std::string* operator->() const noexcept { + return realptr; + } +}; + +} // namespace + +namespace bsoncxx { +inline namespace v_noabi { +namespace detail { +template <> +struct pointer_traits { + constexpr static std::string* to_address(fancy_ptr p) { + return p.realptr; + } +}; + +} // namespace detail +} // namespace v_noabi +} // namespace bsoncxx + +TEST_CASE("To address") { + int* p = nullptr; + CHECK(bsoncxx::detail::to_address(p) == p); + + std::list li = {1, 2, 3, 4}; + auto first = bsoncxx::detail::to_address(li.begin()); + CHECK(first == &li.front()); + + std::string hello = "I am a string"; + fancy_ptr fp{&hello}; + CHECK(bsoncxx::detail::to_address(fp) == &hello); +} + +static_assert(!bsoncxx::detail::is_dereferencable{}, "fail"); +static_assert(bsoncxx::detail::is_dereferencable{}, "fail"); +static_assert(!bsoncxx::detail::is_dereferencable{}, "fail"); + +static_assert(bsoncxx::detail::is_weakly_incrementable{}, "fail"); +static_assert(!bsoncxx::detail::is_weakly_incrementable{}, "fail"); + +static_assert(std::is_base_of>{}, + "fail"); +static_assert(std::is_base_of>{}, + "fail"); +static_assert(std::is_base_of::iterator>>{}, + "fail"); + +static_assert(bsoncxx::detail::is_weakly_incrementable{}, "fail"); +static_assert(bsoncxx::detail::is_detected{}, "fail"); +static_assert(std::is_same, char>::value, "fail"); +static_assert(bsoncxx::detail::is_iterator{}, "fail"); +static_assert(bsoncxx::detail::is_contiguous_iterator{}, "fail"); +static_assert(!bsoncxx::detail::is_contiguous_iterator::iterator>{}, "fail"); + +struct deref_void { + void operator*() const; +}; +static_assert(bsoncxx::detail::is_detected{}, "fail"); +static_assert(!bsoncxx::detail::is_dereferencable{}, "fail"); +static_assert(!bsoncxx::detail::is_detected{}, + "fail"); From 155f52818179f43942b220729de79b10a01d12cd Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Thu, 9 Nov 2023 12:27:14 -0700 Subject: [PATCH 05/47] We don't need to start_mongod for the simple compile tasks --- .mci.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.mci.yml b/.mci.yml index 51788d35c6..79bcef53c6 100644 --- a/.mci.yml +++ b/.mci.yml @@ -608,7 +608,6 @@ tasks: - name: compile_with_shared_libs commands: - func: "setup" - - func: "start_mongod" - func: "fetch_c_driver_source" - func: "compile" From e3575fa1259e89c5628648a3aaa77231dfbd9c62 Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Fri, 10 Nov 2023 14:34:07 -0700 Subject: [PATCH 06/47] A new set of macros for concise diagnostic controls --- .../v_noabi/bsoncxx/config/postlude.hpp | 22 ++++ .../v_noabi/bsoncxx/config/prelude.hpp | 100 +++++++++++++++++- .../v_noabi/bsoncxx/document/value.hpp | 12 +-- .../v_noabi/bsoncxx/stdx/operators.hpp | 8 +- .../include/bsoncxx/v_noabi/bsoncxx/types.hpp | 15 +-- src/bsoncxx/test/CMakeLists.txt | 17 +++ src/bsoncxx/test/type_traits.test.cpp | 7 +- 7 files changed, 149 insertions(+), 32 deletions(-) diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/config/postlude.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/config/postlude.hpp index 5c0c2e303d..4279d3f4c8 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/config/postlude.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/config/postlude.hpp @@ -75,3 +75,25 @@ static_assert(false, "BSONCXX_ENUM must be undef'ed"); #endif #pragma pop_macro("BSONCXX_ENUM") + +#pragma pop_macro("bsoncxx_push_warnings") +#pragma pop_macro("bsoncxx_pop_warnings") +#pragma pop_macro("bsoncxx_disable_warning") + +#pragma pop_macro("BSONCXX_DISABLE_WARNING_IMPL_MSVC") +#pragma pop_macro("BSONCXX_DISABLE_WARNING_IMPL_GCC") +#pragma pop_macro("BSONCXX_DISABLE_WARNING_IMPL_GNU") +#pragma pop_macro("BSONCXX_DISABLE_WARNING_IMPL_Clang") + +#pragma pop_macro("bsoncxx_concat") +#pragma pop_macro("bsoncxx_concat_impl") + +#pragma pop_macro("bsoncxx_pragma") +#pragma pop_macro("bsoncxx_stringify_impl") +#pragma pop_macro("bsoncxx_stringify") +#pragma pop_macro("bsoncxx_force_semicolon") + +#pragma pop_macro("bsoncxx_if_msvc") +#pragma pop_macro("bsoncxx_if_gcc") +#pragma pop_macro("bsoncxx_if_clang") +#pragma pop_macro("bsoncxx_if_gnu_like") diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/config/prelude.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/config/prelude.hpp index 13e5d2bd11..98666b524a 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/config/prelude.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/config/prelude.hpp @@ -106,4 +106,102 @@ noexcept(noexcept(__VA_ARGS__))->decltype(__VA_ARGS__) { \ return __VA_ARGS__; \ } \ - static_assert(true, "") + bsoncxx_force_semicolon + +// clang-format off + +#pragma push_macro("bsoncxx_if_msvc") +#define bsoncxx_if_msvc(...) +#pragma push_macro("bsoncxx_if_gcc") +#define bsoncxx_if_gcc(...) +#pragma push_macro("bsoncxx_if_clang") +#define bsoncxx_if_clang(...) +#pragma push_macro("bsoncxx_if_gnu_like") +#define bsoncxx_if_gnu_like(...) \ + bsoncxx_if_gcc(__VA_ARGS__) \ + bsoncxx_if_clang(__VA_ARGS__) + +#ifdef __GNUC__ + #ifdef __clang__ + #undef bsoncxx_if_clang + #define bsoncxx_if_clang(...) __VA_ARGS__ + #else + #undef bsoncxx_if_gcc + #define bsoncxx_if_gcc(...) __VA_ARGS__ + #endif +#elif defined(_MSC_VER) + #undef bsoncxx_if_msvc + #undef bsoncxx_if_msvc(...) __VA_ARGS__ +#endif + +#pragma push_macro("bsoncxx_stringify") +#pragma push_macro("bsoncxx_stringify_impl") +#define bsoncxx_stringify(...) bsoncxx_stringify_impl(__VA_ARGS__) +#define bsoncxx_stringify_impl(...) #__VA_ARGS__ + +#pragma push_macro("bsoncxx_pragma") +#define bsoncxx_pragma(...) _Pragma(bsoncxx_stringify(__VA_ARGS__)) + +#pragma push_macro("bsoncxx_force_semicolon") +/** + * @brief Use in a declaration position to force the appearence of a semicolon as the next token + */ +#define bsoncxx_force_semicolon static_assert(true, "") + +#pragma push_macro("bsoncxx_concat") +#pragma push_macro("bsoncxx_concat_impl") +#define bsoncxx_concat(A, ...) bsoncxx_concat_impl(A, __VA_ARGS__) +#define bsoncxx_concat_impl(A, ...) A##__VA_ARGS__ + +#pragma push_macro("bsoncxx_disable_warning") +/** + * @brief Disable a warning for a particular compiler. + * + * The argument should be of the form: + * + * - Clang() + * - GCC() + * - GNU() + * - MSVC() + */ +#define bsoncxx_disable_warning(Spec) bsoncxx_concat(BSONCXX_DISABLE_WARNING_IMPL_, Spec) + +#pragma push_macro("bsoncxx_push_warnings") +/** + * @brief Push the current compiler diagnostics settings state + */ +#define bsoncxx_push_warnings() \ + bsoncxx_if_gnu_like(bsoncxx_pragma(GCC diagnostic push);) \ + bsoncxx_if_msvc(bsoncxx_pragma(warning(push));) \ + bsoncxx_force_semicolon + +#pragma push_macro("bsoncxx_pop_warnings") +/** + * @brief Restore prior compiler diagnostics settings from before the most + * recent bsoncxx_push_warnings() + */ +#define bsoncxx_pop_warnings() \ + bsoncxx_if_gnu_like(bsoncxx_pragma(GCC diagnostic pop);) \ + bsoncxx_if_msvc(bsoncxx_pragma(warning(pop));) \ + bsoncxx_force_semicolon + +#pragma push_macro("BSONCXX_DISABLE_WARNING_IMPL_GCC") +#define BSONCXX_DISABLE_WARNING_IMPL_GCC(...) \ + bsoncxx_if_gcc(bsoncxx_pragma(GCC diagnostic ignored __VA_ARGS__);) \ + bsoncxx_force_semicolon + +#pragma push_macro("BSONCXX_DISABLE_WARNING_IMPL_Clang") +#define BSONCXX_DISABLE_WARNING_IMPL_Clang(...) \ + bsoncxx_if_clang(bsoncxx_pragma(GCC diagnostic ignored __VA_ARGS__);) \ + bsoncxx_force_semicolon + +#pragma push_macro("BSONCXX_DISABLE_WARNING_IMPL_GNU") +#define BSONCXX_DISABLE_WARNING_IMPL_GNU(...) \ + BSONCXX_DISABLE_WARNING_IMPL_GCC(__VA_ARGS__); \ + BSONCXX_DISABLE_WARNING_IMPL_Clang(__VA_ARGS__) + +#pragma push_macro("BSONCXX_DISABLE_WARNING_IMPL_MSVC") +#define BSONCXX_DISABLE_WARNING_IMPL_MSVC(...) \ + bsoncxx_if_msvc(warning(disable : __VA_ARGS__)) + +// clang-format on diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/document/value.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/document/value.hpp index e70d50fcb5..446187f5b8 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/document/value.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/document/value.hpp @@ -232,17 +232,13 @@ class BSONCXX_API value { std::size_t _length{0}; }; -#if !defined(__clang__) && defined(__GNUC__) && (__cplusplus >= 201709L) -// Silence false positive with g++ 10.2.1 on Debian 11. -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wmaybe-uninitialized" -#endif BSONCXX_INLINE document::view value::view() const noexcept { + // Silence false positive with g++ 10.2.1 on Debian 11. + bsoncxx_push_warnings(); + bsoncxx_disable_warning(GCC("-Wmaybe-uninitialized")); return document::view{static_cast(_data.get()), _length}; + bsoncxx_pop_warnings(); } -#if !defined(__clang__) && defined(__GNUC__) && (__cplusplus >= 201709L) -#pragma GCC diagnostic pop -#endif BSONCXX_INLINE value::operator document::view() const noexcept { return view(); diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/operators.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/operators.hpp index 82fccbbbb1..898baa32f9 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/operators.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/operators.hpp @@ -94,13 +94,7 @@ class strong_ordering { #undef DEFOP }; -#ifdef __GNUC__ -#define psuedo_inline [[gnu::weak]] -#elif defined _MSC_VER -#define psuedo_inline __declspec(selectany) -#else -#define pseudo_inline -#endif +#define psuedo_inline bsoncxx_if_gnu_like([[gnu::weak]]) bsoncxx_if_msvc(__declspec(selectany)) psuedo_inline const strong_ordering strong_ordering::less = strong_ordering(strong_ordering::_construct{}, -1); diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/types.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/types.hpp index 6c38bfa5f1..af9cc787b6 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/types.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/types.hpp @@ -29,13 +29,8 @@ #pragma push_macro("BSONCXX_ENUM") #undef BSONCXX_ENUM -#if defined(__clang__) -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wfloat-equal" -#elif defined(__GNUC__) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wfloat-equal" -#endif +bsoncxx_push_warnings(); +bsoncxx_disable_warning(GNU("-Wfloat-equal")); namespace bsoncxx { inline namespace v_noabi { @@ -676,11 +671,7 @@ BSONCXX_INLINE bool operator==(const b_maxkey&, const b_maxkey&) { } // namespace v_noabi } // namespace bsoncxx -#if defined(__clang__) -#pragma clang diagnostic pop -#elif defined(__GNUC__) -#pragma GCC diagnostic pop -#endif +bsoncxx_pop_warnings(); #ifdef BSONCXX_ENUM static_assert(false, "BSONCXX_ENUM must be undef'ed"); diff --git a/src/bsoncxx/test/CMakeLists.txt b/src/bsoncxx/test/CMakeLists.txt index a685f92090..238c12cafb 100644 --- a/src/bsoncxx/test/CMakeLists.txt +++ b/src/bsoncxx/test/CMakeLists.txt @@ -94,6 +94,23 @@ if(ENABLE_MACRO_GUARD_TESTS) DEFINE_NO_DEPRECATED BSONCXX_NO_DEPRECATED BSONCXX_UNREACHABLE # prelude.hpp + BSONCXX_DISABLE_WARNING_IMPL_GCC + BSONCXX_DISABLE_WARNING_IMPL_GNU + BSONCXX_DISABLE_WARNING_IMPL_MSVC + BSONCXX_DISABLE_WARNING_IMPL_Clang + bsoncxx_push_warnings + bsoncxx_pop_warnings + bsoncxx_disable_warning + bsoncxx_concat + bsoncxx_concat_impl + bsoncxx_force_semicolon + bsoncxx_pragma + bsoncxx_stringify + bsoncxx_stringify_impl + bsoncxx_if_msvc + bsoncxx_if_gcc + bsoncxx_if_clang + bsoncxx_if_gnu INCLUDE_PATTERNS "include/*.hpp" # Public headers. "lib/*.hh" # Private headers. diff --git a/src/bsoncxx/test/type_traits.test.cpp b/src/bsoncxx/test/type_traits.test.cpp index 07aa86607c..3e54022e2b 100644 --- a/src/bsoncxx/test/type_traits.test.cpp +++ b/src/bsoncxx/test/type_traits.test.cpp @@ -4,11 +4,10 @@ #include #include -#if __GNUC__ +#include + // We declare variables that are only used for compilation checking -// (applies to Clang as well) -#pragma GCC diagnostic ignored "-Wunused" -#endif +bsoncxx_disable_warning(GNU("-Wunused")); namespace { namespace tt = bsoncxx::detail; From fb1ac4686fe5dbf72996652fc693ff89c1682e9d Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Fri, 10 Nov 2023 14:34:56 -0700 Subject: [PATCH 07/47] Disable warnings about void-dereference on Clang --- src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/iterator.hpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/iterator.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/iterator.hpp index f937a6188e..a101cb479a 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/iterator.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/iterator.hpp @@ -66,8 +66,11 @@ using to_address_t = decltype(to_address(std::declval())); /** * @brief The result of applying unary operator* to the given object, if valid */ +bsoncxx_push_warnings(); +bsoncxx_disable_warning(Clang("-Wvoid-ptr-dereference")); template using dereference_t = decltype(*std::declval()); +bsoncxx_pop_warnings(); /** * @brief Detect a type that can be dereferenced (like a pointer) and the result From 41d6765f73d9276338c618f3f8957e7c36d8ba9f Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Mon, 13 Nov 2023 13:59:08 -0700 Subject: [PATCH 08/47] Reorganize macro definitions --- .clang-format | 2 + src/bsoncxx/include/CMakeLists.txt | 1 + .../v_noabi/bsoncxx/config/compiler.hpp | 40 +++-- .../v_noabi/bsoncxx/config/postlude.hpp | 16 +- .../v_noabi/bsoncxx/config/prelude.hpp | 159 +++++------------- .../bsoncxx/v_noabi/bsoncxx/config/util.hpp | 125 ++++++++++++++ src/bsoncxx/test/CMakeLists.txt | 10 +- 7 files changed, 213 insertions(+), 140 deletions(-) create mode 100644 src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/config/util.hpp diff --git a/.clang-format b/.clang-format index 49cba22aaa..6e08b86829 100644 --- a/.clang-format +++ b/.clang-format @@ -21,3 +21,5 @@ NamespaceIndentation: None SpaceBeforeAssignmentOperators: true Standard: Cpp11 UseTab: Never +WhitespaceSensitiveMacros: + - bsoncxx_pragma diff --git a/src/bsoncxx/include/CMakeLists.txt b/src/bsoncxx/include/CMakeLists.txt index 12f2b05bf5..32d173f78a 100644 --- a/src/bsoncxx/include/CMakeLists.txt +++ b/src/bsoncxx/include/CMakeLists.txt @@ -45,6 +45,7 @@ set_dist_list(src_bsoncxx_include_DIST bsoncxx/v_noabi/bsoncxx/config/compiler.hpp bsoncxx/v_noabi/bsoncxx/config/postlude.hpp bsoncxx/v_noabi/bsoncxx/config/prelude.hpp + bsoncxx/v_noabi/bsoncxx/config/util.hpp bsoncxx/v_noabi/bsoncxx/decimal128.hpp bsoncxx/v_noabi/bsoncxx/document/element.hpp bsoncxx/v_noabi/bsoncxx/document/value.hpp diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/config/compiler.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/config/compiler.hpp index 6fdf6000a1..d18f584fdd 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/config/compiler.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/config/compiler.hpp @@ -12,21 +12,35 @@ // See the License for the specific language governing permissions and // limitations under the License. -#if defined(_MSC_VER) +// clang-format off + +#define bsoncxx_if_msvc(...) +#define bsoncxx_if_gcc(...) +#define bsoncxx_if_clang(...) +#define bsoncxx_if_gnu_like(...) \ + bsoncxx_if_gcc(__VA_ARGS__) \ + bsoncxx_if_clang(__VA_ARGS__) + +#ifdef __GNUC__ + #ifdef __clang__ + #undef bsoncxx_if_clang + #define bsoncxx_if_clang(...) __VA_ARGS__ + #else + #undef bsoncxx_if_gcc + #define bsoncxx_if_gcc(...) __VA_ARGS__ + #endif +#elif defined(_MSC_VER) + #undef bsoncxx_if_msvc + #undef bsoncxx_if_msvc(...) __VA_ARGS__ +#endif + +// clang-format on // Disable MSVC warnings that cause a lot of noise related to DLL visibility // for types that we don't control (like std::unique_ptr). -#pragma warning(push) -#pragma warning(disable : 4251 4275) +bsoncxx_push_warnings(); +bsoncxx_disable_warning(MSVC(4251)); +bsoncxx_disable_warning(MSVC(5275)); #define BSONCXX_INLINE inline BSONCXX_PRIVATE - -#define BSONCXX_CALL __cdecl - -#else - -#define BSONCXX_INLINE inline BSONCXX_PRIVATE - -#define BSONCXX_CALL - -#endif +#define BSONCXX_CALL bsoncxx_if_msvc(__cdecl) diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/config/postlude.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/config/postlude.hpp index 4279d3f4c8..9011627fc7 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/config/postlude.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/config/postlude.hpp @@ -15,9 +15,7 @@ // compiler.hpp #undef BSONCXX_INLINE #pragma pop_macro("BSONCXX_INLINE") -#if defined(_MSC_VER) -#pragma warning(pop) -#endif +bsoncxx_pop_warnings(); #undef BSONCXX_CALL #pragma pop_macro("BSONCXX_CALL") @@ -67,7 +65,7 @@ #undef BSONCXX_UNREACHABLE #pragma pop_macro("BSONCXX_UNREACHABLE") -#pragma pop_macro("mongo_cxx14_constexpr") +#pragma pop_macro("bsoncxx_cxx14_constexpr") #pragma pop_macro("bsoncxx_returns") // CXX-2769: out-of-place, but remains for backward compatibility. @@ -76,19 +74,21 @@ static_assert(false, "BSONCXX_ENUM must be undef'ed"); #endif #pragma pop_macro("BSONCXX_ENUM") +// util.hpp #pragma pop_macro("bsoncxx_push_warnings") #pragma pop_macro("bsoncxx_pop_warnings") #pragma pop_macro("bsoncxx_disable_warning") -#pragma pop_macro("BSONCXX_DISABLE_WARNING_IMPL_MSVC") -#pragma pop_macro("BSONCXX_DISABLE_WARNING_IMPL_GCC") -#pragma pop_macro("BSONCXX_DISABLE_WARNING_IMPL_GNU") -#pragma pop_macro("BSONCXX_DISABLE_WARNING_IMPL_Clang") +#pragma pop_macro("_bsoncxxDisableWarningImpl_for_MSVC") +#pragma pop_macro("_bsoncxxDisableWarningImpl_for_GCC") +#pragma pop_macro("_bsoncxxDisableWarningImpl_for_GNU") +#pragma pop_macro("_bsoncxxDisableWarningImpl_for_Clang") #pragma pop_macro("bsoncxx_concat") #pragma pop_macro("bsoncxx_concat_impl") #pragma pop_macro("bsoncxx_pragma") +#pragma pop_macro("_bsoncxxPragma") #pragma pop_macro("bsoncxx_stringify_impl") #pragma pop_macro("bsoncxx_stringify") #pragma pop_macro("bsoncxx_force_semicolon") diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/config/prelude.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/config/prelude.hpp index 98666b524a..fdc77ce970 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/config/prelude.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/config/prelude.hpp @@ -12,11 +12,53 @@ // See the License for the specific language governing permissions and // limitations under the License. +// util.hpp +#pragma push_macro("bsoncxx_concat") +#undef bsoncxx_concat +#pragma push_macro("bsoncxx_concat_impl") +#undef bsoncxx_concat_impl +#pragma push_macro("bsoncxx_stringify") +#undef bsoncxx_stringify +#pragma push_macro("bsoncxx_stringify_impl") +#undef bsoncxx_stringify_impl +#pragma push_macro("bsoncxx_pragma") +#undef bsoncxx_pragma +#pragma push_macro("_bsoncxxPragma") +#undef _bsoncxxPragma +#pragma push_macro("bsoncxx_force_semicolon") +#undef bsoncxx_force_semicolon +#pragma push_macro("bsoncxx_returns") +#undef bsoncxx_returns +#pragma push_macro("bsoncxx_cxx14_constexpr") +#undef bsoncxx_cxx14_constexpr +#pragma push_macro("bsoncxx_disable_warning") +#undef bsoncxx_disable_warning +#pragma push_macro("bsoncxx_push_warnings") +#undef bsoncxx_push_warnings +#pragma push_macro("bsoncxx_pop_warnings") +#undef bsoncxx_pop_warnings +#pragma push_macro("_bsoncxxDisableWarningImpl_for_GCC") +#undef _bsoncxxDisableWarningImpl_for_GCC +#pragma push_macro("_bsoncxxDisableWarningImpl_for_Clang") +#undef _bsoncxxDisableWarningImpl_for_Clang +#pragma push_macro("_bsoncxxDisableWarningImpl_for_MSVC") +#undef _bsoncxxDisableWarningImpl_for_MSVC +#pragma push_macro("_bsoncxxDisableWarningImpl_for_GNU") +#undef _bsoncxxDisableWarningImpl_for_GNU + // compiler.hpp #pragma push_macro("BSONCXX_INLINE") #undef BSONCXX_INLINE #pragma push_macro("BSONCXX_CALL") #undef BSONCXX_CALL +#pragma push_macro("bsoncxx_if_msvc") +#undef bsoncxx_if_msvc +#pragma push_macro("bsoncxx_if_gcc") +#undef bsoncxx_if_gcc +#pragma push_macro("bsoncxx_if_clang") +#undef bsoncxx_if_clang +#pragma push_macro("bsoncxx_if_gnu_like") +#undef bsoncxx_if_gnu_like // config.hpp (generated by CMake) #pragma push_macro("BSONCXX_INLINE_NAMESPACE_BEGIN") @@ -60,6 +102,8 @@ #pragma push_macro("BSONCXX_NO_DEPRECATED") #undef BSONCXX_NO_DEPRECATED +#include +// #include #include #include @@ -90,118 +134,3 @@ /// @namespace bsoncxx::v_noabi::stdx /// Declares polyfills for C++17 forward compatibility. /// - -#pragma push_macro("mongo_cxx14_constexpr") -#if __cplusplus >= 201402L -#define mongo_cxx14_constexpr constexpr -#else -#define mongo_cxx14_constexpr inline -#endif - -#pragma push_macro("bsoncxx_returns") -/** - * @brief Add a trailing noexcept, decltype-return, and return-body to a function definition. - */ -#define bsoncxx_returns(...) \ - noexcept(noexcept(__VA_ARGS__))->decltype(__VA_ARGS__) { \ - return __VA_ARGS__; \ - } \ - bsoncxx_force_semicolon - -// clang-format off - -#pragma push_macro("bsoncxx_if_msvc") -#define bsoncxx_if_msvc(...) -#pragma push_macro("bsoncxx_if_gcc") -#define bsoncxx_if_gcc(...) -#pragma push_macro("bsoncxx_if_clang") -#define bsoncxx_if_clang(...) -#pragma push_macro("bsoncxx_if_gnu_like") -#define bsoncxx_if_gnu_like(...) \ - bsoncxx_if_gcc(__VA_ARGS__) \ - bsoncxx_if_clang(__VA_ARGS__) - -#ifdef __GNUC__ - #ifdef __clang__ - #undef bsoncxx_if_clang - #define bsoncxx_if_clang(...) __VA_ARGS__ - #else - #undef bsoncxx_if_gcc - #define bsoncxx_if_gcc(...) __VA_ARGS__ - #endif -#elif defined(_MSC_VER) - #undef bsoncxx_if_msvc - #undef bsoncxx_if_msvc(...) __VA_ARGS__ -#endif - -#pragma push_macro("bsoncxx_stringify") -#pragma push_macro("bsoncxx_stringify_impl") -#define bsoncxx_stringify(...) bsoncxx_stringify_impl(__VA_ARGS__) -#define bsoncxx_stringify_impl(...) #__VA_ARGS__ - -#pragma push_macro("bsoncxx_pragma") -#define bsoncxx_pragma(...) _Pragma(bsoncxx_stringify(__VA_ARGS__)) - -#pragma push_macro("bsoncxx_force_semicolon") -/** - * @brief Use in a declaration position to force the appearence of a semicolon as the next token - */ -#define bsoncxx_force_semicolon static_assert(true, "") - -#pragma push_macro("bsoncxx_concat") -#pragma push_macro("bsoncxx_concat_impl") -#define bsoncxx_concat(A, ...) bsoncxx_concat_impl(A, __VA_ARGS__) -#define bsoncxx_concat_impl(A, ...) A##__VA_ARGS__ - -#pragma push_macro("bsoncxx_disable_warning") -/** - * @brief Disable a warning for a particular compiler. - * - * The argument should be of the form: - * - * - Clang() - * - GCC() - * - GNU() - * - MSVC() - */ -#define bsoncxx_disable_warning(Spec) bsoncxx_concat(BSONCXX_DISABLE_WARNING_IMPL_, Spec) - -#pragma push_macro("bsoncxx_push_warnings") -/** - * @brief Push the current compiler diagnostics settings state - */ -#define bsoncxx_push_warnings() \ - bsoncxx_if_gnu_like(bsoncxx_pragma(GCC diagnostic push);) \ - bsoncxx_if_msvc(bsoncxx_pragma(warning(push));) \ - bsoncxx_force_semicolon - -#pragma push_macro("bsoncxx_pop_warnings") -/** - * @brief Restore prior compiler diagnostics settings from before the most - * recent bsoncxx_push_warnings() - */ -#define bsoncxx_pop_warnings() \ - bsoncxx_if_gnu_like(bsoncxx_pragma(GCC diagnostic pop);) \ - bsoncxx_if_msvc(bsoncxx_pragma(warning(pop));) \ - bsoncxx_force_semicolon - -#pragma push_macro("BSONCXX_DISABLE_WARNING_IMPL_GCC") -#define BSONCXX_DISABLE_WARNING_IMPL_GCC(...) \ - bsoncxx_if_gcc(bsoncxx_pragma(GCC diagnostic ignored __VA_ARGS__);) \ - bsoncxx_force_semicolon - -#pragma push_macro("BSONCXX_DISABLE_WARNING_IMPL_Clang") -#define BSONCXX_DISABLE_WARNING_IMPL_Clang(...) \ - bsoncxx_if_clang(bsoncxx_pragma(GCC diagnostic ignored __VA_ARGS__);) \ - bsoncxx_force_semicolon - -#pragma push_macro("BSONCXX_DISABLE_WARNING_IMPL_GNU") -#define BSONCXX_DISABLE_WARNING_IMPL_GNU(...) \ - BSONCXX_DISABLE_WARNING_IMPL_GCC(__VA_ARGS__); \ - BSONCXX_DISABLE_WARNING_IMPL_Clang(__VA_ARGS__) - -#pragma push_macro("BSONCXX_DISABLE_WARNING_IMPL_MSVC") -#define BSONCXX_DISABLE_WARNING_IMPL_MSVC(...) \ - bsoncxx_if_msvc(warning(disable : __VA_ARGS__)) - -// clang-format on diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/config/util.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/config/util.hpp new file mode 100644 index 0000000000..65be925b16 --- /dev/null +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/config/util.hpp @@ -0,0 +1,125 @@ +// clang-format off +/** + * @brief Convert the given macro argument to a string literal, after macro expansion + */ +#define bsoncxx_stringify(...) bsoncxx_stringify_impl(__VA_ARGS__) +#define bsoncxx_stringify_impl(...) #__VA_ARGS__ + +/** + * @brief Token-paste two macro arguments, after macro expansion + */ +#define bsoncxx_concat(A, ...) bsoncxx_concat_impl(A, __VA_ARGS__) +#define bsoncxx_concat_impl(A, ...) A##__VA_ARGS__ + +/** + * @brief Expands to a _Pragma() preprocessor directive, after macro expansion + * + * The arguments an arbitrary "token soup", and should not be quoted like a regular + * _Pragma. This macro will stringify-them itself. + * + * Example: + * + * bsoncxx_pragma(GCC diagnostic ignore "-Wconversion") + * + * will become: + * + * _Pragma("GCC diagnostic ignore \"-Wconversion\"") + * + */ +#define bsoncxx_pragma(...) _bsoncxxPragma(__VA_ARGS__) +#ifdef _MSC_VER +// Old MSVC doesn't recognize C++11 _Pragma(), but it always recognized __pragma +#define _bsoncxxPragma(...) __pragma(bsoncxx_stringify(__VA_ARGS__)) +#else +#define _bsoncxxPragma(...) _Pragma(bsoncxx_stringify(__VA_ARGS__)) +#endif + +/** + * @brief Use in a declaration position to force the appearence of a semicolon + * as the next token. Use this for statement-like or declaration-like macros to + * enforce that their call sites are followed by a semicolon + */ +#define bsoncxx_force_semicolon static_assert(true, "") + +/** + * @brief Add a trailing noexcept, decltype-return, and return-body to a + * function definition. (Not compatible with lambda expressions.) + * + * Example: + * + * template + * auto foo(T x, T y) bsoncxx_returns(x + y); + * + * Becomes: + * + * template + * auto foo(T x, T y) noexcept(noexcept(x + y)) + * -> decltype(x + y) + * { return x + y }; + * + */ +#define bsoncxx_returns(...) \ + noexcept(noexcept(__VA_ARGS__))->decltype(__VA_ARGS__) { \ + return __VA_ARGS__; \ + } \ + bsoncxx_force_semicolon + +/** + * @macro mongocxx_cxx14_constexpr + * @brief Expands to `constexpr` if compiling as c++14 or greater, otherwise + * expands to `inline`. + * + * Use this on functions that can only be constexpr in C++14 or newer, including + * non-const member functions. + */ +#if __cplusplus >= 201402L +#define bsoncxx_cxx14_constexpr constexpr +#else +#define bsoncxx_cxx14_constexpr inline +#endif + +/** + * @brief Disable a warning for a particular compiler. + * + * The argument should be of the form: + * + * - Clang() + * - GCC() + * - GNU() + * - MSVC() + * + * The "GNU" form applies to both GCC and Clang + */ +#define bsoncxx_disable_warning(Spec) \ + bsoncxx_concat(_bsoncxxDisableWarningImpl_for_, Spec) \ + bsoncxx_force_semicolon + +/** + * @brief Push the current compiler diagnostics settings state + */ +#define bsoncxx_push_warnings() \ + bsoncxx_if_gnu_like(bsoncxx_pragma(GCC diagnostic push)) \ + bsoncxx_if_msvc(bsoncxx_pragma(warning(push))) \ + bsoncxx_force_semicolon + +/** + * @brief Restore prior compiler diagnostics settings from before the most + * recent bsoncxx_push_warnings() + */ +#define bsoncxx_pop_warnings() \ + bsoncxx_if_gnu_like(bsoncxx_pragma(GCC diagnostic pop)) \ + bsoncxx_if_msvc(bsoncxx_pragma(warning(pop))) \ + bsoncxx_force_semicolon + +#define _bsoncxxDisableWarningImpl_for_GCC(...) \ + bsoncxx_if_gcc(bsoncxx_pragma(GCC diagnostic ignored __VA_ARGS__)) + +#define _bsoncxxDisableWarningImpl_for_Clang(...) \ + bsoncxx_if_clang(bsoncxx_pragma(GCC diagnostic ignored __VA_ARGS__)) + +#define _bsoncxxDisableWarningImpl_for_GNU(...) \ + _bsoncxxDisableWarningImpl_for_GCC(__VA_ARGS__) \ + _bsoncxxDisableWarningImpl_for_Clang(__VA_ARGS__) + +#define _bsoncxxDisableWarningImpl_for_MSVC(...) \ + bsoncxx_if_msvc(warning(disable : __VA_ARGS__)) diff --git a/src/bsoncxx/test/CMakeLists.txt b/src/bsoncxx/test/CMakeLists.txt index 238c12cafb..915246971e 100644 --- a/src/bsoncxx/test/CMakeLists.txt +++ b/src/bsoncxx/test/CMakeLists.txt @@ -94,10 +94,10 @@ if(ENABLE_MACRO_GUARD_TESTS) DEFINE_NO_DEPRECATED BSONCXX_NO_DEPRECATED BSONCXX_UNREACHABLE # prelude.hpp - BSONCXX_DISABLE_WARNING_IMPL_GCC - BSONCXX_DISABLE_WARNING_IMPL_GNU - BSONCXX_DISABLE_WARNING_IMPL_MSVC - BSONCXX_DISABLE_WARNING_IMPL_Clang + _bsoncxxDisableWarningImpl_for_GCC + _bsoncxxDisableWarningImpl_for_GNU + _bsoncxxDisableWarningImpl_for_MSVC + _bsoncxxDisableWarningImpl_for_Clang bsoncxx_push_warnings bsoncxx_pop_warnings bsoncxx_disable_warning @@ -105,12 +105,14 @@ if(ENABLE_MACRO_GUARD_TESTS) bsoncxx_concat_impl bsoncxx_force_semicolon bsoncxx_pragma + _bsoncxxPragma bsoncxx_stringify bsoncxx_stringify_impl bsoncxx_if_msvc bsoncxx_if_gcc bsoncxx_if_clang bsoncxx_if_gnu + bsoncxx_returns INCLUDE_PATTERNS "include/*.hpp" # Public headers. "lib/*.hh" # Private headers. From 3868e351b20e8000a1b6d352a4ef683141c51a57 Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Mon, 13 Nov 2023 17:34:16 -0700 Subject: [PATCH 09/47] Fix: malformed pragmas on MSVC --- .../include/bsoncxx/v_noabi/bsoncxx/config/compiler.hpp | 2 +- src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/config/util.hpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/config/compiler.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/config/compiler.hpp index d18f584fdd..9ea7981760 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/config/compiler.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/config/compiler.hpp @@ -31,7 +31,7 @@ #endif #elif defined(_MSC_VER) #undef bsoncxx_if_msvc - #undef bsoncxx_if_msvc(...) __VA_ARGS__ + #define bsoncxx_if_msvc(...) __VA_ARGS__ #endif // clang-format on diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/config/util.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/config/util.hpp index 65be925b16..276895b495 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/config/util.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/config/util.hpp @@ -29,7 +29,7 @@ #define bsoncxx_pragma(...) _bsoncxxPragma(__VA_ARGS__) #ifdef _MSC_VER // Old MSVC doesn't recognize C++11 _Pragma(), but it always recognized __pragma -#define _bsoncxxPragma(...) __pragma(bsoncxx_stringify(__VA_ARGS__)) +#define _bsoncxxPragma(...) __pragma(__VA_ARGS__) #else #define _bsoncxxPragma(...) _Pragma(bsoncxx_stringify(__VA_ARGS__)) #endif @@ -122,4 +122,4 @@ _bsoncxxDisableWarningImpl_for_Clang(__VA_ARGS__) #define _bsoncxxDisableWarningImpl_for_MSVC(...) \ - bsoncxx_if_msvc(warning(disable : __VA_ARGS__)) + bsoncxx_if_msvc(bsoncxx_pragma(warning(disable : __VA_ARGS__))) From c7350d3b9779e7b30382ee419978311a5e091ae9 Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Tue, 14 Nov 2023 11:59:35 -0700 Subject: [PATCH 10/47] A small amount of std::ranges from the future --- src/bsoncxx/include/CMakeLists.txt | 1 + .../bsoncxx/v_noabi/bsoncxx/stdx/ranges.hpp | 247 ++++++++++++++++++ .../v_noabi/bsoncxx/stdx/type_traits.hpp | 3 +- src/bsoncxx/test/CMakeLists.txt | 2 + src/bsoncxx/test/ranges.test.cpp | 50 ++++ 5 files changed, 301 insertions(+), 2 deletions(-) create mode 100644 src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/ranges.hpp create mode 100644 src/bsoncxx/test/ranges.test.cpp diff --git a/src/bsoncxx/include/CMakeLists.txt b/src/bsoncxx/include/CMakeLists.txt index 32d173f78a..0d3beb2e21 100644 --- a/src/bsoncxx/include/CMakeLists.txt +++ b/src/bsoncxx/include/CMakeLists.txt @@ -61,6 +61,7 @@ set_dist_list(src_bsoncxx_include_DIST bsoncxx/v_noabi/bsoncxx/stdx/make_unique.hpp bsoncxx/v_noabi/bsoncxx/stdx/optional.hpp bsoncxx/v_noabi/bsoncxx/stdx/operators.hpp + bsoncxx/v_noabi/bsoncxx/stdx/ranges.hpp bsoncxx/v_noabi/bsoncxx/stdx/string_view.hpp bsoncxx/v_noabi/bsoncxx/stdx/type_traits.hpp bsoncxx/v_noabi/bsoncxx/string/to_string.hpp diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/ranges.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/ranges.hpp new file mode 100644 index 0000000000..f37fe61a6e --- /dev/null +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/ranges.hpp @@ -0,0 +1,247 @@ +/** + * @file ranges.hpp + * @brief A backport of a small amount of std::ranges from C++20 + * @date 2023-11-14 + * + * @copyright Copyright (c) 2023 + */ +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +namespace bsoncxx { +inline namespace v_noabi { +namespace detail { + +/** + * XXX: These _decay_xyz functions are required for MSVC 14.0 (VS2015) compat. + * + * The requirements on each of the below invocable objects is that the decay-copied + * return type meet certain requirements. It would be easier to include these + * requirements inline directly via enable_if/requires_t, but it is difficult to + * position them in a way that doesn't confuse MSVC 14.0. The most reliable + * configuration is to use a SFINAE-disappearing return type, so these functions + * serve that purpose while simultaneously performing the required decay-copy. + * + * It's possible that these are actually easier on the eyes than the inline + * requirements… + */ +template +constexpr requires_t> _decay_iterator(I i) noexcept { + return i; +} + +template +constexpr requires_t> _decay_sentinel(S s) noexcept { + return s; +} + +template +constexpr requires_t> _decay_integral(Sz s) noexcept { + return s; +} + +template +constexpr requires_t> _decay_copy_pointer(P p) noexcept { + return p; +} + +/** + * @brief Access the beginning iterator of a range-like object. + * + * Requires that the result is a valid iterator type + * + * Based on std::ranges::begin() + */ +static constexpr struct _begin_fn { + // 1: Object is an array + template + static constexpr auto impl(El (&arr)[N], rank<5>) bsoncxx_returns(arr + 0); + + // 2: Object has member .begin() returning an iterator + template + static constexpr auto impl(R& rng, rank<4>) bsoncxx_returns(_decay_iterator(rng.begin())); + + // 3: Object has an ADL-visible begin(x) returning an iterator + template + static constexpr auto impl(R& rng, rank<3>) bsoncxx_returns(_decay_iterator(begin(rng))); + + template + constexpr auto operator()(R&& rng) const bsoncxx_returns((impl)(rng, rank<10>{})); +} begin; + +/** + * @brief Yields the iterator result from calling begin(R&), if that expression + * is valid + */ +template +using iterator_t = decltype(begin(std::declval())); + +/** + * @brief Access the sentinel value for a range-like object. + * + * Requires that a valid begin() is also available, and that the end() returns + * a type which is_sentinel_for the type iterator_t + * + * Based on std::ranges::end(). + */ +static constexpr struct _end_fn { + // 1: Range is an array + template + static constexpr auto impl(El (&arr)[N], rank<5>) bsoncxx_returns(arr + N); + + // 2: Range has member .end() returning a valid sentinel + template + static constexpr auto impl(R& rng, rank<4>) bsoncxx_returns(_decay_sentinel(rng.end())); + + // 3: Range has ADL-found end(x) returning a valid sentinel + template + static constexpr auto impl(R& r, rank<3>) bsoncxx_returns(_decay_sentinel(end(r))); + + template + constexpr auto operator()(R&& rng) const bsoncxx_returns((impl>)(rng, rank<5>{})); +} end; + +/** + * @brief Yield the type resulting from end(R&), if that expression is valid + */ +template +using sentinel_t = decltype(end(std::declval())); + +/** + * @brief Obtain the size of the given range `rng`. + * + * Returns the first valid of: + * - The bounds of the array, if `rng` is an array + * - The result of rng.size() on R, if that returns an integral type + * - The result of size(rng), if such a name is visible via ADL and returns + * an integral type. + * - The value of (end(rng) - begin(rng)) as an unsigned integer if `rng` is + * forward-iterable and the sentinel is a sized sentinel type. + */ +static constexpr struct _size_fn { + // 1: Array of known bound + template + static constexpr auto impl(Element (&)[N], rank<5>) bsoncxx_returns(N); + + // 2: Range with member .size() + template + static constexpr auto impl(R& rng, rank<4>) bsoncxx_returns(_decay_integral(rng.size())); + + // 3: Range with ADL-found size(x) + template + static constexpr auto impl(R& rng, rank<3>) bsoncxx_returns(_decay_integral(size(rng))); + + // 4: Range is a forward-range and has a sized sentinel type + template < + typename R, + typename Iter = iterator_t, + typename Sentinel = sentinel_t, + // Require a forward iterator: + requires_t>> = 0, + // Require a sized sentinel: + requires_t> = 0, + // We cast to an unsigned type from the difference type: + typename Sz = make_unsigned_t>> + static constexpr auto impl(R& rng, rank<3>) + bsoncxx_returns(static_cast(end(rng) - begin(rng))); + + template + constexpr auto operator()(R&& rng) const bsoncxx_returns((impl)(rng, rank<10>{})); +} size; + +/** + * @brief Obtain the size type of the given range + */ +template +using range_size_t = decltype(size(std::declval())); + +/** + * @brief Obtain the size of the given range as a signed integer type + */ +static constexpr struct _ssize_fn { + template , + typename Signed = make_signed_t, + typename RetDiff = + conditional_t<(sizeof(Signed) > sizeof(std::ptrdiff_t)), Signed, std::ptrdiff_t>> + constexpr auto operator()(R&& rng) const bsoncxx_returns(static_cast(size(rng))); +} ssize; + +/** + * @brief Obtain the difference type of the given range + */ +template +using range_difference_t = iter_difference_t>; + +/** + * @brief Obtain a pointer-to-data for the given `rng`. + * + * Returns the first valid of: + * - `rng.data()` if such expression yields a pointer type + * - `data(rng)` if such expression is visible via ADL and returns a pointer type + * - `to_address(begin(rng))` if such expression is valid and iterator_t is + * a contiguous_iterator. + */ +static constexpr struct _data_fn { + template + static constexpr auto impl(R&& rng, rank<2>) bsoncxx_returns(_decay_copy_pointer(rng.data())); + + template >> = 0> + static constexpr auto impl(R&& rng, rank<1>) bsoncxx_returns(to_address(begin(rng))); + + template + constexpr auto operator()(R&& rng) const bsoncxx_returns((impl)(rng, rank<10>{})); +} data; + +/** + * @brief Get the type returned by data(R&), if valid + */ +template +using range_data_t = decltype(data(std::declval())); + +/** + * @brief Get the value type of the range + * + * Equivalent: iter_value_t> + */ +template +using range_value_t = iter_value_t>; + +template +using range_concept_t = iterator_concept_t>; + +/** + * @brief Trait detects if the given type is a range + */ +template +struct is_range : conjunction, is_detected> {}; + +/** + * @brief Detect if the given range is contiguous-ish. + * + * This is not quite like ranges::contiguous_range, as it does not require that + * the iterator be configuous. It only looks for a valid data(R) and size(R). + * Without stdlib support, we cannot fully detect contiguous_iterators, but we + * want to be able to support, basic_string, vector, array, etc, which + * have .data() and .size() + */ +template +struct is_contiguous_range + : conjunction, is_detected, is_detected> {}; + +} // namespace detail +} // namespace v_noabi +} // namespace bsoncxx + +#include diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/type_traits.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/type_traits.hpp index 08d458a503..5cac345d18 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/type_traits.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/type_traits.hpp @@ -459,8 +459,7 @@ struct rank<0> {}; struct _decay_copy_fn { template constexpr auto operator()(T&& arg) const - noexcept(std::is_nothrow_constructible, T&&>{}) - -> requires_t, std::is_constructible, T&&>> { + noexcept(noexcept(static_cast>(static_cast(arg)))) -> decay_t { return static_cast>(static_cast(arg)); } }; diff --git a/src/bsoncxx/test/CMakeLists.txt b/src/bsoncxx/test/CMakeLists.txt index 915246971e..dcfa1480e4 100644 --- a/src/bsoncxx/test/CMakeLists.txt +++ b/src/bsoncxx/test/CMakeLists.txt @@ -38,6 +38,7 @@ add_executable(test_bson oid.cpp view_or_value.cpp make_unique.test.cpp + ranges.test.cpp type_traits.test.cpp iterator.test.cpp ) @@ -144,4 +145,5 @@ set_dist_list(src_bsoncxx_test_DIST type_traits.test.cpp make_unique.test.cpp iterator.test.cpp + ranges.test.cpp ) diff --git a/src/bsoncxx/test/ranges.test.cpp b/src/bsoncxx/test/ranges.test.cpp new file mode 100644 index 0000000000..9d317dd6d1 --- /dev/null +++ b/src/bsoncxx/test/ranges.test.cpp @@ -0,0 +1,50 @@ +#include +#include +#include + +#include +#include +#include + +namespace ranges = bsoncxx::detail; + +static_assert(ranges::is_range>{}, "fail"); +static_assert(ranges::is_contiguous_range>{}, "fail"); +static_assert(ranges::is_contiguous_range&>{}, "fail"); +static_assert(ranges::is_contiguous_range const&>{}, "fail"); + +static_assert( + std::is_same>, std::vector::difference_type>{}, + "fail"); + +static_assert(ranges::is_range{}, "fail"); +static_assert(ranges::is_contiguous_range{}, "fail"); +static_assert(std::is_same, std::ptrdiff_t>{}, "fail"); + +static_assert(ranges::is_range>{}, "fail"); +static_assert(!ranges::is_contiguous_range>{}, "fail"); + +TEST_CASE("Range from vector") { + std::vector nums = {1, 2, 3, 4}; + auto it = ranges::begin(nums); + REQUIRE(it != ranges::end(nums)); + static_assert(std::is_same::iterator>::value, "fail"); + CHECK(*it == 1); + ++it; + CHECK(it == std::next(ranges::begin(nums))); + CHECK(*it == 2); + CHECK(ranges::size(nums) == 4); + CHECK(ranges::ssize(nums) == 4); + CHECK(ranges::data(nums) == nums.data()); + CHECK(ranges::to_address(ranges::begin(nums)) == nums.data()); +} + +TEST_CASE("Range from array") { + int array[] = {1, 2, 3, 4}; + auto it = ranges::begin(array); + CHECK(it == array + 0); + CHECK(ranges::end(array) == array + 4); + CHECK(ranges::size(array) == 4); + CHECK(ranges::ssize(array) == 4); + CHECK(ranges::data(array) == ranges::begin(array)); +} \ No newline at end of file From c13e052f6b49157e8c15e831123fec5c2da097ae Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Tue, 14 Nov 2023 14:39:12 -0700 Subject: [PATCH 11/47] Bring our own std::string_view --- .../v_noabi/bsoncxx/stdx/string_view.hpp | 485 +++++++++++++++--- src/bsoncxx/lib/CMakeLists.txt | 2 + .../v_noabi/bsoncxx/stdx/string_view.cpp | 14 + src/bsoncxx/test/CMakeLists.txt | 2 + src/bsoncxx/test/string_view.test.cpp | 159 ++++++ 5 files changed, 585 insertions(+), 77 deletions(-) create mode 100644 src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/stdx/string_view.cpp create mode 100644 src/bsoncxx/test/string_view.test.cpp diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/string_view.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/string_view.hpp index d58b7d6c21..bb3bbd5a11 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/string_view.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/string_view.hpp @@ -14,92 +14,423 @@ #pragma once -#include - -#if defined(BSONCXX_POLY_USE_MNMLSTC) - -#include - -namespace bsoncxx { -inline namespace v_noabi { -namespace stdx { - -using ::core::basic_string_view; -using ::core::string_view; - -} // namespace stdx -} // namespace v_noabi -} // namespace bsoncxx - -#elif defined(BSONCXX_POLY_USE_BOOST) - -#include - -#if BOOST_VERSION >= 106100 - -#include - -namespace bsoncxx { -inline namespace v_noabi { -namespace stdx { - -using ::boost::basic_string_view; -using ::boost::string_view; - -} // namespace stdx -} // namespace v_noabi -} // namespace bsoncxx - -#else +#include +#include +#include +#include +#include +#include +#include +#include + +#include "./iterator.hpp" +#include "./operators.hpp" +#include "./ranges.hpp" +#include "./type_traits.hpp" -#include - -namespace bsoncxx { -inline namespace v_noabi { -namespace stdx { - -template > -using basic_string_view = ::boost::basic_string_ref; -using string_view = ::boost::string_ref; - -} // namespace stdx -} // namespace v_noabi -} // namespace bsoncxx - -#endif - -#elif defined(BSONCXX_POLY_USE_STD_EXPERIMENTAL) - -#include - -namespace bsoncxx { -inline namespace v_noabi { -namespace stdx { - -using ::std::experimental::basic_string_view; -using ::std::experimental::string_view; - -} // namespace stdx -} // namespace v_noabi -} // namespace bsoncxx - -#elif defined(BSONCXX_POLY_USE_STD) - -#include +#include namespace bsoncxx { inline namespace v_noabi { namespace stdx { -using ::std::basic_string_view; -using ::std::string_view; +namespace detail { + +using namespace bsoncxx::detail; + +[[noreturn]] BSONCXX_API void string_view_oob_terminate(const char* msg, + std::size_t length, + std::ptrdiff_t offset) noexcept; + +// Detects a c_str() method (to detect string-like types) +template +using c_str_t = decltype(std::declval().c_str()); + +} // namespace detail + +/** + * @brief Implementation of std::string_view-like class template + */ +template > +class basic_string_view : detail::equality_operators, detail::ordering_operators { + public: + // Pointer to (non-const) character type + using pointer = Char*; + // Pointer to const-character type + using const_pointer = const Char*; + // Type representing the size of a string + using size_type = std::size_t; + // Type representing the offset within a string + using difference_type = std::ptrdiff_t; + // The type of the string character + using value_type = Char; + + // Constant sentinel value to represent an impossible/invalid string position + static constexpr size_type npos = static_cast(-1); + + private: + // Pointer to the beginning of the string being viewed + const_pointer _begin = nullptr; + // The size of the array that is being viewed via `_begin` + size_type _size = 0; + // Alias of our own type + using self_type = basic_string_view; + + /** + * @brief If R is a type for which we want to permit from-range construction, + * evaluates to the type `int`. Otherwise, is a substitution failure. + */ + template + using _enable_range_constructor = + detail::requires_t, + // Don't eat our own copy/move constructor: + detail::negation>, + // Don't handle character arrays (we use a different constructor for + // that) + detail::negation>, + // The range's value must be the same as our character type + std::is_same, value_type>>; + + public: + using traits_type = Traits; + using reference = Char&; + using const_reference = const Char&; + using iterator = const_pointer; + using const_iterator = iterator; + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + + /** + * @brief Default constructor. Constructs to an empty/null string view + */ + constexpr basic_string_view() = default; + + /// Default copy/move/assign/destroy + + /** + * @brief Construct a new string view from a pointer-to-character and an + * array length. + */ + constexpr basic_string_view(const_pointer s, size_type count) noexcept + : _begin(s), _size(count) {} + + /** + * @brief Construct a new string view from a C-style null-terminated character array. + * + * The string size is inferred as-if by strlen() + */ + constexpr basic_string_view(const_pointer s) noexcept + : _begin(s), _size(traits_type::length(s)) {} + + /** + * Iterator pair range constructor + * + * Requires that `Iterator` be a contiguous iterator, that `Sentinel` be a sized sentinel for + * `Iterator`, and that the value-type of `Iterator` is the character type of the string. + */ + template < + typename Iterator, + typename Sentinel, + detail::requires_t> = 0, + // Requires: The iterator value_type be the same as our value_type + detail::requires_t, value_type>> = 0, + // Requires: We can get a pointer from the iterator via to_address: + detail::requires_t> = 0, + // Requires: "Sentinel" is *not* convertible to std::size_t + // (prevents ambiguity with the pointer+size constructor) + detail::requires_t>> = 0> + constexpr basic_string_view(Iterator iter, Sentinel stop) noexcept + : _begin(detail::to_address(iter)), _size(static_cast(stop - iter)) {} + + /** + * @brief From-range constructor for non-string-like types. This is an explicit constructor. + * + * Requires that `Range` is a non-array contiguous range with the same value + * type as the string view. + */ + template = 0, + detail::requires_t>> + RequiresNotString = 0> + constexpr explicit basic_string_view(Range&& rng) + : _begin(detail::data(rng)), _size(detail::size(rng)) {} + + /** + * @brief From-range constructor, but is an implicit conversion accepting string-like ranges. + * (Seeks a .c_str() member) + * + * Requires that `Range` is a non-array contiguous range with the same value type + * as the string view, and is a std::string-like value. + */ + template < + typename Range, + _enable_range_constructor = 0, + detail::requires_t> RequiresStringLike = 0> + constexpr basic_string_view(Range&& rng) noexcept + : _begin(detail::data(rng)), _size(detail::size(rng)) {} + + // Construction from a null pointer is deleted + basic_string_view(std::nullptr_t) = delete; + + constexpr iterator begin() const noexcept { + return iterator(_begin); + } + constexpr iterator end() const noexcept { + return begin() + size(); + } + constexpr iterator cbegin() const noexcept { + return begin(); + } + constexpr iterator cend() const noexcept { + return end(); + } + + constexpr reverse_iterator rbegin() const noexcept { + return reverse_iterator{end()}; + } + + constexpr reverse_iterator rend() const noexcept { + return reverse_iterator{begin()}; + } + + constexpr const_reverse_iterator crbegin() const noexcept { + return const_reverse_iterator{cend()}; + } + + constexpr const_reverse_iterator crend() const noexcept { + return const_reverse_iterator{crbegin()}; + } + + /** + * @brief Access the Nth element of the referred-to string + * + * @param offset A zero-based offset within the string to access. Must be less + * than size() + */ + constexpr const_reference operator[](size_type offset) const noexcept { + return (_assert_inbounds(offset, for_access, "basic_string_view::operator[]"), + _begin[offset]); + } + + /** + * @brief Access the Nth element of the referred-to string. + * + * @param pos A zero-based offset within the string to access. If not less + * than size(), throws std::out_of_range + */ + bsoncxx_cxx14_constexpr const_reference at(size_type pos) const { + if (pos >= size()) { + throw std::out_of_range{"string_view::at()"}; + } + return _begin[pos]; + } + /// Access the first character in the string + constexpr const_reference front() const noexcept { + return (_assert_inbounds(0, for_access, "basic_string_view::front()"), (*this)[0]); + } + /// Access the last character in the string + constexpr const_reference back() const noexcept { + return (_assert_inbounds(size() - 1, for_access, "basic_string_view::back()"), + (*this)[size() - 1]); + } + + /// Obtain a pointer to the beginning of the referred-to character array + constexpr const_pointer data() const noexcept { + return _begin; + } + /// Obtain a pointer to the beginning of the referred-to character array + constexpr const_pointer c_str() const noexcept { + return _begin; + } + /// Obtain the length of the referred-to string, in number of characters + constexpr size_type size() const noexcept { + return _size; + } + /// Obtain the length of the referred-to string, in number of characters + constexpr size_type length() const noexcept { + return size(); + } + /// Return `true` if size() == 0, otherwise `false` + constexpr bool empty() const noexcept { + return size() == 0; + } + /// Return the maximum value that could be returned by size() + constexpr size_type max_size() const noexcept { + return static_cast(std::numeric_limits::max()); + } + + /** + * @brief In-place modify the string_view to view N fewer characters from the beginning + * + * @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 { + _assert_inbounds(n, for_offset, "basic_string_view::remove_prefix()"); + _begin += n; + _size -= n; + } + + /** + * @brief In-place modify the string_view to view N fewer characters from the end + * + * @param n The number of characters to remove from the end. Must be less than size() + */ + bsoncxx_cxx14_constexpr void remove_suffix(size_type n) noexcept { + _assert_inbounds(n, for_offset, "basic_string_view::remove_suffix()"); + _size -= n; + } + + /** + * @brief Swap the reference with another string_view + */ + bsoncxx_cxx14_constexpr void swap(basic_string_view& other) noexcept { + std::swap(_begin, other._begin); + std::swap(_size, other._size); + } + + /** + * @brief Copy the contents of the viewed string into the given output destination. + * + * @param dest The destination at which to write characters + * @param count The maximum number of characters to copy. + * @param pos The offset within the viewed string to begin copying from. + * @returns The number of characters that were copied to `dest`. The number + * of copied characters is always the lesser of `size()-pos` and `count` + * + * @throws std::out_of_range if pos > size() + */ + bsoncxx_cxx14_constexpr size_type copy(pointer dest, size_type count, size_type pos = 0) const { + if (pos > size()) { + throw std::out_of_range{"basic_string_view::copy()"}; + } + count = (std::min)(count, size() - pos); + Traits::copy(dest, data() + pos, count); + return count; + } + + bsoncxx_cxx14_constexpr self_type substr(size_type pos, size_type count = npos) const { + if (pos > size()) { + throw std::out_of_range{"basic_string_view::substr()"}; + } + return self_type(_begin + pos, (std::min)(count, size() - pos)); + } + + /** + * @brief Compare two strings lexicographically + * + * @param other The "right hand" operand of the comparison + * @retval 0 If *this == other + * @retval n : n < 0 if *this is "less than" other. + * @retval n : n > 0 if *this is "greater than" other. + */ + constexpr int compare(self_type other) const noexcept { + // Another level of indirection to support restricted C++11 constexpr + return _compare2(Traits::compare(data(), other.data(), (std::min)(size(), other.size())), + other); + } + + /** + * @brief Compare a substring of *this with `other` + * + * @returns substr(po1, count1).compare(other) + */ + constexpr int compare(size_type pos1, size_type count1, self_type other) const noexcept { + return substr(pos1, count1).compare(other); + } + + /** + * @brief Compare a substring of *this with a substring of `other` + * + * @returns substr(pos1, count1).compare(other.substr(pos2, count2)) + */ + constexpr int compare(size_type pos1, + size_type count1, + self_type other, + size_type pos2, + size_type count2) const noexcept { + return substr(pos1, count1).compare(other.substr(pos2, count2)); + } + + /** + * @brief Compare a substring of *this with a string viewed through the given pointer+size + * + * @returns substr(pos1, count1).compare(basic_string_view(str, count2)) + */ + constexpr int compare(size_type pos1, + size_type count1, + const_pointer str, + size_type count2) const noexcept { + return substr(pos1, count1).compare(self_type(str, count2)); + } + + /** + * @brief Test whether the string starts-with the given prefix string + */ + constexpr bool starts_with(self_type pfx) const noexcept { + return size() >= pfx.size() && std::equal(begin(), begin() + pfx.size(), pfx.begin()); + } + + /** + * @brief Test whether the string ends-with the given suffix string + */ + constexpr bool ends_with(self_type sfx) const noexcept { + return size() >= sfx.size() && std::equal(rbegin(), rbegin() + sfx.size(), sfx.rbegin()); + } + + /** + * @brief Explicit-conversion to a std::basic_string + */ + template + constexpr explicit operator std::basic_string() const { + return std::basic_string(data(), size()); + } + + private: + /// If the given 'pos' is out of bounds, terminates the program with an error message on stderr + enum bounds_check { for_access, for_offset }; + void _assert_inbounds(size_type pos, bounds_check kind, const char* what) const noexcept { + const auto bound = kind == for_access ? _size + 1 : _size; + if (bound < pos) { + stdx::detail::string_view_oob_terminate(what, _size, static_cast(pos)); + } + } + + // Additional level-of-indirection for constexpr compare() + constexpr int _compare2(int diff, self_type other) const noexcept { + // "diff" is the diff according to Traits::cmp + return diff ? diff : static_cast(size() - other.size()); + } + + // Implementation of equality comparison + constexpr friend bool tag_invoke(detail::equal_to, self_type left, self_type right) noexcept { + return left.size() == right.size() && + std::equal( + left.begin(), + left.end(), + right.begin(), + [](value_type l, value_type r) noexcept -> bool { return Traits::eq(l, r); }); + } + + // Implementation of a three-way-comparison + constexpr friend detail::strong_ordering tag_invoke(detail::compare_three_way cmp, + self_type left, + self_type right) noexcept { + return cmp(left.compare(right), 0); + } + + friend std::basic_ostream& operator<<(std::basic_ostream& out, + self_type self) { + out.write(self.data(), static_cast(self.size())); + return out; + } +}; + +using string_view = basic_string_view; } // namespace stdx } // namespace v_noabi } // namespace bsoncxx -#else -#error "Cannot find a valid polyfill for string_view" -#endif - #include diff --git a/src/bsoncxx/lib/CMakeLists.txt b/src/bsoncxx/lib/CMakeLists.txt index 4b528dda20..54e73abc75 100644 --- a/src/bsoncxx/lib/CMakeLists.txt +++ b/src/bsoncxx/lib/CMakeLists.txt @@ -25,6 +25,7 @@ list(APPEND bsoncxx_sources bsoncxx/v_noabi/bsoncxx/json.cpp bsoncxx/v_noabi/bsoncxx/oid.cpp bsoncxx/v_noabi/bsoncxx/private/itoa.cpp + bsoncxx/v_noabi/bsoncxx/stdx/string_view.cpp bsoncxx/v_noabi/bsoncxx/string/view_or_value.cpp bsoncxx/v_noabi/bsoncxx/types.cpp bsoncxx/v_noabi/bsoncxx/types/bson_value/value.cpp @@ -87,6 +88,7 @@ set_dist_list(src_bsoncxx_lib_DIST bsoncxx/v_noabi/bsoncxx/private/libbson.hh bsoncxx/v_noabi/bsoncxx/private/stack.hh bsoncxx/v_noabi/bsoncxx/private/suppress_deprecation_warnings.hh + bsoncxx/v_noabi/bsoncxx/stdx/string_view.cpp bsoncxx/v_noabi/bsoncxx/string/view_or_value.cpp bsoncxx/v_noabi/bsoncxx/test_util/export_for_testing.hh bsoncxx/v_noabi/bsoncxx/types.cpp diff --git a/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/stdx/string_view.cpp b/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/stdx/string_view.cpp new file mode 100644 index 0000000000..974a36371f --- /dev/null +++ b/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/stdx/string_view.cpp @@ -0,0 +1,14 @@ +#include +#include + +#include + +#include + +void bsoncxx::v_noabi::stdx::detail::string_view_oob_terminate(const char* msg, + std::size_t length, + std::ptrdiff_t position) noexcept { + std::cerr << msg << ": Out-of-bounds access to string_view element at offset " << position + << " (String has length " << length << ")" << std::endl; + std::terminate(); +} diff --git a/src/bsoncxx/test/CMakeLists.txt b/src/bsoncxx/test/CMakeLists.txt index dcfa1480e4..978f939f70 100644 --- a/src/bsoncxx/test/CMakeLists.txt +++ b/src/bsoncxx/test/CMakeLists.txt @@ -39,6 +39,7 @@ add_executable(test_bson view_or_value.cpp make_unique.test.cpp ranges.test.cpp + string_view.test.cpp type_traits.test.cpp iterator.test.cpp ) @@ -146,4 +147,5 @@ set_dist_list(src_bsoncxx_test_DIST make_unique.test.cpp iterator.test.cpp ranges.test.cpp + string_view.test.cpp ) diff --git a/src/bsoncxx/test/string_view.test.cpp b/src/bsoncxx/test/string_view.test.cpp new file mode 100644 index 0000000000..604b35c751 --- /dev/null +++ b/src/bsoncxx/test/string_view.test.cpp @@ -0,0 +1,159 @@ +#include "bsoncxx/stdx/string_view.hpp" + +#include +#include +#include +#include +#include + +#include "bsoncxx/stdx/iterator.hpp" +#include "bsoncxx/stdx/operators.hpp" +#include "bsoncxx/stdx/type_traits.hpp" +#include + +namespace stdx = bsoncxx::stdx; +using stdx::string_view; + +static_assert(std::is_constructible>::value, "fail"); +static_assert(!std::is_constructible>::value, "fail"); +static_assert(std::is_constructible>::value, "fail"); +static_assert(!std::is_constructible::value, "fail"); +static_assert(std::is_constructible::value, "fail"); +static_assert(std::is_constructible::value, "fail"); +static_assert(bsoncxx::detail::is_contiguous_range::value, "fail"); +static_assert(bsoncxx::detail::is_contiguous_range::value, "fail"); +static_assert(bsoncxx::detail::is_contiguous_range::value, "fail"); + +TEST_CASE("Default constructor") { + (void)string_view(); + string_view s; + CHECK(s.size() == 0); + CHECK(s.length() == 0); + CHECK(s.empty()); + CHECK(s.data() == nullptr); + CHECK(s.begin() == s.end()); + CHECK(s == ""); +} + +static const char HELLO[] = "Hello, string_view!"; +TEST_CASE("Pointer+size construct") { + auto s = string_view(HELLO, sizeof HELLO - 1); + CHECK(s.length() == s.size()); + CHECK(s.data() == HELLO + 0); + CHECK(s[0] == 'H'); + CHECK(s == "Hello, string_view!"); + CHECK(s == HELLO); + + s = string_view(HELLO + 7, sizeof HELLO - 8); + CHECK(s.size() == sizeof HELLO - 8); + CHECK(s == "string_view!"); + s = string_view(HELLO + 7, 11); + CHECK(s == "string_view"); + CHECK_FALSE(s != "string_view"); +} + +TEST_CASE("Pointer construct") { + string_view s = "hello"; + CHECK(s.size() == 5); + CHECK(s[4] == 'o'); + CHECK(s == "hello"); + CHECK(s == s); + CHECK_FALSE(s != s); + CHECK("hello" == s); + CHECK_FALSE(s < s); +} + +TEST_CASE("Range construct") { + std::vector cs = {'a', 'b', 'c', 'd'}; + auto sv = string_view(cs); + CHECK(sv == "abcd"); + + cs = {'a', 'b', 0, 'd'}; + sv = string_view(cs); + CHECK(sv == string_view("ab\0d", 4)); + + // Copying is okay + string_view s2(sv); + CHECK(s2 == sv); + CHECK_FALSE(s2 != sv); +} + +TEST_CASE("Reversal") { + string_view string = "Hello!"; + auto rit = string.rbegin(); + CHECK(*rit++ == '!'); + CHECK(*rit++ == 'o'); + CHECK(*rit++ == 'l'); + CHECK(*rit++ == 'l'); + CHECK(*rit++ == 'e'); + CHECK(*rit++ == 'H'); + CHECK(rit == string.rend()); +} + +TEST_CASE("Get chars") { + string_view string = "Hello, world"; + CHECK(string[0] == 'H'); + CHECK(string[0] == string.at(0)); + CHECK(string[1] == 'e'); + CHECK(string[1] == string.at(1)); + CHECK(string[11] == 'd'); + CHECK(string[11] == string.at(11)); + CHECK_THROWS_AS(string.at(12), std::out_of_range); + CHECK(string.front() == string[0]); + CHECK(string.back() == string[11]); +} + +TEST_CASE("Substrings") { + string_view str = "0123456789"; + CHECK(str.substr(0) == str); + CHECK(str.substr(1) == "123456789"); + // Remove an empty prefix + auto dup = str; + dup.remove_prefix(0); + CHECK(str == dup); + // Remove one + dup.remove_prefix(1); + CHECK(dup == str.substr(1)); + // Remove from the end + dup = str; + dup.remove_suffix(1); + CHECK(dup == "012345678"); + // Remove all + dup = str; + dup.remove_prefix(10); + CHECK(dup.empty()); + dup = str; + dup.remove_suffix(10); + CHECK(dup.empty()); + + dup = str.substr(10); + CHECK(dup.empty()); + CHECK(dup.data() == str.data() + 10); + + dup = str.substr(0, 0); + CHECK(dup.empty()); + CHECK(dup.data() == str.data()); + + CHECK_THROWS_AS(dup.substr(500), std::out_of_range); + + // Substr of empty + dup = ""; + dup = dup.substr(0); + CHECK(dup.empty()); + dup = dup.substr(0, 1000); + CHECK(dup.empty()); +} + +TEST_CASE("Compare") { + string_view str = "abc"; + CHECK(str == "abc"); + CHECK_FALSE(str < "abc"); + CHECK(str < "abcd"); + CHECK(str.compare("abc") == 0); + CHECK(str.compare("abcd") < 0); +} + +TEST_CASE("Overloading safety") { + std::vector vec; + CHECK(vec == vec); +} From f2bb2fb918e743f436059d324c6da46560add70a Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Thu, 16 Nov 2023 13:14:12 -0700 Subject: [PATCH 12/47] Avoid warnings about "unsecure stdlib" code --- .../bsoncxx/v_noabi/bsoncxx/stdx/string_view.hpp | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/string_view.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/string_view.hpp index bb3bbd5a11..1812d16075 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/string_view.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/string_view.hpp @@ -14,6 +14,7 @@ #pragma once +#include #include #include #include @@ -369,14 +370,14 @@ class basic_string_view : detail::equality_operators, detail::ordering_operators * @brief Test whether the string starts-with the given prefix string */ constexpr bool starts_with(self_type pfx) const noexcept { - return size() >= pfx.size() && std::equal(begin(), begin() + pfx.size(), pfx.begin()); + return pfx == substr(0, pfx.size()); } /** * @brief Test whether the string ends-with the given suffix string */ constexpr bool ends_with(self_type sfx) const noexcept { - return size() >= sfx.size() && std::equal(rbegin(), rbegin() + sfx.size(), sfx.rbegin()); + return size() >= sfx.size() && substr(size() - sfx.size()) == sfx; } /** @@ -405,12 +406,7 @@ class basic_string_view : detail::equality_operators, detail::ordering_operators // Implementation of equality comparison constexpr friend bool tag_invoke(detail::equal_to, self_type left, self_type right) noexcept { - return left.size() == right.size() && - std::equal( - left.begin(), - left.end(), - right.begin(), - [](value_type l, value_type r) noexcept -> bool { return Traits::eq(l, r); }); + return left.size() == right.size() && left.compare(right) == 0; } // Implementation of a three-way-comparison From fbd5535e4b95efd12985fbbc6869f1a1e29e53c2 Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Wed, 29 Nov 2023 15:55:05 -0700 Subject: [PATCH 13/47] Tweak definition of is_equality_comparable --- .../v_noabi/bsoncxx/stdx/operators.hpp | 25 +++++++++++-------- .../v_noabi/bsoncxx/stdx/type_traits.hpp | 4 +++ 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/operators.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/operators.hpp index 898baa32f9..f3db57fede 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/operators.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/operators.hpp @@ -12,23 +12,26 @@ namespace bsoncxx { inline namespace v_noabi { namespace detail { +template +auto is_equality_comparable_f(...) -> std::false_type; + +template +auto is_equality_comparable_f(int, + bool b = false, + const_reference_t l = soft_declval(), + const_reference_t r = soft_declval()) + -> true_t; + /** * @brief Detect whether two types are equality-comparable. * * Requires L == R, L != R, R == L, and R != L */ template -struct is_equality_comparable : std::false_type {}; - -template -struct is_equality_comparable< - L, - R, - void_t>() == std::declval>()), - decltype(std::declval>() != std::declval>()), - decltype(std::declval>() == std::declval>()), - decltype(std::declval>() != std::declval>())>> - : std::true_type {}; +struct is_equality_comparable : decltype(is_equality_comparable_f(0)) {}; /** * @brief Callable object and tag type for equality comparison diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/type_traits.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/type_traits.hpp index 5cac345d18..91df4de04e 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/type_traits.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/type_traits.hpp @@ -91,6 +91,10 @@ using bool_constant = std::integral_constant; template struct mp_list; +// Like std::declval, but does not generate a hard error if used. +template +extern add_rvalue_reference_t soft_declval() noexcept; + /// ## Implementation of the C++11 detection idiom namespace impl_detection { From 5740433c47f76be49f3c83032e1c0b31dbef33b5 Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Wed, 29 Nov 2023 16:02:56 -0700 Subject: [PATCH 14/47] decay_copy is no longer needed (yet) --- .../bsoncxx/v_noabi/bsoncxx/stdx/type_traits.hpp | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/type_traits.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/type_traits.hpp index 91df4de04e..93fe609660 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/type_traits.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/type_traits.hpp @@ -460,21 +460,6 @@ struct rank : rank {}; template <> struct rank<0> {}; -struct _decay_copy_fn { - template - constexpr auto operator()(T&& arg) const - noexcept(noexcept(static_cast>(static_cast(arg)))) -> decay_t { - return static_cast>(static_cast(arg)); - } -}; - -/** - * @brief Perform a decay-copy on the given value. - * - * Equivalent to the C++23 `auto()` expression. - */ -static constexpr _decay_copy_fn decay_copy; - } // namespace detail } // namespace v_noabi From b318f62bd19d4bab4be05bcc67d73afd066b376f Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Wed, 29 Nov 2023 16:03:16 -0700 Subject: [PATCH 15/47] Check for MSVC's version macro --- src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/config/util.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/config/util.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/config/util.hpp index 276895b495..27354222ed 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/config/util.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/config/util.hpp @@ -72,7 +72,7 @@ * Use this on functions that can only be constexpr in C++14 or newer, including * non-const member functions. */ -#if __cplusplus >= 201402L +#if __cplusplus >= 201402L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201402L) #define bsoncxx_cxx14_constexpr constexpr #else #define bsoncxx_cxx14_constexpr inline From ff7978d31b81da864cc95fd445649d708e367908 Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Wed, 29 Nov 2023 16:03:25 -0700 Subject: [PATCH 16/47] No ADL-only data() --- src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/ranges.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/ranges.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/ranges.hpp index f37fe61a6e..ac68719b59 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/ranges.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/ranges.hpp @@ -189,7 +189,6 @@ using range_difference_t = iter_difference_t>; * * Returns the first valid of: * - `rng.data()` if such expression yields a pointer type - * - `data(rng)` if such expression is visible via ADL and returns a pointer type * - `to_address(begin(rng))` if such expression is valid and iterator_t is * a contiguous_iterator. */ From 4aeae1da984e046f6036fed7397b4f01cd92d762 Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Wed, 29 Nov 2023 16:03:49 -0700 Subject: [PATCH 17/47] Remove c_str(), tweak "string-like" detection --- .../v_noabi/bsoncxx/stdx/string_view.hpp | 33 ++++++++++++------- 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/string_view.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/string_view.hpp index 1812d16075..1437bef5af 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/string_view.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/string_view.hpp @@ -43,9 +43,24 @@ using namespace bsoncxx::detail; std::size_t length, std::ptrdiff_t offset) noexcept; -// Detects a c_str() method (to detect string-like types) template -using c_str_t = decltype(std::declval().c_str()); +auto detect_string_f(...) -> std::false_type; + +template +auto detect_string_f(int, // + const S& s = soft_declval(), + S& mut = soft_declval()) + -> true_t, is_range>>; + +// Heuristic detection of std::string-like types. Not perfect, but should reasonably +// handle most cases. +template +struct is_string_like : decltype(detect_string_f>(0)) {}; } // namespace detail @@ -153,22 +168,20 @@ class basic_string_view : detail::equality_operators, detail::ordering_operators */ template = 0, - detail::requires_t>> + detail::requires_t>> RequiresNotString = 0> constexpr explicit basic_string_view(Range&& rng) : _begin(detail::data(rng)), _size(detail::size(rng)) {} /** * @brief From-range constructor, but is an implicit conversion accepting string-like ranges. - * (Seeks a .c_str() member) * * Requires that `Range` is a non-array contiguous range with the same value type * as the string view, and is a std::string-like value. */ - template < - typename Range, - _enable_range_constructor = 0, - detail::requires_t> RequiresStringLike = 0> + template = 0, + detail::requires_t> RequiresStringLike = 0> constexpr basic_string_view(Range&& rng) noexcept : _begin(detail::data(rng)), _size(detail::size(rng)) {} @@ -241,10 +254,6 @@ class basic_string_view : detail::equality_operators, detail::ordering_operators constexpr const_pointer data() const noexcept { return _begin; } - /// Obtain a pointer to the beginning of the referred-to character array - constexpr const_pointer c_str() const noexcept { - return _begin; - } /// Obtain the length of the referred-to string, in number of characters constexpr size_type size() const noexcept { return _size; From 536fc05b1222d33139711e0c75a13288db107914 Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Wed, 29 Nov 2023 16:04:12 -0700 Subject: [PATCH 18/47] Minor spelling and tests --- src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/iterator.hpp | 4 ++-- src/bsoncxx/test/CMakeLists.txt | 3 ++- src/bsoncxx/test/ranges.test.cpp | 1 + 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/iterator.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/iterator.hpp index a101cb479a..a7a306f7d1 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/iterator.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/iterator.hpp @@ -87,7 +87,7 @@ struct is_dereferencable : conjunction, * @brief Obtain the value type of the given iterator. * * This is only a very rough approximation for our use cases. A more thorough - * C++20 impl requiers additional traits + * C++20 impl requires additional traits */ template using iter_value_t = @@ -182,7 +182,7 @@ template struct is_input_iterator : is_iterator_kind {}; template -struct is_forwrd_iterator : is_iterator_kind {}; +struct is_forward_iterator : is_iterator_kind {}; template struct is_bidirectional_iterator : is_iterator_kind {}; diff --git a/src/bsoncxx/test/CMakeLists.txt b/src/bsoncxx/test/CMakeLists.txt index 978f939f70..e2dd485d4a 100644 --- a/src/bsoncxx/test/CMakeLists.txt +++ b/src/bsoncxx/test/CMakeLists.txt @@ -105,6 +105,7 @@ if(ENABLE_MACRO_GUARD_TESTS) bsoncxx_disable_warning bsoncxx_concat bsoncxx_concat_impl + bsoncxx_cxx14_constexpr bsoncxx_force_semicolon bsoncxx_pragma _bsoncxxPragma @@ -113,7 +114,7 @@ if(ENABLE_MACRO_GUARD_TESTS) bsoncxx_if_msvc bsoncxx_if_gcc bsoncxx_if_clang - bsoncxx_if_gnu + bsoncxx_if_gnu_like bsoncxx_returns INCLUDE_PATTERNS "include/*.hpp" # Public headers. diff --git a/src/bsoncxx/test/ranges.test.cpp b/src/bsoncxx/test/ranges.test.cpp index 9d317dd6d1..367b498fdd 100644 --- a/src/bsoncxx/test/ranges.test.cpp +++ b/src/bsoncxx/test/ranges.test.cpp @@ -28,6 +28,7 @@ TEST_CASE("Range from vector") { std::vector nums = {1, 2, 3, 4}; auto it = ranges::begin(nums); REQUIRE(it != ranges::end(nums)); + REQUIRE((it + 4) == ranges::end(nums)); static_assert(std::is_same::iterator>::value, "fail"); CHECK(*it == 1); ++it; From 39dc52467fe5f6d70287fe1bf5f966a7343ea0ca Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Thu, 30 Nov 2023 12:26:04 -0700 Subject: [PATCH 19/47] MSVC 19.10 lies about C++14 constexpr --- src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/config/util.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/config/util.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/config/util.hpp index 27354222ed..60d372d07f 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/config/util.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/config/util.hpp @@ -72,7 +72,7 @@ * Use this on functions that can only be constexpr in C++14 or newer, including * non-const member functions. */ -#if __cplusplus >= 201402L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201402L) +#if __cplusplus >= 201402L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201402L && _MSC_VER > 1910) #define bsoncxx_cxx14_constexpr constexpr #else #define bsoncxx_cxx14_constexpr inline From d67f942be7d52823f8d1e258f2f2078c778d1b8f Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Thu, 30 Nov 2023 14:56:56 -0700 Subject: [PATCH 20/47] Test and fixup for ADL lookup on VS 2015 --- .../bsoncxx/v_noabi/bsoncxx/stdx/ranges.hpp | 24 +++++++++++++--- src/bsoncxx/test/ranges.test.cpp | 28 ++++++++++++++++++- 2 files changed, 47 insertions(+), 5 deletions(-) diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/ranges.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/ranges.hpp index ac68719b59..5b60e2a567 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/ranges.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/ranges.hpp @@ -21,6 +21,19 @@ namespace bsoncxx { inline namespace v_noabi { + +namespace detailx { +// Workarounds for MSVC 19.10 doing bad: An invocable object with name `n` should not be visible +// within its own call operator. We need to "hide" the ADL name lookup out here in a different +// namespace to prevent them from finding the invocable objects. +template +constexpr auto adl_size(T&& t) bsoncxx_returns(size((T&&)t)); +template +constexpr auto adl_begin(T&& t) bsoncxx_returns(begin((T&&)t)); +template +constexpr auto adl_end(T&& t) bsoncxx_returns(end((T&&)t)); +} // namespace detailx + namespace detail { /** @@ -42,7 +55,7 @@ constexpr requires_t> _decay_iterator(I i) noexcept { } template -constexpr requires_t> _decay_sentinel(S s) noexcept { +constexpr requires_t> _decay_sentinel(S s) noexcept { return s; } @@ -74,7 +87,8 @@ static constexpr struct _begin_fn { // 3: Object has an ADL-visible begin(x) returning an iterator template - static constexpr auto impl(R& rng, rank<3>) bsoncxx_returns(_decay_iterator(begin(rng))); + static constexpr auto impl(R& rng, rank<3>) + bsoncxx_returns(_decay_iterator(detailx::adl_begin(rng))); template constexpr auto operator()(R&& rng) const bsoncxx_returns((impl)(rng, rank<10>{})); @@ -106,7 +120,8 @@ static constexpr struct _end_fn { // 3: Range has ADL-found end(x) returning a valid sentinel template - static constexpr auto impl(R& r, rank<3>) bsoncxx_returns(_decay_sentinel(end(r))); + static constexpr auto impl(R& r, rank<3>) + bsoncxx_returns(_decay_sentinel(detailx::adl_end(r))); template constexpr auto operator()(R&& rng) const bsoncxx_returns((impl>)(rng, rank<5>{})); @@ -140,7 +155,8 @@ static constexpr struct _size_fn { // 3: Range with ADL-found size(x) template - static constexpr auto impl(R& rng, rank<3>) bsoncxx_returns(_decay_integral(size(rng))); + static constexpr auto impl(R& rng, rank<3>) + bsoncxx_returns(_decay_integral(detailx::adl_size(rng))); // 4: Range is a forward-range and has a sized sentinel type template < diff --git a/src/bsoncxx/test/ranges.test.cpp b/src/bsoncxx/test/ranges.test.cpp index 367b498fdd..47faf53c5c 100644 --- a/src/bsoncxx/test/ranges.test.cpp +++ b/src/bsoncxx/test/ranges.test.cpp @@ -48,4 +48,30 @@ TEST_CASE("Range from array") { CHECK(ranges::size(array) == 4); CHECK(ranges::ssize(array) == 4); CHECK(ranges::data(array) == ranges::begin(array)); -} \ No newline at end of file +} + +namespace stuff { + +class custom_vector_wrapper { + using vec = std::vector; + vec numbers = {1, 2, 3, 4, 5}; + + friend vec::iterator begin(custom_vector_wrapper& self) { + return self.numbers.begin(); + } + + friend vec::iterator end(custom_vector_wrapper& self) { + return self.numbers.end(); + } +}; + +} // namespace stuff + +TEST_CASE("ADL-only range") { + stuff::custom_vector_wrapper vec; + static_assert(bsoncxx::detail::is_range{}, "fail"); + auto it = ranges::begin(vec); + CHECK(*it == 1); + CHECK(bsoncxx::detail::size(vec) == 5u); + CHECK(bsoncxx::detail::ssize(vec) == 5); +} From c1a7997a0d1608d06c1adbcbfdb63787df9b52c1 Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Thu, 30 Nov 2023 14:58:09 -0700 Subject: [PATCH 21/47] Cleaner size() constraint --- .../bsoncxx/v_noabi/bsoncxx/stdx/ranges.hpp | 21 +++++++++---------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/ranges.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/ranges.hpp index 5b60e2a567..b29b71b6c6 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/ranges.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/ranges.hpp @@ -159,17 +159,16 @@ static constexpr struct _size_fn { bsoncxx_returns(_decay_integral(detailx::adl_size(rng))); // 4: Range is a forward-range and has a sized sentinel type - template < - typename R, - typename Iter = iterator_t, - typename Sentinel = sentinel_t, - // Require a forward iterator: - requires_t>> = 0, - // Require a sized sentinel: - requires_t> = 0, - // We cast to an unsigned type from the difference type: - typename Sz = make_unsigned_t>> - static constexpr auto impl(R& rng, rank<3>) + template , + typename Sentinel = sentinel_t, + // Require a forward iterator: + requires_t> = 0, + // Require a sized sentinel: + requires_t> = 0, + // We cast to an unsigned type from the difference type: + typename Sz = make_unsigned_t>> + static constexpr auto impl(R& rng, rank<2>) bsoncxx_returns(static_cast(end(rng) - begin(rng))); template From 40f544fc4ca3a2f7b2f2cc6c44306a497592b8f3 Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Thu, 30 Nov 2023 14:59:41 -0700 Subject: [PATCH 22/47] unreachable_sentinel, plus support for arg swapping in equality_operators mixin --- .../bsoncxx/v_noabi/bsoncxx/stdx/operators.hpp | 10 ++++++++-- .../include/bsoncxx/v_noabi/bsoncxx/stdx/ranges.hpp | 13 +++++++++++++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/operators.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/operators.hpp index f3db57fede..5bbada5c3a 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/operators.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/operators.hpp @@ -50,13 +50,19 @@ struct equal_to { * an ADL-only tag_invoke(equal_to, l, r) */ class equality_operators { + template + constexpr static auto impl(rank<1>, L& l, R& r) bsoncxx_returns(tag_invoke(equal_to{}, l, r)); + + template + constexpr static auto impl(rank<0>, L& l, R& r) bsoncxx_returns(tag_invoke(equal_to{}, r, l)); + template constexpr friend auto operator==(const Left& self, const Other& other) - bsoncxx_returns(tag_invoke(equal_to{}, self, other)); + bsoncxx_returns(equality_operators::impl(rank<1>{}, self, other)); template constexpr friend auto operator!=(const Left& self, const Other& other) - bsoncxx_returns(!tag_invoke(equal_to{}, self, other)); + bsoncxx_returns(!equality_operators::impl(rank<1>{}, self, other)); }; /** diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/ranges.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/ranges.hpp index b29b71b6c6..b5e1abbe35 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/ranges.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/ranges.hpp @@ -15,6 +15,7 @@ #include #include +#include #include #include @@ -232,6 +233,9 @@ using range_data_t = decltype(data(std::declval())); template using range_value_t = iter_value_t>; +template +using range_reference_t = iter_reference_t>; + template using range_concept_t = iterator_concept_t>; @@ -254,6 +258,15 @@ template struct is_contiguous_range : conjunction, is_detected, is_detected> {}; +static constexpr struct unreachable_sentinel_t : equality_operators { + template + constexpr friend requires_t> tag_invoke(equal_to, + unreachable_sentinel_t, + I) noexcept { + return false; + } +} unreachable_sentinel; + } // namespace detail } // namespace v_noabi } // namespace bsoncxx From e083ca582a58876413925a90638bae540a23a618 Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Thu, 30 Nov 2023 14:59:58 -0700 Subject: [PATCH 23/47] Qualify test names in string_view tests --- src/bsoncxx/test/string_view.test.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/bsoncxx/test/string_view.test.cpp b/src/bsoncxx/test/string_view.test.cpp index 604b35c751..36ba685406 100644 --- a/src/bsoncxx/test/string_view.test.cpp +++ b/src/bsoncxx/test/string_view.test.cpp @@ -24,7 +24,7 @@ static_assert(bsoncxx::detail::is_contiguous_range::value, "fail"); static_assert(bsoncxx::detail::is_contiguous_range::value, "fail"); static_assert(bsoncxx::detail::is_contiguous_range::value, "fail"); -TEST_CASE("Default constructor") { +TEST_CASE("string_view: Default constructor") { (void)string_view(); string_view s; CHECK(s.size() == 0); @@ -36,7 +36,7 @@ TEST_CASE("Default constructor") { } static const char HELLO[] = "Hello, string_view!"; -TEST_CASE("Pointer+size construct") { +TEST_CASE("string_view: Pointer+size construct") { auto s = string_view(HELLO, sizeof HELLO - 1); CHECK(s.length() == s.size()); CHECK(s.data() == HELLO + 0); @@ -52,7 +52,7 @@ TEST_CASE("Pointer+size construct") { CHECK_FALSE(s != "string_view"); } -TEST_CASE("Pointer construct") { +TEST_CASE("string_view: Pointer construct") { string_view s = "hello"; CHECK(s.size() == 5); CHECK(s[4] == 'o'); @@ -63,7 +63,7 @@ TEST_CASE("Pointer construct") { CHECK_FALSE(s < s); } -TEST_CASE("Range construct") { +TEST_CASE("string_view: Range construct") { std::vector cs = {'a', 'b', 'c', 'd'}; auto sv = string_view(cs); CHECK(sv == "abcd"); @@ -78,7 +78,7 @@ TEST_CASE("Range construct") { CHECK_FALSE(s2 != sv); } -TEST_CASE("Reversal") { +TEST_CASE("string_view: Reversal") { string_view string = "Hello!"; auto rit = string.rbegin(); CHECK(*rit++ == '!'); @@ -90,7 +90,7 @@ TEST_CASE("Reversal") { CHECK(rit == string.rend()); } -TEST_CASE("Get chars") { +TEST_CASE("string_view: Get chars") { string_view string = "Hello, world"; CHECK(string[0] == 'H'); CHECK(string[0] == string.at(0)); @@ -103,7 +103,7 @@ TEST_CASE("Get chars") { CHECK(string.back() == string[11]); } -TEST_CASE("Substrings") { +TEST_CASE("string_view: Substrings") { string_view str = "0123456789"; CHECK(str.substr(0) == str); CHECK(str.substr(1) == "123456789"); @@ -144,7 +144,7 @@ TEST_CASE("Substrings") { CHECK(dup.empty()); } -TEST_CASE("Compare") { +TEST_CASE("string_view: Compare") { string_view str = "abc"; CHECK(str == "abc"); CHECK_FALSE(str < "abc"); @@ -153,7 +153,7 @@ TEST_CASE("Compare") { CHECK(str.compare("abcd") < 0); } -TEST_CASE("Overloading safety") { +TEST_CASE("string_view: Overloading safety") { std::vector vec; CHECK(vec == vec); } From 43c79249b340547d202a8ba561e4b8f2832c00f2 Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Mon, 4 Dec 2023 12:44:04 -0700 Subject: [PATCH 24/47] Bring our own algorithm.hpp --- src/bsoncxx/include/CMakeLists.txt | 1 + .../v_noabi/bsoncxx/stdx/algorithm.hpp | 429 ++++++++++++++++++ src/bsoncxx/test/algorithm.test.cpp | 51 +++ 3 files changed, 481 insertions(+) create mode 100644 src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/algorithm.hpp create mode 100644 src/bsoncxx/test/algorithm.test.cpp diff --git a/src/bsoncxx/include/CMakeLists.txt b/src/bsoncxx/include/CMakeLists.txt index 0d3beb2e21..c33e12165b 100644 --- a/src/bsoncxx/include/CMakeLists.txt +++ b/src/bsoncxx/include/CMakeLists.txt @@ -57,6 +57,7 @@ set_dist_list(src_bsoncxx_include_DIST bsoncxx/v_noabi/bsoncxx/exception/exception.hpp bsoncxx/v_noabi/bsoncxx/json.hpp bsoncxx/v_noabi/bsoncxx/oid.hpp + bsoncxx/v_noabi/bsoncxx/stdx/algorithm.hpp bsoncxx/v_noabi/bsoncxx/stdx/iterator.hpp bsoncxx/v_noabi/bsoncxx/stdx/make_unique.hpp bsoncxx/v_noabi/bsoncxx/stdx/optional.hpp diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/algorithm.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/algorithm.hpp new file mode 100644 index 0000000000..37dcddb825 --- /dev/null +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/algorithm.hpp @@ -0,0 +1,429 @@ +#pragma once + +#include + +#include "./algorithm.hpp" +#include "./iterator.hpp" +#include "./operators.hpp" +#include "./ranges.hpp" +#include "./type_traits.hpp" + +#include + +namespace bsoncxx { + +inline namespace v_noabi { + +namespace detail { + +/** + * @internal + * @brief Checked iterator-advance + * + * Provides two signatures: + * + * - advance(iterator, sentinel) + * - advance(iterator, offset, sentinel) + * + * The default `offset` is 1. The return value is the offset by which the + * iterator was actually shifted, which may be different from `offset` if + * `sentinel` was encountered before advancing the entire distance. + */ +static constexpr struct _advance_fn { + template + constexpr auto operator()(I& iter, S bound) const bsoncxx_returns(impl(iter, 1, bound)); + + template + constexpr auto operator()(I& iter, iter_difference_t off, S bound) const + bsoncxx_returns(impl(iter, off, bound)); + + template + bsoncxx_cxx14_constexpr static auto impl(I& iter, + iter_difference_t off, + S bound) // + noexcept(noexcept(++iter) && noexcept(iter == bound)) + -> requires_t, is_sentinel_for> { + iter_difference_t shift = 0; + while (off > 0 && iter != bound) { + ++iter; + --off; + ++shift; + } + handle_negative(iter, off, bound, shift); + return shift; + } + + // Handle bidirectional iterators and negative offsets + template + bsoncxx_cxx14_constexpr static requires_t> // + handle_negative(I& iter, + iter_difference_t off, + S bound, + iter_difference_t& shift) noexcept(noexcept(--iter)) { + while (off < 0) { + --iter; + ++off; + --shift; + } + } + + // Fallback: Iterator is not bidir. This is less-preferred since it uses an ellipsis + template + bsoncxx_cxx14_constexpr static void handle_negative(I, iter_difference_t, S, ...) noexcept {} +} advance; + +/** + * @internal + * @brief Obtain a new iterator shifted from the given iterator by some amount, + * with bounds-checking + * + * Two signatures: + * + * - next(iterator, bound) + * - next(iterator, offset, bound) + * + * Equivalent to copying `iterator` as `t`, calling `advance(t[, offset], bound)`, + * and returning `t`. + */ +static constexpr struct _next_fn { + template + bsoncxx_cxx14_constexpr auto operator()(I it, S bound) const + -> requires_t> { + advance(it, bound); + return it; + } + + template + bsoncxx_cxx14_constexpr auto operator()(I it, iter_difference_t offset, S bound) const + -> requires_t> { + advance(it, offset, bound); + return it; + } +} next; + +/** + * @internal + * @brief Encloses a range represented by an iterator+sentinel pair + * + * Provides begin(), end(), and empty(). If the iterator+sentinel pair are + * "sized", provides a size() member as well. + */ +template +struct subrange; + +template +struct subrange_base { + I _iter; + S _stop; + + constexpr subrange_base(I i, S s) noexcept : _iter(i), _stop(s) {} + + constexpr I begin() const noexcept { + return _iter; + } + constexpr S end() const noexcept { + return _stop; + } + + constexpr bool empty() const noexcept { + return begin() == end(); + } +}; + +template +struct subrange_base : subrange_base { + using subrange_base::subrange_base; + + constexpr detail::make_unsigned_t> size() const noexcept { + return static_cast>>(this->_stop - + this->_iter); + } +}; + +template +struct subrange : subrange_base::value> { + using subrange::subrange_base::subrange_base; +}; + +/** + * @internal + * @brief Construct a new subrange from the given iterator+sentinel pair + */ +template +constexpr requires_t, is_sentinel_for> make_subrange(I i, S s) noexcept { + return subrange{i, s}; +} + +template +using reversed_t = subrange< + std::reverse_iterator, is_bidirectional_iterator>>>>; + +template +constexpr reversed_t // +make_reversed_view(R&& rng) noexcept { + return {std::make_reverse_iterator(end(rng)), std::make_reverse_iterator(begin(rng))}; +} + +/** + * @internal + * @brief Obtain the size of a range as a signed integer. + * + * Unlike size() or ssize(), this invocable is defined for all ranges, even if the + * underlying operation is not O(1) or the range is an input_range. Uses ssize() + * if available, otherwise counts iterator increments. + */ +static constexpr struct _distance_fn { + template + constexpr auto operator()(I i, S s) const bsoncxx_returns(impl(rank<2>{}, make_subrange(i, s))); + template + constexpr auto operator()(R&& rng) const bsoncxx_returns(impl(rank<2>{}, rng)); + + template + constexpr static auto impl(rank<2>, R& rng) bsoncxx_returns(ssize(rng)); + + template + constexpr static auto impl(rank<1>, R& rng) -> requires_t, is_range> { + range_difference_t count = 0; + auto i = begin(rng); + auto s = end(rng); + for (; i != s; ++i) { + ++count; + } + return count; + } +} distance; + +/** + * @brief An invocable object that simply returns its argument unchanged. + */ +struct identity { + template + constexpr T&& operator()(T&& arg) const noexcept { + return static_cast(arg); + } +}; + +/** + * @internal + * @brief Test whether the given ranges have equal contents + * + * Call as: + * + * - equal(left_range, right_range[, compare_fn[, left-projection[, right-projection]]]) + */ +static constexpr struct _equal_fn { + template + bsoncxx_cxx14_constexpr auto operator()(L&& left, + R&& right, + Compare&& eq = {}, + ProjectLeft&& projleft = {}, + ProjectRight&& projright = {}) const // + -> requires_t>, + invoke_result_t>>> { + if (definitely_different_sizes(rank<1>{}, left, right)) { + // The ranges are known to have different sizes, so cannot be equal + return false; + } + auto li = begin(left); + const auto ls = end(left); + auto ri = begin(right); + const auto rs = end(right); + for (; li != ls && ri != rs; ++li, ++ri) { + if (!eq(projleft(*li), projright(*ri))) { + return false; + } + } + // All elements compared equal, so check that we compared all elements of both ranges: + return li == ls && ri == rs; + } + + template + constexpr static auto definitely_different_sizes(rank<1>, L& l, R& r) + bsoncxx_returns(ssize(l) != ssize(r)); + template + constexpr static auto definitely_different_sizes(rank<0>, L&, R&) noexcept { + return false; + }; +} equal; + +/** + * @internal + * @brief A default searcher implementation for use with search() + * + * Scans the searched range for the needle by simple element-by-element comparison. + */ +template +struct default_searcher; + +/** + * @internal + * @brief Implements subrange-searching + * + * Callable with: + * + * - search(outer_range, inner_range[, compare_fn]) + * - search(outer_range, searcher) + * + * When given two ranges, uses default_searcher with `compare_fn` to search + * for the first occurrence of `inner_range` within `outer_range`. + * + * Returns a subrange referring to the range that was found by searching, or + * an empty subrange pointing to the end of the scanned range if no occurrence + * was found. + */ +static constexpr struct _search_fn { + template > + bsoncxx_cxx14_constexpr static auto impl(Range&& rng, + Searcher&& srch) // + noexcept(noexcept(srch(begin(rng), end(rng)))) + -> requires_t, is_invocable>> { + const std::pair found = srch(begin(rng), end(rng)); + return {found.first, found.second}; + } + + template + constexpr auto operator()(Hay&& hay, Needle&& ndl, Compare&& cmp = {}) const + bsoncxx_returns((impl)(hay, + default_searcher, sentinel_t, Compare>{ + begin(ndl), end(ndl), static_cast(cmp)})); + + template + constexpr auto operator()(Hay&& hay, Searcher&& srch) const bsoncxx_returns(impl(hay, srch)); +} search; + +template +struct default_searcher { + NeedleIter n_first; + NeedleStop n_last; + Compare _compare = Compare(); + iter_difference_t n_size = distance(n_first, n_last); + + default_searcher(NeedleIter first, NeedleStop last, Compare cmp = Compare()) + : n_first(first), n_last(last), _compare(cmp) {} + + template + bsoncxx_cxx14_constexpr std::pair operator()(Iter first, Stop last) const { + auto test_begin = first; + auto test_end = first; + auto ndl = make_subrange(n_first, n_last); + if (advance(test_end, n_size, last) != n_size) { + // We did not advance the full needle size, so the test range is smaller than the + // needle, and cannot contain the needle: + return std::make_pair(test_end, test_end); + } + while (1) { + // Create a subrange of the current part being tested: + auto test_range = make_subrange(test_begin, test_end); + if (equal(test_range, ndl, _compare)) { + // This subrange is equal, so return that subrange + return {test_range.begin(), test_range.end()}; + } + // Step forward: + if (test_end == last) { + return {test_end, test_end}; + } + ++test_begin; + ++test_end; + } + } +}; + +template +struct equal_to_value_t { + T value; + template + constexpr auto operator()(U&& u) const bsoncxx_returns(u == value); +}; + +/** + * @internal + * @brief Create a predicate that tests whether a value is equal to a given value + */ +template +constexpr equal_to_value_t equal_to_value(T&& t) noexcept { + return {static_cast(t)}; +} + +/** + * @internal + * @brief Obtain the iterator referring to the first position in a range for + * which a given predicate returns true + */ +static constexpr struct _find_if_fn { + template + bsoncxx_cxx14_constexpr auto operator()(R&& rng, Predicate&& pred, Project&& proj = {}) const + -> requires_t> { + auto iter = begin(rng); + const auto stop = end(rng); + for (; iter != stop; ++iter) { + if (pred(proj(*iter))) { + break; + } + } + return iter; + } +} find_if; + +/** + * @internal + * @brief Find the given value in the given range, compared by the `==` operator + */ +static constexpr struct _find_fn { + template + constexpr auto operator()(R&& rng, const T& value, Project&& proj = {}) const + bsoncxx_returns(find_if(rng, equal_to_value(value), proj)); +} find; + +template +struct equal_to_any_of_t { + T range; + + template + constexpr auto operator()(U&& value) const bsoncxx_returns(find(range, value) != end(range)); +}; + +/** + * @internal + * @brief Create a predicate that tests whether a value exists within the + * given range of objects. + */ +template +constexpr auto equal_to_any_of(T&& rng) + -> requires_t, is_forward_iterator>> { + return {static_cast(rng)}; +} + +template +struct not_fn_t { + F func; + template + bsoncxx_cxx14_constexpr auto operator()(Args&&... args) + bsoncxx_returns(!invoke(func, static_cast(args)...)); + template + constexpr auto operator()(Args&&... args) const + bsoncxx_returns(!invoke(func, static_cast(args)...)); +}; + +/** + * @internal + * @brief Create a wrapper function that negates the result of invoking the underlying + * invocable + */ +template +constexpr not_fn_t not_fn(F&& fn) { + return {static_cast(fn)}; +} + +} // namespace detail + +} // namespace v_noabi + +} // namespace bsoncxx + +#include diff --git a/src/bsoncxx/test/algorithm.test.cpp b/src/bsoncxx/test/algorithm.test.cpp new file mode 100644 index 0000000000..987ac9a900 --- /dev/null +++ b/src/bsoncxx/test/algorithm.test.cpp @@ -0,0 +1,51 @@ +#include "bsoncxx/stdx/algorithm.hpp" + +#include +#include +#include + +#include "bsoncxx/stdx/iterator.hpp" +#include "bsoncxx/stdx/operators.hpp" +#include "bsoncxx/stdx/ranges.hpp" +#include "bsoncxx/stdx/string_view.hpp" +#include "bsoncxx/stdx/type_traits.hpp" +#include + +namespace ranges = bsoncxx::detail; + +TEST_CASE("Algorithm: Advance an iterator") { + int arr[] = {1, 2, 3}; + auto it = ranges::begin(arr); + auto dup = it; + CHECK(it == dup); + CHECK(*it == 1); + CHECK(ranges::advance(dup, bsoncxx::detail::unreachable_sentinel) == 1); + CHECK(*dup == 2); + CHECK(dup == ranges::next(it, bsoncxx::detail::unreachable_sentinel)); + dup = it; + CHECK(ranges::advance(dup, 2, bsoncxx::detail::unreachable_sentinel) == 2); + CHECK(*dup == 3); + CHECK(dup == ranges::next(it, 2, bsoncxx::detail::unreachable_sentinel)); + dup = it; + CHECK(ranges::advance(dup, 400, ranges::end(arr)) == 3); + CHECK(dup == ranges::end(arr)); + CHECK(dup == ranges::next(it, 3, bsoncxx::detail::unreachable_sentinel)); +} + +TEST_CASE("Algorithm: equal()") { + std::vector a = {1, 2, 3, 4, 5}; + std::vector b = {1, 2, 3, 4, 5}; + CHECK(ranges::equal(a, b)); +} + +TEST_CASE("Algorithm: Simple search") { + auto arr = {1, 2, 3, 4}; + auto needle = {2, 3}; + auto ss = ranges::ssize(ranges::make_subrange(arr.begin(), arr.end())); + auto searcher = + bsoncxx::detail::default_searcher{ + bsoncxx::detail::begin(needle), bsoncxx::detail::end(needle), {}}; + auto found = searcher(bsoncxx::detail::begin(arr), bsoncxx::detail::end(arr)); + CHECK(found.first == bsoncxx::detail::begin(arr) + 1); + auto found2 = bsoncxx::detail::search(arr, needle); +} From 09961a852fc7b20823d4cabfd72d1ed83480f19e Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Mon, 4 Dec 2023 12:44:30 -0700 Subject: [PATCH 25/47] Implement find() and contains() from string_view --- .../v_noabi/bsoncxx/stdx/algorithm.hpp | 37 ++--- .../bsoncxx/v_noabi/bsoncxx/stdx/iterator.hpp | 6 + .../v_noabi/bsoncxx/stdx/string_view.hpp | 141 +++++++++++++++++- src/bsoncxx/test/CMakeLists.txt | 2 + src/bsoncxx/test/algorithm.test.cpp | 2 +- src/bsoncxx/test/string_view.test.cpp | 45 ++++++ 6 files changed, 210 insertions(+), 23 deletions(-) diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/algorithm.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/algorithm.hpp index 37dcddb825..f6152dbca0 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/algorithm.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/algorithm.hpp @@ -30,13 +30,6 @@ namespace detail { * `sentinel` was encountered before advancing the entire distance. */ static constexpr struct _advance_fn { - template - constexpr auto operator()(I& iter, S bound) const bsoncxx_returns(impl(iter, 1, bound)); - - template - constexpr auto operator()(I& iter, iter_difference_t off, S bound) const - bsoncxx_returns(impl(iter, off, bound)); - template bsoncxx_cxx14_constexpr static auto impl(I& iter, iter_difference_t off, @@ -53,6 +46,13 @@ static constexpr struct _advance_fn { return shift; } + template + constexpr auto operator()(I& iter, S bound) const bsoncxx_returns(impl(iter, 1, bound)); + + template + constexpr auto operator()(I& iter, iter_difference_t off, S bound) const + bsoncxx_returns(impl(iter, off, bound)); + // Handle bidirectional iterators and negative offsets template bsoncxx_cxx14_constexpr static requires_t> // @@ -60,7 +60,7 @@ static constexpr struct _advance_fn { iter_difference_t off, S bound, iter_difference_t& shift) noexcept(noexcept(--iter)) { - while (off < 0) { + while (off < 0 && iter != bound) { --iter; ++off; --shift; @@ -161,7 +161,7 @@ using reversed_t = subrange< template constexpr reversed_t // make_reversed_view(R&& rng) noexcept { - return {std::make_reverse_iterator(end(rng)), std::make_reverse_iterator(begin(rng))}; + return {detail::make_reverse_iterator(end(rng)), detail::make_reverse_iterator(begin(rng))}; } /** @@ -173,16 +173,12 @@ make_reversed_view(R&& rng) noexcept { * if available, otherwise counts iterator increments. */ static constexpr struct _distance_fn { - template - constexpr auto operator()(I i, S s) const bsoncxx_returns(impl(rank<2>{}, make_subrange(i, s))); - template - constexpr auto operator()(R&& rng) const bsoncxx_returns(impl(rank<2>{}, rng)); - template - constexpr static auto impl(rank<2>, R& rng) bsoncxx_returns(ssize(rng)); + constexpr static auto impl(rank<2>, R&& rng) bsoncxx_returns(ssize(rng)); template - constexpr static auto impl(rank<1>, R& rng) -> requires_t, is_range> { + bsoncxx_cxx14_constexpr static auto impl(rank<1>, R&& rng) + -> requires_t, is_range> { range_difference_t count = 0; auto i = begin(rng); auto s = end(rng); @@ -191,6 +187,11 @@ static constexpr struct _distance_fn { } return count; } + + template + constexpr auto operator()(I i, S s) const bsoncxx_returns(impl(rank<2>{}, make_subrange(i, s))); + template + constexpr auto operator()(R&& rng) const bsoncxx_returns(impl(rank<2>{}, rng)); } distance; /** @@ -247,9 +248,9 @@ static constexpr struct _equal_fn { constexpr static auto definitely_different_sizes(rank<1>, L& l, R& r) bsoncxx_returns(ssize(l) != ssize(r)); template - constexpr static auto definitely_different_sizes(rank<0>, L&, R&) noexcept { + constexpr static bool definitely_different_sizes(rank<0>, L&, R&) noexcept { return false; - }; + } } equal; /** diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/iterator.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/iterator.hpp index a7a306f7d1..0904d9a0eb 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/iterator.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/iterator.hpp @@ -214,6 +214,12 @@ struct is_sized_sentinel_for std::is_convertible, iter_difference_t>> { }; +template +constexpr auto make_reverse_iterator(I it) noexcept + -> requires_t, is_iterator> { + return std::reverse_iterator(it); +} + } // namespace detail } // namespace v_noabi } // namespace bsoncxx diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/string_view.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/string_view.hpp index 1437bef5af..39ef5798cf 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/string_view.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/string_view.hpp @@ -14,16 +14,14 @@ #pragma once -#include #include #include -#include -#include #include #include #include #include +#include "./algorithm.hpp" #include "./iterator.hpp" #include "./operators.hpp" #include "./ranges.hpp" @@ -82,7 +80,7 @@ class basic_string_view : detail::equality_operators, detail::ordering_operators using value_type = Char; // Constant sentinel value to represent an impossible/invalid string position - static constexpr size_type npos = static_cast(-1); + static constexpr const size_type npos = static_cast(-1); private: // Pointer to the beginning of the string being viewed @@ -320,6 +318,15 @@ class basic_string_view : detail::equality_operators, detail::ordering_operators return count; } + /** + * @brief Obtain a substring of this string + * + * @param pos The zero-based index at which to start the new string. + * @param count The number of characters to include following `pos` in the new string. + * Automatically clamped to the available size + * + * @throws std::out_of_range if `pos` is greater than this->size() + */ bsoncxx_cxx14_constexpr self_type substr(size_type pos, size_type count = npos) const { if (pos > size()) { throw std::out_of_range{"basic_string_view::substr()"}; @@ -375,6 +382,82 @@ class basic_string_view : detail::equality_operators, detail::ordering_operators return substr(pos1, count1).compare(self_type(str, count2)); } + /** + * @brief Find the zero-based index of the left-most occurrence of the given substring + */ + bsoncxx_cxx14_constexpr size_type find(self_type infix, size_type pos = 0) const noexcept { + self_type sub = this->substr((std::min)(pos, size())); + detail::subrange found = detail::search(sub, infix); + if (detail::distance(found) != static_cast(infix.size())) { + return npos; + } + return _iter_to_pos(found.begin()); + } + + /** + * @brief Find the zero-based index of the right-box occurrence of the given substring + */ + bsoncxx_cxx14_constexpr size_type rfind(self_type infix, size_type pos = npos) const noexcept { + self_type sub = this->substr(0, pos); + detail::reversed_t found = + detail::search(detail::make_reversed_view(sub), detail::make_reversed_view(infix)); + if (detail::distance(found) != static_cast(infix.size())) { + return npos; + } + return _iter_to_pos(found.end()); + } + + /** + * @brief Find the zero-based index of the left-most occurrence of any character of the given + * set + */ + constexpr size_type find_first_of(self_type set, size_type pos = 0) const noexcept { + return _find_if(pos, detail::equal_to_any_of(set)); + } + + /** + * @brief Find the zero-based index of the right-most occurrence of any character of the given + * set + */ + constexpr size_type find_last_of(self_type set, size_type pos = npos) const noexcept { + return _rfind_if(pos, detail::equal_to_any_of(set)); + } + + /** + * @brief Find the zero-based index of the left-most occurrence of any character that + * is NOT a member of the given set of characters + */ + constexpr size_type find_first_not_of(self_type set, size_type pos = 0) const noexcept { + return _find_if(pos, detail::not_fn(detail::equal_to_any_of(set))); + } + + /** + * @brief Find the zero-based index of the right-most occurrence of any character that + * is NOT a member of the given set of characters + */ + constexpr size_type find_last_not_of(self_type set, size_type pos = npos) const noexcept { + return _rfind_if(pos, detail::not_fn(detail::equal_to_any_of(set))); + } + +#define DECL_FINDERS(Name, DefaultPos) \ + constexpr size_type Name(value_type chr, size_type pos = DefaultPos) const noexcept { \ + return Name(self_type(&chr, 1), pos); \ + } \ + constexpr size_type Name(const_pointer cstr, size_type pos, size_type count) const noexcept { \ + return Name(self_type(cstr, count), pos); \ + } \ + constexpr size_type Name(const_pointer cstr, size_type pos = DefaultPos) const noexcept { \ + return Name(self_type(cstr), pos); \ + } \ + bsoncxx_force_semicolon + DECL_FINDERS(find, 0); + DECL_FINDERS(rfind, npos); + DECL_FINDERS(find_first_of, 0); + DECL_FINDERS(find_last_of, npos); + DECL_FINDERS(find_first_not_of, 0); + DECL_FINDERS(find_last_not_of, npos); +#undef DECL_FINDERS + /** * @brief Test whether the string starts-with the given prefix string */ @@ -389,6 +472,21 @@ class basic_string_view : detail::equality_operators, detail::ordering_operators return size() >= sfx.size() && substr(size() - sfx.size()) == sfx; } + /** + * @brief Test whether the string contains any occurrence of the given substring + */ + constexpr bool contains(self_type infix) const noexcept { + return find(infix) != npos; + } + + constexpr bool contains(value_type chr) const noexcept { + return contains(string_view(&chr, 1)); + } + + constexpr bool contains(const_pointer cstr) const noexcept { + return contains(self_type(cstr)); + } + /** * @brief Explicit-conversion to a std::basic_string */ @@ -430,8 +528,43 @@ class basic_string_view : detail::equality_operators, detail::ordering_operators out.write(self.data(), static_cast(self.size())); return out; } + + // Find the first index I where the given predicate returns true for substr(I) + template + bsoncxx_cxx14_constexpr size_type _find_if(size_type pos, F pred) const noexcept { + const iterator found = detail::find_if(substr(pos), pred); + if (found == end()) { + return npos; + } + return _iter_to_pos(found); + } + + // Find the last index I where the given predicate returns true for substr(0, I) + template + bsoncxx_cxx14_constexpr size_type _rfind_if(size_type pos, F pred) const noexcept { + const const_reverse_iterator found = + detail::find_if(detail::make_reversed_view(substr(0, pos)), pred); + if (found == rend()) { + return npos; + } + return _iter_to_pos(found); + } + + // Convert an iterator to a zero-based index + constexpr size_type _iter_to_pos(const_iterator it) const noexcept { + return static_cast(it - begin()); + } + + // Convert a reverse-iterator to a zero-based index + constexpr size_type _iter_to_pos(const_reverse_iterator it) const noexcept { + return static_cast(rend() - it); + } }; +// Required to define this here for C++≤14 compatibility. Can be removed in C++≥17 +template +const std::size_t basic_string_view::npos; + using string_view = basic_string_view; } // namespace stdx diff --git a/src/bsoncxx/test/CMakeLists.txt b/src/bsoncxx/test/CMakeLists.txt index e2dd485d4a..3a55c1cbfa 100644 --- a/src/bsoncxx/test/CMakeLists.txt +++ b/src/bsoncxx/test/CMakeLists.txt @@ -40,6 +40,7 @@ add_executable(test_bson make_unique.test.cpp ranges.test.cpp string_view.test.cpp + algorithm.test.cpp type_traits.test.cpp iterator.test.cpp ) @@ -144,6 +145,7 @@ set_dist_list(src_bsoncxx_test_DIST test_macro_guards.cpp.in to_string.hh view_or_value.cpp + algorithm.test.cpp type_traits.test.cpp make_unique.test.cpp iterator.test.cpp diff --git a/src/bsoncxx/test/algorithm.test.cpp b/src/bsoncxx/test/algorithm.test.cpp index 987ac9a900..c340fb8760 100644 --- a/src/bsoncxx/test/algorithm.test.cpp +++ b/src/bsoncxx/test/algorithm.test.cpp @@ -41,11 +41,11 @@ TEST_CASE("Algorithm: equal()") { TEST_CASE("Algorithm: Simple search") { auto arr = {1, 2, 3, 4}; auto needle = {2, 3}; - auto ss = ranges::ssize(ranges::make_subrange(arr.begin(), arr.end())); auto searcher = bsoncxx::detail::default_searcher{ bsoncxx::detail::begin(needle), bsoncxx::detail::end(needle), {}}; auto found = searcher(bsoncxx::detail::begin(arr), bsoncxx::detail::end(arr)); CHECK(found.first == bsoncxx::detail::begin(arr) + 1); auto found2 = bsoncxx::detail::search(arr, needle); + CHECK(found2.begin() == bsoncxx::detail::begin(arr) + 1); } diff --git a/src/bsoncxx/test/string_view.test.cpp b/src/bsoncxx/test/string_view.test.cpp index 36ba685406..15db3ae6da 100644 --- a/src/bsoncxx/test/string_view.test.cpp +++ b/src/bsoncxx/test/string_view.test.cpp @@ -157,3 +157,48 @@ TEST_CASE("string_view: Overloading safety") { std::vector vec; CHECK(vec == vec); } + +TEST_CASE("string_view: find") { + string_view s1 = "abc123abc123"; + auto pos = s1.find("abc"); + CHECK(pos == 0); + pos = s1.find("bc1"); + CHECK(pos == 1); + pos = s1.find("bc1", 1); + CHECK(pos == 1); + pos = s1.find("bc1", 2); + CHECK(pos == 7); + pos = s1.find("", 4); + CHECK(pos == 4); + CHECK(s1.find("") == 0); + CHECK(s1.find("nowhere") == s1.npos); + CHECK(s1.rfind("nowhere") == s1.npos); + CHECK(s1.find("123") == 3); + CHECK(s1.rfind("123") == 9); + CHECK(s1.rfind("abc", 8) == 0); + CHECK(s1.rfind("") == 12); + + CHECK(s1.find_first_of("54321") == 3); + CHECK(s1.find_first_of("nope") == s1.npos); + CHECK(s1.find_last_of("fedcba") == 9); + CHECK(s1.find_last_of("nope") == s1.npos); + + CHECK(s1.find_first_of("54321", 5) == 5); + CHECK(s1.find_first_of("nope", 5) == s1.npos); + CHECK(s1.find_last_of("fedcba", 5) == 3); + CHECK(s1.find_last_of("nope", 5) == s1.npos); + + CHECK(s1.find_first_not_of("abcdef") == 3); + CHECK(s1.find_first_not_of("123456") == 0); + CHECK(s1.find_last_not_of("abcdef") == 12); + CHECK(s1.find_last_not_of("123456") == 9); + CHECK(s1.find_first_not_of("abcdef123456") == s1.npos); + CHECK(s1.find_last_not_of("abcdef123456") == s1.npos); + + CHECK(s1.find_first_not_of("abcdef", 5) == 5); + CHECK(s1.find_first_not_of("123456", 5) == 6); + CHECK(s1.find_last_not_of("abcdef", 5) == 5); + CHECK(s1.find_last_not_of("123456", 5) == 3); + CHECK(s1.find_first_not_of("abcdef123456", 5) == s1.npos); + CHECK(s1.find_last_not_of("abcdef123456", 5) == s1.npos); +} From 1f3c509a9e15582a78e12897d2af800fc86310ce Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Mon, 4 Dec 2023 14:22:59 -0700 Subject: [PATCH 26/47] Remove newer .clang-foramt option, document internal macros as internal --- .clang-format | 2 -- .../include/bsoncxx/v_noabi/bsoncxx/config/util.hpp | 8 ++++++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/.clang-format b/.clang-format index 39aa4ad241..281a4725a5 100644 --- a/.clang-format +++ b/.clang-format @@ -23,5 +23,3 @@ NamespaceIndentation: None SpaceBeforeAssignmentOperators: true Standard: Cpp11 UseTab: Never -WhitespaceSensitiveMacros: - - bsoncxx_pragma diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/config/util.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/config/util.hpp index 60d372d07f..70f4f7f6e5 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/config/util.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/config/util.hpp @@ -1,5 +1,6 @@ // clang-format off /** + * @internal * @brief Convert the given macro argument to a string literal, after macro expansion */ #define bsoncxx_stringify(...) bsoncxx_stringify_impl(__VA_ARGS__) @@ -12,6 +13,7 @@ #define bsoncxx_concat_impl(A, ...) A##__VA_ARGS__ /** + * @internal * @brief Expands to a _Pragma() preprocessor directive, after macro expansion * * The arguments an arbitrary "token soup", and should not be quoted like a regular @@ -35,6 +37,7 @@ #endif /** + * @internal * @brief Use in a declaration position to force the appearence of a semicolon * as the next token. Use this for statement-like or declaration-like macros to * enforce that their call sites are followed by a semicolon @@ -42,6 +45,7 @@ #define bsoncxx_force_semicolon static_assert(true, "") /** + * @internal * @brief Add a trailing noexcept, decltype-return, and return-body to a * function definition. (Not compatible with lambda expressions.) * @@ -65,6 +69,7 @@ bsoncxx_force_semicolon /** + * @internal * @macro mongocxx_cxx14_constexpr * @brief Expands to `constexpr` if compiling as c++14 or greater, otherwise * expands to `inline`. @@ -79,6 +84,7 @@ #endif /** + * @internal * @brief Disable a warning for a particular compiler. * * The argument should be of the form: @@ -95,6 +101,7 @@ bsoncxx_force_semicolon /** + * @internal * @brief Push the current compiler diagnostics settings state */ #define bsoncxx_push_warnings() \ @@ -103,6 +110,7 @@ bsoncxx_force_semicolon /** + * @internal * @brief Restore prior compiler diagnostics settings from before the most * recent bsoncxx_push_warnings() */ From 67af4b34ee9148cc22a4ab53abffcb53a916f4ba Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Wed, 6 Dec 2023 12:03:18 -0700 Subject: [PATCH 27/47] Calm linter --- .../bsoncxx/v_noabi/bsoncxx/stdx/algorithm.hpp | 4 ---- .../include/bsoncxx/v_noabi/bsoncxx/stdx/ranges.hpp | 3 ++- src/bsoncxx/test/algorithm.test.cpp | 13 ++++++------- src/bsoncxx/test/iterator.test.cpp | 5 ++--- src/bsoncxx/test/string_view.test.cpp | 9 ++++----- 5 files changed, 14 insertions(+), 20 deletions(-) diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/algorithm.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/algorithm.hpp index f6152dbca0..0da6501232 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/algorithm.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/algorithm.hpp @@ -11,9 +11,7 @@ #include namespace bsoncxx { - inline namespace v_noabi { - namespace detail { /** @@ -422,9 +420,7 @@ constexpr not_fn_t not_fn(F&& fn) { } } // namespace detail - } // namespace v_noabi - } // namespace bsoncxx #include diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/ranges.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/ranges.hpp index b5e1abbe35..b463fbd4b2 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/ranges.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/ranges.hpp @@ -22,8 +22,8 @@ namespace bsoncxx { inline namespace v_noabi { - namespace detailx { +// clang-format off // Workarounds for MSVC 19.10 doing bad: An invocable object with name `n` should not be visible // within its own call operator. We need to "hide" the ADL name lookup out here in a different // namespace to prevent them from finding the invocable objects. @@ -34,6 +34,7 @@ constexpr auto adl_begin(T&& t) bsoncxx_returns(begin((T&&)t)); template constexpr auto adl_end(T&& t) bsoncxx_returns(end((T&&)t)); } // namespace detailx +// clang-format on namespace detail { diff --git a/src/bsoncxx/test/algorithm.test.cpp b/src/bsoncxx/test/algorithm.test.cpp index c340fb8760..7988ac92e0 100644 --- a/src/bsoncxx/test/algorithm.test.cpp +++ b/src/bsoncxx/test/algorithm.test.cpp @@ -1,14 +1,13 @@ -#include "bsoncxx/stdx/algorithm.hpp" - #include #include #include -#include "bsoncxx/stdx/iterator.hpp" -#include "bsoncxx/stdx/operators.hpp" -#include "bsoncxx/stdx/ranges.hpp" -#include "bsoncxx/stdx/string_view.hpp" -#include "bsoncxx/stdx/type_traits.hpp" +#include +#include +#include +#include +#include +#include #include namespace ranges = bsoncxx::detail; diff --git a/src/bsoncxx/test/iterator.test.cpp b/src/bsoncxx/test/iterator.test.cpp index a2c2f14e47..3153c71c71 100644 --- a/src/bsoncxx/test/iterator.test.cpp +++ b/src/bsoncxx/test/iterator.test.cpp @@ -1,11 +1,10 @@ -#include "bsoncxx/stdx/iterator.hpp" - #include #include #include #include -#include "bsoncxx/stdx/type_traits.hpp" +#include +#include #include namespace { diff --git a/src/bsoncxx/test/string_view.test.cpp b/src/bsoncxx/test/string_view.test.cpp index 15db3ae6da..58739a481a 100644 --- a/src/bsoncxx/test/string_view.test.cpp +++ b/src/bsoncxx/test/string_view.test.cpp @@ -1,14 +1,13 @@ -#include "bsoncxx/stdx/string_view.hpp" - #include #include #include #include #include -#include "bsoncxx/stdx/iterator.hpp" -#include "bsoncxx/stdx/operators.hpp" -#include "bsoncxx/stdx/type_traits.hpp" +#include +#include +#include +#include #include namespace stdx = bsoncxx::stdx; From 2c61f8df10e13290371e550142cd7b66682c5685 Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Fri, 8 Dec 2023 14:55:53 -0700 Subject: [PATCH 28/47] Sort file lists --- src/bsoncxx/include/CMakeLists.txt | 2 +- src/bsoncxx/test/CMakeLists.txt | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/bsoncxx/include/CMakeLists.txt b/src/bsoncxx/include/CMakeLists.txt index 719f1a72ed..3e52aa223b 100644 --- a/src/bsoncxx/include/CMakeLists.txt +++ b/src/bsoncxx/include/CMakeLists.txt @@ -86,8 +86,8 @@ set_dist_list(src_bsoncxx_include_DIST bsoncxx/v_noabi/bsoncxx/stdx/algorithm.hpp bsoncxx/v_noabi/bsoncxx/stdx/iterator.hpp bsoncxx/v_noabi/bsoncxx/stdx/make_unique.hpp - bsoncxx/v_noabi/bsoncxx/stdx/optional.hpp bsoncxx/v_noabi/bsoncxx/stdx/operators.hpp + bsoncxx/v_noabi/bsoncxx/stdx/optional.hpp bsoncxx/v_noabi/bsoncxx/stdx/ranges.hpp bsoncxx/v_noabi/bsoncxx/stdx/string_view.hpp bsoncxx/v_noabi/bsoncxx/stdx/type_traits.hpp diff --git a/src/bsoncxx/test/CMakeLists.txt b/src/bsoncxx/test/CMakeLists.txt index 3a55c1cbfa..55688246f3 100644 --- a/src/bsoncxx/test/CMakeLists.txt +++ b/src/bsoncxx/test/CMakeLists.txt @@ -37,12 +37,12 @@ add_executable(test_bson json.cpp oid.cpp view_or_value.cpp + algorithm.test.cpp + iterator.test.cpp make_unique.test.cpp ranges.test.cpp string_view.test.cpp - algorithm.test.cpp type_traits.test.cpp - iterator.test.cpp ) # Common target properties for test executables. @@ -146,9 +146,9 @@ set_dist_list(src_bsoncxx_test_DIST to_string.hh view_or_value.cpp algorithm.test.cpp - type_traits.test.cpp - make_unique.test.cpp iterator.test.cpp + make_unique.test.cpp ranges.test.cpp string_view.test.cpp + type_traits.test.cpp ) From 7d31688455c68adb378f9415dc6206362e7a0ce9 Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Fri, 8 Dec 2023 14:57:52 -0700 Subject: [PATCH 29/47] Remove string_view assertions --- .../v_noabi/bsoncxx/stdx/string_view.hpp | 23 +++---------------- src/bsoncxx/lib/CMakeLists.txt | 2 -- .../v_noabi/bsoncxx/stdx/string_view.cpp | 14 ----------- 3 files changed, 3 insertions(+), 36 deletions(-) delete mode 100644 src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/stdx/string_view.cpp diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/string_view.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/string_view.hpp index 39ef5798cf..182b912f2b 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/string_view.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/string_view.hpp @@ -37,10 +37,6 @@ namespace detail { using namespace bsoncxx::detail; -[[noreturn]] BSONCXX_API void string_view_oob_terminate(const char* msg, - std::size_t length, - std::ptrdiff_t offset) noexcept; - template auto detect_string_f(...) -> std::false_type; @@ -222,8 +218,7 @@ class basic_string_view : detail::equality_operators, detail::ordering_operators * than size() */ constexpr const_reference operator[](size_type offset) const noexcept { - return (_assert_inbounds(offset, for_access, "basic_string_view::operator[]"), - _begin[offset]); + return _begin[offset]; } /** @@ -240,12 +235,11 @@ class basic_string_view : detail::equality_operators, detail::ordering_operators } /// Access the first character in the string constexpr const_reference front() const noexcept { - return (_assert_inbounds(0, for_access, "basic_string_view::front()"), (*this)[0]); + return (*this)[0]; } /// Access the last character in the string constexpr const_reference back() const noexcept { - return (_assert_inbounds(size() - 1, for_access, "basic_string_view::back()"), - (*this)[size() - 1]); + return (*this)[size() - 1]; } /// Obtain a pointer to the beginning of the referred-to character array @@ -275,7 +269,6 @@ class basic_string_view : detail::equality_operators, detail::ordering_operators * @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 { - _assert_inbounds(n, for_offset, "basic_string_view::remove_prefix()"); _begin += n; _size -= n; } @@ -286,7 +279,6 @@ class basic_string_view : detail::equality_operators, detail::ordering_operators * @param n The number of characters to remove from the end. Must be less than size() */ bsoncxx_cxx14_constexpr void remove_suffix(size_type n) noexcept { - _assert_inbounds(n, for_offset, "basic_string_view::remove_suffix()"); _size -= n; } @@ -496,15 +488,6 @@ class basic_string_view : detail::equality_operators, detail::ordering_operators } private: - /// If the given 'pos' is out of bounds, terminates the program with an error message on stderr - enum bounds_check { for_access, for_offset }; - void _assert_inbounds(size_type pos, bounds_check kind, const char* what) const noexcept { - const auto bound = kind == for_access ? _size + 1 : _size; - if (bound < pos) { - stdx::detail::string_view_oob_terminate(what, _size, static_cast(pos)); - } - } - // Additional level-of-indirection for constexpr compare() constexpr int _compare2(int diff, self_type other) const noexcept { // "diff" is the diff according to Traits::cmp diff --git a/src/bsoncxx/lib/CMakeLists.txt b/src/bsoncxx/lib/CMakeLists.txt index 54e73abc75..4b528dda20 100644 --- a/src/bsoncxx/lib/CMakeLists.txt +++ b/src/bsoncxx/lib/CMakeLists.txt @@ -25,7 +25,6 @@ list(APPEND bsoncxx_sources bsoncxx/v_noabi/bsoncxx/json.cpp bsoncxx/v_noabi/bsoncxx/oid.cpp bsoncxx/v_noabi/bsoncxx/private/itoa.cpp - bsoncxx/v_noabi/bsoncxx/stdx/string_view.cpp bsoncxx/v_noabi/bsoncxx/string/view_or_value.cpp bsoncxx/v_noabi/bsoncxx/types.cpp bsoncxx/v_noabi/bsoncxx/types/bson_value/value.cpp @@ -88,7 +87,6 @@ set_dist_list(src_bsoncxx_lib_DIST bsoncxx/v_noabi/bsoncxx/private/libbson.hh bsoncxx/v_noabi/bsoncxx/private/stack.hh bsoncxx/v_noabi/bsoncxx/private/suppress_deprecation_warnings.hh - bsoncxx/v_noabi/bsoncxx/stdx/string_view.cpp bsoncxx/v_noabi/bsoncxx/string/view_or_value.cpp bsoncxx/v_noabi/bsoncxx/test_util/export_for_testing.hh bsoncxx/v_noabi/bsoncxx/types.cpp diff --git a/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/stdx/string_view.cpp b/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/stdx/string_view.cpp deleted file mode 100644 index 974a36371f..0000000000 --- a/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/stdx/string_view.cpp +++ /dev/null @@ -1,14 +0,0 @@ -#include -#include - -#include - -#include - -void bsoncxx::v_noabi::stdx::detail::string_view_oob_terminate(const char* msg, - std::size_t length, - std::ptrdiff_t position) noexcept { - std::cerr << msg << ": Out-of-bounds access to string_view element at offset " << position - << " (String has length " << length << ")" << std::endl; - std::terminate(); -} From bff45a14704f70c786edd1e895cfc445ef33c4e6 Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Fri, 8 Dec 2023 14:58:59 -0700 Subject: [PATCH 30/47] Add/update copyright banners --- .../v_noabi/bsoncxx/stdx/algorithm.hpp | 14 +++++++++++++ .../bsoncxx/v_noabi/bsoncxx/stdx/iterator.hpp | 14 +++++++++++++ .../v_noabi/bsoncxx/stdx/operators.hpp | 14 +++++++++++++ .../bsoncxx/v_noabi/bsoncxx/stdx/ranges.hpp | 20 ++++++++++++------- .../v_noabi/bsoncxx/stdx/string_view.hpp | 2 +- .../v_noabi/bsoncxx/stdx/type_traits.hpp | 14 +++++++++++++ 6 files changed, 70 insertions(+), 8 deletions(-) diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/algorithm.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/algorithm.hpp index 0da6501232..1776084d37 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/algorithm.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/algorithm.hpp @@ -1,3 +1,17 @@ +// Copyright 2023 MongoDB Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #pragma once #include diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/iterator.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/iterator.hpp index 0904d9a0eb..09705e3e29 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/iterator.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/iterator.hpp @@ -1,3 +1,17 @@ +// Copyright 2023 MongoDB Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #pragma once #include diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/operators.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/operators.hpp index 5bbada5c3a..e06b21f388 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/operators.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/operators.hpp @@ -1,3 +1,17 @@ +// Copyright 2023 MongoDB Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #pragma once #include diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/ranges.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/ranges.hpp index b463fbd4b2..7bf94feebf 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/ranges.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/ranges.hpp @@ -1,10 +1,16 @@ -/** - * @file ranges.hpp - * @brief A backport of a small amount of std::ranges from C++20 - * @date 2023-11-14 - * - * @copyright Copyright (c) 2023 - */ +// Copyright 2023 MongoDB Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. #pragma once #include diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/string_view.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/string_view.hpp index 182b912f2b..d54fd4abb4 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/string_view.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/string_view.hpp @@ -1,4 +1,4 @@ -// Copyright 2015 MongoDB Inc. +// Copyright 2023 MongoDB Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/type_traits.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/type_traits.hpp index 93fe609660..f834a3da6d 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/type_traits.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/type_traits.hpp @@ -1,3 +1,17 @@ +// Copyright 2023 MongoDB Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #pragma once #include From b5026324a69e1ec008e1092114f9e2f0fd35df25 Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Fri, 8 Dec 2023 15:01:21 -0700 Subject: [PATCH 31/47] Tweak is_dereferencable to test lvalues --- .../include/bsoncxx/v_noabi/bsoncxx/stdx/iterator.hpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/iterator.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/iterator.hpp index 09705e3e29..3841d06fa1 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/iterator.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/iterator.hpp @@ -91,11 +91,12 @@ bsoncxx_pop_warnings(); * type is non-void */ template -struct is_dereferencable : conjunction, - // Clang supports dereferencing void*, and we can't detect - // that easily. Refuse if I is (cv-)void* - negation>>, - negation>>> {}; +struct is_dereferencable + : conjunction>, + // Clang supports dereferencing void*, and we can't detect + // that easily. Refuse if I is (cv-)void* + negation>>, + negation>>>> {}; /** * @brief Obtain the value type of the given iterator. From 347228a74b71c3c835ac98a066cacfc35a36b7aa Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Fri, 8 Dec 2023 15:03:04 -0700 Subject: [PATCH 32/47] Tweak some macro names/scoping --- .../v_noabi/bsoncxx/stdx/operators.hpp | 23 +++++++++++-------- .../v_noabi/bsoncxx/stdx/string_view.hpp | 4 +++- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/operators.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/operators.hpp index e06b21f388..f6b367bc50 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/operators.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/operators.hpp @@ -104,7 +104,8 @@ class strong_ordering { constexpr bool operator!=(strong_ordering o) const noexcept { return !(*this == o); } - +#pragma push_macro("DEFOP") +#undef DEFOP #define DEFOP(Op) \ constexpr bool operator Op(std::nullptr_t) const noexcept { \ return _c Op 0; \ @@ -114,21 +115,23 @@ class strong_ordering { DEFOP(>); DEFOP(<=); DEFOP(>=); -#undef DEFOP +#pragma pop_macro("DEFOP") }; -#define psuedo_inline bsoncxx_if_gnu_like([[gnu::weak]]) bsoncxx_if_msvc(__declspec(selectany)) +#pragma push_macro("INLINE_VAR") +#undef INLINE_VAR +#define INLINE_VAR bsoncxx_if_gnu_like([[gnu::weak]]) bsoncxx_if_msvc(__declspec(selectany)) -psuedo_inline const strong_ordering strong_ordering::less = +INLINE_VAR const strong_ordering strong_ordering::less = strong_ordering(strong_ordering::_construct{}, -1); -psuedo_inline const strong_ordering strong_ordering::greater = +INLINE_VAR const strong_ordering strong_ordering::greater = strong_ordering(strong_ordering::_construct{}, 1); -psuedo_inline const strong_ordering strong_ordering::equivalent = +INLINE_VAR const strong_ordering strong_ordering::equivalent = strong_ordering(strong_ordering::_construct{}, 0); -psuedo_inline const strong_ordering strong_ordering::equal = +INLINE_VAR const strong_ordering strong_ordering::equal = strong_ordering(strong_ordering::_construct{}, 0); -#undef psuedo_inline +#pragma pop_macro("INLINE_VAR") /** * @brief Implements a three-way comparison between two objects. That is, in @@ -164,6 +167,8 @@ struct compare_three_way { * implementation of tag_invoke(compare_three_way, l, r) */ struct ordering_operators { +#pragma push_macro("DEFOP") +#undef DEFOP #define DEFOP(Oper) \ template \ constexpr friend auto operator Oper(const L& l, const R& r) \ @@ -172,7 +177,7 @@ struct ordering_operators { DEFOP(>); DEFOP(<=); DEFOP(>=); -#undef DEFOP +#pragma pop_macro("DEFOP") }; } // namespace detail diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/string_view.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/string_view.hpp index d54fd4abb4..265002076b 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/string_view.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/string_view.hpp @@ -431,6 +431,8 @@ class basic_string_view : detail::equality_operators, detail::ordering_operators return _rfind_if(pos, detail::not_fn(detail::equal_to_any_of(set))); } +#pragma push_macro("DECL_FINDERS") +#undef DECL_FINDERS #define DECL_FINDERS(Name, DefaultPos) \ constexpr size_type Name(value_type chr, size_type pos = DefaultPos) const noexcept { \ return Name(self_type(&chr, 1), pos); \ @@ -448,7 +450,7 @@ class basic_string_view : detail::equality_operators, detail::ordering_operators DECL_FINDERS(find_last_of, npos); DECL_FINDERS(find_first_not_of, 0); DECL_FINDERS(find_last_not_of, npos); -#undef DECL_FINDERS +#pragma pop_macro("DECL_FINDERS") /** * @brief Test whether the string starts-with the given prefix string From af787d555e06c9c4f5e08b6bbd32d70aedba6157 Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Fri, 8 Dec 2023 15:11:02 -0700 Subject: [PATCH 33/47] Updating casing on macro names --- .../v_noabi/bsoncxx/config/compiler.hpp | 32 +++++------ .../v_noabi/bsoncxx/config/postlude.hpp | 30 +++++----- .../v_noabi/bsoncxx/config/prelude.hpp | 56 +++++++++---------- .../bsoncxx/v_noabi/bsoncxx/config/util.hpp | 52 ++++++++--------- .../v_noabi/bsoncxx/document/value.hpp | 6 +- .../v_noabi/bsoncxx/stdx/algorithm.hpp | 26 ++++----- .../bsoncxx/v_noabi/bsoncxx/stdx/iterator.hpp | 20 +++---- .../v_noabi/bsoncxx/stdx/operators.hpp | 14 ++--- .../bsoncxx/v_noabi/bsoncxx/stdx/ranges.hpp | 40 ++++++------- .../v_noabi/bsoncxx/stdx/string_view.hpp | 2 +- .../v_noabi/bsoncxx/stdx/type_traits.hpp | 8 +-- .../include/bsoncxx/v_noabi/bsoncxx/types.hpp | 6 +- src/bsoncxx/test/type_traits.test.cpp | 2 +- 13 files changed, 147 insertions(+), 147 deletions(-) diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/config/compiler.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/config/compiler.hpp index 9ea7981760..866c194800 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/config/compiler.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/config/compiler.hpp @@ -14,33 +14,33 @@ // clang-format off -#define bsoncxx_if_msvc(...) -#define bsoncxx_if_gcc(...) -#define bsoncxx_if_clang(...) -#define bsoncxx_if_gnu_like(...) \ - bsoncxx_if_gcc(__VA_ARGS__) \ - bsoncxx_if_clang(__VA_ARGS__) +#define BSONCXX_IF_MSVC(...) +#define BSONCXX_IF_GCC(...) +#define BSONCXX_IF_CLANG(...) +#define BSONCXX_IF_GNU_LIKE(...) \ + BSONCXX_IF_GCC(__VA_ARGS__) \ + BSONCXX_IF_CLANG(__VA_ARGS__) #ifdef __GNUC__ #ifdef __clang__ - #undef bsoncxx_if_clang - #define bsoncxx_if_clang(...) __VA_ARGS__ + #undef BSONCXX_IF_CLANG + #define BSONCXX_IF_CLANG(...) __VA_ARGS__ #else - #undef bsoncxx_if_gcc - #define bsoncxx_if_gcc(...) __VA_ARGS__ + #undef BSONCXX_IF_GCC + #define BSONCXX_IF_GCC(...) __VA_ARGS__ #endif #elif defined(_MSC_VER) - #undef bsoncxx_if_msvc - #define bsoncxx_if_msvc(...) __VA_ARGS__ + #undef BSONCXX_IF_MSVC + #define BSONCXX_IF_MSVC(...) __VA_ARGS__ #endif // clang-format on // Disable MSVC warnings that cause a lot of noise related to DLL visibility // for types that we don't control (like std::unique_ptr). -bsoncxx_push_warnings(); -bsoncxx_disable_warning(MSVC(4251)); -bsoncxx_disable_warning(MSVC(5275)); +BSONCXX_PUSH_WARNINGS(); +BSONCXX_DISABLE_WARNING(MSVC(4251)); +BSONCXX_DISABLE_WARNING(MSVC(5275)); #define BSONCXX_INLINE inline BSONCXX_PRIVATE -#define BSONCXX_CALL bsoncxx_if_msvc(__cdecl) +#define BSONCXX_CALL BSONCXX_IF_MSVC(__cdecl) diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/config/postlude.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/config/postlude.hpp index 9011627fc7..22f1355dd8 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/config/postlude.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/config/postlude.hpp @@ -15,7 +15,7 @@ // compiler.hpp #undef BSONCXX_INLINE #pragma pop_macro("BSONCXX_INLINE") -bsoncxx_pop_warnings(); +BSONCXX_POP_WARNINGS(); #undef BSONCXX_CALL #pragma pop_macro("BSONCXX_CALL") @@ -66,7 +66,7 @@ bsoncxx_pop_warnings(); #pragma pop_macro("BSONCXX_UNREACHABLE") #pragma pop_macro("bsoncxx_cxx14_constexpr") -#pragma pop_macro("bsoncxx_returns") +#pragma pop_macro("BSONCXX_RETURNS") // CXX-2769: out-of-place, but remains for backward compatibility. #ifdef BSONCXX_ENUM @@ -75,25 +75,25 @@ static_assert(false, "BSONCXX_ENUM must be undef'ed"); #pragma pop_macro("BSONCXX_ENUM") // util.hpp -#pragma pop_macro("bsoncxx_push_warnings") -#pragma pop_macro("bsoncxx_pop_warnings") -#pragma pop_macro("bsoncxx_disable_warning") +#pragma pop_macro("BSONCXX_PUSH_WARNINGS") +#pragma pop_macro("BSONCXX_POP_WARNINGS") +#pragma pop_macro("BSONCXX_DISABLE_WARNING") #pragma pop_macro("_bsoncxxDisableWarningImpl_for_MSVC") #pragma pop_macro("_bsoncxxDisableWarningImpl_for_GCC") #pragma pop_macro("_bsoncxxDisableWarningImpl_for_GNU") #pragma pop_macro("_bsoncxxDisableWarningImpl_for_Clang") -#pragma pop_macro("bsoncxx_concat") -#pragma pop_macro("bsoncxx_concat_impl") +#pragma pop_macro("BSONCXX_CONCAT") +#pragma pop_macro("BSONCXX_CONCAT_IMPL") -#pragma pop_macro("bsoncxx_pragma") +#pragma pop_macro("BSONCXX_PRAGMA") #pragma pop_macro("_bsoncxxPragma") -#pragma pop_macro("bsoncxx_stringify_impl") -#pragma pop_macro("bsoncxx_stringify") -#pragma pop_macro("bsoncxx_force_semicolon") +#pragma pop_macro("BSONCXX_STRINGIFY_IMPL") +#pragma pop_macro("BSONCXX_STRINGIFY") +#pragma pop_macro("BSONCXX_FORCE_SEMICOLON") -#pragma pop_macro("bsoncxx_if_msvc") -#pragma pop_macro("bsoncxx_if_gcc") -#pragma pop_macro("bsoncxx_if_clang") -#pragma pop_macro("bsoncxx_if_gnu_like") +#pragma pop_macro("BSONCXX_IF_MSVC") +#pragma pop_macro("BSONCXX_IF_GCC") +#pragma pop_macro("BSONCXX_IF_CLANG") +#pragma pop_macro("BSONCXX_IF_GNU_LIKE") diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/config/prelude.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/config/prelude.hpp index fdc77ce970..7cfa56c1e8 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/config/prelude.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/config/prelude.hpp @@ -13,30 +13,30 @@ // limitations under the License. // util.hpp -#pragma push_macro("bsoncxx_concat") -#undef bsoncxx_concat -#pragma push_macro("bsoncxx_concat_impl") -#undef bsoncxx_concat_impl -#pragma push_macro("bsoncxx_stringify") -#undef bsoncxx_stringify -#pragma push_macro("bsoncxx_stringify_impl") -#undef bsoncxx_stringify_impl -#pragma push_macro("bsoncxx_pragma") -#undef bsoncxx_pragma +#pragma push_macro("BSONCXX_CONCAT") +#undef BSONCXX_CONCAT +#pragma push_macro("BSONCXX_CONCAT_IMPL") +#undef BSONCXX_CONCAT_IMPL +#pragma push_macro("BSONCXX_STRINGIFY") +#undef BSONCXX_STRINGIFY +#pragma push_macro("BSONCXX_STRINGIFY_IMPL") +#undef BSONCXX_STRINGIFY_IMPL +#pragma push_macro("BSONCXX_PRAGMA") +#undef BSONCXX_PRAGMA #pragma push_macro("_bsoncxxPragma") #undef _bsoncxxPragma -#pragma push_macro("bsoncxx_force_semicolon") -#undef bsoncxx_force_semicolon -#pragma push_macro("bsoncxx_returns") -#undef bsoncxx_returns +#pragma push_macro("BSONCXX_FORCE_SEMICOLON") +#undef BSONCXX_FORCE_SEMICOLON +#pragma push_macro("BSONCXX_RETURNS") +#undef BSONCXX_RETURNS #pragma push_macro("bsoncxx_cxx14_constexpr") #undef bsoncxx_cxx14_constexpr -#pragma push_macro("bsoncxx_disable_warning") -#undef bsoncxx_disable_warning -#pragma push_macro("bsoncxx_push_warnings") -#undef bsoncxx_push_warnings -#pragma push_macro("bsoncxx_pop_warnings") -#undef bsoncxx_pop_warnings +#pragma push_macro("BSONCXX_DISABLE_WARNING") +#undef BSONCXX_DISABLE_WARNING +#pragma push_macro("BSONCXX_PUSH_WARNINGS") +#undef BSONCXX_PUSH_WARNINGS +#pragma push_macro("BSONCXX_POP_WARNINGS") +#undef BSONCXX_POP_WARNINGS #pragma push_macro("_bsoncxxDisableWarningImpl_for_GCC") #undef _bsoncxxDisableWarningImpl_for_GCC #pragma push_macro("_bsoncxxDisableWarningImpl_for_Clang") @@ -51,14 +51,14 @@ #undef BSONCXX_INLINE #pragma push_macro("BSONCXX_CALL") #undef BSONCXX_CALL -#pragma push_macro("bsoncxx_if_msvc") -#undef bsoncxx_if_msvc -#pragma push_macro("bsoncxx_if_gcc") -#undef bsoncxx_if_gcc -#pragma push_macro("bsoncxx_if_clang") -#undef bsoncxx_if_clang -#pragma push_macro("bsoncxx_if_gnu_like") -#undef bsoncxx_if_gnu_like +#pragma push_macro("BSONCXX_IF_MSVC") +#undef BSONCXX_IF_MSVC +#pragma push_macro("BSONCXX_IF_GCC") +#undef BSONCXX_IF_GCC +#pragma push_macro("BSONCXX_IF_CLANG") +#undef BSONCXX_IF_CLANG +#pragma push_macro("BSONCXX_IF_GNU_LIKE") +#undef BSONCXX_IF_GNU_LIKE // config.hpp (generated by CMake) #pragma push_macro("BSONCXX_INLINE_NAMESPACE_BEGIN") diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/config/util.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/config/util.hpp index 70f4f7f6e5..b42ce4682b 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/config/util.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/config/util.hpp @@ -3,14 +3,14 @@ * @internal * @brief Convert the given macro argument to a string literal, after macro expansion */ -#define bsoncxx_stringify(...) bsoncxx_stringify_impl(__VA_ARGS__) -#define bsoncxx_stringify_impl(...) #__VA_ARGS__ +#define BSONCXX_STRINGIFY(...) BSONCXX_STRINGIFY_IMPL(__VA_ARGS__) +#define BSONCXX_STRINGIFY_IMPL(...) #__VA_ARGS__ /** * @brief Token-paste two macro arguments, after macro expansion */ -#define bsoncxx_concat(A, ...) bsoncxx_concat_impl(A, __VA_ARGS__) -#define bsoncxx_concat_impl(A, ...) A##__VA_ARGS__ +#define BSONCXX_CONCAT(A, ...) BSONCXX_CONCAT_IMPL(A, __VA_ARGS__) +#define BSONCXX_CONCAT_IMPL(A, ...) A##__VA_ARGS__ /** * @internal @@ -21,19 +21,19 @@ * * Example: * - * bsoncxx_pragma(GCC diagnostic ignore "-Wconversion") + * BSONCXX_PRAGMA(GCC diagnostic ignore "-Wconversion") * * will become: * * _Pragma("GCC diagnostic ignore \"-Wconversion\"") * */ -#define bsoncxx_pragma(...) _bsoncxxPragma(__VA_ARGS__) +#define BSONCXX_PRAGMA(...) _bsoncxxPragma(__VA_ARGS__) #ifdef _MSC_VER // Old MSVC doesn't recognize C++11 _Pragma(), but it always recognized __pragma #define _bsoncxxPragma(...) __pragma(__VA_ARGS__) #else -#define _bsoncxxPragma(...) _Pragma(bsoncxx_stringify(__VA_ARGS__)) +#define _bsoncxxPragma(...) _Pragma(BSONCXX_STRINGIFY(__VA_ARGS__)) #endif /** @@ -42,7 +42,7 @@ * as the next token. Use this for statement-like or declaration-like macros to * enforce that their call sites are followed by a semicolon */ -#define bsoncxx_force_semicolon static_assert(true, "") +#define BSONCXX_FORCE_SEMICOLON static_assert(true, "") /** * @internal @@ -52,7 +52,7 @@ * Example: * * template - * auto foo(T x, T y) bsoncxx_returns(x + y); + * auto foo(T x, T y) BSONCXX_RETURNS(x + y); * * Becomes: * @@ -62,11 +62,11 @@ * { return x + y }; * */ -#define bsoncxx_returns(...) \ +#define BSONCXX_RETURNS(...) \ noexcept(noexcept(__VA_ARGS__))->decltype(__VA_ARGS__) { \ return __VA_ARGS__; \ } \ - bsoncxx_force_semicolon + BSONCXX_FORCE_SEMICOLON /** * @internal @@ -96,38 +96,38 @@ * * The "GNU" form applies to both GCC and Clang */ -#define bsoncxx_disable_warning(Spec) \ - bsoncxx_concat(_bsoncxxDisableWarningImpl_for_, Spec) \ - bsoncxx_force_semicolon +#define BSONCXX_DISABLE_WARNING(Spec) \ + BSONCXX_CONCAT(_bsoncxxDisableWarningImpl_for_, Spec) \ + BSONCXX_FORCE_SEMICOLON /** * @internal * @brief Push the current compiler diagnostics settings state */ -#define bsoncxx_push_warnings() \ - bsoncxx_if_gnu_like(bsoncxx_pragma(GCC diagnostic push)) \ - bsoncxx_if_msvc(bsoncxx_pragma(warning(push))) \ - bsoncxx_force_semicolon +#define BSONCXX_PUSH_WARNINGS() \ + BSONCXX_IF_GNU_LIKE(BSONCXX_PRAGMA(GCC diagnostic push)) \ + BSONCXX_IF_MSVC(BSONCXX_PRAGMA(warning(push))) \ + BSONCXX_FORCE_SEMICOLON /** * @internal * @brief Restore prior compiler diagnostics settings from before the most - * recent bsoncxx_push_warnings() + * recent BSONCXX_PUSH_WARNINGS() */ -#define bsoncxx_pop_warnings() \ - bsoncxx_if_gnu_like(bsoncxx_pragma(GCC diagnostic pop)) \ - bsoncxx_if_msvc(bsoncxx_pragma(warning(pop))) \ - bsoncxx_force_semicolon +#define BSONCXX_POP_WARNINGS() \ + BSONCXX_IF_GNU_LIKE(BSONCXX_PRAGMA(GCC diagnostic pop)) \ + BSONCXX_IF_MSVC(BSONCXX_PRAGMA(warning(pop))) \ + BSONCXX_FORCE_SEMICOLON #define _bsoncxxDisableWarningImpl_for_GCC(...) \ - bsoncxx_if_gcc(bsoncxx_pragma(GCC diagnostic ignored __VA_ARGS__)) + BSONCXX_IF_GCC(BSONCXX_PRAGMA(GCC diagnostic ignored __VA_ARGS__)) #define _bsoncxxDisableWarningImpl_for_Clang(...) \ - bsoncxx_if_clang(bsoncxx_pragma(GCC diagnostic ignored __VA_ARGS__)) + BSONCXX_IF_CLANG(BSONCXX_PRAGMA(GCC diagnostic ignored __VA_ARGS__)) #define _bsoncxxDisableWarningImpl_for_GNU(...) \ _bsoncxxDisableWarningImpl_for_GCC(__VA_ARGS__) \ _bsoncxxDisableWarningImpl_for_Clang(__VA_ARGS__) #define _bsoncxxDisableWarningImpl_for_MSVC(...) \ - bsoncxx_if_msvc(bsoncxx_pragma(warning(disable : __VA_ARGS__))) + BSONCXX_IF_MSVC(BSONCXX_PRAGMA(warning(disable : __VA_ARGS__))) diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/document/value.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/document/value.hpp index e7232c02d9..28bb05b610 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/document/value.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/document/value.hpp @@ -236,10 +236,10 @@ class value { BSONCXX_INLINE document::view value::view() const noexcept { // Silence false positive with g++ 10.2.1 on Debian 11. - bsoncxx_push_warnings(); - bsoncxx_disable_warning(GCC("-Wmaybe-uninitialized")); + BSONCXX_PUSH_WARNINGS(); + BSONCXX_DISABLE_WARNING(GCC("-Wmaybe-uninitialized")); return document::view{static_cast(_data.get()), _length}; - bsoncxx_pop_warnings(); + BSONCXX_POP_WARNINGS(); } BSONCXX_INLINE value::operator document::view() const noexcept { diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/algorithm.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/algorithm.hpp index 1776084d37..a311ca768e 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/algorithm.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/algorithm.hpp @@ -59,11 +59,11 @@ static constexpr struct _advance_fn { } template - constexpr auto operator()(I& iter, S bound) const bsoncxx_returns(impl(iter, 1, bound)); + constexpr auto operator()(I& iter, S bound) const BSONCXX_RETURNS(impl(iter, 1, bound)); template constexpr auto operator()(I& iter, iter_difference_t off, S bound) const - bsoncxx_returns(impl(iter, off, bound)); + BSONCXX_RETURNS(impl(iter, off, bound)); // Handle bidirectional iterators and negative offsets template @@ -186,7 +186,7 @@ make_reversed_view(R&& rng) noexcept { */ static constexpr struct _distance_fn { template - constexpr static auto impl(rank<2>, R&& rng) bsoncxx_returns(ssize(rng)); + constexpr static auto impl(rank<2>, R&& rng) BSONCXX_RETURNS(ssize(rng)); template bsoncxx_cxx14_constexpr static auto impl(rank<1>, R&& rng) @@ -201,9 +201,9 @@ static constexpr struct _distance_fn { } template - constexpr auto operator()(I i, S s) const bsoncxx_returns(impl(rank<2>{}, make_subrange(i, s))); + constexpr auto operator()(I i, S s) const BSONCXX_RETURNS(impl(rank<2>{}, make_subrange(i, s))); template - constexpr auto operator()(R&& rng) const bsoncxx_returns(impl(rank<2>{}, rng)); + constexpr auto operator()(R&& rng) const BSONCXX_RETURNS(impl(rank<2>{}, rng)); } distance; /** @@ -258,7 +258,7 @@ static constexpr struct _equal_fn { template constexpr static auto definitely_different_sizes(rank<1>, L& l, R& r) - bsoncxx_returns(ssize(l) != ssize(r)); + BSONCXX_RETURNS(ssize(l) != ssize(r)); template constexpr static bool definitely_different_sizes(rank<0>, L&, R&) noexcept { return false; @@ -302,12 +302,12 @@ static constexpr struct _search_fn { template constexpr auto operator()(Hay&& hay, Needle&& ndl, Compare&& cmp = {}) const - bsoncxx_returns((impl)(hay, + BSONCXX_RETURNS((impl)(hay, default_searcher, sentinel_t, Compare>{ begin(ndl), end(ndl), static_cast(cmp)})); template - constexpr auto operator()(Hay&& hay, Searcher&& srch) const bsoncxx_returns(impl(hay, srch)); + constexpr auto operator()(Hay&& hay, Searcher&& srch) const BSONCXX_RETURNS(impl(hay, srch)); } search; template @@ -351,7 +351,7 @@ template struct equal_to_value_t { T value; template - constexpr auto operator()(U&& u) const bsoncxx_returns(u == value); + constexpr auto operator()(U&& u) const BSONCXX_RETURNS(u == value); }; /** @@ -390,7 +390,7 @@ static constexpr struct _find_if_fn { static constexpr struct _find_fn { template constexpr auto operator()(R&& rng, const T& value, Project&& proj = {}) const - bsoncxx_returns(find_if(rng, equal_to_value(value), proj)); + BSONCXX_RETURNS(find_if(rng, equal_to_value(value), proj)); } find; template @@ -398,7 +398,7 @@ struct equal_to_any_of_t { T range; template - constexpr auto operator()(U&& value) const bsoncxx_returns(find(range, value) != end(range)); + constexpr auto operator()(U&& value) const BSONCXX_RETURNS(find(range, value) != end(range)); }; /** @@ -417,10 +417,10 @@ struct not_fn_t { F func; template bsoncxx_cxx14_constexpr auto operator()(Args&&... args) - bsoncxx_returns(!invoke(func, static_cast(args)...)); + BSONCXX_RETURNS(!invoke(func, static_cast(args)...)); template constexpr auto operator()(Args&&... args) const - bsoncxx_returns(!invoke(func, static_cast(args)...)); + BSONCXX_RETURNS(!invoke(func, static_cast(args)...)); }; /** diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/iterator.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/iterator.hpp index 3841d06fa1..1663aa5526 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/iterator.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/iterator.hpp @@ -54,16 +54,16 @@ struct pointer_traits : std::pointer_traits { struct _to_address_fn { template static constexpr auto impl(FancyPointer fp, rank<3>) - bsoncxx_returns(pointer_traits::to_address(fp)); + BSONCXX_RETURNS(pointer_traits::to_address(fp)); template - static constexpr auto impl(Iterator iter, rank<2>) bsoncxx_returns(iter.operator->()); + static constexpr auto impl(Iterator iter, rank<2>) BSONCXX_RETURNS(iter.operator->()); template - static constexpr auto impl(T* p, rank<1>) bsoncxx_returns(p); + static constexpr auto impl(T* p, rank<1>) BSONCXX_RETURNS(p); template - constexpr auto operator()(Iterator iter) const bsoncxx_returns((impl)(iter, rank<10>{})); + constexpr auto operator()(Iterator iter) const BSONCXX_RETURNS((impl)(iter, rank<10>{})); }; /** @@ -80,11 +80,11 @@ using to_address_t = decltype(to_address(std::declval())); /** * @brief The result of applying unary operator* to the given object, if valid */ -bsoncxx_push_warnings(); -bsoncxx_disable_warning(Clang("-Wvoid-ptr-dereference")); +BSONCXX_PUSH_WARNINGS(); +BSONCXX_DISABLE_WARNING(Clang("-Wvoid-ptr-dereference")); template using dereference_t = decltype(*std::declval()); -bsoncxx_pop_warnings(); +BSONCXX_POP_WARNINGS(); /** * @brief Detect a type that can be dereferenced (like a pointer) and the result @@ -170,11 +170,11 @@ using ITER_TRAITS = typename ITER_TRAITS_impl::type; struct calc_iterator_concept { struct impl { template - static auto x(I*, rank<3>) bsoncxx_returns(contiguous_iterator_tag{}); + static auto x(I*, rank<3>) BSONCXX_RETURNS(contiguous_iterator_tag{}); template - static auto x(I, rank<2>) bsoncxx_returns(typename ITER_TRAITS::iterator_concept{}); + static auto x(I, rank<2>) BSONCXX_RETURNS(typename ITER_TRAITS::iterator_concept{}); template - static auto x(I, rank<1>) bsoncxx_returns(typename ITER_TRAITS::iterator_category{}); + static auto x(I, rank<1>) BSONCXX_RETURNS(typename ITER_TRAITS::iterator_category{}); }; template auto operator()(I) -> decltype(impl::x(I{}, rank<10>{})); diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/operators.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/operators.hpp index f6b367bc50..855d9b87dc 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/operators.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/operators.hpp @@ -65,18 +65,18 @@ struct equal_to { */ class equality_operators { template - constexpr static auto impl(rank<1>, L& l, R& r) bsoncxx_returns(tag_invoke(equal_to{}, l, r)); + constexpr static auto impl(rank<1>, L& l, R& r) BSONCXX_RETURNS(tag_invoke(equal_to{}, l, r)); template - constexpr static auto impl(rank<0>, L& l, R& r) bsoncxx_returns(tag_invoke(equal_to{}, r, l)); + constexpr static auto impl(rank<0>, L& l, R& r) BSONCXX_RETURNS(tag_invoke(equal_to{}, r, l)); template constexpr friend auto operator==(const Left& self, const Other& other) - bsoncxx_returns(equality_operators::impl(rank<1>{}, self, other)); + BSONCXX_RETURNS(equality_operators::impl(rank<1>{}, self, other)); template constexpr friend auto operator!=(const Left& self, const Other& other) - bsoncxx_returns(!equality_operators::impl(rank<1>{}, self, other)); + BSONCXX_RETURNS(!equality_operators::impl(rank<1>{}, self, other)); }; /** @@ -120,7 +120,7 @@ class strong_ordering { #pragma push_macro("INLINE_VAR") #undef INLINE_VAR -#define INLINE_VAR bsoncxx_if_gnu_like([[gnu::weak]]) bsoncxx_if_msvc(__declspec(selectany)) +#define INLINE_VAR BSONCXX_IF_GNU_LIKE([[gnu::weak]]) BSONCXX_IF_MSVC(__declspec(selectany)) INLINE_VAR const strong_ordering strong_ordering::less = strong_ordering(strong_ordering::_construct{}, -1); @@ -159,7 +159,7 @@ struct compare_three_way { template constexpr auto operator()(L const& l, R const& r) const - bsoncxx_returns((impl)(l, r, rank<2>{})); + BSONCXX_RETURNS((impl)(l, r, rank<2>{})); }; /** @@ -172,7 +172,7 @@ struct ordering_operators { #define DEFOP(Oper) \ template \ constexpr friend auto operator Oper(const L& l, const R& r) \ - bsoncxx_returns(tag_invoke(compare_three_way{}, l, r) Oper 0) + BSONCXX_RETURNS(tag_invoke(compare_three_way{}, l, r) Oper 0) DEFOP(<); DEFOP(>); DEFOP(<=); diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/ranges.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/ranges.hpp index 7bf94feebf..f740217d3e 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/ranges.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/ranges.hpp @@ -34,11 +34,11 @@ namespace detailx { // within its own call operator. We need to "hide" the ADL name lookup out here in a different // namespace to prevent them from finding the invocable objects. template -constexpr auto adl_size(T&& t) bsoncxx_returns(size((T&&)t)); +constexpr auto adl_size(T&& t) BSONCXX_RETURNS(size((T&&)t)); template -constexpr auto adl_begin(T&& t) bsoncxx_returns(begin((T&&)t)); +constexpr auto adl_begin(T&& t) BSONCXX_RETURNS(begin((T&&)t)); template -constexpr auto adl_end(T&& t) bsoncxx_returns(end((T&&)t)); +constexpr auto adl_end(T&& t) BSONCXX_RETURNS(end((T&&)t)); } // namespace detailx // clang-format on @@ -87,19 +87,19 @@ constexpr requires_t> _decay_copy_pointer(P p) noexcept { static constexpr struct _begin_fn { // 1: Object is an array template - static constexpr auto impl(El (&arr)[N], rank<5>) bsoncxx_returns(arr + 0); + static constexpr auto impl(El (&arr)[N], rank<5>) BSONCXX_RETURNS(arr + 0); // 2: Object has member .begin() returning an iterator template - static constexpr auto impl(R& rng, rank<4>) bsoncxx_returns(_decay_iterator(rng.begin())); + static constexpr auto impl(R& rng, rank<4>) BSONCXX_RETURNS(_decay_iterator(rng.begin())); // 3: Object has an ADL-visible begin(x) returning an iterator template static constexpr auto impl(R& rng, rank<3>) - bsoncxx_returns(_decay_iterator(detailx::adl_begin(rng))); + BSONCXX_RETURNS(_decay_iterator(detailx::adl_begin(rng))); template - constexpr auto operator()(R&& rng) const bsoncxx_returns((impl)(rng, rank<10>{})); + constexpr auto operator()(R&& rng) const BSONCXX_RETURNS((impl)(rng, rank<10>{})); } begin; /** @@ -120,19 +120,19 @@ using iterator_t = decltype(begin(std::declval())); static constexpr struct _end_fn { // 1: Range is an array template - static constexpr auto impl(El (&arr)[N], rank<5>) bsoncxx_returns(arr + N); + static constexpr auto impl(El (&arr)[N], rank<5>) BSONCXX_RETURNS(arr + N); // 2: Range has member .end() returning a valid sentinel template - static constexpr auto impl(R& rng, rank<4>) bsoncxx_returns(_decay_sentinel(rng.end())); + static constexpr auto impl(R& rng, rank<4>) BSONCXX_RETURNS(_decay_sentinel(rng.end())); // 3: Range has ADL-found end(x) returning a valid sentinel template static constexpr auto impl(R& r, rank<3>) - bsoncxx_returns(_decay_sentinel(detailx::adl_end(r))); + BSONCXX_RETURNS(_decay_sentinel(detailx::adl_end(r))); template - constexpr auto operator()(R&& rng) const bsoncxx_returns((impl>)(rng, rank<5>{})); + constexpr auto operator()(R&& rng) const BSONCXX_RETURNS((impl>)(rng, rank<5>{})); } end; /** @@ -155,16 +155,16 @@ using sentinel_t = decltype(end(std::declval())); static constexpr struct _size_fn { // 1: Array of known bound template - static constexpr auto impl(Element (&)[N], rank<5>) bsoncxx_returns(N); + static constexpr auto impl(Element (&)[N], rank<5>) BSONCXX_RETURNS(N); // 2: Range with member .size() template - static constexpr auto impl(R& rng, rank<4>) bsoncxx_returns(_decay_integral(rng.size())); + static constexpr auto impl(R& rng, rank<4>) BSONCXX_RETURNS(_decay_integral(rng.size())); // 3: Range with ADL-found size(x) template static constexpr auto impl(R& rng, rank<3>) - bsoncxx_returns(_decay_integral(detailx::adl_size(rng))); + BSONCXX_RETURNS(_decay_integral(detailx::adl_size(rng))); // 4: Range is a forward-range and has a sized sentinel type template >> static constexpr auto impl(R& rng, rank<2>) - bsoncxx_returns(static_cast(end(rng) - begin(rng))); + BSONCXX_RETURNS(static_cast(end(rng) - begin(rng))); template - constexpr auto operator()(R&& rng) const bsoncxx_returns((impl)(rng, rank<10>{})); + constexpr auto operator()(R&& rng) const BSONCXX_RETURNS((impl)(rng, rank<10>{})); } size; /** @@ -198,7 +198,7 @@ static constexpr struct _ssize_fn { typename Signed = make_signed_t, typename RetDiff = conditional_t<(sizeof(Signed) > sizeof(std::ptrdiff_t)), Signed, std::ptrdiff_t>> - constexpr auto operator()(R&& rng) const bsoncxx_returns(static_cast(size(rng))); + constexpr auto operator()(R&& rng) const BSONCXX_RETURNS(static_cast(size(rng))); } ssize; /** @@ -217,13 +217,13 @@ using range_difference_t = iter_difference_t>; */ static constexpr struct _data_fn { template - static constexpr auto impl(R&& rng, rank<2>) bsoncxx_returns(_decay_copy_pointer(rng.data())); + static constexpr auto impl(R&& rng, rank<2>) BSONCXX_RETURNS(_decay_copy_pointer(rng.data())); template >> = 0> - static constexpr auto impl(R&& rng, rank<1>) bsoncxx_returns(to_address(begin(rng))); + static constexpr auto impl(R&& rng, rank<1>) BSONCXX_RETURNS(to_address(begin(rng))); template - constexpr auto operator()(R&& rng) const bsoncxx_returns((impl)(rng, rank<10>{})); + constexpr auto operator()(R&& rng) const BSONCXX_RETURNS((impl)(rng, rank<10>{})); } data; /** diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/string_view.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/string_view.hpp index 265002076b..4729c0d463 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/string_view.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/string_view.hpp @@ -443,7 +443,7 @@ class basic_string_view : detail::equality_operators, detail::ordering_operators constexpr size_type Name(const_pointer cstr, size_type pos = DefaultPos) const noexcept { \ return Name(self_type(cstr), pos); \ } \ - bsoncxx_force_semicolon + BSONCXX_FORCE_SEMICOLON DECL_FINDERS(find, 0); DECL_FINDERS(rfind, npos); DECL_FINDERS(find_first_of, 0); diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/type_traits.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/type_traits.hpp index f834a3da6d..9dbf09cd6c 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/type_traits.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/type_traits.hpp @@ -398,21 +398,21 @@ template struct invoker { template constexpr static auto apply(F&& fun, Args&&... args) - bsoncxx_returns(static_cast(fun)(static_cast(args)...)); + BSONCXX_RETURNS(static_cast(fun)(static_cast(args)...)); }; template <> struct invoker { template constexpr static auto apply(F&& fun, Self&& self, Args&&... args) - bsoncxx_returns((static_cast(self).*fun)(static_cast(args)...)); + BSONCXX_RETURNS((static_cast(self).*fun)(static_cast(args)...)); }; template <> struct invoker { template constexpr static auto apply(F&& fun, Self&& self) - bsoncxx_returns(static_cast(self).*fun); + BSONCXX_RETURNS(static_cast(self).*fun); }; } // namespace impl_invoke @@ -427,7 +427,7 @@ static constexpr struct invoke_fn { template > constexpr auto operator()(F&& fn, Args&&... args) const - bsoncxx_returns(impl_invoke::invoker::value, + BSONCXX_RETURNS(impl_invoke::invoker::value, std::is_member_function_pointer::value> // ::apply(static_cast(fn), static_cast(args)...)); } invoke; diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/types.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/types.hpp index 3e3f5a4c7c..ab9d070d31 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/types.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/types.hpp @@ -31,8 +31,8 @@ #pragma push_macro("BSONCXX_ENUM") #undef BSONCXX_ENUM -bsoncxx_push_warnings(); -bsoncxx_disable_warning(GNU("-Wfloat-equal")); +BSONCXX_PUSH_WARNINGS(); +BSONCXX_DISABLE_WARNING(GNU("-Wfloat-equal")); namespace bsoncxx { inline namespace v_noabi { @@ -673,7 +673,7 @@ BSONCXX_INLINE bool operator==(const b_maxkey&, const b_maxkey&) { } // namespace v_noabi } // namespace bsoncxx -bsoncxx_pop_warnings(); +BSONCXX_POP_WARNINGS(); #ifdef BSONCXX_ENUM static_assert(false, "BSONCXX_ENUM must be undef'ed"); diff --git a/src/bsoncxx/test/type_traits.test.cpp b/src/bsoncxx/test/type_traits.test.cpp index 3e54022e2b..1d1d725c3e 100644 --- a/src/bsoncxx/test/type_traits.test.cpp +++ b/src/bsoncxx/test/type_traits.test.cpp @@ -7,7 +7,7 @@ #include // We declare variables that are only used for compilation checking -bsoncxx_disable_warning(GNU("-Wunused")); +BSONCXX_DISABLE_WARNING(GNU("-Wunused")); namespace { namespace tt = bsoncxx::detail; From 7fb5dc3ee07651b51d5367e8a062dac37aaf12d8 Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Fri, 8 Dec 2023 15:12:41 -0700 Subject: [PATCH 34/47] Exclude some files from Doxygen coverage --- Doxyfile | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Doxyfile b/Doxyfile index 23b7f490ee..ba8a31f09a 100644 --- a/Doxyfile +++ b/Doxyfile @@ -900,7 +900,10 @@ RECURSIVE = YES # Note that relative paths are relative to the directory from which doxygen is # run. -EXCLUDE = +EXCLUDE = src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/iterator.hpp \ + src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/operators.hpp \ + src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/ranges.hpp \ + src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/type_traits.hpp # The EXCLUDE_SYMLINKS tag can be used to select whether or not files or # directories that are symbolic links (a Unix file system feature) are excluded From cb8f1d99f93b85a70ce146aba6b91b4f3aef4a3c Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Fri, 8 Dec 2023 15:13:02 -0700 Subject: [PATCH 35/47] [foldme] macro case updates --- src/bsoncxx/test/CMakeLists.txt | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/bsoncxx/test/CMakeLists.txt b/src/bsoncxx/test/CMakeLists.txt index 55688246f3..6576252a92 100644 --- a/src/bsoncxx/test/CMakeLists.txt +++ b/src/bsoncxx/test/CMakeLists.txt @@ -101,22 +101,22 @@ if(ENABLE_MACRO_GUARD_TESTS) _bsoncxxDisableWarningImpl_for_GNU _bsoncxxDisableWarningImpl_for_MSVC _bsoncxxDisableWarningImpl_for_Clang - bsoncxx_push_warnings - bsoncxx_pop_warnings - bsoncxx_disable_warning - bsoncxx_concat - bsoncxx_concat_impl + BSONCXX_PUSH_WARNINGS + BSONCXX_POP_WARNINGS + BSONCXX_DISABLE_WARNING + BSONCXX_CONCAT + BSONCXX_CONCAT_IMPL bsoncxx_cxx14_constexpr - bsoncxx_force_semicolon - bsoncxx_pragma + BSONCXX_FORCE_SEMICOLON + BSONCXX_PRAGMA _bsoncxxPragma - bsoncxx_stringify - bsoncxx_stringify_impl - bsoncxx_if_msvc - bsoncxx_if_gcc - bsoncxx_if_clang - bsoncxx_if_gnu_like - bsoncxx_returns + BSONCXX_STRINGIFY + BSONCXX_STRINGIFY_IMPL + BSONCXX_IF_MSVC + BSONCXX_IF_GCC + BSONCXX_IF_CLANG + BSONCXX_IF_GNU_LIKE + BSONCXX_RETURNS INCLUDE_PATTERNS "include/*.hpp" # Public headers. "lib/*.hh" # Private headers. From b89c04052449e3e63969b8f547d9884c5f0b0e24 Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Fri, 8 Dec 2023 15:28:03 -0700 Subject: [PATCH 36/47] Simpler iterator_concept_t --- .../bsoncxx/v_noabi/bsoncxx/stdx/iterator.hpp | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/iterator.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/iterator.hpp index 1663aa5526..c4cf6ce173 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/iterator.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/iterator.hpp @@ -168,16 +168,14 @@ using ITER_TRAITS = typename ITER_TRAITS_impl::type; // Get the iterator concept tag from the given iterator-like type struct calc_iterator_concept { - struct impl { - template - static auto x(I*, rank<3>) BSONCXX_RETURNS(contiguous_iterator_tag{}); - template - static auto x(I, rank<2>) BSONCXX_RETURNS(typename ITER_TRAITS::iterator_concept{}); - template - static auto x(I, rank<1>) BSONCXX_RETURNS(typename ITER_TRAITS::iterator_category{}); - }; template - auto operator()(I) -> decltype(impl::x(I{}, rank<10>{})); + static auto impl(I*, rank<3>) -> contiguous_iterator_tag; + template + static auto impl(I, rank<2>) -> typename ITER_TRAITS::iterator_concept; + template + static auto impl(I, rank<1>) -> typename ITER_TRAITS::iterator_category; + template + auto operator()(I) -> decltype(impl(I{}, rank<10>{})); }; /** From 4aad0ebfdf1b8059f2a3f10785f4ecc8b39c79bf Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Fri, 8 Dec 2023 15:28:27 -0700 Subject: [PATCH 37/47] Explain the inclusion of std::contiguous_iterator_tag --- .../include/bsoncxx/v_noabi/bsoncxx/stdx/iterator.hpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/iterator.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/iterator.hpp index c4cf6ce173..5e783472e7 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/iterator.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/iterator.hpp @@ -20,6 +20,7 @@ #include #include #include +// We want to detect stdlib C++20 support. See remarks on contiguous_iterator_tag. #if defined(__has_include) #if __has_include() #include @@ -145,8 +146,14 @@ struct is_iterator : conjunction, // We want contiguous_iterator_tag. We can't get the full functionality without // stdlib support, but we can get reasonable approximation for our purposes #if defined(__cpp_lib_ranges) +// If the C++20 is available, then our iterator_concept_t will pull the I::iterator_concept +// tag from an iterator, which could be std::contiguous_iterator_tag. For compatibility +// with the standard library in that case, use the same iterator tag class exactly: using std::contiguous_iterator_tag; #else +// We are compiling without C++20 stdlib support, so we can't use std::contiguous_iterator_tag. +// In this case, define our own tag type that we can use to detect known pre-c++20 contiguous +// iterators. struct contiguous_iterator_tag : std::random_access_iterator_tag {}; #endif From 2b9291dda702734e32d520b8a8835102652b85d5 Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Fri, 8 Dec 2023 15:30:08 -0700 Subject: [PATCH 38/47] Update #include style --- .../include/bsoncxx/v_noabi/bsoncxx/stdx/algorithm.hpp | 9 ++++----- .../include/bsoncxx/v_noabi/bsoncxx/stdx/iterator.hpp | 4 ++-- .../include/bsoncxx/v_noabi/bsoncxx/stdx/operators.hpp | 2 +- .../bsoncxx/v_noabi/bsoncxx/stdx/string_view.hpp | 10 +++++----- 4 files changed, 12 insertions(+), 13 deletions(-) diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/algorithm.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/algorithm.hpp index a311ca768e..5cdd5527ac 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/algorithm.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/algorithm.hpp @@ -16,11 +16,10 @@ #include -#include "./algorithm.hpp" -#include "./iterator.hpp" -#include "./operators.hpp" -#include "./ranges.hpp" -#include "./type_traits.hpp" +#include +#include +#include +#include #include diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/iterator.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/iterator.hpp index 5e783472e7..3af9dac683 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/iterator.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/iterator.hpp @@ -27,8 +27,8 @@ #endif #endif -#include "./operators.hpp" -#include "./type_traits.hpp" +#include +#include #include diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/operators.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/operators.hpp index 855d9b87dc..a67696ac3c 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/operators.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/operators.hpp @@ -18,7 +18,7 @@ #include #include -#include "./type_traits.hpp" +#include #include diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/string_view.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/string_view.hpp index 4729c0d463..6fb9c5e01d 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/string_view.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/string_view.hpp @@ -21,11 +21,11 @@ #include #include -#include "./algorithm.hpp" -#include "./iterator.hpp" -#include "./operators.hpp" -#include "./ranges.hpp" -#include "./type_traits.hpp" +#include +#include +#include +#include +#include #include From cf495de3918daa5f72951a1ffb9a84a4bb81452b Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Fri, 8 Dec 2023 15:41:42 -0700 Subject: [PATCH 39/47] Qualify bsoncxx::detail references --- .../v_noabi/bsoncxx/stdx/string_view.hpp | 112 ++++++++++-------- 1 file changed, 60 insertions(+), 52 deletions(-) diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/string_view.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/string_view.hpp index 6fb9c5e01d..e94c5e6e14 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/string_view.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/string_view.hpp @@ -35,26 +35,27 @@ namespace stdx { namespace detail { -using namespace bsoncxx::detail; - template auto detect_string_f(...) -> std::false_type; template auto detect_string_f(int, // - const S& s = soft_declval(), - S& mut = soft_declval()) - -> true_t, is_range>>; + const S& s = bsoncxx::detail::soft_declval(), + S& mut = bsoncxx::detail::soft_declval()) + -> bsoncxx::detail::true_t< + typename S::traits_type::char_type, + decltype(s.length()), + decltype(mut = s), + decltype(s.compare(s)), + decltype(s.substr(0, s.size())), + bsoncxx::detail::requires_t, + bsoncxx::detail::is_range>>; // Heuristic detection of std::string-like types. Not perfect, but should reasonably // handle most cases. template -struct is_string_like : decltype(detect_string_f>(0)) {}; +struct is_string_like : decltype(detect_string_f>(0)) {}; } // namespace detail @@ -62,7 +63,7 @@ struct is_string_like : decltype(detect_string_f>(0)) {}; * @brief Implementation of std::string_view-like class template */ template > -class basic_string_view : detail::equality_operators, detail::ordering_operators { +class basic_string_view : bsoncxx::detail::equality_operators, bsoncxx::detail::ordering_operators { public: // Pointer to (non-const) character type using pointer = Char*; @@ -91,17 +92,17 @@ class basic_string_view : detail::equality_operators, detail::ordering_operators * evaluates to the type `int`. Otherwise, is a substitution failure. */ template - using _enable_range_constructor = - detail::requires_t, - // Don't eat our own copy/move constructor: - detail::negation>, - // Don't handle character arrays (we use a different constructor for - // that) - detail::negation>, - // The range's value must be the same as our character type - std::is_same, value_type>>; + using _enable_range_constructor = bsoncxx::detail::requires_t< + int, + // Must be a contiguous range + bsoncxx::detail::is_contiguous_range, + // Don't eat our own copy/move constructor: + bsoncxx::detail::negation>, + // Don't handle character arrays (we use a different constructor for + // that) + bsoncxx::detail::negation>, + // The range's value must be the same as our character type + std::is_same, value_type>>; public: using traits_type = Traits; @@ -143,16 +144,20 @@ class basic_string_view : detail::equality_operators, detail::ordering_operators template < typename Iterator, typename Sentinel, - detail::requires_t> = 0, + bsoncxx::detail::requires_t> = 0, // Requires: The iterator value_type be the same as our value_type - detail::requires_t, value_type>> = 0, + bsoncxx::detail:: + requires_t, value_type>> = 0, // Requires: We can get a pointer from the iterator via to_address: - detail::requires_t> = 0, + bsoncxx::detail::requires_t> = 0, // Requires: "Sentinel" is *not* convertible to std::size_t // (prevents ambiguity with the pointer+size constructor) - detail::requires_t>> = 0> + bsoncxx::detail::requires_t< + int, + bsoncxx::detail::negation>> = 0> constexpr basic_string_view(Iterator iter, Sentinel stop) noexcept - : _begin(detail::to_address(iter)), _size(static_cast(stop - iter)) {} + : _begin(bsoncxx::detail::to_address(iter)), _size(static_cast(stop - iter)) {} /** * @brief From-range constructor for non-string-like types. This is an explicit constructor. @@ -160,12 +165,13 @@ class basic_string_view : detail::equality_operators, detail::ordering_operators * Requires that `Range` is a non-array contiguous range with the same value * type as the string view. */ - template = 0, - detail::requires_t>> - RequiresNotString = 0> + template < + typename Range, + _enable_range_constructor = 0, + bsoncxx::detail::requires_t>> + RequiresNotString = 0> constexpr explicit basic_string_view(Range&& rng) - : _begin(detail::data(rng)), _size(detail::size(rng)) {} + : _begin(bsoncxx::detail::data(rng)), _size(bsoncxx::detail::size(rng)) {} /** * @brief From-range constructor, but is an implicit conversion accepting string-like ranges. @@ -173,11 +179,12 @@ class basic_string_view : detail::equality_operators, detail::ordering_operators * Requires that `Range` is a non-array contiguous range with the same value type * as the string view, and is a std::string-like value. */ - template = 0, - detail::requires_t> RequiresStringLike = 0> + template < + typename Range, + _enable_range_constructor = 0, + bsoncxx::detail::requires_t> RequiresStringLike = 0> constexpr basic_string_view(Range&& rng) noexcept - : _begin(detail::data(rng)), _size(detail::size(rng)) {} + : _begin(bsoncxx::detail::data(rng)), _size(bsoncxx::detail::size(rng)) {} // Construction from a null pointer is deleted basic_string_view(std::nullptr_t) = delete; @@ -379,8 +386,8 @@ class basic_string_view : detail::equality_operators, detail::ordering_operators */ bsoncxx_cxx14_constexpr size_type find(self_type infix, size_type pos = 0) const noexcept { self_type sub = this->substr((std::min)(pos, size())); - detail::subrange found = detail::search(sub, infix); - if (detail::distance(found) != static_cast(infix.size())) { + bsoncxx::detail::subrange found = bsoncxx::detail::search(sub, infix); + if (bsoncxx::detail::distance(found) != static_cast(infix.size())) { return npos; } return _iter_to_pos(found.begin()); @@ -391,9 +398,9 @@ class basic_string_view : detail::equality_operators, detail::ordering_operators */ bsoncxx_cxx14_constexpr size_type rfind(self_type infix, size_type pos = npos) const noexcept { self_type sub = this->substr(0, pos); - detail::reversed_t found = - detail::search(detail::make_reversed_view(sub), detail::make_reversed_view(infix)); - if (detail::distance(found) != static_cast(infix.size())) { + bsoncxx::detail::reversed_t found = bsoncxx::detail::search( + bsoncxx::detail::make_reversed_view(sub), bsoncxx::detail::make_reversed_view(infix)); + if (bsoncxx::detail::distance(found) != static_cast(infix.size())) { return npos; } return _iter_to_pos(found.end()); @@ -404,7 +411,7 @@ class basic_string_view : detail::equality_operators, detail::ordering_operators * set */ constexpr size_type find_first_of(self_type set, size_type pos = 0) const noexcept { - return _find_if(pos, detail::equal_to_any_of(set)); + return _find_if(pos, bsoncxx::detail::equal_to_any_of(set)); } /** @@ -412,7 +419,7 @@ class basic_string_view : detail::equality_operators, detail::ordering_operators * set */ constexpr size_type find_last_of(self_type set, size_type pos = npos) const noexcept { - return _rfind_if(pos, detail::equal_to_any_of(set)); + return _rfind_if(pos, bsoncxx::detail::equal_to_any_of(set)); } /** @@ -420,7 +427,7 @@ class basic_string_view : detail::equality_operators, detail::ordering_operators * is NOT a member of the given set of characters */ constexpr size_type find_first_not_of(self_type set, size_type pos = 0) const noexcept { - return _find_if(pos, detail::not_fn(detail::equal_to_any_of(set))); + return _find_if(pos, bsoncxx::detail::not_fn(bsoncxx::detail::equal_to_any_of(set))); } /** @@ -428,7 +435,7 @@ class basic_string_view : detail::equality_operators, detail::ordering_operators * is NOT a member of the given set of characters */ constexpr size_type find_last_not_of(self_type set, size_type pos = npos) const noexcept { - return _rfind_if(pos, detail::not_fn(detail::equal_to_any_of(set))); + return _rfind_if(pos, bsoncxx::detail::not_fn(bsoncxx::detail::equal_to_any_of(set))); } #pragma push_macro("DECL_FINDERS") @@ -497,14 +504,15 @@ class basic_string_view : detail::equality_operators, detail::ordering_operators } // Implementation of equality comparison - constexpr friend bool tag_invoke(detail::equal_to, self_type left, self_type right) noexcept { + constexpr friend bool tag_invoke(bsoncxx::detail::equal_to, + self_type left, + self_type right) noexcept { return left.size() == right.size() && left.compare(right) == 0; } // Implementation of a three-way-comparison - constexpr friend detail::strong_ordering tag_invoke(detail::compare_three_way cmp, - self_type left, - self_type right) noexcept { + constexpr friend bsoncxx::detail::strong_ordering tag_invoke( + bsoncxx::detail::compare_three_way cmp, self_type left, self_type right) noexcept { return cmp(left.compare(right), 0); } @@ -517,7 +525,7 @@ class basic_string_view : detail::equality_operators, detail::ordering_operators // Find the first index I where the given predicate returns true for substr(I) template bsoncxx_cxx14_constexpr size_type _find_if(size_type pos, F pred) const noexcept { - const iterator found = detail::find_if(substr(pos), pred); + const iterator found = bsoncxx::detail::find_if(substr(pos), pred); if (found == end()) { return npos; } @@ -528,7 +536,7 @@ class basic_string_view : detail::equality_operators, detail::ordering_operators template bsoncxx_cxx14_constexpr size_type _rfind_if(size_type pos, F pred) const noexcept { const const_reverse_iterator found = - detail::find_if(detail::make_reversed_view(substr(0, pos)), pred); + bsoncxx::detail::find_if(bsoncxx::detail::make_reversed_view(substr(0, pos)), pred); if (found == rend()) { return npos; } From c7168a529d1fbfcbcd3d1a78360fdfd8ff077f49 Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Mon, 11 Dec 2023 12:25:51 -0700 Subject: [PATCH 40/47] Spelling/wording tweaks --- .../include/bsoncxx/v_noabi/bsoncxx/stdx/ranges.hpp | 2 +- .../include/bsoncxx/v_noabi/bsoncxx/stdx/string_view.hpp | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/ranges.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/ranges.hpp index f740217d3e..80aba9146c 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/ranges.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/ranges.hpp @@ -30,7 +30,7 @@ namespace bsoncxx { inline namespace v_noabi { namespace detailx { // clang-format off -// Workarounds for MSVC 19.10 doing bad: An invocable object with name `n` should not be visible +// Workarounds for MSVC 14.0 doing bad: An invocable object with name `n` should not be visible // within its own call operator. We need to "hide" the ADL name lookup out here in a different // namespace to prevent them from finding the invocable objects. template diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/string_view.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/string_view.hpp index e94c5e6e14..d707abc7d2 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/string_view.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/string_view.hpp @@ -236,7 +236,7 @@ class basic_string_view : bsoncxx::detail::equality_operators, bsoncxx::detail:: */ bsoncxx_cxx14_constexpr const_reference at(size_type pos) const { if (pos >= size()) { - throw std::out_of_range{"string_view::at()"}; + throw std::out_of_range{"bsoncxx::stdx::basic_string_view::at()"}; } return _begin[pos]; } @@ -310,7 +310,7 @@ class basic_string_view : bsoncxx::detail::equality_operators, bsoncxx::detail:: */ bsoncxx_cxx14_constexpr size_type copy(pointer dest, size_type count, size_type pos = 0) const { if (pos > size()) { - throw std::out_of_range{"basic_string_view::copy()"}; + throw std::out_of_range{"bsoncxx::stdx::basic_string_view::substr()"}; } count = (std::min)(count, size() - pos); Traits::copy(dest, data() + pos, count); @@ -328,7 +328,7 @@ class basic_string_view : bsoncxx::detail::equality_operators, bsoncxx::detail:: */ bsoncxx_cxx14_constexpr self_type substr(size_type pos, size_type count = npos) const { if (pos > size()) { - throw std::out_of_range{"basic_string_view::substr()"}; + throw std::out_of_range{"bsoncxx::stdx::basic_string_view::substr()"}; } return self_type(_begin + pos, (std::min)(count, size() - pos)); } @@ -394,7 +394,7 @@ class basic_string_view : bsoncxx::detail::equality_operators, bsoncxx::detail:: } /** - * @brief Find the zero-based index of the right-box occurrence of the given substring + * @brief Find the zero-based index of the right-most occurrence of the given substring */ bsoncxx_cxx14_constexpr size_type rfind(self_type infix, size_type pos = npos) const noexcept { self_type sub = this->substr(0, pos); From f59fbeaec061f61efac2709cb86ce18588971cc0 Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Mon, 11 Dec 2023 12:26:19 -0700 Subject: [PATCH 41/47] Remove C++20+ string-view APIs --- .../v_noabi/bsoncxx/stdx/string_view.hpp | 69 +------------------ src/bsoncxx/test/string_view.test.cpp | 17 ----- 2 files changed, 1 insertion(+), 85 deletions(-) diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/string_view.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/string_view.hpp index d707abc7d2..c0080bda47 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/string_view.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/string_view.hpp @@ -136,45 +136,7 @@ class basic_string_view : bsoncxx::detail::equality_operators, bsoncxx::detail:: : _begin(s), _size(traits_type::length(s)) {} /** - * Iterator pair range constructor - * - * Requires that `Iterator` be a contiguous iterator, that `Sentinel` be a sized sentinel for - * `Iterator`, and that the value-type of `Iterator` is the character type of the string. - */ - template < - typename Iterator, - typename Sentinel, - bsoncxx::detail::requires_t> = 0, - // Requires: The iterator value_type be the same as our value_type - bsoncxx::detail:: - requires_t, value_type>> = 0, - // Requires: We can get a pointer from the iterator via to_address: - bsoncxx::detail::requires_t> = 0, - // Requires: "Sentinel" is *not* convertible to std::size_t - // (prevents ambiguity with the pointer+size constructor) - bsoncxx::detail::requires_t< - int, - bsoncxx::detail::negation>> = 0> - constexpr basic_string_view(Iterator iter, Sentinel stop) noexcept - : _begin(bsoncxx::detail::to_address(iter)), _size(static_cast(stop - iter)) {} - - /** - * @brief From-range constructor for non-string-like types. This is an explicit constructor. - * - * Requires that `Range` is a non-array contiguous range with the same value - * type as the string view. - */ - template < - typename Range, - _enable_range_constructor = 0, - bsoncxx::detail::requires_t>> - RequiresNotString = 0> - constexpr explicit basic_string_view(Range&& rng) - : _begin(bsoncxx::detail::data(rng)), _size(bsoncxx::detail::size(rng)) {} - - /** - * @brief From-range constructor, but is an implicit conversion accepting string-like ranges. + * @brief From-range conversion accepting string-like ranges. * * Requires that `Range` is a non-array contiguous range with the same value type * as the string view, and is a std::string-like value. @@ -459,35 +421,6 @@ class basic_string_view : bsoncxx::detail::equality_operators, bsoncxx::detail:: DECL_FINDERS(find_last_not_of, npos); #pragma pop_macro("DECL_FINDERS") - /** - * @brief Test whether the string starts-with the given prefix string - */ - constexpr bool starts_with(self_type pfx) const noexcept { - return pfx == substr(0, pfx.size()); - } - - /** - * @brief Test whether the string ends-with the given suffix string - */ - constexpr bool ends_with(self_type sfx) const noexcept { - return size() >= sfx.size() && substr(size() - sfx.size()) == sfx; - } - - /** - * @brief Test whether the string contains any occurrence of the given substring - */ - constexpr bool contains(self_type infix) const noexcept { - return find(infix) != npos; - } - - constexpr bool contains(value_type chr) const noexcept { - return contains(string_view(&chr, 1)); - } - - constexpr bool contains(const_pointer cstr) const noexcept { - return contains(self_type(cstr)); - } - /** * @brief Explicit-conversion to a std::basic_string */ diff --git a/src/bsoncxx/test/string_view.test.cpp b/src/bsoncxx/test/string_view.test.cpp index 58739a481a..e116c6eede 100644 --- a/src/bsoncxx/test/string_view.test.cpp +++ b/src/bsoncxx/test/string_view.test.cpp @@ -13,9 +13,7 @@ namespace stdx = bsoncxx::stdx; using stdx::string_view; -static_assert(std::is_constructible>::value, "fail"); static_assert(!std::is_constructible>::value, "fail"); -static_assert(std::is_constructible>::value, "fail"); static_assert(!std::is_constructible::value, "fail"); static_assert(std::is_constructible::value, "fail"); static_assert(std::is_constructible::value, "fail"); @@ -62,21 +60,6 @@ TEST_CASE("string_view: Pointer construct") { CHECK_FALSE(s < s); } -TEST_CASE("string_view: Range construct") { - std::vector cs = {'a', 'b', 'c', 'd'}; - auto sv = string_view(cs); - CHECK(sv == "abcd"); - - cs = {'a', 'b', 0, 'd'}; - sv = string_view(cs); - CHECK(sv == string_view("ab\0d", 4)); - - // Copying is okay - string_view s2(sv); - CHECK(s2 == sv); - CHECK_FALSE(s2 != sv); -} - TEST_CASE("string_view: Reversal") { string_view string = "Hello!"; auto rit = string.rbegin(); From 348fa3ee45d1a0ac9701d84098a46063696d37ee Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Mon, 11 Dec 2023 13:48:14 -0700 Subject: [PATCH 42/47] More testing and fixes for fencepost errors in string searches --- .../v_noabi/bsoncxx/stdx/string_view.hpp | 54 +++++++------ src/bsoncxx/test/string_view.test.cpp | 81 ++++++++++--------- 2 files changed, 72 insertions(+), 63 deletions(-) diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/string_view.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/string_view.hpp index c0080bda47..1813c9c5dc 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/string_view.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/string_view.hpp @@ -344,7 +344,8 @@ class basic_string_view : bsoncxx::detail::equality_operators, bsoncxx::detail:: } /** - * @brief Find the zero-based index of the left-most occurrence of the given substring + * @brief Find the zero-based offset of the left-most occurrence of the given infix, + * starting with pos. If infix does not occur, returns npos. */ bsoncxx_cxx14_constexpr size_type find(self_type infix, size_type pos = 0) const noexcept { self_type sub = this->substr((std::min)(pos, size())); @@ -352,33 +353,37 @@ class basic_string_view : bsoncxx::detail::equality_operators, bsoncxx::detail:: if (bsoncxx::detail::distance(found) != static_cast(infix.size())) { return npos; } - return _iter_to_pos(found.begin()); + return static_cast(found.begin() - begin()); } /** - * @brief Find the zero-based index of the right-most occurrence of the given substring + * @brief Find the zero-based offset of the right-most occurrence of the given infix, + * starting with (and including) pos. If infix does not occur, returns npos. */ bsoncxx_cxx14_constexpr size_type rfind(self_type infix, size_type pos = npos) const noexcept { - self_type sub = this->substr(0, pos); - bsoncxx::detail::reversed_t found = bsoncxx::detail::search( - bsoncxx::detail::make_reversed_view(sub), bsoncxx::detail::make_reversed_view(infix)); + // Calc the endpos where searching should begin, which includes the infix size + const size_type endpos = pos != npos ? pos + infix.size() : pos; + self_type searched = this->substr(0, endpos); + bsoncxx::detail::reversed_t found = + bsoncxx::detail::search(bsoncxx::detail::make_reversed_view(searched), + bsoncxx::detail::make_reversed_view(infix)); if (bsoncxx::detail::distance(found) != static_cast(infix.size())) { return npos; } - return _iter_to_pos(found.end()); + return static_cast(rend() - found.end()); } /** * @brief Find the zero-based index of the left-most occurrence of any character of the given - * set + * set, starting at pos */ constexpr size_type find_first_of(self_type set, size_type pos = 0) const noexcept { return _find_if(pos, bsoncxx::detail::equal_to_any_of(set)); } /** - * @brief Find the zero-based index of the right-most occurrence of any character of the given - * set + * @brief Find the zero-based index of the right-most occurrence of any character of the + * given set, starting at (and including) pos */ constexpr size_type find_last_of(self_type set, size_type pos = npos) const noexcept { return _rfind_if(pos, bsoncxx::detail::equal_to_any_of(set)); @@ -394,7 +399,7 @@ class basic_string_view : bsoncxx::detail::equality_operators, bsoncxx::detail:: /** * @brief Find the zero-based index of the right-most occurrence of any character that - * is NOT a member of the given set of characters + * is NOT a member of the given set of characters, starting at (and including) pos */ constexpr size_type find_last_not_of(self_type set, size_type pos = npos) const noexcept { return _rfind_if(pos, bsoncxx::detail::not_fn(bsoncxx::detail::equal_to_any_of(set))); @@ -455,35 +460,32 @@ class basic_string_view : bsoncxx::detail::equality_operators, bsoncxx::detail:: return out; } - // Find the first index I where the given predicate returns true for substr(I) + // Find the first in-bounds index I in [pos, size()) where the given predicate + // returns true for substr(I). If no index exists, returns npos template bsoncxx_cxx14_constexpr size_type _find_if(size_type pos, F pred) const noexcept { const iterator found = bsoncxx::detail::find_if(substr(pos), pred); if (found == end()) { return npos; } - return _iter_to_pos(found); + return static_cast(found - begin()); } - // Find the last index I where the given predicate returns true for substr(0, I) + // Find the LAST index I in [0, pos] where the given predicate returns true for + // substr(0, I). If no such index exists, returns npos. template bsoncxx_cxx14_constexpr size_type _rfind_if(size_type pos, F pred) const noexcept { + // Adjust 'pos' for an inclusive range in substr() + const auto rpos = pos == npos ? npos : pos + 1; + // The substring that will be searched: + const auto prefix = substr(0, rpos); const const_reverse_iterator found = - bsoncxx::detail::find_if(bsoncxx::detail::make_reversed_view(substr(0, pos)), pred); + bsoncxx::detail::find_if(bsoncxx::detail::make_reversed_view(prefix), pred); if (found == rend()) { return npos; } - return _iter_to_pos(found); - } - - // Convert an iterator to a zero-based index - constexpr size_type _iter_to_pos(const_iterator it) const noexcept { - return static_cast(it - begin()); - } - - // Convert a reverse-iterator to a zero-based index - constexpr size_type _iter_to_pos(const_reverse_iterator it) const noexcept { - return static_cast(rend() - it); + // Adjust by 1 to account for reversed-ness + return static_cast(rend() - found) - 1u; } }; diff --git a/src/bsoncxx/test/string_view.test.cpp b/src/bsoncxx/test/string_view.test.cpp index e116c6eede..8ab3a61cbc 100644 --- a/src/bsoncxx/test/string_view.test.cpp +++ b/src/bsoncxx/test/string_view.test.cpp @@ -141,46 +141,53 @@ TEST_CASE("string_view: Overloading safety") { } TEST_CASE("string_view: find") { - string_view s1 = "abc123abc123"; - auto pos = s1.find("abc"); + string_view sv = "abc123abc123"; + std::string str{sv}; + auto pos = sv.find("abc"); CHECK(pos == 0); - pos = s1.find("bc1"); + pos = sv.find("bc1"); CHECK(pos == 1); - pos = s1.find("bc1", 1); + pos = sv.find("bc1", 1); CHECK(pos == 1); - pos = s1.find("bc1", 2); + pos = sv.find("bc1", 2); CHECK(pos == 7); - pos = s1.find("", 4); + pos = sv.find("", 4); CHECK(pos == 4); - CHECK(s1.find("") == 0); - CHECK(s1.find("nowhere") == s1.npos); - CHECK(s1.rfind("nowhere") == s1.npos); - CHECK(s1.find("123") == 3); - CHECK(s1.rfind("123") == 9); - CHECK(s1.rfind("abc", 8) == 0); - CHECK(s1.rfind("") == 12); - - CHECK(s1.find_first_of("54321") == 3); - CHECK(s1.find_first_of("nope") == s1.npos); - CHECK(s1.find_last_of("fedcba") == 9); - CHECK(s1.find_last_of("nope") == s1.npos); - - CHECK(s1.find_first_of("54321", 5) == 5); - CHECK(s1.find_first_of("nope", 5) == s1.npos); - CHECK(s1.find_last_of("fedcba", 5) == 3); - CHECK(s1.find_last_of("nope", 5) == s1.npos); - - CHECK(s1.find_first_not_of("abcdef") == 3); - CHECK(s1.find_first_not_of("123456") == 0); - CHECK(s1.find_last_not_of("abcdef") == 12); - CHECK(s1.find_last_not_of("123456") == 9); - CHECK(s1.find_first_not_of("abcdef123456") == s1.npos); - CHECK(s1.find_last_not_of("abcdef123456") == s1.npos); - - CHECK(s1.find_first_not_of("abcdef", 5) == 5); - CHECK(s1.find_first_not_of("123456", 5) == 6); - CHECK(s1.find_last_not_of("abcdef", 5) == 5); - CHECK(s1.find_last_not_of("123456", 5) == 3); - CHECK(s1.find_first_not_of("abcdef123456", 5) == s1.npos); - CHECK(s1.find_last_not_of("abcdef123456", 5) == s1.npos); + CHECK(sv.find("") == str.find("")); + CHECK(sv.find("nowhere") == sv.npos); + CHECK(sv.rfind("nowhere") == str.rfind("nowhere")); + CHECK(sv.find("123") == str.find("123")); + CHECK(sv.find("123", 88888) == str.find("123", 88888)); + CHECK(sv.rfind("123") == str.rfind("123")); + CHECK(sv.rfind("abc", 8) == str.rfind("abc", 8)); + CHECK(sv.rfind("abc", 888888) == str.rfind("abc", 888888)); + CHECK(sv.rfind("") == str.rfind("")); + + CHECK(string_view("").find("") == std::string("").find("")); + CHECK(string_view("").rfind("") == std::string("").rfind("")); + + CHECK(sv.find_first_of("54321") == str.find_first_of("54321")); + CHECK(sv.find_first_of("nope") == str.find_first_of("nope")); + CHECK(sv.find_last_of("fedcba") == str.find_last_of("fedcba")); + CHECK(sv.find_last_of("nope") == str.find_last_of("nope")); + + CHECK(sv.find_first_of("54321", 5) == str.find_first_of("54321", 5)); + CHECK(sv.find_first_of("nope", 5) == str.find_first_of("nope", 5)); + CHECK(sv.find_last_of("fedcba", 5) == str.find_last_of("fedcba", 5)); + CHECK(sv.find_last_of("fedcba", 2) == str.find_last_of("fedcba", 2)); + CHECK(sv.find_last_of("nope", 5) == str.find_last_of("nope", 5)); + + CHECK(sv.find_first_not_of("abcdef") == str.find_first_not_of("abcdef")); + CHECK(sv.find_first_not_of("123456") == str.find_first_not_of("123456")); + CHECK(sv.find_last_not_of("abcdef") == str.find_last_not_of("abcdef")); + CHECK(sv.find_last_not_of("123456") == str.find_last_not_of("123456")); + CHECK(sv.find_first_not_of("abcdef123456") == str.find_first_not_of("abcdef123456")); + CHECK(sv.find_last_not_of("abcdef123456") == str.find_last_not_of("abcdef123456")); + + CHECK(sv.find_first_not_of("abcdef", 5) == str.find_first_not_of("abcdef", 5)); + CHECK(sv.find_first_not_of("123456", 5) == str.find_first_not_of("123456", 5)); + CHECK(sv.find_last_not_of("abcdef", 5) == str.find_last_not_of("abcdef", 5)); + CHECK(sv.find_last_not_of("123456", 5) == str.find_last_not_of("123456", 5)); + CHECK(sv.find_first_not_of("abcdef123456", 5) == str.find_first_not_of("abcdef123456", 5)); + CHECK(sv.find_last_not_of("abcdef123456", 5) == str.find_last_not_of("abcdef123456", 5)); } From b5398c1f3dc497344a3a027a523aa7eb4d53669a Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Tue, 12 Dec 2023 12:50:15 -0700 Subject: [PATCH 43/47] Drop range constructs. Test+fix some more edge cases in string searching. --- Doxyfile | 4 +- src/bsoncxx/include/CMakeLists.txt | 3 - .../v_noabi/bsoncxx/stdx/algorithm.hpp | 439 ------------------ .../bsoncxx/v_noabi/bsoncxx/stdx/iterator.hpp | 247 ---------- .../v_noabi/bsoncxx/stdx/operators.hpp | 3 +- .../bsoncxx/v_noabi/bsoncxx/stdx/ranges.hpp | 281 ----------- .../v_noabi/bsoncxx/stdx/string_view.hpp | 97 ++-- src/bsoncxx/test/CMakeLists.txt | 6 - src/bsoncxx/test/algorithm.test.cpp | 50 -- src/bsoncxx/test/iterator.test.cpp | 79 ---- src/bsoncxx/test/ranges.test.cpp | 77 --- src/bsoncxx/test/string_view.test.cpp | 8 +- 12 files changed, 56 insertions(+), 1238 deletions(-) delete mode 100644 src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/algorithm.hpp delete mode 100644 src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/iterator.hpp delete mode 100644 src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/ranges.hpp delete mode 100644 src/bsoncxx/test/algorithm.test.cpp delete mode 100644 src/bsoncxx/test/iterator.test.cpp delete mode 100644 src/bsoncxx/test/ranges.test.cpp diff --git a/Doxyfile b/Doxyfile index ba8a31f09a..f9e16f709b 100644 --- a/Doxyfile +++ b/Doxyfile @@ -900,9 +900,7 @@ RECURSIVE = YES # Note that relative paths are relative to the directory from which doxygen is # run. -EXCLUDE = src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/iterator.hpp \ - src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/operators.hpp \ - src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/ranges.hpp \ +EXCLUDE = src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/operators.hpp \ src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/type_traits.hpp # The EXCLUDE_SYMLINKS tag can be used to select whether or not files or diff --git a/src/bsoncxx/include/CMakeLists.txt b/src/bsoncxx/include/CMakeLists.txt index 3e52aa223b..ef740ef40d 100644 --- a/src/bsoncxx/include/CMakeLists.txt +++ b/src/bsoncxx/include/CMakeLists.txt @@ -83,12 +83,9 @@ set_dist_list(src_bsoncxx_include_DIST bsoncxx/v_noabi/bsoncxx/json.hpp bsoncxx/v_noabi/bsoncxx/oid-fwd.hpp bsoncxx/v_noabi/bsoncxx/oid.hpp - bsoncxx/v_noabi/bsoncxx/stdx/algorithm.hpp - bsoncxx/v_noabi/bsoncxx/stdx/iterator.hpp bsoncxx/v_noabi/bsoncxx/stdx/make_unique.hpp bsoncxx/v_noabi/bsoncxx/stdx/operators.hpp bsoncxx/v_noabi/bsoncxx/stdx/optional.hpp - bsoncxx/v_noabi/bsoncxx/stdx/ranges.hpp bsoncxx/v_noabi/bsoncxx/stdx/string_view.hpp bsoncxx/v_noabi/bsoncxx/stdx/type_traits.hpp bsoncxx/v_noabi/bsoncxx/string/to_string.hpp diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/algorithm.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/algorithm.hpp deleted file mode 100644 index 5cdd5527ac..0000000000 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/algorithm.hpp +++ /dev/null @@ -1,439 +0,0 @@ -// Copyright 2023 MongoDB Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#pragma once - -#include - -#include -#include -#include -#include - -#include - -namespace bsoncxx { -inline namespace v_noabi { -namespace detail { - -/** - * @internal - * @brief Checked iterator-advance - * - * Provides two signatures: - * - * - advance(iterator, sentinel) - * - advance(iterator, offset, sentinel) - * - * The default `offset` is 1. The return value is the offset by which the - * iterator was actually shifted, which may be different from `offset` if - * `sentinel` was encountered before advancing the entire distance. - */ -static constexpr struct _advance_fn { - template - bsoncxx_cxx14_constexpr static auto impl(I& iter, - iter_difference_t off, - S bound) // - noexcept(noexcept(++iter) && noexcept(iter == bound)) - -> requires_t, is_sentinel_for> { - iter_difference_t shift = 0; - while (off > 0 && iter != bound) { - ++iter; - --off; - ++shift; - } - handle_negative(iter, off, bound, shift); - return shift; - } - - template - constexpr auto operator()(I& iter, S bound) const BSONCXX_RETURNS(impl(iter, 1, bound)); - - template - constexpr auto operator()(I& iter, iter_difference_t off, S bound) const - BSONCXX_RETURNS(impl(iter, off, bound)); - - // Handle bidirectional iterators and negative offsets - template - bsoncxx_cxx14_constexpr static requires_t> // - handle_negative(I& iter, - iter_difference_t off, - S bound, - iter_difference_t& shift) noexcept(noexcept(--iter)) { - while (off < 0 && iter != bound) { - --iter; - ++off; - --shift; - } - } - - // Fallback: Iterator is not bidir. This is less-preferred since it uses an ellipsis - template - bsoncxx_cxx14_constexpr static void handle_negative(I, iter_difference_t, S, ...) noexcept {} -} advance; - -/** - * @internal - * @brief Obtain a new iterator shifted from the given iterator by some amount, - * with bounds-checking - * - * Two signatures: - * - * - next(iterator, bound) - * - next(iterator, offset, bound) - * - * Equivalent to copying `iterator` as `t`, calling `advance(t[, offset], bound)`, - * and returning `t`. - */ -static constexpr struct _next_fn { - template - bsoncxx_cxx14_constexpr auto operator()(I it, S bound) const - -> requires_t> { - advance(it, bound); - return it; - } - - template - bsoncxx_cxx14_constexpr auto operator()(I it, iter_difference_t offset, S bound) const - -> requires_t> { - advance(it, offset, bound); - return it; - } -} next; - -/** - * @internal - * @brief Encloses a range represented by an iterator+sentinel pair - * - * Provides begin(), end(), and empty(). If the iterator+sentinel pair are - * "sized", provides a size() member as well. - */ -template -struct subrange; - -template -struct subrange_base { - I _iter; - S _stop; - - constexpr subrange_base(I i, S s) noexcept : _iter(i), _stop(s) {} - - constexpr I begin() const noexcept { - return _iter; - } - constexpr S end() const noexcept { - return _stop; - } - - constexpr bool empty() const noexcept { - return begin() == end(); - } -}; - -template -struct subrange_base : subrange_base { - using subrange_base::subrange_base; - - constexpr detail::make_unsigned_t> size() const noexcept { - return static_cast>>(this->_stop - - this->_iter); - } -}; - -template -struct subrange : subrange_base::value> { - using subrange::subrange_base::subrange_base; -}; - -/** - * @internal - * @brief Construct a new subrange from the given iterator+sentinel pair - */ -template -constexpr requires_t, is_sentinel_for> make_subrange(I i, S s) noexcept { - return subrange{i, s}; -} - -template -using reversed_t = subrange< - std::reverse_iterator, is_bidirectional_iterator>>>>; - -template -constexpr reversed_t // -make_reversed_view(R&& rng) noexcept { - return {detail::make_reverse_iterator(end(rng)), detail::make_reverse_iterator(begin(rng))}; -} - -/** - * @internal - * @brief Obtain the size of a range as a signed integer. - * - * Unlike size() or ssize(), this invocable is defined for all ranges, even if the - * underlying operation is not O(1) or the range is an input_range. Uses ssize() - * if available, otherwise counts iterator increments. - */ -static constexpr struct _distance_fn { - template - constexpr static auto impl(rank<2>, R&& rng) BSONCXX_RETURNS(ssize(rng)); - - template - bsoncxx_cxx14_constexpr static auto impl(rank<1>, R&& rng) - -> requires_t, is_range> { - range_difference_t count = 0; - auto i = begin(rng); - auto s = end(rng); - for (; i != s; ++i) { - ++count; - } - return count; - } - - template - constexpr auto operator()(I i, S s) const BSONCXX_RETURNS(impl(rank<2>{}, make_subrange(i, s))); - template - constexpr auto operator()(R&& rng) const BSONCXX_RETURNS(impl(rank<2>{}, rng)); -} distance; - -/** - * @brief An invocable object that simply returns its argument unchanged. - */ -struct identity { - template - constexpr T&& operator()(T&& arg) const noexcept { - return static_cast(arg); - } -}; - -/** - * @internal - * @brief Test whether the given ranges have equal contents - * - * Call as: - * - * - equal(left_range, right_range[, compare_fn[, left-projection[, right-projection]]]) - */ -static constexpr struct _equal_fn { - template - bsoncxx_cxx14_constexpr auto operator()(L&& left, - R&& right, - Compare&& eq = {}, - ProjectLeft&& projleft = {}, - ProjectRight&& projright = {}) const // - -> requires_t>, - invoke_result_t>>> { - if (definitely_different_sizes(rank<1>{}, left, right)) { - // The ranges are known to have different sizes, so cannot be equal - return false; - } - auto li = begin(left); - const auto ls = end(left); - auto ri = begin(right); - const auto rs = end(right); - for (; li != ls && ri != rs; ++li, ++ri) { - if (!eq(projleft(*li), projright(*ri))) { - return false; - } - } - // All elements compared equal, so check that we compared all elements of both ranges: - return li == ls && ri == rs; - } - - template - constexpr static auto definitely_different_sizes(rank<1>, L& l, R& r) - BSONCXX_RETURNS(ssize(l) != ssize(r)); - template - constexpr static bool definitely_different_sizes(rank<0>, L&, R&) noexcept { - return false; - } -} equal; - -/** - * @internal - * @brief A default searcher implementation for use with search() - * - * Scans the searched range for the needle by simple element-by-element comparison. - */ -template -struct default_searcher; - -/** - * @internal - * @brief Implements subrange-searching - * - * Callable with: - * - * - search(outer_range, inner_range[, compare_fn]) - * - search(outer_range, searcher) - * - * When given two ranges, uses default_searcher with `compare_fn` to search - * for the first occurrence of `inner_range` within `outer_range`. - * - * Returns a subrange referring to the range that was found by searching, or - * an empty subrange pointing to the end of the scanned range if no occurrence - * was found. - */ -static constexpr struct _search_fn { - template > - bsoncxx_cxx14_constexpr static auto impl(Range&& rng, - Searcher&& srch) // - noexcept(noexcept(srch(begin(rng), end(rng)))) - -> requires_t, is_invocable>> { - const std::pair found = srch(begin(rng), end(rng)); - return {found.first, found.second}; - } - - template - constexpr auto operator()(Hay&& hay, Needle&& ndl, Compare&& cmp = {}) const - BSONCXX_RETURNS((impl)(hay, - default_searcher, sentinel_t, Compare>{ - begin(ndl), end(ndl), static_cast(cmp)})); - - template - constexpr auto operator()(Hay&& hay, Searcher&& srch) const BSONCXX_RETURNS(impl(hay, srch)); -} search; - -template -struct default_searcher { - NeedleIter n_first; - NeedleStop n_last; - Compare _compare = Compare(); - iter_difference_t n_size = distance(n_first, n_last); - - default_searcher(NeedleIter first, NeedleStop last, Compare cmp = Compare()) - : n_first(first), n_last(last), _compare(cmp) {} - - template - bsoncxx_cxx14_constexpr std::pair operator()(Iter first, Stop last) const { - auto test_begin = first; - auto test_end = first; - auto ndl = make_subrange(n_first, n_last); - if (advance(test_end, n_size, last) != n_size) { - // We did not advance the full needle size, so the test range is smaller than the - // needle, and cannot contain the needle: - return std::make_pair(test_end, test_end); - } - while (1) { - // Create a subrange of the current part being tested: - auto test_range = make_subrange(test_begin, test_end); - if (equal(test_range, ndl, _compare)) { - // This subrange is equal, so return that subrange - return {test_range.begin(), test_range.end()}; - } - // Step forward: - if (test_end == last) { - return {test_end, test_end}; - } - ++test_begin; - ++test_end; - } - } -}; - -template -struct equal_to_value_t { - T value; - template - constexpr auto operator()(U&& u) const BSONCXX_RETURNS(u == value); -}; - -/** - * @internal - * @brief Create a predicate that tests whether a value is equal to a given value - */ -template -constexpr equal_to_value_t equal_to_value(T&& t) noexcept { - return {static_cast(t)}; -} - -/** - * @internal - * @brief Obtain the iterator referring to the first position in a range for - * which a given predicate returns true - */ -static constexpr struct _find_if_fn { - template - bsoncxx_cxx14_constexpr auto operator()(R&& rng, Predicate&& pred, Project&& proj = {}) const - -> requires_t> { - auto iter = begin(rng); - const auto stop = end(rng); - for (; iter != stop; ++iter) { - if (pred(proj(*iter))) { - break; - } - } - return iter; - } -} find_if; - -/** - * @internal - * @brief Find the given value in the given range, compared by the `==` operator - */ -static constexpr struct _find_fn { - template - constexpr auto operator()(R&& rng, const T& value, Project&& proj = {}) const - BSONCXX_RETURNS(find_if(rng, equal_to_value(value), proj)); -} find; - -template -struct equal_to_any_of_t { - T range; - - template - constexpr auto operator()(U&& value) const BSONCXX_RETURNS(find(range, value) != end(range)); -}; - -/** - * @internal - * @brief Create a predicate that tests whether a value exists within the - * given range of objects. - */ -template -constexpr auto equal_to_any_of(T&& rng) - -> requires_t, is_forward_iterator>> { - return {static_cast(rng)}; -} - -template -struct not_fn_t { - F func; - template - bsoncxx_cxx14_constexpr auto operator()(Args&&... args) - BSONCXX_RETURNS(!invoke(func, static_cast(args)...)); - template - constexpr auto operator()(Args&&... args) const - BSONCXX_RETURNS(!invoke(func, static_cast(args)...)); -}; - -/** - * @internal - * @brief Create a wrapper function that negates the result of invoking the underlying - * invocable - */ -template -constexpr not_fn_t not_fn(F&& fn) { - return {static_cast(fn)}; -} - -} // namespace detail -} // namespace v_noabi -} // namespace bsoncxx - -#include diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/iterator.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/iterator.hpp deleted file mode 100644 index 3af9dac683..0000000000 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/iterator.hpp +++ /dev/null @@ -1,247 +0,0 @@ -// Copyright 2023 MongoDB Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#pragma once - -#include -#include -#include -#include -#include -#include -// We want to detect stdlib C++20 support. See remarks on contiguous_iterator_tag. -#if defined(__has_include) -#if __has_include() -#include -#endif -#endif - -#include -#include - -#include - -namespace bsoncxx { -inline namespace v_noabi { -namespace detail { - -/** - * @brief Backport of std::pointer_traits with the addition of to_address() for pointers - */ -template -struct pointer_traits : std::pointer_traits {}; - -template -struct pointer_traits : std::pointer_traits { - using typename std::pointer_traits::pointer; - using typename std::pointer_traits::element_type; - - static constexpr pointer to_address(pointer p) noexcept { - return p; - } -}; - -struct _to_address_fn { - template - static constexpr auto impl(FancyPointer fp, rank<3>) - BSONCXX_RETURNS(pointer_traits::to_address(fp)); - - template - static constexpr auto impl(Iterator iter, rank<2>) BSONCXX_RETURNS(iter.operator->()); - - template - static constexpr auto impl(T* p, rank<1>) BSONCXX_RETURNS(p); - - template - constexpr auto operator()(Iterator iter) const BSONCXX_RETURNS((impl)(iter, rank<10>{})); -}; - -/** - * @brief Convert an iterator or pointer-like type to a raw pointer. - */ -constexpr static _to_address_fn to_address; - -/** - * @brief The type obtained by to_address() for the given object, if valid - */ -template -using to_address_t = decltype(to_address(std::declval())); - -/** - * @brief The result of applying unary operator* to the given object, if valid - */ -BSONCXX_PUSH_WARNINGS(); -BSONCXX_DISABLE_WARNING(Clang("-Wvoid-ptr-dereference")); -template -using dereference_t = decltype(*std::declval()); -BSONCXX_POP_WARNINGS(); - -/** - * @brief Detect a type that can be dereferenced (like a pointer) and the result - * type is non-void - */ -template -struct is_dereferencable - : conjunction>, - // Clang supports dereferencing void*, and we can't detect - // that easily. Refuse if I is (cv-)void* - negation>>, - negation>>>> {}; - -/** - * @brief Obtain the value type of the given iterator. - * - * This is only a very rough approximation for our use cases. A more thorough - * C++20 impl requires additional traits - */ -template -using iter_value_t = - requires_t::value_type, is_dereferencable>; - -/** - * @brief Obtain the reference type of the given iterator (unless that type is `void`) - */ -template -using iter_reference_t = requires_t()), is_dereferencable>; - -/** - * @brief Obtain the difference type for the given iterator - */ -template -using iter_difference_t = typename std::iterator_traits::difference_type; - -template -struct is_weakly_incrementable : std::false_type {}; - -template -struct is_weakly_incrementable< // - Iter, - requires_t, - std::is_assignable, - is_detected, - true_t()), // - decltype(std::declval()++)>, - std::is_same()), Iter&>>> : std::true_type {}; - -/** - * @brief Detect a type that may be used as an iterator - */ -template -struct is_iterator : conjunction, - is_detected, - is_detected> {}; - -// We want contiguous_iterator_tag. We can't get the full functionality without -// stdlib support, but we can get reasonable approximation for our purposes -#if defined(__cpp_lib_ranges) -// If the C++20 is available, then our iterator_concept_t will pull the I::iterator_concept -// tag from an iterator, which could be std::contiguous_iterator_tag. For compatibility -// with the standard library in that case, use the same iterator tag class exactly: -using std::contiguous_iterator_tag; -#else -// We are compiling without C++20 stdlib support, so we can't use std::contiguous_iterator_tag. -// In this case, define our own tag type that we can use to detect known pre-c++20 contiguous -// iterators. -struct contiguous_iterator_tag : std::random_access_iterator_tag {}; -#endif - -// Base case, use the iterator to get the actual traits from it. -template -struct ITER_TRAITS_impl { - using type = I; -}; - -// If std::iterator_traits is not "the default" (which contains no difference_type), -// then use std::iterator_traits. -template -struct ITER_TRAITS_impl::difference_type>> { - using type = std::iterator_traits; -}; - -template -using ITER_TRAITS = typename ITER_TRAITS_impl::type; - -// Get the iterator concept tag from the given iterator-like type -struct calc_iterator_concept { - template - static auto impl(I*, rank<3>) -> contiguous_iterator_tag; - template - static auto impl(I, rank<2>) -> typename ITER_TRAITS::iterator_concept; - template - static auto impl(I, rank<1>) -> typename ITER_TRAITS::iterator_category; - template - auto operator()(I) -> decltype(impl(I{}, rank<10>{})); -}; - -/** - * @brief Obtain the iterator concept/category tag type, if present. - * - * Without C++20 stdlib support, does not detect contiguous_iterator_tag except - * for on raw pointers. - */ -template -using iterator_concept_t = decltype(calc_iterator_concept{}(I{})); - -template -struct is_iterator_kind - : conjunction, std::is_base_of>> {}; - -template -struct is_input_iterator : is_iterator_kind {}; - -template -struct is_forward_iterator : is_iterator_kind {}; - -template -struct is_bidirectional_iterator : is_iterator_kind {}; - -template -struct is_random_access_iterator : is_iterator_kind {}; - -template -struct is_contiguous_iterator : is_iterator_kind {}; - -/** - * @brief Detect if the type `Sentinel` is a range sentinel for iterator `Iter` - */ -template -struct is_sentinel_for : conjunction, is_iterator> {}; - -template -using difference_t = decltype(std::declval() - std::declval()); - -/** - * @brief Detect if the type `Sentinel` is a sentinel for `Iter` and subtraction - * is defined between them. - */ -template -struct is_sized_sentinel_for - : conjunction< - is_sentinel_for, - std::is_convertible, iter_difference_t>, - std::is_convertible, iter_difference_t>> { -}; - -template -constexpr auto make_reverse_iterator(I it) noexcept - -> requires_t, is_iterator> { - return std::reverse_iterator(it); -} - -} // namespace detail -} // namespace v_noabi -} // namespace bsoncxx - -#include diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/operators.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/operators.hpp index a67696ac3c..13a0537ece 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/operators.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/operators.hpp @@ -44,12 +44,11 @@ auto is_equality_comparable_f(int, * * Requires L == R, L != R, R == L, and R != L */ -template +template struct is_equality_comparable : decltype(is_equality_comparable_f(0)) {}; /** * @brief Callable object and tag type for equality comparison - * */ struct equal_to { template diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/ranges.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/ranges.hpp deleted file mode 100644 index 80aba9146c..0000000000 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/ranges.hpp +++ /dev/null @@ -1,281 +0,0 @@ -// Copyright 2023 MongoDB Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -#pragma once - -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include - -namespace bsoncxx { -inline namespace v_noabi { -namespace detailx { -// clang-format off -// Workarounds for MSVC 14.0 doing bad: An invocable object with name `n` should not be visible -// within its own call operator. We need to "hide" the ADL name lookup out here in a different -// namespace to prevent them from finding the invocable objects. -template -constexpr auto adl_size(T&& t) BSONCXX_RETURNS(size((T&&)t)); -template -constexpr auto adl_begin(T&& t) BSONCXX_RETURNS(begin((T&&)t)); -template -constexpr auto adl_end(T&& t) BSONCXX_RETURNS(end((T&&)t)); -} // namespace detailx -// clang-format on - -namespace detail { - -/** - * XXX: These _decay_xyz functions are required for MSVC 14.0 (VS2015) compat. - * - * The requirements on each of the below invocable objects is that the decay-copied - * return type meet certain requirements. It would be easier to include these - * requirements inline directly via enable_if/requires_t, but it is difficult to - * position them in a way that doesn't confuse MSVC 14.0. The most reliable - * configuration is to use a SFINAE-disappearing return type, so these functions - * serve that purpose while simultaneously performing the required decay-copy. - * - * It's possible that these are actually easier on the eyes than the inline - * requirements… - */ -template -constexpr requires_t> _decay_iterator(I i) noexcept { - return i; -} - -template -constexpr requires_t> _decay_sentinel(S s) noexcept { - return s; -} - -template -constexpr requires_t> _decay_integral(Sz s) noexcept { - return s; -} - -template -constexpr requires_t> _decay_copy_pointer(P p) noexcept { - return p; -} - -/** - * @brief Access the beginning iterator of a range-like object. - * - * Requires that the result is a valid iterator type - * - * Based on std::ranges::begin() - */ -static constexpr struct _begin_fn { - // 1: Object is an array - template - static constexpr auto impl(El (&arr)[N], rank<5>) BSONCXX_RETURNS(arr + 0); - - // 2: Object has member .begin() returning an iterator - template - static constexpr auto impl(R& rng, rank<4>) BSONCXX_RETURNS(_decay_iterator(rng.begin())); - - // 3: Object has an ADL-visible begin(x) returning an iterator - template - static constexpr auto impl(R& rng, rank<3>) - BSONCXX_RETURNS(_decay_iterator(detailx::adl_begin(rng))); - - template - constexpr auto operator()(R&& rng) const BSONCXX_RETURNS((impl)(rng, rank<10>{})); -} begin; - -/** - * @brief Yields the iterator result from calling begin(R&), if that expression - * is valid - */ -template -using iterator_t = decltype(begin(std::declval())); - -/** - * @brief Access the sentinel value for a range-like object. - * - * Requires that a valid begin() is also available, and that the end() returns - * a type which is_sentinel_for the type iterator_t - * - * Based on std::ranges::end(). - */ -static constexpr struct _end_fn { - // 1: Range is an array - template - static constexpr auto impl(El (&arr)[N], rank<5>) BSONCXX_RETURNS(arr + N); - - // 2: Range has member .end() returning a valid sentinel - template - static constexpr auto impl(R& rng, rank<4>) BSONCXX_RETURNS(_decay_sentinel(rng.end())); - - // 3: Range has ADL-found end(x) returning a valid sentinel - template - static constexpr auto impl(R& r, rank<3>) - BSONCXX_RETURNS(_decay_sentinel(detailx::adl_end(r))); - - template - constexpr auto operator()(R&& rng) const BSONCXX_RETURNS((impl>)(rng, rank<5>{})); -} end; - -/** - * @brief Yield the type resulting from end(R&), if that expression is valid - */ -template -using sentinel_t = decltype(end(std::declval())); - -/** - * @brief Obtain the size of the given range `rng`. - * - * Returns the first valid of: - * - The bounds of the array, if `rng` is an array - * - The result of rng.size() on R, if that returns an integral type - * - The result of size(rng), if such a name is visible via ADL and returns - * an integral type. - * - The value of (end(rng) - begin(rng)) as an unsigned integer if `rng` is - * forward-iterable and the sentinel is a sized sentinel type. - */ -static constexpr struct _size_fn { - // 1: Array of known bound - template - static constexpr auto impl(Element (&)[N], rank<5>) BSONCXX_RETURNS(N); - - // 2: Range with member .size() - template - static constexpr auto impl(R& rng, rank<4>) BSONCXX_RETURNS(_decay_integral(rng.size())); - - // 3: Range with ADL-found size(x) - template - static constexpr auto impl(R& rng, rank<3>) - BSONCXX_RETURNS(_decay_integral(detailx::adl_size(rng))); - - // 4: Range is a forward-range and has a sized sentinel type - template , - typename Sentinel = sentinel_t, - // Require a forward iterator: - requires_t> = 0, - // Require a sized sentinel: - requires_t> = 0, - // We cast to an unsigned type from the difference type: - typename Sz = make_unsigned_t>> - static constexpr auto impl(R& rng, rank<2>) - BSONCXX_RETURNS(static_cast(end(rng) - begin(rng))); - - template - constexpr auto operator()(R&& rng) const BSONCXX_RETURNS((impl)(rng, rank<10>{})); -} size; - -/** - * @brief Obtain the size type of the given range - */ -template -using range_size_t = decltype(size(std::declval())); - -/** - * @brief Obtain the size of the given range as a signed integer type - */ -static constexpr struct _ssize_fn { - template , - typename Signed = make_signed_t, - typename RetDiff = - conditional_t<(sizeof(Signed) > sizeof(std::ptrdiff_t)), Signed, std::ptrdiff_t>> - constexpr auto operator()(R&& rng) const BSONCXX_RETURNS(static_cast(size(rng))); -} ssize; - -/** - * @brief Obtain the difference type of the given range - */ -template -using range_difference_t = iter_difference_t>; - -/** - * @brief Obtain a pointer-to-data for the given `rng`. - * - * Returns the first valid of: - * - `rng.data()` if such expression yields a pointer type - * - `to_address(begin(rng))` if such expression is valid and iterator_t is - * a contiguous_iterator. - */ -static constexpr struct _data_fn { - template - static constexpr auto impl(R&& rng, rank<2>) BSONCXX_RETURNS(_decay_copy_pointer(rng.data())); - - template >> = 0> - static constexpr auto impl(R&& rng, rank<1>) BSONCXX_RETURNS(to_address(begin(rng))); - - template - constexpr auto operator()(R&& rng) const BSONCXX_RETURNS((impl)(rng, rank<10>{})); -} data; - -/** - * @brief Get the type returned by data(R&), if valid - */ -template -using range_data_t = decltype(data(std::declval())); - -/** - * @brief Get the value type of the range - * - * Equivalent: iter_value_t> - */ -template -using range_value_t = iter_value_t>; - -template -using range_reference_t = iter_reference_t>; - -template -using range_concept_t = iterator_concept_t>; - -/** - * @brief Trait detects if the given type is a range - */ -template -struct is_range : conjunction, is_detected> {}; - -/** - * @brief Detect if the given range is contiguous-ish. - * - * This is not quite like ranges::contiguous_range, as it does not require that - * the iterator be configuous. It only looks for a valid data(R) and size(R). - * Without stdlib support, we cannot fully detect contiguous_iterators, but we - * want to be able to support, basic_string, vector, array, etc, which - * have .data() and .size() - */ -template -struct is_contiguous_range - : conjunction, is_detected, is_detected> {}; - -static constexpr struct unreachable_sentinel_t : equality_operators { - template - constexpr friend requires_t> tag_invoke(equal_to, - unreachable_sentinel_t, - I) noexcept { - return false; - } -} unreachable_sentinel; - -} // namespace detail -} // namespace v_noabi -} // namespace bsoncxx - -#include diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/string_view.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/string_view.hpp index 1813c9c5dc..ef58e933a6 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/string_view.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/string_view.hpp @@ -14,6 +14,7 @@ #pragma once +#include #include #include #include @@ -21,10 +22,7 @@ #include #include -#include -#include #include -#include #include #include @@ -41,16 +39,20 @@ auto detect_string_f(...) -> std::false_type; template auto detect_string_f(int, // const S& s = bsoncxx::detail::soft_declval(), - S& mut = bsoncxx::detail::soft_declval()) + S& mut = bsoncxx::detail::soft_declval(), + void (*conv_cptr)(typename S::const_pointer) = + bsoncxx::detail::soft_declval(), + void (*conv_size)(typename S::size_type) = + bsoncxx::detail::soft_declval()) -> bsoncxx::detail::true_t< typename S::traits_type::char_type, decltype(s.length()), decltype(mut = s), decltype(s.compare(s)), decltype(s.substr(0, s.size())), - bsoncxx::detail::requires_t, - bsoncxx::detail::is_range>>; + decltype(conv_cptr(s.data())), + decltype(conv_size(s.size())), + bsoncxx::detail::requires_t>>; // Heuristic detection of std::string-like types. Not perfect, but should reasonably // handle most cases. @@ -88,21 +90,17 @@ class basic_string_view : bsoncxx::detail::equality_operators, bsoncxx::detail:: using self_type = basic_string_view; /** - * @brief If R is a type for which we want to permit from-range construction, + * @brief If R is a type for which we want to permit implicit conversion, * evaluates to the type `int`. Otherwise, is a substitution failure. */ - template - using _enable_range_constructor = bsoncxx::detail::requires_t< + template + using _enable_string_conversion = bsoncxx::detail::requires_t< int, - // Must be a contiguous range - bsoncxx::detail::is_contiguous_range, // Don't eat our own copy/move constructor: - bsoncxx::detail::negation>, - // Don't handle character arrays (we use a different constructor for - // that) - bsoncxx::detail::negation>, + bsoncxx::detail::negation>, // The range's value must be the same as our character type - std::is_same, value_type>>; + std::is_same::value_type, value_type>, + detail::is_string_like>; public: using traits_type = Traits; @@ -136,17 +134,14 @@ class basic_string_view : bsoncxx::detail::equality_operators, bsoncxx::detail:: : _begin(s), _size(traits_type::length(s)) {} /** - * @brief From-range conversion accepting string-like ranges. + * @brief Implicit conversion from string-like ranges. * - * Requires that `Range` is a non-array contiguous range with the same value type - * as the string view, and is a std::string-like value. + * Requires that `StringLike` is a non-array contiguous range with the same + * value type as this string view, and is a std::string-like value. */ - template < - typename Range, - _enable_range_constructor = 0, - bsoncxx::detail::requires_t> RequiresStringLike = 0> - constexpr basic_string_view(Range&& rng) noexcept - : _begin(bsoncxx::detail::data(rng)), _size(bsoncxx::detail::size(rng)) {} + template = 0> + constexpr basic_string_view(StringLike&& str) noexcept + : _begin(str.data()), _size(str.size()) {} // Construction from a null pointer is deleted basic_string_view(std::nullptr_t) = delete; @@ -299,9 +294,9 @@ class basic_string_view : bsoncxx::detail::equality_operators, bsoncxx::detail:: * @brief Compare two strings lexicographically * * @param other The "right hand" operand of the comparison - * @retval 0 If *this == other - * @retval n : n < 0 if *this is "less than" other. - * @retval n : n > 0 if *this is "greater than" other. + * @returns `0` If *this == other + * @returns `n : n < 0` if *this is "less than" other. + * @returns `n : n > 0` if *this is "greater than" other. */ constexpr int compare(self_type other) const noexcept { // Another level of indirection to support restricted C++11 constexpr @@ -348,12 +343,19 @@ class basic_string_view : bsoncxx::detail::equality_operators, bsoncxx::detail:: * starting with pos. If infix does not occur, returns npos. */ bsoncxx_cxx14_constexpr size_type find(self_type infix, size_type pos = 0) const noexcept { - self_type sub = this->substr((std::min)(pos, size())); - bsoncxx::detail::subrange found = bsoncxx::detail::search(sub, infix); - if (bsoncxx::detail::distance(found) != static_cast(infix.size())) { + if (pos > size()) { + return npos; + } + self_type sub = this->substr(pos); + if (infix.empty()) { + // The empty string is always "present" at the beginning of any string + return pos; + } + const_iterator found = std::search(sub.begin(), sub.end(), infix.begin(), infix.end()); + if (found == sub.end()) { return npos; } - return static_cast(found.begin() - begin()); + return static_cast(found - begin()); } /** @@ -362,15 +364,16 @@ class basic_string_view : bsoncxx::detail::equality_operators, bsoncxx::detail:: */ bsoncxx_cxx14_constexpr size_type rfind(self_type infix, size_type pos = npos) const noexcept { // Calc the endpos where searching should begin, which includes the infix size - const size_type endpos = pos != npos ? pos + infix.size() : pos; - self_type searched = this->substr(0, endpos); - bsoncxx::detail::reversed_t found = - bsoncxx::detail::search(bsoncxx::detail::make_reversed_view(searched), - bsoncxx::detail::make_reversed_view(infix)); - if (bsoncxx::detail::distance(found) != static_cast(infix.size())) { + const size_type substr_size = pos != npos ? pos + infix.size() : pos; + if (infix.empty()) { + return (std::min)(pos, size()); + } + self_type searched = this->substr(0, substr_size); + auto f = std::search(searched.rbegin(), searched.rend(), infix.rbegin(), infix.rend()); + if (f == searched.rend()) { return npos; } - return static_cast(rend() - found.end()); + return static_cast(rend() - f) - infix.size(); } /** @@ -378,7 +381,7 @@ class basic_string_view : bsoncxx::detail::equality_operators, bsoncxx::detail:: * set, starting at pos */ constexpr size_type find_first_of(self_type set, size_type pos = 0) const noexcept { - return _find_if(pos, bsoncxx::detail::equal_to_any_of(set)); + return _find_if(pos, [&](value_type chr) { return set.find(chr) != npos; }); } /** @@ -386,7 +389,7 @@ class basic_string_view : bsoncxx::detail::equality_operators, bsoncxx::detail:: * given set, starting at (and including) pos */ constexpr size_type find_last_of(self_type set, size_type pos = npos) const noexcept { - return _rfind_if(pos, bsoncxx::detail::equal_to_any_of(set)); + return _rfind_if(pos, [&](value_type chr) { return set.find(chr) != npos; }); } /** @@ -394,7 +397,7 @@ class basic_string_view : bsoncxx::detail::equality_operators, bsoncxx::detail:: * is NOT a member of the given set of characters */ constexpr size_type find_first_not_of(self_type set, size_type pos = 0) const noexcept { - return _find_if(pos, bsoncxx::detail::not_fn(bsoncxx::detail::equal_to_any_of(set))); + return _find_if(pos, [&](value_type chr) { return set.find(chr) == npos; }); } /** @@ -402,7 +405,7 @@ class basic_string_view : bsoncxx::detail::equality_operators, bsoncxx::detail:: * is NOT a member of the given set of characters, starting at (and including) pos */ constexpr size_type find_last_not_of(self_type set, size_type pos = npos) const noexcept { - return _rfind_if(pos, bsoncxx::detail::not_fn(bsoncxx::detail::equal_to_any_of(set))); + return _rfind_if(pos, [&](value_type chr) { return set.find(chr) == npos; }); } #pragma push_macro("DECL_FINDERS") @@ -464,7 +467,8 @@ class basic_string_view : bsoncxx::detail::equality_operators, bsoncxx::detail:: // returns true for substr(I). If no index exists, returns npos template bsoncxx_cxx14_constexpr size_type _find_if(size_type pos, F pred) const noexcept { - const iterator found = bsoncxx::detail::find_if(substr(pos), pred); + const auto sub = substr(pos); + const iterator found = std::find_if(sub.begin(), sub.end(), pred); if (found == end()) { return npos; } @@ -479,8 +483,7 @@ class basic_string_view : bsoncxx::detail::equality_operators, bsoncxx::detail:: const auto rpos = pos == npos ? npos : pos + 1; // The substring that will be searched: const auto prefix = substr(0, rpos); - const const_reverse_iterator found = - bsoncxx::detail::find_if(bsoncxx::detail::make_reversed_view(prefix), pred); + const const_reverse_iterator found = std::find_if(prefix.rbegin(), prefix.rend(), pred); if (found == rend()) { return npos; } diff --git a/src/bsoncxx/test/CMakeLists.txt b/src/bsoncxx/test/CMakeLists.txt index 6576252a92..1c483b37d2 100644 --- a/src/bsoncxx/test/CMakeLists.txt +++ b/src/bsoncxx/test/CMakeLists.txt @@ -37,10 +37,7 @@ add_executable(test_bson json.cpp oid.cpp view_or_value.cpp - algorithm.test.cpp - iterator.test.cpp make_unique.test.cpp - ranges.test.cpp string_view.test.cpp type_traits.test.cpp ) @@ -145,10 +142,7 @@ set_dist_list(src_bsoncxx_test_DIST test_macro_guards.cpp.in to_string.hh view_or_value.cpp - algorithm.test.cpp - iterator.test.cpp make_unique.test.cpp - ranges.test.cpp string_view.test.cpp type_traits.test.cpp ) diff --git a/src/bsoncxx/test/algorithm.test.cpp b/src/bsoncxx/test/algorithm.test.cpp deleted file mode 100644 index 7988ac92e0..0000000000 --- a/src/bsoncxx/test/algorithm.test.cpp +++ /dev/null @@ -1,50 +0,0 @@ -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -namespace ranges = bsoncxx::detail; - -TEST_CASE("Algorithm: Advance an iterator") { - int arr[] = {1, 2, 3}; - auto it = ranges::begin(arr); - auto dup = it; - CHECK(it == dup); - CHECK(*it == 1); - CHECK(ranges::advance(dup, bsoncxx::detail::unreachable_sentinel) == 1); - CHECK(*dup == 2); - CHECK(dup == ranges::next(it, bsoncxx::detail::unreachable_sentinel)); - dup = it; - CHECK(ranges::advance(dup, 2, bsoncxx::detail::unreachable_sentinel) == 2); - CHECK(*dup == 3); - CHECK(dup == ranges::next(it, 2, bsoncxx::detail::unreachable_sentinel)); - dup = it; - CHECK(ranges::advance(dup, 400, ranges::end(arr)) == 3); - CHECK(dup == ranges::end(arr)); - CHECK(dup == ranges::next(it, 3, bsoncxx::detail::unreachable_sentinel)); -} - -TEST_CASE("Algorithm: equal()") { - std::vector a = {1, 2, 3, 4, 5}; - std::vector b = {1, 2, 3, 4, 5}; - CHECK(ranges::equal(a, b)); -} - -TEST_CASE("Algorithm: Simple search") { - auto arr = {1, 2, 3, 4}; - auto needle = {2, 3}; - auto searcher = - bsoncxx::detail::default_searcher{ - bsoncxx::detail::begin(needle), bsoncxx::detail::end(needle), {}}; - auto found = searcher(bsoncxx::detail::begin(arr), bsoncxx::detail::end(arr)); - CHECK(found.first == bsoncxx::detail::begin(arr) + 1); - auto found2 = bsoncxx::detail::search(arr, needle); - CHECK(found2.begin() == bsoncxx::detail::begin(arr) + 1); -} diff --git a/src/bsoncxx/test/iterator.test.cpp b/src/bsoncxx/test/iterator.test.cpp deleted file mode 100644 index 3153c71c71..0000000000 --- a/src/bsoncxx/test/iterator.test.cpp +++ /dev/null @@ -1,79 +0,0 @@ -#include -#include -#include -#include - -#include -#include -#include - -namespace { - -struct fancy_ptr { - std::string* realptr; - - constexpr std::string* operator->() const noexcept { - return realptr; - } -}; - -} // namespace - -namespace bsoncxx { -inline namespace v_noabi { -namespace detail { -template <> -struct pointer_traits { - constexpr static std::string* to_address(fancy_ptr p) { - return p.realptr; - } -}; - -} // namespace detail -} // namespace v_noabi -} // namespace bsoncxx - -TEST_CASE("To address") { - int* p = nullptr; - CHECK(bsoncxx::detail::to_address(p) == p); - - std::list li = {1, 2, 3, 4}; - auto first = bsoncxx::detail::to_address(li.begin()); - CHECK(first == &li.front()); - - std::string hello = "I am a string"; - fancy_ptr fp{&hello}; - CHECK(bsoncxx::detail::to_address(fp) == &hello); -} - -static_assert(!bsoncxx::detail::is_dereferencable{}, "fail"); -static_assert(bsoncxx::detail::is_dereferencable{}, "fail"); -static_assert(!bsoncxx::detail::is_dereferencable{}, "fail"); - -static_assert(bsoncxx::detail::is_weakly_incrementable{}, "fail"); -static_assert(!bsoncxx::detail::is_weakly_incrementable{}, "fail"); - -static_assert(std::is_base_of>{}, - "fail"); -static_assert(std::is_base_of>{}, - "fail"); -static_assert(std::is_base_of::iterator>>{}, - "fail"); - -static_assert(bsoncxx::detail::is_weakly_incrementable{}, "fail"); -static_assert(bsoncxx::detail::is_detected{}, "fail"); -static_assert(std::is_same, char>::value, "fail"); -static_assert(bsoncxx::detail::is_iterator{}, "fail"); -static_assert(bsoncxx::detail::is_contiguous_iterator{}, "fail"); -static_assert(!bsoncxx::detail::is_contiguous_iterator::iterator>{}, "fail"); - -struct deref_void { - void operator*() const; -}; -static_assert(bsoncxx::detail::is_detected{}, "fail"); -static_assert(!bsoncxx::detail::is_dereferencable{}, "fail"); -static_assert(!bsoncxx::detail::is_detected{}, - "fail"); diff --git a/src/bsoncxx/test/ranges.test.cpp b/src/bsoncxx/test/ranges.test.cpp deleted file mode 100644 index 47faf53c5c..0000000000 --- a/src/bsoncxx/test/ranges.test.cpp +++ /dev/null @@ -1,77 +0,0 @@ -#include -#include -#include - -#include -#include -#include - -namespace ranges = bsoncxx::detail; - -static_assert(ranges::is_range>{}, "fail"); -static_assert(ranges::is_contiguous_range>{}, "fail"); -static_assert(ranges::is_contiguous_range&>{}, "fail"); -static_assert(ranges::is_contiguous_range const&>{}, "fail"); - -static_assert( - std::is_same>, std::vector::difference_type>{}, - "fail"); - -static_assert(ranges::is_range{}, "fail"); -static_assert(ranges::is_contiguous_range{}, "fail"); -static_assert(std::is_same, std::ptrdiff_t>{}, "fail"); - -static_assert(ranges::is_range>{}, "fail"); -static_assert(!ranges::is_contiguous_range>{}, "fail"); - -TEST_CASE("Range from vector") { - std::vector nums = {1, 2, 3, 4}; - auto it = ranges::begin(nums); - REQUIRE(it != ranges::end(nums)); - REQUIRE((it + 4) == ranges::end(nums)); - static_assert(std::is_same::iterator>::value, "fail"); - CHECK(*it == 1); - ++it; - CHECK(it == std::next(ranges::begin(nums))); - CHECK(*it == 2); - CHECK(ranges::size(nums) == 4); - CHECK(ranges::ssize(nums) == 4); - CHECK(ranges::data(nums) == nums.data()); - CHECK(ranges::to_address(ranges::begin(nums)) == nums.data()); -} - -TEST_CASE("Range from array") { - int array[] = {1, 2, 3, 4}; - auto it = ranges::begin(array); - CHECK(it == array + 0); - CHECK(ranges::end(array) == array + 4); - CHECK(ranges::size(array) == 4); - CHECK(ranges::ssize(array) == 4); - CHECK(ranges::data(array) == ranges::begin(array)); -} - -namespace stuff { - -class custom_vector_wrapper { - using vec = std::vector; - vec numbers = {1, 2, 3, 4, 5}; - - friend vec::iterator begin(custom_vector_wrapper& self) { - return self.numbers.begin(); - } - - friend vec::iterator end(custom_vector_wrapper& self) { - return self.numbers.end(); - } -}; - -} // namespace stuff - -TEST_CASE("ADL-only range") { - stuff::custom_vector_wrapper vec; - static_assert(bsoncxx::detail::is_range{}, "fail"); - auto it = ranges::begin(vec); - CHECK(*it == 1); - CHECK(bsoncxx::detail::size(vec) == 5u); - CHECK(bsoncxx::detail::ssize(vec) == 5); -} diff --git a/src/bsoncxx/test/string_view.test.cpp b/src/bsoncxx/test/string_view.test.cpp index 8ab3a61cbc..b5ad0e0f8e 100644 --- a/src/bsoncxx/test/string_view.test.cpp +++ b/src/bsoncxx/test/string_view.test.cpp @@ -4,7 +4,6 @@ #include #include -#include #include #include #include @@ -13,13 +12,12 @@ namespace stdx = bsoncxx::stdx; using stdx::string_view; +static_assert(bsoncxx::stdx::detail::is_string_like::value, "fail"); + static_assert(!std::is_constructible>::value, "fail"); static_assert(!std::is_constructible::value, "fail"); static_assert(std::is_constructible::value, "fail"); static_assert(std::is_constructible::value, "fail"); -static_assert(bsoncxx::detail::is_contiguous_range::value, "fail"); -static_assert(bsoncxx::detail::is_contiguous_range::value, "fail"); -static_assert(bsoncxx::detail::is_contiguous_range::value, "fail"); TEST_CASE("string_view: Default constructor") { (void)string_view(); @@ -154,6 +152,7 @@ TEST_CASE("string_view: find") { pos = sv.find("", 4); CHECK(pos == 4); CHECK(sv.find("") == str.find("")); + CHECK(sv.find("", 5000) == str.find("", 5000)); CHECK(sv.find("nowhere") == sv.npos); CHECK(sv.rfind("nowhere") == str.rfind("nowhere")); CHECK(sv.find("123") == str.find("123")); @@ -162,6 +161,7 @@ TEST_CASE("string_view: find") { CHECK(sv.rfind("abc", 8) == str.rfind("abc", 8)); CHECK(sv.rfind("abc", 888888) == str.rfind("abc", 888888)); CHECK(sv.rfind("") == str.rfind("")); + CHECK(sv.rfind("", 5000) == str.rfind("", 5000)); CHECK(string_view("").find("") == std::string("").find("")); CHECK(string_view("").rfind("") == std::string("").rfind("")); From 2a0650339e96ebda951bf3f3a4fd79b770d2632c Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Tue, 12 Dec 2023 13:27:37 -0700 Subject: [PATCH 44/47] Drop equality requirement --- .../bsoncxx/v_noabi/bsoncxx/stdx/string_view.hpp | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/string_view.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/string_view.hpp index ef58e933a6..ce4d03b283 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/string_view.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/string_view.hpp @@ -44,15 +44,13 @@ auto detect_string_f(int, // bsoncxx::detail::soft_declval(), void (*conv_size)(typename S::size_type) = bsoncxx::detail::soft_declval()) - -> bsoncxx::detail::true_t< - typename S::traits_type::char_type, - decltype(s.length()), - decltype(mut = s), - decltype(s.compare(s)), - decltype(s.substr(0, s.size())), - decltype(conv_cptr(s.data())), - decltype(conv_size(s.size())), - bsoncxx::detail::requires_t>>; + -> bsoncxx::detail::true_t; // Heuristic detection of std::string-like types. Not perfect, but should reasonably // handle most cases. From ffc332ed2487919a122ca4194e1a34bbecb069b4 Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Thu, 14 Dec 2023 15:18:42 -0700 Subject: [PATCH 45/47] More review and cleanup + spec matching --- .../v_noabi/bsoncxx/stdx/operators.hpp | 2 - .../v_noabi/bsoncxx/stdx/string_view.hpp | 153 +++++++++++------- src/bsoncxx/test/string_view.test.cpp | 2 +- 3 files changed, 96 insertions(+), 61 deletions(-) diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/operators.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/operators.hpp index 13a0537ece..8e889b0b1a 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/operators.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/operators.hpp @@ -23,7 +23,6 @@ #include namespace bsoncxx { -inline namespace v_noabi { namespace detail { template @@ -180,7 +179,6 @@ struct ordering_operators { }; } // namespace detail -} // namespace v_noabi } // namespace bsoncxx #include diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/string_view.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/string_view.hpp index 547f48965d..fa09eaf2f0 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/string_view.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/string_view.hpp @@ -84,8 +84,6 @@ class basic_string_view : bsoncxx::detail::equality_operators, bsoncxx::detail:: const_pointer _begin = nullptr; // The size of the array that is being viewed via `_begin` size_type _size = 0; - // Alias of our own type - using self_type = basic_string_view; /** * @brief If S is a type for which we want to permit implicit conversion, @@ -95,7 +93,7 @@ class basic_string_view : bsoncxx::detail::equality_operators, bsoncxx::detail:: using _enable_string_conversion = bsoncxx::detail::requires_t< int, // Don't eat our own copy/move constructor: - bsoncxx::detail::negation>, + bsoncxx::detail::negation>, // The range's value must be the same as our character type std::is_same::value_type, value_type>, detail::is_string_like>; @@ -104,15 +102,18 @@ class basic_string_view : bsoncxx::detail::equality_operators, bsoncxx::detail:: using traits_type = Traits; using reference = Char&; using const_reference = const Char&; - using iterator = const_pointer; - using const_iterator = iterator; - using reverse_iterator = std::reverse_iterator; + using const_iterator = const_pointer; + using iterator = const_iterator; using const_reverse_iterator = std::reverse_iterator; + using reverse_iterator = const_reverse_iterator; /** * @brief Default constructor. Constructs to an empty/null string view */ - constexpr basic_string_view() = default; + constexpr basic_string_view() noexcept = default; + 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 @@ -120,16 +121,14 @@ class basic_string_view : bsoncxx::detail::equality_operators, bsoncxx::detail:: * @brief Construct a new string view from a pointer-to-character and an * array length. */ - constexpr basic_string_view(const_pointer s, size_type count) noexcept - : _begin(s), _size(count) {} + constexpr basic_string_view(const_pointer s, size_type count) : _begin(s), _size(count) {} /** * @brief Construct a new string view from a C-style null-terminated character array. * * The string size is inferred as-if by strlen() */ - constexpr basic_string_view(const_pointer s) noexcept - : _begin(s), _size(traits_type::length(s)) {} + constexpr basic_string_view(const_pointer s) : _begin(s), _size(traits_type::length(s)) {} /** * @brief Implicit conversion from string-like ranges. @@ -144,25 +143,25 @@ class basic_string_view : bsoncxx::detail::equality_operators, bsoncxx::detail:: // Construction from a null pointer is deleted basic_string_view(std::nullptr_t) = delete; - constexpr iterator begin() const noexcept { - return iterator(_begin); + constexpr const_iterator begin() const noexcept { + return const_iterator(_begin); } - constexpr iterator end() const noexcept { + constexpr const_iterator end() const noexcept { return begin() + size(); } - constexpr iterator cbegin() const noexcept { + constexpr const_iterator cbegin() const noexcept { return begin(); } - constexpr iterator cend() const noexcept { + constexpr const_iterator cend() const noexcept { return end(); } - constexpr reverse_iterator rbegin() const noexcept { - return reverse_iterator{end()}; + constexpr const_reverse_iterator rbegin() const noexcept { + return const_reverse_iterator{end()}; } - constexpr reverse_iterator rend() const noexcept { - return reverse_iterator{begin()}; + constexpr const_reverse_iterator rend() const noexcept { + return const_reverse_iterator{begin()}; } constexpr const_reverse_iterator crbegin() const noexcept { @@ -179,7 +178,7 @@ class basic_string_view : bsoncxx::detail::equality_operators, bsoncxx::detail:: * @param offset A zero-based offset within the string to access. Must be less * than size() */ - constexpr const_reference operator[](size_type offset) const noexcept { + constexpr const_reference operator[](size_type offset) const { return _begin[offset]; } @@ -196,11 +195,11 @@ class basic_string_view : bsoncxx::detail::equality_operators, bsoncxx::detail:: return _begin[pos]; } /// Access the first character in the string - constexpr const_reference front() const noexcept { + constexpr const_reference front() const { return (*this)[0]; } /// Access the last character in the string - constexpr const_reference back() const noexcept { + constexpr const_reference back() const { return (*this)[size() - 1]; } @@ -240,14 +239,14 @@ class basic_string_view : bsoncxx::detail::equality_operators, bsoncxx::detail:: * * @param n The number of characters to remove from the end. Must be less than size() */ - bsoncxx_cxx14_constexpr void remove_suffix(size_type n) noexcept { + bsoncxx_cxx14_constexpr void remove_suffix(size_type n) { _size -= n; } /** * @brief Swap the reference with another string_view */ - bsoncxx_cxx14_constexpr void swap(basic_string_view& other) noexcept { + bsoncxx_cxx14_constexpr void swap(basic_string_view& other) { std::swap(_begin, other._begin); std::swap(_size, other._size); } @@ -281,11 +280,12 @@ class basic_string_view : bsoncxx::detail::equality_operators, bsoncxx::detail:: * * @throws std::out_of_range if `pos` is greater than this->size() */ - bsoncxx_cxx14_constexpr self_type substr(size_type pos, size_type count = npos) const { + bsoncxx_cxx14_constexpr basic_string_view substr(size_type pos = 0, + size_type count = npos) const { if (pos > size()) { throw std::out_of_range{"bsoncxx::stdx::basic_string_view::substr()"}; } - return self_type(_begin + pos, (std::min)(count, size() - pos)); + return basic_string_view(_begin + pos, (std::min)(count, size() - pos)); } /** @@ -296,21 +296,39 @@ class basic_string_view : bsoncxx::detail::equality_operators, bsoncxx::detail:: * @returns `n : n < 0` if *this is "less than" other. * @returns `n : n > 0` if *this is "greater than" other. */ - constexpr int compare(self_type other) const noexcept { + constexpr int compare(basic_string_view other) const noexcept { // Another level of indirection to support restricted C++11 constexpr return _compare2(Traits::compare(data(), other.data(), (std::min)(size(), other.size())), other); } + /** + * @brief Compare *this with the given C-string + * + * @returns compare(basic_string_view(cstr)) + */ + constexpr int compare(const_pointer cstr) const { + return compare(basic_string_view(cstr)); + } + /** * @brief Compare a substring of *this with `other` * * @returns substr(po1, count1).compare(other) */ - constexpr int compare(size_type pos1, size_type count1, self_type other) const noexcept { + constexpr int compare(size_type pos1, size_type count1, basic_string_view other) const { return substr(pos1, count1).compare(other); } + /** + * @brief Compare a substring of *this with the given C-string + * + * @returns substr(pos1, count1, basic_string_view(cstr)) + */ + constexpr int compare(size_type pos1, size_type count1, const_pointer cstr) const { + return compare(pos1, count1, basic_string_view(cstr)); + } + /** * @brief Compare a substring of *this with a substring of `other` * @@ -318,9 +336,9 @@ class basic_string_view : bsoncxx::detail::equality_operators, bsoncxx::detail:: */ constexpr int compare(size_type pos1, size_type count1, - self_type other, + basic_string_view other, size_type pos2, - size_type count2) const noexcept { + size_type count2) const { return substr(pos1, count1).compare(other.substr(pos2, count2)); } @@ -332,19 +350,20 @@ class basic_string_view : bsoncxx::detail::equality_operators, bsoncxx::detail:: constexpr int compare(size_type pos1, size_type count1, const_pointer str, - size_type count2) const noexcept { - return substr(pos1, count1).compare(self_type(str, count2)); + size_type count2) const { + return substr(pos1, count1).compare(basic_string_view(str, count2)); } /** * @brief Find the zero-based offset of the left-most occurrence of the given infix, * starting with pos. If infix does not occur, returns npos. */ - bsoncxx_cxx14_constexpr size_type find(self_type infix, size_type pos = 0) const noexcept { + bsoncxx_cxx14_constexpr size_type find(basic_string_view infix, + size_type pos = 0) const noexcept { if (pos > size()) { return npos; } - self_type sub = this->substr(pos); + basic_string_view sub = this->substr(pos); if (infix.empty()) { // The empty string is always "present" at the beginning of any string return pos; @@ -360,13 +379,14 @@ class basic_string_view : bsoncxx::detail::equality_operators, bsoncxx::detail:: * @brief Find the zero-based offset of the right-most occurrence of the given infix, * starting with (and including) pos. If infix does not occur, returns npos. */ - bsoncxx_cxx14_constexpr size_type rfind(self_type infix, size_type pos = npos) const noexcept { + bsoncxx_cxx14_constexpr size_type rfind(basic_string_view infix, + size_type pos = npos) const noexcept { // Calc the endpos where searching should begin, which includes the infix size const size_type substr_size = pos != npos ? pos + infix.size() : pos; if (infix.empty()) { return (std::min)(pos, size()); } - self_type searched = this->substr(0, substr_size); + basic_string_view searched = this->substr(0, substr_size); auto f = std::search(searched.rbegin(), searched.rend(), infix.rbegin(), infix.rend()); if (f == searched.rend()) { return npos; @@ -378,7 +398,7 @@ class basic_string_view : bsoncxx::detail::equality_operators, bsoncxx::detail:: * @brief Find the zero-based index of the left-most occurrence of any character of the given * set, starting at pos */ - constexpr size_type find_first_of(self_type set, size_type pos = 0) const noexcept { + constexpr size_type find_first_of(basic_string_view set, size_type pos = 0) const noexcept { return _find_if(pos, [&](value_type chr) { return set.find(chr) != npos; }); } @@ -386,7 +406,7 @@ class basic_string_view : bsoncxx::detail::equality_operators, bsoncxx::detail:: * @brief Find the zero-based index of the right-most occurrence of any character of the * given set, starting at (and including) pos */ - constexpr size_type find_last_of(self_type set, size_type pos = npos) const noexcept { + constexpr size_type find_last_of(basic_string_view set, size_type pos = npos) const noexcept { return _rfind_if(pos, [&](value_type chr) { return set.find(chr) != npos; }); } @@ -394,7 +414,7 @@ class basic_string_view : bsoncxx::detail::equality_operators, bsoncxx::detail:: * @brief Find the zero-based index of the left-most occurrence of any character that * is NOT a member of the given set of characters */ - constexpr size_type find_first_not_of(self_type set, size_type pos = 0) const noexcept { + constexpr size_type find_first_not_of(basic_string_view set, size_type pos = 0) const noexcept { return _find_if(pos, [&](value_type chr) { return set.find(chr) == npos; }); } @@ -402,22 +422,23 @@ class basic_string_view : bsoncxx::detail::equality_operators, bsoncxx::detail:: * @brief Find the zero-based index of the right-most occurrence of any character that * is NOT a member of the given set of characters, starting at (and including) pos */ - constexpr size_type find_last_not_of(self_type set, size_type pos = npos) const noexcept { + constexpr size_type find_last_not_of(basic_string_view set, + size_type pos = npos) const noexcept { return _rfind_if(pos, [&](value_type chr) { return set.find(chr) == npos; }); } #pragma push_macro("DECL_FINDERS") #undef DECL_FINDERS -#define DECL_FINDERS(Name, DefaultPos) \ - constexpr size_type Name(value_type chr, size_type pos = DefaultPos) const noexcept { \ - return Name(self_type(&chr, 1), pos); \ - } \ - constexpr size_type Name(const_pointer cstr, size_type pos, size_type count) const noexcept { \ - return Name(self_type(cstr, count), pos); \ - } \ - constexpr size_type Name(const_pointer cstr, size_type pos = DefaultPos) const noexcept { \ - return Name(self_type(cstr), pos); \ - } \ +#define DECL_FINDERS(Name, DefaultPos) \ + constexpr size_type Name(value_type chr, size_type pos = DefaultPos) const noexcept { \ + return Name(basic_string_view(&chr, 1), pos); \ + } \ + constexpr size_type Name(const_pointer cstr, size_type pos, size_type count) const { \ + return Name(basic_string_view(cstr, count), pos); \ + } \ + constexpr size_type Name(const_pointer cstr, size_type pos = DefaultPos) const { \ + return Name(basic_string_view(cstr), pos); \ + } \ BSONCXX_FORCE_SEMICOLON DECL_FINDERS(find, 0); DECL_FINDERS(rfind, npos); @@ -431,33 +452,35 @@ class basic_string_view : bsoncxx::detail::equality_operators, bsoncxx::detail:: * @brief Explicit-conversion to a std::basic_string */ template - constexpr explicit operator std::basic_string() const { + explicit operator std::basic_string() const { return std::basic_string(data(), size()); } private: // Additional level-of-indirection for constexpr compare() - constexpr int _compare2(int diff, self_type other) const noexcept { + constexpr int _compare2(int diff, basic_string_view other) const noexcept { // "diff" is the diff according to Traits::cmp return diff ? diff : static_cast(size() - other.size()); } // Implementation of equality comparison constexpr friend bool tag_invoke(bsoncxx::detail::equal_to, - self_type left, - self_type right) noexcept { + basic_string_view left, + basic_string_view right) noexcept { return left.size() == right.size() && left.compare(right) == 0; } // Implementation of a three-way-comparison constexpr friend bsoncxx::detail::strong_ordering tag_invoke( - bsoncxx::detail::compare_three_way cmp, self_type left, self_type right) noexcept { + bsoncxx::detail::compare_three_way cmp, + basic_string_view left, + basic_string_view right) noexcept { return cmp(left.compare(right), 0); } friend std::basic_ostream& operator<<(std::basic_ostream& out, - self_type self) { - out.write(self.data(), static_cast(self.size())); + basic_string_view self) { + out << std::basic_string(self); return out; } @@ -510,3 +533,17 @@ using ::bsoncxx::v_noabi::stdx::string_view; } // namespace bsoncxx #include + +namespace std { + +template +struct hash> + : private std::hash> { + std::size_t operator()( + const bsoncxx::v_noabi::stdx::basic_string_view& str) const { + return std::hash>::operator()( + std::basic_string(str.data(), str.size())); + } +}; + +} // namespace std \ No newline at end of file diff --git a/src/bsoncxx/test/string_view.test.cpp b/src/bsoncxx/test/string_view.test.cpp index b5ad0e0f8e..a93402ebb6 100644 --- a/src/bsoncxx/test/string_view.test.cpp +++ b/src/bsoncxx/test/string_view.test.cpp @@ -12,7 +12,7 @@ namespace stdx = bsoncxx::stdx; using stdx::string_view; -static_assert(bsoncxx::stdx::detail::is_string_like::value, "fail"); +static_assert(bsoncxx::v_noabi::stdx::detail::is_string_like::value, "fail"); static_assert(!std::is_constructible>::value, "fail"); static_assert(!std::is_constructible::value, "fail"); From 3608164c2955420fc1c8f4444ab1bf01f4a6af38 Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Thu, 14 Dec 2023 16:47:27 -0700 Subject: [PATCH 46/47] More careful conversion to/from std types --- .../v_noabi/bsoncxx/stdx/string_view.hpp | 67 +++++++------------ src/bsoncxx/test/string_view.test.cpp | 28 +++++++- 2 files changed, 50 insertions(+), 45 deletions(-) diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/string_view.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/string_view.hpp index fa09eaf2f0..d9798bccf8 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/string_view.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/string_view.hpp @@ -27,38 +27,20 @@ #include +#ifdef __has_include +#if __has_include() +#include +#endif +#endif + +#ifdef __cpp_lib_string_view +#include +#endif + namespace bsoncxx { namespace v_noabi { namespace stdx { -namespace detail { - -template -auto detect_string_f(...) -> std::false_type; - -template -auto detect_string_f(int, // - const S& s = bsoncxx::detail::soft_declval(), - S& mut = bsoncxx::detail::soft_declval(), - void (*conv_cptr)(typename S::const_pointer) = - bsoncxx::detail::soft_declval(), - void (*conv_size)(typename S::size_type) = - bsoncxx::detail::soft_declval()) - -> bsoncxx::detail::true_t; - -// Heuristic detection of std::string-like types. Not perfect, but should reasonably -// handle most cases. -template -struct is_string_like : decltype(detect_string_f>(0)) {}; - -} // namespace detail - /** * @brief Implementation of std::string_view-like class template */ @@ -85,19 +67,6 @@ class basic_string_view : bsoncxx::detail::equality_operators, bsoncxx::detail:: // The size of the array that is being viewed via `_begin` size_type _size = 0; - /** - * @brief If S is a type for which we want to permit implicit conversion, - * evaluates to the type `int`. Otherwise, is a substitution failure. - */ - template - using _enable_string_conversion = bsoncxx::detail::requires_t< - int, - // Don't eat our own copy/move constructor: - bsoncxx::detail::negation>, - // The range's value must be the same as our character type - std::is_same::value_type, value_type>, - detail::is_string_like>; - public: using traits_type = Traits; using reference = Char&; @@ -136,10 +105,16 @@ class basic_string_view : bsoncxx::detail::equality_operators, bsoncxx::detail:: * Requires that `StringLike` is a non-array contiguous range with the same * value type as this string view, and is a std::string-like value. */ - template = 0> - constexpr basic_string_view(StringLike&& str) noexcept + template + constexpr basic_string_view( + const std::basic_string& str) noexcept : _begin(str.data()), _size(str.size()) {} +#if __cpp_lib_string_view + constexpr basic_string_view(std::basic_string_view sv) noexcept + : _begin(sv.data()), _size(sv.size()) {} +#endif + // Construction from a null pointer is deleted basic_string_view(std::nullptr_t) = delete; @@ -456,6 +431,12 @@ class basic_string_view : bsoncxx::detail::equality_operators, bsoncxx::detail:: return std::basic_string(data(), size()); } +#if __cpp_lib_string_view + explicit operator std::basic_string_view() const noexcept { + return std::basic_string_view(data(), size()); + } +#endif + private: // Additional level-of-indirection for constexpr compare() constexpr int _compare2(int diff, basic_string_view other) const noexcept { diff --git a/src/bsoncxx/test/string_view.test.cpp b/src/bsoncxx/test/string_view.test.cpp index a93402ebb6..9c14d773c4 100644 --- a/src/bsoncxx/test/string_view.test.cpp +++ b/src/bsoncxx/test/string_view.test.cpp @@ -4,6 +4,16 @@ #include #include +#ifdef __has_include +#if __has_include() +#include +#endif +#endif + +#if __cpp_lib_string_view +#include +#endif + #include #include #include @@ -12,11 +22,10 @@ namespace stdx = bsoncxx::stdx; using stdx::string_view; -static_assert(bsoncxx::v_noabi::stdx::detail::is_string_like::value, "fail"); - static_assert(!std::is_constructible>::value, "fail"); static_assert(!std::is_constructible::value, "fail"); static_assert(std::is_constructible::value, "fail"); +static_assert(std::is_convertible::value, "fail"); static_assert(std::is_constructible::value, "fail"); TEST_CASE("string_view: Default constructor") { @@ -191,3 +200,18 @@ TEST_CASE("string_view: find") { CHECK(sv.find_first_not_of("abcdef123456", 5) == str.find_first_not_of("abcdef123456", 5)); CHECK(sv.find_last_not_of("abcdef123456", 5) == str.find_last_not_of("abcdef123456", 5)); } + +#ifdef __cpp_lib_string_view +static_assert(std::is_constructible::value, "fail"); + +TEST_CASE("Convert to/from std::string_view") { + std::string std_str = "Hello!"; + string_view bson_sv = std_str; + std::string_view std_sv = std::string_view(bson_sv); + CHECK(bson_sv == std_str); + CHECK(std_sv == bson_sv); + CHECK(std_sv == std_str); + bson_sv = std_sv; + CHECK(bson_sv == std_sv); +} +#endif \ No newline at end of file From 87bc4261ac922c846c429338d0f34747cc45f906 Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Fri, 15 Dec 2023 12:49:10 -0700 Subject: [PATCH 47/47] ClangFormat changes its mind in the future, +stray noexcepts --- .../v_noabi/bsoncxx/stdx/string_view.hpp | 18 ++++++++---------- .../include/bsoncxx/v_noabi/bsoncxx/types.hpp | 1 + 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/string_view.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/string_view.hpp index d9798bccf8..785e873d77 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/string_view.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/string_view.hpp @@ -84,8 +84,6 @@ class basic_string_view : bsoncxx::detail::equality_operators, bsoncxx::detail:: bsoncxx_cxx14_constexpr basic_string_view& operator=(const basic_string_view&) noexcept = default; - /// Default copy/move/assign/destroy - /** * @brief Construct a new string view from a pointer-to-character and an * array length. @@ -204,7 +202,7 @@ class basic_string_view : bsoncxx::detail::equality_operators, bsoncxx::detail:: * * @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 { + bsoncxx_cxx14_constexpr void remove_prefix(size_type n) { _begin += n; _size -= n; } @@ -237,7 +235,7 @@ class basic_string_view : bsoncxx::detail::equality_operators, bsoncxx::detail:: * * @throws std::out_of_range if pos > size() */ - 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 { if (pos > size()) { throw std::out_of_range{"bsoncxx::stdx::basic_string_view::substr()"}; } @@ -333,8 +331,8 @@ class basic_string_view : bsoncxx::detail::equality_operators, bsoncxx::detail:: * @brief Find the zero-based offset of the left-most occurrence of the given infix, * starting with pos. If infix does not occur, returns npos. */ - 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 { if (pos > size()) { return npos; } @@ -354,8 +352,8 @@ class basic_string_view : bsoncxx::detail::equality_operators, bsoncxx::detail:: * @brief Find the zero-based offset of the right-most occurrence of the given infix, * starting with (and including) pos. If infix does not occur, returns npos. */ - 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 { // Calc the endpos where searching should begin, which includes the infix size const size_type substr_size = pos != npos ? pos + infix.size() : pos; if (infix.empty()) { @@ -397,8 +395,8 @@ class basic_string_view : bsoncxx::detail::equality_operators, bsoncxx::detail:: * @brief Find the zero-based index of the right-most occurrence of any character that * is NOT a member of the given set of characters, starting at (and including) pos */ - 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 { return _rfind_if(pos, [&](value_type chr) { return set.find(chr) == npos; }); } diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/types.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/types.hpp index 183f378073..8a9133c89c 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/types.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/types.hpp @@ -675,6 +675,7 @@ BSONCXX_INLINE bool operator==(const b_maxkey&, const b_maxkey&) { } // namespace bsoncxx BSONCXX_POP_WARNINGS(); + namespace bsoncxx { using ::bsoncxx::v_noabi::to_string;