You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mesos.apache.org by mp...@apache.org on 2017/12/05 01:40:48 UTC
[1/2] mesos git commit: Added `cpp17::invoke` in .
Repository: mesos
Updated Branches:
refs/heads/master 3c25233c2 -> 8670d2e92
Added `cpp17::invoke` in <stout/cpp17.hpp>.
Review: https://reviews.apache.org/r/64248/
Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/3b9db404
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/3b9db404
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/3b9db404
Branch: refs/heads/master
Commit: 3b9db404cb0b50edef1958423b26364e63ccaa27
Parents: 3c25233
Author: Michael Park <mp...@apache.org>
Authored: Mon Dec 4 17:25:33 2017 -0800
Committer: Michael Park <mp...@apache.org>
Committed: Mon Dec 4 17:25:33 2017 -0800
----------------------------------------------------------------------
3rdparty/stout/Makefile.am | 1 +
3rdparty/stout/include/Makefile.am | 1 +
3rdparty/stout/include/stout/cpp17.hpp | 65 +++++++++++++++++++++++++++++
3rdparty/stout/tests/CMakeLists.txt | 1 +
3rdparty/stout/tests/cpp17_tests.cpp | 58 +++++++++++++++++++++++++
5 files changed, 126 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/mesos/blob/3b9db404/3rdparty/stout/Makefile.am
----------------------------------------------------------------------
diff --git a/3rdparty/stout/Makefile.am b/3rdparty/stout/Makefile.am
index 4386017..bcf3842 100644
--- a/3rdparty/stout/Makefile.am
+++ b/3rdparty/stout/Makefile.am
@@ -132,6 +132,7 @@ stout_tests_SOURCES = \
tests/boundedhashmap_tests.cpp \
tests/bytes_tests.cpp \
tests/cache_tests.cpp \
+ tests/cpp17_tests.cpp \
tests/duration_tests.cpp \
tests/dynamiclibrary_tests.cpp \
tests/error_tests.cpp \
http://git-wip-us.apache.org/repos/asf/mesos/blob/3b9db404/3rdparty/stout/include/Makefile.am
----------------------------------------------------------------------
diff --git a/3rdparty/stout/include/Makefile.am b/3rdparty/stout/include/Makefile.am
index bdd3e99..d4fdc81 100644
--- a/3rdparty/stout/include/Makefile.am
+++ b/3rdparty/stout/include/Makefile.am
@@ -20,6 +20,7 @@ nobase_include_HEADERS = \
stout/boundedhashmap.hpp \
stout/bits.hpp \
stout/bytes.hpp \
+ stout/cpp17.hpp \
stout/cache.hpp \
stout/check.hpp \
stout/duration.hpp \
http://git-wip-us.apache.org/repos/asf/mesos/blob/3b9db404/3rdparty/stout/include/stout/cpp17.hpp
----------------------------------------------------------------------
diff --git a/3rdparty/stout/include/stout/cpp17.hpp b/3rdparty/stout/include/stout/cpp17.hpp
new file mode 100644
index 0000000..3c4cc53
--- /dev/null
+++ b/3rdparty/stout/include/stout/cpp17.hpp
@@ -0,0 +1,65 @@
+// 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.
+// limitations under the License.
+
+#ifndef __STOUT_CPP17_HPP__
+#define __STOUT_CPP17_HPP__
+
+#include <utility>
+
+// This file contains implementation of C++17 standard library features.
+// Once we adopt C++17, this file should be removed and usages of its
+// functionality should be replaced with the standard library equivalents
+// by replacing `cpp17` with `std` and including the appropriate headers.
+
+// Note that code in this file may not follow stout conventions strictly
+// as it uses names as defined in C++ standard.
+
+namespace cpp17 {
+
+// <functional>
+
+// `std::invoke`
+
+#ifdef __WINDOWS__
+using std::invoke;
+#else
+#define RETURN(...) -> decltype(__VA_ARGS__) { return __VA_ARGS__; }
+
+// NOTE: This implementation is not strictly conforming currently
+// as attempting to use it with `std::reference_wrapper` will result
+// in compilation failure.
+
+template <typename F, typename... As>
+constexpr auto invoke(F&& f, As&&... as)
+ RETURN(std::forward<F>(f)(std::forward<As>(as)...))
+
+template <typename B, typename T, typename D>
+constexpr auto invoke(T B::*pmv, D&& d)
+ RETURN(std::forward<D>(d).*pmv)
+
+template <typename Pmv, typename Ptr>
+constexpr auto invoke(Pmv pmv, Ptr&& ptr)
+ RETURN((*std::forward<Ptr>(ptr)).*pmv)
+
+template <typename B, typename T, typename D, typename... As>
+constexpr auto invoke(T B::*pmf, D&& d, As&&... as)
+ RETURN((std::forward<D>(d).*pmf)(std::forward<As>(as)...))
+
+template <typename Pmf, typename Ptr, typename... As>
+constexpr auto invoke(Pmf pmf, Ptr&& ptr, As&&... as)
+ RETURN(((*std::forward<Ptr>(ptr)).*pmf)(std::forward<As>(as)...))
+
+#undef RETURN
+#endif
+
+} // namespace cpp17 {
+
+#endif // __STOUT_CPP17_HPP__
http://git-wip-us.apache.org/repos/asf/mesos/blob/3b9db404/3rdparty/stout/tests/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/3rdparty/stout/tests/CMakeLists.txt b/3rdparty/stout/tests/CMakeLists.txt
index 6e5773f..bc2498d 100644
--- a/3rdparty/stout/tests/CMakeLists.txt
+++ b/3rdparty/stout/tests/CMakeLists.txt
@@ -21,6 +21,7 @@ set(STOUT_ROOT_TESTS_SRC
bits_tests.cpp
bytes_tests.cpp
cache_tests.cpp
+ cpp17_tests.cpp
duration_tests.cpp
dynamiclibrary_tests.cpp
error_tests.cpp
http://git-wip-us.apache.org/repos/asf/mesos/blob/3b9db404/3rdparty/stout/tests/cpp17_tests.cpp
----------------------------------------------------------------------
diff --git a/3rdparty/stout/tests/cpp17_tests.cpp b/3rdparty/stout/tests/cpp17_tests.cpp
new file mode 100644
index 0000000..37d817f
--- /dev/null
+++ b/3rdparty/stout/tests/cpp17_tests.cpp
@@ -0,0 +1,58 @@
+// 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
+
+#include <gtest/gtest.h>
+
+#include <stout/cpp17.hpp>
+
+int f(int i) { return i + 101; }
+
+TEST(Invoke, Free)
+{
+ // Invoke a free function.
+ EXPECT_EQ(202, cpp17::invoke(f, 101));
+}
+
+
+TEST(Invoke, Lambda)
+{
+ // Invoke a lambda.
+ EXPECT_EQ(42, cpp17::invoke([]() { return 42; }));
+}
+
+
+TEST(Invoke, Member) {
+ // Invoke a member function.
+ struct S
+ {
+ int f(int i) const { return n + i; }
+ int n;
+ };
+
+ S s{101};
+ EXPECT_EQ(303, cpp17::invoke(&S::f, s, 202));
+
+ // Invoke (access) a data member.
+ EXPECT_EQ(101, cpp17::invoke(&S::n, s));
+}
+
+
+TEST(Invoke, FunctionObject)
+{
+ // Invoke a function object.
+ struct F
+ {
+ int operator()(int i) const { return i + 202; }
+ };
+
+ EXPECT_EQ(404, cpp17::invoke(F{}, 202));
+}
[2/2] mesos git commit: Added `lambda::partial` to .
Posted by mp...@apache.org.
Added `lambda::partial` to <stout/lambda.hpp>.
Review: https://reviews.apache.org/r/64274/
Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/8670d2e9
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/8670d2e9
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/8670d2e9
Branch: refs/heads/master
Commit: 8670d2e9224485b94a40654d4a2102d8340fe4ac
Parents: 3b9db40
Author: Michael Park <mp...@apache.org>
Authored: Mon Dec 4 17:25:36 2017 -0800
Committer: Michael Park <mp...@apache.org>
Committed: Mon Dec 4 17:25:36 2017 -0800
----------------------------------------------------------------------
3rdparty/stout/include/stout/lambda.hpp | 150 +++++++++++++++++++++++++++
3rdparty/stout/tests/lambda_tests.cpp | 138 +++++++++++++++++++++++-
2 files changed, 286 insertions(+), 2 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/mesos/blob/8670d2e9/3rdparty/stout/include/stout/lambda.hpp
----------------------------------------------------------------------
diff --git a/3rdparty/stout/include/stout/lambda.hpp b/3rdparty/stout/include/stout/lambda.hpp
index a61d97b..c14241a 100644
--- a/3rdparty/stout/include/stout/lambda.hpp
+++ b/3rdparty/stout/include/stout/lambda.hpp
@@ -15,8 +15,12 @@
#include <algorithm>
#include <functional>
+#include <type_traits>
+#include <utility>
#include <vector>
+#include <stout/cpp14.hpp>
+#include <stout/cpp17.hpp>
#include <stout/result_of.hpp>
namespace lambda {
@@ -155,6 +159,152 @@ std::vector<V> map(F&& f, std::initializer_list<U> input)
return output;
}
+
+#define RETURN(...) -> decltype(__VA_ARGS__) { return __VA_ARGS__; }
+
+
+namespace internal {
+
+// The `int` specializations here for `is_placeholder<T>::value`.
+// `is_placeholder<T>::value` returns a `0` for non-placeholders,
+// and I > 0 for placeholders where I indicates the placeholder
+// value. e.g., `is_placeholder<decltype(_1)>::value == 1`
+
+template <int I>
+struct Expand
+{
+ // Bound argument is a placeholder.
+ template <typename T, typename Args>
+ auto operator()(T&&, Args&& args) const
+ RETURN(std::get<I - 1>(std::forward<Args>(args)))
+};
+
+
+template <>
+struct Expand<0>
+{
+ // Bound argument is not a placeholder.
+ template <typename T, typename Args>
+ auto operator()(T&& t, Args&&) const
+ RETURN(std::forward<T>(t))
+};
+
+
+template <typename F, typename... BoundArgs>
+class Partial
+{
+ F f;
+ std::tuple<BoundArgs...> bound_args;
+
+ template <typename T, typename Args>
+ static auto expand(T&& t, Args&& args)
+ RETURN(Expand<std::is_placeholder<typename std::decay<T>::type>::value>{}(
+ std::forward<T>(t), std::forward<Args>(args)))
+
+ // Invoke the given function `f` with bound arguments expanded. If a bound
+ // argument is a placeholder, we use the index `I` of the placeholder to
+ // pass the `I`th argument out of `args` along. Otherwise, we pass the bound
+ // argument through preserving its value category. That is, passing the bound
+ // argument as an lvalue-ref or rvalue-ref depending correspondingly on
+ // whether the `Partial` itself is an lvalue or rvalue.
+ template <typename F_, typename BoundArgs_, typename Args, std::size_t... Is>
+ static auto invoke_expand(
+ F_&& f,
+ BoundArgs_&& bound_args,
+ cpp14::index_sequence<Is...>,
+ Args&& args)
+ RETURN(cpp17::invoke(
+ std::forward<F_>(f),
+ expand(
+ std::get<Is>(std::forward<BoundArgs_>(bound_args)),
+ std::forward<Args>(args))...))
+
+public:
+ template <typename... BoundArgs_>
+ explicit Partial(const F& f, BoundArgs_&&... args)
+ : f(f), bound_args(std::forward<BoundArgs_>(args)...) {}
+
+ template <typename... BoundArgs_>
+ explicit Partial(F&& f, BoundArgs_&&... args)
+ : f(std::move(f)), bound_args(std::forward<BoundArgs_>(args)...) {}
+
+ Partial(const Partial&) = default;
+ Partial(Partial&&) = default;
+
+ Partial& operator=(const Partial&) = default;
+ Partial& operator=(Partial&&) = default;
+
+ template <typename... Args>
+ auto operator()(Args&&... args) &
+ RETURN(invoke_expand(
+ f,
+ bound_args,
+ cpp14::make_index_sequence<sizeof...(BoundArgs)>(),
+ std::forward_as_tuple(std::forward<Args>(args)...)))
+
+ template <typename... Args>
+ auto operator()(Args&&... args) const &
+ RETURN(invoke_expand(
+ f,
+ bound_args,
+ cpp14::make_index_sequence<sizeof...(BoundArgs)>(),
+ std::forward_as_tuple(std::forward<Args>(args)...)))
+
+ template <typename... Args>
+ auto operator()(Args&&... args) &&
+ RETURN(invoke_expand(
+ std::move(f),
+ std::move(bound_args),
+ cpp14::make_index_sequence<sizeof...(BoundArgs)>(),
+ std::forward_as_tuple(std::forward<Args>(args)...)))
+
+ template <typename... Args>
+ auto operator()(Args&&... args) const &&
+ RETURN(invoke_expand(
+ std::move(f),
+ std::move(bound_args),
+ cpp14::make_index_sequence<sizeof...(BoundArgs)>(),
+ std::forward_as_tuple(std::forward<Args>(args)...)))
+};
+
+} // namespace internal {
+
+
+// Performs partial function application, similar to `std::bind`. However,
+// it supports moving the bound arguments through, unlike `std::bind`.
+// To do so, the `operator()` must be invoked on a rvalue `lambda::partial`.
+//
+// Unsupported `std::bind` features:
+// - There is no special treatment for nested bind expressions. When calling
+// `operator()` on partial, call parameters will not be passed to nested
+// bind expression. Instead, bind expression will be passed as-is to the
+// wrapped function object. This behavior is intentional, for simplicity
+// reasons, and is in sync with C++20's `std::bind_front`.
+// - Passing `std::reference_wrapper` is not implemented.
+template <typename F, typename... Args>
+internal::Partial<
+ typename std::decay<F>::type,
+ typename std::decay<Args>::type...>
+partial(F&& f, Args&&... args)
+{
+ using R = internal::Partial<
+ typename std::decay<F>::type,
+ typename std::decay<Args>::type...>;
+ return R(std::forward<F>(f), std::forward<Args>(args)...);
+}
+
+
+#undef RETURN
+
} // namespace lambda {
+
+namespace std {
+
+template <typename F, typename... Args>
+struct is_bind_expression<lambda::internal::Partial<F, Args...>>
+ : true_type {};
+
+} // namespace std {
+
#endif // __STOUT_LAMBDA_HPP__
http://git-wip-us.apache.org/repos/asf/mesos/blob/8670d2e9/3rdparty/stout/tests/lambda_tests.cpp
----------------------------------------------------------------------
diff --git a/3rdparty/stout/tests/lambda_tests.cpp b/3rdparty/stout/tests/lambda_tests.cpp
index ad8c2ef..11b0343 100644
--- a/3rdparty/stout/tests/lambda_tests.cpp
+++ b/3rdparty/stout/tests/lambda_tests.cpp
@@ -18,14 +18,29 @@
struct OnlyMoveable
{
+ OnlyMoveable() : i(-1) {}
OnlyMoveable(int i) : i(i) {}
- OnlyMoveable(OnlyMoveable&&) = default;
+
+ OnlyMoveable(OnlyMoveable&& that)
+ {
+ *this = std::move(that);
+ }
+
OnlyMoveable(const OnlyMoveable&) = delete;
- OnlyMoveable& operator=(OnlyMoveable&&) = default;
+
+ OnlyMoveable& operator=(OnlyMoveable&& that)
+ {
+ i = that.i;
+ j = that.j;
+ that.valid = false;
+ return *this;
+ }
+
OnlyMoveable& operator=(const OnlyMoveable&) = delete;
int i;
int j = 0;
+ bool valid = true;
};
@@ -88,3 +103,122 @@ TEST(LambdaTest, Map)
EXPECT_EQ(o.i, o.j);
}
}
+
+
+namespace {
+
+template <typename F, typename ...Args>
+auto callable(F&& f, Args&&... args)
+ -> decltype(std::forward<F>(f)(std::forward<Args>(args)...),
+ void(),
+ std::true_type());
+
+
+template <typename F>
+std::false_type callable(F&& f, ...);
+
+
+// Compile-time check that f cannot be called with specified arguments.
+// This is implemented by defining two callable function overloads and
+// differentiating on return type. The first overload is selected only
+// when call expression is valid, and it has return type of std::true_type,
+// while second overload is selected for everything else.
+template <typename F, typename ...Args>
+void EXPECT_CALL_INVALID(F&& f, Args&&... args)
+{
+ static_assert(
+ !decltype(
+ callable(std::forward<F>(f), std::forward<Args>(args)...))::value,
+ "call expression is expected to be invalid");
+}
+
+} // namespace {
+
+
+
+namespace {
+
+int returnIntNoParams()
+{
+ return 8;
+}
+
+
+void returnVoidStringParam(std::string s) {}
+
+
+void returnVoidStringCRefParam(const std::string& s) {}
+
+
+int returnIntOnlyMovableParam(OnlyMoveable o)
+{
+ EXPECT_TRUE(o.valid);
+ return 1;
+}
+
+} // namespace {
+
+
+// This is mostly a compile time test of lambda::partial,
+// verifying that it works for different types of expressions.
+TEST(PartialTest, Test)
+{
+ // standalone functions
+ auto p1 = lambda::partial(returnIntNoParams);
+ int p1r1 = p1();
+ int p1r2 = std::move(p1)();
+ EXPECT_EQ(p1r1, p1r2);
+
+ auto p2 = lambda::partial(returnVoidStringParam, "");
+ p2();
+ std::move(p2)();
+
+ auto p3 = lambda::partial(returnVoidStringParam, lambda::_1);
+ p3("");
+ std::move(p3)("");
+
+ auto p4 = lambda::partial(&returnVoidStringCRefParam, lambda::_1);
+ p4("");
+ std::move(p4)("");
+
+ auto p5 = lambda::partial(&returnIntOnlyMovableParam, lambda::_1);
+ p5(OnlyMoveable());
+ p5(10);
+ std::move(p5)(OnlyMoveable());
+
+ auto p6 = lambda::partial(&returnIntOnlyMovableParam, OnlyMoveable());
+ EXPECT_CALL_INVALID(p6);
+ std::move(p6)();
+
+ // lambdas
+ auto l1 = [](const OnlyMoveable& m) { EXPECT_TRUE(m.valid); };
+ auto pl1 = lambda::partial(l1, OnlyMoveable());
+ pl1();
+ pl1();
+ std::move(pl1)();
+
+ auto pl2 = lambda::partial([](OnlyMoveable&& m) { EXPECT_TRUE(m.valid); },
+ lambda::_1);
+ pl2(OnlyMoveable());
+ pl2(OnlyMoveable());
+ std::move(pl2)(OnlyMoveable());
+
+ auto pl3 = lambda::partial([](OnlyMoveable&& m) { EXPECT_TRUE(m.valid); },
+ OnlyMoveable());
+ EXPECT_CALL_INVALID(pl3);
+ std::move(pl3)();
+
+ // member functions
+ struct Object
+ {
+ int method() { return 0; };
+ };
+
+ auto mp1 = lambda::partial(&Object::method, lambda::_1);
+ mp1(Object());
+ std::move(mp1)(Object());
+
+ auto mp2 = lambda::partial(&Object::method, Object());
+ mp2();
+ std::move(mp2)();
+}