entity
Entity/Component System for C++
saturated_pool.hpp
Go to the documentation of this file.
1 // ****************************************************************************
2 // entity/component/saturated_pool.h
3 //
4 // Represents a component pool where the number of components
5 // equals the number of entities. Allows assumptions to be
6 // made to optimize bookkeeping and iteration.
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_SATURATEDPOOL_H_INCLUDED_
16 #define _ENTITY_COMPONENT_SATURATEDPOOL_H_INCLUDED_
17 
18 #include <boost/bind/bind.hpp>
19 #include <boost/bind/placeholders.hpp>
20 #include <boost/iterator/iterator_facade.hpp>
21 #include <boost/signals2.hpp>
22 #include <boost/signals2/connection.hpp>
23 #include <algorithm>
24 #include <cstddef>
25 #include <functional>
26 #include <mutex>
27 #include <vector>
28 
29 #include "entity/config.hpp" // IWYU pragma: keep
30 #include "entity/entity.hpp"
31 #include "entity/entity_index.hpp"
32 #include "entity/entity_pool.hpp"
33 
34 namespace boost {
35 namespace iterators {
36 struct forward_traversal_tag;
37 } // namespace iterators
38 } // namespace boost
39 
40 // ----------------------------------------------------------------------------
41 //
42 namespace entity { namespace component
43 {
44  template<typename ComponentPool>
45  class creation_queue;
46  template<typename ComponentPool>
47  class destruction_queue;
48 
49  template<typename T>
51  {
52  private:
53 
54  struct iterator_impl
55  : boost::iterator_facade<
56  iterator_impl
57  , T&
58  , boost::forward_traversal_tag
59  >
60  {
61  iterator_impl()
62  {}
63 
64  entity get_entity() const
65  {
66  return make_entity(entity_index_);
67  }
68 
69  private:
70 
71  friend class boost::iterator_core_access;
72  friend class saturated_pool;
73 
74  typedef T* parent_iterator;
75 
76  iterator_impl(
77  saturated_pool* parent,
78  entity_index_t idx)
79  : parent_(parent)
80  , entity_index_(idx)
81  {}
82 
83  void increment()
84  {
85  ++entity_index_;
86  }
87 
88  bool equal(iterator_impl const& other) const
89  {
90  return entity_index_ == other.entity_index_;
91  }
92 
93  T& dereference() const
94  {
95  return parent_->components_[entity_index_];
96  }
97 
98  saturated_pool* parent_;
99  entity_index_t entity_index_;
100  };
101 
102  public:
103 
104  typedef T type;
105  typedef iterator_impl iterator;
106 
107  // --------------------------------------------------------------------
108  //
109  template<typename EntityListIterator>
111  : boost::iterator_facade<
112  entity_iterator<EntityListIterator>
113  , T&
114  , boost::forward_traversal_tag
115  >
116  {
118  {}
119 
121  {
122  return *entity_iter_;
123  }
124 
125  bool is_valid() const
126  {
127  return true;
128  }
129 
130  private:
131 
133  friend class saturated_pool;
134 
135  entity_iterator(saturated_pool* parent, EntityListIterator entity_iter)
136  : parent_(parent)
137  , entity_iter_(std::move(entity_iter))
138  {}
139 
140  void increment()
141  {
142  ++entity_iter_;
143  }
144 
145  bool equal(entity_iterator const& other) const
146  {
147  return entity_iter_ == other.entity_iter_;
148  }
149 
150  T& dereference() const
151  {
152  return parent_->components_[get_entity().index()];
153  }
154 
155  saturated_pool* parent_;
156  EntityListIterator entity_iter_;
157  };
158 
159  // --------------------------------------------------------------------
160  //
161  struct window
162  {
163  typedef type value_type;
164 
166  {}
167 
168  bool is_entity(entity) const
169  {
170  return true;
171  }
172 
174  {
175  ++data_;
176  return true;
177  }
178 
179  bool advance(entity e)
180  {
181  data_ = data_begin_ + e.index();
182  return true;
183  }
184 
185  value_type& get() const
186  {
187  return *data_;
188  }
189 
190  bool is_end() const
191  {
192  return false;
193  }
194 
195  private:
196 
197  friend class saturated_pool;
198 
199  window(saturated_pool* parent)
200  : data_begin_(&parent->components_[0])
201  , data_(&parent->components_[0])
202  {}
203 
204  value_type* data_begin_;
205  value_type* data_;
206  };
207 
208  // --------------------------------------------------------------------
209  //
210  saturated_pool(entity_pool& owner_pool, T const& default_value = T())
211  {
212  components_.resize(owner_pool.size(), default_value);
213 
214  slots_.entity_destroy_handler =
215  owner_pool.signals().on_entity_destroy.connect(
216  boost::bind(
217  &saturated_pool::handle_destroy_entity,
218  this,
219  ::_1
220  )
221  )
222  ;
223 
224  slots_.entity_swap_handler =
225  owner_pool.signals().on_entity_swap.connect(
226  boost::bind(
227  &saturated_pool::handle_swap_entity,
228  this,
229  ::_1,
230  ::_2
231  )
232  )
233  ;
234  }
235 
236  #if ENTITY_SUPPORT_VARIADICS
237  template<typename... Args>
238  void auto_create_components(entity_pool& owner_pool, Args... constructor_args)
239  {
240  slots_.entity_create_handler =
241  owner_pool.signals().on_entity_create.connect(
242  std::function<void(entity)>(
243  [this, constructor_args...](entity e)
244  {
245  create(e, constructor_args...);
246  }
247  )
248  )
249  ;
250  }
251  #else
252  void auto_create_components(entity_pool& owner_pool, T const& default_value)
253  {
254  slots_.entity_create_handler =
255  owner_pool.signals().on_entity_create.connect(
256  boost::bind(
258  this,
259  ::_1,
260  default_value
261  )
262  )
263  ;
264  }
265  #endif
266 
267  #if ENTITY_SUPPORT_VARIADICS
268  template<typename... Args>
269  T* create(entity e, Args&&... args)
270  {
271  components_.emplace(components_.begin() + e.index(), std::forward<Args>(args)...);
272  return &components_[e.index()];
273  }
274  #else
275  T* create(entity e, type original)
276  {
277  components_.emplace(components_.begin() + e.index(), std::move(original));
278  return &components_[e.index()];
279  }
280  #endif
281 
282  void destroy(entity e)
283  {
284  components_.erase(components_.begin() + e.index());
285  }
286 
287  T* get(entity e)
288  {
289  return get_component(e);
290  }
291 
292  T const* get(entity e) const
293  {
294  return get_component(e);
295  }
296 
297  iterator begin()
298  {
299  return iterator(this, 0);
300  }
301 
302  iterator end()
303  {
304  return iterator(this, components_.size());
305  }
306 
308  {
309  return window(this);
310  }
311 
312  std::size_t size()
313  {
314  return components_.size();
315  }
316 
317  private:
318 
319  // No copying.
321  saturated_pool operator=(saturated_pool);
322 
323  friend class creation_queue<saturated_pool<T>>;
325 
326  struct slot_list
327  {
328  boost::signals2::scoped_connection entity_create_handler;
329  boost::signals2::scoped_connection entity_destroy_handler;
330  boost::signals2::scoped_connection entity_swap_handler;
331  };
332 
333  T* get_component(entity e)
334  {
335  return &components_[e.index()];
336  }
337 
338  T const* get_component(entity e) const
339  {
340  return &components_[e.index()];
341  }
342 
343  // --------------------------------------------------------------------
344  // Queue interface.
345  template<typename Iter>
346  void create_range(Iter first, Iter last)
347  {
348  while(first != last)
349  {
350  create(first->first.lock().get(), std::move(first->second));
351  ++first;
352  }
353  }
354 
355  template<typename Iter>
356  void destroy_range(Iter current, Iter last)
357  {
358  while(current != last)
359  {
360  destroy(current->lock().get());
361  ++current;
362  }
363  }
364 
365  // --------------------------------------------------------------------
366  // Slot Handlers.
367  void handle_destroy_entity(entity e)
368  {
369  destroy(e);
370  }
371 
372  void handle_swap_entity(entity a, entity b)
373  {
374  using std::swap;
375  swap(components_[a.index()], components_[b.index()]);
376  }
377 
378  std::vector<type> components_;
379  slot_list slots_;
380  };
381 } } // namespace entity { namespace component
382 
383 #endif // _ENTITY_COMPONENT_SATURATEDPOOL_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.
saturated_pool(entity_pool &owner_pool, T const &default_value=T())
void swap(unique_entity &a, unique_entity &b)
Definition: entity.hpp:125
entity_index_t index() const
Definition: entity.hpp:35
std::size_t entity_index_t
void auto_create_components(entity_pool &owner_pool, Args...constructor_args)
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
std::size_t size() const
boost::signals2::signal< void(entity, entity)> on_entity_swap
Definition: entity_pool.hpp:94