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