From 84cae060b1cd86b0cef5d8c5d2da44f70ecb3a02 Mon Sep 17 00:00:00 2001 From: Ben Lubar Date: Wed, 4 Mar 2020 18:23:49 -0600 Subject: [PATCH] move find_union_tag from check-structures-sanity to DataDefs.h --- library/DataDefs.cpp | 87 ++++++++++++++++ library/include/DataDefs.h | 10 ++ plugins/devel/check-structures-sanity.cpp | 118 ++-------------------- 3 files changed, 106 insertions(+), 109 deletions(-) diff --git a/library/DataDefs.cpp b/library/DataDefs.cpp index 92bd19fd4..cd3474619 100644 --- a/library/DataDefs.cpp +++ b/library/DataDefs.cpp @@ -454,3 +454,90 @@ void DFHack::flagarrayToString(std::vector *pvec, const void *p, } } } + +static const struct_field_info *find_union_tag_candidate(const struct_field_info *fields, const struct_field_info *union_field) +{ + std::string name(union_field->name); + if (name.length() >= 4 && name.substr(name.length() - 4) == "data") + { + name.erase(name.length() - 4, 4); + name += "type"; + + for (auto field = fields; field->mode != struct_field_info::END; field++) + { + if (field->name == name) + { + return field; + } + } + } + + if (name.length() > 7 && + name.substr(name.length() - 7) == "_target" && + fields != union_field && + (union_field - 1)->name == name.substr(0, name.length() - 7)) + { + return union_field - 1; + } + + return union_field + 1; +} + +const struct_field_info *DFHack::find_union_tag(const struct_field_info *fields, const struct_field_info *union_field) +{ + CHECK_NULL_POINTER(fields); + CHECK_NULL_POINTER(union_field); + + auto tag_candidate = find_union_tag_candidate(fields, union_field); + + if (union_field->mode == struct_field_info::SUBSTRUCT && + union_field->type && + union_field->type->type() == IDTYPE_UNION) + { + // union field + + if (tag_candidate->mode == struct_field_info::PRIMITIVE && + tag_candidate->type && + tag_candidate->type->type() == IDTYPE_ENUM) + { + return tag_candidate; + } + + return nullptr; + } + + if (union_field->mode != struct_field_info::CONTAINER || + !union_field->type || + union_field->type->type() != IDTYPE_CONTAINER) + { + // not a union field or a vector; bail + return nullptr; + } + + auto container_type = static_cast(union_field->type); + if (container_type->getFullName(nullptr) != "vector" || + !container_type->getItemType() || + container_type->getItemType()->type() != IDTYPE_UNION) + { + // not a vector of unions + return nullptr; + } + + if (tag_candidate->mode != struct_field_info::CONTAINER || + !tag_candidate->type || + tag_candidate->type->type() != IDTYPE_CONTAINER) + { + // candidate is not a vector + return nullptr; + } + + auto tag_container_type = static_cast(tag_candidate->type); + if (tag_container_type->getFullName(nullptr) == "vector" && + tag_container_type->getItemType() && + tag_container_type->getItemType()->type() == IDTYPE_ENUM) + { + return tag_candidate; + } + + return nullptr; +} diff --git a/library/include/DataDefs.h b/library/include/DataDefs.h index f772629cf..704b1abf7 100644 --- a/library/include/DataDefs.h +++ b/library/include/DataDefs.h @@ -796,6 +796,16 @@ namespace DFHack { flagarray_to_string(&tmp, val); return join_strings(sep, tmp); } + + /** + * Finds the tag field for a given union field. + * + * The returned tag field is a primitive enum field or nullptr. + * + * If the union field is a container type, the returned tag field is + * a container of primitive enum types. + */ + DFHACK_EXPORT const struct_field_info *find_union_tag(const struct_field_info *fields, const struct_field_info *union_field); } #define ENUM_ATTR(enum,attr,val) (df::enum_traits::attrs(val).attr) diff --git a/plugins/devel/check-structures-sanity.cpp b/plugins/devel/check-structures-sanity.cpp index 1d832aaac..b5cd1aa5f 100644 --- a/plugins/devel/check-structures-sanity.cpp +++ b/plugins/devel/check-structures-sanity.cpp @@ -97,97 +97,6 @@ static const char *const *get_enum_item_key(enum_identity *identity, int64_t val return &identity->getKeys()[index]; } -static const struct_field_info *find_union_tag_field(const struct_field_info *fields, const struct_field_info *union_field) -{ - std::string name(union_field->name); - if (name.length() >= 4 && name.substr(name.length() - 4) == "data") - { - name.erase(name.length() - 4, 4); - name += "type"; - - for (auto field = fields; field->mode != struct_field_info::END; field++) - { - if (field->name == name) - { - return field; - } - } - } - - if (name.length() > 7 && - name.substr(name.length() - 7) == "_target" && - fields != union_field && - (union_field - 1)->name == name.substr(0, name.length() - 7)) - { - return union_field - 1; - } - - return union_field + 1; -} - -static const struct_field_info *find_union_tag(const struct_field_info *fields, const struct_field_info *union_field) -{ - if (union_field->mode != struct_field_info::SUBSTRUCT || - !union_field->type || - union_field->type->type() != IDTYPE_UNION) - { - // not a union - return nullptr; - } - - - const struct_field_info *tag_field = find_union_tag_field(fields, union_field); - if (tag_field->mode != struct_field_info::PRIMITIVE || - !tag_field->type || - tag_field->type->type() != IDTYPE_ENUM) - { - // no tag - return nullptr; - } - - return tag_field; -} - -static const struct_field_info *find_union_vector_tag_vector(const struct_field_info *fields, const struct_field_info *union_field) -{ - if (union_field->mode != struct_field_info::CONTAINER || - !union_field->type || - union_field->type->type() != IDTYPE_CONTAINER) - { - // not a vector - return nullptr; - } - - auto container_type = static_cast(union_field->type); - if (container_type->getFullName(nullptr) != "vector" || - !container_type->getItemType() || - container_type->getItemType()->type() != IDTYPE_UNION) - { - // not a union - return nullptr; - } - - const struct_field_info *tag_field = find_union_tag_field(fields, union_field); - if (tag_field->mode != struct_field_info::CONTAINER || - !tag_field->type || - tag_field->type->type() != IDTYPE_CONTAINER) - { - // no tag vector - return nullptr; - } - - auto tag_container_type = static_cast(tag_field->type); - if (tag_container_type->getFullName(nullptr) != "vector" || - !tag_container_type->getItemType() || - tag_container_type->getItemType()->type() != IDTYPE_ENUM) - { - // not an enum - return nullptr; - } - - return tag_field; -} - struct ToCheck { std::vector path; @@ -693,27 +602,18 @@ void Checker::queue_static_array(const ToCheck & array, void *base, type_identit bool Checker::maybe_queue_union(const ToCheck & item, const struct_field_info *fields, const struct_field_info *union_field) { auto tag_field = find_union_tag(fields, union_field); - if (tag_field) - { - ToCheck union_item(item, "." + std::string(union_field->name), PTR_ADD(item.ptr, union_field->offset), union_field->type); - ToCheck tag_item(item, "." + std::string(tag_field->name), PTR_ADD(item.ptr, tag_field->offset), tag_field->type); - queue_union(union_item, tag_item); - - return true; - } - - tag_field = find_union_vector_tag_vector(fields, union_field); - if (tag_field) - { - ToCheck union_vector_item(item, "." + std::string(union_field->name), PTR_ADD(item.ptr, union_field->offset), union_field->type); - ToCheck tag_vector_item(item, "." + std::string(tag_field->name), PTR_ADD(item.ptr, tag_field->offset), tag_field->type); + if (!tag_field) + return false; - queue_union_vector(union_vector_item, tag_vector_item); + ToCheck union_item(item, "." + std::string(union_field->name), PTR_ADD(item.ptr, union_field->offset), union_field->type); + ToCheck tag_item(item, "." + std::string(tag_field->name), PTR_ADD(item.ptr, tag_field->offset), tag_field->type); - return true; - } + if (union_field->mode == struct_field_info::SUBSTRUCT) + queue_union(union_item, tag_item); + else + queue_union_vector(union_item, tag_item); - return false; + return true; } void Checker::queue_union(const ToCheck & item, const ToCheck & tag_item)