diff options
-rw-r--r-- | src/mongo/bson/bsonobjbuilder.h | 6 | ||||
-rw-r--r-- | src/mongo/bson/util/builder.h | 8 | ||||
-rw-r--r-- | src/mongo/db/exec/document_value/value.h | 14 | ||||
-rw-r--r-- | src/mongo/db/query/optimizer/algebra/operator.h | 18 | ||||
-rw-r--r-- | src/mongo/executor/remote_command_request.h | 12 | ||||
-rw-r--r-- | src/mongo/platform/mutex.h | 5 | ||||
-rw-r--r-- | src/mongo/transport/asio/asio_networking_baton.h | 1 | ||||
-rw-r--r-- | src/mongo/unittest/assert.h | 23 | ||||
-rw-r--r-- | src/mongo/util/SConscript | 1 | ||||
-rw-r--r-- | src/mongo/util/concepts.h | 210 | ||||
-rw-r--r-- | src/mongo/util/concepts_test.cpp | 170 | ||||
-rw-r--r-- | src/mongo/util/functional.h | 15 | ||||
-rw-r--r-- | src/mongo/util/future.h | 251 | ||||
-rw-r--r-- | src/mongo/util/future_impl.h | 51 | ||||
-rw-r--r-- | src/mongo/util/future_test_promise_int.cpp | 1 | ||||
-rw-r--r-- | src/mongo/util/future_test_utils.h | 1 | ||||
-rw-r--r-- | src/mongo/util/future_util.h | 26 | ||||
-rw-r--r-- | src/mongo/util/interruptible.h | 5 | ||||
-rw-r--r-- | src/mongo/util/invalidating_lru_cache.h | 25 | ||||
-rw-r--r-- | src/mongo/util/lru_cache.h | 28 | ||||
-rw-r--r-- | src/mongo/util/read_through_cache.h | 34 | ||||
-rw-r--r-- | src/mongo/util/registry_list.h | 9 |
22 files changed, 257 insertions, 657 deletions
diff --git a/src/mongo/bson/bsonobjbuilder.h b/src/mongo/bson/bsonobjbuilder.h index be826d5a824..be37f4e9f80 100644 --- a/src/mongo/bson/bsonobjbuilder.h +++ b/src/mongo/bson/bsonobjbuilder.h @@ -539,9 +539,9 @@ public: * Append a map of values as a sub-object. * Note: the keys of the map should be StringData-compatible (i.e. strings). */ - TEMPLATE(typename Map) - REQUIRES(std::is_convertible_v<decltype(std::declval<Map>().begin()->first), StringData>) - Derived& append(StringData fieldName, const Map& map) { + template <typename Map> + requires std::is_convertible_v<decltype(std::declval<Map>().begin()->first), StringData> + Derived& append(StringData fieldName, const Map& map) { typename std::remove_reference<Derived>::type bob; for (auto&& [k, v] : map) { bob.append(k, v); diff --git a/src/mongo/bson/util/builder.h b/src/mongo/bson/util/builder.h index 5d7d2d5673c..a3ce39883d7 100644 --- a/src/mongo/bson/util/builder.h +++ b/src/mongo/bson/util/builder.h @@ -53,7 +53,6 @@ #include "mongo/stdx/type_traits.h" #include "mongo/util/allocator.h" #include "mongo/util/assert_util.h" -#include "mongo/util/concepts.h" #include "mongo/util/itoa.h" #include "mongo/util/shared_buffer.h" #include "mongo/util/shared_buffer_fragment.h" @@ -380,8 +379,8 @@ public: appendNumImpl(high); } - REQUIRES_FOR_NON_TEMPLATE(!std::is_same_v<int64_t, long long>) - void appendNum(int64_t j) { + template <int...> + requires(!std::is_same_v<int64_t, long long>) void appendNum(int64_t j) { appendNumImpl(j); } @@ -465,7 +464,8 @@ public: * Replaces the buffer backing this BufBuilder with the passed in SharedBuffer. * Only legal to call when this builder is empty and when the SharedBuffer isn't shared. */ - REQUIRES_FOR_NON_TEMPLATE(std::is_same_v<BufferAllocator, SharedBufferAllocator>) + template <int...> + requires std::is_same_v<BufferAllocator, SharedBufferAllocator> void useSharedBuffer(SharedBuffer buf) { invariant(len() == 0); // Can only do this while empty. invariant(reservedBytes() == 0); diff --git a/src/mongo/db/exec/document_value/value.h b/src/mongo/db/exec/document_value/value.h index c3e3dc78546..1d6cc5fd1a6 100644 --- a/src/mongo/db/exec/document_value/value.h +++ b/src/mongo/db/exec/document_value/value.h @@ -32,7 +32,6 @@ #include "mongo/base/static_assert.h" #include "mongo/base/string_data.h" #include "mongo/db/exec/document_value/value_internal.h" -#include "mongo/util/concepts.h" #include "mongo/util/safe_num.h" #include "mongo/util/uuid.h" @@ -417,22 +416,15 @@ inline void swap(mongo::Value& lhs, mongo::Value& rhs) { lhs.swap(rhs); } -MONGO_MAKE_BOOL_TRAIT(CanConstructValueFrom, - (typename T), - (T), - (T val), - // - Value(std::forward<T>(val))); - /** * This class is identical to Value, but supports implicit creation from any of the types explicitly * supported by Value. */ class ImplicitValue : public Value { public: - TEMPLATE(typename T) - REQUIRES(CanConstructValueFrom<T>) - ImplicitValue(T&& arg) : Value(std::forward<T>(arg)) {} + template <typename T> + requires std::is_constructible_v<Value, T> ImplicitValue(T&& arg) + : Value(std::forward<T>(arg)) {} ImplicitValue(std::initializer_list<ImplicitValue> values) : Value(convertToValues(values)) {} ImplicitValue(std::vector<ImplicitValue> values) : Value(convertToValues(values)) {} diff --git a/src/mongo/db/query/optimizer/algebra/operator.h b/src/mongo/db/query/optimizer/algebra/operator.h index 1dd75272747..dede8effa6c 100644 --- a/src/mongo/db/query/optimizer/algebra/operator.h +++ b/src/mongo/db/query/optimizer/algebra/operator.h @@ -33,8 +33,6 @@ #include <utility> #include <vector> -#include "mongo/util/concepts.h" - namespace mongo::optimizer { namespace algebra { @@ -66,19 +64,17 @@ class OpFixedArity : public OpNodeStorage<Slot, Arity> { using Base = OpNodeStorage<Slot, Arity>; public: - TEMPLATE(typename... Ts) - REQUIRES(sizeof...(Ts) == Arity) - OpFixedArity(Ts&&... vals) : Base({std::forward<Ts>(vals)...}) {} + template <typename... Ts> + requires(sizeof...(Ts) == Arity) OpFixedArity(Ts&&... vals) + : Base({std::forward<Ts>(vals)...}) {} - TEMPLATE(int I) - REQUIRES(I >= 0 && I < Arity) - auto& get() noexcept { + template <int I> + requires(I >= 0 && I < Arity) auto& get() noexcept { return this->_nodes[I]; } - TEMPLATE(int I) - REQUIRES(I >= 0 && I < Arity) - const auto& get() const noexcept { + template <int I> + requires(I >= 0 && I < Arity) const auto& get() const noexcept { return this->_nodes[I]; } }; diff --git a/src/mongo/executor/remote_command_request.h b/src/mongo/executor/remote_command_request.h index 5d8e8fbf8c5..44435615052 100644 --- a/src/mongo/executor/remote_command_request.h +++ b/src/mongo/executor/remote_command_request.h @@ -38,7 +38,6 @@ #include "mongo/executor/hedge_options_util.h" #include "mongo/rpc/metadata.h" #include "mongo/transport/transport_layer.h" -#include "mongo/util/concepts.h" #include "mongo/util/net/hostandport.h" #include "mongo/util/time_support.h" @@ -127,15 +126,16 @@ struct RemoteCommandRequestImpl : RemoteCommandRequestBase { RemoteCommandRequestImpl(); // Allow implicit conversion from RemoteCommandRequest to RemoteCommandRequestOnAny - REQUIRES_FOR_NON_TEMPLATE(std::is_same_v<Target, std::vector<HostAndPort>>) - RemoteCommandRequestImpl(const RemoteCommandRequestImpl<HostAndPort>& other) + template <int...> + requires std::is_same_v<Target, std::vector<HostAndPort>> RemoteCommandRequestImpl( + const RemoteCommandRequestImpl<HostAndPort>& other) : RemoteCommandRequestBase(other), target({other.target}) {} // Allow conversion from RemoteCommandRequestOnAny to RemoteCommandRequest with the index of a // particular host - REQUIRES_FOR_NON_TEMPLATE(std::is_same_v<Target, HostAndPort>) - RemoteCommandRequestImpl(const RemoteCommandRequestImpl<std::vector<HostAndPort>>& other, - size_t idx) + template <int...> + requires std::is_same_v<Target, HostAndPort> RemoteCommandRequestImpl( + const RemoteCommandRequestImpl<std::vector<HostAndPort>>& other, size_t idx) : RemoteCommandRequestBase(other), target(other.target[idx]) {} RemoteCommandRequestImpl(RequestId requestId, diff --git a/src/mongo/platform/mutex.h b/src/mongo/platform/mutex.h index 94361dd938e..a7f19d773d6 100644 --- a/src/mongo/platform/mutex.h +++ b/src/mongo/platform/mutex.h @@ -41,7 +41,6 @@ #include "mongo/platform/source_location.h" #include "mongo/stdx/mutex.h" #include "mongo/util/assert_util.h" -#include "mongo/util/concepts.h" #include "mongo/util/decorable.h" #include "mongo/util/duration.h" #include "mongo/util/hierarchical_acquisition.h" @@ -196,8 +195,8 @@ inline auto& getDiagnosticListenerState() noexcept { * DiagnosticListeners subclass, please provide the switch on that subclass to noop its * functions. It is only safe to add a DiagnosticListener during a MONGO_INITIALIZER. */ -TEMPLATE(typename ListenerT) -REQUIRES(std::is_base_of_v<DiagnosticListener, ListenerT>) +template <typename ListenerT> +requires std::is_base_of_v<DiagnosticListener, ListenerT> void installDiagnosticListener() { auto& state = getDiagnosticListenerState(); diff --git a/src/mongo/transport/asio/asio_networking_baton.h b/src/mongo/transport/asio/asio_networking_baton.h index 122962fc54f..3d3086a30b1 100644 --- a/src/mongo/transport/asio/asio_networking_baton.h +++ b/src/mongo/transport/asio/asio_networking_baton.h @@ -40,7 +40,6 @@ #include "mongo/stdx/unordered_map.h" #include "mongo/transport/asio/asio_session.h" #include "mongo/transport/baton.h" -#include "mongo/util/concepts.h" #include "mongo/util/functional.h" #include "mongo/util/future.h" #include "mongo/util/hierarchical_acquisition.h" diff --git a/src/mongo/unittest/assert.h b/src/mongo/unittest/assert.h index 62e71077982..7d94d57c709 100644 --- a/src/mongo/unittest/assert.h +++ b/src/mongo/unittest/assert.h @@ -441,7 +441,6 @@ public: StringData a, StringData b); - // Use a single implementation (identical to the templated one) for all pointer and array types. // Note: this is selected instead of the StringData overload for char* and string literals // because they are supposed to compare pointers, not contents. @@ -451,16 +450,18 @@ public: StringData bExpression, const void* a, const void* b); - TEMPLATE(typename A, typename B) - REQUIRES(!(std::is_convertible_v<A, StringData> && std::is_convertible_v<B, StringData>)&& // - !(std::is_pointer_v<A> && std::is_pointer_v<B>)&& // - !(std::is_array_v<A> && std::is_array_v<B>)) - static ComparisonAssertion make(const char* theFile, - unsigned theLine, - StringData aExpression, - StringData bExpression, - const A& a, - const B& b) { + + template <typename A, typename B> + requires( // + !(std::is_convertible_v<A, StringData> && std::is_convertible_v<B, StringData>)&& // + !(std::is_pointer_v<A> && std::is_pointer_v<B>)&& // + !(std::is_array_v<A> && std::is_array_v<B>)) // + static ComparisonAssertion make(const char* theFile, + unsigned theLine, + StringData aExpression, + StringData bExpression, + const A& a, + const B& b) { return ComparisonAssertion(theFile, theLine, aExpression, bExpression, a, b); } diff --git a/src/mongo/util/SConscript b/src/mongo/util/SConscript index aff0ed44fef..992990e9fbc 100644 --- a/src/mongo/util/SConscript +++ b/src/mongo/util/SConscript @@ -748,7 +748,6 @@ icuEnv.CppUnitTest( 'base64_test.cpp', 'cancellation_test.cpp', 'clock_source_mock_test.cpp', - 'concepts_test.cpp', 'container_size_helper_test.cpp', 'ctype_test.cpp', 'decimal_counter_test.cpp', diff --git a/src/mongo/util/concepts.h b/src/mongo/util/concepts.h deleted file mode 100644 index fcee167037d..00000000000 --- a/src/mongo/util/concepts.h +++ /dev/null @@ -1,210 +0,0 @@ -/** - * Copyright (C) 2018-present MongoDB, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the Server Side Public License, version 1, - * as published by MongoDB, Inc. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * Server Side Public License for more details. - * - * You should have received a copy of the Server Side Public License - * along with this program. If not, see - * <http://www.mongodb.com/licensing/server-side-public-license>. - * - * As a special exception, the copyright holders give permission to link the - * code of portions of this program with the OpenSSL library under certain - * conditions as described in each individual source file and distribute - * linked combinations including the program with the OpenSSL library. You - * must comply with the Server Side Public License in all respects for - * all of the code used other than as permitted herein. If you modify file(s) - * with this exception, you may extend this exception to your version of the - * file(s), but you are not obligated to do so. If you do not wish to do so, - * delete this exception statement from your version. If you delete this - * exception statement from all source files in the program, then also delete - * it in the license file. - */ - -#pragma once - -#include <type_traits> - -#if defined(__cpp_concepts) - -// -// These macros provide an emulation of C++20-style requires-clauses and requires-expression. These -// are part of the "Concepts" feature, however this does not provide a way to emulate the definition -// of actual concepts. You will need to continue either using the std type_traits, or define your -// own constexpr bools. -// -// The emulation does allow overloading based on requirements, however because it doesn't have a way -// to define actual concepts, there is no subsumption/refinement rules. In other words, you are -// responsible for ensuring that only one overload (with the same arguments) will match a given -// call, the compiler won't select the best one. eg, with real concepts support, you can overload -// these functions and it will do the right thing: -// template <typename T> void doThing(T); -// template <typename T> requires(IsFoo<T>) void doThing(T); -// template <typename T> requires(IsFoo<T> && IsBar<T>) void doThing(T); -// -// With the emulation, you need to explicitly make them all mutually exclusive: -// template <typename T> requires(!IsFoo<T>) void doThing(T); -// template <typename T> requires( IsFoo<T> && !IsBar<T>) void doThing(T); -// template <typename T> requires( IsFoo<T> && IsBar<T>) void doThing(T); -// - -/** - * Use "TEMPLATE(typename T)" instead of "template <typename T>" when you are using the REQUIRES - * macros. - */ -#define TEMPLATE(...) template <__VA_ARGS__> - -/** - * Disables this template if the argument evaluates to false at compile time. - * - * Use the OUT_OF_LINE_DEF version when you are defining the template out of line following an - * earlier forward declaration. - * - * Must be placed between the TEMPLATE() macro and the declaration (ie it doesn't support the - * "trailing requires clause" style). Can not be used to enable/disable explicit specializations, - * they will need to match exactly one version of the primary template. - * - * Be careful will top-level commas, because everything before the comma will be ignored. - * - * Example (you could also just define the body with the initial declaration): - * - * TEMPLATE(typename Callback) - * REQUIRES(std::is_invocable_v<Callback, Status>) - * void registerCallback(Callback&& cb); - * - * TEMPLATE(typename Callback) - * REQUIRES_OUT_OF_LINE_DEF(std::is_invocable_v<Callback, Status>) - * void registerCallback(Callback&& cb) { stuff } - */ -#define REQUIRES(...) requires(__VA_ARGS__) -#define REQUIRES_OUT_OF_LINE_DEF(...) requires(__VA_ARGS__) - -/** - * Use this on a non-template to impose requirements on it. With *very* few exceptions, this should - * only be used on non-template methods inside of a class template. - * - * Due to limitations of the emulation, you cannot forward declare methods this is used with. - * - * Example: - * template <typename T> - * struct Holder { - * REQUIRES_FOR_NON_TEMPLATE(sizeof(T) == 4) - * void doThing() {} - * - * REQUIRES_FOR_NON_TEMPLATE(sizeof(T) == 8) - * void doThing() {} - * }; - */ -#define REQUIRES_FOR_NON_TEMPLATE(...) \ - template <int... ignoreThisArg> \ - requires(__VA_ARGS__) - -/** - * Defines a boolean trait that is true if a set of expressions compiles. - * - * Args (some are lists that must be wrapped in parens): - * name - name of the template - * (tpl_params) - template parameters for the trait definition (ie with typename) - * (tpl_args) - template arguments for a usage of the trait (ie without typename) - * (decls) - declarations of variables used in the trait's expression - * exprs - the expressions that are tested to see if they compile - * - * Examples (the // separator tends to improve readability with clang-format): - * MONGO_MAKE_BOOL_TRAIT(isAddable, - * (typename LHS, typename RHS), - * (LHS, RHS), - * (LHS& mutableLhs, const LHS& lhs, const RHS& rhs), - * // - * mutableLhs += rhs); - * lhs + rhs, - * - * MONGO_MAKE_BOOL_TRAIT(isCallable, - * (typename Func, typename... Args), - * (Func, Args...), - * (Func& func, Args&&... args), - * // - * func(args...)); - * - * WARNING: This only works for compiler failures in the "immediate context" of the expression. - * For example, if a function is templated to take all arguments, but the body will fail to - * compile with some, isCallable will either return true or cause a hard compile error. - * These should only be used with well-constrained functions. - * - * We need to use a real concept to work around https://gcc.gnu.org/bugzilla/show_bug.cgi?id=90287. - * Still using a constexpr bool in the public API for consistency with the no-concepts - * implementation so it doesn't behave like a concept during normalization and overload resolution. - */ -#define MONGO_MAKE_BOOL_TRAIT(name, tpl_params, tpl_args, decls, /*exprs*/...) \ - template <MONGO_MAKE_BOOL_TRAIT_HELPER_EXPAND tpl_params> \ - MONGO_MAKE_BOOL_TRAIT_CONCEPTS_KEYWORD make_trait_impl_##name##_concept = \ - requires(MONGO_MAKE_BOOL_TRAIT_HELPER_EXPAND decls) { \ - {__VA_ARGS__}; \ - }; \ - template <MONGO_MAKE_BOOL_TRAIT_HELPER_EXPAND tpl_params> \ - constexpr inline bool name = \ - make_trait_impl_##name##_concept<MONGO_MAKE_BOOL_TRAIT_HELPER_EXPAND tpl_args> - -// Everything under here is an implementation detail, so you should only need to read it if you are -// looking to change or add something. The whole public API is described above. - -#if __cpp_concepts <= 201507 // gcc-8 still uses concepts TS syntax. -#define MONGO_MAKE_BOOL_TRAIT_CONCEPTS_KEYWORD concept bool -#else -#define MONGO_MAKE_BOOL_TRAIT_CONCEPTS_KEYWORD concept -#endif - -#else -// This is the polyfill for when not using concepts-enabled compilers. - -#define TEMPLATE(...) template <__VA_ARGS__, // intentionally left open; closed below. - -// Note: the best error messages are generated when __VA_ARGS__ is the direct first argument of -// enable_if_t, or directly inside of the parens of a decltype without an extra set of parens. -// If you want to alter these, be sure to check error messages on clang and gcc! -#define REQUIRES(...) std::enable_if_t<(__VA_ARGS__), int> = 0 > - -// Same as above, but without the default argument since some compilers (correctly) disallow -// repeating the default argument on the definition. -#define REQUIRES_OUT_OF_LINE_DEF(...) std::enable_if_t<(__VA_ARGS__), int> > - -// Need the second arg in the template to depend on both a template argument (so it is dependent), -// and the current line number (so it can be overloaded). The __VA_ARGS__ expression will generally -// be a constant expression at parse time (or class instantiation time), so in order to allow more -// than one overload that is false, we need to defer the evaluation of the outer enable_if_t to -// function instantiation time. -#define REQUIRES_FOR_NON_TEMPLATE(...) \ - template <int ignoreThisArg = 0, \ - std::enable_if_t<(__VA_ARGS__), \ - std::enable_if_t<(ignoreThisArg * __LINE__) == 0, int>> = 0> - -// Works by declaring a function template taking `decls` arguments and using expression-SFINAE using -// `exprs` on the return type. A bool is defined as true if it is possible to instantiate the -// template with the supplied arguments by taking its address. -#define MONGO_MAKE_BOOL_TRAIT(name, tpl_params, tpl_args, decls, /*exprs*/...) \ - template <MONGO_MAKE_BOOL_TRAIT_HELPER_EXPAND tpl_params> \ - auto make_trait_impl_##name##_fn(MONGO_MAKE_BOOL_TRAIT_HELPER_EXPAND decls) \ - ->decltype(__VA_ARGS__); \ - \ - template <typename ALWAYS_VOID, MONGO_MAKE_BOOL_TRAIT_HELPER_EXPAND tpl_params> \ - constexpr inline bool make_trait_impl_##name##_bool = false; \ - \ - template <MONGO_MAKE_BOOL_TRAIT_HELPER_EXPAND tpl_params> \ - constexpr inline bool make_trait_impl_##name##_bool< \ - std::void_t< \ - decltype(&make_trait_impl_##name##_fn<MONGO_MAKE_BOOL_TRAIT_HELPER_EXPAND tpl_args>)>, \ - MONGO_MAKE_BOOL_TRAIT_HELPER_EXPAND tpl_args> = true; \ - \ - template <MONGO_MAKE_BOOL_TRAIT_HELPER_EXPAND tpl_params> \ - constexpr inline bool name = \ - make_trait_impl_##name##_bool<void, MONGO_MAKE_BOOL_TRAIT_HELPER_EXPAND tpl_args> - -#endif - -// Strips off wrapping parens used to group some arguments. Use *without* any parens. -#define MONGO_MAKE_BOOL_TRAIT_HELPER_EXPAND(...) __VA_ARGS__ diff --git a/src/mongo/util/concepts_test.cpp b/src/mongo/util/concepts_test.cpp deleted file mode 100644 index bf9efa260f8..00000000000 --- a/src/mongo/util/concepts_test.cpp +++ /dev/null @@ -1,170 +0,0 @@ -/** - * Copyright (C) 2019-present MongoDB, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the Server Side Public License, version 1, - * as published by MongoDB, Inc. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * Server Side Public License for more details. - * - * You should have received a copy of the Server Side Public License - * along with this program. If not, see - * <http://www.mongodb.com/licensing/server-side-public-license>. - * - * As a special exception, the copyright holders give permission to link the - * code of portions of this program with the OpenSSL library under certain - * conditions as described in each individual source file and distribute - * linked combinations including the program with the OpenSSL library. You - * must comply with the Server Side Public License in all respects for - * all of the code used other than as permitted herein. If you modify file(s) - * with this exception, you may extend this exception to your version of the - * file(s), but you are not obligated to do so. If you do not wish to do so, - * delete this exception statement from your version. If you delete this - * exception statement from all source files in the program, then also delete - * it in the license file. - */ - -#include "mongo/platform/basic.h" - -#include "mongo/util/concepts.h" - -#include <boost/preprocessor/cat.hpp> -#include <cstdint> -#include <string> - -#include "mongo/unittest/unittest.h" - -namespace mongo { -namespace { - -// Everything this test tests is tests at compile time. If it compiles, it is a success. -// Intentionally using different metaprogramming techniques as in concepts.h to ensure that the test -// doesn't false negative due to the same compiler bug that would cause problems in the real -// implementation. - -template <int num> -using Overload = std::integral_constant<int, num>; - -// Using overload resolution in test to ensure a useful error message. -#define ASSERT_SELECTS_OVERLOAD(num, ...) \ - int compileTestName(Overload<num>); \ - static_assert(sizeof(decltype(compileTestName(__VA_ARGS__)))); - -// Actual tests are below here. Note to anyone thinking of adding more, You should always have at -// least three overloads with the same signature, since some bugs would only be visible if multiple -// overloads would be disabled. - -template <typename T> -struct NonTemplateTest { - REQUIRES_FOR_NON_TEMPLATE(sizeof(T) == 4) - static void test() {} - - REQUIRES_FOR_NON_TEMPLATE(sizeof(T) == 8) - static void test() {} - - REQUIRES_FOR_NON_TEMPLATE(sizeof(T) == 9) - static void test() {} -}; - -template <typename T> -constexpr inline auto sizeof_ = sizeof(T); - -static_assert(std::is_void_v<decltype(NonTemplateTest<int32_t>::test())>); -static_assert(std::is_void_v<decltype(NonTemplateTest<int64_t>::test())>); -ASSERT_DOES_NOT_COMPILE(CharNonTemplateTest, typename Char = char, NonTemplateTest<Char>::test()); - -// Uncomment to see error message. -// auto x = NonTemplateTest<char>::test(); - -TEMPLATE(typename T) -REQUIRES(sizeof(T) == 0) -Overload<1> requiresTest() { - return {}; -} - -TEMPLATE(typename T) -REQUIRES(sizeof(T) == 1) -Overload<2> requiresTest() { - return {}; -} - -TEMPLATE(typename T) -REQUIRES(sizeof(T) == 4) -Overload<3> requiresTest() { - return {}; -} - -// Note: it is valid to overload template args with typename vs NTTP. -TEMPLATE(int I) -REQUIRES(I == 0) -Overload<11> requiresTest() { - return {}; -} - -TEMPLATE(int I) -REQUIRES(I > 0) -Overload<12> requiresTest() { - return {}; -} - -TEMPLATE(int I) -REQUIRES(-10 < I && I < 0) -Overload<13> requiresTest(); - -TEMPLATE(int I) -REQUIRES_OUT_OF_LINE_DEF(-10 < I && I < 0) -Overload<13> requiresTest() { - return {}; -} - -ASSERT_SELECTS_OVERLOAD(2, requiresTest<char>()); -ASSERT_SELECTS_OVERLOAD(3, requiresTest<int32_t>()); -ASSERT_DOES_NOT_COMPILE(Int64RequiresTest, typename Int64_t = int64_t, requiresTest<Int64_t>()); - -ASSERT_SELECTS_OVERLOAD(11, requiresTest<0>()); -ASSERT_SELECTS_OVERLOAD(12, requiresTest<1>()); -ASSERT_SELECTS_OVERLOAD(13, requiresTest<-1>()); -ASSERT_DOES_NOT_COMPILE(IntRequiresTest, int i = -10, requiresTest<i>()); - -MONGO_MAKE_BOOL_TRAIT(isAddable, - (typename LHS, typename RHS), - (LHS, RHS), - (LHS & mutableLhs, const LHS& lhs, const RHS& rhs), - // - mutableLhs += rhs, - lhs + rhs); - -static_assert(isAddable<int, int>); -static_assert(isAddable<int, double>); -static_assert(isAddable<std::string, std::string>); -static_assert(!isAddable<std::string, int>); -static_assert(!isAddable<int, std::string>); - - -MONGO_MAKE_BOOL_TRAIT(isCallable, - (typename Func, typename... Args), - (Func, Args...), - (Func & func, Args&&... args), - // - func(args...)); - -static_assert(isCallable<void()>); -static_assert(!isCallable<void(), int>); -static_assert(isCallable<void(...)>); -static_assert(isCallable<void(...), int>); -static_assert(isCallable<void(...), int, int>); -static_assert(isCallable<void(StringData), StringData>); -static_assert(isCallable<void(StringData), const char*>); -static_assert(isCallable<void(StringData), std::string>); -static_assert(!isCallable<void(StringData)>); -static_assert(!isCallable<void(StringData), int>); -static_assert(!isCallable<void(StringData), StringData, StringData>); - -// The unittest framework gets angry if you have no tests. -TEST(Concepts, DummyTest) {} - -} // namespace -} // namespace mongo diff --git a/src/mongo/util/functional.h b/src/mongo/util/functional.h index c697d267aaa..8d53fbfb5de 100644 --- a/src/mongo/util/functional.h +++ b/src/mongo/util/functional.h @@ -34,7 +34,6 @@ #include "mongo/stdx/type_traits.h" #include "mongo/util/assert_util.h" -#include "mongo/util/concepts.h" namespace mongo { template <typename Function> @@ -61,10 +60,11 @@ class function_ref; template <typename RetType, typename... Args> class function_ref<RetType(Args...)> { public: - TEMPLATE(typename F) - REQUIRES(std::is_invocable_r_v<RetType, F&, Args...> && - !std::is_same_v<stdx::remove_cvref_t<F>, function_ref>) - /*implicit*/ function_ref(F&& f) noexcept { + /** Implicitly convertible from any `f` callable with signature `RetType f(Args...)`. */ + template <typename F> + requires(std::is_invocable_r_v<RetType, F&, Args...> && + !std::is_same_v<stdx::remove_cvref_t<F>, function_ref>) function_ref(F&& f) + noexcept { // removing then re-adding pointer ensures that (language-level) function references and // function pointer are treated the same. using Pointer = std::add_pointer_t<std::remove_pointer_t<std::remove_reference_t<F>>>; @@ -114,9 +114,8 @@ public: * somebody really needs it, we could try to allow T& but not T&&, since T& is less likely to * dangle, but I don't think there is an actual use case for this, so not doing it at this time. */ - TEMPLATE(typename T) - REQUIRES(!std::is_function_v<std::remove_pointer_t<T>>) - function_ref& operator=(T) = delete; + template <typename T> + requires(!std::is_function_v<std::remove_pointer_t<T>>) function_ref& operator=(T) = delete; RetType operator()(Args... args) const { return _adapter(_target, std::forward<Args>(args)...); diff --git a/src/mongo/util/future.h b/src/mongo/util/future.h index 63eddbcbff0..986da3f7fa7 100644 --- a/src/mongo/util/future.h +++ b/src/mongo/util/future.h @@ -143,7 +143,8 @@ public: return SemiFuture(Impl::makeReady(std::move(val))); } - REQUIRES_FOR_NON_TEMPLATE(std::is_void_v<T>) + template <int...> + requires std::is_void_v<T> static SemiFuture<void> makeReady() { return SemiFuture(Impl::makeReady()); } @@ -296,9 +297,9 @@ private: }; // Deduction Guides -TEMPLATE(typename T) -REQUIRES(!isStatusOrStatusWith<T> && !future_details::isFutureLike<T>) -SemiFuture(T)->SemiFuture<T>; +template <typename T> +requires(!isStatusOrStatusWith<T> && !future_details::isFutureLike<T>) SemiFuture(T) +->SemiFuture<T>; template <typename T> SemiFuture(StatusWith<T>) -> SemiFuture<T>; @@ -343,7 +344,8 @@ public: static Future<T> makeReady(StatusWith<T_unless_void> val) { return Future(Impl::makeReady(std::move(val))); } - REQUIRES_FOR_NON_TEMPLATE(std::is_void_v<T>) + template <int...> + requires std::is_void_v<T> static Future<void> makeReady() { return Future(Impl::makeReady()); } @@ -366,10 +368,9 @@ public: * * TODO decide how to handle func throwing. */ - TEMPLATE(typename Policy, typename Func) - REQUIRES(future_details::isCallableExactR<void, Func, StatusOrStatusWith<T>>&& - isFuturePolicy<Policy>) - void getAsync(Policy policy, Func&& func) && noexcept { + template <typename Policy, typename Func> + requires(future_details::isCallableExactR<void, Func, StatusOrStatusWith<T>>&& + isFuturePolicy<Policy>) void getAsync(Policy policy, Func&& func) && noexcept { std::move(this->_impl).getAsync(policy, std::forward<Func>(func)); } @@ -408,9 +409,9 @@ public: * The callback takes a T and can return anything (see above for how Statusy and Futurey returns * are handled.) */ - TEMPLATE(typename Policy, typename Func) - REQUIRES(future_details::isCallable<Func, T>&& isFuturePolicy<Policy>) - /*see above*/ auto then(Policy policy, Func&& func) && noexcept { + template <typename Policy, typename Func> + requires(future_details::isCallable<Func, T>&& isFuturePolicy<Policy>) auto then( + Policy policy, Func&& func) && noexcept { return wrap<Func, T>(std::move(this->_impl).then(policy, std::forward<Func>(func))); } @@ -421,9 +422,9 @@ public: * The callback takes a StatusOrStatusWith<T> and can return anything (see above for how Statusy * and Futurey returns are handled.) */ - TEMPLATE(typename Policy, typename Func) - REQUIRES(future_details::isCallable<Func, StatusOrStatusWith<T>>&& isFuturePolicy<Policy>) - /*see above*/ auto onCompletion(Policy policy, Func&& func) && noexcept { + template <typename Policy, typename Func> + requires(future_details::isCallable<Func, StatusOrStatusWith<T>>&& + isFuturePolicy<Policy>) auto onCompletion(Policy policy, Func&& func) && noexcept { return wrap<Func, Status>( std::move(this->_impl).onCompletion(policy, std::forward<Func>(func))); } @@ -441,9 +442,9 @@ public: * The callback takes a non-OK Status and returns a possibly-wrapped T (see above for how * Statusy and Futurey returns are handled.) */ - TEMPLATE(typename Policy, typename Func) - REQUIRES(future_details::isCallableR<T, Func, Status>&& isFuturePolicy<Policy>) - /*see above*/ auto onError(Policy policy, Func&& func) && noexcept { + template <typename Policy, typename Func> + requires(future_details::isCallableR<T, Func, Status>&& isFuturePolicy<Policy>) auto onError( + Policy policy, Func&& func) && noexcept { return wrap<Func, Status>(std::move(this->_impl).onError(policy, std::forward<Func>(func))); } @@ -454,9 +455,9 @@ public: * The callback takes a non-OK Status and returns a possibly-wrapped T (see above for how * Statusy and Futurey returns are handled.) */ - TEMPLATE(ErrorCodes::Error code, typename Policy, typename Func) - REQUIRES(future_details::isCallableR<T, Func, Status>&& isFuturePolicy<Policy>) - /*see above*/ auto onError(Policy policy, Func&& func) && noexcept { + template <ErrorCodes::Error code, typename Policy, typename Func> + requires(future_details::isCallableR<T, Func, Status>&& isFuturePolicy<Policy>) auto onError( + Policy policy, Func&& func) && noexcept { return wrap<Func, Status>( std::move(this->_impl).template onError<code>(policy, std::forward<Func>(func))); } @@ -468,9 +469,10 @@ public: * The callback takes a non-OK Status and returns a possibly-wrapped T (see above for how * Statusy and Futurey returns are handled.) */ - TEMPLATE(ErrorCategory category, typename Policy, typename Func) - REQUIRES(future_details::isCallableR<T, Func, Status>&& isFuturePolicy<Policy>) - /*see above*/ auto onErrorCategory(Policy policy, Func&& func) && noexcept { + template <ErrorCategory category, typename Policy, typename Func> + requires(future_details::isCallableR<T, Func, Status>&& + isFuturePolicy<Policy>) auto onErrorCategory(Policy policy, + Func&& func) && noexcept { return wrap<Func, Status>( std::move(this->_impl) .template onErrorCategory<category>(policy, std::forward<Func>(func))); @@ -496,9 +498,9 @@ public: * * The callback takes a const T& and must return void. */ - TEMPLATE(typename Policy, typename Func) - REQUIRES(future_details::isCallableExactR<void, Func, const T>&& isFuturePolicy<Policy>) - Future<T> tap(Policy policy, Func&& func) && noexcept { + template <typename Policy, typename Func> + requires(future_details::isCallableExactR<void, Func, const T>&& isFuturePolicy<Policy>) + Future<T> tap(Policy policy, Func&& func) && noexcept { return Future<T>(std::move(this->_impl).tap(policy, std::forward<Func>(func))); } @@ -509,9 +511,9 @@ public: * * The callback takes a non-OK Status and must return void. */ - TEMPLATE(typename Policy, typename Func) - REQUIRES(future_details::isCallableExactR<void, Func, const Status>&& isFuturePolicy<Policy>) - Future<T> tapError(Policy policy, Func&& func) && noexcept { + template <typename Policy, typename Func> + requires(future_details::isCallableExactR<void, Func, const Status>&& isFuturePolicy<Policy>) + Future<T> tapError(Policy policy, Func&& func) && noexcept { return Future<T>(std::move(this->_impl).tapError(policy, std::forward<Func>(func))); } @@ -523,10 +525,9 @@ public: * * The callback takes a StatusOrStatusWith<T> and must return void. */ - TEMPLATE(typename Policy, typename Func) - REQUIRES(future_details::isCallableExactR<void, Func, const StatusOrStatusWith<T>>&& - isFuturePolicy<Policy>) - Future<T> tapAll(Policy policy, Func&& func) && noexcept { + template <typename Policy, typename Func> + requires(future_details::isCallableExactR<void, Func, const StatusOrStatusWith<T>>&& + isFuturePolicy<Policy>) Future<T> tapAll(Policy policy, Func&& func) && noexcept { return Future<T>(std::move(this->_impl).tapAll(policy, std::forward<Func>(func))); } @@ -541,50 +542,50 @@ public: * * TODO(SERVER-66126): Remove all tag-taking methods and associated default implementations. */ - TEMPLATE(typename Func) - REQUIRES(future_details::isCallableExactR<void, Func, StatusOrStatusWith<T>>) + template <typename Func> + requires future_details::isCallableExactR<void, Func, StatusOrStatusWith<T>> void getAsync(Func&& func) && noexcept { std::move(*this).getAsync(destroyDefault, std::forward<Func>(func)); } - TEMPLATE(typename Func) - REQUIRES(future_details::isCallable<Func, T>) + template <typename Func> + requires future_details::isCallable<Func, T> auto then(Func&& func) && noexcept { return std::move(*this).then(destroyDefault, std::forward<Func>(func)); } - TEMPLATE(typename Func) - REQUIRES(future_details::isCallable<Func, StatusOrStatusWith<T>>) + template <typename Func> + requires future_details::isCallable<Func, StatusOrStatusWith<T>> auto onCompletion(Func&& func) && noexcept { return std::move(*this).onCompletion(destroyDefault, std::forward<Func>(func)); } - TEMPLATE(typename Func) - REQUIRES(future_details::isCallableR<T, Func, Status>) + template <typename Func> + requires future_details::isCallableR<T, Func, Status> auto onError(Func&& func) && noexcept { return std::move(*this).onError(destroyDefault, std::forward<Func>(func)); } - TEMPLATE(ErrorCodes::Error code, typename Func) - REQUIRES(future_details::isCallableR<T, Func, Status>) + template <ErrorCodes::Error code, typename Func> + requires future_details::isCallableR<T, Func, Status> auto onError(Func&& func) && noexcept { return std::move(*this).template onError<code>(destroyDefault, std::forward<Func>(func)); } - TEMPLATE(ErrorCategory category, typename Func) - REQUIRES(future_details::isCallableR<T, Func, Status>) + template <ErrorCategory category, typename Func> + requires future_details::isCallableR<T, Func, Status> auto onErrorCategory(Func&& func) && noexcept { return std::move(*this).template onErrorCategory<category>(destroyDefault, std::forward<Func>(func)); } - TEMPLATE(typename Func) - REQUIRES(future_details::isCallableExactR<void, Func, const T>) - Future<T> tap(Func&& func) && noexcept { + template <typename Func> + requires future_details::isCallableExactR<void, Func, const T> Future<T> tap( + Func&& func) && noexcept { return std::move(*this).tap(destroyDefault, std::forward<Func>(func)); } - TEMPLATE(typename Func) - REQUIRES(future_details::isCallableExactR<void, Func, const Status>) - Future<T> tapError(Func&& func) && noexcept { + template <typename Func> + requires future_details::isCallableExactR<void, Func, const Status> Future<T> tapError( + Func&& func) && noexcept { return std::move(*this).tapError(destroyDefault, std::forward<Func>(func)); } - TEMPLATE(typename Func) - REQUIRES(future_details::isCallableExactR<void, Func, const StatusOrStatusWith<T>>) - Future<T> tapAll(Func&& func) && noexcept { + template <typename Func> + requires future_details::isCallableExactR<void, Func, const StatusOrStatusWith<T>> Future<T> + tapAll(Func&& func) && noexcept { return std::move(*this).tapAll(destroyDefault, std::forward<Func>(func)); } @@ -607,9 +608,9 @@ private: }; // Deduction Guides -TEMPLATE(typename T) -REQUIRES(!isStatusOrStatusWith<T> && !future_details::isFutureLike<T>) -Future(T)->Future<T>; +template <typename T> +requires(!isStatusOrStatusWith<T> && !future_details::isFutureLike<T>) Future(T) +->Future<T>; template <typename T> Future(StatusWith<T>) -> Future<T>; @@ -649,7 +650,8 @@ public: static_assert(!std::is_void_v<T>); } - REQUIRES_FOR_NON_TEMPLATE(std::is_void_v<T>) + template <int...> + requires std::is_void_v<T> explicit ExecutorFuture(ExecutorPtr exec) : SemiFuture<void>(), _exec(std::move(exec)) {} /** @@ -690,10 +692,9 @@ public: * Attach a completion callback to asynchronously consume this `ExecutorFuture`'s result. * \see `Future<T>::getAsync()`. */ - TEMPLATE(typename Policy, typename Func) - REQUIRES(future_details::isCallableExactR<void, Func, StatusOrStatusWith<T>>&& - isFuturePolicy<Policy>) - void getAsync(Policy policy, Func&& func) && noexcept { + template <typename Policy, typename Func> + requires(future_details::isCallableExactR<void, Func, StatusOrStatusWith<T>>&& + isFuturePolicy<Policy>) void getAsync(Policy policy, Func&& func) && noexcept { static_assert(std::is_void_v<decltype(func(std::declval<StatusOrStatusWith<T>>()))>, "func passed to getAsync must return void"); @@ -713,17 +714,17 @@ public: }); } - TEMPLATE(typename Policy, typename Func) - REQUIRES(future_details::isCallable<Func, T>&& isFuturePolicy<Policy>) - auto then(Policy policy, Func&& func) && noexcept { + template <typename Policy, typename Func> + requires(future_details::isCallable<Func, T>&& isFuturePolicy<Policy>) auto then( + Policy policy, Func&& func) && noexcept { return mongo::ExecutorFuture( std::move(_exec), std::move(this->_impl).then(policy, wrapCB<T>(policy, std::forward<Func>(func)))); } - TEMPLATE(typename Policy, typename Func) - REQUIRES(future_details::isCallable<Func, StatusOrStatusWith<T>>&& isFuturePolicy<Policy>) - auto onCompletion(Policy policy, Func&& func) && noexcept { + template <typename Policy, typename Func> + requires(future_details::isCallable<Func, StatusOrStatusWith<T>>&& + isFuturePolicy<Policy>) auto onCompletion(Policy policy, Func&& func) && noexcept { return mongo::ExecutorFuture( std::move(_exec), std::move(this->_impl) @@ -731,27 +732,27 @@ public: wrapCB<StatusOrStatusWith<T>>(policy, std::forward<Func>(func)))); } - TEMPLATE(typename Policy, typename Func) - REQUIRES(future_details::isCallableR<T, Func, Status>&& isFuturePolicy<Policy>) - ExecutorFuture<T> onError(Policy policy, Func&& func) && noexcept { + template <typename Policy, typename Func> + requires(future_details::isCallableR<T, Func, Status>&& isFuturePolicy<Policy>) + ExecutorFuture<T> onError(Policy policy, Func&& func) && noexcept { return mongo::ExecutorFuture( std::move(_exec), std::move(this->_impl) .onError(policy, wrapCB<Status>(policy, std::forward<Func>(func)))); } - TEMPLATE(ErrorCodes::Error code, typename Policy, typename Func) - REQUIRES(future_details::isCallableR<T, Func, Status>&& isFuturePolicy<Policy>) - ExecutorFuture<T> onError(Policy policy, Func&& func) && noexcept { + template <ErrorCodes::Error code, typename Policy, typename Func> + requires(future_details::isCallableR<T, Func, Status>&& isFuturePolicy<Policy>) + ExecutorFuture<T> onError(Policy policy, Func&& func) && noexcept { return mongo::ExecutorFuture( std::move(_exec), std::move(this->_impl) .template onError<code>(policy, wrapCB<Status>(policy, std::forward<Func>(func)))); } - TEMPLATE(ErrorCategory category, typename Policy, typename Func) - REQUIRES(future_details::isCallableR<T, Func, Status>&& isFuturePolicy<Policy>) - ExecutorFuture<T> onErrorCategory(Policy policy, Func&& func) && noexcept { + template <ErrorCategory category, typename Policy, typename Func> + requires(future_details::isCallableR<T, Func, Status>&& isFuturePolicy<Policy>) + ExecutorFuture<T> onErrorCategory(Policy policy, Func&& func) && noexcept { return mongo::ExecutorFuture( std::move(_exec), std::move(this->_impl) @@ -773,33 +774,33 @@ public: * * TODO(SERVER-66126): Remove all tag-taking methods and associated default implementations. */ - TEMPLATE(typename Func) - REQUIRES(future_details::isCallableExactR<void, Func, StatusOrStatusWith<T>>) + template <typename Func> + requires future_details::isCallableExactR<void, Func, StatusOrStatusWith<T>> void getAsync(Func&& func) && noexcept { std::move(*this).getAsync(destroyDefault, std::forward<Func>(func)); } - TEMPLATE(typename Func) - REQUIRES(future_details::isCallable<Func, T>) + template <typename Func> + requires future_details::isCallable<Func, T> auto then(Func&& func) && noexcept { return std::move(*this).then(destroyDefault, std::forward<Func>(func)); } - TEMPLATE(typename Func) - REQUIRES(future_details::isCallable<Func, StatusOrStatusWith<T>>) + template <typename Func> + requires future_details::isCallable<Func, StatusOrStatusWith<T>> auto onCompletion(Func&& func) && noexcept { return std::move(*this).onCompletion(destroyDefault, std::forward<Func>(func)); } - TEMPLATE(typename Func) - REQUIRES(future_details::isCallableR<T, Func, Status>) + template <typename Func> + requires future_details::isCallableR<T, Func, Status> auto onError(Func&& func) && noexcept { return std::move(*this).onError(destroyDefault, std::forward<Func>(func)); } - TEMPLATE(ErrorCodes::Error code, typename Func) - REQUIRES(future_details::isCallableR<T, Func, Status>) + template <ErrorCodes::Error code, typename Func> + requires future_details::isCallableR<T, Func, Status> auto onError(Func&& func) && noexcept { return std::move(*this).template onError<code>(destroyDefault, std::forward<Func>(func)); } - TEMPLATE(ErrorCategory category, typename Func) - REQUIRES(future_details::isCallableR<T, Func, Status>) + template <ErrorCategory category, typename Func> + requires future_details::isCallableR<T, Func, Status> auto onErrorCategory(Func&& func) && noexcept { return std::move(*this).template onErrorCategory<category>(destroyDefault, std::forward<Func>(func)); @@ -816,8 +817,8 @@ private: * Future<U>, then schedules a task on _exec to complete the associated promise with the result * of calling func with that argument. */ - TEMPLATE(typename RawArg, typename Policy, typename Func) - REQUIRES(isFuturePolicy<Policy>) + template <typename RawArg, typename Policy, typename Func> + requires isFuturePolicy<Policy> auto wrapCB(Policy policy, Func&& func) { // Have to take care to never put void in argument position, since that is a hard error. using Result = typename std::conditional_t<std::is_void_v<RawArg>, @@ -848,9 +849,10 @@ private: }; // Deduction Guides -TEMPLATE(typename T) -REQUIRES(!isStatusOrStatusWith<T> && !future_details::isFutureLike<T>) -ExecutorFuture(ExecutorPtr, T)->ExecutorFuture<T>; +template <typename T> +requires(!isStatusOrStatusWith<T> && !future_details::isFutureLike<T>) + ExecutorFuture(ExecutorPtr, T) +->ExecutorFuture<T>; template <typename T> ExecutorFuture(ExecutorPtr, future_details::FutureImpl<T>) -> ExecutorFuture<T>; template <typename T> @@ -928,13 +930,13 @@ public: * because this method will correctly propagate errors thrown from makeResult(), rather than * ErrorCodes::BrokenPromise. */ - TEMPLATE(typename Policy, typename Func) - REQUIRES(future_details::isCallableR<T, Func, void>&& isFuturePolicy<Policy>) - void setWith(Policy policy, Func&& func) noexcept { + template <typename Policy, typename Func> + requires(future_details ::isCallableR<T, Func, void>&& isFuturePolicy<Policy>) void setWith( + Policy policy, Func&& func) noexcept { setFrom(Future<void>::makeReady().then(policy, std::forward<Func>(func))); } - TEMPLATE(typename Func) - REQUIRES(future_details::isCallableR<T, Func, void>) + template <typename Func> + requires future_details::isCallableR<T, Func, void> void setWith(Func&& func) noexcept { setWith(destroyDefault, std::forward<Func>(func)); } @@ -962,16 +964,16 @@ public: } // Use emplaceValue(Args&&...) instead. - REQUIRES_FOR_NON_TEMPLATE(!std::is_void_v<T>) - void setFrom(T_unless_void val) noexcept = delete; + template <int...> + requires(!std::is_void_v<T>) void setFrom(T_unless_void val) noexcept = delete; // Use setError(Status) instead. - REQUIRES_FOR_NON_TEMPLATE(!std::is_void_v<T>) - void setFrom(Status) noexcept = delete; + template <int...> + requires(!std::is_void_v<T>) void setFrom(Status) noexcept = delete; - TEMPLATE(typename... Args) - REQUIRES(std::is_constructible_v<T, Args...> || (std::is_void_v<T> && sizeof...(Args) == 0)) - void emplaceValue(Args&&... args) noexcept { + template <typename... Args> + requires std::is_constructible_v<T, Args...> || + (std::is_void_v<T> && sizeof...(Args) == 0) void emplaceValue(Args&&... args) noexcept { setImpl([&](boost::intrusive_ptr<SharedStateT>&& sharedState) { sharedState->emplaceValue(std::forward<Args>(args)...); }); @@ -1167,9 +1169,9 @@ private: }; // Deduction Guides -TEMPLATE(typename T) -REQUIRES(!isStatusOrStatusWith<T> && !future_details::isFutureLike<T>) -SharedSemiFuture(T)->SharedSemiFuture<T>; +template <typename T> +requires(!isStatusOrStatusWith<T> && !future_details::isFutureLike<T>) SharedSemiFuture(T) +->SharedSemiFuture<T>; template <typename T> SharedSemiFuture(StatusWith<T>) -> SharedSemiFuture<T>; @@ -1221,13 +1223,13 @@ public: return SharedSemiFuture<T>(_sharedState); } - TEMPLATE(typename Policy, typename Func) - REQUIRES(future_details::isCallableR<T, Func, void>&& isFuturePolicy<Policy>) - void setWith(Policy policy, Func&& func) noexcept { + template <typename Policy, typename Func> + requires(future_details::isCallableR<T, Func, void>&& isFuturePolicy<Policy>) void setWith( + Policy policy, Func&& func) noexcept { setFrom(Future<void>::makeReady().then(policy, std::forward<Func>(func))); } - TEMPLATE(typename Func) - REQUIRES(future_details::isCallableR<T, Func, void>) + template <typename Func> + requires future_details::isCallableR<T, Func, void> void setWith(Func&& func) noexcept { setWith(destroyDefault, std::forward<Func>(func)); } @@ -1252,16 +1254,17 @@ public: } // Use emplaceValue(Args&&...) instead. - REQUIRES_FOR_NON_TEMPLATE(!std::is_void_v<T>) - void setFrom(T_unless_void val) noexcept = delete; + template <int...> + requires(!std ::is_void_v<T>) void setFrom(T_unless_void val) noexcept = delete; // Use setError(Status) instead. - REQUIRES_FOR_NON_TEMPLATE(!std::is_void_v<T>) - void setFrom(Status) noexcept = delete; + template <int...> + requires(!std ::is_void_v<T>) void setFrom(Status) noexcept = delete; - TEMPLATE(typename... Args) - REQUIRES(std::is_constructible_v<T, Args...> || (std::is_void_v<T> && sizeof...(Args) == 0)) - void emplaceValue(Args&&... args) noexcept { + template <typename... Args> + requires(std::is_constructible_v<T, Args...> || + (std::is_void_v<T> && + sizeof...(Args) == 0)) void emplaceValue(Args&&... args) noexcept { invariant(!std::exchange(_haveCompleted, true)); _sharedState->emplaceValue(std::forward<Args>(args)...); } @@ -1341,8 +1344,8 @@ auto coerceToFuture(T&& value) { * * Note that if func returns an unready Future, this function will not block until it is ready. */ -TEMPLATE(typename Func) -REQUIRES(future_details::isCallable<Func, void>) +template <typename Func> +requires future_details::isCallable<Func, void> auto makeReadyFutureWith(Func&& func) -> Future<FutureContinuationResult<Func&&>> try { if constexpr (std::is_void_v<std::invoke_result_t<Func>>) { std::forward<Func>(func)(); diff --git a/src/mongo/util/future_impl.h b/src/mongo/util/future_impl.h index 940199e975c..1d825db5628 100644 --- a/src/mongo/util/future_impl.h +++ b/src/mongo/util/future_impl.h @@ -641,7 +641,8 @@ struct SharedStateImpl final : SharedStateBase { } } - REQUIRES_FOR_NON_TEMPLATE(std::is_same_v<T, FakeVoid>) + template <int...> + requires std::is_same_v<T, FakeVoid> void setFrom(Status status) { if (status.isOK()) { emplaceValue(); @@ -942,8 +943,8 @@ public: return _shared.getNoThrow(interruptible); } - TEMPLATE(typename Policy, typename Func) - REQUIRES(isFuturePolicy<Policy>) + template <typename Policy, typename Func> + requires isFuturePolicy<Policy> void getAsync(Policy policy, Func&& func) && noexcept { static_assert(std::is_void<decltype(call(func, std::declval<StatusWith<T>>()))>::value, "func passed to getAsync must return void"); @@ -967,8 +968,8 @@ public: }); } - TEMPLATE(typename Policy, typename Func) - REQUIRES(isFuturePolicy<Policy>) + template <typename Policy, typename Func> + requires isFuturePolicy<Policy> auto then(Policy policy, Func&& func) && noexcept { using Result = NormalizedCallResult<Func, T>; if constexpr (!isFutureLike<Result>) { @@ -1025,8 +1026,8 @@ public: } } - TEMPLATE(typename Policy, typename Func) - REQUIRES(isFuturePolicy<Policy>) + template <typename Policy, typename Func> + requires isFuturePolicy<Policy> auto onCompletion(Policy policy, Func&& func) && noexcept { using Wrapper = StatusOrStatusWith<T>; using Result = NormalizedCallResult<Func, StatusOrStatusWith<T>>; @@ -1103,9 +1104,9 @@ public: } } - TEMPLATE(typename Policy, typename Func) - REQUIRES(isFuturePolicy<Policy>) - FutureImpl<FakeVoidToVoid<T>> onError(Policy policy, Func&& func) && noexcept { + template <typename Policy, typename Func> + requires isFuturePolicy<Policy> FutureImpl<FakeVoidToVoid<T>> onError(Policy policy, + Func&& func) && noexcept { using Result = NormalizedCallResult<Func, Status>; static_assert( std::is_same<VoidToFakeVoid<UnwrappedType<Result>>, T>::value, @@ -1160,9 +1161,9 @@ public: } } - TEMPLATE(ErrorCodes::Error code, typename Policy, typename Func) - REQUIRES(isFuturePolicy<Policy>) - FutureImpl<FakeVoidToVoid<T>> onError(Policy policy, Func&& func) && noexcept { + template <ErrorCodes::Error code, typename Policy, typename Func> + requires isFuturePolicy<Policy> FutureImpl<FakeVoidToVoid<T>> onError(Policy policy, + Func&& func) && noexcept { using Result = NormalizedCallResult<Func, Status>; static_assert( std::is_same_v<UnwrappedType<Result>, FakeVoidToVoid<T>>, @@ -1181,9 +1182,9 @@ public: }); } - TEMPLATE(ErrorCategory category, typename Policy, typename Func) - REQUIRES(isFuturePolicy<Policy>) - FutureImpl<FakeVoidToVoid<T>> onErrorCategory(Policy policy, Func&& func) && noexcept { + template <ErrorCategory category, typename Policy, typename Func> + requires isFuturePolicy<Policy> FutureImpl<FakeVoidToVoid<T>> onErrorCategory( + Policy policy, Func&& func) && noexcept { using Result = NormalizedCallResult<Func, Status>; static_assert(std::is_same_v<UnwrappedType<Result>, FakeVoidToVoid<T>>, "func passed to Future<T>::onErrorCategory must return T, StatusWith<T>, " @@ -1200,9 +1201,9 @@ public: }); } - TEMPLATE(typename Policy, typename Func) - REQUIRES(isFuturePolicy<Policy>) - FutureImpl<FakeVoidToVoid<T>> tap(Policy policy, Func&& func) && noexcept { + template <typename Policy, typename Func> + requires isFuturePolicy<Policy> FutureImpl<FakeVoidToVoid<T>> tap(Policy policy, + Func&& func) && noexcept { static_assert(std::is_void<decltype(call(func, std::declval<const T&>()))>::value, "func passed to tap must return void"); @@ -1212,9 +1213,9 @@ public: [](Func&& failFunc, const Status& status) noexcept {}); } - TEMPLATE(typename Policy, typename Func) - REQUIRES(isFuturePolicy<Policy>) - FutureImpl<FakeVoidToVoid<T>> tapError(Policy policy, Func&& func) && noexcept { + template <typename Policy, typename Func> + requires isFuturePolicy<Policy> FutureImpl<FakeVoidToVoid<T>> tapError( + Policy policy, Func&& func) && noexcept { static_assert(std::is_void<decltype(call(func, std::declval<const Status&>()))>::value, "func passed to tapError must return void"); @@ -1224,9 +1225,9 @@ public: [](Func&& failFunc, const Status& status) noexcept { call(failFunc, status); }); } - TEMPLATE(typename Policy, typename Func) - REQUIRES(isFuturePolicy<Policy>) - FutureImpl<FakeVoidToVoid<T>> tapAll(Policy policy, Func&& func) && noexcept { + template <typename Policy, typename Func> + requires isFuturePolicy<Policy> FutureImpl<FakeVoidToVoid<T>> tapAll(Policy policy, + Func&& func) && noexcept { static_assert( std::is_void<decltype(call(func, std::declval<const StatusOrStatusWith<T>&>()))>::value, "func passed to tapAll must return void"); diff --git a/src/mongo/util/future_test_promise_int.cpp b/src/mongo/util/future_test_promise_int.cpp index 38bc194688c..d710691abfa 100644 --- a/src/mongo/util/future_test_promise_int.cpp +++ b/src/mongo/util/future_test_promise_int.cpp @@ -34,7 +34,6 @@ #include "mongo/stdx/thread.h" #include "mongo/unittest/death_test.h" #include "mongo/unittest/unittest.h" -#include "mongo/util/concepts.h" #include "mongo/util/future_test_utils.h" diff --git a/src/mongo/util/future_test_utils.h b/src/mongo/util/future_test_utils.h index c1695c3e392..6608b254193 100644 --- a/src/mongo/util/future_test_utils.h +++ b/src/mongo/util/future_test_utils.h @@ -34,7 +34,6 @@ #include "mongo/stdx/thread.h" #include "mongo/unittest/death_test.h" #include "mongo/unittest/unittest.h" -#include "mongo/util/concepts.h" #include "mongo/util/executor_test_util.h" #if !defined(__has_feature) diff --git a/src/mongo/util/future_util.h b/src/mongo/util/future_util.h index 5753a3d74e5..eb713f3da39 100644 --- a/src/mongo/util/future_util.h +++ b/src/mongo/util/future_util.h @@ -495,11 +495,11 @@ public: * error as soon as any input future is set with an error. The resulting vector contains the results * of all of the input futures in the same order in which they were provided. */ -TEMPLATE(typename FutureLike, - typename Value = typename FutureLike::value_type, - typename ResultVector = std::vector<Value>) -REQUIRES(!std::is_void_v<Value> && future_util_details::isFutureOrExecutorFuture<FutureLike>) -SemiFuture<ResultVector> whenAllSucceed(std::vector<FutureLike>&& futures) { +template <typename FutureLike, + typename Value = typename FutureLike::value_type, + typename ResultVector = std::vector<Value>> +requires(!std::is_void_v<Value> && future_util_details::isFutureOrExecutorFuture<FutureLike>) + SemiFuture<ResultVector> whenAllSucceed(std::vector<FutureLike>&& futures) { invariant(futures.size() > 0, future_util_details::kWhenAllSucceedEmptyInputInvariantMsg); // A structure used to share state between the input futures. @@ -559,9 +559,9 @@ SemiFuture<ResultVector> whenAllSucceed(std::vector<FutureLike>&& futures) { * Variant of whenAllSucceed for void input futures. The only behavior difference is that it returns * SemiFuture<void> instead of SemiFuture<std::vector<T>>. */ -TEMPLATE(typename FutureLike, typename Value = typename FutureLike::value_type) -REQUIRES(std::is_void_v<Value>&& future_util_details::isFutureOrExecutorFuture<FutureLike>) -SemiFuture<void> whenAllSucceed(std::vector<FutureLike>&& futures) { +template <typename FutureLike, typename Value = typename FutureLike::value_type> +requires(std::is_void_v<Value>&& future_util_details::isFutureOrExecutorFuture<FutureLike>) + SemiFuture<void> whenAllSucceed(std::vector<FutureLike>&& futures) { invariant(futures.size() > 0, future_util_details::kWhenAllSucceedEmptyInputInvariantMsg); // A structure used to share state between the input futures. @@ -714,11 +714,11 @@ SemiFuture<Result> whenAny(std::vector<FutureT>&& futures) { * we peel off the first element of each input list in order to assist the compiler in type * inference and to prevent 0 length lists from compiling. */ -TEMPLATE(typename... FuturePack, - typename FutureLike = std::common_type_t<FuturePack...>, - typename Value = typename FutureLike::value_type, - typename ResultVector = std::vector<Value>) -REQUIRES(future_util_details::isFutureOrExecutorFuture<FutureLike>) +template <typename... FuturePack, + typename FutureLike = std::common_type_t<FuturePack...>, + typename Value = typename FutureLike::value_type, + typename ResultVector = std::vector<Value>> +requires future_util_details::isFutureOrExecutorFuture<FutureLike> auto whenAllSucceed(FuturePack&&... futures) { return whenAllSucceed( future_util_details::variadicArgsToVector(std::forward<FuturePack>(futures)...)); diff --git a/src/mongo/util/interruptible.h b/src/mongo/util/interruptible.h index 1e9cc070c64..d7ffefcc3f6 100644 --- a/src/mongo/util/interruptible.h +++ b/src/mongo/util/interruptible.h @@ -33,7 +33,6 @@ #include "mongo/platform/mutex.h" #include "mongo/stdx/condition_variable.h" -#include "mongo/util/concepts.h" #include "mongo/util/lockable_adapter.h" #include "mongo/util/scopeguard.h" #include "mongo/util/time_support.h" @@ -255,8 +254,8 @@ public: /** * Get the name for a Latch */ - TEMPLATE(typename LatchT) - REQUIRES(std::is_base_of_v<latch_detail::Latch, LatchT>) // + template <typename LatchT> + requires std::is_base_of_v<latch_detail::Latch, LatchT> static StringData getLatchName(const stdx::unique_lock<LatchT>& lk) { return lk.mutex()->getName(); } diff --git a/src/mongo/util/invalidating_lru_cache.h b/src/mongo/util/invalidating_lru_cache.h index 6acde61f6c0..df82059d0f6 100644 --- a/src/mongo/util/invalidating_lru_cache.h +++ b/src/mongo/util/invalidating_lru_cache.h @@ -432,10 +432,9 @@ public: * it could still get evicted if the cache is under pressure. The returned handle must be * destroyed before the owning cache object itself is destroyed. */ - TEMPLATE(typename KeyType) - REQUIRES(IsComparable<KeyType>) - ValueHandle get( - const KeyType& key, + template <typename KeyType> + requires IsComparable<KeyType> ValueHandle + get(const KeyType& key, CacheCausalConsistency causalConsistency = CacheCausalConsistency::kLatestCached) { stdx::lock_guard<Latch> lg(_mutex); std::shared_ptr<StoredValue> storedValue; @@ -492,8 +491,8 @@ public: * Returns true if the passed 'newTimeInStore' is grater than the time of the currently cached * value or if no value is cached for 'key'. */ - TEMPLATE(typename KeyType) - REQUIRES(IsComparable<KeyType>) + template <typename KeyType> + requires IsComparable<KeyType> bool advanceTimeInStore(const KeyType& key, const Time& newTimeInStore) { stdx::lock_guard<Latch> lg(_mutex); std::shared_ptr<StoredValue> storedValue; @@ -522,9 +521,9 @@ public: * which can either be from the time of insertion or from the latest call to * 'advanceTimeInStore'. Otherwise, returns a nullptr ValueHandle and Time(). */ - TEMPLATE(typename KeyType) - REQUIRES(IsComparable<KeyType>) - std::pair<ValueHandle, Time> getCachedValueAndTimeInStore(const KeyType& key) { + template <typename KeyType> + requires IsComparable<KeyType> std::pair<ValueHandle, Time> getCachedValueAndTimeInStore( + const KeyType& key) { stdx::lock_guard<Latch> lg(_mutex); std::shared_ptr<StoredValue> storedValue; if (auto it = _cache.find(key); it != _cache.end()) { @@ -548,8 +547,8 @@ public: * Any already returned ValueHandles will start returning isValid = false. Subsequent calls to * 'get' will *not* return value for 'key' until the next call to 'insertOrAssign'. */ - TEMPLATE(typename KeyType) - REQUIRES(IsComparable<KeyType>) + template <typename KeyType> + requires IsComparable<KeyType> void invalidate(const KeyType& key) { LockGuardWithPostUnlockDestructor guard(_mutex); _invalidate(&guard, key, _cache.find(key)); @@ -641,8 +640,8 @@ private: * the key may not exist, and after this call will no longer be valid and will not be in either * of the maps. */ - TEMPLATE(typename KeyType) - REQUIRES(IsComparable<KeyType>) + template <typename KeyType> + requires IsComparable<KeyType> void _invalidate(LockGuardWithPostUnlockDestructor* guard, const KeyType& key, typename Cache::iterator it, diff --git a/src/mongo/util/lru_cache.h b/src/mongo/util/lru_cache.h index bdcc5e68a7f..f724e22eea9 100644 --- a/src/mongo/util/lru_cache.h +++ b/src/mongo/util/lru_cache.h @@ -138,9 +138,8 @@ public: /** * Finds an element in the cache by key. */ - TEMPLATE(typename KeyType) - REQUIRES(IsComparable<KeyType>) - iterator find(const KeyType& key) { + template <typename KeyType> + requires IsComparable<KeyType> iterator find(const KeyType& key) { return promote(key); } @@ -153,9 +152,9 @@ public: * the find(...) method above will prevent the LRUCache from functioning * properly. */ - TEMPLATE(typename KeyType) - REQUIRES(IsComparable<KeyType>) - const_iterator cfind(const KeyType& key) const { + template <typename KeyType> + requires IsComparable<KeyType> const_iterator cfind(const KeyType& key) + const { auto it = _map.find(key); return (it == _map.end()) ? end() : const_iterator(it->second); } @@ -164,9 +163,8 @@ public: * Promotes the element matching the given key, if one exists in the cache, * to the least recently used element. */ - TEMPLATE(typename KeyType) - REQUIRES(IsComparable<KeyType>) - iterator promote(const KeyType& key) { + template <typename KeyType> + requires IsComparable<KeyType> iterator promote(const KeyType& key) { auto it = _map.find(key); return (it == _map.end()) ? end() : promote(it->second); } @@ -201,8 +199,8 @@ public: * Removes the element in the cache stored for this key, if one * exists. Returns the count of elements erased. */ - TEMPLATE(typename KeyType) - REQUIRES(IsComparable<KeyType>) + template <typename KeyType> + requires IsComparable<KeyType> typename Map::size_type erase(const KeyType& key) { auto it = _map.find(key); if (it == _map.end()) { @@ -237,8 +235,8 @@ public: * If the given key has a matching element stored in the cache, returns true. * Otherwise, returns false. */ - TEMPLATE(typename KeyType) - REQUIRES(IsComparable<KeyType>) + template <typename KeyType> + requires IsComparable<KeyType> bool hasKey(const KeyType& key) const { return _map.find(key) != _map.end(); } @@ -296,8 +294,8 @@ public: return _list.cend(); } - TEMPLATE(typename KeyType) - REQUIRES(IsComparable<KeyType>) + template <typename KeyType> + requires IsComparable<KeyType> typename Map::size_type count(const KeyType& key) const { return _map.count(key); } diff --git a/src/mongo/util/read_through_cache.h b/src/mongo/util/read_through_cache.h index 3ed61e98e39..d3dcdbfece4 100644 --- a/src/mongo/util/read_through_cache.h +++ b/src/mongo/util/read_through_cache.h @@ -250,11 +250,11 @@ public: * The returned value may be invalid by the time the caller gets to access it, if 'invalidate' * is called for 'key'. */ - TEMPLATE(typename KeyType) - REQUIRES(IsComparable<KeyType>&& std::is_constructible_v<Key, KeyType>) - SharedSemiFuture<ValueHandle> acquireAsync( - const KeyType& key, - CacheCausalConsistency causalConsistency = CacheCausalConsistency::kLatestCached) { + template <typename KeyType> + requires(IsComparable<KeyType>&& std::is_constructible_v<Key, KeyType>) + SharedSemiFuture<ValueHandle> acquireAsync( + const KeyType& key, + CacheCausalConsistency causalConsistency = CacheCausalConsistency::kLatestCached) { // Fast path if (auto cachedValue = _cache.get(key, causalConsistency)) @@ -294,12 +294,11 @@ public: * NOTES: * This is a potentially blocking method. */ - TEMPLATE(typename KeyType) - REQUIRES(IsComparable<KeyType>) - ValueHandle acquire( - OperationContext* opCtx, - const KeyType& key, - CacheCausalConsistency causalConsistency = CacheCausalConsistency::kLatestCached) { + template <typename KeyType> + requires IsComparable<KeyType> ValueHandle + acquire(OperationContext* opCtx, + const KeyType& key, + CacheCausalConsistency causalConsistency = CacheCausalConsistency::kLatestCached) { return acquireAsync(key, causalConsistency).get(opCtx); } @@ -310,9 +309,8 @@ public: * Doesn't attempt to lookup, and so doesn't block, but this means it will ignore any * in-progress keys or keys whose time in store is newer than what is currently cached. */ - TEMPLATE(typename KeyType) - REQUIRES(IsComparable<KeyType>) - ValueHandle peekLatestCached(const KeyType& key) { + template <typename KeyType> + requires IsComparable<KeyType> ValueHandle peekLatestCached(const KeyType& key) { return {_cache.get(key, CacheCausalConsistency::kLatestCached)}; } @@ -401,8 +399,8 @@ public: * Returns true if the passed 'newTimeInStore' is greater than the time of the currently cached * value or if no value is cached for 'key'. */ - TEMPLATE(typename KeyType) - REQUIRES(IsComparable<KeyType>) + template <typename KeyType> + requires IsComparable<KeyType> bool advanceTimeInStore(const KeyType& key, const Time& newTime) { stdx::lock_guard lg(_mutex); if (auto it = _inProgressLookups.find(key); it != _inProgressLookups.end()) @@ -421,8 +419,8 @@ public: * In essence, the invalidate+ calls serve as an externally induced "barrier" for the affected * keys. */ - TEMPLATE(typename KeyType) - REQUIRES(IsComparable<KeyType>) + template <typename KeyType> + requires IsComparable<KeyType> void invalidateKey(const KeyType& key) { stdx::lock_guard lg(_mutex); if (auto it = _inProgressLookups.find(key); it != _inProgressLookups.end()) diff --git a/src/mongo/util/registry_list.h b/src/mongo/util/registry_list.h index f451cb78a46..26db8b9b04d 100644 --- a/src/mongo/util/registry_list.h +++ b/src/mongo/util/registry_list.h @@ -33,7 +33,6 @@ #include <memory> #include "mongo/stdx/mutex.h" -#include "mongo/util/concepts.h" namespace mongo { @@ -87,8 +86,8 @@ private: * This class does no lifetime management for its elements besides construction and destruction. If * you use it to store pointers, the pointed-to memory should be immortal. */ -TEMPLATE(typename ElementT) -REQUIRES(std::is_default_constructible_v<ElementT>) +template <typename ElementT> +requires std::is_default_constructible_v<ElementT> class RegistryList { public: using ElementType = ElementT; @@ -159,8 +158,8 @@ private: /** * Wrap the basic RegistryList concept to handle weak_ptrs */ -TEMPLATE(typename T) -REQUIRES(std::is_constructible_v<std::weak_ptr<T>>) +template <typename T> +requires std::is_constructible_v<std::weak_ptr<T>> class WeakPtrRegistryList : public RegistryList<std::weak_ptr<T>> { public: using ElementType = std::weak_ptr<T>; |