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

PredatorCZ / PreCore / 461

pending completion
461

push

github-actions-ci

PredatorCZ
update readme

3204 of 6096 relevant lines covered (52.56%)

354.05 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

3
    Copyright 2018-2023 Lukas Cone
4

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

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

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

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

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

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

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

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

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

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

57
  return nullptr;
58
}
59

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

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

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

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

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

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

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

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

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

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

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

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

148
  return errType;
168✔
149
}
150

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

240
  uint64 eValue = 0;
241

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

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

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

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

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

19✔
268
  uint64 cValue = 0;
2✔
269

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

284
  fallbackValue |= 1ULL << cValue;
285

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

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

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

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

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

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

324
  return errType;
23✔
325
}
326

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

13✔
570
  return errType;
571
}
572

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

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

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

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

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

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

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

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

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

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

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

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

637
  return ErrorType::InvalidDestination;
638
}
639

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

797
  return result;
798
}
27✔
799

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

105✔
942
    break;
943
  }
105✔
944

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

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

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

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

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

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

973
    return outVal;
63✔
974
  }
8✔
975

×
976
  return "";
977
}
978

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

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

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

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

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

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

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

74✔
1017
    uint64 eValue;
1018

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

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

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

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

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

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

42✔
1046
    ReflType subType = arr.asVector;
1047

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

1056
    uint64 eValue;
1057

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

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

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

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

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

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

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

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

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

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

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

15✔
1110
ReflectedEnum::RegistryType &ReflectedEnum::Registry() {
1111
  static RegistryType registry;
5✔
1112
  return registry;
1113
}
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