Program Listing for File Duct.hpp

Return to documentation for file (include/uit/ducts/Duct.hpp)

#pragma once
#ifndef UIT_DUCTS_DUCT_HPP_INCLUDE
#define UIT_DUCTS_DUCT_HPP_INCLUDE

#include <stddef.h>
#include <string>
#include <type_traits>
#include <utility>
#include <variant>

#include "../../../third-party/Empirical/source/base/assert.h"
#include "../../../third-party/Empirical/source/base/optional.h"
#include "../../../third-party/Empirical/source/meta/TypePack.h"
#include "../../../third-party/Empirical/source/tools/string_utils.h"

#include "../../uitsl/math/math_utils.hpp"
#include "../../uitsl/meta/HasMemberFunction.hpp"
#include "../../uitsl/mpi/mpi_utils.hpp"
#include "../../uitsl/utility/print_utils.hpp"

namespace uit {
namespace internal {

UITSL_GENERATE_HAS_MEMBER_FUNCTION( CanStep );

template<typename ImplSpec>
class Duct {

  using ducts_t = typename emp::TypePack<
    typename ImplSpec::IntraDuct,
    typename ImplSpec::ThreadDuct,
    typename ImplSpec::ProcInletDuct,
    typename ImplSpec::ProcOutletDuct
  >::make_unique;

  typename ducts_t::template apply<std::variant> impl;

  using T = typename ImplSpec::T;

  bool MaybeHoldsIntraImpl() const {
    return std::holds_alternative<typename ImplSpec::IntraDuct>( impl );
  }

  bool MaybeHoldsThreadImpl() const {
    return std::holds_alternative<typename ImplSpec::ThreadDuct>( impl );
  }

  bool MaybeHoldsProcImpl() const {
    return (
      std::holds_alternative<typename ImplSpec::ProcInletDuct>( impl )
      || std::holds_alternative<typename ImplSpec::ProcOutletDuct>( impl )
    );
  }

  bool HoldsAmbiguousImpl() const {
    return uitsl::sum(
      MaybeHoldsIntraImpl(),
      MaybeHoldsThreadImpl(),
      MaybeHoldsProcImpl()
    ) > 1;
  }

public:

  using uid_t = std::uintptr_t;

  Duct(Duct& other) = default;

  Duct(const Duct& other) = default;

  Duct(Duct&& other) = default;

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

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

  bool TryPut(const T& val) {
    return std::visit(
      [&val](auto& arg) -> bool { return arg.TryPut(val); },
      impl
    );
  }

  template<typename P>
  bool TryPut(P&& val) {
    return std::visit(
      [&val](auto& arg) -> bool { return arg.TryPut(std::forward<P>(val)); },
      impl
    );
  }

  bool TryFlush() {
    return std::visit(
      [](auto& arg) -> bool { return arg.TryFlush(); },
      impl
    );
  }

  const T& Get() const {
    return std::visit(
      [](auto& arg) -> const T& { return arg.Get(); },
      impl
    );
  }

  T& Get() {
    return std::visit(
      [](auto& arg) -> T& { return arg.Get(); },
      impl
    );
  }

  size_t TryConsumeGets(const size_t requested) {
    return std::visit(
      [requested](auto& arg) -> size_t {
        return arg.TryConsumeGets(requested);
      },
      impl
    );
  }

  std::string WhichImplIsActive() const {
    return std::visit(
      [](auto& arg) -> std::string { return arg.GetName(); },
      impl
    );
  }

  emp::optional<bool> HoldsIntraImpl() const {
    if ( MaybeHoldsIntraImpl() ) {
      return HoldsAmbiguousImpl() ? std::nullopt : emp::optional<bool>{ true };
    } else return false;
  }

  emp::optional<bool> HoldsThreadImpl() const {
    if ( MaybeHoldsThreadImpl() ) {
      return HoldsAmbiguousImpl() ? std::nullopt : emp::optional<bool>{ true };
    } else return false;
  }

  emp::optional<bool> HoldsProcImpl() const {
    if ( MaybeHoldsProcImpl() ) {
      return HoldsAmbiguousImpl() ? std::nullopt : emp::optional<bool>{ true };
    } else return false;
  }

  uid_t GetUID() const { return reinterpret_cast<uid_t>(this); }

  bool CanStep() const {
    return std::visit(
      [](const auto& arg) -> bool {
        using impl_t = typename std::decay<decltype(arg)>::type;
        if constexpr ( HasMemberFunction_CanStep<impl_t, bool()>::value ) {
          return impl_t::CanStep();
        } else return false;
      },
      impl
    );
  }

  std::string ToString() const {
    std::stringstream ss;
    ss << uitsl::format_member(
      "uitsl::get_proc_id()",
      uitsl::get_proc_id()
    ) << std::endl;
    ss << uitsl::format_member(
      "GetUID()",
      GetUID()
    ) << std::endl;
    ss << uitsl::format_member(
      "std::variant impl",
      std::visit(
        [](auto& arg) -> std::string { return arg.ToString(); },
        impl
      )
    );
    return ss.str();
  }

};

} // namespace internal
} // namespace uit

#endif // #ifndef UIT_DUCTS_DUCT_HPP_INCLUDE