Commit 2aa9fa87 authored by Jan Wilken Dörrie's avatar Jan Wilken Dörrie Committed by Commit Bot

[base] Add base/functional folder

This change adds a new base/functional/ folder and moves base::invoke
and base::identity from base/stl_util.h to the new location.

Bug: None
Change-Id: I98cb577b5154561c82d41bfb7dc23e0ff9abee27
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2494923
Commit-Queue: Jan Wilken Dörrie <jdoerrie@chromium.org>
Reviewed-by: default avatarDaniel Cheng <dcheng@chromium.org>
Reviewed-by: default avatardanakj <danakj@chromium.org>
Cr-Commit-Position: refs/heads/master@{#822124}
parent 1a201c94
......@@ -260,6 +260,8 @@ component("base") {
"files/scoped_temp_dir.cc",
"files/scoped_temp_dir.h",
"format_macros.h",
"functional/identity.h",
"functional/invoke.h",
"gtest_prod_util.h",
"guid.cc",
"guid.h",
......@@ -2739,6 +2741,8 @@ test("base_unittests") {
"files/important_file_writer_unittest.cc",
"files/memory_mapped_file_unittest.cc",
"files/scoped_temp_dir_unittest.cc",
"functional/identity_unittest.cc",
"functional/invoke_unittest.cc",
"gmock_unittest.cc",
"guid_unittest.cc",
"hash/hash_unittest.cc",
......
# base/functional library
[TOC]
## What goes here
This directory contains function objects from future STL versions and closely
related types.
Things should be moved here that are generally applicable across the code base.
Don't add things here just because you need them in one place and think others
may someday want something similar. You can put specialized function objects in
your component's directory and we can promote them here later if we feel there
is broad applicability.
### Design and naming
Fundamental [//base principles](../README.md#design-and-naming) apply, i.e.:
Function objects should either come directly from the STL or adhere as closely
to STL as possible. Functions and behaviors not present in STL should only be
added when they are related to the specific function objects.
For STL-like function objects our policy is that they should use STL-like naming
even when it may conflict with the style guide. So functions and class names
should be lower case with underscores. Non-STL-like classes and functions should
use Google naming. Be sure to use the base namespace.
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef BASE_FUNCTIONAL_IDENTITY_H_
#define BASE_FUNCTIONAL_IDENTITY_H_
#include <utility>
namespace base {
// Implementation of C++20's std::identity.
//
// Reference:
// - https://en.cppreference.com/w/cpp/utility/functional/identity
// - https://wg21.link/func.identity
struct identity {
template <typename T>
constexpr T&& operator()(T&& t) const noexcept {
return std::forward<T>(t);
}
using is_transparent = void;
};
} // namespace base
#endif // BASE_FUNCTIONAL_IDENTITY_H_
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/functional/identity.h"
#include <vector>
#include "testing/gtest/include/gtest/gtest.h"
namespace base {
TEST(FunctionalTest, Identity) {
static constexpr identity id;
std::vector<int> v;
EXPECT_EQ(&v, &id(v));
constexpr int arr = {0};
static_assert(arr == id(arr), "");
}
} // namespace base
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef BASE_FUNCTIONAL_INVOKE_H_
#define BASE_FUNCTIONAL_INVOKE_H_
#include <type_traits>
#include <utility>
namespace base {
namespace internal {
// Helper struct and alias to deduce the class type from a member function
// pointer or member object pointer.
template <typename DecayedF>
struct member_pointer_class {};
template <typename ReturnT, typename ClassT>
struct member_pointer_class<ReturnT ClassT::*> {
using type = ClassT;
};
template <typename DecayedF>
using member_pointer_class_t = typename member_pointer_class<DecayedF>::type;
// Utility struct to detect specializations of std::reference_wrapper.
template <typename T>
struct is_reference_wrapper : std::false_type {};
template <typename T>
struct is_reference_wrapper<std::reference_wrapper<T>> : std::true_type {};
// Small helpers used below in internal::invoke to make the SFINAE more concise.
template <typename F>
const bool& IsMemFunPtr =
std::is_member_function_pointer<std::decay_t<F>>::value;
template <typename F>
const bool& IsMemObjPtr = std::is_member_object_pointer<std::decay_t<F>>::value;
template <typename F,
typename T,
typename MemPtrClass = member_pointer_class_t<std::decay_t<F>>>
const bool& IsMemPtrToBaseOf =
std::is_base_of<MemPtrClass, std::decay_t<T>>::value;
template <typename T>
const bool& IsRefWrapper = is_reference_wrapper<std::decay_t<T>>::value;
template <bool B>
using EnableIf = std::enable_if_t<B, bool>;
// Invokes a member function pointer on a reference to an object of a suitable
// type. Covers bullet 1 of the INVOKE definition.
//
// Reference: https://wg21.link/func.require#1.1
template <typename F,
typename T1,
typename... Args,
EnableIf<IsMemFunPtr<F> && IsMemPtrToBaseOf<F, T1>> = true>
constexpr decltype(auto) InvokeImpl(F&& f, T1&& t1, Args&&... args) {
return (std::forward<T1>(t1).*f)(std::forward<Args>(args)...);
}
// Invokes a member function pointer on a std::reference_wrapper to an object of
// a suitable type. Covers bullet 2 of the INVOKE definition.
//
// Reference: https://wg21.link/func.require#1.2
template <typename F,
typename T1,
typename... Args,
EnableIf<IsMemFunPtr<F> && IsRefWrapper<T1>> = true>
constexpr decltype(auto) InvokeImpl(F&& f, T1&& t1, Args&&... args) {
return (t1.get().*f)(std::forward<Args>(args)...);
}
// Invokes a member function pointer on a pointer-like type to an object of a
// suitable type. Covers bullet 3 of the INVOKE definition.
//
// Reference: https://wg21.link/func.require#1.3
template <typename F,
typename T1,
typename... Args,
EnableIf<IsMemFunPtr<F> && !IsMemPtrToBaseOf<F, T1> &&
!IsRefWrapper<T1>> = true>
constexpr decltype(auto) InvokeImpl(F&& f, T1&& t1, Args&&... args) {
return ((*std::forward<T1>(t1)).*f)(std::forward<Args>(args)...);
}
// Invokes a member object pointer on a reference to an object of a suitable
// type. Covers bullet 4 of the INVOKE definition.
//
// Reference: https://wg21.link/func.require#1.4
template <typename F,
typename T1,
EnableIf<IsMemObjPtr<F> && IsMemPtrToBaseOf<F, T1>> = true>
constexpr decltype(auto) InvokeImpl(F&& f, T1&& t1) {
return std::forward<T1>(t1).*f;
}
// Invokes a member object pointer on a std::reference_wrapper to an object of
// a suitable type. Covers bullet 5 of the INVOKE definition.
//
// Reference: https://wg21.link/func.require#1.5
template <typename F,
typename T1,
EnableIf<IsMemObjPtr<F> && IsRefWrapper<T1>> = true>
constexpr decltype(auto) InvokeImpl(F&& f, T1&& t1) {
return t1.get().*f;
}
// Invokes a member object pointer on a pointer-like type to an object of a
// suitable type. Covers bullet 6 of the INVOKE definition.
//
// Reference: https://wg21.link/func.require#1.6
template <typename F,
typename T1,
EnableIf<IsMemObjPtr<F> && !IsMemPtrToBaseOf<F, T1> &&
!IsRefWrapper<T1>> = true>
constexpr decltype(auto) InvokeImpl(F&& f, T1&& t1) {
return (*std::forward<T1>(t1)).*f;
}
// Invokes a regular function or function object. Covers bullet 7 of the INVOKE
// definition.
//
// Reference: https://wg21.link/func.require#1.7
template <typename F, typename... Args>
constexpr decltype(auto) InvokeImpl(F&& f, Args&&... args) {
return std::forward<F>(f)(std::forward<Args>(args)...);
}
} // namespace internal
// Implementation of C++17's std::invoke. This is not based on implementation
// referenced in original std::invoke proposal, but rather a manual
// implementation, so that it can be constexpr.
//
// References:
// - https://wg21.link/n4169#implementability
// - https://en.cppreference.com/w/cpp/utility/functional/invoke
// - https://wg21.link/func.invoke
template <typename F, typename... Args>
constexpr decltype(auto) invoke(F&& f, Args&&... args) {
return internal::InvokeImpl(std::forward<F>(f), std::forward<Args>(args)...);
}
} // namespace base
#endif // BASE_FUNCTIONAL_INVOKE_H_
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/functional/invoke.h"
#include <functional>
#include "testing/gtest/include/gtest/gtest.h"
namespace base {
TEST(FunctionalTest, Invoke) {
struct S {
int i;
constexpr int add(int x) const { return i + x; }
};
constexpr S s = {1};
// Note: The tests involving a std::reference_wrapper are not static_asserts,
// since std::reference_wrapper is not constexpr prior to C++20.
static_assert(base::invoke(&S::add, s, 2) == 3, "");
EXPECT_EQ(base::invoke(&S::add, std::ref(s), 2), 3);
static_assert(base::invoke(&S::add, &s, 3) == 4, "");
static_assert(base::invoke(&S::i, s) == 1, "");
EXPECT_EQ(base::invoke(&S::i, std::ref(s)), 1);
static_assert(base::invoke(&S::i, &s) == 1, "");
static_assert(base::invoke(std::plus<>(), 1, 2) == 3, "");
}
} // namespace base
......@@ -11,9 +11,10 @@
#include <type_traits>
#include <utility>
#include "base/functional/identity.h"
#include "base/functional/invoke.h"
#include "base/ranges/functional.h"
#include "base/ranges/ranges.h"
#include "base/stl_util.h"
#include "base/template_util.h"
namespace base {
......
......@@ -171,157 +171,6 @@ constexpr std::add_const_t<T>& as_const(T& t) noexcept {
template <typename T>
void as_const(const T&& t) = delete;
namespace internal {
// Helper struct and alias to deduce the class type from a member function
// pointer or member object pointer.
template <typename DecayedF>
struct member_pointer_class {};
template <typename ReturnT, typename ClassT>
struct member_pointer_class<ReturnT ClassT::*> {
using type = ClassT;
};
template <typename DecayedF>
using member_pointer_class_t = typename member_pointer_class<DecayedF>::type;
// Utility struct to detect specializations of std::reference_wrapper.
template <typename T>
struct is_reference_wrapper : std::false_type {};
template <typename T>
struct is_reference_wrapper<std::reference_wrapper<T>> : std::true_type {};
// Small helpers used below in internal::invoke to make the SFINAE more concise.
template <typename F>
const bool& IsMemFunPtr =
std::is_member_function_pointer<std::decay_t<F>>::value;
template <typename F>
const bool& IsMemObjPtr = std::is_member_object_pointer<std::decay_t<F>>::value;
template <typename F,
typename T,
typename MemPtrClass = member_pointer_class_t<std::decay_t<F>>>
const bool& IsMemPtrToBaseOf =
std::is_base_of<MemPtrClass, std::decay_t<T>>::value;
template <typename T>
const bool& IsRefWrapper = is_reference_wrapper<std::decay_t<T>>::value;
template <bool B>
using EnableIf = std::enable_if_t<B, bool>;
// Invokes a member function pointer on a reference to an object of a suitable
// type. Covers bullet 1 of the INVOKE definition.
//
// Reference: https://wg21.link/func.require#1.1
template <typename F,
typename T1,
typename... Args,
EnableIf<IsMemFunPtr<F> && IsMemPtrToBaseOf<F, T1>> = true>
constexpr decltype(auto) InvokeImpl(F&& f, T1&& t1, Args&&... args) {
return (std::forward<T1>(t1).*f)(std::forward<Args>(args)...);
}
// Invokes a member function pointer on a std::reference_wrapper to an object of
// a suitable type. Covers bullet 2 of the INVOKE definition.
//
// Reference: https://wg21.link/func.require#1.2
template <typename F,
typename T1,
typename... Args,
EnableIf<IsMemFunPtr<F> && IsRefWrapper<T1>> = true>
constexpr decltype(auto) InvokeImpl(F&& f, T1&& t1, Args&&... args) {
return (t1.get().*f)(std::forward<Args>(args)...);
}
// Invokes a member function pointer on a pointer-like type to an object of a
// suitable type. Covers bullet 3 of the INVOKE definition.
//
// Reference: https://wg21.link/func.require#1.3
template <typename F,
typename T1,
typename... Args,
EnableIf<IsMemFunPtr<F> && !IsMemPtrToBaseOf<F, T1> &&
!IsRefWrapper<T1>> = true>
constexpr decltype(auto) InvokeImpl(F&& f, T1&& t1, Args&&... args) {
return ((*std::forward<T1>(t1)).*f)(std::forward<Args>(args)...);
}
// Invokes a member object pointer on a reference to an object of a suitable
// type. Covers bullet 4 of the INVOKE definition.
//
// Reference: https://wg21.link/func.require#1.4
template <typename F,
typename T1,
EnableIf<IsMemObjPtr<F> && IsMemPtrToBaseOf<F, T1>> = true>
constexpr decltype(auto) InvokeImpl(F&& f, T1&& t1) {
return std::forward<T1>(t1).*f;
}
// Invokes a member object pointer on a std::reference_wrapper to an object of
// a suitable type. Covers bullet 5 of the INVOKE definition.
//
// Reference: https://wg21.link/func.require#1.5
template <typename F,
typename T1,
EnableIf<IsMemObjPtr<F> && IsRefWrapper<T1>> = true>
constexpr decltype(auto) InvokeImpl(F&& f, T1&& t1) {
return t1.get().*f;
}
// Invokes a member object pointer on a pointer-like type to an object of a
// suitable type. Covers bullet 6 of the INVOKE definition.
//
// Reference: https://wg21.link/func.require#1.6
template <typename F,
typename T1,
EnableIf<IsMemObjPtr<F> && !IsMemPtrToBaseOf<F, T1> &&
!IsRefWrapper<T1>> = true>
constexpr decltype(auto) InvokeImpl(F&& f, T1&& t1) {
return (*std::forward<T1>(t1)).*f;
}
// Invokes a regular function or function object. Covers bullet 7 of the INVOKE
// definition.
//
// Reference: https://wg21.link/func.require#1.7
template <typename F, typename... Args>
constexpr decltype(auto) InvokeImpl(F&& f, Args&&... args) {
return std::forward<F>(f)(std::forward<Args>(args)...);
}
} // namespace internal
// Implementation of C++17's std::invoke. This is not based on implementation
// referenced in original std::invoke proposal, but rather a manual
// implementation, so that it can be constexpr.
//
// References:
// - https://wg21.link/n4169#implementability
// - https://en.cppreference.com/w/cpp/utility/functional/invoke
// - https://wg21.link/func.invoke
template <typename F, typename... Args>
constexpr decltype(auto) invoke(F&& f, Args&&... args) {
return internal::InvokeImpl(std::forward<F>(f), std::forward<Args>(args)...);
}
// Implementation of C++20's std::identity.
//
// Reference:
// - https://en.cppreference.com/w/cpp/utility/functional/identity
// - https://wg21.link/func.identity
struct identity {
template <typename T>
constexpr T&& operator()(T&& t) const noexcept {
return std::forward<T>(t);
}
using is_transparent = void;
};
// Simplified C++14 implementation of C++20's std::to_address.
// Note: This does not consider specializations of pointer_traits<>::to_address,
// since that member function may only be present in C++20 and later.
......
......@@ -289,37 +289,6 @@ TEST(STLUtilTest, AsConst) {
"Error: base::as_const() returns an unexpected type");
}
TEST(STLUtilTest, Invoke) {
struct S {
int i;
constexpr int add(int x) const { return i + x; }
};
constexpr S s = {1};
// Note: The tests involving a std::reference_wrapper are not static_asserts,
// since std::reference_wrapper is not constexpr prior to C++20.
static_assert(invoke(&S::add, s, 2) == 3, "");
EXPECT_EQ(invoke(&S::add, std::ref(s), 2), 3);
static_assert(invoke(&S::add, &s, 3) == 4, "");
static_assert(invoke(&S::i, s) == 1, "");
EXPECT_EQ(invoke(&S::i, std::ref(s)), 1);
static_assert(invoke(&S::i, &s) == 1, "");
static_assert(invoke(std::plus<>(), 1, 2) == 3, "");
}
TEST(STLUtilTest, Identity) {
static constexpr identity id;
std::vector<int> v;
EXPECT_EQ(&v, &id(v));
constexpr int arr = {0};
static_assert(arr == id(arr), "");
}
TEST(STLUtilTest, GetUnderlyingContainer) {
{
std::queue<int> queue({1, 2, 3, 4, 5});
......
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