<commit_before>#pragma once
#include "AnySharedPointer.h"
#include "AutoCheckout.h"
#include "auto_out.h"
#include "auto_pooled.h"
#include "Object.h"
#include "optional_ptr.h"
#include "SatCounter.h"
#include <boost/any.hpp>
#include <boost/thread/mutex.hpp>
#include MEMORY_HEADER
#include TYPE_INDEX_HEADER
#include STL_UNORDERED_MAP
#include EXCEPTION_PTR_HEADER

class AutoPacketFactory;
class AutoPacketProfiler;
class AutoPacketSubscriber;

template<class T>
struct subscriber_traits;

/// <summary>
/// A decorator-style processing packet
/// </summary>
/// <remarks>
/// A processing packet may be decorated with additional types as desired by the user.
/// The pipeline packet is not a type of context; querying the packet for an element of
/// a particular type will look for an element of precisely that type, not an inherited
/// type or a related interface.
///
/// Consumers who wish to advertise a particular field under multiple types must do so
/// manually with the Advertise function.
/// </remarks>
class AutoPacket:
  public std::enable_shared_from_this<AutoPacket>
{
public:
  AutoPacket(AutoPacketFactory& factory);
  ~AutoPacket(void);

private:
  /// <remarks>
  /// A disposition holder, used to maintain initialization state on the key
  /// </remarks>
  struct DecorationDisposition
  {
    DecorationDisposition(void) :
      m_pImmediate(nullptr),
      satisfied(false),
      isCheckedOut(false),
      wasCheckedOut(false)
    {}

    // The decoration proper--potentially, this decoration might be from a prior execution of this
    // packet.  In the case of immediate decorations, this value will be invalid.
    AnySharedPointer m_decoration;

    // A pointer to the immediate decoration, if one is specified, or else nullptr
    const void* m_pImmediate;

    // Satisfaction counters, with the second part indicating a required entry
    std::vector<std::pair<SatCounter*, bool>> m_subscribers;

    // Flag indicating that this entry is satisfied
    bool satisfied;

    // Indicates that the internally held object is currently checked out
    bool isCheckedOut;

    // Indicates that this entry was checked out at some point in the past, and can no longer be
    // checked out for a subsequent satisfaction
    bool wasCheckedOut;

    void Reset(void) {
      satisfied = false;
      isCheckedOut = false;
      wasCheckedOut = false;
    }
  };

  // The parent packet factory:
  AutoPacketFactory& m_factory;

  // A back-link to the previously issued packet in the packet sequence.  May potentially be null,
  // if this is the first packet issued by the packet factory.
  std::shared_ptr<AutoPacket> m_prior;

  // The set of decorations currently attached to this object, and the associated lock:
  mutable boost::mutex m_lock;
  std::unordered_map<std::type_index, DecorationDisposition> m_decorations;

  // Saturation counters, constructed when the packet is created and reset each time thereafter
  std::vector<SatCounter> m_satCounters;

  /// <summary>
  /// Marks the specified entry as being unsatisfiable
  /// </summary>
  void MarkUnsatisfiable(const std::type_info& info);

  /// <summary>
  /// Updates subscriber statuses given that the specified type information has been satisfied
  /// </summary>
  /// <param name="info">The decoration which was just added to this packet</param>
  /// <remarks>
  /// This method results in a call to the AutoFilter method on any subscribers which are
  /// satisfied by this decoration.
  /// </remarks>
  void UpdateSatisfaction(const std::type_info& info);

  /// <summary>
  /// Performs a "satisfaction pulse", which will avoid notifying any deferred filters
  /// </summary>
  void PulseSatisfaction(const std::type_info& info);

  /// <summary>
  /// Invoked from a checkout when a checkout has completed
  /// <param name="ready">Ready flag, set to false if the decoration should be marked unsatisfiable</param>
  template<class T>
  void CompleteCheckout(bool ready) {
    {
      boost::lock_guard<boost::mutex> lk(m_lock);
      auto& entry = m_decorations[typeid(T)];

      if(!ready)
        // Memory must be released, the checkout was cancelled
        entry.m_decoration->reset();

      // Reset the checkout flag before releasing the lock:
      assert(entry.isCheckedOut);
      entry.isCheckedOut = false;
    }

    if(ready)
      UpdateSatisfaction(typeid(T));
    else
      MarkUnsatisfiable(typeid(T));
  }

public:
  /// <summary>
  /// Clears all decorations and copies over all satisfaction counters
  /// </summary>
  void Reset(void);

  /// <summary>
  /// Detects the desired type, or throws an exception if such a type cannot be found
  /// </summary>
  template<class T>
  const T& Get(void) const {
    const T* retVal;
    if(!Get(retVal))
      throw_rethrowable std::runtime_error("Attempted to obtain a value which was not decorated on this packet");
    return *retVal;
  }

  /// <summary>
  /// Determines whether this pipeline packet contains an entry of the specified type
  /// </summary>
  template<class T>
  bool Get(const T*& out) const {
    static_assert(!std::is_same<T, AutoPacket>::value, "Cannot decorate a packet with another packet");

    auto q = m_decorations.find(typeid(T));
    if(q != m_decorations.end() && q->second.satisfied) {
      auto& disposition = q->second;
      if(disposition.m_decoration) {
        out = disposition.m_decoration->as<T>().get();
        return true;
      }
    }

    out = nullptr;
    return false;
  }

  /// <summary>
  /// Provides the passed enumerator function with a list of all interior types
  /// </summary>
  template<class Fx>
  void Enumerate(Fx&& fx) {
    boost::lock_guard<boost::mutex> lk(m_lock);
    for(auto q = m_decorations.begin(); q != m_decorations.end(); q++)
      if(q->second.satisfied)
        fx(q->first, q->second.pEnclosure);
  }

  /// <summary>
  /// Checks out the specified type, providing it to the caller to be filled in
  /// </summary>
  /// <param name="use_pool">If set, allocations will use an object pool instead of an
  /// <remarks>
  /// The caller must call Ready on the returned value before it falls out of scope in order
  /// to ensure that the checkout is eventually committed.  The checkout will be committed
  /// when it falls out of scope if so marked.
  /// </remarks>
  template<class T>
  AutoCheckout<T> Checkout(bool use_pool = false) {
    // This allows us to install correct entries for decorated input requests
    typedef typename subscriber_traits<T>::type type;

    DecorationDisposition* entry;
    {
      boost::lock_guard<boost::mutex> lk(m_lock);
      auto q = m_decorations.find(typeid(type));
      if(q == m_decorations.end())
        // No parties interested in this entry, return here
        return AutoCheckout<T>(*this, nullptr, &AutoPacket::CompleteCheckout<T>);

      entry = &m_decorations[typeid(type)];
      if(entry->satisfied)
        throw std::runtime_error("Cannot decorate this packet with type T, the requested decoration already exists");
      entry->satisfied = true;
      entry->isCheckedOut = true;
      entry->wasCheckedOut = true;
    }

    auto& enclosure = (entry->m_decoration = std::make_shared<T>());
    return AutoCheckout<T>(
      *this,
      enclosure.get(),
      &AutoPacket::CompleteCheckout<T>
    );
  }

  /// <summary>
  /// Marks the named decoration as unsatisfiable
  /// </summary>
  /// <remarks>
  /// Marking a decoration as unsatisfiable immediately causes any filters with an optional
  /// input on this type to be called, if the remainder of their inputs are available.
  /// </remarks>
  template<class T>
  void Unsatisfiable(void) {
    {
      // Insert a null entry at this location:
      boost::lock_guard<boost::mutex> lk(m_lock);
      auto& entry = m_decorations[typeid(T)];
      if(entry.satisfied)
        throw std::runtime_error("Cannot mark a decoration as unsatisfiable when that decoration is already present on this packet");

      // Mark the entry as appropriate:
      entry.satisfied = true;
      entry.wasCheckedOut = true;
    }

    // Now trigger a rescan:
    MarkUnsatisfiable(typeid(T));
  }

  /// <summary>
  /// Decorates this packet with a particular type
  /// </summary>
  /// <returns>A reference to the internally persisted object</returns>
  /// <remarks>
  /// Unlike Publish, the Decorate method is unconditional and will install the passed
  /// value regardless of whether any subscribers exist.
  /// </remarks>
  template<class T>
  T& Decorate(T&& t) {
    DecorationDisposition* pEntry;
    {
      boost::lock_guard<boost::mutex> lk(m_lock);
      pEntry = &m_decorations[typeid(T)];
      if(pEntry->satisfied)
        throw std::runtime_error("Cannot decorate this packet with type T, the requested decoration already exists");
      pEntry->satisfied = true;
    }

    SharedPointerSlotT<T>& retVal = pEntry->m_decoration->init<T>();
    retVal = std::make_shared<T>(std::forward<T>(t));
    UpdateSatisfaction(typeid(T));
    return *retVal;
  }

  /// <summary>
  /// Attaches a decoration which will only be valid for the duration of the call
  /// </summary>
  /// <remarks>
  /// The attached decoration is only valid for AutoFilters which are valid during
  /// this call.  The type of the decoration is "T", and the passed pointer is not
  /// copied.
  /// </remarks>
  template<class T>
  void DecorateImmediate(const T* pt) {
    // Perform standard decoration with a short initialization:
    DecorationDisposition* pEntry;
    {
      boost::lock_guard<boost::mutex> lk(m_lock);
      pEntry = &m_decorations[typeid(T)];
      if(pEntry->satisfied)
        throw std::runtime_error("Cannot perform immediate decoration with type T, the requested decoration already exists");
      pEntry->satisfied = true;<commit_msg>Correcting bad use of reference type<commit_after>#pragma once
#include "AnySharedPointer.h"
#include "AutoCheckout.h"
#include "auto_out.h"
#include "auto_pooled.h"
#include "Object.h"
#include "optional_ptr.h"
#include "SatCounter.h"
#include <boost/any.hpp>
#include <boost/thread/mutex.hpp>
#include MEMORY_HEADER
#include TYPE_INDEX_HEADER
#include STL_UNORDERED_MAP
#include EXCEPTION_PTR_HEADER

class AutoPacketFactory;
class AutoPacketProfiler;
class AutoPacketSubscriber;

template<class T>
struct subscriber_traits;

/// <summary>
/// A decorator-style processing packet
/// </summary>
/// <remarks>
/// A processing packet may be decorated with additional types as desired by the user.
/// The pipeline packet is not a type of context; querying the packet for an element of
/// a particular type will look for an element of precisely that type, not an inherited
/// type or a related interface.
///
/// Consumers who wish to advertise a particular field under multiple types must do so
/// manually with the Advertise function.
/// </remarks>
class AutoPacket:
  public std::enable_shared_from_this<AutoPacket>
{
public:
  AutoPacket(AutoPacketFactory& factory);
  ~AutoPacket(void);

private:
  /// <remarks>
  /// A disposition holder, used to maintain initialization state on the key
  /// </remarks>
  struct DecorationDisposition
  {
    DecorationDisposition(void) :
      m_pImmediate(nullptr),
      satisfied(false),
      isCheckedOut(false),
      wasCheckedOut(false)
    {}

    // The decoration proper--potentially, this decoration might be from a prior execution of this
    // packet.  In the case of immediate decorations, this value will be invalid.
    AnySharedPointer m_decoration;

    // A pointer to the immediate decoration, if one is specified, or else nullptr
    const void* m_pImmediate;

    // Satisfaction counters, with the second part indicating a required entry
    std::vector<std::pair<SatCounter*, bool>> m_subscribers;

    // Flag indicating that this entry is satisfied
    bool satisfied;

    // Indicates that the internally held object is currently checked out
    bool isCheckedOut;

    // Indicates that this entry was checked out at some point in the past, and can no longer be
    // checked out for a subsequent satisfaction
    bool wasCheckedOut;

    void Reset(void) {
      satisfied = false;
      isCheckedOut = false;
      wasCheckedOut = false;
    }
  };

  // The parent packet factory:
  AutoPacketFactory& m_factory;

  // A back-link to the previously issued packet in the packet sequence.  May potentially be null,
  // if this is the first packet issued by the packet factory.
  std::shared_ptr<AutoPacket> m_prior;

  // The set of decorations currently attached to this object, and the associated lock:
  mutable boost::mutex m_lock;
  std::unordered_map<std::type_index, DecorationDisposition> m_decorations;

  // Saturation counters, constructed when the packet is created and reset each time thereafter
  std::vector<SatCounter> m_satCounters;

  /// <summary>
  /// Marks the specified entry as being unsatisfiable
  /// </summary>
  void MarkUnsatisfiable(const std::type_info& info);

  /// <summary>
  /// Updates subscriber statuses given that the specified type information has been satisfied
  /// </summary>
  /// <param name="info">The decoration which was just added to this packet</param>
  /// <remarks>
  /// This method results in a call to the AutoFilter method on any subscribers which are
  /// satisfied by this decoration.
  /// </remarks>
  void UpdateSatisfaction(const std::type_info& info);

  /// <summary>
  /// Performs a "satisfaction pulse", which will avoid notifying any deferred filters
  /// </summary>
  void PulseSatisfaction(const std::type_info& info);

  /// <summary>
  /// Invoked from a checkout when a checkout has completed
  /// <param name="ready">Ready flag, set to false if the decoration should be marked unsatisfiable</param>
  template<class T>
  void CompleteCheckout(bool ready) {
    {
      boost::lock_guard<boost::mutex> lk(m_lock);
      auto& entry = m_decorations[typeid(T)];

      if(!ready)
        // Memory must be released, the checkout was cancelled
        entry.m_decoration->reset();

      // Reset the checkout flag before releasing the lock:
      assert(entry.isCheckedOut);
      entry.isCheckedOut = false;
    }

    if(ready)
      UpdateSatisfaction(typeid(T));
    else
      MarkUnsatisfiable(typeid(T));
  }

public:
  /// <summary>
  /// Clears all decorations and copies over all satisfaction counters
  /// </summary>
  void Reset(void);

  /// <summary>
  /// Detects the desired type, or throws an exception if such a type cannot be found
  /// </summary>
  template<class T>
  const T& Get(void) const {
    const T* retVal;
    if(!Get(retVal))
      throw_rethrowable std::runtime_error("Attempted to obtain a value which was not decorated on this packet");
    return *retVal;
  }

  /// <summary>
  /// Determines whether this pipeline packet contains an entry of the specified type
  /// </summary>
  template<class T>
  bool Get(const T*& out) const {
    static_assert(!std::is_same<T, AutoPacket>::value, "Cannot decorate a packet with another packet");

    auto q = m_decorations.find(typeid(T));
    if(q != m_decorations.end() && q->second.satisfied) {
      auto& disposition = q->second;
      if(disposition.m_decoration) {
        out = disposition.m_decoration->as<T>().get();
        return true;
      }
    }

    out = nullptr;
    return false;
  }

  /// <summary>
  /// Provides the passed enumerator function with a list of all interior types
  /// </summary>
  template<class Fx>
  void Enumerate(Fx&& fx) {
    boost::lock_guard<boost::mutex> lk(m_lock);
    for(auto q = m_decorations.begin(); q != m_decorations.end(); q++)
      if(q->second.satisfied)
        fx(q->first, q->second.pEnclosure);
  }

  /// <summary>
  /// Checks out the specified type, providing it to the caller to be filled in
  /// </summary>
  /// <param name="use_pool">If set, allocations will use an object pool instead of an
  /// <remarks>
  /// The caller must call Ready on the returned value before it falls out of scope in order
  /// to ensure that the checkout is eventually committed.  The checkout will be committed
  /// when it falls out of scope if so marked.
  /// </remarks>
  template<class T>
  AutoCheckout<T> Checkout(bool use_pool = false) {
    // This allows us to install correct entries for decorated input requests
    typedef typename subscriber_traits<T>::type type;

    DecorationDisposition* entry;
    {
      boost::lock_guard<boost::mutex> lk(m_lock);
      auto q = m_decorations.find(typeid(type));
      if(q == m_decorations.end())
        // No parties interested in this entry, return here
        return AutoCheckout<T>(*this, nullptr, &AutoPacket::CompleteCheckout<T>);

      entry = &m_decorations[typeid(type)];
      if(entry->satisfied)
        throw std::runtime_error("Cannot decorate this packet with type T, the requested decoration already exists");
      entry->satisfied = true;
      entry->isCheckedOut = true;
      entry->wasCheckedOut = true;
    }

    auto& enclosure = (entry->m_decoration = std::make_shared<T>());
    return AutoCheckout<T>(
      *this,
      enclosure.get(),
      &AutoPacket::CompleteCheckout<T>
    );
  }

  /// <summary>
  /// Marks the named decoration as unsatisfiable
  /// </summary>
  /// <remarks>
  /// Marking a decoration as unsatisfiable immediately causes any filters with an optional
  /// input on this type to be called, if the remainder of their inputs are available.
  /// </remarks>
  template<class T>
  void Unsatisfiable(void) {
    {
      // Insert a null entry at this location:
      boost::lock_guard<boost::mutex> lk(m_lock);
      auto& entry = m_decorations[typeid(T)];
      if(entry.satisfied)
        throw std::runtime_error("Cannot mark a decoration as unsatisfiable when that decoration is already present on this packet");

      // Mark the entry as appropriate:
      entry.satisfied = true;
      entry.wasCheckedOut = true;
    }

    // Now trigger a rescan:
    MarkUnsatisfiable(typeid(T));
  }

  /// <summary>
  /// Decorates this packet with a particular type
  /// </summary>
  /// <returns>A reference to the internally persisted object</returns>
  /// <remarks>
  /// Unlike Publish, the Decorate method is unconditional and will install the passed
  /// value regardless of whether any subscribers exist.
  /// </remarks>
  template<class T>
  T& Decorate(T&& t) {
    typedef typename std::remove_reference<T>::type Type;

    DecorationDisposition* pEntry;
    {
      boost::lock_guard<boost::mutex> lk(m_lock);
      pEntry = &m_decorations[typeid(Type)];
      if(pEntry->satisfied)
        throw std::runtime_error("Cannot decorate this packet with type T, the requested decoration already exists");
      pEntry->satisfied = true;
    }

    SharedPointerSlotT<Type>& retVal = pEntry->m_decoration->init<Type>();
    retVal = std::make_shared<Type>(std::forward<T>(t));
    UpdateSatisfaction(typeid(Type));
    return *retVal;
  }

  /// <summary>
  /// Attaches a decoration which will only be valid for the duration of the call
  /// </summary>
  /// <remarks>
  /// The attached decoration is only valid for AutoFilters which are valid during
  /// this call.  The type of the decoration is "T", and the passed pointer is not
  /// copied.
  /// </remarks>
  template<class T>
  void DecorateImmediate(const T* pt) {
    // Perform standard decoration with a short initialization:
    DecorationDisposition* pEntry;
    {
      boost::lock_guard<boost::mutex> lk(m_lock);
      pEntry = &m_decorations[typeid(T)];
      if(pEntry->satisfied)
        throw std::runtime_error("Cannot perform immediate decoration with type T, the requested decoration already exists");
      pEntry->satisfied = true;
{'fraction_non_alphanumeric': 0.10909735230091631, 'fraction_numerical': 0.0, 'mean_word_length': 3.216435432230523, 'pattern_counts': {'":': 0, '<': 168, '<?xml version=': 0, '>': 204, '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': '4838659', 'n_tokens_mistral': 5793, 'n_tokens_neox': 5558, 'n_words': 1958}