BatchInterfaceAdaptStruct.h
Go to the documentation of this file.
1/*!
2 *
3 *
4 * \brief Defines an batch adptor for structures.
5 *
6 *
7 *
8 * \author O.Krause
9 * \date 2012
10 *
11 *
12 * \par Copyright 1995-2017 Shark Development Team
13 *
14 * <BR><HR>
15 * This file is part of Shark.
16 * <https://shark-ml.github.io/Shark/>
17 *
18 * Shark is free software: you can redistribute it and/or modify
19 * it under the terms of the GNU Lesser General Public License as published
20 * by the Free Software Foundation, either version 3 of the License, or
21 * (at your option) any later version.
22 *
23 * Shark is distributed in the hope that it will be useful,
24 * but WITHOUT ANY WARRANTY; without even the implied warranty of
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 * GNU Lesser General Public License for more details.
27 *
28 * You should have received a copy of the GNU Lesser General Public License
29 * along with Shark. If not, see <http://www.gnu.org/licenses/>.
30 *
31 */
32#ifndef SHARK_DATA_BATCHINTERFACEADAPTSTRUCT_H
33#define SHARK_DATA_BATCHINTERFACEADAPTSTRUCT_H
34
35#include <boost/fusion/sequence/intrinsic/swap.hpp>
36#include <boost/fusion/algorithm/iteration/for_each.hpp>
37#include <boost/fusion/algorithm/transformation/transform.hpp>
39
40#include <boost/preprocessor/seq/transform.hpp>
41#include "Impl/BoostFusion151DefineStructInl.hpp"
42namespace shark{
43namespace detail{
44///serializes the object into the archive
45template<class Archive>
46struct ItemSerializer {
47 ItemSerializer(Archive& ar):m_ar(ar) {}
48
49 template<typename T>
50 void operator()(T& o)const{
51 m_ar & o;
52 }
53private:
54 Archive& m_ar;
55};
56
57
58struct CreateBatch{
59 CreateBatch(std::size_t size):m_size(size) {}
60
61 template<class> struct result;
62 template<class T>
63 struct result<CreateBatch(T const&)> {
64 typedef typename shark::Batch<T>::type type;
65 };
66
67 template<class T>
68 typename result<CreateBatch(T const&)>::type operator()(T const& value)const{
69 return shark::Batch<T>::createBatch(value,m_size);
70 }
71private:
72 std::size_t m_size;
73};
74struct resize{
75 resize(std::size_t size1, std::size_t size2):m_size1(size1),m_size2(size2){};
76 template<class T>
77 void operator()(T& batch)const{
78 BatchTraits<T>::type::resize(batch,m_size1,m_size2);
79 }
80private:
81 std::size_t m_size1;
82 std::size_t m_size2;
83};
84
85///calls getBatchElement(container,index) on a container. Used as boost fusion functor in the creation of references in the Batch Interface
86struct MakeRef{
87 template<class> struct result;
88 template<class T>
89 struct result<MakeRef(T const&)> {
90 typedef typename BatchTraits<T>::type::reference type;
91 };
92
93 MakeRef(std::size_t index):m_index(index){}
94
95 template<class T>
96 typename result<MakeRef(T const&) >::type operator()(T const& container)const{
97 return getBatchElement(const_cast<T&>(container),m_index);//we need the const cast since the argument type must be a const ref.
98 }
99private:
100 std::size_t m_index;
101};
102///calls getBatchElement(container,index) on a container. Used as boost fusion functor in the creation of references in the Batch Interface
103struct MakeConstRef{
104 template<class> struct result;
105 template<class T>
106 struct result<MakeConstRef(T const&)> {
107 typedef typename BatchTraits<T>::type::const_reference type;
108 };
109
110 MakeConstRef(std::size_t index):m_index(index){}
111
112 template<class T>
113 typename result<MakeConstRef(T const&) >::type operator()(T const& container)const{
114 return getBatchElement(container,m_index);
115 }
116private:
117 std::size_t m_index;
118};
119
120template<class FusionSequence>
121struct FusionFacade: public FusionSequence{
122 FusionFacade(){}
123 template<class Sequence>
124 FusionFacade(Sequence const& sequence):FusionSequence(sequence){}
125};
126
127template<class Type>
128struct isFusionFacade{
129private:
130 struct Big{ int big[100]; };
131 template <class S>
132 static Big tester(FusionFacade<S>*);
133 template <class S>
134 static Big tester(FusionFacade<S> const*);
135 static char tester(...);
136 static Type* generator();
137
138 BOOST_STATIC_CONSTANT(std::size_t, size = sizeof(tester(generator())));
139public:
140 BOOST_STATIC_CONSTANT(bool, value = (size!= 1));
141 typedef boost::mpl::bool_<value> type;
142};
143
144}
145
146template<class S>
147S& fusionize(detail::FusionFacade<S> & facade){
148 return static_cast<S&>(facade);
149}
150template<class S>
151S const& fusionize(detail::FusionFacade<S> const& facade){
152 return static_cast<S const&>(facade);
153}
154
155template<class S>
156typename boost::disable_if<detail::isFusionFacade<S>,S&>::type
157fusionize(S& facade){
158 return facade;
159}
160template<class S>
161typename boost::disable_if<detail::isFusionFacade<S>,S const& >::type
162fusionize(S const& facade){
163 return facade;
164}
165}
166#define SHARK_TRANSFORM_BATCH_ATTRIBUTES_TPL_IMPL(s,TYPE,ELEM)\
167 ( typename Batch<BOOST_PP_TUPLE_ELEM(2, 0, ELEM)>::TYPE,BOOST_PP_TUPLE_ELEM(2, 1, ELEM))
168
169#define SHARK_TRANSFORM_TUPLELIST_IMPL(s, data,ELEM)\
170 BOOST_PP_TUPLE_ELEM(2, 0, ELEM),BOOST_PP_TUPLE_ELEM(2, 1, ELEM)
171#define SHARK_TRANSFORM_TUPLELIST(ELEMS)\
172 BOOST_PP_SEQ_TRANSFORM(SHARK_TRANSFORM_TUPLELIST_IMPL, _ , ELEMS)
173
174#define SHARK_TRANSFORM_BATCH_ATTRIBUTES_TPL(TYPE,ATTRIBUTES)\
175 SHARK_TRANSFORM_TUPLELIST(BOOST_PP_SEQ_TRANSFORM(\
176 SHARK_TRANSFORM_BATCH_ATTRIBUTES_TPL_IMPL,\
177 TYPE, BOOST_PP_CAT(SHARK_FUSION_ADAPT_STRUCT_FILLER_0 ATTRIBUTES,_END)))
178
179#define SHARK_TRANSFORM_BATCH_ATTRIBUTES_IMPL(s,TYPE,ELEM)\
180 ( Batch<BOOST_PP_TUPLE_ELEM(2, 0, ELEM)>::TYPE,BOOST_PP_TUPLE_ELEM(2, 1, ELEM))
181
182#define SHARK_TRANSFORM_BATCH_ATTRIBUTES(TYPE,ATTRIBUTES)\
183 SHARK_TRANSFORM_TUPLELIST(BOOST_PP_SEQ_TRANSFORM(\
184 SHARK_TRANSFORM_BATCH_ATTRIBUTES_IMPL,\
185 TYPE, BOOST_PP_CAT(SHARK_FUSION_ADAPT_STRUCT_FILLER_0 ATTRIBUTES,_END)))
186
187///\brief creates default implementation for reference or const_reference types of Batches
188#define SHARK_CREATE_BATCH_REFERENCES_TPL(ATTRIBUTES)\
189private:\
190SHARK_FUSION_DEFINE_STRUCT_REF_INLINE(FusionRef, SHARK_TRANSFORM_BATCH_ATTRIBUTES_TPL(reference,ATTRIBUTES))\
191SHARK_FUSION_DEFINE_STRUCT_CONST_REF_INLINE(FusionConstRef, SHARK_TRANSFORM_BATCH_ATTRIBUTES_TPL(const_reference,ATTRIBUTES))\
192public:\
193struct reference: public detail::FusionFacade<FusionRef>{\
194 template<class Batch>\
195 reference(Batch& batch, std::size_t i)\
196 :detail::FusionFacade<FusionRef>(boost::fusion::transform(fusionize(batch),detail::MakeRef(i))){}\
197 template<class Other>\
198 reference& operator= (Other const& other ){\
199 fusionize(*this) = other;\
200 return *this;\
201 }\
202 reference& operator= (reference const& other ){\
203 fusionize(*this) = other;\
204 return *this;\
205 }\
206 friend void swap(reference op1, reference op2){\
207 boost::fusion::swap(op1,op2);\
208 }\
209 operator value_type()const{\
210 value_type ret;\
211 boost::fusion::copy(fusionize(*this), ret);\
212 return ret;\
213 }\
214};\
215struct const_reference: public detail::FusionFacade<FusionConstRef>{\
216private:\
217const_reference& operator= (const_reference const& other );\
218public:\
219 template<class Batch>\
220 const_reference(Batch& batch, std::size_t i)\
221 :detail::FusionFacade<FusionConstRef>(boost::fusion::transform(fusionize(batch),detail::MakeConstRef(i))){}\
222 operator value_type()const{\
223 value_type ret;\
224 boost::fusion::copy(fusionize(*this), ret);\
225 return ret;\
226 }\
227};
228
229#define SHARK_CREATE_BATCH_REFERENCES(ATTRIBUTES)\
230private:\
231SHARK_FUSION_DEFINE_STRUCT_REF_INLINE(FusionRef, SHARK_TRANSFORM_BATCH_ATTRIBUTES(reference,ATTRIBUTES))\
232SHARK_FUSION_DEFINE_STRUCT_CONST_REF_INLINE(FusionConstRef, SHARK_TRANSFORM_BATCH_ATTRIBUTES(const_reference,ATTRIBUTES))\
233public:\
234struct reference: public detail::FusionFacade<FusionRef>{\
235 template<class Batch>\
236 reference(Batch& batch, std::size_t i)\
237 :detail::FusionFacade<FusionRef>(boost::fusion::transform(fusionize(batch),detail::MakeRef(i))){}\
238 template<class Other>\
239 reference& operator= (Other const& other ){\
240 fusionize(*this) = other;\
241 return *this;\
242 }\
243 reference& operator= (reference const& other ){\
244 fusionize(*this) = other;\
245 return *this;\
246 }\
247 friend void swap(reference& op1, reference& op2){\
248 boost::fusion::swap(op1,op2);\
249 }\
250 operator value_type()const{\
251 value_type ret;\
252 boost::fusion::copy(fusionize(*this), ret);\
253 return ret;\
254 }\
255};\
256struct const_reference: public detail::FusionFacade<FusionConstRef>{\
257 template<class Batch>\
258 const_reference(Batch& batch, std::size_t i)\
259 :detail::FusionFacade<FusionConstRef>(boost::fusion::transform(fusionize(batch),detail::MakeConstRef(i))){}\
260 template<class Other>\
261 const_reference& operator= (Other const& other ){\
262 fusionize(*this) = other;\
263 return *this;\
264 }\
265 operator value_type()const{\
266 value_type ret;\
267 boost::fusion::copy(fusionize(*this), ret);\
268 return ret;\
269 }\
270};
271
272///\brief creates default typedefs for iterator or const_iterator types of Batches
273#define SHARK_CREATE_BATCH_ITERATORS()\
274typedef ProxyIterator<type, value_type, reference > iterator;\
275typedef ProxyIterator<const type, value_type, const_reference > const_iterator;\
276iterator begin(){\
277 return iterator(*this,0);\
278}\
279const_iterator begin()const{\
280 return const_iterator(*this,0);\
281}\
282iterator end(){\
283 return iterator(*this,size());\
284}\
285const_iterator end()const{\
286 return const_iterator(*this,size());\
287}
288
289///\brief This macro can be used to specialize a structure type easily to a batch type.
290///
291///Assume, that your input Data looks like:
292///<code>
293///template<class T>
294///struct DataType{
295/// RealVector A;
296/// T B;
297///};
298///</code>
299///Than the Batch type should propably look like
300///<code>
301///struct DataTypeBatch{
302/// RealMatrix A;
303/// RealVector B;
304///};
305///</code>
306///In this case the macro can be used to generate a complete specialisation of Batch<DataType>
307///<code>
308///#define DataVars (RealVector, A)(double B)
309///
310///SHARK_CREATE_BATCH_INTERFACE( DataType,DataVars)
311///};
312///As any other batch model th result also offers iterators over the range of elements.
313///In this case also boost::fusion support is added to the sequence. e.g. it is
314///handled similar to any other tuple type (RealMatrix,RealVector). This is useful for MKL or Transfer
315///kernels
316///</code>
317#define SHARK_CREATE_BATCH_INTERFACE(NAME,ATTRIBUTES)\
318private:\
319 SHARK_FUSION_DEFINE_STRUCT_INLINE(FusionType, SHARK_TRANSFORM_BATCH_ATTRIBUTES_TPL(type,ATTRIBUTES))\
320public:\
321 struct type: public detail::FusionFacade<FusionType>{\
322 typedef NAME value_type;\
323 \
324 SHARK_CREATE_BATCH_REFERENCES_TPL(ATTRIBUTES)\
325 SHARK_CREATE_BATCH_ITERATORS()\
326 \
327 type(){}\
328 type(std::size_t size1, std::size_t size2){\
329 resize(size1,size2);\
330 }\
331 void resize(std::size_t batchSize, std::size_t elementSize){\
332 boost::fusion::for_each(fusionize(*this), detail::resize(batchSize,elementSize));\
333 }\
334 \
335 friend void swap(type& op1, type& op2){\
336 boost::fusion::swap(fusionize(op1),fusionize(op2));\
337 }\
338 std::size_t size()const{\
339 return batchSize(boost::fusion::at_c<0>(fusionize(*this)));\
340 }\
341 reference operator[](std::size_t i){\
342 return *(begin()+i);\
343 }\
344 const_reference operator[](std::size_t i)const{\
345 return *(begin()+i);\
346 }\
347 template<class Archive>\
348 void serialize(Archive & archive,unsigned int version)\
349 {\
350 boost::fusion::for_each(fusionize(*this), detail::ItemSerializer<Archive>(archive));\
351 }\
352 };\
353 typedef NAME value_type;\
354 typedef typename type::reference reference;\
355 typedef typename type::const_reference const_reference;\
356 typedef typename type::iterator iterator;\
357 typedef typename type::const_iterator const_iterator;\
358 \
359 static type createBatch(value_type const& input, std::size_t size = 1){\
360 type batch;\
361 boost::fusion::copy(boost::fusion::transform(input,detail::CreateBatch(size)),fusionize(batch));\
362 return batch;\
363 }\
364 template<class Iterator>\
365 static type createBatchFromRange(Iterator const& begin, Iterator const& end){\
366 std::size_t points = end - begin;\
367 type batch = createBatch(*begin,points);\
368 Iterator pos = begin;\
369 for(std::size_t i = 0; i != points; ++i,++pos){\
370 getBatchElement(batch,i) = *pos;\
371 }\
372 return batch;\
373 }\
374 static void resize(type& batch, std::size_t batchSize, std::size_t elements){\
375 batch.resize(batchSize,elements);\
376 }\
377 template<class T>\
378 static std::size_t size(T const& batch){return batch.size();}\
379 \
380 template<class T>\
381 static typename T::reference get(T& batch, std::size_t i){\
382 return batch[i];\
383 }\
384 template<class T>\
385 static const_reference get(T const& batch, std::size_t i){\
386 return batch[i];\
387 }\
388 template<class T>\
389 static typename T::iterator begin(T& batch){\
390 return batch.begin();\
391 }\
392 template<class T>\
393 static const_iterator begin(T const& batch){\
394 return batch.begin();\
395 }\
396 template<class T>\
397 static typename T::iterator end(T& batch){\
398 return batch.end();\
399 }\
400 template<class T>\
401 static const_iterator end(T const& batch){\
402 return batch.end();\
403 }
404
405
406///\brief This macro can be used to specialize a structure type easily to a batch type.
407///
408///Assume, thjat your input Data looks like:
409///<code>
410///struct DataType{
411/// RealVector A;
412/// double B;
413///};
414///</code>
415///Than the Batch type should propably look like
416///<code>
417///struct DataTypeBatch{
418/// RealMatrix A;
419/// RealVector B;
420///};
421///</code>
422///In this case the macro can be used to generate a complete specialisation of Batch<DataType>
423///<code>
424///#define DataVars (RealVector, A)(double B)
425///
426///SHARK_CREATE_BATCH_INTERFACE( DataType,DataVars)
427///};
428///As any other batch model the result also offers iterators over the range of elements.
429///In this case also boost::fusion support is added to the sequence. e.g. it is
430///handled similar to any other tuple type (RealMatrix,RealVector). This is useful for MKL or Transfer
431///kernels
432///</code>
433#define SHARK_CREATE_BATCH_INTERFACE_NO_TPL(NAME,ATTRIBUTES)\
434private:\
435 SHARK_FUSION_DEFINE_STRUCT_INLINE(FusionType, SHARK_TRANSFORM_BATCH_ATTRIBUTES(type,ATTRIBUTES))\
436public:\
437 struct type: public detail::FusionFacade<FusionType>{\
438 typedef NAME value_type;\
439 \
440 SHARK_CREATE_BATCH_REFERENCES(ATTRIBUTES)\
441 SHARK_CREATE_BATCH_ITERATORS()\
442 \
443 type(){}\
444 type(std::size_t size1, std::size_t size2){\
445 resize(size1,size2);\
446 }\
447 void resize(std::size_t batchSize, std::size_t elementSize){\
448 boost::fusion::for_each(fusionize(*this), detail::resize(batchSize,elementSize));\
449 }\
450 reference operator[](std::size_t i){\
451 return *(begin()+i);\
452 }\
453 const_reference operator[](std::size_t i)const{\
454 return *(begin()+i);\
455 }\
456 friend void swap(type& op1, type& op2){\
457 boost::fusion::swap(fusionize(op1),fusionize(op2));\
458 }\
459 std::size_t size()const{\
460 return batchSize(boost::fusion::at_c<0>(fusionize(*this)));\
461 }\
462 template<class Archive>\
463 void serialize(Archive & archive,unsigned int version)\
464 {\
465 boost::fusion::for_each(fusionize(*this), detail::ItemSerializer<Archive>(archive));\
466 }\
467 };\
468 typedef NAME value_type;\
469 typedef type::reference reference;\
470 typedef type::const_reference const_reference;\
471 typedef type::iterator iterator;\
472 typedef type::const_iterator const_iterator;\
473 \
474 static type createBatch(value_type const& input, std::size_t size = 1){\
475 type batch;\
476 boost::fusion::copy(boost::fusion::transform(input,detail::CreateBatch(size)),fusionize(batch));\
477 return batch;\
478 }\
479 template<class Iterator>\
480 static type createBatchFromRange(Iterator const& begin, Iterator const& end){\
481 std::size_t points = end - begin;\
482 type batch = createBatch(*begin,points);\
483 Iterator pos = begin;\
484 for(std::size_t i = 0; i != points; ++i,++pos){\
485 getBatchElement(batch,i) = *pos;\
486 }\
487 return batch;\
488 }\
489 static void resize(type& batch, std::size_t batchSize, std::size_t elements){\
490 batch.resize(batchSize,elements);\
491 }\
492 template<class T>\
493 static std::size_t size(T const& batch){return batch.size();}\
494 \
495 template<class T>\
496 static typename T::reference get(T& batch, std::size_t i){\
497 return batch[i];\
498 }\
499 template<class T>\
500 static const_reference get(T const& batch, std::size_t i){\
501 return batch[i];\
502 }\
503 template<class T>\
504 static typename T::iterator begin(T& batch){\
505 return batch.begin();\
506 }\
507 template<class T>\
508 static const_iterator begin(T const& batch){\
509 return batch.begin();\
510 }\
511 template<class T>\
512 static typename T::iterator end(T& batch){\
513 return batch.end();\
514 }\
515 template<class T>\
516 static const_iterator end(T const& batch){\
517 return batch.end();\
518 }
519
520#endif