Skip to content

Commit

Permalink
Support nested types, pointers, and generalized arrays (#14)
Browse files Browse the repository at this point in the history
* Feature coverage, including nested types, arrays and pointers in signatures

* Tweaks to nested type logic
  • Loading branch information
DefaultRyan authored Feb 4, 2021
1 parent 88225c9 commit 66f3fcd
Show file tree
Hide file tree
Showing 8 changed files with 277 additions and 37 deletions.
22 changes: 21 additions & 1 deletion src/impl/winmd_reader/cache.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,19 @@ namespace winmd::reader

for (auto&& type : db.TypeDef)
{
if (!type.Flags().WindowsRuntime())
if (type.Flags().value == 0 || is_nested(type))
{
continue;
}

auto& ns = m_namespaces[type.TypeNamespace()];
ns.types.try_emplace(type.TypeName(), type);
}

for (auto&& row : db.NestedClass)
{
m_nested_types[row.EnclosingType()].push_back(row.NestedType());
}
}

for (auto&&[namespace_name, members] : m_namespaces)
Expand Down Expand Up @@ -160,6 +165,20 @@ namespace winmd::reader
remove(members.delegates, name);
}

std::vector<TypeDef> const& nested_types(TypeDef const& enclosing_type) const
{
auto it = m_nested_types.find(enclosing_type);
if (it != m_nested_types.end())
{
return it->second;
}
else
{
static const std::vector<TypeDef> empty;
return empty;
}
}

struct namespace_members
{
std::map<std::string_view, TypeDef> types;
Expand All @@ -178,5 +197,6 @@ namespace winmd::reader

std::list<database> m_databases;
std::map<std::string_view, namespace_members> m_namespaces;
std::map<TypeDef, std::vector<TypeDef>> m_nested_types;
};
}
48 changes: 47 additions & 1 deletion src/impl/winmd_reader/column.h
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,7 @@ namespace winmd::reader
inline auto Constant::ValueString() const
{
XLANG_ASSERT(Type() == ConstantType::String);
return get_blob(2).as_string();
return get_blob(2).as_u16string_constant();
}

inline auto Constant::ValueClass() const
Expand Down Expand Up @@ -502,4 +502,50 @@ namespace winmd::reader
{
return get_target_row<TypeDef>(2);
}

inline TypeDef NestedClass::NestedType() const
{
return get_target_row<TypeDef>(0);
}

inline TypeDef NestedClass::EnclosingType() const
{
return get_target_row<TypeDef>(1);
}

inline auto TypeDef::EnclosingType() const
{
auto const range = equal_range(get_database().NestedClass, *this);
TypeDef result;
if (range.first != range.second)
{
XLANG_ASSERT(range.second - range.first == 1);
result = range.first.EnclosingType();
}
return result;
}

inline auto Field::FieldMarshal() const
{
auto const range = equal_range(get_database().FieldMarshal, coded_index<HasFieldMarshal>());
reader::FieldMarshal result;
if (range.first != range.second)
{
XLANG_ASSERT(range.second - range.first == 1);
result = range.first;
}
return result;
}

inline auto Param::FieldMarshal() const
{
auto const range = equal_range(get_database().FieldMarshal, coded_index<HasFieldMarshal>());
reader::FieldMarshal result;
if (range.first != range.second)
{
XLANG_ASSERT(range.second - range.first == 1);
result = range.first;
}
return result;
}
}
61 changes: 59 additions & 2 deletions src/impl/winmd_reader/helpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,69 @@ namespace winmd::reader

inline auto find(TypeRef const& type)
{
return type.get_database().get_cache().find(type.TypeNamespace(), type.TypeName());
if (type.ResolutionScope().type() != ResolutionScope::TypeRef)
{
return type.get_database().get_cache().find(type.TypeNamespace(), type.TypeName());
}
else
{
auto enclosing_type = find(type.ResolutionScope().TypeRef());
if (!enclosing_type)
{
return TypeDef{};
}
auto const& nested_types = enclosing_type.get_cache().nested_types(enclosing_type);
auto iter = std::find_if(nested_types.begin(), nested_types.end(),
[name = type.TypeName()](TypeDef const& arg)
{
return name == arg.TypeName();
});
if (iter == nested_types.end())
{
return TypeDef{};
}
return *iter;
}
}

inline auto find_required(TypeRef const& type)
{
return type.get_database().get_cache().find_required(type.TypeNamespace(), type.TypeName());
if (type.ResolutionScope().type() != ResolutionScope::TypeRef)
{
return type.get_database().get_cache().find_required(type.TypeNamespace(), type.TypeName());
}
else
{
auto enclosing_type = find_required(type.ResolutionScope().TypeRef());
auto const& nested_types = enclosing_type.get_cache().nested_types(enclosing_type);
auto iter = std::find_if(nested_types.begin(), nested_types.end(),
[name = type.TypeName()](TypeDef const& arg)
{
return name == arg.TypeName();
});
if (iter == nested_types.end())
{
impl::throw_invalid("Type '", enclosing_type.TypeName(), ".", type.TypeName(), "' could not be found");
}
return *iter;
}
}

inline TypeDef find(coded_index<TypeDefOrRef> const& type)
{
if (type.type() == TypeDefOrRef::TypeRef)
{
return find(type.TypeRef());
}
else if (type.type() == TypeDefOrRef::TypeDef)
{
return type.TypeDef();
}
else
{
XLANG_ASSERT(false);
return {};
}
}

inline TypeDef find_required(coded_index<TypeDefOrRef> const& type)
Expand Down
36 changes: 36 additions & 0 deletions src/impl/winmd_reader/key.h
Original file line number Diff line number Diff line change
Expand Up @@ -174,4 +174,40 @@ namespace winmd::reader

return {};
}

enum class category
{
interface_type,
class_type,
enum_type,
struct_type,
delegate_type
};

inline category get_category(TypeDef const& type)
{
if (type.Flags().Semantics() == TypeSemantics::Interface || get_attribute(type, "System.Runtime.InteropServices"sv, "GuidAttribute"sv))
{
return category::interface_type;
}

auto const& [extends_namespace, extends_name] = get_base_class_namespace_and_name(type);

if (extends_name == "Enum"sv && extends_namespace == "System"sv)
{
return category::enum_type;
}

if (extends_name == "ValueType"sv && extends_namespace == "System"sv)
{
return category::struct_type;
}

if (extends_name == "MulticastDelegate"sv && extends_namespace == "System"sv)
{
return category::delegate_type;
}

return category::class_type;
}
}
34 changes: 33 additions & 1 deletion src/impl/winmd_reader/schema.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ namespace winmd::reader
auto EventList() const;
auto MethodImplList() const;

auto EnclosingType() const;

bool is_enum() const;
auto get_enum_definition() const;
};
Expand Down Expand Up @@ -179,6 +181,7 @@ namespace winmd::reader
auto CustomAttribute() const;
auto Constant() const;
auto Parent() const;
auto FieldMarshal() const;
};

struct Param : row_base<Param>
Expand All @@ -202,6 +205,7 @@ namespace winmd::reader

auto CustomAttribute() const;
auto Constant() const;
auto FieldMarshal() const;
};

struct InterfaceImpl : row_base<InterfaceImpl>
Expand All @@ -222,7 +226,7 @@ namespace winmd::reader
{
using row_base::row_base;

using constant_type = std::variant<bool, char16_t, int8_t, uint8_t, int16_t, uint16_t, int32_t, uint32_t, int64_t, uint64_t, float, double, std::string_view, std::nullptr_t>;
using constant_type = std::variant<bool, char16_t, int8_t, uint8_t, int16_t, uint16_t, int32_t, uint32_t, int64_t, uint64_t, float, double, std::u16string_view, std::nullptr_t>;

auto Type() const
{
Expand Down Expand Up @@ -255,6 +259,11 @@ namespace winmd::reader
struct FieldMarshal : row_base<FieldMarshal>
{
using row_base::row_base;

auto Parent() const
{
return get_coded_index<HasFieldMarshal>(0);
}
};

struct TypeSpec : row_base<TypeSpec>
Expand Down Expand Up @@ -577,6 +586,9 @@ namespace winmd::reader
struct NestedClass : row_base<NestedClass>
{
using row_base::row_base;

TypeDef NestedType() const;
TypeDef EnclosingType() const;
};

struct GenericParam : row_base<GenericParam>
Expand Down Expand Up @@ -659,4 +671,24 @@ namespace winmd::reader
{
return left.Association() < right;
}

inline bool operator<(NestedClass const& left, TypeDef const& right) noexcept
{
return left.NestedType() < right;
}

inline bool operator<(TypeDef const& left, NestedClass const& right) noexcept
{
return left < right.NestedType();
}

inline bool operator<(coded_index<HasFieldMarshal> const& left, FieldMarshal const& right) noexcept
{
return left < right.Parent();
}

inline bool operator<(FieldMarshal const& left, coded_index<HasFieldMarshal> const& right) noexcept
{
return left.Parent() < right;
}
}
Loading

0 comments on commit 66f3fcd

Please sign in to comment.