flatten 20260225
This commit is contained in:
18
tjp/core/ptr/Ptr+IO.h
Executable file
18
tjp/core/ptr/Ptr+IO.h
Executable file
@@ -0,0 +1,18 @@
|
||||
// License: Modified MIT (NON-AI)
|
||||
// See the LICENSE file in the root directory for license information.
|
||||
// Copyright 2025 Timothy Prepscius
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Ptr+Version.h"
|
||||
|
||||
#if defined(USING_PTR_MAPS)
|
||||
#include "using_maps/Ptr+IO.h"
|
||||
|
||||
#elif defined(USING_PTR_INFO)
|
||||
#include "using_info/Ptr+IO.h"
|
||||
|
||||
#elif defined(USING_PTR_STD)
|
||||
#include "std/Ptr+IO.h"
|
||||
|
||||
#endif
|
||||
32
tjp/core/ptr/Ptr+Log.hpp
Executable file
32
tjp/core/ptr/Ptr+Log.hpp
Executable file
@@ -0,0 +1,32 @@
|
||||
// License: Modified MIT (NON-AI)
|
||||
// See the LICENSE file in the root directory for license information.
|
||||
// Copyright 2025 Timothy Prepscius
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Ptr+Version.h"
|
||||
|
||||
#if defined(USING_PTR_MAPS)
|
||||
#include "using_maps/Ptr+Log.h"
|
||||
|
||||
#elif defined(USING_PTR_INFO)
|
||||
#include "using_info/Ptr+Log.h"
|
||||
|
||||
#elif defined(USING_PTR_STD)
|
||||
#include "std/Ptr+Log.h"
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
namespace tjp::core {
|
||||
|
||||
#if defined(USING_PTR_MAPS)
|
||||
using namespace ptr::using_maps;
|
||||
|
||||
#elif defined(USING_PTR_INFO)
|
||||
using namespace ptr::using_info;
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
} // namespace
|
||||
9
tjp/core/ptr/Ptr+Version.h
Executable file
9
tjp/core/ptr/Ptr+Version.h
Executable file
@@ -0,0 +1,9 @@
|
||||
// License: Modified MIT (NON-AI)
|
||||
// See the LICENSE file in the root directory for license information.
|
||||
// Copyright 2025 Timothy Prepscius
|
||||
|
||||
#pragma once
|
||||
|
||||
//#define USING_PTR_MAPS
|
||||
//#define USING_PTR_INFO
|
||||
#define USING_PTR_STD
|
||||
49
tjp/core/ptr/Ptr.h
Executable file
49
tjp/core/ptr/Ptr.h
Executable file
@@ -0,0 +1,49 @@
|
||||
// License: Modified MIT (NON-AI)
|
||||
// See the LICENSE file in the root directory for license information.
|
||||
// Copyright 2025 Timothy Prepscius
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Ptr+Version.h"
|
||||
|
||||
#include "../system/Debug.h"
|
||||
|
||||
#if defined(USING_PTR_MAPS)
|
||||
#include "using_maps/Ptr.h"
|
||||
|
||||
#elif defined(USING_PTR_INFO)
|
||||
#include "using_info/Ptr.h"
|
||||
|
||||
#elif defined(USING_PTR_STD)
|
||||
#include "std/Ptr.h"
|
||||
|
||||
#elif
|
||||
#error
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
namespace tjp {
|
||||
namespace core {
|
||||
namespace ptr {
|
||||
|
||||
#if defined(USING_PTR_MAPS)
|
||||
using namespace using_maps;
|
||||
|
||||
#elif defined(USING_PTR_INFO)
|
||||
using namespace using_info;
|
||||
|
||||
#elif defined(USING_PTR_INFO)
|
||||
using namespace using_info;
|
||||
|
||||
#elif defined(USING_PTR_STD)
|
||||
using namespace using_std;
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace ptr
|
||||
|
||||
using namespace ptr;
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
42
tjp/core/ptr/Ptr.hpp
Executable file
42
tjp/core/ptr/Ptr.hpp
Executable file
@@ -0,0 +1,42 @@
|
||||
// License: Modified MIT (NON-AI)
|
||||
// See the LICENSE file in the root directory for license information.
|
||||
// Copyright 2025 Timothy Prepscius
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Ptr+Version.h"
|
||||
|
||||
#include "../system/Debug.h"
|
||||
#include "Ptr.h"
|
||||
|
||||
#if defined(USING_PTR_MAPS)
|
||||
#include "using_maps/Ptr.hpp"
|
||||
#include "using_maps/Ptr+Log.h"
|
||||
|
||||
#elif defined(USING_PTR_INFO)
|
||||
#include "using_info/Ptr.hpp"
|
||||
#include "using_info/Ptr+Log.h"
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
namespace tjp {
|
||||
namespace core {
|
||||
namespace ptr {
|
||||
|
||||
#if defined(USING_PTR_MAPS)
|
||||
using namespace using_maps;
|
||||
|
||||
#elif defined(USING_PTR_INFO)
|
||||
using namespace using_info;
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace
|
||||
|
||||
using namespace ptr;
|
||||
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
||||
152
tjp/core/ptr/_tests/Ptr.cpp
Executable file
152
tjp/core/ptr/_tests/Ptr.cpp
Executable file
@@ -0,0 +1,152 @@
|
||||
// License: Modified MIT (NON-AI)
|
||||
// See the LICENSE file in the root directory for license information.
|
||||
// Copyright 2025 Timothy Prepscius
|
||||
|
||||
#include <tjp/core/ptr/Ptr.hpp>
|
||||
#include <tjp/core/ptr/Ptr+IO.h>
|
||||
|
||||
#include <tjp/core/testing/catch.hpp>
|
||||
#include <tjp/core/testing/NO_WHEN.h>
|
||||
|
||||
//#include "std/CustomControlBlock.h"
|
||||
|
||||
namespace tjp {
|
||||
namespace core {
|
||||
|
||||
namespace memory {
|
||||
namespace test_compile {
|
||||
|
||||
struct A
|
||||
{
|
||||
int i;
|
||||
|
||||
~A ()
|
||||
{
|
||||
i = 2;
|
||||
}
|
||||
} ;
|
||||
|
||||
struct B
|
||||
{
|
||||
static int allocations;
|
||||
int x = 5;
|
||||
B () {
|
||||
allocations++;
|
||||
}
|
||||
~B () {
|
||||
allocations--;
|
||||
}
|
||||
};
|
||||
|
||||
int B::allocations = 0;
|
||||
|
||||
int num_c_deallocations = 0;
|
||||
int num_c_destroys = 0;
|
||||
|
||||
struct C
|
||||
{
|
||||
int x= 5;
|
||||
|
||||
~C ()
|
||||
{
|
||||
num_c_destroys++;
|
||||
x = 2;
|
||||
}
|
||||
} ;
|
||||
|
||||
|
||||
void on_deallocate(C *p)
|
||||
{
|
||||
num_c_deallocations++;
|
||||
}
|
||||
|
||||
struct CustomDeleter : StrongThis<CustomDeleter>
|
||||
{
|
||||
int called = 0;
|
||||
|
||||
template<typename T>
|
||||
void deallocate(T *t)
|
||||
{
|
||||
called++;
|
||||
delete t;
|
||||
}
|
||||
} ;
|
||||
|
||||
SCENARIO("core::ptr")
|
||||
{
|
||||
GIVEN("a ptr to normal")
|
||||
{
|
||||
WHEN("a ptr is created normal")
|
||||
{
|
||||
B::allocations = 0;
|
||||
|
||||
auto ptr = strong<B>();
|
||||
REQUIRE(B::allocations == 1);
|
||||
ptr = nullptr;
|
||||
|
||||
REQUIRE(B::allocations == 0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
GIVEN("a ptr")
|
||||
{
|
||||
WHEN("a ptr is created normal")
|
||||
{
|
||||
num_c_deallocations = num_c_destroys = 0;
|
||||
|
||||
auto ptr = strong<C>();
|
||||
ptr = nullptr;
|
||||
|
||||
REQUIRE(num_c_deallocations == 1);
|
||||
REQUIRE(num_c_destroys == 1);
|
||||
}
|
||||
|
||||
WHEN("a ptr is created with a custom deleter")
|
||||
{
|
||||
CustomDeleter deleter;
|
||||
|
||||
num_c_deallocations = num_c_destroys = 0;
|
||||
|
||||
auto ptr = strong_with_delete<C>(
|
||||
new C(), [&](C *t) { deleter.deallocate(t); }
|
||||
);
|
||||
ptr = nullptr;
|
||||
|
||||
REQUIRE(num_c_deallocations == 1);
|
||||
REQUIRE(num_c_destroys == 1);
|
||||
REQUIRE(deleter.called == 1);
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("a ptr with a custom deleter")
|
||||
{
|
||||
CustomDeleter deleter;
|
||||
|
||||
WHEN("create a pointer")
|
||||
{
|
||||
auto a = strong_with_delete<A>(
|
||||
new A(), [&](A *t) { deleter.deallocate(t); }
|
||||
);
|
||||
|
||||
WHEN("transfer the pointer elsewherez")
|
||||
{
|
||||
auto b = a;
|
||||
a = nullptr;
|
||||
|
||||
WHEN("nullify the pointer")
|
||||
{
|
||||
b = nullptr;
|
||||
|
||||
REQUIRE(deleter.called == 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
63
tjp/core/ptr/std/CustomControlBlock.h
Executable file
63
tjp/core/ptr/std/CustomControlBlock.h
Executable file
@@ -0,0 +1,63 @@
|
||||
// License: Modified MIT (NON-AI)
|
||||
// See the LICENSE file in the root directory for license information.
|
||||
// Copyright 2025 Timothy Prepscius
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace tjp::core::ptr::using_std {
|
||||
|
||||
template <class _Tp, class _Dp, class _Alloc>
|
||||
class CustomControlBlock1
|
||||
: public std::__shared_weak_count
|
||||
{
|
||||
std::__compressed_pair<std::__compressed_pair<_Tp, _Dp>, _Alloc> __data_;
|
||||
public:
|
||||
_LIBCPP_INLINE_VISIBILITY
|
||||
CustomControlBlock1(_Tp __p, _Dp __d, _Alloc __a)
|
||||
: __data_(std::__compressed_pair<_Tp, _Dp>(__p, _VSTD::move(__d)), _VSTD::move(__a)) {}
|
||||
|
||||
#ifndef _LIBCPP_NO_RTTI
|
||||
virtual const void* __get_deleter(const std::type_info&) const _NOEXCEPT;
|
||||
#endif
|
||||
|
||||
private:
|
||||
virtual void __on_zero_shared() _NOEXCEPT;
|
||||
virtual void __on_zero_shared_weak() _NOEXCEPT;
|
||||
};
|
||||
|
||||
#ifndef _LIBCPP_NO_RTTI
|
||||
|
||||
template <class _Tp, class _Dp, class _Alloc>
|
||||
const void*
|
||||
CustomControlBlock1<_Tp, _Dp, _Alloc>::__get_deleter(const std::type_info& __t) const _NOEXCEPT
|
||||
{
|
||||
return __t == typeid(_Dp) ? _VSTD::addressof(__data_.first().second()) : nullptr;
|
||||
}
|
||||
|
||||
#endif // _LIBCPP_NO_RTTI
|
||||
|
||||
template <class _Tp, class _Dp, class _Alloc>
|
||||
void
|
||||
CustomControlBlock1<_Tp, _Dp, _Alloc>::__on_zero_shared() _NOEXCEPT
|
||||
{
|
||||
__data_.first().second()(__data_.first().first());
|
||||
__data_.first().second().~_Dp();
|
||||
}
|
||||
|
||||
template <class _Tp, class _Dp, class _Alloc>
|
||||
void
|
||||
CustomControlBlock1<_Tp, _Dp, _Alloc>::__on_zero_shared_weak() _NOEXCEPT
|
||||
{
|
||||
typedef typename std::__allocator_traits_rebind<_Alloc, CustomControlBlock1>::type _Al;
|
||||
typedef std::allocator_traits<_Al> _ATraits;
|
||||
typedef std::pointer_traits<typename _ATraits::pointer> _PTraits;
|
||||
|
||||
_Al __a(__data_.second());
|
||||
__data_.second().~_Alloc();
|
||||
// __a.deallocate(_PTraits::pointer_to(*this), 1);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
12
tjp/core/ptr/std/Ptr+Debug.h
Executable file
12
tjp/core/ptr/std/Ptr+Debug.h
Executable file
@@ -0,0 +1,12 @@
|
||||
// License: Modified MIT (NON-AI)
|
||||
// See the LICENSE file in the root directory for license information.
|
||||
// Copyright 2025 Timothy Prepscius
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef DEBUG
|
||||
#define MEMORY_PTR_DEBUG_TYPE
|
||||
#endif
|
||||
|
||||
#define MEMORY_PTR_DEBUG_ALLOCATIONS
|
||||
#define LOG_MEMORY_PTR
|
||||
129
tjp/core/ptr/std/Ptr+GCC.h
Executable file
129
tjp/core/ptr/std/Ptr+GCC.h
Executable file
@@ -0,0 +1,129 @@
|
||||
// License: Modified MIT (NON-AI)
|
||||
// See the LICENSE file in the root directory for license information.
|
||||
// Copyright 2025 Timothy Prepscius
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace tjp::core::ptr::using_std {
|
||||
|
||||
template<typename T, typename A>
|
||||
class StrongPtrAllocator
|
||||
{
|
||||
public:
|
||||
typedef A Allocator;
|
||||
typedef size_t size_type;
|
||||
typedef std::ptrdiff_t difference_type;
|
||||
typedef T* pointer;
|
||||
typedef const T* const_pointer;
|
||||
typedef T& reference;
|
||||
typedef const T& const_reference;
|
||||
typedef T value_type;
|
||||
|
||||
public:
|
||||
template<typename _Tp1> struct rebind {
|
||||
typedef StrongPtrAllocator<
|
||||
_Tp1,
|
||||
typename A::template rebind<_Tp1>::other
|
||||
> other;
|
||||
};
|
||||
|
||||
Allocator allocator;
|
||||
|
||||
public:
|
||||
StrongPtrAllocator() {}
|
||||
StrongPtrAllocator (const StrongPtrAllocator &) {}
|
||||
~StrongPtrAllocator () {}
|
||||
|
||||
template <class _Up>
|
||||
StrongPtrAllocator (const _Up &) { }
|
||||
|
||||
T *allocate (size_t size)
|
||||
{
|
||||
return allocator.allocate(size);
|
||||
}
|
||||
|
||||
void deallocate(T *t, size_t size)
|
||||
{
|
||||
return allocator.deallocate(t, size);
|
||||
}
|
||||
|
||||
void construct(pointer __p)
|
||||
{
|
||||
return allocator.construct(__p);
|
||||
}
|
||||
|
||||
template<typename U, typename... Args>
|
||||
void construct(U* p, Args&&... args)
|
||||
{
|
||||
allocator.construct(p, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
void destroy(pointer p)
|
||||
{
|
||||
deallocate_detail(p);
|
||||
allocator.destroy(p);
|
||||
}
|
||||
|
||||
template<typename U>
|
||||
void destroy(U* p)
|
||||
{
|
||||
deallocate_detail(p);
|
||||
allocator.destroy(p);
|
||||
}
|
||||
} ;
|
||||
|
||||
template<typename T, typename ... Args>
|
||||
auto strong_no_deallocate(Args && ...args)
|
||||
{
|
||||
return std::make_shared<T>(
|
||||
std::forward<Args>(args)...
|
||||
);
|
||||
}
|
||||
|
||||
template<typename T, typename ... Args>
|
||||
auto strong_with_deallocate(Args && ...args)
|
||||
{
|
||||
return std::allocate_shared<T>(
|
||||
StrongPtrAllocator<T, std::allocator<T>>(),
|
||||
std::forward<Args>(args)...
|
||||
);
|
||||
}
|
||||
|
||||
template<typename T, typename ... Args>
|
||||
auto strong(Args && ...args)
|
||||
{
|
||||
if constexpr (type_has_deallocate<T>::value) {
|
||||
return strong_with_deallocate<T>(
|
||||
std::forward<Args>(args)...
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
return strong_no_deallocate<T>(
|
||||
std::forward<Args>(args)...
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T, typename F>
|
||||
auto strong_with_delete(T *ptr, F &&f)
|
||||
{
|
||||
return std::shared_ptr<T>(
|
||||
ptr,
|
||||
makeDeleterWithFunction<T>(std::move(f))
|
||||
);
|
||||
}
|
||||
|
||||
template<typename T, typename Allocator, typename ...Args>
|
||||
auto strong_with_allocator(Allocator allocator, Args&& ...args)
|
||||
{
|
||||
return std::allocate_shared<T>(
|
||||
StrongPtrAllocator<T, Allocator> { allocator },
|
||||
std::forward<Args>(args)...
|
||||
);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
34
tjp/core/ptr/std/Ptr+IO.h
Executable file
34
tjp/core/ptr/std/Ptr+IO.h
Executable file
@@ -0,0 +1,34 @@
|
||||
// License: Modified MIT (NON-AI)
|
||||
// See the LICENSE file in the root directory for license information.
|
||||
// Copyright 2025 Timothy Prepscius
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace std {
|
||||
|
||||
template<typename IO, typename T>
|
||||
void io_ptr_allocate(IO &io, shared_ptr<T> &ptr)
|
||||
{
|
||||
io.allocate(ptr);
|
||||
}
|
||||
|
||||
template<typename IO, typename T>
|
||||
void io_ptr_allocate_default(IO &io, shared_ptr<T> &ptr)
|
||||
{
|
||||
ptr = tjp::core::ptr::using_std::strong<T>();
|
||||
}
|
||||
|
||||
template<typename IO, typename T>
|
||||
void io_w(IO &io, const shared_ptr<T> &r)
|
||||
{
|
||||
io.any(tjp::core::ptr::using_std::ptr_of(r));
|
||||
}
|
||||
|
||||
template<typename IO, typename T>
|
||||
void io_r(IO &io, shared_ptr<T> &t)
|
||||
{
|
||||
auto p = io.template pointer<T>(t);
|
||||
io.any(p);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
78
tjp/core/ptr/std/Ptr+LLVM.h
Executable file
78
tjp/core/ptr/std/Ptr+LLVM.h
Executable file
@@ -0,0 +1,78 @@
|
||||
// License: Modified MIT (NON-AI)
|
||||
// See the LICENSE file in the root directory for license information.
|
||||
// Copyright 2025 Timothy Prepscius
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
namespace tjp::core::ptr::using_std {
|
||||
|
||||
template<typename T, typename ... Args>
|
||||
auto strong_no_deallocate(Args && ...args)
|
||||
{
|
||||
return std::make_shared<T>(
|
||||
std::forward<Args>(args)...
|
||||
);
|
||||
}
|
||||
|
||||
template<typename T, typename ... Args>
|
||||
auto strong_with_deallocate(Args && ...args)
|
||||
{
|
||||
return std::shared_ptr<T>(
|
||||
new T(std::forward<Args>(args)...),
|
||||
makeDeleter<T>()
|
||||
);
|
||||
}
|
||||
|
||||
template<typename T, typename ... Args>
|
||||
auto strong(Args && ...args)
|
||||
{
|
||||
if constexpr (type_has_deallocate<T>::value) {
|
||||
return strong_with_deallocate<T>(
|
||||
std::forward<Args>(args)...
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
return strong_no_deallocate<T>(
|
||||
std::forward<Args>(args)...
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T, typename F>
|
||||
auto strong_with_delete(T *ptr, F &&f)
|
||||
{
|
||||
return std::shared_ptr<T>(
|
||||
ptr,
|
||||
makeDeleterWithFunction<T>(std::move(f))
|
||||
);
|
||||
}
|
||||
|
||||
template<typename T, typename Allocator, typename ... Args>
|
||||
auto strong_with_allocator(Allocator allocator, Args && ...args)
|
||||
{
|
||||
auto ptr = allocator.allocate(1);
|
||||
allocator.construct(ptr, std::forward<Args>(args)...);
|
||||
|
||||
auto f = makeDeleterWithAllocator<T>(allocator);
|
||||
typedef decltype(f) F;
|
||||
|
||||
typedef T *Tp;
|
||||
typedef std::__shared_ptr_pointer<Tp, F, Allocator> TControlBlock;
|
||||
using ControlBlockAllocator = typename Allocator::template rebind<TControlBlock>::other;
|
||||
|
||||
#ifdef _DEBUG
|
||||
auto controlBlockSize = sizeof(TControlBlock);
|
||||
(void)controlBlockSize;
|
||||
#endif
|
||||
|
||||
ControlBlockAllocator controlBlockAllocator;
|
||||
auto ctrl = controlBlockAllocator.allocate(1);
|
||||
controlBlockAllocator.construct(ctrl, ptr, f, allocator);
|
||||
|
||||
return std::shared_ptr<T>::__create_with_control_block(ptr, ctrl);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
38
tjp/core/ptr/std/Ptr+Log.h
Executable file
38
tjp/core/ptr/std/Ptr+Log.h
Executable file
@@ -0,0 +1,38 @@
|
||||
// License: Modified MIT (NON-AI)
|
||||
// See the LICENSE file in the root directory for license information.
|
||||
// Copyright 2025 Timothy Prepscius
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../../log/LogOf.h"
|
||||
#include "Ptr.h"
|
||||
|
||||
namespace std {
|
||||
|
||||
template<typename T>
|
||||
auto logOf(const std::shared_ptr<T> &v)
|
||||
{
|
||||
return tjp::core::logPtrValue(tjp::core::ptr::using_std::ptr_of(v));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
auto logOf(const std::weak_ptr<T> &v)
|
||||
{
|
||||
return tjp::core::logPtrValue(tjp::core::ptr::using_std::ptr_of(tjp::core::ptr::using_std::strong(v)));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T *logPtr(const std::shared_ptr<T> &v)
|
||||
{
|
||||
return tjp::core::ptr::using_std::ptr_of(v);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T *logPtr(const std::weak_ptr<T> &v)
|
||||
{
|
||||
return tjp::core::ptr::using_std::ptr_of(strong(v));
|
||||
}
|
||||
|
||||
|
||||
} // namespace
|
||||
|
||||
140
tjp/core/ptr/std/Ptr.h
Executable file
140
tjp/core/ptr/std/Ptr.h
Executable file
@@ -0,0 +1,140 @@
|
||||
// License: Modified MIT (NON-AI)
|
||||
// See the LICENSE file in the root directory for license information.
|
||||
// Copyright 2025 Timothy Prepscius
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
|
||||
#include "../../debug/Debug.h"
|
||||
|
||||
template <typename T, typename = void>
|
||||
struct type_has_deallocate : std::false_type {};
|
||||
|
||||
template <typename T>
|
||||
struct type_has_deallocate<
|
||||
T,
|
||||
std::void_t<
|
||||
decltype(
|
||||
on_deallocate(
|
||||
std::declval<T *>()
|
||||
)
|
||||
)
|
||||
>
|
||||
> : std::true_type {};
|
||||
|
||||
template<typename T>
|
||||
void on_deallocate(T *t)
|
||||
{
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void deallocate_detail(T *t)
|
||||
{
|
||||
on_deallocate(t);
|
||||
}
|
||||
|
||||
namespace tjp::core::ptr::using_std {
|
||||
|
||||
template<typename T>
|
||||
auto makeDeleter()
|
||||
{
|
||||
return [](T *p) {
|
||||
deallocate_detail(p);
|
||||
delete p;
|
||||
} ;
|
||||
}
|
||||
|
||||
template<typename T, typename F>
|
||||
auto makeDeleterWithFunction(F &&f)
|
||||
{
|
||||
return [f](T *p) {
|
||||
deallocate_detail(p);
|
||||
f(p);
|
||||
} ;
|
||||
}
|
||||
|
||||
template<typename T, typename A>
|
||||
auto makeDeleterWithAllocator(A a)
|
||||
{
|
||||
return [a](T *p) {
|
||||
deallocate_detail(p);
|
||||
|
||||
auto &a_ = const_cast<A &>(a);
|
||||
a_.destroy(p);
|
||||
a_.deallocate(p, 1);
|
||||
} ;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
using StrongPtr = std::shared_ptr<T>;
|
||||
|
||||
template<typename T>
|
||||
using WeakPtr = std::weak_ptr<T>;
|
||||
|
||||
template<typename T>
|
||||
using StrongThis = std::enable_shared_from_this<T>;
|
||||
|
||||
template<typename T, typename V>
|
||||
auto strong_ptr_dynamic_cast(const V &v)
|
||||
{
|
||||
return std::dynamic_pointer_cast<T>(v);
|
||||
}
|
||||
|
||||
template<typename T, typename V>
|
||||
auto strong_ptr_cast(const V &v)
|
||||
{
|
||||
return std::static_pointer_cast<T>(v);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
auto weak_this(T *t)
|
||||
{
|
||||
return t->weak_from_this();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
auto strong_this(T *t)
|
||||
{
|
||||
return std::static_pointer_cast<T>(t ? t->weak_from_this().lock() : std::shared_ptr<T>());
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
auto strong(const WeakPtr<T> &t)
|
||||
{
|
||||
return t.lock();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
auto weak(const StrongPtr<T> &t)
|
||||
{
|
||||
return std::weak_ptr<T>(t);
|
||||
}
|
||||
|
||||
|
||||
template<typename T>
|
||||
auto strong_thread(const T &t)
|
||||
{
|
||||
return t;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
auto ptr_of(const StrongPtr<T> &t)
|
||||
{
|
||||
return t.get();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
auto ref_this(T *t)
|
||||
{
|
||||
return strong_this(t);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
#ifdef _GLIBCXX_MEMORY
|
||||
#include "Ptr+GCC.h"
|
||||
#else
|
||||
#include "Ptr+LLVM.h"
|
||||
#endif
|
||||
22
tjp/core/ptr/strong_emplace.hpp
Executable file
22
tjp/core/ptr/strong_emplace.hpp
Executable file
@@ -0,0 +1,22 @@
|
||||
// License: Modified MIT (NON-AI)
|
||||
// See the LICENSE file in the root directory for license information.
|
||||
// Copyright 2025 Timothy Prepscius
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace tjp::core {
|
||||
|
||||
template<typename T, typename ... Args>
|
||||
StrongPtr<T> &strong_emplace(StrongPtr<T> &t, Args&& ...args)
|
||||
{
|
||||
return t = strong<T>(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
StrongPtr<T> &strong_emplace(StrongPtr<T> &t)
|
||||
{
|
||||
return t = strong<T>();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
22
tjp/core/ptr/strong_init.hpp
Executable file
22
tjp/core/ptr/strong_init.hpp
Executable file
@@ -0,0 +1,22 @@
|
||||
// License: Modified MIT (NON-AI)
|
||||
// See the LICENSE file in the root directory for license information.
|
||||
// Copyright 2025 Timothy Prepscius
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace tjp {
|
||||
namespace core {
|
||||
|
||||
struct InitRequired {};
|
||||
|
||||
template<typename T, typename ... Args>
|
||||
auto strong_init(Args && ...args)
|
||||
{
|
||||
auto v = strong<T>(InitRequired{}, std::forward<Args>(args)...);
|
||||
v->init(v);
|
||||
return v;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
||||
24
tjp/core/ptr/strong_of.hpp
Executable file
24
tjp/core/ptr/strong_of.hpp
Executable file
@@ -0,0 +1,24 @@
|
||||
// License: Modified MIT (NON-AI)
|
||||
// See the LICENSE file in the root directory for license information.
|
||||
// Copyright 2025 Timothy Prepscius
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
namespace tjp::core {
|
||||
|
||||
template<typename T>
|
||||
auto strong_of_value(const T &t)
|
||||
{
|
||||
return strong<T>(t);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
auto strong_of(T &&t)
|
||||
{
|
||||
return strong<std::decay_t<T>>(std::forward<T>(t));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
14
tjp/core/ptr/using_info/Ptr+Debug.h
Executable file
14
tjp/core/ptr/using_info/Ptr+Debug.h
Executable file
@@ -0,0 +1,14 @@
|
||||
// License: Modified MIT (NON-AI)
|
||||
// See the LICENSE file in the root directory for license information.
|
||||
// Copyright 2025 Timothy Prepscius
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../../system/Debug.h"
|
||||
|
||||
#ifdef DEBUG
|
||||
#define MEMORY_PTR_DEBUG_TYPE
|
||||
#endif
|
||||
|
||||
//#define MEMORY_PTR_DEBUG_ALLOCATIONS
|
||||
//#define LOG_MEMORY_PTR
|
||||
55
tjp/core/ptr/using_info/Ptr+IO.h
Executable file
55
tjp/core/ptr/using_info/Ptr+IO.h
Executable file
@@ -0,0 +1,55 @@
|
||||
// License: Modified MIT (NON-AI)
|
||||
// See the LICENSE file in the root directory for license information.
|
||||
// Copyright 2025 Timothy Prepscius
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace tjp {
|
||||
namespace core {
|
||||
namespace ptr {
|
||||
namespace using_info {
|
||||
namespace detail {
|
||||
|
||||
template<typename IO, typename T>
|
||||
void io_ptr_allocate(IO &io, StrongPtr<T> &ptr)
|
||||
{
|
||||
io.allocate(ptr);
|
||||
}
|
||||
|
||||
template<typename IO, typename T>
|
||||
void io_ptr_allocate_default(IO &io, StrongPtr<T> &ptr)
|
||||
{
|
||||
ptr = strong<T>();
|
||||
}
|
||||
|
||||
template<typename IO, typename T>
|
||||
void io_json_w(IO &io, const StrongPtr<T> &r)
|
||||
{
|
||||
io.any((T *)r);
|
||||
}
|
||||
|
||||
template<typename IO, typename T>
|
||||
void io_json_r(IO &io, StrongPtr<T> &t)
|
||||
{
|
||||
auto p = io.template pointer<T>(t);
|
||||
io.any(p);
|
||||
}
|
||||
|
||||
template<typename IO, typename T>
|
||||
void io_bin_w(IO &io, const StrongPtr<T> &r)
|
||||
{
|
||||
io.any((T *)r);
|
||||
}
|
||||
|
||||
template<typename IO, typename T>
|
||||
void io_bin_r(IO &io, StrongPtr<T> &r)
|
||||
{
|
||||
auto p = io.template pointer<T>(r);
|
||||
io.any(p);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
} // namespace
|
||||
} // namespace
|
||||
} // namespace
|
||||
13
tjp/core/ptr/using_info/Ptr+Log.cpp
Executable file
13
tjp/core/ptr/using_info/Ptr+Log.cpp
Executable file
@@ -0,0 +1,13 @@
|
||||
// License: Modified MIT (NON-AI)
|
||||
// See the LICENSE file in the root directory for license information.
|
||||
// Copyright 2025 Timothy Prepscius
|
||||
|
||||
#include "Ptr+Log.h"
|
||||
|
||||
namespace tjp {
|
||||
namespace core {
|
||||
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
||||
27
tjp/core/ptr/using_info/Ptr+Log.h
Executable file
27
tjp/core/ptr/using_info/Ptr+Log.h
Executable file
@@ -0,0 +1,27 @@
|
||||
// License: Modified MIT (NON-AI)
|
||||
// See the LICENSE file in the root directory for license information.
|
||||
// Copyright 2025 Timothy Prepscius
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../../log/LogOf.h"
|
||||
#include "Ptr.h"
|
||||
|
||||
namespace tjp {
|
||||
namespace core {
|
||||
namespace ptr {
|
||||
namespace using_info {
|
||||
namespace detail {
|
||||
|
||||
template<typename T>
|
||||
std::ostream &operator <<(std::ostream &o, const StrongPtr<T> &v)
|
||||
{
|
||||
return o << logOf(v.ptr());
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
} // namespace
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
||||
46
tjp/core/ptr/using_info/Ptr+Logging.cpp
Executable file
46
tjp/core/ptr/using_info/Ptr+Logging.cpp
Executable file
@@ -0,0 +1,46 @@
|
||||
// License: Modified MIT (NON-AI)
|
||||
// See the LICENSE file in the root directory for license information.
|
||||
// Copyright 2025 Timothy Prepscius
|
||||
|
||||
#include "Ptr.hpp"
|
||||
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
#include <set>
|
||||
|
||||
namespace tjp {
|
||||
namespace core {
|
||||
namespace ptr {
|
||||
namespace using_info {
|
||||
namespace detail {
|
||||
|
||||
std::string Debug::getInfoFor (K k)
|
||||
{
|
||||
return "not implemented";
|
||||
}
|
||||
|
||||
std::string setToString(const std::set<void *> &ids)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
|
||||
oss << " [";
|
||||
for (auto &id: ids)
|
||||
{
|
||||
oss << id << " ";
|
||||
}
|
||||
oss << "] ";
|
||||
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
void Debug::print ()
|
||||
{
|
||||
std::cout << "SmartPtr printDebug " << std::endl;;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
} // namespace
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
||||
26
tjp/core/ptr/using_info/Ptr.cpp
Executable file
26
tjp/core/ptr/using_info/Ptr.cpp
Executable file
@@ -0,0 +1,26 @@
|
||||
// License: Modified MIT (NON-AI)
|
||||
// See the LICENSE file in the root directory for license information.
|
||||
// Copyright 2025 Timothy Prepscius
|
||||
|
||||
#include "Ptr.hpp"
|
||||
|
||||
namespace tjp {
|
||||
namespace core {
|
||||
namespace ptr {
|
||||
namespace using_info {
|
||||
|
||||
namespace detail {
|
||||
|
||||
Mutex &Object::mutex()
|
||||
{
|
||||
static Mutex v;
|
||||
return v;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
||||
95
tjp/core/ptr/using_info/Ptr.h
Executable file
95
tjp/core/ptr/using_info/Ptr.h
Executable file
@@ -0,0 +1,95 @@
|
||||
// License: Modified MIT (NON-AI)
|
||||
// See the LICENSE file in the root directory for license information.
|
||||
// Copyright 2025 Timothy Prepscius
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Ptr+Debug.h"
|
||||
|
||||
#include "../../threads/Lock.h"
|
||||
#include <cstddef>
|
||||
|
||||
template<typename T>
|
||||
void onStrongPtrDelete(T *t);
|
||||
|
||||
namespace tjp {
|
||||
namespace core {
|
||||
namespace ptr {
|
||||
namespace using_info {
|
||||
namespace detail {
|
||||
|
||||
class Catalog;
|
||||
|
||||
template<typename T>
|
||||
class StrongPtr;
|
||||
|
||||
template<typename T>
|
||||
class WeakPtr;
|
||||
|
||||
template<typename T>
|
||||
class StrongThis;
|
||||
|
||||
class Debug;
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template<typename T>
|
||||
using StrongPtr = detail::StrongPtr<T>;
|
||||
|
||||
template<typename T>
|
||||
using WeakPtr = detail::WeakPtr<T>;
|
||||
|
||||
template<typename T>
|
||||
using StrongThis = detail::StrongThis<T>;
|
||||
|
||||
using Catalog = detail::Catalog;
|
||||
|
||||
// ------------------------------------------------
|
||||
|
||||
template<typename T>
|
||||
size_t refCount (T *k);
|
||||
|
||||
template<typename T, typename ... Args>
|
||||
StrongPtr<T> strong (Args&& ...);
|
||||
|
||||
template<typename T>
|
||||
StrongPtr<T> strong_any (T *);
|
||||
|
||||
template<typename T>
|
||||
StrongPtr<T> strong (const StrongPtr<T> &t);
|
||||
|
||||
template<typename T>
|
||||
WeakPtr<T> weak (const StrongPtr<T> &t);
|
||||
|
||||
template<typename T>
|
||||
StrongPtr<T> strong (const WeakPtr<T> &t);
|
||||
|
||||
template<typename T>
|
||||
StrongPtr<T> strong_this (T *that);
|
||||
|
||||
template<typename T>
|
||||
StrongPtr<T> ref_this(T *that);
|
||||
|
||||
template<typename T>
|
||||
WeakPtr<T> weak_this (T *that);
|
||||
|
||||
template<typename T>
|
||||
StrongPtr<T> strong_thread(const StrongPtr<T> &t);
|
||||
|
||||
template<typename T>
|
||||
StrongPtr<T> strong_thread_this(T *t);
|
||||
|
||||
template<typename T>
|
||||
StrongPtr<T> strong_thread (const WeakPtr<T> &t);
|
||||
|
||||
template<typename T>
|
||||
T *ptr_of(const StrongPtr<T> &t);
|
||||
|
||||
template<typename T, typename V>
|
||||
StrongPtr<T> strong_ptr_cast(const StrongPtr<V> &t);
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
||||
315
tjp/core/ptr/using_info/Ptr.hpp
Executable file
315
tjp/core/ptr/using_info/Ptr.hpp
Executable file
@@ -0,0 +1,315 @@
|
||||
// License: Modified MIT (NON-AI)
|
||||
// See the LICENSE file in the root directory for license information.
|
||||
// Copyright 2025 Timothy Prepscius
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Ptr.h"
|
||||
|
||||
#include <unordered_map>
|
||||
#include <algorithm>
|
||||
#include <atomic>
|
||||
|
||||
#include "../../threads/Lock.hpp"
|
||||
#include "../../containers/FilledArray.hpp"
|
||||
#include "../../assert/debug_assert.h"
|
||||
#include "../../rtti/RTTI.hpp"
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#ifdef MEMORY_PTR_DEBUG_ALLOCATIONS
|
||||
#include <set>
|
||||
#endif
|
||||
|
||||
template<typename T>
|
||||
void onStrongPtrDelete(T *t);
|
||||
|
||||
template<typename T>
|
||||
void deallocate(T *t);
|
||||
|
||||
namespace tjp {
|
||||
namespace core {
|
||||
namespace ptr {
|
||||
namespace using_info {
|
||||
namespace detail {
|
||||
|
||||
typedef core::Mutex Mutex;
|
||||
typedef core::Mutex::Lock Lock;
|
||||
|
||||
typedef void *K;
|
||||
typedef void *W;
|
||||
|
||||
struct NotCataloged {};
|
||||
struct Cataloged {};
|
||||
|
||||
struct WeakRef;
|
||||
|
||||
struct Object
|
||||
{
|
||||
typedef detail::Lock Lock;
|
||||
static Mutex &mutex();
|
||||
|
||||
template<typename T>
|
||||
Object(T *p, bool allocated);
|
||||
|
||||
std::atomic<size_t> count = 0;
|
||||
K p;
|
||||
bool allocated;
|
||||
bool threaded = false;
|
||||
|
||||
StrongPtr<WeakRef> *weak = nullptr;
|
||||
|
||||
template<typename T>
|
||||
T *ptr();
|
||||
|
||||
void mark_threaded ();
|
||||
|
||||
void ref (void *that);
|
||||
|
||||
template<typename T>
|
||||
T *unref_no_lock (void *that);
|
||||
|
||||
template<typename T>
|
||||
T *unref_lock (void *that);
|
||||
|
||||
template<typename T>
|
||||
void unref (void *that);
|
||||
|
||||
StrongPtr<WeakRef> get_weak();
|
||||
|
||||
#ifdef MEMORY_PTR_DEBUG_TYPE
|
||||
const char *typeName;
|
||||
#endif
|
||||
|
||||
#ifdef MEMORY_PTR_DEBUG_ALLOCATIONS
|
||||
Mutex idsMutex;
|
||||
std::set<void *> ids;
|
||||
#endif
|
||||
} ;
|
||||
|
||||
class Debug
|
||||
{
|
||||
public:
|
||||
static std::string getInfoFor (K k);
|
||||
static void print ();
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class StrongPtr;
|
||||
|
||||
class WeakRef
|
||||
{
|
||||
private:
|
||||
friend class Object;
|
||||
Object *object = nullptr;
|
||||
bool threaded = false;
|
||||
|
||||
WeakRef &operator = (const WeakRef &rhs) = delete;
|
||||
WeakRef (const WeakRef &w) = delete;
|
||||
|
||||
void ref(Object *object);
|
||||
void unref();
|
||||
|
||||
void mark_threaded();
|
||||
|
||||
public:
|
||||
WeakRef(Object *object_);
|
||||
~WeakRef();
|
||||
|
||||
template<typename T>
|
||||
StrongPtr<T> ptr();
|
||||
} ;
|
||||
|
||||
template<typename T>
|
||||
class WeakPtr;
|
||||
|
||||
template<typename T>
|
||||
class StrongPtr {
|
||||
|
||||
public:
|
||||
typedef T value_type;
|
||||
typedef T element_type;
|
||||
typedef T *pointer_type;
|
||||
|
||||
private:
|
||||
detail::Object *object = nullptr;
|
||||
|
||||
template<typename U>
|
||||
void check_compatible_u() const
|
||||
{
|
||||
debug_assert(static_cast<U *>((T *)0) == 0);
|
||||
}
|
||||
|
||||
StrongPtr<T> *mutable_this() const;
|
||||
void ref (detail::Object *object_);
|
||||
void unref ();
|
||||
void swap (detail::Object *&lhs, void *lhs_, detail::Object *&rhs, void *rhs_);
|
||||
|
||||
public:
|
||||
detail::Object *&accessObject() const;
|
||||
|
||||
public:
|
||||
~StrongPtr ();
|
||||
|
||||
StrongPtr ();
|
||||
|
||||
StrongPtr (const detail::Object *object_);
|
||||
|
||||
// -------------------------
|
||||
|
||||
StrongPtr(StrongPtr<T> &&rhs);
|
||||
StrongPtr(const StrongPtr<T> &rhs);
|
||||
|
||||
// -------------------------
|
||||
|
||||
template<typename U>
|
||||
StrongPtr(const StrongPtr<U> &rhs)
|
||||
{
|
||||
check_compatible_u<U>();
|
||||
ref(rhs.accessObject());
|
||||
}
|
||||
|
||||
template<typename U>
|
||||
StrongPtr(StrongPtr<U> &&rhs)
|
||||
{
|
||||
check_compatible_u<U>();
|
||||
swap(object, (void *)this, rhs.accessObject(), (void *)&rhs);
|
||||
}
|
||||
|
||||
// -------------------------
|
||||
|
||||
StrongPtr &operator =(const StrongPtr<T> &rhs);
|
||||
StrongPtr &operator =(StrongPtr<T> &&rhs);
|
||||
|
||||
// -------------------------
|
||||
|
||||
operator bool() const;
|
||||
bool operator !() const;
|
||||
|
||||
// -------------------------
|
||||
|
||||
template<typename U>
|
||||
StrongPtr<U> cast() const
|
||||
{
|
||||
check_compatible_u<U>();
|
||||
|
||||
if (!object)
|
||||
return {};
|
||||
|
||||
auto *t = object->ptr<T>();
|
||||
auto *u = dynamic_cast<U *>(t);
|
||||
debug_assert((void *)u == (void *)t || u == nullptr);
|
||||
|
||||
if (u)
|
||||
{
|
||||
return StrongPtr<U>(object);
|
||||
}
|
||||
|
||||
return StrongPtr<U>();
|
||||
}
|
||||
|
||||
T *ptr() const;
|
||||
|
||||
operator T *() const;
|
||||
T &operator *() const;
|
||||
T *operator -> () const;
|
||||
|
||||
bool operator == (const T *_t) const;
|
||||
bool operator == (const StrongPtr<T> &_t) const;
|
||||
bool operator != (const StrongPtr<T> &_t) const;
|
||||
bool operator <(const StrongPtr<T> &rhs) const;
|
||||
|
||||
WeakPtr<T> weak() const;
|
||||
|
||||
void mark_threaded();
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class WeakPtr
|
||||
{
|
||||
private:
|
||||
StrongPtr<WeakRef> t;
|
||||
|
||||
protected:
|
||||
|
||||
public:
|
||||
WeakPtr ();
|
||||
WeakPtr (const StrongPtr<WeakRef> &rhs);
|
||||
WeakPtr (const WeakPtr<T> &rhs);
|
||||
WeakPtr (WeakPtr<T> &&rhs);
|
||||
|
||||
WeakPtr &operator =(const WeakPtr<T> &rhs);
|
||||
WeakPtr &operator =(WeakPtr<T> &&rhs);
|
||||
|
||||
StrongPtr<T> ptr() const;
|
||||
} ;
|
||||
|
||||
template<typename T>
|
||||
class StrongThis
|
||||
{
|
||||
StrongThis(const StrongThis &rhs) = delete;
|
||||
void operator =(const StrongThis &rhs) = delete;
|
||||
|
||||
protected:
|
||||
Object strong_tracker;
|
||||
|
||||
public:
|
||||
StrongThis();
|
||||
|
||||
Object *get_strong_this() {
|
||||
return &strong_tracker;
|
||||
}
|
||||
} ;
|
||||
|
||||
template <typename T>
|
||||
class has_strong_this
|
||||
{
|
||||
typedef char one;
|
||||
struct two { char x[2]; };
|
||||
|
||||
template <typename C> static one test( decltype(&C::get_strong_this) ) ;
|
||||
template <typename C> static two test(...);
|
||||
|
||||
public:
|
||||
enum { value = sizeof(test<T>(0)) == sizeof(char) };
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
Object *object_from_this(T *t)
|
||||
{
|
||||
return t->get_strong_this();
|
||||
}
|
||||
|
||||
template<typename T, typename std::enable_if<!has_strong_this<T>::value, T>::type* = nullptr>
|
||||
Object *object_for(T *t)
|
||||
{
|
||||
return new Object(t, true);
|
||||
}
|
||||
|
||||
template<typename T, typename std::enable_if<has_strong_this<T>::value, T>::type* = nullptr>
|
||||
Object *object_for(T *t)
|
||||
{
|
||||
return object_from_this(t);
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template<typename T>
|
||||
using StrongPtr = detail::StrongPtr<T>;
|
||||
|
||||
template<typename T>
|
||||
using WeakPtr = detail::WeakPtr<T>;
|
||||
|
||||
template<typename T>
|
||||
using StrongThis = detail::StrongThis<T>;
|
||||
|
||||
using Catalog = detail::Catalog;
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
||||
} // namespace
|
||||
|
||||
#include "Ptr.inl"
|
||||
|
||||
545
tjp/core/ptr/using_info/Ptr.inl
Executable file
545
tjp/core/ptr/using_info/Ptr.inl
Executable file
@@ -0,0 +1,545 @@
|
||||
// License: Modified MIT (NON-AI)
|
||||
// See the LICENSE file in the root directory for license information.
|
||||
// Copyright 2025 Timothy Prepscius
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef LOG_MEMORY_PTR
|
||||
#include "../../log/Log.h"
|
||||
#include "../../log/LogOf.h"
|
||||
#define LogDebugStrongPtr(x) xLogDebug(x)
|
||||
#else
|
||||
#define LogDebugStrongPtr(x)
|
||||
#endif
|
||||
|
||||
template<typename T>
|
||||
void onStrongPtrDelete(T *t) {}
|
||||
|
||||
template<typename T>
|
||||
void deallocate(T *t)
|
||||
{
|
||||
delete t;
|
||||
}
|
||||
|
||||
namespace tjp {
|
||||
namespace core {
|
||||
namespace ptr {
|
||||
namespace using_info {
|
||||
namespace detail {
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
|
||||
template<typename T>
|
||||
StrongThis<T>::StrongThis () :
|
||||
strong_tracker(static_cast<T *>(this), false)
|
||||
{}
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
|
||||
inline
|
||||
void Object::mark_threaded()
|
||||
{
|
||||
threaded = true;
|
||||
get_weak()->mark_threaded();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Object::Object(T *p_, bool allocated_) :
|
||||
p(p_),
|
||||
allocated(allocated_)
|
||||
{
|
||||
#ifdef MEMORY_PTR_DEBUG_TYPE
|
||||
typeName = type_id<T>().name();
|
||||
#endif
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T *Object::ptr()
|
||||
{
|
||||
return reinterpret_cast<T *>(p);
|
||||
}
|
||||
|
||||
inline
|
||||
void Object::ref (void *that)
|
||||
{
|
||||
++count;
|
||||
|
||||
#ifdef MEMORY_PTR_DEBUG_ALLOCATIONS
|
||||
{
|
||||
auto l = lock_of(idsMutex);
|
||||
ids.insert(that);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T *Object::unref_no_lock (void *that)
|
||||
{
|
||||
T *t = nullptr;
|
||||
{
|
||||
#ifdef MEMORY_PTR_DEBUG_ALLOCATIONS
|
||||
{
|
||||
auto l = lock_of(idsMutex);
|
||||
ids.erase(that);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (--count == 0)
|
||||
{
|
||||
if (weak)
|
||||
{
|
||||
weak->ptr()->unref();
|
||||
delete weak;
|
||||
weak = nullptr;
|
||||
}
|
||||
|
||||
t = ptr<T>();
|
||||
p = nullptr;
|
||||
if (allocated)
|
||||
delete this;
|
||||
}
|
||||
}
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
|
||||
template<typename T>
|
||||
T *Object::unref_lock (void *that)
|
||||
{
|
||||
Object::Lock l(Object::mutex());
|
||||
|
||||
return unref_no_lock<T>(that);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void Object::unref (void *that)
|
||||
{
|
||||
T *t = nullptr;
|
||||
if (threaded)
|
||||
t = unref_lock<T>(that);
|
||||
else
|
||||
t = unref_no_lock<T>(that);
|
||||
|
||||
if (t)
|
||||
{
|
||||
onStrongPtrDelete(t);
|
||||
deallocate(t);
|
||||
}
|
||||
}
|
||||
|
||||
inline
|
||||
StrongPtr<WeakRef> Object::get_weak()
|
||||
{
|
||||
if (!weak)
|
||||
weak = new StrongPtr<WeakRef>(strong<WeakRef>(this));
|
||||
|
||||
return *weak;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
|
||||
inline
|
||||
void WeakRef::ref(Object *object_)
|
||||
{
|
||||
unref();
|
||||
object = object_;
|
||||
}
|
||||
|
||||
inline
|
||||
void WeakRef::unref()
|
||||
{
|
||||
object = nullptr;
|
||||
}
|
||||
|
||||
inline
|
||||
WeakRef::WeakRef(Object *object_)
|
||||
{
|
||||
ref(object_);
|
||||
}
|
||||
|
||||
inline
|
||||
WeakRef::~WeakRef()
|
||||
{
|
||||
unref();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
StrongPtr<T> WeakRef::ptr()
|
||||
{
|
||||
if (threaded)
|
||||
{
|
||||
detail::Object::Lock l(detail::Object::mutex());
|
||||
return StrongPtr<T>(object);
|
||||
}
|
||||
|
||||
return StrongPtr<T>(object);
|
||||
}
|
||||
|
||||
inline
|
||||
void WeakRef::mark_threaded()
|
||||
{
|
||||
threaded = true;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
|
||||
template<typename T>
|
||||
StrongPtr<T> *StrongPtr<T>::mutable_this() const
|
||||
{
|
||||
return const_cast<StrongPtr<T> *>(this);
|
||||
}
|
||||
|
||||
|
||||
template<typename T>
|
||||
detail::Object *&StrongPtr<T>::accessObject() const
|
||||
{
|
||||
return mutable_this()->object;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void StrongPtr<T>::ref (Object *object_)
|
||||
{
|
||||
debug_assert(object == nullptr);
|
||||
object = object_;
|
||||
|
||||
if (object)
|
||||
{
|
||||
object->ref(this);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void StrongPtr<T>::unref ()
|
||||
{
|
||||
if (object)
|
||||
{
|
||||
object->unref<T>(this);
|
||||
}
|
||||
|
||||
object = nullptr;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void StrongPtr<T>::swap(detail::Object *&lhs, void *lhs_, detail::Object *&rhs, void *rhs_)
|
||||
{
|
||||
#ifdef MEMORY_PTR_DEBUG_ALLOCATIONS
|
||||
{
|
||||
if (lhs)
|
||||
{
|
||||
Lock ll(lhs->idsMutex);
|
||||
lhs->ids.erase(lhs_);
|
||||
lhs->ids.insert(rhs_);
|
||||
}
|
||||
|
||||
if (rhs)
|
||||
{
|
||||
Lock lr(rhs->idsMutex);
|
||||
rhs->ids.erase(rhs_);
|
||||
rhs->ids.insert(lhs_);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
std::swap(lhs, rhs);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
StrongPtr<T>::~StrongPtr ()
|
||||
{
|
||||
unref();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
StrongPtr<T>::StrongPtr ()
|
||||
{
|
||||
ref(nullptr);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
StrongPtr<T>::StrongPtr (const Object *object_)
|
||||
{
|
||||
ref(const_cast<Object *>(object_));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
StrongPtr<T>::StrongPtr(StrongPtr<T> &&rhs)
|
||||
{
|
||||
swap(object, this, rhs.object, &rhs);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
StrongPtr<T>::StrongPtr(const StrongPtr<T> &rhs)
|
||||
{
|
||||
ref(rhs.object);
|
||||
}
|
||||
|
||||
// -------------------------
|
||||
|
||||
template<typename T>
|
||||
StrongPtr<T> &StrongPtr<T>::operator =(const StrongPtr<T> &rhs)
|
||||
{
|
||||
if (rhs.object == object)
|
||||
return *this;
|
||||
|
||||
unref();
|
||||
ref(rhs.object);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
StrongPtr<T> &StrongPtr<T>::operator =(StrongPtr<T> &&rhs)
|
||||
{
|
||||
std::swap(object, rhs.object);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
StrongPtr<T>::operator bool() const
|
||||
{
|
||||
return object != nullptr;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool StrongPtr<T>::operator !() const
|
||||
{
|
||||
return object == nullptr;
|
||||
}
|
||||
|
||||
|
||||
template<typename T>
|
||||
T *StrongPtr<T>::ptr() const
|
||||
{
|
||||
if (!object)
|
||||
return nullptr;
|
||||
|
||||
return object->ptr<T>();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
StrongPtr<T>::operator T *() const
|
||||
{
|
||||
return ptr();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T &StrongPtr<T>::operator *() const
|
||||
{
|
||||
return *ptr();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T *StrongPtr<T>::operator -> () const
|
||||
{
|
||||
return ptr();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool StrongPtr<T>::operator == (const T *_t) const
|
||||
{
|
||||
return ptr() == _t;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool StrongPtr<T>::operator == (const StrongPtr<T> &rhs) const
|
||||
{
|
||||
return ptr() == rhs.ptr();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool StrongPtr<T>::operator != (const StrongPtr<T> &rhs) const
|
||||
{
|
||||
return ptr() != rhs.ptr();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool StrongPtr<T>::operator <(const StrongPtr<T> &rhs) const
|
||||
{
|
||||
return ptr() < rhs.ptr();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
WeakPtr<T> StrongPtr<T>::weak() const
|
||||
{
|
||||
return object ? WeakPtr<T>(object->get_weak()) : WeakPtr<T>();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void StrongPtr<T>::mark_threaded()
|
||||
{
|
||||
if (object)
|
||||
{
|
||||
object->mark_threaded();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// -------------
|
||||
|
||||
|
||||
template<typename T>
|
||||
WeakPtr<T>::WeakPtr ()
|
||||
{
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
WeakPtr<T>::WeakPtr (const StrongPtr<WeakRef> &rhs) : t(rhs)
|
||||
{
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
WeakPtr<T>::WeakPtr (const WeakPtr<T> &rhs) : t(rhs.t)
|
||||
{
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
WeakPtr<T>::WeakPtr (WeakPtr<T> &&rhs) : t(std::move(rhs.t))
|
||||
{
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
WeakPtr<T> &WeakPtr<T>::operator =(const WeakPtr<T> &rhs)
|
||||
{
|
||||
t = rhs.t;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
WeakPtr<T> &WeakPtr<T>::operator =(WeakPtr<T> &&rhs)
|
||||
{
|
||||
t = std::move(rhs.t);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
StrongPtr<T> WeakPtr<T>::ptr() const
|
||||
{
|
||||
return t ? t->ptr<T>() : StrongPtr<T>();
|
||||
}
|
||||
|
||||
// -------------------------------------------------------
|
||||
|
||||
template<typename T>
|
||||
size_t ref_count_of(T *t)
|
||||
{
|
||||
auto o = object_from_this(t);
|
||||
return o->count;
|
||||
}
|
||||
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template<typename T>
|
||||
size_t refCount(T *t)
|
||||
{
|
||||
return detail::ref_count_of(t);
|
||||
}
|
||||
|
||||
template<typename T, typename ... Args>
|
||||
StrongPtr<T> strong_ (Args&& ... args)
|
||||
{
|
||||
auto t = new T(std::forward<Args>(args)...);
|
||||
|
||||
return StrongPtr<T>(
|
||||
detail::object_for(t)
|
||||
);
|
||||
}
|
||||
|
||||
template<typename T, typename ... Args>
|
||||
StrongPtr<T> strong (Args&& ... args)
|
||||
{
|
||||
return strong_<T>(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
StrongPtr<T> strong (const StrongPtr<T> &t)
|
||||
{
|
||||
return t;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
WeakPtr<T> weak (const StrongPtr<T> &t)
|
||||
{
|
||||
return t.weak();
|
||||
}
|
||||
|
||||
|
||||
template<typename T>
|
||||
StrongPtr<T> strong(const WeakPtr<T> &t)
|
||||
{
|
||||
return t.ptr();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
StrongPtr<T> strong_this (T *that)
|
||||
{
|
||||
return StrongPtr<T>(
|
||||
detail::object_from_this(that)
|
||||
);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
StrongPtr<T> ref_this(T *that)
|
||||
{
|
||||
auto *object = detail::object_from_this(that);
|
||||
if (object->count == 0)
|
||||
return {};
|
||||
|
||||
return StrongPtr<T>(object);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
WeakPtr<T> weak_this (T *that)
|
||||
{
|
||||
return detail::object_from_this(that)->get_weak();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
StrongPtr<T> strong_thread(const StrongPtr<T> &t)
|
||||
{
|
||||
detail::Object::Lock l(detail::Object::mutex());
|
||||
auto v = strong(t);
|
||||
v.mark_threaded();
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
template<typename T>
|
||||
StrongPtr<T> strong_thread(const WeakPtr<T> &t)
|
||||
{
|
||||
detail::Object::Lock l(detail::Object::mutex());
|
||||
auto v = strong(t);
|
||||
v.mark_threaded();
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
template<typename T>
|
||||
StrongPtr<T> strong_thread_this(T *t)
|
||||
{
|
||||
detail::Object::Lock l(detail::Object::mutex());
|
||||
auto v = strong_this(t);
|
||||
v.mark_threaded();
|
||||
return v;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T *ptr_of(const StrongPtr<T> &t)
|
||||
{
|
||||
return t.ptr();
|
||||
}
|
||||
|
||||
template<typename T, typename V>
|
||||
StrongPtr<T> strong_ptr_cast(const StrongPtr<V> &t)
|
||||
{
|
||||
return t.template cast<T>();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
||||
} // namespace
|
||||
|
||||
65
tjp/core/ptr/using_info/_tests/Ptr.cpp
Executable file
65
tjp/core/ptr/using_info/_tests/Ptr.cpp
Executable file
@@ -0,0 +1,65 @@
|
||||
// License: Modified MIT (NON-AI)
|
||||
// See the LICENSE file in the root directory for license information.
|
||||
// Copyright 2025 Timothy Prepscius
|
||||
|
||||
#include <tjp/core/ptr/using_info/Ptr.hpp>
|
||||
#include <tjp/core/testing/catch.hpp>
|
||||
|
||||
namespace tjp::core::ptr::using_info {
|
||||
namespace {
|
||||
|
||||
struct Deletable : StrongThis<Deletable> {
|
||||
size_t &flag;
|
||||
Deletable(size_t &flag_) : flag(flag_)
|
||||
{}
|
||||
~Deletable()
|
||||
{ flag++; }
|
||||
} ;
|
||||
|
||||
|
||||
SCENARIO("core::ptr::using_info::custom_ptr_to_info")
|
||||
{
|
||||
size_t deleteFlag = 0;
|
||||
GIVEN("ptr")
|
||||
{
|
||||
|
||||
auto *v = new Deletable(deleteFlag);
|
||||
auto p1 = strong_this(v);
|
||||
|
||||
WHEN("referenced only once")
|
||||
{
|
||||
REQUIRE(refCount(v) == 1);
|
||||
}
|
||||
|
||||
WHEN("referenced")
|
||||
{
|
||||
auto p2 = p1;
|
||||
|
||||
THEN("references is 2")
|
||||
{
|
||||
REQUIRE(refCount(v) == 2);
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("referenced and removed")
|
||||
{
|
||||
{
|
||||
auto p2 = p1;
|
||||
}
|
||||
|
||||
THEN("references is 1")
|
||||
{
|
||||
REQUIRE(refCount(v) == 1);
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("item is deleted")
|
||||
{
|
||||
p1 = {};
|
||||
REQUIRE(deleteFlag == 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
14
tjp/core/ptr/using_maps/Ptr+Debug.h
Executable file
14
tjp/core/ptr/using_maps/Ptr+Debug.h
Executable file
@@ -0,0 +1,14 @@
|
||||
// License: Modified MIT (NON-AI)
|
||||
// See the LICENSE file in the root directory for license information.
|
||||
// Copyright 2025 Timothy Prepscius
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../../system/Debug.h"
|
||||
|
||||
#ifdef DEBUG
|
||||
#define MEMORY_PTR_DEBUG_TYPE
|
||||
#endif
|
||||
|
||||
//#define MEMORY_PTR_DEBUG_ALLOCATIONS
|
||||
//#define LOG_MEMORY_PTR
|
||||
41
tjp/core/ptr/using_maps/Ptr+IO.h
Executable file
41
tjp/core/ptr/using_maps/Ptr+IO.h
Executable file
@@ -0,0 +1,41 @@
|
||||
// License: Modified MIT (NON-AI)
|
||||
// See the LICENSE file in the root directory for license information.
|
||||
// Copyright 2025 Timothy Prepscius
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace tjp {
|
||||
namespace core {
|
||||
namespace ptr {
|
||||
namespace using_maps {
|
||||
|
||||
template<typename IO, typename T>
|
||||
void io_json_w(IO &io, const StrongPtr<T> &r)
|
||||
{
|
||||
io.any((T *)r);
|
||||
}
|
||||
|
||||
template<typename IO, typename T>
|
||||
void io_json_r(IO &io, StrongPtr<T> &t)
|
||||
{
|
||||
auto p = io.template pointer<T>(t);
|
||||
io.any(p);
|
||||
}
|
||||
|
||||
template<typename IO, typename T>
|
||||
void io_bin_w(IO &io, const StrongPtr<T> &r)
|
||||
{
|
||||
io.any((T *)r);
|
||||
}
|
||||
|
||||
template<typename IO, typename T>
|
||||
void io_bin_r(IO &io, StrongPtr<T> &r)
|
||||
{
|
||||
auto p = io.template pointer<T>(r);
|
||||
io.any(p);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
} // namespace
|
||||
} // namespace
|
||||
25
tjp/core/ptr/using_maps/Ptr+Log.h
Executable file
25
tjp/core/ptr/using_maps/Ptr+Log.h
Executable file
@@ -0,0 +1,25 @@
|
||||
// License: Modified MIT (NON-AI)
|
||||
// See the LICENSE file in the root directory for license information.
|
||||
// Copyright 2025 Timothy Prepscius
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../../log/LogOf.h"
|
||||
#include "Ptr.h"
|
||||
|
||||
namespace tjp {
|
||||
namespace core {
|
||||
namespace ptr {
|
||||
namespace using_maps {
|
||||
|
||||
template<typename T>
|
||||
std::ostream &operator <<(std::ostream &o, const StrongPtr<T> &v)
|
||||
{
|
||||
return o << logOf(ptr_of(v));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
||||
70
tjp/core/ptr/using_maps/Ptr+Logging.cpp
Executable file
70
tjp/core/ptr/using_maps/Ptr+Logging.cpp
Executable file
@@ -0,0 +1,70 @@
|
||||
// License: Modified MIT (NON-AI)
|
||||
// See the LICENSE file in the root directory for license information.
|
||||
// Copyright 2025 Timothy Prepscius
|
||||
|
||||
#include "Ptr.hpp"
|
||||
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
#include <set>
|
||||
|
||||
namespace tjp {
|
||||
namespace core {
|
||||
namespace ptr {
|
||||
namespace using_maps {
|
||||
|
||||
std::string SmartPtrBase::getInfoFor (K k)
|
||||
{
|
||||
auto l = lock_of(m());
|
||||
std::ostringstream ss;
|
||||
auto &items_ = items();
|
||||
auto i = items_.find(k);
|
||||
if (i != items_.end())
|
||||
{
|
||||
ss << i->second.count;
|
||||
}
|
||||
else
|
||||
ss << "0";
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::string setToString(const std::set<void *> &ids)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
|
||||
oss << " [";
|
||||
for (auto &id: ids)
|
||||
{
|
||||
oss << id << " ";
|
||||
}
|
||||
oss << "] ";
|
||||
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
void SmartPtrBase::printDebug ()
|
||||
{
|
||||
std::cout << "SmartPtr printDebug " << std::endl;;
|
||||
|
||||
auto l = lock_of(m());
|
||||
for (auto &i : items())
|
||||
{
|
||||
std::cout << "\t" << i.first << "\t" << i.second.count
|
||||
#ifdef MEMORY_PTR_DEBUG_TYPE
|
||||
<< "\t" << i.second.typeName
|
||||
#endif
|
||||
#ifdef MEMORY_PTR_DEBUG_ALLOCATIONS
|
||||
<< setToString(i.second.ids)
|
||||
#endif
|
||||
;
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
||||
37
tjp/core/ptr/using_maps/Ptr.cpp
Executable file
37
tjp/core/ptr/using_maps/Ptr.cpp
Executable file
@@ -0,0 +1,37 @@
|
||||
// License: Modified MIT (NON-AI)
|
||||
// See the LICENSE file in the root directory for license information.
|
||||
// Copyright 2025 Timothy Prepscius
|
||||
|
||||
#include "Ptr.hpp"
|
||||
|
||||
namespace tjp {
|
||||
namespace core {
|
||||
namespace ptr {
|
||||
namespace using_maps {
|
||||
|
||||
SmartPtrStatics::Items &SmartPtrStatics::items()
|
||||
{
|
||||
static Items *items_ = new Items();
|
||||
return *items_;
|
||||
}
|
||||
|
||||
SmartPtrStatics::Weaks &SmartPtrStatics::weaks()
|
||||
{
|
||||
static Weaks *weaks_ = new Weaks();
|
||||
return *weaks_;
|
||||
}
|
||||
|
||||
Mutex &SmartPtrStatics::m()
|
||||
{
|
||||
static Mutex *m_ = new Mutex();
|
||||
return *m_;
|
||||
}
|
||||
|
||||
// ------------------------------------------------
|
||||
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
||||
61
tjp/core/ptr/using_maps/Ptr.h
Executable file
61
tjp/core/ptr/using_maps/Ptr.h
Executable file
@@ -0,0 +1,61 @@
|
||||
// License: Modified MIT (NON-AI)
|
||||
// See the LICENSE file in the root directory for license information.
|
||||
// Copyright 2025 Timothy Prepscius
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Ptr+Debug.h"
|
||||
|
||||
template<typename T>
|
||||
void onStrongPtrDelete(T *t);
|
||||
|
||||
namespace tjp {
|
||||
namespace core {
|
||||
namespace ptr {
|
||||
namespace using_maps {
|
||||
|
||||
struct SmartPtrStatics;
|
||||
|
||||
class SmartPtrBase;
|
||||
|
||||
template<typename T>
|
||||
class StrongPtr;
|
||||
|
||||
template<typename T>
|
||||
class WeakRef;
|
||||
|
||||
template<typename T>
|
||||
class WeakPtr;
|
||||
|
||||
template<typename T>
|
||||
class StrongPtr;
|
||||
|
||||
template<typename T>
|
||||
StrongPtr<T> strong (T *t);
|
||||
|
||||
template<typename T>
|
||||
StrongPtr<T> strong (const StrongPtr<T> &t);
|
||||
|
||||
template<typename T>
|
||||
WeakPtr<T> weak (const StrongPtr<T> &t);
|
||||
|
||||
template<typename T>
|
||||
StrongPtr<T> strong_this (T *that);
|
||||
|
||||
template<typename T>
|
||||
StrongPtr<T> ref_this(T *that);
|
||||
|
||||
template<typename T>
|
||||
WeakPtr<T> weak_this (T *that);
|
||||
|
||||
template<typename T>
|
||||
auto ptr_of(const StrongPtr<T> &t)
|
||||
{
|
||||
return t.get();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
||||
598
tjp/core/ptr/using_maps/Ptr.hpp
Executable file
598
tjp/core/ptr/using_maps/Ptr.hpp
Executable file
@@ -0,0 +1,598 @@
|
||||
// License: Modified MIT (NON-AI)
|
||||
// See the LICENSE file in the root directory for license information.
|
||||
// Copyright 2025 Timothy Prepscius
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Ptr.h"
|
||||
|
||||
#include <unordered_map>
|
||||
#include <algorithm>
|
||||
|
||||
#include "../../threads/Lock.hpp"
|
||||
#include "../../containers/FilledArray.hpp"
|
||||
#include "../../assert/debug_assert.h"
|
||||
#include "../../rtti/RTTI.hpp"
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#ifdef LOG_MEMORY_PTR
|
||||
#include "../../log/Log.h"
|
||||
#include "../../log/LogOf.h"
|
||||
#define LogDebugStrongPtr(x) xLogDebug(x)
|
||||
#else
|
||||
#define LogDebugStrongPtr(x)
|
||||
#endif
|
||||
|
||||
#ifdef MEMORY_PTR_DEBUG_ALLOCATIONS
|
||||
#include <set>
|
||||
#endif
|
||||
|
||||
template<typename T>
|
||||
void onStrongPtrDelete(T *t) {}
|
||||
|
||||
template<typename T>
|
||||
void deallocate(T *t)
|
||||
{
|
||||
delete t;
|
||||
}
|
||||
|
||||
namespace tjp {
|
||||
namespace core {
|
||||
namespace ptr {
|
||||
namespace using_maps {
|
||||
|
||||
struct SmartPtrStatics
|
||||
{
|
||||
typedef void *K;
|
||||
typedef int V;
|
||||
typedef void *W;
|
||||
|
||||
struct Item
|
||||
{
|
||||
size_t count;
|
||||
|
||||
#ifdef MEMORY_PTR_DEBUG_TYPE
|
||||
const char *typeName;
|
||||
#endif
|
||||
|
||||
#ifdef MEMORY_PTR_DEBUG_ALLOCATIONS
|
||||
std::set<void *> ids;
|
||||
#endif
|
||||
} ;
|
||||
|
||||
// typedef std::map<K, V> Items;
|
||||
typedef std::unordered_map<K, Item> Items;
|
||||
|
||||
// typedef std::vector<W> WeakList;
|
||||
struct WeakList {
|
||||
bool valid = false;
|
||||
FilledArray<W> values;
|
||||
} ;
|
||||
// typedef FilledArray<W> WeakList;
|
||||
|
||||
// typedef std::map<K, WeakList > Weaks;
|
||||
typedef std::unordered_map<K, WeakList > Weaks;
|
||||
|
||||
static Items &items();
|
||||
static Weaks &weaks();
|
||||
static Mutex &m();
|
||||
} ;
|
||||
|
||||
class SmartPtrBase : public SmartPtrStatics
|
||||
{
|
||||
|
||||
public:
|
||||
static size_t refCount (K k)
|
||||
{
|
||||
auto l = lock_of(m());
|
||||
auto &items_ = items();
|
||||
if (items_.find(k) != items_.end())
|
||||
return items_[k].count;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static std::string getInfoFor (K k);
|
||||
static void printDebug ();
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class StrongPtr;
|
||||
|
||||
template<typename T>
|
||||
class WeakRef : public SmartPtrBase
|
||||
{
|
||||
private:
|
||||
WeakList *l = nullptr;
|
||||
T *t;
|
||||
|
||||
void ref ()
|
||||
{
|
||||
if (t != 0)
|
||||
{
|
||||
auto lock = lock_of(m());
|
||||
|
||||
auto &weaks_ = weaks();
|
||||
|
||||
auto i = weaks_.find(t);
|
||||
if (i == weaks_.end())
|
||||
{
|
||||
auto &w = weaks_[t];
|
||||
l = &w;
|
||||
|
||||
auto &items_ = items();
|
||||
w.valid = items_.find(t) != items_.end();
|
||||
}
|
||||
else
|
||||
{
|
||||
l = &i->second;
|
||||
}
|
||||
|
||||
l->values.push_back(this);
|
||||
}
|
||||
}
|
||||
|
||||
void unref ()
|
||||
{
|
||||
if (t != 0)
|
||||
{
|
||||
auto lock = lock_of(m());
|
||||
|
||||
auto i = std::find(l->values.begin(), l->values.end(), this);
|
||||
if (i != l->values.end())
|
||||
l->values.erase(i);
|
||||
}
|
||||
}
|
||||
|
||||
void validate ()
|
||||
{
|
||||
debug_assert(l->valid);
|
||||
}
|
||||
|
||||
WeakRef &operator = (const WeakRef &rhs);
|
||||
WeakRef (const WeakRef &w) = delete;
|
||||
|
||||
public:
|
||||
WeakRef(const T *_t) :
|
||||
t(const_cast<T *>(_t))
|
||||
{
|
||||
ref();
|
||||
}
|
||||
|
||||
~WeakRef()
|
||||
{
|
||||
unref();
|
||||
}
|
||||
|
||||
static void validate_nolock (T *t)
|
||||
{
|
||||
if (t != 0)
|
||||
{
|
||||
auto &weaks_ = weaks();
|
||||
auto l = weaks_.find(t);
|
||||
if (l == weaks_.end())
|
||||
return;
|
||||
|
||||
l->second.valid = true;
|
||||
}
|
||||
}
|
||||
static void validate (T *t)
|
||||
{
|
||||
if (!t)
|
||||
return;
|
||||
|
||||
auto lock = lock_of(m());
|
||||
return validate_nolock(t);
|
||||
}
|
||||
|
||||
static void nullify_nolock (T *t)
|
||||
{
|
||||
if (!t)
|
||||
return;
|
||||
|
||||
auto &weaks_ = weaks();
|
||||
auto l = weaks_.find(t);
|
||||
if (l == weaks_.end())
|
||||
return;
|
||||
|
||||
for (auto &i : l->second.values)
|
||||
((WeakRef<T> *)i)->t = 0;
|
||||
|
||||
weaks_.erase(l);
|
||||
}
|
||||
|
||||
static void nullify (T *t)
|
||||
{
|
||||
if (!t)
|
||||
return;
|
||||
|
||||
auto lock = lock_of(m());
|
||||
return nullify(t);
|
||||
}
|
||||
|
||||
StrongPtr<T> ptr()
|
||||
{
|
||||
auto lock = lock_of(m());
|
||||
if (t)
|
||||
validate();
|
||||
|
||||
return StrongPtr<T>(t);
|
||||
}
|
||||
} ;
|
||||
|
||||
template<typename T>
|
||||
class WeakPtr;
|
||||
|
||||
template<typename T>
|
||||
class StrongPtr : public SmartPtrBase {
|
||||
|
||||
public:
|
||||
typedef T value_type;
|
||||
typedef T element_type;
|
||||
typedef T *pointer_type;
|
||||
|
||||
private:
|
||||
T *t = nullptr;
|
||||
|
||||
public:
|
||||
~StrongPtr ()
|
||||
{
|
||||
set(nullptr);
|
||||
}
|
||||
|
||||
// -------------------------
|
||||
|
||||
StrongPtr ()
|
||||
{
|
||||
}
|
||||
|
||||
StrongPtr (const T *_t)
|
||||
{
|
||||
set(_t);
|
||||
}
|
||||
|
||||
// -------------------------
|
||||
|
||||
StrongPtr(StrongPtr<T> &&rhs)
|
||||
{
|
||||
swap(std::move(rhs));
|
||||
}
|
||||
|
||||
StrongPtr(const StrongPtr<T> &rhs)
|
||||
{
|
||||
set(rhs);
|
||||
}
|
||||
|
||||
// -------------------------
|
||||
|
||||
template<typename U>
|
||||
StrongPtr(const StrongPtr<U> &rhs)
|
||||
{
|
||||
set(rhs);
|
||||
}
|
||||
|
||||
template<typename U>
|
||||
StrongPtr(StrongPtr<U> &&rhs)
|
||||
{
|
||||
swap(std::move(rhs));
|
||||
}
|
||||
|
||||
// -------------------------
|
||||
|
||||
StrongPtr &operator =(const StrongPtr<T> &rhs)
|
||||
{
|
||||
set(rhs);
|
||||
return *this;
|
||||
}
|
||||
|
||||
StrongPtr &operator =(StrongPtr<T> &&rhs)
|
||||
{
|
||||
swap(std::move(rhs));
|
||||
return *this;
|
||||
}
|
||||
|
||||
// -------------------------
|
||||
|
||||
operator bool() const
|
||||
{
|
||||
return t != nullptr;
|
||||
}
|
||||
|
||||
bool operator !() const
|
||||
{
|
||||
return t == nullptr;
|
||||
}
|
||||
|
||||
template<typename U>
|
||||
StrongPtr<U> cast() const
|
||||
{
|
||||
auto *u = dynamic_cast<U *>(t);
|
||||
debug_assert((void *)u == (void *)t || u == nullptr);
|
||||
return StrongPtr<U>(u);
|
||||
}
|
||||
|
||||
template<typename U>
|
||||
U *&move () const
|
||||
{
|
||||
debug_assert(static_cast<T *>(static_cast<U *>(t))==t);
|
||||
return (U *&)t;
|
||||
}
|
||||
|
||||
T *ptr() const
|
||||
{
|
||||
return t;
|
||||
}
|
||||
|
||||
T *get() const
|
||||
{
|
||||
return t;
|
||||
}
|
||||
|
||||
operator T *() const
|
||||
{
|
||||
return t;
|
||||
}
|
||||
|
||||
T &operator *() const
|
||||
{
|
||||
return *t;
|
||||
}
|
||||
|
||||
T *operator -> () const
|
||||
{
|
||||
return t;
|
||||
}
|
||||
|
||||
bool operator == (const T *_t) const
|
||||
{
|
||||
return t == _t;
|
||||
}
|
||||
|
||||
bool operator == (const StrongPtr<T> &_t) const
|
||||
{
|
||||
return t == _t.t;
|
||||
}
|
||||
|
||||
bool operator != (const StrongPtr<T> &_t) const
|
||||
{
|
||||
return t != _t.t;
|
||||
}
|
||||
|
||||
bool operator <(const StrongPtr<T> &rhs) const
|
||||
{
|
||||
return t < rhs.t;
|
||||
}
|
||||
|
||||
WeakPtr<T> weak() const
|
||||
{
|
||||
auto l = lock_of(m());
|
||||
return WeakPtr<T>(t ? new WeakRef<T>(t) : nullptr);
|
||||
}
|
||||
|
||||
private:
|
||||
#ifdef MEMORY_PTR_DEBUG_ALLOCATIONS
|
||||
void on_swap_no_lock(T *l, T *r, void *lp, void *rp)
|
||||
{
|
||||
if (l == r)
|
||||
return;
|
||||
|
||||
auto &items_ = items();
|
||||
|
||||
if (l != 0)
|
||||
{
|
||||
auto i = items_.find(l);
|
||||
i->second.ids.erase(lp);
|
||||
i->second.ids.insert(rp);
|
||||
}
|
||||
|
||||
if (r != 0)
|
||||
{
|
||||
auto i = items_.find(r);
|
||||
i->second.ids.erase(rp);
|
||||
i->second.ids.insert(lp);
|
||||
}
|
||||
}
|
||||
#else
|
||||
void on_swap_no_lock(T *l, T *r, void *lp, void *rp) {}
|
||||
#endif
|
||||
|
||||
T *set_return_deferred_delete_no_lock(const T *_t)
|
||||
{
|
||||
if (t == _t)
|
||||
return nullptr;
|
||||
|
||||
T *deferredDelete = nullptr;
|
||||
auto &items_ = items();
|
||||
|
||||
if (t != 0)
|
||||
{
|
||||
LogDebugStrongPtr(logOfThis(this) << type_id<T>().name() << ": this" << logOfThis(this) << " -> " << t << " #" << getInfoFor(t) << "--");
|
||||
|
||||
auto i = items_.find(t);
|
||||
|
||||
debug_assert(i != items_.end());
|
||||
i->second.count--;
|
||||
|
||||
#ifdef MEMORY_PTR_DEBUG_ALLOCATIONS
|
||||
i->second.ids.erase((void *)this);
|
||||
#endif
|
||||
|
||||
if (i->second.count == 0)
|
||||
{
|
||||
items_.erase (i);
|
||||
deferredDelete = t;
|
||||
WeakRef<T>::nullify_nolock(deferredDelete);
|
||||
}
|
||||
}
|
||||
|
||||
t = const_cast<T *>(_t);
|
||||
|
||||
if (t != 0)
|
||||
{
|
||||
auto i = items_.find(t);
|
||||
if (items_.find(t) != items_.end())
|
||||
{
|
||||
i->second.count++;
|
||||
#ifdef MEMORY_PTR_DEBUG_ALLOCATIONS
|
||||
i->second.ids.insert((void*)this);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
items_.insert(std::pair<T *, Item>(
|
||||
t,
|
||||
{
|
||||
1
|
||||
#ifdef MEMORY_PTR_DEBUG_TYPE
|
||||
, type_id<T>().name()
|
||||
#endif
|
||||
#ifdef MEMORY_PTR_DEBUG_ALLOCATIONS
|
||||
, { (void*)this }
|
||||
#endif
|
||||
}
|
||||
));
|
||||
WeakRef<T>::validate_nolock(t);
|
||||
}
|
||||
|
||||
LogDebugStrongPtr(logOfThis(this) << type_id<T>().name() << ": this" << logOfThis(this) << " -> " << t << " #" << getInfoFor(t));
|
||||
}
|
||||
|
||||
return deferredDelete;
|
||||
}
|
||||
|
||||
void set(const T *t_)
|
||||
{
|
||||
T *deferredDelete = nullptr;
|
||||
{
|
||||
auto l = lock_of(m());
|
||||
deferredDelete = set_return_deferred_delete_no_lock(t_);
|
||||
}
|
||||
|
||||
do_delete(deferredDelete);
|
||||
}
|
||||
|
||||
template<typename U>
|
||||
void set(const StrongPtr<U> &rhs)
|
||||
{
|
||||
T *deferredDelete = nullptr;
|
||||
{
|
||||
auto l = lock_of(m());
|
||||
deferredDelete = set_return_deferred_delete_no_lock(ptr_of(rhs));
|
||||
}
|
||||
|
||||
do_delete(deferredDelete);
|
||||
}
|
||||
|
||||
|
||||
template<typename U>
|
||||
void swap(StrongPtr<U> &&rhs)
|
||||
{
|
||||
auto l = lock_of(m());
|
||||
on_swap_no_lock(t, rhs.template move<T>(), this, &rhs);
|
||||
std::swap(t, rhs.template move<T>());
|
||||
}
|
||||
|
||||
void do_delete(T *t)
|
||||
{
|
||||
if (t)
|
||||
{
|
||||
LogDebugStrongPtr(logOfThis(this) << type_id<T>().name() << ":" << t << " # deferredDelete");
|
||||
|
||||
onStrongPtrDelete(t);
|
||||
deallocate(t);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class WeakPtr
|
||||
{
|
||||
private:
|
||||
StrongPtr<WeakRef<T> > t;
|
||||
|
||||
protected:
|
||||
|
||||
public:
|
||||
WeakPtr () {}
|
||||
WeakPtr (WeakRef<T> *rhs) : t(rhs) {}
|
||||
WeakPtr (const WeakPtr<T> &rhs) : t(rhs.t) {}
|
||||
WeakPtr (WeakPtr<T> &&rhs) : t(std::move(rhs.t)) {}
|
||||
|
||||
WeakPtr &operator =(const WeakPtr<T> &rhs)
|
||||
{
|
||||
t = rhs.t;
|
||||
return *this;
|
||||
}
|
||||
|
||||
WeakPtr &operator =(WeakPtr<T> &&rhs)
|
||||
{
|
||||
t = std::move(rhs.t);
|
||||
return *this;
|
||||
}
|
||||
|
||||
StrongPtr<T> ptr() const
|
||||
{
|
||||
return t ? t->ptr() : nullptr;
|
||||
}
|
||||
} ;
|
||||
|
||||
// ------------------------------------------------
|
||||
|
||||
|
||||
template<typename T>
|
||||
size_t refCount (T *that)
|
||||
{
|
||||
return SmartPtrBase::refCount(that);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
StrongPtr<T> strong (T *t)
|
||||
{
|
||||
return StrongPtr<T>(t);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
StrongPtr<T> strong (const StrongPtr<T> &t)
|
||||
{
|
||||
return t;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
WeakPtr<T> weak (const StrongPtr<T> &t)
|
||||
{
|
||||
return t.weak();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
StrongPtr<T> strong_this (T *that)
|
||||
{
|
||||
debug_assert(refCount(that) > 0);
|
||||
auto s = strong(that);
|
||||
return s;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
StrongPtr<T> ref_this(T *that)
|
||||
{
|
||||
auto l = lock_of(SmartPtrBase::m());
|
||||
if (refCount(that) > 0)
|
||||
return strong(that);
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
WeakPtr<T> weak_this (T *that)
|
||||
{
|
||||
// auto s = strong_this(that);
|
||||
// return s.weak();
|
||||
|
||||
return WeakPtr<T>(new WeakRef<T>(that));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
||||
68
tjp/core/ptr/using_maps/_tests/Ptr.cpp
Executable file
68
tjp/core/ptr/using_maps/_tests/Ptr.cpp
Executable file
@@ -0,0 +1,68 @@
|
||||
// License: Modified MIT (NON-AI)
|
||||
// See the LICENSE file in the root directory for license information.
|
||||
// Copyright 2025 Timothy Prepscius
|
||||
|
||||
#include <tjp/core/ptr/using_maps/Ptr.hpp>
|
||||
#include <tjp/core/testing/catch.hpp>
|
||||
|
||||
namespace tjp::core::ptr::using_maps {
|
||||
namespace {
|
||||
|
||||
//SmartPtrBase::Items SmartPtrBase::items;
|
||||
//SmartPtrBase::Weaks SmartPtrBase::weaks;
|
||||
//Mutex SmartPtrBase::m;
|
||||
|
||||
struct Deletable {
|
||||
size_t &flag;
|
||||
Deletable(size_t &flag_) : flag(flag_) {}
|
||||
~Deletable() { flag++; }
|
||||
} ;
|
||||
|
||||
|
||||
SCENARIO("core::ptr::using_maps::custom_ptr")
|
||||
{
|
||||
size_t deleteFlag = 0;
|
||||
GIVEN("ptr")
|
||||
{
|
||||
|
||||
auto *v = new Deletable(deleteFlag);
|
||||
auto p1 = strong(v);
|
||||
|
||||
WHEN("referenced only once")
|
||||
{
|
||||
REQUIRE(refCount(v) == 1);
|
||||
}
|
||||
|
||||
WHEN("referenced")
|
||||
{
|
||||
auto p2 = p1;
|
||||
|
||||
THEN("references is 2")
|
||||
{
|
||||
REQUIRE(refCount(v) == 2);
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("referenced and removed")
|
||||
{
|
||||
{
|
||||
auto p2 = p1;
|
||||
}
|
||||
|
||||
THEN("references is 1")
|
||||
{
|
||||
REQUIRE(refCount(v) == 1);
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("item is deleted")
|
||||
{
|
||||
p1 = (Deletable *)nullptr;
|
||||
REQUIRE(refCount(v) == 0);
|
||||
REQUIRE(deleteFlag == 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
Reference in New Issue
Block a user