entity
Entity/Component System for C++
dense_pool.hpp
Go to the documentation of this file.
1 // ****************************************************************************
2 // entity/component/dense_pool.hpp
3 //
4 // Represents a component pool where the number of components
5 // approaches the number of entitys on those components.
6 // Basically trades space for run time efficiency.
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 #ifndef _ENTITY_COMPONENT_DENSEPOOL_H_INCLUDED_
16 #define _ENTITY_COMPONENT_DENSEPOOL_H_INCLUDED_
17 
18 #include <boost/assert.hpp>
19 #include <boost/bind/bind.hpp>
20 #include <boost/bind/placeholders.hpp>
21 #include <boost/ref.hpp>
22 #include <boost/iterator/iterator_facade.hpp>
23 #include <boost/signals2.hpp>
24 #include <boost/signals2/connection.hpp>
25 #include <algorithm>
26 #include <cstddef>
27 #include <functional>
28 #include <mutex>
29 #include <new>
30 #include <vector>
31 
32 #include "entity/config.hpp" // IWYU pragma: keep
33 #include "entity/entity.hpp"
34 #include "entity/entity_index.hpp"
35 #include "entity/entity_pool.hpp"
36 
37 namespace boost {
38 namespace iterators {
39 struct forward_traversal_tag;
40 } // namespace iterators
41 } // namespace boost
42 
43 // ----------------------------------------------------------------------------
44 //
45 namespace entity { namespace component
46 {
47  template<typename ComponentPool>
48  class creation_queue;
49  template<typename ComponentPool>
51 
52  template<typename T>
53  class dense_pool
54  {
55  private:
56 
57  struct element_t
58  {
59  char mem_[sizeof(T)];
60  };
61 
62  struct iterator_impl
63  : boost::iterator_facade<
64  iterator_impl
65  , T&
66  , boost::forward_traversal_tag
67  >
68  {
69  iterator_impl()
70  {}
71 
72  entity get_entity() const
73  {
74  return make_entity(entity_index_);
75  }
76 
77  private:
78 
79  friend class boost::iterator_core_access;
80  friend class dense_pool;
81 
82  typedef typename std::vector<char>::iterator parent_iterator;
83 
84  iterator_impl(dense_pool* parent, entity_index_t start)
85  : parent_(parent)
86  , entity_index_(start)
87  {
88  // Fast forward to the first available.
89  auto available_iterator = parent_->available_.begin() + start;
90  while(entity_index_ < parent_->available_.size() && *available_iterator)
91  {
92  ++available_iterator;
93  ++entity_index_;
94  }
95  }
96 
97  void increment()
98  {
99  auto available_iterator = parent_->available_.begin() + entity_index_;
100  auto end_iterator = parent_->available_.end();
101  if(available_iterator != end_iterator)
102  ++entity_index_;
103  while(available_iterator != end_iterator && *available_iterator)
104  {
105  ++available_iterator;
106  ++entity_index_;
107  }
108  }
109 
110  bool equal(iterator_impl const& other) const
111  {
112  return entity_index_ == other.entity_index_;
113  }
114 
115  T& dereference() const
116  {
117  return *parent_->get_component(get_entity().index());
118  }
119 
120  dense_pool* parent_;
121  entity_index_t entity_index_;
122  };
123 
124  public:
125 
126  typedef T type;
127  typedef iterator_impl iterator;
128 
129  // --------------------------------------------------------------------
130  //
131  struct window
132  {
133  typedef type value_type;
134 
136  {}
137 
138  bool is_entity(entity) const
139  {
140  return !(*available_);
141  }
142 
144  {
145  ++data_;
146  ++available_;
147  return !(*available_);
148  }
149 
150  bool advance(entity e)
151  {
152  data_ = data_begin_ + e.index();
153  available_ = available_begin_ + e.index();
154  return !(*available_);
155  }
156 
157  value_type& get() const
158  {
159  return *reinterpret_cast<value_type*>(data_);
160  }
161 
162  bool is_end() const
163  {
164  return false;
165  }
166 
167  private:
168 
169  friend class dense_pool;
170 
171  window(dense_pool* parent)
172  : available_begin_(&parent->available_[0])
173  , available_(&parent->available_[0])
174  , data_begin_(&parent->components_[0])
175  , data_(&parent->components_[0])
176  {}
177 
178  char const* available_begin_;
179  char const* available_;
180  typename dense_pool::element_t* data_begin_;
181  typename dense_pool::element_t* data_;
182  };
183 
184  // --------------------------------------------------------------------
185  //
186  dense_pool(entity_pool& owner_pool, T const& default_value = T())
187  : used_count_(0)
188  {
189  components_.resize(owner_pool.size());
190  available_.resize(owner_pool.size(), true);
191 
192  #if ENTITY_SUPPORT_VARIADICS
193  auto create_func = &dense_pool::create<T const&>;
194  #else
195  auto create_func = &dense_pool::create;
196  #endif
197 
198  // Create default values for existing entities.
200  owner_pool.begin(),
201  owner_pool.end(),
202  boost::bind(
203  create_func,
204  this,
205  ::_1,
206  boost::ref(default_value)
207  )
208  );
209 
210  slots_.entity_create_handler =
211  owner_pool.signals().on_entity_create.connect(
212  boost::bind(
213  &dense_pool::handle_create_entity,
214  this,
215  ::_1
216  )
217  )
218  ;
219 
220  slots_.entity_destroy_handler =
221  owner_pool.signals().on_entity_destroy.connect(
222  boost::bind(
223  &dense_pool::handle_destroy_entity,
224  this,
225  ::_1
226  )
227  )
228  ;
229 
230  slots_.entity_swap_handler =
231  owner_pool.signals().on_entity_swap.connect(
232  boost::bind(
233  &dense_pool::handle_swap_entity,
234  this,
235  ::_1,
236  ::_2
237  )
238  )
239  ;
240  }
241 
242  #if ENTITY_SUPPORT_VARIADICS
243  template<typename... Args>
244  void auto_create_components(entity_pool& owner_pool, Args&&... constructor_args)
245  {
246  slots_.entity_create_handler =
247  owner_pool.signals().on_entity_create.connect(
248  std::function<void(entity)>(
249  [this, constructor_args...](entity e)
250  {
251  create_entity_slot(e);
252  create(e, constructor_args...);
253  }
254  )
255  )
256  ;
257  }
258  #else
259  void auto_create_components(entity_pool& owner_pool, T const& default_value)
260  {
261  slots_.entity_create_handler =
262  owner_pool.signals().on_entity_create.connect(
263  std::function<void(entity)>(
264  [this, default_value](entity e)
265  {
266  create_entity_slot(e);
267  create(e, default_value);
268  }
269  )
270  )
271  ;
272  }
273  #endif
274 
275  #if ENTITY_SUPPORT_VARIADICS
276  template<typename... Args>
277  T* create(entity e, Args&&... args)
278  {
279  set_available(e.index(), false);
280  T* ret_val = get_component(e.index());
281  new(ret_val) T(std::forward<Args>(args)...);
282  ++used_count_;
283  return ret_val;
284  }
285  #else
286  T* create(entity e, type original)
287  {
288  set_available(e.index(), false);
289  T* ret_val = get_component(e.index());
290  new(ret_val) T(std::move(original));
291  ++used_count_;
292  return ret_val;
293  }
294  #endif
295 
296  void destroy(entity e)
297  {
298  BOOST_ASSERT(!is_available(e.index()) && "Trying to destroy un-allocated component.");
299  --used_count_;
300  T* p = get_component(e.index());
301  p->~T();
302 
303  set_available(e.index(), true);
304  }
305 
306  T* get(entity e)
307  {
308  if(is_available(e.index()))
309  {
310  return nullptr;
311  }
312 
313  return get_component(e.index());
314  }
315 
316  T const* get(entity e) const
317  {
318  if(is_available(e.index()))
319  {
320  return nullptr;
321  }
322 
323  return get_component(e.index());
324  }
325 
326  iterator begin()
327  {
328  return iterator(this, 0);
329  }
330 
331  iterator end()
332  {
333  return iterator(this, available_.size());
334  }
335 
337  {
338  return window(this);
339  }
340 
341  std::size_t size()
342  {
343  return used_count_;
344  }
345 
346  private:
347 
348  // No copying
349  dense_pool(dense_pool const&);
350  dense_pool operator=(dense_pool);
351 
352  friend class creation_queue<dense_pool<T>>;
353  friend class destruction_queue<dense_pool<T>>;
354 
355  struct slot_list
356  {
357  boost::signals2::scoped_connection entity_create_handler;
358  boost::signals2::scoped_connection entity_destroy_handler;
359  boost::signals2::scoped_connection entity_swap_handler;
360  };
361 
362  T* get_component(entity_index_t e)
363  {
364  return reinterpret_cast<T*>(&components_[e]);
365  }
366 
367  T const* get_component(entity_index_t e) const
368  {
369  return reinterpret_cast<T*>(&components_[e]);
370  }
371 
372  bool is_available(entity_index_t idx)
373  {
374  return available_[idx] != 0;
375  }
376 
377  void set_available(entity_index_t idx, bool available)
378  {
379  available_[idx] = (available == true);
380  }
381 
382  void create_entity_slot(entity e)
383  {
384  components_.insert(components_.begin() + e.index(), element_t());
385  available_.emplace(available_.begin() + e.index(), true);
386  }
387 
388  void free_entity_slot(entity e)
389  {
390  available_.erase(available_.begin() + e.index());
391  components_.erase(components_.begin() + e.index());
392  }
393 
394  // --------------------------------------------------------------------
395  // Queue interface.
396  template<typename Iter>
397  void create_range(Iter current, Iter last)
398  {
399  while(current != last)
400  {
401  create(current->first.lock().get(), std::move(current->second));
402  ++current;
403  }
404  }
405 
406  template<typename Iter>
407  void destroy_range(Iter current, Iter last)
408  {
409  while(current != last)
410  {
411  destroy(current->lock().get());
412  ++current;
413  }
414  }
415 
416  // --------------------------------------------------------------------
417  // Slot Handlers
418  void handle_create_entity(entity e)
419  {
420  create_entity_slot(e);
421  }
422 
423  void handle_destroy_entity(entity e)
424  {
425  if(!is_available(e.index()))
426  {
427  destroy(e);
428  }
429 
430  free_entity_slot(e);
431  }
432 
433  void handle_swap_entity(entity a, entity b)
434  {
435  using std::swap;
436 
437  auto c_a = get(a);
438  auto c_b = get(b);
439 
440  if(c_a && c_b)
441  {
442  swap(*c_a, *c_b);
443  }
444  else if(c_a)
445  {
446  create(b, std::move(*c_a));
447  destroy(a);
448  }
449  else if(c_b)
450  {
451  create(a, std::move(*c_b));
452  destroy(b);
453  }
454  }
455 
456  std::vector<element_t> components_;
457  std::vector<char> available_;
458  std::size_t used_count_;
459  slot_list slots_;
460  };
461 } } // namespace entity { namespace component
462 
463 #endif // _ENTITY_COMPONENT_DENSEPOOL_H_INCLUDED_
signal_list & signals()
T * create(entity e, Args &&...args)
Definition: dense_pool.hpp:277
boost::signals2::signal< void(entity)> on_entity_destroy
Definition: entity_pool.hpp:93
void swap(unique_entity &a, unique_entity &b)
Definition: entity.hpp:125
iterator begin() const
std::size_t entity_index_t
iterator end() const
dense_pool(entity_pool &owner_pool, T const &default_value=T())
Definition: dense_pool.hpp:186
boost::signals2::signal< void(entity)> on_entity_create
Definition: entity_pool.hpp:92
entity make_entity(entity_index_t idx) BOOST_NOEXCEPT_OR_NOTHROW
Definition: entity.hpp:64
void for_each(EntityList const &entities, ComponentPoolTuple &&p, iterator_traits::is_incremental_tag, Fn f)
Definition: for_each.hpp:37
std::size_t size() const
boost::signals2::signal< void(entity, entity)> on_entity_swap
Definition: entity_pool.hpp:94
void auto_create_components(entity_pool &owner_pool, Args &&...constructor_args)
Definition: dense_pool.hpp:244