entity
Entity/Component System for C++
sparse_pool.hpp
Go to the documentation of this file.
1 // ****************************************************************************
2 // entity/component/sparse_pool.h
3 //
4 // Represents a component pool where the number of components
5 // is significantly less than the number of entities with those components.
6 // Uses less space and will be faster to iterate under these conditions.
7 //
8 // Copyright Chris Glover 2014-2015
9 //
10 // Distributed under the Boost Software License, Version 1.0.
11 // See accompanying file LICENSE_1_0.txt or copy at
12 // http://www.boost.org/LICENSE_1_0.txt
13 //
14 // ****************************************************************************
15 #pragma once
16 #ifndef _ENTITY_COMPONENT_SPARSEPOOL_H_INCLUDED_
17 #define _ENTITY_COMPONENT_SPARSEPOOL_H_INCLUDED_
18 
19 #include <boost/bind/bind.hpp>
20 #include <boost/bind/placeholders.hpp>
21 #include <boost/container/container_fwd.hpp>
22 #include <boost/container/flat_map.hpp>
23 #include <boost/ref.hpp>
24 #include <boost/iterator/iterator_facade.hpp>
25 #include <boost/signals2.hpp>
26 #include <boost/signals2/connection.hpp>
27 #include <algorithm>
28 #include <cstddef>
29 #include <functional>
30 #include <iterator>
31 #include <mutex>
32 #include <utility>
33 #include <vector>
34 
35 #include "entity/config.hpp" // IWYU pragma: keep
36 #include "entity/entity.hpp"
37 #include "entity/entity_pool.hpp"
38 
39 namespace boost {
40 namespace iterators {
41 struct forward_traversal_tag;
42 } // namespace iterators
43 } // namespace boost
44 
45 // ----------------------------------------------------------------------------
46 //
47 namespace entity { namespace component
48 {
49  template<typename ComponentPool>
50  class creation_queue;
51  template<typename ComponentPool>
52  class destruction_queue;
53 
54  template<typename T>
56  {
57  struct iterator_impl
58  : boost::iterator_facade<
59  iterator_impl
60  , T&
61  , boost::forward_traversal_tag
62  >
63  {
64  entity get_entity() const
65  {
66  return iterator_->first;
67  }
68 
69  iterator_impl()
70  {}
71 
72  private:
73 
74  friend class boost::iterator_core_access;
75  friend class sparse_pool;
76 
77  typedef typename boost::container::flat_map<entity, T>::iterator parent_iterator;
78 
79  explicit iterator_impl(parent_iterator convert_from)
80  : iterator_(std::move(convert_from))
81  {}
82 
83  void increment()
84  {
85  ++iterator_;
86  }
87 
88  bool equal(iterator_impl const& other) const
89  {
90  return iterator_ == other.iterator_;
91  }
92 
93  T& dereference() const
94  {
95  return iterator_->second;
96  }
97 
98  parent_iterator iterator_;
99  };
100 
101  public:
102 
103  typedef T type;
104  typedef iterator_impl iterator;
105 
106  // --------------------------------------------------------------------
107  //
108  struct window
109  {
110  typedef type value_type;
111 
113  {}
114 
115  bool is_entity(entity e) const
116  {
117  return iterator_ != end_ && e == iterator_->first;
118  }
119 
120  bool increment(entity target)
121  {
122  while(iterator_ != end_ && iterator_->first < target)
123  ++iterator_;
124 
125  return iterator_ != end_ && iterator_->first == target;
126  }
127 
128  bool advance(entity target)
129  {
130  return increment(target);
131  }
132 
133  value_type& get() const
134  {
135  return iterator_->second;
136  }
137 
138  bool is_end() const
139  {
140  return iterator_ == end_;
141  }
142 
143  private:
144 
145  friend class sparse_pool;
146 
147  typedef typename boost::container::flat_map<
148  entity, value_type
149  >::iterator parent_iterator;
150 
151  window(parent_iterator start, parent_iterator end)
152  : iterator_(std::move(start))
153  , end_(std::move(end))
154  {}
155 
156  parent_iterator iterator_;
157  parent_iterator end_;
158  };
159 
160  // --------------------------------------------------------------------
161  //
162  sparse_pool(entity_pool& owner_pool, T const& default_value = T())
163  {
164  #if ENTITY_SUPPORT_VARIADICS
165  auto create_func = &sparse_pool::create<T const&>;
166  #else
167  auto create_func = &sparse_pool::create;
168  #endif
169 
170  // Create default values for existing entities.
172  owner_pool.begin(),
173  owner_pool.end(),
174  boost::bind(
175  create_func,
176  this,
177  ::_1,
178  boost::ref(default_value)
179  )
180  );
181 
182  slots_.entity_destroy_handler =
183  owner_pool.signals().on_entity_destroy.connect(
184  boost::bind(
185  &sparse_pool::handle_destroy_entity,
186  this,
187  ::_1
188  )
189  )
190  ;
191 
192  slots_.entity_swap_handler =
193  owner_pool.signals().on_entity_swap.connect(
194  boost::bind(
195  &sparse_pool::handle_swap_entity,
196  this,
197  ::_1,
198  ::_2
199  )
200  )
201  ;
202  }
203 
204  #if ENTITY_SUPPORT_VARIADICS
205  template<typename... Args>
206  void auto_create_components(entity_pool& owner_pool, Args&&... constructor_args)
207  {
208  slots_.entity_create_handler =
209  owner_pool.signals().on_entity_create.connect(
210  std::function<void(entity)>(
211  [this, constructor_args...](entity e)
212  {
213  create(e, constructor_args...);
214  }
215  )
216  )
217  ;
218  }
219  #else
220  void auto_create_components(entity_pool& owner_pool, T const& default_value)
221  {
222  slots_.entity_create_handler =
223  owner_pool.signals().on_entity_create.connect(
224  boost::bind(
226  this,
227  ::_1,
228  default_value
229  )
230  )
231  ;
232  }
233  #endif
234 
235  #if ENTITY_SUPPORT_VARIADICS
236  template<typename... Args>
237  T* create(entity e, Args&&... args)
238  {
239  auto r = components_.emplace(e, std::forward<Args>(args)...);
240  return &(r.first->second);
241  }
242  #else
243  T* create(entity e, type original)
244  {
245  auto r = components_.emplace(e, std::move(original));
246  return &(r.first->second);
247  }
248  #endif
249 
250  void destroy(entity e)
251  {
252  components_.erase(e);
253  }
254 
255  T* get(entity e)
256  {
257  auto obj = components_.find(e);
258  if(obj != components_.end())
259  {
260  return &obj->second;
261  }
262 
263  return nullptr;
264  }
265 
266  T const* get(entity e) const
267  {
268  auto obj = components_.find(e);
269  if(obj != components_.end())
270  {
271  return &obj->second;
272  }
273 
274  return nullptr;
275  }
276 
277  iterator begin()
278  {
279  return iterator(components_.begin());
280  }
281 
282  iterator end()
283  {
284  return iterator(components_.end());
285  }
286 
288  {
289  return window(components_.begin(), components_.end());
290  }
291 
292  std::size_t size()
293  {
294  return components_.size();
295  }
296 
297  private:
298 
299  // No copying
300  sparse_pool(sparse_pool const&);
301  sparse_pool operator=(sparse_pool);
302 
303  friend class creation_queue<sparse_pool<T>>;
304  friend class destruction_queue<sparse_pool<T>>;
305 
306  struct slot_list
307  {
308  boost::signals2::scoped_connection entity_create_handler;
309  boost::signals2::scoped_connection entity_destroy_handler;
310  boost::signals2::scoped_connection entity_swap_handler;
311  };
312 
313  // --------------------------------------------------------------------
314  // Queue interface.
315  template<typename Iter>
316  void create_range(Iter first, Iter last)
317  {
318  std::vector<std::pair<entity, T>> entities;
319  std::transform(first, last, std::back_inserter(entities), [entities](std::pair<weak_entity, type>& h)
320  {
321  return std::make_pair(h.first.lock().get(), std::move(h.second));
322  });
323 
324  components_.insert(boost::container::ordered_unique_range_t(), entities.begin(), entities.end());
325  }
326 
327  template<typename Iter>
328  void destroy_range(Iter current, Iter last)
329  {
330  while(current != last)
331  {
332  destroy(current->lock().get());
333  ++current;
334  }
335  }
336 
337  // --------------------------------------------------------------------
338  // Slot Handlers.
339  void handle_destroy_entity(entity e)
340  {
341  destroy(e);
342  }
343 
344  void handle_swap_entity(entity a, entity b)
345  {
346  using std::swap;
347  auto c_a = components_.find(a);
348  auto c_b = components_.find(b);
349  auto end = components_.end();
350 
351  if(c_a != end && c_b != end)
352  {
353  swap(c_a->second, c_b->second);
354  }
355  else if(c_a != end)
356  {
357  components_.emplace(b, std::move(c_a->second));
358  components_.erase(a);
359  }
360  else if(c_b != end)
361  {
362  components_.emplace(a, std::move(c_b->second));
363  components_.erase(b);
364  }
365  }
366 
367  boost::container::flat_map<entity, T> components_;
368  slot_list slots_;
369  };
370 } } // namespace entity { namespace component
371 
372 #endif // _ENTITY_COMPONENT_SPARSEPOOL_H_INCLUDED_
signal_list & signals()
boost::signals2::signal< void(entity)> on_entity_destroy
Definition: entity_pool.hpp:93
T * create(entity e, Args &&...args)
STL namespace.
void auto_create_components(entity_pool &owner_pool, Args &&...constructor_args)
void swap(unique_entity &a, unique_entity &b)
Definition: entity.hpp:125
iterator begin() const
iterator end() const
sparse_pool(entity_pool &owner_pool, T const &default_value=T())
boost::signals2::signal< void(entity)> on_entity_create
Definition: entity_pool.hpp:92
void for_each(EntityList const &entities, ComponentPoolTuple &&p, iterator_traits::is_incremental_tag, Fn f)
Definition: for_each.hpp:37
boost::signals2::signal< void(entity, entity)> on_entity_swap
Definition: entity_pool.hpp:94