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

PredatorCZ / PreCore / 575

18 Nov 2025 09:45PM UTC coverage: 51.773% (+0.006%) from 51.767%
575

push

github

PredatorCZ
move from logic errors

0 of 5 new or added lines in 3 files covered. (0.0%)

1 existing line in 1 file now uncovered.

4131 of 7979 relevant lines covered (51.77%)

11430.45 hits per line

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

82.15
/src/reflector.cpp
1
/*  A source for Reflector class
2

3
    Copyright 2018-2024 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/except.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 <memory>
27
#include <ostream>
28
#include <string_view>
29

30
static const char *TYPE_NAMES[]{"x", "y", "z", "w"};
31

32
ReflType Make(REFType type, int index, int size) {
280✔
33
  ReflType retVal;
34
  retVal.type = type;
280✔
35
  retVal.index = index;
280✔
36
  retVal.offset = size * index;
280✔
37
  retVal.valueNameHash = JenHash(TYPE_NAMES[index]);
280✔
38
  retVal.size = size;
280✔
39

40
  return retVal;
280✔
41
};
42

43
union VectorKey {
44
  uint32 raw = 0;
45
  struct {
46
    REFType type;
47
    uint8 numElements;
48
    uint8 size;
49
  };
50

51
  bool operator<(VectorKey o) const { return raw < o.raw; }
1,470✔
52
};
53

54
template <REFType type, int size>
55
static const ReflType VECTOR_TYPES[4]{
56
    Make(type, 0, size),
57
    Make(type, 1, size),
58
    Make(type, 2, size),
59
    Make(type, 3, size),
60
};
61

62
template <REFType type, int numElements, int size>
63
consteval std::pair<VectorKey, reflectorStatic> MakeVectorRefl() {
64
  VectorKey key {
65
    .type = type,
66
    .numElements = numElements,
67
    .size = size,
68
  };
69

70
  return {key, reflectorStatic(numElements, VECTOR_TYPES<type, size>,
71
                               TYPE_NAMES, numElements * size)};
72
}
73

74
static const std::map<VectorKey, reflectorStatic> VECTORS{
75
    MakeVectorRefl<REFType::FloatingPoint, 2, 4>(),
76
    MakeVectorRefl<REFType::FloatingPoint, 3, 4>(),
77
    MakeVectorRefl<REFType::FloatingPoint, 4, 4>(),
78
    MakeVectorRefl<REFType::Integer, 2, 1>(),
79
    MakeVectorRefl<REFType::Integer, 3, 1>(),
80
    MakeVectorRefl<REFType::Integer, 4, 1>(),
81
    MakeVectorRefl<REFType::Integer, 2, 2>(),
82
    MakeVectorRefl<REFType::Integer, 3, 2>(),
83
    MakeVectorRefl<REFType::Integer, 4, 2>(),
84
    MakeVectorRefl<REFType::Integer, 2, 4>(),
85
    MakeVectorRefl<REFType::Integer, 3, 4>(),
86
    MakeVectorRefl<REFType::Integer, 4, 4>(),
87
    MakeVectorRefl<REFType::UnsignedInteger, 2, 1>(),
88
    MakeVectorRefl<REFType::UnsignedInteger, 3, 1>(),
89
    MakeVectorRefl<REFType::UnsignedInteger, 4, 1>(),
90
    MakeVectorRefl<REFType::UnsignedInteger, 2, 2>(),
91
    MakeVectorRefl<REFType::UnsignedInteger, 3, 2>(),
92
    MakeVectorRefl<REFType::UnsignedInteger, 4, 2>(),
93
    MakeVectorRefl<REFType::UnsignedInteger, 2, 4>(),
94
    MakeVectorRefl<REFType::UnsignedInteger, 3, 4>(),
95
    MakeVectorRefl<REFType::UnsignedInteger, 4, 4>(),
96
};
97

98
static ReflectorMember::ErrorType
99
SetReflectedMember(ReflType reflValue, std::string_view value, char *objAddr,
100
                   const reflectorStatic *refl);
101

102
static const ReflType *GetReflectedType(const reflectorStatic *inst,
381✔
103
                                        const JenHash hash) {
104
  const size_t _ntypes = inst->nTypes;
381✔
105

106
  for (size_t t = 0; t < _ntypes; t++) {
6,995✔
107
    if (inst->types[t].valueNameHash == hash) {
6,991✔
108
      return inst->types + t;
377✔
109
    }
110
  }
111

112
  if (inst->typeAliasHashes) {
4✔
113
    for (size_t t = 0; t < _ntypes; t++) {
4✔
114
      if (inst->typeAliasHashes[t] == hash) {
4✔
115
        return inst->types + t;
2✔
116
      }
117
    }
118
  }
119

120
  return nullptr;
121
}
122

123
ReflectorMember Reflector::operator[](JenHash hash) const {
381✔
124
  ReflectedInstance inst = GetReflectedInstance();
381✔
125
  if (!inst) {
381✔
126
    return {{}, 0};
127
  }
128
  const ReflType *retVal = ::GetReflectedType(inst.rfStatic, hash);
381✔
129

130
  if (retVal) {
381✔
131
    return {inst, retVal->index};
379✔
132
  }
133

134
  while (inst.rfStatic->baseClass.raw()) {
2✔
135
    inst.rfStatic = reflectorStatic::Registry().at(inst.rfStatic->baseClass);
×
136
    retVal = ::GetReflectedType(inst.rfStatic, hash);
×
137
    if (retVal) {
×
138
      return {inst, retVal->index};
×
139
    }
140
  }
141

142
  return {{}, 0};
143
}
144

145
template <class T> struct LimitProxy {
146
  static const size_t numBits = sizeof(T) * 8;
147
  static const uint64 uMax = std::numeric_limits<T>::max();
148
  static const int64 iMin = std::numeric_limits<T>::min();
149
  static const int64 iMax = static_cast<int64>(uMax);
150
};
151

152
template <class type> struct BFTag {
153
  type value;
154
  BFTag(const type &value_) : value(value_) {}
16✔
155
  operator type() const { return value; }
156
};
157

158
template <class type> struct LimitProxy<BFTag<type>> {
159
  size_t numBits;
160
  const uint64 uMax;
161
  const int64 iMax;
162
  const int64 iMin;
163

164
  LimitProxy(size_t numBits_)
16✔
165
      : numBits(numBits_), uMax((1 << numBits) - 1), iMax(uMax >> 1),
16✔
166
        iMin(~iMax) {}
16✔
167
};
168

169
template <typename T, class ProxyType>
170
static ReflectorMember::ErrorType SetNumber(std::string_view input_, T &output,
139✔
171
                                            ProxyType proxy) {
172
  std::string input(input_);
139✔
173
  ReflectorMember::ErrorType errType = ReflectorMember::ErrorType::None;
174
  const int base =
175
      !input.compare(0, 2, "0x") || !input.compare(0, 3, "-0x") ? 16 : 10;
139✔
176
  if constexpr (std::is_signed_v<T>) {
177
    int64 value = 0;
178
    const int64 iMin = proxy.iMin;
179
    const int64 iMax = proxy.iMax;
180
    bool OOR = false;
181

182
    try {
183
      value = std::stoll(input, nullptr, base);
184
    } catch (const std::invalid_argument &) {
5✔
185
      printerror("[Reflector] Invalid value: " << input);
2✔
186
      return ReflectorMember::ErrorType::InvalidFormat;
187
    } catch (const std::out_of_range &) {
3✔
188
      OOR = true;
189
    }
190

191
    if (OOR || value > iMax || value < iMin) {
47✔
192
      printwarning("[Reflector] Integer out of range, got: "
24✔
193
                   << value << " for a signed " << proxy.numBits
194
                   << "bit number!");
195
      output = static_cast<T>(input[0] == '-' ? iMin : iMax);
12✔
196
      return ReflectorMember::ErrorType::OutOfRange;
12✔
197
    }
198

199
    output = static_cast<T>(value);
46✔
200
  } else {
201
    uint64 value = 0;
202
    const uint64 iMax = proxy.uMax;
16✔
203
    bool OOR = false;
204

205
    try {
206
      value = std::stoull(input, nullptr, base);
207
    } catch (const std::invalid_argument &) {
1✔
208
      printerror("[Reflector] Invalid value: " << input);
×
209
      return ReflectorMember::ErrorType::InvalidFormat;
210
    } catch (const std::out_of_range &) {
1✔
211
      OOR = true;
212
    }
213

214
    if (input[0] == '-') {
80✔
215
      value = static_cast<T>(value);
216
      printwarning("[Reflector] Applying "
24✔
217
                   << input
218
                   << " to an unsigned integer, casting to: " << value);
219
      errType = ReflectorMember::ErrorType::SignMismatch;
220
    }
221

222
    if (OOR || value > iMax) {
80✔
223
      printwarning("[Reflector] Integer out of range, got: "
11✔
224
                   << value << " for an unsigned " << proxy.numBits
225
                   << "bit number!");
226
      output = static_cast<T>(iMax);
5✔
227
      return ReflectorMember::ErrorType::OutOfRange;
5✔
228
    }
229

230
    output = static_cast<T>(value);
75✔
231
  }
232

233
  return errType;
121✔
234
}
235

14✔
236
template <typename T>
237
static ReflectorMember::ErrorType SetNumber(std::string_view input_,
14✔
238
                                            T &output) {
239
  if constexpr (std::is_floating_point_v<T>) {
240
    std::string input(input_);
14✔
241
    constexpr T fMax = std::numeric_limits<T>::max();
242
    constexpr T fMin = std::numeric_limits<T>::min();
243

244
    try {
245
      output = [&input] {
246
        if constexpr (std::is_same_v<T, float>) {
247
          return std::stof(input);
248
        } else {
249
          return std::stod(input);
250
        }
251
      }();
252

253
      // MSVC Underflow fix
254
      if (std::fpclassify(output) == FP_SUBNORMAL) {
255
        throw std::out_of_range("");
256
      }
257
    } catch (const std::invalid_argument &) {
258
      printerror("[Reflector] Invalid value: " << input);
259
      return ReflectorMember::ErrorType::InvalidFormat;
260
    } catch (const std::out_of_range &) {
261
      printwarning("[Reflector] Float out of range, got: " << input);
262

263
      double fVal = atof(input.c_str());
264

265
      if (fVal > 0)
266
        output = fVal > 1.0 ? fMax : fMin;
267
      else
268
        output = fVal < -1.0 ? -fMax : -fMin;
269

270
      return ReflectorMember::ErrorType::OutOfRange;
271
    }
272

1✔
273
    return ReflectorMember::ErrorType::None;
×
274
  } else {
275
    return SetNumber(input_, output, LimitProxy<T>{});
1✔
276
  }
277
}
278

279
static ReflectorMember::ErrorType SetBoolean(std::string input, bool &output) {
14✔
280
  std::for_each(input.begin(), input.end(),
281
                [](char &c) { c = static_cast<char>(std::tolower(c)); });
6✔
282

283
  output = !memcmp(input.c_str(), "true", 4);
284

285
  if (!output && memcmp(input.c_str(), "false", 5)) {
286
    printwarning("[Reflector] Expected true/false, got: " << input);
287
    return ReflectorMember::ErrorType::InvalidFormat;
14✔
288
  }
2✔
289

290
  return ReflectorMember::ErrorType::None;
291
}
1✔
292

1✔
293
static uint64 GetEnumValue(std::string_view input, JenHash hash,
294
                           const ReflectedEnum **rEnumFallback = nullptr) {
295
  const ReflectedEnum *rEnum = rEnumFallback && *rEnumFallback
13✔
296
                                   ? *rEnumFallback
297
                                   : ReflectedEnum::Registry().at(hash);
298

13✔
299
  if (rEnumFallback) {
300
    *rEnumFallback = rEnum;
14✔
301
  }
302

14✔
303
  auto namesEnd = rEnum->names + rEnum->numMembers;
304
  auto foundItem =
305
      std::find_if(rEnum->names, namesEnd, [input](std::string_view item) {
14✔
306
        return !item.compare(input);
307
      });
308

309
  if (namesEnd == foundItem) {
310
    throw std::range_error("[Reflector] Enum value not found: " +
311
                           static_cast<std::string>(input));
312
  }
313

314
  return rEnum->values[std::distance(rEnum->names, foundItem)];
315
}
316

317
static ReflectorMember::ErrorType SetEnum(std::string_view input, char *objAddr,
318
                                          JenHash hash, uint16 size) {
319
  input = es::SkipEndWhitespace(input);
320

321
  if (input.empty()) {
322
    printerror("[Reflector] Empty input for enum " << hash.raw());
323
    return ReflectorMember::ErrorType::EmptyInput;
324
  }
325

326
  uint64 eValue = 0;
327

328
  try {
329
    eValue = GetEnumValue(input, hash);
330
  } catch (const std::out_of_range &) {
331
    printerror("[Reflector] Unregistered enum hash: "
332
               << hash.raw() << " for value: " << input);
333
    return ReflectorMember::ErrorType::InvalidDestination;
334
  } catch (const std::range_error &e) {
335
    printerror(e.what());
336
    return ReflectorMember::ErrorType::InvalidFormat;
337
  }
×
338

×
339
  memcpy(objAddr, &eValue, size);
340

×
341
  return ReflectorMember::ErrorType::None;
342
}
343

344
static ReflectorMember::ErrorType FlagFromEnum(std::string_view input,
14✔
345
                                               JenHash hash,
346
                                               uint64 &fallbackValue,
6✔
347
                                               const ReflectedEnum *&fallback) {
348
  input = es::TrimWhitespace(input);
349

350
  if (input.empty()) {
351
    printerror("[Reflector] Empty input for enum flag " << hash.raw());
352
    return ReflectorMember::ErrorType::EmptyInput;
14✔
353
  }
2✔
354

355
  uint64 cValue = 0;
356

1✔
357
  try {
1✔
358
    cValue = GetEnumValue(input, hash, &fallback);
359
  } catch (const std::out_of_range &) {
360
    printerror("[Reflector] Unregistered enum hash: "
13✔
361
               << hash.raw() << " for value: " << input);
362
    return ReflectorMember::ErrorType::InvalidDestination;
363
  } catch (const std::range_error &e) {
13✔
364
    if (input != "NULL") {
365
      printerror(e.what());
18✔
366
      return ReflectorMember::ErrorType::InvalidFormat;
367
    }
18✔
368
    return ReflectorMember::ErrorType::None;
369
  }
370

18✔
371
  fallbackValue |= 1ULL << cValue;
372

373
  return ReflectorMember::ErrorType::None;
374
}
375

376
static ReflectorMember::ErrorType
377
SetEnumFlags(std::string_view input, char *objAddr, JenHash hash, uint16 size) {
378
  auto lastIterator = input.data();
379
  auto inputEnd = input.data() + input.size();
380
  ReflectorMember::ErrorType errType = ReflectorMember::ErrorType::None;
381
  uint64 eValue = 0;
382
  const ReflectedEnum *rEnumFallback = nullptr;
383

384
  for (auto &c : input) {
385
    if (c == '|') {
386
      auto subErrType = FlagFromEnum({lastIterator, size_t(&c - lastIterator)},
387
                                     hash, eValue, rEnumFallback);
388
      if (subErrType == ReflectorMember::ErrorType::InvalidDestination) {
389
        return subErrType;
390
      } else if (subErrType != ReflectorMember::ErrorType::None) {
391
        errType = subErrType;
392
      }
393

394
      lastIterator = &c + 1;
395
    }
396
  }
397

398
  if (lastIterator < inputEnd) {
399
    auto subErrType =
400
        FlagFromEnum({lastIterator, size_t(inputEnd - lastIterator)}, hash,
401
                     eValue, rEnumFallback);
402
    if (subErrType == ReflectorMember::ErrorType::InvalidDestination) {
×
403
      return subErrType;
×
404
    } else if (subErrType != ReflectorMember::ErrorType::None) {
405
      errType = subErrType;
×
406
    }
407
  }
408

409
  memcpy(objAddr, &eValue, size);
18✔
410

411
  return errType;
6✔
412
}
413

414
static size_t ReflectedArraySize(char startBrace, char endBrace,
415
                                 std::string_view value) {
416
  if (value.empty()) {
417
    return 0;
18✔
418
  }
2✔
419

420
  const size_t arrBegin = value.find(startBrace);
421

1✔
422
  if (arrBegin == value.npos) {
1✔
423
    return -1;
424
  }
425

17✔
426
  const size_t arrEnd = value.find_last_of(endBrace);
427

428
  if (arrEnd == value.npos) {
17✔
429
    return -1;
430
  } else if (arrEnd < arrBegin) {
18✔
431
    return -1;
432
  }
18✔
433

434
  value = {value.data() + arrBegin + 1, arrEnd - arrBegin - 1};
435

18✔
436
  if (value.empty()) {
437
    return 0;
438
  }
439

440
  size_t curElement = 0;
441
  bool localScope = false;
442

443
  for (auto it = value.begin(); it != value.end(); it++) {
444
    const bool isEnding = std::next(it) == value.end();
445

446
    if ((*it == ']' || *it == '"' || *it == ')' || *it == '}') && localScope) {
447
      localScope = false;
448
    }
449

450
    if (localScope || *it == '[' || *it == '"' || *it == '(' || *it == '{') {
451
      localScope = true;
452
      continue;
453
    }
454

455
    if (*it == ',' || isEnding) {
456
      curElement++;
457
    }
458
  }
459

460
  return curElement;
461
}
462

463
static ReflectorMember::ErrorType
464
SetReflectedArray(char startBrace, char endBrace, char *objAddr,
465
                  std::string_view value, ReflType reflValue,
466
                  const reflectorStatic *refl) {
467
  const size_t arrBegin = value.find(startBrace);
×
468

×
469
  if (arrBegin == value.npos) {
470
    printerror("[Reflector] Expected " << startBrace << " not found.");
×
471
    return ReflectorMember::ErrorType::InvalidFormat;
472
  }
473

474
  const size_t arrEnd = value.find_last_of(endBrace);
18✔
475

476
  if (arrEnd == value.npos) {
6✔
477
    printerror("[Reflector] Expected " << endBrace << " not found.");
478
    return ReflectorMember::ErrorType::InvalidFormat;
479
  } else if (arrEnd < arrBegin) {
480
    printerror("[Reflector] " << endBrace << " was found before " << startBrace
481
                              << '.');
482
    return ReflectorMember::ErrorType::InvalidFormat;
18✔
483
  }
2✔
484

485
  value = {value.data() + arrBegin + 1, arrEnd - arrBegin - 1};
486

1✔
487
  if (value.empty()) {
1✔
488
    printerror("[Reflector] Empty array input.");
489
    return ReflectorMember::ErrorType::EmptyInput;
490
  }
17✔
491

492
  size_t curElement = 0;
493
  auto curIter = value.begin();
17✔
494
  bool localScope = false;
495
  const auto &arr = reflValue.asArray;
11✔
496

497
  for (auto it = value.begin(); it != value.end(); it++) {
11✔
498
    const bool isEnding = std::next(it) == value.end();
499

500
    if ((*it == ']' || *it == '"' || *it == ')' || *it == '}') && localScope) {
11✔
501
      localScope = false;
502
    }
503

504
    if (localScope || *it == '[' || *it == '"' || *it == '(' || *it == '{') {
505
      localScope = true;
506
      continue;
507
    }
508

509
    if (*it == ',' || isEnding) {
3✔
510
      std::string_view cValue(
×
511
          &*curIter, std::distance(curIter, (isEnding ? value.end() : it)));
512
      cValue = es::SkipStartWhitespace(cValue);
3✔
513

514
      if (cValue.empty() && curElement < arr.numItems) {
515
        printerror("[Reflector] Array expected "
516
                   << int(arr.numItems) << " but got " << curElement << '.');
517
        return ReflectorMember::ErrorType::ShortInput;
6✔
518
      }
519

520
      if (!cValue.empty() && curElement >= arr.numItems) {
3✔
521
        printerror("[Reflector] Too many array elements, " << int(arr.numItems)
3✔
522
                                                           << " expected.");
523
        return ReflectorMember::ErrorType::OutOfRange;
524
      }
8✔
525

526
      SetReflectedMember(arr, cValue, objAddr + (arr.stride * curElement),
527
                         refl);
528
      curIter = it + 1;
529
      curElement++;
530
    }
531
  }
532

533
  return ReflectorMember::ErrorType::None;
534
}
535

536
static ReflectorMember::ErrorType
537
SetReflectedMember(ReflType reflValue, std::string_view value, char *objAddr,
538
                   const reflectorStatic *refl) {
539
  ReflectorMember::ErrorType errType = ReflectorMember::ErrorType::None;
540
  char startBrace = 0;
541
  char endBrace = 0;
542
  value = es::SkipStartWhitespace(value);
543

544
  if (!(reflValue.container == REFContainer::None ||
545
        reflValue.container == REFContainer::Pointer)) {
546
    startBrace = '{';
547
    endBrace = '}';
548
  } else if (reflValue.type == REFType::Vector) {
549
    startBrace = '[';
550
    endBrace = ']';
551
  }
552

553
  if (reflValue.container == REFContainer::InlineArray) {
554
    return SetReflectedArray(startBrace, endBrace, objAddr, value, reflValue,
555
                             refl);
556
  } else if (reflValue.container == REFContainer::ContainerVector ||
557
             reflValue.container == REFContainer::ContainerVectorMap) {
558
    const VectorMethods methods = refl->vectorMethods[reflValue.index];
8✔
559
    const size_t numItems = ReflectedArraySize(startBrace, endBrace, value);
560
    methods.signal(objAddr, VectorMethods::Resize, numItems, 0);
19✔
561
    if (numItems > 0) {
562
      char *vData = static_cast<char *>(methods.at(objAddr, 0));
19✔
563
      reflValue.asArray.type = reflValue.type;
564
      reflValue.asArray.numItems = numItems;
565
      reflValue.asArray.stride = reflValue.size;
19✔
566
      return SetReflectedArray(startBrace, endBrace, vData, value, reflValue,
567
                               refl);
568
    }
569
    return ReflectorMember::ErrorType::EmptyInput;
570
  }
571

572
  switch (reflValue.type) {
573
  case REFType::Bool:
574
    return SetBoolean(std::string(value), *reinterpret_cast<bool *>(objAddr));
×
575
  case REFType::Integer: {
×
576
    switch (reflValue.size) {
577
    case 1:
×
578
      return SetNumber(value, *objAddr);
579
    case 2:
580
      return SetNumber(value, *reinterpret_cast<short *>(objAddr));
581
    case 4:
19✔
582
      return SetNumber(value, *reinterpret_cast<int *>(objAddr));
6✔
583
    case 8:
584
      return SetNumber(value, *reinterpret_cast<int64 *>(objAddr));
585
    default:
3✔
586
      return ReflectorMember::ErrorType::InvalidDestination;
3✔
587
    }
588
  }
589
  case REFType::UnsignedInteger: {
16✔
590
    switch (reflValue.size) {
591
    case 1:
592
      return SetNumber(value, *reinterpret_cast<unsigned char *>(objAddr));
593
    case 2:
594
      return SetNumber(value, *reinterpret_cast<unsigned short *>(objAddr));
595
    case 4:
596
      return SetNumber(value, *reinterpret_cast<unsigned int *>(objAddr));
597
    case 8:
598
      return SetNumber(value, *reinterpret_cast<uint64 *>(objAddr));
599
    default:
600
      return ReflectorMember::ErrorType::InvalidDestination;
601
    }
602
  }
603
  case REFType::FloatingPoint: {
604
    if (reflValue.asFloat.customFormat) {
605
      const auto &flt = reflValue.asFloat;
606
      double outValue;
607
      auto err = SetNumber(value, outValue);
608
      if (!flt.sign && outValue < 0) {
609
        printwarning("[Reflector] Applying " << outValue
610
                                             << " to an unsigned float");
611
        err = ReflectorMember::ErrorType::SignMismatch;
612
      }
613
      size_t convertedValue = esFloatDetail::FromFloat(outValue, flt.mantissa,
614
                                                       flt.exponent, flt.sign);
615
      memcpy(objAddr, &convertedValue, reflValue.size);
616
      return err;
617
    } else {
618
      switch (reflValue.size) {
619
      case 4:
620
        return SetNumber(value, *reinterpret_cast<float *>(objAddr));
621
      case 8:
622
        return SetNumber(value, *reinterpret_cast<double *>(objAddr));
623
      default:
16✔
624
        return ReflectorMember::ErrorType::InvalidDestination;
625
      }
13✔
626
    }
627
  }
13✔
628
  case REFType::BitFieldMember: {
629
    uint64 &output = *reinterpret_cast<uint64 *>(objAddr);
630
    auto doStuff = [&](auto &&insertVal) {
13✔
631
      LimitProxy<std::decay_t<decltype(insertVal)>> proxy{reflValue.bit.size};
632
      auto err = SetNumber(value, insertVal, proxy);
633
      BitMember bfMember;
634
      bfMember.size = reflValue.bit.size;
635
      bfMember.position = reflValue.bit.position;
636
      auto mask = bfMember.GetMask<uint64>();
637
      output &= ~mask;
638
      output |= insertVal.value << reflValue.bit.position;
639
      return err;
×
640
    };
×
641

642
    switch (reflValue.asBitfield.type) {
×
643
    case REFType::UnsignedInteger:
644
      return doStuff(BFTag<uint64>{0});
645
      break;
646
    case REFType::Integer:
13✔
647
      return doStuff(BFTag<int64>{0});
6✔
648
      break;
649
    case REFType::FloatingPoint: {
650
      const auto &flt = reflValue.asBitfield.asFloat;
3✔
651

3✔
652
      if (flt.customFormat) {
653
        double outValue;
654
        auto err = SetNumber(value, outValue);
10✔
655
        if (!flt.sign && outValue < 0) {
656
          printwarning("[Reflector] Applying " << outValue
657
                                               << " to an unsigned float");
658
          err = ReflectorMember::ErrorType::SignMismatch;
659
        }
660
        size_t convertedValue = esFloatDetail::FromFloat(
661
            outValue, flt.mantissa, flt.exponent, flt.sign);
662
        BitMember bfMember;
663
        bfMember.size = reflValue.bit.size;
664
        bfMember.position = reflValue.bit.position;
665
        auto mask = bfMember.GetMask<uint64>();
666
        output &= ~mask;
667
        output |= convertedValue << reflValue.bit.position;
668
        return err;
669
      }
670

671
      return ReflectorMember::ErrorType::InvalidDestination;
672
    }
673
    case REFType::Bool: {
674
      bool result;
675
      auto err = SetBoolean(std::string(value), result);
676
      auto mask = (1ULL << reflValue.bit.position);
677

678
      if (result) {
679
        output |= mask;
680
      } else {
681
        output &= ~mask;
682
      }
683
      return err;
684
    }
685
    case REFType::Enum: {
686
      uint64 bValue;
687
      auto err =
688
          SetEnum(value, reinterpret_cast<char *>(&bValue),
10✔
689
                  JenHash(reflValue.asBitfield.typeHash), sizeof(bValue));
690
      BitMember bfMember;
16✔
691
      bfMember.size = reflValue.bit.size;
692
      bfMember.position = reflValue.bit.position;
16✔
693
      auto mask = bfMember.GetMask<uint64>();
694
      output &= ~mask;
695
      output |= bValue << reflValue.bit.position;
16✔
696
      return err;
697
    }
698

699
    default:
700
      return ReflectorMember::ErrorType::InvalidDestination;
701
    }
702
  }
703
  case REFType::Enum:
704
    return SetEnum(value, objAddr, JenHash(reflValue.asClass.typeHash),
2✔
705
                   reflValue.size);
2✔
706
  case REFType::EnumFlags:
707
    return SetEnumFlags(value, objAddr, JenHash(reflValue.asClass.typeHash),
×
708
                        reflValue.size);
709
  case REFType::String:
710
    *reinterpret_cast<std::string *>(objAddr) = value;
711
    break;
15✔
712
  case REFType::Vector:
6✔
713
    return SetReflectedArray(startBrace, endBrace, objAddr, value, reflValue,
714
                             refl);
715
  default:
3✔
716
    break;
3✔
717
  }
718

719
  return errType;
12✔
720
}
721

722
template <class... Ts> struct overloaded : Ts... {
723
  using Ts::operator()...;
724
};
725

726
ReflectorMember::ErrorType
727
ReflectorMember::ReflectValue(ReflectorInputValue value, size_t index) {
728
  if (!data) {
729
    return ErrorType::InvalidDestination;
730
  }
731
  char *thisAddr = static_cast<char *>(data.instance);
732
  ReflType type = data.rfStatic->types[id];
733
  thisAddr =
734
      thisAddr + (type.type == REFType::BitFieldMember ? 0 : type.offset);
735

736
  if (index != size_t(-1)) {
737
    if (type.container == REFContainer::InlineArray) {
738
      ReflTypeArray arrType = type.asArray;
739
      thisAddr += index * arrType.stride;
740
      type = arrType;
741

742
      if (index >= arrType.numItems) {
743
        return ReflectorMember::ErrorType::OutOfRange;
744
      }
745
    } else if (type.type == REFType::Vector) {
746
      ReflTypeVector vecType = type.asVector;
747
      thisAddr += index * vecType.stride;
748
      type = vecType;
749

750
      if (index >= vecType.numItems) {
751
        return ReflectorMember::ErrorType::OutOfRange;
752
      }
753
    } else if (type.container == REFContainer::ContainerVector ||
12✔
754
               type.container == REFContainer::ContainerVectorMap) {
755
      const VectorMethods methods = data.rfStatic->vectorMethods[type.index];
756
      type.asArray.type = type.type;
757
      type.asArray.numItems = methods.size(thisAddr);
×
758
      type.asArray.stride = type.size;
759
      if (type.asArray.numItems <= index) {
760
        methods.signal(thisAddr, VectorMethods::Resize, index + 1, 0);
×
761
        type.asArray.numItems = methods.size(thisAddr);
762
      }
763

764
      thisAddr = static_cast<char *>(methods.at(thisAddr, index));
765
      type = type.asArray;
766
    }
767
  }
768

769
  switch (type.type) {
770
  case REFType::BitFieldClass:
771
  case REFType::Class:
772
    throw std::runtime_error("Cannot set reflected value (value is subclass)");
773

774
  default:
775
    break;
776
  }
777

778
  auto SetPodType = [type, thisAddr](auto item) {
779
    switch (type.type) {
780
    case REFType::Bool: {
781
      uint64 cvtItem = bool(item);
782
      memcpy(thisAddr, &cvtItem, type.size);
783
      break;
784
    }
785
    case REFType::FloatingPoint: {
786
      if (type.size == 4) {
787
        float cvtItem = item;
×
788
        memcpy(thisAddr, &cvtItem, type.size);
789
      } else if (type.size == 8) {
790
        double cvtItem = item;
791
        memcpy(thisAddr, &cvtItem, type.size);
792
      } else {
×
NEW
793
        throw es::ImplementationError("Invlid floating point size");
×
794
      }
795

×
796
      break;
797
    }
798
    case REFType::Integer: {
799
      int64 cvtItem = item;
×
800
      memcpy(thisAddr, &cvtItem, type.size);
801
      break;
×
802
    }
803
    case REFType::UnsignedInteger: {
804
      uint64 cvtItem = item;
805
      memcpy(thisAddr, &cvtItem, type.size);
806
      break;
807
    }
×
808

×
809
    default:
810
      return ErrorType::InvalidDestination;
811
    }
×
812

×
813
    return ErrorType::None;
814
  };
815

×
816
  return std::visit(
817
      overloaded{
818
          [&](std::string_view item) {
×
819
            return SetReflectedMember(type, item, thisAddr, data.rfStatic);
820
          },
16✔
821
          SetPodType,
822
      },
16✔
823
      value);
824
}
825

16✔
826
static std::string_view
827
PrintEnumValue(JenHash hash, uint64 value,
828
               const ReflectedEnum **rEnumFallback = nullptr) {
829
  const ReflectedEnum *rEnum = rEnumFallback && *rEnumFallback
830
                                   ? *rEnumFallback
831
                                   : ReflectedEnum::Registry().at(hash);
832

833
  if (rEnumFallback)
834
    *rEnumFallback = rEnum;
835

836
  const uint64 *valuesEnd = rEnum->values + rEnum->numMembers;
837
  const uint64 *foundItem = std::find_if(
838
      rEnum->values, valuesEnd, [value](uint64 item) { return item == value; });
839

840
  if (foundItem == valuesEnd) {
841
    throw std::range_error("[Reflector] Enum value not found: " +
842
                           std::to_string(value));
843
  }
844

845
  return rEnum->names[std::distance(rEnum->values, foundItem)];
846
}
847

848
static std::string PrintEnum(const char *objAddr, JenHash hash, uint16 elSize) {
849
  uint64 eValue = 0;
850

851
  memcpy(reinterpret_cast<char *>(&eValue), objAddr, elSize);
852

16✔
853
  return std::string{PrintEnumValue(hash, eValue)};
854
}
855

856
static std::string PrintEnumFlags(const char *objAddr, JenHash hash,
857
                                  uint16 elSize) {
×
858
  uint64 eValue;
×
859
  const ReflectedEnum *rEnumFallback = nullptr;
860
  std::string result;
×
861
  const size_t numBits = elSize * 8;
862

863
  memcpy(reinterpret_cast<char *>(&eValue), objAddr, elSize);
864

16✔
865
  for (size_t t = 0; t < numBits; t++) {
866
    if (eValue & (1ULL << t)) {
×
867
      if (result.size())
868
        result.append(" | ");
869

870
      try {
871
        result.append(PrintEnumValue(hash, t, &rEnumFallback));
872
      } catch (const std::out_of_range &) {
16✔
873
        printerror("[Reflector] Unregistered enum hash: " << hash.raw());
3✔
874
        break;
875
      } catch (const std::range_error &e) {
876
        printerror(e.what());
1✔
877
      } catch (...) {
1✔
878
        printerror("[Reflector] Unhandled exception: PrintEnumValue");
879
        break;
880
      }
15✔
881
    }
882
  }
883

15✔
884
  if (result.empty())
885
    return "NULL";
886

887
  return result;
240✔
888
}
889

890
static std::string GetReflectedPrimitive(const char *objAddr, ReflType type,
240✔
891
                                         const reflectorStatic *refl) {
892
  char startBrace = 0;
893
  char endBrace = 0;
894

895
  if (!(type.container == REFContainer::None ||
230✔
896
        type.container == REFContainer::Pointer)) {
897
    startBrace = '{';
898
    endBrace = '}';
899
  } else if (type.type == REFType::Vector) {
900
    startBrace = '[';
901
    endBrace = ']';
902
  }
903

904
  if (startBrace && endBrace) {
905
    ReflTypeArray arr = type.asArray;
×
906

907
    if (type.container == REFContainer::ContainerVector ||
12✔
908
        type.container == REFContainer::ContainerVectorMap) {
4✔
909
      const VectorMethods methods = refl->vectorMethods[type.index];
910
      arr.type = type.type;
16✔
911
      arr.numItems = methods.size(objAddr);
16✔
912
      arr.stride = type.size;
913

914
      if (arr.numItems > 0) {
915
        objAddr = static_cast<const char *>(
8✔
916
            methods.at(const_cast<char *>(objAddr), 0));
6✔
917
      } else {
918
        char data[]{startBrace, endBrace, 0};
6✔
919
        return data;
920
      }
921
    }
922

923
    std::string outVal;
924
    outVal.push_back(startBrace);
925

123✔
926
    for (int i = 0; i < arr.numItems; i++) {
927
      outVal += GetReflectedPrimitive(objAddr + (arr.stride * i), arr, refl);
928
      outVal += ", ";
215✔
929
    }
930

931
    outVal.pop_back();
215✔
932
    outVal.pop_back();
933
    outVal.push_back(endBrace);
934

935
    return outVal;
936
  }
209✔
937

938
  switch (type.type) {
939
  case REFType::Bool:
940
    return *reinterpret_cast<const bool *>(objAddr) ? "true" : "false";
941

942
  case REFType::Integer: {
943
    switch (type.size) {
944
    case 1:
945
      return std::to_string(
946
          static_cast<int32>(*reinterpret_cast<const int8 *>(objAddr)));
×
947
    case 2:
948
      return std::to_string(*reinterpret_cast<const int16 *>(objAddr));
8✔
949
    case 4:
4✔
950
      return std::to_string(*reinterpret_cast<const int32 *>(objAddr));
951
    case 8:
8✔
952
      return std::to_string(*reinterpret_cast<const int64 *>(objAddr));
8✔
953

954
    default:
955
      return "";
956
    }
4✔
957
  }
3✔
958
  case REFType::UnsignedInteger: {
959
    switch (type.size) {
3✔
960
    case 1:
961
      return std::to_string(
962
          static_cast<int32>(*reinterpret_cast<const uint8 *>(objAddr)));
963
    case 2:
964
      return std::to_string(*reinterpret_cast<const uint16 *>(objAddr));
965
    case 4:
966
      return std::to_string(*reinterpret_cast<const uint32 *>(objAddr));
967
    case 8:
968
      return std::to_string(*reinterpret_cast<const uint64 *>(objAddr));
969

25✔
970
    default:
971
      return "";
972
    }
25✔
973
  }
974
  case REFType::FloatingPoint: {
975
    char _tmpBuffer[0x20]{};
976
    if (type.asFloat.customFormat) {
977
      size_t encValue = 0;
21✔
978
      const auto &flt = type.asFloat;
979
      memcpy(&encValue, objAddr, type.size);
980

981
      auto retVal = esFloatDetail::ToFloat(encValue, flt.mantissa, flt.exponent,
982
                                           flt.sign);
983
      snprintf(_tmpBuffer, sizeof(_tmpBuffer), "%.6g", retVal);
984
    } else {
985

986
      switch (type.size) {
987
      case 4:
×
988
        snprintf(_tmpBuffer, sizeof(_tmpBuffer), "%.6g",
989
                 *reinterpret_cast<const float *>(objAddr));
4✔
990
        break;
×
991
      case 8:
992
        snprintf(_tmpBuffer, sizeof(_tmpBuffer), "%.13g",
8✔
993
                 *reinterpret_cast<const double *>(objAddr));
8✔
994
        break;
995

996
      default:
997
        break;
4✔
998
      }
3✔
999
    }
1000
    return _tmpBuffer;
3✔
1001
  }
1002
  case REFType::BitFieldMember: {
1003
    uint64 output = *reinterpret_cast<const uint64 *>(objAddr);
1004
    BitMember bfMember;
1005
    bfMember.size = type.bit.size;
1006
    bfMember.position = type.bit.position;
1007
    auto mask = bfMember.GetMask<uint64>();
1008
    output = (output & mask) >> bfMember.position;
1009

1010
    switch (type.asBitfield.type) {
1011
    case REFType::UnsignedInteger:
45✔
1012
      return std::to_string(output);
1013
    case REFType::Bool:
207✔
1014
      return output ? "true" : "false";
1015
    case REFType::Enum:
45✔
1016
      return std::string(
1017
          PrintEnumValue(JenHash(type.asBitfield.typeHash), output));
45✔
1018
    case REFType::FloatingPoint: {
2✔
1019
      const auto &flt = type.asBitfield.asFloat;
1✔
1020

1021
      if (flt.customFormat) {
1022
        char _tmpBuffer[0x20]{};
1023
        auto retVal = esFloatDetail::ToFloat(output, flt.mantissa, flt.exponent,
1024
                                             flt.sign);
1025
        snprintf(_tmpBuffer, sizeof(_tmpBuffer), "%.6g", retVal);
100✔
1026
        return _tmpBuffer;
1027
      }
53✔
1028

100✔
1029
      return "NaN";
73✔
1030
    }
1031
    default:
73✔
1032
      break;
53✔
1033
    }
1034

1035
    int64 signedOutput = output;
100✔
1036
    LimitProxy<BFTag<int64>> limit{type.size};
1037

1038
    if (signedOutput & limit.iMin) {
224✔
1039
      signedOutput |= ~limit.uMax;
1040
    }
1041

100✔
1042
    return std::to_string(signedOutput);
11✔
1043
  }
22✔
1044

1045
  case REFType::EnumFlags:
1046
    return PrintEnumFlags(objAddr, JenHash(type.asClass.typeHash), type.size);
89✔
1047

1048
  case REFType::Enum: {
1049
    try {
47✔
1050
      return PrintEnum(objAddr, JenHash(type.asClass.typeHash), type.size);
1051
    } catch (const std::out_of_range &) {
1052
      printerror(
1053
          "[Reflector] Unregistered enum hash: " << type.asClass.typeHash);
47✔
1054
    } catch (const std::range_error &e) {
×
1055
      printerror(e.what());
×
1056
    } catch (...) {
1057
      printerror("[Reflector] Unhandled exception: PrintEnum");
1058
    }
47✔
1059

1060
    break;
1061
  }
47✔
1062

8✔
1063
  case REFType::CString:
×
1064
    return *reinterpret_cast<const char *const *>(objAddr);
1065

1066
  case REFType::String:
8✔
1067
    return *reinterpret_cast<const std::string *>(objAddr);
16✔
1068

1069
  case REFType::Class:
8✔
1070
  case REFType::BitFieldClass:
1071
    return "SUBCLASS_TYPE";
39✔
1072
  default:
1073
    break;
39✔
1074
  }
1075

1076
  return "";
62✔
1077
}
1078

1079
std::string ReflectorMember::ReflectedValue(size_t index) const {
1080
  const char *thisAddr = static_cast<const char *>(data.constInstance);
62✔
1081
  ReflType type = data.rfStatic->types[id];
1082
  const int valueOffset =
62✔
1083
      type.type == REFType::BitFieldMember ? 0 : type.offset;
18✔
1084

9✔
1085
  const char *objAddr = thisAddr + valueOffset;
1086

1087
  if (index != size_t(-1)) {
1088
    if (type.container == REFContainer::InlineArray) {
1089
      const auto &arr = type.asArray;
1090
      if (arr.numItems <= index) {
53✔
1091
        return "";
3✔
1092
      }
×
1093

1094
      objAddr += arr.stride * index;
1095
      type = arr;
3✔
1096
    } else if (type.type == REFType::Vector) {
1✔
1097
      ReflTypeVector vecType = type.asVector;
4✔
1098

1099
      if (index >= vecType.numItems) {
1100
        return "";
1101
      }
3✔
1102

1103
      objAddr += vecType.stride * index;
50✔
1104
      type = vecType;
1105
    } else if (type.type == REFType::EnumFlags) {
50✔
1106
      if (type.size * 8 <= index) {
1107
        return "";
1108
      }
1109

26✔
1110
      uint64 eValue;
1111

26✔
1112
      memcpy(reinterpret_cast<char *>(&eValue), objAddr, type.size);
1113

26✔
1114
      return (eValue & (1ULL << index)) ? "true" : "false";
26✔
1115
    } else if (type.container == REFContainer::ContainerVector ||
1116
               type.container == REFContainer::ContainerVectorMap) {
571✔
1117
      const VectorMethods methods = data.rfStatic->vectorMethods[type.index];
545✔
1118
      type.asArray.type = type.type;
36✔
1119
      type.asArray.numItems = methods.size(objAddr);
1120
      type.asArray.stride = type.size;
36✔
1121
      if (type.asArray.numItems <= index) {
1122
        return "";
36✔
1123
      }
1124

1125
      objAddr = static_cast<const char *>(
1126
          methods.at(const_cast<char *>(objAddr), index));
36✔
1127
      type = type.asArray;
1128
    }
1129
  }
1130

26✔
1131
  return GetReflectedPrimitive(objAddr, type, data.rfStatic);
1132
}
26✔
1133

1134
const reflectorStatic *GetReflectedFlags(uint32 hash) {
26✔
1135
  struct FlagProxy {
1136
    std::vector<ReflType> types;
26✔
1137
    reflectorStatic main;
1138

1139
    FlagProxy(const ReflectedEnum *refEnum)
1140
        : types(refEnum->numMembers), main(refEnum->numMembers, types.data(),
1141
                                           refEnum->names, refEnum->size) {
26✔
1142
      for (size_t i = 0; i < refEnum->numMembers; i++) {
1143
        ReflType &curType = types.at(i);
26✔
1144
        curType.type = REFType::BitFieldMember;
1145
        curType.index = i;
1146
        curType.bit.position = refEnum->values[i];
1✔
1147
        curType.bit.size = 1;
1148
        curType.valueNameHash = JenHash(refEnum->names[i]);
1✔
1149
        curType.size = refEnum->size;
1150
        curType.asBitfield.type = REFType::Bool;
1151
      }
1152
    }
1✔
1153
  };
1154
  static std::map<uint32, std::unique_ptr<FlagProxy>> REGISTRY;
1✔
1155

1156
  auto foundStored = REGISTRY.find(hash);
1157

1158
  if (foundStored != REGISTRY.end()) {
1159
    return &foundStored->second->main;
1160
  }
1✔
1161

1162
  auto found = ReflectedEnum::Registry().find(JenHash(hash));
1✔
1163

1164
  if (found == ReflectedEnum::Registry().end()) {
1165
    return nullptr;
1166
  }
1✔
1167

1168
  const ReflectedEnum *refEnum = found->second;
1✔
1169

1170
  return &REGISTRY.emplace(hash, std::make_unique<FlagProxy>(refEnum))
1171
              .first->second->main;
1172
}
1173

1174
ReflectorPureWrap ReflectorMember::ReflectedSubClass(size_t index) const {
1175
  if (!data) {
15✔
1176
    return {{}};
1177
  }
1178
  const char *thisAddr = static_cast<const char *>(data.constInstance);
14✔
1179
  ReflType type = data.rfStatic->types[id];
1180
  const char *objAddr = thisAddr + type.offset;
1181
  ReflTypeClass classType = type.asClass;
1182
  ReflTypeVector vectorType = type.asVector;
14✔
1183

1184
  if (type.container == REFContainer::InlineArray) {
×
1185
    const auto &arr = type.asArray;
1186
    if (index >= type.asArray.numItems) {
1187
      return {{}};
14✔
1188
    }
4✔
1189

1190
    objAddr += index * arr.stride;
1191
    classType = arr.asClass;
1192
    vectorType = arr.asVector;
1193
    type = arr;
1194
  } else if (type.container == REFContainer::ContainerVector ||
1195
             type.container == REFContainer::ContainerVectorMap) {
1196
    const VectorMethods methods = data.rfStatic->vectorMethods[type.index];
81✔
1197
    if (methods.size(objAddr) <= index) {
1198
      methods.signal(const_cast<char *>(objAddr), VectorMethods::Resize,
1199
                     index + 1, 0);
81✔
1200
    }
1201

81✔
1202
    objAddr =
24✔
1203
        static_cast<char *>(methods.at(const_cast<char *>(objAddr), index));
8✔
1204
    classType = type.asClass;
1205
    vectorType = type.asVector;
1206
  }
73✔
1207

1208
  switch (type.type) {
73✔
1209
  case REFType::Class:
12✔
1210
  case REFType::BitFieldClass: {
4✔
1211
    auto found = reflectorStatic::Registry().find(JenHash(classType.typeHash));
69✔
1212

×
1213
    if (found == reflectorStatic::Registry().end()) {
1214
      return {{}};
×
1215
    }
1216

1217
    return {{found->second, objAddr}};
69✔
1218
  }
1219

69✔
1220
  case REFType::Vector: {
×
1221
    VectorKey key;
×
1222
    key.type = vectorType.type;
1223
    key.numElements = vectorType.numItems;
1224
    key.size = vectorType.stride;
1225
    return {{&VECTORS.at(key), objAddr}};
1226
  }
1227

1228
  case REFType::EnumFlags: {
1229
    const reflectorStatic *asRef = GetReflectedFlags(type.asClass.typeHash);
1,454✔
1230
    return {{asRef, objAddr}};
1231
  }
1232

1,393✔
1233
  default:
1234
    break;
1235
  }
1236

1,393✔
1237
  return {{}};
1238
}
199✔
1239

1240
reflectorStatic::RegistryType &reflectorStatic::Registry() {
1241
  static RegistryType registry;
1,194✔
1242
  return registry;
1243
}
270✔
1244

1245
ReflectedEnum::RegistryType &ReflectedEnum::Registry() {
1246
  static RegistryType registry;
205✔
1247
  return registry;
16✔
1248
}
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