Lumiera  0.pre.03
»edityourfreedom«
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
depend.hpp
Go to the documentation of this file.
1 /*
2  DEPEND.hpp - access point to singletons and dependencies
3 
4  Copyright (C) Lumiera.org
5  2013, Hermann Vosseler <Ichthyostega@web.de>
6  2018, Hermann Vosseler <Ichthyostega@web.de>
7 
8  This program is free software; you can redistribute it and/or
9  modify it under the terms of the GNU General Public License as
10  published by the Free Software Foundation; either version 2 of
11  the License, or (at your option) any later version.
12 
13  This program is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  GNU General Public License for more details.
17 
18  You should have received a copy of the GNU General Public License
19  along with this program; if not, write to the Free Software
20  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 
22 */
23 
24 
88 #ifndef LIB_DEPEND_H
89 #define LIB_DEPEND_H
90 
91 
92 #include "lib/error.hpp"
93 #include "lib/nocopy.hpp"
94 #include "lib/nobug-init.hpp"
95 #include "lib/sync-classlock.hpp"
96 #include "lib/zombie-check.hpp"
97 #include "lib/meta/util.hpp"
98 
99 #include <type_traits>
100 #include <functional>
101 #include <atomic>
102 #include <memory>
103 
104 
105 namespace lib {
106  namespace error = lumiera::error;
107 
108 
119  template<class OBJ>
122  {
123  using Creator = std::function<OBJ*()>;
124  using Deleter = std::function<void()>;
125 
128 
129  public:
131 
132  DependencyFactory() = default;
134  {
135  if (deleter_)
136  deleter_();
137  }
138 
139  OBJ*
141  {
142  return creator_? creator_()
143  : buildAndManage();
144  }
145 
146  template<typename FUN>
147  void
148  defineCreator (FUN&& ctor)
149  {
150  creator_ = std::forward<FUN> (ctor);
151  }
152 
153  template<typename FUN>
154  void
156  {
157  creator_ = [this,ctor]
158  {
159  OBJ* obj = ctor();
160  atDestruction ([obj]{ delete obj; });
161  return obj;
162  };
163  }
164 
165  void
167  {
168  creator_ = []() -> OBJ*
169  {
170  throw error::Fatal("Service not available at this point of the Application Lifecycle"
171  ,error::LERR_(LIFECYCLE));
172  };
173  }
174 
175  template<typename FUN>
176  void
177  atDestruction (FUN&& additionalAction)
178  {
179  if (deleter_)
180  {
181  Deleter oldDeleter{std::move (deleter_)};
182  deleter_ = [oldDeleter, additionalAction]
183  {
184  oldDeleter();
185  additionalAction();
186  };
187  }
188  else
189  deleter_ = std::forward<FUN> (additionalAction);
190  }
191 
192  void
194  {
195  creator_ = std::move (source.creator_);
196  deleter_ = std::move (source.deleter_);
197  source.creator_ = Creator();
198  source.deleter_ = Deleter(); // clear possible leftover deleter
199  }
200 
201  private:
202  OBJ*
204  {
205  OBJ* obj = buildInstance<OBJ>();
206  atDestruction ([obj]{ delete obj; });
207  return obj;
208  }
209 
210  // try to instantiate the default ctor
211  template<class X, typename = decltype(X())>
212  static std::true_type __try_instantiate(int);
213  template<class>
214  static std::false_type __try_instantiate(...);
215 
220  template<typename X>
222  : decltype(__try_instantiate<X>(0))
223  { };
224 
225 
226  template<class TAR>
228  TAR* >
230  {
231  return new TAR;
232  }
233 
234  template<class ABS>
236  ABS* >
238  {
239  throw error::Fatal("Attempt to create a singleton instance of an abstract class. "
240  "Application architecture or lifecycle is seriously broken.");
241  }
242  template<class ABS>
243  static meta::disable_if<std::__or_<std::is_abstract<ABS>,canDefaultConstruct<ABS>>,
244  ABS* >
246  {
247  throw error::Fatal("Desired singleton class is not default constructible. "
248  "Application architecture or lifecycle is seriously broken.");
249  }
250  };
251 
252 
253 
258  template<class SRV>
259  class DependInject;
260 
261 
274  template<class SRV>
275  class Depend
276  {
277  using Instance = std::atomic<SRV*>;
280 
281  /* === shared per type === */
283  static Factory factory;
284 
285  friend class DependInject<SRV>;
286 
287 
288  public:
295  SRV&
297  {
298  SRV* object = instance.load (std::memory_order_acquire);
299  if (!object)
300  {
301  factory.zombieCheck();
302  Lock guard;
303 
304  object = instance.load (std::memory_order_relaxed);
305  if (!object)
306  {
307  object = factory();
308  factory.disable();
309  factory.atDestruction([]{ instance = nullptr; });
310  }
311  instance.store (object, std::memory_order_release);
312  }
313  ENSURE (object);
314  return *object;
315  }
316 
317 
322  explicit
323  operator bool() const
324  {
325  return instance.load (std::memory_order_acquire);
326  }
327  };
328 
329 
330 
331 
332  /* === allocate Storage for static per type instance management === */
333  template<class SRV>
334  std::atomic<SRV*> Depend<SRV>::instance;
335 
336  template<class SRV>
337  DependencyFactory<SRV> Depend<SRV>::factory;
338 
339 
340 
341 } // namespace lib
342 #endif /*LIB_DEPEND_H*/
void atDestruction(FUN &&additionalAction)
Definition: depend.hpp:177
static Instance instance
Definition: depend.hpp:282
typename enable_if_c< not Cond::value, T >::type disable_if
Definition: meta/util.hpp:94
std::function< OBJ *()> Creator
Definition: depend.hpp:123
Trigger the basic NoBug initialisation by placing a static variable.
typename enable_if_c< Cond::value, T >::type enable_if
SFINAE helper to control the visibility of specialisations and overloads.
Definition: meta/util.hpp:91
Simple and lightweight helpers for metaprogramming and type detection.
static meta::enable_if< canDefaultConstruct< TAR >, TAR * > buildInstance()
Definition: depend.hpp:229
Any copy and copy construction prohibited.
Definition: nocopy.hpp:46
void defineCreatorAndManage(FUN &&ctor)
Definition: depend.hpp:155
void transferDefinition(DependencyFactory &&source)
Definition: depend.hpp:193
Access point to singletons and other kinds of dependencies designated by type.
Definition: depend.hpp:275
std::function< void()> Deleter
Definition: depend.hpp:124
SRV & operator()()
Interface to be used by clients for retrieving the service instance.
Definition: depend.hpp:296
Implementation namespace for support and library code.
static std::true_type __try_instantiate(int)
Mix-Ins to allow or prohibit various degrees of copying and cloning.
This framework allows to (re)configure the lib::Depend front-end for dependency-injection.
std::atomic< SRV * > Instance
Definition: depend.hpp:277
static Factory factory
Definition: depend.hpp:283
void defineCreator(FUN &&ctor)
Definition: depend.hpp:148
#define LERR_(_NAME_)
Definition: error.hpp:58
metafunction: can we instantiate the desired object here?
Definition: depend.hpp:221
A special implementation of lib::Sync, where the storage of the object monitor is associated directly...
Automatic lifecycle tracker, to produce an alarm when accessing objects after deletion.
Lumiera error handling (C++ interface).
A synchronisation protection guard employing a lock scoped to the parameter type as a whole...
Helper to abstract creation and lifecycle of a dependency.
Definition: depend.hpp:120
ZombieCheck zombieCheck
Definition: depend.hpp:130
ENSURE(r==&pq)
static meta::enable_if< std::is_abstract< ABS >, ABS * > buildInstance()
Definition: depend.hpp:237
static meta::disable_if< std::__or_< std::is_abstract< ABS >, canDefaultConstruct< ABS > >, ABS * > buildInstance()
Definition: depend.hpp:245
LumieraError< LERR_(FATAL), Logic > Fatal
Definition: error.hpp:213