VirtualBox

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

Last change on this file since 93176 was 93115, checked in by vboxsync, 3 years ago

scm --update-copyright-year

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