#ifndef ABSL_BASE_NO_DESTRUCTOR_H_
#define ABSL_BASE_NO_DESTRUCTOR_H_
#include <new>
#include <type_traits>
#include <utility>
#include "absl/base/config.h"
#include "absl/base/nullability.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
template <typename T>
class NoDestructor {
public:
template <typename... Ts,
typename std::enable_if<!std::is_same<void(std::decay_t<Ts>&...),
void(NoDestructor&)>::value,
int>::type = 0>
explicit constexpr NoDestructor(Ts&&... args)
: impl_(std::forward<Ts>(args)...) {}
explicit constexpr NoDestructor(const T& x) : impl_(x) {}
explicit constexpr NoDestructor(T&& x)
: impl_(std::move(x)) {}
NoDestructor(const NoDestructor&) = delete;
NoDestructor& operator=(const NoDestructor&) = delete;
T& operator*() { return *get(); }
absl::Nonnull<T*> operator->() { return get(); }
absl::Nonnull<T*> get() { return impl_.get(); }
const T& operator*() const { return *get(); }
absl::Nonnull<const T*> operator->() const { return get(); }
absl::Nonnull<const T*> get() const { return impl_.get(); }
private:
class DirectImpl {
public:
template <typename... Args>
explicit constexpr DirectImpl(Args&&... args)
: value_(std::forward<Args>(args)...) {}
absl::Nonnull<const T*> get() const { return &value_; }
absl::Nonnull<T*> get() { return &value_; }
private:
T value_;
};
class PlacementImpl {
public:
template <typename... Args>
explicit PlacementImpl(Args&&... args) {
new (&space_) T(std::forward<Args>(args)...);
}
absl::Nonnull<const T*> get() const {
return Launder(reinterpret_cast<const T*>(&space_));
}
absl::Nonnull<T*> get() { return Launder(reinterpret_cast<T*>(&space_)); }
private:
template <typename P>
static absl::Nonnull<P*> Launder(absl::Nonnull<P*> p) {
#if defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606L
return std::launder(p);
#elif ABSL_HAVE_BUILTIN(__builtin_launder)
return __builtin_launder(p);
#else
#if defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wstrict-aliasing"
#endif
return p;
#if defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic pop
#endif
#endif
}
alignas(T) unsigned char space_[sizeof(T)];
};
std::conditional_t<std::is_trivially_destructible<T>::value, DirectImpl,
PlacementImpl>
impl_;
};
#ifdef ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION
template <typename T>
NoDestructor(T) -> NoDestructor<T>;
#endif
ABSL_NAMESPACE_END
}
#endif