Program Listing for File CachingOutletWrapper.hpp

Return to documentation for file (include/uit/spouts/wrappers/outlet/CachingOutletWrapper.hpp)

#pragma once
#ifndef UIT_SPOUTS_WRAPPERS_OUTLET_CACHINGOUTLETWRAPPER_HPP_INCLUDE
#define UIT_SPOUTS_WRAPPERS_OUTLET_CACHINGOUTLETWRAPPER_HPP_INCLUDE

#include <cstddef>
#include <optional>
#include <string>
#include <typeinfo>

#include "../../../../uit_emp/datastructs/QueueCache.hpp"

#include "../../../../uitsl/debug/WarnOnce.hpp"
#include "../../../../uitsl/distributed/CachePacket.hpp"
#include "../../../../uitsl/mpi/proc_id_t.hpp"
#include "../../../../uitsl/parallel/thread_utils.hpp"

namespace uit {
namespace internal {

template<typename Outlet>
class CachingOutletWrapper {

  Outlet outlet;

  using ImplSpec = typename Outlet::ImplSpec;

  using this_t = CachingOutletWrapper<Outlet>;
  using value_type = typename ImplSpec::value_type;

  uit_emp::QueueCache<
    size_t,
    value_type,
    ImplSpec::SpoutCacheSize
  > cache;

  void CacheCurrent() {
    const auto& packet = outlet.Get();
    if ( packet.HasData() ) cache.Put( packet.GetID(), packet.GetData() );
    else if ( cache.Contains(packet.GetID()) ) cache.Get( packet.GetID() );
    //^ Get moves item to the front of the cache
    else {
      static const uitsl::WarnOnce w{ "missing cache packet" };
    }
  }

  size_t DoProcTryStep(const size_t num_steps=1) {

    size_t num_steps_countdown{ num_steps };

    while ( num_steps_countdown && outlet.TryStep( 1 ) ) {
      --num_steps_countdown;
      CacheCurrent();
    }

    return num_steps - num_steps_countdown;
  }

  size_t DoProcJump() {
    if ( CanStep() ) return DoProcTryStep( std::numeric_limits<size_t>::max() );
    else {
      const size_t res{ outlet.Jump() };
      CacheCurrent();
      return res;
    }
  }

  const value_type& DoProcGet() const {
    const static value_type pristine{};
    if ( cache.Empty() ) return pristine;
    else return cache.begin()->second;
  }

  value_type& DoProcGet() {
    const static uitsl::WarnOnce w{
      std::string{}
      + "Calling non-const Get on CachingOutletWrapper incurs extra copy, T "
      + typeid( value_type ).name()
      + " ... consider using std::as_const"
    };

    thread_local value_type mutable_copy;
    mutable_copy = const_cast<const this_t*>(this)->DoProcGet();
    return mutable_copy;
  }


public:

  CachingOutletWrapper(CachingOutletWrapper& other) = default;

  CachingOutletWrapper(const CachingOutletWrapper& other) = default;

  CachingOutletWrapper(CachingOutletWrapper&& other) = default;

  template <typename... Args>
  CachingOutletWrapper(Args&&... args)
  : outlet(std::forward<Args>(args)...)
  { ; }

  size_t TryStep(const size_t num_steps) {
    if ( HoldsProcImpl().value_or( true ) ) return DoProcTryStep( num_steps );
    else return outlet.TryStep( num_steps );
  }

  size_t Jump() {
    if ( HoldsProcImpl().value_or( true ) ) return DoProcJump();
    else return outlet.Jump();
  }

  const value_type& Get() const {
    if ( HoldsProcImpl().value_or( true ) ) return DoProcGet();
    else return outlet.Get().GetData();
  }

  value_type& Get() {
    if ( HoldsProcImpl().value_or( true ) ) return DoProcGet();
    else return outlet.Get().GetData();
  }

  const value_type& JumpGet() { Jump(); return Get(); }

  void Step(size_t num_steps=1) {
    while ( num_steps ) num_steps -= TryStep(num_steps);
  }

  const value_type& GetNext() { while (TryStep() == 0); return Get(); }

  using optional_ref_t = std::optional<std::reference_wrapper<
    const value_type
  >>;

  optional_ref_t GetNextOrNullopt() {
  return TryStep()
    ? optional_ref_t{ std::reference_wrapper{ Get() } }
    : std::nullopt;
  }

  decltype(auto) GetNumReadsPerformed() const {
    return outlet.GetNumReadsPerformed();
  }

  decltype(auto) GetNumReadsThatWereFresh() const {
    return outlet.GetNumReadsThatWereFresh();
  }

  decltype(auto) GetNumReadsThatWereStale() const {
    return outlet.GetNumReadsThatWereStale();
  }

  decltype(auto) GetNumRevisionsPulled() const {
    return outlet.GetNumRevisionsPulled();
  }

  decltype(auto) GetNumTryPullsAttempted() const {
    return outlet.GetNumTryPullsAttempted();
  }

  decltype(auto) GetNumBlockingPulls() const {
    return outlet.GetNumBlockingPulls();
  }

  decltype(auto) GetNumBlockingPullsThatBlocked() const {
    return outlet.GetNumBlockingPullsThatBlocked();
  }

  decltype(auto) GetNumRevisionsFromTryPulls() const {
    return outlet.GetNumRevisionsFromTryPulls();
  }

  decltype(auto) GetNumRevisionsFromBlockingPulls() const {
    return outlet.GetNumRevisionsFromBlockingPulls();
  }

  decltype(auto) GetNumPullsAttempted() const {
    return outlet.GetNumPullsAttempted();
  }

  decltype(auto) GetNumPullsThatWereLadenEventually() const {
    return outlet.GetNumPullsThatWereLadenEventually();
  }

  decltype(auto) GetNumBlockingPullsThatWereLadenImmediately() const {
    return outlet.GetNumBlockingPullsThatWereLadenImmediately();
  }

  decltype(auto) GetNumBlockingPullsThatWereLadenEventually() const {
    return outlet.GetNumBlockingPullsThatWereLadenEventually();
  }

  decltype(auto) GetNumPullsThatWereLadenImmediately() const {
    return outlet.GetNumPullsThatWereLadenImmediately();
  }

  decltype(auto) GetNumTryPullsThatWereLaden() const {
    return outlet.GetNumTryPullsThatWereLaden();
  }

  decltype(auto) GetNumTryPullsThatWereUnladen() const {
    return outlet.GetNumTryPullsThatWereUnladen();
  }

  decltype(auto) GetFractionTryPullsThatWereLaden() const {
    return outlet.GetFractionTryPullsThatWereLaden();
  }

  decltype(auto) GetFractionTryPullsThatWereUnladen() const {
    return outlet.GetFractionTryPullsThatWereUnladen();
  }

  decltype(auto) GetFractionBlockingPullsThatBlocked() const {
    return outlet.GetFractionBlockingPullsThatBlocked();
  }

  decltype(auto) GetFractionBlockingPullsThatWereLadenImmediately() const {
    return outlet.GetFractionBlockingPullsThatWereLadenImmediately();
  }

  decltype(auto) GetFractionPullsThatWereLadenImmediately() const {
    return outlet.GetFractionPullsThatWereLadenImmediately();
  }

  decltype(auto) GetFractionPullsThatWereLadenEventually() const {
    return outlet.GetFractionPullsThatWereLadenEventually();
  }

  decltype(auto) GetNetFluxThroughDuct() const {
    return outlet.GetNetFluxThroughDuct();
  }

  decltype(auto) GetFractionReadsThatWereFresh() const {
    return outlet.GetFractionReadsThatWereFresh();
  }

  decltype(auto) GetFractionReadsThatWereStale() const {
    return outlet.GetFractionReadsThatWereStale();
  }

  decltype(auto) GetFractionRevisionsThatWereRead() const {
    return outlet.GetFractionRevisionsThatWereRead();
  }

  decltype(auto) GetFractionRevisionsThatWereNotRead() const {
    return outlet.GetFractionRevisionsThatWereNotRead();
  }

  decltype(auto) GetFractionDuctFluxThatWasSteppedThrough() const {
    return outlet.GetFractionDuctFluxThatWasSteppedThrough();
  }

  decltype(auto) GetFractionDuctFluxThatWasJumpedOver() const {
    return outlet.GetFractionDuctFluxThatWasJumpedOver();
  }

  decltype(auto) GetFractionDuctFluxThatWasRead() const {
    return outlet.GetFractionDuctFluxThatWasRead();
  }

  template <typename WhichDuct, typename... Args>
  void EmplaceDuct(Args&&... args) {
    outlet.template EmplaceDuct<WhichDuct>( std::forward<Args>(args)... );
  }

  template <typename WhichDuct, typename... Args>
  void SplitDuct(Args&&... args) {
    outlet.template SplitDuct<WhichDuct>( std::forward<Args>(args)... );
  }

  auto GetDuctUID() const { return outlet.GetUID(); }

  decltype(auto) HoldsIntraImpl() const { return outlet.HoldsIntraImpl(); }

  decltype(auto) HoldsThreadImpl() const { return outlet.HoldsThreadImpl(); }

  decltype(auto) HoldsProcImpl() const { return outlet.HoldsProcImpl(); }

  decltype(auto) WhichImplHeld() const { return outlet.WhichImplHeld(); }

  decltype(auto) CanStep() const { return outlet.CanStep(); }

  void RegisterInletProc(const uitsl::proc_id_t proc) const {
    outlet.RegisterInletProc(proc);
  }

  void RegisterInletThread(const uitsl::thread_id_t thread) const {
    outlet.RegisterInletThread(thread);
  }

  void RegisterOutletProc(const uitsl::proc_id_t proc) const {
    outlet.RegisterOutletProc(proc);
  }

  void RegisterOutletThread(const uitsl::thread_id_t thread) const {
    outlet.RegisterOutletThread(thread);
  }

  void RegisterEdgeID(const size_t edge_id) const {
    outlet.RegisterEdgeID(edge_id);
  }

  void RegisterInletNodeID(const size_t node_id) const {
    outlet.RegisterInletNodeID(node_id);
  }

  void RegisterOutletNodeID(const size_t node_id) const {
    outlet.RegisterOutletNodeID(node_id);
  }

  void RegisterMeshID(const size_t mesh_id) const {
    outlet.RegisterMeshID(mesh_id);
  }

  decltype(auto) LookupOutletProc() const { return outlet.LookupOutletProc(); }

  decltype(auto) LookupOutletThread() const {
    return outlet.LookupOutletThread();
  }

  decltype(auto) LookupInletProc() const { return outlet.LookupInletProc(); }

  decltype(auto) LookupInletThread() const {
    return outlet.LookupInletThread();
  }

  decltype(auto) LookupEdgeID() const { return outlet.LookupEdgeID(); }

  decltype(auto) LookupInletNodeID() const {
    return outlet.LookupInletNodeID();
  }

  decltype(auto) LookupOutletNodeID() const {
    return outlet.LookupOutletNodeID();
  }

  decltype(auto) LookupMeshID() const { return outlet.LookupMeshID(); }

};

} // namespace internal
} // namespace uit

#endif // #ifndef UIT_SPOUTS_WRAPPERS_OUTLET_CACHINGOUTLETWRAPPER_HPP_INCLUDE