/src/libtorrent/include/libtorrent/tailqueue.hpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | |
3 | | Copyright (c) 2010, 2013-2017, 2019, 2022, Arvid Norberg |
4 | | Copyright (c) 2017, Alden Torres |
5 | | All rights reserved. |
6 | | |
7 | | Redistribution and use in source and binary forms, with or without |
8 | | modification, are permitted provided that the following conditions |
9 | | are met: |
10 | | |
11 | | * Redistributions of source code must retain the above copyright |
12 | | notice, this list of conditions and the following disclaimer. |
13 | | * Redistributions in binary form must reproduce the above copyright |
14 | | notice, this list of conditions and the following disclaimer in |
15 | | the documentation and/or other materials provided with the distribution. |
16 | | * Neither the name of the author nor the names of its |
17 | | contributors may be used to endorse or promote products derived |
18 | | from this software without specific prior written permission. |
19 | | |
20 | | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
21 | | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
22 | | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
23 | | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
24 | | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
25 | | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
26 | | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
27 | | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
28 | | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
29 | | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
30 | | POSSIBILITY OF SUCH DAMAGE. |
31 | | |
32 | | */ |
33 | | |
34 | | #ifndef TORRENT_TAILQUEUE_HPP |
35 | | #define TORRENT_TAILQUEUE_HPP |
36 | | |
37 | | #include "libtorrent/assert.hpp" |
38 | | #include <utility> // for std::move |
39 | | |
40 | | namespace libtorrent { |
41 | | |
42 | | template <typename T> |
43 | | struct tailqueue_node |
44 | | { |
45 | 2 | tailqueue_node() : next(nullptr) {} |
46 | | T* next; |
47 | | }; |
48 | | |
49 | | template<class N> |
50 | | inline N* postinc(N*& e) |
51 | | { |
52 | | N* ret = e; |
53 | | e = static_cast<N*>(ret->next); |
54 | | return ret; |
55 | | } |
56 | | |
57 | | template <typename T> |
58 | | struct tailqueue_iterator |
59 | | { |
60 | | template <typename U> friend struct tailqueue; |
61 | | |
62 | 8 | T* get() const { return m_current; } |
63 | 2 | void next() { m_current = m_current->next; } |
64 | | |
65 | | private: |
66 | | explicit tailqueue_iterator(T* cur) |
67 | 4 | : m_current(cur) {} |
68 | | // the current element |
69 | | T* m_current; |
70 | | }; |
71 | | |
72 | | template <typename T> |
73 | | struct tailqueue |
74 | | { |
75 | 10 | tailqueue(): m_first(nullptr), m_last(nullptr), m_size(0) {} |
76 | | |
77 | | tailqueue(tailqueue const&) = delete; |
78 | 8 | tailqueue(tailqueue&& t): m_first(t.m_first), m_last(t.m_last), m_size(t.m_size) |
79 | 8 | { |
80 | 8 | t.m_first = nullptr; |
81 | 8 | t.m_last = nullptr; |
82 | 8 | t.m_size = 0; |
83 | 8 | } |
84 | | |
85 | | tailqueue& operator=(tailqueue const&) = delete; |
86 | | tailqueue& operator=(tailqueue&& t) |
87 | 2 | { |
88 | 2 | TORRENT_ASSERT(m_first == nullptr); |
89 | 2 | TORRENT_ASSERT(m_last == nullptr); |
90 | 2 | TORRENT_ASSERT(m_size == 0); |
91 | | |
92 | 2 | m_first = t.m_first; |
93 | 2 | m_last = t.m_last; |
94 | 2 | m_size = t.m_size; |
95 | | |
96 | 2 | t.m_first = nullptr; |
97 | 2 | t.m_last = nullptr; |
98 | 2 | t.m_size = 0; |
99 | 2 | return *this; |
100 | 2 | } |
101 | | |
102 | | tailqueue_iterator<const T> iterate() const |
103 | | { return tailqueue_iterator<const T>(m_first); } |
104 | | |
105 | | tailqueue_iterator<T> iterate() |
106 | 4 | { return tailqueue_iterator<T>(m_first); } |
107 | | |
108 | | void append(tailqueue<T> rhs) & |
109 | 2 | { |
110 | 2 | TORRENT_ASSERT(m_last == nullptr || m_last->next == nullptr); |
111 | 2 | TORRENT_ASSERT(rhs.m_last == nullptr || rhs.m_last->next == nullptr); |
112 | | |
113 | 2 | if (rhs.m_first == nullptr) return; |
114 | | |
115 | 2 | if (m_first == nullptr) |
116 | 2 | { |
117 | 2 | swap(rhs); |
118 | 2 | return; |
119 | 2 | } |
120 | | |
121 | 0 | m_last->next = rhs.m_first; |
122 | 0 | m_last = rhs.m_last; |
123 | 0 | m_size += rhs.m_size; |
124 | |
|
125 | 0 | TORRENT_ASSERT(m_last == nullptr || m_last->next == nullptr); |
126 | 0 | } |
127 | | |
128 | | void prepend(tailqueue<T> rhs) & |
129 | | { |
130 | | TORRENT_ASSERT(m_last == nullptr || m_last->next == nullptr); |
131 | | TORRENT_ASSERT(rhs.m_last == nullptr || rhs.m_last->next == nullptr); |
132 | | TORRENT_ASSERT((m_last == nullptr) == (m_first == nullptr)); |
133 | | TORRENT_ASSERT((rhs.m_last == nullptr) == (rhs.m_first == nullptr)); |
134 | | |
135 | | if (rhs.m_first == nullptr) return; |
136 | | |
137 | | if (m_first == nullptr) |
138 | | { |
139 | | swap(rhs); |
140 | | return; |
141 | | } |
142 | | |
143 | | swap(rhs); |
144 | | append(std::move(rhs)); |
145 | | TORRENT_ASSERT(m_last == nullptr || m_last->next == nullptr); |
146 | | TORRENT_ASSERT(rhs.m_last == nullptr || rhs.m_last->next == nullptr); |
147 | | } |
148 | | |
149 | | T* pop_front() |
150 | 2 | { |
151 | 2 | TORRENT_ASSERT(m_last == nullptr || m_last->next == nullptr); |
152 | 2 | T* e = m_first; |
153 | 2 | m_first = m_first->next; |
154 | 2 | if (e == m_last) m_last = nullptr; |
155 | 2 | e->next = nullptr; |
156 | 2 | --m_size; |
157 | 2 | return e; |
158 | 2 | } |
159 | | void push_front(T* e) & |
160 | 0 | { |
161 | 0 | TORRENT_ASSERT(e->next == nullptr); |
162 | 0 | TORRENT_ASSERT(m_last == nullptr || m_last->next == nullptr); |
163 | 0 | e->next = m_first; |
164 | 0 | m_first = e; |
165 | 0 | if (!m_last) m_last = e; |
166 | 0 | ++m_size; |
167 | 0 | } |
168 | | void push_back(T* e) & |
169 | 4 | { |
170 | 4 | TORRENT_ASSERT(e->next == nullptr); |
171 | 4 | TORRENT_ASSERT(m_last == nullptr || m_last->next == nullptr); |
172 | 4 | if (m_last) m_last->next = e; |
173 | 4 | else m_first = e; |
174 | 4 | m_last = e; |
175 | 4 | e->next = nullptr; |
176 | 4 | ++m_size; |
177 | 4 | } |
178 | | T* get_all() & |
179 | 2 | { |
180 | 2 | TORRENT_ASSERT(m_last == nullptr || m_last->next == nullptr); |
181 | 2 | T* e = m_first; |
182 | 2 | m_first = nullptr; |
183 | 2 | m_last = nullptr; |
184 | 2 | m_size = 0; |
185 | 2 | return e; |
186 | 2 | } |
187 | | void swap(tailqueue<T>& rhs) |
188 | 2 | { |
189 | 2 | std::swap(m_first, rhs.m_first); |
190 | 2 | std::swap(m_last, rhs.m_last); |
191 | 2 | std::swap(m_size, rhs.m_size); |
192 | 2 | } |
193 | 6 | int size() const { TORRENT_ASSERT(m_size >= 0); return m_size; } |
194 | 27 | bool empty() const { TORRENT_ASSERT(m_size >= 0); return m_size == 0; } |
195 | | T* first() const& { TORRENT_ASSERT(m_size > 0); return m_first; } |
196 | | T* last() const& { TORRENT_ASSERT(m_size > 0); return m_last; } |
197 | | private: |
198 | | T* m_first; |
199 | | T* m_last; |
200 | | int m_size; |
201 | | }; |
202 | | } |
203 | | |
204 | | namespace std { |
205 | | |
206 | | template <typename T> |
207 | | void swap(libtorrent::tailqueue<T>& lhs, libtorrent::tailqueue<T>& rhs) |
208 | | { |
209 | | lhs.swap(rhs); |
210 | | } |
211 | | |
212 | | } |
213 | | |
214 | | #endif // TAILQUEUE_HPP |