1 /*---------------------------------------------------------------------------* 2 Project: Horizon 3 File: util_AutoObject.h 4 5 Copyright (C)2009-2012 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: 46347 $ 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 #ifndef 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 private: 203 204 Object* m_P; 205 DecrementAndDelete()206 void DecrementAndDelete() 207 { 208 if (m_P && !detail::AutoObjectCoreAccess::DecrementRefCount(*m_P)) 209 { 210 delete m_P; 211 } 212 } 213 214 #ifndef NN_SWITCH_DISABLE_ASSERT_WARNING 215 AssertNotUpdating()216 void AssertNotUpdating() const 217 { 218 NN_TASSERT_((reinterpret_cast<const uptr&>(m_P) & 1) == 0); 219 } 220 SetUpdating()221 void SetUpdating() 222 { 223 AssertNotUpdating(); 224 reinterpret_cast<uptr&>(m_P) |= 1; 225 } 226 UnsetUpdating()227 void UnsetUpdating() 228 { 229 reinterpret_cast<uptr&>(m_P) &= ~1; 230 } 231 232 #else 233 AssertNotUpdating()234 void AssertNotUpdating() const {} SetUpdating()235 void SetUpdating() {} UnsetUpdating()236 void UnsetUpdating() {} 237 238 #endif 239 240 }; 241 242 } 243 244 }} 245 246 #define NN_UTIL_AUTOOBJECT_BEGIN_DEFINE_DECL_T0(name, ...) \ 247 class name : public ::nn::util::detail::AutoObject<name, __VA_ARGS__ > 248 249 #define NN_UTIL_AUTOOBJECT_BEGIN_DEFINE_DECL_T1(name, ...) \ 250 template <typename NN_UTIL_AUTOOBJECT_T0> \ 251 class name : public ::nn::util::detail::AutoObject<name<NN_UTIL_AUTOOBJECT_T0>, __VA_ARGS__ > 252 253 #define NN_UTIL_AUTOOBJECT_BEGIN_DEFINE_BODY(name, ...) \ 254 { \ 255 private: \ 256 typedef ::nn::util::detail::AutoObject<name, __VA_ARGS__ > Base; \ 257 friend class ::nn::util::detail::AutoObject<name, __VA_ARGS__ >; \ 258 name(__VA_ARGS__* p) : Base(p) {} \ 259 public: \ 260 name(const name& other) : Base(static_cast<const Base&>(other)) {} \ 261 friend name Move(name& _this) { return _this.Release(); } \ 262 name& operator=(const name& rhs) \ 263 { \ 264 return Base::Assign(rhs); \ 265 } \ 266 private: 267 268 #define NN_UTIL_AUTOOBJECT_BEGIN_DEFINE(name, ...) \ 269 NN_UTIL_AUTOOBJECT_BEGIN_DEFINE_DECL_T0(name, __VA_ARGS__) \ 270 NN_UTIL_AUTOOBJECT_BEGIN_DEFINE_BODY(name, __VA_ARGS__) 271 272 #define NN_UTIL_AUTOOBJECT_BEGIN_DEFINE_T1(name, ...) \ 273 NN_UTIL_AUTOOBJECT_BEGIN_DEFINE_DECL_T1(name, __VA_ARGS__) \ 274 NN_UTIL_AUTOOBJECT_BEGIN_DEFINE_BODY(name, __VA_ARGS__) 275 276 #define NN_UTIL_AUTOOBJECT_END_DEFINE \ 277 }; 278 279 #endif 280