dawn-cmake/src/common/RefCounted.h
Austin Eng d761d5a575 Add Chromium's StackVector base class and ityp::stack_vec
In order to lift Dawn's restriction on the number of bindings
per bind group, static sized arays need to be converted to
dynamically sized vectors. This CL adds Chromium's StackVector
class which behaves like std::vector but provides a stack allocator
to allocate small vectors on the stack. Dawn can use this to avoid
making separate heap allocations for a smaller, realistic binding
counts.

The CL also adds an ityp::stack_vec class to support using
a StackVector with TypedInteger indices.

Bug: dawn:442, dawn:443
Change-Id: I7604c02b3ea52cd63990a2e8b45ed238a5d52232
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/23681
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Bryan Bernhart <bryan.bernhart@intel.com>
Reviewed-by: Austin Eng <enga@chromium.org>
Commit-Queue: Austin Eng <enga@chromium.org>
2020-07-08 20:27:30 +00:00

192 lines
4.1 KiB
C++

// Copyright 2017 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef COMMON_REFCOUNTED_H_
#define COMMON_REFCOUNTED_H_
#include <atomic>
#include <cstdint>
class RefCounted {
public:
RefCounted(uint64_t payload = 0);
uint64_t GetRefCountForTesting() const;
uint64_t GetRefCountPayload() const;
// Dawn API
void Reference();
void Release();
protected:
virtual ~RefCounted() = default;
// A Derived class may override this if they require a custom deleter.
virtual void DeleteThis();
private:
std::atomic_uint64_t mRefCount;
};
template <typename T>
class Ref {
public:
Ref() = default;
constexpr Ref(std::nullptr_t) {
}
Ref& operator=(std::nullptr_t) {
Release();
mPointee = nullptr;
return *this;
}
template <typename U>
Ref(U* p) : mPointee(p) {
static_assert(std::is_convertible<U*, T*>::value, "");
Reference();
}
Ref(const Ref<T>& other) : mPointee(other.mPointee) {
Reference();
}
template <typename U>
Ref(const Ref<U>& other) : mPointee(other.mPointee) {
static_assert(std::is_convertible<U*, T*>::value, "");
Reference();
}
Ref<T>& operator=(const Ref<T>& other) {
if (&other == this)
return *this;
other.Reference();
Release();
mPointee = other.mPointee;
return *this;
}
template <typename U>
Ref<T>& operator=(const Ref<U>& other) {
static_assert(std::is_convertible<U*, T*>::value, "");
other.Reference();
Release();
mPointee = other.mPointee;
return *this;
}
template <typename U>
Ref(Ref<U>&& other) {
static_assert(std::is_convertible<U*, T*>::value, "");
mPointee = other.mPointee;
other.mPointee = nullptr;
}
Ref<T>& operator=(Ref<T>&& other) {
if (&other == this)
return *this;
Release();
mPointee = other.mPointee;
other.mPointee = nullptr;
return *this;
}
template <typename U>
Ref<T>& operator=(Ref<U>&& other) {
static_assert(std::is_convertible<U*, T*>::value, "");
Release();
mPointee = other.mPointee;
other.mPointee = nullptr;
return *this;
}
~Ref() {
Release();
mPointee = nullptr;
}
bool operator==(const T* other) const {
return mPointee == other;
}
bool operator!=(const T* other) const {
return mPointee != other;
}
operator bool() {
return mPointee != nullptr;
}
const T& operator*() const {
return *mPointee;
}
T& operator*() {
return *mPointee;
}
const T* operator->() const {
return mPointee;
}
T* operator->() {
return mPointee;
}
const T* Get() const {
return mPointee;
}
T* Get() {
return mPointee;
}
T* Detach() {
T* pointee = mPointee;
mPointee = nullptr;
return pointee;
}
private:
// Friend is needed so that instances of Ref<U> can assign mPointee
// members of Ref<T>.
template <typename U>
friend class Ref;
void Reference() const {
if (mPointee != nullptr) {
mPointee->Reference();
}
}
void Release() const {
if (mPointee != nullptr) {
mPointee->Release();
}
}
T* mPointee = nullptr;
};
template <typename T>
Ref<T> AcquireRef(T* pointee) {
Ref<T> ref(pointee);
ref->Release();
return ref;
}
#endif // COMMON_REFCOUNTED_H_