Files
Utilities/include/Tribool.h
T
2020-02-10 20:31:06 +01:00

204 lines
4.9 KiB
C++

#ifndef TRIBOOL_H
#define TRIBOOL_H
#include <iostream>
namespace Utilities {
class Tribool
{
public:
struct IndeterminateType
{
};
typedef bool (*IndeterminateKeywordType)(Tribool, IndeterminateType);
public:
Tribool();
Tribool(bool value);
Tribool(const IndeterminateKeywordType& value);
explicit operator bool() const;
Tribool operator!() const;
Tribool operator&&(const Tribool& other) const;
friend Tribool operator&&(const Tribool& lhs, bool rhs);
friend Tribool operator&&(bool lhs, const Tribool& rhs);
friend Tribool operator&&(const IndeterminateKeywordType& lhs, const Tribool& rhs);
friend Tribool operator&&(const Tribool& lhs, const IndeterminateKeywordType& rhs);
Tribool operator||(const Tribool& other) const;
friend Tribool operator||(const Tribool& lhs, bool rhs);
friend Tribool operator||(bool lhs, const Tribool& rhs);
friend Tribool operator||(const IndeterminateKeywordType& lhs, const Tribool& rhs);
friend Tribool operator||(const Tribool& lhs, const IndeterminateKeywordType& rhs);
Tribool operator==(const Tribool& other) const;
friend Tribool operator==(const Tribool& lhs, bool rhs);
friend Tribool operator==(bool lhs, const Tribool& rhs);
friend Tribool operator==(const IndeterminateKeywordType& lhs, const Tribool& rhs);
friend Tribool operator==(const Tribool& lhs, const IndeterminateKeywordType& rhs);
Tribool operator!=(const Tribool& other) const;
friend Tribool operator!=(const Tribool& lhs, bool rhs);
friend Tribool operator!=(bool lhs, const Tribool& rhs);
friend Tribool operator!=(const IndeterminateKeywordType& lhs, const Tribool& rhs);
friend Tribool operator!=(const Tribool& lhs, const IndeterminateKeywordType& rhs);
static inline bool Indeterminate(Tribool x, Tribool::IndeterminateType = Tribool::IndeterminateType())
{
return x.m_value == Tribool::TriboolValue::Indeterminate;
}
private:
class TriboolValue
{
public:
enum type
{
True,
False,
Indeterminate
};
};
private:
TriboolValue::type m_value;
};
template<typename CharT, typename Traits>
inline std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& out, Tribool x)
{
if (!Tribool::Indeterminate(x)) {
out << static_cast<bool>(x);
}
else
{
typename std::basic_ostream<CharT, Traits>::sentry cerberus(out);
if (cerberus)
{
if (out.flags() & std::ios_base::boolalpha)
out << "indeterminate";
else
out << 2;
}
}
return out;
}
template<typename CharT, typename Traits>
inline std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& out, bool (*)(Tribool, Tribool::IndeterminateType))
{
return out << Tribool(Tribool::Indeterminate);
}
template<typename CharT, typename Traits>
std::basic_istream<CharT, Traits>& operator>>(std::basic_istream<CharT, Traits>& in, Tribool& x)
{
if (in.flags() & std::ios_base::boolalpha)
{
typename std::basic_istream<CharT, Traits>::sentry cerberus(in);
if (cerberus)
{
typedef std::basic_string<CharT> string_type;
string_type falsename = "false";
string_type truename = "true";
string_type indeterminatename = "indeterminate";
typename string_type::size_type pos = 0;
bool falsename_ok = true;
bool truename_ok = true;
bool indeterminatename_ok = true;
while ((falsename_ok && pos < falsename.size()) || (truename_ok && pos < truename.size()) || (indeterminatename_ok && pos < indeterminatename.size()))
{
typename Traits::int_type c = in.get();
if (c == Traits::eof())
return in;
bool matched = false;
if (falsename_ok && pos < falsename.size())
{
if (Traits::eq(Traits::to_char_type(c), falsename[pos]))
matched = true;
else
falsename_ok = false;
}
if (truename_ok && pos < truename.size())
{
if (Traits::eq(Traits::to_char_type(c), truename[pos]))
matched = true;
else
truename_ok = false;
}
if (indeterminatename_ok && pos < indeterminatename.size())
{
if (Traits::eq(Traits::to_char_type(c), indeterminatename[pos]))
matched = true;
else
indeterminatename_ok = false;
}
if (matched)
++pos;
if (pos > falsename.size())
falsename_ok = false;
if (pos > truename.size())
truename_ok = false;
if (pos > indeterminatename.size())
indeterminatename_ok = false;
}
if (pos == 0)
{
in.setstate(std::ios_base::failbit);
}
else
{
if (falsename_ok)
x = false;
else if (truename_ok)
x = true;
else if (indeterminatename_ok)
x = Tribool::Indeterminate;
else
in.setstate(std::ios_base::failbit);
}
}
}
else
{
long value;
if (in >> value)
{
switch (value)
{
case 0:
x = false;
break;
case 1:
x = true;
break;
case 2:
x = Tribool::Indeterminate;
break;
default:
in.setstate(std::ios_base::failbit);
break;
}
}
}
return in;
}
} // namespace Utilities
#endif // TRIBOOL_H