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