Optimize flags and flags parser
No more dynamically allocated objects
Setup union for easy array access of flags in rpg headers
Linear search static array of tag strings, no std::map.
Optimzies read/write routines
MODIFY
generator/generate.py
generator/generate.py
@@ -89,6 +89,9 @@ def pod_default(field):
return " = " + str(dfl)
+def num_flags(flag):
+ return len(flag)
+
def flag_size(flag):
return (len(flag) + 7) // 8
@@ -142,7 +145,7 @@ def struct_headers(ty, header_map):
return []
if re.match(r'(.*)_Flags$', ty):
- return []
+ return ['<array>']
m = re.match(r'Array<(.*):(.*)>', ty)
if m:
@@ -344,6 +347,7 @@ def main(argv):
env.filters["pod_default"] = pod_default
env.filters["struct_has_code"] = filter_structs_without_codes
env.filters["field_is_used"] = filter_unused_fields
+ env.filters["num_flags"] = num_flags
env.filters["flag_size"] = flag_size
env.filters["flag_set"] = flag_set
env.tests['needs_ctor'] = needs_ctor

MODIFY
generator/templates/flag_reader.tmpl
generator/templates/flag_reader.tmpl
// Read {{ struct_name }}.
-typedef RPG::{{ struct_name }}::Flags flags_type;
+using flags_type = RPG::{{ struct_name }}::Flags;
template <>
-char const* const Flags<flags_type>::name("{{ struct_name }}_Flags");
+char const* const Flags<flags_type>::name = "{{ struct_name }}_Flags";
template <>
-const Flags<flags_type>::Flag* Flags<flags_type>::flags[] = {
+decltype(Flags<flags_type>::flag_names) Flags<flags_type>::flag_names = {
{%- for flag in flags[struct_name] %}
- new Flags<flags_type>::Flag(&flags_type::{{ flag.field }}, "{{ flag.field }}", {{ flag.is2k3 }}),
-{%- if loop.last %}
- NULL
-{%- endif %}
-
+ "{{ flag.field }}"{%- if not loop.last %}, {%- endif %}
{%- endfor %}
};
template <>
-const uint32_t Flags<flags_type>::max_size = {{ flags[struct_name]|flag_size }};
+decltype(Flags<flags_type>::flags_is2k3) Flags<flags_type>::flags_is2k3 = {
+{%- for flag in flags[struct_name] %}
+ {{ flag.is2k3 }}{%- if not loop.last %}, {%- endif %}
+{%- endfor %}
+};

MODIFY
generator/templates/rpg_header.tmpl
generator/templates/rpg_header.tmpl
@@ -48,9 +48,20 @@ namespace RPG {
{%- if not field.size %}
{%- if field.type.endswith("_Flags") %}
struct Flags {
+ union {
+ struct {
{%- for flag in flags[struct_name] %}
- bool {{ flag.field }} = {{ field|flag_set(loop.index) }};
+ bool {{ flag.field }};
{%- endfor %}
+ };
+ std::array<bool, {{ flags[struct_name]|num_flags }}> flags;
+ };
+ //TODO: Should try to switch to member initializers when we upgrade to VS2017.
+ Flags() noexcept
+ {%- for flag in flags[struct_name] %}
+ {%- if loop.first %}:{%- else %},{%- endif %} {{ flag.field }}({{ field|flag_set(loop.index) }})
+ {%- endfor %}
+ {}
} {{ field.name }};
{%- else %}
{{ field.type|cpp_type(prefix=False) }} {{ field.name }}{{ field|pod_default }};

MODIFY
src/generated/ldb_terrain_flags.cpp
src/generated/ldb_terrain_flags.cpp
Binary files a/src/generated/ldb_terrain_flags.cpp and b/src/generated/ldb_terrain_flags.cpp differ

MODIFY
src/generated/ldb_trooppagecondition_flags.cpp
src/generated/ldb_trooppagecondition_flags.cpp
Binary files a/src/generated/ldb_trooppagecondition_flags.cpp and b/src/generated/ldb_trooppagecondition_flags.cpp differ

MODIFY
src/generated/lmu_eventpagecondition_flags.cpp
src/generated/lmu_eventpagecondition_flags.cpp
Binary files a/src/generated/lmu_eventpagecondition_flags.cpp and b/src/generated/lmu_eventpagecondition_flags.cpp differ

MODIFY
src/generated/lsd_savepicture_flags.cpp
src/generated/lsd_savepicture_flags.cpp
Binary files a/src/generated/lsd_savepicture_flags.cpp and b/src/generated/lsd_savepicture_flags.cpp differ

MODIFY
src/generated/rpg_eventpagecondition.h
src/generated/rpg_eventpagecondition.h
Binary files a/src/generated/rpg_eventpagecondition.h and b/src/generated/rpg_eventpagecondition.h differ

MODIFY
src/generated/rpg_savepicture.h
src/generated/rpg_savepicture.h
Binary files a/src/generated/rpg_savepicture.h and b/src/generated/rpg_savepicture.h differ

MODIFY
src/generated/rpg_terrain.h
src/generated/rpg_terrain.h
Binary files a/src/generated/rpg_terrain.h and b/src/generated/rpg_terrain.h differ

MODIFY
src/generated/rpg_trooppagecondition.h
src/generated/rpg_trooppagecondition.h
Binary files a/src/generated/rpg_trooppagecondition.h and b/src/generated/rpg_trooppagecondition.h differ

MODIFY
src/reader_flags.cpp
src/reader_flags.cpp
// Templates
-template <class S>
-void Flags<S>::MakeTagMap() {
- if (!tag_map.empty())
- return;
- for (int i = 0; flags[i] != NULL; i++)
- tag_map[flags[i]->name] = flags[i];
-}
-
template <class S>
void Flags<S>::ReadLcf(S& obj, LcfReader& stream, uint32_t length) {
- assert(length >= 1 && length <= max_size);
- uint8_t bitflag;
- for (int i = 0; flags[i] != NULL; i++) {
- if (i % 8 == 0) {
- if (i / 8 >= (int) length)
+ uint8_t byte;
+ int bitidx = 0;
+ int byteidx = 0;
+ stream.Read(byte);
+ for (size_t i = 0; i < num_flags; ++i) {
+ if (bitidx == 8) {
+ ++byteidx;
+ if (byteidx >= int(length)) {
break;
- stream.Read(bitflag);
}
- bool S::*ref = flags[i]->ref;
- obj.*ref = ((bitflag >> (i % 8)) & 0x1) != 0;
+ stream.Read(byte);
+ bitidx = 0;
+ }
+ obj.flags[i] |= (byte >> bitidx) & 1;
+ ++bitidx;
}
}
template <class S>
void Flags<S>::WriteLcf(const S& obj, LcfWriter& stream) {
- const bool is2k3 = (Data::system.ldb_id == 2003);
- uint8_t buffer[max_size] = {};
+ const bool db_is2k3 = (Data::system.ldb_id == 2003);
+ uint8_t byte = 0;
int bitidx = 0;
- int byteidx = 0;
- for (int i = 0; flags[i] != NULL; i++) {
- if (!is2k3 && flags[i]->is2k3) {
+ for (size_t i = 0; i < num_flags; ++i) {
+ const auto flag_is2k3 = flags_is2k3[i];
+ if (!db_is2k3 && flag_is2k3) {
continue;
}
- auto ref = flags[i]->ref;
- auto& byteflag = buffer[byteidx];
- auto value = obj.*ref;
- byteflag |= (value << bitidx);
+ byte |= (obj.flags[i] << bitidx);
++bitidx;
if (bitidx == 8) {
- stream.Write(byteflag);
- ++byteidx;
+ stream.Write(byte);
bitidx = 0;
+ byte = 0;
}
}
if (bitidx != 0) {
- stream.Write(buffer[max_size-1]);
+ stream.Write(byte);
}
}
template <class S>
int Flags<S>::LcfSize(const S& obj, LcfWriter& /* stream */) {
- const bool is2k3 = (Data::system.ldb_id == 2003);
+ const bool db_is2k3 = (Data::system.ldb_id == 2003);
int num_bits = 0;
- for (int i = 0; flags[i] != NULL; i++) {
- if (!is2k3 && flags[i]->is2k3) {
+ for (size_t i = 0; i < num_flags; ++i) {
+ const auto flag_is2k3 = flags_is2k3[i];
+ if (!db_is2k3 && flag_is2k3) {
continue;
}
++num_bits;
}
- auto num_bytes = (num_bits - 1) / 8 + 1;
+ auto num_bytes = (num_bits + 7) / 8;
return num_bytes;
}
template <class S>
void Flags<S>::WriteXml(const S& obj, XmlWriter& stream) {
+ const bool db_is2k3 = (Data::system.ldb_id == 2003);
stream.BeginElement(name);
- for (int i = 0; flags[i] != NULL; i++) {
- const Flag* flag = flags[i];
- bool S::*ref = flag->ref;
- stream.WriteNode<bool>(flag->name, obj.*ref);
+ for (size_t i = 0; i < num_flags; ++i) {
+ const auto flag_is2k3 = flags_is2k3[i];
+ if (!db_is2k3 && flag_is2k3) {
+ continue;
+ }
+ const auto* flag_name = flag_names[i];
+ stream.WriteNode<bool>(flag_name, obj.flags[i]);
}
stream.EndElement(name);
}
@@ -100,19 +99,16 @@ private:
bool* field;
public:
FlagsXmlHandler(S& obj) : obj(obj), field(NULL) {
- Flags<S>::MakeTagMap();
}
void StartElement(XmlReader& stream, const char* name, const char** /* atts */) {
- const typename Flags<S>::Flag* flag = Flags<S>::tag_map[name];
- if (flag != NULL) {
- bool S::*ref = flag->ref;
- field = &(obj.*ref);
- }
- else {
+ const auto idx = Flags<S>::idx(name);
+ if (idx < 0) {
stream.Error("Unrecognized field '%s'", name);
field = NULL;
+ return;
}
+ field = &obj.flags[idx];
}
void EndElement(XmlReader& /* stream */, const char* /* name */) {
field = NULL;

MODIFY
src/reader_struct.h
src/reader_struct.h
@@ -588,27 +588,21 @@ struct TypeReader<std::vector<T>, Category::Struct> {
}
};
+
+
/**
* Flags class template.
*/
template <class S>
class Flags {
-public:
- struct Flag {
- Flag(bool S::*ref, const char* const name, bool is2k2) : ref(ref), name(name), is2k3(is2k3) {}
- bool S::*ref;
- const char* const name;
- bool is2k3;
- };
-
private:
- static const uint32_t max_size;
- typedef std::map<const char* const, const Flag*, StringComparator> tag_map_type;
- static const Flag* flags[];
- static tag_map_type tag_map;
static const char* const name;
+ static constexpr size_t num_flags = std::tuple_size<decltype(S::flags)>::value;
+ static const std::array<const char* const, num_flags> flag_names;
+ static const std::array<bool, num_flags> flags_is2k3;
- static void MakeTagMap();
+ static const char* tag(int idx);
+ static int idx(const char* tag);
template <class T> friend class FlagsXmlHandler;
@@ -621,7 +615,19 @@ public:
};
template <class S>
-std::map<const char* const, const typename Flags<S>::Flag*, StringComparator> Flags<S>::tag_map;
+inline const char* Flags<S>::tag(int idx) {
+ return Flags<S>::flag_names[idx];
+}
+
+template <class S>
+inline int Flags<S>::idx(const char* tag) {
+ for (size_t i = 0; i < flag_names.size(); ++i) {
+ if (std::strcmp(flag_names[i], tag) == 0) {
+ return i;
+ }
+ }
+ return -1;
+}
/**
* Wrapper XML handler struct.

Optimize flags and flags parser

- No more dynamically allocated objects
- Setup union for easy array access of flags in rpg headers
- Linear search static array of tag strings, no std::map.
- Optimzies read/write routines