From: James Sedgwick Date: Wed, 18 Oct 2017 18:49:02 +0000 (-0700) Subject: move Partial to functional/ X-Git-Tag: v2017.10.23.00~26 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=e372e3d34fd57695d9655336b43e13be8784c81d;p=folly.git move Partial to functional/ Summary: as above Reviewed By: ngoyal Differential Revision: D6087941 fbshipit-source-id: 948ff4f2faa87dd34f87d14ea01c83335f850a27 --- diff --git a/folly/Makefile.am b/folly/Makefile.am index 7159baea..e91dba2d 100644 --- a/folly/Makefile.am +++ b/folly/Makefile.am @@ -205,6 +205,7 @@ nobase_follyinclude_HEADERS = \ Format.h \ Format-inl.h \ functional/Invoke.h \ + functional/Partial.h \ futures/Barrier.h \ futures/Future-pre.h \ futures/helpers.h \ @@ -341,7 +342,6 @@ nobase_follyinclude_HEADERS = \ Overload.h \ PackedSyncPtr.h \ Padded.h \ - Partial.h \ PicoSpinLock.h \ Portability.h \ portability/Asm.h \ diff --git a/folly/Partial.h b/folly/Partial.h deleted file mode 100644 index b3914528..00000000 --- a/folly/Partial.h +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright 2017 Facebook, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include - -namespace folly { - -namespace detail { -namespace partial { - -// helper type to make sure that the templated constructor in Partial does -// not accidentally act as copy or move constructor -struct PartialConstructFromCallable {}; - -template -class Partial { - private: - F f_; - Tuple stored_args_; - - public: - template - Partial(PartialConstructFromCallable, Callable&& callable, Args&&... args) - : f_(std::forward(callable)), - stored_args_(std::forward(args)...) {} - - template - auto operator()(CArgs&&... cargs) & -> decltype(applyTuple( - static_cast(f_), - static_cast(stored_args_), - std::forward_as_tuple(std::forward(cargs)...))) { - return applyTuple( - static_cast(f_), - static_cast(stored_args_), - std::forward_as_tuple(std::forward(cargs)...)); - } - - template - auto operator()(CArgs&&... cargs) const& -> decltype(applyTuple( - static_cast(f_), - static_cast(stored_args_), - std::forward_as_tuple(std::forward(cargs)...))) { - return applyTuple( - static_cast(f_), - static_cast(stored_args_), - std::forward_as_tuple(std::forward(cargs)...)); - } - - template - auto operator()(CArgs&&... cargs) && -> decltype(applyTuple( - static_cast(f_), - static_cast(stored_args_), - std::forward_as_tuple(std::forward(cargs)...))) { - return applyTuple( - static_cast(f_), - static_cast(stored_args_), - std::forward_as_tuple(std::forward(cargs)...)); - } -}; - -} // namespace partial -} // namespace detail - -/** - * Partially applies arguments to a callable - * - * `partial` takes a callable and zero or more additional arguments and returns - * a callable object, which when called with zero or more arguments, will invoke - * the original callable with the additional arguments passed to `partial`, - * followed by those passed to the call. - * - * E.g. `partial(Foo, 1, 2)(3)` is equivalent to `Foo(1, 2, 3)`. - * - * `partial` can be used to bind a class method to an instance: - * `partial(&Foo::method, foo_pointer)` returns a callable object that can be - * invoked in the same way as `foo_pointer->method`. In case the first - * argument in a call to `partial` is a member pointer, the second argument - * can be a reference, pointer or any object that can be dereferenced to - * an object of type Foo (like `std::shared_ptr` or `std::unique_ptr`). - * - * `partial` is similar to `std::bind`, but you don't have to use placeholders - * to have arguments passed on. Any number of arguments passed to the object - * returned by `partial` when called will be added to those passed to `partial` - * and passed to the original callable. - */ -template -auto partial(F&& f, Args&&... args) -> detail::partial::Partial< - typename std::decay::type, - std::tuple::type...>> { - return {detail::partial::PartialConstructFromCallable{}, - std::forward(f), - std::forward(args)...}; -} - -} // namespace folly diff --git a/folly/functional/Partial.h b/folly/functional/Partial.h new file mode 100644 index 00000000..b3914528 --- /dev/null +++ b/folly/functional/Partial.h @@ -0,0 +1,110 @@ +/* + * Copyright 2017 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +namespace folly { + +namespace detail { +namespace partial { + +// helper type to make sure that the templated constructor in Partial does +// not accidentally act as copy or move constructor +struct PartialConstructFromCallable {}; + +template +class Partial { + private: + F f_; + Tuple stored_args_; + + public: + template + Partial(PartialConstructFromCallable, Callable&& callable, Args&&... args) + : f_(std::forward(callable)), + stored_args_(std::forward(args)...) {} + + template + auto operator()(CArgs&&... cargs) & -> decltype(applyTuple( + static_cast(f_), + static_cast(stored_args_), + std::forward_as_tuple(std::forward(cargs)...))) { + return applyTuple( + static_cast(f_), + static_cast(stored_args_), + std::forward_as_tuple(std::forward(cargs)...)); + } + + template + auto operator()(CArgs&&... cargs) const& -> decltype(applyTuple( + static_cast(f_), + static_cast(stored_args_), + std::forward_as_tuple(std::forward(cargs)...))) { + return applyTuple( + static_cast(f_), + static_cast(stored_args_), + std::forward_as_tuple(std::forward(cargs)...)); + } + + template + auto operator()(CArgs&&... cargs) && -> decltype(applyTuple( + static_cast(f_), + static_cast(stored_args_), + std::forward_as_tuple(std::forward(cargs)...))) { + return applyTuple( + static_cast(f_), + static_cast(stored_args_), + std::forward_as_tuple(std::forward(cargs)...)); + } +}; + +} // namespace partial +} // namespace detail + +/** + * Partially applies arguments to a callable + * + * `partial` takes a callable and zero or more additional arguments and returns + * a callable object, which when called with zero or more arguments, will invoke + * the original callable with the additional arguments passed to `partial`, + * followed by those passed to the call. + * + * E.g. `partial(Foo, 1, 2)(3)` is equivalent to `Foo(1, 2, 3)`. + * + * `partial` can be used to bind a class method to an instance: + * `partial(&Foo::method, foo_pointer)` returns a callable object that can be + * invoked in the same way as `foo_pointer->method`. In case the first + * argument in a call to `partial` is a member pointer, the second argument + * can be a reference, pointer or any object that can be dereferenced to + * an object of type Foo (like `std::shared_ptr` or `std::unique_ptr`). + * + * `partial` is similar to `std::bind`, but you don't have to use placeholders + * to have arguments passed on. Any number of arguments passed to the object + * returned by `partial` when called will be added to those passed to `partial` + * and passed to the original callable. + */ +template +auto partial(F&& f, Args&&... args) -> detail::partial::Partial< + typename std::decay::type, + std::tuple::type...>> { + return {detail::partial::PartialConstructFromCallable{}, + std::forward(f), + std::forward(args)...}; +} + +} // namespace folly diff --git a/folly/functional/test/PartialTest.cpp b/folly/functional/test/PartialTest.cpp new file mode 100644 index 00000000..0a037ad0 --- /dev/null +++ b/folly/functional/test/PartialTest.cpp @@ -0,0 +1,147 @@ +/* + * Copyright 2017 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include +#include + +#include + +using folly::partial; + +int add3(int x, int y, int z) { + return 100 * x + 10 * y + z; +} + +TEST(Partial, Simple) { + auto p0 = partial(&add3); + EXPECT_EQ(123, p0(1, 2, 3)); + + auto p1 = partial(&add3, 2); + EXPECT_EQ(234, p1(3, 4)); + + auto p2 = partial(&add3, 3, 4); + EXPECT_EQ(345, p2(5)); + + auto p3 = partial(&add3, 4, 5, 6); + EXPECT_EQ(456, p3()); +} + +struct Foo { + int method(int& x, int& y, int& z) { + return 1000 + 100 * x + 10 * y + z; + } + int constMethod(int const& x, int const& y, int const& z) const { + return 2000 + 100 * x + 10 * y + z; + } + int tempMethod(int&& x, int&& y, int&& z) { + return 3000 + 100 * x + 10 * y + z; + } +}; + +TEST(Partial, ReferenceArguments) { + auto p0 = partial(&Foo::method, Foo{}, 2, 3); + int four = 4; + EXPECT_EQ(1234, p0(four)); + + auto const p1 = partial(&Foo::constMethod, Foo{}, 3, 4); + EXPECT_EQ(2345, p1(5)); + + auto p2 = partial(&Foo::tempMethod, Foo{}, 4, 5); + EXPECT_EQ(3456, std::move(p2)(6)); +} + +struct RefQualifiers { + int operator()(int x, int y, int z) & { + return 1000 + 100 * x + 10 * y + z; + } + int operator()(int x, int y, int z) const& { + return 2000 + 100 * x + 10 * y + z; + } + int operator()(int x, int y, int z) && { + return 3000 + 100 * x + 10 * y + z; + } +}; + +TEST(Partial, RefQualifiers) { + auto p = partial(RefQualifiers{}); + auto const& pconst = p; + + EXPECT_EQ(1234, p(2, 3, 4)); + EXPECT_EQ(2345, pconst(3, 4, 5)); + EXPECT_EQ(3456, std::move(p)(4, 5, 6)); +} + +struct RefQualifiers2 { + int operator()(int& x, int const& y, int z) & { + return 1000 + 100 * x + 10 * y + z; + } + int operator()(int const& x, int y, int z) const& { + return 2000 + 100 * x + 10 * y + z; + } + int operator()(int&& x, int const& y, int z) && { + return 3000 + 100 * x + 10 * y + z; + } +}; + +TEST(Partial, RefQualifiers2) { + auto p = partial(RefQualifiers2{}, 9, 8); + auto const& pconst = p; + + EXPECT_EQ(1984, p(4)); + EXPECT_EQ(2985, pconst(5)); + EXPECT_EQ(3986, std::move(p)(6)); +} + +std::unique_ptr calc_uptr(std::unique_ptr x, std::unique_ptr y) { + *x = 100 * *x + 10 * *y; + return x; +} + +TEST(Partial, MoveOnly) { + auto five = std::make_unique(5); + auto six = std::make_unique(6); + + // create a partial object which holds a pointer to the `calc_uptr` function + // and a `unique_ptr` for the first argument + auto p = partial(&calc_uptr, std::move(five)); + + // `five` should be moved out of + EXPECT_FALSE(five); + + // call to the partial object as rvalue, which allows the call to consume + // captured data (here: the `unique_ptr` storing 5), and pass it + // the other `unique_ptr` + auto result = std::move(p)(std::move(six)); + + // ...which now should be moved out of + EXPECT_FALSE(six); + + EXPECT_EQ(560, *result); +} + +TEST(Partial, WrapInStdFunction) { + auto p1 = partial(&add3, 2); + std::function func = p1; + EXPECT_EQ(234, func(3, 4)); +} + +TEST(Partial, WrapInFollyFunction) { + auto p1 = partial(&add3, 2); + folly::Function func = p1; + EXPECT_EQ(234, func(3, 4)); +} diff --git a/folly/test/PartialTest.cpp b/folly/test/PartialTest.cpp deleted file mode 100644 index aecd26d9..00000000 --- a/folly/test/PartialTest.cpp +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright 2017 Facebook, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include - -#include -#include - -#include - -using folly::partial; - -int add3(int x, int y, int z) { - return 100 * x + 10 * y + z; -} - -TEST(Partial, Simple) { - auto p0 = partial(&add3); - EXPECT_EQ(123, p0(1, 2, 3)); - - auto p1 = partial(&add3, 2); - EXPECT_EQ(234, p1(3, 4)); - - auto p2 = partial(&add3, 3, 4); - EXPECT_EQ(345, p2(5)); - - auto p3 = partial(&add3, 4, 5, 6); - EXPECT_EQ(456, p3()); -} - -struct Foo { - int method(int& x, int& y, int& z) { - return 1000 + 100 * x + 10 * y + z; - } - int constMethod(int const& x, int const& y, int const& z) const { - return 2000 + 100 * x + 10 * y + z; - } - int tempMethod(int&& x, int&& y, int&& z) { - return 3000 + 100 * x + 10 * y + z; - } -}; - -TEST(Partial, ReferenceArguments) { - auto p0 = partial(&Foo::method, Foo{}, 2, 3); - int four = 4; - EXPECT_EQ(1234, p0(four)); - - auto const p1 = partial(&Foo::constMethod, Foo{}, 3, 4); - EXPECT_EQ(2345, p1(5)); - - auto p2 = partial(&Foo::tempMethod, Foo{}, 4, 5); - EXPECT_EQ(3456, std::move(p2)(6)); -} - -struct RefQualifiers { - int operator()(int x, int y, int z) & { - return 1000 + 100 * x + 10 * y + z; - } - int operator()(int x, int y, int z) const& { - return 2000 + 100 * x + 10 * y + z; - } - int operator()(int x, int y, int z) && { - return 3000 + 100 * x + 10 * y + z; - } -}; - -TEST(Partial, RefQualifiers) { - auto p = partial(RefQualifiers{}); - auto const& pconst = p; - - EXPECT_EQ(1234, p(2, 3, 4)); - EXPECT_EQ(2345, pconst(3, 4, 5)); - EXPECT_EQ(3456, std::move(p)(4, 5, 6)); -} - -struct RefQualifiers2 { - int operator()(int& x, int const& y, int z) & { - return 1000 + 100 * x + 10 * y + z; - } - int operator()(int const& x, int y, int z) const& { - return 2000 + 100 * x + 10 * y + z; - } - int operator()(int&& x, int const& y, int z) && { - return 3000 + 100 * x + 10 * y + z; - } -}; - -TEST(Partial, RefQualifiers2) { - auto p = partial(RefQualifiers2{}, 9, 8); - auto const& pconst = p; - - EXPECT_EQ(1984, p(4)); - EXPECT_EQ(2985, pconst(5)); - EXPECT_EQ(3986, std::move(p)(6)); -} - -std::unique_ptr calc_uptr(std::unique_ptr x, std::unique_ptr y) { - *x = 100 * *x + 10 * *y; - return x; -} - -TEST(Partial, MoveOnly) { - auto five = std::make_unique(5); - auto six = std::make_unique(6); - - // create a partial object which holds a pointer to the `calc_uptr` function - // and a `unique_ptr` for the first argument - auto p = partial(&calc_uptr, std::move(five)); - - // `five` should be moved out of - EXPECT_FALSE(five); - - // call to the partial object as rvalue, which allows the call to consume - // captured data (here: the `unique_ptr` storing 5), and pass it - // the other `unique_ptr` - auto result = std::move(p)(std::move(six)); - - // ...which now should be moved out of - EXPECT_FALSE(six); - - EXPECT_EQ(560, *result); -} - -TEST(Partial, WrapInStdFunction) { - auto p1 = partial(&add3, 2); - std::function func = p1; - EXPECT_EQ(234, func(3, 4)); -} - -TEST(Partial, WrapInFollyFunction) { - auto p1 = partial(&add3, 2); - folly::Function func = p1; - EXPECT_EQ(234, func(3, 4)); -}