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) 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 
102 #ifndef LIB_DEPEND_H
103 #define LIB_DEPEND_H
104 
105 
106 #include "lib/error.hpp"
107 #include "lib/nocopy.hpp"
108 #include "lib/nobug-init.hpp"
109 #include "lib/sync-classlock.hpp"
110 #include "lib/zombie-check.hpp"
111 #include "lib/meta/util.hpp"
112 
113 #include <type_traits>
114 #include <functional>
115 #include <atomic>
116 #include <memory>
117 
118 
119 namespace lib {
120  namespace error = lumiera::error;
121 
122 
133  template<class OBJ>
136  {
137  using Creator = std::function<OBJ*()>;
138  using Deleter = std::function<void()>;
139 
140  Creator creator_;
141  Deleter deleter_;
142 
143  public:
144  ZombieCheck zombieCheck{util::typeStr<OBJ>()};
145 
146  DependencyFactory() = default;
148  {
149  if (deleter_)
150  deleter_();
151  }
152 
153  OBJ*
154  buildTarget()
155  {
156  return creator_? creator_()
157  : buildAndManage();
158  }
159 
160  template<typename FUN>
161  void
162  defineCreator (FUN&& ctor)
163  {
164  creator_ = std::forward<FUN> (ctor);
165  }
166 
167  template<typename FUN>
168  void
169  defineCreatorAndManage (FUN&& ctor)
170  {
171  creator_ = [this,ctor]
172  {
173  OBJ* obj = ctor();
174  atDestruction ([obj]{ delete obj; });
175  return obj;
176  };
177  }
178 
179  void
180  disable()
181  {
182  creator_ = []() -> OBJ*
183  {
184  throw error::Fatal("Service not available at this point of the Application Lifecycle"
185  ,LERR_(LIFECYCLE));
186  };
187  }
188 
189  template<typename FUN>
190  void
191  atDestruction (FUN&& additionalAction)
192  {
193  if (deleter_)
194  {
195  Deleter oldDeleter{std::move (deleter_)};
196  deleter_ = [oldDeleter, additionalAction]
197  {
198  oldDeleter();
199  additionalAction();
200  };
201  }
202  else
203  deleter_ = std::forward<FUN> (additionalAction);
204  }
205 
206  void
207  transferDefinition (DependencyFactory&& source)
208  {
209  creator_ = std::move (source.creator_);
210  deleter_ = std::move (source.deleter_);
211  source.creator_ = Creator();
212  source.deleter_ = Deleter(); // clear possible leftover deleter
213  }
214 
215  private:
216  OBJ*
217  buildAndManage()
218  {
219  OBJ* obj = buildInstance<OBJ>();
220  atDestruction ([obj]{ delete obj; });
221  return obj;
222  }
223 
224  // try to instantiate the default ctor
225  template<class X, typename = decltype(X())>
226  static std::true_type __try_instantiate(int);
227  template<class>
228  static std::false_type __try_instantiate(...);
229 
234  template<typename X>
236  : decltype(__try_instantiate<X>(0))
237  { };
238 
239 
240  template<class TAR>
242  TAR* >
243  buildInstance()
244  {
245  return new TAR;
246  }
247 
248  template<class ABS>
250  ABS* >
251  buildInstance()
252  {
253  throw error::Fatal("Attempt to create a singleton instance of an abstract class. "
254  "Application architecture or lifecycle is seriously broken.");
255  }
256  template<class ABS>
257  static meta::disable_if<std::__or_<std::is_abstract<ABS>,canDefaultConstruct<ABS>>,
258  ABS* >
259  buildInstance()
260  {
261  throw error::Fatal("Desired singleton class is not default constructible. "
262  "Application architecture or lifecycle is seriously broken.");
263  }
264  };
265 
266 
267 
272  template<class SRV>
273  class DependInject;
274 
275 
288  template<class SRV>
289  class Depend
290  {
291  using Instance = std::atomic<SRV*>;
294 
296  static Instance instance;
297 
298  static Factory&
299  factory()
300  {
301  static Factory sharedFactory;
302  return sharedFactory;
303  }
304 
305  friend class DependInject<SRV>;
306 
307 
308  public:
315  SRV&
316  operator() ()
317  {
318  SRV* object = instance.load (std::memory_order_acquire);
319  if (!object)
320  {
321  factory().zombieCheck();
322  Lock guard;
323 
324  object = instance.load (std::memory_order_relaxed);
325  if (!object)
326  {
327  object = factory().buildTarget();
328  factory().disable();
329  factory().atDestruction([]{ instance = nullptr; });
330  }
331  instance.store (object, std::memory_order_release);
332  }
333  ENSURE (object);
334  return *object;
335  }
336 
337 
342  explicit
343  operator bool() const
344  {
345  return instance.load (std::memory_order_acquire);
346  }
347 
352  {
353  factory().zombieCheck();
354  }
355  };
356 
357 
358 
359 
360  /* === allocate Storage for static per type instance management === */
361  template<class SRV>
362  std::atomic<SRV*> Depend<SRV>::instance;
363 
364 
365 
366 } // namespace lib
367 #endif /*LIB_DEPEND_H*/
static Instance instance
shared per type
Definition: depend.hpp:296
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:46
Access point to singletons and other kinds of dependencies designated by type.
Definition: depend.hpp:289
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:92
Derived specific exceptions within Lumiera&#39;s exception hierarchy.
Definition: error.hpp:199
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:235
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:134
Detector to set off alarm when (re)using deceased objects.