// Description: Optional object
#ifndef PASTELSYS_OPTIONAL_H
#define PASTELSYS_OPTIONAL_H
#include "pastel/sys/hashing.h"
#include <utility>
namespace Pastel
{
class Epsilon {};
template <typename Type>
class Optional
{
public:
Optional()
: data_()
, empty_(true)
{
}
Optional(Epsilon)
: data_()
, empty_(true)
{
}
Optional(const Optional& that)
: data_(that.data())
, empty_(that.empty_)
{
}
template <typename That>
Optional(const Optional<That>& that)
: data_(that.data())
, empty_(that.empty_)
{
// Note that this function never
// matches the copy-constructor.
}
Optional(Optional&& that)
: data_(std::move(that.data()))
, empty_(std::move(that.empty_))
{
}
template <typename That>
Optional(Optional<That>&& that)
: data_(std::move(that.data()))
, empty_(std::move(that.empty_))
{
// Note that this function never
// matches the move-constructor.
}
Optional(Type that)
: data_(std::move(that))
, empty_(false)
{
}
Type& operator*()
{
return data_;
}
const Type& operator*() const
{
return data_;
}
Type* operator->()
{
return &data_;
}
const Type* operator->() const
{
return &data_;
}
Type& data()
{
return data_;
}
const Type& data() const
{
return data_;
}
Optional& operator=(Optional that)
{
data_ = std::move(that.data());
empty_ = std::move(that.empty_);
return *this;
}
template <typename That>
bool operator==(const Optional<That>& that) const
{
return compare(that);
}
template <typename That>
bool operator!=(const Optional<That>& that) const
{
return !compare(that);
}
template <typename That>
bool operator==(const That& that) const
{
// Treat 'that' as if it was a non-empty
// optional.
if (empty())
{
return false;
}
return data() == that;
}
template <typename That>
bool operator!=(const That& that) const
{
return !(*this == that);
}
void swap(Optional& that)
{
using std::swap;
swap((Type&)*this, (Type&)that);
swap(empty_, that.empty_);
}
void clear()
{
empty_ = true;
}
bool empty() const
{
return empty_;
}
private:
template <typename That>
bool compare(const Optional<That>& that) const
{
if (empty() != that.empty())
{
return false;
}
if (empty())
{
return true;
}
return data() == that.data();
}
BOOST_ATTRIBUTE_NO_UNIQUE_ADDRESS
Type data_;
bool empty_;
};
}
namespace std
{
template <typename Type>
struct hash<Pastel::Optional<Type>>
{
public:
Pastel::hash_integer operator()(
const Pastel::Optional<Type>& that) const
{
if (that.empty())
{
return Pastel::computeHash(that.empty());
}
return Pastel::computeHash(that.data());
}
};
}
#endif