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