1 /*
2  Copyright (c) 2008-2020, Benoit AUTHEMAN All rights reserved.
3 
4  Redistribution and use in source and binary forms, with or without
5  modification, are permitted provided that the following conditions are met:
6     * Redistributions of source code must retain the above copyright
7       notice, this list of conditions and the following disclaimer.
8     * Redistributions in binary form must reproduce the above copyright
9       notice, this list of conditions and the following disclaimer in the
10       documentation and/or other materials provided with the distribution.
11     * Neither the name of the author or Destrat.io nor the
12       names of its contributors may be used to endorse or promote products
13       derived from this software without specific prior written permission.
14 
15  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
16  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18  DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY
19  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26 
27 //-----------------------------------------------------------------------------
28 // This file is a part of the GTpo software library.
29 //
30 // \file	graph_behaviour.h
31 // \author	benoit@destrat.io
32 // \date	2017 03 09
33 //-----------------------------------------------------------------------------
34 
35 #pragma once
36 
37 // GTpo headers
38 #include "./behaviour.h"
39 #include "./node.h"
40 #include "./edge.h"
41 
42 namespace gtpo { // ::gtpo
43 
44 /*! \brief Define an observer interface to catch changes in a gtpo::graph.
45  *
46  */
47 template < class config_t >
48 class graph_behaviour :  public gtpo::behaviour<gtpo::graph<config_t>>
49 {
50 public:
graph_behaviour()51     graph_behaviour() noexcept : gtpo::behaviour<gtpo::graph<config_t>>{} {}
52     ~graph_behaviour() noexcept = default;
53     graph_behaviour( const graph_behaviour<config_t>& ) = delete;
54     graph_behaviour& operator=( const graph_behaviour<config_t>& ) = delete;
55 
56     using weak_node_t      = std::weak_ptr<typename config_t::final_node_t>;
57     using weak_edge_t      = std::weak_ptr<typename config_t::final_edge_t>;
58 
59     /*! \name Graph Notification Interface *///--------------------------------
60     //@{
61 public:
62     //! Called immediatly after node \c weakNode has been inserted in graph.
node_inserted(weak_node_t & weakNode)63     void    node_inserted( weak_node_t& weakNode ) noexcept { static_cast<void>(weakNode); }
64     //! Called immediatly before node \c weakNode is removed from graph.
node_removed(weak_node_t & weakNode)65     void    node_removed( weak_node_t& weakNode) noexcept { static_cast<void>(weakNode); }
66 
67 public:
68     //! Called immediatly after group \c weakGroup has been inserted in graph.
group_inserted(weak_node_t & weakGroup)69     void    group_inserted( weak_node_t& weakGroup ) noexcept { static_cast<void>(weakGroup); }
70     //! Called immediatly before group \c weakGroup is removed from graph.
group_removed(weak_node_t & weakGroup)71     void    group_removed( weak_node_t& weakGroup ) noexcept { static_cast<void>(weakGroup); }
72 
73 public:
74     //! Called immediatly after \c weakEdge has been inserted.
edge_inserted(weak_edge_t & weakEdge)75     void    edge_inserted( weak_edge_t& weakEdge ) noexcept { static_cast<void>(weakEdge); }
76     //! Called when \c weakEdge is about to be removed.
edge_removed(weak_edge_t & weakEdge)77     void    edge_removed( weak_edge_t& weakEdge ) noexcept { static_cast<void>(weakEdge); }
78     //@}
79     //-------------------------------------------------------------------------
80 };
81 
82 /*! \brief Abstract interface for dynamic (virtual) graph behaviours.
83  *
84  */
85 template < class config_t >
86 class dynamic_graph_behaviour :  public graph_behaviour<config_t>
87 {
88 public:
dynamic_graph_behaviour()89     dynamic_graph_behaviour() noexcept : graph_behaviour<config_t>{} {}
90     virtual ~dynamic_graph_behaviour() noexcept = default;
91     dynamic_graph_behaviour( const dynamic_graph_behaviour<config_t>& ) = delete;
92     dynamic_graph_behaviour& operator=( const dynamic_graph_behaviour<config_t>& ) = delete;
93     dynamic_graph_behaviour( dynamic_graph_behaviour<config_t>&& ) = default;
94     dynamic_graph_behaviour& operator=( dynamic_graph_behaviour<config_t>&& ) = default;
95 
96     using weak_node_t      = std::weak_ptr<typename config_t::final_node_t>;
97     using weak_edge_t      = std::weak_ptr<typename config_t::final_edge_t>;
98 
99 public:
node_inserted(weak_node_t & weakNode)100     void    node_inserted( weak_node_t& weakNode ) noexcept { on_node_inserted(weakNode); }
node_removed(weak_node_t & weakNode)101     void    node_removed( weak_node_t& weakNode) noexcept { on_node_removed(weakNode); }
group_inserted(weak_node_t & weakGroup)102     void    group_inserted( weak_node_t& weakGroup ) noexcept { on_group_inserted(weakGroup); }
group_removed(weak_node_t & weakGroup)103     void    group_removed( weak_node_t& weakGroup ) noexcept { on_group_removed(weakGroup); }
edge_inserted(weak_edge_t & weakEdge)104     void    edge_inserted( weak_edge_t& weakEdge ) noexcept { on_edge_inserted(weakEdge); }
edge_removed(weak_edge_t & weakEdge)105     void    edge_removed( weak_edge_t& weakEdge ) noexcept { on_edge_removed(weakEdge); }
106 
107     /*! \name Graph Dynamic (virtual) Notification Interface *///--------------
108     //@{
109 protected:
110     //! Called immediatly after node \c weakNode has been inserted in graph.
on_node_inserted(weak_node_t & weakNode)111     virtual void    on_node_inserted( weak_node_t& weakNode ) noexcept { static_cast<void>(weakNode); }
112     //! Called immediatly before node \c weakNode is removed from graph.
on_node_removed(weak_node_t & weakNode)113     virtual void    on_node_removed( weak_node_t& weakNode) noexcept { static_cast<void>(weakNode); }
114 
115     //! Called immediatly after group \c weakGroup has been inserted in graph.
on_group_inserted(weak_node_t & weakGroup)116     virtual void    on_group_inserted( weak_node_t& weakGroup ) noexcept { static_cast<void>(weakGroup); }
117     //! Called immediatly before group \c weakGroup is removed from graph.
on_group_removed(weak_node_t & weakGroup)118     virtual void    on_group_removed( weak_node_t& weakGroup ) noexcept { static_cast<void>(weakGroup); }
119 
120 protected:
121     //! Called immediatly after \c weakEdge has been inserted.
on_edge_inserted(weak_edge_t & weakEdge)122     virtual void    on_edge_inserted( weak_edge_t& weakEdge ) noexcept { static_cast<void>(weakEdge); }
123     //! Called when \c weakEdge is about to be removed.
on_edge_removed(weak_edge_t & weakEdge)124     virtual void    on_edge_removed( weak_edge_t& weakEdge ) noexcept { static_cast<void>(weakEdge); }
125     //@}
126     //-------------------------------------------------------------------------
127 };
128 
129 
130 /*! \brief Enable dynamic behaviour (observers) on gtpo::Graph<>.
131  *
132  * \note Add enable_graph_behaviour<> to gtpo::config::graph_behaviours tuple to enable dynamic
133  * graph behaviours, otherwise, any gtpo::dynamic_graph_behaviour added using gtpo::graph::add_dynamic_graph_behaviour()
134  * method won't be notified of changes in topology.
135  */
136 template < class config_t >
137 class enable_graph_dynamic_behaviour :  public gtpo::graph_behaviour<config_t>
138 {
139 public:
enable_graph_dynamic_behaviour()140     enable_graph_dynamic_behaviour() noexcept : gtpo::graph_behaviour<config_t>{} {}
141     ~enable_graph_dynamic_behaviour() noexcept = default;
142     enable_graph_dynamic_behaviour( const enable_graph_dynamic_behaviour<config_t>& ) = delete;
143     enable_graph_dynamic_behaviour& operator=( const enable_graph_dynamic_behaviour<config_t>& ) = delete;
144 
145     using weak_node_t      = std::weak_ptr<typename config_t::final_node_t>;
146     using weak_edge_t      = std::weak_ptr<typename config_t::final_edge_t>;
147 
148 public:
149     template < class primitive_t >
150     auto get_primitive_graph(std::weak_ptr<primitive_t>& weak_primitive) -> gtpo::graph<config_t>*
151     {
152         auto primitive = weak_primitive.lock();
153         return ( primitive ? primitive->get_graph() : nullptr );
154     }
155 
node_inserted(weak_node_t & weakNode)156     void    node_inserted( weak_node_t& weakNode ) noexcept {
157         const auto graph = get_primitive_graph(weakNode);
158         if ( graph != nullptr )
159             graph->notify_dynamic_behaviours( &dynamic_graph_behaviour<config_t>::node_inserted, weakNode );
160     }
node_removed(weak_node_t & weakNode)161     void    node_removed( weak_node_t& weakNode) noexcept {
162         const auto graph = get_primitive_graph(weakNode);
163         if ( graph != nullptr )
164             graph->notify_dynamic_behaviours( &dynamic_graph_behaviour<config_t>::node_removed, weakNode );
165     }
group_inserted(weak_node_t & weakGroup)166     void    group_inserted( weak_node_t& weakGroup ) noexcept {
167         const auto graph = get_primitive_graph(weakGroup);
168         if ( graph != nullptr )
169             graph->notify_dynamic_behaviours( &dynamic_graph_behaviour<config_t>::group_inserted, weakGroup );
170     }
group_removed(weak_node_t & weakGroup)171     void    group_removed( weak_node_t& weakGroup ) noexcept {
172         const auto graph = get_primitive_graph(weakGroup);
173         if ( graph != nullptr )
174             graph->notify_dynamic_behaviours( &dynamic_graph_behaviour<config_t>::group_removed, weakGroup );
175     }
edge_inserted(weak_edge_t & weakEdge)176     void    edge_inserted( weak_edge_t& weakEdge ) noexcept {
177         const auto graph = get_primitive_graph(weakEdge);
178         if ( graph != nullptr )
179             graph->notify_dynamic_behaviours( &dynamic_graph_behaviour<config_t>::edge_inserted, weakEdge );
180     }
edge_removed(weak_edge_t & weakEdge)181     void    edge_removed( weak_edge_t& weakEdge ) noexcept {
182         const auto graph = get_primitive_graph(weakEdge);
183         if ( graph != nullptr )
184             graph->notify_dynamic_behaviours( &dynamic_graph_behaviour<config_t>::edge_removed, weakEdge );
185     }
186     //@}
187     //-------------------------------------------------------------------------
188 };
189 
190 /*! \brief Enable static and dynamic behaviour support for gtpo::Graph.
191  *
192  * \nosubgrouping
193  */
194 template <class config_t>
195 class behaviourable_graph : public behaviourable<dynamic_graph_behaviour<config_t>,
196                                                  typename config_t::graph_behaviours
197                                                 > // gtpo::behaviourable<>
198 {
199     /*! \name behaviourable_graph Object Management *///------------------------
200     //@{
201 public:
202     friend enable_graph_dynamic_behaviour<config_t>;   // enable_graph_dynamic_behaviour<> need access to notify_dynamic_behaviours
203 
204     using dynamic_graph_behaviour_t = dynamic_graph_behaviour<config_t>;
205     using graph_static_behaviours_t = typename config_t::graph_behaviours;
206     using behaviourable_base = behaviourable<dynamic_graph_behaviour<config_t>, typename config_t::graph_behaviours>;
207 
behaviourable_graph()208     behaviourable_graph() : behaviourable_base{} { }
~behaviourable_graph()209     ~behaviourable_graph() noexcept { /* Nil */ }
210     behaviourable_graph( const behaviourable_graph<config_t>& ) = delete;
211     behaviourable_graph& operator=( const behaviourable_graph<config_t>& ) = delete;
212     //@}
213     //-------------------------------------------------------------------------
214 
215     /*! \name Notification Helper Methods *///---------------------------------
216     //@{
217 public:
218     inline auto     add_dynamic_graph_behaviour( std::unique_ptr<dynamic_graph_behaviour_t> behaviour ) -> void {
219         behaviourable<dynamic_graph_behaviour_t, graph_static_behaviours_t>::add_behaviour(std::move(behaviour));
220     }
221 
222     template < class node_t >
223     auto    notify_node_inserted( node_t& node ) noexcept -> void;
224 
225     template < class node_t >
226     auto    notify_node_removed( node_t& node ) noexcept -> void;
227 
228     template < class edge_t >
229     auto    notify_edge_inserted( edge_t& node ) noexcept -> void;
230 
231     template < class edge_t >
232     auto    notify_edge_removed( edge_t& node ) noexcept -> void;
233 
234     template < class group_t >
235     auto    notify_group_inserted( group_t& group ) noexcept -> void;
236 
237     template < class group_t >
238     auto    notify_group_removed( group_t& group ) noexcept -> void;
239     //@}
240     //-------------------------------------------------------------------------
241 };
242 
243 } // ::gtpo
244 
245 #include "./graph_behaviour.hpp"
246