• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

PredatorCZ / PreCore / 460

pending completion
460

push

github-actions-ci

PredatorCZ
try fix coverage

3204 of 6095 relevant lines covered (52.57%)

354.19 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

81.99
/src/reflector.cpp
1
/*  A source for Reflector class
2
    more info in README for PreCore Project
3

4
    Copyright 2018-2021 Lukas Cone
5

6
    Licensed under the Apache License, Version 2.0 (the "License");
7
    you may not use this file except in compliance with the License.
8
    You may obtain a copy of the License at
9

10
        http://www.apache.org/licenses/LICENSE-2.0
11

12
    Unless required by applicable law or agreed to in writing, software
13
    distributed under the License is distributed on an "AS IS" BASIS,
14
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
    See the License for the specific language governing permissions and
16
    limitations under the License.
17
*/
18

19
#include "spike/reflect/reflector.hpp"
20
#include "spike/master_printer.hpp"
21
#include "spike/type/bitfield.hpp"
22
#include "spike/type/float.hpp"
23
#include <algorithm>
24
#include <cctype>
25
#include <cmath>
26
#include <ostream>
27
#include <string_view>
28

29
static bool IsArray(REFType type) {
30
  return type == REFType::Array || type == REFType::ArrayClass;
40✔
31
}
32

33
static bool IsArrayVec(REFType type) {
34
  return type == REFType::Array || type == REFType::ArrayClass ||
53✔
35
         type == REFType::Vector;
36
}
37

38
static Reflector::ErrorType
39
SetReflectedMember(ReflType reflValue, std::string_view value, char *objAddr);
40

41
const ReflType *Reflector::GetReflectedType(const JenHash hash) const {
722✔
42
  const reflectorStatic *inst = GetReflectedInstance().rfStatic;
722✔
43
  const size_t _ntypes = GetNumReflectedValues();
44

45
  for (size_t t = 0; t < _ntypes; t++) {
14,316✔
46
    if (inst->types[t].valueNameHash == hash) {
14,305✔
47
      return GetReflectedType(t);
48
    }
49
  }
50

51
  if (inst->typeAliasHashes)
11✔
52
    for (size_t t = 0; t < _ntypes; t++) {
10✔
53
      if (inst->typeAliasHashes[t] == hash) {
10✔
54
        return GetReflectedType(t);
55
      }
56
    }
57

58
  return nullptr;
59
}
60

61
template <class T> struct LimitProxy {
62
  static const size_t numBits = sizeof(T) * 8;
63
  static const uint64 uMax = std::numeric_limits<T>::max();
64
  static const int64 iMin = std::numeric_limits<T>::min();
65
  static const int64 iMax = static_cast<int64>(uMax);
66
};
67

68
template <class type> struct BFTag {
69
  type value;
70
  BFTag(const type &value_) : value(value_) {}
28✔
71
  operator type() const { return value; }
72
};
73

74
template <class type> struct LimitProxy<BFTag<type>> {
75
  size_t numBits;
76
  const uint64 uMax;
77
  const int64 iMax;
78
  const int64 iMin;
79

80
  LimitProxy(size_t numBits_)
28✔
81
      : numBits(numBits_), uMax((1 << numBits) - 1), iMax(uMax >> 1),
28✔
82
        iMin(~iMax) {}
28✔
83
};
84

85
template <typename T, class ProxyType>
86
static Reflector::ErrorType SetNumber(std::string_view input_, T &output,
186✔
87
                                      ProxyType proxy) {
88
  std::string input(input_);
186✔
89
  Reflector::ErrorType errType = Reflector::ErrorType::None;
90
  const int base =
91
      !input.compare(0, 2, "0x") || !input.compare(0, 3, "-0x") ? 16 : 10;
186✔
92
  if constexpr (std::is_signed_v<T>) {
93
    int64 value = 0;
94
    const int64 iMin = proxy.iMin;
95
    const int64 iMax = proxy.iMax;
96
    bool OOR = false;
97

98
    try {
99
      value = std::stoll(input, nullptr, base);
100
    } catch (const std::invalid_argument &) {
5✔
101
      printerror("[Reflector] Invalid value: " << input);
2✔
102
      return Reflector::ErrorType::InvalidFormat;
103
    } catch (const std::out_of_range &) {
3✔
104
      OOR = true;
105
    }
106

107
    if (OOR || value > iMax || value < iMin) {
59✔
108
      printwarning("[Reflector] Integer out of range, got: "
24✔
109
                   << value << " for a signed " << proxy.numBits
110
                   << "bit number!");
111
      output = static_cast<T>(input[0] == '-' ? iMin : iMax);
12✔
112
      return Reflector::ErrorType::OutOfRange;
12✔
113
    }
114

115
    output = static_cast<T>(value);
61✔
116
  } else {
117
    uint64 value = 0;
118
    const uint64 iMax = proxy.uMax;
28✔
119
    bool OOR = false;
120

121
    try {
122
      value = std::stoull(input, nullptr, base);
123
    } catch (const std::invalid_argument &) {
1✔
124
      printerror("[Reflector] Invalid value: " << input);
×
125
      return Reflector::ErrorType::InvalidFormat;
126
    } catch (const std::out_of_range &) {
1✔
127
      OOR = true;
128
    }
129

130
    if (input[0] == '-') {
112✔
131
      value = static_cast<T>(value);
132
      printwarning("[Reflector] Applying "
24✔
133
                   << input
134
                   << " to an unsigned integer, casting to: " << value);
135
      errType = Reflector::ErrorType::SignMismatch;
136
    }
137

138
    if (OOR || value > iMax) {
112✔
139
      printwarning("[Reflector] Integer out of range, got: "
11✔
140
                   << value << " for an unsigned " << proxy.numBits
141
                   << "bit number!");
142
      output = static_cast<T>(iMax);
5✔
143
      return Reflector::ErrorType::OutOfRange;
5✔
144
    }
145

146
    output = static_cast<T>(value);
107✔
147
  }
148

149
  return errType;
168✔
150
}
151

19✔
152
template <typename T>
153
static Reflector::ErrorType SetNumber(std::string_view input_, T &output) {
19✔
154
  if constexpr (std::is_floating_point_v<T>) {
155
    std::string input(input_);
156
    constexpr T fMax = std::numeric_limits<T>::max();
19✔
157
    constexpr T fMin = std::numeric_limits<T>::min();
158

159
    try {
160
      output = [&input] {
161
        if constexpr (std::is_same_v<T, float>) {
162
          return std::stof(input);
163
        } else {
164
          return std::stod(input);
165
        }
166
      }();
167

168
      // MSVC Underflow fix
169
      if (std::fpclassify(output) == FP_SUBNORMAL) {
170
        throw std::out_of_range("");
171
      }
172
    } catch (const std::invalid_argument &) {
173
      printerror("[Reflector] Invalid value: " << input);
174
      return Reflector::ErrorType::InvalidFormat;
175
    } catch (const std::out_of_range &) {
176
      printwarning("[Reflector] Float out of range, got: " << input);
177

178
      double fVal = atof(input.c_str());
179

180
      if (fVal > 0)
181
        output = fVal > 1.0 ? fMax : fMin;
182
      else
183
        output = fVal < -1.0 ? -fMax : -fMin;
184

185
      return Reflector::ErrorType::OutOfRange;
186
    }
187

188
    return Reflector::ErrorType::None;
1✔
189
  } else {
×
190
    return SetNumber(input_, output, LimitProxy<T>{});
191
  }
1✔
192
}
193

194
static Reflector::ErrorType SetBoolean(std::string input, bool &output) {
195
  std::for_each(input.begin(), input.end(),
19✔
196
                [](char &c) { c = static_cast<char>(std::tolower(c)); });
197

6✔
198
  output = !memcmp(input.c_str(), "true", 4);
199

200
  if (!output && memcmp(input.c_str(), "false", 5)) {
201
    printwarning("[Reflector] Expected true/false, got: " << input);
202
    return Reflector::ErrorType::InvalidFormat;
203
  }
19✔
204

2✔
205
  return Reflector::ErrorType::None;
206
}
207

1✔
208
static uint64 GetEnumValue(std::string_view input, JenHash hash,
1✔
209
                           const ReflectedEnum **rEnumFallback = nullptr) {
210
  const ReflectedEnum *rEnum = rEnumFallback && *rEnumFallback
211
                                   ? *rEnumFallback
18✔
212
                                   : ReflectedEnum::Registry().at(hash);
213

214
  if (rEnumFallback) {
18✔
215
    *rEnumFallback = rEnum;
216
  }
19✔
217

218
  auto namesEnd = rEnum->names + rEnum->numMembers;
19✔
219
  auto foundItem =
220
      std::find_if(rEnum->names, namesEnd, [input](std::string_view item) {
221
        return !item.compare(input);
19✔
222
      });
223

224
  if (namesEnd == foundItem) {
225
    throw std::range_error("[Reflector] Enum value not found: " +
226
                           static_cast<std::string>(input));
227
  }
228

229
  return rEnum->values[std::distance(rEnum->names, foundItem)];
230
}
231

232
static Reflector::ErrorType SetEnum(std::string_view input, char *objAddr,
233
                                    JenHash hash, uint16 size) {
234
  input = es::SkipEndWhitespace(input);
235

236
  if (input.empty()) {
237
    printerror("[Reflector] Empty input for enum " << hash.raw());
238
    return Reflector::ErrorType::EmptyInput;
239
  }
240

241
  uint64 eValue = 0;
242

243
  try {
244
    eValue = GetEnumValue(input, hash);
245
  } catch (const std::out_of_range &) {
246
    printerror("[Reflector] Unregistered enum hash: "
247
               << hash.raw() << " for value: " << input);
248
    return Reflector::ErrorType::InvalidDestination;
249
  } catch (const std::range_error &e) {
250
    printerror(e.what());
251
    return Reflector::ErrorType::InvalidFormat;
252
  }
253

×
254
  memcpy(objAddr, &eValue, size);
×
255

256
  return Reflector::ErrorType::None;
×
257
}
258

259
static Reflector::ErrorType FlagFromEnum(std::string_view input, JenHash hash,
260
                                         uint64 &fallbackValue,
19✔
261
                                         const ReflectedEnum *&fallback) {
262
  input = es::TrimWhitespace(input);
6✔
263

264
  if (input.empty()) {
265
    printerror("[Reflector] Empty input for enum flag " << hash.raw());
266
    return Reflector::ErrorType::EmptyInput;
267
  }
268

19✔
269
  uint64 cValue = 0;
2✔
270

271
  try {
272
    cValue = GetEnumValue(input, hash, &fallback);
1✔
273
  } catch (const std::out_of_range &) {
1✔
274
    printerror("[Reflector] Unregistered enum hash: "
275
               << hash.raw() << " for value: " << input);
276
    return Reflector::ErrorType::InvalidDestination;
18✔
277
  } catch (const std::range_error &e) {
278
    if (input != "NULL") {
279
      printerror(e.what());
18✔
280
      return Reflector::ErrorType::InvalidFormat;
281
    }
23✔
282
    return Reflector::ErrorType::None;
283
  }
23✔
284

285
  fallbackValue |= 1ULL << cValue;
286

23✔
287
  return Reflector::ErrorType::None;
288
}
289

290
static Reflector::ErrorType SetEnumFlags(std::string_view input, char *objAddr,
291
                                         JenHash hash, uint16 size) {
292
  auto lastIterator = input.data();
293
  auto inputEnd = input.data() + input.size();
294
  Reflector::ErrorType errType = Reflector::ErrorType::None;
295
  uint64 eValue = 0;
296
  const ReflectedEnum *rEnumFallback = nullptr;
297

298
  for (auto &c : input) {
299
    if (c == '|') {
300
      auto subErrType = FlagFromEnum({lastIterator, size_t(&c - lastIterator)},
301
                                     hash, eValue, rEnumFallback);
302
      if (subErrType == Reflector::ErrorType::InvalidDestination) {
303
        return subErrType;
304
      } else if (subErrType != Reflector::ErrorType::None) {
305
        errType = subErrType;
306
      }
307

308
      lastIterator = &c + 1;
309
    }
310
  }
311

312
  if (lastIterator < inputEnd) {
313
    auto subErrType =
314
        FlagFromEnum({lastIterator, size_t(inputEnd - lastIterator)}, hash,
315
                     eValue, rEnumFallback);
316
    if (subErrType == Reflector::ErrorType::InvalidDestination) {
317
      return subErrType;
318
    } else if (subErrType != Reflector::ErrorType::None) {
×
319
      errType = subErrType;
×
320
    }
321
  }
×
322

323
  memcpy(objAddr, &eValue, size);
324

325
  return errType;
23✔
326
}
327

6✔
328
static Reflector::ErrorType SetReflectedArray(char startBrace, char endBrace,
329
                                              char *objAddr,
330
                                              std::string_view value,
331
                                              ReflType reflValue) {
332
  const size_t arrBegin = value.find(startBrace);
333

23✔
334
  if (arrBegin == value.npos) {
2✔
335
    printerror("[Reflector] Expected " << startBrace << " not found.");
336
    return Reflector::ErrorType::InvalidFormat;
337
  }
1✔
338

1✔
339
  const size_t arrEnd = value.find_last_of(endBrace);
340

341
  if (arrEnd == value.npos) {
22✔
342
    printerror("[Reflector] Expected " << endBrace << " not found.");
343
    return Reflector::ErrorType::InvalidFormat;
344
  } else if (arrEnd < arrBegin) {
22✔
345
    printerror("[Reflector] " << endBrace << " was found before " << startBrace
346
                              << '.');
23✔
347
    return Reflector::ErrorType::InvalidFormat;
348
  }
23✔
349

350
  value = {value.data() + arrBegin + 1, arrEnd - arrBegin - 1};
351

23✔
352
  if (value.empty()) {
353
    printerror("[Reflector] Empty array input.");
354
    return Reflector::ErrorType::EmptyInput;
355
  }
356

357
  size_t curElement = 0;
358
  auto curIter = value.begin();
359
  bool localScope = false;
360
  const auto &arr = reflValue.asArray;
361

362
  for (auto it = value.begin(); it != value.end(); it++) {
363
    const bool isEnding = std::next(it) == value.end();
364

365
    if ((*it == ']' || *it == '"' || *it == ')' || *it == '}') && localScope) {
366
      localScope = false;
367
    }
368

369
    if (localScope || *it == '[' || *it == '"' || *it == '(' || *it == '{') {
370
      localScope = true;
371
      continue;
372
    }
373

374
    if (*it == ',' || isEnding) {
375
      std::string_view cValue(
376
          &*curIter, std::distance(curIter, (isEnding ? value.end() : it)));
377
      cValue = es::SkipStartWhitespace(cValue);
378

379
      if (cValue.empty() && curElement < arr.numItems) {
380
        printerror("[Reflector] Array expected " << arr.numItems << " but got "
381
                                                 << curElement << '.');
382
        return Reflector::ErrorType::ShortInput;
383
      }
×
384

×
385
      if (!cValue.empty() && curElement >= arr.numItems) {
386
        printerror("[Reflector] Too many array elements, " << arr.numItems
×
387
                                                           << " expected.");
388
        return Reflector::ErrorType::OutOfRange;
389
      }
390

23✔
391
      SetReflectedMember(arr, cValue, objAddr + (arr.stride * curElement));
392
      curIter = it + 1;
6✔
393
      curElement++;
394
    }
395
  }
396

397
  return Reflector::ErrorType::None;
398
}
23✔
399

2✔
400
static Reflector::ErrorType
401
SetReflectedMember(ReflType reflValue, std::string_view value, char *objAddr) {
402
  Reflector::ErrorType errType = Reflector::ErrorType::None;
1✔
403
  char startBrace = 0;
1✔
404
  char endBrace = 0;
405
  value = es::SkipStartWhitespace(value);
406

22✔
407
  switch (reflValue.type) {
408
  case REFType::Array:
409
    startBrace = '{';
22✔
410
    endBrace = '}';
411
    break;
14✔
412
  case REFType::Vector:
413
    startBrace = '[';
14✔
414
    endBrace = ']';
415
    break;
416
  case REFType::ArrayClass:
14✔
417
    startBrace = '(';
418
    endBrace = ')';
419
  default:
420
    break;
421
  }
422

423
  switch (reflValue.type) {
424
  case REFType::Bool:
425
    return SetBoolean(std::string(value), *reinterpret_cast<bool *>(objAddr));
3✔
426
  case REFType::Integer: {
×
427
    switch (reflValue.size) {
428
    case 1:
3✔
429
      return SetNumber(value, *objAddr);
430
    case 2:
431
      return SetNumber(value, *reinterpret_cast<short *>(objAddr));
432
    case 4:
433
      return SetNumber(value, *reinterpret_cast<int *>(objAddr));
6✔
434
    case 8:
435
      return SetNumber(value, *reinterpret_cast<int64 *>(objAddr));
436
    default:
3✔
437
      return Reflector::ErrorType::InvalidDestination;
3✔
438
    }
439
  }
440
  case REFType::UnsignedInteger: {
11✔
441
    switch (reflValue.size) {
442
    case 1:
443
      return SetNumber(value, *reinterpret_cast<unsigned char *>(objAddr));
444
    case 2:
445
      return SetNumber(value, *reinterpret_cast<unsigned short *>(objAddr));
446
    case 4:
447
      return SetNumber(value, *reinterpret_cast<unsigned int *>(objAddr));
448
    case 8:
449
      return SetNumber(value, *reinterpret_cast<uint64 *>(objAddr));
450
    default:
451
      return Reflector::ErrorType::InvalidDestination;
452
    }
453
  }
454
  case REFType::FloatingPoint: {
455
    if (reflValue.asFloat.customFormat) {
456
      const auto &flt = reflValue.asFloat;
457
      double outValue;
458
      auto err = SetNumber(value, outValue);
459
      if (!flt.sign && outValue < 0) {
460
        printwarning("[Reflector] Applying " << outValue
461
                                             << " to an unsigned float");
462
        err = Reflector::ErrorType::SignMismatch;
463
      }
464
      size_t convertedValue = esFloatDetail::FromFloat(outValue, flt.mantissa,
465
                                                       flt.exponent, flt.sign);
466
      memcpy(objAddr, &convertedValue, reflValue.size);
467
      return err;
468
    } else {
469
      switch (reflValue.size) {
470
      case 4:
471
        return SetNumber(value, *reinterpret_cast<float *>(objAddr));
472
      case 8:
473
        return SetNumber(value, *reinterpret_cast<double *>(objAddr));
474
      default:
11✔
475
        return Reflector::ErrorType::InvalidDestination;
476
      }
25✔
477
    }
478
  }
25✔
479
  case REFType::BitFieldMember: {
480
    uint64 &output = *reinterpret_cast<uint64 *>(objAddr);
481
    auto doStuff = [&](auto &&insertVal) {
25✔
482
      LimitProxy<std::decay_t<decltype(insertVal)>> proxy{reflValue.bit.size};
483
      auto err = SetNumber(value, insertVal, proxy);
484
      BitMember bfMember;
485
      bfMember.size = reflValue.bit.size;
486
      bfMember.position = reflValue.bit.position;
487
      auto mask = bfMember.GetMask<uint64>();
488
      output &= ~mask;
489
      output |= insertVal.value << reflValue.bit.position;
490
      return err;
×
491
    };
×
492

493
    switch (reflValue.asBitfield.type) {
×
494
    case REFType::UnsignedInteger:
495
      return doStuff(BFTag<uint64>{0});
496
      break;
497
    case REFType::Integer:
25✔
498
      return doStuff(BFTag<int64>{0});
6✔
499
      break;
500
    case REFType::FloatingPoint: {
501
      const auto &flt = reflValue.asBitfield.asFloat;
3✔
502

3✔
503
      if (flt.customFormat) {
504
        double outValue;
505
        auto err = SetNumber(value, outValue);
22✔
506
        if (!flt.sign && outValue < 0) {
507
          printwarning("[Reflector] Applying " << outValue
508
                                               << " to an unsigned float");
509
          err = Reflector::ErrorType::SignMismatch;
510
        }
511
        size_t convertedValue = esFloatDetail::FromFloat(
512
            outValue, flt.mantissa, flt.exponent, flt.sign);
513
        BitMember bfMember;
514
        bfMember.size = reflValue.bit.size;
515
        bfMember.position = reflValue.bit.position;
516
        auto mask = bfMember.GetMask<uint64>();
517
        output &= ~mask;
518
        output |= convertedValue << reflValue.bit.position;
519
        return err;
520
      }
521

522
      return Reflector::ErrorType::InvalidDestination;
523
    }
524
    case REFType::Bool: {
525
      bool result;
526
      auto err = SetBoolean(std::string(value), result);
527
      auto mask = (1ULL << reflValue.bit.position);
528

529
      if (result) {
530
        output |= mask;
531
      } else {
532
        output &= ~mask;
533
      }
534
      return err;
535
    }
536
    case REFType::Enum: {
537
      uint64 bValue;
538
      auto err =
539
          SetEnum(value, reinterpret_cast<char *>(&bValue),
22✔
540
                  JenHash(reflValue.asBitfield.typeHash), sizeof(bValue));
541
      BitMember bfMember;
16✔
542
      bfMember.size = reflValue.bit.size;
543
      bfMember.position = reflValue.bit.position;
16✔
544
      auto mask = bfMember.GetMask<uint64>();
545
      output &= ~mask;
546
      output |= bValue << reflValue.bit.position;
16✔
547
      return err;
548
    }
549

550
    default:
551
      return Reflector::ErrorType::InvalidDestination;
552
    }
553
  }
554
  case REFType::Enum:
555
    return SetEnum(value, objAddr, JenHash(reflValue.asClass.typeHash),
×
556
                   reflValue.size);
×
557
  case REFType::EnumFlags:
558
    return SetEnumFlags(value, objAddr, JenHash(reflValue.asClass.typeHash),
×
559
                        reflValue.size);
560
  case REFType::String:
561
    *reinterpret_cast<std::string *>(objAddr) = value;
562
    break;
16✔
563
  case REFType::Array:
6✔
564
  case REFType::Vector:
565
  case REFType::ArrayClass:
566
    return SetReflectedArray(startBrace, endBrace, objAddr, value, reflValue);
3✔
567
  default:
3✔
568
    break;
569
  }
570

13✔
571
  return errType;
572
}
573

574
Reflector::ErrorType Reflector::SetReflectedValue(ReflType type,
575
                                                  std::string_view value) {
576
  auto inst = GetReflectedInstance();
577
  char *thisAddr = static_cast<char *>(inst.instance);
578
  thisAddr =
579
      thisAddr + (type.type == REFType::BitFieldMember ? 0 : type.offset);
580

581
  return SetReflectedMember(type, value, thisAddr);
582
}
583

584
Reflector::ErrorType Reflector::SetReflectedValue(ReflType type,
585
                                                  std::string_view value,
586
                                                  size_t subID) {
587
  auto inst = GetReflectedInstance();
588
  char *thisAddr = static_cast<char *>(inst.instance);
589
  thisAddr += type.offset;
590

591
  if (IsArrayVec(type.type)) {
592
    thisAddr += type.asArray.stride * subID;
593
  }
594

595
  if (type.type == REFType::Vector) {
596
    return SetReflectedMember(type.asVector, value, thisAddr);
597
  }
598

599
  return SetReflectedMember(type.asArray, value, thisAddr);
600
}
601

602
Reflector::ErrorType Reflector::SetReflectedValue(ReflType type,
603
                                                  std::string_view value,
604
                                                  size_t subID,
13✔
605
                                                  size_t element) {
606
  if (!::IsArray(type.type)) {
19✔
607
    return ErrorType::InvalidDestination;
608
  }
19✔
609
  bool enumFlags = false;
610
  const auto &arr = type.asArray;
611

19✔
612
  switch (arr.type) {
613
  /*case REFType::EnumFlags:
614
    enumFlags = true;*/
615
  case REFType::Vector:
616
    break;
617
  default:
618
    return ErrorType::InvalidDestination;
619
  }
620

2✔
621
  auto inst = GetReflectedInstance();
2✔
622
  char *thisAddr = static_cast<char *>(inst.instance);
623
  thisAddr += type.offset + arr.stride * subID;
×
624

625
  if (!enumFlags) {
626
    const auto &vec = arr.asVector;
627

18✔
628
    if (element >= vec.numItems) {
6✔
629
      printerror("[Reflector] Too many vector elements, " << (int)vec.numItems
630
                                                          << " expected.");
631
      return ErrorType::OutOfRange;
3✔
632
    }
3✔
633

634
    thisAddr += vec.stride * element;
635
    return SetReflectedMember(arr.asVector, value, thisAddr);
15✔
636
  }
637

638
  return ErrorType::InvalidDestination;
639
}
640

641
Reflector::ErrorType
642
Reflector::SetReflectedValueInt(ReflType reflValue, int64 value, size_t subID) {
643
  auto inst = GetReflectedInstance();
644
  char *thisAddr = static_cast<char *>(inst.instance);
645
  thisAddr = thisAddr + reflValue.offset;
646
  bool isArrVec = IsArrayVec(reflValue.type);
647
  REFType cType = reflValue.type;
648
  size_t typeSize = reflValue.size;
649

650
  if (isArrVec) {
651
    const auto &arr = reflValue.asArray;
652
    if (subID >= arr.numItems) {
653
      return Reflector::ErrorType::OutOfRange;
654
    }
655

656
    thisAddr += subID * arr.stride;
657
    cType = arr.type;
658
    typeSize = arr.stride;
659
  }
660

661
  if (cType != REFType::Integer) {
662
    return Reflector::ErrorType::InvalidDestination;
663
  }
664

665
  memcpy(thisAddr, &value, typeSize);
666

667
  return Reflector::ErrorType::None;
668
}
669

15✔
670
Reflector::ErrorType Reflector::SetReflectedValueUInt(ReflType reflValue,
671
                                                      uint64 value,
672
                                                      size_t subID) {
673
  auto inst = GetReflectedInstance();
×
674
  char *thisAddr = static_cast<char *>(inst.instance);
675
  thisAddr = thisAddr + reflValue.offset;
676
  bool isArrVec = IsArrayVec(reflValue.type);
×
677
  REFType cType = reflValue.type;
678
  size_t typeSize = reflValue.size;
679

680
  if (isArrVec) {
681
    const auto &arr = reflValue.asArray;
682
    if (subID >= arr.numItems) {
683
      return Reflector::ErrorType::OutOfRange;
684
    }
685

686
    thisAddr += subID * arr.stride;
687
    cType = arr.type;
688
    typeSize = arr.stride;
689
  }
690

691
  if (cType != REFType::UnsignedInteger) {
692
    return Reflector::ErrorType::InvalidDestination;
693
  }
694

695
  memcpy(thisAddr, &value, typeSize);
696

697
  return Reflector::ErrorType::None;
698
}
699

700
Reflector::ErrorType Reflector::SetReflectedValueFloat(ReflType reflValue,
701
                                                       double value,
702
                                                       size_t subID) {
703
  auto inst = GetReflectedInstance();
×
704
  char *thisAddr = static_cast<char *>(inst.instance);
705
  thisAddr = thisAddr + reflValue.offset;
706
  bool isArrVec = IsArrayVec(reflValue.type);
707
  REFType cType = reflValue.type;
708
  size_t typeSize = reflValue.size;
×
709

×
710
  if (isArrVec) {
711
    const auto &arr = reflValue.asArray;
×
712
    if (subID >= arr.numItems) {
713
      return Reflector::ErrorType::OutOfRange;
714
    }
715

×
716
    thisAddr += subID * arr.stride;
717
    cType = arr.type;
×
718
    typeSize = arr.stride;
719
  }
720

721
  if (cType != REFType::FloatingPoint) {
722
    return Reflector::ErrorType::InvalidDestination;
723
  }
×
724
  // todo esfloat
×
725
  switch (typeSize) {
726
  case 4:
727
    reinterpret_cast<float &>(*thisAddr) = static_cast<float>(value);
×
728
    return Reflector::ErrorType::None;
×
729
  case 8:
730
    reinterpret_cast<double &>(*thisAddr) = value;
731
    return Reflector::ErrorType::None;
×
732
  default:
733
    return Reflector::ErrorType::InvalidDestination;
734
  }
×
735
}
736

28✔
737
static std::string_view
738
PrintEnumValue(JenHash hash, uint64 value,
28✔
739
               const ReflectedEnum **rEnumFallback = nullptr) {
740
  const ReflectedEnum *rEnum = rEnumFallback && *rEnumFallback
741
                                   ? *rEnumFallback
28✔
742
                                   : ReflectedEnum::Registry().at(hash);
743

744
  if (rEnumFallback)
745
    *rEnumFallback = rEnum;
746

747
  const uint64 *valuesEnd = rEnum->values + rEnum->numMembers;
748
  const uint64 *foundItem = std::find_if(
749
      rEnum->values, valuesEnd, [value](uint64 item) { return item == value; });
750

751
  if (foundItem == valuesEnd) {
752
    throw std::range_error("[Reflector] Enum value not found: " +
753
                           std::to_string(value));
754
  }
755

756
  return rEnum->names[std::distance(rEnum->values, foundItem)];
757
}
758

759
static std::string PrintEnum(const char *objAddr, JenHash hash, uint16 elSize) {
760
  uint64 eValue = 0;
761

762
  memcpy(reinterpret_cast<char *>(&eValue), objAddr, elSize);
763

764
  return std::string{PrintEnumValue(hash, eValue)};
765
}
766

767
static std::string PrintEnumFlags(const char *objAddr, JenHash hash,
768
                                  uint16 elSize) {
28✔
769
  uint64 eValue;
770
  const ReflectedEnum *rEnumFallback = nullptr;
771
  std::string result;
772
  const size_t numBits = elSize * 8;
773

×
774
  memcpy(reinterpret_cast<char *>(&eValue), objAddr, elSize);
×
775

776
  for (size_t t = 0; t < numBits; t++) {
×
777
    if (eValue & (1ULL << t)) {
778
      if (result.size())
779
        result.append(" | ");
780

28✔
781
      try {
782
        result.append(PrintEnumValue(hash, t, &rEnumFallback));
×
783
      } catch (const std::out_of_range &) {
784
        printerror("[Reflector] Unregistered enum hash: " << hash.raw());
785
        break;
786
      } catch (const std::range_error &e) {
787
        printerror(e.what());
788
      } catch (...) {
28✔
789
        printerror("[Reflector] Unhandled exception: PrintEnumValue");
3✔
790
        break;
791
      }
792
    }
1✔
793
  }
1✔
794

795
  if (result.empty())
796
    return "NULL";
27✔
797

798
  return result;
799
}
27✔
800

801
static std::string GetReflectedPrimitive(const char *objAddr, ReflType type) {
802
  char startBrace = 0;
803
  char endBrace = 0;
297✔
804

805
  switch (type.type) {
297✔
806
  case REFType::Array:
807
    startBrace = '{';
808
    endBrace = '}';
809
    break;
810
  case REFType::Vector:
287✔
811
    startBrace = '[';
812
    endBrace = ']';
813
    break;
814
  case REFType::ArrayClass:
815
    startBrace = '(';
816
    endBrace = ')';
817
  default:
818
    break;
819
  }
820

×
821
  switch (type.type) {
822
  case REFType::Bool:
12✔
823
    return *reinterpret_cast<const bool *>(objAddr) ? "true" : "false";
4✔
824

825
  case REFType::Integer: {
16✔
826
    switch (type.size) {
16✔
827
    case 1:
828
      return std::to_string(
829
          static_cast<int32>(*reinterpret_cast<const int8 *>(objAddr)));
830
    case 2:
8✔
831
      return std::to_string(*reinterpret_cast<const int16 *>(objAddr));
6✔
832
    case 4:
833
      return std::to_string(*reinterpret_cast<const int32 *>(objAddr));
6✔
834
    case 8:
835
      return std::to_string(*reinterpret_cast<const int64 *>(objAddr));
836

837
    default:
838
      return "";
839
    }
840
  }
158✔
841
  case REFType::UnsignedInteger: {
842
    switch (type.size) {
843
    case 1:
265✔
844
      return std::to_string(
845
          static_cast<int32>(*reinterpret_cast<const uint8 *>(objAddr)));
265✔
846
    case 2:
847
      return std::to_string(*reinterpret_cast<const uint16 *>(objAddr));
848
    case 4:
849
      return std::to_string(*reinterpret_cast<const uint32 *>(objAddr));
850
    case 8:
259✔
851
      return std::to_string(*reinterpret_cast<const uint64 *>(objAddr));
852

853
    default:
854
      return "";
855
    }
856
  }
857
  case REFType::FloatingPoint: {
858
    char _tmpBuffer[0x20]{};
859
    if (type.asFloat.customFormat) {
860
      size_t encValue = 0;
×
861
      const auto &flt = type.asFloat;
862
      memcpy(&encValue, objAddr, type.size);
8✔
863

4✔
864
      auto retVal = esFloatDetail::ToFloat(encValue, flt.mantissa, flt.exponent,
865
                                           flt.sign);
8✔
866
      snprintf(_tmpBuffer, sizeof(_tmpBuffer), "%.6g", retVal);
8✔
867
    } else {
868

869
      switch (type.size) {
870
      case 4:
4✔
871
        snprintf(_tmpBuffer, sizeof(_tmpBuffer), "%.6g",
3✔
872
                 *reinterpret_cast<const float *>(objAddr));
873
        break;
3✔
874
      case 8:
875
        snprintf(_tmpBuffer, sizeof(_tmpBuffer), "%.13g",
876
                 *reinterpret_cast<const double *>(objAddr));
877
        break;
878

879
      default:
880
        break;
881
      }
882
    }
883
    return _tmpBuffer;
32✔
884
  }
885
  case REFType::BitFieldMember: {
32✔
886
    uint64 output = *reinterpret_cast<const uint64 *>(objAddr);
887
    BitMember bfMember;
888
    bfMember.size = type.bit.size;
889
    bfMember.position = type.bit.position;
890
    auto mask = bfMember.GetMask<uint64>();
28✔
891
    output = (output & mask) >> bfMember.position;
892

893
    switch (type.asBitfield.type) {
894
    case REFType::UnsignedInteger:
895
      return std::to_string(output);
896
    case REFType::Bool:
897
      return output ? "true" : "false";
898
    case REFType::Enum:
899
      return std::string(
900
          PrintEnumValue(JenHash(type.asBitfield.typeHash), output));
×
901
    case REFType::FloatingPoint: {
902
      const auto &flt = type.asBitfield.asFloat;
4✔
903

×
904
      if (flt.customFormat) {
905
        char _tmpBuffer[0x20]{};
8✔
906
        auto retVal = esFloatDetail::ToFloat(output, flt.mantissa, flt.exponent,
8✔
907
                                             flt.sign);
908
        snprintf(_tmpBuffer, sizeof(_tmpBuffer), "%.6g", retVal);
909
        return _tmpBuffer;
910
      }
4✔
911

3✔
912
      return "NaN";
913
    }
3✔
914
    default:
915
      break;
916
    }
917

918
    int64 signedOutput = output;
919
    LimitProxy<BFTag<int64>> limit{type.size};
920

921
    if (signedOutput & limit.iMin) {
922
      signedOutput |= ~limit.uMax;
923
    }
924

29✔
925
    return std::to_string(signedOutput);
926
  }
136✔
927

928
  case REFType::EnumFlags:
29✔
929
    return PrintEnumFlags(objAddr, JenHash(type.asClass.typeHash), type.size);
930

29✔
931
  case REFType::Enum: {
2✔
932
    try {
1✔
933
      return PrintEnum(objAddr, JenHash(type.asClass.typeHash), type.size);
934
    } catch (const std::out_of_range &) {
935
      printerror(
936
          "[Reflector] Unregistered enum hash: " << type.asClass.typeHash);
937
    } catch (const std::range_error &e) {
938
      printerror(e.what());
142✔
939
    } catch (...) {
940
      printerror("[Reflector] Unhandled exception: PrintEnum");
79✔
941
    }
142✔
942

105✔
943
    break;
944
  }
105✔
945

79✔
946
  case REFType::CString:
947
    return *reinterpret_cast<const char *const *>(objAddr);
948

142✔
949
  case REFType::String:
950
    return *reinterpret_cast<const std::string *>(objAddr);
951

318✔
952
  case REFType::Class:
953
  case REFType::BitFieldClass:
954
    return "SUBCLASS_TYPE";
142✔
955
  default:
13✔
956
    break;
26✔
957
  }
958

959
  if (startBrace && endBrace) {
129✔
960
    const auto &arr = type.asArray;
961
    const auto numItems = arr.numItems;
962
    std::string outVal;
63✔
963
    outVal.push_back(startBrace);
964

965
    for (int i = 0; i < numItems; i++) {
966
      outVal += GetReflectedPrimitive(objAddr + (arr.stride * i), arr);
63✔
967
      outVal += ", ";
×
968
    }
×
969

970
    outVal.pop_back();
971
    outVal.pop_back();
63✔
972
    outVal.push_back(endBrace);
973

974
    return outVal;
63✔
975
  }
8✔
976

×
977
  return "";
978
}
979

8✔
980
std::string Reflector::GetReflectedValue(size_t id) const {
16✔
981
  if (id >= GetNumReflectedValues())
982
    return "";
8✔
983

984
  auto inst = GetReflectedInstance();
55✔
985
  const char *thisAddr = static_cast<const char *>(inst.constInstance);
986
  const ReflType &reflValue = inst.rfStatic->types[id];
55✔
987
  const int valueOffset =
988
      reflValue.type == REFType::BitFieldMember ? 0 : reflValue.offset;
989

88✔
990
  return GetReflectedPrimitive(thisAddr + valueOffset, reflValue);
991
}
992

88✔
993
std::string Reflector::GetReflectedValue(size_t id, size_t subID) const {
994
  if (id >= GetNumReflectedValues())
88✔
995
    return "";
18✔
996

9✔
997
  auto inst = GetReflectedInstance();
998
  const char *thisAddr = static_cast<const char *>(inst.constInstance);
999
  const ReflType &reflValue = inst.rfStatic->types[id];
1000
  const char *objAddr = thisAddr + reflValue.offset;
1001

1002
  switch (reflValue.type) {
79✔
1003
  case REFType::Array:
5✔
1004
  case REFType::Vector:
×
1005
  case REFType::ArrayClass: {
1006
    const auto &arr = reflValue.asArray;
1007
    if (arr.numItems <= subID) {
5✔
1008
      return "";
3✔
1009
    }
4✔
1010

1011
    return GetReflectedPrimitive(objAddr + arr.stride * subID, arr);
1012
  }
1013
  case REFType::EnumFlags: {
5✔
1014
    if (reflValue.size * 8 <= subID) {
1015
      return "";
74✔
1016
    }
1017

74✔
1018
    uint64 eValue;
1019

1020
    memcpy(reinterpret_cast<char *>(&eValue), objAddr, reflValue.size);
42✔
1021

1022
    return (eValue & (1ULL << subID)) ? "true" : "false";
1023
  }
42✔
1024

1025
  default:
42✔
1026
    return "";
42✔
1027
  }
1028
}
817✔
1029

775✔
1030
std::string Reflector::GetReflectedValue(size_t id, size_t subID,
46✔
1031
                                         size_t element) const {
1032
  if (id >= GetNumReflectedValues() || !IsArray(id))
46✔
1033
    return "";
1034

46✔
1035
  auto inst = GetReflectedInstance();
1036
  const char *thisAddr = static_cast<const char *>(inst.constInstance);
1037
  const ReflType &reflValue = inst.rfStatic->types[id];
1038
  const char *objAddr = thisAddr + reflValue.offset;
46✔
1039
  const auto &arr = reflValue.asArray;
1040

1041
  switch (arr.type) {
1042
  case REFType::Vector: {
42✔
1043
    if (arr.numItems <= subID || arr.asVector.numItems <= element) {
1044
      return "";
42✔
1045
    }
1046

42✔
1047
    ReflType subType = arr.asVector;
1048

42✔
1049
    return GetReflectedPrimitive(
1050
        objAddr + arr.stride * subID + subType.size * element, subType);
1051
  }
1052
  case REFType::EnumFlags: {
1053
    if (arr.stride * 8 <= element || arr.numItems <= subID) {
42✔
1054
      return "";
1055
    }
42✔
1056

1057
    uint64 eValue;
1058

117✔
1059
    memcpy(reinterpret_cast<char *>(&eValue), objAddr + arr.stride * subID,
1060
           arr.stride);
1061

1062
    return (eValue & (1ULL << element)) ? "true" : "false";
117✔
1063
  }
1064

117✔
1065
  default:
24✔
1066
    return "";
8✔
1067
  }
1068
}
1069

109✔
1070
ReflectedInstance Reflector::GetReflectedSubClass(size_t id,
1071
                                                  size_t subID) const {
109✔
1072
  if (id >= GetNumReflectedValues())
12✔
1073
    return {};
4✔
1074

105✔
1075
  auto inst = GetReflectedInstance();
×
1076
  const ReflType &reflValue = inst.rfStatic->types[id];
1077
  const char *thisAddr =
×
1078
      static_cast<const char *>(inst.constInstance) + reflValue.offset;
1079
  REFType cType = reflValue.type;
1080
  const bool isArray = IsArray(id);
105✔
1081
  ReflTypeClass classType = reflValue.asClass;
1082

105✔
1083
  if (isArray) {
×
1084
    const auto &arr = reflValue.asArray;
×
1085
    if (subID >= reflValue.asArray.numItems) {
1086
      return {};
1087
    }
1088

1089
    thisAddr += subID * arr.stride;
1090
    cType = arr.type;
1091
    classType = arr.asClass;
1092
  }
2,352✔
1093

1094
  if ((cType != REFType::Class && cType != REFType::BitFieldClass) ||
1095
      !reflectorStatic::Registry().count(JenHash(classType.typeHash)))
2,256✔
1096
    return {};
1097

1098
  return {reflectorStatic::Registry().at(JenHash(classType.typeHash)),
1099
          thisAddr};
2,256✔
1100
}
1101

402✔
1102
ReflectedInstance Reflector::GetReflectedSubClass(size_t id, size_t subID) {
1103
  return const_cast<const Reflector *>(this)->GetReflectedSubClass(id, subID);
1104
}
1,854✔
1105

1106
reflectorStatic::RegistryType &reflectorStatic::Registry() {
414✔
1107
  static RegistryType registry;
1108
  return registry;
1109
}
314✔
1110

15✔
1111
ReflectedEnum::RegistryType &ReflectedEnum::Registry() {
1112
  static RegistryType registry;
5✔
1113
  return registry;
1114
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc