1 /* Siconos is a program dedicated to modeling, simulation and control
2 * of non smooth dynamical systems.
3 *
4 * Copyright 2021 INRIA.
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18
19 /*! \file SiconosProperties.hpp
20
21 \brief Exterior properties to vertices or edges of a SiconosGraph
22 can be attach with Siconos::Properties. These properties are
23 referenced with vertices or edges indices. update_vertices_indices()
24 or update_edges_indices() must have been done after any vertices or
25 edges insertion or deletion.
26
27 */
28
29
30 #ifndef SICONOS_PROPERTIES_HPP
31 #define SICONOS_PROPERTIES_HPP
32
33 #include "SiconosSerialization.hpp"
34
35 #include <boost/config.hpp>
36 #include <boost/version.hpp>
37
38 #if (BOOST_VERSION >= 104000)
39 #include <boost/property_map/property_map.hpp>
40 #else
41 #include <boost/property_map.hpp>
42 #endif
43
44
45 #include <SiconosConfig.h>
46 #include <memory>
47 #include <map>
48
49
50 #include <boost/mpl/eval_if.hpp>
51 #include <boost/static_assert.hpp>
52 #include <vector>
53 #include <queue>
54
55 #include <boost/mpl/bool.hpp>
56 #include <boost/type_traits.hpp>
57
58 namespace Siconos
59 {
60
61 /** some local type traits */
62 template <typename T>
63 struct IsSharedPtr : boost::mpl::false_ {};
64
65 template <typename T>
66 struct IsSharedPtr<std::shared_ptr<T> > : boost::mpl::true_ {};
67
68 template <typename T>
69 struct IsPointer : boost::mpl::or_<boost::is_pointer<T>, IsSharedPtr<T> > {};
70
71
72 template <typename T>
73 struct RemovePointer
74 {
75 typedef T type;
76 };
77
78 template <typename T>
79 struct RemovePointer<std::shared_ptr<T> >
80 {
81 typedef T type;
82 };
83
84
85
86
87 /* a templated way to access edge or vertex with the help of
88 * boost::mpl::if_ */
89
90 /** get vertex needed data */
91 template<typename G>
92 struct VertexAccess
93 {
94 typedef VertexAccess type;
95 typedef typename G::VDescriptor descriptor;
96 typedef typename G::VIterator iterator;
97
elementsSiconos::VertexAccess98 std::pair<iterator, iterator> elements(G& g)
99 {
100 return g.vertices();
101 }
102
103
sizeSiconos::VertexAccess104 size_t size(G& g)
105 {
106 return g.vertices_number();
107 }
108
isElemSiconos::VertexAccess109 bool isElem(G& g, typename G::VDescriptor& vd)
110 {
111 return g.is_vertex(g.bundle(vd));
112 }
113
114 };
115
116 /** get edge needed data */
117 template<typename G>
118 struct EdgeAccess
119 {
120 typedef EdgeAccess type;
121 typedef typename G::EDescriptor descriptor;
122 typedef typename G::EIterator iterator;
123
elementsSiconos::EdgeAccess124 std::pair<iterator, iterator> elements(G& g)
125 {
126 return g.edges();
127 }
128
129
sizeSiconos::EdgeAccess130 static size_t size(const G& g)
131 {
132 return g.edges_number();
133 }
134
isElemSiconos::EdgeAccess135 bool isElem(G& g, typename G::EDescriptor& ed)
136 {
137 return g.is_edge(g.source(ed), g.target(ed), g.bundle(ed));
138 }
139 };
140
141
142 /** choose vertex or edge access according to IndexMap */
143 template<typename G, typename IndexMap>
144 struct VertexOrEdge
145 {
146 typedef typename boost::mpl::if_ < boost::is_same<typename G::VIndexAccess, IndexMap>,
147 VertexAccess<G> ,
148 EdgeAccess<G> >::type Access;
149 };
150
151 /** swap data */
152 template <typename T>
153 struct SwapPointedValues
154 {
155
156 typedef SwapPointedValues type;
157
operator ()Siconos::SwapPointedValues158 void operator()(T a, T b)
159 {
160 //note: if T is abstract, swap(T& a, T&b) must be implemented
161 using std::swap;
162 swap(*a, *b);
163 }
164 };
165
166
167 template <typename T>
168 struct SwapValues
169 {
170
171 typedef SwapValues type;
172
operator ()Siconos::SwapValues173 void operator()(T&a, T&b)
174 {
175 using std::swap;
176 swap(a, b);
177 }
178 };
179
180 template <typename T>
181 struct SwapProperties
182 {
183 typedef typename boost::mpl::if_ < IsPointer<T>,
184 SwapPointedValues<T>,
185 SwapValues<T> >::type type;
186 };
187
188 template <typename T>
189 struct GetPointedValue
190 {
191 typedef GetPointedValue type;
192
operator ()Siconos::GetPointedValue193 typename RemovePointer<T>::type& operator()(T a)
194 {
195 return *a;
196 }
197 };
198
199 template <typename T>
200 struct GetValue
201 {
202 typedef GetValue type;
203
operator ()Siconos::GetValue204 T& operator()(T& a)
205 {
206 return a;
207 }
208 };
209
210 template <typename T>
211 struct GetProperty
212 {
213
214 typedef typename boost::mpl::if_ < IsPointer<T>,
215 GetPointedValue<T>,
216 GetValue<T> >::type type;
217
218 };
219
220
221 /** the general properties structure, from boost::vector_property_map :
222 \param T the property data type
223 \param G the graph type
224 \param IndexMap the index map, should be either G::VIndexAccess or G:EIndexAccess
225 */
226 template<typename T, typename G, typename IndexMap>
227
228
229 class Properties
230 {
231
232 public:
233 typedef typename VertexOrEdge<G, IndexMap>::Access Access;
234
235 Access access;
236
237 typedef typename boost::property_traits<IndexMap>::key_type key_type;
238 typedef T value_type;
239 typedef typename std::iterator_traits <
240 typename std::vector<T>::iterator >::reference reference;
241 typedef boost::lvalue_property_map_tag category;
242
243
244 public:
245 G& _g;
246
247 // serialization issue with key_type as simple pointer (void *)
248 std::shared_ptr< std::map<key_type, T> > _store;
249
250 int _stamp;
251
252
253 /** constructor from a SiconosGraph
254 \param g a SiconosGraph
255 */
256
Properties(G & g)257 Properties(G& g) : _g(g), _store(new std::map<key_type, T>()), _stamp(-1)
258 {}
259
260
261 /** insert an element in the Property descriptor
262 * \param v a SiconosGraph::VDescriptor or
263 * SiconosGraph::EDescriptor according to IndexMap type
264 * \param t the element to be inserted
265 */
insert(const key_type & v,T t)266 void insert(const key_type& v, T t)
267 {
268 (*_store)[v] = t;
269 };
270
271 /** data access from a SiconosGraph vertex descriptor or edge
272 descriptor
273 \warning this operator creates an empty element if the key
274 is not in the map. Dot not use it to test if a key is present
275 or not in the map ...
276 \param v a SiconosGraph::VDescriptor or
277 SiconosGraph::EDescriptor according to IndexMap type
278 \return the element in the vector
279 */
operator [](const key_type & v)280 reference operator[](const key_type& v)
281 {
282 return (*_store)[v];
283 };
284
285 /** data access from a SiconosGraph vertex descriptor or edge
286 descriptor
287 \param v a SiconosGraph::VDescriptor or
288 SiconosGraph::EDescriptor according to IndexMap type */
at(const key_type & v)289 value_type at(const key_type& v)
290 {
291 return _store->at(v);
292 };
293
294 /** find data associated with the given key
295 \param v a SiconosGraph::VDescriptor or
296 SiconosGraph::EDescriptor according to IndexMap type
297 \return an iterator
298 */
find(const key_type & v)299 reference find(const key_type& v)
300 {
301 return _store->find(v).second;
302 };
303
304 /** check if a given property exists
305 \param v a SiconosGraph::VDescriptor or
306 SiconosGraph::EDescriptor according to IndexMap type
307 \return true if the key is a property, otherwise false
308 */
hasKey(const key_type & v)309 inline bool hasKey(const key_type& v)
310 {
311 return _store->find(v) != _store->end();
312 };
313
314
315 typedef void serializable;
316
317 /* Note: compilation with clang fail on this. And friend
318 * Siconos::siconos_io is not recognized anyway (attributes are public)
319
320 protected:
321 template<typename Archive>
322 friend void Siconos::siconos_io(Archive&, Properties<T,G,IndexMap>&, const unsigned int);
323 friend class boost::serialization::access;
324 */
325 };
326
327
328 /** vertex property structure:
329 \param T the property data type
330 \param G the graph type
331 */
332 template<typename T, typename G>
333 class VertexProperties : public Properties<T, G, typename G::VIndexAccess>
334 {
335 public:
VertexProperties(G & g)336 VertexProperties(G& g) : Properties<T, G, typename G::VIndexAccess>(g)
337 {};
338
339
340 typedef void serializable;
341
342 /*
343 protected:
344 template<typename Archive>
345 friend void Siconos::siconos_io(Archive&, VertexProperties<T,G>&, const unsigned int);
346 friend class boost::serialization::access;
347 */
348 };
349
350 /** vertex property structure with shared_pre
351 \param T the property data type
352 \param G the graph type
353 */
354 template<typename T, typename G>
355 class VertexSPProperties : public VertexProperties<std::shared_ptr<T>, G>
356 {
357 public:
VertexSPProperties(G & g)358 VertexSPProperties(G& g) : VertexProperties<std::shared_ptr<T>, G>(g)
359 {};
360
361
362 typedef typename boost::property_traits<typename G::VIndexAccess>::key_type key_type;
363 typedef void serializable;
364
365 /** data access from a SiconosGraph vertex descriptor or edge
366 descriptor
367 \warning this operator creates an empty element if the key
368 is not in the map. Dot not use it to test if a key os present
369 or not in the map ...
370 \param v a SiconosGraph::VDescriptor or
371 SiconosGraph::EDescriptor according to IndexMap type
372 \return the element in the vector
373 */
getRef(const key_type & v)374 inline T& getRef(const key_type& v)
375 {
376 return *((*this->_store)[v]).get();
377 };
378 };
379
380
381 /** edge property structure:
382 \param T the property data type
383 \param G the graph type
384 */
385 template<typename T, typename G>
386 class EdgeProperties : public Properties<T, G, typename G::EIndexAccess>
387 {
388 public:
EdgeProperties(G & g)389 EdgeProperties(G& g) : Properties<T, G, typename G::EIndexAccess>(g)
390 {};
391
392
393 typedef void serializable;
394
395 /*
396 protected:
397 template<typename Archive>
398 friend void Siconos::siconos_io(Archive&, EdgeProperties<T,G>&, const unsigned int);
399 friend class boost::serialization::access;
400 */
401 };
402
403 /** function to build a VertexProperties from one template parameter
404 \param g the graph
405 */
406 template<typename T, typename G>
vertexProperties(G & g)407 VertexProperties<T, G> vertexProperties(G& g)
408 {
409 return VertexProperties<T, G>(g);
410 }
411
412 /** function to build a EdgeProperties from one template parameter
413 \param g the graph
414 */
415 template<typename T, typename G>
edgeProperties(G & g)416 EdgeProperties<T, G> edgeProperties(G& g)
417 {
418 return EdgeProperties<T, G>(g);
419 }
420
421
422 /** global properties : they may be attached to main graph and may be
423 * referenced from subgraphs. They are not used for the moment */
424
425 template<typename T, typename G, typename IndexMap>
426 class SubProperties
427 {
428 private:
429 typedef Properties<T, G, IndexMap> RefProperties;
430 RefProperties _properties;
431 G& _g;
432
433 typedef typename boost::property_traits<IndexMap>::key_type key_type;
434 typedef T value_type;
435 typedef typename std::iterator_traits <
436 typename std::vector<T>::iterator >::reference reference;
437 typedef boost::lvalue_property_map_tag category;
438
439 public:
440
SubProperties(RefProperties & p,G & g)441 SubProperties(RefProperties& p, G& g)
442 : _properties(p), _g(g) {}
443
operator [](const key_type & v)444 reference operator[](const key_type& v)
445 {
446 return _properties[_g.descriptor0(v)];
447 }
448
449 };
450
451 template<typename T, typename G>
452 class VertexSubProperties : public SubProperties<T, G, typename G::VIndexAccess>
453 {
454 public:
455 typedef Properties<T, G, typename G::VIndexAccess> RefProperties;
456
VertexSubProperties(RefProperties & p,G & g)457 VertexSubProperties(RefProperties& p, G& g) : SubProperties<T, G, typename G::VIndexAccess>(p, g)
458 {};
459 };
460
461 template<typename T, typename G>
462 class EdgeSubProperties : public SubProperties<T, G, typename G::EIndexAccess>
463 {
464 public:
465 typedef Properties<T, G, typename G::EIndexAccess> RefProperties;
466
EdgeSubProperties(RefProperties & p,G & g)467 EdgeSubProperties(RefProperties& p, G& g) : SubProperties<T, G, typename G::EIndexAccess>(p, g)
468 {};
469 };
470
471
472 }
473
474 /* convenience macro for properties declarations */
475
476 #include <boost/preprocessor/seq/seq.hpp>
477 #include <boost/preprocessor/seq/for_each.hpp>
478 #include <boost/preprocessor/tuple/elem.hpp>
479 #include <boost/preprocessor/cat.hpp>
480
481 #define I_DECLARE_MEMBERS(r,gt,p) \
482 Siconos:: BOOST_PP_CAT(BOOST_PP_TUPLE_ELEM(3,0,p),Properties)< BOOST_PP_TUPLE_ELEM(3,1,p), BOOST_PP_CAT(_,gt)> BOOST_PP_TUPLE_ELEM(3,2,p);
483
484 #define I_CONS_MEMBERS(r,gt,p) \
485 BOOST_PP_TUPLE_ELEM(3,2,p) (Siconos:: BOOST_PP_CAT(BOOST_PP_TUPLE_ELEM(3,0,p),Properties)< BOOST_PP_TUPLE_ELEM(3,1,p), BOOST_PP_CAT(_,gt)>(*static_cast<BOOST_PP_CAT(_,gt)*>(this))),
486
487 #define INSTALL_GRAPH_PROPERTIES(GraphType, PROPERTIES) \
488 BOOST_PP_SEQ_FOR_EACH(I_DECLARE_MEMBERS, BOOST_PP_CAT(GraphType, Graph), PROPERTIES) \
489 bool dummy; \
490 \
491 BOOST_PP_CAT(GraphType, Graph)() : \
492 BOOST_PP_SEQ_FOR_EACH(I_CONS_MEMBERS, BOOST_PP_CAT(GraphType, Graph), PROPERTIES) dummy(true) {} \
493
494 #endif
495