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