VirtualBox

Changeset 15042 in vbox for trunk/include/VBox


Ignore:
Timestamp:
Dec 5, 2008 1:38:10 PM (16 years ago)
Author:
vboxsync
Message:

Main/SafeArray: Added SafeArray::push_back() and attachedRaw(); implemented dynamic size change using resize(). Fixed a number of bugs (did't affect the old code but could pop up in the new).

File:
1 edited

Legend:

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

    r14045 r15042  
    359359////////////////////////////////////////////////////////////////////////////////
    360360
     361struct SafeArrayTraitsBase
     362{
     363protected:
     364
     365    static SAFEARRAY *CreateSafeArray (VARTYPE aVarType, SAFEARRAYBOUND *aBound)
     366    { return SafeArrayCreate (aVarType, 1, aBound); }
     367};
     368
    361369/**
    362370 * Provides various helpers for SafeArray.
     
    381389 */
    382390template <typename T>
    383 struct SafeArrayTraits
    384 {
     391struct SafeArrayTraits : public SafeArrayTraitsBase
     392{
     393protected:
     394
    385395    // Arbitrary types are treated as passed by value and each value is
    386396    // represented by a number of VT_Ix type elements where VT_Ix has the
     
    425435
    426436template<>
    427 struct SafeArrayTraits <LONG>
     437struct SafeArrayTraits <LONG> : public SafeArrayTraitsBase
    428438{
    429439protected:
     
    437447
    438448template<>
    439 struct SafeArrayTraits <ULONG>
     449struct SafeArrayTraits <ULONG> : public SafeArrayTraitsBase
    440450{
    441451protected:
     
    449459
    450460template<>
    451 struct SafeArrayTraits <LONG64>
     461struct SafeArrayTraits <LONG64> : public SafeArrayTraitsBase
    452462{
    453463protected:
     
    461471
    462472template<>
    463 struct SafeArrayTraits <ULONG64>
     473struct SafeArrayTraits <ULONG64> : public SafeArrayTraitsBase
    464474{
    465475protected:
     
    473483
    474484template<>
    475 struct SafeArrayTraits <BSTR>
     485struct SafeArrayTraits <BSTR> : public SafeArrayTraitsBase
    476486{
    477487protected:
     
    488498
    489499template<>
    490 struct SafeArrayTraits <GUID>
     500struct SafeArrayTraits <GUID> : public SafeArrayTraitsBase
    491501{
    492502protected:
     
    505515
    506516    static void Copy (GUID aFrom, GUID &aTo) { aTo = aFrom; }
     517};
     518
     519/**
     520 * Helper for SafeArray::__asOutParam() that automatically updates m.raw after a
     521 * non-NULL m.arr assignment.
     522 */
     523class OutSafeArrayDipper
     524{
     525    OutSafeArrayDipper (SAFEARRAY **aArr, void **aRaw)
     526        : arr (aArr), raw (aRaw) { Assert (*aArr == NULL && *aRaw == NULL); }
     527
     528    SAFEARRAY **arr;
     529    void **raw;
     530
     531    template <class, class> friend class SafeArray;
     532
     533public:
     534
     535    ~OutSafeArrayDipper()
     536    {
     537        if (*arr != NULL)
     538        {
     539            HRESULT rc = SafeArrayAccessData (*arr, raw);
     540            AssertComRC (rc);
     541        }
     542    }
     543
     544    operator SAFEARRAY **() { return arr; }
    507545};
    508546
     
    551589     * array initialized with null values.
    552590     *
    553      * @param aSize     Initial number of elements in the array. Must be greater
    554      *                  than 0.
     591     * @param aSize     Initial number of elements in the array.
    555592     *
    556593     * @note If this object remains null after construction it means that there
     
    558595     *       The constructor will also assert in this case.
    559596     */
    560     SafeArray (size_t aSize) { reset (aSize); }
     597    SafeArray (size_t aSize) { resize (aSize); }
    561598
    562599    /**
     
    600637                                 ("Expected vartype %d, got %d.\n",
    601638                                  VarType(), vt));
     639
     640            rc = SafeArrayAccessData (arg, (void HUGEP **) &m.raw);
     641            AssertComRCReturnVoid (rc);
    602642        }
    603643
     
    605645        m.isWeak = true;
    606646
    607         AssertReturnVoid (m.arr == NULL || accessRaw() != NULL);
    608 
    609647#endif /* defined (VBOX_WITH_XPCOM) */
    610648    }
     
    621659    SafeArray (const C <T, A> & aCntr)
    622660    {
    623         reset (aCntr.size());
     661        resize (aCntr.size());
    624662        AssertReturnVoid (!isNull());
    625663
     
    677715
    678716    /**
     717     * Appends a copy of the given element at the end of the array.
     718     *
     719     * The array size is increased by one by this method and the additional
     720     * space is allocated as needed.
     721     *
     722     * This method is handy in cases where you want to assign a copy of the
     723     * existing value to the array element, for example:
     724     * <tt>Bstr string; array.push_back (string);</tt>. If you create a string
     725     * just to put it to the array, you may find #appendedRaw() more useful.
     726     *
     727     * @param aElement Element to append.
     728     *
     729     * @return          @c true on success and false if there is not enough
     730     *                  memory for resizing.
     731     */
     732    bool push_back (const T &aElement)
     733    {
     734        if (!ensureCapacity (size() + 1))
     735            return false;
     736
     737#if defined (VBOX_WITH_XPCOM)
     738        Copy (aElement, m.arr [m.size]);
     739        ++ m.size;
     740#else
     741        Copy (aElement, m.raw [size() - 1]);
     742#endif
     743        return true;
     744    }
     745
     746    /**
     747     * Appends an empty element at the end of the array and returns a raw
     748     * pointer to it suitable for assigning a raw value (w/o constructing a
     749     * copy).
     750     *
     751     * The array size is increased by one by this method and the additional
     752     * space is allocated as needed.
     753     *
     754     * Note that in case of raw assignment, value ownership (for types with
     755     * dynamically allocated data and for interface pointers) is transferred to
     756     * the safe array object.
     757     *
     758     * This method is handy for operations like
     759     * <tt>Bstr ("foo").detacTo (array.appendedRaw());</tt>. Don't use it as
     760     * l-value (<tt>array.appendedRaw() = SysAllocString (L"tralala");</tt>)
     761     * since this doesn't check for a NULL condition; use #resize() and
     762     * #setRawAt() instead. If you need to assign a copy of the existing value
     763     * instead of transferring the ownership, look at #push_back().
     764     *
     765     * @return          Raw pointer to the added element or NULL if no memory.
     766     */
     767    T *appendedRaw()
     768    {
     769        if (!ensureCapacity (size() + 1))
     770            return NULL;
     771
     772#if defined (VBOX_WITH_XPCOM)
     773        Init (m.arr [m.size]);
     774        ++ m.size;
     775        return &m.arr [m.size - 1];
     776#else
     777        /* nothing to do here, SafeArrayCreate() has performed element
     778         * initialization */
     779        return &m.raw [size() - 1];
     780#endif
     781    }
     782
     783    /**
    679784     * Resizes the array preserving its contents when possible. If the new size
    680      * is bigger than the old size, new elements are initialized with null
    681      * values. If the new size is smaller than the old size, the contents of the
    682      * array above the new size is lost.
     785     * is larget than the old size, new elements are initialized with null
     786     * values. If the new size is less than the old size, the contents of the
     787     * array beyond the new size is lost.
    683788     *
    684789     * @param aNewSize  New number of elements in the array.
     
    686791     *                  memory for resizing.
    687792     */
    688     virtual bool resize (size_t aNewSize)
    689     {
    690         /// @todo Implement me!
    691         NOREF (aNewSize);
    692         AssertFailedReturn (false);
     793    bool resize (size_t aNewSize)
     794    {
     795        if (!ensureCapacity (aNewSize))
     796            return false;
     797
     798#if defined (VBOX_WITH_XPCOM)
     799
     800        if (m.size < aNewSize)
     801        {
     802            /* initialize the new elements */
     803            for (size_t i = m.size; i < aNewSize; ++ i)
     804                Init (m.arr [i]);
     805        }
     806
     807        m.size = aNewSize;
     808#else
     809        /* nothing to do here, SafeArrayCreate() has performed element
     810         * initialization */
     811#endif
     812        return true;
    693813    }
    694814
     
    701821     *                  memory for resizing.
    702822     */
    703     virtual bool reset (size_t aNewSize)
     823    bool reset (size_t aNewSize)
    704824    {
    705825        m.uninit();
    706 
    707 #if defined (VBOX_WITH_XPCOM)
    708 
    709         /* Note: for zero-sized arrays, we use the size of 1 because whether
    710          * malloc(0) returns a null pointer or not (which is used in isNull())
    711          * is implementation-dependent according to the C standard. */
    712 
    713         m.arr = (T *) nsMemory::Alloc (RT_MAX (aNewSize, 1) * sizeof (T));
    714         AssertReturn (m.arr != NULL, false);
    715 
    716         m.size = aNewSize;
    717 
    718         for (size_t i = 0; i < m.size; ++ i)
    719             Init (m.arr [i]);
    720 
    721 #else
    722 
    723         SAFEARRAYBOUND bound = { VarCount (aNewSize), 0 };
    724         m.arr = SafeArrayCreate (VarType(), 1, &bound);
    725         AssertReturn (m.arr != NULL, false);
    726 
    727         AssertReturn (accessRaw() != NULL, false);
    728 
    729 #endif
    730         return true;
     826        return resize (aNewSize);
    731827    }
    732828
     
    743839        return m.arr;
    744840#else
    745         return accessRaw();
     841        return m.raw;
    746842#endif
    747843    }
     
    755851        return m.arr;
    756852#else
    757         return accessRaw();
     853        return m.raw;
    758854#endif
    759855    }
     
    775871        return m.arr [aIdx];
    776872#else
    777 
    778         AssertReturn (accessRaw() != NULL,  *((T *) NULL));
     873        AssertReturn (m.raw != NULL,  *((T *) NULL));
    779874        return m.raw [aIdx];
    780875#endif
     
    791886        return m.arr [aIdx];
    792887#else
    793         AssertReturn (unconst (this)->accessRaw() != NULL,  *((T *) NULL));
     888        AssertReturn (m.raw != NULL,  *((T *) NULL));
    794889        return m.raw [aIdx];
    795890#endif
     
    892987
    893988    /** Internal function Never call it directly. */
    894     SAFEARRAY ** __asOutParam() { setNull(); return &m.arr; }
     989    OutSafeArrayDipper __asOutParam()
     990    { setNull(); return OutSafeArrayDipper (&m.arr, (void **) &m.raw); }
    895991
    896992#endif /* defined (VBOX_WITH_XPCOM) */
     
    902998    DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP(SafeArray)
    903999
    904 #if defined (VBOX_WITH_XPCOM)
    905 #else /* defined (VBOX_WITH_XPCOM) */
    906 
    907     /** Requests access to the raw data pointer. */
    908     T *accessRaw()
    909     {
    910         if (m.arr && m.raw == NULL)
    911         {
    912             HRESULT rc = SafeArrayAccessData (m.arr, (void HUGEP **) &m.raw);
    913             AssertComRCReturn (rc, NULL);
    914         }
    915         return m.raw;
    916     }
    917 
    918 #endif /* defined (VBOX_WITH_XPCOM) */
     1000    /**
     1001     * Ensures that the array is big enough to contaon aNewSize elements.
     1002     *
     1003     * If the new size is greater than the current capacity, a new array is
     1004     * allocated and elements from the old array are copied over. The  size of
     1005     * the array doesn't change, only the capacity increases (which is always
     1006     * greater than the size). Note that the additionally allocated elements are
     1007     * left uninitialized by this method.
     1008     *
     1009     * If the new size is less than the current size, the existing array is
     1010     * truncated to the specified size and the elements outside the new array
     1011     * boundary are freed.
     1012     *
     1013     * If the new size is the same as the current size, nothing happens.
     1014     *
     1015     * @param aNewSize  New size of the array.
     1016     *
     1017     * @return @c true on success and @c false if not enough memory.
     1018     */
     1019    bool ensureCapacity (size_t aNewSize)
     1020    {
     1021        AssertReturn (!m.isWeak, false);
     1022
     1023#if defined (VBOX_WITH_XPCOM)
     1024
     1025        /* Note: we distinguish between a null array and an empty (zero
     1026         * elements) array. Therefore we never use zero in malloc (even if
     1027         * aNewSize is zero) to make sure we get a non-null pointer. */
     1028
     1029        if (m.size == aNewSize && m.arr != NULL)
     1030            return true;
     1031
     1032        /* allocate in 16-byte pieces */
     1033        size_t newCapacity = RT_MAX ((aNewSize + 15) / 16 * 16, 16);
     1034
     1035        if (m.capacity != newCapacity)
     1036        {
     1037            T *newArr = (T *) nsMemory::Alloc (RT_MAX (newCapacity, 1) * sizeof (T));
     1038            AssertReturn (newArr != NULL, false);
     1039
     1040            if (m.arr != NULL)
     1041            {
     1042                if (m.size > aNewSize)
     1043                {
     1044                    /* truncation takes place, uninit exceeding elements and
     1045                     * shrink the size */
     1046                    for (size_t i = aNewSize; i < m.size; ++ i)
     1047                        Uninit (m.arr [i]);
     1048
     1049                    m.size = aNewSize;
     1050                }
     1051
     1052                /* copy the old contents */
     1053                memcpy (newArr, m.arr, m.size * sizeof (T));
     1054                nsMemory::Free ((void *) m.arr);
     1055            }
     1056
     1057            m.arr = newArr;
     1058        }
     1059        else
     1060        {
     1061            if (m.size > aNewSize)
     1062            {
     1063                /* truncation takes place, uninit exceeding elements and
     1064                 * shrink the size */
     1065                for (size_t i = aNewSize; i < m.size; ++ i)
     1066                    Uninit (m.arr [i]);
     1067
     1068                m.size = aNewSize;
     1069            }
     1070        }
     1071
     1072        m.capacity = newCapacity;
     1073
     1074#else
     1075
     1076        SAFEARRAYBOUND bound = { VarCount (aNewSize), 0 };
     1077        HRESULT rc;
     1078
     1079        if (m.arr == NULL)
     1080        {
     1081            m.arr = CreateSafeArray (VarType(), &bound);
     1082            AssertReturn (m.arr != NULL, false);
     1083        }
     1084        else
     1085        {
     1086            SafeArrayUnaccessData (m.arr);
     1087
     1088            rc = SafeArrayRedim (m.arr, &bound);
     1089            AssertComRCReturn (rc == S_OK, false);
     1090        }
     1091
     1092        rc = SafeArrayAccessData (m.arr, (void HUGEP **) &m.raw);
     1093        AssertComRCReturn (rc, false);
     1094
     1095#endif
     1096        return true;
     1097    }
    9191098
    9201099    struct Data
     
    9231102            : isWeak (false)
    9241103#if defined (VBOX_WITH_XPCOM)
    925             , size (0), arr (NULL)
     1104            , capacity (0), size (0), arr (NULL)
    9261105#else
    9271106            , arr (NULL), raw (NULL)
     
    9431122
    9441123                    nsMemory::Free ((void *) arr);
    945 
     1124                }
     1125                else
    9461126                    isWeak = false;
    947                 }
     1127
    9481128                arr = NULL;
    9491129            }
     1130
     1131            size = capacity = 0;
    9501132
    9511133#else /* defined (VBOX_WITH_XPCOM) */
     
    9631145                    HRESULT rc = SafeArrayDestroy (arr);
    9641146                    AssertComRCReturnVoid (rc);
    965 
     1147                }
     1148                else
    9661149                    isWeak = false;
    967                 }
     1150
    9681151                arr = NULL;
    9691152            }
     
    9751158
    9761159#if defined (VBOX_WITH_XPCOM)
     1160        PRUint32 capacity;
    9771161        PRUint32 size;
    9781162        T *arr;
     
    11901374            aTo = NULL;
    11911375    }
     1376
     1377    static SAFEARRAY *CreateSafeArray (VARTYPE aVarType, SAFEARRAYBOUND *aBound)
     1378    {
     1379        NOREF (aVarType);
     1380        return SafeArrayCreateEx (VT_UNKNOWN, 1, aBound, (PVOID) &_ATL_IIDOF (I));
     1381    }
    11921382};
    11931383
     
    12271417     *       The constructor will also assert in this case.
    12281418     */
    1229     SafeIfaceArray (size_t aSize) { reset (aSize); }
     1419    SafeIfaceArray (size_t aSize) { resize (aSize); }
    12301420
    12311421    /**
     
    12751465                                 ("Expected IID {%Vuuid}, got {%Vuuid}.\n",
    12761466                                  &_ATL_IIDOF (I), &guid));
     1467
     1468            rc = SafeArrayAccessData (arg, (void HUGEP **) &m.raw);
     1469            AssertComRCReturnVoid (rc);
    12771470        }
    12781471
    12791472        m.arr = arg;
    12801473        m.isWeak = true;
    1281 
    1282         AssertReturnVoid (accessRaw() != NULL);
    12831474
    12841475#endif /* defined (VBOX_WITH_XPCOM) */
     
    13011492        typedef C <ComPtr <OI>, A> List;
    13021493
    1303         reset (aCntr.size());
     1494        resize (aCntr.size());
    13041495        AssertReturnVoid (!Base::isNull());
    13051496
     
    13301521        typedef C <ComObjPtr <OI>, A> List;
    13311522
    1332         reset (aCntr.size());
     1523        resize (aCntr.size());
    13331524        AssertReturnVoid (!Base::isNull());
    13341525
     
    13421533#endif
    13431534    }
    1344 
    1345     /**
    1346      * Reinitializes this instance by preallocating space for the given number
    1347      * of elements. The previous array contents is lost.
    1348      *
    1349      * @param aNewSize  New number of elements in the array.
    1350      * @return          @c true on success and false if there is not enough
    1351      *                  memory for resizing.
    1352      */
    1353     virtual bool reset (size_t aNewSize)
    1354     {
    1355         Base::m.uninit();
    1356 
    1357 #if defined (VBOX_WITH_XPCOM)
    1358 
    1359         /* Note: for zero-sized arrays, we use the size of 1 because whether
    1360          * malloc(0) returns a null pointer or not (which is used in isNull())
    1361          * is implementation-dependent according to the C standard. */
    1362 
    1363         Base::m.arr = (I **) nsMemory::Alloc (RT_MAX (aNewSize, 1) * sizeof (I *));
    1364         AssertReturn (Base::m.arr != NULL, false);
    1365 
    1366         Base::m.size = aNewSize;
    1367 
    1368         for (size_t i = 0; i < Base::m.size; ++ i)
    1369             Init (Base::m.arr [i]);
    1370 
    1371 #else
    1372 
    1373         SAFEARRAYBOUND bound = { (ULONG)aNewSize, 0 };
    1374         m.arr = SafeArrayCreateEx (VT_UNKNOWN, 1, &bound,
    1375                                    (PVOID) &_ATL_IIDOF (I));
    1376         AssertReturn (m.arr != NULL, false);
    1377 
    1378         AssertReturn (accessRaw() != NULL, false);
    1379 
    1380 #endif
    1381         return true;
    1382     }
    13831535};
    13841536
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