Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

An Optional_-class to discuss.

29 views
Skip to first unread message

Alf P. Steinbach

unread,
May 16, 2016, 12:40:19 AM5/16/16
to
I just coded up this and I wonder if there's much wrong with this code,
and/or improvements to the design, and/or kind words about my hairdo?

I don't have any test cases for this, at all.

And that's another thing I wonder about: how would one go about testing
code like this? I'm not even sure of requirements on template param.


<file Optional_.hpp>
#pragma once
// Copyright © 2016 Alf P. Steinbach

#include "type_builders.hpp" // cppx::(Ref_, Rvref_, Ptr_)
#include "hopefully_and_fail.hpp" // cppx::(hopefully, fail)

#include <memory> // std::align
#include <new> // ::operator new( size_t, void* )
#include <type_traits> // std::aligned_union_t

namespace cppx {
struct None {};

// The Optional_ class is intended to be an optimization of this
spec, modulo
// the kinds of execptions thrown, so that Optional_<Some_builtin_type>
// doesn't incur unacceptable overhead:
# if 0 // SPEC:
template< class Type >
class Optional_
{
private:
std::vector<Type> item_;
public:
auto has_object() const -> bool { return item_.size() > 0; }
auto object() -> Ref_<Type> { return item_.at( 0 ); }
auto object() const -> Ref_<const Type> { return item_.at(
0 ); }
auto operator=( Ref_<Optional_> other ) -> Ref_<Optional_>
{ item_ = other.item_; }
auto operator=( Rvref_<Optional_> other ) ->
Ref_<Optional_> { item_ = move( other.item_ ); }
Optional_( None = None() ) {}
Optional_( Type o ) { item_.push_back( move( o ) ); }
Optional_( Ref_<const Optional_> other ): item_(
other.item_ ) {}
Optional_( Rvref_<Optional_> other ): item_( move(
other.item_ ) ) {}
};
# endif

template< class Type >
class Optional_
{
private:
using Alignment_info = std::aligned_union<0, Type>;
using Storage = typename Alignment_info::type;
static constexpr int alignment = Alignment_info::alignment_value;

Storage storage_;
Ptr_<Type> p_object_ = nullptr;

auto aligned_storage()
-> Ptr_<void>
{
Ptr_<void> p_storage = &storage_;
size_t size = sizeof( storage_ );

return std::align( alignment, sizeof( Type ), p_storage,
size );
}

public:
auto has_object() const
-> bool
{ return !!p_object_; }

auto object()
-> Ref_<Type>
{
hopefully( has_object() )
|| fail( "Optional_: no object" );
return *p_object_;
}

auto object() const
-> Ref_<const Type>
{
hopefully( has_object() )
|| fail( "Optional_: no object" );
return *p_object_;
}

auto operator=( Ref_<const Optional_> other )
-> Ref_<Optional_>
{
if( other.has_object() )
{
if( has_object() )
{
*p_object_ = *other.p_object_;
}
else
{
p_object_ = ::new( aligned_storage() ) Type(
*other.p_object_ );
}
}
else
{
if( has_object() )
{
p_object_->Type::~Type();
p_object_ = nullptr;
}
}
return *this;
}

auto operator=( Rvref_<Optional_> other )
-> Ref_<Optional_>
{
if( other.has_object() )
{
if( has_object() )
{
*p_object_ = move( *other.p_object_ );
}
else
{
p_object_ = ::new( aligned_storage() ) Type( move(
*other.p_object_ ) );
}
}
else
{
if( has_object() )
{
p_object_->Type::~Type();
p_object_ = nullptr;
}
}
return *this;
}

~Optional_()
{
if( has_object() )
{
p_object_->Type::~Type();
}
}

Optional_( None = None() ) {}

Optional_( Type o )
: p_object_( ::new( aligned_storage() ) Type( move( o ) ) )
{}

Optional_( Ref_<const Optional_> other )
{
if( other.has_object() )
{
p_object_ = ::new( aligned_storage() ) Type(
*other.p_object_ );
}
}

Optional_( Rvref_<Optional_> other )
{
if( other.has_object() )
{
p_object_ = ::new( aligned_storage() ) Type( move(
*other.object_ptr() ) );
}
}
};
} // namespace cppx
</file>


Cheers!,

- Alf

Öö Tiib

unread,
May 16, 2016, 2:50:14 AM5/16/16
to
On Monday, 16 May 2016 07:40:19 UTC+3, Alf P. Steinbach wrote:
> I just coded up this and I wonder if there's much wrong with this code,
> and/or improvements to the design, and/or kind words about my hairdo?
>

Seems fine on first glance. Why you decided to write another 'optional'
(AKA 'fallible' and 'nullable')? Would be more worth of it if you tried
to achieve constexprness of it. Maybe go full way and use a bool instead
of pointer. It will result with tiniest optional being 2 bytes instead of
16 on lot of platforms.

> I don't have any test cases for this, at all.
>
> And that's another thing I wonder about: how would one go about testing
> code like this? I'm not even sure of requirements on template param.

Easiest might be to install boost and get some unit tests for rather
similar thing (IIRC in $(boost_root)/libs/optional/test).
0 new messages