/src/serenity/AK/CircularQueue.h
Line | Count | Source (jump to first uncovered line) |
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 | | |
13 | | namespace AK { |
14 | | |
15 | | template<typename T, size_t Capacity> |
16 | | class CircularQueue { |
17 | | public: |
18 | 0 | CircularQueue() = default; Unexecuted instantiation: AK::CircularQueue<AK::ByteString, 8ul>::CircularQueue() Unexecuted instantiation: AK::CircularQueue<Web::Painting::BorderEdge, 4ul>::CircularQueue() |
19 | | |
20 | | ~CircularQueue() |
21 | 0 | { |
22 | 0 | clear(); |
23 | 0 | } Unexecuted instantiation: AK::CircularQueue<AK::ByteString, 8ul>::~CircularQueue() Unexecuted instantiation: AK::CircularQueue<Web::Painting::BorderEdge, 4ul>::~CircularQueue() |
24 | | |
25 | | void clear() |
26 | 0 | { |
27 | 0 | for (size_t i = 0; i < m_size; ++i) |
28 | 0 | elements()[(m_head + i) % Capacity].~T(); |
29 | |
|
30 | 0 | m_head = 0; |
31 | 0 | m_size = 0; |
32 | 0 | } Unexecuted instantiation: AK::CircularQueue<AK::ByteString, 8ul>::clear() Unexecuted instantiation: AK::CircularQueue<Web::Painting::BorderEdge, 4ul>::clear() |
33 | | |
34 | 0 | bool is_empty() const { return m_size == 0; } Unexecuted instantiation: AK::CircularQueue<AK::ByteString, 8ul>::is_empty() const Unexecuted instantiation: AK::CircularQueue<Web::Painting::BorderEdge, 4ul>::is_empty() const |
35 | 0 | size_t size() const { return m_size; } Unexecuted instantiation: AK::CircularQueue<AK::ByteString, 8ul>::size() const Unexecuted instantiation: AK::CircularQueue<Web::Painting::BorderEdge, 4ul>::size() const |
36 | | |
37 | | size_t capacity() const { return Capacity; } |
38 | | |
39 | | template<typename U = T> |
40 | | void enqueue(U&& value) |
41 | 0 | { |
42 | 0 | auto& slot = elements()[(m_head + m_size) % Capacity]; |
43 | 0 | if (m_size == Capacity) |
44 | 0 | slot.~T(); |
45 | |
|
46 | 0 | new (&slot) T(forward<U>(value)); |
47 | 0 | if (m_size == Capacity) |
48 | 0 | m_head = (m_head + 1) % Capacity; |
49 | 0 | else |
50 | 0 | ++m_size; |
51 | 0 | } Unexecuted instantiation: void AK::CircularQueue<AK::ByteString, 8ul>::enqueue<AK::ByteString&>(AK::ByteString&) Unexecuted instantiation: void AK::CircularQueue<Web::Painting::BorderEdge, 4ul>::enqueue<Web::Painting::BorderEdge>(Web::Painting::BorderEdge&&) |
52 | | |
53 | | T dequeue() |
54 | 0 | { |
55 | 0 | VERIFY(!is_empty()); |
56 | 0 | auto& slot = elements()[m_head]; |
57 | 0 | T value = move(slot); |
58 | 0 | slot.~T(); |
59 | 0 | m_head = (m_head + 1) % Capacity; |
60 | 0 | --m_size; |
61 | 0 | return value; |
62 | 0 | } |
63 | | |
64 | 0 | T const& at(size_t index) const { return elements()[(m_head + index) % Capacity]; } Unexecuted instantiation: AK::CircularQueue<AK::ByteString, 8ul>::at(unsigned long) const Unexecuted instantiation: AK::CircularQueue<Web::Painting::BorderEdge, 4ul>::at(unsigned long) const |
65 | 0 | T& at(size_t index) { return elements()[(m_head + index) % Capacity]; } Unexecuted instantiation: AK::CircularQueue<AK::ByteString, 8ul>::at(unsigned long) Unexecuted instantiation: AK::CircularQueue<Web::Painting::BorderEdge, 4ul>::at(unsigned long) |
66 | | |
67 | | T const& first() const { return at(0); } |
68 | 0 | T const& last() const { return at(size() - 1); } Unexecuted instantiation: AK::CircularQueue<AK::ByteString, 8ul>::last() const Unexecuted instantiation: AK::CircularQueue<Web::Painting::BorderEdge, 4ul>::last() const |
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, size_t const 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 | 0 | bool operator!=(Iterator const& other) { return m_index != other.m_index; } |
95 | | Iterator& operator++() |
96 | 0 | { |
97 | 0 | ++m_index; |
98 | 0 | return *this; |
99 | 0 | } |
100 | | |
101 | 0 | 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 | 0 | : m_queue(queue) |
107 | 0 | , m_index(index) |
108 | 0 | { |
109 | 0 | } |
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 | 0 | Iterator begin() { return Iterator(*this, 0); } |
118 | 0 | Iterator end() { return Iterator(*this, size()); } |
119 | | |
120 | | size_t head_index() const { return m_head; } |
121 | | |
122 | | protected: |
123 | 0 | T* elements() { return reinterpret_cast<T*>(m_storage); } Unexecuted instantiation: AK::CircularQueue<AK::ByteString, 8ul>::elements() Unexecuted instantiation: AK::CircularQueue<Web::Painting::BorderEdge, 4ul>::elements() |
124 | 0 | T const* elements() const { return reinterpret_cast<T const*>(m_storage); } Unexecuted instantiation: AK::CircularQueue<AK::ByteString, 8ul>::elements() const Unexecuted instantiation: AK::CircularQueue<Web::Painting::BorderEdge, 4ul>::elements() const |
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 |
135 | | using AK::CircularQueue; |
136 | | #endif |