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
5792namespace { // anonymous
5893
@@ -66,11 +101,80 @@ enum class NODISCARD TypeEnum : uint32_t {
66101constexpr 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 -----------------------
70174class NODISCARD Converter final
71175{
72176private:
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
76180public:
@@ -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
117213private:
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
133218Converter::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