123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561 |
- #ifndef UI_FACTORY_HPP
- #define UI_FACTORY_HPP
- #include <vector>
- #include <memory>
- #include <numeric>
- #include <limits>
- #include <string>
- #include "simple/support/meta.hpp"
- #include "simple/support/tuple_utils.hpp"
- #include "simple/support/rational.hpp"
- #include "simple/support/algorithm/utils.hpp"
- template <typename... Interfaces>
- class entities;
- template <typename Base, typename... Interfaces>
- struct object_interface
- {
- static constexpr size_t type_count = 1 + sizeof...(Interfaces);
- };
- template <typename... Types>
- class components
- {
- public:
- using types = std::tuple<Types...>;
- template <typename Element, typename ...Args>
- auto& emplace(Args&&... args)
- {
- using simple::support::meta::find_t;
- using simple::support::meta::bind;
- using simple::support::meta::make_index_segment;
- using simple::support::tuple_car;
- using simple::support::tuple_car_t;
- using simple::support::tuple_tie_cdr;
- using simple::support::tie_subtuple;
- using simple::support::is_template_instance_v;
- using found = find_t<bind<is_component, size_constant<0>, Element>, types>;
- static_assert(found::value != std::tuple_size_v<types>, "Element type not found in known component list.");
- if constexpr (is_template_instance_v<object_interface, typename found::type>)
- {
- auto object_vectors = tie_subtuple(vectors,
- make_index_segment<
- found::functor::binding::value,
- found::type::type_count
- >()
- );
- auto& elements = tuple_car(object_vectors);
- auto element = std::make_unique<Element>(std::forward<Args>(args)...);
- Element& raw = *element.get();
- add_interface(raw, tuple_tie_cdr(object_vectors));
- elements.emplace_back(std::move(element));
- return raw;
- }
- else
- {
- return std::get<found::functor::binding::value>(vectors).emplace_back(std::forward<Args>(args)...);
- }
- }
- template <typename Element>
- Element& push(Element&& element)
- { return emplace<Element>(std::forward<Element>(element)); }
-
- template <typename Component>
- const auto& get() const noexcept
- {
- using simple::support::meta::find_v;
- return std::get<find_v<Component, flat_types>>(vectors);
- }
- std::string log_sizes() const
- {
- std::string info;
- simple::support::transform([&](auto& v){
- info += std::to_string(v.size()) + ": " + typeid(typename std::remove_reference_t<decltype(v)>::value_type).name() + '\n';
- }, vectors);
- return info;
- }
- private:
- template <typename T>
- struct flatten_object_interface { using type = std::tuple<T>; };
- template <typename Base, typename... Interfaces>
- struct flatten_object_interface<object_interface<Base, Interfaces...>>
- { using type = std::tuple<std::unique_ptr<Base>, Interfaces*...>; };
- template <size_t i> using size_constant = std::integral_constant<size_t, i>;
- template <typename flat_index, typename T, typename Component>
- struct is_component : std::is_same<T,Component>
- {
- using binding = size_constant<flat_index{} + !is_component::value>;
- };
- template <typename flat_index, typename T, typename Base, typename... Interfaces>
- struct is_component<flat_index, T, object_interface<Base,Interfaces...>>
- {
- static constexpr bool value = std::is_base_of_v<Base, T>;
- static constexpr size_t increment =
- [](bool value)
- {
- return value
- ? 0
- : object_interface<Base,Interfaces...>::type_count
- ;
- }
- (is_component::value);
- using binding = size_constant<flat_index{} + increment>;
- };
- using flat_types = simple::support::meta::reconstruct_t<types,flatten_object_interface>;
- template <typename T>
- using container = std::vector<T>;
- template <typename Tuple>
- using make_containers_t = simple::support::meta::transform_t<Tuple, container>;
- template <typename T>
- using container_ref = container<T>&;
- template <typename... Ts>
- using make_container_refs_t = simple::support::meta::transform_t<std::tuple<Ts...>, container_ref>;
- template <typename T>
- using iterator = typename std::vector<T>::const_iterator;
- using iterators = simple::support::meta::transform_t<flat_types, iterator>;
- template <typename El>
- void add_interface(El&, std::tuple<>){}
- template <typename El, typename In, typename... Rest>
-
-
- void add_interface(El& element, std::tuple<container<In*>&, container<Rest>&...> interfaces)
- {
- using simple::support::tuple_car;
- using simple::support::tuple_tie_cdr;
- if constexpr (std::is_base_of_v<In, El>)
- tuple_car(interfaces).push_back(&element);
- add_interface(element,tuple_tie_cdr(interfaces));
- }
- make_containers_t<flat_types> vectors;
- template <typename Component>
- auto& get() noexcept
- {
- using simple::support::meta::find_v;
- return std::get<find_v<Component, flat_types>>(vectors);
- }
- friend class entities<Types...>;
- };
- template <typename... Components>
- class entities
- {
- public:
- using entity_id_t = simple::support::rational<unsigned,
- simple::support::meta_constant<unsigned, 1u << (std::numeric_limits<unsigned>::digits/2)>>;
- entities(components<Components...> components) :
- _components(std::move(components)),
- offsets(simple::support::from_tuple<decltype(offsets)>(simple::support::transform(
- [](auto& v) -> entity_size_t {return v.size();}, _components.vectors )))
- {}
- template <typename T>
- struct entity
- {
- public:
- T components;
- const entity_id_t id;
- entities& world;
- bool owning;
- ~entity()
- {
- if(owning)
- world.erase(id);
- }
- entity(entity& other) = delete;
- entity& operator=(entity& other) = delete;
- entity& operator=(entity&& other) = delete;
- entity(entity&& other)
- : entity(other.world, std::move(other.components), other.id)
- {
- other.release();
- }
- void release()
- {
- owning = false;
- }
- private:
- entity(entities& world, T&& components, const entity_id_t& id) :
- components(std::forward<T>(components)),
- id(id),
- world(world),
- owning(true)
- {}
- friend class entities;
- };
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- template <typename Function>
- entity<std::invoke_result_t<
- Function, components<Components...>&>>
- make(Function&& function)
- {
- using simple::support::transform;
- auto size = transform([](const auto& x) {return x.size(); },
- _components.vectors);
- auto&& product = std::invoke(
- std::forward<Function>(function),
- _components);
- auto id = get_id();
- entity_ids.push_back(id);
- transform([](auto& entity_size, auto size, const auto& component)
- {
- entity_size.push_back(component.size() - size);
- }, entity_sizes, size, _components.vectors);
- return
- {
- *this,
- std::forward<decltype(product)>(product),
- id
- };
- };
-
-
-
-
-
-
-
-
-
-
-
-
- bool erase(entity_id_t id)
- {
- auto found = lower_bound
- (
- begin(entity_ids),
- end(entity_ids),
- id
- );
- if(found != end(entity_ids))
- {
- using simple::support::transform;
- transform([&](auto& components, auto& sizes, auto offset)
- {
- auto size_begin = begin(sizes);
- auto found_size = size_begin +
- (found - begin(entity_ids));
- auto components_begin = begin(components) + offset +
- accumulate(size_begin, found_size, 0);
- components.erase
- (
- components_begin,
- components_begin + *found_size
- );
- sizes.erase(found_size);
- }, _components.vectors, entity_sizes, offsets);
- entity_ids.erase(found);
- return true;
- }
- return false;
- }
- template <typename Component>
- decltype(auto) get_all() const noexcept
- { return _components.template get<Component>(); }
- template <typename Component>
- auto get() const noexcept
- {
- using simple::support::make_range;
- using simple::support::meta::find_v;
- auto& components = make_range(_components.template get<Component>());
- components.begin() += offsets[find_v<Component, types>];
- return components;
- }
-
- template <typename Component = void>
- auto find(entity_id_t id) noexcept
- {
- using simple::support::transform;
- using simple::support::meta::find_v;
- auto found = lower_bound
- (
- begin(entity_ids),
- end(entity_ids),
- id
- );
- constexpr auto component_index = find_v<Component, types>;
- if constexpr (component_index == std::tuple_size_v<types>)
- {
- return transform([&found,this](auto& components, auto& sizes, auto offset)
- {
-
- return this->get_components(found,components,sizes,offset);
- }, _components.vectors, entity_sizes, offsets);
- }
- else
- {
- return get_components
- (
- found,
- _components.template get<Component>(),
- entity_sizes[component_index],
- offsets[component_index]
- );
- }
- }
- template <typename Component, typename It, size_t Index = 0>
- class component_iterator
- {
- public:
- using iterator = It;
- using difference_type = typename std::iterator_traits<iterator>::difference_type;
- using value_type = Component;
- using pointer = Component*;
- using reference = Component&;
- using iterator_category = typename std::iterator_traits<iterator>::iterator_category;
- component_iterator(It base, entities& world) :
- base(base), world(&world)
- {}
- constexpr decltype(auto) operator*() const
- { return *(world->find<Component>(base->id).begin() + Index); }
- constexpr auto operator->() const
- { return world->find<Component>(base->id).begin() + Index; }
- constexpr decltype(auto) operator*()
- { return *(world->find<Component>(base->id).begin() + Index); }
- constexpr auto operator->()
- { return world->find<Component>(base->id).begin() + Index; }
- constexpr component_iterator& operator++()
- {
- ++base;
- return *this;
- }
- constexpr component_iterator operator++(int)
- {
- component_iterator ret = *this;
- ++(*this);
- return ret;
- }
- constexpr component_iterator& operator+=(difference_type d)
- {
- base += d;
- return *this;
- }
- constexpr component_iterator& operator-=(difference_type d)
- {
- base -= d;
- return *this;
- }
- constexpr friend component_iterator operator+(const component_iterator& one, difference_type d)
- {
- return component_iterator(one) += d;
- }
- constexpr friend component_iterator operator+(difference_type d, const component_iterator& one)
- {
- return component_iterator(one) += d;
- }
- constexpr friend component_iterator operator-(const component_iterator& one, difference_type d)
- {
- return component_iterator(one) -= d;
- }
- constexpr friend component_iterator operator-(difference_type d, const component_iterator& one)
- {
- return component_iterator(one) -= d;
- }
- constexpr friend difference_type operator-(const component_iterator& one, const component_iterator& other)
- {
- return one.base - other.base;
- }
- constexpr friend bool operator==(const component_iterator& one, const component_iterator& other)
- {
- return one.base == other.base && one.world == other.world;
- }
- constexpr friend bool operator!=(const component_iterator& one, const component_iterator& other)
- {
- return !(one == other);
- }
- private:
- iterator base;
- entities* world;
- };
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- template <typename Component, size_t Index = 0, typename EntityIt = entity_id_t*>
- auto get_component_iterator(EntityIt i)
- {
- return component_iterator<Component,EntityIt, Index>{i, *this};
- }
- std::string log_sizes() const
- {
-
- return _components.log_sizes();
- }
- private:
- using entity_size_t = unsigned short;
- template <typename ComponentVector>
- auto get_components
- (
- std::vector<entity_id_t>::const_iterator entity_itr,
- ComponentVector& components,
- const std::vector<entity_size_t>& sizes,
- const entity_size_t offset
- )
- {
- using simple::support::range;
- using std::accumulate;
- if(entity_itr == end(entity_ids))
- return range{components.end(),components.end()};
- auto size_begin = begin(sizes);
- auto found_size = size_begin +
- (entity_itr - begin(entity_ids));
- auto components_begin = begin(components) + offset +
- accumulate(size_begin, found_size, 0);
- return range{
- components_begin,
- components_begin + *found_size
- };
- };
- entity_id_t get_id()
- {
- if(empty(entity_ids))
- return entity_id_t{};
- return entity_ids.back() + 1;
-
-
-
-
-
-
-
-
-
-
- }
- using components_t = components<Components...>;
- using types = typename components_t::flat_types;
- components_t _components;
- std::vector<entity_id_t> entity_ids;
- std::array<
- std::vector<entity_size_t>,
- std::tuple_size_v<types>
- > entity_sizes;
- std::array<
- entity_size_t,
- std::tuple_size_v<types>
- > offsets;
- };
- #endif
|