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	behaviourable.h
31 // \author	benoit@destrat.io
32 // \date	2016 02 08
33 //-----------------------------------------------------------------------------
34 
35 #ifndef gtpo_behaviourable_h
36 #define gtpo_behaviourable_h
37 
38 // STD headers
39 #include <cstddef>          // std::size_t
40 #include <functional>       // std::function
41 #include <vector>
42 #include <memory>
43 #include <utility>          // c++14 std::index_sequence
44 
45 // GTpo headers
46 #include "./behaviour.h"
47 
48 namespace gtpo { // ::gtpo
49 
50 namespace impl { // ::gtpo::impl
51 
52 // C++14 O(N log(N)) copied from: http://stackoverflow.com/a/26902803
53 // There is more complex O(N) solutions available on SO
54 template< class F, class...Ts, std::size_t...Is >
for_each_in_tuple(std::tuple<Ts...> & tuple,F func,std::index_sequence<Is...>)55 void for_each_in_tuple( std::tuple<Ts...> & tuple, F func, std::index_sequence<Is...> ) noexcept {
56     (void)tuple; // Avoid C4100 warning for size 1 std::tuple with MSVC2015 U2
57     (void)func;  // Avoid C4100 warning for size 1 std::tuple with MSVC2015 U2
58     using expander = int[];
59     (void)expander { 0, ((void)func(std::get<Is>(tuple)), 0)... };
60 }
61 
62 template< class F, class...Ts >
for_each_in_tuple(std::tuple<Ts...> & tuple,F func)63 void for_each_in_tuple( std::tuple<Ts...>& tuple, F func ) noexcept {
64     for_each_in_tuple( tuple, func, std::make_index_sequence<sizeof...(Ts)>() );
65 }
66 
67 } // ::gtpo::impl
68 
69 /*! \brief Empty interface definition for graph primitives supporting behaviour concept.
70  */
71 class abstract_behaviourable {
72 public:
abstract_behaviourable()73     abstract_behaviourable() {}
74     ~abstract_behaviourable() = default;
75 
76     abstract_behaviourable( const abstract_behaviourable& ) = default;
77     abstract_behaviourable& operator=( const abstract_behaviourable& ) = default;
78     abstract_behaviourable( abstract_behaviourable&& ) = default;
79     abstract_behaviourable& operator=( abstract_behaviourable&& ) = default;
80 };
81 
82 /*! \brief Base class for all type supporting behaviours (actually gtpo::graph and gtpo::group).
83  *
84  * \nosubgrouping
85  */
86 template < class behaviour_t, typename static_behaviours_t >
87 class behaviourable : public abstract_behaviourable
88 {
89     /*! \name behaviourable Object Management *///-----------------------------
90     //@{
91 public:
behaviourable()92     behaviourable() : abstract_behaviourable() { }
~behaviourable()93     ~behaviourable() noexcept { _dynamic_behaviours.clear(); }
94     behaviourable( const behaviourable<behaviour_t, static_behaviours_t>& ) = default;
95     behaviourable& operator=( const behaviourable<behaviour_t, static_behaviours_t>& ) = default;
96 
97 public:
98     //! Clear all registered behaviours (they are automatically deleted).
99     inline  auto    clear() -> void { _dynamic_behaviours.clear(); }
100     //@}
101     //-------------------------------------------------------------------------
102 
103     /*! \name Dynamic (virtual) Behaviours Management *///---------------------
104     //@{
105 public:
106     /*! \brief Add a behaviour to the primitive inheriting from this behaviourable (observable) interface.
107      *
108      * \note This is a sink method, Behaviourable get ownership for \c behaviour, since it is
109      * difficult to "downcast" unique_ptr, use the following code for calling:
110      * \code
111      *   gtpo::graph<> sg;
112      *   sg.addBehaviour( std::make_unique< MyBehaviour >( ) );
113      * \endcode
114      */
115     inline auto     add_behaviour( std::unique_ptr<behaviour_t> behaviour ) -> void {
116         _dynamic_behaviours.emplace_back( std::move( behaviour ) );
117     }
118 
119     //! std::vector of std::unique_ptr pointers on behaviour.
120     using behaviours_t = std::vector<std::unique_ptr<behaviour_t>>;
121 
122 public:
123     //! Return true if a behaviours is currently registered (ie getBehaviours().size()>0).
124     inline auto    hasBehaviours() const noexcept -> bool { return _dynamic_behaviours.size() > 0; }
125 
126     //! Return a read only container of actually registered behaviours.
127     inline auto    getBehaviours() const noexcept -> const behaviours_t& { return _dynamic_behaviours; }
128 
129 protected:
130     /*! \brief Call a pointer on a method on all registered dynamic behaviours.
131      *
132      * Example use:
133      * \code
134      *    // For a given node_behaviour method: auto    notifyNodeModified( weak_node_t& node ) -> void;
135      *    notify_behaviours< weak_node_t >( &behaviour::nodeModified, node );
136      * \endcode
137      */
138     template < class T >
139     auto    notify_dynamic_behaviours( void (behaviour_t::*method)(T&) /*noexcept*/, T& arg ) noexcept -> void;
140 
141     template < class T, class T2 >
142     auto    notify_dynamic_behaviours( void (behaviour_t::*method)(T&, T2&) /*noexcept*/, T& arg, T2&) noexcept -> void;
143 
144     template < class T, class T2, class T3 >
145     auto    notify_dynamic_behaviours( void (behaviour_t::*method)(T&, T2&, const T3&) /*noexcept*/, T&, T2&, const T3&) noexcept -> void;
146 
147     //! Similar to notifyBahaviours() but without arguments.
148     auto    notify_dynamic_behaviours0( void (behaviour_t::*method)() /*noexcept*/ ) noexcept -> void;
149 
150 private:
151     behaviours_t    _dynamic_behaviours;
152     //@}
153     //-------------------------------------------------------------------------
154 
155     /*! \name Static Behaviours Management *///--------------------------------
156     //@{
157 public:
158     /*! \brief Apply a functor on all registered static behaviours.
159      *
160      * Example use:
161      * \code
162      * \endcode
163      */
164     template < class Functor >
165     auto    notify_static_behaviours( Functor f ) noexcept -> void {
166         impl::for_each_in_tuple( _static_behaviours, f );
167     }
168 
169 private:
170     static_behaviours_t _static_behaviours;
171     //@}
172     //-------------------------------------------------------------------------
173 };
174 
175 } // ::gtpo
176 
177 #include "./behaviourable.hpp"
178 
179 #endif // gtpo_behaviourable_h
180