Handle most complex enum metadata on the C++ side

develop
lethosor 2018-04-09 03:00:58 -04:00
parent 165167defe
commit ae6b8a16e8
3 changed files with 108 additions and 9 deletions

@ -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<int64_t> 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,

@ -188,9 +188,22 @@ namespace DFHack
class struct_identity;
class DFHACK_EXPORT enum_identity : public compound_identity {
public:
struct ComplexData {
std::map<int64_t, size_t> value_index_map;
std::vector<int64_t> index_value_map;
ComplexData(std::initializer_list<int64_t> 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<class T>
inline typename df::enum_traits<T>::enum_type next_enum_item(T v) {
inline typename std::enable_if<
!df::enum_traits<T>::is_complex,
typename df::enum_traits<T>::enum_type
>::type next_enum_item(T v, bool wrap = true)
{
typedef df::enum_traits<T> 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<class T>
inline typename std::enable_if<
df::enum_traits<T>::is_complex,
typename df::enum_traits<T>::enum_type
>::type next_enum_item(T v, bool wrap = true)
{
typedef df::enum_traits<T> 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<class T>
inline bool is_valid_enum_item(T v) {
inline typename std::enable_if<
!df::enum_traits<T>::is_complex,
bool
>::type is_valid_enum_item(T v)
{
return df::enum_traits<T>::is_valid(v);
}
template<class T>
inline typename std::enable_if<
df::enum_traits<T>::is_complex,
bool
>::type is_valid_enum_item(T v)
{
const auto &complex = df::enum_traits<T>::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<class T>
inline const char *enum_item_raw_key(T val) {
inline typename std::enable_if<
!df::enum_traits<T>::is_complex,
const char *
>::type enum_item_raw_key(T val) {
typedef df::enum_traits<T> traits;
return traits::is_valid(val) ? traits::key_table[(short)val - traits::first_item_value] : NULL;
}
template<class T>
inline typename std::enable_if<
df::enum_traits<T>::is_complex,
const char *
>::type enum_item_raw_key(T val) {
typedef df::enum_traits<T> 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<df::enum>(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.

@ -1 +1 @@
Subproject commit 3c0bf63674d5430deadaf7befaec42f0ec1e8bc5
Subproject commit d3491fa8790469e5325cf3f1ef1bf064b8011248