diff --git a/library/DataDefs.cpp b/library/DataDefs.cpp index ab50eb942..ce97904ad 100644 --- a/library/DataDefs.cpp +++ b/library/DataDefs.cpp @@ -143,11 +143,29 @@ enum_identity::enum_identity(size_t size, type_identity *base_type, int64_t first_item_value, int64_t last_item_value, const char *const *keys, + const ComplexData *complex, const void *attrs, struct_identity *attr_type) : compound_identity(size, NULL, scope_parent, dfhack_name), - keys(keys), first_item_value(first_item_value), last_item_value(last_item_value), + keys(keys), complex(complex), + first_item_value(first_item_value), last_item_value(last_item_value), base_type(base_type), attrs(attrs), attr_type(attr_type) { + if (complex) { + count = complex->size(); + } + else { + count = int(last_item_value-first_item_value+1); + } +} + +enum_identity::ComplexData::ComplexData(std::initializer_list values) +{ + size_t i = 0; + for (int64_t value : values) { + value_index_map[value] = i; + index_value_map.push_back(value); + i++; + } } struct_identity::struct_identity(size_t size, TAllocateFn alloc, diff --git a/library/include/DataDefs.h b/library/include/DataDefs.h index ed37a91fc..1da1be939 100644 --- a/library/include/DataDefs.h +++ b/library/include/DataDefs.h @@ -188,9 +188,22 @@ namespace DFHack class struct_identity; class DFHACK_EXPORT enum_identity : public compound_identity { + public: + struct ComplexData { + std::map value_index_map; + std::vector index_value_map; + ComplexData(std::initializer_list values); + size_t size() const { + return index_value_map.size(); + } + }; + + private: const char *const *keys; + const ComplexData *complex; int64_t first_item_value; int64_t last_item_value; + int count; type_identity *base_type; @@ -209,13 +222,14 @@ namespace DFHack type_identity *base_type, int64_t first_item_value, int64_t last_item_value, const char *const *keys, + const ComplexData *complex, const void *attrs, struct_identity *attr_type); virtual identity_type type() { return IDTYPE_ENUM; } int64_t getFirstItem() { return first_item_value; } int64_t getLastItem() { return last_item_value; } - int getCount() { return int(last_item_value-first_item_value+1); } + int getCount() { return count; } const char *const *getKeys() { return keys; } type_identity *getBaseType() { return base_type; } @@ -496,33 +510,100 @@ namespace DFHack { */ /** - * Return the next item in the enum, wrapping to the first one at the end. + * Return the next item in the enum, wrapping to the first one at the end if 'wrap' is true (otherwise an invalid item). */ template - inline typename df::enum_traits::enum_type next_enum_item(T v) { + inline typename std::enable_if< + !df::enum_traits::is_complex, + typename df::enum_traits::enum_type + >::type next_enum_item(T v, bool wrap = true) + { typedef df::enum_traits traits; typedef typename traits::base_type base_type; base_type iv = base_type(v); - return (iv < traits::last_item_value) ? T(iv+1) : traits::first_item; + if (iv < traits::last_item_value) + { + return T(iv + 1); + } + else + { + if (wrap) + return traits::first_item; + else + return T(traits::last_item_value + 1); + } + } + + template + inline typename std::enable_if< + df::enum_traits::is_complex, + typename df::enum_traits::enum_type + >::type next_enum_item(T v, bool wrap = true) + { + typedef df::enum_traits traits; + const auto &complex = traits::complex; + const auto it = complex.value_index_map.find(v); + if (it != complex.value_index_map.end()) + { + if (!wrap && it->second + 1 == complex.size()) + { + return T(traits::last_item_value + 1); + } + size_t next_index = (it->second + 1) % complex.size(); + return T(complex.index_value_map[next_index]); + } + else + return T(traits::last_item_value + 1); } /** * Check if the value is valid for its enum type. */ template - inline bool is_valid_enum_item(T v) { + inline typename std::enable_if< + !df::enum_traits::is_complex, + bool + >::type is_valid_enum_item(T v) + { return df::enum_traits::is_valid(v); } + template + inline typename std::enable_if< + df::enum_traits::is_complex, + bool + >::type is_valid_enum_item(T v) + { + const auto &complex = df::enum_traits::complex; + return complex.value_index_map.find(v) != complex.value_index_map.end(); + } + /** * Return the enum item key string pointer, or NULL if none. */ template - inline const char *enum_item_raw_key(T val) { + inline typename std::enable_if< + !df::enum_traits::is_complex, + const char * + >::type enum_item_raw_key(T val) { typedef df::enum_traits traits; return traits::is_valid(val) ? traits::key_table[(short)val - traits::first_item_value] : NULL; } + template + inline typename std::enable_if< + df::enum_traits::is_complex, + const char * + >::type enum_item_raw_key(T val) { + typedef df::enum_traits traits; + const auto &value_index_map = traits::complex.value_index_map; + auto it = value_index_map.find(val); + if (it != value_index_map.end()) + return traits::key_table[it->second]; + else + return NULL; + } + /** * Return the enum item key string pointer, or "?" if none. */ @@ -700,7 +781,7 @@ namespace DFHack { #define ENUM_NEXT_ITEM(enum,val) \ (DFHack::next_enum_item(val)) #define FOR_ENUM_ITEMS(enum,iter) \ - for(df::enum iter = ENUM_FIRST_ITEM(enum); is_valid_enum_item(iter); iter = df::enum(1+int(iter))) + for(df::enum iter = ENUM_FIRST_ITEM(enum); DFHack::is_valid_enum_item(iter); iter = DFHack::next_enum_item(iter, false)) /* * Include mandatory generated headers. diff --git a/library/xml b/library/xml index 3c0bf6367..d3491fa87 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 3c0bf63674d5430deadaf7befaec42f0ec1e8bc5 +Subproject commit d3491fa8790469e5325cf3f1ef1bf064b8011248