#ifndef CRUCIBLE_PROGRESS_H #define CRUCIBLE_PROGRESS_H #include "crucible/error.h" #include #include #include #include namespace crucible { using namespace std; template class ProgressTracker { struct ProgressTrackerState; class ProgressHolderState; public: using value_type = T; using ProgressHolder = shared_ptr; ProgressTracker(const value_type &v); value_type begin() const; value_type end() const; ProgressHolder hold(const value_type &v); friend class ProgressHolderState; private: struct ProgressTrackerState { using key_type = pair; mutex m_mutex; map m_in_progress; value_type m_begin; value_type m_end; }; class ProgressHolderState { shared_ptr m_state; const value_type m_value; public: ProgressHolderState(shared_ptr state, const value_type &v); ~ProgressHolderState(); value_type get() const; }; shared_ptr m_state; }; template typename ProgressTracker::value_type ProgressTracker::begin() const { unique_lock lock(m_state->m_mutex); return m_state->m_begin; } template typename ProgressTracker::value_type ProgressTracker::end() const { unique_lock lock(m_state->m_mutex); return m_state->m_end; } template typename ProgressTracker::value_type ProgressTracker::ProgressHolderState::get() const { return m_value; } template ProgressTracker::ProgressTracker(const ProgressTracker::value_type &t) : m_state(make_shared()) { m_state->m_begin = t; m_state->m_end = t; } template ProgressTracker::ProgressHolderState::ProgressHolderState(shared_ptr state, const value_type &v) : m_state(state), m_value(v) { unique_lock lock(m_state->m_mutex); m_state->m_in_progress[make_pair(m_value, this)] = true; if (m_state->m_end < m_value) { m_state->m_end = m_value; } } template ProgressTracker::ProgressHolderState::~ProgressHolderState() { unique_lock lock(m_state->m_mutex); m_state->m_in_progress[make_pair(m_value, this)] = false; auto p = m_state->m_in_progress.begin(); while (p != m_state->m_in_progress.end()) { if (p->second) { break; } if (m_state->m_begin < p->first.first) { m_state->m_begin = p->first.first; } m_state->m_in_progress.erase(p); p = m_state->m_in_progress.begin(); } } template shared_ptr::ProgressHolderState> ProgressTracker::hold(const value_type &v) { return make_shared(m_state, v); } } #endif // CRUCIBLE_PROGRESS_H