VirtualBox

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

Last change on this file since 46162 was 45520, checked in by vboxsync, 12 years ago

iprt/cpp/list.h,iprt/cpp/mtlist.h: Added assertions for index out of range conditions and tried to force those cases to have predictable non-destructive behavior. (Not possible when indexing an empty list, unfortunately.) Fixed RTMemRealloc bugs. Added missing read locking. Also changed the testcase to not wait forever in the multithreaded test2() function.

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