1+
2+ namespace winmd ::reader
3+ {
4+ struct cache
5+ {
6+ cache () = default ;
7+ cache (cache const &) = delete ;
8+ cache& operator =(cache const &) = delete ;
9+
10+ template <typename C, typename T = typename C::value_type, typename TypeFilter>
11+ explicit cache (C const & files, TypeFilter filter)
12+ {
13+ for (auto && file : files)
14+ {
15+ auto & db = m_databases.emplace_back (file, this );
16+
17+ for (auto && type : db.TypeDef )
18+ {
19+ if (type.Flags ().value == 0 || is_nested (type) || !filter (type))
20+ {
21+ continue ;
22+ }
23+
24+ auto & ns = m_namespaces[type.TypeNamespace ()];
25+ ns.types .try_emplace (type.TypeName (), type);
26+ }
27+
28+ for (auto && row : db.NestedClass )
29+ {
30+ m_nested_types[row.EnclosingType ()].push_back (row.NestedType ());
31+ }
32+ }
33+
34+ for (auto &&[namespace_name, members] : m_namespaces)
35+ {
36+ for (auto &&[name, type] : members.types )
37+ {
38+ add_type_to_members (type, members);
39+ }
40+ }
41+ }
42+
43+ template <typename C, typename T = typename C::value_type>
44+ explicit cache (C const & files) : cache{ files, default_type_filter{} }
45+ {
46+ }
47+
48+ template <typename TypeFilter>
49+ explicit cache (std::string const & file, TypeFilter filter) : cache{ std::vector<std::string>{ file }, filter }
50+ {
51+ }
52+
53+ explicit cache (std::string const & file) : cache{ std::vector<std::string>{ file }, default_type_filter{} }
54+ {
55+ }
56+
57+ struct default_type_filter
58+ {
59+ bool operator ()(TypeDef const &) const noexcept
60+ {
61+ return true ;
62+ }
63+ };
64+
65+ TypeDef find (std::string_view const & type_namespace, std::string_view const & type_name) const noexcept
66+ {
67+ auto ns = m_namespaces.find (type_namespace);
68+
69+ if (ns == m_namespaces.end ())
70+ {
71+ return {};
72+ }
73+
74+ auto type = ns->second .types .find (type_name);
75+
76+ if (type == ns->second .types .end ())
77+ {
78+ return {};
79+ }
80+
81+ return type->second ;
82+ }
83+
84+ TypeDef find (std::string_view const & type_string) const
85+ {
86+ auto pos = type_string.rfind (' .' );
87+
88+ if (pos == std::string_view::npos)
89+ {
90+ impl::throw_invalid (" Type '" , type_string, " ' is missing a namespace qualifier" );
91+ }
92+
93+ return find (type_string.substr (0 , pos), type_string.substr (pos + 1 , type_string.size ()));
94+ }
95+
96+ TypeDef find_required (std::string_view const & type_namespace, std::string_view const & type_name) const
97+ {
98+ auto definition = find (type_namespace, type_name);
99+
100+ if (!definition)
101+ {
102+ impl::throw_invalid (" Type '" , type_namespace, " ." , type_name, " ' could not be found" );
103+ }
104+
105+ return definition;
106+ }
107+
108+ TypeDef find_required (std::string_view const & type_string) const
109+ {
110+ auto pos = type_string.rfind (' .' );
111+
112+ if (pos == std::string_view::npos)
113+ {
114+ impl::throw_invalid (" Type '" , type_string, " ' is missing a namespace qualifier" );
115+ }
116+
117+ return find_required (type_string.substr (0 , pos), type_string.substr (pos + 1 , type_string.size ()));
118+ }
119+
120+ auto const & databases () const noexcept
121+ {
122+ return m_databases;
123+ }
124+
125+ auto const & namespaces () const noexcept
126+ {
127+ return m_namespaces;
128+ }
129+
130+ void remove_type (std::string_view const & ns, std::string_view const & name)
131+ {
132+ auto m = m_namespaces.find (ns);
133+ if (m == m_namespaces.end ())
134+ {
135+ return ;
136+ }
137+ auto & members = m->second ;
138+
139+ auto remove = [&](auto && collection, auto && name)
140+ {
141+ auto pos = std::find_if (collection.begin (), collection.end (), [&](auto && type)
142+ {
143+ return type.TypeName () == name;
144+ });
145+
146+ if (pos != collection.end ())
147+ {
148+ collection.erase (pos);
149+ }
150+ };
151+
152+ remove (members.interfaces , name);
153+ remove (members.classes , name);
154+ remove (members.enums , name);
155+ remove (members.structs , name);
156+ remove (members.delegates , name);
157+ }
158+
159+ // This won't invalidate any existing database or row_base (e.g. TypeDef) instances
160+ // However, it may invalidate iterators and references to namespace_members, because those are stored in std::vector
161+ template <typename TypeFilter>
162+ void add_database (std::string_view const & file, TypeFilter filter)
163+ {
164+ auto & db = m_databases.emplace_back (file, this );
165+ for (auto && type : db.TypeDef )
166+ {
167+ if (type.Flags ().value == 0 || is_nested (type) || !filter (type))
168+ {
169+ continue ;
170+ }
171+
172+ auto & ns = m_namespaces[type.TypeNamespace ()];
173+ auto [iter, inserted] = ns.types .try_emplace (type.TypeName (), type);
174+ if (inserted)
175+ {
176+ add_type_to_members (type, ns);
177+ }
178+ }
179+
180+ for (auto && row : db.NestedClass )
181+ {
182+ m_nested_types[row.EnclosingType ()].push_back (row.NestedType ());
183+ }
184+ }
185+
186+ void add_database (std::string_view const & file)
187+ {
188+ add_database (file, default_type_filter{});
189+ }
190+
191+ std::vector<TypeDef> const & nested_types (TypeDef const & enclosing_type) const
192+ {
193+ auto it = m_nested_types.find (enclosing_type);
194+ if (it != m_nested_types.end ())
195+ {
196+ return it->second ;
197+ }
198+ else
199+ {
200+ static const std::vector<TypeDef> empty;
201+ return empty;
202+ }
203+ }
204+
205+ struct namespace_members
206+ {
207+ std::map<std::string_view, TypeDef> types;
208+ std::vector<TypeDef> interfaces;
209+ std::vector<TypeDef> classes;
210+ std::vector<TypeDef> enums;
211+ std::vector<TypeDef> structs;
212+ std::vector<TypeDef> delegates;
213+ std::vector<TypeDef> attributes;
214+ std::vector<TypeDef> contracts;
215+ };
216+
217+ using namespace_type = std::pair<std::string_view const , namespace_members> const &;
218+
219+ private:
220+
221+ void add_type_to_members (TypeDef const & type, namespace_members& members)
222+ {
223+ switch (get_category (type))
224+ {
225+ case category::interface_type:
226+ members.interfaces .push_back (type);
227+ return ;
228+ case category::class_type:
229+ if (extends_type (type, " System" sv, " Attribute" sv))
230+ {
231+ members.attributes .push_back (type);
232+ return ;
233+ }
234+ members.classes .push_back (type);
235+ return ;
236+ case category::enum_type:
237+ members.enums .push_back (type);
238+ return ;
239+ case category::struct_type:
240+ if (get_attribute (type, " Windows.Foundation.Metadata" sv, " ApiContractAttribute" sv))
241+ {
242+ members.contracts .push_back (type);
243+ return ;
244+ }
245+ members.structs .push_back (type);
246+ return ;
247+ case category::delegate_type:
248+ members.delegates .push_back (type);
249+ return ;
250+ }
251+ }
252+
253+ std::list<database> m_databases;
254+ std::map<std::string_view, namespace_members> m_namespaces;
255+ std::map<TypeDef, std::vector<TypeDef>> m_nested_types;
256+ };
257+ }
0 commit comments