move find_union_tag from check-structures-sanity to DataDefs.h

develop
Ben Lubar 2020-03-04 18:23:49 -06:00
parent 864264aec0
commit 84cae060b1
No known key found for this signature in database
GPG Key ID: 92939677AB59EDA4
3 changed files with 106 additions and 109 deletions

@ -454,3 +454,90 @@ void DFHack::flagarrayToString(std::vector<std::string> *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<container_identity *>(union_field->type);
if (container_type->getFullName(nullptr) != "vector<void>" ||
!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<container_identity *>(tag_candidate->type);
if (tag_container_type->getFullName(nullptr) == "vector<void>" &&
tag_container_type->getItemType() &&
tag_container_type->getItemType()->type() == IDTYPE_ENUM)
{
return tag_candidate;
}
return nullptr;
}

@ -796,6 +796,16 @@ namespace DFHack {
flagarray_to_string<T>(&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<df::enum>::attrs(val).attr)

@ -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<container_identity *>(union_field->type);
if (container_type->getFullName(nullptr) != "vector<void>" ||
!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<container_identity *>(tag_field->type);
if (tag_container_type->getFullName(nullptr) != "vector<void>" ||
!tag_container_type->getItemType() ||
tag_container_type->getItemType()->type() != IDTYPE_ENUM)
{
// not an enum
return nullptr;
}
return tag_field;
}
struct ToCheck
{
std::vector<std::string> 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)