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