xpcom/glue/nsCOMArray.h

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/xpcom/glue/nsCOMArray.h	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,456 @@
     1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
     1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +#ifndef nsCOMArray_h__
    1.10 +#define nsCOMArray_h__
    1.11 +
    1.12 +#include "mozilla/Attributes.h"
    1.13 +#include "mozilla/MemoryReporting.h"
    1.14 +
    1.15 +#include "nsCycleCollectionNoteChild.h"
    1.16 +#include "nsTArray.h"
    1.17 +#include "nsISupports.h"
    1.18 +
    1.19 +// See below for the definition of nsCOMArray<T>
    1.20 +
    1.21 +// a class that's nsISupports-specific, so that we can contain the
    1.22 +// work of this class in the XPCOM dll
    1.23 +class NS_COM_GLUE nsCOMArray_base
    1.24 +{
    1.25 +    friend class nsArray;
    1.26 +protected:
    1.27 +    nsCOMArray_base() {}
    1.28 +    nsCOMArray_base(int32_t aCount) : mArray(aCount) {}
    1.29 +    nsCOMArray_base(const nsCOMArray_base& other);
    1.30 +    ~nsCOMArray_base();
    1.31 +
    1.32 +    int32_t IndexOf(nsISupports* aObject, uint32_t aStartIndex = 0) const;
    1.33 +    bool Contains(nsISupports* aObject) const {
    1.34 +        return IndexOf(aObject) != -1;
    1.35 +    }
    1.36 +
    1.37 +    int32_t IndexOfObject(nsISupports* aObject) const;
    1.38 +    bool ContainsObject(nsISupports* aObject) const {
    1.39 +        return IndexOfObject(aObject) != -1;
    1.40 +    }
    1.41 +
    1.42 +    typedef bool (* nsBaseArrayEnumFunc)
    1.43 +        (void* aElement, void *aData);
    1.44 +
    1.45 +    // enumerate through the array with a callback.
    1.46 +    bool EnumerateForwards(nsBaseArrayEnumFunc aFunc, void* aData) const;
    1.47 +
    1.48 +    bool EnumerateBackwards(nsBaseArrayEnumFunc aFunc, void* aData) const;
    1.49 +
    1.50 +    typedef int (* nsBaseArrayComparatorFunc)
    1.51 +        (nsISupports* aElement1, nsISupports* aElement2, void* aData);
    1.52 +
    1.53 +    struct nsCOMArrayComparatorContext {
    1.54 +        nsBaseArrayComparatorFunc mComparatorFunc;
    1.55 +        void* mData;
    1.56 +    };
    1.57 +
    1.58 +    static int nsCOMArrayComparator(const void* aElement1, const void* aElement2, void* aData);
    1.59 +    void Sort(nsBaseArrayComparatorFunc aFunc, void* aData);
    1.60 +
    1.61 +    bool InsertObjectAt(nsISupports* aObject, int32_t aIndex);
    1.62 +    void InsertElementAt(uint32_t aIndex, nsISupports* aElement);
    1.63 +    bool InsertObjectsAt(const nsCOMArray_base& aObjects, int32_t aIndex);
    1.64 +    void InsertElementsAt(uint32_t aIndex, const nsCOMArray_base& aElements);
    1.65 +    void InsertElementsAt(uint32_t aIndex, nsISupports* const* aElements, uint32_t aCount);
    1.66 +    bool ReplaceObjectAt(nsISupports* aObject, int32_t aIndex);
    1.67 +    void ReplaceElementAt(uint32_t aIndex, nsISupports* aElement) {
    1.68 +        nsISupports* oldElement = mArray[aIndex];
    1.69 +        NS_IF_ADDREF(mArray[aIndex] = aElement);
    1.70 +        NS_IF_RELEASE(oldElement);
    1.71 +    }
    1.72 +    bool AppendObject(nsISupports *aObject) {
    1.73 +        return InsertObjectAt(aObject, Count());
    1.74 +    }
    1.75 +    void AppendElement(nsISupports* aElement) {
    1.76 +        InsertElementAt(Length(), aElement);
    1.77 +    }
    1.78 +    bool AppendObjects(const nsCOMArray_base& aObjects) {
    1.79 +        return InsertObjectsAt(aObjects, Count());
    1.80 +    }
    1.81 +    void AppendElements(const nsCOMArray_base& aElements) {
    1.82 +        return InsertElementsAt(Length(), aElements);
    1.83 +    }
    1.84 +    void AppendElements(nsISupports* const* aElements, uint32_t aCount) {
    1.85 +        return InsertElementsAt(Length(), aElements, aCount);
    1.86 +    }
    1.87 +    bool RemoveObject(nsISupports *aObject);
    1.88 +    nsISupports** Elements() {
    1.89 +        return mArray.Elements();
    1.90 +    }
    1.91 +    void SwapElements(nsCOMArray_base& aOther) {
    1.92 +        mArray.SwapElements(aOther.mArray);
    1.93 +    }
    1.94 +
    1.95 +    void Adopt(nsISupports** aElements, uint32_t aCount);
    1.96 +    uint32_t Forget(nsISupports*** aElements);
    1.97 +public:
    1.98 +    // elements in the array (including null elements!)
    1.99 +    int32_t Count() const {
   1.100 +        return mArray.Length();
   1.101 +    }
   1.102 +    // nsTArray-compatible version
   1.103 +    uint32_t Length() const {
   1.104 +        return mArray.Length();
   1.105 +    }
   1.106 +    bool IsEmpty() const {
   1.107 +        return mArray.IsEmpty();
   1.108 +    }
   1.109 +
   1.110 +    // If the array grows, the newly created entries will all be null;
   1.111 +    // if the array shrinks, the excess entries will all be released.
   1.112 +    bool SetCount(int32_t aNewCount);
   1.113 +    // nsTArray-compatible version
   1.114 +    void TruncateLength(uint32_t aNewLength) {
   1.115 +        if (mArray.Length() > aNewLength)
   1.116 +            RemoveElementsAt(aNewLength, mArray.Length() - aNewLength);
   1.117 +    }
   1.118 +
   1.119 +    // remove all elements in the array, and call NS_RELEASE on each one
   1.120 +    void Clear();
   1.121 +
   1.122 +    nsISupports* ObjectAt(int32_t aIndex) const {
   1.123 +        return mArray[aIndex];
   1.124 +    }
   1.125 +    // nsTArray-compatible version
   1.126 +    nsISupports* ElementAt(uint32_t aIndex) const {
   1.127 +        return mArray[aIndex];
   1.128 +    }
   1.129 +
   1.130 +    nsISupports* SafeObjectAt(int32_t aIndex) const {
   1.131 +        return mArray.SafeElementAt(aIndex, nullptr);
   1.132 +    }
   1.133 +    // nsTArray-compatible version
   1.134 +    nsISupports* SafeElementAt(uint32_t aIndex) const {
   1.135 +        return mArray.SafeElementAt(aIndex, nullptr);
   1.136 +    }
   1.137 +
   1.138 +    nsISupports* operator[](int32_t aIndex) const {
   1.139 +        return mArray[aIndex];
   1.140 +    }
   1.141 +
   1.142 +    // remove an element at a specific position, shrinking the array
   1.143 +    // as necessary
   1.144 +    bool RemoveObjectAt(int32_t aIndex);
   1.145 +    // nsTArray-compatible version
   1.146 +    void RemoveElementAt(uint32_t aIndex);
   1.147 +
   1.148 +    // remove a range of elements at a specific position, shrinking the array
   1.149 +    // as necessary
   1.150 +    bool RemoveObjectsAt(int32_t aIndex, int32_t aCount);
   1.151 +    // nsTArray-compatible version
   1.152 +    void RemoveElementsAt(uint32_t aIndex, uint32_t aCount);
   1.153 +
   1.154 +    void SwapElementsAt(uint32_t aIndex1, uint32_t aIndex2) {
   1.155 +        nsISupports *tmp = mArray[aIndex1];
   1.156 +        mArray[aIndex1] = mArray[aIndex2];
   1.157 +        mArray[aIndex2] = tmp;
   1.158 +    }
   1.159 +
   1.160 +    // Ensures there is enough space to store a total of aCapacity objects.
   1.161 +    // This method never deletes any objects.
   1.162 +    void SetCapacity(uint32_t aCapacity) {
   1.163 +        mArray.SetCapacity(aCapacity);
   1.164 +    }
   1.165 +    uint32_t Capacity() {
   1.166 +        return mArray.Capacity();
   1.167 +    }
   1.168 +
   1.169 +    typedef size_t (* nsBaseArraySizeOfElementIncludingThisFunc)
   1.170 +        (nsISupports* aElement, mozilla::MallocSizeOf aMallocSizeOf, void *aData);
   1.171 +
   1.172 +    // Measures the size of the array's element storage, and if
   1.173 +    // |aSizeOfElement| is non-nullptr, measures the size of things pointed to
   1.174 +    // by elements.
   1.175 +    size_t SizeOfExcludingThis(
   1.176 +             nsBaseArraySizeOfElementIncludingThisFunc aSizeOfElementIncludingThis,
   1.177 +             mozilla::MallocSizeOf aMallocSizeOf, void* aData = nullptr) const;
   1.178 +
   1.179 +private:
   1.180 +
   1.181 +    // the actual storage
   1.182 +    nsTArray<nsISupports*> mArray;
   1.183 +
   1.184 +    // don't implement these, defaults will muck with refcounts!
   1.185 +    nsCOMArray_base& operator=(const nsCOMArray_base& other) MOZ_DELETE;
   1.186 +};
   1.187 +
   1.188 +inline void
   1.189 +ImplCycleCollectionUnlink(nsCOMArray_base& aField)
   1.190 +{
   1.191 +    aField.Clear();
   1.192 +}
   1.193 +
   1.194 +inline void
   1.195 +ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback,
   1.196 +                            nsCOMArray_base& aField,
   1.197 +                            const char* aName,
   1.198 +                            uint32_t aFlags = 0)
   1.199 +{
   1.200 +    aFlags |= CycleCollectionEdgeNameArrayFlag;
   1.201 +    int32_t length = aField.Count();
   1.202 +    for (int32_t i = 0; i < length; ++i) {
   1.203 +        CycleCollectionNoteChild(aCallback, aField[i], aName, aFlags);
   1.204 +    }
   1.205 +}
   1.206 +
   1.207 +
   1.208 +// a non-XPCOM, refcounting array of XPCOM objects
   1.209 +// used as a member variable or stack variable - this object is NOT
   1.210 +// refcounted, but the objects that it holds are
   1.211 +//
   1.212 +// most of the read-only accessors like ObjectAt()/etc do NOT refcount
   1.213 +// on the way out. This means that you can do one of two things:
   1.214 +//
   1.215 +// * does an addref, but holds onto a reference
   1.216 +// nsCOMPtr<T> foo = array[i];
   1.217 +//
   1.218 +// * avoids the refcount, but foo might go stale if array[i] is ever
   1.219 +// * modified/removed. Be careful not to NS_RELEASE(foo)!
   1.220 +// T* foo = array[i];
   1.221 +//
   1.222 +// This array will accept null as an argument for any object, and will
   1.223 +// store null in the array, just like nsVoidArray. But that also means
   1.224 +// that methods like ObjectAt() may return null when referring to an
   1.225 +// existing, but null entry in the array.
   1.226 +template <class T>
   1.227 +class nsCOMArray : public nsCOMArray_base
   1.228 +{
   1.229 + public:
   1.230 +    nsCOMArray() {}
   1.231 +
   1.232 +    explicit
   1.233 +    nsCOMArray(int32_t aCount) : nsCOMArray_base(aCount) {}
   1.234 +
   1.235 +    explicit
   1.236 +    nsCOMArray(const nsCOMArray<T>& aOther) : nsCOMArray_base(aOther) { }
   1.237 +
   1.238 +    nsCOMArray(nsCOMArray<T>&& aOther) { SwapElements(aOther); }
   1.239 +
   1.240 +    ~nsCOMArray() {}
   1.241 +
   1.242 +    // We have a move assignment operator, but no copy assignment operator.
   1.243 +    nsCOMArray<T>& operator=(nsCOMArray<T>&& aOther) {
   1.244 +        SwapElements(aOther);
   1.245 +        return *this;
   1.246 +    }
   1.247 +
   1.248 +    // these do NOT refcount on the way out, for speed
   1.249 +    T* ObjectAt(int32_t aIndex) const {
   1.250 +        return static_cast<T*>(nsCOMArray_base::ObjectAt(aIndex));
   1.251 +    }
   1.252 +    // nsTArray-compatible version
   1.253 +    T* ElementAt(uint32_t aIndex) const {
   1.254 +        return static_cast<T*>(nsCOMArray_base::ElementAt(aIndex));
   1.255 +    }
   1.256 +
   1.257 +    // these do NOT refcount on the way out, for speed
   1.258 +    T* SafeObjectAt(int32_t aIndex) const {
   1.259 +        return static_cast<T*>(nsCOMArray_base::SafeObjectAt(aIndex));
   1.260 +    }
   1.261 +    // nsTArray-compatible version
   1.262 +    T* SafeElementAt(uint32_t aIndex) const {
   1.263 +        return static_cast<T*>(nsCOMArray_base::SafeElementAt(aIndex));
   1.264 +    }
   1.265 +
   1.266 +    // indexing operator for syntactic sugar
   1.267 +    T* operator[](int32_t aIndex) const {
   1.268 +        return ObjectAt(aIndex);
   1.269 +    }
   1.270 +
   1.271 +    // index of the element in question.. does NOT refcount
   1.272 +    // note: this does not check COM object identity. Use
   1.273 +    // IndexOfObject() for that purpose
   1.274 +    int32_t IndexOf(T* aObject, uint32_t aStartIndex = 0) const {
   1.275 +        return nsCOMArray_base::IndexOf(aObject, aStartIndex);
   1.276 +    }
   1.277 +    bool Contains(nsISupports* aObject) const {
   1.278 +        return nsCOMArray_base::Contains(aObject);
   1.279 +    }
   1.280 +
   1.281 +    // index of the element in question.. be careful!
   1.282 +    // this is much slower than IndexOf() because it uses
   1.283 +    // QueryInterface to determine actual COM identity of the object
   1.284 +    // if you need to do this frequently then consider enforcing
   1.285 +    // COM object identity before adding/comparing elements
   1.286 +    int32_t IndexOfObject(T* aObject) const {
   1.287 +        return nsCOMArray_base::IndexOfObject(aObject);
   1.288 +    }
   1.289 +    bool ContainsObject(nsISupports* aObject) const {
   1.290 +        return nsCOMArray_base::ContainsObject(aObject);
   1.291 +    }
   1.292 +
   1.293 +    // inserts aObject at aIndex, shifting the objects at aIndex and
   1.294 +    // later to make space
   1.295 +    bool InsertObjectAt(T* aObject, int32_t aIndex) {
   1.296 +        return nsCOMArray_base::InsertObjectAt(aObject, aIndex);
   1.297 +    }
   1.298 +    // nsTArray-compatible version
   1.299 +    void InsertElementAt(uint32_t aIndex, T* aElement) {
   1.300 +        nsCOMArray_base::InsertElementAt(aIndex, aElement);
   1.301 +    }
   1.302 +
   1.303 +    // inserts the objects from aObject at aIndex, shifting the
   1.304 +    // objects at aIndex and later to make space
   1.305 +    bool InsertObjectsAt(const nsCOMArray<T>& aObjects, int32_t aIndex) {
   1.306 +        return nsCOMArray_base::InsertObjectsAt(aObjects, aIndex);
   1.307 +    }
   1.308 +    // nsTArray-compatible version
   1.309 +    void InsertElementsAt(uint32_t aIndex, const nsCOMArray<T>& aElements) {
   1.310 +        nsCOMArray_base::InsertElementsAt(aIndex, aElements);
   1.311 +    }
   1.312 +    void InsertElementsAt(uint32_t aIndex, T* const* aElements, uint32_t aCount) {
   1.313 +        nsCOMArray_base::InsertElementsAt(aIndex, reinterpret_cast<nsISupports* const*>(aElements), aCount);
   1.314 +    }
   1.315 +
   1.316 +    // replaces an existing element. Warning: if the array grows,
   1.317 +    // the newly created entries will all be null
   1.318 +    bool ReplaceObjectAt(T* aObject, int32_t aIndex) {
   1.319 +        return nsCOMArray_base::ReplaceObjectAt(aObject, aIndex);
   1.320 +    }
   1.321 +    // nsTArray-compatible version
   1.322 +    void ReplaceElementAt(uint32_t aIndex, T* aElement) {
   1.323 +        nsCOMArray_base::ReplaceElementAt(aIndex, aElement);
   1.324 +    }
   1.325 +
   1.326 +    // Enumerator callback function. Return false to stop
   1.327 +    // Here's a more readable form:
   1.328 +    // bool enumerate(T* aElement, void* aData)
   1.329 +    typedef bool (* nsCOMArrayEnumFunc)
   1.330 +        (T* aElement, void *aData);
   1.331 +
   1.332 +    // enumerate through the array with a callback. 
   1.333 +    bool EnumerateForwards(nsCOMArrayEnumFunc aFunc, void* aData) {
   1.334 +        return nsCOMArray_base::EnumerateForwards(nsBaseArrayEnumFunc(aFunc),
   1.335 +                                                  aData);
   1.336 +    }
   1.337 +
   1.338 +    bool EnumerateBackwards(nsCOMArrayEnumFunc aFunc, void* aData) {
   1.339 +        return nsCOMArray_base::EnumerateBackwards(nsBaseArrayEnumFunc(aFunc),
   1.340 +                                                  aData);
   1.341 +    }
   1.342 +
   1.343 +    typedef int (* nsCOMArrayComparatorFunc)
   1.344 +        (T* aElement1, T* aElement2, void* aData);
   1.345 +
   1.346 +    void Sort(nsCOMArrayComparatorFunc aFunc, void* aData) {
   1.347 +        nsCOMArray_base::Sort(nsBaseArrayComparatorFunc(aFunc), aData);
   1.348 +    }
   1.349 +
   1.350 +    // append an object, growing the array as necessary
   1.351 +    bool AppendObject(T *aObject) {
   1.352 +        return nsCOMArray_base::AppendObject(aObject);
   1.353 +    }
   1.354 +    // nsTArray-compatible version
   1.355 +    void AppendElement(T* aElement) {
   1.356 +        nsCOMArray_base::AppendElement(aElement);
   1.357 +    }
   1.358 +
   1.359 +    // append objects, growing the array as necessary
   1.360 +    bool AppendObjects(const nsCOMArray<T>& aObjects) {
   1.361 +        return nsCOMArray_base::AppendObjects(aObjects);
   1.362 +    }
   1.363 +    // nsTArray-compatible version
   1.364 +    void AppendElements(const nsCOMArray<T>& aElements) {
   1.365 +        return nsCOMArray_base::AppendElements(aElements);
   1.366 +    }
   1.367 +    void AppendElements(T* const* aElements, uint32_t aCount) {
   1.368 +        InsertElementsAt(Length(), aElements, aCount);
   1.369 +    }
   1.370 +
   1.371 +    // remove the first instance of the given object and shrink the
   1.372 +    // array as necessary
   1.373 +    // Warning: if you pass null here, it will remove the first null element
   1.374 +    bool RemoveObject(T *aObject) {
   1.375 +        return nsCOMArray_base::RemoveObject(aObject);
   1.376 +    }
   1.377 +    // nsTArray-compatible version
   1.378 +    bool RemoveElement(T* aElement) {
   1.379 +        return nsCOMArray_base::RemoveObject(aElement);
   1.380 +    }
   1.381 +
   1.382 +    T** Elements() {
   1.383 +        return reinterpret_cast<T**>(nsCOMArray_base::Elements());
   1.384 +    }
   1.385 +    void SwapElements(nsCOMArray<T>& aOther) {
   1.386 +        nsCOMArray_base::SwapElements(aOther);
   1.387 +    }
   1.388 +
   1.389 +    // Each element in an nsCOMArray<T> is actually a T*, so this function is
   1.390 +    // "IncludingThis" rather than "ExcludingThis" because it needs to measure
   1.391 +    // the memory taken by the T itself as well as anything it points to.
   1.392 +    typedef size_t (* nsCOMArraySizeOfElementIncludingThisFunc)
   1.393 +        (T* aElement, mozilla::MallocSizeOf aMallocSizeOf, void *aData);
   1.394 +
   1.395 +    size_t SizeOfExcludingThis(
   1.396 +             nsCOMArraySizeOfElementIncludingThisFunc aSizeOfElementIncludingThis, 
   1.397 +             mozilla::MallocSizeOf aMallocSizeOf, void *aData = nullptr) const {
   1.398 +        return nsCOMArray_base::SizeOfExcludingThis(
   1.399 +                 nsBaseArraySizeOfElementIncludingThisFunc(aSizeOfElementIncludingThis),
   1.400 +                 aMallocSizeOf, aData);
   1.401 +    }
   1.402 +
   1.403 +    /**
   1.404 +     * Adopt parameters that resulted from an XPIDL outparam. The aElements
   1.405 +     * parameter will be freed as a result of the call.
   1.406 +     *
   1.407 +     * Example usage:
   1.408 +     * nsCOMArray<nsISomeInterface> array;
   1.409 +     * nsISomeInterface** elements;
   1.410 +     * uint32_t length;
   1.411 +     * ptr->GetSomeArray(&elements, &length);
   1.412 +     * array.Adopt(elements, length);
   1.413 +     */
   1.414 +    void Adopt(T** aElements, uint32_t aSize) {
   1.415 +        nsCOMArray_base::Adopt(reinterpret_cast<nsISupports**>(aElements),
   1.416 +            aSize);
   1.417 +    }
   1.418 +
   1.419 +    /**
   1.420 +     * Export the contents of this array to an XPIDL outparam. The array will be
   1.421 +     * Clear()'d after this operation.
   1.422 +     *
   1.423 +     * Example usage:
   1.424 +     * nsCOMArray<nsISomeInterface> array;
   1.425 +     * *length = array.Forget(retval);
   1.426 +     */
   1.427 +    uint32_t Forget(T*** elements) {
   1.428 +        return nsCOMArray_base::Forget(
   1.429 +            reinterpret_cast<nsISupports***>(elements));
   1.430 +    }
   1.431 +
   1.432 +private:
   1.433 +
   1.434 +    // don't implement these!
   1.435 +    nsCOMArray<T>& operator=(const nsCOMArray<T>& other) MOZ_DELETE;
   1.436 +};
   1.437 +
   1.438 +template <typename T>
   1.439 +inline void
   1.440 +ImplCycleCollectionUnlink(nsCOMArray<T>& aField)
   1.441 +{
   1.442 +    aField.Clear();
   1.443 +}
   1.444 +
   1.445 +template <typename E>
   1.446 +inline void
   1.447 +ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback,
   1.448 +                            nsCOMArray<E>& aField,
   1.449 +                            const char* aName,
   1.450 +                            uint32_t aFlags = 0)
   1.451 +{
   1.452 +    aFlags |= CycleCollectionEdgeNameArrayFlag;
   1.453 +    int32_t length = aField.Count();
   1.454 +    for (int32_t i = 0; i < length; ++i) {
   1.455 +        CycleCollectionNoteChild(aCallback, aField[i], aName, aFlags);
   1.456 +    }
   1.457 +}
   1.458 +
   1.459 +#endif

mercurial