text: /*
   * Copyright (C) 2017 The Android Open Source Project
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  #ifndef TNT_UTILS_ENTITYMANAGER_H
  #define TNT_UTILS_ENTITYMANAGER_H
  
  #include <assert.h>
  #include <stdint.h>
  
  #include <utils/Entity.h>
  
  namespace utils {
  
  class EntityManager {
  public:
      // Get the global EntityManager. Is is recommended to cache this value.
      // Thread Safe.
      static EntityManager& get() noexcept;
  
      class Listener {
      public:
          virtual void onEntitiesDestroyed(size_t n, Entity const* entities) noexcept = 0;
          virtual void onAllEntitiesDestroyed() noexcept = 0;
      protected:
          ~Listener() noexcept = default;
      };
  
  
      // maximum number of entities that can exist at the same time
      static size_t getMaxEntityCount() noexcept {
          // because index 0 is reserved, we only have 2^GENERATION_SHIFT - 1 valid indices
          return RAW_INDEX_COUNT - 1;
      }
  
      // create n entities. Thread safe.
      void create(size_t n, Entity* entities);
  
      // destroys n entities. Thread safe.
      void destroy(size_t n, Entity* entities) noexcept;
  
      // create a new Entity. Thread safe.
      // Return Entity.isNull() if the entity cannot be allocated.
      Entity create() {
          Entity e;
          create(1, &e);
          return e;
      }
  
      // destroys an Entity. Thread safe.
      void destroy(Entity e) noexcept {
          destroy(1, &e);
      }
  
      // return whether the given Entity has been destroyed (false) or not (true).
      // Thread safe.
      bool isAlive(Entity e) const noexcept {
          assert(getIndex(e) < RAW_INDEX_COUNT);
          return (!e.isNull()) && (getGeneration(e) == mGens[getIndex(e)]);
      }
  
      // registers a listener to be called when an entity is destroyed. thread safe.
      // if the listener is already register, this method has no effect.
      void registerListener(Listener* l) noexcept;
  
      // unregisters a listener.
      void unregisterListener(Listener* l) noexcept;
  
      // destroys all entities and return to the initial state. Thread Safe.
      // Use this carefully -- this is mostly for testing
      void clear() noexcept;
  
  
      /* no user serviceable parts below */
  
      // current generation of the given index. Use for debugging and testing.
      uint8_t getGenerationForIndex(size_t index) const noexcept {
          return mGens[index];
      }
      // singleton, can't be copied
      EntityManager(const EntityManager& rhs) = delete;
      EntityManager& operator=(const EntityManager& rhs) = delete;
  
  private:
      friend class EntityManagerImpl;
      EntityManager();
      ~EntityManager();
  
      // GENERATION_SHIFT determines how many simultaneous Entities are available, the
      // minimum memory requirement is 2^GENERATION_SHIFT bytes.
      static constexpr const int GENERATION_SHIFT = 17;
      static constexpr const size_t RAW_INDEX_COUNT = (1 << GENERATION_SHIFT);
      static constexpr const Entity::Type INDEX_MASK = (1 << GENERATION_SHIFT) - 1u;
  
      static inline Entity::Type getGeneration(Entity e) noexcept {
          return e.getId() >> GENERATION_SHIFT;
      }
      static inline Entity::Type getIndex(Entity e) noexcept  {
          return e.getId() & INDEX_MASK;
      }
      static inline Entity::Type makeIdentity(Entity::Type g, Entity::Type i) noexcept {
          return (g << GENERATION_SHIFT) | (i & INDEX_MASK);
      }
  
      // stores the generation of each index.
      uint8_t * const mGens;
  };
  
  } // namespace utils
  
  #endif // TNT_UTILS_ENTITYMANAGER_H
  