VirtualBox

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

Last change on this file since 104212 was 98103, checked in by vboxsync, 23 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 34.2 KB
Line 
1/** @file
2 * IPRT - Generic List Class.
3 */
4
5/*
6 * Copyright (C) 2011-2023 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 other.m_guard.enterRead();
501 m_guard.enterWrite();
502
503 /* Delete all items. */
504 RTCListHelper<T, ITYPE>::eraseRange(m_pArray, 0, m_cElements);
505
506 /* Need we to realloc memory. */
507 if (other.m_cElements != m_cCapacity)
508 resizeArrayNoErase(other.m_cElements);
509 m_cElements = other.m_cElements;
510
511 /* Copy new items. */
512 RTCListHelper<T, ITYPE>::copyTo(m_pArray, other.m_pArray, 0, other.m_cElements);
513
514 m_guard.leaveWrite();
515 other.m_guard.leaveRead();
516 }
517 return *this;
518 }
519
520 /**
521 * Compares if this list's items match the other list.
522 *
523 * @returns \c true if both lists contain the same items, \c false if not.
524 * @param other The list to compare this list with.
525 */
526 bool operator==(const RTCListBase<T, ITYPE, MT>& other)
527 {
528 /* Prevent self comparrison */
529 if (RT_LIKELY(this == &other))
530 return true;
531
532 other.m_guard.enterRead();
533 m_guard.enterRead();
534
535 bool fEqual = true;
536 if (other.m_cElements == m_cElements)
537 {
538 for (size_t i = 0; i < m_cElements; i++)
539 {
540 if (RTCListHelper<T, ITYPE>::at(m_pArray, i) != RTCListHelper<T, ITYPE>::at(other.m_pArray, i))
541 {
542 fEqual = false;
543 break;
544 }
545 }
546 }
547 else
548 fEqual = false;
549
550 m_guard.leaveRead();
551 other.m_guard.leaveRead();
552
553 return fEqual;
554 }
555
556 /**
557 * Compares if this list's items do not match the other list.
558 *
559 * @returns \c true if the lists do not match, \c false if otherwise.
560 * @param other The list to compare this list with.
561 */
562 bool operator!=(const RTCListBase<T, ITYPE, MT>& other)
563 {
564 return !(*this == other);
565 }
566
567 /**
568 * Replace an item in the list.
569 *
570 * @param i The position of the item to replace. If this is out of range,
571 * the request will be ignored, strict builds will assert.
572 * @param val The new value.
573 * @return a reference to this list.
574 */
575 RTCListBase<T, ITYPE, MT> &replace(size_t i, const T &val)
576 {
577 m_guard.enterWrite();
578
579 if (i < m_cElements)
580 {
581 RTCListHelper<T, ITYPE>::erase(m_pArray, i);
582 RTCListHelper<T, ITYPE>::set(m_pArray, i, val);
583 }
584 else
585 AssertMsgFailed(("i=%zu m_cElements=%zu\n", i, m_cElements));
586
587 m_guard.leaveWrite();
588 return *this;
589 }
590
591 /**
592 * Applies a filter of type T to this list.
593 *
594 * @param other The list which contains the elements to filter out from this list.
595 * @return a reference to this list.
596 */
597 RTCListBase<T, ITYPE, MT> &filter(const RTCListBase<T, ITYPE, MT> &other)
598 {
599 AssertReturn(this != &other, *this);
600
601 other.m_guard.enterRead();
602 m_guard.enterWrite();
603
604 for (size_t i = 0; i < m_cElements; i++)
605 {
606 for (size_t f = 0; f < other.m_cElements; f++)
607 {
608 if (RTCListHelper<T, ITYPE>::at(m_pArray, i) == RTCListHelper<T, ITYPE>::at(other.m_pArray, f))
609 removeAtLocked(i);
610 }
611 }
612
613 m_guard.leaveWrite();
614 other.m_guard.leaveRead();
615 return *this;
616 }
617
618 /**
619 * Return the first item as constant object.
620 *
621 * @return A reference or pointer to the first item.
622 *
623 * @note No boundary checks are done. Make sure there is at least one
624 * element.
625 */
626 GET_CRTYPE first() const
627 {
628 m_guard.enterRead();
629 Assert(m_cElements > 0);
630 GET_CRTYPE res = RTCListHelper<T, ITYPE>::at(m_pArray, 0);
631 m_guard.leaveRead();
632 return res;
633 }
634
635 /**
636 * Return the first item.
637 *
638 * @return A reference or pointer to the first item.
639 *
640 * @note No boundary checks are done. Make sure there is at least one
641 * element.
642 */
643 GET_RTYPE first()
644 {
645 m_guard.enterRead();
646 Assert(m_cElements > 0);
647 GET_RTYPE res = RTCListHelper<T, ITYPE>::at(m_pArray, 0);
648 m_guard.leaveRead();
649 return res;
650 }
651
652 /**
653 * Return the last item as constant object.
654 *
655 * @return A reference or pointer to the last item.
656 *
657 * @note No boundary checks are done. Make sure there is at least one
658 * element.
659 */
660 GET_CRTYPE last() const
661 {
662 m_guard.enterRead();
663 Assert(m_cElements > 0);
664 GET_CRTYPE res = RTCListHelper<T, ITYPE>::at(m_pArray, m_cElements - 1);
665 m_guard.leaveRead();
666 return res;
667 }
668
669 /**
670 * Return the last item.
671 *
672 * @return A reference or pointer to the last item.
673 *
674 * @note No boundary checks are done. Make sure there is at least one
675 * element.
676 */
677 GET_RTYPE last()
678 {
679 m_guard.enterRead();
680 Assert(m_cElements > 0);
681 GET_RTYPE res = RTCListHelper<T, ITYPE>::at(m_pArray, m_cElements - 1);
682 m_guard.leaveRead();
683 return res;
684 }
685
686 /**
687 * Return the item at position @a i as constant object.
688 *
689 * @param i The position of the item to return. This better not be out of
690 * bounds, however should it be the last element of the array
691 * will be return and strict builds will raise an assertion.
692 * Should the array be empty, a crash is very likely.
693 * @return The item at position @a i.
694 */
695 GET_CRTYPE at(size_t i) const
696 {
697 m_guard.enterRead();
698 AssertMsgStmt(i < m_cElements, ("i=%zu m_cElements=%zu\n", i, m_cElements), i = m_cElements - 1);
699 GET_CRTYPE res = RTCListHelper<T, ITYPE>::at(m_pArray, i);
700 m_guard.leaveRead();
701 return res;
702 }
703
704 /**
705 * Return the item at position @a i.
706 *
707 * @param i The position of the item to return. This better not be out of
708 * bounds, however should it be the last element of the array
709 * will be return and strict builds will raise an assertion.
710 * Should the array be empty, a crash is very likely.
711 * @return The item at position @a i.
712 */
713 GET_RTYPE at(size_t i)
714 {
715 m_guard.enterRead();
716 AssertMsgStmt(i < m_cElements, ("i=%zu m_cElements=%zu\n", i, m_cElements), i = m_cElements - 1);
717 GET_RTYPE res = RTCListHelper<T, ITYPE>::at(m_pArray, i);
718 m_guard.leaveRead();
719 return res;
720 }
721
722 /**
723 * Return the item at position @a i as mutable reference.
724 *
725 * @param i The position of the item to return. This better not be out of
726 * bounds, however should it be the last element of the array
727 * will be return and strict builds will raise an assertion.
728 * Should the array be empty, a crash is very likely.
729 * @return The item at position @a i.
730 */
731 T &operator[](size_t i)
732 {
733 m_guard.enterRead();
734 AssertMsgStmt(i < m_cElements, ("i=%zu m_cElements=%zu\n", i, m_cElements), i = m_cElements - 1);
735 T &res = RTCListHelper<T, ITYPE>::at(m_pArray, i);
736 m_guard.leaveRead();
737 return res;
738 }
739
740 /**
741 * Return the item at position @a i as immutable reference.
742 *
743 * @param i The position of the item to return. This better not be out of
744 * bounds, however should it be the last element of the array
745 * will be return and strict builds will raise an assertion.
746 * Should the array be empty, a crash is very likely.
747 * @return The item at position @a i.
748 */
749 const T &operator[](size_t i) const
750 {
751 m_guard.enterRead();
752 AssertMsgStmt(i < m_cElements, ("i=%zu m_cElements=%zu\n", i, m_cElements), i = m_cElements - 1);
753 const T &rRet = RTCListHelper<T, ITYPE>::atConst(m_pArray, i);
754 m_guard.leaveRead();
755 return rRet;
756 }
757
758 /**
759 * Return a copy of the item at position @a i or default value if out of range.
760 *
761 * @param i The position of the item to return.
762 * @return Copy of the item at position @a i or default value.
763 */
764 T value(size_t i) const
765 {
766 m_guard.enterRead();
767 if (RT_LIKELY(i < m_cElements))
768 {
769 T res = RTCListHelper<T, ITYPE>::at(m_pArray, i);
770 m_guard.leaveRead();
771 return res;
772 }
773 m_guard.leaveRead();
774 return T();
775 }
776
777 /**
778 * Return a copy of the item at position @a i, or @a defaultVal if out of range.
779 *
780 * @param i The position of the item to return.
781 * @param defaultVal The value to return in case @a i is invalid.
782 * @return Copy of the item at position @a i or @a defaultVal.
783 */
784 T value(size_t i, const T &defaultVal) const
785 {
786 m_guard.enterRead();
787 if (RT_LIKELY(i < m_cElements))
788 {
789 T res = RTCListHelper<T, ITYPE>::at(m_pArray, i);
790 m_guard.leaveRead();
791 return res;
792 }
793 m_guard.leaveRead();
794 return defaultVal;
795 }
796
797 /**
798 * Check if @a val is contained in the array.
799 *
800 * @param val The value to check for.
801 * @return true if it is found, false otherwise.
802 */
803 bool contains(const T &val) const
804 {
805 m_guard.enterRead();
806 bool fRc = RTCListHelper<T, ITYPE>::find(m_pArray, val, m_cElements) < m_cElements;
807 m_guard.leaveRead();
808 return fRc;
809 }
810
811 /**
812 * Remove the first item.
813 *
814 * @note You should make sure the list isn't empty. Strict builds will assert.
815 * The other builds will quietly ignore the request.
816 */
817 void removeFirst()
818 {
819 removeAt(0);
820 }
821
822 /**
823 * Remove the last item.
824 *
825 * @note You should make sure the list isn't empty. Strict builds will assert.
826 * The other builds will quietly ignore the request.
827 */
828 void removeLast()
829 {
830 m_guard.enterWrite();
831 removeAtLocked(m_cElements - 1);
832 m_guard.leaveWrite();
833 }
834
835 /**
836 * Remove the item at position @a i.
837 *
838 * @param i The position of the item to remove. Out of bounds values will
839 * be ignored and an assertion will be raised in strict builds.
840 */
841 void removeAt(size_t i)
842 {
843 m_guard.enterWrite();
844 removeAtLocked(i);
845 m_guard.leaveWrite();
846 }
847
848 /**
849 * Remove a range of items from the list.
850 *
851 * @param iStart The start position of the items to remove.
852 * @param iEnd The end position of the items to remove (excluded).
853 */
854 void removeRange(size_t iStart, size_t iEnd)
855 {
856 AssertReturnVoid(iStart <= iEnd);
857 m_guard.enterWrite();
858
859 AssertMsgStmt(iEnd <= m_cElements, ("iEnd=%zu m_cElements=%zu\n", iEnd, m_cElements), iEnd = m_cElements);
860 AssertMsgStmt(iStart < m_cElements, ("iStart=%zu m_cElements=%zu\n", iStart, m_cElements), iStart = m_cElements);
861 size_t const cElements = iEnd - iStart;
862 if (cElements > 0)
863 {
864 Assert(iStart < m_cElements);
865 RTCListHelper<T, ITYPE>::eraseRange(m_pArray, iStart, cElements);
866 if (m_cElements > iEnd)
867 memmove(&m_pArray[iStart], &m_pArray[iEnd], (m_cElements - iEnd) * sizeof(ITYPE));
868 m_cElements -= cElements;
869 }
870
871 m_guard.leaveWrite();
872 }
873
874 /**
875 * Delete all items in the list.
876 */
877 void clear()
878 {
879 m_guard.enterWrite();
880
881 /* Values cleanup */
882 RTCListHelper<T, ITYPE>::eraseRange(m_pArray, 0, m_cElements);
883 if (m_cElements != kDefaultCapacity)
884 resizeArrayNoErase(kDefaultCapacity);
885 m_cElements = 0;
886
887 m_guard.leaveWrite();
888 }
889
890 /**
891 * Return the raw array.
892 *
893 * For native types this is a pointer to continuous memory of the items. For
894 * pointer types this is a continuous memory of pointers to the items.
895 *
896 * @warning If you change anything in the underlaying list, this memory
897 * will very likely become invalid. So take care when using this
898 * method and better try to avoid using it.
899 *
900 * @returns the raw memory.
901 */
902 ITYPE *raw() const
903 {
904 m_guard.enterRead();
905 ITYPE *pRet = m_pArray;
906 m_guard.leaveRead();
907 return pRet;
908 }
909
910 RTCListBase<T, ITYPE, MT> &operator<<(const T &val)
911 {
912 return append(val);
913 }
914
915 /* Define our own new and delete. */
916#ifdef RT_NEED_NEW_AND_DELETE
917 RTMEM_IMPLEMENT_NEW_AND_DELETE();
918#else
919 RTMEMEF_NEW_AND_DELETE_OPERATORS();
920#endif
921
922 /**
923 * The default capacity of the list. This is also used as grow factor.
924 */
925 static const size_t kDefaultCapacity;
926
927protected:
928
929 /**
930 * Generic resizes the array, surplus elements are erased.
931 *
932 * @param cElementsNew The new array size.
933 * @throws std::bad_alloc.
934 */
935 void resizeArray(size_t cElementsNew)
936 {
937 /* Same size? */
938 if (cElementsNew == m_cCapacity)
939 return;
940
941 /* If we get smaller we have to delete some of the objects at the end
942 of the list. */
943 if ( cElementsNew < m_cElements
944 && m_pArray)
945 RTCListHelper<T, ITYPE>::eraseRange(m_pArray, cElementsNew, m_cElements - cElementsNew);
946
947 resizeArrayNoErase(cElementsNew);
948 }
949
950 /**
951 * Resizes the array without doing the erase() thing on surplus elements.
952 *
953 * @param cElementsNew The new array size.
954 * @throws std::bad_alloc.
955 */
956 void resizeArrayNoErase(size_t cElementsNew)
957 {
958 /* Same size? */
959 if (cElementsNew == m_cCapacity)
960 return;
961
962 /* Resize the array. */
963 if (cElementsNew > 0)
964 {
965 void *pvNew = RTMemRealloc(m_pArray, sizeof(ITYPE) * cElementsNew);
966 if (!pvNew)
967 {
968#ifdef RT_EXCEPTIONS_ENABLED
969 throw std::bad_alloc();
970#endif
971 return;
972 }
973 m_pArray = static_cast<ITYPE*>(pvNew);
974 }
975 /* If we get zero we delete the array it self. */
976 else if (m_pArray)
977 {
978 RTMemFree(m_pArray);
979 m_pArray = NULL;
980 }
981
982 m_cCapacity = cElementsNew;
983 if (m_cElements > cElementsNew)
984 m_cElements = cElementsNew;
985 }
986
987 /**
988 * Special realloc method which require that the array will grow.
989 *
990 * @param cElementsNew The new array size.
991 * @throws std::bad_alloc.
992 * @note No boundary checks are done!
993 */
994 void growArray(size_t cElementsNew)
995 {
996 Assert(cElementsNew > m_cCapacity);
997 void *pvNew = RTMemRealloc(m_pArray, sizeof(ITYPE) * cElementsNew);
998 if (pvNew)
999 {
1000 m_cCapacity = cElementsNew;
1001 m_pArray = static_cast<ITYPE*>(pvNew);
1002 }
1003 else
1004 {
1005#ifdef RT_EXCEPTIONS_ENABLED
1006 throw std::bad_alloc();
1007#endif
1008 }
1009 }
1010
1011 /**
1012 * Remove the item at position @a i.
1013 *
1014 * @param i The position of the item to remove. Out of bounds values will
1015 * be ignored and an assertion will be raised in strict builds.
1016 * @remarks
1017 */
1018 void removeAtLocked(size_t i)
1019 {
1020 AssertMsgReturnVoid(i < m_cElements, ("i=%zu m_cElements=%zu\n", i, m_cElements));
1021
1022 RTCListHelper<T, ITYPE>::erase(m_pArray, i);
1023 if (i < m_cElements - 1)
1024 memmove(&m_pArray[i], &m_pArray[i + 1], (m_cElements - i - 1) * sizeof(ITYPE));
1025 --m_cElements;
1026 }
1027
1028
1029 /** The internal list array. */
1030 ITYPE *m_pArray;
1031 /** The current count of items in use. */
1032 size_t m_cElements;
1033 /** The current capacity of the internal array. */
1034 size_t m_cCapacity;
1035 /** The guard used to serialize the access to the items. */
1036 RTCListGuard<MT> m_guard;
1037};
1038
1039template <class T, typename ITYPE, bool MT>
1040const size_t RTCListBase<T, ITYPE, MT>::kDefaultCapacity = 10;
1041
1042/**
1043 * Template class which automatically determines the type of list to use.
1044 *
1045 * @see RTCListBase
1046 */
1047template <class T, typename ITYPE = typename RTCIf<(sizeof(T) > sizeof(void*)), T*, T>::result>
1048class RTCList : public RTCListBase<T, ITYPE, false>
1049{
1050 /* Traits */
1051 typedef RTCListBase<T, ITYPE, false> BASE;
1052
1053public:
1054 /**
1055 * Creates a new list.
1056 *
1057 * This preallocates @a cCapacity elements within the list.
1058 *
1059 * @param cCapacity The initial capacity the list has.
1060 * @throws std::bad_alloc
1061 */
1062 RTCList(size_t cCapacity = BASE::kDefaultCapacity)
1063 : BASE(cCapacity) {}
1064
1065 RTCList(const BASE &other)
1066 : BASE(other) {}
1067
1068 /* Define our own new and delete. */
1069#ifdef RT_NEED_NEW_AND_DELETE
1070 RTMEM_IMPLEMENT_NEW_AND_DELETE();
1071#else
1072 RTMEMEF_NEW_AND_DELETE_OPERATORS();
1073#endif
1074};
1075
1076/**
1077 * Specialized class for using the native type list for unsigned 64-bit
1078 * values even on a 32-bit host.
1079 *
1080 * @see RTCListBase
1081 */
1082template <>
1083class RTCList<uint64_t>: public RTCListBase<uint64_t, uint64_t, false>
1084{
1085 /* Traits */
1086 typedef RTCListBase<uint64_t, uint64_t, false> BASE;
1087
1088public:
1089 /**
1090 * Creates a new list.
1091 *
1092 * This preallocates @a cCapacity elements within the list.
1093 *
1094 * @param cCapacity The initial capacity the list has.
1095 * @throws std::bad_alloc
1096 */
1097 RTCList(size_t cCapacity = BASE::kDefaultCapacity)
1098 : BASE(cCapacity) {}
1099
1100 /* Define our own new and delete. */
1101#ifdef RT_NEED_NEW_AND_DELETE
1102 RTMEM_IMPLEMENT_NEW_AND_DELETE();
1103#else
1104 RTMEMEF_NEW_AND_DELETE_OPERATORS();
1105#endif
1106};
1107
1108/**
1109 * Specialized class for using the native type list for signed 64-bit
1110 * values even on a 32-bit host.
1111 *
1112 * @see RTCListBase
1113 */
1114template <>
1115class RTCList<int64_t>: public RTCListBase<int64_t, int64_t, false>
1116{
1117 /* Traits */
1118 typedef RTCListBase<int64_t, int64_t, false> BASE;
1119
1120public:
1121 /**
1122 * Creates a new list.
1123 *
1124 * This preallocates @a cCapacity elements within the list.
1125 *
1126 * @param cCapacity The initial capacity the list has.
1127 * @throws std::bad_alloc
1128 */
1129 RTCList(size_t cCapacity = BASE::kDefaultCapacity)
1130 : BASE(cCapacity) {}
1131
1132 /* Define our own new and delete. */
1133#ifdef RT_NEED_NEW_AND_DELETE
1134 RTMEM_IMPLEMENT_NEW_AND_DELETE();
1135#else
1136 RTMEMEF_NEW_AND_DELETE_OPERATORS();
1137#endif
1138};
1139
1140/** @} */
1141
1142#endif /* !IPRT_INCLUDED_cpp_list_h */
1143
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