flatten 20260225

This commit is contained in:
Timothy Prepscius
2026-02-25 12:43:06 -05:00
commit 996151a56a
521 changed files with 46722 additions and 0 deletions

18
tjp/core/ptr/Ptr+IO.h Executable file
View 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
View 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
View 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
View 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
View 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
View 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

View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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

View 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

View 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

View 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

View 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

View 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
View 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
View 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
View 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
View 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

View 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

View 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

View 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

View 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

View 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
View 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
View 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
View 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

View 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