/*
 * Logserver
 * Copyright (C) 2017-2025 Joel Reardon
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

#ifndef __EPOCH__H__
#define __EPOCH__H__

#include <condition_variable>
#include <mutex>

#include "constants.h"

using namespace std;

/* stores the current epoch. This is used in rendering, so whenever the state
 * changes the renderer starts computing the lines to show for a particular
 * epoch. if that render doesn't finish before the epoch advances those lines
 * are not displayed
 */
class Epoch {
public:
	// start at epoch 1, so at the start renderers can pretend they've
	// successfully rendered epoch 0
	Epoch() : _epoch(1) {}

	virtual ~Epoch() {
	}

	// signal anyone waiting on the epoch advance to wake up, since we are
	// shuting down
	virtual void shutdown() {
		_epoch = G::NO_POS;
		_cond.notify_all();
	}

	// increment the epoch and notify listeners.
	virtual inline size_t advance() {
		if (_epoch != G::NO_POS) {
			++_epoch;
		}
		_cond.notify_all();
		return _epoch;
	}

	// wait until epoch advances
	template <typename T>
	inline void wait(T* ul) const {
		if (_epoch == G::NO_POS) return;
		_cond.wait(*ul);
	}

	// returns the current epoch
	virtual inline size_t cur() const {
		return _epoch;
	}

protected:
	// value of epoch
	atomic<size_t> _epoch;
	// condition waiting on epoch change
	mutable condition_variable_any _cond;
	// mutex for threadsafety
	mutex _m;
};

#endif  // __EPOCH__H__
