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