VirtualBox

Changeset 45520 in vbox


Ignore:
Timestamp:
Apr 12, 2013 2:22:41 PM (12 years ago)
Author:
vboxsync
Message:

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.

Location:
trunk
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/include/VBox/com/list.h

    r37861 r45520  
    55
    66/*
    7  * Copyright (C) 2011 Oracle Corporation
     7 * Copyright (C) 2011-2013 Oracle Corporation
    88 *
    99 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    3030#include <VBox/com/ptr.h>
    3131#include <VBox/com/string.h>
     32#include <VBox/com/array.h>
    3233#include <iprt/cpp/list.h>
     34
    3335
    3436/**
     
    5557     * @throws  std::bad_alloc
    5658     */
    57     RTCList(size_t cCapacity = BASE::DefaultCapacity)
    58      : BASE(cCapacity) {}
     59    RTCList(size_t cCapacity = BASE::kDefaultCapacity)
     60        : BASE(cCapacity) {}
    5961
    6062    /* Define our own new and delete. */
     
    8587     * @throws  std::bad_alloc
    8688     */
    87     RTCList(size_t cCapacity = BASE::DefaultCapacity)
    88      : BASE(cCapacity) {}
     89    RTCList(size_t cCapacity = BASE::kDefaultCapacity)
     90        : BASE(cCapacity) {}
    8991
    9092    /* Define our own new and delete. */
     
    98100 */
    99101template <>
    100 class RTCList<Utf8Str>: public RTCListBase<Utf8Str, Utf8Str*, false>
     102class RTCList<com::Utf8Str>: public RTCListBase<com::Utf8Str, com::Utf8Str*, false>
    101103{
    102104    /* Traits */
    103     typedef Utf8Str                   T;
     105    typedef com::Utf8Str              T;
    104106    typedef T                        *ITYPE;
    105107    static const bool                 MT = false;
     
    115117     * @throws  std::bad_alloc
    116118     */
    117     RTCList(size_t cCapacity = BASE::DefaultCapacity)
    118      : BASE(cCapacity) {}
     119    RTCList(size_t cCapacity = BASE::kDefaultCapacity)
     120        : BASE(cCapacity) {}
    119121
    120122    /**
     
    131133    {
    132134        com::SafeArray<IN_BSTR> sfaOther(ComSafeArrayInArg(other));
    133         realloc(sfaOther.size());
    134         m_cSize = sfaOther.size();
    135         for (size_t i = 0; i < m_cSize; ++i)
     135        size_t const cElementsOther = sfaOther.size();
     136        resizeArray(cElementsOther);
     137        m_cElements = cElementsOther;
     138        for (size_t i = 0; i < cElementsOther; ++i)
    136139            RTCListHelper<T, ITYPE>::set(m_pArray, i, T(sfaOther[i]));
    137140    }
     
    148151     */
    149152    RTCList(const com::SafeArray<IN_BSTR> &other)
    150      : BASE(other.size())
    151     {
    152         for (size_t i = 0; i < m_cSize; ++i)
     153        : BASE(other.size())
     154    {
     155        for (size_t i = 0; i < m_cElements; ++i)
    153156            RTCListHelper<T, ITYPE>::set(m_pArray, i, T(other[i]));
    154157    }
     
    165168    {
    166169        m_guard.enterWrite();
     170
    167171        /* Values cleanup */
    168         RTCListHelper<T, ITYPE>::eraseRange(m_pArray, 0, m_cSize);
     172        RTCListHelper<T, ITYPE>::eraseRange(m_pArray, 0, m_cElements);
     173
    169174        /* Copy */
    170         if (other.size() != m_cCapacity)
    171             realloc_no_elements_clean(other.size());
    172         m_cSize = other.size();
    173         for (size_t i = 0; i < other.size(); ++i)
     175        size_t cElementsOther = other.size();
     176        if (cElementsOther != m_cCapacity)
     177            resizeArrayNoErase(cElementsOther);
     178        m_cElements = cElementsOther;
     179        for (size_t i = 0; i < cElementsOther; ++i)
    174180            RTCListHelper<T, ITYPE>::set(m_pArray, i, T(other[i]));
     181
    175182        m_guard.leaveWrite();
    176 
    177183        return *this;
    178184    }
  • trunk/include/VBox/com/mtlist.h

    r37861 r45520  
    55
    66/*
    7  * Copyright (C) 2011 Oracle Corporation
     7 * Copyright (C) 2011-2013 Oracle Corporation
    88 *
    99 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    3030#include <VBox/com/ptr.h>
    3131#include <VBox/com/string.h>
     32#include <VBox/com/array.h>
    3233#include <iprt/cpp/mtlist.h>
    3334
     
    5556     * @throws  std::bad_alloc
    5657     */
    57     RTCList(size_t cCapacity = BASE::DefaultCapacity)
    58      : BASE(cCapacity) {}
     58    RTCMTList(size_t cCapacity = BASE::kDefaultCapacity)
     59        : BASE(cCapacity) {}
    5960
    6061    /* Define our own new and delete. */
     
    8586     * @throws  std::bad_alloc
    8687     */
    87     RTCList(size_t cCapacity = BASE::DefaultCapacity)
     88    RTCMTList(size_t cCapacity = BASE::kDefaultCapacity)
    8889     : BASE(cCapacity) {}
    8990
     
    9899 */
    99100template <>
    100 class RTCMTList<Utf8Str>: public RTCListBase<Utf8Str, Utf8Str*, true>
     101class RTCMTList<com::Utf8Str>: public RTCListBase<com::Utf8Str, com::Utf8Str *, true>
    101102{
    102103    /* Traits */
    103     typedef Utf8Str                   T;
     104    typedef com::Utf8Str              T;
    104105    typedef T                        *ITYPE;
    105106    static const bool                 MT = true;
     
    115116     * @throws  std::bad_alloc
    116117     */
    117     RTCMTList(size_t cCapacity = BASE::DefaultCapacity)
    118      : BASE(cCapacity) {}
     118    RTCMTList(size_t cCapacity = BASE::kDefaultCapacity)
     119        : BASE(cCapacity) {}
    119120
    120121    /**
     
    131132    {
    132133        com::SafeArray<IN_BSTR> sfaOther(ComSafeArrayInArg(other));
    133         realloc(sfaOther.size());
    134         m_cSize = sfaOther.size();
    135         for (size_t i = 0; i < m_cSize; ++i)
     134        size_t const cElementsOther = sfaOther.size();
     135        resizeArray(cElementsOther);
     136        m_cElements = cElementsOther;
     137        for (size_t i = 0; i < cElementsOther; ++i)
    136138            RTCListHelper<T, ITYPE>::set(m_pArray, i, T(sfaOther[i]));
    137139    }
     
    150152      : BASE(other.size())
    151153    {
    152         for (size_t i = 0; i < m_cSize; ++i)
     154        for (size_t i = 0; i < m_cElements; ++i)
    153155            RTCListHelper<T, ITYPE>::set(m_pArray, i, T(other[i]));
    154156    }
     
    166168        m_guard.enterWrite();
    167169         /* Values cleanup */
    168         RTCListHelper<T, ITYPE>::eraseRange(m_pArray, 0, m_cSize);
     170        RTCListHelper<T, ITYPE>::eraseRange(m_pArray, 0, m_cElements);
    169171        /* Copy */
    170172        if (other.size() != m_cCapacity)
    171             realloc_no_elements_clean(other.size());
    172         m_cSize = other.size();
     173            resizeArrayNoErase(other.size());
     174        m_cElements = other.size();
    173175        for (size_t i = 0; i < other.size(); ++i)
    174176            RTCListHelper<T, ITYPE>::set(m_pArray, i, T(other[i]));
  • trunk/include/iprt/cpp/list.h

    r37861 r45520  
    44
    55/*
    6  * Copyright (C) 2011 Oracle Corporation
     6 * Copyright (C) 2011-2013 Oracle Corporation
    77 *
    88 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    3030#include <iprt/mem.h>
    3131#include <iprt/string.h> /* for memcpy */
     32#include <iprt/assert.h>
    3233
    3334#include <new> /* For std::bad_alloc */
     
    134135    static inline void      set(T2 *p, size_t i, const T1 &v) { p[i] = v; }
    135136    static inline T1 &      at(T2 *p, size_t i) { return p[i]; }
    136     static inline size_t    find(T2 *p, const T1 &v, size_t cSize)
    137     {
    138         size_t i = 0;
    139         while(i < cSize)
    140         {
     137    static inline size_t    find(T2 *p, const T1 &v, size_t cElements)
     138    {
     139        size_t i = cElements;
     140        while (i-- > 0)
    141141            if (p[i] == v)
    142                 break;
    143             ++i;
    144         }
    145         return i;
     142                return i;
     143        return cElements;
    146144    }
    147145    static inline void      copyTo(T2 *p, T2 *const p1 , size_t iTo, size_t cSize)
     
    163161    static inline void      set(T1 **p, size_t i, const T1 &v) { p[i] = new T1(v); }
    164162    static inline T1 &      at(T1 **p, size_t i) { return *p[i]; }
    165     static inline size_t    find(T1 **p, const T1 &v, size_t cSize)
    166     {
    167         size_t i = 0;
    168         while(i < cSize)
    169         {
     163    static inline size_t    find(T1 **p, const T1 &v, size_t cElements)
     164    {
     165        size_t i = cElements;
     166        while (i-- > 0)
    170167            if (*p[i] == v)
    171                 break;
    172             ++i;
    173         }
    174         return i;
     168                return i;
     169        return cElements;
    175170    }
    176171    static inline void      copyTo(T1 **p, T1 **const p1 , size_t iTo, size_t cSize)
     
    180175    }
    181176    static inline void      erase(T1 **p, size_t i) { delete p[i]; }
    182     static inline void      eraseRange(T1 **p, size_t cFrom, size_t cSize)
    183     {
    184         for (size_t i = cFrom; i < cFrom + cSize; ++i)
    185             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++];
    186181    }
    187182};
     
    195190class RTCListBase
    196191{
    197     /**
    198      * Traits
     192    /** @name Traits.
    199193     *
    200194     * Defines the return type of most of the getter methods. If the internal
    201195     * used type is a pointer, we return a reference. If not we return by
    202196     * value.
     197     *
     198     * @{
    203199     */
    204200    typedef typename RTCIfPtr<ITYPE, T&, T>::result GET_RTYPE;
    205201    typedef typename RTCIfPtr<ITYPE, const T&, T>::result GET_CRTYPE;
     202    /** @}  */
    206203
    207204public:
     
    214211     * @throws  std::bad_alloc
    215212     */
    216     RTCListBase(size_t cCapacity = DefaultCapacity)
    217       : m_pArray(0)
    218       , m_cSize(0)
    219       , m_cCapacity(0)
     213    RTCListBase(size_t cCapacity = kDefaultCapacity)
     214        : m_pArray(0)
     215        , m_cElements(0)
     216        , m_cCapacity(0)
    220217    {
    221218        if (cCapacity > 0)
    222             realloc_grow(cCapacity);
     219            growArray(cCapacity);
    223220    }
    224221
     
    233230     */
    234231    RTCListBase(const RTCListBase<T, ITYPE, MT>& other)
    235       : m_pArray(0)
    236       , m_cSize(0)
    237       , m_cCapacity(0)
    238     {
    239         realloc_no_elements_clean(other.m_cSize);
    240         RTCListHelper<T, ITYPE>::copyTo(m_pArray, other.m_pArray, 0, other.m_cSize);
    241         m_cSize = other.m_cSize;
     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();
    242244    }
    243245
     
    247249    ~RTCListBase()
    248250    {
    249         RTCListHelper<T, ITYPE>::eraseRange(m_pArray, 0, m_cSize);
     251        RTCListHelper<T, ITYPE>::eraseRange(m_pArray, 0, m_cElements);
    250252        if (m_pArray)
     253        {
    251254            RTMemFree(m_pArray);
     255            m_pArray = NULL;
     256        }
     257        m_cElements = m_cCapacity = 0;
    252258    }
    253259
     
    256262     *
    257263     * If the new capacity is bigger than the old size, it will be simply
    258      * preallocated more space for the new items. If the new capacity is
     264     * preallocated more space for the new items.  If the new capacity is
    259265     * smaller than the previous size, items at the end of the list will be
    260266     * deleted.
     
    266272    {
    267273        m_guard.enterWrite();
    268         realloc(cCapacity);
     274        resizeArray(cCapacity);
    269275        m_guard.leaveWrite();
    270276    }
     
    275281     * @return   The actual capacity.
    276282     */
    277     size_t capacity() const { return m_cCapacity; }
     283    size_t capacity() const
     284    {
     285        m_guard.enterRead();
     286        size_t cRet = m_cCapacity;
     287        m_guard.leaveRead();
     288        return cRet;
     289    }
    278290
    279291    /**
     
    282294     * @return   True if there is more than zero items, false otherwise.
    283295     */
    284     bool isEmpty() const { return m_cSize == 0; }
     296    bool isEmpty() const
     297    {
     298        m_guard.enterRead();
     299        bool fEmpty = m_cElements == 0;
     300        m_guard.leaveRead();
     301        return fEmpty;
     302    }
    285303
    286304    /**
     
    289307     * @return   The current element count.
    290308     */
    291     size_t size() const { return m_cSize; }
     309    size_t size() const
     310    {
     311        m_guard.enterRead();
     312        size_t cRet = m_cElements;
     313        m_guard.leaveRead();
     314        return cRet;
     315    }
    292316
    293317    /**
    294318     * Inserts an item to the list at position @a i.
    295319     *
    296      * @param   i     The position of the new item.
     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.
    297324     * @param   val   The new item.
    298325     * @return  a reference to this list.
     
    302329    {
    303330        m_guard.enterWrite();
    304         if (m_cSize == m_cCapacity)
    305             realloc_grow(m_cCapacity + DefaultCapacity);
    306         memmove(&m_pArray[i + 1], &m_pArray[i], (m_cSize - i) * sizeof(ITYPE));
     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));
    307338        RTCListHelper<T, ITYPE>::set(m_pArray, i, val);
    308         ++m_cSize;
    309         m_guard.leaveWrite();
    310 
     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();
    311381        return *this;
    312382    }
     
    333403    RTCListBase<T, ITYPE, MT> &prepend(const RTCListBase<T, ITYPE, MT> &other)
    334404    {
    335         m_guard.enterWrite();
    336         if (m_cCapacity - m_cSize < other.m_cSize)
    337             realloc_grow(m_cCapacity + (other.m_cSize - (m_cCapacity - m_cSize)));
    338         memmove(&m_pArray[other.m_cSize], &m_pArray[0], m_cSize * sizeof(ITYPE));
    339         RTCListHelper<T, ITYPE>::copyTo(m_pArray, other.m_pArray, 0, other.m_cSize);
    340         m_cSize += other.m_cSize;
    341         m_guard.leaveWrite();
    342 
    343         return *this;
     405        return insert(0, other);
    344406    }
    345407
     
    354416    {
    355417        m_guard.enterWrite();
    356         if (m_cSize == m_cCapacity)
    357             realloc_grow(m_cCapacity + DefaultCapacity);
    358         RTCListHelper<T, ITYPE>::set(m_pArray, m_cSize, val);
    359         ++m_cSize;
     418        if (m_cElements == m_cCapacity)
     419            growArray(m_cCapacity + kDefaultCapacity);
     420        RTCListHelper<T, ITYPE>::set(m_pArray, m_cElements, val);
     421        ++m_cElements;
    360422        m_guard.leaveWrite();
    361423
     
    366428     * Append a list of type T to the list.
    367429     *
    368      * @param   other   The list to append.
     430     * @param   other   The list to append. Must not be the same as the destination
     431     *                  list, will assert and return without doing anything.
    369432     * @return  a reference to this list.
    370433     * @throws  std::bad_alloc
     
    372435    RTCListBase<T, ITYPE, MT> &append(const RTCListBase<T, ITYPE, MT> &other)
    373436    {
    374         m_guard.enterWrite();
    375         if (RT_LIKELY(other.m_cSize > 0))
    376         {
    377             if (m_cCapacity - m_cSize < other.m_cSize)
    378                 realloc_grow(m_cCapacity + (other.m_cSize - (m_cCapacity - m_cSize)));
    379             RTCListHelper<T, ITYPE>::copyTo(m_pArray, other.m_pArray, m_cSize, other.m_cSize);
    380             m_cSize += other.m_cSize;
    381         }
    382         m_guard.leaveWrite();
    383 
     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();
    384446        return *this;
    385447    }
    386448
    387449    /**
    388      * Copy the items of the other list into this list. All previous items of
    389      * this list are deleted.
     450     * Copy the items of the other list into this list.
     451     *
     452     * All previous items of this list are deleted.
    390453     *
    391454     * @param   other   The list to copy.
     
    398461            return *this;
    399462
    400         m_guard.enterWrite();
     463        other.m_guard.enterRead();
     464        m_guard.enterWrite();
     465
    401466        /* Delete all items. */
    402         RTCListHelper<T, ITYPE>::eraseRange(m_pArray, 0, m_cSize);
     467        RTCListHelper<T, ITYPE>::eraseRange(m_pArray, 0, m_cElements);
     468
    403469        /* Need we to realloc memory. */
    404         if (other.m_cSize != m_cCapacity)
    405             realloc_no_elements_clean(other.m_cSize);
    406         m_cSize = other.m_cSize;
     470        if (other.m_cElements != m_cCapacity)
     471            resizeArrayNoErase(other.m_cElements);
     472        m_cElements = other.m_cElements;
     473
    407474        /* Copy new items. */
    408         RTCListHelper<T, ITYPE>::copyTo(m_pArray, other.m_pArray, 0, other.m_cSize);
    409         m_guard.leaveWrite();
    410 
     475        RTCListHelper<T, ITYPE>::copyTo(m_pArray, other.m_pArray, 0, other.m_cElements);
     476
     477        m_guard.leaveWrite();
     478        other.m_guard.leaveRead();
    411479        return *this;
    412480    }
     
    415483     * Replace an item in the list.
    416484     *
    417      * @note No boundary checks are done. Make sure @a i is equal or greater zero
    418      *       and smaller than RTCList::size.
    419      *
    420      * @param   i     The position of the item to replace.
     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.
    421487     * @param   val   The new value.
    422488     * @return  a reference to this list.
     
    425491    {
    426492        m_guard.enterWrite();
    427         RTCListHelper<T, ITYPE>::erase(m_pArray, i);
    428         RTCListHelper<T, ITYPE>::set(m_pArray, i, val);
    429         m_guard.leaveWrite();
    430 
     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();
    431503        return *this;
    432504    }
     
    435507     * Return the first item as constant object.
    436508     *
    437      * @note No boundary checks are done. Make sure there is at least one
    438      * element.
    439      *
    440      * @return   The first item.
     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.
    441513     */
    442514    GET_CRTYPE first() const
    443515    {
    444516        m_guard.enterRead();
     517        Assert(m_cElements > 0);
    445518        GET_CRTYPE res = RTCListHelper<T, ITYPE>::at(m_pArray, 0);
    446519        m_guard.leaveRead();
     
    451524     * Return the first item.
    452525     *
    453      * @note No boundary checks are done. Make sure there is at least one
    454      * element.
    455      *
    456      * @return   The first item.
     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.
    457530     */
    458531    GET_RTYPE first()
    459532    {
    460533        m_guard.enterRead();
     534        Assert(m_cElements > 0);
    461535        GET_RTYPE res = RTCListHelper<T, ITYPE>::at(m_pArray, 0);
    462536        m_guard.leaveRead();
     
    467541     * Return the last item as constant object.
    468542     *
    469      * @note No boundary checks are done. Make sure there is at least one
    470      * element.
    471      *
    472      * @return   The last item.
     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.
    473547     */
    474548    GET_CRTYPE last() const
    475549    {
    476550        m_guard.enterRead();
    477         GET_CRTYPE res = RTCListHelper<T, ITYPE>::at(m_pArray, m_cSize - 1);
     551        Assert(m_cElements > 0);
     552        GET_CRTYPE res = RTCListHelper<T, ITYPE>::at(m_pArray, m_cElements - 1);
    478553        m_guard.leaveRead();
    479554        return res;
     
    483558     * Return the last item.
    484559     *
    485      * @note No boundary checks are done. Make sure there is at least one
    486      * element.
    487      *
    488      * @return   The last item.
     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.
    489564     */
    490565    GET_RTYPE last()
    491566    {
    492567        m_guard.enterRead();
    493         GET_RTYPE res = RTCListHelper<T, ITYPE>::at(m_pArray, m_cSize - 1);
     568        Assert(m_cElements > 0);
     569        GET_RTYPE res = RTCListHelper<T, ITYPE>::at(m_pArray, m_cElements - 1);
    494570        m_guard.leaveRead();
    495571        return res;
     
    499575     * Return the item at position @a i as constant object.
    500576     *
    501      * @note No boundary checks are done. Make sure @a i is equal or greater zero
    502      *       and smaller than RTCList::size.
    503      *
    504      * @param   i     The position of the item to return.
     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.
    505581     * @return  The item at position @a i.
    506582     */
     
    508584    {
    509585        m_guard.enterRead();
     586        AssertMsgStmt(i < m_cElements, ("i=%zu m_cElements=%zu\n", i, m_cElements), i = m_cElements - 1);
    510587        GET_CRTYPE res = RTCListHelper<T, ITYPE>::at(m_pArray, i);
    511588        m_guard.leaveRead();
     
    516593     * Return the item at position @a i.
    517594     *
    518      * @note No boundary checks are done. Make sure @a i is equal or greater zero
    519      *       and smaller than RTCList::size.
    520      *
    521      * @param   i     The position of the item to return.
     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.
    522599     * @return   The item at position @a i.
    523600     */
     
    525602    {
    526603        m_guard.enterRead();
     604        AssertMsgStmt(i < m_cElements, ("i=%zu m_cElements=%zu\n", i, m_cElements), i = m_cElements - 1);
    527605        GET_RTYPE res = RTCListHelper<T, ITYPE>::at(m_pArray, i);
    528606        m_guard.leaveRead();
     
    533611     * Return the item at position @a i as mutable reference.
    534612     *
    535      * @note No boundary checks are done. Make sure @a i is equal or greater zero
    536      *       and smaller than RTCList::size.
    537      *
    538      * @param   i     The position of the item to return.
     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.
    539617     * @return   The item at position @a i.
    540618     */
     
    542620    {
    543621        m_guard.enterRead();
     622        AssertMsgStmt(i < m_cElements, ("i=%zu m_cElements=%zu\n", i, m_cElements), i = m_cElements - 1);
    544623        T &res = RTCListHelper<T, ITYPE>::at(m_pArray, i);
    545624        m_guard.leaveRead();
     
    548627
    549628    /**
    550      * Return the item at position @a i. If @a i isn't valid within the list a
    551      * default value is returned.
     629     * Return the item at position @a i or default value if out of range.
    552630     *
    553631     * @param   i              The position of the item to return.
    554      * @return  The item at position @a i.
     632     * @return  The item at position @a i or default value.
    555633     */
    556634    T value(size_t i) const
    557635    {
    558636        m_guard.enterRead();
    559         if (RT_UNLIKELY(i >= m_cSize))
     637        if (RT_UNLIKELY(i >= m_cElements))
    560638        {
    561639            m_guard.leaveRead();
     
    568646
    569647    /**
    570      * Return the item at position @a i. If @a i isn't valid within the list
    571      * @a defaultVal is returned.
     648     * Return the item at position @a i, or @a defaultVal if out of range.
    572649     *
    573650     * @param   i              The position of the item to return.
    574651     * @param   defaultVal     The value to return in case @a i is invalid.
    575      * @return  The item at position @a i.
     652     * @return  The item at position @a i or @a defaultVal.
    576653     */
    577654    T value(size_t i, const T &defaultVal) const
    578655    {
    579656        m_guard.enterRead();
    580         if (RT_UNLIKELY(i >= m_cSize))
     657        if (RT_UNLIKELY(i >= m_cElements))
    581658        {
    582659            m_guard.leaveRead();
     
    597674    {
    598675        m_guard.enterRead();
    599         bool res = RTCListHelper<T, ITYPE>::find(m_pArray, val, m_cSize) != m_cSize;
    600         m_guard.leaveRead();
    601         return res;
     676        bool fRc = RTCListHelper<T, ITYPE>::find(m_pArray, val, m_cElements) < m_cElements;
     677        m_guard.leaveRead();
     678        return fRc;
    602679    }
    603680
     
    605682     * Remove the first item.
    606683     *
    607      * @note No boundary checks are done. Make sure there is at least one
    608      * element.
     684     * @note You should make sure the list isn't empty. Strict builds will assert.
     685     *       The other builds will quietly ignore the request.
    609686     */
    610687    void removeFirst()
     
    616693     * Remove the last item.
    617694     *
    618      * @note No boundary checks are done. Make sure there is at least one
    619      * element.
     695     * @note You should make sure the list isn't empty. Strict builds will assert.
     696     *       The other builds will quietly ignore the request.
    620697     */
    621698    void removeLast()
    622699    {
    623         removeAt(m_cSize - 1);
     700        m_guard.enterWrite();
     701        removeAtLocked(m_cElements - 1);
     702        m_guard.leaveWrite();
    624703    }
    625704
     
    627706     * Remove the item at position @a i.
    628707     *
    629      * @note No boundary checks are done. Make sure @a i is equal or greater zero
    630      *       and smaller than RTCList::size.
    631      *
    632      * @param   i   The position of the item to remove.
     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.
    633710     */
    634711    void removeAt(size_t i)
    635712    {
    636713        m_guard.enterWrite();
    637         RTCListHelper<T, ITYPE>::erase(m_pArray, i);
    638         /* Not last element? */
    639         if (i < m_cSize - 1)
    640             memmove(&m_pArray[i], &m_pArray[i + 1], (m_cSize - i - 1) * sizeof(ITYPE));
    641         --m_cSize;
     714        removeAtLocked(i);
    642715        m_guard.leaveWrite();
    643716    }
     
    646719     * Remove a range of items from the list.
    647720     *
    648      * @note No boundary checks are done. Make sure @a iFrom is equal or
    649      *       greater zero and smaller than RTCList::size. @a iTo has to be
    650      *       greater than @a iFrom and equal or smaller than RTCList::size.
    651      *
    652      * @param   iFrom   The start position of the items to remove.
    653      * @param   iTo     The end position of the items to remove (excluded).
    654      */
    655     void removeRange(size_t iFrom, size_t iTo)
    656     {
    657         m_guard.enterWrite();
    658         RTCListHelper<T, ITYPE>::eraseRange(m_pArray, iFrom, iTo - iFrom);
    659         /* Not last elements? */
    660         if (m_cSize - iTo > 0)
    661             memmove(&m_pArray[iFrom], &m_pArray[iTo], (m_cSize - iTo) * sizeof(ITYPE));
    662         m_cSize -= iTo - iFrom;
     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
    663741        m_guard.leaveWrite();
    664742    }
     
    670748    {
    671749        m_guard.enterWrite();
     750
    672751        /* Values cleanup */
    673         RTCListHelper<T, ITYPE>::eraseRange(m_pArray, 0, m_cSize);
    674         if (m_cSize != DefaultCapacity)
    675             realloc_no_elements_clean(DefaultCapacity);
    676         m_cSize = 0;
    677         m_guard.leaveWrite();
    678     }
    679 
    680     /**
    681      * Return the raw array. For native types this is a pointer to continuous
    682      * memory of the items. For pointer types this is a continuous memory of
    683      * pointers to the items.
     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.
    684765     *
    685766     * @warning If you change anything in the underlaying list, this memory
     
    689770     * @returns the raw memory.
    690771     */
    691     ITYPE* raw() const
    692     {
    693         m_guard.enterRead();
    694         ITYPE* res = m_pArray;
    695         m_guard.leaveRead();
    696         return res;
     772    ITYPE *raw() const
     773    {
     774        m_guard.enterRead();
     775        ITYPE *pRet = m_pArray;
     776        m_guard.leaveRead();
     777        return pRet;
    697778    }
    698779
     
    708789     * The default capacity of the list. This is also used as grow factor.
    709790     */
    710     static const size_t DefaultCapacity;
     791    static const size_t kDefaultCapacity;
    711792
    712793protected:
    713794
    714795    /**
    715      * Generic realloc, which does some kind of boundary checking.
    716      */
    717     void realloc(size_t cNewSize)
     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)
    718802    {
    719803        /* Same size? */
    720         if (cNewSize == m_cCapacity)
     804        if (cElementsNew == m_cCapacity)
    721805            return;
    722806
    723807        /* If we get smaller we have to delete some of the objects at the end
    724808           of the list. */
    725         if (   cNewSize < m_cSize
     809        if (   cElementsNew < m_cElements
    726810            && m_pArray)
    727             RTCListHelper<T, ITYPE>::eraseRange(m_pArray, cNewSize, m_cSize - cNewSize);
    728         realloc_no_elements_clean(cNewSize);
    729     }
    730 
    731     void realloc_no_elements_clean(size_t cNewSize)
     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)
    732823    {
    733824        /* Same size? */
    734         if (cNewSize == m_cCapacity)
     825        if (cElementsNew == m_cCapacity)
    735826            return;
    736827
    737         /* If we get smaller we have to delete some of the objects at the end
    738            of the list. */
    739         if (   cNewSize < m_cSize
    740             && m_pArray)
    741             m_cSize -= m_cSize - cNewSize;
    742 
    743         /* If we get zero we delete the array it self. */
    744         if (   cNewSize == 0
    745             && m_pArray)
     828        /* Resize the array. */
     829        if (cElementsNew > 0)
    746830        {
    747             RTMemFree(m_pArray);
    748             m_pArray = 0;
    749         }
    750         m_cCapacity = cNewSize;
    751 
    752         /* Resize the array. */
    753         if (cNewSize > 0)
    754         {
    755             m_pArray = static_cast<ITYPE*>(RTMemRealloc(m_pArray, sizeof(ITYPE) * cNewSize));
    756             if (!m_pArray)
     831            void *pvNew = RTMemRealloc(m_pArray, sizeof(ITYPE) * cElementsNew);
     832            if (!pvNew)
    757833            {
    758                 /** @todo you leak memory. */
    759                 m_cCapacity = 0;
    760                 m_cSize = 0;
    761834#ifdef RT_EXCEPTIONS_ENABLED
    762835                throw std::bad_alloc();
    763836#endif
     837                return;
    764838            }
     839            m_pArray = static_cast<ITYPE*>(pvNew);
    765840        }
     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;
    766851    }
    767852
     
    769854     * Special realloc method which require that the array will grow.
    770855     *
     856     * @param   cElementsNew    The new array size.
     857     * @throws  std::bad_alloc.
    771858     * @note No boundary checks are done!
    772859     */
    773     void realloc_grow(size_t cNewSize)
    774     {
    775         /* Resize the array. */
    776         m_cCapacity = cNewSize;
    777         m_pArray = static_cast<ITYPE*>(RTMemRealloc(m_pArray, sizeof(ITYPE) * cNewSize));
    778         if (!m_pArray)
     860    void growArray(size_t cElementsNew)
     861    {
     862        Assert(cElementsNew > m_cCapacity);
     863        void *pvNew = RTMemRealloc(m_pArray, sizeof(ITYPE) * cElementsNew);
     864        if (pvNew)
    779865        {
    780             /** @todo you leak memory. */
    781             m_cCapacity = 0;
    782             m_cSize = 0;
     866            m_cCapacity = cElementsNew;
     867            m_pArray = static_cast<ITYPE*>(pvNew);
     868        }
     869        else
     870        {
    783871#ifdef RT_EXCEPTIONS_ENABLED
    784872            throw std::bad_alloc();
     
    787875    }
    788876
     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
    789895    /** The internal list array. */
    790896    ITYPE *m_pArray;
    791897    /** The current count of items in use. */
    792     size_t m_cSize;
     898    size_t m_cElements;
    793899    /** The current capacity of the internal array. */
    794900    size_t m_cCapacity;
     
    798904
    799905template <class T, typename ITYPE, bool MT>
    800 const size_t RTCListBase<T, ITYPE, MT>::DefaultCapacity = 10;
     906const size_t RTCListBase<T, ITYPE, MT>::kDefaultCapacity = 10;
    801907
    802908/**
     
    820926     * @throws  std::bad_alloc
    821927     */
    822     RTCList(size_t cCapacity = BASE::DefaultCapacity)
    823      : BASE(cCapacity) {}
     928    RTCList(size_t cCapacity = BASE::kDefaultCapacity)
     929        : BASE(cCapacity) {}
    824930
    825931    RTCList(const BASE &other)
    826      : BASE(other) {}
     932        : BASE(other) {}
    827933
    828934    /* Define our own new and delete. */
     
    851957     * @throws  std::bad_alloc
    852958     */
    853     RTCList(size_t cCapacity = BASE::DefaultCapacity)
    854      : BASE(cCapacity) {}
     959    RTCList(size_t cCapacity = BASE::kDefaultCapacity)
     960        : BASE(cCapacity) {}
    855961
    856962    /* Define our own new and delete. */
     
    879985     * @throws  std::bad_alloc
    880986     */
    881     RTCList(size_t cCapacity = BASE::DefaultCapacity)
    882      : BASE(cCapacity) {}
     987    RTCList(size_t cCapacity = BASE::kDefaultCapacity)
     988        : BASE(cCapacity) {}
    883989
    884990    /* Define our own new and delete. */
  • trunk/include/iprt/cpp/mtlist.h

    r36654 r45520  
    44
    55/*
    6  * Copyright (C) 2011 Oracle Corporation
     6 * Copyright (C) 2011-2013 Oracle Corporation
    77 *
    88 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    2828
    2929#include <iprt/cpp/list.h>
    30 
    3130#include <iprt/semaphore.h>
    3231
     
    4241{
    4342public:
    44     RTCListGuard() { int rc = RTSemRWCreate(&m_hRWSem); AssertRC(rc); }
    45     ~RTCListGuard() { RTSemRWDestroy(m_hRWSem); }
     43    RTCListGuard() : m_hRWSem(NIL_RTSEMRW)
     44    {
     45#if defined(RT_LOCK_STRICT_ORDER) && defined(IN_RING3)
     46        RTLOCKVALCLASS hClass;
     47        int rc = RTLockValidatorClassCreate(&hClass, true /*fAutodidact*/, RT_SRC_POS, "RTCListGuard");
     48        AssertStmt(RT_SUCCESS(rc), hClass = NIL_RTLOCKVALCLASS);
     49        rc = RTSemRWCreateEx(&m_hRWSem, 0 /*fFlags*/, hClass, RTLOCKVAL_SUB_CLASS_NONE, NULL /*pszNameFmt*/);
     50        AssertRC(rc);
     51#else
     52        int rc = RTSemRWCreateEx(&m_hRWSem, 0 /*fFlags*/, NIL_RTLOCKVALCLASS, 0, NULL);
     53        AssertRC(rc);
     54#endif
     55    }
     56
     57    ~RTCListGuard()
     58    {
     59        RTSemRWDestroy(m_hRWSem);
     60        m_hRWSem = NIL_RTSEMRW;
     61    }
     62
    4663    inline void enterRead() const { int rc = RTSemRWRequestRead(m_hRWSem, RT_INDEFINITE_WAIT); AssertRC(rc); }
    4764    inline void leaveRead() const { int rc = RTSemRWReleaseRead(m_hRWSem); AssertRC(rc); }
     
    87104     * @throws  std::bad_alloc
    88105     */
    89     RTCMTList(size_t cCapacity = BASE::DefaultCapacity)
    90      : BASE(cCapacity) {}
     106    RTCMTList(size_t cCapacity = BASE::kDefaultCapacity)
     107        : BASE(cCapacity) {}
    91108
    92109    /* Define our own new and delete. */
     
    115132     * @throws  std::bad_alloc
    116133     */
    117     RTCMTList(size_t cCapacity = BASE::DefaultCapacity)
    118      : BASE(cCapacity) {}
     134    RTCMTList(size_t cCapacity = BASE::kDefaultCapacity)
     135        : BASE(cCapacity) {}
    119136
    120137    /* Define our own new and delete. */
     
    143160     * @throws  std::bad_alloc
    144161     */
    145     RTCMTList(size_t cCapacity = BASE::DefaultCapacity)
    146      : BASE(cCapacity) {}
     162    RTCMTList(size_t cCapacity = BASE::kDefaultCapacity)
     163        : BASE(cCapacity) {}
    147164
    148165    /* Define our own new and delete. */
  • trunk/src/VBox/Runtime/testcase/tstIprtList.cpp

    r37861 r45520  
    3434#include <iprt/rand.h>
    3535#include <iprt/thread.h>
     36#include <iprt/time.h>
    3637
    3738
     
    166167    L<T1, T2> testList;
    167168
    168     const size_t defCap = L<T1, T2>::DefaultCapacity;
     169    const size_t defCap = L<T1, T2>::kDefaultCapacity;
    169170    RTTESTI_CHECK(testList.isEmpty());
    170171    RTTESTI_CHECK(testList.size()     == 0);
     
    376377    RTTESTI_CHECK(testList5.capacity()  == 0);
    377378
     379    /*
     380     * Negative testing.
     381     */
     382    bool fMayPanic = RTAssertMayPanic();
     383    bool fQuiet    = RTAssertAreQuiet();
     384    RTAssertSetMayPanic(false);
     385    RTAssertSetQuiet(true);
     386
     387    L<T1, T2> testList6;
     388    for (size_t i = 0; i < cTestItems; ++i)
     389        testList6.insert(i, paTestData[i]);
     390    RTTESTI_CHECK(testList6.size() == cTestItems);
     391
     392    /* Insertion beyond the end of the array ends up at the end. */
     393    size_t cBefore = testList6.size();
     394    testList6.insert(cBefore + 3, paTestData[0]);
     395    RTTESTI_CHECK(testList6.size() == cBefore + 1);
     396    RTTESTI_CHECK(testList6.at(cBefore) == paTestData[0]);
     397
     398    cBefore = testList6.size();
     399    L<T1, T2> testList7(testList6);
     400    testList6.insert(testList6.size() + 42, testList7);
     401    RTTESTI_CHECK(testList6.size() == cBefore + testList7.size());
     402
     403    /* Inserting, appending or prepending a list to itself is not supported. */
     404    cBefore = testList6.size();
     405    testList6.insert(3, testList6);
     406    RTTESTI_CHECK(testList6.size() == cBefore);
     407
     408    cBefore = testList6.size();
     409    testList6.append(testList6);
     410    RTTESTI_CHECK(testList6.size() == cBefore);
     411
     412    cBefore = testList6.size();
     413    testList6.prepend(testList6);
     414    RTTESTI_CHECK(testList6.size() == cBefore);
     415
     416    /* Replace does nothing if the index is bad. */
     417    cBefore = testList6.size();
     418    testList6.replace(cBefore, testList6[6]);
     419    RTTESTI_CHECK(testList6.size() == cBefore);
     420
     421    cBefore = testList6.size();
     422    testList6.replace(cBefore + 64, testList6[6]);
     423    RTTESTI_CHECK(testList6.size() == cBefore);
     424
     425    /* Indexing beyond the array returns the last element. */
     426    cBefore = testList6.size();
     427    RTTESTI_CHECK(testList6[cBefore] == testList6.last());
     428    RTTESTI_CHECK(testList6[cBefore + 42] == testList6.last());
     429
     430    RTTESTI_CHECK(&testList6[cBefore]      == &testList6[cBefore - 1]);
     431    RTTESTI_CHECK(&testList6[cBefore + 42] == &testList6[cBefore - 1]);
     432
     433    /* removeAt does nothing if the index is bad. */
     434    cBefore = testList6.size();
     435    testList6.removeAt(cBefore);
     436    RTTESTI_CHECK(testList6.size() == cBefore);
     437
     438    cBefore = testList6.size();
     439    testList6.removeAt(cBefore + 42);
     440    RTTESTI_CHECK(testList6.size() == cBefore);
     441
     442    L<T1, T2> testListEmpty1; RTTESTI_CHECK(!testListEmpty1.size());
     443    testListEmpty1.removeFirst();
     444    RTTESTI_CHECK(!testListEmpty1.size());
     445
     446    testListEmpty1.removeLast();
     447    RTTESTI_CHECK(!testListEmpty1.size());
     448
     449    testListEmpty1.removeAt(128);
     450    RTTESTI_CHECK(!testListEmpty1.size());
     451
     452    /* removeRange interprets indexes beyond the end as the end of array (asserted). */
     453    testListEmpty1.removeRange(42, 128);
     454    RTTESTI_CHECK(!testListEmpty1.size());
     455
     456    cBefore = testList6.size();
     457    testList6.removeRange(cBefore, cBefore);
     458    RTTESTI_CHECK(testList6.size() == cBefore);
     459
     460    cBefore = testList6.size();
     461    testList6.removeRange(cBefore + 12, cBefore + 128);
     462    RTTESTI_CHECK(testList6.size() == cBefore);
     463
     464    /* If end is less or equal to the start, nothing is done. */
     465    testListEmpty1.removeRange(128, 0);
     466    RTTESTI_CHECK(!testListEmpty1.size());
     467
     468    cBefore = testList6.size();
     469    testList6.removeRange(cBefore, 0);
     470    RTTESTI_CHECK(testList6.size() == cBefore);
     471
     472    cBefore = testList6.size();
     473    testList6.removeRange(0, 0);
     474    RTTESTI_CHECK(testList6.size() == cBefore);
     475
     476    cBefore = testList6.size();
     477    testList6.removeRange(0, 0);
     478    RTTESTI_CHECK(testList6.size() == cBefore);
     479
     480    RTAssertSetQuiet(fQuiet);
     481    RTAssertSetMayPanic(fMayPanic);
    378482}
    379483
    380484/* define RTCList here to see what happens without MT support ;)
    381485 * (valgrind is the preferred tool to check). */
    382 #define MTTESTLISTTYPE RTCMTList
    383 #define MTTESTTYPE uint32_t
    384 #define MTTESTITEMS 1000
     486#define MTTESTLISTTYPE  RTCMTList
     487#define MTTESTTYPE      uint32_t
     488#define MTTESTITEMS     1000
    385489
    386490/**
     
    390494 * @param   pvUser      The provided user data.
    391495 */
    392 DECLCALLBACK(int) mttest1(RTTHREAD hSelf, void *pvUser)
     496static DECLCALLBACK(int) MtTest1ThreadProc(RTTHREAD hSelf, void *pvUser)
    393497{
    394498    MTTESTLISTTYPE<MTTESTTYPE> *pTestList = (MTTESTLISTTYPE<MTTESTTYPE> *)pvUser;
     
    407511 * @param   pvUser      The provided user data.
    408512 */
    409 DECLCALLBACK(int) mttest2(RTTHREAD hSelf, void *pvUser)
     513static DECLCALLBACK(int) MtTest2ThreadProc(RTTHREAD hSelf, void *pvUser)
    410514{
    411515    MTTESTLISTTYPE<MTTESTTYPE> *pTestList = (MTTESTLISTTYPE<MTTESTTYPE> *)pvUser;
     
    424528 * @param   pvUser      The provided user data.
    425529 */
    426 DECLCALLBACK(int) mttest3(RTTHREAD hSelf, void *pvUser)
     530static DECLCALLBACK(int) MtTest3ThreadProc(RTTHREAD hSelf, void *pvUser)
    427531{
    428532    MTTESTLISTTYPE<MTTESTTYPE> *pTestList = (MTTESTLISTTYPE<MTTESTTYPE> *)pvUser;
     
    441545 * @param   pvUser      The provided user data.
    442546 */
    443 DECLCALLBACK(int) mttest4(RTTHREAD hSelf, void *pvUser)
     547static DECLCALLBACK(int) MtTest4ThreadProc(RTTHREAD hSelf, void *pvUser)
    444548{
    445549    MTTESTLISTTYPE<MTTESTTYPE> *pTestList = (MTTESTLISTTYPE<MTTESTTYPE> *)pvUser;
     
    450554    {
    451555        /* Make sure there is at least one item in the list. */
    452         while (pTestList->isEmpty()) {};
     556        while (pTestList->isEmpty())
     557            RTThreadYield();
    453558        a = pTestList->at(RTRandU32Ex(0, (uint32_t)pTestList->size() - 1));
    454559    }
     
    463568 * @param   pvUser      The provided user data.
    464569 */
    465 DECLCALLBACK(int) mttest5(RTTHREAD hSelf, void *pvUser)
     570static DECLCALLBACK(int) MtTest5ThreadProc(RTTHREAD hSelf, void *pvUser)
    466571{
    467572    MTTESTLISTTYPE<MTTESTTYPE> *pTestList = (MTTESTLISTTYPE<MTTESTTYPE> *)pvUser;
     
    471576    {
    472577        /* Make sure there is at least one item in the list. */
    473         while (pTestList->isEmpty()) {};
     578        while (pTestList->isEmpty())
     579            RTThreadYield();
    474580        pTestList->replace(RTRandU32Ex(0, (uint32_t)pTestList->size() - 1), 0xFF00FF00);
    475581    }
     
    484590 * @param   pvUser      The provided user data.
    485591 */
    486 DECLCALLBACK(int) mttest6(RTTHREAD hSelf, void *pvUser)
     592static DECLCALLBACK(int) MtTest6ThreadProc(RTTHREAD hSelf, void *pvUser)
    487593{
    488594    MTTESTLISTTYPE<MTTESTTYPE> *pTestList = (MTTESTLISTTYPE<MTTESTTYPE> *)pvUser;
     
    492598    {
    493599        /* Make sure there is at least one item in the list. */
    494         while (pTestList->isEmpty()) {};
     600        while (pTestList->isEmpty())
     601            RTThreadYield();
    495602        pTestList->removeAt(RTRandU32Ex(0, (uint32_t)pTestList->size() - 1));
    496603    }
     
    508615    RTTestISubF("MT test with 6 threads (%u tests per thread).", MTTESTITEMS);
    509616
    510     RTTHREAD hThread1, hThread2, hThread3, hThread4, hThread5, hThread6;
    511     int rc = VINF_SUCCESS;
    512 
    513     MTTESTLISTTYPE<MTTESTTYPE> testList;
    514     rc = RTThreadCreate(&hThread1, &mttest1, &testList, 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "mttest1");
    515     AssertRC(rc);
    516     rc = RTThreadCreate(&hThread2, &mttest2, &testList, 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "mttest2");
    517     AssertRC(rc);
    518     rc = RTThreadCreate(&hThread3, &mttest3, &testList, 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "mttest3");
    519     AssertRC(rc);
    520     rc = RTThreadCreate(&hThread4, &mttest4, &testList, 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "mttest4");
    521     AssertRC(rc);
    522     rc = RTThreadCreate(&hThread5, &mttest5, &testList, 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "mttest5");
    523     AssertRC(rc);
    524     rc = RTThreadCreate(&hThread6, &mttest6, &testList, 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "mttest6");
    525     AssertRC(rc);
    526 
    527     rc = RTThreadWait(hThread1, RT_INDEFINITE_WAIT, 0);
    528     AssertRC(rc);
    529     rc = RTThreadWait(hThread2, RT_INDEFINITE_WAIT, 0);
    530     AssertRC(rc);
    531     rc = RTThreadWait(hThread3, RT_INDEFINITE_WAIT, 0);
    532     AssertRC(rc);
    533     rc = RTThreadWait(hThread4, RT_INDEFINITE_WAIT, 0);
    534     AssertRC(rc);
    535     rc = RTThreadWait(hThread5, RT_INDEFINITE_WAIT, 0);
    536     AssertRC(rc);
    537     rc = RTThreadWait(hThread6, RT_INDEFINITE_WAIT, 0);
    538     AssertRC(rc);
     617    int                         rc;
     618    MTTESTLISTTYPE<MTTESTTYPE>  testList;
     619    RTTHREAD                    ahThreads[6];
     620    static PFNRTTHREAD          apfnThreads[6] =
     621    {
     622        MtTest1ThreadProc, MtTest2ThreadProc, MtTest3ThreadProc, MtTest4ThreadProc, MtTest5ThreadProc, MtTest6ThreadProc
     623    };
     624
     625    for (unsigned i = 0; i < RT_ELEMENTS(ahThreads); i++)
     626    {
     627        RTTESTI_CHECK_RC_RETV(RTThreadCreateF(&ahThreads[i], apfnThreads[i], &testList, 0,
     628                                              RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "mttest%u", i), VINF_SUCCESS);
     629    }
     630
     631    uint64_t tsMsDeadline = RTTimeMilliTS() + 60000;
     632    for (unsigned i = 0; i < RT_ELEMENTS(ahThreads); i++)
     633    {
     634        uint64_t tsNow = RTTimeMilliTS();
     635        uint32_t cWait = tsNow > tsMsDeadline ? 5000 : tsMsDeadline - tsNow;
     636        RTTESTI_CHECK_RC(RTThreadWait(ahThreads[i], tsNow, NULL), VINF_SUCCESS);
     637    }
    539638
    540639    RTTESTI_CHECK_RETV(testList.size() == MTTESTITEMS * 2);
     
    557656    RTTestBanner(hTest);
    558657
    559     /* Some host info. */
    560     RTTestIPrintf(RTTESTLVL_ALWAYS, "sizeof(void*)=%d", sizeof(void*));
    561 
    562     /*
    563      * The tests.
    564      */
    565 
    566658    /*
    567659     * Native types.
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette