1 /* 2 * Copyright (C) 2017 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 #pragma clang diagnostic push 18 #pragma clang diagnostic ignored "-Wunused-parameter" 19 #pragma clang diagnostic ignored "-Wunused-variable" 20 #pragma clang diagnostic ignored "-Wunused-value" 21 22 #define C2_LOG_VERBOSE 23 24 #include <C2Debug.h> 25 #include <C2Param.h> 26 #include <C2ParamDef.h> 27 #include <C2ParamInternal.h> 28 #include <util/C2InterfaceUtils.h> 29 30 #include <cmath> 31 #include <limits> 32 #include <map> 33 #include <type_traits> 34 35 #include <android-base/stringprintf.h> 36 37 std::ostream& operator<<(std::ostream& os, const _C2FieldId &i); 38 39 std::ostream& operator<<(std::ostream& os, const C2ParamField &i); 40 41 /* ---------------------------- C2SupportedRange ---------------------------- */ 42 43 /** 44 * Helper class for supported values range calculations. 45 */ 46 template<typename T, bool FP=std::is_floating_point<T>::value> 47 struct _C2TypedSupportedRangeHelper { 48 /** 49 * type of range size: a - b if a >= b and a and b are of type T 50 */ 51 typedef typename std::make_unsigned<T>::type DiffType; 52 53 /** 54 * calculate (high - low) mod step 55 */ 56 static DiffType mod(T low, T high, T step) { 57 return DiffType(high - low) % DiffType(step); 58 } 59 }; 60 61 template<typename T> 62 struct _C2TypedSupportedRangeHelper<T, true> { 63 typedef T DiffType; 64 65 static DiffType mod(T low, T high, T step) { 66 return fmod(high - low, step); 67 } 68 }; 69 70 template<typename T> 71 C2SupportedRange<T>::C2SupportedRange(const C2FieldSupportedValues &values) { 72 if (values.type == C2FieldSupportedValues::RANGE) { 73 _mMin = values.range.min.ref<ValueType>(); 74 _mMax = values.range.max.ref<ValueType>(); 75 _mStep = values.range.step.ref<ValueType>(); 76 _mNum = values.range.num.ref<ValueType>(); 77 _mDenom = values.range.denom.ref<ValueType>(); 78 } else { 79 _mMin = MAX_VALUE; 80 _mMax = MIN_VALUE; 81 _mStep = MIN_STEP; 82 _mNum = 0; 83 _mDenom = 0; 84 } 85 } 86 87 template<typename T> 88 bool C2SupportedRange<T>::contains(T value) const { 89 // value must fall between min and max 90 if (value < _mMin || value > _mMax) { 91 return false; 92 } 93 // simple ranges contain all values between min and max 94 if (isSimpleRange()) { 95 return true; 96 } 97 // min is always part of the range 98 if (value == _mMin) { 99 return true; 100 } 101 // stepped ranges require (val - min) % step to be zero 102 if (isArithmeticSeries()) { 103 return _C2TypedSupportedRangeHelper<T>::mod(_mMin, value, _mStep) == 0; 104 } 105 // pure geometric series require (val / min) to be integer multiple of (num/denom) 106 if (isGeometricSeries()) { 107 if (value <= 0) { 108 return false; 109 } 110 double log2base = log2(_mNum / _mDenom); 111 double power = llround(log2(value / double(_mMin)) / log2base); 112 // TODO: validate that result falls within precision (other than round) 113 return value == T(_mMin * pow(_mNum / _mDenom, power) + MIN_STEP / 2); 114 } 115 // multiply-accumulate series require validating by walking through the series 116 if (isMacSeries()) { 117 double lastValue = _mMin; 118 double base = _mNum / _mDenom; 119 while (true) { 120 // this cast is safe as _mMin <= lastValue <= _mMax 121 if (T(lastValue + MIN_STEP / 2) == value) { 122 return true; 123 } 124 double nextValue = fma(lastValue, base, _mStep); 125 if (nextValue <= lastValue || nextValue > _mMax) { 126 return false; // series is no longer monotonic or within range 127 } 128 lastValue = nextValue; 129 }; 130 } 131 // if we are here, this must be an invalid range 132 return false; 133 } 134 135 template<typename T> 136 C2SupportedRange<T> C2SupportedRange<T>::limitedTo(const C2SupportedRange<T> &limit) const { 137 // TODO - this only works for simple ranges 138 return C2SupportedRange(std::max(_mMin, limit._mMin), std::min(_mMax, limit._mMax), 139 std::max(_mStep, limit._mStep)); 140 } 141 142 template class C2SupportedRange<uint8_t>; 143 template class C2SupportedRange<char>; 144 template class C2SupportedRange<int32_t>; 145 template class C2SupportedRange<uint32_t>; 146 //template class C2SupportedRange<c2_cntr32_t>; 147 template class C2SupportedRange<int64_t>; 148 template class C2SupportedRange<uint64_t>; 149 //template class C2SupportedRange<c2_cntr64_t>; 150 template class C2SupportedRange<float>; 151 152 /* -------------------------- C2SupportedFlags -------------------------- */ 153 154 /** 155 * Ordered supported flag set for a field of a given type. 156 */ 157 // float flags are not supported, but define a few methods to support generic supported values code 158 template<> 159 bool C2SupportedFlags<float>::contains(float value) const { 160 return false; 161 } 162 163 template<> 164 const std::vector<float> C2SupportedFlags<float>::flags() const { 165 return std::vector<float>(); 166 } 167 168 template<> 169 C2SupportedFlags<float> C2SupportedFlags<float>::limitedTo(const C2SupportedFlags<float> &limit) const { 170 std::vector<C2Value::Primitive> values; 171 return C2SupportedFlags(std::move(values)); 172 } 173 174 template<> 175 float C2SupportedFlags<float>::min() const { 176 return 0; 177 } 178 179 template<typename T> 180 bool C2SupportedFlags<T>::contains(T value) const { 181 // value must contain the minimal mask 182 T minMask = min(); 183 if (~value & minMask) { 184 return false; 185 } 186 value &= ~minMask; 187 // otherwise, remove flags from value and see if we arrive at 0 188 for (const C2Value::Primitive &v : _mValues) { 189 if (value == 0) { 190 break; 191 } 192 if ((~value & v.ref<ValueType>()) == 0) { 193 value &= ~v.ref<ValueType>(); 194 } 195 } 196 return value == 0; 197 } 198 199 template<typename T> 200 const std::vector<T> C2SupportedFlags<T>::flags() const { 201 std::vector<T> vals(c2_max(_mValues.size(), 1u) - 1); 202 if (!_mValues.empty()) { 203 std::transform(_mValues.cbegin() + 1, _mValues.cend(), vals.begin(), 204 [](const C2Value::Primitive &p)->T { 205 return p.ref<ValueType>(); 206 }); 207 } 208 return vals; 209 } 210 211 template<typename T> 212 C2SupportedFlags<T> C2SupportedFlags<T>::limitedTo(const C2SupportedFlags<T> &limit) const { 213 std::vector<C2Value::Primitive> values = _mValues; // make a copy 214 T minMask = min() | limit.min(); 215 // minimum mask must be covered by both this and other 216 if (limit.contains(minMask) && contains(minMask)) { 217 values[0] = minMask; 218 // keep only flags that are covered by limit 219 std::remove_if(values.begin(), values.end(), [&limit, minMask](const C2Value::Primitive &v) -> bool { 220 T value = v.ref<ValueType>() | minMask; 221 return value == minMask || !limit.contains(value); }); 222 // we also need to do it vice versa 223 for (const C2Value::Primitive &v : _mValues) { 224 T value = v.ref<ValueType>() | minMask; 225 if (value != minMask && contains(value)) { 226 values.emplace_back((ValueType)value); 227 } 228 } 229 } 230 return C2SupportedFlags(std::move(values)); 231 } 232 233 template<typename T> 234 T C2SupportedFlags<T>::min() const { 235 if (!_mValues.empty()) { 236 return _mValues.front().template ref<ValueType>(); 237 } else { 238 return T(0); 239 } 240 } 241 242 template class C2SupportedFlags<uint8_t>; 243 template class C2SupportedFlags<char>; 244 template class C2SupportedFlags<int32_t>; 245 template class C2SupportedFlags<uint32_t>; 246 //template class C2SupportedFlags<c2_cntr32_t>; 247 template class C2SupportedFlags<int64_t>; 248 template class C2SupportedFlags<uint64_t>; 249 //template class C2SupportedFlags<c2_cntr64_t>; 250 251 /* -------------------------- C2SupportedValueSet -------------------------- */ 252 253 /** 254 * Ordered supported value set for a field of a given type. 255 */ 256 template<typename T> 257 bool C2SupportedValueSet<T>::contains(T value) const { 258 return std::find_if(_mValues.cbegin(), _mValues.cend(), 259 [value](const C2Value::Primitive &p) -> bool { 260 return value == p.ref<ValueType>(); 261 }) != _mValues.cend(); 262 } 263 264 template<typename T> 265 C2SupportedValueSet<T> C2SupportedValueSet<T>::limitedTo(const C2SupportedValueSet<T> &limit) const { 266 std::vector<C2Value::Primitive> values = _mValues; // make a copy 267 std::remove_if(values.begin(), values.end(), [&limit](const C2Value::Primitive &v) -> bool { 268 return !limit.contains(v.ref<ValueType>()); }); 269 return C2SupportedValueSet(std::move(values)); 270 } 271 272 template<typename T> 273 C2SupportedValueSet<T> C2SupportedValueSet<T>::limitedTo(const C2SupportedRange<T> &limit) const { 274 std::vector<C2Value::Primitive> values = _mValues; // make a copy 275 std::remove_if(values.begin(), values.end(), [&limit](const C2Value::Primitive &v) -> bool { 276 return !limit.contains(v.ref<ValueType>()); }); 277 return C2SupportedValueSet(std::move(values)); 278 } 279 280 template<typename T> 281 C2SupportedValueSet<T> C2SupportedValueSet<T>::limitedTo(const C2SupportedFlags<T> &limit) const { 282 std::vector<C2Value::Primitive> values = _mValues; // make a copy 283 std::remove_if(values.begin(), values.end(), [&limit](const C2Value::Primitive &v) -> bool { 284 return !limit.contains(v.ref<ValueType>()); }); 285 return C2SupportedValueSet(std::move(values)); 286 } 287 288 template<typename T> 289 const std::vector<T> C2SupportedValueSet<T>::values() const { 290 std::vector<T> vals(_mValues.size()); 291 std::transform(_mValues.cbegin(), _mValues.cend(), vals.begin(), [](const C2Value::Primitive &p) -> T { 292 return p.ref<ValueType>(); 293 }); 294 return vals; 295 } 296 297 template class C2SupportedValueSet<uint8_t>; 298 template class C2SupportedValueSet<char>; 299 template class C2SupportedValueSet<int32_t>; 300 template class C2SupportedValueSet<uint32_t>; 301 //template class C2SupportedValueSet<c2_cntr32_t>; 302 template class C2SupportedValueSet<int64_t>; 303 template class C2SupportedValueSet<uint64_t>; 304 //template class C2SupportedValueSet<c2_cntr64_t>; 305 template class C2SupportedValueSet<float>; 306 307 /* ---------------------- C2FieldSupportedValuesHelper ---------------------- */ 308 309 template<typename T> 310 struct C2FieldSupportedValuesHelper<T>::Impl { 311 Impl(const C2FieldSupportedValues &values) 312 : _mType(values.type), 313 _mRange(values), 314 _mValues(values), 315 _mFlags(values) { } 316 317 bool supports(T value) const; 318 319 private: 320 typedef typename _C2FieldValueHelper<T>::ValueType ValueType; 321 C2FieldSupportedValues::type_t _mType; 322 C2SupportedRange<ValueType> _mRange; 323 C2SupportedValueSet<ValueType> _mValues; 324 C2SupportedValueSet<ValueType> _mFlags; 325 326 // friend std::ostream& operator<< <T>(std::ostream& os, const C2FieldSupportedValuesHelper<T>::Impl &i); 327 // friend std::ostream& operator<<(std::ostream& os, const Impl &i); 328 std::ostream& streamOut(std::ostream& os) const; 329 }; 330 331 template<typename T> 332 bool C2FieldSupportedValuesHelper<T>::Impl::supports(T value) const { 333 switch (_mType) { 334 case C2FieldSupportedValues::RANGE: return _mRange.contains(value); 335 case C2FieldSupportedValues::VALUES: return _mValues.contains(value); 336 case C2FieldSupportedValues::FLAGS: return _mFlags.contains(value); 337 default: return false; 338 } 339 } 340 341 template<typename T> 342 C2FieldSupportedValuesHelper<T>::C2FieldSupportedValuesHelper(const C2FieldSupportedValues &values) 343 : _mImpl(std::make_unique<C2FieldSupportedValuesHelper<T>::Impl>(values)) { } 344 345 template<typename T> 346 C2FieldSupportedValuesHelper<T>::~C2FieldSupportedValuesHelper() = default; 347 348 template<typename T> 349 bool C2FieldSupportedValuesHelper<T>::supports(T value) const { 350 return _mImpl->supports(value); 351 } 352 353 template class C2FieldSupportedValuesHelper<uint8_t>; 354 template class C2FieldSupportedValuesHelper<char>; 355 template class C2FieldSupportedValuesHelper<int32_t>; 356 template class C2FieldSupportedValuesHelper<uint32_t>; 357 //template class C2FieldSupportedValuesHelper<c2_cntr32_t>; 358 template class C2FieldSupportedValuesHelper<int64_t>; 359 template class C2FieldSupportedValuesHelper<uint64_t>; 360 //template class C2FieldSupportedValuesHelper<c2_cntr64_t>; 361 template class C2FieldSupportedValuesHelper<float>; 362 363 /* ----------------------- C2ParamFieldValuesBuilder ----------------------- */ 364 365 template<typename T> 366 struct C2ParamFieldValuesBuilder<T>::Impl { 367 Impl(const C2ParamField &field) 368 : _mParamField(field), 369 _mType(type_t::RANGE), 370 _mDefined(false), 371 _mRange(C2SupportedRange<T>::Any()), 372 _mValues(C2SupportedValueSet<T>::None()), 373 _mFlags(C2SupportedFlags<T>::None()) { } 374 375 /** 376 * Get C2ParamFieldValues from this builder. 377 */ 378 operator C2ParamFieldValues() const { 379 if (!_mDefined) { 380 return C2ParamFieldValues(_mParamField); 381 } 382 switch (_mType) { 383 case type_t::EMPTY: 384 case type_t::VALUES: 385 return C2ParamFieldValues(_mParamField, (C2FieldSupportedValues)_mValues); 386 case type_t::RANGE: 387 return C2ParamFieldValues(_mParamField, (C2FieldSupportedValues)_mRange); 388 case type_t::FLAGS: 389 return C2ParamFieldValues(_mParamField, (C2FieldSupportedValues)_mFlags); 390 default: 391 // TRESPASS 392 // should never get here 393 return C2ParamFieldValues(_mParamField); 394 } 395 } 396 397 /** Define the supported values as the currently supported values of this builder. */ 398 void any() { 399 _mDefined = true; 400 } 401 402 /** Restrict (and thus define) the supported values to none. */ 403 void none() { 404 _mDefined = true; 405 _mType = type_t::VALUES; 406 _mValues.clear(); 407 } 408 409 /** Restrict (and thus define) the supported values to |value| alone. */ 410 void equalTo(T value) { 411 return limitTo(C2SupportedValueSet<T>::OneOf({value})); 412 } 413 414 /** Restrict (and thus define) the supported values to a value set. */ 415 void limitTo(const C2SupportedValueSet<T> &limit) { 416 if (!_mDefined) { 417 C2_LOG(VERBOSE) << "NA.limitTo(" << C2FieldSupportedValuesHelper<T>(limit) << ")"; 418 419 // shortcut for first limit applied 420 _mDefined = true; 421 _mValues = limit; 422 _mType = _mValues.isEmpty() ? type_t::EMPTY : type_t::VALUES; 423 } else { 424 switch (_mType) { 425 case type_t::EMPTY: 426 case type_t::VALUES: 427 C2_LOG(VERBOSE) << "(" << C2FieldSupportedValuesHelper<T>(_mValues) << ").limitTo(" 428 << C2FieldSupportedValuesHelper<T>(limit) << ")"; 429 430 _mValues = _mValues.limitedTo(limit); 431 _mType = _mValues.isEmpty() ? type_t::EMPTY : type_t::VALUES; 432 break; 433 case type_t::RANGE: 434 C2_LOG(VERBOSE) << "(" << C2FieldSupportedValuesHelper<T>(_mRange) << ").limitTo(" 435 << C2FieldSupportedValuesHelper<T>(limit) << ")"; 436 437 _mValues = limit.limitedTo(_mRange); 438 _mType = _mValues.isEmpty() ? type_t::EMPTY : type_t::VALUES; 439 break; 440 case type_t::FLAGS: 441 C2_LOG(VERBOSE) << "(" << C2FieldSupportedValuesHelper<T>(_mRange) << ").limitTo(" 442 << C2FieldSupportedValuesHelper<T>(limit) << ")"; 443 444 _mValues = limit.limitedTo(_mFlags); 445 _mType = _mValues.isEmpty() ? type_t::EMPTY : type_t::VALUES; 446 break; 447 default: 448 C2_LOG(FATAL); // should not be here 449 } 450 // TODO: support flags 451 } 452 C2_LOG(VERBOSE) << " = " << _mType << ":" << C2FieldSupportedValuesHelper<T>(_mValues); 453 } 454 455 /** Restrict (and thus define) the supported values to a flag set. */ 456 void limitTo(const C2SupportedFlags<T> &limit) { 457 if (!_mDefined) { 458 C2_LOG(VERBOSE) << "NA.limitTo(" << C2FieldSupportedValuesHelper<T>(limit) << ")"; 459 460 // shortcut for first limit applied 461 _mDefined = true; 462 _mFlags = limit; 463 _mType = _mFlags.isEmpty() ? type_t::EMPTY : type_t::FLAGS; 464 } else { 465 switch (_mType) { 466 case type_t::EMPTY: 467 case type_t::VALUES: 468 C2_LOG(VERBOSE) << "(" << C2FieldSupportedValuesHelper<T>(_mValues) << ").limitTo(" 469 << C2FieldSupportedValuesHelper<T>(limit) << ")"; 470 471 _mValues = _mValues.limitedTo(limit); 472 _mType = _mValues.isEmpty() ? type_t::EMPTY : type_t::VALUES; 473 C2_LOG(VERBOSE) << " = " << _mType << ":" << C2FieldSupportedValuesHelper<T>(_mValues); 474 break; 475 case type_t::FLAGS: 476 C2_LOG(VERBOSE) << "(" << C2FieldSupportedValuesHelper<T>(_mFlags) << ").limitTo(" 477 << C2FieldSupportedValuesHelper<T>(limit) << ")"; 478 479 _mFlags = _mFlags.limitedTo(limit); 480 _mType = _mFlags.isEmpty() ? type_t::EMPTY : type_t::FLAGS; 481 C2_LOG(VERBOSE) << " = " << _mType << ":" << C2FieldSupportedValuesHelper<T>(_mFlags); 482 break; 483 case type_t::RANGE: 484 C2_LOG(FATAL) << "limiting ranges to flags is not supported"; 485 _mType = type_t::EMPTY; 486 break; 487 default: 488 C2_LOG(FATAL); // should not be here 489 } 490 } 491 } 492 493 void limitTo(const C2SupportedRange<T> &limit) { 494 if (!_mDefined) { 495 C2_LOG(VERBOSE) << "NA.limitTo(" << C2FieldSupportedValuesHelper<T>(limit) << ")"; 496 497 // shortcut for first limit applied 498 _mDefined = true; 499 _mRange = limit; 500 _mType = _mRange.isEmpty() ? type_t::EMPTY : type_t::RANGE; 501 C2_LOG(VERBOSE) << " = " << _mType << ":" << C2FieldSupportedValuesHelper<T>(_mRange); 502 } else { 503 switch (_mType) { 504 case type_t::EMPTY: 505 case type_t::VALUES: 506 C2_LOG(VERBOSE) << "(" << C2FieldSupportedValuesHelper<T>(_mValues) << ").limitTo(" 507 << C2FieldSupportedValuesHelper<T>(limit) << ")"; 508 _mValues = _mValues.limitedTo(limit); 509 _mType = _mValues.isEmpty() ? type_t::EMPTY : type_t::VALUES; 510 C2_LOG(VERBOSE) << " = " << _mType << ":" << C2FieldSupportedValuesHelper<T>(_mValues); 511 break; 512 case type_t::FLAGS: 513 C2_LOG(FATAL) << "limiting flags to ranges is not supported"; 514 _mType = type_t::EMPTY; 515 break; 516 case type_t::RANGE: 517 C2_LOG(VERBOSE) << "(" << C2FieldSupportedValuesHelper<T>(_mRange) << ").limitTo(" 518 << C2FieldSupportedValuesHelper<T>(limit) << ")"; 519 _mRange = _mRange.limitedTo(limit); 520 C2_DCHECK(_mValues.isEmpty()); 521 _mType = _mRange.isEmpty() ? type_t::EMPTY : type_t::RANGE; 522 C2_LOG(VERBOSE) << " = " << _mType << ":" << C2FieldSupportedValuesHelper<T>(_mRange); 523 break; 524 default: 525 C2_LOG(FATAL); // should not be here 526 } 527 } 528 } 529 530 private: 531 void instantiate() __unused { 532 (void)_mValues.values(); // instantiate non-const values() 533 } 534 535 void instantiate() const __unused { 536 (void)_mValues.values(); // instantiate const values() 537 } 538 539 typedef C2FieldSupportedValues::type_t type_t; 540 541 C2ParamField _mParamField; 542 type_t _mType; 543 bool _mDefined; 544 C2SupportedRange<T> _mRange; 545 C2SupportedValueSet<T> _mValues; 546 C2SupportedFlags<T> _mFlags; 547 548 }; 549 550 template<typename T> 551 C2ParamFieldValuesBuilder<T>::operator C2ParamFieldValues() const { 552 return (C2ParamFieldValues)(*_mImpl.get()); 553 } 554 555 template<typename T> 556 C2ParamFieldValuesBuilder<T>::C2ParamFieldValuesBuilder(const C2ParamField &field) 557 : _mImpl(std::make_unique<C2ParamFieldValuesBuilder<T>::Impl>(field)) { } 558 559 template<typename T> 560 C2ParamFieldValuesBuilder<T> &C2ParamFieldValuesBuilder<T>::any() { 561 _mImpl->any(); 562 return *this; 563 } 564 565 template<typename T> 566 C2ParamFieldValuesBuilder<T> &C2ParamFieldValuesBuilder<T>::none() { 567 _mImpl->none(); 568 return *this; 569 } 570 571 template<typename T> 572 C2ParamFieldValuesBuilder<T> &C2ParamFieldValuesBuilder<T>::equalTo(T value) { 573 _mImpl->equalTo(value); 574 return *this; 575 } 576 577 template<typename T> 578 C2ParamFieldValuesBuilder<T> &C2ParamFieldValuesBuilder<T>::limitTo(const C2SupportedValueSet<T> &limit) { 579 _mImpl->limitTo(limit); 580 return *this; 581 } 582 583 template<typename T> 584 C2ParamFieldValuesBuilder<T> &C2ParamFieldValuesBuilder<T>::limitTo(const C2SupportedFlags<T> &limit) { 585 _mImpl->limitTo(limit); 586 return *this; 587 } 588 589 template<typename T> 590 C2ParamFieldValuesBuilder<T> &C2ParamFieldValuesBuilder<T>::limitTo(const C2SupportedRange<T> &limit) { 591 _mImpl->limitTo(limit); 592 return *this; 593 } 594 595 template<typename T> 596 C2ParamFieldValuesBuilder<T>::C2ParamFieldValuesBuilder(const C2ParamFieldValuesBuilder<T> &other) 597 : _mImpl(std::make_unique<C2ParamFieldValuesBuilder<T>::Impl>(*other._mImpl.get())) { } 598 599 template<typename T> 600 C2ParamFieldValuesBuilder<T> &C2ParamFieldValuesBuilder<T>::operator=( 601 const C2ParamFieldValuesBuilder<T> &other) { 602 _mImpl = std::make_unique<C2ParamFieldValuesBuilder<T>::Impl>(*other._mImpl.get()); 603 return *this; 604 } 605 606 template<typename T> 607 C2ParamFieldValuesBuilder<T>::~C2ParamFieldValuesBuilder() = default; 608 609 template class C2ParamFieldValuesBuilder<uint8_t>; 610 template class C2ParamFieldValuesBuilder<char>; 611 template class C2ParamFieldValuesBuilder<int32_t>; 612 template class C2ParamFieldValuesBuilder<uint32_t>; 613 //template class C2ParamFieldValuesBuilder<c2_cntr32_t>; 614 template class C2ParamFieldValuesBuilder<int64_t>; 615 template class C2ParamFieldValuesBuilder<uint64_t>; 616 //template class C2ParamFieldValuesBuilder<c2_cntr64_t>; 617 template class C2ParamFieldValuesBuilder<float>; 618 619 /* ------------------------- C2SettingResultBuilder ------------------------- */ 620 621 C2SettingConflictsBuilder::C2SettingConflictsBuilder() : _mConflicts() { } 622 623 C2SettingConflictsBuilder::C2SettingConflictsBuilder(C2ParamFieldValues &&conflict) { 624 _mConflicts.emplace_back(std::move(conflict)); 625 } 626 627 C2SettingConflictsBuilder& C2SettingConflictsBuilder::with(C2ParamFieldValues &&conflict) { 628 _mConflicts.emplace_back(std::move(conflict)); 629 return *this; 630 } 631 632 std::vector<C2ParamFieldValues> C2SettingConflictsBuilder::retrieveConflicts() { 633 return std::move(_mConflicts); 634 } 635 636 /* ------------------------- C2SettingResult/sBuilder ------------------------- */ 637 638 C2SettingResult C2SettingResultBuilder::ReadOnly(const C2ParamField ¶m) { 639 return C2SettingResult { C2SettingResult::READ_ONLY, { param }, { } }; 640 } 641 642 C2SettingResult C2SettingResultBuilder::BadValue(const C2ParamField ¶mField, bool isInfo) { 643 return { isInfo ? C2SettingResult::INFO_BAD_VALUE : C2SettingResult::BAD_VALUE, 644 { paramField }, { } }; 645 } 646 647 C2SettingResult C2SettingResultBuilder::Conflict( 648 C2ParamFieldValues &¶mFieldValues, C2SettingConflictsBuilder &conflicts, bool isInfo) { 649 C2_CHECK(!conflicts.empty()); 650 if (isInfo) { 651 return C2SettingResult { 652 C2SettingResult::INFO_CONFLICT, 653 std::move(paramFieldValues), conflicts.retrieveConflicts() 654 }; 655 } else { 656 return C2SettingResult { 657 C2SettingResult::CONFLICT, 658 std::move(paramFieldValues), conflicts.retrieveConflicts() 659 }; 660 } 661 } 662 663 C2SettingResultsBuilder::C2SettingResultsBuilder(C2SettingResult &&result) 664 : _mStatus(C2_BAD_VALUE) { 665 _mResults.emplace_back(new C2SettingResult(std::move(result))); 666 } 667 668 C2SettingResultsBuilder C2SettingResultsBuilder::plus(C2SettingResultsBuilder&& results) { 669 for (std::unique_ptr<C2SettingResult> &r : results._mResults) { 670 _mResults.emplace_back(std::move(r)); 671 } 672 results._mResults.clear(); 673 // TODO: mStatus 674 return std::move(*this); 675 } 676 677 c2_status_t C2SettingResultsBuilder::retrieveFailures( 678 std::vector<std::unique_ptr<C2SettingResult>>* const failures) { 679 for (std::unique_ptr<C2SettingResult> &r : _mResults) { 680 failures->emplace_back(std::move(r)); 681 } 682 _mResults.clear(); 683 return _mStatus; 684 } 685 686 C2SettingResultsBuilder::C2SettingResultsBuilder(c2_status_t status) : _mStatus(status) { 687 // status must be one of OK, BAD_STATE, TIMED_OUT or CORRUPTED 688 // mainly: BLOCKING, BAD_INDEX, BAD_VALUE and NO_MEMORY requires a setting attempt 689 } 690 691 #pragma clang diagnostic pop 692 693 /* ------------------------- C2FieldUtils ------------------------- */ 694 695 struct C2_HIDE C2FieldUtils::_Inspector { 696 /// returns the implementation object 697 inline static std::shared_ptr<Info::Impl> GetImpl(const Info &info) { 698 return info._mImpl; 699 } 700 }; 701 702 /* ------------------------- C2FieldUtils::Info ------------------------- */ 703 704 struct C2_HIDE C2FieldUtils::Info::Impl { 705 C2FieldDescriptor field; 706 std::shared_ptr<Impl> parent; 707 uint32_t index; 708 uint32_t depth; 709 uint32_t baseFieldOffset; 710 uint32_t arrayOffset; 711 uint32_t usedExtent; 712 713 /// creates a copy of this object including copies of its parent chain 714 Impl clone() const; 715 716 /// creates a copy of a shared pointer to an object 717 static std::shared_ptr<Impl> Clone(const std::shared_ptr<Impl> &); 718 719 Impl(const C2FieldDescriptor &field_, std::shared_ptr<Impl> parent_, 720 uint32_t index_, uint32_t depth_, uint32_t baseFieldOffset_, 721 uint32_t arrayOffset_, uint32_t usedExtent_) 722 : field(field_), parent(parent_), index(index_), depth(depth_), 723 baseFieldOffset(baseFieldOffset_), arrayOffset(arrayOffset_), usedExtent(usedExtent_) { } 724 }; 725 726 std::shared_ptr<C2FieldUtils::Info::Impl> C2FieldUtils::Info::Impl::Clone(const std::shared_ptr<Impl> &info) { 727 if (info) { 728 return std::make_shared<Impl>(info->clone()); 729 } 730 return nullptr; 731 } 732 733 C2FieldUtils::Info::Impl C2FieldUtils::Info::Impl::clone() const { 734 Impl res = Impl(*this); 735 res.parent = Clone(res.parent); 736 return res; 737 } 738 739 C2FieldUtils::Info::Info(std::shared_ptr<Impl> impl) 740 : _mImpl(impl) { } 741 742 size_t C2FieldUtils::Info::arrayOffset() const { 743 return _mImpl->arrayOffset; 744 } 745 746 size_t C2FieldUtils::Info::arraySize() const { 747 return extent() * size(); 748 } 749 750 size_t C2FieldUtils::Info::baseFieldOffset() const { 751 return _mImpl->baseFieldOffset; 752 }; 753 754 size_t C2FieldUtils::Info::depth() const { 755 return _mImpl->depth; 756 } 757 758 size_t C2FieldUtils::Info::extent() const { 759 return _mImpl->usedExtent; 760 } 761 762 size_t C2FieldUtils::Info::index() const { 763 return _mImpl->index; 764 } 765 766 bool C2FieldUtils::Info::isArithmetic() const { 767 switch (_mImpl->field.type()) { 768 case C2FieldDescriptor::BLOB: 769 case C2FieldDescriptor::CNTR32: 770 case C2FieldDescriptor::CNTR64: 771 case C2FieldDescriptor::FLOAT: 772 case C2FieldDescriptor::INT32: 773 case C2FieldDescriptor::INT64: 774 case C2FieldDescriptor::STRING: 775 case C2FieldDescriptor::UINT32: 776 case C2FieldDescriptor::UINT64: 777 return true; 778 default: 779 return false; 780 } 781 } 782 783 bool C2FieldUtils::Info::isFlexible() const { 784 return _mImpl->field.extent() == 0; 785 } 786 787 C2String C2FieldUtils::Info::name() const { 788 return _mImpl->field.name(); 789 } 790 791 const C2FieldUtils::Info::NamedValuesType &C2FieldUtils::Info::namedValues() const { 792 return _mImpl->field.namedValues(); 793 } 794 795 size_t C2FieldUtils::Info::offset() const { 796 return _C2ParamInspector::GetOffset(_mImpl->field); 797 } 798 799 C2FieldUtils::Info C2FieldUtils::Info::parent() const { 800 return Info(_mImpl->parent); 801 }; 802 803 size_t C2FieldUtils::Info::size() const { 804 return _C2ParamInspector::GetSize(_mImpl->field); 805 } 806 807 C2FieldUtils::Info::type_t C2FieldUtils::Info::type() const { 808 return _mImpl->field.type(); 809 } 810 811 /* ------------------------- C2FieldUtils::Iterator ------------------------- */ 812 813 struct C2_HIDE C2FieldUtils::Iterator::Impl : public _C2ParamInspector { 814 Impl() = default; 815 816 virtual ~Impl() = default; 817 818 /// implements object equality 819 virtual bool equals(const std::shared_ptr<Impl> &other) const { 820 return other != nullptr && mHead == other->mHead; 821 }; 822 823 /// returns the info pointed to by this iterator 824 virtual value_type get() const { 825 return Info(mHead); 826 } 827 828 /// increments this iterator 829 virtual void increment() { 830 // note: this cannot be abstract as we instantiate this for List::end(). increment to end() 831 // instead. 832 mHead.reset(); 833 } 834 835 protected: 836 Impl(std::shared_ptr<C2FieldUtils::Info::Impl> head) 837 : mHead(head) { } 838 839 std::shared_ptr<Info::Impl> mHead; ///< current field 840 }; 841 842 C2FieldUtils::Iterator::Iterator(std::shared_ptr<Impl> impl) 843 : mImpl(impl) { } 844 845 C2FieldUtils::Iterator::value_type C2FieldUtils::Iterator::operator*() const { 846 return mImpl->get(); 847 } 848 849 C2FieldUtils::Iterator& C2FieldUtils::Iterator::operator++() { 850 mImpl->increment(); 851 return *this; 852 } 853 854 bool C2FieldUtils::Iterator::operator==(const Iterator &other) const { 855 return mImpl->equals(other.mImpl); 856 } 857 858 /* ------------------------- C2FieldUtils::List ------------------------- */ 859 860 struct C2_HIDE C2FieldUtils::List::Impl { 861 virtual std::shared_ptr<Iterator::Impl> begin() const = 0; 862 863 /// returns an iterator to the end of the list 864 virtual std::shared_ptr<Iterator::Impl> end() const { 865 return std::make_shared<Iterator::Impl>(); 866 } 867 868 virtual ~Impl() = default; 869 }; 870 871 C2FieldUtils::List::List(std::shared_ptr<Impl> impl) 872 : mImpl(impl) { } 873 874 C2FieldUtils::Iterator C2FieldUtils::List::begin() const { 875 return C2FieldUtils::Iterator(mImpl->begin()); 876 } 877 878 C2FieldUtils::Iterator C2FieldUtils::List::end() const { 879 return C2FieldUtils::Iterator(mImpl->end()); 880 } 881 882 /* ------------------------- C2FieldUtils::enumerateFields ------------------------- */ 883 884 namespace { 885 886 /** 887 * Iterator base class helper that allows descending into the field hierarchy. 888 */ 889 struct C2FieldUtilsFieldsIteratorHelper : public C2FieldUtils::Iterator::Impl { 890 virtual ~C2FieldUtilsFieldsIteratorHelper() override = default; 891 892 /// returns the base-field's offset of the parent field (or the param offset if no parent) 893 static inline uint32_t GetParentBaseFieldOffset( 894 const std::shared_ptr<C2FieldUtils::Info::Impl> parent) { 895 return parent == nullptr ? sizeof(C2Param) : parent->baseFieldOffset; 896 } 897 898 /// returns the offset of the parent field (or the param) 899 static inline uint32_t GetParentOffset(const std::shared_ptr<C2FieldUtils::Info::Impl> parent) { 900 return parent == nullptr ? sizeof(C2Param) : GetOffset(parent->field); 901 } 902 903 protected: 904 C2FieldUtilsFieldsIteratorHelper( 905 std::shared_ptr<C2ParamReflector> reflector, 906 uint32_t paramSize, 907 std::shared_ptr<C2FieldUtils::Info::Impl> head = nullptr) 908 : C2FieldUtils::Iterator::Impl(head), 909 mParamSize(paramSize), 910 mReflector(reflector) { } 911 912 /// returns a leaf info object at a specific index for a child field 913 std::shared_ptr<C2FieldUtils::Info::Impl> makeLeaf( 914 const C2FieldDescriptor &field, uint32_t index) { 915 uint32_t parentOffset = GetParentOffset(mHead); 916 uint32_t arrayOffset = parentOffset + GetOffset(field); 917 uint32_t usedExtent = field.extent() ? : 918 (std::max(arrayOffset, mParamSize) - arrayOffset) / GetSize(field); 919 920 return std::make_shared<C2FieldUtils::Info::Impl>( 921 OffsetFieldDescriptor(field, parentOffset + index * GetSize(field)), 922 mHead /* parent */, index, mHead == nullptr ? 0 : mHead->depth + 1, 923 GetParentBaseFieldOffset(mHead) + GetOffset(field), 924 arrayOffset, usedExtent); 925 } 926 927 /// returns whether this struct index have been traversed to get to this field 928 bool visited(C2Param::CoreIndex index) const { 929 for (const std::shared_ptr<C2StructDescriptor> &sd : mHistory) { 930 if (sd->coreIndex() == index) { 931 return true; 932 } 933 } 934 return false; 935 } 936 937 uint32_t mParamSize; 938 std::shared_ptr<C2ParamReflector> mReflector; 939 std::vector<std::shared_ptr<C2StructDescriptor>> mHistory; // structure types visited 940 }; 941 942 /** 943 * Iterator implementing enumerateFields() that visits each base field. 944 */ 945 struct C2FieldUtilsFieldsIterator : public C2FieldUtilsFieldsIteratorHelper { 946 /// enumerate base fields of a parameter 947 C2FieldUtilsFieldsIterator(const C2Param ¶m, std::shared_ptr<C2ParamReflector> reflector) 948 : C2FieldUtilsFieldsIteratorHelper(reflector, param.size()) { 949 descendInto(param.coreIndex()); 950 } 951 952 /// enumerate base fields of a field 953 C2FieldUtilsFieldsIterator(std::shared_ptr<C2FieldUtilsFieldsIterator> impl) 954 : C2FieldUtilsFieldsIteratorHelper(impl->mReflector, impl->mParamSize, impl->mHead) { 955 mHistory = impl->mHistory; 956 if (mHead->field.type() & C2FieldDescriptor::STRUCT_FLAG) { 957 C2Param::CoreIndex index = { mHead->field.type() &~C2FieldDescriptor::STRUCT_FLAG }; 958 if (!visited(index)) { 959 descendInto(index); 960 } 961 } 962 } 963 964 virtual ~C2FieldUtilsFieldsIterator() override = default; 965 966 /// Increments this iterator by visiting each base field. 967 virtual void increment() override { 968 // don't go past end 969 if (mHead == nullptr || _mFields.empty()) { 970 return; 971 } 972 973 // descend into structures 974 if (mHead->field.type() & C2FieldDescriptor::STRUCT_FLAG) { 975 C2Param::CoreIndex index = { mHead->field.type() &~C2FieldDescriptor::STRUCT_FLAG }; 976 // do not recurse into the same structs 977 if (!visited(index) && descendInto(index)) { 978 return; 979 } 980 } 981 982 // ascend after the last field in the current struct 983 while (!mHistory.empty() && _mFields.back() == mHistory.back()->end()) { 984 mHead = mHead->parent; 985 mHistory.pop_back(); 986 _mFields.pop_back(); 987 } 988 989 // done if history is now empty 990 if (_mFields.empty()) { 991 // we could be traversing a sub-tree so clear head 992 mHead.reset(); 993 return; 994 } 995 996 // move to the next field in the current struct 997 C2StructDescriptor::field_iterator next = _mFields.back(); 998 mHead->field = OffsetFieldDescriptor(*next, GetParentOffset(mHead->parent)); 999 mHead->index = 0; // reset index just in case for correctness 1000 mHead->baseFieldOffset = GetParentBaseFieldOffset(mHead->parent) + GetOffset(*next); 1001 mHead->arrayOffset = GetOffset(mHead->field); 1002 mHead->usedExtent = mHead->field.extent() ? : 1003 (std::max(mHead->arrayOffset, mParamSize) - mHead->arrayOffset) 1004 / GetSize(mHead->field); 1005 ++_mFields.back(); 1006 } 1007 1008 private: 1009 /// If the current field is a known, valid (untraversed) structure, it modifies this iterator 1010 /// to point to the first field of the structure and returns true. Otherwise, it does not 1011 /// modify this iterator and returns false. 1012 bool descendInto(C2Param::CoreIndex index) { 1013 std::unique_ptr<C2StructDescriptor> descUnique = mReflector->describe(index); 1014 // descend into known structs (as long as they have at least one field) 1015 if (descUnique && descUnique->begin() != descUnique->end()) { 1016 std::shared_ptr<C2StructDescriptor> desc(std::move(descUnique)); 1017 mHistory.emplace_back(desc); 1018 C2StructDescriptor::field_iterator first = desc->begin(); 1019 mHead = makeLeaf(*first, 0 /* index */); 1020 _mFields.emplace_back(++first); 1021 return true; 1022 } 1023 return false; 1024 } 1025 1026 /// next field pointers for each depth. 1027 /// note: _mFields may be shorted than mHistory, if iterating at a depth 1028 std::vector<C2StructDescriptor::field_iterator> _mFields; 1029 }; 1030 1031 /** 1032 * Iterable implementing enumerateFields(). 1033 */ 1034 struct C2FieldUtilsFieldIterable : public C2FieldUtils::List::Impl { 1035 /// returns an iterator to the beginning of the list 1036 virtual std::shared_ptr<C2FieldUtils::Iterator::Impl> begin() const override { 1037 return std::make_shared<C2FieldUtilsFieldsIterator>(*_mParam, _mReflector); 1038 }; 1039 1040 C2FieldUtilsFieldIterable(const C2Param ¶m, std::shared_ptr<C2ParamReflector> reflector) 1041 : _mParam(¶m), _mReflector(reflector) { } 1042 1043 private: 1044 const C2Param *_mParam; 1045 std::shared_ptr<C2ParamReflector> _mReflector; 1046 }; 1047 1048 } 1049 1050 C2FieldUtils::List C2FieldUtils::enumerateFields( 1051 const C2Param ¶m, const std::shared_ptr<C2ParamReflector> &reflector) { 1052 return C2FieldUtils::List(std::make_shared<C2FieldUtilsFieldIterable>(param, reflector)); 1053 } 1054 1055 /* ------------------------- C2FieldUtils::enumerate siblings ------------------------- */ 1056 1057 namespace { 1058 1059 struct C2FieldUtilsCousinsIterator : public C2FieldUtils::Iterator::Impl { 1060 C2FieldUtilsCousinsIterator( 1061 const std::shared_ptr<C2FieldUtils::Info::Impl> &info, size_t level) 1062 // clone info chain as this iterator will change it 1063 : C2FieldUtils::Iterator::Impl(C2FieldUtils::Info::Impl::Clone(info)) { 1064 if (level == 0) { 1065 return; 1066 } 1067 1068 // store parent chain (up to level) for quick access 1069 std::shared_ptr<C2FieldUtils::Info::Impl> node = mHead; 1070 size_t ix = 0; 1071 for (; ix < level && node; ++ix) { 1072 node->index = 0; 1073 _mPath.emplace_back(node); 1074 node = node->parent; 1075 } 1076 setupPath(ix); 1077 } 1078 1079 virtual ~C2FieldUtilsCousinsIterator() override = default; 1080 1081 /// Increments this iterator by visiting each index. 1082 virtual void increment() override { 1083 size_t ix = 0; 1084 while (ix < _mPath.size()) { 1085 if (++_mPath[ix]->index < _mPath[ix]->usedExtent) { 1086 setupPath(ix + 1); 1087 return; 1088 } 1089 _mPath[ix++]->index = 0; 1090 } 1091 mHead.reset(); 1092 } 1093 1094 private: 1095 /// adjusts field offsets along the path up to the specific level - 1. 1096 /// This in-fact has to be done down the path from parent to child as child fields must 1097 /// fall within parent fields. 1098 void setupPath(size_t level) { 1099 C2_CHECK_LE(level, _mPath.size()); 1100 uint32_t oldArrayOffset = level ? _mPath[level - 1]->arrayOffset : 0 /* unused */; 1101 while (level) { 1102 --level; 1103 C2FieldUtils::Info::Impl &path = *_mPath[level]; 1104 uint32_t size = GetSize(path.field); 1105 uint32_t offset = path.arrayOffset + size * path.index; 1106 SetOffset(path.field, offset); 1107 if (level) { 1108 // reset child's array offset to fall within current index, but hold onto the 1109 // original value of the arrayOffset so that we can adjust subsequent children. 1110 // This is because the modulo is only defined within the current array. 1111 uint32_t childArrayOffset = 1112 offset + (_mPath[level - 1]->arrayOffset - oldArrayOffset) % size; 1113 oldArrayOffset = _mPath[level - 1]->arrayOffset; 1114 _mPath[level - 1]->arrayOffset = childArrayOffset; 1115 } 1116 } 1117 } 1118 1119 std::vector<std::shared_ptr<C2FieldUtils::Info::Impl>> _mPath; 1120 }; 1121 1122 /** 1123 * Iterable implementing enumerateFields(). 1124 */ 1125 struct C2FieldUtilsCousinsIterable : public C2FieldUtils::List::Impl { 1126 /// returns an iterator to the beginning of the list 1127 virtual std::shared_ptr<C2FieldUtils::Iterator::Impl> begin() const override { 1128 return std::make_shared<C2FieldUtilsCousinsIterator>(_mHead, _mLevel); 1129 }; 1130 1131 C2FieldUtilsCousinsIterable(const C2FieldUtils::Info &field, uint32_t level) 1132 : _mHead(C2FieldUtils::_Inspector::GetImpl(field)), _mLevel(level) { } 1133 1134 private: 1135 std::shared_ptr<C2FieldUtils::Info::Impl> _mHead; 1136 size_t _mLevel; 1137 }; 1138 1139 } 1140 1141 C2FieldUtils::List C2FieldUtils::enumerateCousins(const C2FieldUtils::Info &field, uint32_t level) { 1142 return C2FieldUtils::List(std::make_shared<C2FieldUtilsCousinsIterable>(field, level)); 1143 } 1144 1145 /* ------------------------- C2FieldUtils::locateField ------------------------- */ 1146 1147 namespace { 1148 1149 /** 1150 * Iterator implementing locateField(). 1151 */ 1152 struct C2FieldUtilsFieldLocator : public C2FieldUtilsFieldsIteratorHelper { 1153 C2FieldUtilsFieldLocator( 1154 C2Param::CoreIndex index, const _C2FieldId &field, uint32_t paramSize, 1155 std::shared_ptr<C2ParamReflector> reflector) 1156 : C2FieldUtilsFieldsIteratorHelper(reflector, paramSize), 1157 _mField(field) { 1158 while (descendInto(index)) { 1159 if ((mHead->field.type() & C2FieldDescriptor::STRUCT_FLAG) == 0) { 1160 break; 1161 } 1162 index = C2Param::CoreIndex(mHead->field.type() &~ C2FieldDescriptor::STRUCT_FLAG); 1163 } 1164 } 1165 1166 void increment() { 1167 mHead = _mTail; 1168 _mTail = nullptr; 1169 } 1170 1171 private: 1172 /// If the current field is a known, valid (untraversed) structure, it modifies this iterator 1173 /// to point to the field at the beginning/end of the given field of the structure and returns 1174 /// true. Otherwise, including if no such field exists in the structure, it does not modify this 1175 /// iterator and returns false. 1176 bool descendInto(C2Param::CoreIndex index) { 1177 // check that the boundaries of the field to be located are still within the same parent 1178 // field 1179 if (mHead != _mTail) { 1180 return false; 1181 } 1182 1183 std::unique_ptr<C2StructDescriptor> descUnique = mReflector->describe(index); 1184 // descend into known structs (as long as they have at least one field) 1185 if (descUnique && descUnique->begin() != descUnique->end()) { 1186 std::shared_ptr<C2StructDescriptor> desc(std::move(descUnique)); 1187 mHistory.emplace_back(desc); 1188 1189 uint32_t parentOffset = GetParentOffset(mHead); 1190 1191 // locate field using a dummy field descriptor 1192 C2FieldDescriptor dummy = { 1193 C2FieldDescriptor::BLOB, 1 /* extent */, "name", 1194 GetOffset(_mField) - parentOffset, GetSize(_mField) 1195 }; 1196 1197 // locate first field where offset is greater than dummy offset (which is one past) 1198 auto it = std::upper_bound( 1199 desc->cbegin(), desc->cend(), dummy, 1200 [](const C2FieldDescriptor &a, const C2FieldDescriptor &b) -> bool { 1201 return _C2ParamInspector::GetOffset(a) < _C2ParamInspector::GetOffset(b); 1202 }); 1203 if (it == desc->begin()) { 1204 // field is prior to first field 1205 return false; 1206 } 1207 --it; 1208 const C2FieldDescriptor &field = *it; 1209 1210 // check that dummy end-offset is within this field 1211 uint32_t structSize = std::max(mParamSize, parentOffset) - parentOffset; 1212 if (GetEndOffset(dummy) > GetEndOffset(field, structSize)) { 1213 return false; 1214 } 1215 1216 uint32_t startIndex = (GetOffset(dummy) - GetOffset(field)) / GetSize(field); 1217 uint32_t endIndex = 1218 (GetEndOffset(dummy) - GetOffset(field) + GetSize(field) - 1) / GetSize(field); 1219 if (endIndex > startIndex) { 1220 // Field size could be zero, in which case end index is still on start index. 1221 // However, for all other cases, endIndex was rounded up to the next index, so 1222 // decrement it. 1223 --endIndex; 1224 } 1225 std::shared_ptr<C2FieldUtils::Info::Impl> startLeaf = 1226 makeLeaf(field, startIndex); 1227 if (endIndex == startIndex) { 1228 _mTail = startLeaf; 1229 mHead = startLeaf; 1230 } else { 1231 _mTail = makeLeaf(field, endIndex); 1232 mHead = startLeaf; 1233 } 1234 return true; 1235 } 1236 return false; 1237 } 1238 1239 _C2FieldId _mField; 1240 std::shared_ptr<C2FieldUtils::Info::Impl> _mTail; 1241 }; 1242 1243 /** 1244 * Iterable implementing locateField(). 1245 */ 1246 struct C2FieldUtilsFieldLocation : public C2FieldUtils::List::Impl { 1247 /// returns an iterator to the beginning of the list 1248 virtual std::shared_ptr<C2FieldUtils::Iterator::Impl> begin() const override { 1249 return std::make_shared<C2FieldUtilsFieldLocator>( 1250 _mIndex, _mField, _mParamSize, _mReflector); 1251 }; 1252 1253 C2FieldUtilsFieldLocation( 1254 const C2ParamField &pf, std::shared_ptr<C2ParamReflector> reflector) 1255 : _mIndex(C2Param::CoreIndex(_C2ParamInspector::GetIndex(pf))), 1256 _mField(_C2ParamInspector::GetField(pf)), 1257 _mParamSize(0), 1258 _mReflector(reflector) { } 1259 1260 1261 C2FieldUtilsFieldLocation( 1262 const C2Param ¶m, const _C2FieldId &field, 1263 std::shared_ptr<C2ParamReflector> reflector) 1264 : _mIndex(param.coreIndex()), 1265 _mField(field), 1266 _mParamSize(param.size()), 1267 _mReflector(reflector) { } 1268 1269 private: 1270 C2Param::CoreIndex _mIndex; 1271 _C2FieldId _mField; 1272 uint32_t _mParamSize; 1273 std::shared_ptr<C2ParamReflector> _mReflector; 1274 }; 1275 1276 } 1277 1278 std::vector<C2FieldUtils::Info> C2FieldUtils::locateField( 1279 const C2ParamField &pf, const std::shared_ptr<C2ParamReflector> &reflector) { 1280 C2FieldUtils::List location = { std::make_shared<C2FieldUtilsFieldLocation>(pf, reflector) }; 1281 return std::vector<Info>(location.begin(), location.end()); 1282 } 1283 1284 std::vector<C2FieldUtils::Info> C2FieldUtils::locateField( 1285 const C2Param ¶m, const _C2FieldId &field, 1286 const std::shared_ptr<C2ParamReflector> &reflector) { 1287 C2FieldUtils::List location = { 1288 std::make_shared<C2FieldUtilsFieldLocation>(param, field, reflector) 1289 }; 1290 return std::vector<Info>(location.begin(), location.end()); 1291 } 1292 1293