<commit_before>#ifndef IAUNS_ENTITY_SYSTEM_COMPONENTCONTAINER_HPP
#define IAUNS_ENTITY_SYSTEM_COMPONENTCONTAINER_HPP

#include <cstdint>
#include <vector>
#include <algorithm>
#include "TemplateID.hpp"
#include "BaseComponentContainer.hpp"

namespace CPM_ES_NS {

/// Component container.
/// \todo Add maximum size caps to the container. Should also check size
///       caps for the number of removed components as well.
template <typename T>
class ComponentContainer : public BaseComponentContainer
{
  // SFINAE implementation of possible function calls inside of component
  // structures.
  template<class V>
  static auto maybe_component_construct(V& v, uint64_t sequence, int)
      -> decltype(v.componentConstruct(sequence), void())
  {
    v.componentConstruct(sequence);
  }

  template<class V>
  static void maybe_component_construct(V&, size_t, long){}


  template<class V>
  static auto maybe_component_destruct(V& v, uint64_t sequence, int)
      -> decltype(v.componentDestruct(sequence), void())
  {
    v.componentDestruct(sequence);
  }

  template<class V>
  static void maybe_component_destruct(V&, size_t, long){}

public:
  ComponentContainer() :
      mIsStatic(false),
      mLastSortedSize(0),
      mUpperSequence(0),
      mLowerSequence(0)
  {
    /// \todo Extract information from global table regarding default / max size
    ///       of components.
    //mComponents.reserve();
  }

  virtual ~ComponentContainer()
  {
    // Remove all componnts, and if their destructors exist, call those
    // as well.
    removeAll();
  }

  /// Item that represents one component paired with a sequence.
  struct ComponentItem
  {
    ComponentItem() : sequence(0)
    {
    }

    ComponentItem(uint64_t seq, const T& comp) :
        sequence(seq),
        component(comp)
    {}

    //ComponentItem(uint64_t seq, T&& comp) :
    //    sequence(seq),
    //    component(std::move(comp))
    //{}

    uint64_t  sequence;   ///< Commonly used element in the first cacheline.
    T         component;  ///< Copy constructable component data.
  };


  static bool componentCompare(const ComponentItem& a, const ComponentItem& b)
  {
    return a.sequence < b.sequence;
  }

  /// Returns -1 if no component of the given sequence is found.
  int getComponentItemIndexWithSequence(uint64_t sequence) const
  {
    if (mComponents.size() == 0)
      return -1;

    // You cannot search within static components. They are the same for all
    // entities. Therefore we return the first index, 0.
    if (isStatic())
      return 0;

    auto last = mComponents.cbegin() + mLastSortedSize;

    ComponentItem item;
    item.sequence = sequence;

    auto it = std::lower_bound(mComponents.cbegin(), last, item,
                               componentCompare);

    if (it->sequence == sequence)
    {
      return it - mComponents.cbegin();
    }
    else
    {
      return -1;
    }
  }

  ComponentItem* getComponentItemWithSequence(uint64_t sequence)
  {
    if (mComponents.size() == 0)
      return nullptr;

    if (isStatic())
      return &mComponents.front();

    auto last = mComponents.begin() + mLastSortedSize;

    // Unfortunately, we have to do this in order to take advantage of
    // STL algorithms (duplicate the exact component).
    ComponentItem item;
    item.sequence = sequence;

    // lower_bound uses a binary search to find the target component.
    // Our vector is always sorted, so we can pull this off.
    auto it = std::lower_bound(mComponents.begin(), last, item,
                               componentCompare);

    if (it->sequence == sequence)
    {
      return &(*it);
    }
    else
    {
      return nullptr;
    }
  }

  /// Retrieves component with the indicated sequence.
  const T* getComponentWithSequence(uint64_t sequence)
  {
    ComponentItem* item = getComponentItemWithSequence(sequence);
    if (item)
      &item->component;
    else
      return item;
  }

  /// Sorts in added components and removes deleted components.
  /// Neither of these operations (addition or deletion) take affect when the
  /// system is operating. This way, each timestep is completely deterministic.
  /// The same set of data is acted upon by all systems.
  void renormalize(bool stableSort) override
  {
    // Changes should come FIRST. Changes rely on direct indices to values.
    // No additions or removals should come before modifications.

    // Removals should come *after* addition of new components. This keeps
    // logic consistent within one frame in an entire entity was removed.
    // If an entity was adding components to itself, then subsequently deleted,
    // some of it's components would be left dangling if removal was performed
    // first. But, adding before removal has no side effects, especially if
    // stable sort is used. Then removal from the beginning or end of the list
    // is guaranteed to be consistent.

    if (mModifications.size() > 0)
    {
      // Sort modifications to maintain some semblance of cache friendliness
      // and to detect modification conflicts and resolve with priority.
      // Stable sort is not needed, a priority is used to determine who
      // resolves the modifications.<commit_msg>Add getComponent function to ComponentContainer.<commit_after>#ifndef IAUNS_ENTITY_SYSTEM_COMPONENTCONTAINER_HPP
#define IAUNS_ENTITY_SYSTEM_COMPONENTCONTAINER_HPP

#include <cstdint>
#include <vector>
#include <algorithm>
#include "TemplateID.hpp"
#include "BaseComponentContainer.hpp"

namespace CPM_ES_NS {

/// Component container.
/// \todo Add maximum size caps to the container. Should also check size
///       caps for the number of removed components as well.
template <typename T>
class ComponentContainer : public BaseComponentContainer
{
  // SFINAE implementation of possible function calls inside of component
  // structures.
  template<class V>
  static auto maybe_component_construct(V& v, uint64_t sequence, int)
      -> decltype(v.componentConstruct(sequence), void())
  {
    v.componentConstruct(sequence);
  }

  template<class V>
  static void maybe_component_construct(V&, size_t, long){}


  template<class V>
  static auto maybe_component_destruct(V& v, uint64_t sequence, int)
      -> decltype(v.componentDestruct(sequence), void())
  {
    v.componentDestruct(sequence);
  }

  template<class V>
  static void maybe_component_destruct(V&, size_t, long){}

public:
  ComponentContainer() :
      mIsStatic(false),
      mLastSortedSize(0),
      mUpperSequence(0),
      mLowerSequence(0)
  {
    /// \todo Extract information from global table regarding default / max size
    ///       of components.
    //mComponents.reserve();
  }

  virtual ~ComponentContainer()
  {
    // Remove all componnts, and if their destructors exist, call those
    // as well.
    removeAll();
  }

  /// Item that represents one component paired with a sequence.
  struct ComponentItem
  {
    ComponentItem() : sequence(0)
    {
    }

    ComponentItem(uint64_t seq, const T& comp) :
        sequence(seq),
        component(comp)
    {}

    //ComponentItem(uint64_t seq, T&& comp) :
    //    sequence(seq),
    //    component(std::move(comp))
    //{}

    uint64_t  sequence;   ///< Commonly used element in the first cacheline.
    T         component;  ///< Copy constructable component data.
  };


  static bool componentCompare(const ComponentItem& a, const ComponentItem& b)
  {
    return a.sequence < b.sequence;
  }

  /// Returns -1 if no component of the given sequence is found.
  int getComponentItemIndexWithSequence(uint64_t sequence) const
  {
    if (mComponents.size() == 0)
      return -1;

    // You cannot search within static components. They are the same for all
    // entities. Therefore we return the first index, 0.
    if (isStatic())
      return 0;

    auto last = mComponents.cbegin() + mLastSortedSize;

    ComponentItem item;
    item.sequence = sequence;

    auto it = std::lower_bound(mComponents.cbegin(), last, item,
                               componentCompare);

    if (it->sequence == sequence)
    {
      return it - mComponents.cbegin();
    }
    else
    {
      return -1;
    }
  }

  ComponentItem* getComponentItemWithSequence(uint64_t sequence)
  {
    if (mComponents.size() == 0)
      return nullptr;

    if (isStatic())
      return &mComponents.front();

    auto last = mComponents.begin() + mLastSortedSize;

    // Unfortunately, we have to do this in order to take advantage of
    // STL algorithms (duplicate the exact component).
    ComponentItem item;
    item.sequence = sequence;

    // lower_bound uses a binary search to find the target component.
    // Our vector is always sorted, so we can pull this off.
    auto it = std::lower_bound(mComponents.begin(), last, item,
                               componentCompare);

    if (it->sequence == sequence)
    {
      return &(*it);
    }
    else
    {
      return nullptr;
    }
  }

  /// Retrieves component with the indicated sequence.
  const T* getComponentWithSequence(uint64_t sequence)
  {
    ComponentItem* item = getComponentItemWithSequence(sequence);
    if (item)
      &item->component;
    else
      return item;
  }

  /// Retrieves the component for the given sequence. Returns both a pointer
  /// to the component and its index in the component container. You can
  /// use this index to modify the components value using modifyIndex.
  std::pair<const T*, size_t> getComponent(uint64_t sequence) const
  {
    if (mComponents.size() == 0)
      return std::make_pair(nullptr, 0);

    if (isStatic())
      return std::make_pair(&mComponents.front().component, 0);

    auto last = mComponents.cbegin() + mLastSortedSize;

    // Unfortunately, we have to do this in order to take advantage of
    // STL algorithms (duplicate the exact component).
    ComponentItem item;
    item.sequence = sequence;

    // lower_bound uses a binary search to find the target component.
    // Our vector is always sorted, so we can pull this off.
    auto it = std::lower_bound(mComponents.cbegin(), last, item,
                               componentCompare);

    if (it->sequence == sequence)
    {
      size_t index = it - mComponents.cbegin();
      return std::make_pair(&it->component, index);
    }
    else
    {
      return std::make_pair(nullptr, 0);
    }
  }

  /// Sorts in added components and removes deleted components.
  /// Neither of these operations (addition or deletion) take affect when the
  /// system is operating. This way, each timestep is completely deterministic.
  /// The same set of data is acted upon by all systems.
  void renormalize(bool stableSort) override
  {
    // Changes should come FIRST. Changes rely on direct indices to values.
    // No additions or removals should come before modifications.

    // Removals should come *after* addition of new components. This keeps
    // logic consistent within one frame in an entire entity was removed.
    // If an entity was adding components to itself, then subsequently deleted,
    // some of it's components would be left dangling if removal was performed
    // first. But, adding before removal has no side effects, especially if
    // stable sort is used. Then removal from the beginning or end of the list
    // is guaranteed to be consistent.

    if (mModifications.size() > 0)
    {
      // Sort modifications to maintain some semblance of cache friendliness
      // and to detect modification conflicts and resolve with priority.
      // Stable sort is not needed, a priority is used to determine who
      // resolves the modifications.
{'fraction_non_alphanumeric': 0.09077636551013397, 'fraction_numerical': 0.005324630711095843, 'mean_word_length': 2.800587467362924, 'pattern_counts': {'":': 0, '<': 26, '<?xml version=': 0, '>': 34, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2259228', 'n_tokens_mistral': 3292, 'n_tokens_neox': 3156, 'n_words': 1146}