Project
Loading...
Searching...
No Matches
runtime_container.h
Go to the documentation of this file.
1// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
2// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3// All rights not expressly granted are reserved.
4//
5// This software is distributed under the terms of the GNU General Public
6// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7//
8// In applying this license CERN does not waive the privileges and immunities
9// granted to it by virtue of its status as an Intergovernmental Organization
10// or submit itself to any jurisdiction.
11
12//-*- Mode: C++ -*-
13
14#ifndef RUNTIME_CONTAINER_H
15#define RUNTIME_CONTAINER_H
16//****************************************************************************
17//* This file is free software: you can redistribute it and/or modify *
18//* it under the terms of the GNU General Public License as published by *
19//* the Free Software Foundation, either version 3 of the License, or *
20//* (at your option) any later version. *
21//* *
22//* Primary Author(s): Matthias Richter <mail@matthias-richter.com> *
23//* *
24//* The authors make no claims about the suitability of this software for *
25//* any purpose. It is provided "as is" without express or implied warranty. *
26//****************************************************************************
27
33
34// clang-format off
35
36// A general runtime container for a compile time sequence
37// of types. A mixin class is used to represent a member of each data
38// type. Every data type in the sequence describes a mixin on top of
39// the previous one. The runtime container accumulates the type
40// properties.
41
42#include <iostream>
43#include <iomanip>
44#include <boost/mpl/equal.hpp>
45#include <boost/mpl/minus.hpp>
46#include <boost/mpl/less.hpp>
47#include <boost/mpl/fold.hpp>
48#include <boost/mpl/lambda.hpp>
49#include <boost/mpl/vector.hpp>
50#include <boost/mpl/push_back.hpp>
51#include <boost/mpl/protect.hpp>
52#include <boost/mpl/begin.hpp>
53#include <boost/mpl/end.hpp>
54#include <boost/mpl/next.hpp>
55#include <boost/mpl/deref.hpp>
56#include <boost/mpl/at.hpp>
57#include <boost/mpl/range_c.hpp>
58#include <boost/mpl/size.hpp>
59
60using namespace boost::mpl::placeholders;
61
62namespace gNeric {
63
79{
80public:
83
84 void print() const {}
85};
86
91{
92 template<typename T>
93 void operator()(T&) {}
94};
95
109{
110 template<typename T>
111 void operator()(T& v) {v=0; v-=214.5;}
112};
113
118{
119 template<typename T>
120 bool operator()(const T& v, int level = -1) {return false;}
121};
122
126template<bool recursive = true>
128{
129 template<typename T>
130 bool operator()(const T& v, int level = -1) {
131 std::cout << "RC mixin level "
132 << std::setw(2)
133 << level << ": " << v << std::endl;
134 return recursive;
135 }
136};
137
142
143// preserve backward compatibility
145
150
154template<typename U>
156public:
157 typedef void return_type;
158 typedef U value_type;
159
160 set_value(U u) : mValue(u) {}
161 template<typename T>
163 *t = mValue;
164 }
165
166private:
167 set_value(); // forbidden
168 U mValue;
169};
170
174template<typename U>
176public:
177 typedef void return_type;
178 typedef U value_type;
179
180 add_value(U u) : mValue(u) {}
181 template<typename T>
183 *t += mValue;
184 }
185
186private:
187 add_value(); // forbidden
188 U mValue;
189};
190
197template<typename U>
199public:
200 typedef U return_type;
201 typedef U value_type;
202 class NullType {};
203private:
204 /* could not solve the problem that one has to instantiate Traits
205 with a fixed number of template arguments where wrapped_type
206 would need to be provided already to go into the specialization
207 template<typename InstanceType, typename Dummy = InstanceType>
208 struct Traits {
209 typedef NullType container_type;
210 typedef InstanceType type;
211 static return_type apply(InstanceType& c) {
212 std::cout << "Traits";
213 return c;
214 }
215 };
216 // specialization for container instances
217 template<typename InstanceType>
218 struct Traits<InstanceType, typename InstanceType::wrapped_type> {
219 typedef InstanceType container_type;
220 typedef typename InstanceType::wrapped_type type;
221 static return_type apply(InstanceType& c) {
222 std::cout << "specialized Traits";
223 return c.get();
224 }
225 };
226 */
227
228public:
229 template<typename T>
231 return t.get();
232 //return (typename Traits<T>::type)(t);
233 }
234};
235
236
237/******************************************************************************
238 * @brief apply functor to the wrapped member object in the runtime container
239 * This meta function recurses through the list while incrementing the index
240 * and calls the functor at the required position
241 *
242 * @note internal meta function for the RuntimeContainers' apply function
243 */
244template <
245 typename _ContainerT // container type
246 , typename _IndexT // data type of position index
247 , typename _Iterator // current iterator position
248 , typename _End // end iterator position
249 , _IndexT _Index // current index
250 , typename F // functor
251 >
253{
254 static typename F::return_type apply( _ContainerT& c, _IndexT position, F& f )
255 {
256 if ( position == _Index ) {
257 // this is the queried position, make the type cast to the current
258 // stage of the runtime container and execute function for it.
259 // Terminate loop by forwarding _End as _Iterator and thus
260 // calling the specialization
261 typedef typename boost::mpl::deref< _Iterator >::type stagetype;
262 stagetype& stage = static_cast<stagetype&>(c);
263 return f(stage);
264 } else {
265 // go to next element
266 return rc_apply_at<
267 _ContainerT
268 , _IndexT
269 , typename boost::mpl::next< _Iterator >::type
270 , _End
271 , _Index + 1
272 , F
273 >::apply( c, position, f );
274 }
275 }
276};
277// specialization: end of recursive loop, kicks in if _Iterator matches
278// _End.
279// here we end up if the position parameter is out of bounds
280template <
281 typename _ContainerT // container type
282 , typename _IndexT // data type of position index
283 , typename _End // end iterator position
284 , _IndexT _Index // current index
285 , typename F // functor
286 >
287struct rc_apply_at<_ContainerT
288 , _IndexT
289 , _End
290 , _End
291 , _Index
292 , F
293 >
294{
295 static typename F::return_type apply( _ContainerT& c, _IndexT position, F& f )
296 {
297 // TODO: this is probably the place to throw an exeption because
298 // we are out of bound
299 return typename F::return_type(0);
300 }
301};
302
308template<typename _ContainerT
309 , typename _StageT
310 , typename _IndexT
311 , typename F>
312struct rc_apply {
313 typedef typename _ContainerT::types types;
314 static typename F::return_type apply(_ContainerT& c, _IndexT /*ignored*/, F& f)
315 {
316 return f(static_cast<_StageT&>(c));
317 }
318};
319
328template<typename _ContainerT
329 , typename F
330 , typename Position = boost::mpl::size<typename _ContainerT::types>
331 , typename _IndexT = int
332 >
334 typedef typename _ContainerT::types types;
335 typedef typename boost::mpl::if_<
336 boost::mpl::less<Position, boost::mpl::size<types> >
338 , rc_apply_at<
339 _ContainerT
340 , _IndexT
341 , typename boost::mpl::begin<types>::type
342 , typename boost::mpl::end<types>::type
343 , 0
344 , F
345 >
347
348 static typename F::return_type apply(_ContainerT& c, _IndexT position, F& f) {
349 return type::apply(c, position, f);
350 }
351};
352
363template<typename InterfacePolicy = DefaultInterface
364 , typename InitializerPolicy = default_initializer
365 , typename PrinterPolicy = default_printer>
366struct RuntimeContainer : public InterfacePolicy
367{
368 InitializerPolicy _initializer;
369 PrinterPolicy _printer;
370 typedef boost::mpl::int_<-1> level;
371 typedef boost::mpl::vector<>::type types;
372
374 constexpr std::size_t size() const {return 0;}
375
376 void print() {
377 const char* string = "base";
378 _printer(string, level::value);
379 }
380
381 // not yet clear if we need the setter and getter in the base class
382 // at least wrapped_type is not defined in the base
383 //void set(wrapped_type) {mMember = v;}
384 //wrapped_type get() const {return mMember;}
385
386};
387
399template <typename BASE, typename T>
400class rc_mixin : public BASE
401{
402public:
403 rc_mixin() : mMember() {BASE::_initializer(mMember);}
404
406 typedef T wrapped_type;
410 typedef typename boost::mpl::push_back<typename BASE::types, mixin_type>::type types;
412 typedef typename boost::mpl::plus< typename BASE::level, boost::mpl::int_<1> >::type level;
413 void print() {
414 // use the printer policy of this level, the policy returns
415 // a bool determining whether to call the underlying level
416 if (BASE::_printer(mMember, level::value)) {
417 BASE::print();
418 }
419 }
420
422 constexpr std::size_t size() const {return level::value + 1;}
424 void set(wrapped_type v) {mMember = v;}
426 wrapped_type get() const {return mMember;}
428 wrapped_type& operator*() {return mMember;}
430 wrapped_type& operator=(const wrapped_type& v) {mMember = v; return mMember;}
432 operator wrapped_type() const {return mMember;}
434 wrapped_type& operator+=(const wrapped_type& v) {mMember += v; return mMember;}
436 wrapped_type operator+(const wrapped_type& v) {return mMember + v;}
437
441 template<typename F>
443 public:
444 member_apply_at(F& f) : mFunctor(f) {}
445 typedef typename F::return_type return_type;
446 template<typename _T>
447 typename F::return_type operator()(_T& me) {
448 return mFunctor(*me);
449 }
450 private:
451 member_apply_at(); //forbidden
452 F& mFunctor;
453 };
454
462 /*
463 template<typename F>
464 typename F::return_type applyToMember(int index, F f) {
465 return apply(index, member_apply_at<F>(f));
466 }
467 */
468
469 /*
470 * Apply a functor to the runtime container at index
471 *
472 * For performance tests there is a template option to do an explicite loop
473 * unrolling for the first n (=10) elements. This is however only effective
474 * if the compiler optimization is switched of. This is in the end a nice
475 * demonstrator for the potential of compiler optimization. Unrolling is
476 * switched on with the compile time switch RC_UNROLL.
477 */
478 template<typename F
479#ifdef RC_UNROLL
480 , bool unroll = true
481#else
482 , bool unroll = false
483#endif
484 >
485 typename F::return_type apply(int index, F f) {
486 if (unroll) {// this is a compile time switch
487 // do unrolling for the first n elements and forward to generic
488 // recursive function for the rest.
489 switch (index) {
490 case 0: return rc_dispatcher<mixin_type, F, boost::mpl::int_<0>, int>::apply(*this, 0, f);
491 case 1: return rc_dispatcher<mixin_type, F, boost::mpl::int_<1>, int>::apply(*this, 1, f);
492 case 2: return rc_dispatcher<mixin_type, F, boost::mpl::int_<2>, int>::apply(*this, 2, f);
493 case 3: return rc_dispatcher<mixin_type, F, boost::mpl::int_<3>, int>::apply(*this, 3, f);
494 case 4: return rc_dispatcher<mixin_type, F, boost::mpl::int_<4>, int>::apply(*this, 4, f);
495 case 5: return rc_dispatcher<mixin_type, F, boost::mpl::int_<5>, int>::apply(*this, 5, f);
496 case 6: return rc_dispatcher<mixin_type, F, boost::mpl::int_<6>, int>::apply(*this, 6, f);
497 case 7: return rc_dispatcher<mixin_type, F, boost::mpl::int_<7>, int>::apply(*this, 7, f);
498 case 8: return rc_dispatcher<mixin_type, F, boost::mpl::int_<8>, int>::apply(*this, 8, f);
499 case 9: return rc_dispatcher<mixin_type, F, boost::mpl::int_<9>, int>::apply(*this, 9, f);
500 }
501 }
503 }
504
505private:
506 T mMember;
507};
508
514typedef typename boost::mpl::lambda< rc_mixin<_1, _2> >::type apply_rc_mixin;
515
521template< typename T, typename N > struct rtc_less
522: boost::mpl::bool_<(T::level::value < boost::mpl::minus<N, boost::mpl::int_<1>>::value) > {};
523
524template< typename T, typename N > struct rtc_equal
525: boost::mpl::bool_<boost::mpl::equal<typename T::wrapped_type, N>::type> {};
526
534template<typename Types, typename Base, typename N = boost::mpl::size<Types>>
535struct create_rtc
536{
537 typedef typename boost::mpl::lambda<
538 // mpl fold loops over all elements in the list of the first template
539 // parameter and provides this as placeholder _2; for every element the
540 // operation of the third template parameter is applied to the result of
541 // the previous stage which is provided as placeholder _1 to the operation
542 // and initialized to the second template argument for the very first
543 // operation
544 typename boost::mpl::fold<
545 // list of types, each element provided as placeholder _1
546 Types
547 // initializer for the _1 placeholder
548 , Base
549 // recursively applied operation, depending on the outcome of rtc_less
550 // either the next mixin level is applied or the current state is used
551 , boost::mpl::if_<
552 rtc_less<_1, N >
553 // apply mixin level
554 , boost::mpl::apply2< boost::mpl::protect<apply_rc_mixin>::type, _1, _2 >
555 // keep current state by identity
556 , boost::mpl::identity<_1>
557 >
558 >::type
559 >::type type;
560};
561
570template<typename Types, typename Base, typename N = boost::mpl::size<Types>>
571struct create_rtc_types
572{
573 typedef typename boost::mpl::fold<
574 boost::mpl::range_c<int, 0, N::value>
575 , boost::mpl::vector< >
576 , boost::mpl::push_back<_1, create_rtc<Types , Base , boost::mpl::plus<_2, boost::mpl::int_<1>>>>
577 >::type type;
578};
579
580};// namespace gNeric
581// clang-format on
582
583#endif
uint32_t c
Definition RawData.h:2
The default interface for the RuntimeContainer.
return_type operator()(T &t)
Getter functor, forwards to the container mixin's get function.
return_type operator()(T &t)
Mixin component is used with different data types.
wrapped_type & operator*()
get wrapped object reference
wrapped_type get() const
get wrapped object
wrapped_type operator+(const wrapped_type &v)
operator
rc_mixin< BASE, wrapped_type > mixin_type
this is the self type
constexpr std::size_t size() const
get size at this stage
T wrapped_type
each stage of the mixin class wraps one type
boost::mpl::push_back< typenameBASE::types, mixin_type >::type types
a vector of all mixin stage types so far
void set(wrapped_type v)
set member wrapped object
wrapped_type & operator+=(const wrapped_type &v)
operator
F::return_type apply(int index, F f)
boost::mpl::plus< typenameBASE::level, boost::mpl::int_< 1 > >::type level
increment the level counter
wrapped_type & operator=(const wrapped_type &v)
assignment operator to wrapped type
Setter functor, forwards to the container mixin's set function.
return_type operator()(T &t)
const GLdouble * v
Definition glcorearb.h:832
GLuint index
Definition glcorearb.h:781
GLdouble f
Definition glcorearb.h:310
GLint GLint GLsizei GLint GLenum GLenum type
Definition glcorearb.h:275
recursive_printer verbose_printer
boost::mpl::lambda< rc_mixin< _1, _2 > >::type apply_rc_mixin
Applying rc_mixin with the template parameters as placeholders The wrapping into an mpl lambda is nec...
the technical base of the mixin class
boost::mpl::int_<-1 > level
constexpr std::size_t size() const
get size which is 0 at this level
InitializerPolicy _initializer
boost::mpl::vector ::type types
Default initializer does nothing.
Default printer prints nothing.
bool operator()(const T &v, int level=-1)
An initializer for simple types The initializer makes use of truncation for non-float types,...
static F::return_type apply(_ContainerT &c, _IndexT position, F &f)
static F::return_type apply(_ContainerT &c, _IndexT position, F &f)
_ContainerT::types types
static F::return_type apply(_ContainerT &c, _IndexT, F &f)
static F::return_type apply(_ContainerT &c, _IndexT position, F &f)
boost::mpl::if_< boost::mpl::less< Position, boost::mpl::size< types > >, rc_apply< _ContainerT, typenameboost::mpl::at< types, Position >::type, _IndexT, F >, rc_apply_at< _ContainerT, _IndexT, typenameboost::mpl::begin< types >::type, typenameboost::mpl::end< types >::type, 0, F > >::type type
_ContainerT::types types
Verbose printer to print levels recursively.
check the mixin level to be below specified level
Verbose printer to print a single level.
Verbose printer prints level and content.
bool operator()(const T &v, int level=-1)