VirtualBox

source: vbox/trunk/include/iprt/cpp/list.h@ 97583

Last change on this file since 97583 was 96407, checked in by vboxsync, 2 years ago

scm copyright and license note update

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 32.2 KB
Line 
1/** @file
2 * IPRT - Generic List Class.
3 */
4
5/*
6 * Copyright (C) 2011-2022 Oracle and/or its affiliates.
7 *
8 * This file is part of VirtualBox base platform packages, as
9 * available from https://www.virtualbox.org.
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * as published by the Free Software Foundation, in version 3 of the
14 * License.
15 *
16 * This program is distributed in the hope that it will be useful, but
17 * WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, see <https://www.gnu.org/licenses>.
23 *
24 * The contents of this file may alternatively be used under the terms
25 * of the Common Development and Distribution License Version 1.0
26 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
27 * in the VirtualBox distribution, in which case the provisions of the
28 * CDDL are applicable instead of those of the GPL.
29 *
30 * You may elect to license modified versions of this file under the
31 * terms and conditions of either the GPL or the CDDL or both.
32 *
33 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
34 */
35
36#ifndef IPRT_INCLUDED_cpp_list_h
37#define IPRT_INCLUDED_cpp_list_h
38#ifndef RT_WITHOUT_PRAGMA_ONCE
39# pragma once
40#endif
41
42#include <iprt/cpp/meta.h>
43#include <iprt/mem.h>
44#include <iprt/string.h> /* for memcpy */
45#include <iprt/assert.h>
46
47#include <new> /* For std::bad_alloc */
48
49/** @defgroup grp_rt_cpp_list C++ List support
50 * @ingroup grp_rt_cpp
51 *
52 * @brief Generic C++ list class support.
53 *
54 * This list classes manage any amount of data in a fast and easy to use way.
55 * They have no dependencies on STL, only on generic memory management methods
56 * of IRPT. This allows list handling in situations where the use of STL
57 * container classes is forbidden.
58 *
59 * Not all of the functionality of STL container classes is implemented. There
60 * are no iterators or any other high level access/modifier methods (e.g.
61 * std::algorithms).
62 *
63 * The implementation is array based which allows fast access to the items.
64 * Appending items is usually also fast, cause the internal array is
65 * preallocated. To minimize the memory overhead, native types (that is
66 * everything smaller then the size of void*) are directly saved in the array.
67 * If bigger types are used (e.g. RTCString) the internal array is an array of
68 * pointers to the objects.
69 *
70 * The size of the internal array will usually not shrink, but grow
71 * automatically. Only certain methods, like RTCList::clear or the "=" operator
72 * will reset any previously allocated memory. You can call
73 * RTCList::setCapacity for manual adjustment. If the size of an new list will
74 * be known, calling the constructor with the necessary capacity will speed up
75 * the insertion of the new items.
76 *
77 * For the full public interface these list classes offer see RTCListBase.
78 *
79 * There are some requirements for the types used which follow:
80 * -# They need a default and a copy constructor.
81 * -# Some methods (e.g. RTCList::contains) need an equal operator.
82 * -# If the type is some complex class (that is, having a constructor which
83 * allocates members on the heap) it has to be greater than sizeof(void*) to
84 * be used correctly. If this is not the case you can manually overwrite the
85 * list behavior. Just add T* as a second parameter to the list template if
86 * your class is called T. Another possibility is to specialize the list for
87 * your target class. See below for more information.
88 *
89 * The native types like int, bool, ptr, ..., are meeting this criteria, so
90 * they are save to use.
91 *
92 * Please note that the return type of some of the getter methods are slightly
93 * different depending on the list type. Native types return the item by value,
94 * items with a size greater than sizeof(void*) by reference. As native types
95 * saved directly in the internal array, returning a reference to them (and
96 * saving them in a reference as well) would make them invalid (or pointing to
97 * a wrong item) when the list is changed in the meanwhile. Returning a
98 * reference for bigger types isn't problematic and makes sure we get out the
99 * best speed of the list. The one exception to this rule is the index
100 * operator[]. This operator always return a reference to make it possible to
101 * use it as a lvalue. Its your responsibility to make sure the list isn't
102 * changed when using the value as reference returned by this operator.
103 *
104 * The list class is reentrant. For a thread-safe variant see RTCMTList.
105 *
106 * Implementation details:
107 * It is possible to specialize any type. This might be necessary to get the
108 * best speed out of the list. Examples are the 64-bit types, which use the
109 * native (no pointers) implementation even on a 32-bit host. Consult the
110 * source code for more details.
111 *
112 * Current specialized implementations:
113 * - int64_t: RTCList<int64_t>
114 * - uint64_t: RTCList<uint64_t>
115 *
116 * @{
117 */
118
119/**
120 * The guard definition.
121 */
122template <bool G>
123class RTCListGuard;
124
125/**
126 * The default guard which does nothing.
127 */
128template <>
129class RTCListGuard<false>
130{
131public:
132 inline void enterRead() const {}
133 inline void leaveRead() const {}
134 inline void enterWrite() {}
135 inline void leaveWrite() {}
136
137 /* Define our own new and delete. */
138#ifdef RT_NEED_NEW_AND_DELETE
139 RTMEM_IMPLEMENT_NEW_AND_DELETE();
140#else
141 RTMEMEF_NEW_AND_DELETE_OPERATORS();
142#endif
143};
144
145/**
146 * General helper template for managing native values in RTCListBase.
147 */
148template <typename T1, typename T2>
149class RTCListHelper
150{
151public:
152 static inline void set(T2 *p, size_t i, const T1 &v) { p[i] = v; }
153 static inline T1 & at(T2 *p, size_t i) { return p[i]; }
154 static inline const T1 &atConst(T2 const *p, size_t i) { return p[i]; }
155 static inline size_t find(T2 *p, const T1 &v, size_t cElements)
156 {
157 size_t i = cElements;
158 while (i-- > 0)
159 if (p[i] == v)
160 return i;
161 return cElements;
162 }
163 static inline void copyTo(T2 *p, T2 *const p1 , size_t iTo, size_t cSize)
164 {
165 if (cSize > 0)
166 memcpy(&p[iTo], &p1[0], sizeof(T1) * cSize);
167 }
168 static inline void erase(T2 * /* p */, size_t /* i */) { /* Nothing to do here. */ }
169 static inline void eraseRange(T2 * /* p */, size_t /* cFrom */, size_t /* cSize */) { /* Nothing to do here. */ }
170};
171
172/**
173 * Specialized helper template for managing pointer values in RTCListBase.
174 */
175template <typename T1>
176class RTCListHelper<T1, T1*>
177{
178public:
179 static inline void set(T1 **p, size_t i, const T1 &v) { p[i] = new T1(v); }
180 static inline T1 & at(T1 **p, size_t i) { return *p[i]; }
181 static inline const T1 &atConst(T1 * const *p, size_t i) { return *p[i]; }
182 static inline size_t find(T1 **p, const T1 &v, size_t cElements)
183 {
184 size_t i = cElements;
185 while (i-- > 0)
186 if (*p[i] == v)
187 return i;
188 return cElements;
189 }
190 static inline void copyTo(T1 **p, T1 **const p1 , size_t iTo, size_t cSize)
191 {
192 for (size_t i = 0; i < cSize; ++i)
193 p[iTo + i] = new T1(*p1[i]);
194 }
195 static inline void erase(T1 **p, size_t i) { delete p[i]; }
196 static inline void eraseRange(T1 **p, size_t iFrom, size_t cItems)
197 {
198 while (cItems-- > 0)
199 delete p[iFrom++];
200 }
201};
202
203/**
204 * This is the base class for all other list classes. It implements the
205 * necessary list functionality in a type independent way and offers the public
206 * list interface to the user.
207 */
208template <class T, typename ITYPE, bool MT>
209class RTCListBase
210{
211 /** @name Traits.
212 *
213 * Defines the return type of most of the getter methods. If the internal
214 * used type is a pointer, we return a reference. If not we return by
215 * value.
216 *
217 * @{
218 */
219 typedef typename RTCIfPtr<ITYPE, T&, T>::result GET_RTYPE;
220 typedef typename RTCIfPtr<ITYPE, const T&, T>::result GET_CRTYPE;
221 /** @} */
222
223public:
224 /**
225 * Creates a new list.
226 *
227 * This preallocates @a cCapacity elements within the list.
228 *
229 * @param cCapacity The initial capacity the list has.
230 * @throws std::bad_alloc
231 */
232 RTCListBase(size_t cCapacity = kDefaultCapacity)
233 : m_pArray(0)
234 , m_cElements(0)
235 , m_cCapacity(0)
236 {
237 if (cCapacity > 0)
238 growArray(cCapacity);
239 }
240
241 /**
242 * Creates a copy of another list.
243 *
244 * The other list will be fully copied and the capacity will be the same as
245 * the size of the other list.
246 *
247 * @param other The list to copy.
248 * @throws std::bad_alloc
249 */
250 RTCListBase(const RTCListBase<T, ITYPE, MT>& other)
251 : m_pArray(0)
252 , m_cElements(0)
253 , m_cCapacity(0)
254 {
255 other.m_guard.enterRead();
256
257 size_t const cElementsOther = other.m_cElements;
258 resizeArrayNoErase(cElementsOther);
259 RTCListHelper<T, ITYPE>::copyTo(m_pArray, other.m_pArray, 0, cElementsOther);
260 m_cElements = cElementsOther;
261
262 other.m_guard.leaveRead();
263 }
264
265 /**
266 * Destructor.
267 */
268 ~RTCListBase()
269 {
270 RTCListHelper<T, ITYPE>::eraseRange(m_pArray, 0, m_cElements);
271 if (m_pArray)
272 {
273 RTMemFree(m_pArray);
274 m_pArray = NULL;
275 }
276 m_cElements = m_cCapacity = 0;
277 }
278
279 /**
280 * Sets a new capacity within the list.
281 *
282 * If the new capacity is bigger than the old size, it will be simply
283 * preallocated more space for the new items. If the new capacity is
284 * smaller than the previous size, items at the end of the list will be
285 * deleted.
286 *
287 * @param cCapacity The new capacity within the list.
288 * @throws std::bad_alloc
289 */
290 void setCapacity(size_t cCapacity)
291 {
292 m_guard.enterWrite();
293 resizeArray(cCapacity);
294 m_guard.leaveWrite();
295 }
296
297 /**
298 * Return the current capacity of the list.
299 *
300 * @return The actual capacity.
301 */
302 size_t capacity() const
303 {
304 m_guard.enterRead();
305 size_t cRet = m_cCapacity;
306 m_guard.leaveRead();
307 return cRet;
308 }
309
310 /**
311 * Check if an list contains any items.
312 *
313 * @return True if there is more than zero items, false otherwise.
314 */
315 bool isEmpty() const
316 {
317 m_guard.enterRead();
318 bool fEmpty = m_cElements == 0;
319 m_guard.leaveRead();
320 return fEmpty;
321 }
322
323 /**
324 * Return the current count of elements within the list.
325 *
326 * @return The current element count.
327 */
328 size_t size() const
329 {
330 m_guard.enterRead();
331 size_t cRet = m_cElements;
332 m_guard.leaveRead();
333 return cRet;
334 }
335
336 /**
337 * Inserts an item to the list at position @a i.
338 *
339 * @param i The position of the new item. The must be within or at the
340 * exact end of the list. Indexes specified beyond the end of
341 * the list will be changed to an append() operation and strict
342 * builds will raise an assert.
343 * @param val The new item.
344 * @return a reference to this list.
345 * @throws std::bad_alloc
346 */
347 RTCListBase<T, ITYPE, MT> &insert(size_t i, const T &val)
348 {
349 m_guard.enterWrite();
350
351 AssertMsgStmt(i <= m_cElements, ("i=%zu m_cElements=%zu\n", i, m_cElements), i = m_cElements);
352
353 if (m_cElements == m_cCapacity)
354 growArray(m_cCapacity + kDefaultCapacity);
355
356 memmove(&m_pArray[i + 1], &m_pArray[i], (m_cElements - i) * sizeof(ITYPE));
357 RTCListHelper<T, ITYPE>::set(m_pArray, i, val);
358 ++m_cElements;
359
360 m_guard.leaveWrite();
361 return *this;
362 }
363
364 /**
365 * Inserts a list to the list at position @a i.
366 *
367 * @param i The position of the new item. The must be within or at the
368 * exact end of the list. Indexes specified beyond the end of
369 * the list will be changed to an append() operation and strict
370 * builds will raise an assert.
371 * @param other The other list. This MUST not be the same as the destination
372 * list, will assert and return without doing anything if this
373 * happens.
374 * @return a reference to this list.
375 * @throws std::bad_alloc
376 */
377 RTCListBase<T, ITYPE, MT> &insert(size_t i, const RTCListBase<T, ITYPE, MT> &other)
378 {
379 AssertReturn(this != &other, *this);
380
381 other.m_guard.enterRead();
382 m_guard.enterWrite();
383
384 AssertMsgStmt(i <= m_cElements, ("i=%zu m_cElements=%zu\n", i, m_cElements), i = m_cElements);
385
386 size_t cElementsOther = other.m_cElements;
387 if (RT_LIKELY(cElementsOther > 0))
388 {
389 if (m_cCapacity - m_cElements < cElementsOther)
390 growArray(m_cCapacity + (cElementsOther - (m_cCapacity - m_cElements)));
391 if (i < m_cElements)
392 memmove(&m_pArray[i + cElementsOther], &m_pArray[i], (m_cElements - i) * sizeof(ITYPE));
393
394 RTCListHelper<T, ITYPE>::copyTo(&m_pArray[i], other.m_pArray, 0, cElementsOther);
395 m_cElements += cElementsOther;
396 }
397
398 m_guard.leaveWrite();
399 other.m_guard.leaveRead();
400 return *this;
401 }
402
403 /**
404 * Prepend an item to the list.
405 *
406 * @param val The new item.
407 * @return a reference to this list.
408 * @throws std::bad_alloc
409 */
410 RTCListBase<T, ITYPE, MT> &prepend(const T &val)
411 {
412 return insert(0, val);
413 }
414
415 /**
416 * Prepend a list of type T to the list.
417 *
418 * @param other The list to prepend.
419 * @return a reference to this list.
420 * @throws std::bad_alloc
421 */
422 RTCListBase<T, ITYPE, MT> &prepend(const RTCListBase<T, ITYPE, MT> &other)
423 {
424 return insert(0, other);
425 }
426
427 /**
428 * Append a default item to the list.
429 *
430 * @return a mutable reference to the item
431 * @throws std::bad_alloc
432 */
433 GET_RTYPE append()
434 {
435 m_guard.enterWrite();
436 if (m_cElements == m_cCapacity)
437 growArray(m_cCapacity + kDefaultCapacity);
438 RTCListHelper<T, ITYPE>::set(m_pArray, m_cElements, T());
439 GET_RTYPE rRet = RTCListHelper<T, ITYPE>::at(m_pArray, m_cElements);
440 ++m_cElements;
441 m_guard.leaveWrite();
442
443 return rRet;
444 }
445
446 /**
447 * Append an item to the list.
448 *
449 * @param val The new item.
450 * @return a reference to this list.
451 * @throws std::bad_alloc
452 */
453 RTCListBase<T, ITYPE, MT> &append(const T &val)
454 {
455 m_guard.enterWrite();
456 if (m_cElements == m_cCapacity)
457 growArray(m_cCapacity + kDefaultCapacity);
458 RTCListHelper<T, ITYPE>::set(m_pArray, m_cElements, val);
459 ++m_cElements;
460 m_guard.leaveWrite();
461
462 return *this;
463 }
464
465 /**
466 * Append a list of type T to the list.
467 *
468 * @param other The list to append. Must not be the same as the destination
469 * list, will assert and return without doing anything.
470 * @return a reference to this list.
471 * @throws std::bad_alloc
472 */
473 RTCListBase<T, ITYPE, MT> &append(const RTCListBase<T, ITYPE, MT> &other)
474 {
475 AssertReturn(this != &other, *this);
476
477 other.m_guard.enterRead();
478 m_guard.enterWrite();
479
480 insert(m_cElements, other);
481
482 m_guard.leaveWrite();
483 other.m_guard.leaveRead();
484 return *this;
485 }
486
487 /**
488 * Copy the items of the other list into this list.
489 *
490 * All previous items of this list are deleted.
491 *
492 * @param other The list to copy.
493 * @return a reference to this list.
494 */
495 RTCListBase<T, ITYPE, MT> &operator=(const RTCListBase<T, ITYPE, MT>& other)
496 {
497 /* Prevent self assignment */
498 if (RT_LIKELY(this != &other))
499 {
500
501 other.m_guard.enterRead();
502 m_guard.enterWrite();
503
504 /* Delete all items. */
505 RTCListHelper<T, ITYPE>::eraseRange(m_pArray, 0, m_cElements);
506
507 /* Need we to realloc memory. */
508 if (other.m_cElements != m_cCapacity)
509 resizeArrayNoErase(other.m_cElements);
510 m_cElements = other.m_cElements;
511
512 /* Copy new items. */
513 RTCListHelper<T, ITYPE>::copyTo(m_pArray, other.m_pArray, 0, other.m_cElements);
514
515 m_guard.leaveWrite();
516 other.m_guard.leaveRead();
517 }
518 return *this;
519 }
520
521 /**
522 * Replace an item in the list.
523 *
524 * @param i The position of the item to replace. If this is out of range,
525 * the request will be ignored, strict builds will assert.
526 * @param val The new value.
527 * @return a reference to this list.
528 */
529 RTCListBase<T, ITYPE, MT> &replace(size_t i, const T &val)
530 {
531 m_guard.enterWrite();
532
533 if (i < m_cElements)
534 {
535 RTCListHelper<T, ITYPE>::erase(m_pArray, i);
536 RTCListHelper<T, ITYPE>::set(m_pArray, i, val);
537 }
538 else
539 AssertMsgFailed(("i=%zu m_cElements=%zu\n", i, m_cElements));
540
541 m_guard.leaveWrite();
542 return *this;
543 }
544
545 /**
546 * Return the first item as constant object.
547 *
548 * @return A reference or pointer to the first item.
549 *
550 * @note No boundary checks are done. Make sure there is at least one
551 * element.
552 */
553 GET_CRTYPE first() const
554 {
555 m_guard.enterRead();
556 Assert(m_cElements > 0);
557 GET_CRTYPE res = RTCListHelper<T, ITYPE>::at(m_pArray, 0);
558 m_guard.leaveRead();
559 return res;
560 }
561
562 /**
563 * Return the first item.
564 *
565 * @return A reference or pointer to the first item.
566 *
567 * @note No boundary checks are done. Make sure there is at least one
568 * element.
569 */
570 GET_RTYPE first()
571 {
572 m_guard.enterRead();
573 Assert(m_cElements > 0);
574 GET_RTYPE res = RTCListHelper<T, ITYPE>::at(m_pArray, 0);
575 m_guard.leaveRead();
576 return res;
577 }
578
579 /**
580 * Return the last item as constant object.
581 *
582 * @return A reference or pointer to the last item.
583 *
584 * @note No boundary checks are done. Make sure there is at least one
585 * element.
586 */
587 GET_CRTYPE last() const
588 {
589 m_guard.enterRead();
590 Assert(m_cElements > 0);
591 GET_CRTYPE res = RTCListHelper<T, ITYPE>::at(m_pArray, m_cElements - 1);
592 m_guard.leaveRead();
593 return res;
594 }
595
596 /**
597 * Return the last item.
598 *
599 * @return A reference or pointer to the last item.
600 *
601 * @note No boundary checks are done. Make sure there is at least one
602 * element.
603 */
604 GET_RTYPE last()
605 {
606 m_guard.enterRead();
607 Assert(m_cElements > 0);
608 GET_RTYPE res = RTCListHelper<T, ITYPE>::at(m_pArray, m_cElements - 1);
609 m_guard.leaveRead();
610 return res;
611 }
612
613 /**
614 * Return the item at position @a i as constant object.
615 *
616 * @param i The position of the item to return. This better not be out of
617 * bounds, however should it be the last element of the array
618 * will be return and strict builds will raise an assertion.
619 * Should the array be empty, a crash is very likely.
620 * @return The item at position @a i.
621 */
622 GET_CRTYPE at(size_t i) const
623 {
624 m_guard.enterRead();
625 AssertMsgStmt(i < m_cElements, ("i=%zu m_cElements=%zu\n", i, m_cElements), i = m_cElements - 1);
626 GET_CRTYPE res = RTCListHelper<T, ITYPE>::at(m_pArray, i);
627 m_guard.leaveRead();
628 return res;
629 }
630
631 /**
632 * Return the item at position @a i.
633 *
634 * @param i The position of the item to return. This better not be out of
635 * bounds, however should it be the last element of the array
636 * will be return and strict builds will raise an assertion.
637 * Should the array be empty, a crash is very likely.
638 * @return The item at position @a i.
639 */
640 GET_RTYPE at(size_t i)
641 {
642 m_guard.enterRead();
643 AssertMsgStmt(i < m_cElements, ("i=%zu m_cElements=%zu\n", i, m_cElements), i = m_cElements - 1);
644 GET_RTYPE res = RTCListHelper<T, ITYPE>::at(m_pArray, i);
645 m_guard.leaveRead();
646 return res;
647 }
648
649 /**
650 * Return the item at position @a i as mutable reference.
651 *
652 * @param i The position of the item to return. This better not be out of
653 * bounds, however should it be the last element of the array
654 * will be return and strict builds will raise an assertion.
655 * Should the array be empty, a crash is very likely.
656 * @return The item at position @a i.
657 */
658 T &operator[](size_t i)
659 {
660 m_guard.enterRead();
661 AssertMsgStmt(i < m_cElements, ("i=%zu m_cElements=%zu\n", i, m_cElements), i = m_cElements - 1);
662 T &res = RTCListHelper<T, ITYPE>::at(m_pArray, i);
663 m_guard.leaveRead();
664 return res;
665 }
666
667 /**
668 * Return the item at position @a i as immutable reference.
669 *
670 * @param i The position of the item to return. This better not be out of
671 * bounds, however should it be the last element of the array
672 * will be return and strict builds will raise an assertion.
673 * Should the array be empty, a crash is very likely.
674 * @return The item at position @a i.
675 */
676 const T &operator[](size_t i) const
677 {
678 m_guard.enterRead();
679 AssertMsgStmt(i < m_cElements, ("i=%zu m_cElements=%zu\n", i, m_cElements), i = m_cElements - 1);
680 const T &rRet = RTCListHelper<T, ITYPE>::atConst(m_pArray, i);
681 m_guard.leaveRead();
682 return rRet;
683 }
684
685 /**
686 * Return a copy of the item at position @a i or default value if out of range.
687 *
688 * @param i The position of the item to return.
689 * @return Copy of the item at position @a i or default value.
690 */
691 T value(size_t i) const
692 {
693 m_guard.enterRead();
694 if (RT_LIKELY(i < m_cElements))
695 {
696 T res = RTCListHelper<T, ITYPE>::at(m_pArray, i);
697 m_guard.leaveRead();
698 return res;
699 }
700 m_guard.leaveRead();
701 return T();
702 }
703
704 /**
705 * Return a copy of the item at position @a i, or @a defaultVal if out of range.
706 *
707 * @param i The position of the item to return.
708 * @param defaultVal The value to return in case @a i is invalid.
709 * @return Copy of the item at position @a i or @a defaultVal.
710 */
711 T value(size_t i, const T &defaultVal) const
712 {
713 m_guard.enterRead();
714 if (RT_LIKELY(i < m_cElements))
715 {
716 T res = RTCListHelper<T, ITYPE>::at(m_pArray, i);
717 m_guard.leaveRead();
718 return res;
719 }
720 m_guard.leaveRead();
721 return defaultVal;
722 }
723
724 /**
725 * Check if @a val is contained in the array.
726 *
727 * @param val The value to check for.
728 * @return true if it is found, false otherwise.
729 */
730 bool contains(const T &val) const
731 {
732 m_guard.enterRead();
733 bool fRc = RTCListHelper<T, ITYPE>::find(m_pArray, val, m_cElements) < m_cElements;
734 m_guard.leaveRead();
735 return fRc;
736 }
737
738 /**
739 * Remove the first item.
740 *
741 * @note You should make sure the list isn't empty. Strict builds will assert.
742 * The other builds will quietly ignore the request.
743 */
744 void removeFirst()
745 {
746 removeAt(0);
747 }
748
749 /**
750 * Remove the last item.
751 *
752 * @note You should make sure the list isn't empty. Strict builds will assert.
753 * The other builds will quietly ignore the request.
754 */
755 void removeLast()
756 {
757 m_guard.enterWrite();
758 removeAtLocked(m_cElements - 1);
759 m_guard.leaveWrite();
760 }
761
762 /**
763 * Remove the item at position @a i.
764 *
765 * @param i The position of the item to remove. Out of bounds values will
766 * be ignored and an assertion will be raised in strict builds.
767 */
768 void removeAt(size_t i)
769 {
770 m_guard.enterWrite();
771 removeAtLocked(i);
772 m_guard.leaveWrite();
773 }
774
775 /**
776 * Remove a range of items from the list.
777 *
778 * @param iStart The start position of the items to remove.
779 * @param iEnd The end position of the items to remove (excluded).
780 */
781 void removeRange(size_t iStart, size_t iEnd)
782 {
783 AssertReturnVoid(iStart <= iEnd);
784 m_guard.enterWrite();
785
786 AssertMsgStmt(iEnd <= m_cElements, ("iEnd=%zu m_cElements=%zu\n", iEnd, m_cElements), iEnd = m_cElements);
787 AssertMsgStmt(iStart < m_cElements, ("iStart=%zu m_cElements=%zu\n", iStart, m_cElements), iStart = m_cElements);
788 size_t const cElements = iEnd - iStart;
789 if (cElements > 0)
790 {
791 Assert(iStart < m_cElements);
792 RTCListHelper<T, ITYPE>::eraseRange(m_pArray, iStart, cElements);
793 if (m_cElements > iEnd)
794 memmove(&m_pArray[iStart], &m_pArray[iEnd], (m_cElements - iEnd) * sizeof(ITYPE));
795 m_cElements -= cElements;
796 }
797
798 m_guard.leaveWrite();
799 }
800
801 /**
802 * Delete all items in the list.
803 */
804 void clear()
805 {
806 m_guard.enterWrite();
807
808 /* Values cleanup */
809 RTCListHelper<T, ITYPE>::eraseRange(m_pArray, 0, m_cElements);
810 if (m_cElements != kDefaultCapacity)
811 resizeArrayNoErase(kDefaultCapacity);
812 m_cElements = 0;
813
814 m_guard.leaveWrite();
815 }
816
817 /**
818 * Return the raw array.
819 *
820 * For native types this is a pointer to continuous memory of the items. For
821 * pointer types this is a continuous memory of pointers to the items.
822 *
823 * @warning If you change anything in the underlaying list, this memory
824 * will very likely become invalid. So take care when using this
825 * method and better try to avoid using it.
826 *
827 * @returns the raw memory.
828 */
829 ITYPE *raw() const
830 {
831 m_guard.enterRead();
832 ITYPE *pRet = m_pArray;
833 m_guard.leaveRead();
834 return pRet;
835 }
836
837 RTCListBase<T, ITYPE, MT> &operator<<(const T &val)
838 {
839 return append(val);
840 }
841
842 /* Define our own new and delete. */
843#ifdef RT_NEED_NEW_AND_DELETE
844 RTMEM_IMPLEMENT_NEW_AND_DELETE();
845#else
846 RTMEMEF_NEW_AND_DELETE_OPERATORS();
847#endif
848
849 /**
850 * The default capacity of the list. This is also used as grow factor.
851 */
852 static const size_t kDefaultCapacity;
853
854protected:
855
856 /**
857 * Generic resizes the array, surplus elements are erased.
858 *
859 * @param cElementsNew The new array size.
860 * @throws std::bad_alloc.
861 */
862 void resizeArray(size_t cElementsNew)
863 {
864 /* Same size? */
865 if (cElementsNew == m_cCapacity)
866 return;
867
868 /* If we get smaller we have to delete some of the objects at the end
869 of the list. */
870 if ( cElementsNew < m_cElements
871 && m_pArray)
872 RTCListHelper<T, ITYPE>::eraseRange(m_pArray, cElementsNew, m_cElements - cElementsNew);
873
874 resizeArrayNoErase(cElementsNew);
875 }
876
877 /**
878 * Resizes the array without doing the erase() thing on surplus elements.
879 *
880 * @param cElementsNew The new array size.
881 * @throws std::bad_alloc.
882 */
883 void resizeArrayNoErase(size_t cElementsNew)
884 {
885 /* Same size? */
886 if (cElementsNew == m_cCapacity)
887 return;
888
889 /* Resize the array. */
890 if (cElementsNew > 0)
891 {
892 void *pvNew = RTMemRealloc(m_pArray, sizeof(ITYPE) * cElementsNew);
893 if (!pvNew)
894 {
895#ifdef RT_EXCEPTIONS_ENABLED
896 throw std::bad_alloc();
897#endif
898 return;
899 }
900 m_pArray = static_cast<ITYPE*>(pvNew);
901 }
902 /* If we get zero we delete the array it self. */
903 else if (m_pArray)
904 {
905 RTMemFree(m_pArray);
906 m_pArray = NULL;
907 }
908
909 m_cCapacity = cElementsNew;
910 if (m_cElements > cElementsNew)
911 m_cElements = cElementsNew;
912 }
913
914 /**
915 * Special realloc method which require that the array will grow.
916 *
917 * @param cElementsNew The new array size.
918 * @throws std::bad_alloc.
919 * @note No boundary checks are done!
920 */
921 void growArray(size_t cElementsNew)
922 {
923 Assert(cElementsNew > m_cCapacity);
924 void *pvNew = RTMemRealloc(m_pArray, sizeof(ITYPE) * cElementsNew);
925 if (pvNew)
926 {
927 m_cCapacity = cElementsNew;
928 m_pArray = static_cast<ITYPE*>(pvNew);
929 }
930 else
931 {
932#ifdef RT_EXCEPTIONS_ENABLED
933 throw std::bad_alloc();
934#endif
935 }
936 }
937
938 /**
939 * Remove the item at position @a i.
940 *
941 * @param i The position of the item to remove. Out of bounds values will
942 * be ignored and an assertion will be raised in strict builds.
943 * @remarks
944 */
945 void removeAtLocked(size_t i)
946 {
947 AssertMsgReturnVoid(i < m_cElements, ("i=%zu m_cElements=%zu\n", i, m_cElements));
948
949 RTCListHelper<T, ITYPE>::erase(m_pArray, i);
950 if (i < m_cElements - 1)
951 memmove(&m_pArray[i], &m_pArray[i + 1], (m_cElements - i - 1) * sizeof(ITYPE));
952 --m_cElements;
953 }
954
955
956 /** The internal list array. */
957 ITYPE *m_pArray;
958 /** The current count of items in use. */
959 size_t m_cElements;
960 /** The current capacity of the internal array. */
961 size_t m_cCapacity;
962 /** The guard used to serialize the access to the items. */
963 RTCListGuard<MT> m_guard;
964};
965
966template <class T, typename ITYPE, bool MT>
967const size_t RTCListBase<T, ITYPE, MT>::kDefaultCapacity = 10;
968
969/**
970 * Template class which automatically determines the type of list to use.
971 *
972 * @see RTCListBase
973 */
974template <class T, typename ITYPE = typename RTCIf<(sizeof(T) > sizeof(void*)), T*, T>::result>
975class RTCList : public RTCListBase<T, ITYPE, false>
976{
977 /* Traits */
978 typedef RTCListBase<T, ITYPE, false> BASE;
979
980public:
981 /**
982 * Creates a new list.
983 *
984 * This preallocates @a cCapacity elements within the list.
985 *
986 * @param cCapacity The initial capacity the list has.
987 * @throws std::bad_alloc
988 */
989 RTCList(size_t cCapacity = BASE::kDefaultCapacity)
990 : BASE(cCapacity) {}
991
992 RTCList(const BASE &other)
993 : BASE(other) {}
994
995 /* Define our own new and delete. */
996#ifdef RT_NEED_NEW_AND_DELETE
997 RTMEM_IMPLEMENT_NEW_AND_DELETE();
998#else
999 RTMEMEF_NEW_AND_DELETE_OPERATORS();
1000#endif
1001};
1002
1003/**
1004 * Specialized class for using the native type list for unsigned 64-bit
1005 * values even on a 32-bit host.
1006 *
1007 * @see RTCListBase
1008 */
1009template <>
1010class RTCList<uint64_t>: public RTCListBase<uint64_t, uint64_t, false>
1011{
1012 /* Traits */
1013 typedef RTCListBase<uint64_t, uint64_t, false> BASE;
1014
1015public:
1016 /**
1017 * Creates a new list.
1018 *
1019 * This preallocates @a cCapacity elements within the list.
1020 *
1021 * @param cCapacity The initial capacity the list has.
1022 * @throws std::bad_alloc
1023 */
1024 RTCList(size_t cCapacity = BASE::kDefaultCapacity)
1025 : BASE(cCapacity) {}
1026
1027 /* Define our own new and delete. */
1028#ifdef RT_NEED_NEW_AND_DELETE
1029 RTMEM_IMPLEMENT_NEW_AND_DELETE();
1030#else
1031 RTMEMEF_NEW_AND_DELETE_OPERATORS();
1032#endif
1033};
1034
1035/**
1036 * Specialized class for using the native type list for signed 64-bit
1037 * values even on a 32-bit host.
1038 *
1039 * @see RTCListBase
1040 */
1041template <>
1042class RTCList<int64_t>: public RTCListBase<int64_t, int64_t, false>
1043{
1044 /* Traits */
1045 typedef RTCListBase<int64_t, int64_t, false> BASE;
1046
1047public:
1048 /**
1049 * Creates a new list.
1050 *
1051 * This preallocates @a cCapacity elements within the list.
1052 *
1053 * @param cCapacity The initial capacity the list has.
1054 * @throws std::bad_alloc
1055 */
1056 RTCList(size_t cCapacity = BASE::kDefaultCapacity)
1057 : BASE(cCapacity) {}
1058
1059 /* Define our own new and delete. */
1060#ifdef RT_NEED_NEW_AND_DELETE
1061 RTMEM_IMPLEMENT_NEW_AND_DELETE();
1062#else
1063 RTMEMEF_NEW_AND_DELETE_OPERATORS();
1064#endif
1065};
1066
1067/** @} */
1068
1069#endif /* !IPRT_INCLUDED_cpp_list_h */
1070
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette