1 /*
2   Copyright (c) DataStax, Inc.
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 #ifndef DATASTAX_INTERNAL_REF_COUNTED_HPP
18 #define DATASTAX_INTERNAL_REF_COUNTED_HPP
19 
20 #include "allocated.hpp"
21 #include "atomic.hpp"
22 #include "macros.hpp"
23 #include "memory.hpp"
24 
25 #include <assert.h>
26 #include <new>
27 #include <uv.h>
28 
29 namespace datastax { namespace internal {
30 
31 template <class T>
32 class RefCounted : public Allocated {
33 public:
RefCounted()34   RefCounted()
35       : ref_count_(0) {}
36 
ref_count() const37   int ref_count() const { return ref_count_.load(MEMORY_ORDER_ACQUIRE); }
38 
inc_ref() const39   void inc_ref() const { ref_count_.fetch_add(1, MEMORY_ORDER_RELAXED); }
40 
dec_ref() const41   void dec_ref() const {
42     int new_ref_count = ref_count_.fetch_sub(1, MEMORY_ORDER_RELEASE);
43     assert(new_ref_count >= 1);
44     if (new_ref_count == 1) {
45       atomic_thread_fence(MEMORY_ORDER_ACQUIRE);
46       delete static_cast<const T*>(this);
47     }
48   }
49 
50 private:
51   mutable Atomic<int> ref_count_;
52   DISALLOW_COPY_AND_ASSIGN(RefCounted);
53 };
54 
55 template <class T>
56 class SharedRefPtr {
57 public:
SharedRefPtr(T * ptr=NULL)58   explicit SharedRefPtr(T* ptr = NULL)
59       : ptr_(ptr) {
60     if (ptr_ != NULL) {
61       ptr_->inc_ref();
62     }
63   }
64 
SharedRefPtr(const SharedRefPtr<T> & ref)65   SharedRefPtr(const SharedRefPtr<T>& ref)
66       : ptr_(NULL) {
67     copy<T>(ref.ptr_);
68   }
69 
70   template <class S>
SharedRefPtr(const SharedRefPtr<S> & ref)71   SharedRefPtr(const SharedRefPtr<S>& ref)
72       : ptr_(NULL) {
73     copy<S>(ref.ptr_);
74   }
75 
operator =(const SharedRefPtr<T> & ref)76   SharedRefPtr<T>& operator=(const SharedRefPtr<T>& ref) {
77     copy<T>(ref.ptr_);
78     return *this;
79   }
80 
81   template <class S>
operator =(const SharedRefPtr<S> & ref)82   SharedRefPtr<S>& operator=(const SharedRefPtr<S>& ref) {
83     copy<S>(ref.ptr_);
84     return *this;
85   }
86 
~SharedRefPtr()87   ~SharedRefPtr() {
88     if (ptr_ != NULL) {
89       ptr_->dec_ref();
90     }
91   }
92 
operator ==(const T * ptr) const93   bool operator==(const T* ptr) const { return ptr_ == ptr; }
94 
operator ==(const SharedRefPtr<T> & ref) const95   bool operator==(const SharedRefPtr<T>& ref) const { return ptr_ == ref.ptr_; }
96 
reset(T * ptr=NULL)97   void reset(T* ptr = NULL) { copy<T>(ptr); }
98 
get() const99   T* get() const { return ptr_; }
operator *() const100   T& operator*() const { return *ptr_; }
operator ->() const101   T* operator->() const { return ptr_; }
operator bool() const102   operator bool() const { return ptr_ != NULL; }
103 
104 private:
105   template <class S>
106   friend class SharedRefPtr;
107 
108   template <class S>
copy(S * ptr)109   void copy(S* ptr) {
110     if (ptr == ptr_) return;
111     if (ptr != NULL) {
112       ptr->inc_ref();
113     }
114     T* temp = ptr_;
115     ptr_ = static_cast<T*>(ptr);
116     if (temp != NULL) {
117       temp->dec_ref();
118     }
119   }
120 
121   T* ptr_;
122 };
123 
124 class RefBuffer : public RefCounted<RefBuffer> {
125 public:
126   typedef SharedRefPtr<RefBuffer> Ptr;
127 
create(size_t size)128   static RefBuffer* create(size_t size) {
129 #if defined(_WIN32)
130 #pragma warning(push)
131 #pragma warning(disable : 4291) // Invalid warning thrown RefBuffer has a delete function
132 #endif
133     return new (size) RefBuffer();
134 #if defined(_WIN32)
135 #pragma warning(pop)
136 #endif
137   }
138 
data()139   char* data() { return reinterpret_cast<char*>(this) + sizeof(RefBuffer); }
140 
operator delete(void * ptr)141   void operator delete(void* ptr) { Memory::free(ptr); }
142 
143 private:
RefBuffer()144   RefBuffer() {}
145 
operator new(size_t size,size_t extra)146   void* operator new(size_t size, size_t extra) { return Memory::malloc(size + extra); }
147 
148   DISALLOW_COPY_AND_ASSIGN(RefBuffer);
149 };
150 
151 }} // namespace datastax::internal
152 
153 #endif
154