/* This file is part of the OpenLB library * * Copyright (C) 2017 Adrian Kummerlaender * E-mail contact: info@openlb.net * The most recent release of OpenLB can be downloaded at * * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the Free * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef FUNCTOR_PTR_H #define FUNCTOR_PTR_H #include #include namespace olb { namespace util { /// Backport of C++17's std::void_t template struct void_t { using type = void; }; /// Indicates existence of F::identity_functor_type typedef template struct has_identity_functor : std::false_type { }; /// Indicates existence of F::identity_functor_type typedef template struct has_identity_functor::type> : std::true_type { }; } /// Smart pointer for managing the various ways of passing functors around /** * There is a rich set of functors that compose other functors by accepting * them as constructor arguments. e.g. SuperLpNorm3D, SuperPlaneIntegralF3D * * Previously all of these functors only accepted other functors by reference * which prevented e.g. the use case of accepting a std::unique_ptr to a * indicator freshly created by SuperGeometry3D::getMaterialIndicator. * * This class hides the memory management required to support accepting either * functor references, non-owning pointers or owning pointers in a single argument. * * Note that if this class is constructed by reference or raw pointer the caller * is responsible for assuring that the passed functor is available for the full * lifetime. This is not the case when constructed by a smart pointer. **/ template class FunctorPtr { private: /// Optional functor owner std::unique_ptr _ownF; /// Optional shared functor std::shared_ptr _sharedF; /// Pointer to the exposed functor F* _f; /// True iff FunctorPtr was constructed owning const bool _owning; public: /// Constructor for transparently accepting a functor reference FunctorPtr(F& f); /// Constructor for transparently accepting a non-owning functor pointer FunctorPtr(F* f); /// Constructor for transparently accepting a owning functor pointer /** * Equivalent to construction using a non-owning functor pointer **/ FunctorPtr(const std::unique_ptr& f); /// Constructor for transparently taking ownership of a owning functor pointer FunctorPtr(std::unique_ptr&& f); /// Constructor for transparently sharing ownership of a functor FunctorPtr(std::shared_ptr f); /// Constructor for an empty instance /** * Equivalent to construction by nullptr. **/ FunctorPtr(); /// Copy construction is disabled as it is incompatible with unique ownership FunctorPtr(FunctorPtr&) = delete; /// Move constructor FunctorPtr(FunctorPtr&&) = default; /// Perfect forwarding functor operator template bool operator()(Args... args) { return _f->operator()(std::forward(args)...); } /// \returns reference to the exposed functor typename std::add_lvalue_reference::type operator*() const; /// Enable pointer-like access to the exposed functor's members typename std::add_pointer::type operator->() const noexcept; /// Indicates whether a functor instance is exposed /** * \returns true iff a functor is exposed * * This is useful for supporting optional functors in constructor interfaces * by constructing FunctorPtr using a nullptr **/ operator bool() const; /// Indicates whether a functor instance is both exposed and owned /** * \returns true iff FunctorPtr took ownership of managed functor during construction * * It is not enough to check _ownF and _sharedF for non-nullptr contents as _sharedF * is also used to store F::identity_functor_type instances created by toShared. **/ bool isOwning() const; /// Lifts managed functor reference for usage in std::shared_ptr arithmetic template auto toShared() -> typename std::enable_if< util::has_identity_functor::value, std::shared_ptr>::type; /// Lifts managed functor reference for usage in std::shared_ptr arithmetic (limited) template auto toShared() -> typename std::enable_if::value, std::shared_ptr>::type; }; } #endif