#pragma once
#include <type_traits>
#include <wtf/Optional.h>
#include <wtf/StdLibExtras.h>
namespace WTF {
template<
typename EnumType,
typename std::underlying_type<EnumType>::type constant = std::numeric_limits<typename std::underlying_type<EnumType>::type>::max()>
struct EnumMarkableTraits {
static_assert(std::is_enum<EnumType>::value, "");
using UnderlyingType = typename std::underlying_type<EnumType>::type;
constexpr static bool isEmptyValue(EnumType value)
{
return static_cast<UnderlyingType>(value) == constant;
}
constexpr static EnumType emptyValue()
{
return static_cast<EnumType>(constant);
}
};
template<typename IntegralType, IntegralType constant = 0>
struct IntegralMarkableTraits {
static_assert(std::is_integral<IntegralType>::value, "");
constexpr static bool isEmptyValue(IntegralType value)
{
return value == constant;
}
constexpr static IntegralType emptyValue()
{
return constant;
}
};
template<typename T, typename Traits>
class Markable {
WTF_MAKE_FAST_ALLOCATED;
public:
constexpr Markable()
: m_value(Traits::emptyValue())
{ }
constexpr Markable(WTF::nullopt_t)
: Markable()
{ }
constexpr Markable(T&& value)
: m_value(WTFMove(value))
{ }
constexpr Markable(const T& value)
: m_value(value)
{ }
template<typename... Args>
constexpr explicit Markable(std::in_place_t, Args&&... args)
: m_value(std::forward<Args>(args)...)
{ }
constexpr Markable(const Optional<T>& value)
: m_value(bool(value) ? *value : Traits::emptyValue())
{ }
constexpr Markable(Optional<T>&& value)
: m_value(bool(value) ? WTFMove(*value) : Traits::emptyValue())
{ }
constexpr explicit operator bool() const { return !Traits::isEmptyValue(m_value); }
void reset() { m_value = Traits::emptyValue(); }
constexpr const T& value() const& { return m_value; }
constexpr T& value() & { return m_value; }
constexpr T&& value() && { return WTFMove(m_value); }
constexpr const T* operator->() const { return std::addressof(m_value); }
constexpr T* operator->() { return std::addressof(m_value); }
constexpr const T& operator*() const& { return m_value; }
constexpr T& operator*() & { return m_value; }
operator Optional<T>() &&
{
if (bool(*this))
return WTFMove(m_value);
return WTF::nullopt;
}
operator Optional<T>() const&
{
if (bool(*this))
return m_value;
return WTF::nullopt;
}
Optional<T> asOptional() const
{
return Optional<T>(*this);
}
private:
T m_value;
};
template <typename T, typename Traits> constexpr bool operator==(const Markable<T, Traits>& x, const Markable<T, Traits>& y)
{
if (bool(x) != bool(y))
return false;
if (!bool(x))
return true;
return x.value() == y.value();
}
template <typename T, typename Traits> constexpr bool operator==(const Markable<T, Traits>& x, const T& v) { return bool(x) && x.value() == v; }
template <typename T, typename Traits> constexpr bool operator==(const T& v, const Markable<T, Traits>& x) { return bool(x) && v == x.value(); }
template <typename T, typename Traits> constexpr bool operator!=(const Markable<T, Traits>& x, const Markable<T, Traits>& y) { return !(x == y); }
template <typename T, typename Traits> constexpr bool operator!=(const Markable<T, Traits>& x, const T& v) { return !(x == v); }
template <typename T, typename Traits> constexpr bool operator!=(const T& v, const Markable<T, Traits>& x) { return !(v == x); }
}
using WTF::Markable;
using WTF::IntegralMarkableTraits;
using WTF::EnumMarkableTraits;