/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */ /* * Copyright 2022 Couchbase, 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 #include #include /* replace with standard version once http://wg21.link/P0288 will be accepted and implemented */ namespace couchbase::core::utils { template class movable_function : public std::function { template struct wrapper; template struct wrapper>> { Functor fn; template auto operator()(Args&&... args) { return fn(std::forward(args)...); } }; template struct copy_wrapper { Functor fn; explicit copy_wrapper(Functor&& f) : fn(std::move(f)) { } }; template struct wrapper && std::is_move_constructible_v>> { std::shared_ptr> fnPtr; explicit wrapper(Functor&& f) : fnPtr(new copy_wrapper(std::move(f))) { } wrapper(wrapper&& /* other */) noexcept = default; auto operator=(wrapper&& /* other */) noexcept -> wrapper& = default; wrapper(const wrapper& other) = default; auto operator=(const wrapper& /* other */) -> wrapper& = default; template auto operator()(Args&&... args) { return std::move(fnPtr->fn)(std::forward(args)...); } }; using base = std::function; public: movable_function() noexcept = default; movable_function(std::nullptr_t) noexcept : base(nullptr) { } template movable_function(Functor&& f) : base(wrapper{ std::forward(f) }) { } movable_function(movable_function&& other) noexcept : base(std::move(static_cast(other))) { other = nullptr; } auto operator=(movable_function&& other) noexcept -> movable_function& { base::operator=(std::move(static_cast(other))); other = nullptr; return *this; } auto operator=(std::nullptr_t /* other */) -> movable_function& { base::operator=(nullptr); return *this; } template auto operator=(Functor&& f) -> movable_function& { base::operator=(wrapper{ std::forward(f) }); return *this; } using base::operator bool; using base::operator(); }; } // namespace couchbase::core::utils