diff --git a/src/Makefile.am b/src/Makefile.am index 13812de0e7d..d2c7400bbbc 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -223,6 +223,7 @@ BITCOIN_CORE_H = \ util/message.h \ util/moneystr.h \ util/rbf.h \ + util/ref.h \ util/settings.h \ util/string.h \ util/threadnames.h \ diff --git a/src/Makefile.test.include b/src/Makefile.test.include index 3a0d4fdc158..6ba0e9f2702 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -229,6 +229,7 @@ BITCOIN_TESTS =\ test/prevector_tests.cpp \ test/raii_event_tests.cpp \ test/random_tests.cpp \ + test/ref_tests.cpp \ test/reverselock_tests.cpp \ test/rpc_tests.cpp \ test/sanity_tests.cpp \ diff --git a/src/test/ref_tests.cpp b/src/test/ref_tests.cpp new file mode 100644 index 00000000000..0ec0799fbcb --- /dev/null +++ b/src/test/ref_tests.cpp @@ -0,0 +1,33 @@ +// Copyright (c) 2020 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include + +#include + +BOOST_AUTO_TEST_SUITE(ref_tests) + +BOOST_AUTO_TEST_CASE(ref_test) +{ + util::Ref ref; + BOOST_CHECK(!ref.Has()); + BOOST_CHECK_THROW(ref.Get(), NonFatalCheckError); + int value = 5; + ref.Set(value); + BOOST_CHECK(ref.Has()); + BOOST_CHECK_EQUAL(ref.Get(), 5); + ++ref.Get(); + BOOST_CHECK_EQUAL(ref.Get(), 6); + BOOST_CHECK_EQUAL(value, 6); + ++value; + BOOST_CHECK_EQUAL(value, 7); + BOOST_CHECK_EQUAL(ref.Get(), 7); + BOOST_CHECK(!ref.Has()); + BOOST_CHECK_THROW(ref.Get(), NonFatalCheckError); + ref.Clear(); + BOOST_CHECK(!ref.Has()); + BOOST_CHECK_THROW(ref.Get(), NonFatalCheckError); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/util/check.h b/src/util/check.h index d18887ae958..5c0f32cf519 100644 --- a/src/util/check.h +++ b/src/util/check.h @@ -5,6 +5,10 @@ #ifndef BITCOIN_UTIL_CHECK_H #define BITCOIN_UTIL_CHECK_H +#if defined(HAVE_CONFIG_H) +#include +#endif + #include #include diff --git a/src/util/ref.h b/src/util/ref.h new file mode 100644 index 00000000000..9685ea9fec0 --- /dev/null +++ b/src/util/ref.h @@ -0,0 +1,38 @@ +// Copyright (c) 2020 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_UTIL_REF_H +#define BITCOIN_UTIL_REF_H + +#include + +#include + +namespace util { + +/** + * Type-safe dynamic reference. + * + * This implements a small subset of the functionality in C++17's std::any + * class, and can be dropped when the project updates to C++17 + * (https://github.com/bitcoin/bitcoin/issues/16684) + */ +class Ref +{ +public: + Ref() = default; + template Ref(T& value) { Set(value); } + template T& Get() const { CHECK_NONFATAL(Has()); return *static_cast(m_value); } + template void Set(T& value) { m_value = &value; m_type = std::type_index(typeid(T)); } + template bool Has() const { return m_value && m_type == std::type_index(typeid(T)); } + void Clear() { m_value = nullptr; m_type = std::type_index(typeid(void)); } + +private: + void* m_value = nullptr; + std::type_index m_type = std::type_index(typeid(void)); +}; + +} // namespace util + +#endif // BITCOIN_UTIL_REF_H