• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 /** \file
18  * Templates used to declare parameters.
19  */
20 #ifndef C2PARAM_DEF_H_
21 #define C2PARAM_DEF_H_
22 
23 #include <type_traits>
24 
25 #include <C2Param.h>
26 
27 /// \addtogroup Parameters
28 /// @{
29 
30 /* ======================== UTILITY TEMPLATES FOR PARAMETER DEFINITIONS ======================== */
31 
32 /// \addtogroup internal
33 /// @{
34 
35 /// Helper class that checks if a type has equality and inequality operators.
36 struct C2_HIDE _C2Comparable_impl
37 {
38     template<typename S, typename=decltype(S() == S())>
39     static std::true_type TestEqual(int);
40     template<typename>
41     static std::false_type TestEqual(...);
42 
43     template<typename S, typename=decltype(S() != S())>
44     static std::true_type TestNotEqual(int);
45     template<typename>
46     static std::false_type TestNotEqual(...);
47 };
48 
49 /**
50  * Helper template that returns if a type has equality and inequality operators.
51  *
52  * Use as _C2Comparable<typename S>::value.
53  */
54 template<typename S>
55 struct C2_HIDE _C2Comparable
56     : public std::integral_constant<bool, decltype(_C2Comparable_impl::TestEqual<S>(0))::value
57                         || decltype(_C2Comparable_impl::TestNotEqual<S>(0))::value> {
58 };
59 
60 ///  Helper class that checks if a type has a CORE_INDEX constant.
61 struct C2_HIDE _C2CoreIndexHelper_impl
62 {
63     template<typename S, int=S::CORE_INDEX>
64     static std::true_type TestCoreIndex(int);
65     template<typename>
66     static std::false_type TestCoreIndex(...);
67 };
68 
69 /// Macro that defines and thus overrides a type's CORE_INDEX for a setting
70 #define _C2_CORE_INDEX_OVERRIDE(coreIndex) \
71 public: \
72     enum : uint32_t { CORE_INDEX = coreIndex };
73 
74 
75 /// Helper template that adds a CORE_INDEX to a type if it does not have one (for testing)
76 template<typename S, int CoreIndex>
77 struct C2_HIDE _C2AddCoreIndex : public S {
78     _C2_CORE_INDEX_OVERRIDE(CoreIndex)
79 };
80 
81 /**
82  * \brief Helper class to check struct requirements for parameters.
83  *
84  * Features:
85  *  - verify default constructor, no virtual methods, and no equality operators.
86  *  - expose PARAM_TYPE, and non-flex FLEX_SIZE.
87  */
88 template<typename S, int CoreIndex, unsigned TypeFlags>
89 struct C2_HIDE _C2StructCheck {
90     static_assert(
91             std::is_default_constructible<S>::value, "C2 structure must have default constructor");
92     static_assert(!std::is_polymorphic<S>::value, "C2 structure must not have virtual methods");
93     static_assert(!_C2Comparable<S>::value, "C2 structure must not have operator== or !=");
94 
95 public:
96     enum : uint32_t {
97         PARAM_TYPE = CoreIndex | TypeFlags
98     };
99 
100     // the underlying param struct type
101     typedef S Struct;
102 
103 protected:
104     enum : uint32_t {
105         FLEX_SIZE = 0,
106     };
107 };
108 
109 /// Helper class that checks if a type has an integer FLEX_SIZE member.
110 struct C2_HIDE _C2Flexible_impl {
111     /// specialization for types that have a FLEX_SIZE member
112     template<typename S, unsigned=S::FLEX_SIZE>
113     static std::true_type TestFlexSize(int);
114     template<typename>
115     static std::false_type TestFlexSize(...);
116 };
117 
118 /// Helper template that returns if a type has an integer FLEX_SIZE member.
119 template<typename S>
120 struct C2_HIDE _C2Flexible
121     : public std::integral_constant<bool, decltype(_C2Flexible_impl::TestFlexSize<S>(0))::value> {
122 };
123 
124 /// Macro to test if a type is flexible (has a FLEX_SIZE member).
125 #define IF_FLEXIBLE(S) ENABLE_IF(_C2Flexible<S>::value)
126 /// Shorthand for std::enable_if
127 #define ENABLE_IF(cond) typename std::enable_if<cond>::type
128 
129 template<typename T, typename V=void>
130 struct C2_HIDE _c2_enable_if_type {
131     typedef V type;
132 };
133 
134 /// Helper template that exposes the flexible subtype of a struct.
135 template<typename S, typename E=void>
136 struct C2_HIDE _C2FlexHelper {
137     typedef void FlexType;
138     enum : uint32_t { FLEX_SIZE = 0 };
139 };
140 
141 /// Specialization for flexible types. This only works if _FlexMemberType is public.
142 template<typename S>
143 struct C2_HIDE _C2FlexHelper<S,
144         typename _c2_enable_if_type<typename S::_FlexMemberType>::type> {
145     typedef typename _C2FlexHelper<typename S::_FlexMemberType>::FlexType FlexType;
146     enum : uint32_t { FLEX_SIZE = _C2FlexHelper<typename S::_FlexMemberType>::FLEX_SIZE };
147 };
148 
149 /// Specialization for flex arrays.
150 template<typename S>
151 struct C2_HIDE _C2FlexHelper<S[],
152         typename std::enable_if<std::is_void<typename _C2FlexHelper<S>::FlexType>::value>::type> {
153     typedef S FlexType;
154     enum : uint32_t { FLEX_SIZE = sizeof(S) };
155 };
156 
157 /**
158  * \brief Helper class to check flexible struct requirements and add common operations.
159  *
160  * Features:
161  *  - expose CORE_INDEX and FieldList (this is normally inherited from the struct, but flexible
162  *    structs cannot be base classes and thus inherited from)
163  *  - disable copy assignment and construction (TODO: this is already done in the FLEX macro for the
164  *    flexible struct, so may not be needed here)
165  */
166 template<typename S, int ParamIndex, unsigned TypeFlags>
167 struct C2_HIDE _C2FlexStructCheck :
168 // add flexible flag as _C2StructCheck defines PARAM_TYPE
169         public _C2StructCheck<S, ParamIndex | C2Param::CoreIndex::IS_FLEX_FLAG, TypeFlags> {
170 public:
171     enum : uint32_t {
172         /// \hideinitializer
173         CORE_INDEX = ParamIndex | C2Param::CoreIndex::IS_FLEX_FLAG, ///< flexible struct core-index
174     };
175 
176     inline static const std::vector<C2FieldDescriptor> FieldList() { return S::FieldList(); }
177 
178     // default constructor needed because of the disabled copy constructor
179     inline _C2FlexStructCheck() = default;
180 
181 protected:
182     // cannot copy flexible params
183     _C2FlexStructCheck(const _C2FlexStructCheck<S, ParamIndex, TypeFlags> &) = delete;
184     _C2FlexStructCheck& operator= (const _C2FlexStructCheck<S, ParamIndex, TypeFlags> &) = delete;
185 
186     // constants used for helper methods
187     enum : uint32_t {
188         /// \hideinitializer
189         FLEX_SIZE = _C2FlexHelper<S>::FLEX_SIZE, ///< size of flexible type
190         /// \hideinitializer
191         MAX_SIZE = (uint32_t)std::min((size_t)UINT32_MAX, SIZE_MAX), // TODO: is this always u32 max?
192         /// \hideinitializer
193         BASE_SIZE = sizeof(S) + sizeof(C2Param), ///< size of the base param
194     };
195 
196     /// returns the allocated size of this param with flexCount, or 0 if it would overflow.
197     inline static size_t CalcSize(size_t flexCount, size_t size = BASE_SIZE) {
198         if (flexCount <= (MAX_SIZE - size) / S::FLEX_SIZE) {
199             return size + S::FLEX_SIZE * flexCount;
200         }
201         return 0;
202     }
203 
204     /// dynamic new operator usable for params of type S
205     inline void* operator new(size_t size, size_t flexCount) noexcept {
206         // TODO: assert(size == BASE_SIZE);
207         size = CalcSize(flexCount, size);
208         if (size > 0) {
209             return ::operator new(size);
210         }
211         return nullptr;
212     }
213 };
214 
215 /// Define From() cast operators for params.
216 #define DEFINE_CAST_OPERATORS(_Type) \
217     inline static _Type* From(C2Param *other) { \
218         return (_Type*)C2Param::IfSuitable( \
219                 other, sizeof(_Type), _Type::PARAM_TYPE, _Type::FLEX_SIZE, \
220                 (_Type::PARAM_TYPE & T::Index::DIR_UNDEFINED) != T::Index::DIR_UNDEFINED); \
221     } \
222     inline static const _Type* From(const C2Param *other) { \
223         return const_cast<const _Type*>(From(const_cast<C2Param *>(other))); \
224     } \
225     inline static _Type* From(std::nullptr_t) { return nullptr; } \
226 
227 /**
228  * Define flexible allocators (AllocShared or AllocUnique) for flexible params.
229  *  - P::AllocXyz(flexCount, args...): allocate for given flex-count. This maps to
230  *          T(flexCount, args...)\
231  *
232  * Clang does not support args... followed by templated param as args... eats it. Hence,
233  * provide specializations where the initializer replaces the flexCount.
234  *
235  * Specializations that deduce flexCount:
236  *  - P::AllocXyz(T[], args...): allocate for size of (and with) init array.
237  *  - P::AllocXyz(std::initializer_list<T>, args...): allocate for size of (and with) initializer
238  *            list.
239  *  - P::AllocXyz(std::vector<T>, args...): allocate for size of (and with) init vector.
240  *  These specializations map to T(flexCount = size-of-init, args..., init)
241  */
242 #define DEFINE_FLEXIBLE_ALLOC(_Type, S, ptr, Ptr) \
243     template<typename ...Args> \
244     inline static std::ptr##_ptr<_Type> Alloc##Ptr(size_t flexCount, const Args(&... args)) { \
245         return std::ptr##_ptr<_Type>(new(flexCount) _Type(flexCount, args...)); \
246     } \
247     template<typename ...Args, typename U=typename S::FlexType> \
248     inline static std::ptr##_ptr<_Type> Alloc##Ptr( \
249             const std::initializer_list<U> &init, const Args(&... args)) { \
250         return std::ptr##_ptr<_Type>(new(init.size()) _Type(init.size(), args..., init)); \
251     } \
252     template<typename ...Args, typename U=typename S::FlexType> \
253     inline static std::ptr##_ptr<_Type> Alloc##Ptr( \
254             const std::vector<U> &init, const Args(&... args)) { \
255         return std::ptr##_ptr<_Type>(new(init.size()) _Type(init.size(), args..., init)); \
256     } \
257     template<typename ...Args, typename U=typename S::FlexType, unsigned N> \
258     inline static std::ptr##_ptr<_Type> Alloc##Ptr(const U(&init)[N], const Args(&... args)) { \
259         return std::ptr##_ptr<_Type>(new(N) _Type(N, args..., init)); \
260     } \
261 
262 /**
263  * Define flexible methods AllocShared, AllocUnique and flexCount.
264  */
265 #define DEFINE_FLEXIBLE_METHODS(_Type, S) \
266     DEFINE_FLEXIBLE_ALLOC(_Type, S, shared, Shared) \
267     DEFINE_FLEXIBLE_ALLOC(_Type, S, unique, Unique) \
268     inline size_t flexCount() const { \
269         static_assert(sizeof(_Type) == _Type::BASE_SIZE, "incorrect BASE_SIZE"); \
270         size_t sz = this->size(); \
271         if (sz >= sizeof(_Type)) { \
272             return (sz - sizeof(_Type)) / _Type::FLEX_SIZE; \
273         } \
274         return 0; \
275     } \
276     inline void setFlexCount(size_t count) { \
277         if (count < flexCount()) { \
278             this->setSize(sizeof(_Type) + _Type::FLEX_SIZE * count); \
279         } \
280     } \
281 
282 /// Mark flexible member variable and make structure flexible.
283 #define FLEX(cls, m) \
284     C2_DO_NOT_COPY(cls) \
285 private: \
286     C2PARAM_MAKE_FRIENDS \
287     /** \if 0 */ \
288     template<typename, typename> friend struct _C2FlexHelper; \
289 public: \
290     typedef decltype(m) _FlexMemberType; \
291     /* default constructor with flexCount */ \
292     inline cls(size_t) : cls() {} \
293     /* constexpr static _FlexMemberType cls::* flexMember = &cls::m; */ \
294     typedef typename _C2FlexHelper<_FlexMemberType>::FlexType FlexType; \
295     static_assert(\
296             !std::is_void<FlexType>::value, \
297             "member is not flexible, or a flexible array of a flexible type"); \
298     enum : uint32_t { FLEX_SIZE = _C2FlexHelper<_FlexMemberType>::FLEX_SIZE }; \
299     /** \endif */ \
300 
301 /// @}
302 
303 /**
304  * Global-parameter template.
305  *
306  * Base template to define a global setting/tuning or info based on a structure and
307  * an optional ParamIndex. Global parameters are not tied to a port (input or output).
308  *
309  * Parameters wrap structures by prepending a (parameter) header. The fields of the wrapped
310  * structure can be accessed directly, and constructors and potential public methods are also
311  * wrapped.
312  *
313  * \tparam T param type C2Setting, C2Tuning or C2Info
314  * \tparam S wrapped structure
315  * \tparam ParamIndex optional parameter index override. Must be specified for base/reused
316  * structures.
317  */
318 template<typename T, typename S, int ParamIndex=S::CORE_INDEX, class Flex=void>
319 struct C2_HIDE C2GlobalParam : public T, public S,
320         public _C2StructCheck<S, ParamIndex, T::PARAM_KIND | T::Type::DIR_GLOBAL> {
321     _C2_CORE_INDEX_OVERRIDE(ParamIndex)
322 private:
323     typedef C2GlobalParam<T, S, ParamIndex> _Type;
324 
325 public:
326     /// Wrapper around base structure's constructor.
327     template<typename ...Args>
328     inline C2GlobalParam(const Args(&... args)) : T(sizeof(_Type), _Type::PARAM_TYPE), S(args...) { }
329 
330     DEFINE_CAST_OPERATORS(_Type)
331 };
332 
333 /**
334  * Global-parameter template for flexible structures.
335  *
336  * Base template to define a global setting/tuning or info based on a flexible structure and
337  * an optional ParamIndex. Global parameters are not tied to a port (input or output).
338  *
339  * \tparam T param type C2Setting, C2Tuning or C2Info
340  * \tparam S wrapped flexible structure
341  * \tparam ParamIndex optional parameter index override. Must be specified for base/reused
342  *         structures.
343  *
344  * Parameters wrap structures by prepending a (parameter) header. The fields and methods of flexible
345  * structures can be accessed via the m member variable; however, the constructors of the structure
346  * are wrapped directly. (This is because flexible types cannot be subclassed.)
347  */
348 template<typename T, typename S, int ParamIndex>
349 struct C2_HIDE C2GlobalParam<T, S, ParamIndex, IF_FLEXIBLE(S)>
350     : public T, public _C2FlexStructCheck<S, ParamIndex, T::PARAM_KIND | T::Type::DIR_GLOBAL> {
351 private:
352     typedef C2GlobalParam<T, S, ParamIndex> _Type;
353 
354     /// Wrapper around base structure's constructor.
355     template<typename ...Args>
356     inline C2GlobalParam(size_t flexCount, const Args(&... args))
357         : T(_Type::CalcSize(flexCount), _Type::PARAM_TYPE), m(flexCount, args...) { }
358 
359 public:
360     S m; ///< wrapped flexible structure
361 
362     DEFINE_FLEXIBLE_METHODS(_Type, S)
363     DEFINE_CAST_OPERATORS(_Type)
364 };
365 
366 /**
367  * Port-parameter template.
368  *
369  * Base template to define a port setting/tuning or info based on a structure and
370  * an optional ParamIndex. Port parameters are tied to a port (input or output), but not to a
371  * specific stream.
372  *
373  * \tparam T param type C2Setting, C2Tuning or C2Info
374  * \tparam S wrapped structure
375  * \tparam ParamIndex optional parameter index override. Must be specified for base/reused
376  *         structures.
377  *
378  * Parameters wrap structures by prepending a (parameter) header. The fields of the wrapped
379  * structure can be accessed directly, and constructors and potential public methods are also
380  * wrapped.
381  *
382  * There are 3 flavors of port parameters: unspecified, input and output. Parameters with
383  * unspecified port expose a setPort method, and add an initial port parameter to the constructor.
384  */
385 template<typename T, typename S, int ParamIndex=S::CORE_INDEX, class Flex=void>
386 struct C2_HIDE C2PortParam : public T, public S,
387         private _C2StructCheck<S, ParamIndex, T::PARAM_KIND | T::Index::DIR_UNDEFINED> {
388     _C2_CORE_INDEX_OVERRIDE(ParamIndex)
389 private:
390     typedef C2PortParam<T, S, ParamIndex> _Type;
391 
392 public:
393     /// Default constructor.
394     inline C2PortParam() : T(sizeof(_Type), _Type::PARAM_TYPE) { }
395     template<typename ...Args>
396     /// Wrapper around base structure's constructor while specifying port/direction.
397     inline C2PortParam(bool _output, const Args(&... args))
398         : T(sizeof(_Type), _output ? output::PARAM_TYPE : input::PARAM_TYPE), S(args...) { }
399     /// Set port/direction.
400     inline void setPort(bool output) { C2Param::setPort(output); }
401 
402     DEFINE_CAST_OPERATORS(_Type)
403 
404     /// Specialization for an input port parameter.
405     struct input : public T, public S,
406             public _C2StructCheck<S, ParamIndex, T::PARAM_KIND | T::Index::DIR_INPUT> {
407         _C2_CORE_INDEX_OVERRIDE(ParamIndex)
408         /// Wrapper around base structure's constructor.
409         template<typename ...Args>
410         inline input(const Args(&... args)) : T(sizeof(_Type), input::PARAM_TYPE), S(args...) { }
411 
412         DEFINE_CAST_OPERATORS(input)
413 
414     };
415 
416     /// Specialization for an output port parameter.
417     struct output : public T, public S,
418             public _C2StructCheck<S, ParamIndex, T::PARAM_KIND | T::Index::DIR_OUTPUT> {
419         _C2_CORE_INDEX_OVERRIDE(ParamIndex)
420         /// Wrapper around base structure's constructor.
421         template<typename ...Args>
422         inline output(const Args(&... args)) : T(sizeof(_Type), output::PARAM_TYPE), S(args...) { }
423 
424         DEFINE_CAST_OPERATORS(output)
425     };
426 };
427 
428 /**
429  * Port-parameter template for flexible structures.
430  *
431  * Base template to define a port setting/tuning or info based on a flexible structure and
432  * an optional ParamIndex. Port parameters are tied to a port (input or output), but not to a
433  * specific stream.
434  *
435  * \tparam T param type C2Setting, C2Tuning or C2Info
436  * \tparam S wrapped flexible structure
437  * \tparam ParamIndex optional parameter index override. Must be specified for base/reused
438  *         structures.
439  *
440  * Parameters wrap structures by prepending a (parameter) header. The fields and methods of flexible
441  * structures can be accessed via the m member variable; however, the constructors of the structure
442  * are wrapped directly. (This is because flexible types cannot be subclassed.)
443  *
444  * There are 3 flavors of port parameters: unspecified, input and output. Parameters with
445  * unspecified port expose a setPort method, and add an initial port parameter to the constructor.
446  */
447 template<typename T, typename S, int ParamIndex>
448 struct C2_HIDE C2PortParam<T, S, ParamIndex, IF_FLEXIBLE(S)>
449     : public T, public _C2FlexStructCheck<S, ParamIndex, T::PARAM_KIND | T::Type::DIR_UNDEFINED> {
450 private:
451     typedef C2PortParam<T, S, ParamIndex> _Type;
452 
453     /// Default constructor for basic allocation: new(flexCount) P.
454     inline C2PortParam(size_t flexCount) : T(_Type::CalcSize(flexCount), _Type::PARAM_TYPE) { }
455     template<typename ...Args>
456     /// Wrapper around base structure's constructor while also specifying port/direction.
457     inline C2PortParam(size_t flexCount, bool _output, const Args(&... args))
458         : T(_Type::CalcSize(flexCount), _output ? output::PARAM_TYPE : input::PARAM_TYPE),
459           m(flexCount, args...) { }
460 
461 public:
462     /// Set port/direction.
463     inline void setPort(bool output) { C2Param::setPort(output); }
464 
465     S m; ///< wrapped flexible structure
466 
467     DEFINE_FLEXIBLE_METHODS(_Type, S)
468     DEFINE_CAST_OPERATORS(_Type)
469 
470     /// Specialization for an input port parameter.
471     struct input : public T,
472             public _C2FlexStructCheck<S, ParamIndex, T::PARAM_KIND | T::Index::DIR_INPUT> {
473     private:
474         /// Wrapper around base structure's constructor while also specifying port/direction.
475         template<typename ...Args>
476         inline input(size_t flexCount, const Args(&... args))
477             : T(_Type::CalcSize(flexCount), input::PARAM_TYPE), m(flexCount, args...) { }
478 
479     public:
480         S m; ///< wrapped flexible structure
481 
482         DEFINE_FLEXIBLE_METHODS(input, S)
483         DEFINE_CAST_OPERATORS(input)
484     };
485 
486     /// Specialization for an output port parameter.
487     struct output : public T,
488             public _C2FlexStructCheck<S, ParamIndex, T::PARAM_KIND | T::Index::DIR_OUTPUT> {
489     private:
490         /// Wrapper around base structure's constructor while also specifying port/direction.
491         template<typename ...Args>
492         inline output(size_t flexCount, const Args(&... args))
493             : T(_Type::CalcSize(flexCount), output::PARAM_TYPE), m(flexCount, args...) { }
494 
495     public:
496         S m; ///< wrapped flexible structure
497 
498         DEFINE_FLEXIBLE_METHODS(output, S)
499         DEFINE_CAST_OPERATORS(output)
500     };
501 };
502 
503 /**
504  * Stream-parameter template.
505  *
506  * Base template to define a stream setting/tuning or info based on a structure and
507  * an optional ParamIndex. Stream parameters are tied to a specific stream on a port (input or
508  * output).
509  *
510  * \tparam T param type C2Setting, C2Tuning or C2Info
511  * \tparam S wrapped structure
512  * \tparam ParamIndex optional paramter index override. Must be specified for base/reused
513  *         structures.
514  *
515  * Parameters wrap structures by prepending a (parameter) header. The fields of the wrapped
516  * structure can be accessed directly, and constructors and potential public methods are also
517  * wrapped.
518  *
519  * There are 3 flavors of stream parameters: unspecified port, input and output. All of these expose
520  * a setStream method and an extra initial streamID parameter for the constructor. Moreover,
521  * parameters with unspecified port expose a setPort method, and add an additional initial port
522  * parameter to the constructor.
523  */
524 template<typename T, typename S, int ParamIndex=S::CORE_INDEX, class Flex=void>
525 struct C2_HIDE C2StreamParam : public T, public S,
526         private _C2StructCheck<S, ParamIndex,
527                 T::PARAM_KIND | T::Index::IS_STREAM_FLAG | T::Index::DIR_UNDEFINED> {
528     _C2_CORE_INDEX_OVERRIDE(ParamIndex)
529 private:
530     typedef C2StreamParam<T, S, ParamIndex> _Type;
531 
532 public:
533     /// Default constructor. Port/direction and stream-ID is undefined.
534     inline C2StreamParam() : T(sizeof(_Type), _Type::PARAM_TYPE) { }
535     /// Wrapper around base structure's constructor while also specifying port/direction and
536     /// stream-ID.
537     template<typename ...Args>
538     inline C2StreamParam(bool _output, unsigned stream, const Args(&... args))
539         : T(sizeof(_Type), _output ? output::PARAM_TYPE : input::PARAM_TYPE, stream),
540           S(args...) { }
541     /// Set port/direction.
542     inline void setPort(bool output) { C2Param::setPort(output); }
543     /// Set stream-id. \retval true if the stream-id was successfully set.
544     inline bool setStream(unsigned stream) { return C2Param::setStream(stream); }
545 
546     DEFINE_CAST_OPERATORS(_Type)
547 
548     /// Specialization for an input stream parameter.
549     struct input : public T, public S,
550             public _C2StructCheck<S, ParamIndex,
551                     T::PARAM_KIND | T::Index::IS_STREAM_FLAG | T::Type::DIR_INPUT> {
552         _C2_CORE_INDEX_OVERRIDE(ParamIndex)
553 
554         /// Default constructor. Stream-ID is undefined.
555         inline input() : T(sizeof(_Type), input::PARAM_TYPE) { }
556         /// Wrapper around base structure's constructor while also specifying stream-ID.
557         template<typename ...Args>
558         inline input(unsigned stream, const Args(&... args))
559             : T(sizeof(_Type), input::PARAM_TYPE, stream), S(args...) { }
560         /// Set stream-id. \retval true if the stream-id was successfully set.
561         inline bool setStream(unsigned stream) { return C2Param::setStream(stream); }
562 
563         DEFINE_CAST_OPERATORS(input)
564     };
565 
566     /// Specialization for an output stream parameter.
567     struct output : public T, public S,
568             public _C2StructCheck<S, ParamIndex,
569                     T::PARAM_KIND | T::Index::IS_STREAM_FLAG | T::Type::DIR_OUTPUT> {
570         _C2_CORE_INDEX_OVERRIDE(ParamIndex)
571 
572         /// Default constructor. Stream-ID is undefined.
573         inline output() : T(sizeof(_Type), output::PARAM_TYPE) { }
574         /// Wrapper around base structure's constructor while also specifying stream-ID.
575         template<typename ...Args>
576         inline output(unsigned stream, const Args(&... args))
577             : T(sizeof(_Type), output::PARAM_TYPE, stream), S(args...) { }
578         /// Set stream-id. \retval true if the stream-id was successfully set.
579         inline bool setStream(unsigned stream) { return C2Param::setStream(stream); }
580 
581         DEFINE_CAST_OPERATORS(output)
582     };
583 };
584 
585 /**
586  * Stream-parameter template for flexible structures.
587  *
588  * Base template to define a stream setting/tuning or info based on a flexible structure and
589  * an optional ParamIndex. Stream parameters are tied to a specific stream on a port (input or
590  * output).
591  *
592  * \tparam T param type C2Setting, C2Tuning or C2Info
593  * \tparam S wrapped flexible structure
594  * \tparam ParamIndex optional parameter index override. Must be specified for base/reused
595  *         structures.
596  *
597  * Parameters wrap structures by prepending a (parameter) header. The fields and methods of flexible
598  * structures can be accessed via the m member variable; however, the constructors of the structure
599  * are wrapped directly. (This is because flexible types cannot be subclassed.)
600  *
601  * There are 3 flavors of stream parameters: unspecified port, input and output. All of these expose
602  * a setStream method and an extra initial streamID parameter for the constructor. Moreover,
603  * parameters with unspecified port expose a setPort method, and add an additional initial port
604  * parameter to the constructor.
605  */
606 template<typename T, typename S, int ParamIndex>
607 struct C2_HIDE C2StreamParam<T, S, ParamIndex, IF_FLEXIBLE(S)>
608     : public T,
609       public _C2FlexStructCheck<S, ParamIndex,
610               T::PARAM_KIND | T::Index::IS_STREAM_FLAG | T::Index::DIR_UNDEFINED> {
611 private:
612     typedef C2StreamParam<T, S, ParamIndex> _Type;
613     /// Default constructor. Port/direction and stream-ID is undefined.
614     inline C2StreamParam(size_t flexCount) : T(_Type::CalcSize(flexCount), _Type::PARAM_TYPE, 0u) { }
615     /// Wrapper around base structure's constructor while also specifying port/direction and
616     /// stream-ID.
617     template<typename ...Args>
618     inline C2StreamParam(size_t flexCount, bool _output, unsigned stream, const Args(&... args))
619         : T(_Type::CalcSize(flexCount), _output ? output::PARAM_TYPE : input::PARAM_TYPE, stream),
620           m(flexCount, args...) { }
621 
622 public:
623     S m; ///< wrapped flexible structure
624 
625     /// Set port/direction.
626     inline void setPort(bool output) { C2Param::setPort(output); }
627     /// Set stream-id. \retval true if the stream-id was successfully set.
628     inline bool setStream(unsigned stream) { return C2Param::setStream(stream); }
629 
630     DEFINE_FLEXIBLE_METHODS(_Type, S)
631     DEFINE_CAST_OPERATORS(_Type)
632 
633     /// Specialization for an input stream parameter.
634     struct input : public T,
635             public _C2FlexStructCheck<S, ParamIndex,
636                     T::PARAM_KIND | T::Index::IS_STREAM_FLAG | T::Type::DIR_INPUT> {
637     private:
638         /// Default constructor. Stream-ID is undefined.
639         inline input(size_t flexCount) : T(_Type::CalcSize(flexCount), input::PARAM_TYPE) { }
640         /// Wrapper around base structure's constructor while also specifying stream-ID.
641         template<typename ...Args>
642         inline input(size_t flexCount, unsigned stream, const Args(&... args))
643             : T(_Type::CalcSize(flexCount), input::PARAM_TYPE, stream), m(flexCount, args...) { }
644 
645     public:
646         S m; ///< wrapped flexible structure
647 
648         /// Set stream-id. \retval true if the stream-id was successfully set.
649         inline bool setStream(unsigned stream) { return C2Param::setStream(stream); }
650 
651         DEFINE_FLEXIBLE_METHODS(input, S)
652         DEFINE_CAST_OPERATORS(input)
653     };
654 
655     /// Specialization for an output stream parameter.
656     struct output : public T,
657             public _C2FlexStructCheck<S, ParamIndex,
658                     T::PARAM_KIND | T::Index::IS_STREAM_FLAG | T::Type::DIR_OUTPUT> {
659     private:
660         /// Default constructor. Stream-ID is undefined.
661         inline output(size_t flexCount) : T(_Type::CalcSize(flexCount), output::PARAM_TYPE) { }
662         /// Wrapper around base structure's constructor while also specifying stream-ID.
663         template<typename ...Args>
664         inline output(size_t flexCount, unsigned stream, const Args(&... args))
665             : T(_Type::CalcSize(flexCount), output::PARAM_TYPE, stream), m(flexCount, args...) { }
666 
667     public:
668         S m; ///< wrapped flexible structure
669 
670         /// Set stream-id. \retval true if the stream-id was successfully set.
671         inline bool setStream(unsigned stream) { return C2Param::setStream(stream); }
672 
673         DEFINE_FLEXIBLE_METHODS(output, S)
674         DEFINE_CAST_OPERATORS(output)
675     };
676 };
677 
678 /* ======================== SIMPLE VALUE PARAMETERS ======================== */
679 
680 /**
681  * \ingroup internal
682  * A structure template encapsulating a single element with default constructors and no core-index.
683  */
684 template<typename T>
685 struct C2SimpleValueStruct {
686     T value; ///< simple value of the structure
687     // Default constructor.
688     inline C2SimpleValueStruct() = default;
689     // Constructor with an initial value.
690     inline C2SimpleValueStruct(T value) : value(value) {}
691     DEFINE_BASE_C2STRUCT(SimpleValue)
692 };
693 
694 // TODO: move this and next to some generic place
695 /**
696  * Interface to a block of (mapped) memory containing an array of some type (T).
697  */
698 template<typename T>
699 struct C2MemoryBlock {
700     /// \returns the number of elements in this block.
701     virtual size_t size() const = 0;
702     /// \returns a const pointer to the start of this block. Care must be taken to not read outside
703     /// the block.
704     virtual const T *data() const = 0; // TODO: should this be friend access only in some C2Memory module?
705     /// \returns a pointer to the start of this block. Care must be taken to not read or write
706     /// outside the block.
707     inline T *data() { return const_cast<T*>(const_cast<const C2MemoryBlock*>(this)->data()); }
708 
709 protected:
710     // TODO: for now it should never be deleted as C2MemoryBlock
711     virtual ~C2MemoryBlock() = default;
712 };
713 
714 /**
715  * Interface to a block of memory containing a constant (constexpr) array of some type (T).
716  */
717 template<typename T>
718 struct C2ConstMemoryBlock : public C2MemoryBlock<T> {
719     virtual const T * data() const { return _mData; }
720     virtual size_t size() const { return _mSize; }
721 
722     /// Constructor.
723     template<unsigned N>
724     inline constexpr C2ConstMemoryBlock(const T(&init)[N]) : _mData(init), _mSize(N) {}
725 
726 private:
727     const T *_mData;
728     const size_t _mSize;
729 };
730 
731 /// \addtogroup internal
732 /// @{
733 
734 /// Helper class to initialize flexible arrays with various initalizers.
735 struct _C2ValueArrayHelper {
736     // char[]-s are used as null terminated strings, so the last element is never inited.
737 
738     /// Initialize a flexible array using a constexpr memory block.
739     template<typename T>
740     static void init(T(&array)[], size_t arrayLen, const C2MemoryBlock<T> &block) {
741         // reserve last element for terminal 0 for strings
742         if (arrayLen && std::is_same<T, char>::value) {
743             --arrayLen;
744         }
745         if (block.data()) {
746             memcpy(array, block.data(), std::min(arrayLen, block.size()) * sizeof(T));
747         }
748     }
749 
750     /// Initialize a flexible array using an initializer list.
751     template<typename T>
752     static void init(T(&array)[], size_t arrayLen, const std::initializer_list<T> &init) {
753         size_t ix = 0;
754         // reserve last element for terminal 0 for strings
755         if (arrayLen && std::is_same<T, char>::value) {
756             --arrayLen;
757         }
758         for (const T &item : init) {
759             if (ix == arrayLen) {
760                 break;
761             }
762             array[ix++] = item;
763         }
764     }
765 
766     /// Initialize a flexible array using a vector.
767     template<typename T>
768     static void init(T(&array)[], size_t arrayLen, const std::vector<T> &init) {
769         size_t ix = 0;
770         // reserve last element for terminal 0 for strings
771         if (arrayLen && std::is_same<T, char>::value) {
772             --arrayLen;
773         }
774         for (const T &item : init) {
775             if (ix == arrayLen) {
776                 break;
777             }
778             array[ix++] = item;
779         }
780     }
781 
782     /// Initialize a flexible array using another flexible array.
783     template<typename T, unsigned N>
784     static void init(T(&array)[], size_t arrayLen, const T(&str)[N]) {
785         // reserve last element for terminal 0 for strings
786         if (arrayLen && std::is_same<T, char>::value) {
787             --arrayLen;
788         }
789         if (arrayLen) {
790             memcpy(array, str, std::min(arrayLen, (size_t)N) * sizeof(T));
791         }
792     }
793 };
794 
795 /**
796  * Specialization for a flexible blob and string arrays. A structure template encapsulating a single
797  * flexible array member with default flexible constructors and no core-index. This type cannot be
798  * constructed on its own as it's size is 0.
799  *
800  * \internal This is different from C2SimpleArrayStruct<T[]> simply because its member has the name
801  * as value to reflect this is a single value.
802  */
803 template<typename T>
804 struct C2SimpleValueStruct<T[]> {
805     static_assert(std::is_same<T, char>::value || std::is_same<T, uint8_t>::value,
806                   "C2SimpleValueStruct<T[]> is only for BLOB or STRING");
807     T value[];
808 
809     inline C2SimpleValueStruct() = default;
810     DEFINE_BASE_C2STRUCT(SimpleValue)
811     FLEX(C2SimpleValueStruct, value)
812 
813 private:
814     inline C2SimpleValueStruct(size_t flexCount, const C2MemoryBlock<T> &block) {
815         _C2ValueArrayHelper::init(value, flexCount, block);
816     }
817 
818     inline C2SimpleValueStruct(size_t flexCount, const std::initializer_list<T> &init) {
819         _C2ValueArrayHelper::init(value, flexCount, init);
820     }
821 
822     inline C2SimpleValueStruct(size_t flexCount, const std::vector<T> &init) {
823         _C2ValueArrayHelper::init(value, flexCount, init);
824     }
825 
826     template<unsigned N>
827     inline C2SimpleValueStruct(size_t flexCount, const T(&init)[N]) {
828         _C2ValueArrayHelper::init(value, flexCount, init);
829     }
830 };
831 
832 /// @}
833 
834 /**
835  * A structure template encapsulating a single flexible array element of a specific type (T) with
836  * default constructors and no core-index. This type cannot be constructed on its own as it's size
837  * is 0. Instead, it is meant to be used as a parameter, e.g.
838  *
839  *   typedef C2StreamParam<C2Info, C2SimpleArrayStruct<C2MyFancyStruct>,
840  *           kParamIndexMyFancyArrayStreamParam> C2MyFancyArrayStreamInfo;
841  */
842 template<typename T>
843 struct C2SimpleArrayStruct {
844     static_assert(!std::is_same<T, char>::value && !std::is_same<T, uint8_t>::value,
845                   "use C2SimpleValueStruct<T[]> is for BLOB or STRING");
846 
847     T values[]; ///< array member
848     /// Default constructor
849     inline C2SimpleArrayStruct() = default;
850     DEFINE_BASE_FLEX_C2STRUCT(SimpleArray, values)
851     //FLEX(C2SimpleArrayStruct, values)
852 
853 private:
854     /// Construct from a C2MemoryBlock.
855     /// Used only by the flexible parameter allocators (AllocUnique & AllocShared).
856     inline C2SimpleArrayStruct(size_t flexCount, const C2MemoryBlock<T> &block) {
857         _C2ValueArrayHelper::init(values, flexCount, block);
858     }
859 
860     /// Construct from an initializer list.
861     /// Used only by the flexible parameter allocators (AllocUnique & AllocShared).
862     inline C2SimpleArrayStruct(size_t flexCount, const std::initializer_list<T> &init) {
863         _C2ValueArrayHelper::init(values, flexCount, init);
864     }
865 
866     /// Construct from an vector.
867     /// Used only by the flexible parameter allocators (AllocUnique & AllocShared).
868     inline C2SimpleArrayStruct(size_t flexCount, const std::vector<T> &init) {
869         _C2ValueArrayHelper::init(values, flexCount, init);
870     }
871 
872     /// Construct from another flexible array.
873     /// Used only by the flexible parameter allocators (AllocUnique & AllocShared).
874     template<unsigned N>
875     inline C2SimpleArrayStruct(size_t flexCount, const T(&init)[N]) {
876         _C2ValueArrayHelper::init(values, flexCount, init);
877     }
878 };
879 
880 /**
881  * \addtogroup simplevalue Simple value and array structures.
882  * @{
883  *
884  * Simple value structures.
885  *
886  * Structures containing a single simple value. These can be reused to easily define simple
887  * parameters of various types:
888  *
889  *   typedef C2PortParam<C2Tuning, C2Int32Value, kParamIndexMyIntegerPortParam>
890  *           C2MyIntegerPortParamTuning;
891  *
892  * They contain a single member (value or values) that is described as "value" or "values".
893  *
894  * These structures don't define a core index, and as such, they cannot be used in structure
895  * declarations. Use type[] instead, such as int32_t field[].
896  */
897 /// A 32-bit signed integer parameter in value, described as "value"
898 typedef C2SimpleValueStruct<int32_t> C2Int32Value;
899 /// A 32-bit signed integer array parameter in values, described as "values"
900 typedef C2SimpleArrayStruct<int32_t> C2Int32Array;
901 /// A 32-bit unsigned integer parameter in value, described as "value"
902 typedef C2SimpleValueStruct<uint32_t> C2Uint32Value;
903 /// A 32-bit unsigned integer array parameter in values, described as "values"
904 typedef C2SimpleArrayStruct<uint32_t> C2Uint32Array;
905 /// A 64-bit signed integer parameter in value, described as "value"
906 typedef C2SimpleValueStruct<int64_t> C2Int64Value;
907 /// A 64-bit signed integer array parameter in values, described as "values"
908 typedef C2SimpleArrayStruct<int64_t> C2Int64Array;
909 /// A 64-bit unsigned integer parameter in value, described as "value"
910 typedef C2SimpleValueStruct<uint64_t> C2Uint64Value;
911 /// A 64-bit unsigned integer array parameter in values, described as "values"
912 typedef C2SimpleArrayStruct<uint64_t> C2Uint64Array;
913 /// A float parameter in value, described as "value"
914 typedef C2SimpleValueStruct<float> C2FloatValue;
915 /// A float array parameter in values, described as "values"
916 typedef C2SimpleArrayStruct<float> C2FloatArray;
917 /// A blob flexible parameter in value, described as "value"
918 typedef C2SimpleValueStruct<uint8_t[]> C2BlobValue;
919 /// A string flexible parameter in value, described as "value"
920 typedef C2SimpleValueStruct<char[]> C2StringValue;
921 
922 template<typename T>
923 const std::vector<C2FieldDescriptor> C2SimpleValueStruct<T>::FieldList() {
924     return { DESCRIBE_C2FIELD(value, "value") };
925 }
926 template<typename T>
927 const std::vector<C2FieldDescriptor> C2SimpleValueStruct<T[]>::FieldList() {
928     return { DESCRIBE_C2FIELD(value, "value") };
929 }
930 template<typename T>
931 const std::vector<C2FieldDescriptor> C2SimpleArrayStruct<T>::FieldList() {
932     return { DESCRIBE_C2FIELD(values, "values") };
933 }
934 
935 /// @}
936 
937 /// @}
938 
939 #endif  // C2PARAM_DEF_H_
940