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