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