Newer
Older
PrismSoftware / ECTrainer2 / RingBuffer.h
#pragma once

#include <mutex>

namespace nkc {

template<class T>
class RingBuffer
{
	static const int DEEFAULT_SIZE = 4;
	T* _data;
	std::mutex* _mtxData;
	std::mutex _mtxIndex;
	int _size;
	int _write;
	int _read;
	bool _update;
public:
	// コンストラクタ
	// size バッファのサイズ
	// initial 全要素の初期値
	RingBuffer(int size = DEEFAULT_SIZE);
	RingBuffer(int size, T initial);

	// デストラクタ
	~RingBuffer();

	// データを格納する
	void Put(T value);

	// 最新のデータ取り出し
	// peeking true 取り出し記録しない  false (デフォルト)取り出し記録する
	// past 過去にさかのぼる(デフォルト=0)
	T Get(bool peeking = false, int past = 0);

	// 新しいデータが追加されたか
	bool IsNew() { return _update; };
};

template<class T>
RingBuffer<T>::RingBuffer(int size)
	: _data(NULL)
	, _write(0)
	, _read(0)
	, _update(false)
{
	_size = size;
	_data = new T[_size];
	_mtxData = new std::mutex[_size];
}

template<class T>
RingBuffer<T>::RingBuffer(int size, T initial)
	: _data(NULL)
	, _write(0)
	, _read(0)
	, _update(false) {
	_size = size;
	_data = new T[_size];
	for (int i = 0; i < _size; i++) _data[i] = initial;
	_mtxData = new std::mutex[_size];
}

template<class T>
RingBuffer<T>::~RingBuffer() {
	delete[] _data;
	delete[] _mtxData;
}

template<class T>
void RingBuffer<T>::Put(T value) {
	int write = _write;
	_mtxData[write].lock();
	_data[write] = value;
	_mtxData[write].unlock();

	_mtxIndex.lock();
	_read = write;
	_write = (write + 1) % _size;
	_update = true;
	_mtxIndex.unlock();
}

template<class T>
T RingBuffer<T>::Get(bool peeking, int past) {
	int read = (_read + _size - past) % _size;
	_mtxData[read].lock();
	T value = _data[read];
	_mtxData[read].unlock();

	if (!peeking) {
		_mtxIndex.lock();
		_update = false;
		_mtxIndex.unlock();
	}

	return value;
}

}; // namespace nkc