Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 15 additions & 24 deletions cpp/Platform.Disposables/DisposableBase.h
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
namespace Platform::Disposables
#pragma once
#include <atomic>
#include <string>
#include <typeinfo>
#include <cstdint>

namespace Platform::Disposables
{
class DisposableBase : public IDisposable
{
private: static readonly ConcurrentStack<WeakReference<DisposableBase>> _disposablesWeekReferencesStack = ConcurrentStack<WeakReference<DisposableBase>>();

private: volatile std::int32_t _disposed;
private: std::atomic<std::int32_t> _disposed;

public: bool IsDisposed()
{
return _disposed > 0;
return _disposed.load() > 0;
}

protected: virtual std::string ObjectName()
Expand All @@ -26,12 +31,10 @@
return false;
}

static DisposableBase() { std::atexit(OnProcessExit); }

protected: DisposableBase()
{
_disposed = 0;
_disposablesWeekReferencesStack.Push(WeakReference<DisposableBase>(this, false));
}

~DisposableBase() { Destruct(); }
Expand All @@ -41,14 +44,13 @@
public: void Dispose()
{
this->Dispose(true);
GC.SuppressFinalize(this);
}

public: void Destruct()
{
try
{
if (!IsDisposed)
if (!IsDisposed())
{
this->Dispose(false);
}
Expand All @@ -61,28 +63,17 @@

protected: virtual void Dispose(bool manual)
{
auto originalDisposedValue = Interlocked.CompareExchange(ref _disposed, 1, 0);
auto wasDisposed = originalDisposedValue > 0;
if (wasDisposed && !AllowMultipleDisposeCalls && manual)
std::int32_t expected = 0;
auto wasDisposed = !_disposed.compare_exchange_strong(expected, 1);
if (wasDisposed && !AllowMultipleDisposeCalls() && manual)
{
Platform::Disposables::EnsureExtensions::NotDisposed(Platform::Exceptions::Ensure::Always, this, ObjectName, "Multiple dispose calls are not allowed. Override AllowMultipleDisposeCalls property to modify behavior.");
Platform::Disposables::EnsureExtensions::NotDisposed(Platform::Exceptions::Ensure::Always, this, ObjectName(), "Multiple dispose calls are not allowed. Override AllowMultipleDisposeCalls property to modify behavior.");
}
if (AllowMultipleDisposeAttempts || !wasDisposed)
if (AllowMultipleDisposeAttempts() || !wasDisposed)
{
this->Dispose(manual, wasDisposed);
}
}

private: static void OnProcessExit()
{
while (_disposablesWeekReferencesStack.TryPop(out WeakReference<DisposableBase> weakReference))
{
if (weakReference.TryGetTarget(out DisposableBase disposable))
{
GC.SuppressFinalize(disposable);
disposable.Destruct();
}
}
}
};
}
Binary file added experiments/test_compilation
Binary file not shown.
83 changes: 83 additions & 0 deletions experiments/test_compilation.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
#include <iostream>
#include <atomic>
#include <string>
#include <typeinfo>
#include <cstdint>

// Mock System::IDisposable
namespace System
{
class IDisposable
{
public:
virtual void Dispose() = 0;
};
}

// Mock Platform::Disposables::IDisposable
namespace Platform::Disposables
{
class IDisposable : public System::IDisposable
{
public:
virtual bool IsDisposed() = 0;
virtual void Destruct() = 0;
};
}

// Mock Platform::Exceptions::ExceptionExtensions
namespace Platform::Exceptions
{
class ExceptionExtensions
{
public:
static void Ignore(const std::exception& exception)
{
// Mock implementation
}
};

class Ensure
{
public:
static Ensure Always;
};

Ensure Ensure::Always;
}

// Mock Platform::Disposables::EnsureExtensions
namespace Platform::Disposables
{
class EnsureExtensions
{
public:
static void NotDisposed(Platform::Exceptions::Ensure& ensure, void* obj, const std::string& name, const std::string& message)
{
// Mock implementation - throw an exception
throw std::runtime_error(message);
}
};
}

// Include the actual DisposableBase
#include "../cpp/Platform.Disposables/DisposableBase.h"

// Test implementation
class TestDisposable : public Platform::Disposables::DisposableBase
{
protected:
void Dispose(bool manual, bool wasDisposed) override
{
std::cout << "TestDisposable::Dispose called with manual=" << manual << ", wasDisposed=" << wasDisposed << std::endl;
}
};

int main()
{
TestDisposable test;
std::cout << "IsDisposed before: " << test.IsDisposed() << std::endl;
test.Platform::Disposables::DisposableBase::Dispose();
std::cout << "IsDisposed after: " << test.IsDisposed() << std::endl;
return 0;
}
Loading