VirtualBox

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

Last change on this file since 69844 was 69105, checked in by vboxsync, 7 years ago

include/iprt/: (C) year

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