tile/tile/base/handle.h
2024-12-19 14:39:59 +08:00

105 lines
2.2 KiB
C++

#ifndef TILE_BASE_HANDLE_H
#define TILE_BASE_HANDLE_H
#pragma once
#include "tile/base/logging.h"
#include <unistd.h>
namespace tile {
namespace detail {
struct HandleDeleter {
void operator()(int fd) const noexcept
{
if (fd == 0 || fd == -1) { return; }
TILE_PCHECK(::close(fd) == 0);
}
};
namespace handle {
template<typename T, typename... Args>
constexpr T
GetFirstArg(T first, Args...)
{
return first;
}
template<typename T>
constexpr bool
NotEqualToAnd(T val, T first)
{
return val != first;
}
template<typename T, typename... Args>
constexpr bool
NotEqualToAnd(T val, T first, Args... args)
{
return val != first && NotEqualToAnd(val, std::forward<Args>(args)...);
}
}// namespace handle
template<typename T, typename Deleter, T... kInvalidHandles>
class GenericHandle : private Deleter {
static constexpr T kDefaultInvalid = ::tile::detail::handle::GetFirstArg(kInvalidHandles...);
public:
GenericHandle() = default;
constexpr explicit GenericHandle(T handle) noexcept : handle_(handle) {}
~GenericHandle() { Reset(); }
GenericHandle(GenericHandle &&h) noexcept
{
handle_ = h.handle_;
h.handle_ = kDefaultInvalid;
}
GenericHandle &operator=(GenericHandle &&h) noexcept
{
if (&h == this) { return *this; }
handle_ = h.handle_;
h.handle_ = kDefaultInvalid;
return *this;
}
GenericHandle(const GenericHandle &) = delete;
GenericHandle &operator=(const GenericHandle &) = delete;
T *Retrieve() noexcept { return &handle_; }
constexpr T Get() const noexcept { return handle_; }
constexpr explicit operator bool() const noexcept
{
return ::tile::detail::handle::NotEqualToAnd(handle_, kInvalidHandles...);
}
TILE_NODISCARD T Leak() noexcept
{
int rc = handle_;
handle_ = kDefaultInvalid;
return rc;
}
void Reset(T new_value = kDefaultInvalid) noexcept
{
if (operator bool()) { Deleter::operator()(handle_); }
handle_ = new_value;
}
private:
T handle_ = kDefaultInvalid;
};
}// namespace detail
using Handle = detail::GenericHandle<int, detail::HandleDeleter, -1, 0>;
}// namespace tile
#endif// TILE_BASE_HANDLE_H