• 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

91.28
/src/reflector_xml.cpp
1
/*  a XML I/O source for Reflector class
2

3
    Copyright 2019-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_xml.hpp"
19
#include "spike/master_printer.hpp"
20
#include "spike/util/pugiex.hpp"
21

22
struct ReflectedInstanceFriend : ReflectedInstance {
23
  using ReflectedInstance::rfStatic;
24
  void *Instance() { return instance; }
25
  const void *Instance() const { return constInstance; }
26
  const reflectorStatic *Refl() const { return rfStatic; }
27
};
28

29
class ReflectorFriend : public Reflector {
30
public:
31
  using Reflector::GetReflectedInstance;
32
};
33

34
auto GetMakeAttribute(pugi::xml_node node, const std::string &name) {
163✔
35
  if (auto child = node.attribute(name.c_str()); child) {
163✔
36
    return child;
×
37
  } else {
38
    return node.append_attribute(name.c_str());
163✔
39
  }
40
}
41

42
auto GetMakeChild(pugi::xml_node node, const std::string &name) {
33✔
43
  if (auto child = node.child(name.c_str()); child) {
33✔
44
    return child;
×
45
  } else {
46
    return node.append_child(name.c_str());
33✔
47
  }
48
}
49

50
class ReflectorMemberFriend : public ReflectorMember {
51
public:
52
  using ReflectorMember::data;
53
  using ReflectorMember::id;
54
  ReflectedInstanceFriend Ref() const { return ReflectedInstanceFriend{data}; }
290✔
55
  operator const ReflType &() const { return Ref().Refl()->types[id]; }
74✔
56

57
  std::string Name() const {
142✔
58
    auto stat = Ref().Refl();
142✔
59
    std::string varName;
60

61
    if (stat->typeNames && stat->typeNames[id]) {
142✔
62
      varName = stat->typeNames[id];
63
    } else {
64
      varName.resize(15);
65
      const auto cHash = stat->types[id].valueNameHash.raw();
×
66
      snprintf(&varName[0], 15, "h:%X", cHash);
67
    }
68

69
    return varName;
142✔
70
  }
71
};
72

73
static bool SaveV2(ReflectorMemberFriend member, pugi::xml_node thisNode,
50✔
74
                   ReflectorXMLUtil::flag_type flags) {
75
  const ReflType &cType = member;
76
  std::string varName = member.Name();
50✔
77

78
  switch (cType.type) {
50✔
79
  case REFType::String:
80
  case REFType::CString: {
81
    if (!flags[ReflectorXMLUtil::Flags_StringAsAttribute]) {
1✔
82
      return false;
83
    }
84
  }
85
    [[fallthrough]];
86
  case REFType::Bool:
87
  case REFType::Enum:
88
  case REFType::FloatingPoint:
89
  case REFType::Integer:
90
  case REFType::UnsignedInteger:
91
  case REFType::BitFieldMember: {
92
    std::string str = member.ReflectedValue();
40✔
93
    auto cNode = GetMakeAttribute(thisNode, varName);
40✔
94
    cNode.set_value(str.data());
40✔
95
    return true;
96
  }
97
  case REFType::Vector: {
4✔
98
    static const char axes[4][2]{"x", "y", "z", "w"};
99
    pugi::xml_node cNode = GetMakeChild(thisNode, varName);
4✔
100

101
    for (size_t a = 0; a < cType.asVector.numItems; a++) {
17✔
102
      std::string str = member.ReflectedValue(a);
13✔
103
      GetMakeAttribute(cNode, axes[a]).set_value(str.data());
26✔
104
    }
105

106
    return true;
107
  }
108

109
  case REFType::EnumFlags: {
2✔
110
    if (!ReflectedEnum::Registry().count(JenHash(cType.asClass.typeHash))) {
2✔
111
      return false;
112
    }
113

114
    auto cEnum = ReflectedEnum::Registry().at(JenHash(cType.asClass.typeHash));
2✔
115
    pugi::xml_node cNode = GetMakeChild(thisNode, varName);
2✔
116

117
    for (size_t e = 0; e < cEnum->numMembers; e++) {
8✔
118
      auto name = cEnum->names[e];
6✔
119
      const uint64 value = cEnum->values[e];
6✔
120
      auto valueName = member.ReflectedValue(value);
6✔
121
      GetMakeAttribute(cNode, name).set_value(valueName.data());
12✔
122
    }
123

124
    return true;
125
  }
126
  default:
127
    return false;
128
  }
129
}
130

131
static pugi::xml_node MakeNode(const Reflector &, const reflectorStatic *stat,
1✔
132
                               pugi::xml_node node) {
133
  std::string className;
134

135
  if (stat->className)
1✔
136
    className = stat->className;
137
  else {
138
    className.resize(15);
139
    const auto cHash = stat->classHash.raw();
140
    snprintf(&className[0], 15, "h:%X", cHash);
141
  }
142

143
  return GetMakeChild(node, className.c_str());
2✔
144
}
145

146
static std::string GetName(const Reflector &, const reflectorStatic *stat,
147
                           const ReflType &cType, size_t t) {
148
  std::string varName;
149

150
  if (stat->typeNames && stat->typeNames[t]) {
151
    varName = stat->typeNames[t];
152
  } else {
153
    varName.resize(15);
154
    const auto cHash = cType.valueNameHash.raw();
155
    snprintf(&varName[0], 15, "h:%X", cHash);
156
  }
157

158
  return varName;
159
}
160

161
pugi::xml_node ReflectorXMLUtil::Save(const Reflector &ri, pugi::xml_node node,
8✔
162
                                      flag_type opts) {
163
  const ReflectorFriend &rif = static_cast<const ReflectorFriend &>(ri);
164
  ReflectedInstanceFriend instance{rif.GetReflectedInstance()};
8✔
165
  ReflectorPureWrap wrap(instance);
8✔
166
  const reflectorStatic *stat = instance.Refl();
167
  pugi::xml_node thisNode =
168
      opts[Flags_ClassNode] ? MakeNode(ri, stat, node) : node;
8✔
169

170
  while (true) {
171
    for (ReflectorMember mem_ : wrap) {
82✔
172
      ReflectorMemberFriend mem{mem_};
74✔
173
      std::string varName = mem.Name();
74✔
174
      const ReflType &cType = mem;
175

176
      if (!mem.IsArray() && ::SaveV2(mem, thisNode, opts)) {
74✔
177
        continue;
178
      }
179

180
      if (mem.IsReflectedSubClass()) {
28✔
181
        if (mem.IsArray()) {
5✔
182
          const size_t numItems = mem.Size();
2✔
183

184
          for (size_t s = 0; s < numItems; s++) {
6✔
185
            auto subRef = mem.ReflectedSubClass(s);
4✔
186
            auto nodeName = varName + '-' + std::to_string(s);
8✔
187
            pugi::xml_node cNode = GetMakeChild(thisNode, nodeName);
4✔
188
            auto subOpts = opts;
189
            subOpts -= Flags_ClassNode;
190
            Save(subRef, cNode, subOpts);
4✔
191
          }
192
        } else {
193
          auto subRef = mem.ReflectedSubClass();
3✔
194
          pugi::xml_node cNode = GetMakeChild(thisNode, varName);
3✔
195
          auto subOpts = opts;
196
          subOpts -= Flags_ClassNode;
197
          Save(subRef, cNode, subOpts);
3✔
198
        }
199
      } else if (mem.IsArray()) {
23✔
200
        const size_t numItems = mem.Size();
22✔
201
        ReflType arr = cType.asArray;
202
        REFType type = cType.container == REFContainer::InlineArray
22✔
203
                           ? arr.type
22✔
204
                           : cType.type;
205
        switch (type) {
22✔
206
        case REFType::String: {
207
          if (!opts[ReflectorXMLUtil::Flags_StringAsAttribute]) {
×
208
            for (size_t s = 0; s < numItems; s++) {
×
209
              std::string str = mem.ReflectedValue(s);
×
210
              auto nodeName = varName + '-' + std::to_string(s);
×
211
              auto cNode = GetMakeChild(thisNode, nodeName.data());
×
212
              cNode.append_buffer(str.data(), str.size());
×
213
            }
214
            break;
215
          }
216
        }
217
          [[fallthrough]];
218
        case REFType::Bool:
219
        case REFType::Enum:
220
        case REFType::FloatingPoint:
221
        case REFType::Integer:
222
        case REFType::UnsignedInteger:
223
        case REFType::BitFieldMember: {
224
          for (size_t s = 0; s < numItems; s++) {
64✔
225
            std::string str = mem.ReflectedValue(s);
48✔
226
            auto nodeName = varName + '-' + std::to_string(s);
96✔
227
            auto cNode = GetMakeAttribute(thisNode, nodeName.data());
96✔
228
            cNode.set_value(str.data());
48✔
229
          }
230
          break;
231
        }
232
        case REFType::Vector: {
233
          for (size_t s = 0; s < numItems; s++) {
16✔
234
            static const char axes[4][2]{"x", "y", "z", "w"};
235
            auto nodeName = varName + '-' + std::to_string(s);
24✔
236
            pugi::xml_node cNode = GetMakeChild(thisNode, nodeName.c_str());
12✔
237
            ReflectorPureWrap rfWrap(mem.ReflectedSubClass(s));
12✔
238

239
            for (size_t a = 0; a < arr.asVector.numItems; a++) {
50✔
240
              std::string str = rfWrap[a].ReflectedValue();
38✔
241
              GetMakeAttribute(cNode, axes[a]).set_value(str.data());
76✔
242
            }
243
          }
244
          break;
245
        }
246
        case REFType::EnumFlags: {
2✔
247
          if (!ReflectedEnum::Registry().count(JenHash(arr.asClass.typeHash))) {
2✔
248
            break;
249
          }
250

251
          auto &&cEnum =
252
              ReflectedEnum::Registry().at(JenHash(arr.asClass.typeHash));
2✔
253

254
          for (size_t s = 0; s < numItems; s++) {
8✔
255
            auto nodeName = varName + '-' + std::to_string(s);
12✔
256
            pugi::xml_node cNode = GetMakeChild(thisNode, nodeName.c_str());
6✔
257
            ReflectorPureWrap rfWrap(mem.ReflectedSubClass(s));
6✔
258

259
            for (auto m_ : rfWrap) {
24✔
260
              ReflectorMemberFriend m(m_);
18✔
261
              std::string mValue(m);
262
              GetMakeAttribute(cNode, m.Name()).set_value(mValue.c_str());
36✔
263
            }
264
          }
265
          break;
266
        }
267
        default: {
268
          pugi::xml_node cNode = GetMakeChild(thisNode, varName.c_str());
×
269
          std::string str = mem.ReflectedValue();
×
270
          cNode.append_buffer(str.c_str(), str.size());
×
271
          break;
272
        }
273
        }
274
      } else {
275
        pugi::xml_node cNode = GetMakeChild(thisNode, varName);
1✔
276
        std::string str = mem.ReflectedValue();
1✔
277
        cNode.append_buffer(str.c_str(), str.size());
1✔
278
      }
279
    }
280

281
    if (stat->baseClass.raw() == 0) {
8✔
282
      break;
283
    }
284

285
    stat = reflectorStatic::Registry().at(stat->baseClass);
×
286
    instance.rfStatic = stat;
287
    wrap = instance;
×
288
  };
289

290
  return thisNode;
8✔
291
}
292

293
pugi::xml_node ReflectorXMLUtil::Load(Reflector &ri, pugi::xml_node node,
8✔
294
                                      bool lookupClassNode) {
295
  auto &&rif = static_cast<ReflectorFriend &>(ri);
296
  const reflectorStatic *stat =
297
      static_cast<ReflectedInstanceFriend &&>(rif.GetReflectedInstance())
8✔
298
          .Refl();
8✔
299
  pugi::xml_node thisNode;
8✔
300
  static constexpr size_t nan_ = -1;
301
  struct retval {
302
    JenHash hash;
303
    size_t index = nan_;
304
  };
305

306
  auto MakeHash = [](std::string_view name) -> JenHash {
121✔
307
    if (name[0] == 'h' && name[1] == ':') {
121✔
308
      name.remove_prefix(2);
309
      return JenHash(strtoul(name.data(), nullptr, 16));
×
310
    } else {
311
      return name;
121✔
312
    }
313
  };
314

315
  auto MakeNode = [MakeHash](auto a) {
120✔
316
    std::string_view name(a.name());
120✔
317
    retval retVal;
318
    const size_t found = name.find_last_of('-');
319

320
    if (found != name.npos) {
120✔
321
      char *endChar = nullptr;
70✔
322
      const char *startChar = name.data() + found + 1;
70✔
323
      auto index = strtoll(startChar, &endChar, 10);
70✔
324

325
      if (startChar != endChar) {
70✔
326
        name = name.substr(0, found);
70✔
327
        retVal.index = index;
70✔
328
      }
329
    }
330

331
    retVal.hash = MakeHash(name);
120✔
332

333
    return retVal;
120✔
334
  };
335

32✔
336
  if (lookupClassNode) {
32✔
337
    thisNode = node.find_child([&](pugi::xml_node nde) {
338
      return !nde.empty() && MakeHash(nde.name()) == stat->classHash;
339
    });
340
  } else {
32✔
341
    thisNode = node;
22✔
342
  }
22✔
343

22✔
344
  for (auto a : thisNode.attributes()) {
345
    auto node = MakeNode(a);
22✔
346
    ReflectorMember mem(ri[node.hash]);
22✔
347

22✔
348
    if (node.index == nan_) {
349
      mem.ReflectValue(a.value());
350
    } else {
351
      mem.ReflectValue(a.value(), node.index);
32✔
352
    }
353
  }
32✔
354

355
  for (auto a : thisNode.children()) {
88✔
356
    auto node = MakeNode(a);
88✔
357
    ReflectorMember mem(ri[node.hash]);
358

359
    if (mem.IsReflectedSubClass()) {
360
      if (node.index == nan_) {
88✔
361
        node.index = 0;
48✔
362
      }
48✔
363

48✔
364
      auto rfInst = mem.ReflectedSubClass(node.index);
365
      ReflectorXMLUtil::Load(rfInst, a);
48✔
366
      continue;
48✔
367
    }
48✔
368

369
    if (a.attributes_begin() == a.attributes_end()) {
370
      mem.ReflectValue(a.text().as_string());
371
      continue;
88✔
372
    }
373

88✔
374
    ReflectorMemberFriend memFriend{mem};
375
    const ReflType &refType = memFriend;
376

8✔
377
    auto DoFlags = [&a](ReflectorPureWrap wrp) {
1✔
378
      for (auto t : a.attributes()) {
1✔
379
        wrp[std::string_view(t.name())] = t.as_string();
380
      }
381
    };
7✔
382

383
    switch (refType.type) {
384
    case REFType::EnumFlags:
96✔
385
    case REFType::Vector: {
88✔
386
      DoFlags(mem.ReflectedSubClass(node.index == nan_ ? 0 : node.index));
88✔
387
      break;
388
    }
88✔
389

40✔
390
    default:
391
      break;
48✔
392
    }
393
  }
394

395
  return thisNode;
40✔
396
}
32✔
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