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