File:  [Isaki's NoNo m68k/m88k emulator] / nono / lib / spscqueue.h
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Wed Apr 29 17:05:08 2026 UTC (2 months, 3 weeks ago) by root
Branches: MAIN, Isaki
CVS tags: v027, v026, v025, v024, v023, v022, v021, v020, v019, v018, v017, v016, v015, HEAD
nono 0.3.0

//
// nono
// Copyright (C) 2021 nono project
// Licensed under nono-license.txt
//

//
// シングルプロデューサ/シングルコンシューマのロックレス固定長キュー
//

#pragma once

#include "header.h"
#include <array>
#include <atomic>

// reader が 1 スレッド、writer が 1 スレッドの場合にのみスレッドセーフ。
// 要素型 T はデストラクト不要な型(プリミティブまたはその構造体など)を
// 期待している。
template <typename T, size_t CAPACITY>
class SPSCQueue
{
 public:
	SPSCQueue()
	{
	}

	// 読み込みを開始する。
	// 読み込み要素のポインタを返す。
	// 読み込み要素がないときは nullptr を返す。
	const T *BeginRead()
	{
		if (length == 0) {
			return nullptr;
		}
		return &mem[ri];
	}

	// 書き込みを開始する。
	// 書き込み要素のポインタを返す。
	// 書き込み要素がないときは nullptr を返す。
	T *BeginWrite()
	{
		if (length >= CAPACITY) {
			return nullptr;
		}
		return &mem[wi];
	}

	// BeginRead で開始した読み込みをキャンセルする。
	void CancelRead()
	{
		// nop
	}

	// BeginWrite で開始した書き込みをキャンセルする。
	void CancelWrite()
	{
		// nop
	}

	// BeginRead で開始した読み込みを終了する。
	// これ以降は BeginRead で返された要素にアクセスしてはならない。
	// BeginRead を呼び出していないのに EndRead を呼び出してはならない。
	void EndRead()
	{
		assert(length > 0);
		ri = (ri + 1) % CAPACITY;
		--length;
	}

	// BeginWrite で開始した書き込みを終了する。
	// これ以降は BeginWrite で返された要素にアクセスしてはならない。
	// BeginWrite を呼び出していないのに EndWrite を呼び出してはならない。
	void EndWrite()
	{
		assert(length < CAPACITY);
		wi = (wi + 1) % CAPACITY;
		++length;
	}

	// item をコピー投入する。
	bool Enqueue(const T& item)
	{
		T *p = BeginWrite();
		if (p == nullptr) {
			return false;
		}
		*p = item;
		EndWrite();
		return true;
	}

	// pitem にコピー取り出しする。
	bool Dequeue(T *pitem)
	{
		const T *p = BeginRead();
		if (p == nullptr) {
			return false;
		}
		*pitem = *p;
		EndRead();
		return true;
	}

	// 最大要素数を返す。
	constexpr size_t Capacity() const { return CAPACITY; }

	// 現在の要素数を返す。
	// 取得した直後に変化するかもしれないことに注意。
	size_t Length() const { return length; }

 private:
	std::atomic<size_t> length {};
	int ri {};						// reader の index
	int wi {};						// writer の index
	std::array<T, CAPACITY> mem {};
};

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.