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