/
query.h
74 lines (60 loc) · 3.06 KB
/
query.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
// Copyright (C) 2019 Sean Middleditch, all rights reserverd.
#pragma once
#include "_export.h"
#include "potato/foundation/typelist.h"
#include "potato/foundation/vector.h"
#include "potato/foundation/delegate.h"
#include "potato/foundation/span.h"
#include "potato/foundation/sort.h"
#include "potato/ecs/component.h"
namespace up {
/// A Query is used to select a list of Archetypes that provide a particular set of Components,
/// used to efficiency enumerate all matching Entities.
template <typename... Components>
class Query {
public:
static_assert(sizeof...(Components) != 0, "Empty Query objects are not allowed");
using Function = void(size_t, EntityId const*, Components*...);
using Delegate = delegate_ref<Function>;
/// Constructs a new Query object.
///
/// This is a non-trivial operation and Query objects should be cached and reused.
Query() noexcept;
/// Fetches the sorted list of ComponentIds required by this Query.
view<ComponentId> components() const noexcept { return _components; }
/// Given a World and a callback, finds all matching Archetypes, and invokes the
/// callback once for each Chunk belonging to the Archetypes, with appropriate pointers.
///
/// This is the primary mechanism for finding or mutating Entities.
void select(World& world, Delegate callback) const;
private:
template <size_t... Indices>
void _invoke(std::index_sequence<Indices...>, size_t, EntityId const*, view<void*>, Delegate& callback) const;
ComponentId _components[sizeof...(Components)];
ComponentId _sortedComponents[sizeof...(Components)];
};
template <typename... Components>
Query<Components...>::Query() noexcept : _components{getComponentId<Components>()...} {
// Generate a sorted set of indices from the main Components list
uint32 indices[sizeof...(Components)];
for (uint32 index = 0; index != sizeof...(Components); ++index) {
indices[index] = index;
}
sort(indices, {}, [this](uint32 index) noexcept { return _components[index]; });
// Store the sorted ComponentId list for selection usage
for (size_t index = 0; index != sizeof...(Components); ++index) {
_sortedComponents[index] = _components[indices[index]];
}
}
template <typename... Components>
template <size_t... Indices>
void Query<Components...>::_invoke(std::index_sequence<Indices...>, size_t count, EntityId const* entities, view<void*> arrays, Delegate& callback) const {
callback(count, entities, static_cast<Components*>(arrays[Indices])...);
}
template <typename... Components>
void Query<Components...>::select(World &world, Delegate callback) const {
world.selectRaw(_sortedComponents, _components, [&, this](size_t count, EntityId const* entities, view<void*> arrays) {
this->_invoke(std::make_index_sequence<sizeof...(Components)>(), count, entities, arrays, callback);
});
}
} // namespace up