mirror of
https://github.com/mikage-emu/mikage-dev.git
synced 2025-01-09 06:50:59 +01:00
145 lines
4.4 KiB
C++
145 lines
4.4 KiB
C++
// Unique resource wrapper imported (and slightly modified) from
|
|
// https://github.com/tandasat/PgResarch (MIT licensed)
|
|
|
|
//
|
|
// N3949 - Scoped Resource - Generic RAII Wrapper for the Standard Library
|
|
// Peter Sommerlad and Andrew L. Sandoval
|
|
//
|
|
#ifndef UNIQUE_RESOURCE_H_
|
|
#define UNIQUE_RESOURCE_H_
|
|
|
|
#include <type_traits>
|
|
#include <utility>
|
|
|
|
#ifndef _MSC_VER
|
|
#define UNIQUE_RESOURCE_NOEXCEPT noexcept
|
|
#else
|
|
#define UNIQUE_RESOURCE_NOEXCEPT
|
|
#endif
|
|
|
|
#define UNIQUE_RESOURCE_TRY_BEGIN try {
|
|
#define UNIQUE_RESOURCE_CATCH_ALL } catch (...) {
|
|
#define UNIQUE_RESOURCE_CATCH_END }
|
|
|
|
|
|
namespace std {
|
|
namespace experimental {
|
|
|
|
enum class invoke_it { once, again };
|
|
|
|
template<typename R, typename D>
|
|
class unique_resource_t
|
|
{
|
|
R resource;
|
|
D deleter;
|
|
bool execute_on_destruction; // exposition only
|
|
unique_resource_t& operator=(unique_resource_t const &) = delete;
|
|
unique_resource_t(unique_resource_t const &) = delete; // no copies!
|
|
|
|
public:
|
|
// construction
|
|
explicit unique_resource_t(R && resource, D && deleter, bool shouldrun = true) UNIQUE_RESOURCE_NOEXCEPT
|
|
: resource(std::move(resource))
|
|
, deleter(std::move(deleter))
|
|
, execute_on_destruction{ shouldrun }
|
|
{}
|
|
|
|
// move
|
|
unique_resource_t(unique_resource_t &&other) UNIQUE_RESOURCE_NOEXCEPT
|
|
: resource(std::move(other.resource))
|
|
, deleter(std::move(other.deleter))
|
|
, execute_on_destruction{ other.execute_on_destruction }
|
|
{
|
|
other.release();
|
|
}
|
|
|
|
unique_resource_t& operator=(unique_resource_t &&other) UNIQUE_RESOURCE_NOEXCEPT
|
|
{
|
|
this->invoke(invoke_it::once);
|
|
deleter = std::move(other.deleter);
|
|
resource = std::move(other.resource);
|
|
execute_on_destruction = other.execute_on_destruction;
|
|
other.release();
|
|
return *this;
|
|
}
|
|
|
|
// resource release
|
|
~unique_resource_t()
|
|
{
|
|
this->invoke(invoke_it::once);
|
|
}
|
|
|
|
void invoke(invoke_it const strategy = invoke_it::once) UNIQUE_RESOURCE_NOEXCEPT
|
|
{
|
|
if (execute_on_destruction)
|
|
{
|
|
UNIQUE_RESOURCE_TRY_BEGIN
|
|
this->get_deleter()(resource);
|
|
UNIQUE_RESOURCE_CATCH_ALL
|
|
UNIQUE_RESOURCE_CATCH_END
|
|
}
|
|
execute_on_destruction = strategy == invoke_it::again;
|
|
}
|
|
|
|
R const & release() UNIQUE_RESOURCE_NOEXCEPT
|
|
{
|
|
execute_on_destruction = false;
|
|
return this->get();
|
|
}
|
|
|
|
void reset(R && newresource) UNIQUE_RESOURCE_NOEXCEPT
|
|
{
|
|
invoke(invoke_it::again);
|
|
resource = std::move(newresource);
|
|
}
|
|
|
|
// resource access
|
|
R const & get() const UNIQUE_RESOURCE_NOEXCEPT
|
|
{
|
|
return resource;
|
|
}
|
|
|
|
operator R const &() const UNIQUE_RESOURCE_NOEXCEPT
|
|
{
|
|
return resource;
|
|
}
|
|
|
|
R operator->() const UNIQUE_RESOURCE_NOEXCEPT
|
|
{
|
|
return resource;
|
|
}
|
|
|
|
std::add_lvalue_reference_t<std::remove_pointer_t<R>> operator*() const
|
|
{
|
|
return *resource;
|
|
}
|
|
|
|
// deleter access
|
|
const D & get_deleter() const UNIQUE_RESOURCE_NOEXCEPT
|
|
{
|
|
return deleter;
|
|
}
|
|
};
|
|
|
|
//factories
|
|
template<typename R, typename D>
|
|
unique_resource_t<R, D> unique_resource(R && r, D t) UNIQUE_RESOURCE_NOEXCEPT
|
|
{
|
|
return unique_resource_t<R, D>(std::move(r), std::move(t), true);
|
|
}
|
|
|
|
template<typename R, typename D>
|
|
unique_resource_t<R, D> unique_resource_checked(R r, R invalid, D t) UNIQUE_RESOURCE_NOEXCEPT
|
|
{
|
|
bool shouldrun = (r != invalid);
|
|
return unique_resource_t<R, D>(std::move(r), std::move(t), shouldrun);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
#undef UNIQUE_RESOURCE_TRY_BEGIN
|
|
#undef UNIQUE_RESOURCE_CATCH_ALL
|
|
#undef UNIQUE_RESOURCE_CATCH_END
|
|
#undef UNIQUE_RESOURCE_NOEXCEPT
|
|
#endif /* UNIQUE RESOURCE H */
|