lairworks / nas2d-core

NAS2D is an open source, object oriented 2D game development framework written in portable C++.
http://nas2d.lairworks.com
zlib License
10 stars 5 forks source link

Refactor Sprite XML loading code #797

Open DanRStevens opened 4 years ago

DanRStevens commented 4 years ago

Related: #739, #211

The Sprite XML loading code should be examined and refactored. One goal here is to limit the use of XML code, such that it can be largely decoupled from the NAS2D library. This may make it easier to remove the TinyXML dependency from direct inclusion, allowing us to switch to vcpkg dependency installation, while also making it easier to transition to TinyXML2.

One feature needed by the Sprite code that is absent from the Configuration code is the ability to process arrays of data (the frame list).

Similar to the Configuration code, we may need to report errors due to missing required keys, or for extra unexpected keys which are neither required nor optional. This is likely to be true whether the we use XML, or JSON, or some other text format to store the data, so such error detecting and reporting code may need to be general and accessible to all such text processing methods.

DanRStevens commented 3 years ago

It would be helpful to have template code that could parameterized with an arbitrary struct, and then serialize that struct. Or at least convert between a struct and a Dictionary.

There is no reflection in C++ that would allow automatic extraction of struct field names. It's also entirely possible the field names in the serialized form will be different than the field names in the struct. As such, we may need to specify field names for the serialized form, which may differ from the struct field names.

Usage might look something like:

struct SomeData {
  int field1;
  std::string field2;
};

const auto someData = SomeData{1, "data"};
const auto dictionary = structToDictionary<"fieldName1", "fieldName2">(dataStruct);

EXPECT_EQ(Dictionary{{{"fieldName1", 1}, {"fieldName2", "data"}}}, dictionary);

To support the above, I was doing a bit of reading on templates. The structured binding feature can be used to some advantage here, though there is still a problem of determining how many fields are in any given struct. A long while back, I read a bit about the magic_get library, which seems to have come up again. Here are some relevant links:

DanRStevens commented 3 years ago

I was just thinking, if we require the programmer to specify text strings for each field name, then we can already infer the expected number of fields in a struct by matching it with the number of text strings provided. And if they ever don't match, we could (and probably should) declare a compile error. It's likely an easier problem to detect if a struct has a certain number of fields, then to try and count them.

Given the number of fields in the struct, the next problem would be to determine the type of each struct field by index. This may relate to determining the type of a std::tuple field by index. It is possible to convert between a struct and a std::tuple. One way appears to be considerably more involved than the other though, and the conversion may involve structured bindings. Though this may be getting away from the original problem, and perhaps the techniques for std::tuple can be borrowed and applied to struct types without any conversion to std::tuple.

References: Mundane std::tuple tricks: Finding a type in a tuple Stack Overflow: struct to/from std::tuple conversion

DanRStevens commented 3 years ago

The author of magic_get has a couple of C++ talks on the development of the library. They are both basically the same talk, though the later with a few updates, including use of C++17's destructuring feature.

Another interesting discussion was about the use of string constants as template non-type parameters. Apparently it was not really possible before C++11 due to issues of internal versus external linkage. Since then some interesting styles were developed for doing this.