/* Copyright 2022 Bga Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ #pragma once #include #include #include #include #pragma push_macro("Self") #undef Self #define Self Queue namespace Bga { #warning Never fully fill Queue_NoCaryyCheck or you will not pop from it template struct Queue_NoCaryyCheck { typedef ArrayTypeArg ArrayType; typedef IndexArg Index; ArrayType* const data; const Index size; Index tailIndex; Index headIndex; void clear() { this->tailIndex = this->headIndex = 0; } Queue_NoCaryyCheck(ArrayType* data_, Index size_): data(data_), size(size_) { this->clear(); } inline Index postCycleIndex(Index& v) { Index vCopy = v; cycleInc(v, this->size); return vCopy; } inline Bool isEmpty() const { return this->tailIndex == this->headIndex; } inline Bool isFull() const { return false; } inline Bool push(ArrayType const& v) { this->data[this->postCycleIndex(this->headIndex)] = v; return true; } inline ::std::optional peek() const { if(this->isEmpty()) { return ::std::nullopt; }; return this->data[this->tailIndex]; } inline ::std::optional pop() { if(this->isEmpty()) { return ::std::nullopt; }; return this->data[this->postCycleIndex(this->tailIndex)]; } }; template struct Queue_CarryCheckBoolFlag { typedef ArrayTypeArg ArrayType; typedef IndexArg Index; ArrayType* const data; const Index size; Index tailIndex; Index headIndex; Bool isCarry; void clear() { this->tailIndex = this->headIndex = 0; this->isCarry = false; } Queue_CarryCheckBoolFlag(ArrayType* data_, Index size_): data(data_), size(size_) { this->clear(); } inline Index postCycleIndex(Index& v) { Index vCopy = v; cycleInc(v, this->size); return vCopy; } inline Bool isEmpty() const { return this->tailIndex == this->headIndex && !this->isCarry; } inline Bool isFull() const { return this->tailIndex == this->headIndex && this->isCarry; } inline Bool push(ArrayType const& v) { if(this->isFull()) { return false; }; this->data[this->postCycleIndex(this->headIndex)] = v; if(this->headIndex == this->tailIndex) { this->isCarry = true; }; return true; } inline ::std::optional peek() const { if(this->isEmpty()) { return ::std::nullopt; }; return this->data[this->tailIndex]; } inline ::std::optional pop() { if(this->isEmpty()) { return ::std::nullopt; }; this->isCarry = false; return this->data[this->postCycleIndex(this->tailIndex)]; } }; template struct Queue_CarryCheckBiggerIndex { typedef ArrayTypeArg ArrayType; typedef IndexArg Index; ArrayType* const data; const Index size; Index tailIndex; Index headIndex; void clear() { this->tailIndex = this->headIndex = 0; } Queue_CarryCheckBiggerIndex(ArrayType* data_, Index size_): data(data_), size(size_) { this->clear(); } inline Index postCycleIndex(Index& v) { Index vCopy = v; cycleInc(v, this->size); return vCopy; } inline Bool isEmpty() const { return this->tailIndex == this->headIndex; } inline Bool isFull() const { if(isPowerOf2(this->size)) { Index x = this->headIndex ^ this->tailIndex; return x != 0 && (x & (this->size - 1)) == 0; } else { return this->headIndex != this->tailIndex && this->headIndex % this->size == this->tailIndex % this->size; } // return this->headIndex != this->tailIndex && this->headIndex % this->size == this->tailIndex % this->size; } inline Bool push(ArrayType const& v) { if(this->isFull()) { return false; }; this->data[this->headIndex++ % this->size] = v; return true; } inline ::std::optional peek() const { if(this->isEmpty()) { return ::std::nullopt; }; return this->data[this->tailIndex % this->size]; } inline ::std::optional pop() { if(this->isEmpty()) { return ::std::nullopt; }; return this->data[this->tailIndex++ % this->size]; } }; template struct Queue_TailPlusSize { typedef ArrayTypeArg ArrayType; typedef IndexArg Index; ArrayType* const data; const Index size; Index tailIndex; Index currentSize; void clear() { this->tailIndex = this->currentSize = 0; } Queue_TailPlusSize(ArrayType* data_, Index size_): data(data_), size(size_) { this->clear(); } inline Index postCycleIndex(Index& v) { Index vCopy = v; cycleInc(v, this->size); return vCopy; } inline Bool isEmpty() const { return this->currentSize == 0; } inline Bool isFull() const { return this->size <= this->currentSize; } inline Bool push(ArrayType const& v) { if(this->isFull()) { return false; }; this->data[(this->tailIndex + this->currentSize++) % this->size] = v; return true; } inline ::std::optional peek() const { if(this->isEmpty()) { return ::std::nullopt; }; return this->data[(this->tailIndex) % this->size]; } inline ::std::optional pop() { if(this->isEmpty()) { return ::std::nullopt; }; this->currentSize--; return this->data[this->tailIndex++ % this->size]; } }; } //# namespace #ifdef BGA__TESTRUNNER_ON char const* const nullopt_string = "nullopt"; template ::std::ostream& operator<<(::std::ostream& stream, const ::std::optional& v) { if(v) { stream << *v; } else { stream << nullopt_string; } return stream; } ::std::ostream& operator<<(::std::ostream& stream, const ::std::nullopt_t& v) { stream << nullopt_string; return stream; } enum Queue_test_Option { Queue_test_Option_noCarryCheck = _BV(1), }; template class QueueArg> void Queue_test(char const* className, UInt options = 0) { TestRunnerNS::setUserDefinedScope(className); Int data[2]; Int uuid = 1; QueueArg q(data, arraySize(data)); q.clear(); assert_eq(q.isEmpty(), true); assert_eq(q.isFull(), false); assert_eq(q.pop(), ::std::nullopt); assert_eq(q.push(++uuid), true); assert_eq(q.isEmpty(), false); assert_eq(q.isFull(), false); assert_eq(q.pop(), ::std::make_optional(Int(uuid))); assert_eq(q.pop(), ::std::nullopt); assert_eq(q.pop(), ::std::nullopt); assert_eq(q.push(++uuid), true); assert_eq(q.isEmpty(), false); assert_eq(q.isFull(), false); assert_eq(q.pop(), ::std::make_optional(Int(uuid))); assert_eq(q.pop(), ::std::nullopt); assert_eq(q.pop(), ::std::nullopt); assert_eq(q.push(++uuid), true); assert_eq(q.push(++uuid), true); assert_eq(q.isEmpty(), false); assert_eq(q.isFull(), true); if(!hasBitMask(options, Queue_test_Option_noCarryCheck)) { assert_eq(q.push(++uuid), false); }; } example(BGA__STR(Self)) { using namespace ::Bga; Queue_test("Queue_NoCaryyCheck", Queue_test_Option_noCarryCheck); Queue_test("Queue_CarryCheckBoolFlag"); Queue_test("Queue_CarryCheckBiggerIndex"); Queue_test("Queue_TailPlusSize"); } #endif #pragma pop_macro("Self")