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