Skip to content

Commit fc4e96d

Browse files
committed
refactor XmlMapStorage TypeEnum to fix warning and add sanity checks
Enumerator TypeEnum::TypeEnum cannot have the same name as its enclosing enum TypeEnum
1 parent 93d43e3 commit fc4e96d

1 file changed

Lines changed: 120 additions & 54 deletions

File tree

src/mapstorage/XmlMapStorage.cpp

Lines changed: 120 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -37,22 +37,57 @@
3737
#include <QXmlStreamReader>
3838
#include <QXmlStreamWriter>
3939

40+
// clang-format off
41+
42+
4043
// ---------------------------- XmlMapStorage::TypeEnum ------------------------
4144
// list know enum types
45+
//
46+
// Each called X(_x) should use:
47+
//
48+
// TYPE_NAME_ENUM_VALUE(_x), or
49+
// TYPE_NAME_ENUM_TYPE(_x) to construct the enum type name, or
50+
// TYPE_NAME_STRING(_x) to construct the string representing the type name.
51+
//
52+
// Caution: these must match XFOREACH_CONVERTER defined below; the reason we can't just have
53+
// a single mscro is because XFOREACH_CONVERTER calls this but macros can't be recursive.
4254
#define XFOREACH_TYPE_ENUM(X) \
43-
X(RoomAlignEnum) \
44-
X(DoorFlagEnum) \
45-
X(ExitFlagEnum) \
46-
X(RoomLightEnum) \
47-
X(RoomLoadFlagEnum) \
48-
X(InfomarkClassEnum) \
49-
X(InfomarkTypeEnum) \
50-
X(RoomMobFlagEnum) \
51-
X(RoomPortableEnum) \
52-
X(RoomRidableEnum) \
53-
X(RoomSundeathEnum) \
54-
X(RoomTerrainEnum) \
55-
X(TypeEnum)
55+
X(RoomAlign) \
56+
X(DoorFlag) \
57+
X(ExitFlag) \
58+
X(RoomLight) \
59+
X(RoomLoadFlag) \
60+
X(InfomarkClass) \
61+
X(InfomarkType) \
62+
X(RoomMobFlag) \
63+
X(RoomPortable) \
64+
X(RoomRidable) \
65+
X(RoomSundeath) \
66+
X(RoomTerrain) \
67+
X(Type)
68+
69+
// Caution: these must match the enum types listed in XFOREACH_TYPE_ENUM above.
70+
// X(_x, _xfor, _xdecl)
71+
#define XFOREACH_CONVERTER(X, X_SEP) \
72+
X(RoomAlign, XFOREACH_RoomAlignEnum, X_DECL_SINGLE) X_SEP() \
73+
X(DoorFlag, XFOREACH_DOOR_FLAG, X_DECL_MULTI) X_SEP() \
74+
X(ExitFlag, XFOREACH_EXIT_FLAG, X_DECL_MULTI) X_SEP() \
75+
X(RoomLight, XFOREACH_RoomLightEnum, X_DECL_SINGLE) X_SEP() \
76+
X(RoomLoadFlag, XFOREACH_ROOM_LOAD_FLAG, X_DECL_SINGLE) X_SEP() \
77+
X(InfomarkClass, XFOREACH_INFOMARK_CLASS, X_DECL_SINGLE) X_SEP() \
78+
X(InfomarkType, XFOREACH_INFOMARK_TYPE, X_DECL_SINGLE) X_SEP() \
79+
X(RoomMobFlag, XFOREACH_ROOM_MOB_FLAG, X_DECL_SINGLE) X_SEP() \
80+
X(RoomPortable, XFOREACH_RoomPortableEnum, X_DECL_SINGLE) X_SEP() \
81+
X(RoomRidable, XFOREACH_RoomRidableEnum, X_DECL_SINGLE) X_SEP() \
82+
X(RoomSundeath, XFOREACH_RoomSundeathEnum, X_DECL_SINGLE) X_SEP() \
83+
X(RoomTerrain, XFOREACH_RoomTerrainEnum, X_DECL_SINGLE) X_SEP() \
84+
X(Type, XFOREACH_TYPE_ENUM, X_DECL_TYPE_ENUM)
85+
86+
// clang-format on
87+
88+
#define TYPE_NAME_ENUM_VALUE(_x) (TypeEnum::_x)
89+
#define TYPE_NAME_ENUM_TYPE(_x) _x##Enum
90+
#define TYPE_NAME_C_STRING(_x) (#_x "Enum")
5691

5792
namespace { // anonymous
5893

@@ -66,11 +101,80 @@ enum class NODISCARD TypeEnum : uint32_t {
66101
constexpr const size_t NUM_XMLMAPSTORAGE_TYPE = (XFOREACH_TYPE_ENUM(X_ADD));
67102
#undef X_ADD
68103

104+
#define X_SEP() ,
105+
#define X_DECL(_x, _xfor, _xdecl) _x
106+
enum class NODISCARD SanityCheckEnum : uint32_t { XFOREACH_CONVERTER(X_DECL, X_SEP) };
107+
#undef X_DECL
108+
#undef X_SEP
109+
110+
#define X_SEP() ;
111+
#define X_CHECK(_x, _xfor, _xdecl) \
112+
static_assert(static_cast<uint32_t>(SanityCheckEnum::_x) \
113+
== static_cast<uint32_t>(TYPE_NAME_ENUM_VALUE(_x)))
114+
XFOREACH_CONVERTER(X_CHECK, X_SEP);
115+
#undef X_CHECK
116+
#undef X_SEP
117+
118+
// define a bunch of methods
119+
// static constexpr TypeEnum enumToType(RoomAlignEnum) { return TypeEnum::RoomAlign; }
120+
// static constexpr TypeEnum enumToType(DoorFlagEnum) { return TypeEnum::DoorFlag; }
121+
// ...
122+
// converting an enumeration type to its corresponding TypeEnum value,
123+
// which can be used as argument in enumToString() and stringToEnum()
124+
#define X_DECL(_x) \
125+
NODISCARD constexpr TypeEnum enumToType(TYPE_NAME_ENUM_TYPE(_x)) \
126+
{ \
127+
return TYPE_NAME_ENUM_VALUE(_x); \
128+
}
129+
XFOREACH_TYPE_ENUM(X_DECL)
130+
#undef X_DECL
131+
132+
NODISCARD constexpr const char *to_c_string(const TypeEnum val)
133+
{
134+
#define X_CASE(_x) \
135+
case TYPE_NAME_ENUM_VALUE(_x): \
136+
return TYPE_NAME_C_STRING(_x);
137+
//
138+
switch (val) {
139+
XFOREACH_TYPE_ENUM(X_CASE)
140+
}
141+
return "unknown";
142+
#undef X_CASE
143+
}
144+
145+
static_assert(enumToType(RoomAlignEnum::UNDEFINED) == TypeEnum::RoomAlign);
146+
static_assert(enumToType(RoomTerrainEnum::UNDEFINED) == TypeEnum::RoomTerrain);
147+
148+
static_assert(enumToType(TypeEnum::RoomAlign) == TypeEnum::Type);
149+
static_assert(enumToType(TypeEnum::RoomTerrain) == TypeEnum::Type);
150+
static_assert(enumToType(TypeEnum::Type) == TypeEnum::Type);
151+
152+
static_assert(to_c_string(TypeEnum::RoomAlign) == std::string_view{"RoomAlignEnum"});
153+
static_assert(to_c_string(TypeEnum::RoomTerrain) == std::string_view{"RoomTerrainEnum"});
154+
static_assert(to_c_string(TypeEnum::Type) == std::string_view{"TypeEnum"});
155+
156+
NODISCARD std::vector<std::vector<QString>> make_enum_to_strings_table()
157+
{
158+
#define X_SEP() ,
159+
#define X_DECL_SINGLE(_x) /*QString*/ {#_x},
160+
#define X_DECL_MULTI(_x, ...) /*QString*/ {#_x},
161+
#define X_DECL_TYPE_ENUM(_x) /*QString*/ {TYPE_NAME_C_STRING(_x)},
162+
#define X_CONVERT(_x, _xfor, _xdecl) /*std::vector<QString>*/ {_xfor(_xdecl)}
163+
164+
return {XFOREACH_CONVERTER(X_CONVERT, X_SEP)};
165+
166+
#undef X_DECL_SINGLE
167+
#undef X_DECL_MULTI
168+
#undef X_DECL_TYPE_ENUM
169+
#undef X_CONVERT
170+
#undef X_SEP
171+
}
172+
69173
// ---------------------------- XmlMapStorage::Converter -----------------------
70174
class NODISCARD Converter final
71175
{
72176
private:
73-
std::vector<std::vector<QString>> m_enumToStrings;
177+
std::vector<std::vector<QString>> m_enumToStrings = make_enum_to_strings_table();
74178
std::vector<QHash<QStringView, uint32_t>> m_stringToEnums;
75179

76180
public:
@@ -100,57 +204,18 @@ class NODISCARD Converter final
100204
{
101205
static_assert(std::is_enum_v<ENUM>, "template type ENUM must be an enumeration");
102206
if constexpr (std::is_same_v<ENUM, TypeEnum>) {
103-
#define X_CASE(x) \
104-
case TypeEnum::x: \
105-
return #x;
106-
//
107-
switch (val) {
108-
XFOREACH_TYPE_ENUM(X_CASE)
109-
}
110-
return "unknown";
111-
#undef X_CASE
207+
return ::to_c_string(val);
112208
} else {
113209
return enumToString(enumToType(val), static_cast<uint32_t>(val));
114210
}
115211
}
116212

117213
private:
118-
// define a bunch of methods
119-
// static constexpr TypeEnum enumToType(RoomAlignEnum) { return TypeEnum::RoomAlignEnum; }
120-
// static constexpr TypeEnum enumToType(DoorFlagEnum) { return TypeEnum::DoorFlagEnum; }
121-
// ...
122-
// converting an enumeration type to its corresponding Type value,
123-
// which can be used as argument in enumToString() and stringToEnum()
124-
#define X_DECL(X) \
125-
MAYBE_UNUSED NODISCARD static constexpr TypeEnum enumToType(X) { return TypeEnum::X; }
126-
XFOREACH_TYPE_ENUM(X_DECL)
127-
#undef X_DECL
128-
129214
NODISCARD std::optional<uint32_t> stringToEnum(TypeEnum type, QStringView str) const;
130215
NODISCARD const QString &enumToString(TypeEnum type, uint32_t val) const;
131216
};
132217

133218
Converter::Converter()
134-
: m_enumToStrings{
135-
#define X_DECL(X) /* */ {#X},
136-
#define X_DECL2(X, ...) {#X},
137-
/* these must match the enum types listed in XFOREACH_TYPE_ENUM above */
138-
{XFOREACH_RoomAlignEnum(X_DECL)},
139-
{XFOREACH_DOOR_FLAG(X_DECL2)},
140-
{XFOREACH_EXIT_FLAG(X_DECL2)},
141-
{XFOREACH_RoomLightEnum(X_DECL)},
142-
{XFOREACH_ROOM_LOAD_FLAG(X_DECL)},
143-
{XFOREACH_INFOMARK_CLASS(X_DECL)},
144-
{XFOREACH_INFOMARK_TYPE(X_DECL)},
145-
{XFOREACH_ROOM_MOB_FLAG(X_DECL)},
146-
{XFOREACH_RoomPortableEnum(X_DECL)},
147-
{XFOREACH_RoomRidableEnum(X_DECL)},
148-
{XFOREACH_RoomSundeathEnum(X_DECL)},
149-
{XFOREACH_RoomTerrainEnum(X_DECL)},
150-
{XFOREACH_TYPE_ENUM(X_DECL)},
151-
#undef X_DECL
152-
#undef X_DECL2
153-
}
154219
{
155220
if (m_enumToStrings.size() != NUM_XMLMAPSTORAGE_TYPE) {
156221
throw std::runtime_error("XmlMapStorage internal error: enum names do not match enum types");
@@ -950,3 +1015,4 @@ void XmlMapStorage::saveRoomMobFlags(QXmlStreamWriter &stream, const RoomMobFlag
9501015
}
9511016

9521017
#undef XFOREACH_TYPE_ENUM
1018+
#undef XFOREACH_CONVERTER

0 commit comments

Comments
 (0)