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