Program Listing for File poisson_queue.hpp

Return to documentation for file (rcppsw/ds/poisson_queue.hpp)

#pragma once

/*******************************************************************************
 * Includes
 ******************************************************************************/
#include <boost/optional.hpp>
#include <deque>

#include "rcsw/common/fpc.h"

#include "rcppsw/math/rng.hpp"
#include "rcppsw/rcppsw.hpp"
#include "rcppsw/types/timestep.hpp"

/*******************************************************************************
 * Namespaces/Decls
 ******************************************************************************/
namespace rcppsw::ds {

/*******************************************************************************
 * Class Definitions
 ******************************************************************************/
template <typename T>
class poisson_queue {
 public:
  struct op_metadata {
    size_t count{ 0 };

    size_t total_count{ 0 };

    types::timestep interval_accum{ 0 };

    types::timestep total_interval_accum{ 0 };
  };

  poisson_queue(double lambda, double mu, math::rng* rng)
      : mc_lambda(lambda), mc_mu(mu), m_rng(rng) {}

  /* not assignable or copy-constructible by default */
  poisson_queue(const poisson_queue&) = delete;
  const poisson_queue& operator=(const poisson_queue&) = delete;

  op_metadata enqueue_data(void) const { return m_enqueue.md; }

  op_metadata dequeue_data(void) const { return m_dequeue.md; }

  double lambda(void) const { return mc_lambda; }
  double mu(void) const { return mc_mu; }

  bool enqueue_check(const types::timestep& t) {
    RCSW_FPC_NV(false, mc_lambda > 0.0);
    if (!m_enqueue.op_set) {
      double val = m_rng->exponential(mc_lambda);

      m_enqueue.next_op_time = m_enqueue.last_op_time + static_cast<uint>(val);
      m_enqueue.op_set = true;
    }
    return t >= m_enqueue.next_op_time;
  }

  bool dequeue_check(const types::timestep& t) {
    RCSW_FPC_NV(false, mc_mu > 0.0);
    if (!m_dequeue.op_set) {
      double val = m_rng->exponential(mc_mu);
      m_dequeue.next_op_time = m_dequeue.last_op_time + static_cast<uint>(val);
      m_dequeue.op_set = true;
    }
    return t >= m_dequeue.next_op_time;
  }

  void enqueue(const T& item, const types::timestep& t) {
    ++m_enqueue.md.total_count;
    ++m_enqueue.md.count;
    m_enqueue.md.interval_accum += types::timestep(t - m_enqueue.last_op_time);
    m_enqueue.md.total_interval_accum +=
        types::timestep(t - m_enqueue.last_op_time);

    m_enqueue.last_op_time = t;
    m_enqueue.op_set = false;
    m_queue.push_back(item);
  }

  boost::optional<T> dequeue(const types::timestep& t, bool fake) {
    ++m_dequeue.md.count;
    ++m_dequeue.md.total_count;
    m_dequeue.md.interval_accum += types::timestep(t - m_dequeue.last_op_time);
    m_dequeue.md.total_interval_accum +=
        types::timestep(t - m_dequeue.last_op_time);

    m_dequeue.last_op_time = t;
    m_dequeue.op_set = false;

    if (fake || m_queue.empty()) {
      return boost::none;
    }
    auto val = m_queue.front();
    m_queue.pop_front();
    return boost::make_optional(val);
  }

  void reset_metrics(void) {
    m_enqueue.md.count = 0;
    m_enqueue.md.interval_accum = types::timestep(0);

    m_dequeue.md.count = 0;
    m_dequeue.md.interval_accum = types::timestep(0);
  }

  bool contains(const T& key) const {
    return m_queue.end() != std::find_if(m_queue.begin(),
                                         m_queue.end(),
                                         [&](const auto& a) { return a == key; });
  }

 private:
  struct op_data {
    struct op_metadata md;
    bool op_set{ false };
    types::timestep last_op_time{ 0 };
    types::timestep next_op_time{ 0 };
  };

  /* clang-format off */
  const double    mc_lambda;
  const double    mc_mu;

  math::rng*      m_rng;
  struct op_data  m_enqueue{};
  struct op_data  m_dequeue{};
  std::deque<T>   m_queue{};
  /* clang-format on */

 public:
  RCPPSW_WRAP_DECLDEF(size, m_queue, const);
  RCPPSW_WRAP_DECLDEF(size, m_queue);
};

} /* namespace rcppsw::ds */