1 /*
2  * Copyright (c) 2011-2021, The DART development contributors
3  * All rights reserved.
4  *
5  * The list of contributors can be found at:
6  *   https://github.com/dartsim/dart/blob/master/LICENSE
7  *
8  * This file is provided under the following "BSD-style" License:
9  *   Redistribution and use in source and binary forms, with or
10  *   without modification, are permitted provided that the following
11  *   conditions are met:
12  *   * Redistributions of source code must retain the above copyright
13  *     notice, this list of conditions and the following disclaimer.
14  *   * Redistributions in binary form must reproduce the above
15  *     copyright notice, this list of conditions and the following
16  *     disclaimer in the documentation and/or other materials provided
17  *     with the distribution.
18  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
19  *   CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
20  *   INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
21  *   MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22  *   DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
23  *   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
26  *   USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
27  *   AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  *   LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
29  *   ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  *   POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 #ifndef DART_COMMON_DETAIL_COMPOSITE_HPP_
34 #define DART_COMMON_DETAIL_COMPOSITE_HPP_
35 
36 #include "dart/common/Composite.hpp"
37 
38 #define DART_COMMON_CHECK_ILLEGAL_ASPECT_ERASE(Func, T, ReturnType)            \
39   if (requiresAspect<T>())                                                     \
40   {                                                                            \
41     dterr << "[Composite::" #Func << "] Illegal request to remove required "   \
42           << "Aspect [" << typeid(T).name() << "]!\n";                         \
43     assert(false);                                                             \
44     return ReturnType;                                                         \
45   }
46 
47 namespace dart {
48 namespace common {
49 
50 //==============================================================================
51 template <class T>
has() const52 bool Composite::has() const
53 {
54   return (get<T>() != nullptr);
55 }
56 
57 //==============================================================================
58 template <class T>
get()59 T* Composite::get()
60 {
61   AspectMap::iterator it = mAspectMap.find(typeid(T));
62   if (mAspectMap.end() == it)
63     return nullptr;
64 
65   return static_cast<T*>(it->second.get());
66 }
67 
68 //==============================================================================
69 template <class T>
get() const70 const T* Composite::get() const
71 {
72   return const_cast<Composite*>(this)->get<T>();
73 }
74 
75 //==============================================================================
76 template <class T>
set(const T * aspect)77 void Composite::set(const T* aspect)
78 {
79   _set(typeid(T), aspect);
80 }
81 
82 //==============================================================================
83 template <class T>
set(std::unique_ptr<T> && aspect)84 void Composite::set(std::unique_ptr<T>&& aspect)
85 {
86   _set(typeid(T), std::move(aspect));
87 }
88 
89 //==============================================================================
90 template <class T, typename... Args>
91 T* Composite::createAspect(Args&&... args)
92 {
93   T* aspect = new T(std::forward<Args>(args)...);
94   mAspectMap[typeid(T)] = std::unique_ptr<T>(aspect);
95   addToComposite(aspect);
96 
97   return aspect;
98 }
99 
100 //==============================================================================
101 template <class T>
removeAspect()102 void Composite::removeAspect()
103 {
104   AspectMap::iterator it = mAspectMap.find(typeid(T));
105   DART_COMMON_CHECK_ILLEGAL_ASPECT_ERASE(removeAspect, T, DART_BLANK)
106   if (mAspectMap.end() != it)
107   {
108     removeFromComposite(it->second.get());
109     it->second = nullptr;
110   }
111 }
112 
113 //==============================================================================
114 template <class T>
releaseAspect()115 std::unique_ptr<T> Composite::releaseAspect()
116 {
117   std::unique_ptr<T> extraction = nullptr;
118   AspectMap::iterator it = mAspectMap.find(typeid(T));
119   DART_COMMON_CHECK_ILLEGAL_ASPECT_ERASE(releaseAspect, T, nullptr)
120   if (mAspectMap.end() != it)
121   {
122     removeFromComposite(it->second.get());
123     extraction = std::unique_ptr<T>(static_cast<T*>(it->second.release()));
124   }
125 
126   return extraction;
127 }
128 
129 //==============================================================================
130 template <class T>
isSpecializedFor()131 constexpr bool Composite::isSpecializedFor()
132 {
133   return false;
134 }
135 
136 //==============================================================================
137 template <class T>
requiresAspect() const138 bool Composite::requiresAspect() const
139 {
140   return (mRequiredAspects.find(typeid(T)) != mRequiredAspects.end());
141 }
142 
143 //==============================================================================
144 template <class T>
createAspects(T *)145 void createAspects(T* /*comp*/)
146 {
147   // Do nothing
148 }
149 
150 //==============================================================================
151 template <class T, class NextAspect, class... Aspects>
createAspects(T * comp)152 void createAspects(T* comp)
153 {
154   comp->template createAspect<NextAspect>();
155 
156   createAspects<T, Aspects...>(comp);
157 }
158 
159 } // namespace common
160 } // namespace dart
161 
162 //==============================================================================
163 // Create non-template alternatives to Composite functions
164 #define DART_BAKE_SPECIALIZED_ASPECT_IRREGULAR(TypeName, AspectName)           \
165   /** Check if this Composite currently has AspectName. */                     \
166   inline bool has##AspectName() const                                          \
167   {                                                                            \
168     return this->template has<TypeName>();                                     \
169   }                                                                            \
170                                                                                \
171   /** Get a(an) AspectName from this Composite. */                             \
172   inline TypeName* get##AspectName()                                           \
173   {                                                                            \
174     return this->template get<TypeName>();                                     \
175   }                                                                            \
176                                                                                \
177   /** Get a(an) AspectName from this Composite. */                             \
178   inline const TypeName* get##AspectName() const                               \
179   {                                                                            \
180     return this->template get<TypeName>();                                     \
181   }                                                                            \
182                                                                                \
183   /**                                                                          \
184     Get a(an) AspectName from this Composite. If _createIfNull is true, then   \
185     a(an) AspectName will be generated if one does not already exist.          \
186    */                                                                          \
187   inline TypeName* get##AspectName(const bool createIfNull)                    \
188   {                                                                            \
189     TypeName* aspect = get##AspectName();                                      \
190                                                                                \
191     if (createIfNull && nullptr == aspect)                                     \
192       return create##AspectName();                                             \
193                                                                                \
194     return aspect;                                                             \
195   }                                                                            \
196                                                                                \
197   /**                                                                          \
198     Make a clone of AspectName and place the clone into this Composite. If     \
199     a(an) AspectName already exists in this Composite, the existing AspectName \
200     will be destroyed.                                                         \
201    */                                                                          \
202   inline void set##AspectName(const TypeName* aspect)                          \
203   {                                                                            \
204     this->template set<TypeName>(aspect);                                      \
205   }                                                                            \
206                                                                                \
207   /**                                                                          \
208     Use move semantics to place AspectName into this Composite. If a(an)       \
209     AspectName already exists in this Composite, the existing AspectName will  \
210     be destroyed.                                                              \
211    */                                                                          \
212   inline void set##AspectName(std::unique_ptr<TypeName>&& aspect)              \
213   {                                                                            \
214     this->template set<TypeName>(std::move(aspect));                           \
215   }                                                                            \
216                                                                                \
217   /** Construct a(an) AspectName inside of this Composite. */                  \
218   template <typename... Args>                                                  \
219   inline TypeName* create##AspectName(Args&&... args)                          \
220   {                                                                            \
221     return this->template createAspect<TypeName>(std::forward<Args>(args)...); \
222   }                                                                            \
223                                                                                \
224   /** Remove a(an) AspectName from this Composite. */                          \
225   inline void remove##AspectName()                                             \
226   {                                                                            \
227     this->template removeAspect<TypeName>();                                   \
228   }                                                                            \
229                                                                                \
230   /**                                                                          \
231     Remove a(an) AspectName from this Composite, but return its unique_ptr     \
232     instead of letting it be deleted. This allows you to safely use move       \
233     semantics to transfer a(an) AspectName between two Composites.             \
234    */                                                                          \
235   inline std::unique_ptr<TypeName> release##AspectName()                       \
236   {                                                                            \
237     return this->template releaseAspect<TypeName>();                           \
238   }
239 
240 //==============================================================================
241 #define DART_BAKE_SPECIALIZED_ASPECT(AspectName)                               \
242   DART_BAKE_SPECIALIZED_ASPECT_IRREGULAR(AspectName, AspectName);
243 
244 #endif // DART_COMMON_DETAIL_COMPOSITE_HPP_
245