aboutsummaryrefslogtreecommitdiffstats
path: root/include/estd/SortedIntrusiveList.hpp
blob: 1d65ee37f5726308bbb0b0f3ccf991ff11ea2209 (plain)
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
/**
 * \file
 * \brief SortedIntrusiveList 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_SORTEDINTRUSIVELIST_HPP_
#define ESTD_SORTEDINTRUSIVELIST_HPP_

#include "estd/IntrusiveList.hpp"

#include <algorithm>

namespace estd
{

/**
 * \brief SortedIntrusiveList class is an IntrusiveList with sorted elements
 *
 * This class tries to provide an interface similar to std::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 IntrusiveListNode variable
 * \tparam NodePointer is a pointer-to-member to IntrusiveListNode 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, IntrusiveListNode T::* NodePointer, typename U = T>
class SortedIntrusiveList
{
public:

	/// unsorted intrusive list used internally
	using UnsortedIntrusiveList = IntrusiveList<T, NodePointer, U>;

	/// const iterator of elements on the list
	using const_iterator = typename UnsortedIntrusiveList::const_iterator;

	/// const reverse iterator of elements on the list
	using const_reverse_iterator = typename UnsortedIntrusiveList::const_reverse_iterator;

	/// const pointer to value linked in the list
	using const_pointer = typename UnsortedIntrusiveList::const_pointer;

	/// const reference to value linked in the list
	using const_reference = typename UnsortedIntrusiveList::const_reference;

	/// iterator of elements on the list
	using iterator = typename UnsortedIntrusiveList::iterator;

	/// reverse iterator of elements on the list
	using reverse_iterator = typename UnsortedIntrusiveList::reverse_iterator;

	/// pointer to value linked in the list
	using pointer = typename UnsortedIntrusiveList::pointer;

	/// reference to value linked in the list
	using reference = typename UnsortedIntrusiveList::reference;

	/// value linked in the list
	using value_type = typename UnsortedIntrusiveList::value_type;

	/**
	 * \brief SortedIntrusiveList's constructor
	 *
	 * \param [in] compare is a reference to Compare object used to copy-construct internal comparison functor
	 */

	constexpr SortedIntrusiveList(const Compare& compare = Compare{}) :
			implementation_{compare}
	{

	}

	/**
	 * \return reference to last element on the list
	 */

	reference back()
	{
		return implementation_.intrusiveList.back();
	}

	/**
	 * \return const reference to last element on the list
	 */

	const_reference back() const
	{
		return implementation_.intrusiveList.back();
	}

	/**
	 * \return iterator of first element on the list
	 */

	iterator begin()
	{
		return implementation_.intrusiveList.begin();
	}

	/**
	 * \return const iterator of first element on the list
	 */

	const_iterator begin() const
	{
		return implementation_.intrusiveList.begin();
	}

	/**
	 * \return const iterator of first element on the list
	 */

	const_iterator cbegin() const
	{
		return implementation_.intrusiveList.cbegin();
	}

	/**
	 * \return const iterator of "one past the last" element on the list
	 */

	const_iterator cend() const
	{
		return implementation_.intrusiveList.cend();
	}

	/**
	 * \brief Unlinks all elements from the list.
	 */

	void clear()
	{
		implementation_.intrusiveList.clear();
	}

	/**
	 * \return true is the list is empty, false otherwise
	 */

	bool empty() const
	{
		return implementation_.intrusiveList.empty();
	}

	/**
	 * \return iterator of "one past the last" element on the list
	 */

	iterator end()
	{
		return implementation_.intrusiveList.end();
	}

	/**
	 * \return const iterator of "one past the last" element on the list
	 */

	const_iterator end() const
	{
		return implementation_.intrusiveList.end();
	}

	/**
	 * \return reference to first element on the list
	 */

	reference front()
	{
		return implementation_.intrusiveList.front();
	}

	/**
	 * \return const reference to first element on the list
	 */

	const_reference front() const
	{
		return implementation_.intrusiveList.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 UnsortedIntrusiveList::insert(implementation_.findInsertPosition(newElement), newElement);
	}

	/**
	 * \brief Unlinks the last element from the list.
	 */

	void pop_back()
	{
		implementation_.intrusiveList.pop_back();
	}

	/**
	 * \brief Unlinks the first element from the list.
	 */

	void pop_front()
	{
		implementation_.intrusiveList.pop_front();
	}

	/**
	 * \brief Transfers the element from another list to this one, keeping it sorted.
	 *
	 * \param [in] splicedElement is an iterator of the element that will be spliced from another list to this one
	 */

	void splice(const iterator splicedElement)
	{
		UnsortedIntrusiveList::splice(implementation_.findInsertPosition(*splicedElement), splicedElement);
	}

	/**
	 * \brief Swaps contents with another list.
	 *
	 * \param [in] other is a reference to SortedIntrusiveList with which contents of this list will be swapped
	 */

	void swap(SortedIntrusiveList& other)
	{
		implementation_.swap(other.implementation_);
	}

	/**
	 * \brief Unlinks the element at \a position from the list.
	 *
	 * \note No instance of the list is needed for this operation.
	 *
	 * \param [in] position is an iterator of the element that will be unlinked from the list
	 *
	 * \return iterator of the element that was following the element which was unlinked
	 */

	static iterator erase(const iterator position)
	{
		return UnsortedIntrusiveList::erase(position);
	}

	SortedIntrusiveList(const SortedIntrusiveList&) = delete;
	SortedIntrusiveList(SortedIntrusiveList&&) = default;
	const SortedIntrusiveList& operator=(const SortedIntrusiveList&) = delete;
	SortedIntrusiveList& operator=(SortedIntrusiveList&&) = 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},
				intrusiveList{}
		{

		}

		/**
		 * \brief Finds insert 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 dereferenced value and \a newElement returns
		 * true.
		 */

		iterator findInsertPosition(const_reference newElement)
		{
			return std::find_if(intrusiveList.begin(), intrusiveList.end(),
					[this, &newElement](const_reference& element) -> bool
					{
						return this->Compare::operator()(element, newElement);
					}
			);
		}

		/**
		 * \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)
		{
			intrusiveList.swap(other.intrusiveList);
			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 IntrusiveList
		UnsortedIntrusiveList intrusiveList;
	};

	/// internal Implementation object - unsorted IntrusiveList 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 IntrusiveListNode variable
 * \tparam NodePointer is a pointer-to-member to IntrusiveListNode 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 SortedIntrusiveList with which contents of \a right will be swapped
 * \param [in] right is a reference to SortedIntrusiveList with which contents of \a left will be swapped
 */

template<typename Compare, typename T, IntrusiveListNode T::* NodePointer, typename U = T>
inline void swap(SortedIntrusiveList<Compare, T, NodePointer, U>& left,
		SortedIntrusiveList<Compare, T, NodePointer, U>& right)
{
	left.swap(right);
}

}	// namespace estd

#endif	// ESTD_SORTEDINTRUSIVELIST_HPP_