entity
Entity/Component System for C++
entity_pool.hpp
Go to the documentation of this file.
1 // ****************************************************************************
2 // entity/entity_pool.h
3 //
4 // Represents a pool of entity ids.
5 //
6 // Copyright Chris Glover 2014-2015
7 //
8 // Distributed under the Boost Software License, Version 1.0.
9 // See accompanying file LICENSE_1_0.txt or copy at
10 // http://www.boost.org/LICENSE_1_0.txt
11 //
12 // ****************************************************************************
13 #ifndef _ENTITY_ENTITYPOOL_H_INCLUDED_
14 #define _ENTITY_ENTITYPOOL_H_INCLUDED_
15 
16 #include <boost/function.hpp>
17 #include <boost/iterator/iterator_facade.hpp>
18 #include <boost/pool/pool.hpp>
19 #include <boost/signals2.hpp>
20 #include <boost/signals2/optional_last_value.hpp>
21 #include <boost/smart_ptr/shared_ptr.hpp>
22 #include <algorithm>
23 #include <cstddef>
24 #include <new>
25 #include <type_traits>
26 #include <vector>
27 
28 #include "entity/config.hpp" // IWYU pragma: keep
29 #include "entity/entity.hpp"
30 #include "entity/entity_index.hpp"
32 
33 namespace boost {
34 namespace iterators {
35 struct forward_traversal_tag;
36 } // namespace iterators
37 } // namespace boost
38 namespace entity {
39 namespace iterator_traits {
40 template <typename EntityList> struct entity_list_is_incremental;
41 } // namespace iterator_traits
42 } // namespace entity
43 
44 // ----------------------------------------------------------------------------
45 //
46 namespace entity
47 {
49  {
50  struct iterator_impl
51  : boost::iterator_facade<
52  iterator_impl
53  , entity
54  , boost::forward_traversal_tag
55  , entity
56  >
57  {
58  private:
59 
60  friend class boost::iterator_core_access;
61  friend class entity_pool;
62 
63  iterator_impl(entity_index_t idx)
64  : iterator_(idx)
65  {}
66 
67  void increment()
68  {
69  ++iterator_;
70  }
71 
72  bool equal(iterator_impl const& other) const
73  {
74  return iterator_ == other.iterator_;
75  }
76 
77  entity dereference() const
78  {
79  return make_entity(iterator_);
80  }
81 
82  entity_index_t iterator_;
83  };
84 
85  public:
86 
87  typedef iterator_impl iterator;
88  typedef iterator_impl const_iterator;
89 
90  struct signal_list
91  {
92  boost::signals2::signal<void(entity)> on_entity_create;
93  boost::signals2::signal<void(entity)> on_entity_destroy;
94  boost::signals2::signal<void(entity, entity)> on_entity_swap;
95  };
96 
98  : entity_pool_(16)
99  {}
100 
102  {
103  while(!entities_.empty())
104  {
105  destroy(make_entity(*entities_.back()));
106  }
107  }
108 
110  {
111  entity_index_t* new_idx = new(entity_pool_.malloc()) entity_index_t(entities_.size());
112  entity ret_val = make_entity(*new_idx);
113  entities_.push_back(new_idx);
114  signals().on_entity_create(ret_val);
115  return ret_val;
116  }
117 
119  {
120  entity_index_t* new_idx_ptr = nullptr;
121  void* new_index_mem = nullptr;
122  bool pop_on_catch = false;
123  try
124  {
125  new_index_mem = entity_pool_.malloc();
126  new_idx_ptr = new(new_index_mem) entity_index_t(entities_.size());
127 
128  entity ent_val = make_entity(*new_idx_ptr);
129  entities_.push_back(new_idx_ptr);
130 
131  // Ensure we leave the container in a good state if shared_ptr throws.
132  pop_on_catch = true;
133 
134  unique_entity::ref_type new_idx(
135  new_idx_ptr,
136  entity_deleter(*this)
137  );
138 
139  signals().on_entity_create(ent_val);
140  return std::move(new_idx);
141  }
142  catch(...)
143  {
144  if(pop_on_catch)
145  entities_.pop_back();
146  if(new_idx_ptr)
147  new_idx_ptr->~entity_index_t();
148  if(new_index_mem)
149  entity_pool_.free(new_index_mem);
150  throw;
151  }
152  }
153 
155  {
156  return create_unique();
157  }
158 
159  void destroy(entity e)
160  {
161  destroy_impl(e.index());
162  }
163 
164  std::size_t size() const
165  {
166  return entities_.size();
167  }
168 
169  bool empty() const
170  {
171  return entities_.empty();
172  }
173 
174  iterator begin() const
175  {
176  return iterator_impl(0);
177  }
178 
179  iterator end() const
180  {
181  return iterator_impl(size());
182  }
183 
185  {
186  return signals_;
187  }
188 
189  private:
190 
191  entity_pool(entity_pool const&);
192  entity_pool operator=(entity_pool);
193 
194  struct entity_deleter
195  {
196  entity_deleter(entity_pool& owner_pool)
197  : owner_pool_(owner_pool)
198  {}
199 
200  void operator()(entity_index_t const* p)
201  {
202  owner_pool_.destroy_impl(*p);
203  }
204 
205  entity_pool& owner_pool_;
206  };
207 
208  void swap_entities(entity_index_t a, entity_index_t b)
209  {
210  using std::swap;
211  swap(entities_[a], entities_[b]);
212  swap(*entities_[a], *entities_[b]);
214  }
215 
216  void destroy_impl(entity_index_t e)
217  {
218  // Avoid swapping if this is at the end.
219  if((e + 1) < entities_.size())
220  {
221  swap_entities(e, *entities_.back());
222  }
223 
224  entity_index_t* idx = entities_.back();
225  entities_.pop_back();
226  try
227  {
229  idx->~entity_index_t();
230  void* idx_mem = idx;
231  idx = nullptr;
232  entity_pool_.free(idx_mem);
233  }
234  catch(...)
235  {
236  if(idx)
237  entities_.push_back(idx);
238  }
239  }
240 
241  boost::pool<> entity_pool_;
242  std::vector<entity_index_t*> entities_;
243  signal_list signals_;
244  };
245 
247  {
248  return p.begin();
249  }
250 
252  {
253  return p.end();
254  }
255 
256  // Entitiy pools are garanteed to be inremental
257  namespace iterator_traits
258  {
259  template<>
261  {};
262  }
263 
264 }
265 
266 #endif // _ENTITY_ENTITYPOOL_H_INCLUDED_
signal_list & signals()
iterator_impl const_iterator
Definition: entity_pool.hpp:88
entity_pool::iterator end(entity_pool const &p)
boost::signals2::signal< void(entity)> on_entity_destroy
Definition: entity_pool.hpp:93
unique_entity create_unique()
void swap(unique_entity &a, unique_entity &b)
Definition: entity.hpp:125
iterator begin() const
std::size_t entity_index_t
iterator end() const
entity_pool::iterator begin(entity_pool const &p)
shared_entity create_shared()
boost::signals2::signal< void(entity)> on_entity_create
Definition: entity_pool.hpp:92
void destroy(entity e)
iterator_impl iterator
Definition: entity_pool.hpp:87
entity make_entity(entity_index_t idx) BOOST_NOEXCEPT_OR_NOTHROW
Definition: entity.hpp:64
bool empty() const
std::size_t size() const
boost::signals2::signal< void(entity, entity)> on_entity_swap
Definition: entity_pool.hpp:94