mirror of
https://github.com/RPCS3/rpcs3.git
synced 2024-11-25 12:12:50 +01:00
f63e89f9b4
Moved Atomic.h to util/atomic.hpp List source files in CMakeLists.txt
152 lines
2.5 KiB
C++
152 lines
2.5 KiB
C++
#pragma once
|
|
|
|
#include "util/atomic.hpp"
|
|
#include <memory>
|
|
#include <cstddef>
|
|
|
|
// Unfinished. Only std::default_delete will work as expected.
|
|
template<typename T, typename D>
|
|
class atomic_ptr_base : D
|
|
{
|
|
protected:
|
|
atomic_t<T*> m_ptr;
|
|
|
|
constexpr atomic_ptr_base(T* ptr)
|
|
: m_ptr(ptr)
|
|
{
|
|
}
|
|
|
|
public:
|
|
~atomic_ptr_base()
|
|
{
|
|
if (m_ptr)
|
|
{
|
|
(*this)(m_ptr.load());
|
|
}
|
|
}
|
|
|
|
D& get_deleter()
|
|
{
|
|
return *this;
|
|
}
|
|
|
|
const D& get_deleter() const
|
|
{
|
|
return *this;
|
|
}
|
|
};
|
|
|
|
// Simple atomic pointer with unique ownership. Draft, unfinished.
|
|
template<typename T, typename D = std::default_delete<T>>
|
|
class atomic_ptr final : atomic_ptr_base<T, D>
|
|
{
|
|
using base = atomic_ptr_base<T, D>;
|
|
|
|
static_assert(sizeof(T*) == sizeof(base), "atomic_ptr<> error: invalid deleter (empty class expected)");
|
|
|
|
public:
|
|
constexpr atomic_ptr()
|
|
: base(nullptr)
|
|
{
|
|
}
|
|
|
|
constexpr atomic_ptr(std::nullptr_t)
|
|
: base(nullptr)
|
|
{
|
|
}
|
|
|
|
explicit atomic_ptr(T* ptr)
|
|
: base(ptr)
|
|
{
|
|
}
|
|
|
|
template<typename T2, typename = std::enable_if_t<std::is_convertible<T2, T>::value>>
|
|
atomic_ptr(std::unique_ptr<T2, D>&& ptr)
|
|
: base(ptr.release())
|
|
{
|
|
}
|
|
|
|
atomic_ptr& operator =(std::nullptr_t)
|
|
{
|
|
if (T* old = base::m_ptr.exchange(nullptr))
|
|
{
|
|
this->get_deleter()(old);
|
|
}
|
|
|
|
return *this;
|
|
}
|
|
|
|
template<typename T2, typename = std::enable_if_t<std::is_convertible<T2, T>::value>>
|
|
atomic_ptr& operator =(std::unique_ptr<T2, D>&& ptr)
|
|
{
|
|
if (T* old = base::m_ptr.exchange(ptr.release()))
|
|
{
|
|
this->get_deleter()(old);
|
|
}
|
|
|
|
return *this;
|
|
}
|
|
|
|
void swap(std::unique_ptr<T, D>& ptr)
|
|
{
|
|
ptr.reset(base::m_ptr.exchange(ptr.release()));
|
|
}
|
|
|
|
std::add_lvalue_reference_t<T> operator *() const
|
|
{
|
|
return *base::m_ptr;
|
|
}
|
|
|
|
T* operator ->() const
|
|
{
|
|
return base::m_ptr;
|
|
}
|
|
|
|
T* get() const
|
|
{
|
|
return base::m_ptr;
|
|
}
|
|
|
|
explicit operator bool() const
|
|
{
|
|
return base::m_ptr != nullptr;
|
|
}
|
|
|
|
T* release() const
|
|
{
|
|
return base::m_ptr.exchange(0);
|
|
}
|
|
|
|
void reset(T* ptr = nullptr)
|
|
{
|
|
if (T* old = base::m_ptr.exchange(ptr))
|
|
{
|
|
this->get_deleter()(old);
|
|
}
|
|
}
|
|
|
|
// Steal the pointer from `ptr`, convert old value to unique_ptr
|
|
std::unique_ptr<T, D> exchange(std::unique_ptr<T, D>&& ptr)
|
|
{
|
|
return std::unique_ptr<T, D>(base::m_ptr.exchange(ptr.release()));
|
|
}
|
|
|
|
// If pointer is null, steal it from `ptr`
|
|
bool test_and_swap(std::unique_ptr<T, D>&& ptr)
|
|
{
|
|
if (base::m_ptr.compare_and_swap_test(nullptr, ptr.get()))
|
|
{
|
|
ptr.release();
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
};
|
|
|
|
template<typename T, typename D>
|
|
class atomic_ptr<T[], D> final : atomic_ptr_base<T[], D>
|
|
{
|
|
// TODO
|
|
};
|