Program Listing for File Outlet.hpp

Return to documentation for file (include/uit/spouts/Outlet.hpp)

#pragma once
#ifndef UIT_SPOUTS_OUTLET_HPP_INCLUDE
#define UIT_SPOUTS_OUTLET_HPP_INCLUDE

#include <cstdint>
#include <iostream>
#include <limits>
#include <memory>
#include <stddef.h>
#include <utility>

#include "../../../third-party/Empirical/source/base/optional.h"

#include "../../uitsl/debug/occupancy_audit.hpp"
#include "../../uitsl/nonce/CircularIndex.hpp"
#include "../../uitsl/parallel/thread_utils.hpp"

#include "../ducts/Duct.hpp"

namespace uit {

template<typename ImplSpec_>
class Outlet {

public:
  using ImplSpec = ImplSpec_;

private:
  using T = typename ImplSpec::T;
  constexpr inline static size_t N{ImplSpec::N};

  using index_t = uitsl::CircularIndex<N>;

  using duct_t = internal::Duct<ImplSpec>;
  std::shared_ptr<duct_t> duct;

  // TODO move this to ImplSpec?
  static_assert(N > 0);

  mutable size_t read_count{0};

  size_t revision_count{0};

  size_t net_flux{0};

  uitsl_occupancy_auditor;

  size_t TryConsumeGets(const size_t n) {
    uitsl_occupancy_audit(1);
    return LogStep( duct->TryConsumeGets(n) );
  }

  size_t LogStep(const size_t n) {
    revision_count += (n > 0);
    net_flux += n;
    return n;
  }

  void LogRead() const { ++read_count; }

public:

  Outlet(
    std::shared_ptr<duct_t> duct_
  ) : duct(duct_) { ; }

  size_t TryStep(const size_t num_steps=1) {
    return TryConsumeGets(num_steps);
  }

  size_t Jump() {
    return TryConsumeGets( std::numeric_limits<size_t>::max() );
  }

  const T& Get() const { LogRead(); return duct->Get(); }

  T& Get() { LogRead(); return duct->Get(); }

  const T& JumpGet() {
    uitsl_occupancy_audit(1);
    Jump();
    return Get();
  }

  const T& GetNext() {
    uitsl_occupancy_audit(1);
    while (TryStep() == 0);
    return Get();
  }



  using optional_ref_t = emp::optional<std::reference_wrapper<const T>>;

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

  size_t GetReadCount() const { return read_count; }

  size_t GetRevisionCount() const { return revision_count; }

  size_t GetNetFlux() const { return net_flux; }

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

  template <typename WhichDuct, typename... Args>
  void SplitDuct(Args&&... args) {
    duct = std::make_shared<duct_t>(
      std::in_place_type_t<WhichDuct>{},
      std::forward<Args>(args)...
    );
  }

  typename duct_t::uid_t GetDuctUID() const { return duct->GetUID(); }

  emp::optional<bool> HoldsIntraImpl() const { return duct->HoldsIntraImpl(); }

  emp::optional<bool> HoldsThreadImpl() const {
    return duct->HoldsThreadImpl();
  }

  emp::optional<bool> HoldsProcImpl() const { return duct->HoldsProcImpl(); }

  bool CanStep() const { return duct->CanStep(); }

  std::string ToString() const {
    std::stringstream ss;
    ss << uitsl::format_member("std::shared_ptr<duct_t> duct", *duct) << std::endl;
    ss << uitsl::format_member("size_t read_count", read_count) << std::endl;
    ss << uitsl::format_member("size_t revision_count", revision_count) << std::endl;
    ss << uitsl::format_member("size_t net_flux", net_flux);
    return ss.str();
  }

};

} // namespace uit

#endif // #ifndef UIT_SPOUTS_OUTLET_HPP_INCLUDE