|
|
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 {};
};
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.