View Issue Details
| ID | Project | Category | View Status | Date Submitted | Last Update |
|---|---|---|---|---|---|
| 0001232 | NoesisGUI | C++ SDK | public | 2018-02-06 05:16 | 2022-11-02 11:59 |
| Reporter | nikobarli | Assigned To | jsantos | ||
| Priority | normal | Severity | feature | ||
| Status | assigned | Resolution | open | ||
| Product Version | 2.1.0rc2 | ||||
| Summary | 0001232: Weak pointer support | ||||
| Description | This is follow up for the meeting with Jesus on Feb 1, 2018. We feel that we sometimes need weak pointer to manage resources. Please consider adding this feature back in the future. | ||||
| Platform | Any | ||||
|
I am attaching a potential implementation for weak pointers in Noesis. We have plans to officially implement this in the future although we need more discussions. BaseRefCounted.cpp.patch (2,211 bytes)
Index: BaseRefCounted.cpp
===================================================================
--- BaseRefCounted.cpp (revision 11648)
+++ BaseRefCounted.cpp (working copy)
@@ -6,12 +6,72 @@
#include <NsCore/BaseRefCounted.h>
#include <NsCore/ReflectionImplementEmpty.h>
+#include <NsCore/HashMap.h>
+#include <NsCore/Ptr.h>
+#include <NsCore/SpinMutex.h>
using namespace Noesis;
+static SpinMutex gHandlesMutex;
+static AtomicInteger gHandlesCounter;
+static HashMap<uint32_t, BaseRefCounted*> gHandlesMap;
+
+
////////////////////////////////////////////////////////////////////////////////////////////////////
+BaseRefCounted::~BaseRefCounted()
+{
+ NS_CHECK([&]()
+ {
+ // Note that 1 is valid when the object lives is the stack or is being manually destroyed
+ int32_t n = mRefCount.Load();
+ NS_CHECK(n == 1 || n == 0, "Unexpected RefCount(%d) deleting object at %p", n, this);
+ return true;
+ }
+ (), "");
+
+ if (mHandle != 0)
+ {
+ SpinMutex::ScopedLock lock(gHandlesMutex);
+ gHandlesMap.Erase(mHandle);
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+uint32_t BaseRefCounted::GetHandle()
+{
+ if (mHandle == 0)
+ {
+ mHandle = gHandlesCounter.IncrementAndFetch();
+
+ SpinMutex::ScopedLock lock(gHandlesMutex);
+ gHandlesMap.Insert(mHandle, this);
+ }
+
+ return mHandle;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+Ptr<BaseRefCounted> BaseRefCounted::FromHandle(uint32_t handle)
+{
+ SpinMutex::ScopedLock lock(gHandlesMutex);
+ auto it = gHandlesMap.Find(handle);
+
+ if (it != gHandlesMap.End())
+ {
+ uint32_t refs = it->value->mRefCount.IncrementAndFetch();
+
+ if (refs > 1)
+ {
+ return Ptr<BaseRefCounted>(*it->value);
+ }
+ }
+
+ return nullptr;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
NS_BEGIN_COLD_REGION
NS_IMPLEMENT_REFLECTION_(BaseRefCounted)
BaseRefCounted.h.patch (1,197 bytes)
Index: BaseRefCounted.h
===================================================================
--- BaseRefCounted.h (revision 11648)
+++ BaseRefCounted.h (working copy)
@@ -28,6 +28,7 @@
#define NS_BASEREFCOUNTED_OVERRIDABLE
#endif
+template<class T> class Ptr;
////////////////////////////////////////////////////////////////////////////////////////////////////
/// Base class for types that control their lifetime with a reference counter. Instances of this
@@ -65,6 +66,12 @@
/// Gets current reference count for the object
int32_t GetNumReferences() const;
+ /// Returns a handle for the object. Handles are weak references
+ uint32_t GetHandle();
+
+ /// Retrieves the object referenced by the handle or nullptr if it was already destroyed
+ static Ptr<BaseRefCounted> FromHandle(uint32_t handle);
+
protected:
/// Invoked when the reference counter reaches 0. By default the instance is deleted
/// Can be reimplemented by child classes to avoid the default destruction
@@ -73,6 +80,7 @@
private:
AtomicInteger mRefCount;
+ uint32_t mHandle;
NS_DECLARE_REFLECTION(BaseRefCounted, BaseObject)
};
BaseRefCounted.inl.patch (1,074 bytes)
Index: BaseRefCounted.inl
===================================================================
--- BaseRefCounted.inl (revision 11648)
+++ BaseRefCounted.inl (working copy)
@@ -12,19 +12,11 @@
////////////////////////////////////////////////////////////////////////////////////////////////////
-inline BaseRefCounted::BaseRefCounted(): mRefCount(1)
+inline BaseRefCounted::BaseRefCounted(): mRefCount(1), mHandle(0)
{
}
////////////////////////////////////////////////////////////////////////////////////////////////////
-inline BaseRefCounted::~BaseRefCounted()
-{
- // Note that 1 is valid when the object lives is the stack or is being manually destroyed
- int32_t refs = mRefCount.Load();
- NS_CHECK(refs == 1 || refs == 0, "Unexpected RefCount(%d) deleting object at %p", refs, this);
-}
-
-////////////////////////////////////////////////////////////////////////////////////////////////////
inline int32_t BaseRefCounted::AddReference() const
{
return const_cast<BaseRefCounted*>(this)->mRefCount.IncrementAndFetch();
|
|
|
The patch looks promising. There is a concern in the way the handles are generated, which seems to be done by simply incrementing a global counter (int32) without reuse. In case when application up time is long and handle generation occurs frequently, this could possibly lead to an overflow (duplicated handles). |
|
|
You are right about that potential handle collision. The alternative could be using 64-bit handles and user the pointer itself as handle. But that is also dangerous. And alternative is using the 32 bits for a global counter and the lower 32 bits filled with a hash of the pointer. With this, the chances of collision are almost impossible. |
|
| Date Modified | Username | Field | Change |
|---|---|---|---|
| 2018-02-06 05:16 | nikobarli | New Issue | |
| 2018-11-01 02:14 | jsantos | View Status | public => private |
| 2018-11-22 09:36 | sfernandez | Assigned To | => jsantos |
| 2018-11-22 09:36 | sfernandez | Status | new => assigned |
| 2018-11-22 09:36 | sfernandez | View Status | private => public |
| 2018-11-22 09:36 | sfernandez | Platform | => Any |
| 2022-10-24 12:51 | jsantos | Note Added: 0008105 | |
| 2022-10-24 12:51 | jsantos | File Added: BaseRefCounted.cpp.patch | |
| 2022-10-24 12:51 | jsantos | File Added: BaseRefCounted.h.patch | |
| 2022-10-24 12:51 | jsantos | File Added: BaseRefCounted.inl.patch | |
| 2022-10-24 12:51 | jsantos | Note Edited: 0008105 | |
| 2022-10-24 12:51 | jsantos | Note Edited: 0008105 | |
| 2022-10-26 07:01 | satorp | Note Added: 0008106 | |
| 2022-11-02 11:59 | jsantos | Note Added: 0008110 |