Serenity Operating System
at master 136 lines 3.3 kB view raw
1/* 2 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7#pragma once 8 9#include <AK/Assertions.h> 10#include <AK/Forward.h> 11#include <AK/StdLibExtras.h> 12 13namespace AK { 14 15template<typename T, size_t Capacity> 16class CircularQueue { 17public: 18 CircularQueue() = default; 19 20 ~CircularQueue() 21 { 22 clear(); 23 } 24 25 void clear() 26 { 27 for (size_t i = 0; i < m_size; ++i) 28 elements()[(m_head + i) % Capacity].~T(); 29 30 m_head = 0; 31 m_size = 0; 32 } 33 34 bool is_empty() const { return m_size == 0; } 35 size_t size() const { return m_size; } 36 37 size_t capacity() const { return Capacity; } 38 39 template<typename U = T> 40 void enqueue(U&& value) 41 { 42 auto& slot = elements()[(m_head + m_size) % Capacity]; 43 if (m_size == Capacity) 44 slot.~T(); 45 46 new (&slot) T(forward<U>(value)); 47 if (m_size == Capacity) 48 m_head = (m_head + 1) % Capacity; 49 else 50 ++m_size; 51 } 52 53 T dequeue() 54 { 55 VERIFY(!is_empty()); 56 auto& slot = elements()[m_head]; 57 T value = move(slot); 58 slot.~T(); 59 m_head = (m_head + 1) % Capacity; 60 --m_size; 61 return value; 62 } 63 64 T const& at(size_t index) const { return elements()[(m_head + index) % Capacity]; } 65 T& at(size_t index) { return elements()[(m_head + index) % Capacity]; } 66 67 T const& first() const { return at(0); } 68 T const& last() const { return at(size() - 1); } 69 70 class ConstIterator { 71 public: 72 bool operator!=(ConstIterator const& other) { return m_index != other.m_index; } 73 ConstIterator& operator++() 74 { 75 ++m_index; 76 return *this; 77 } 78 79 T const& operator*() const { return m_queue.at(m_index); } 80 81 private: 82 friend class CircularQueue; 83 ConstIterator(CircularQueue const& queue, const size_t index) 84 : m_queue(queue) 85 , m_index(index) 86 { 87 } 88 CircularQueue const& m_queue; 89 size_t m_index { 0 }; 90 }; 91 92 class Iterator { 93 public: 94 bool operator!=(Iterator const& other) { return m_index != other.m_index; } 95 Iterator& operator++() 96 { 97 ++m_index; 98 return *this; 99 } 100 101 T& operator*() const { return m_queue.at(m_index); } 102 103 private: 104 friend class CircularQueue; 105 Iterator(CircularQueue& queue, size_t const index) 106 : m_queue(queue) 107 , m_index(index) 108 { 109 } 110 CircularQueue& m_queue; 111 size_t m_index { 0 }; 112 }; 113 114 ConstIterator begin() const { return ConstIterator(*this, 0); } 115 ConstIterator end() const { return ConstIterator(*this, size()); } 116 117 Iterator begin() { return Iterator(*this, 0); } 118 Iterator end() { return Iterator(*this, size()); } 119 120 size_t head_index() const { return m_head; } 121 122protected: 123 T* elements() { return reinterpret_cast<T*>(m_storage); } 124 T const* elements() const { return reinterpret_cast<T const*>(m_storage); } 125 126 friend class ConstIterator; 127 alignas(T) u8 m_storage[sizeof(T) * Capacity]; 128 size_t m_size { 0 }; 129 size_t m_head { 0 }; 130}; 131 132} 133 134#if USING_AK_GLOBALLY 135using AK::CircularQueue; 136#endif