// Description: Optional object
#ifndef PASTELSYS_OPTIONAL_H
#define PASTELSYS_OPTIONAL_H
#include "pastel/sys/generic/class.h"
#include "pastel/sys/hashing.h"
#include <utility>
namespace Pastel
{
class Epsilon {};
template <typename Type>
class Optional
: public Class<Type>
{
public:
using Type_Class = Class<Type>
;
Optional()
: Type_Class()
, empty_(true)
{
}
Optional(Epsilon)
: Type_Class()
, empty_(true)
{
}
Optional(const Optional& that)
: Type_Class(that.data())
, empty_(that.empty_)
{
}
template <typename That>
Optional(const Optional<That>& that)
: Type_Class(that.data())
, empty_(that.empty_)
{
// Note that this function never
// matches the copy-constructor.
}
Optional(Optional&& that)
: Type_Class(std::move(that.data()))
, empty_(std::move(that.empty_))
{
}
template <typename That>
Optional(Optional<That>&& that)
: Type_Class(std::move(that.data()))
, empty_(std::move(that.empty_))
{
// Note that this function never
// matches the move-constructor.
}
Optional(Type that)
: Type_Class(std::move(that))
, empty_(false)
{
}
Optional& operator=(Optional that)
{
Type_Class::operator=(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_Class&)*this, (Type_Class&)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();
}
Type_Class& data()
{
return (Type_Class&)*this;
}
const Type_Class& data() const
{
return (const Type_Class&)*this;
}
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(
(const typename Pastel::Class<Type>&)that);
}
};
}
#endif