Lumiera  0.pre.03
»edit your freedom«
depend.hpp
Go to the documentation of this file.
1 /*
2  DEPEND.hpp - access point to singletons and dependencies
3 
4  Copyright (C)
5  2013, Hermann Vosseler <Ichthyostega@web.de>
6  2018, Hermann Vosseler <Ichthyostega@web.de>
7 
8   **Lumiera** is free software; you can redistribute it and/or modify it
9   under the terms of the GNU General Public License as published by the
10   Free Software Foundation; either version 2 of the License, or (at your
11   option) any later version. See the file COPYING for further details.
12 
13 */
14 
15 
93 #ifndef LIB_DEPEND_H
94 #define LIB_DEPEND_H
95 
96 
97 #include "lib/error.hpp"
98 #include "lib/nocopy.hpp"
99 #include "lib/nobug-init.hpp"
100 #include "lib/sync-classlock.hpp"
101 #include "lib/zombie-check.hpp"
102 #include "lib/meta/util.hpp"
103 
104 #include <type_traits>
105 #include <functional>
106 #include <atomic>
107 #include <memory>
108 
109 
110 namespace lib {
111  namespace error = lumiera::error;
112 
113 
124  template<class OBJ>
127  {
128  using Creator = std::function<OBJ*()>;
129  using Deleter = std::function<void()>;
130 
131  Creator creator_;
132  Deleter deleter_;
133 
134  public:
135  ZombieCheck zombieCheck{util::typeStr<OBJ>()};
136 
137  DependencyFactory() = default;
139  {
140  if (deleter_)
141  deleter_();
142  }
143 
144  OBJ*
145  buildTarget()
146  {
147  return creator_? creator_()
148  : buildAndManage();
149  }
150 
151  template<typename FUN>
152  void
153  defineCreator (FUN&& ctor)
154  {
155  creator_ = std::forward<FUN> (ctor);
156  }
157 
158  template<typename FUN>
159  void
160  defineCreatorAndManage (FUN&& ctor)
161  {
162  creator_ = [this,ctor]
163  {
164  OBJ* obj = ctor();
165  atDestruction ([obj]{ delete obj; });
166  return obj;
167  };
168  }
169 
170  void
171  disable()
172  {
173  creator_ = []() -> OBJ*
174  {
175  throw error::Fatal("Service not available at this point of the Application Lifecycle"
176  ,LERR_(LIFECYCLE));
177  };
178  }
179 
180  template<typename FUN>
181  void
182  atDestruction (FUN&& additionalAction)
183  {
184  if (deleter_)
185  {
186  Deleter oldDeleter{std::move (deleter_)};
187  deleter_ = [oldDeleter, additionalAction]
188  {
189  oldDeleter();
190  additionalAction();
191  };
192  }
193  else
194  deleter_ = std::forward<FUN> (additionalAction);
195  }
196 
197  void
198  transferDefinition (DependencyFactory&& source)
199  {
200  creator_ = std::move (source.creator_);
201  deleter_ = std::move (source.deleter_);
202  source.creator_ = Creator();
203  source.deleter_ = Deleter(); // clear possible leftover deleter
204  }
205 
206  private:
207  OBJ*
208  buildAndManage()
209  {
210  OBJ* obj = buildInstance<OBJ>();
211  atDestruction ([obj]{ delete obj; });
212  return obj;
213  }
214 
215  // try to instantiate the default ctor
216  template<class X, typename = decltype(X())>
217  static std::true_type __try_instantiate(int);
218  template<class>
219  static std::false_type __try_instantiate(...);
220 
225  template<typename X>
227  : decltype(__try_instantiate<X>(0))
228  { };
229 
230 
231  template<class TAR>
233  TAR* >
234  buildInstance()
235  {
236  return new TAR;
237  }
238 
239  template<class ABS>
241  ABS* >
242  buildInstance()
243  {
244  throw error::Fatal("Attempt to create a singleton instance of an abstract class. "
245  "Application architecture or lifecycle is seriously broken.");
246  }
247  template<class ABS>
248  static meta::disable_if<std::__or_<std::is_abstract<ABS>,canDefaultConstruct<ABS>>,
249  ABS* >
250  buildInstance()
251  {
252  throw error::Fatal("Desired singleton class is not default constructible. "
253  "Application architecture or lifecycle is seriously broken.");
254  }
255  };
256 
257 
258 
263  template<class SRV>
264  class DependInject;
265 
266 
279  template<class SRV>
280  class Depend
281  {
282  using Instance = std::atomic<SRV*>;
285 
287  static Instance instance;
288 
289  static Factory&
290  factory()
291  {
292  static Factory sharedFactory;
293  return sharedFactory;
294  }
295 
296  friend class DependInject<SRV>;
297 
298 
299  public:
306  SRV&
307  operator() ()
308  {
309  SRV* object = instance.load (std::memory_order_acquire);
310  if (!object)
311  {
312  factory().zombieCheck();
313  Lock guard;
314 
315  object = instance.load (std::memory_order_relaxed);
316  if (!object)
317  {
318  object = factory().buildTarget();
319  factory().disable();
320  factory().atDestruction([]{ instance = nullptr; });
321  }
322  instance.store (object, std::memory_order_release);
323  }
324  ENSURE (object);
325  return *object;
326  }
327 
328 
333  explicit
334  operator bool() const
335  {
336  return instance.load (std::memory_order_acquire);
337  }
338 
343  {
344  factory().zombieCheck();
345  }
346  };
347 
348 
349 
350 
351  /* === allocate Storage for static per type instance management === */
352  template<class SRV>
353  std::atomic<SRV*> Depend<SRV>::instance;
354 
355 
356 
357 } // namespace lib
358 #endif /*LIB_DEPEND_H*/
static Instance instance
shared per type
Definition: depend.hpp:287
Trigger the basic NoBug initialisation by placing a static variable.
Simple and lightweight helpers for metaprogramming and type detection.
Any copy and copy construction prohibited.
Definition: nocopy.hpp:37
Access point to singletons and other kinds of dependencies designated by type.
Definition: depend.hpp:280
Implementation namespace for support and library code.
typename enable_if_c< Cond::value, T >::type enable_if
SFINAE helper to control the visibility of specialisations and overloads.
Definition: meta/util.hpp:83
Derived specific exceptions within Lumiera&#39;s exception hierarchy.
Definition: error.hpp:190
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.
metafunction: can we instantiate the desired object here?
Definition: depend.hpp:226
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:125
Detector to set off alarm when (re)using deceased objects.