1 /*---------------------------------------------------------------------------* 2 Project: Horizon 3 File: util_AutoObject.h 4 5 Copyright (C)2009 Nintendo Co., Ltd. All rights reserved. 6 7 These coded instructions, statements, and computer programs contain 8 proprietary information of Nintendo of America Inc. and/or Nintendo 9 Company Ltd., and are protected by Federal copyright law. They may 10 not be disclosed to third parties or copied or duplicated in any form, 11 in whole or in part, without the prior written consent of Nintendo. 12 13 $Rev: 28252 $ 14 *---------------------------------------------------------------------------*/ 15 16 #ifndef NN_UTIL_UTIL_AUTOOBJECT_H_ 17 #define NN_UTIL_UTIL_AUTOOBJECT_H_ 18 19 #include <nn/util/util_NonCopyable.h> 20 #include <nn/WithInitialize.h> 21 #include <memory> 22 23 namespace nn { namespace util { 24 25 namespace detail 26 { 27 struct AutoObjectCoreAccess; 28 } 29 30 template <typename Int> 31 class ReferenceCounter 32 { 33 friend struct detail::AutoObjectCoreAccess; 34 private: 35 Int m_Value; 36 protected: ReferenceCounter()37 ReferenceCounter() : m_Value(1) { NN_LOG_DEBUG("ctor0\n"); } ReferenceCounter(const ReferenceCounter &)38 ReferenceCounter(const ReferenceCounter&) : m_Value(1) { NN_LOG_DEBUG("copy\n"); } ~ReferenceCounter()39 ~ReferenceCounter() { NN_TASSERT_(m_Value == 0); NN_LOG_DEBUG("dtor\n"); } 40 ReferenceCounter& operator=(const ReferenceCounter& rhs) 41 { 42 if (this != &rhs) 43 { 44 NN_TASSERT_(m_Value == 0); 45 m_Value = 1; 46 }; 47 return *this; 48 } 49 private: IncrementRefCount()50 void IncrementRefCount() { ++m_Value; NN_LOG_DEBUG("inc\n"); } DecrementRefCount()51 bool DecrementRefCount() { NN_LOG_DEBUG("dec\n"); return --m_Value > 0; } TryDecrementRefCount()52 bool TryDecrementRefCount() { return (m_Value > 1) && (--m_Value, NN_LOG_DEBUG("trydec\n"), true); } 53 public: GetReferenceCounter()54 Int GetReferenceCounter() const { return m_Value; } 55 }; 56 57 namespace detail 58 { 59 60 struct AutoObjectCoreAccess 61 { 62 template <typename ReferenceCounter> IncrementRefCountAutoObjectCoreAccess63 static void IncrementRefCount(ReferenceCounter& r) { r.IncrementRefCount(); } 64 template <typename ReferenceCounter> DecrementRefCountAutoObjectCoreAccess65 static bool DecrementRefCount(ReferenceCounter& r) { return r.DecrementRefCount(); } 66 template <typename ReferenceCounter> TryDecrementRefCountAutoObjectCoreAccess67 static bool TryDecrementRefCount(ReferenceCounter& r) { return r.TryDecrementRefCount(); } 68 }; 69 70 template <class Self, class TObject> 71 class AutoObject 72 { 73 protected: 74 75 typedef TObject Object; 76 77 AutoObject()78 AutoObject() : m_P(0) {} 79 AutoObject(const nn::WithInitialize &)80 AutoObject(const nn::WithInitialize&) : m_P(new Object()) {} 81 82 template <class T> AutoObject(const T & x)83 AutoObject(const T& x) : m_P(new Object(x)) {} 84 AutoObject(const AutoObject & other)85 AutoObject(const AutoObject& other) : m_P(other.m_P) 86 { 87 other.AssertNotUpdating(); 88 if (m_P) 89 { 90 detail::AutoObjectCoreAccess::IncrementRefCount(*m_P); 91 } 92 } 93 ~AutoObject()94 ~AutoObject() 95 { 96 AssertNotUpdating(); 97 DecrementAndDelete(); 98 } 99 Assign(const Self & rhs)100 Self& Assign(const Self& rhs) 101 { 102 AssertNotUpdating(); 103 rhs.AssertNotUpdating(); 104 if (this != &rhs && m_P != rhs.m_P) 105 { 106 DecrementAndDelete(); 107 this->m_P = rhs.m_P; 108 if (m_P) 109 { 110 detail::AutoObjectCoreAccess::IncrementRefCount(*m_P); 111 } 112 } 113 return static_cast<Self&>(*this); 114 } 115 Clear()116 void Clear() 117 { 118 AssertNotUpdating(); 119 DecrementAndDelete(); 120 this->m_P = 0; 121 } 122 123 const Object& operator*() const 124 { 125 NN_TASSERT_(IsValid()); 126 AssertNotUpdating(); 127 return *m_P; 128 } 129 130 const Object* operator->() const 131 { 132 NN_TASSERT_(IsValid()); 133 AssertNotUpdating(); 134 return m_P; 135 } 136 IsValid()137 bool IsValid() const 138 { 139 return m_P != 0; 140 } 141 142 friend class Updater; 143 144 class Updater 145 { 146 private: 147 148 AutoObject& m_AutoObject; 149 150 #ifdef NN_SWITCH_DISABLE_ASSERT_WARNING GetObject()151 Object* GetObject() { return reinterpret_cast<Object*>(reinterpret_cast<uptr>(m_AutoObject.m_P) & ~1); } 152 #else GetObject()153 Object* GetObject() { return m_AutoObject.m_P; } 154 #endif 155 156 public: 157 Updater(AutoObject & autoObject)158 Updater(AutoObject& autoObject) : m_AutoObject(autoObject) 159 { 160 NN_TASSERT_(autoObject.IsValid()); 161 if (detail::AutoObjectCoreAccess::DecrementRefCount(*autoObject.m_P)) 162 { 163 autoObject.m_P = new Object(*autoObject); 164 } 165 else 166 { 167 detail::AutoObjectCoreAccess::IncrementRefCount(*autoObject.m_P); 168 } 169 autoObject.SetUpdating(); 170 } 171 ~Updater()172 ~Updater() { m_AutoObject.UnsetUpdating(); } 173 174 Object& operator*() 175 { 176 return *GetObject(); 177 } 178 179 Object* operator->() 180 { 181 return GetObject(); 182 } 183 }; 184 AutoObject(Object * p)185 AutoObject(Object* p) : m_P(p) {} 186 Release()187 Object* Release() 188 { 189 AssertNotUpdating(); 190 Object* p = m_P; 191 this->m_P = 0; 192 if (!detail::AutoObjectCoreAccess::TryDecrementRefCount(*p)) 193 { 194 return p; 195 } 196 else 197 { 198 return new Object(*p); 199 } 200 } 201 202 public: GetObject()203 Object* GetObject() { return m_P; } 204 205 private: 206 207 Object* m_P; 208 DecrementAndDelete()209 void DecrementAndDelete() 210 { 211 if (m_P && !detail::AutoObjectCoreAccess::DecrementRefCount(*m_P)) 212 { 213 delete m_P; 214 } 215 } 216 217 #ifdef NN_SWITCH_DISABLE_ASSERT_WARNING 218 AssertNotUpdating()219 void AssertNotUpdating() const 220 { 221 NN_TASSERT_((reinterpret_cast<const uptr&>(m_P) & 1) == 0); 222 } 223 SetUpdating()224 void SetUpdating() 225 { 226 AssertNotUpdating(); 227 reinterpret_cast<uptr&>(m_P) |= 1; 228 } 229 UnsetUpdating()230 void UnsetUpdating() 231 { 232 reinterpret_cast<uptr&>(m_P) &= ~1; 233 } 234 235 #else 236 AssertNotUpdating()237 void AssertNotUpdating() const {} SetUpdating()238 void SetUpdating() {} UnsetUpdating()239 void UnsetUpdating() {} 240 241 #endif 242 243 }; 244 245 } 246 247 }} 248 249 #define NN_UTIL_AUTOOBJECT_BEGIN_DEFINE_DECL_T0(name, ...) \ 250 class name : public ::nn::util::detail::AutoObject<name, __VA_ARGS__ > 251 252 #define NN_UTIL_AUTOOBJECT_BEGIN_DEFINE_DECL_T1(name, ...) \ 253 template <typename NN_UTIL_AUTOOBJECT_T0> \ 254 class name : public ::nn::util::detail::AutoObject<name<NN_UTIL_AUTOOBJECT_T0>, __VA_ARGS__ > 255 256 #define NN_UTIL_AUTOOBJECT_BEGIN_DEFINE_BODY(name, ...) \ 257 { \ 258 private: \ 259 typedef ::nn::util::detail::AutoObject<name, __VA_ARGS__ > Base; \ 260 friend class ::nn::util::detail::AutoObject<name, __VA_ARGS__ >; \ 261 name(__VA_ARGS__* p) : Base(p) {} \ 262 public: \ 263 name(const name& other) : Base(static_cast<const Base&>(other)) {} \ 264 friend name Move(name& _this) { return _this.Release(); } \ 265 name& operator=(const name& rhs) \ 266 { \ 267 return Base::Assign(rhs); \ 268 } \ 269 private: 270 271 #define NN_UTIL_AUTOOBJECT_BEGIN_DEFINE(name, ...) \ 272 NN_UTIL_AUTOOBJECT_BEGIN_DEFINE_DECL_T0(name, __VA_ARGS__) \ 273 NN_UTIL_AUTOOBJECT_BEGIN_DEFINE_BODY(name, __VA_ARGS__) 274 275 #define NN_UTIL_AUTOOBJECT_BEGIN_DEFINE_T1(name, ...) \ 276 NN_UTIL_AUTOOBJECT_BEGIN_DEFINE_DECL_T1(name, __VA_ARGS__) \ 277 NN_UTIL_AUTOOBJECT_BEGIN_DEFINE_BODY(name, __VA_ARGS__) 278 279 #define NN_UTIL_AUTOOBJECT_END_DEFINE \ 280 }; 281 282 #endif 283