summaryrefslogtreecommitdiff
path: root/src/utilities/functorPtr.h
blob: 438b358152ce1d5dc0550fda4a3fb3004a3dbd59 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
/*  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
 *  <http://www.openlb.net/>
 *
 *  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 <memory>
#include <type_traits>

namespace olb {

namespace util {

/// Backport of C++17's std::void_t
template<typename...>
struct void_t {
  using type = void;
};

/// Indicates existence of F::identity_functor_type typedef
template<class F, class U = void>
struct has_identity_functor : std::false_type { };
/// Indicates existence of F::identity_functor_type typedef
template<class F>
struct has_identity_functor<F, typename void_t<typename F::identity_functor_type>::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<typename F>
class FunctorPtr {
private:
  /// Optional functor owner
  std::unique_ptr<F> _ownF;
  /// Optional shared functor
  std::shared_ptr<F> _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>& f);
  /// Constructor for transparently taking ownership of a owning functor pointer
  FunctorPtr(std::unique_ptr<F>&& f);
  /// Constructor for transparently sharing ownership of a functor
  FunctorPtr(std::shared_ptr<F> 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<typename... Args>
  bool operator()(Args... args)
  {
    return _f->operator()(std::forward<Args>(args)...);
  }

  /// \returns reference to the exposed functor
  typename std::add_lvalue_reference<F>::type operator*() const;
  /// Enable pointer-like access to the exposed functor's members
  typename std::add_pointer<F>::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<F> arithmetic
  template<typename G = F>
  auto toShared() -> typename std::enable_if< util::has_identity_functor<G>::value, std::shared_ptr<F>>::type;
  /// Lifts managed functor reference for usage in std::shared_ptr<F> arithmetic (limited)
  template<typename G = F>
  auto toShared() -> typename std::enable_if<!util::has_identity_functor<G>::value, std::shared_ptr<F>>::type;

};

}

#endif