130d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun/* 230d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun * Copyright 2011 Google Inc. All Rights Reserved. 330d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun * 430d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun * Licensed under the Apache License, Version 2.0 (the "License"); 530d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun * you may not use this file except in compliance with the License. 630d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun * You may obtain a copy of the License at 730d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun * 830d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun * http://www.apache.org/licenses/LICENSE-2.0 930d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun * 1030d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun * Unless required by applicable law or agreed to in writing, software 1130d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun * distributed under the License is distributed on an "AS IS" BASIS, 1230d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1330d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun * See the License for the specific language governing permissions and 1430d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun * limitations under the License. 1530d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun */ 1630d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun 1730d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun// Object reference count and smart pointer implementation. 1830d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun 1930d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun// Smart pointer usage in sfntly: 2030d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun// 2130d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun// sfntly carries a smart pointer implementation like COM. Ref-countable object 2230d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun// type inherits from RefCounted<>, which have AddRef and Release just like 2330d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun// IUnknown (but no QueryInterface). Use a Ptr<> based smart pointer to hold 2430d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun// the object so that the object ref count is handled correctly. 2530d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun// 2630d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun// class Foo : public RefCounted<Foo> { 2730d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun// public: 2830d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun// static Foo* CreateInstance() { 2930d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun// Ptr<Foo> obj = new Foo(); // ref count = 1 3030d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun// return obj.Detach(); 3130d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun// } 3230d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun// }; 3330d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun// typedef Ptr<Foo> FooPtr; // common short-hand notation 3430d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun// FooPtr obj; 3530d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun// obj.Attach(Foo::CreatedInstance()); // ref count = 1 3630d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun// { 3730d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun// FooPtr obj2 = obj; // ref count = 2 3830d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun// } // ref count = 1, obj2 out of scope 3930d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun// obj.Release(); // ref count = 0, object destroyed 4030d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun 4130d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun// Notes on usage: 4230d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun// 1. Virtual inherit from RefCount interface in base class if smart pointers 4330d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun// are going to be defined. 4430d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun// 2. All RefCounted objects must be instantiated on the heap. Allocating the 4530d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun// object on stack will cause crash. 4630d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun// 3. Be careful when you have complex inheritance. For example, 4730d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun// class A : public RefCounted<A>; 4830d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun// class B : public A, public RefCounted<B>; 4930d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun// In this case the smart pointer is pretty dumb and don't count on it to 5030d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun// nicely destroy your objects as designed. Try refactor your code like 5130d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun// class I; // the common interface and implementations 5230d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun// class A : public I, public RefCounted<A>; // A specific implementation 5330d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun// class B : public I, public RefCounted<B>; // B specific implementation 5430d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun// 4. Smart pointers here are very bad candidates for function parameters. Use 5530d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun// dumb pointers in function parameter list. 5630d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun// 5. When down_cast is performed on a dangling pointer due to bugs in code, 5730d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun// VC++ will generate SEH which is not handled well in VC++ debugger. One 5830d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun// can use WinDBG to run it and get the faulting stack. 5930d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun// 6. Idioms for heap object as return value 6030d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun// Foo* createFoo() { FooPtr obj = new Foo(); return obj.Detach(); } 6130d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun// Foo* passthru() { FooPtr obj = createFoo(), return obj; } 6230d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun// FooPtr end_scope_pointer; 6330d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun// end_scope_pointer.Attach(passThrough); 6430d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun// If you are not passing that object back, you are the end of scope. 6530d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun 6630d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#ifndef SFNTLY_CPP_SRC_SFNTLY_PORT_REFCOUNT_H_ 6730d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#define SFNTLY_CPP_SRC_SFNTLY_PORT_REFCOUNT_H_ 6830d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun 6930d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#if !defined (NDEBUG) 7030d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun #define ENABLE_OBJECT_COUNTER 7130d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun// #define REF_COUNT_DEBUGGING 7230d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#endif 7330d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun 7430d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#if defined (REF_COUNT_DEBUGGING) 7530d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun #include <stdio.h> 7630d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun #include <typeinfo> 7730d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#endif 7830d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun 7930d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#include "sfntly/port/atomic.h" 8030d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#include "sfntly/port/type.h" 8130d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun 8230d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun// Special tag for functions that requires caller to attach instead of using 8330d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun// assignment operators. 8430d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#define CALLER_ATTACH 8530d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun 8630d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#if defined (REF_COUNT_DEBUGGING) 8730d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun #define DEBUG_OUTPUT(a) \ 8830d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun fprintf(stderr, "%s%s:oc=%d,oid=%d,rc=%d\n", a, \ 8930d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun typeid(this).name(), object_counter_, object_id_, ref_count_) 9030d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#else 9130d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun #define DEBUG_OUTPUT(a) 9230d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#endif 9330d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun 9430d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#if defined (_MSC_VER) 9530d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun // VC 2008/2010 incorrectly gives this warning for pure virtual functions 9630d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun // in virtual inheritance. The only way to get around it is to disable it. 9730d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun #pragma warning(disable:4250) 9830d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#endif 9930d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun 10030d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurunnamespace sfntly { 10130d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun 10230d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurunclass RefCount { 10330d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun public: 10430d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun // Make gcc -Wnon-virtual-dtor happy. 10530d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun virtual ~RefCount() {} 10630d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun 10730d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun virtual size_t AddRef() const = 0; 10830d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun virtual size_t Release() const = 0; 10930d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun}; 11030d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun 11130d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Guruntemplate <typename T> 11230d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurunclass NoAddRefRelease : public T { 11330d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun public: 11430d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun NoAddRefRelease(); 11530d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun ~NoAddRefRelease(); 11630d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun 11730d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun private: 11830d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun virtual size_t AddRef() const = 0; 11930d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun virtual size_t Release() const = 0; 12030d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun}; 12130d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun 12230d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Guruntemplate <typename TDerived> 12330d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurunclass RefCounted : virtual public RefCount { 12430d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun public: 12530d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun RefCounted() : ref_count_(0) { 12630d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#if defined (ENABLE_OBJECT_COUNTER) 12730d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun object_id_ = AtomicIncrement(&next_id_); 12830d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun AtomicIncrement(&object_counter_); 12930d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun DEBUG_OUTPUT("C "); 13030d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#endif 13130d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun } 13230d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun RefCounted(const RefCounted<TDerived>&) : ref_count_(0) {} 13330d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun virtual ~RefCounted() { 13430d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#if defined (ENABLE_OBJECT_COUNTER) 13530d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun AtomicDecrement(&object_counter_); 13630d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun DEBUG_OUTPUT("D "); 13730d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#endif 13830d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun } 13930d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun 14030d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun RefCounted<TDerived>& operator=(const RefCounted<TDerived>&) { 14130d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun // Each object maintains own ref count, don't propagate. 14230d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun return *this; 14330d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun } 14430d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun 14530d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun virtual size_t AddRef() const { 14630d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun size_t new_count = AtomicIncrement(&ref_count_); 14730d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun DEBUG_OUTPUT("A "); 14830d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun return new_count; 14930d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun } 15030d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun 15130d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun virtual size_t Release() const { 15230d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun size_t new_ref_count = AtomicDecrement(&ref_count_); 15330d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun DEBUG_OUTPUT("R "); 15430d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun if (new_ref_count == 0) { 15530d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun // A C-style is used to cast away const-ness and to derived. 15630d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun // lint does not like this but this is how it works. 15730d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun delete (TDerived*)(this); 15830d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun } 15930d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun return new_ref_count; 16030d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun } 16130d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun 16230d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun mutable size_t ref_count_; // reference count of current object 16330d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#if defined (ENABLE_OBJECT_COUNTER) 16430d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun static size_t object_counter_; 16530d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun static size_t next_id_; 16630d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun mutable size_t object_id_; 16730d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#endif 16830d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun}; 16930d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun 17030d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#if defined (ENABLE_OBJECT_COUNTER) 17130d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Guruntemplate <typename TDerived> size_t RefCounted<TDerived>::object_counter_ = 0; 17230d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Guruntemplate <typename TDerived> size_t RefCounted<TDerived>::next_id_ = 0; 17330d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#endif 17430d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun 17530d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun// semi-smart pointer for RefCount derived objects, similar to CComPtr 17630d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Guruntemplate <typename T> 17730d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurunclass Ptr { 17830d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun public: 17930d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun Ptr() : p_(NULL) { 18030d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun } 18130d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun 18230d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun // This constructor shall not be explicit. 18330d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun // lint does not like this but this is how it works. 18430d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun Ptr(T* pT) : p_(NULL) { 18530d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun *this = pT; 18630d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun } 18730d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun 18830d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun Ptr(const Ptr<T>& p) : p_(NULL) { 18930d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun *this = p; 19030d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun } 19130d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun 19230d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun ~Ptr() { 19330d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun Release(); 19430d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun } 19530d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun 19630d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun T* operator=(T* pT) { 19730d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun if (p_ == pT) { 19830d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun return p_; 19930d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun } 20030d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun if (pT) { 20130d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun RefCount* p = static_cast<RefCount*>(pT); 20230d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun if (p == NULL) { 20330d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun return NULL; 20430d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun } 20530d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun p->AddRef(); // always AddRef() before Release() 20630d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun } 20730d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun Release(); 20830d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun p_ = pT; 20930d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun return p_; 21030d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun } 21130d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun 21230d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun T* operator=(const Ptr<T>& p) { 21330d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun if (p_ == p.p_) { 21430d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun return p_; 21530d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun } 21630d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun return operator=(p.p_); 21730d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun } 21830d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun 21930d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun operator T*&() { 22030d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun return p_; 22130d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun } 22230d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun 22330d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun T& operator*() const { 22430d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun return *p_; // It can throw! 22530d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun } 22630d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun 22730d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun NoAddRefRelease<T>* operator->() const { 22830d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun return (NoAddRefRelease<T>*)p_; // It can throw! 22930d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun } 23030d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun 23130d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun bool operator!() const { 23230d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun return (p_ == NULL); 23330d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun } 23430d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun 23530d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun bool operator<(const Ptr<T>& p) const { 23630d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun return (p_ < p.p_); 23730d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun } 23830d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun 23930d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun bool operator!=(T* pT) const { 24030d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun return !operator==(pT); 24130d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun } 24230d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun 24330d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun bool operator==(T* pT) const { 24430d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun return (p_ == pT); 24530d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun } 24630d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun 24730d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun size_t Release() const { 24830d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun size_t ref_count = 0; 24930d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun if (p_) { 25030d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun RefCount* p = static_cast<RefCount*>(p_); 25130d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun if (p) { 25230d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun ref_count = p->Release(); 25330d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun } 25430d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun p_ = NULL; 25530d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun } 25630d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun return ref_count; 25730d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun } 25830d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun 25930d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun void Attach(T* pT) { 26030d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun if (p_ != pT) { 26130d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun Release(); 26230d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun p_ = pT; 26330d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun } 26430d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun } 26530d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun 26630d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun T* Detach() { 26730d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun T* pT = p_; 26830d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun p_ = NULL; 26930d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun return pT; 27030d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun } 27130d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun 27230d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun mutable T* p_; 27330d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun}; 27430d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun 27530d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun} // namespace sfntly 27630d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun 27730d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#endif // SFNTLY_CPP_SRC_SFNTLY_PORT_REFCOUNT_H_ 278