/* 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 . */ #pragma once #include #include #include #include #include #include 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 class LazyInit { public: using value_type = T; static_assert(std::is_object_v, "Function, reference, and void types are not supported"); static_assert(!std::is_array_v, "Array types are not supported."); static_assert(!std::is_volatile_v, "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 value_type& init(F&& _fun) { doInit(std::forward(_fun)); return m_value.value(); } template value_type const& init(F&& _fun) const { doInit(std::forward(_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 void doInit(F&& _fun) const { if (!m_value.has_value()) m_value.emplace(std::forward(_fun)()); } mutable std::optional m_value; }; }