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