1 // Copyright (C) 2018 Intel Corporation
2 //
3 //
4 // SPDX-License-Identifier: Apache-2.0
5 //
6
7 /// @file typed_graph.hpp
8
9 #ifndef ADE_TYPED_GRAPH_HPP
10 #define ADE_TYPED_GRAPH_HPP
11
12 #include <unordered_set>
13 #include <string>
14
15 #include <array>
16
17 #include "util/assert.hpp"
18 #include "util/memory_range.hpp"
19
20 #include "graph.hpp"
21 #include "typed_metadata.hpp"
22
23 namespace ade
24 {
25
26 template <typename T>
27 struct MetadataNameTag
28 {
29 };
30
31 /// User must provide means to get metadata name for each type he want to use
32 /// in graph metadata.
33 /// This can be done either via static member function:
34 /// \code{.cpp}
35 /// static const char* MyType::name();
36 /// \endcode
37 /// or via special function overload:
38 /// \code{.cpp}
39 /// const char* getMetadataName(ade::MetadataNameTag<MyType>);
40 /// \endcode
41 template<typename T>
getMetadataName(MetadataNameTag<T>)42 auto getMetadataName(MetadataNameTag<T>)
43 ->decltype(T::name())
44 {
45 return T::name();
46 }
47
48 namespace details
49 {
50
51 template<typename T>
getMetadataNameImpl()52 auto getMetadataNameImpl()
53 ->decltype(getMetadataName(MetadataNameTag<T>()))
54 {
55 return getMetadataName(MetadataNameTag<T>());
56 }
57
58 template<typename... Types>
checkUniqueNames()59 void checkUniqueNames()
60 {
61 std::unordered_multiset<std::string> names( { details::getMetadataNameImpl<Types>()... } );
62 auto not_unique = std::find_if(names.begin(), names.end(),
63 [&names](const std::string& n){ return names.count(n) != 1; });
64
65 if (not_unique != names.end()) throw_error(std::logic_error("Name " + *not_unique + " is not unique in graph metadata"));
66 }
67
68 template<typename T, typename... Remaining>
69 struct InitIdsArray final
70 {
operator ()ade::details::InitIdsArray71 inline void operator()(const ade::Graph& gr, util::MemoryRange<ade::details::MetadataId> ids) const
72 {
73 ADE_ASSERT(ids.size == (1 + sizeof...(Remaining)));
74 ids[0] = gr.getMetadataId(getMetadataNameImpl<T>());
75 InitIdsArray<Remaining...>()(gr, ids.Slice(1, ids.size - 1));
76 }
77 };
78
79 template<typename T>
80 struct InitIdsArray<T> final
81 {
operator ()ade::details::InitIdsArray82 inline void operator()(const ade::Graph& gr, util::MemoryRange<ade::details::MetadataId> ids) const
83 {
84 ADE_ASSERT(1 == ids.size);
85 ids[0] = gr.getMetadataId(getMetadataNameImpl<T>());
86 }
87 };
88
89 }
90
91 template<typename... Types>
92 class TypedGraph;
93
94 template<typename... Types>
95 class ConstTypedGraph
96 {
97 protected:
98 static_assert(sizeof...(Types) > 0, "Type list is empty");
99
100 // Store graph ptr as uintptr_t to avoid const_casts in derived class
101 std::uintptr_t m_srcGraph;
102 std::array<ade::details::MetadataId, sizeof...(Types)> m_ids;
103
getCGraph() const104 const ade::Graph& getCGraph() const
105 {
106 return *reinterpret_cast<const ade::Graph*>(m_srcGraph);
107 }
108
initIds()109 void initIds()
110 {
111 details::InitIdsArray<Types...>()(getCGraph(), util::memory_range(m_ids.data(), m_ids.size()));;
112 }
113
114
115 public:
116 template<typename... OtherTypes>
117 friend class ConstTypedGraph;
118
119 using CMetadataT = ade::TypedMetadata<true, Types...>;
120
ConstTypedGraph(const ade::Graph & graph)121 ConstTypedGraph(const ade::Graph& graph):
122 m_srcGraph(reinterpret_cast<std::uintptr_t>(&graph))
123 {
124 details::checkUniqueNames<Types...>();
125 initIds();
126 }
127
128 template<typename... OtherTypes>
ConstTypedGraph(const ConstTypedGraph<OtherTypes...> & other)129 ConstTypedGraph(const ConstTypedGraph<OtherTypes...>& other):
130 m_srcGraph(other.m_srcGraph)
131 {
132 details::checkUniqueNames<Types...>();
133 initIds();
134 }
135
136 ConstTypedGraph& operator=(const ConstTypedGraph&) = delete;
137
nodes() const138 ade::Graph::NodesListCRange nodes() const
139 {
140 return getCGraph().nodes();
141 }
142
metadata() const143 CMetadataT metadata() const
144 {
145 return CMetadataT(m_ids, getCGraph().metadata());
146 }
147
metadata(const ade::NodeHandle & handle) const148 CMetadataT metadata(const ade::NodeHandle& handle) const
149 {
150 return CMetadataT(m_ids, getCGraph().metadata(handle));
151 }
152
metadata(const ade::EdgeHandle & handle) const153 CMetadataT metadata(const ade::EdgeHandle& handle) const
154 {
155 return CMetadataT(m_ids, getCGraph().metadata(handle));
156 }
157 };
158
159 template<typename... Types>
160 class TypedGraph final : public ConstTypedGraph<Types...>
161 {
162 protected:
163 static_assert(sizeof...(Types) > 0, "Type list is empty");
164
getGraph() const165 ade::Graph& getGraph() const
166 {
167 return *reinterpret_cast<ade::Graph*>(this->m_srcGraph);
168 }
169
170 public:
171 using MetadataT = ade::TypedMetadata<false, Types...>;
172
TypedGraph(ade::Graph & graph)173 TypedGraph(ade::Graph& graph):
174 ConstTypedGraph<Types...>(graph)
175 {
176 }
177
178 template<typename... OtherTypes>
TypedGraph(const TypedGraph<OtherTypes...> & other)179 TypedGraph(const TypedGraph<OtherTypes...>& other):
180 ConstTypedGraph<Types...>(other)
181 {
182
183 }
184
185 TypedGraph& operator=(const TypedGraph&) = delete;
186
187 /// Create new node
createNode()188 ade::NodeHandle createNode()
189 {
190 return getGraph().createNode();
191 }
192
193 /// Delete node and all connected edges from graph and null all handles pointing to it
erase(const ade::NodeHandle & node)194 void erase(const ade::NodeHandle& node)
195 {
196 getGraph().erase(node);
197 }
198
199 /// Delete all edges, connected to this node
unlink(const ade::NodeHandle & node)200 void unlink(const ade::NodeHandle& node)
201 {
202 getGraph().unlink(node);
203 }
204
205 /// Delete node and all connected edges from graph and null all handles pointing to it
erase(const ade::EdgeHandle & edge)206 void erase(const ade::EdgeHandle& edge)
207 {
208 getGraph().erase(edge);
209 }
210
211 /// Create new edge between src_node and dst_node
link(const ade::NodeHandle & src_node,const ade::NodeHandle & dst_node)212 ade::EdgeHandle link(const ade::NodeHandle& src_node, const ade::NodeHandle& dst_node)
213 {
214 return getGraph().link(src_node, dst_node);
215 }
216
217 /// Change src_edge destination node to dst_node
218 /// noop if src_edge destination node is already dst_node
219 /// returns src_edge
link(const ade::EdgeHandle & src_edge,const ade::NodeHandle & dst_node)220 ade::EdgeHandle link(const ade::EdgeHandle& src_edge, const ade::NodeHandle& dst_node)
221 {
222 return getGraph().link(src_edge, dst_node);
223 }
224
225 /// Change dst_edge source node to src_node
226 /// noop if dst_edge source node is already src_node
227 /// returns dst_edge
link(const ade::NodeHandle & src_node,const ade::EdgeHandle & dst_edge)228 ade::EdgeHandle link(const ade::NodeHandle& src_node, const ade::EdgeHandle& dst_edge)
229 {
230 return getGraph().link(src_node, dst_edge);
231 }
232
233 using ConstTypedGraph<Types...>::nodes;
234 using ConstTypedGraph<Types...>::metadata;
235
nodes()236 ade::Graph::NodesListRange nodes()
237 {
238 return getGraph().nodes();
239 }
240
metadata()241 MetadataT metadata()
242 {
243 return MetadataT(this->m_ids, getGraph().metadata());
244 }
245
metadata(const ade::NodeHandle & handle)246 MetadataT metadata(const ade::NodeHandle& handle)
247 {
248 return MetadataT(this->m_ids, getGraph().metadata(handle));
249 }
250
metadata(const ade::EdgeHandle & handle)251 MetadataT metadata(const ade::EdgeHandle& handle)
252 {
253 return MetadataT(this->m_ids, getGraph().metadata(handle));
254 }
255 };
256
257 }
258
259 #endif // ADE_TYPED_GRAPH_HPP
260