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 "aemu/base/containers/Lookup.h" 17 #include "aemu/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(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 getHandleIndex(EntityHandle h)59 static size_t getHandleIndex(EntityHandle h) { 60 return static_cast<size_t>(h & ((1ULL << indexBits) - 1ULL)); 61 } 62 getHandleGeneration(EntityHandle h)63 static size_t getHandleGeneration(EntityHandle h) { 64 return static_cast<size_t>( 65 (h >> indexBits) & 66 ((1ULL << generationBits) - 1ULL)); 67 } 68 getHandleType(EntityHandle h)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 makeHandle(size_t index,size_t generation,size_t type)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 withIndex(EntityHandle h,size_t i)86 static EntityHandle withIndex(EntityHandle h, size_t i) { 87 return makeHandle(i, getHandleGeneration(h), getHandleType(h)); 88 } 89 withGeneration(EntityHandle h,size_t nextGen)90 static EntityHandle withGeneration(EntityHandle h, size_t nextGen) { 91 return makeHandle(getHandleIndex(h), nextGen, getHandleType(h)); 92 } 93 withType(EntityHandle h,size_t newType)94 static EntityHandle withType(EntityHandle h, size_t newType) { 95 return makeHandle(getHandleIndex(h), getHandleGeneration(h), newType); 96 } 97 EntityManager()98 EntityManager() : EntityManager(0) { } 99 EntityManager(size_t initialItems)100 EntityManager(size_t initialItems) : 101 mEntries(initialItems), 102 mFirstFreeIndex(0), 103 mLiveEntries(0) { 104 reserve(initialItems); 105 } 106 ~EntityManager()107 ~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 clear()118 void clear() { 119 reserve(mEntries.size()); 120 mFirstFreeIndex = 0; 121 mLiveEntries = 0; 122 } 123 nextFreeIndex()124 size_t nextFreeIndex() const { 125 return mFirstFreeIndex; 126 } 127 add(const Item & item,size_t type)128 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 addFixed(EntityHandle fixedHandle,const Item & item,size_t type)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 } remove(EntityHandle h)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 get(EntityHandle h)302 Item* get(EntityHandle h) { 303 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 get_const(EntityHandle h)317 const Item* get_const(EntityHandle h) const { 318 size_t index = getHandleIndex(h); 319 if (index >= mEntries.size()) return nullptr; 320 321 const auto& entry = mEntries.data() + index; 322 if (entry->liveGeneration != getHandleGeneration(h)) return nullptr; 323 324 return &entry->item; 325 } 326 isLive(EntityHandle h)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 forEachEntry(IteratorFunc func)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 forEachLiveEntry(IteratorFunc func)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 forEachLiveEntry_const(ConstIteratorFunc func)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 369 private: reserve(size_t count)370 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 } 386 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. 395 template<size_t indexBits, 396 size_t generationBits, 397 size_t typeBits, 398 class Data> 399 class ComponentManager { 400 public: 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 clear()432 void clear() { 433 mData.clear(); 434 mEntityToComponentMap.clear(); 435 } 436 437 // If we didn't explicitly track, just fail. getComponentHandle(EntityHandle h)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 getEntityHandle(ComponentHandle h)444 EntityHandle getEntityHandle(ComponentHandle h) const { 445 return mData.get(h)->entityHandle; 446 } 447 removeByEntity(EntityHandle h)448 void removeByEntity(EntityHandle h) { 449 auto componentHandle = getComponentHandle(h); 450 removeByComponent(componentHandle); 451 } 452 removeByComponent(ComponentHandle h)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 getByEntity(EntityHandle h)464 Data* getByEntity(EntityHandle h) { 465 return getByComponent(getComponentHandle(h)); 466 } 467 getByComponent(ComponentHandle h)468 Data* getByComponent(ComponentHandle h) { 469 auto item = mData.get(h); 470 if (!item) return nullptr; 471 return &(item->data); 472 } 473 forEachComponent(ComponentIteratorFunc func)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 forEachLiveComponent(ComponentIteratorFunc func)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 forEachLiveComponent_const(ConstComponentIteratorFunc func)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 495 private: 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. 511 template<size_t indexBits, 512 size_t generationBits, 513 size_t typeBits, 514 class Data> 515 class UnpackedComponentManager { 516 public: 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 add(EntityHandle h,const Data & data)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 clear()539 void clear() { 540 mItems.clear(); 541 } 542 remove(EntityHandle h)543 void remove(EntityHandle h) { 544 size_t index = indexOfEntity(h); 545 if (index >= mItems.size()) return; 546 mItems[index].live = false; 547 } 548 get(EntityHandle h)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 get_const(EntityHandle h)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 forEachComponent(ComponentIteratorFunc func)573 void forEachComponent(ComponentIteratorFunc func) { 574 for (auto& item : mItems) { 575 func(item.live, item.handle, item.handle, item.data); 576 } 577 } 578 forEachLiveComponent(ComponentIteratorFunc func)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 forEachLiveComponent_const(ConstComponentIteratorFunc func)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 591 private: indexOfEntity(EntityHandle h)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 607