Utility: nano::optional_ptr (#2605)

* optional_ptr

* Implement feedback from Wesley/Guilherme
This commit is contained in:
cryptocode 2020-02-27 14:53:56 +01:00 committed by GitHub
commit bac78d0273
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 122 additions and 0 deletions

View file

@ -1,3 +1,4 @@
#include <nano/lib/optional_ptr.hpp>
#include <nano/lib/timer.hpp>
#include <nano/lib/utility.hpp>
#include <nano/lib/worker.hpp>
@ -7,6 +8,33 @@
#include <boost/filesystem.hpp>
TEST (optional_ptr, basic)
{
struct valtype
{
int64_t x{ 1 };
int64_t y{ 2 };
int64_t z{ 3 };
};
nano::optional_ptr<valtype> opt;
ASSERT_FALSE (opt);
ASSERT_FALSE (opt.is_initialized ());
{
auto val = valtype{};
opt = val;
ASSERT_LT (sizeof (opt), sizeof (val));
std::unique_ptr<valtype> uptr;
ASSERT_EQ (sizeof (opt), sizeof (uptr));
}
ASSERT_TRUE (opt);
ASSERT_TRUE (opt.is_initialized ());
ASSERT_EQ (opt->x, 1);
ASSERT_EQ (opt->y, 2);
ASSERT_EQ (opt->z, 3);
}
TEST (thread, worker)
{
std::atomic<bool> passed_sleep{ false };

View file

@ -41,6 +41,7 @@ add_library (nano_lib
memory.cpp
numbers.hpp
numbers.cpp
optional_ptr.hpp
rep_weights.hpp
rep_weights.cpp
rocksdbconfig.hpp

93
nano/lib/optional_ptr.hpp Normal file
View file

@ -0,0 +1,93 @@
#pragma once
#include <nano/lib/utility.hpp>
#include <cstddef>
#include <memory>
namespace nano
{
/**
* A space efficient optional which does heap allocation when needed.
* This is an alternative to boost/std::optional when the value type is
* large and often not present.
*
* optional_ptr is similar to using std::unique_ptr as an optional, with the
* main difference being that it's copyable.
*/
template <typename T>
class optional_ptr
{
static_assert (sizeof (T) > alignof (std::max_align_t), "Use [std|boost]::optional");
public:
optional_ptr () = default;
optional_ptr (T const & value) :
ptr (new T{ value })
{
}
optional_ptr (optional_ptr const & other)
{
if (other && other.ptr)
{
ptr = std::make_unique<T> (*other.ptr);
}
}
optional_ptr & operator= (optional_ptr const & other)
{
if (other && other.ptr)
{
ptr = std::make_unique<T> (*other.ptr);
}
return *this;
}
T & operator* ()
{
return *ptr;
}
T const & operator* () const
{
return *ptr;
}
T * const operator-> ()
{
return ptr.operator-> ();
}
T const * const operator-> () const
{
return ptr.operator-> ();
}
T const * const get () const
{
debug_assert (is_initialized ());
return ptr.get ();
}
T * const get ()
{
debug_assert (is_initialized ());
return ptr.get ();
}
explicit operator bool () const
{
return static_cast<bool> (ptr);
}
bool is_initialized () const
{
return static_cast<bool> (ptr);
}
private:
std::unique_ptr<T> ptr{ nullptr };
};
}