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) Lumiera.org
5  2009, Hermann Vosseler <Ichthyostega@web.de>
6 
7  This program is free software; you can redistribute it and/or
8  modify it under the terms of the GNU General Public License as
9  published by the Free Software Foundation; either version 2 of
10  the License, or (at your option) any later version.
11 
12  This program is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  GNU General Public License for more details.
16 
17  You should have received a copy of the GNU General Public License
18  along with this program; if not, write to the Free Software
19  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 
21 */
22 
61 #ifndef LIB_MULTIFACT_H
62 #define LIB_MULTIFACT_H
63 
64 
65 #include "lib/error.hpp"
66 #include "lib/depend.hpp"
67 #include "util.hpp"
68 
69 #include <functional>
70 #include <utility>
71 #include <memory>
72 #include <map>
73 
74 
75 
76 namespace lib {
77  namespace factory {
78 
79  // Helpers to wrap the factory's product
80 
87  template<typename TAR>
88  struct PassAsIs
89  {
90  typedef TAR RawType;
91  typedef TAR BareType;
92  typedef TAR ResultType;
93 
94  template<class FUN, typename... ARGS>
95  ResultType
96  wrap (FUN create, ARGS&&... args) noexcept
97  {
98  return create(std::forward<ARGS>(args)...);
99  }
100  };
101 
102 
107  template<typename RAW>
109  {
110  using RawType = typename std::remove_pointer<RAW>::type;
111  using BareType = RawType *;
113 
114  template<class FUN, typename... ARGS>
115  ResultType
116  wrap (FUN create, ARGS&&... args)
117  {
118  return ResultType (create(std::forward<ARGS>(args)...));
119  }
120  };
121 
122 
134  template<typename TAR>
135  struct Build
136  {
137  template<typename RAW>
138  struct Wrapper
139  {
140  using RawType = RAW;
141  using BareType = RAW;
142  using ResultType = TAR;
143 
144  using WrapFunc = std::function<ResultType(BareType)>;
145 
146  void
147  defineFinalWrapper (WrapFunc&& fun)
148  {
149  this->wrapper_ = fun;
150  }
151 
152  template<class FUN, typename... ARGS>
153  ResultType
154  wrap (FUN create, ARGS&&... args)
155  {
156  return wrapper_(std::forward<BareType> (create(std::forward<ARGS>(args)...)));
157  }
158 
159  private:
160  WrapFunc wrapper_;
161  };
162  };
163 
164 
165 
166 
167 
174  template<typename SIG, typename ID>
175  struct Fab
176  {
177  typedef std::function<SIG> FactoryFunc;
178 
179 
180  FactoryFunc&
181  select (ID const& id)
182  {
183  if (!contains (id))
184  throw lumiera::error::Invalid("unknown factory product requested.");
185 
186  return producerTable_[id];
187  }
188 
189  void
190  defineProduction (ID const& id, FactoryFunc fun)
191  {
192  producerTable_[id] = fun;
193  }
194 
195 
196  /* === diagnostics === */
197 
198  bool empty () const { return producerTable_.empty(); }
199  bool contains (ID id) const { return util::contains (producerTable_,id); }
200 
201  private:
202  std::map<ID, FactoryFunc> producerTable_;
203  };
204 
205 
206 
211  template< typename TY
212  , template<class> class Wrapper
213  >
214  struct FabConfig
215  {
216  using WrapFunctor = Wrapper<TY>;
217  using BareProduct = typename WrapFunctor::BareType;
218  using WrappedProduct = typename WrapFunctor::ResultType;
219 
220  typedef BareProduct SIG_Fab(void);
221 
222  enum{ ARGUMENT_CNT = 0 };
223  };
228  template< typename RET
229  , typename... ARGS
230  , template<class> class Wrapper
231  >
232  struct FabConfig<RET(ARGS...), Wrapper>
233  {
234  using WrapFunctor = Wrapper<RET>;
235  using BareProduct = typename WrapFunctor::BareType;
236  using WrappedProduct = typename WrapFunctor::ResultType;
237 
238  typedef BareProduct SIG_Fab(ARGS...);
239 
240  enum{ ARGUMENT_CNT = sizeof...(ARGS)};
241  };
242 
243 
244 
245 
246  /* === Main type === */
247 
258  template< typename SIG
259  , typename ID
260  , template<class> class Wrapper = PassAsIs
261  >
262  class MultiFact
263  : public FabConfig<SIG,Wrapper>::WrapFunctor
264  {
266  using SIG_Fab = typename _Conf::SIG_Fab;
267  using _Fab = Fab<SIG_Fab,ID>;
268 
269  _Fab funcTable_;
270 
271 
272  protected:
273  using Creator = typename _Fab::FactoryFunc;
274 
275  Creator&
276  selectProducer (ID const& id)
277  {
278  return funcTable_.select(id);
279  }
280 
281 
282  public:
283  using Product = typename _Conf::WrappedProduct;
284 
294  template<typename... ARGS>
295  Product
296  operator() (ID const& id, ARGS&& ...args)
297  {
298  static_assert (sizeof...(ARGS) == _Conf::ARGUMENT_CNT,
299  "MultiFac instance invoked with the wrong number "
300  "of fabrication arguments. See template parameter SIG");
301 
302  Creator& creator = selectProducer (id);
303  return this->wrap (creator, std::forward<ARGS>(args)...);
304  }
305 
307  template<typename... ARGS>
308  Product
309  invokeFactory (ID const& id, ARGS&& ...args)
310  {
311  return this->operator() (id, std::forward<ARGS>(args)...);
312  }
313 
314 
318  template<typename FUNC>
319  void
320  defineProduction (ID id, FUNC&& fun)
321  {
322  funcTable_.defineProduction (id, fun);
323  }
324 
325 
331  template<class IMP>
332  class Singleton
333  : lib::Depend<IMP>
334  {
336 
337  Creator
338  createSingleton_accessFunction()
339  {
340  return std::bind (&SingleFact::operator()
341  , static_cast<SingleFact*>(this));
342  }
343 
344  public:
345  Singleton (MultiFact& factory, ID id)
346  {
347  factory.defineProduction(id, createSingleton_accessFunction());
348  }
349  };
350 
351 
352  /* === diagnostics === */
353 
354  bool empty () const { return funcTable_.empty(); }
355  bool contains (ID id) const { return funcTable_.contains (id); }
356  };
357 
358 
359 
360 }} // namespace lib::factory
361 #endif
Dummy "wrapper", to perform the fabrication and return the unaltered product.
Definition: multifact.hpp:88
Policy: use a custom functor to finish the generated product.
Definition: multifact.hpp:135
Access point to singletons and other kinds of dependencies designated by type.
Definition: depend.hpp:289
lib::TypedContext< Goal::Result > ResultType
Context used for generating type-IDs to denote the specific result types of issued queries...
Definition: query.hpp:222
Implementation namespace for support and library code.
Derived specific exceptions within Lumiera&#39;s exception hierarchy.
Definition: error.hpp:199
Factory for creating a family of objects by ID.
Definition: multifact.hpp:262
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:320
Lumiera error handling (C++ interface).
Table of registered production functions for MultiFact.
Definition: multifact.hpp:175
Wrapper taking ownership, by wrapping into smart-ptr.
Definition: multifact.hpp:108
Convenience shortcut for automatically setting up a production line, to fabricate a singleton instanc...
Definition: multifact.hpp:332
Product invokeFactory(ID const &id, ARGS &&...args)
more legible alias for the function operator
Definition: multifact.hpp:309