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 &param) {
655     return C2SettingResult { C2SettingResult::READ_ONLY, { param }, { } };
656 }
657 
BadValue(const C2ParamField & paramField,bool isInfo)658 C2SettingResult C2SettingResultBuilder::BadValue(const C2ParamField &paramField, 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 &&paramFieldValues, 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 &param, 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 &param, std::shared_ptr<C2ParamReflector> reflector)
1057         : _mParam(&param), _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 &param, 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 &param, 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 &param, 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, &params);
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, &params);
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