1// ======================================================================== //
2// Copyright 2009-2019 Intel Corporation //
3// //
4// Licensed under the Apache License, Version 2.0 (the "License"); //
5// you may not use this file except in compliance with the License. //
6// You may obtain a copy of the License at //
7// //
8// http://www.apache.org/licenses/LICENSE-2.0 //
9// //
10// Unless required by applicable law or agreed to in writing, software //
11// distributed under the License is distributed on an "AS IS" BASIS, //
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. //
13// See the License for the specific language governing permissions and //
14// limitations under the License. //
15// ======================================================================== //
16
17#pragma once
18
19#include "platform.h"
20
21namespace oidn {
22
23 class RefCount
24 {
25 private:
26 std::atomic<size_t> count;
27
28 public:
29 __forceinline RefCount(int count = 0) noexcept : count(count) {}
30
31 __forceinline size_t incRef() noexcept
32 {
33 return count.fetch_add(1) + 1;
34 }
35
36 __forceinline size_t decRef()
37 {
38 const size_t newCount = decRefKeep();
39 if (newCount == 0)
40 destroy();
41 return newCount;
42 }
43
44 __forceinline size_t decRefKeep() noexcept
45 {
46 return count.fetch_add(-1) - 1;
47 }
48
49 __forceinline void destroy()
50 {
51 delete this;
52 }
53
54 protected:
55 // Disable copying
56 RefCount(const RefCount&) = delete;
57 RefCount& operator =(const RefCount&) = delete;
58
59 virtual ~RefCount() noexcept = default;
60 };
61
62 template<typename T>
63 class Ref
64 {
65 private:
66 T* ptr;
67
68 public:
69 __forceinline Ref() noexcept : ptr(nullptr) {}
70 __forceinline Ref(std::nullptr_t) noexcept : ptr(nullptr) {}
71 __forceinline Ref(const Ref& other) noexcept : ptr(other.ptr) { if (ptr) ptr->incRef(); }
72 __forceinline Ref(Ref&& other) noexcept : ptr(other.ptr) { other.ptr = nullptr; }
73 __forceinline Ref(T* ptr) noexcept : ptr(ptr) { if (ptr) ptr->incRef(); }
74
75 template<typename Y>
76 __forceinline Ref(const Ref<Y>& other) noexcept : ptr(other.get()) { if (ptr) ptr->incRef(); }
77
78 template<typename Y>
79 __forceinline explicit Ref(Y* ptr) noexcept : ptr(ptr) { if (ptr) ptr->incRef(); }
80
81 __forceinline ~Ref() { if (ptr) ptr->decRef(); }
82
83 __forceinline Ref& operator =(const Ref& other)
84 {
85 if (other.ptr)
86 other.ptr->incRef();
87 if (ptr)
88 ptr->decRef();
89 ptr = other.ptr;
90 return *this;
91 }
92
93 __forceinline Ref& operator =(Ref&& other)
94 {
95 if (ptr)
96 ptr->decRef();
97 ptr = other.ptr;
98 other.ptr = nullptr;
99 return *this;
100 }
101
102 __forceinline Ref& operator =(T* other)
103 {
104 if (other)
105 other->incRef();
106 if (ptr)
107 ptr->decRef();
108 ptr = other;
109 return *this;
110 }
111
112 __forceinline Ref& operator =(std::nullptr_t)
113 {
114 if (ptr)
115 ptr->decRef();
116 ptr = nullptr;
117 return *this;
118 }
119
120 __forceinline operator bool() const noexcept { return ptr != nullptr; }
121
122 __forceinline T& operator *() const noexcept { return *ptr; }
123 __forceinline T* operator ->() const noexcept { return ptr; }
124
125 __forceinline T* get() const noexcept { return ptr; }
126
127 __forceinline T* detach() noexcept
128 {
129 T* res = ptr;
130 ptr = nullptr;
131 return res;
132 }
133 };
134
135 template<typename T> __forceinline bool operator < (const Ref<T>& a, const Ref<T>& b) noexcept { return a.ptr < b.ptr; }
136
137 template<typename T> __forceinline bool operator ==(const Ref<T>& a, std::nullptr_t) noexcept { return a.ptr == nullptr; }
138 template<typename T> __forceinline bool operator ==(std::nullptr_t, const Ref<T>& b) noexcept { return nullptr == b.ptr; }
139 template<typename T> __forceinline bool operator ==(const Ref<T>& a, const Ref<T>& b) noexcept { return a.ptr == b.ptr; }
140
141 template<typename T> __forceinline bool operator !=(const Ref<T>& a, std::nullptr_t) noexcept { return a.ptr != nullptr; }
142 template<typename T> __forceinline bool operator !=(std::nullptr_t, const Ref<T>& b) noexcept { return nullptr != b.ptr; }
143 template<typename T> __forceinline bool operator !=(const Ref<T>& a, const Ref<T>& b) noexcept { return a.ptr != b.ptr; }
144
145 template<typename T, typename... Args>
146 __forceinline Ref<T> makeRef(Args&&... args)
147 {
148 return Ref<T>(new T(std::forward<Args>(args)...));
149 }
150
151 template<typename T, typename Y>
152 __forceinline Ref<Y> staticRefCast(const Ref<T>& a)
153 {
154 return Ref<Y>(static_cast<Y*>(a.get()));
155 }
156
157 template<typename T, typename Y>
158 __forceinline Ref<Y> dynamicRefCast(const Ref<T>& a)
159 {
160 return Ref<Y>(dynamic_cast<Y*>(a.get()));
161 }
162
163} // namespace oidn
164