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