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 #include <cassert>
34 #include <iostream>
35
36 #include "dart/common/Composite.hpp"
37 #include "dart/common/Console.hpp"
38
39 namespace dart {
40 namespace common {
41
42 //==============================================================================
43 /// Type maps are std::map containers which map an object's Type Info to some
44 /// instance or trait of that type. For example, an ObjectMap will map an
45 /// object's type to a std::unique_ptr of an instance of that object. a StateMap
46 /// will map an Object's type to a std::unique_ptr of a State instance for that
47 /// Object. Type maps are used for the dart::common::Aspect class.
48 ///
49 /// This function will move data from an Object instance into a container where
50 /// the data is sorted by the Object type that it belongs to. If the DataMap
51 /// that is being filled with data already has an instance of the data for a
52 /// particular Object type, it will perform a copy instead of a clone to improve
53 /// performance.
54 template <
55 typename ObjectType,
56 class DataType,
57 const DataType* (ObjectType::*getData)() const,
58 typename ObjectMap
59 = std::map<std::type_index, std::unique_ptr<ObjectType> >,
60 typename DataMap = std::map<std::type_index, std::unique_ptr<DataType> > >
extractDataFromObjectTypeMap(DataMap & dataMap,const ObjectMap & objectMap)61 static void extractDataFromObjectTypeMap(
62 DataMap& dataMap, const ObjectMap& objectMap)
63 {
64 // This method allows us to avoid dynamic allocation (cloning) whenever
65 // possible.
66 for (const auto& object : objectMap)
67 {
68 if (nullptr == object.second)
69 continue;
70
71 const DataType* data = (object.second.get()->*getData)();
72 if (data)
73 {
74 // Attempt to insert a nullptr to see whether this data exists while also
75 // creating an iterator to it if it did not already exist. This allows us
76 // to search for a spot in the data map once, instead of searching the map
77 // to see if the data entry already exists and then searching the map
78 // again in order to insert the entry if it didn't already exist.
79 std::pair<typename DataMap::iterator, bool> insertion
80 = dataMap.insert(typename DataMap::value_type(object.first, nullptr));
81
82 typename DataMap::iterator& it = insertion.first;
83 const bool existed = !insertion.second;
84
85 if (existed)
86 {
87 // The entry already existed
88 if (it->second)
89 {
90 // The entry was not a nullptr, so we can do an efficient copy
91 it->second->copy(*data);
92 }
93 else
94 {
95 // The entry was a nullptr, so we need to clone
96 it->second = data->clone();
97 }
98 }
99 else
100 {
101 // The entry did not already exist, so we need to clone
102 it->second = data->clone();
103 }
104 }
105 }
106 }
107
108 //==============================================================================
109 /// Type maps are std::map containers which map an object's Type Info to some
110 /// instance or trait of that type. For example, an ObjectMap will map an
111 /// object's type to a std::unique_ptr of an instance of that object. a StateMap
112 /// will map an Object's type to a std::unique_ptr of a State instance for that
113 /// Object. Type maps are used for the dart::common::Aspect class.
114 ///
115 /// This function will take a type map of Data and pass its contents into the
116 /// Objects contained in an ObjectMap for each corresponding Object type which
117 /// is available.
118 template <
119 typename ObjectType,
120 class DataType,
121 void (ObjectType::*setData)(const DataType&),
122 typename ObjectMap
123 = std::map<std::type_index, std::unique_ptr<ObjectType> >,
124 typename DataMap = std::map<std::type_index, std::unique_ptr<DataType> > >
setObjectsFromDataTypeMap(ObjectMap & objectMap,const DataMap & dataMap)125 static void setObjectsFromDataTypeMap(
126 ObjectMap& objectMap, const DataMap& dataMap)
127 {
128 typename ObjectMap::iterator objects = objectMap.begin();
129 typename DataMap::const_iterator data = dataMap.begin();
130
131 while (objectMap.end() != objects && dataMap.end() != data)
132 {
133 if (objects->first == data->first)
134 {
135 ObjectType* object = objects->second.get();
136 if (object && data->second)
137 (object->*setData)(*data->second);
138
139 ++objects;
140 ++data;
141 }
142 else if (objects->first < data->first)
143 {
144 ++objects;
145 }
146 else
147 {
148 ++data;
149 }
150 }
151 }
152
153 //==============================================================================
setCompositeState(const State & newStates)154 void Composite::setCompositeState(const State& newStates)
155 {
156 setObjectsFromDataTypeMap<Aspect, Aspect::State, &Aspect::setAspectState>(
157 mAspectMap, newStates.getMap());
158 }
159
160 //==============================================================================
getCompositeState() const161 Composite::State Composite::getCompositeState() const
162 {
163 State states;
164 copyCompositeStateTo(states);
165
166 return states;
167 }
168
169 //==============================================================================
copyCompositeStateTo(State & outgoingStates) const170 void Composite::copyCompositeStateTo(State& outgoingStates) const
171 {
172 auto& states = outgoingStates.getMap();
173 extractDataFromObjectTypeMap<Aspect, Aspect::State, &Aspect::getAspectState>(
174 states, mAspectMap);
175 }
176
177 //==============================================================================
setCompositeProperties(const Properties & newProperties)178 void Composite::setCompositeProperties(const Properties& newProperties)
179 {
180 setObjectsFromDataTypeMap<
181 Aspect,
182 Aspect::Properties,
183 &Aspect::setAspectProperties>(mAspectMap, newProperties.getMap());
184 }
185
186 //==============================================================================
getCompositeProperties() const187 Composite::Properties Composite::getCompositeProperties() const
188 {
189 Properties properties;
190 copyCompositePropertiesTo(properties);
191
192 return properties;
193 }
194
195 //==============================================================================
copyCompositePropertiesTo(Properties & outgoingProperties) const196 void Composite::copyCompositePropertiesTo(Properties& outgoingProperties) const
197 {
198 auto& properties = outgoingProperties.getMap();
199 extractDataFromObjectTypeMap<
200 Aspect,
201 Aspect::Properties,
202 &Aspect::getAspectProperties>(properties, mAspectMap);
203 }
204
205 //==============================================================================
duplicateAspects(const Composite * fromComposite)206 void Composite::duplicateAspects(const Composite* fromComposite)
207 {
208 if (nullptr == fromComposite)
209 {
210 dterr << "[Composite::duplicateAspects] You have asked to duplicate the "
211 << "Aspects of a nullptr, which is not allowed!\n";
212 assert(false);
213 return;
214 }
215
216 if (this == fromComposite)
217 return;
218
219 const AspectMap& otherMap = fromComposite->mAspectMap;
220
221 AspectMap::iterator receiving = mAspectMap.begin();
222 AspectMap::const_iterator incoming = otherMap.begin();
223
224 while (otherMap.end() != incoming)
225 {
226 if (mAspectMap.end() == receiving)
227 {
228 // If we've reached the end of this Composite's AspectMap, then we should
229 // just add each entry
230 _set(incoming->first, incoming->second.get());
231 ++incoming;
232 }
233 else if (receiving->first == incoming->first)
234 {
235 if (incoming->second)
236 _set(incoming->first, incoming->second.get());
237
238 ++receiving;
239 ++incoming;
240 }
241 else if (receiving->first < incoming->first)
242 {
243 ++receiving;
244 }
245 else
246 {
247 // If this Composite does not have an entry corresponding to the incoming
248 // Aspect, then we must create it
249 _set(incoming->first, incoming->second.get());
250 ++incoming;
251 }
252 }
253 }
254
255 //==============================================================================
matchAspects(const Composite * otherComposite)256 void Composite::matchAspects(const Composite* otherComposite)
257 {
258 if (nullptr == otherComposite)
259 {
260 dterr << "[Composite::matchAspects] You have asked to match the Aspects "
261 << "of a nullptr, which is not allowed!\n";
262 assert(false);
263 return;
264 }
265
266 for (auto& aspect : mAspectMap)
267 aspect.second = nullptr;
268
269 duplicateAspects(otherComposite);
270 }
271
272 //==============================================================================
addToComposite(Aspect * aspect)273 void Composite::addToComposite(Aspect* aspect)
274 {
275 if (aspect)
276 aspect->setComposite(this);
277 }
278
279 //==============================================================================
removeFromComposite(Aspect * aspect)280 void Composite::removeFromComposite(Aspect* aspect)
281 {
282 if (aspect)
283 aspect->loseComposite(this);
284 }
285
286 //==============================================================================
_set(std::type_index type_idx,const Aspect * aspect)287 void Composite::_set(std::type_index type_idx, const Aspect* aspect)
288 {
289 if (aspect)
290 {
291 mAspectMap[type_idx] = aspect->cloneAspect();
292 addToComposite(mAspectMap[type_idx].get());
293 }
294 else
295 {
296 mAspectMap[type_idx] = nullptr;
297 }
298 }
299
300 //==============================================================================
_set(std::type_index type_idx,std::unique_ptr<Aspect> aspect)301 void Composite::_set(std::type_index type_idx, std::unique_ptr<Aspect> aspect)
302 {
303 mAspectMap[type_idx] = std::move(aspect);
304 addToComposite(mAspectMap[type_idx].get());
305 }
306
307 } // namespace common
308 } // namespace dart
309