gfx/2d/GenericRefCounted.h

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/gfx/2d/GenericRefCounted.h	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,131 @@
     1.4 +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
     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 +// This header provides virtual, non-templated alternatives to MFBT's RefCounted<T>.
    1.10 +// It intentionally uses MFBT coding style with the intention of moving there
    1.11 +// should there be other use cases for it.
    1.12 +
    1.13 +#ifndef MOZILLA_GENERICREFCOUNTED_H_
    1.14 +#define MOZILLA_GENERICREFCOUNTED_H_
    1.15 +
    1.16 +#include "mozilla/RefPtr.h"
    1.17 +
    1.18 +namespace mozilla {
    1.19 +
    1.20 +/**
    1.21 + * Common base class for GenericRefCounted and GenericAtomicRefCounted.
    1.22 + *
    1.23 + * Having this shared base class, common to both the atomic and non-atomic
    1.24 + * cases, allows to have RefPtr's that don't care about whether the
    1.25 + * objects they're managing have atomic refcounts or not.
    1.26 + */
    1.27 +class GenericRefCountedBase
    1.28 +{
    1.29 +  protected:
    1.30 +    virtual ~GenericRefCountedBase() {};
    1.31 +
    1.32 +  public:
    1.33 +    // AddRef() and Release() method names are for compatibility with nsRefPtr.
    1.34 +    virtual void AddRef() = 0;
    1.35 +
    1.36 +    virtual void Release() = 0;
    1.37 +
    1.38 +    // ref() and deref() method names are for compatibility with wtf::RefPtr.
    1.39 +    // No virtual keywords here: if a subclass wants to override the refcounting
    1.40 +    // mechanism, it is welcome to do so by overriding AddRef() and Release().
    1.41 +    void ref() { AddRef(); }
    1.42 +    void deref() { Release(); }
    1.43 +
    1.44 +#ifdef MOZ_REFCOUNTED_LEAK_CHECKING
    1.45 +    virtual const char* typeName() const = 0;
    1.46 +    virtual size_t typeSize() const = 0;
    1.47 +#endif
    1.48 +};
    1.49 +
    1.50 +namespace detail {
    1.51 +
    1.52 +template<RefCountAtomicity Atomicity>
    1.53 +class GenericRefCounted : public GenericRefCountedBase
    1.54 +{
    1.55 +  protected:
    1.56 +    GenericRefCounted() : refCnt(0) { }
    1.57 +
    1.58 +    virtual ~GenericRefCounted() {
    1.59 +      MOZ_ASSERT(refCnt == detail::DEAD);
    1.60 +    }
    1.61 +
    1.62 +  public:
    1.63 +    virtual void AddRef() {
    1.64 +      // Note: this method must be thread safe for GenericAtomicRefCounted.
    1.65 +      MOZ_ASSERT(int32_t(refCnt) >= 0);
    1.66 +#ifndef MOZ_REFCOUNTED_LEAK_CHECKING
    1.67 +      ++refCnt;
    1.68 +#else
    1.69 +      const char* type = typeName();
    1.70 +      uint32_t size = typeSize();
    1.71 +      const void* ptr = this;
    1.72 +      MozRefCountType cnt = ++refCnt;
    1.73 +      detail::RefCountLogger::logAddRef(ptr, cnt, type, size);
    1.74 +#endif
    1.75 +    }
    1.76 +
    1.77 +    virtual void Release() {
    1.78 +      // Note: this method must be thread safe for GenericAtomicRefCounted.
    1.79 +      MOZ_ASSERT(int32_t(refCnt) > 0);
    1.80 +#ifndef MOZ_REFCOUNTED_LEAK_CHECKING
    1.81 +      MozRefCountType cnt = --refCnt;
    1.82 +#else
    1.83 +      const char* type = typeName();
    1.84 +      const void* ptr = this;
    1.85 +      MozRefCountType cnt = --refCnt;
    1.86 +      // Note: it's not safe to touch |this| after decrementing the refcount,
    1.87 +      // except for below.
    1.88 +      detail::RefCountLogger::logRelease(ptr, cnt, type);
    1.89 +#endif
    1.90 +      if (0 == cnt) {
    1.91 +        // Because we have atomically decremented the refcount above, only
    1.92 +        // one thread can get a 0 count here, so as long as we can assume that
    1.93 +        // everything else in the system is accessing this object through
    1.94 +        // RefPtrs, it's safe to access |this| here.
    1.95 +#ifdef DEBUG
    1.96 +        refCnt = detail::DEAD;
    1.97 +#endif
    1.98 +        delete this;
    1.99 +      }
   1.100 +    }
   1.101 +
   1.102 +    MozRefCountType refCount() const { return refCnt; }
   1.103 +    bool hasOneRef() const {
   1.104 +      MOZ_ASSERT(refCnt > 0);
   1.105 +      return refCnt == 1;
   1.106 +    }
   1.107 +
   1.108 +  private:
   1.109 +    typename Conditional<Atomicity == AtomicRefCount, Atomic<MozRefCountType>, MozRefCountType>::Type refCnt;
   1.110 +};
   1.111 +
   1.112 +} // namespace detail
   1.113 +
   1.114 +/**
   1.115 + * This reference-counting base class is virtual instead of
   1.116 + * being templated, which is useful in cases where one needs
   1.117 + * genericity at binary code level, but comes at the cost
   1.118 + * of a moderate performance and size overhead, like anything virtual.
   1.119 + */
   1.120 +class GenericRefCounted : public detail::GenericRefCounted<detail::NonAtomicRefCount>
   1.121 +{
   1.122 +};
   1.123 +
   1.124 +/**
   1.125 + * GenericAtomicRefCounted is like GenericRefCounted, with an atomically updated
   1.126 + * reference counter.
   1.127 + */
   1.128 +class GenericAtomicRefCounted : public detail::GenericRefCounted<detail::AtomicRefCount>
   1.129 +{
   1.130 +};
   1.131 +
   1.132 +} // namespace mozilla
   1.133 +
   1.134 +#endif

mercurial