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