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

PredatorCZ / PreCore / 536

22 Sep 2024 12:23PM UTC coverage: 52.238% (-3.0%) from 55.265%
536

push

github

PredatorCZ
remove old xml serializers

4084 of 7818 relevant lines covered (52.24%)

10609.73 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/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 <memory>
26
#include <ostream>
27
#include <string_view>
28

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

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

39
  return retVal;
280✔
40
};
41

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

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

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

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

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

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

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

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

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

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

118
  return nullptr;
119
}
120

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

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

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

140
  return {{}, 0};
141
}
142

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

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

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

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

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

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

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

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

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

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

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

228
    output = static_cast<T>(value);
75✔
229
  }
230

231
  return errType;
121✔
232
}
233

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

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

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

261
      double fVal = atof(input.c_str());
262

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

268
      return ReflectorMember::ErrorType::OutOfRange;
269
    }
270

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

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

281
  output = !memcmp(input.c_str(), "true", 4);
282

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

288
  return ReflectorMember::ErrorType::None;
289
}
1✔
290

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

13✔
297
  if (rEnumFallback) {
298
    *rEnumFallback = rEnum;
14✔
299
  }
300

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

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

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

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

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

324
  uint64 eValue = 0;
325

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

×
337
  memcpy(objAddr, &eValue, size);
338

×
339
  return ReflectorMember::ErrorType::None;
340
}
341

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

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

353
  uint64 cValue = 0;
354

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

18✔
369
  fallbackValue |= 1ULL << cValue;
370

371
  return ReflectorMember::ErrorType::None;
372
}
373

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

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

392
      lastIterator = &c + 1;
393
    }
394
  }
395

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

407
  memcpy(objAddr, &eValue, size);
18✔
408

409
  return errType;
6✔
410
}
411

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

418
  const size_t arrBegin = value.find(startBrace);
419

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

17✔
424
  const size_t arrEnd = value.find_last_of(endBrace);
425

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

432
  value = {value.data() + arrBegin + 1, arrEnd - arrBegin - 1};
433

18✔
434
  if (value.empty()) {
435
    return 0;
436
  }
437

438
  size_t curElement = 0;
439
  bool localScope = false;
440

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

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

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

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

458
  return curElement;
459
}
460

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

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

472
  const size_t arrEnd = value.find_last_of(endBrace);
18✔
473

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

483
  value = {value.data() + arrBegin + 1, arrEnd - arrBegin - 1};
484

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

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

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

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

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

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

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

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

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

531
  return ReflectorMember::ErrorType::None;
532
}
533

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

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

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

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

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

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

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

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

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

717
  return errType;
12✔
718
}
719

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

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

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

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

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

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

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

772
  default:
773
    break;
774
  }
775

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

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

×
807
    default:
808
      return ErrorType::InvalidDestination;
809
    }
×
810

×
811
    return ErrorType::None;
812
  };
813

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

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

831
  if (rEnumFallback)
832
    *rEnumFallback = rEnum;
833

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

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

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

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

849
  memcpy(reinterpret_cast<char *>(&eValue), objAddr, elSize);
850

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

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

861
  memcpy(reinterpret_cast<char *>(&eValue), objAddr, elSize);
862

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

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

15✔
882
  if (result.empty())
883
    return "NULL";
884

885
  return result;
240✔
886
}
887

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

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

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

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

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

921
    std::string outVal;
922
    outVal.push_back(startBrace);
923

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

929
    outVal.pop_back();
215✔
930
    outVal.pop_back();
931
    outVal.push_back(endBrace);
932

933
    return outVal;
934
  }
209✔
935

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

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

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

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

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

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

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

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

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

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

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

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

100✔
1040
    return std::to_string(signedOutput);
11✔
1041
  }
22✔
1042

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

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

1058
    break;
1059
  }
47✔
1060

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

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

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

1074
  return "";
62✔
1075
}
1076

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

9✔
1083
  const char *objAddr = thisAddr + valueOffset;
1084

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

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

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

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

26✔
1108
      uint64 eValue;
1109

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

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

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

26✔
1129
  return GetReflectedPrimitive(objAddr, type, data.rfStatic);
1130
}
26✔
1131

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

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

1154
  auto foundStored = REGISTRY.find(hash);
1155

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

1160
  auto found = ReflectedEnum::Registry().find(JenHash(hash));
1✔
1161

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

1166
  const ReflectedEnum *refEnum = found->second;
1✔
1167

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

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

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

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

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

73✔
1205
  switch (type.type) {
1206
  case REFType::Class:
73✔
1207
  case REFType::BitFieldClass: {
12✔
1208
    auto found = reflectorStatic::Registry().find(JenHash(classType.typeHash));
4✔
1209

69✔
1210
    if (found == reflectorStatic::Registry().end()) {
×
1211
      return {{}};
1212
    }
×
1213

1214
    return {{found->second, objAddr}};
1215
  }
69✔
1216

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

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

1230
  default:
1,393✔
1231
    break;
1232
  }
1233

1234
  return {{}};
1,393✔
1235
}
1236

199✔
1237
reflectorStatic::RegistryType &reflectorStatic::Registry() {
1238
  static RegistryType registry;
1239
  return registry;
1,194✔
1240
}
1241

270✔
1242
ReflectedEnum::RegistryType &ReflectedEnum::Registry() {
1243
  static RegistryType registry;
1244
  return registry;
205✔
1245
}
16✔
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