blob: 838a43175260ba87318c002d6f84aa4b42a6dd1c [file]
/*
* Copyright 2010-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
#pragma once
#include <type_traits>
#include <utility>
#include "Utils.hpp"
namespace kotlin {
// Like T but must be manually constructed and destroyed.
template <typename T, bool kChecked = false>
class ManuallyScoped : private Pinned {
public:
// Construct T
template <typename... Args>
void construct(Args&&... args) noexcept(std::is_nothrow_constructible_v<T, Args...>) {
new (impl()) T(std::forward<Args>(args)...);
}
// Destroy T
void destroy() noexcept { impl()->~T(); }
T& operator*() noexcept { return *impl(); }
T* operator->() noexcept { return impl(); }
const T& operator*() const noexcept { return *impl(); }
const T* operator->() const noexcept { return impl(); }
private:
__attribute__((used)) T* impl() noexcept { return reinterpret_cast<T*>(implStorage_); }
const T* impl() const noexcept { return reinterpret_cast<const T*>(implStorage_); }
alignas(T) char implStorage_[sizeof(T)];
};
template <typename T>
class ManuallyScoped<T, true> : private Pinned {
public:
ManuallyScoped() : constructed_(false) {}
~ManuallyScoped() { assertDestroyed(); }
// Construct T
template <typename... Args>
void construct(Args&&... args) noexcept(noexcept(T(std::forward<Args>(args)...))) {
assertDestroyed();
impl_.construct(std::forward<Args>(args)...);
constructed_ = true;
}
// Destroy T
void destroy() noexcept {
assertConstructed();
impl_.destroy();
constructed_ = false;
}
T& operator*() noexcept { return *impl(); }
T* operator->() noexcept { return impl(); }
const T& operator*() const noexcept { return *impl(); }
const T* operator->() const noexcept { return impl(); }
private:
T* impl() noexcept {
assertConstructed();
return &*impl_;
}
const T* impl() const noexcept {
assertConstructed();
return &*impl_;
}
ALWAYS_INLINE void assertConstructed() const noexcept {
RuntimeAssert(constructed_, "ManuallyScoped value must have been constructed by this point");
}
ALWAYS_INLINE void assertDestroyed() const noexcept {
RuntimeAssert(!constructed_, "ManuallyScoped value must have been destroyed by this point");
}
bool constructed_;
ManuallyScoped<T, false> impl_;
};
} // namespace kotlin