1 // Copyright 2009-2021 Intel Corporation
2 // SPDX-License-Identifier: Apache-2.0
3 
4 #pragma once
5 
6 #include "atomic.h"
7 
8 namespace embree
9 {
10   struct NullTy {
11   };
12 
13   extern MAYBE_UNUSED NullTy null;
14 
15   class RefCount
16   {
17   public:
refCounter(val)18     RefCount(int val = 0) : refCounter(val) {}
~RefCount()19     virtual ~RefCount() {};
20 
refInc()21     virtual RefCount* refInc() { refCounter.fetch_add(1); return this; }
refDec()22     virtual void refDec() { if (refCounter.fetch_add(-1) == 1) delete this; }
23   private:
24     std::atomic<size_t> refCounter;
25   };
26 
27   ////////////////////////////////////////////////////////////////////////////////
28   /// Reference to single object
29   ////////////////////////////////////////////////////////////////////////////////
30 
31   template<typename Type>
32   class Ref
33   {
34   public:
35     Type* ptr;
36 
37     ////////////////////////////////////////////////////////////////////////////////
38     /// Constructors, Assignment & Cast Operators
39     ////////////////////////////////////////////////////////////////////////////////
40 
Ref()41     __forceinline Ref() : ptr(nullptr) {}
Ref(NullTy)42     __forceinline Ref(NullTy) : ptr(nullptr) {}
Ref(const Ref & input)43     __forceinline Ref(const Ref& input) : ptr(input.ptr) { if (ptr) ptr->refInc(); }
Ref(Ref && input)44     __forceinline Ref(Ref&& input) : ptr(input.ptr) { input.ptr = nullptr; }
45 
Ref(Type * const input)46     __forceinline Ref(Type* const input) : ptr(input)
47     {
48       if (ptr)
49         ptr->refInc();
50     }
51 
~Ref()52     __forceinline ~Ref()
53     {
54       if (ptr)
55         ptr->refDec();
56     }
57 
58     __forceinline Ref& operator =(const Ref& input)
59     {
60       if (input.ptr)
61         input.ptr->refInc();
62       if (ptr)
63         ptr->refDec();
64       ptr = input.ptr;
65       return *this;
66     }
67 
68     __forceinline Ref& operator =(Ref&& input)
69     {
70       if (ptr)
71         ptr->refDec();
72       ptr = input.ptr;
73       input.ptr = nullptr;
74       return *this;
75     }
76 
77     __forceinline Ref& operator =(Type* const input)
78     {
79       if (input)
80         input->refInc();
81       if (ptr)
82         ptr->refDec();
83       ptr = input;
84       return *this;
85     }
86 
87     __forceinline Ref& operator =(NullTy)
88     {
89       if (ptr)
90         ptr->refDec();
91       ptr = nullptr;
92       return *this;
93     }
94 
95     __forceinline operator bool() const { return ptr != nullptr; }
96 
97     __forceinline const Type& operator  *() const { return *ptr; }
98     __forceinline       Type& operator  *()       { return *ptr; }
99     __forceinline const Type* operator ->() const { return  ptr; }
100     __forceinline       Type* operator ->()       { return  ptr; }
101 
102     template<typename TypeOut>
cast()103     __forceinline       Ref<TypeOut> cast()       { return Ref<TypeOut>(static_cast<TypeOut*>(ptr)); }
104     template<typename TypeOut>
cast()105     __forceinline const Ref<TypeOut> cast() const { return Ref<TypeOut>(static_cast<TypeOut*>(ptr)); }
106 
107     template<typename TypeOut>
dynamicCast()108     __forceinline       Ref<TypeOut> dynamicCast()       { return Ref<TypeOut>(dynamic_cast<TypeOut*>(ptr)); }
109     template<typename TypeOut>
dynamicCast()110     __forceinline const Ref<TypeOut> dynamicCast() const { return Ref<TypeOut>(dynamic_cast<TypeOut*>(ptr)); }
111   };
112 
113   template<typename Type> __forceinline bool operator < (const Ref<Type>& a, const Ref<Type>& b) { return a.ptr   <  b.ptr;   }
114 
115   template<typename Type> __forceinline bool operator ==(const Ref<Type>& a, NullTy            ) { return a.ptr   == nullptr; }
116   template<typename Type> __forceinline bool operator ==(NullTy            , const Ref<Type>& b) { return nullptr == b.ptr;   }
117   template<typename Type> __forceinline bool operator ==(const Ref<Type>& a, const Ref<Type>& b) { return a.ptr   == b.ptr;   }
118 
119   template<typename Type> __forceinline bool operator !=(const Ref<Type>& a, NullTy            ) { return a.ptr   != nullptr; }
120   template<typename Type> __forceinline bool operator !=(NullTy            , const Ref<Type>& b) { return nullptr != b.ptr;   }
121   template<typename Type> __forceinline bool operator !=(const Ref<Type>& a, const Ref<Type>& b) { return a.ptr   != b.ptr;   }
122 }
123