--- nono/lib/fixedqueue.h 2026/04/29 17:04:34 1.1.1.4 +++ nono/lib/fixedqueue.h 2026/04/29 17:05:52 1.1.1.12 @@ -4,6 +4,10 @@ // Licensed under nono-license.txt // +// +// 固定長キュー +// + #pragma once #include "header.h" @@ -11,22 +15,24 @@ // 固定長キュー // std::queue では出来ないことがいくつかあるので仕方なく車輪の再開発。 +// std::vector を親に使っているが empty() と Empty() の動作が異なるなど +// しているため public にせず private 継承している。 // // T 型で上限 capacity 個のキュー。 // スレッドセーフではない。 -template -class FixedQueue +template +class FixedQueue final : private std::vector { + using inherited = std::vector; public: // コンストラクタ FixedQueue() - : buf(capacity) + : inherited(capacity) { - Clear(); } // デストラクタ - virtual ~FixedQueue() { + ~FixedQueue() { } // 空にする @@ -35,25 +41,33 @@ class FixedQueue length = 0; } - // 追加 - bool Enqueue(T val) { - if (length < capacity) { - // 空きがあれば追加 - buf[(start + length) % capacity] = val; + // 空きがあれば追加して true を返す。 + // 空きがなければ何もせず false を返す。 + bool Enqueue(const T& val) { + if (IsFull()) { + return false; + } else { + (*this)[(start + length) % capacity] = val; length++; return true; - } else { - return false; } } + // 空きがなければ古いのを捨てて追加する。 + void EnqueueForce(const T& val) { + if (IsFull()) { + Dequeue(); + } + Enqueue(val); + } + // 取り出し // 要素が1つ以上あれば *outp に取り出して true を返す。 // キューが空なら false を返す。 bool Dequeue(T *outp) { if (length > 0) { // 1つ以上あれば取り出し - *outp = buf[start]; + *outp = (*this)[start]; start = (start + 1) % capacity; length--; return true; @@ -64,14 +78,16 @@ class FixedQueue // 取り出し // 先頭の要素を取り出して返す。 - // キューが空の時に呼ぶと不定値が返る。 + // キューが空の時に呼ぶと T() が返る。 T Dequeue() { - T val = buf[start]; if (length > 0) { + T val = (*this)[start]; start = (start + 1) % capacity; length--; + return val; + } else { + return T(); } - return val; } // 現在の要素数を取得 @@ -79,20 +95,61 @@ class FixedQueue return length; } + // 要素が空なら true を返す + bool Empty() const { + return (length == 0); + } + // 要素が一杯なら true を返す bool IsFull() const { - return (length >= capacity); + return (Length() >= capacity); } // 要素を覗き見る。 // idx は 0 .. length-1 までで、0 がキューの先頭。 - T Peek(int idx) const { + T Peek(uint idx) const { // XXX 範囲チェックすべきだがとりあえず - return buf[(start + idx) % capacity]; + return (*this)[(start + idx) % capacity]; + } + // 最新の要素を覗き見る。 + T PeekLatest() const { + return Peek(Length() - 1); + } + + // 要素数を返す + constexpr uint Capacity() const { + return capacity; + } + + // 先頭側から追加する。 + // 空きがなければ何もせず false を返す。 + bool PushFront(const T& val) { + if (IsFull()) { + return false; + } else { + start = (start + capacity - 1) % capacity; + (*this)[start] = val; + length++; + return true; + } + } + + // 移動平均値を返す。(T が数値型のときに限る) + T GetMovingAverage() const + { + static_assert(std::is_arithmetic::value, "T must be arithmetic"); + + if (Empty()) { + return 0; + } + T sum = 0; + for (uint i = 0; i < length; i++) { + sum += Peek(i); + } + return sum / length; } private: - std::vector buf; // バッファ - uint start = 0; // 開始位置 - uint length = 0; // 現在有効な長さ + uint start {}; // 開始位置 + uint length {}; // 現在有効な長さ };