mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #8931 from random-internet-cat/lazy-init
Add LazyInit
This commit is contained in:
commit
2d1e7d9504
@ -153,10 +153,10 @@ FunctionDefinition const* ContractDefinition::receiveFunction() const
|
||||
|
||||
vector<EventDefinition const*> const& ContractDefinition::interfaceEvents() const
|
||||
{
|
||||
if (!m_interfaceEvents)
|
||||
{
|
||||
return m_interfaceEvents.init([&]{
|
||||
set<string> eventsSeen;
|
||||
m_interfaceEvents = make_unique<vector<EventDefinition const*>>();
|
||||
vector<EventDefinition const*> interfaceEvents;
|
||||
|
||||
for (ContractDefinition const* contract: annotation().linearizedBaseContracts)
|
||||
for (EventDefinition const* e: contract->events())
|
||||
{
|
||||
@ -169,19 +169,20 @@ vector<EventDefinition const*> const& ContractDefinition::interfaceEvents() cons
|
||||
if (eventsSeen.count(eventSignature) == 0)
|
||||
{
|
||||
eventsSeen.insert(eventSignature);
|
||||
m_interfaceEvents->push_back(e);
|
||||
interfaceEvents.push_back(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
return *m_interfaceEvents;
|
||||
|
||||
return interfaceEvents;
|
||||
});
|
||||
}
|
||||
|
||||
vector<pair<util::FixedHash<4>, FunctionTypePointer>> const& ContractDefinition::interfaceFunctionList(bool _includeInheritedFunctions) const
|
||||
{
|
||||
if (!m_interfaceFunctionList[_includeInheritedFunctions])
|
||||
{
|
||||
return m_interfaceFunctionList[_includeInheritedFunctions].init([&]{
|
||||
set<string> signaturesSeen;
|
||||
m_interfaceFunctionList[_includeInheritedFunctions] = make_unique<vector<pair<util::FixedHash<4>, FunctionTypePointer>>>();
|
||||
vector<pair<util::FixedHash<4>, FunctionTypePointer>> interfaceFunctionList;
|
||||
|
||||
for (ContractDefinition const* contract: annotation().linearizedBaseContracts)
|
||||
{
|
||||
if (_includeInheritedFunctions == false && contract != this)
|
||||
@ -203,12 +204,13 @@ vector<pair<util::FixedHash<4>, FunctionTypePointer>> const& ContractDefinition:
|
||||
{
|
||||
signaturesSeen.insert(functionSignature);
|
||||
util::FixedHash<4> hash(util::keccak256(functionSignature));
|
||||
m_interfaceFunctionList[_includeInheritedFunctions]->emplace_back(hash, fun);
|
||||
interfaceFunctionList.emplace_back(hash, fun);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return *m_interfaceFunctionList[_includeInheritedFunctions];
|
||||
|
||||
return interfaceFunctionList;
|
||||
});
|
||||
}
|
||||
|
||||
TypePointer ContractDefinition::type() const
|
||||
|
@ -31,6 +31,7 @@
|
||||
#include <liblangutil/SourceLocation.h>
|
||||
#include <libevmasm/Instruction.h>
|
||||
#include <libsolutil/FixedHash.h>
|
||||
#include <libsolutil/LazyInit.h>
|
||||
|
||||
#include <boost/noncopyable.hpp>
|
||||
#include <json/json.h>
|
||||
@ -536,8 +537,8 @@ private:
|
||||
ContractKind m_contractKind;
|
||||
bool m_abstract{false};
|
||||
|
||||
mutable std::unique_ptr<std::vector<std::pair<util::FixedHash<4>, FunctionTypePointer>>> m_interfaceFunctionList[2];
|
||||
mutable std::unique_ptr<std::vector<EventDefinition const*>> m_interfaceEvents;
|
||||
util::LazyInit<std::vector<std::pair<util::FixedHash<4>, FunctionTypePointer>>> m_interfaceFunctionList[2];
|
||||
util::LazyInit<std::vector<EventDefinition const*>> m_interfaceEvents;
|
||||
};
|
||||
|
||||
class InheritanceSpecifier: public ASTNode
|
||||
|
@ -207,26 +207,31 @@ void MemberList::combine(MemberList const & _other)
|
||||
|
||||
pair<u256, unsigned> const* MemberList::memberStorageOffset(string const& _name) const
|
||||
{
|
||||
if (!m_storageOffsets)
|
||||
{
|
||||
TypePointers memberTypes;
|
||||
memberTypes.reserve(m_memberTypes.size());
|
||||
for (auto const& member: m_memberTypes)
|
||||
memberTypes.push_back(member.type);
|
||||
m_storageOffsets = std::make_unique<StorageOffsets>();
|
||||
m_storageOffsets->computeOffsets(memberTypes);
|
||||
}
|
||||
StorageOffsets const& offsets = storageOffsets();
|
||||
|
||||
for (size_t index = 0; index < m_memberTypes.size(); ++index)
|
||||
if (m_memberTypes[index].name == _name)
|
||||
return m_storageOffsets->offset(index);
|
||||
return offsets.offset(index);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
u256 const& MemberList::storageSize() const
|
||||
{
|
||||
// trigger lazy computation
|
||||
memberStorageOffset("");
|
||||
return m_storageOffsets->storageSize();
|
||||
return storageOffsets().storageSize();
|
||||
}
|
||||
|
||||
StorageOffsets const& MemberList::storageOffsets() const {
|
||||
return m_storageOffsets.init([&]{
|
||||
TypePointers memberTypes;
|
||||
memberTypes.reserve(m_memberTypes.size());
|
||||
for (auto const& member: m_memberTypes)
|
||||
memberTypes.push_back(member.type);
|
||||
|
||||
StorageOffsets storageOffsets;
|
||||
storageOffsets.computeOffsets(memberTypes);
|
||||
|
||||
return storageOffsets;
|
||||
});
|
||||
}
|
||||
|
||||
/// Helper functions for type identifier
|
||||
|
@ -29,6 +29,7 @@
|
||||
|
||||
#include <libsolutil/Common.h>
|
||||
#include <libsolutil/CommonIO.h>
|
||||
#include <libsolutil/LazyInit.h>
|
||||
#include <libsolutil/Result.h>
|
||||
|
||||
#include <boost/rational.hpp>
|
||||
@ -139,8 +140,10 @@ public:
|
||||
MemberMap::const_iterator end() const { return m_memberTypes.end(); }
|
||||
|
||||
private:
|
||||
StorageOffsets const& storageOffsets() const;
|
||||
|
||||
MemberMap m_memberTypes;
|
||||
mutable std::unique_ptr<StorageOffsets> m_storageOffsets;
|
||||
util::LazyInit<StorageOffsets> m_storageOffsets;
|
||||
};
|
||||
|
||||
static_assert(std::is_nothrow_move_constructible<MemberList>::value, "MemberList should be noexcept move constructible");
|
||||
|
@ -733,11 +733,7 @@ Json::Value const& CompilerStack::contractABI(Contract const& _contract) const
|
||||
|
||||
solAssert(_contract.contract, "");
|
||||
|
||||
// caches the result
|
||||
if (!_contract.abi)
|
||||
_contract.abi = make_unique<Json::Value>(ABI::generate(*_contract.contract));
|
||||
|
||||
return *_contract.abi;
|
||||
return _contract.abi.init([&]{ return ABI::generate(*_contract.contract); });
|
||||
}
|
||||
|
||||
Json::Value const& CompilerStack::storageLayout(string const& _contractName) const
|
||||
@ -755,11 +751,7 @@ Json::Value const& CompilerStack::storageLayout(Contract const& _contract) const
|
||||
|
||||
solAssert(_contract.contract, "");
|
||||
|
||||
// caches the result
|
||||
if (!_contract.storageLayout)
|
||||
_contract.storageLayout = make_unique<Json::Value>(StorageLayout().generate(*_contract.contract));
|
||||
|
||||
return *_contract.storageLayout;
|
||||
return _contract.storageLayout.init([&]{ return StorageLayout().generate(*_contract.contract); });
|
||||
}
|
||||
|
||||
Json::Value const& CompilerStack::natspecUser(string const& _contractName) const
|
||||
@ -777,11 +769,7 @@ Json::Value const& CompilerStack::natspecUser(Contract const& _contract) const
|
||||
|
||||
solAssert(_contract.contract, "");
|
||||
|
||||
// caches the result
|
||||
if (!_contract.userDocumentation)
|
||||
_contract.userDocumentation = make_unique<Json::Value>(Natspec::userDocumentation(*_contract.contract));
|
||||
|
||||
return *_contract.userDocumentation;
|
||||
return _contract.userDocumentation.init([&]{ return Natspec::userDocumentation(*_contract.contract); });
|
||||
}
|
||||
|
||||
Json::Value const& CompilerStack::natspecDev(string const& _contractName) const
|
||||
@ -799,11 +787,7 @@ Json::Value const& CompilerStack::natspecDev(Contract const& _contract) const
|
||||
|
||||
solAssert(_contract.contract, "");
|
||||
|
||||
// caches the result
|
||||
if (!_contract.devDocumentation)
|
||||
_contract.devDocumentation = make_unique<Json::Value>(Natspec::devDocumentation(*_contract.contract));
|
||||
|
||||
return *_contract.devDocumentation;
|
||||
return _contract.devDocumentation.init([&]{ return Natspec::devDocumentation(*_contract.contract); });
|
||||
}
|
||||
|
||||
Json::Value CompilerStack::methodIdentifiers(string const& _contractName) const
|
||||
@ -832,11 +816,7 @@ string const& CompilerStack::metadata(Contract const& _contract) const
|
||||
|
||||
solAssert(_contract.contract, "");
|
||||
|
||||
// cache the result
|
||||
if (!_contract.metadata)
|
||||
_contract.metadata = make_unique<string>(createMetadata(_contract));
|
||||
|
||||
return *_contract.metadata;
|
||||
return _contract.metadata.init([&]{ return createMetadata(_contract); });
|
||||
}
|
||||
|
||||
Scanner const& CompilerStack::scanner(string const& _sourceName) const
|
||||
|
@ -37,6 +37,7 @@
|
||||
|
||||
#include <libsolutil/Common.h>
|
||||
#include <libsolutil/FixedHash.h>
|
||||
#include <libsolutil/LazyInit.h>
|
||||
|
||||
#include <boost/noncopyable.hpp>
|
||||
#include <json/json.h>
|
||||
@ -342,11 +343,11 @@ private:
|
||||
std::string yulIROptimized; ///< Optimized experimental Yul IR code.
|
||||
std::string ewasm; ///< Experimental Ewasm text representation
|
||||
evmasm::LinkerObject ewasmObject; ///< Experimental Ewasm code
|
||||
mutable std::unique_ptr<std::string const> metadata; ///< The metadata json that will be hashed into the chain.
|
||||
mutable std::unique_ptr<Json::Value const> abi;
|
||||
mutable std::unique_ptr<Json::Value const> storageLayout;
|
||||
mutable std::unique_ptr<Json::Value const> userDocumentation;
|
||||
mutable std::unique_ptr<Json::Value const> devDocumentation;
|
||||
util::LazyInit<std::string const> metadata; ///< The metadata json that will be hashed into the chain.
|
||||
util::LazyInit<Json::Value const> abi;
|
||||
util::LazyInit<Json::Value const> storageLayout;
|
||||
util::LazyInit<Json::Value const> userDocumentation;
|
||||
util::LazyInit<Json::Value const> devDocumentation;
|
||||
mutable std::unique_ptr<std::string const> sourceMapping;
|
||||
mutable std::unique_ptr<std::string const> runtimeSourceMapping;
|
||||
};
|
||||
|
@ -19,6 +19,7 @@ set(sources
|
||||
JSON.h
|
||||
Keccak256.cpp
|
||||
Keccak256.h
|
||||
LazyInit.h
|
||||
picosha2.h
|
||||
Result.h
|
||||
StringUtils.cpp
|
||||
|
94
libsolutil/LazyInit.h
Normal file
94
libsolutil/LazyInit.h
Normal file
@ -0,0 +1,94 @@
|
||||
/*
|
||||
This file is part of solidity.
|
||||
|
||||
solidity is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
solidity is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with solidity. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <libsolutil/Assertions.h>
|
||||
#include <libsolutil/Exceptions.h>
|
||||
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace solidity::util
|
||||
{
|
||||
|
||||
DEV_SIMPLE_EXCEPTION(BadLazyInitAccess);
|
||||
|
||||
/**
|
||||
* A value that is initialized at some point after construction of the LazyInit. The stored value can only be accessed
|
||||
* while calling "init", which initializes the stored value (if it has not already been initialized).
|
||||
*
|
||||
* @tparam T the type of the stored value; may not be a function, reference, array, or void type; may be const-qualified.
|
||||
*/
|
||||
template<typename T>
|
||||
class LazyInit
|
||||
{
|
||||
public:
|
||||
using value_type = T;
|
||||
|
||||
static_assert(std::is_object_v<value_type>, "Function, reference, and void types are not supported");
|
||||
static_assert(!std::is_array_v<value_type>, "Array types are not supported.");
|
||||
static_assert(!std::is_volatile_v<value_type>, "Volatile-qualified types are not supported.");
|
||||
|
||||
LazyInit() = default;
|
||||
|
||||
LazyInit(LazyInit const&) = delete;
|
||||
LazyInit& operator=(LazyInit const&) = delete;
|
||||
|
||||
// Move constructor must be overridden to ensure that moved-from object is left empty.
|
||||
constexpr LazyInit(LazyInit&& _other) noexcept:
|
||||
m_value(std::move(_other.m_value))
|
||||
{
|
||||
_other.m_value.reset();
|
||||
}
|
||||
|
||||
LazyInit& operator=(LazyInit&& _other) noexcept
|
||||
{
|
||||
this->m_value.swap(_other.m_value);
|
||||
_other.m_value.reset();
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
value_type& init(F&& _fun)
|
||||
{
|
||||
doInit(std::forward<F>(_fun));
|
||||
return m_value.value();
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
value_type const& init(F&& _fun) const
|
||||
{
|
||||
doInit(std::forward<F>(_fun));
|
||||
return m_value.value();
|
||||
}
|
||||
|
||||
private:
|
||||
/// Although not quite logically const, this is marked const for pragmatic reasons. It doesn't change the platonic
|
||||
/// value of the object (which is something that is initialized to some computed value on first use).
|
||||
template<typename F>
|
||||
void doInit(F&& _fun) const
|
||||
{
|
||||
if (!m_value.has_value())
|
||||
m_value.emplace(std::forward<F>(_fun)());
|
||||
}
|
||||
|
||||
mutable std::optional<value_type> m_value;
|
||||
};
|
||||
|
||||
}
|
@ -34,6 +34,7 @@ set(libsolutil_sources
|
||||
libsolutil/IterateReplacing.cpp
|
||||
libsolutil/JSON.cpp
|
||||
libsolutil/Keccak256.cpp
|
||||
libsolutil/LazyInit.cpp
|
||||
libsolutil/StringUtils.cpp
|
||||
libsolutil/SwarmHash.cpp
|
||||
libsolutil/UTF8.cpp
|
||||
|
@ -24,9 +24,12 @@
|
||||
#include <test/contracts/ContractInterface.h>
|
||||
#include <test/EVMHost.h>
|
||||
|
||||
#include <libsolutil/LazyInit.h>
|
||||
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <optional>
|
||||
|
||||
using namespace std;
|
||||
using namespace solidity;
|
||||
@ -212,17 +215,18 @@ contract GlobalRegistrar is Registrar, AuctionSystem {
|
||||
}
|
||||
)DELIMITER";
|
||||
|
||||
static unique_ptr<bytes> s_compiledRegistrar;
|
||||
static LazyInit<bytes> s_compiledRegistrar;
|
||||
|
||||
class AuctionRegistrarTestFramework: public SolidityExecutionFramework
|
||||
{
|
||||
protected:
|
||||
void deployRegistrar()
|
||||
{
|
||||
if (!s_compiledRegistrar)
|
||||
s_compiledRegistrar = make_unique<bytes>(compileContract(registrarCode, "GlobalRegistrar"));
|
||||
bytes const& compiled = s_compiledRegistrar.init([&]{
|
||||
return compileContract(registrarCode, "GlobalRegistrar");
|
||||
});
|
||||
|
||||
sendMessage(*s_compiledRegistrar, true);
|
||||
sendMessage(compiled, true);
|
||||
BOOST_REQUIRE(m_transactionSuccessful);
|
||||
BOOST_REQUIRE(!m_output.empty());
|
||||
}
|
||||
|
@ -20,8 +20,11 @@
|
||||
* Tests for a fixed fee registrar contract.
|
||||
*/
|
||||
|
||||
#include <libsolutil/LazyInit.h>
|
||||
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <optional>
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(push)
|
||||
@ -122,17 +125,18 @@ contract FixedFeeRegistrar is Registrar {
|
||||
}
|
||||
)DELIMITER";
|
||||
|
||||
static unique_ptr<bytes> s_compiledRegistrar;
|
||||
static LazyInit<bytes> s_compiledRegistrar;
|
||||
|
||||
class RegistrarTestFramework: public SolidityExecutionFramework
|
||||
{
|
||||
protected:
|
||||
void deployRegistrar()
|
||||
{
|
||||
if (!s_compiledRegistrar)
|
||||
s_compiledRegistrar = make_unique<bytes>(compileContract(registrarCode, "FixedFeeRegistrar"));
|
||||
bytes const& compiled = s_compiledRegistrar.init([&]{
|
||||
return compileContract(registrarCode, "FixedFeeRegistrar");
|
||||
});
|
||||
|
||||
sendMessage(*s_compiledRegistrar, true);
|
||||
sendMessage(compiled, true);
|
||||
BOOST_REQUIRE(m_transactionSuccessful);
|
||||
BOOST_REQUIRE(!m_output.empty());
|
||||
}
|
||||
|
@ -20,8 +20,11 @@
|
||||
* Tests for a (comparatively) complex multisig wallet contract.
|
||||
*/
|
||||
|
||||
#include <libsolutil/LazyInit.h>
|
||||
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <optional>
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(push)
|
||||
@ -435,7 +438,7 @@ contract Wallet is multisig, multiowned, daylimit {
|
||||
}
|
||||
)DELIMITER";
|
||||
|
||||
static unique_ptr<bytes> s_compiledWallet;
|
||||
static LazyInit<bytes> s_compiledWallet;
|
||||
|
||||
class WalletTestFramework: public SolidityExecutionFramework
|
||||
{
|
||||
@ -447,11 +450,12 @@ protected:
|
||||
u256 _dailyLimit = 0
|
||||
)
|
||||
{
|
||||
if (!s_compiledWallet)
|
||||
s_compiledWallet = make_unique<bytes>(compileContract(walletCode, "Wallet"));
|
||||
bytes const& compiled = s_compiledWallet.init([&]{
|
||||
return compileContract(walletCode, "Wallet");
|
||||
});
|
||||
|
||||
bytes args = encodeArgs(u256(0x60), _required, _dailyLimit, u256(_owners.size()), _owners);
|
||||
sendMessage(*s_compiledWallet + args, true, _value);
|
||||
sendMessage(compiled + args, true, _value);
|
||||
BOOST_REQUIRE(m_transactionSuccessful);
|
||||
BOOST_REQUIRE(!m_output.empty());
|
||||
}
|
||||
|
118
test/libsolutil/LazyInit.cpp
Normal file
118
test/libsolutil/LazyInit.cpp
Normal file
@ -0,0 +1,118 @@
|
||||
/*
|
||||
This file is part of solidity.
|
||||
|
||||
solidity is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
solidity is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with solidity. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <libsolutil/LazyInit.h>
|
||||
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
#include <utility>
|
||||
|
||||
namespace solidity::util::test
|
||||
{
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
template<typename T>
|
||||
void assertInitCalled(LazyInit<T> lazyInit, bool target)
|
||||
{
|
||||
bool initCalled = false;
|
||||
|
||||
lazyInit.init([&]{
|
||||
initCalled = true;
|
||||
return T();
|
||||
});
|
||||
|
||||
BOOST_REQUIRE_EQUAL(initCalled, target);
|
||||
}
|
||||
|
||||
// Take ownership to ensure that it doesn't "mutate"
|
||||
template<typename T>
|
||||
void assertNotEmpty(LazyInit<T> _lazyInit) { assertInitCalled(std::move(_lazyInit), false); }
|
||||
|
||||
// Take ownership to ensure that it doesn't "mutate"
|
||||
template<typename T>
|
||||
void assertEmpty(LazyInit<T> _lazyInit) { assertInitCalled(std::move(_lazyInit), true); }
|
||||
|
||||
template<typename T>
|
||||
T valueOf(LazyInit<T> _lazyInit)
|
||||
{
|
||||
return _lazyInit.init([&]{
|
||||
BOOST_REQUIRE(false); // this should never be called
|
||||
return T();
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(LazyInitTests)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(default_constructed_is_empty)
|
||||
{
|
||||
assertEmpty(LazyInit<int>());
|
||||
assertEmpty(LazyInit<int const>());
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(initialized_is_not_empty)
|
||||
{
|
||||
LazyInit<int> lazyInit;
|
||||
lazyInit.init([]{ return 12; });
|
||||
|
||||
assertNotEmpty(std::move(lazyInit));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(init_returns_init_value)
|
||||
{
|
||||
LazyInit<int> lazyInit;
|
||||
|
||||
BOOST_CHECK_EQUAL(lazyInit.init([]{ return 12; }), 12);
|
||||
|
||||
// A second call to init should not change the value
|
||||
BOOST_CHECK_EQUAL(lazyInit.init([]{ return 42; }), 12);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(moved_from_is_empty)
|
||||
{
|
||||
{
|
||||
LazyInit<int> lazyInit;
|
||||
{ [[maybe_unused]] auto pilfered = std::move(lazyInit); }
|
||||
|
||||
assertEmpty(std::move(lazyInit));
|
||||
}
|
||||
|
||||
{
|
||||
LazyInit<int> lazyInit;
|
||||
lazyInit.init([]{ return 12; });
|
||||
|
||||
{ [[maybe_unused]] auto pilfered = std::move(lazyInit); }
|
||||
|
||||
assertEmpty(std::move(lazyInit));
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(move_constructed_has_same_value_as_original)
|
||||
{
|
||||
LazyInit<int> original;
|
||||
original.init([]{ return 12; });
|
||||
|
||||
LazyInit<int> moveConstructed = std::move(original);
|
||||
BOOST_CHECK_EQUAL(valueOf(std::move(moveConstructed)), 12);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user