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