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