VirtualBox

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

Last change on this file since 77946 was 76585, checked in by vboxsync, 6 years ago

*: scm --fix-header-guard-endif

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