blob: e969a8d19d906cb273935d0478cd84ab2e963308 [file] [log] [blame]
Lingfeng Yangc02cb032020-10-26 14:21:25 -07001// Copyright (C) 2019 The Android Open Source Project
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14#pragma once
15
16#include "base/Lookup.h"
17#include "base/Optional.h"
18
19#include <functional>
20#include <unordered_map>
21#include <vector>
22
23#include <inttypes.h>
24#include <stdio.h>
25
26#define ENTITY_MANAGER_DEBUG 0
27
28#if ENTITY_MANAGER_DEBUG
29
30#define EM_DBG(fmt,...) fprintf(stderr, "%s:%d " fmt "\n", __func__, __LINE__, ##__VA_ARGS__);
31
32#else
33#define EM_DBG(...)
34#endif
35
36#define INVALID_ENTITY_HANDLE 0
37#define INVALID_COMPONENT_HANDLE 0
38
39namespace android {
40namespace base {
41
42// EntityManager: A way to represent an abstrat space of objects with handles.
43// Each handle is associated with data of type Item for quick access from handles to data.
44// Otherwise, entity data is spread through ComponentManagers.
45template<size_t indexBits,
46 size_t generationBits,
47 size_t typeBits,
48 class Item>
49class EntityManager {
50public:
51
52 static_assert(64 == (indexBits + generationBits + typeBits),
53 "bits of index, generation, and type must add to 64");
54
55 using EntityHandle = uint64_t;
56 using IteratorFunc = std::function<void(bool live, EntityHandle h, Item& item)>;
57 using ConstIteratorFunc = std::function<void(bool live, EntityHandle h, const Item& item)>;
58
59 static size_t getHandleIndex(EntityHandle h) {
60 return static_cast<size_t>(h & ((1ULL << indexBits) - 1ULL));
61 }
62
63 static size_t getHandleGeneration(EntityHandle h) {
64 return static_cast<size_t>(
65 (h >> indexBits) &
66 ((1ULL << generationBits) - 1ULL));
67 }
68
69 static size_t getHandleType(EntityHandle h) {
70 return static_cast<size_t>(
71 (h >> (indexBits + generationBits)) &
72 ((1ULL << typeBits) - 1ULL));
73 return h & ((1ULL << indexBits) - 1ULL);
74 }
75
76 static EntityHandle makeHandle(
77 size_t index,
78 size_t generation,
79 size_t type) {
80 EntityHandle res = index;
81 res |= generation << indexBits;
82 res |= type << (indexBits + generationBits);
83 return res;
84 }
85
86 static EntityHandle withIndex(EntityHandle h, size_t i) {
87 return makeHandle(i, getHandleGeneration(h), getHandleType(h));
88 }
89
90 static EntityHandle withGeneration(EntityHandle h, size_t nextGen) {
91 return makeHandle(getHandleIndex(h), nextGen, getHandleType(h));
92 }
93
94 static EntityHandle withType(EntityHandle h, size_t newType) {
95 return makeHandle(getHandleIndex(h), getHandleGeneration(h), newType);
96 }
97
98 EntityManager() : EntityManager(0) { }
99
Lingfeng Yang62dcb4e2021-01-06 14:57:56 -0800100 EntityManager(size_t initialItems) :
101 mEntries(initialItems),
102 mFirstFreeIndex(0),
103 mLiveEntries(0) {
104 reserve(initialItems);
105 }
106
Lingfeng Yangc02cb032020-10-26 14:21:25 -0700107 ~EntityManager() { clear(); }
108
109 struct EntityEntry {
110 EntityHandle handle = 0;
111 size_t nextFreeIndex = 0;
112 // 0 is a special generation for brand new entries
113 // that are not used yet
114 size_t liveGeneration = 1;
115 Item item;
116 };
117
Lingfeng Yang62dcb4e2021-01-06 14:57:56 -0800118 void clear() {
119 reserve(mEntries.size());
Lingfeng Yangc02cb032020-10-26 14:21:25 -0700120 mFirstFreeIndex = 0;
121 mLiveEntries = 0;
122 }
123
Lingfeng Yang62dcb4e2021-01-06 14:57:56 -0800124 size_t nextFreeIndex() const {
125 return mFirstFreeIndex;
126 }
127
Lingfeng Yangc02cb032020-10-26 14:21:25 -0700128 EntityHandle add(const Item& item, size_t type) {
129
130 if (!type) return INVALID_ENTITY_HANDLE;
131
132 size_t maxElements = (1ULL << indexBits);
133 if (mLiveEntries == maxElements) return INVALID_ENTITY_HANDLE;
134
135 size_t newIndex = mFirstFreeIndex;
136
137 EM_DBG("newIndex/firstFree: %zu type: %zu", newIndex, type);
138
139 size_t neededCapacity = newIndex + 1;
140 if (maxElements < neededCapacity) return INVALID_ENTITY_HANDLE;
141
142 size_t currentCapacity = mEntries.size();
143 size_t nextCapacity = neededCapacity << 1;
144 if (nextCapacity > maxElements) nextCapacity = maxElements;
145
146 EM_DBG("needed/current/next capacity: %zu %zu %zu",
147 neededCapacity,
148 currentCapacity,
149 nextCapacity);
150
151 if (neededCapacity > mEntries.size()) {
152 mEntries.resize(nextCapacity);
153 for (size_t i = currentCapacity; i < nextCapacity; ++i) {
154 mEntries[i].handle = makeHandle(i, 0, type);
155 mEntries[i].nextFreeIndex = i + 1;
156 EM_DBG("new un-init entry: index %zu nextFree %zu",
157 i, i + 1);
158 }
159 }
160
161 mEntries[newIndex].handle =
162 makeHandle(newIndex, mEntries[newIndex].liveGeneration, type);
163 mEntries[newIndex].item = item;
164
165 mFirstFreeIndex = mEntries[newIndex].nextFreeIndex;
166 EM_DBG("created. new first free: %zu", mFirstFreeIndex);
167
168 ++mLiveEntries;
169
170 EM_DBG("result handle: 0x%llx", (unsigned long long)mEntries[newIndex].handle);
171
172 return mEntries[newIndex].handle;
173 }
174
175 EntityHandle addFixed(EntityHandle fixedHandle, const Item& item, size_t type) {
176 // 3 cases:
177 // 1. handle is not allocated and doesn't correspond to mFirstFreeIndex
178 bool isFreeListNonHead = false;
179 // 2. handle already exists (replace)
180 bool isAlloced = false;
181 // 3. index(handle) == mFirstFreeIndex
182 bool isFreeListHead = false;
183
184 if (!type) return INVALID_ENTITY_HANDLE;
185
186 size_t maxElements = (1ULL << indexBits);
187 if (mLiveEntries == maxElements) return INVALID_ENTITY_HANDLE;
188
189 size_t newIndex = getHandleIndex(fixedHandle);
190
191 EM_DBG("newIndex/firstFree: %zu type: %zu", newIndex, type);
192
193 size_t neededCapacity = newIndex + 1;
194
195 if (maxElements < neededCapacity) return INVALID_ENTITY_HANDLE;
196
197 size_t currentCapacity = mEntries.size();
198 size_t nextCapacity = neededCapacity << 1;
199 if (nextCapacity > maxElements) nextCapacity = maxElements;
200
201 EM_DBG("needed/current/next capacity: %zu %zu %zu",
202 neededCapacity,
203 currentCapacity,
204 nextCapacity);
205
206 if (neededCapacity > mEntries.size()) {
207 mEntries.resize(nextCapacity);
208 for (size_t i = currentCapacity; i < nextCapacity; ++i) {
209 mEntries[i].handle = makeHandle(i, 0, type);
210 mEntries[i].nextFreeIndex = i + 1;
211 EM_DBG("new un-init entry: index %zu nextFree %zu",
212 i, i + 1);
213 }
214 }
215
216 // Now we ensured that there is enough space to talk about the entry of
217 // this |fixedHandle|.
218 if (mFirstFreeIndex == newIndex) {
219 isFreeListHead = true;
220 } else {
221 auto& entry = mEntries[newIndex];
222 if (entry.liveGeneration == getHandleGeneration(entry.handle)) {
223 isAlloced = true;
224 } else {
225 isFreeListNonHead = true;
226 }
227 }
228
229 mEntries[newIndex].handle = fixedHandle;
230 mEntries[newIndex].liveGeneration = getHandleGeneration(fixedHandle);
231 mEntries[newIndex].item = item;
232
233 EM_DBG("new index: %zu", newIndex);
234
235 if (isFreeListHead) {
236
237 EM_DBG("first free index reset from %zu to %zu",
238 mFirstFreeIndex, mEntries[newIndex].nextFreeIndex);
239
240 mFirstFreeIndex = mEntries[newIndex].nextFreeIndex;
241
242 ++mLiveEntries;
243
244 } else if (isAlloced) {
245 // Already replaced whatever is there, and since it's already allocated,
246 // no need to update freelist.
247 EM_DBG("entry at %zu already alloced. replacing.", newIndex);
248 } else if (isFreeListNonHead) {
249 // Go through the freelist and skip over the entry we just added.
250 size_t prevEntryIndex = mFirstFreeIndex;
251
252 EM_DBG("in free list but not head. reorganizing freelist. "
253 "start at %zu -> %zu",
254 mFirstFreeIndex, mEntries[prevEntryIndex].nextFreeIndex);
255
256 while (mEntries[prevEntryIndex].nextFreeIndex != newIndex) {
257 EM_DBG("next: %zu -> %zu",
258 prevEntryIndex,
259 mEntries[prevEntryIndex].nextFreeIndex);
260 prevEntryIndex =
261 mEntries[prevEntryIndex].nextFreeIndex;
262 }
263
264 EM_DBG("finished. set prev entry %zu to new entry's next, %zu",
265 prevEntryIndex, mEntries[newIndex].nextFreeIndex);
266
267 mEntries[prevEntryIndex].nextFreeIndex =
268 mEntries[newIndex].nextFreeIndex;
269
270 ++mLiveEntries;
271 }
272
273 return fixedHandle;
274 }
275 void remove(EntityHandle h) {
276
277 if (get(h) == nullptr) return;
278
279 size_t index = getHandleIndex(h);
280
281 EM_DBG("remove handle: 0x%llx -> index %zu", (unsigned long long)h, index);
282
283 auto& entry = mEntries[index];
284
285 EM_DBG("handle gen: %zu entry gen: %zu", getHandleGeneration(h), entry.liveGeneration);
286
287 ++entry.liveGeneration;
288 if ((entry.liveGeneration == 0) ||
289 (entry.liveGeneration == (1ULL << generationBits))) {
290 entry.liveGeneration = 1;
291 }
292
293 entry.nextFreeIndex = mFirstFreeIndex;
294
295 mFirstFreeIndex = index;
296
297 EM_DBG("new first free: %zu next free: %zu", mFirstFreeIndex, entry.nextFreeIndex);
298
299 --mLiveEntries;
300 }
301
302 Item* get(EntityHandle h) {
Lingfeng Yang62dcb4e2021-01-06 14:57:56 -0800303 EM_DBG("get 0x%llx", (unsigned long long)h);
304 size_t index = getHandleIndex(h);
305 if (index >= mEntries.size()) {
306 return nullptr;
307 }
308
309 auto& entry = mEntries[index];
310 if (entry.liveGeneration != getHandleGeneration(h)) {
311 return nullptr;
312 }
313
314 return &entry.item;
315 }
316
317 const Item* get_const(EntityHandle h) const {
Lingfeng Yangc02cb032020-10-26 14:21:25 -0700318 size_t index = getHandleIndex(h);
319 if (index >= mEntries.size()) return nullptr;
320
Lingfeng Yang62dcb4e2021-01-06 14:57:56 -0800321 const auto& entry = mEntries.data() + index;
322 if (entry->liveGeneration != getHandleGeneration(h)) return nullptr;
Lingfeng Yangc02cb032020-10-26 14:21:25 -0700323
Lingfeng Yang62dcb4e2021-01-06 14:57:56 -0800324 return &entry->item;
Lingfeng Yangc02cb032020-10-26 14:21:25 -0700325 }
326
327 bool isLive(EntityHandle h) const {
328 size_t index = getHandleIndex(h);
329 if (index >= mEntries.size()) return false;
330
331 const auto& entry = mEntries[index];
332
333 return (entry.liveGeneration == getHandleGeneration(h));
334 }
335
336 void forEachEntry(IteratorFunc func) {
337 for (auto& entry: mEntries) {
338 auto handle = entry.handle;
339 bool live = isLive(handle);
340 auto& item = entry.item;
341 func(live, handle, item);
342 }
343 }
344
345 void forEachLiveEntry(IteratorFunc func) {
346 for (auto& entry: mEntries) {
347 auto handle = entry.handle;
348 bool live = isLive(handle);
349
350 if (!live) continue;
351
352 auto& item = entry.item;
353 func(live, handle, item);
354 }
355 }
356
357 void forEachLiveEntry_const(ConstIteratorFunc func) const {
358 for (auto& entry: mEntries) {
359 auto handle = entry.handle;
360 bool live = isLive(handle);
361
362 if (!live) continue;
363
364 const auto& item = entry.item;
365 func(live, handle, item);
366 }
367 }
368
369private:
Lingfeng Yang62dcb4e2021-01-06 14:57:56 -0800370 void reserve(size_t count) {
371 if (mEntries.size() < count) {
372 mEntries.resize(count);
373 }
374 for (size_t i = 0; i < count; ++i) {
375 mEntries[i].handle = makeHandle(i, 0, 1);
376 mEntries[i].nextFreeIndex = i + 1;
377 ++mEntries[i].liveGeneration;
378 if ((mEntries[i].liveGeneration == 0) ||
379 (mEntries[i].liveGeneration == (1ULL << generationBits))) {
380 mEntries[i].liveGeneration = 1;
381 }
382 EM_DBG("new un-init entry: index %zu nextFree %zu",
383 i, i + 1);
384 }
385 }
Lingfeng Yangc02cb032020-10-26 14:21:25 -0700386
387 std::vector<EntityEntry> mEntries;
388 size_t mFirstFreeIndex;
389 size_t mLiveEntries;
390};
391
392// Tracks components over a given space of entities.
393// Looking up by entity index is slower, but takes less space overall versus
394// a flat array that parallels the entities.
395template<size_t indexBits,
396 size_t generationBits,
397 size_t typeBits,
398 class Data>
399class ComponentManager {
400public:
401
402 static_assert(64 == (indexBits + generationBits + typeBits),
403 "bits of index, generation, and type must add to 64");
404
405 using ComponentHandle = uint64_t;
406 using EntityHandle = uint64_t;
407 using ComponentIteratorFunc = std::function<void(bool, ComponentHandle componentHandle, EntityHandle entityHandle, Data& data)>;
408 using ConstComponentIteratorFunc = std::function<void(bool, ComponentHandle componentHandle, EntityHandle entityHandle, const Data& data)>;
409
410 // Adds the given |data| and associates it with EntityHandle.
411 // We can also opt-in to immediately tracking the handle in the reverse mapping,
412 // which has an upfront cost in runtime.
413 // Many uses of ComponentManager don't really need to track the associated entity handle,
414 // so it is opt-in.
415
416 ComponentHandle add(
417 EntityHandle h,
418 const Data& data,
419 size_t type,
420 bool tracked = false) {
421
422 InternalItem item = { h, data, tracked };
423 auto res = static_cast<ComponentHandle>(mData.add(item, type));
424
425 if (tracked) {
426 mEntityToComponentMap[h] = res;
427 }
428
429 return res;
430 }
431
432 void clear() {
433 mData.clear();
434 mEntityToComponentMap.clear();
435 }
436
437 // If we didn't explicitly track, just fail.
438 ComponentHandle getComponentHandle(EntityHandle h) const {
439 auto componentHandlePtr = android::base::find(mEntityToComponentMap, h);
440 if (!componentHandlePtr) return INVALID_COMPONENT_HANDLE;
441 return *componentHandlePtr;
442 }
443
444 EntityHandle getEntityHandle(ComponentHandle h) const {
445 return mData.get(h)->entityHandle;
446 }
447
448 void removeByEntity(EntityHandle h) {
449 auto componentHandle = getComponentHandle(h);
450 removeByComponent(componentHandle);
451 }
452
453 void removeByComponent(ComponentHandle h) {
454 auto item = mData.get(h);
455
456 if (!item) return;
457 if (item->tracked) {
458 mEntityToComponentMap.erase(item->entityHandle);
459 }
460
461 mData.remove(h);
462 }
463
464 Data* getByEntity(EntityHandle h) {
465 return getByComponent(getComponentHandle(h));
466 }
467
468 Data* getByComponent(ComponentHandle h) {
469 auto item = mData.get(h);
470 if (!item) return nullptr;
471 return &(item->data);
472 }
473
474 void forEachComponent(ComponentIteratorFunc func) {
475 mData.forEachEntry(
476 [func](bool live, typename InternalEntityManager::EntityHandle componentHandle, InternalItem& item) {
477 func(live, componentHandle, item.entityHandle, item.data);
478 });
479 }
480
481 void forEachLiveComponent(ComponentIteratorFunc func) {
482 mData.forEachLiveEntry(
483 [func](bool live, typename InternalEntityManager::EntityHandle componentHandle, InternalItem& item) {
484 func(live, componentHandle, item.entityHandle, item.data);
485 });
486 }
487
488 void forEachLiveComponent_const(ConstComponentIteratorFunc func) const {
489 mData.forEachLiveEntry_const(
490 [func](bool live, typename InternalEntityManager::EntityHandle componentHandle, const InternalItem& item) {
491 func(live, componentHandle, item.entityHandle, item.data);
492 });
493 }
494
495private:
496 struct InternalItem {
497 EntityHandle entityHandle;
498 Data data;
499 bool tracked;
500 };
501
502 using InternalEntityManager = EntityManager<indexBits, generationBits, typeBits, InternalItem>;
503 using EntityToComponentMap = std::unordered_map<EntityHandle, ComponentHandle>;
504
505 mutable InternalEntityManager mData;
506 EntityToComponentMap mEntityToComponentMap;
507};
508
509// ComponentManager, but unpacked; uses the same index space as the associated
510// entities. Takes more space by default, but not more if all entities have this component.
511template<size_t indexBits,
512 size_t generationBits,
513 size_t typeBits,
514 class Data>
515class UnpackedComponentManager {
516public:
517 using ComponentHandle = uint64_t;
518 using EntityHandle = uint64_t;
519 using ComponentIteratorFunc =
520 std::function<void(bool, ComponentHandle componentHandle, EntityHandle entityHandle, Data& data)>;
521 using ConstComponentIteratorFunc =
522 std::function<void(bool, ComponentHandle componentHandle, EntityHandle entityHandle, const Data& data)>;
523
524 EntityHandle add(EntityHandle h, const Data& data) {
525
526 size_t index = indexOfEntity(h);
527
528 if (index + 1 > mItems.size()) {
529 mItems.resize((index + 1) * 2);
530 }
531
532 mItems[index].live = true;
533 mItems[index].handle = h;
534 mItems[index].data = data;
535
536 return h;
537 }
538
539 void clear() {
540 mItems.clear();
541 }
542
543 void remove(EntityHandle h) {
544 size_t index = indexOfEntity(h);
545 if (index >= mItems.size()) return;
546 mItems[index].live = false;
547 }
548
549 Data* get(EntityHandle h) {
550 size_t index = indexOfEntity(h);
551
552 if (index + 1 > mItems.size()) {
553 mItems.resize((index + 1) * 2);
554 }
555
556 auto item = mItems.data() + index;
557 if (!item->live) return nullptr;
558 return &item->data;
559 }
560
561 const Data* get_const(EntityHandle h) const {
562 size_t index = indexOfEntity(h);
563
564 if (index + 1 > mItems.size()) {
565 return nullptr;
566 }
567
568 auto item = mItems.data() + index;
569 if (!item->live) return nullptr;
570 return &item->data;
571 }
572
573 void forEachComponent(ComponentIteratorFunc func) {
574 for (auto& item : mItems) {
575 func(item.live, item.handle, item.handle, item.data);
576 }
577 }
578
579 void forEachLiveComponent(ComponentIteratorFunc func) {
580 for (auto& item : mItems) {
581 if (item.live) func(item.live, item.handle, item.handle, item.data);
582 }
583 }
584
585 void forEachLiveComponent_const(ConstComponentIteratorFunc func) const {
586 for (auto& item : mItems) {
587 if (item.live) func(item.live, item.handle, item.handle, item.data);
588 }
589 }
590
591private:
592 static size_t indexOfEntity(EntityHandle h) {
593 return EntityManager<indexBits, generationBits, typeBits, int>::getHandleIndex(h);
594 }
595
596 struct InternalItem {
597 bool live = false;
598 EntityHandle handle = 0;
599 Data data;
600 };
601
602 std::vector<InternalItem> mItems;
603};
604
605} // namespace android
606} // namespace base