1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
|
/**
* \file
* \brief SortedIntrusiveForwardList template class header
*
* \author Copyright (C) 2015 Kamil Szczygiel http://www.distortec.com http://www.freddiechopin.info
*
* \par License
* This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not
* distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#ifndef ESTD_SORTEDINTRUSIVEFORWARDLIST_HPP_
#define ESTD_SORTEDINTRUSIVEFORWARDLIST_HPP_
#include "estd/IntrusiveForwardList.hpp"
#include <algorithm>
namespace estd
{
/**
* \brief SortedIntrusiveForwardList class is an IntrusiveForwardList with sorted elements
*
* This class tries to provide an interface similar to std::forward_list.
*
* \note The elements are sorted as long as the user does not modify the contents.
*
* \tparam Compare is a type of functor used for comparison, std::less results in descending order, std::greater - in
* ascending order
* \tparam T is the type that has the IntrusiveForwardListNode variable
* \tparam NodePointer is a pointer-to-member to IntrusiveForwardListNode variable in \a T
* \tparam U is the type that will be stored on the list; it can be different from \a T, but must be implicitly
* convertible to \a T (so usually a type derived from \a T); default - \a T; using different type than \a T can be used
* to break circular dependencies, because \a T must be fully defined to instantiate this class, but it is enough to
* forward declare \a U - it only needs to be fully defined to use member functions
*/
template<typename Compare, typename T, IntrusiveForwardListNode T::* NodePointer, typename U = T>
class SortedIntrusiveForwardList
{
public:
/// unsorted intrusive forward list used internally
using UnsortedIntrusiveForwardList = IntrusiveForwardList<T, NodePointer, U>;
/// const iterator of elements on the list
using const_iterator = typename UnsortedIntrusiveForwardList::const_iterator;
/// const pointer to value linked in the list
using const_pointer = typename UnsortedIntrusiveForwardList::const_pointer;
/// const reference to value linked in the list
using const_reference = typename UnsortedIntrusiveForwardList::const_reference;
/// iterator of elements on the list
using iterator = typename UnsortedIntrusiveForwardList::iterator;
/// pointer to value linked in the list
using pointer = typename UnsortedIntrusiveForwardList::pointer;
/// reference to value linked in the list
using reference = typename UnsortedIntrusiveForwardList::reference;
/// value linked in the list
using value_type = typename UnsortedIntrusiveForwardList::value_type;
/**
* \brief SortedIntrusiveForwardList's constructor
*
* \param [in] compare is a reference to Compare object used to copy-construct internal comparison functor
*/
constexpr SortedIntrusiveForwardList(const Compare& compare = Compare{}) :
implementation_{compare}
{
}
/**
* \return iterator of "one before the first" element on the list
*/
iterator before_begin()
{
return implementation_.intrusiveForwardList.before_begin();
}
/**
* \return const iterator of "one before the first" element on the list
*/
const_iterator before_begin() const
{
return implementation_.intrusiveForwardList.before_begin();
}
/**
* \return iterator of first element on the list
*/
iterator begin()
{
return implementation_.intrusiveForwardList.begin();
}
/**
* \return const iterator of first element on the list
*/
const_iterator begin() const
{
return implementation_.intrusiveForwardList.begin();
}
/**
* \return const iterator of "one before the first" element on the list
*/
const_iterator cbefore_begin() const
{
return implementation_.intrusiveForwardList.cbefore_begin();
}
/**
* \return const iterator of first element on the list
*/
const_iterator cbegin() const
{
return implementation_.intrusiveForwardList.cbegin();
}
/**
* \return const iterator of "one past the last" element on the list
*/
const_iterator cend() const
{
return implementation_.intrusiveForwardList.cend();
}
/**
* \brief Unlinks all elements from the list.
*/
void clear()
{
implementation_.intrusiveForwardList.clear();
}
/**
* \return true is the list is empty, false otherwise
*/
bool empty() const
{
return implementation_.intrusiveForwardList.empty();
}
/**
* \return iterator of "one past the last" element on the list
*/
iterator end()
{
return implementation_.intrusiveForwardList.end();
}
/**
* \return const iterator of "one past the last" element on the list
*/
const_iterator end() const
{
return implementation_.intrusiveForwardList.end();
}
/**
* \return reference to first element on the list
*/
reference front()
{
return implementation_.intrusiveForwardList.front();
}
/**
* \return const reference to first element on the list
*/
const_reference front() const
{
return implementation_.intrusiveForwardList.front();
}
/**
* \brief Links the element in the list, keeping it sorted.
*
* \param [in] newElement is a reference to the element that will be linked in the list
*
* \return iterator of \a newElement
*/
iterator insert(reference newElement)
{
return UnsortedIntrusiveForwardList::insert_after(implementation_.findInsertPositionBefore(newElement),
newElement);
}
/**
* \brief Unlinks the first element from the list.
*/
void pop_front()
{
implementation_.intrusiveForwardList.pop_front();
}
/**
* \brief Transfers the element from another list to this one, keeping it sorted.
*
* \param [in] beforeSplicedElement is an iterator of the element preceding the one which will be spliced from
* another list to this one
*/
void splice_after(const iterator beforeSplicedElement)
{
const auto splicedElement = std::next(beforeSplicedElement);
UnsortedIntrusiveForwardList::splice_after(implementation_.findInsertPositionBefore(*splicedElement),
beforeSplicedElement);
}
/**
* \brief Swaps contents with another list.
*
* \param [in] other is a reference to SortedIntrusiveForwardList with which contents of this list will be swapped
*/
void swap(SortedIntrusiveForwardList& other)
{
implementation_.swap(other.implementation_);
}
/**
* \brief Unlinks the element following \a position from the list.
*
* \note No instance of the list is needed for this operation.
*
* \param [in] position is an iterator preceding the element which will be unlinked from the list
*
* \return iterator of the element that was following the element which was unlinked
*/
static iterator erase_after(const iterator position)
{
return UnsortedIntrusiveForwardList::erase_after(position);
}
SortedIntrusiveForwardList(const SortedIntrusiveForwardList&) = delete;
SortedIntrusiveForwardList(SortedIntrusiveForwardList&&) = default;
const SortedIntrusiveForwardList& operator=(const SortedIntrusiveForwardList&) = delete;
SortedIntrusiveForwardList& operator=(SortedIntrusiveForwardList&&) = delete;
private:
/// Implementation struct is used primarily for "Empty Base Optimization" with \a Compare type
struct Implementation : public Compare
{
/**
* \brief Implementation's constructor
*
* \param [in] comparee is a reference to Compare object used to copy-construct internal comparison functor
*/
constexpr Implementation(const Compare& comparee) :
Compare{comparee},
intrusiveForwardList{}
{
}
/**
* \brief Finds insert position "before" the position that satisfies sorting criteria.
*
* \param [in] newElement is a const reference to new element that is going to be inserted/spliced
*
* \return iterator for which Compare's function call operator of next value and \a newElement returns true.
*/
iterator findInsertPositionBefore(const_reference newElement)
{
auto it = intrusiveForwardList.before_begin();
auto next = intrusiveForwardList.begin();
const auto end = intrusiveForwardList.end();
while (next != end && this->Compare::operator()(*next, newElement) == false)
{
it = next;
++next;
}
return it;
}
/**
* \brief Swaps contents with another instance.
*
* \param [in] other is a reference to Implementation with which contents of this instance will be swapped
*/
void swap(Implementation& other)
{
intrusiveForwardList.swap(other.intrusiveForwardList);
using std::swap;
swap(static_cast<Compare&>(*this), static_cast<Compare&>(other));
}
Implementation(const Implementation&) = delete;
Implementation(Implementation&&) = default;
const Implementation& operator=(const Implementation&) = delete;
Implementation& operator=(Implementation&&) = delete;
/// internal unsorted IntrusiveForwardList
UnsortedIntrusiveForwardList intrusiveForwardList;
};
/// internal Implementation object - unsorted IntrusiveForwardList and Compare instance
Implementation implementation_;
};
/**
* \brief Swaps contents of two lists.
*
* \tparam Compare is a type of functor used for comparison, std::less results in descending order, std::greater - in
* ascending order
* \tparam T is the type that has the IntrusiveForwardListNode variable
* \tparam NodePointer is a pointer-to-member to IntrusiveForwardListNode variable in \a T
* \tparam U is the type that will be stored on the list; it can be different from \a T, but must be implicitly
* convertible to \a T (so usually a type derived from \a T); default - \a T;
*
* \param [in] left is a reference to SortedIntrusiveForwardList with which contents of \a right will be swapped
* \param [in] right is a reference to SortedIntrusiveForwardList with which contents of \a left will be swapped
*/
template<typename Compare, typename T, IntrusiveForwardListNode T::* NodePointer, typename U = T>
inline void swap(SortedIntrusiveForwardList<Compare, T, NodePointer, U>& left,
SortedIntrusiveForwardList<Compare, T, NodePointer, U>& right)
{
left.swap(right);
}
} // namespace estd
#endif // ESTD_SORTEDINTRUSIVEFORWARDLIST_HPP_
|