Utility: nano::optional_ptr (#2605)
* optional_ptr * Implement feedback from Wesley/Guilherme
This commit is contained in:
		
					parent
					
						
							
								e10701220f
							
						
					
				
			
			
				commit
				
					
						bac78d0273
					
				
			
		
					 3 changed files with 122 additions and 0 deletions
				
			
		| 
						 | 
				
			
			@ -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 };
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
									
								
							
							
						
						
									
										93
									
								
								nano/lib/optional_ptr.hpp
									
										
									
									
									
										Normal 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 };
 | 
			
		||||
};
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue