[K/N] Add kotlin::ManuallyScoped<T> ^KT-56233
kotlin::ManuallyScoped<T> is a wrapper over T that pins T in place and has a trivial constructor and destructor. Creation and destruction of T must be carried out manually by construct and destroy methods.
This commit is contained in:
committed by
Space Team
parent
6a0e6b11bd
commit
aad6d2c8f8
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* 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>
|
||||
class ManuallyScoped : private Pinned {
|
||||
public:
|
||||
// Construct T
|
||||
template <typename... Args>
|
||||
void construct(Args&&... args) noexcept(noexcept(T(std::forward<Args>(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:
|
||||
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)];
|
||||
};
|
||||
|
||||
} // namespace kotlin
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "ManuallyScoped.hpp"
|
||||
|
||||
#include "gmock/gmock.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
using namespace kotlin;
|
||||
|
||||
using ::testing::_;
|
||||
|
||||
namespace {
|
||||
|
||||
struct NonTrivialCtor {
|
||||
int x = 123;
|
||||
};
|
||||
|
||||
static_assert(!std::is_trivially_constructible_v<NonTrivialCtor>);
|
||||
static_assert(std::is_trivially_destructible_v<NonTrivialCtor>);
|
||||
static_assert(std::is_trivially_constructible_v<ManuallyScoped<NonTrivialCtor>>);
|
||||
static_assert(std::is_trivially_destructible_v<ManuallyScoped<NonTrivialCtor>>);
|
||||
|
||||
class NonTrivialDtor : private Pinned {
|
||||
public:
|
||||
explicit NonTrivialDtor(std::function<void(NonTrivialDtor*)> dtorHook) : dtorHook_(std::move(dtorHook)) {}
|
||||
|
||||
~NonTrivialDtor() { dtorHook_(this); }
|
||||
|
||||
private:
|
||||
std::function<void(NonTrivialDtor*)> dtorHook_;
|
||||
};
|
||||
|
||||
static_assert(!std::is_trivially_constructible_v<NonTrivialDtor>);
|
||||
static_assert(!std::is_trivially_destructible_v<NonTrivialDtor>);
|
||||
static_assert(std::is_trivially_constructible_v<ManuallyScoped<NonTrivialDtor>>);
|
||||
static_assert(std::is_trivially_destructible_v<ManuallyScoped<NonTrivialDtor>>);
|
||||
|
||||
} // namespace
|
||||
|
||||
class ManuallyScopedTest : public testing::Test {
|
||||
public:
|
||||
testing::MockFunction<void(NonTrivialDtor*)>& dtorHook() noexcept { return dtorHook_; }
|
||||
|
||||
private:
|
||||
testing::StrictMock<testing::MockFunction<void(NonTrivialDtor*)>> dtorHook_;
|
||||
};
|
||||
|
||||
TEST_F(ManuallyScopedTest, NonTrivialCtor) {
|
||||
ManuallyScoped<NonTrivialCtor> instance;
|
||||
instance.construct();
|
||||
EXPECT_THAT(instance->x, 123);
|
||||
}
|
||||
|
||||
TEST_F(ManuallyScopedTest, NonTrivialDtor) {
|
||||
ManuallyScoped<NonTrivialDtor> instance;
|
||||
instance.construct(dtorHook().AsStdFunction());
|
||||
EXPECT_CALL(dtorHook(), Call(&*instance));
|
||||
instance.destroy();
|
||||
}
|
||||
|
||||
TEST_F(ManuallyScopedTest, NonTrivialDtorLeak) {
|
||||
ManuallyScoped<NonTrivialDtor> instance;
|
||||
instance.construct(dtorHook().AsStdFunction());
|
||||
EXPECT_CALL(dtorHook(), Call(_)).Times(0);
|
||||
}
|
||||
Reference in New Issue
Block a user