ecs.hpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561
  1. #ifndef UI_FACTORY_HPP
  2. #define UI_FACTORY_HPP
  3. #include <vector>
  4. #include <memory>
  5. #include <numeric>
  6. #include <limits>
  7. #include <string>
  8. #include "simple/support/meta.hpp"
  9. #include "simple/support/tuple_utils.hpp"
  10. #include "simple/support/rational.hpp"
  11. #include "simple/support/algorithm/utils.hpp"
  12. template <typename... Interfaces>
  13. class entities;
  14. template <typename Base, typename... Interfaces>
  15. // TODO: enable if is_abstract<Base> && has_virtual_destructor<Base>
  16. // and maybe is_abstract<Interfaces>, but not sure
  17. struct object_interface
  18. {
  19. static constexpr size_t type_count = 1 + sizeof...(Interfaces);
  20. };
  21. // TODO: parameterise std::unique_ptr and std::vector templates?? do I need that within a project or between projects, cause in a latter case can get away with using declaration in a configuration header
  22. template <typename... Types>
  23. class components
  24. {
  25. public:
  26. using types = std::tuple<Types...>;
  27. template <typename Element, typename ...Args>
  28. auto& emplace(Args&&... args)
  29. {
  30. using simple::support::meta::find_t;
  31. using simple::support::meta::bind;
  32. using simple::support::meta::make_index_segment;
  33. using simple::support::tuple_car;
  34. using simple::support::tuple_car_t;
  35. using simple::support::tuple_tie_cdr;
  36. using simple::support::tie_subtuple;
  37. using simple::support::is_template_instance_v;
  38. using found = find_t<bind<is_component, size_constant<0>, Element>, types>;
  39. static_assert(found::value != std::tuple_size_v<types>, "Element type not found in known component list.");
  40. if constexpr (is_template_instance_v<object_interface, typename found::type>)
  41. {
  42. auto object_vectors = tie_subtuple(vectors,
  43. make_index_segment<
  44. found::functor::binding::value,
  45. found::type::type_count
  46. >()
  47. );
  48. auto& elements = tuple_car(object_vectors);
  49. auto element = std::make_unique<Element>(std::forward<Args>(args)...);
  50. Element& raw = *element.get();
  51. add_interface(raw, tuple_tie_cdr(object_vectors));
  52. elements.emplace_back(std::move(element)); // assuming raw pointer will not change... that's safe right?
  53. return raw;
  54. }
  55. else
  56. {
  57. return std::get<found::functor::binding::value>(vectors).emplace_back(std::forward<Args>(args)...);
  58. }
  59. }
  60. template <typename Element>
  61. Element& push(Element&& element)
  62. { return emplace<Element>(std::forward<Element>(element)); }
  63. // TODO: return a range ??
  64. template <typename Component>
  65. const auto& get() const noexcept
  66. {
  67. using simple::support::meta::find_v;
  68. return std::get<find_v<Component, flat_types>>(vectors);
  69. }
  70. std::string log_sizes() const
  71. {
  72. std::string info;
  73. simple::support::transform([&](auto& v){
  74. info += std::to_string(v.size()) + ": " + typeid(typename std::remove_reference_t<decltype(v)>::value_type).name() + '\n';
  75. }, vectors);
  76. return info;
  77. }
  78. private:
  79. template <typename T>
  80. struct flatten_object_interface { using type = std::tuple<T>; };
  81. template <typename Base, typename... Interfaces>
  82. struct flatten_object_interface<object_interface<Base, Interfaces...>>
  83. { using type = std::tuple<std::unique_ptr<Base>, Interfaces*...>; };
  84. template <size_t i> using size_constant = std::integral_constant<size_t, i>;
  85. template <typename flat_index, typename T, typename Component>
  86. struct is_component : std::is_same<T,Component>
  87. {
  88. using binding = size_constant<flat_index{} + !is_component::value>;
  89. };
  90. template <typename flat_index, typename T, typename Base, typename... Interfaces>
  91. struct is_component<flat_index, T, object_interface<Base,Interfaces...>>
  92. {
  93. static constexpr bool value = std::is_base_of_v<Base, T>;
  94. static constexpr size_t increment =
  95. [](bool value)
  96. {
  97. return value
  98. ? 0
  99. : object_interface<Base,Interfaces...>::type_count
  100. ;
  101. }
  102. (is_component::value);
  103. using binding = size_constant<flat_index{} + increment>;
  104. };
  105. using flat_types = simple::support::meta::reconstruct_t<types,flatten_object_interface>;
  106. template <typename T>
  107. using container = std::vector<T>;
  108. template <typename Tuple>
  109. using make_containers_t = simple::support::meta::transform_t<Tuple, container>;
  110. template <typename T>
  111. using container_ref = container<T>&;
  112. template <typename... Ts>
  113. using make_container_refs_t = simple::support::meta::transform_t<std::tuple<Ts...>, container_ref>;
  114. template <typename T>
  115. using iterator = typename std::vector<T>::const_iterator;
  116. using iterators = simple::support::meta::transform_t<flat_types, iterator>;
  117. template <typename El>
  118. void add_interface(El&, std::tuple<>){}
  119. template <typename El, typename In, typename... Rest>
  120. // NOTE: this shorthand can't deduce the In :/
  121. // void add_interface(El& element, make_container_refs_t<In*, Rest...> interfaces)
  122. void add_interface(El& element, std::tuple<container<In*>&, container<Rest>&...> interfaces)
  123. {
  124. using simple::support::tuple_car;
  125. using simple::support::tuple_tie_cdr;
  126. if constexpr (std::is_base_of_v<In, El>)
  127. tuple_car(interfaces).push_back(&element);
  128. add_interface(element,tuple_tie_cdr(interfaces));
  129. }
  130. make_containers_t<flat_types> vectors;
  131. template <typename Component>
  132. auto& get() noexcept
  133. {
  134. using simple::support::meta::find_v;
  135. return std::get<find_v<Component, flat_types>>(vectors);
  136. }
  137. friend class entities<Types...>;
  138. };
  139. template <typename... Components>
  140. class entities
  141. {
  142. public:
  143. using entity_id_t = simple::support::rational<unsigned,
  144. simple::support::meta_constant<unsigned, 1u << (std::numeric_limits<unsigned>::digits/2)>>;
  145. entities(components<Components...> components) :
  146. _components(std::move(components)),
  147. offsets(simple::support::from_tuple<decltype(offsets)>(simple::support::transform(
  148. [](auto& v) -> entity_size_t {return v.size();}, _components.vectors )))
  149. {}
  150. template <typename T>
  151. struct entity
  152. {
  153. public:
  154. T components;
  155. const entity_id_t id;
  156. entities& world;
  157. bool owning;
  158. ~entity()
  159. {
  160. if(owning)
  161. world.erase(id);
  162. }
  163. entity(entity& other) = delete;
  164. entity& operator=(entity& other) = delete;
  165. entity& operator=(entity&& other) = delete;
  166. entity(entity&& other)
  167. : entity(other.world, std::move(other.components), other.id)
  168. {
  169. other.release();
  170. }
  171. void release()
  172. {
  173. owning = false;
  174. }
  175. private:
  176. entity(entities& world, T&& components, const entity_id_t& id) :
  177. components(std::forward<T>(components)),
  178. id(id),
  179. world(world),
  180. owning(true)
  181. {}
  182. friend class entities;
  183. };
  184. // TODO; emplace specific components to replace the make function below,
  185. // component type1, args1
  186. // component_type2, args2
  187. // ...
  188. // component_typeN, argsN
  189. //
  190. // maybe use a component helper template, so it looks like this:
  191. // entities.emplace
  192. // (
  193. // component<Type1>(args1...),
  194. // component<Type2>(args2...),
  195. // component<Type3>(args3...),
  196. // component<Type4>(args4...),
  197. // );
  198. // can also sfinae on this helper template.
  199. //
  200. // return a predictable entity object with references to all components and the id
  201. //
  202. // then again do you actually need to make new types of entity at runtime? entity types (which are defined by entity_sizes) should also be compile time, and also also also maybe fixed per id block
  203. template <typename Function>
  204. entity<std::invoke_result_t<
  205. Function, components<Components...>&>>
  206. make(Function&& function)
  207. {
  208. using simple::support::transform;
  209. auto size = transform([](const auto& x) {return x.size(); },
  210. _components.vectors);
  211. auto&& product = std::invoke(
  212. std::forward<Function>(function),
  213. _components);
  214. auto id = get_id();
  215. entity_ids.push_back(id);
  216. transform([](auto& entity_size, auto size, const auto& component)
  217. {
  218. entity_size.push_back(component.size() - size);
  219. }, entity_sizes, size, _components.vectors);
  220. return
  221. {
  222. *this,
  223. std::forward<decltype(product)>(product),
  224. id
  225. };
  226. };
  227. // template <typename Element, typename ...Args>
  228. // Element& emplace(Args&&... args)
  229. // {
  230. // return make([&](auto& components) -> auto&
  231. // {
  232. // return
  233. // components.template emplace<Element>
  234. // (std::forward<Args>(args)...);
  235. // }).components;
  236. // }
  237. // TODO: reuse code from find, why is it so hard :/
  238. // TODO: forget() method, that will turn this into a nop (you know, the classic problem: we technically own all objects we hand out, but we pretend that the user owns them instead with owning handles. now the user's destruction pattern might not be very efficient for our arrangement, and we can do nothing about that, exceeeeept when we know we are going to be destroyed as well, then we can ignore user requests to destroy and take care of it all in one go, unfortunately if the user is following RAII diligently, everything will be destroyed before us, so we have to give them a way to indicate this doomsday scenario manually)
  239. bool erase(entity_id_t id)
  240. {
  241. auto found = lower_bound
  242. (
  243. begin(entity_ids),
  244. end(entity_ids),
  245. id
  246. );
  247. if(found != end(entity_ids))
  248. {
  249. using simple::support::transform;
  250. transform([&](auto& components, auto& sizes, auto offset)
  251. {
  252. auto size_begin = begin(sizes);
  253. auto found_size = size_begin +
  254. (found - begin(entity_ids));
  255. auto components_begin = begin(components) + offset +
  256. accumulate(size_begin, found_size, 0);
  257. components.erase
  258. (
  259. components_begin,
  260. components_begin + *found_size
  261. );
  262. sizes.erase(found_size);
  263. }, _components.vectors, entity_sizes, offsets);
  264. entity_ids.erase(found);
  265. return true;
  266. }
  267. return false;
  268. }
  269. template <typename Component>
  270. decltype(auto) get_all() const noexcept
  271. { return _components.template get<Component>(); }
  272. template <typename Component>
  273. auto get() const noexcept
  274. {
  275. using simple::support::make_range;
  276. using simple::support::meta::find_v;
  277. auto& components = make_range(_components.template get<Component>());
  278. components.begin() += offsets[find_v<Component, types>];
  279. return components;
  280. }
  281. // TODO: support a subset of components, not just one or all
  282. template <typename Component = void>
  283. auto find(entity_id_t id) noexcept
  284. {
  285. using simple::support::transform;
  286. using simple::support::meta::find_v;
  287. auto found = lower_bound
  288. (
  289. begin(entity_ids),
  290. end(entity_ids),
  291. id
  292. );
  293. constexpr auto component_index = find_v<Component, types>;
  294. if constexpr (component_index == std::tuple_size_v<types>)
  295. {
  296. return transform([&found,this](auto& components, auto& sizes, auto offset)
  297. {
  298. // TODO: remove this->, when stupod clang 11+ stops complaining about unused this ffs
  299. return this->get_components(found,components,sizes,offset);
  300. }, _components.vectors, entity_sizes, offsets);
  301. }
  302. else
  303. {
  304. return get_components
  305. (
  306. found,
  307. _components.template get<Component>(),
  308. entity_sizes[component_index],
  309. offsets[component_index]
  310. );
  311. }
  312. }
  313. template <typename Component, typename It, size_t Index = 0>
  314. class component_iterator
  315. {
  316. public:
  317. using iterator = It;
  318. using difference_type = typename std::iterator_traits<iterator>::difference_type;
  319. using value_type = Component;
  320. using pointer = Component*;
  321. using reference = Component&;
  322. using iterator_category = typename std::iterator_traits<iterator>::iterator_category;
  323. component_iterator(It base, entities& world) :
  324. base(base), world(&world)
  325. {}
  326. constexpr decltype(auto) operator*() const
  327. { return *(world->find<Component>(base->id).begin() + Index); }
  328. constexpr auto operator->() const
  329. { return world->find<Component>(base->id).begin() + Index; }
  330. constexpr decltype(auto) operator*()
  331. { return *(world->find<Component>(base->id).begin() + Index); }
  332. constexpr auto operator->()
  333. { return world->find<Component>(base->id).begin() + Index; }
  334. constexpr component_iterator& operator++()
  335. {
  336. ++base;
  337. return *this;
  338. }
  339. constexpr component_iterator operator++(int)
  340. {
  341. component_iterator ret = *this;
  342. ++(*this);
  343. return ret;
  344. }
  345. constexpr component_iterator& operator+=(difference_type d)
  346. {
  347. base += d;
  348. return *this;
  349. }
  350. constexpr component_iterator& operator-=(difference_type d)
  351. {
  352. base -= d;
  353. return *this;
  354. }
  355. constexpr friend component_iterator operator+(const component_iterator& one, difference_type d)
  356. {
  357. return component_iterator(one) += d;
  358. }
  359. constexpr friend component_iterator operator+(difference_type d, const component_iterator& one)
  360. {
  361. return component_iterator(one) += d;
  362. }
  363. constexpr friend component_iterator operator-(const component_iterator& one, difference_type d)
  364. {
  365. return component_iterator(one) -= d;
  366. }
  367. constexpr friend component_iterator operator-(difference_type d, const component_iterator& one)
  368. {
  369. return component_iterator(one) -= d;
  370. }
  371. constexpr friend difference_type operator-(const component_iterator& one, const component_iterator& other)
  372. {
  373. return one.base - other.base;
  374. }
  375. constexpr friend bool operator==(const component_iterator& one, const component_iterator& other)
  376. {
  377. return one.base == other.base && one.world == other.world;
  378. }
  379. constexpr friend bool operator!=(const component_iterator& one, const component_iterator& other)
  380. {
  381. return !(one == other);
  382. }
  383. private:
  384. iterator base;
  385. entities* world;
  386. };
  387. // template <typename Component, typename It>
  388. // class iterator
  389. // {
  390. // public:
  391. // using difference_type = entity id difference
  392. // using value_type = tuple of assignable ranges
  393. // using pointer = ???
  394. // using reference = value_type???
  395. // using iterator_category = bidirectional, could be random access if limited to a block and if block is guaranteed to be all same entity type then we can store single element size for whole block and use multiplication yay... now go do it
  396. //
  397. // iterator(entities& world) :
  398. // world(&world)
  399. // {}
  400. //
  401. // iterator(entity_id_t id, entities& world) :
  402. // base(base), world(&world)
  403. // {}
  404. //
  405. // private:
  406. // entities* world;
  407. // };
  408. template <typename Component, size_t Index = 0, typename EntityIt = entity_id_t*>
  409. auto get_component_iterator(EntityIt i)
  410. {
  411. return component_iterator<Component,EntityIt, Index>{i, *this};
  412. }
  413. std::string log_sizes() const
  414. {
  415. // TODO: entity ids, entity_sizes, offsets
  416. return _components.log_sizes();
  417. }
  418. private:
  419. using entity_size_t = unsigned short;
  420. template <typename ComponentVector>
  421. auto get_components
  422. (
  423. std::vector<entity_id_t>::const_iterator entity_itr,
  424. ComponentVector& components,
  425. const std::vector<entity_size_t>& sizes,
  426. const entity_size_t offset
  427. )
  428. {
  429. using simple::support::range;
  430. using std::accumulate;
  431. if(entity_itr == end(entity_ids))
  432. return range{components.end(),components.end()};
  433. auto size_begin = begin(sizes);
  434. auto found_size = size_begin +
  435. (entity_itr - begin(entity_ids));
  436. auto components_begin = begin(components) + offset +
  437. accumulate(size_begin, found_size, 0);
  438. return range{
  439. components_begin,
  440. components_begin + *found_size
  441. };
  442. };
  443. entity_id_t get_id()
  444. {
  445. if(empty(entity_ids))
  446. return entity_id_t{};
  447. return entity_ids.back() + 1; //TODO: what if we run out?
  448. // but it'll take like two hundred bajillion years D':
  449. // yes, what will this program do after two hundred bajillion years of runtime?
  450. // reuse ids? do I smell std::rotate? =)
  451. // not even one hundred bajilion years later I come to replace the integer here with a rational,
  452. // to divide the id/address space into blocks of whole numbers that each can contain many fractions,
  453. // allowing grouping of entities that need to stay contiguous (not an optimization btw, pure business logic).
  454. // not so simple anymore, is it? might not be one bajilion years dependent on the denominator and use case,
  455. // so even more pressing to implement reuse of ids, and rotate is here already =)
  456. //
  457. // where's rotate? I don't see it, not here no more -_-
  458. }
  459. using components_t = components<Components...>;
  460. using types = typename components_t::flat_types;
  461. components_t _components;
  462. std::vector<entity_id_t> entity_ids;
  463. std::array<
  464. std::vector<entity_size_t>,
  465. std::tuple_size_v<types>
  466. > entity_sizes;
  467. std::array<
  468. entity_size_t,
  469. std::tuple_size_v<types>
  470. > offsets;
  471. };
  472. #endif /* end of include guard */