Lumiera  0.pre.03
»edit your freedom«
multifact.hpp
Go to the documentation of this file.
1 /*
2  MULTIFACT.hpp - flexible family-of-object factory template
3 
4  Copyright (C)
5  2009, Hermann Vosseler <Ichthyostega@web.de>
6 
7   **Lumiera** is free software; you can redistribute it and/or modify it
8   under the terms of the GNU General Public License as published by the
9   Free Software Foundation; either version 2 of the License, or (at your
10   option) any later version. See the file COPYING for further details.
11 
12 */
13 
52 #ifndef LIB_MULTIFACT_H
53 #define LIB_MULTIFACT_H
54 
55 
56 #include "lib/error.hpp"
57 #include "lib/depend.hpp"
58 #include "util.hpp"
59 
60 #include <functional>
61 #include <utility>
62 #include <memory>
63 #include <map>
64 
65 
66 
67 namespace lib {
68  namespace factory {
69 
70  // Helpers to wrap the factory's product
71 
78  template<typename TAR>
79  struct PassAsIs
80  {
81  typedef TAR RawType;
82  typedef TAR BareType;
83  typedef TAR ResultType;
84 
85  template<class FUN, typename... ARGS>
86  ResultType
87  wrap (FUN create, ARGS&&... args) noexcept
88  {
89  return create(std::forward<ARGS>(args)...);
90  }
91  };
92 
93 
98  template<typename RAW>
100  {
101  using RawType = typename std::remove_pointer<RAW>::type;
102  using BareType = RawType *;
104 
105  template<class FUN, typename... ARGS>
106  ResultType
107  wrap (FUN create, ARGS&&... args)
108  {
109  return ResultType (create(std::forward<ARGS>(args)...));
110  }
111  };
112 
113 
125  template<typename TAR>
126  struct Build
127  {
128  template<typename RAW>
129  struct Wrapper
130  {
131  using RawType = RAW;
132  using BareType = RAW;
133  using ResultType = TAR;
134 
135  using WrapFunc = std::function<ResultType(BareType)>;
136 
137  void
138  defineFinalWrapper (WrapFunc&& fun)
139  {
140  this->wrapper_ = fun;
141  }
142 
143  template<class FUN, typename... ARGS>
144  ResultType
145  wrap (FUN create, ARGS&&... args)
146  {
147  return wrapper_(std::forward<BareType> (create(std::forward<ARGS>(args)...)));
148  }
149 
150  private:
151  WrapFunc wrapper_;
152  };
153  };
154 
155 
156 
157 
158 
165  template<typename SIG, typename ID>
166  struct Fab
167  {
168  typedef std::function<SIG> FactoryFunc;
169 
170 
171  FactoryFunc&
172  select (ID const& id)
173  {
174  if (!contains (id))
175  throw lumiera::error::Invalid("unknown factory product requested.");
176 
177  return producerTable_[id];
178  }
179 
180  void
181  defineProduction (ID const& id, FactoryFunc fun)
182  {
183  producerTable_[id] = fun;
184  }
185 
186 
187  /* === diagnostics === */
188 
189  bool empty () const { return producerTable_.empty(); }
190  bool contains (ID id) const { return util::contains (producerTable_,id); }
191 
192  private:
193  std::map<ID, FactoryFunc> producerTable_;
194  };
195 
196 
197 
202  template< typename TY
203  , template<class> class Wrapper
204  >
205  struct FabConfig
206  {
207  using WrapFunctor = Wrapper<TY>;
208  using BareProduct = typename WrapFunctor::BareType;
209  using WrappedProduct = typename WrapFunctor::ResultType;
210 
211  typedef BareProduct SIG_Fab(void);
212 
213  enum{ ARGUMENT_CNT = 0 };
214  };
219  template< typename RET
220  , typename... ARGS
221  , template<class> class Wrapper
222  >
223  struct FabConfig<RET(ARGS...), Wrapper>
224  {
225  using WrapFunctor = Wrapper<RET>;
226  using BareProduct = typename WrapFunctor::BareType;
227  using WrappedProduct = typename WrapFunctor::ResultType;
228 
229  typedef BareProduct SIG_Fab(ARGS...);
230 
231  enum{ ARGUMENT_CNT = sizeof...(ARGS)};
232  };
233 
234 
235 
236 
237  /* === Main type === */
238 
249  template< typename SIG
250  , typename ID
251  , template<class> class Wrapper = PassAsIs
252  >
253  class MultiFact
254  : public FabConfig<SIG,Wrapper>::WrapFunctor
255  {
257  using SIG_Fab = typename _Conf::SIG_Fab;
258  using _Fab = Fab<SIG_Fab,ID>;
259 
260  _Fab funcTable_;
261 
262 
263  protected:
264  using Creator = typename _Fab::FactoryFunc;
265 
266  Creator&
267  selectProducer (ID const& id)
268  {
269  return funcTable_.select(id);
270  }
271 
272 
273  public:
274  using Product = typename _Conf::WrappedProduct;
275 
285  template<typename... ARGS>
286  Product
287  operator() (ID const& id, ARGS&& ...args)
288  {
289  static_assert (sizeof...(ARGS) == _Conf::ARGUMENT_CNT,
290  "MultiFac instance invoked with the wrong number "
291  "of fabrication arguments. See template parameter SIG");
292 
293  Creator& creator = selectProducer (id);
294  return this->wrap (creator, std::forward<ARGS>(args)...);
295  }
296 
298  template<typename... ARGS>
299  Product
300  invokeFactory (ID const& id, ARGS&& ...args)
301  {
302  return this->operator() (id, std::forward<ARGS>(args)...);
303  }
304 
305 
309  template<typename FUNC>
310  void
311  defineProduction (ID id, FUNC&& fun)
312  {
313  funcTable_.defineProduction (id, fun);
314  }
315 
316 
322  template<class IMP>
323  class Singleton
324  : lib::Depend<IMP>
325  {
327 
328  Creator
329  createSingleton_accessFunction()
330  {
331  return std::bind (&SingleFact::operator()
332  , static_cast<SingleFact*>(this));
333  }
334 
335  public:
336  Singleton (MultiFact& factory, ID id)
337  {
338  factory.defineProduction(id, createSingleton_accessFunction());
339  }
340  };
341 
342 
343  /* === diagnostics === */
344 
345  bool empty () const { return funcTable_.empty(); }
346  bool contains (ID id) const { return funcTable_.contains (id); }
347  };
348 
349 
350 
351 }} // namespace lib::factory
352 #endif
Dummy "wrapper", to perform the fabrication and return the unaltered product.
Definition: multifact.hpp:79
Policy: use a custom functor to finish the generated product.
Definition: multifact.hpp:126
Access point to singletons and other kinds of dependencies designated by type.
Definition: depend.hpp:280
lib::TypedContext< Goal::Result > ResultType
Context used for generating type-IDs to denote the specific result types of issued queries...
Definition: query.hpp:213
Implementation namespace for support and library code.
Derived specific exceptions within Lumiera&#39;s exception hierarchy.
Definition: error.hpp:190
Factory for creating a family of objects by ID.
Definition: multifact.hpp:253
Tiny helper functions and shortcuts to be used everywhere Consider this header to be effectively incl...
Singleton services and Dependency Injection.
void defineProduction(ID id, FUNC &&fun)
to set up a production line, associated with a specific ID
Definition: multifact.hpp:311
Lumiera error handling (C++ interface).
Table of registered production functions for MultiFact.
Definition: multifact.hpp:166
Wrapper taking ownership, by wrapping into smart-ptr.
Definition: multifact.hpp:99
Convenience shortcut for automatically setting up a production line, to fabricate a singleton instanc...
Definition: multifact.hpp:323
Product invokeFactory(ID const &id, ARGS &&...args)
more legible alias for the function operator
Definition: multifact.hpp:300