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