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