// Copyright 2018 Google LLC // // 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. #ifndef GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_INTERNAL_FUTURE_THEN_IMPL_H #define GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_INTERNAL_FUTURE_THEN_IMPL_H /** * @file * * Define the `future::then_impl()` template functions. * * These functions cannot be defined inline, as most template functions are, * because the full definition of `future`, `future` and `future`, * must be visible at the point of definition. There is no order of definition * for the `future` specializations that would permit us to define the * functions inline. */ #include "google/cloud/future_generic.h" #include "google/cloud/future_void.h" #include "google/cloud/version.h" namespace google { namespace cloud { inline namespace GOOGLE_CLOUD_CPP_NS { // These functions cannot be defined inline, as most template functions are, // because the full definition of `future`, `future` and `future`, // must be visible at the point of definition. There is no order of definition // for the `future` specializations that would permit us to define the // functions inline. template inline future::future(future>&& rhs) : future(rhs.then([](future> f) { return f.get(); })) {} template template typename internal::then_helper::future_t future::then_impl( F&& functor, std::false_type) { // g++-4.9 gets confused about the use of a protected type alias here, so // create a non-protected one: using local_state_type = typename internal::future_shared_state; // Some type aliases to make the rest of the code more readable. using functor_result_t = typename internal::then_helper::functor_result_t; using future_t = typename internal::then_helper::future_t; // The `shared_state_type` (aka `future_shared_state`) is written // without any reference to the `future` class, otherwise there would // be cyclic dependencies between the two classes. We must adapt the // provided functor, which takes a `future` parameter to take a // `shared_ptr(func)) {} auto operator()(std::shared_ptr state) -> functor_result_t { return functor(future(std::move(state))); } typename std::decay::type functor; }; auto output_shared_state = local_state_type::make_continuation( this->shared_state_, adapter(std::forward(functor))); // Nothing throws after this point, and we have not changed the state if // anything did throw. this->shared_state_.reset(); return future_t(std::move(output_shared_state)); } template template typename internal::then_helper::future_t future::then_impl( F&& functor, std::true_type) { // g++-4.9 gets confused about the use of a protected type alias here, so // create a non-protected one: using local_state_type = internal::future_shared_state; // Some type aliases to make the rest of the code more readable. using result_t = typename internal::then_helper::result_t; using future_t = typename internal::then_helper::future_t; // `F` is basically a callable that meets the `future(future)` // signature. The `shared_state_type` (aka `future_shared_state`) is // written without any reference to the `future` class, otherwise there // would be cyclic dependencies between the two classes. We must adapt the // provided functor, to meet this signature: // // `std::shared_ptr>(std::shared_ptr>)` // // Because we need to support C++11, we use a local class instead of a lambda, // as support for move+capture in lambdas is a C++14 feature. struct adapter { // NOLINT(readability-identifier-naming) explicit adapter(F&& func) : functor(std::forward(func)) {} auto operator()(std::shared_ptr state) -> std::shared_ptr> { return functor(future(std::move(state))).shared_state_; } typename std::decay::type functor; }; auto output_shared_state = local_state_type::make_continuation( this->shared_state_, adapter(std::forward(functor)), std::true_type{}); // Nothing throws after this point, and we have not changed the state if // anything did throw. this->shared_state_.reset(); return future_t(std::move(output_shared_state)); } inline future::future(future>&& rhs) : future(rhs.then([](future> f) { return f.get(); })) {} template typename internal::then_helper::future_t future::then_impl( F&& functor, std::false_type) { // g++-4.9 gets confused about the use of a protected type alias here, so // create a non-protected one: using local_state_type = typename internal::future_shared_state; // Some type aliases to make the rest of the code more readable. using functor_result_t = typename internal::then_helper::functor_result_t; using future_t = typename internal::then_helper::future_t; // The `shared_state_type` (aka `future_shared_state`) is written // without any reference to the `future` class, otherwise there would // be cyclic dependencies between the two classes. We must adapt the // provided functor, which takes a `future` parameter to take a // `shared_ptr(func)) {} auto operator()(std::shared_ptr state) -> functor_result_t { return functor(future(std::move(state))); } typename std::decay::type functor; }; auto output_shared_state = shared_state_type::make_continuation( shared_state_, adapter(std::forward(functor))); // Nothing throws after this point, and we have not changed the state if // anything did throw. shared_state_.reset(); return future_t(std::move(output_shared_state)); } template typename internal::then_helper::future_t future::then_impl( F&& functor, std::true_type) { // g++-4.9 gets confused about the use of a protected type alias here, so // create a non-protected one: using local_state_type = internal::future_shared_state; // Some type aliases to make the rest of the code more readable. using result_t = typename internal::then_helper::result_t; using future_t = typename internal::then_helper::future_t; // `F` is basically a callable that meets the `future(future)` // signature. The `shared_state_type` (aka `future_shared_state`) is // written without any reference to the `future` class, otherwise there // would be cyclic dependencies between the two classes. We must adapt the // provided functor, to meet this signature: // // `std::shared_ptr>(std::shared_ptr>)` // // Because we need to support C++11, we use a local class instead of a lambda, // as support for move+capture in lambdas is a C++14 feature. struct adapter { // NOLINT(readability-identifier-naming) explicit adapter(F&& func) : functor(std::forward(func)) {} auto operator()(std::shared_ptr state) -> std::shared_ptr> { return functor(future(std::move(state))).shared_state_; } typename std::decay::type functor; }; auto output_shared_state = local_state_type::make_continuation( this->shared_state_, adapter(std::forward(functor)), std::true_type{}); // Nothing throws after this point, and we have not changed the state if // anything did throw. this->shared_state_.reset(); return future_t(std::move(output_shared_state)); } } // namespace GOOGLE_CLOUD_CPP_NS } // namespace cloud } // namespace google #endif // GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_INTERNAL_FUTURE_THEN_IMPL_H