1 #ifndef _Object_Map_h_
2 #define _Object_Map_h_
3
4
5 #include <boost/range/any_range.hpp>
6 #include <boost/range/size.hpp>
7 #include <boost/range/adaptor/map.hpp>
8 #include <boost/serialization/access.hpp>
9
10 #include "../util/Export.h"
11
12 #include <map>
13 #include <memory>
14 #include <set>
15 #include <string>
16 #include <vector>
17 #include <type_traits>
18
19
20 struct UniverseObjectVisitor;
21
22 class UniverseObject;
23 class ResourceCenter;
24 class PopCenter;
25 class Ship;
26 class Fleet;
27 class Planet;
28 class System;
29 class Building;
30 class Field;
31
32 FO_COMMON_API extern const int ALL_EMPIRES;
33
34
35 /** Contains a set of objects that make up a (known or complete) Universe. */
36 class FO_COMMON_API ObjectMap {
37 public:
38 template <typename T>
39 using container_type = std::map<int, std::shared_ptr<T>>;
40
41 /** \name Structors */ //@{
42 ObjectMap();
43 ~ObjectMap();
44
45 /** Copies contents of this ObjectMap to a new ObjectMap, which is
46 * returned. Copies are limited to only duplicate information that the
47 * empire with id \a empire_id would know about the copied objects. */
48 ObjectMap* Clone(int empire_id = ALL_EMPIRES) const;
49 //@}
50
51 /** \name Accessors */ //@{
52 /** Returns the number of objects of the specified class in this ObjectMap. */
53 template <typename T = UniverseObject>
54 std::size_t size() const;
55
56 /** Returns true if this ObjectMap contains no objects */
57 bool empty() const;
58
59 /** Returns a pointer to the object of type T with ID number \a id.
60 * Returns a null std::shared_ptr if none exists or the object with
61 * ID \a id is not of type T. */
62 template <typename T = UniverseObject>
63 std::shared_ptr<const T> get(int id) const;
64
65 /** Returns a pointer to the object of type T with ID number \a id.
66 * Returns a null std::shared_ptr if none exists or the object with
67 * ID \a id is not of type T. */
68 template <typename T = UniverseObject>
69 std::shared_ptr<T> get(int id);
70
71 using id_range = boost::any_range<int, boost::forward_traversal_tag>;
72
73 /** Returns a vector containing the objects with ids in \a object_ids that
74 * are of type T */
75 template <typename T = UniverseObject>
76 std::vector<std::shared_ptr<const T>> find(const id_range& object_ids) const;
77
78 /** Returns a vector containing the objects with ids in \a object_ids that
79 * are of type T */
80 template <typename T = UniverseObject>
81 std::vector<std::shared_ptr<T>> find(const id_range& object_ids);
82
83 /** Returns all the objects that match \a visitor */
84 template <typename T = UniverseObject>
85 std::vector<std::shared_ptr<const T>> find(const UniverseObjectVisitor& visitor) const;
86
87 /** Returns all the objects that match \a visitor */
88 template <typename T = UniverseObject>
89 std::vector<std::shared_ptr<T>> find(const UniverseObjectVisitor& visitor);
90
91 /** Returns all the objects of type T */
92 template <typename T = UniverseObject>
all()93 boost::select_second_const_range<container_type<T>> all() const
94 { return Map<T>() | boost::adaptors::map_values; }
95
96 /** Returns all the objects of type T */
97 template <typename T = UniverseObject>
all()98 boost::select_second_mutable_range<container_type<T>> all()
99 { return Map<T>() | boost::adaptors::map_values; }
100
101 /** Returns the IDs of all objects not known to have been destroyed. */
102 std::vector<int> FindExistingObjectIDs() const;
103
104 /** Returns highest used object ID in this ObjectMap */
105 int HighestObjectID() const;
106
107 std::string Dump(unsigned short ntabs = 0) const;
108
109 /** */
110 std::shared_ptr<const UniverseObject> ExistingObject(int id) const;
111
ExistingObjects()112 const container_type<const UniverseObject>& ExistingObjects() const
113 { return m_existing_objects; }
ExistingResourceCenters()114 const container_type<const UniverseObject>& ExistingResourceCenters() const
115 { return m_existing_resource_centers; }
ExistingPopCenters()116 const container_type<const UniverseObject>& ExistingPopCenters() const
117 { return m_existing_pop_centers; }
ExistingShips()118 const container_type<const UniverseObject>& ExistingShips() const
119 { return m_existing_ships; }
ExistingFleets()120 const container_type<const UniverseObject>& ExistingFleets() const
121 { return m_existing_fleets; }
ExistingPlanets()122 const container_type<const UniverseObject>& ExistingPlanets() const
123 { return m_existing_planets; }
ExistingSystems()124 const container_type<const UniverseObject>& ExistingSystems() const
125 { return m_existing_systems; }
ExistingBuildings()126 const container_type<const UniverseObject>& ExistingBuildings() const
127 { return m_existing_buildings; }
ExistingFields()128 const container_type<const UniverseObject>& ExistingFields() const
129 { return m_existing_fields; }
130 //@}
131
132 /** \name Mutators */ //@{
133
134 /** Copies the contents of the ObjectMap \a copied_map into this ObjectMap.
135 * Each object in \a copied_map has information transferred to this map.
136 * If there already is a version of an object in \a copied_map in this map
137 * then information is copied onto this map's version of the object using
138 * the UniverseObject::Copy function. If there is no corresponding object
139 * in this map, a new object is created using the UinverseObject::Clone
140 * function. The copied objects are complete copies if \a empire_id is
141 * ALL_EMPIRES, but if another \a empire_id is specified, the copied
142 * information is limited by passing \a empire_id to are limited to the
143 * Copy or Clone functions of the copied UniverseObjects. Any objects
144 * in this ObjectMap that have no corresponding object in \a copied_map
145 * are left unchanged. */
146 void Copy(const ObjectMap& copied_map, int empire_id = ALL_EMPIRES);
147
148 /** Copies the contents of the ObjectMap \a copied_map into this ObjectMap, in
149 * preparation for serializing this ObjectMap. The normal object-by-object
150 * CopyObject process is bypassed and only m_objects is copied, in a direct fashion. */
151 void CopyForSerialize(const ObjectMap& copied_map);
152
153 /** Copies the passed \a object into this ObjectMap, overwriting any
154 * existing information about that object or creating a new object in this
155 * map as appropriate with UniverseObject::Copy or UniverseObject::Clone.
156 * The object is fully copied if \a empire_id is ALL_EMPIRES, but if
157 * another empire id is specified, then the copied information is limited
158 * by passing the visibility of the object by the empire specified by
159 * \a empire_id to Copy or Clone of the object. The passed object is
160 * unchanged. */
161 void CopyObject(std::shared_ptr<const UniverseObject> source, int empire_id = ALL_EMPIRES);
162
163 /** Adds object \a obj to the map under its ID, if it is a valid object.
164 * If there already was an object in the map with the id \a id then
165 * that object will be removed. */
166 template <typename T>
167 void insert(std::shared_ptr<T> obj, int empire_id = ALL_EMPIRES);
168
169 /** Removes object with id \a id from map, and returns that object, if
170 * there was an object under that ID in the map. If no such object
171 * existed in the map, a null shared_ptr is returned and nothing is
172 * removed. The ObjectMap will no longer share ownership of the
173 * returned object. */
174 std::shared_ptr<UniverseObject> erase(int id);
175
176 /** Empties map, removing shared ownership by this map of all
177 * previously contained objects. */
178 void clear();
179
180 /** Swaps the contents of *this with \a rhs. */
181 void swap(ObjectMap& rhs);
182
183 /** */
184 void UpdateCurrentDestroyedObjects(const std::set<int>& destroyed_object_ids);
185
186 /** Recalculates contained objects for all objects in this ObjectMap based
187 * on what other objects exist in this ObjectMap. Useful to eliminate
188 * cases where there are inconsistencies between whan an object thinks it
189 * contains, and what other objects think they are contained by the first
190 * object. */
191 void AuditContainment(const std::set<int>& destroyed_object_ids);
192 //@}
193
194 private:
195 void insertCore(std::shared_ptr<UniverseObject> item, int empire_id = ALL_EMPIRES);
196
197 void CopyObjectsToSpecializedMaps();
198
199 template <typename T>
200 const container_type<T>& Map() const;
201
202 template <typename T>
203 container_type<T>& Map();
204
205 template <typename T>
206 static void SwapMap(container_type<T>& map, ObjectMap& rhs);
207
208 container_type<UniverseObject> m_objects;
209 container_type<ResourceCenter> m_resource_centers;
210 container_type<PopCenter> m_pop_centers;
211 container_type<Ship> m_ships;
212 container_type<Fleet> m_fleets;
213 container_type<Planet> m_planets;
214 container_type<System> m_systems;
215 container_type<Building> m_buildings;
216 container_type<Field> m_fields;
217
218 container_type<const UniverseObject> m_existing_objects;
219 container_type<const UniverseObject> m_existing_resource_centers;
220 container_type<const UniverseObject> m_existing_pop_centers;
221 container_type<const UniverseObject> m_existing_ships;
222 container_type<const UniverseObject> m_existing_fleets;
223 container_type<const UniverseObject> m_existing_planets;
224 container_type<const UniverseObject> m_existing_systems;
225 container_type<const UniverseObject> m_existing_buildings;
226 container_type<const UniverseObject> m_existing_fields;
227
228 friend class boost::serialization::access;
229 template <typename Archive>
230 void serialize(Archive& ar, const unsigned int version);
231 };
232
233 template <typename T>
get(int id)234 std::shared_ptr<const T> ObjectMap::get(int id) const {
235 auto it = Map<typename std::remove_const<T>::type>().find(id);
236 return std::shared_ptr<const T>(
237 it != Map<typename std::remove_const<T>::type>().end()
238 ? it->second
239 : nullptr);
240 }
241
242 template <typename T>
get(int id)243 std::shared_ptr<T> ObjectMap::get(int id) {
244 auto it = Map<typename std::remove_const<T>::type>().find(id);
245 return std::shared_ptr<T>(
246 it != Map<typename std::remove_const<T>::type>().end()
247 ? it->second
248 : nullptr);
249 }
250
251 template <typename T>
find(const id_range & object_ids)252 std::vector<std::shared_ptr<const T>> ObjectMap::find(const id_range& object_ids) const {
253 std::vector<std::shared_ptr<const T>> retval;
254 retval.reserve(boost::size(object_ids));
255 typedef typename std::remove_const<T>::type mutableT;
256 for (int object_id : object_ids) {
257 auto map_it = Map<mutableT>().find(object_id);
258 if (map_it != Map<mutableT>().end())
259 retval.push_back(std::shared_ptr<const T>(map_it->second));
260 }
261 return retval;
262 }
263
264 template <typename T>
find(const id_range & object_ids)265 std::vector<std::shared_ptr<T>> ObjectMap::find(const id_range& object_ids) {
266 std::vector<std::shared_ptr<T>> retval;
267 retval.reserve(boost::size(object_ids));
268 typedef typename std::remove_const<T>::type mutableT;
269 for (int object_id : object_ids) {
270 auto map_it = Map<mutableT>().find(object_id);
271 if (map_it != Map<mutableT>().end())
272 retval.push_back(std::shared_ptr<T>(map_it->second));
273 }
274 return retval;
275 }
276
277 template <typename T>
find(const UniverseObjectVisitor & visitor)278 std::vector<std::shared_ptr<const T>> ObjectMap::find(const UniverseObjectVisitor& visitor) const {
279 std::vector<std::shared_ptr<const T>> result;
280 typedef typename std::remove_const<T>::type mutableT;
281 result.reserve(size<mutableT>());
282 for (auto entry : Map<mutableT>()) {
283 if (entry.second->Accept(visitor))
284 result.push_back(entry.second);
285 }
286 return result;
287 }
288
289 template <typename T>
find(const UniverseObjectVisitor & visitor)290 std::vector<std::shared_ptr<T>> ObjectMap::find(const UniverseObjectVisitor& visitor) {
291 std::vector<std::shared_ptr<T>> result;
292 typedef typename std::remove_const<T>::type mutableT;
293 result.reserve(size<mutableT>());
294 for (const auto& entry : Map<mutableT>()) {
295 if (entry.second->Accept(visitor))
296 result.push_back(entry.second);
297 }
298 return result;
299 }
300
301 template <typename T>
size()302 std::size_t ObjectMap::size() const
303 { return Map<typename std::remove_const<T>::type>().size(); }
304
305 template <typename T>
insert(std::shared_ptr<T> item,int empire_id)306 void ObjectMap::insert(std::shared_ptr<T> item, int empire_id /* = ALL_EMPIRES */) {
307 if (!item)
308 return;
309 insertCore(std::dynamic_pointer_cast<UniverseObject>(item), empire_id);
310 }
311
312 // template specializations
313
314 template <>
315 FO_COMMON_API const ObjectMap::container_type<UniverseObject>& ObjectMap::Map() const;
316
317 template <>
318 FO_COMMON_API const ObjectMap::container_type<ResourceCenter>& ObjectMap::Map() const;
319
320 template <>
321 FO_COMMON_API const ObjectMap::container_type<PopCenter>& ObjectMap::Map() const;
322
323 template <>
324 FO_COMMON_API const ObjectMap::container_type<Ship>& ObjectMap::Map() const;
325
326 template <>
327 FO_COMMON_API const ObjectMap::container_type<Fleet>& ObjectMap::Map() const;
328
329 template <>
330 FO_COMMON_API const ObjectMap::container_type<Planet>& ObjectMap::Map() const;
331
332 template <>
333 FO_COMMON_API const ObjectMap::container_type<System>& ObjectMap::Map() const;
334
335 template <>
336 FO_COMMON_API const ObjectMap::container_type<Building>& ObjectMap::Map() const;
337
338 template <>
339 FO_COMMON_API const ObjectMap::container_type<Field>& ObjectMap::Map() const;
340
341 template <>
342 FO_COMMON_API ObjectMap::container_type<UniverseObject>& ObjectMap::Map();
343
344 template <>
345 FO_COMMON_API ObjectMap::container_type<ResourceCenter>& ObjectMap::Map();
346
347 template <>
348 FO_COMMON_API ObjectMap::container_type<PopCenter>& ObjectMap::Map();
349
350 template <>
351 FO_COMMON_API ObjectMap::container_type<Ship>& ObjectMap::Map();
352
353 template <>
354 FO_COMMON_API ObjectMap::container_type<Fleet>& ObjectMap::Map();
355
356 template <>
357 FO_COMMON_API ObjectMap::container_type<Planet>& ObjectMap::Map();
358
359 template <>
360 FO_COMMON_API ObjectMap::container_type<System>& ObjectMap::Map();
361
362 template <>
363 FO_COMMON_API ObjectMap::container_type<Building>& ObjectMap::Map();
364
365 template <>
366 FO_COMMON_API ObjectMap::container_type<Field>& ObjectMap::Map();
367
368 #endif
369