Commit 0b49f8af by Derek Mauro Committed by Copybara-Service

Mutex: Remove MSVC 2015 workarounds

PiperOrigin-RevId: 526653332
Change-Id: I0a20d4ac636da3f1a930f96e0cdb9275527e4688
parent 8bd7178b
...@@ -695,6 +695,20 @@ class Condition { ...@@ -695,6 +695,20 @@ class Condition {
template<typename T> template<typename T>
Condition(bool (*func)(T *), T *arg); Condition(bool (*func)(T *), T *arg);
// Same as above, but allows for cases where `arg` comes from a pointer that
// is convertible to the function parameter type `T*` but not an exact match.
//
// For example, the argument might be `X*` but the function takes `const X*`,
// or the argument might be `Derived*` while the function takes `Base*`, and
// so on for cases where the argument pointer can be implicitly converted.
//
// Implementation notes: This constructor overload is required in addition to
// the one above to allow deduction of `T` from `arg` for cases such as where
// a function template is passed as `func`. Also, the dummy `typename = void`
// template parameter exists just to work around a MSVC mangling bug.
template <typename T, typename = void>
Condition(bool (*func)(T *), typename absl::internal::identity<T>::type *arg);
// Templated version for invoking a method that returns a `bool`. // Templated version for invoking a method that returns a `bool`.
// //
// `Condition(object, &Class::Method)` constructs a `Condition` that evaluates // `Condition(object, &Class::Method)` constructs a `Condition` that evaluates
...@@ -1023,6 +1037,12 @@ inline Condition::Condition(bool (*func)(T *), T *arg) ...@@ -1023,6 +1037,12 @@ inline Condition::Condition(bool (*func)(T *), T *arg)
StoreCallback(func); StoreCallback(func);
} }
template <typename T, typename>
inline Condition::Condition(bool (*func)(T *),
typename absl::internal::identity<T>::type *arg)
// Just delegate to the overload above.
: Condition(func, arg) {}
template <typename T> template <typename T>
inline Condition::Condition(T *object, inline Condition::Condition(T *object,
bool (absl::internal::identity<T>::type::*method)()) bool (absl::internal::identity<T>::type::*method)())
......
...@@ -872,6 +872,111 @@ TEST(Mutex, LockedMutexDestructionBug) ABSL_NO_THREAD_SAFETY_ANALYSIS { ...@@ -872,6 +872,111 @@ TEST(Mutex, LockedMutexDestructionBug) ABSL_NO_THREAD_SAFETY_ANALYSIS {
} }
} }
// Some functions taking pointers to non-const.
bool Equals42(int *p) { return *p == 42; }
bool Equals43(int *p) { return *p == 43; }
// Some functions taking pointers to const.
bool ConstEquals42(const int *p) { return *p == 42; }
bool ConstEquals43(const int *p) { return *p == 43; }
// Some function templates taking pointers. Note it's possible for `T` to be
// deduced as non-const or const, which creates the potential for ambiguity,
// but which the implementation is careful to avoid.
template <typename T>
bool TemplateEquals42(T *p) {
return *p == 42;
}
template <typename T>
bool TemplateEquals43(T *p) {
return *p == 43;
}
TEST(Mutex, FunctionPointerCondition) {
// Some arguments.
int x = 42;
const int const_x = 42;
// Parameter non-const, argument non-const.
EXPECT_TRUE(absl::Condition(Equals42, &x).Eval());
EXPECT_FALSE(absl::Condition(Equals43, &x).Eval());
// Parameter const, argument non-const.
EXPECT_TRUE(absl::Condition(ConstEquals42, &x).Eval());
EXPECT_FALSE(absl::Condition(ConstEquals43, &x).Eval());
// Parameter const, argument const.
EXPECT_TRUE(absl::Condition(ConstEquals42, &const_x).Eval());
EXPECT_FALSE(absl::Condition(ConstEquals43, &const_x).Eval());
// Parameter type deduced, argument non-const.
EXPECT_TRUE(absl::Condition(TemplateEquals42, &x).Eval());
EXPECT_FALSE(absl::Condition(TemplateEquals43, &x).Eval());
// Parameter type deduced, argument const.
EXPECT_TRUE(absl::Condition(TemplateEquals42, &const_x).Eval());
EXPECT_FALSE(absl::Condition(TemplateEquals43, &const_x).Eval());
// Parameter non-const, argument const is not well-formed.
EXPECT_FALSE((std::is_constructible<absl::Condition, decltype(Equals42),
decltype(&const_x)>::value));
// Validate use of is_constructible by contrasting to a well-formed case.
EXPECT_TRUE((std::is_constructible<absl::Condition, decltype(ConstEquals42),
decltype(&const_x)>::value));
}
// Example base and derived class for use in predicates and test below. Not a
// particularly realistic example, but it suffices for testing purposes.
struct Base {
explicit Base(int v) : value(v) {}
int value;
};
struct Derived : Base {
explicit Derived(int v) : Base(v) {}
};
// Some functions taking pointer to non-const `Base`.
bool BaseEquals42(Base *p) { return p->value == 42; }
bool BaseEquals43(Base *p) { return p->value == 43; }
// Some functions taking pointer to const `Base`.
bool ConstBaseEquals42(const Base *p) { return p->value == 42; }
bool ConstBaseEquals43(const Base *p) { return p->value == 43; }
TEST(Mutex, FunctionPointerConditionWithDerivedToBaseConversion) {
// Some arguments.
Derived derived(42);
const Derived const_derived(42);
// Parameter non-const base, argument derived non-const.
EXPECT_TRUE(absl::Condition(BaseEquals42, &derived).Eval());
EXPECT_FALSE(absl::Condition(BaseEquals43, &derived).Eval());
// Parameter const base, argument derived non-const.
EXPECT_TRUE(absl::Condition(ConstBaseEquals42, &derived).Eval());
EXPECT_FALSE(absl::Condition(ConstBaseEquals43, &derived).Eval());
// Parameter const base, argument derived const.
EXPECT_TRUE(absl::Condition(ConstBaseEquals42, &const_derived).Eval());
EXPECT_FALSE(absl::Condition(ConstBaseEquals43, &const_derived).Eval());
// Parameter const base, argument derived const.
EXPECT_TRUE(absl::Condition(ConstBaseEquals42, &const_derived).Eval());
EXPECT_FALSE(absl::Condition(ConstBaseEquals43, &const_derived).Eval());
// Parameter derived, argument base is not well-formed.
bool (*derived_pred)(const Derived *) = [](const Derived *) { return true; };
EXPECT_FALSE((std::is_constructible<absl::Condition, decltype(derived_pred),
Base *>::value));
EXPECT_FALSE((std::is_constructible<absl::Condition, decltype(derived_pred),
const Base *>::value));
// Validate use of is_constructible by contrasting to well-formed cases.
EXPECT_TRUE((std::is_constructible<absl::Condition, decltype(derived_pred),
Derived *>::value));
EXPECT_TRUE((std::is_constructible<absl::Condition, decltype(derived_pred),
const Derived *>::value));
}
struct True { struct True {
template <class... Args> template <class... Args>
bool operator()(Args...) const { bool operator()(Args...) const {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment