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