// Three-state boolean logic library | |
// Copyright Douglas Gregor 2002-2004. Use, modification and | |
// distribution is subject to the Boost Software License, Version | |
// 1.0. (See accompanying file LICENSE_1_0.txt or copy at | |
// http://www.boost.org/LICENSE_1_0.txt) | |
#ifndef BOOST_LOGIC_TRIBOOL_IO_HPP | |
#define BOOST_LOGIC_TRIBOOL_IO_HPP | |
#include <boost/logic/tribool.hpp> | |
#include <boost/detail/workaround.hpp> | |
#include <boost/noncopyable.hpp> | |
#if BOOST_WORKAROUND(_MSC_VER, >= 1200) | |
# pragma once | |
#endif | |
#ifndef BOOST_NO_STD_LOCALE | |
# include <locale> | |
#endif | |
#include <string> | |
#include <iostream> | |
namespace boost { namespace logic { | |
#ifdef BOOST_NO_STD_LOCALE | |
/** | |
* \brief Returns a string containing the default name for the \c | |
* false value of a tribool with the given character type T. | |
* | |
* This function only exists when the C++ standard library | |
* implementation does not support locales. | |
*/ | |
template<typename T> std::basic_string<T> default_false_name(); | |
/** | |
* \brief Returns the character string "false". | |
* | |
* This function only exists when the C++ standard library | |
* implementation does not support locales. | |
*/ | |
template<> | |
inline std::basic_string<char> default_false_name<char>() | |
{ return "false"; } | |
# ifndef BOOST_NO_WCHAR_T | |
/** | |
* \brief Returns the wide character string L"false". | |
* | |
* This function only exists when the C++ standard library | |
* implementation does not support locales. | |
*/ | |
template<> | |
inline std::basic_string<wchar_t> default_false_name<wchar_t>() | |
{ return L"false"; } | |
# endif | |
/** | |
* \brief Returns a string containing the default name for the \c true | |
* value of a tribool with the given character type T. | |
* | |
* This function only exists when the C++ standard library | |
* implementation does not support locales. | |
*/ | |
template<typename T> std::basic_string<T> default_true_name(); | |
/** | |
* \brief Returns the character string "true". | |
* | |
* This function only exists when the C++ standard library | |
* implementation does not support locales. | |
*/ | |
template<> | |
inline std::basic_string<char> default_true_name<char>() | |
{ return "true"; } | |
# ifndef BOOST_NO_WCHAR_T | |
/** | |
* \brief Returns the wide character string L"true". | |
* | |
* This function only exists * when the C++ standard library | |
* implementation does not support * locales. | |
*/ | |
template<> | |
inline std::basic_string<wchar_t> default_true_name<wchar_t>() | |
{ return L"true"; } | |
# endif | |
#endif | |
/** | |
* \brief Returns a string containing the default name for the indeterminate | |
* value of a tribool with the given character type T. | |
* | |
* This routine is used by the input and output streaming operators | |
* for tribool when there is no locale support or the stream's locale | |
* does not contain the indeterminate_name facet. | |
*/ | |
template<typename T> std::basic_string<T> get_default_indeterminate_name(); | |
/// Returns the character string "indeterminate". | |
template<> | |
inline std::basic_string<char> get_default_indeterminate_name<char>() | |
{ return "indeterminate"; } | |
#if BOOST_WORKAROUND(BOOST_MSVC, < 1300) | |
// VC++ 6.0 chokes on the specialization below, so we're stuck without | |
// wchar_t support. What a pain. TODO: it might just need a the template | |
// parameter as function parameter... | |
#else | |
# ifndef BOOST_NO_WCHAR_T | |
/// Returns the wide character string L"indeterminate". | |
template<> | |
inline std::basic_string<wchar_t> get_default_indeterminate_name<wchar_t>() | |
{ return L"indeterminate"; } | |
# endif | |
#endif | |
// http://www.cantrip.org/locale.html | |
#ifndef BOOST_NO_STD_LOCALE | |
/** | |
* \brief A locale facet specifying the name of the indeterminate | |
* value of a tribool. | |
* | |
* The facet is used to perform I/O on tribool values when \c | |
* std::boolalpha has been specified. This class template is only | |
* available if the C++ standard library implementation supports | |
* locales. | |
*/ | |
template<typename CharT> | |
class indeterminate_name : public std::locale::facet, private boost::noncopyable | |
{ | |
public: | |
typedef CharT char_type; | |
typedef std::basic_string<CharT> string_type; | |
/// Construct the facet with the default name | |
indeterminate_name() : name_(get_default_indeterminate_name<CharT>()) {} | |
/// Construct the facet with the given name for the indeterminate value | |
explicit indeterminate_name(const string_type& name) : name_(name) {} | |
/// Returns the name for the indeterminate value | |
string_type name() const { return name_; } | |
/// Uniquily identifies this facet with the locale. | |
static std::locale::id id; | |
private: | |
string_type name_; | |
}; | |
template<typename CharT> std::locale::id indeterminate_name<CharT>::id; | |
#endif | |
/** | |
* \brief Writes the value of a tribool to a stream. | |
* | |
* When the value of @p x is either \c true or \c false, this routine | |
* is semantically equivalent to: | |
* \code out << static_cast<bool>(x); \endcode | |
* | |
* When @p x has an indeterminate value, it outputs either the integer | |
* value 2 (if <tt>(out.flags() & std::ios_base::boolalpha) == 0</tt>) | |
* or the name of the indeterminate value. The name of the | |
* indeterminate value comes from the indeterminate_name facet (if it | |
* is defined in the output stream's locale), or from the | |
* get_default_indeterminate_name function (if it is not defined in the | |
* locale or if the C++ standard library implementation does not | |
* support locales). | |
* | |
* \returns @p out | |
*/ | |
template<typename CharT, typename Traits> | |
inline std::basic_ostream<CharT, Traits>& | |
operator<<(std::basic_ostream<CharT, Traits>& out, tribool x) | |
{ | |
if (!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) { | |
#ifndef BOOST_NO_STD_LOCALE | |
if (BOOST_HAS_FACET(indeterminate_name<CharT>, out.getloc())) { | |
const indeterminate_name<CharT>& facet = | |
BOOST_USE_FACET(indeterminate_name<CharT>, out.getloc()); | |
out << facet.name(); | |
} else { | |
out << get_default_indeterminate_name<CharT>(); | |
} | |
#else | |
out << get_default_indeterminate_name<CharT>(); | |
#endif | |
} | |
else | |
out << 2; | |
} | |
} | |
return out; | |
} | |
/** | |
* \brief Writes the indeterminate tribool value to a stream. | |
* | |
* This routine outputs either the integer | |
* value 2 (if <tt>(out.flags() & std::ios_base::boolalpha) == 0</tt>) | |
* or the name of the indeterminate value. The name of the | |
* indeterminate value comes from the indeterminate_name facet (if it | |
* is defined in the output stream's locale), or from the | |
* get_default_indeterminate_name function (if it is not defined in the | |
* locale or if the C++ standard library implementation does not | |
* support locales). | |
* | |
* \returns @p out | |
*/ | |
template<typename CharT, typename Traits> | |
inline std::basic_ostream<CharT, Traits>& | |
operator<<(std::basic_ostream<CharT, Traits>& out, | |
bool (*)(tribool, detail::indeterminate_t)) | |
{ return out << tribool(indeterminate); } | |
/** | |
* \brief Reads a tribool value from a stream. | |
* | |
* When <tt>(out.flags() & std::ios_base::boolalpha) == 0</tt>, this | |
* function reads a \c long value from the input stream @p in and | |
* converts that value to a tribool. If that value is 0, @p x becomes | |
* \c false; if it is 1, @p x becomes \c true; if it is 2, @p becomes | |
* \c indetermine; otherwise, the operation fails (and the fail bit is | |
* set on the input stream @p in). | |
* | |
* When <tt>(out.flags() & std::ios_base::boolalpha) != 0</tt>, this | |
* function first determines the names of the false, true, and | |
* indeterminate values. The false and true names are extracted from | |
* the \c std::numpunct facet of the input stream's locale (if the C++ | |
* standard library implementation supports locales), or from the \c | |
* default_false_name and \c default_true_name functions (if there is | |
* no locale support). The indeterminate name is extracted from the | |
* appropriate \c indeterminate_name facet (if it is available in the | |
* input stream's locale), or from the \c get_default_indeterminate_name | |
* function (if the C++ standard library implementation does not | |
* support locales, or the \c indeterminate_name facet is not | |
* specified for this locale object). The input is then matched to | |
* each of these names, and the tribool @p x is assigned the value | |
* corresponding to the longest name that matched. If no name is | |
* matched or all names are empty, the operation fails (and the fail | |
* bit is set on the input stream @p in). | |
* | |
* \returns @p in | |
*/ | |
template<typename CharT, typename Traits> | |
inline 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; | |
#ifndef BOOST_NO_STD_LOCALE | |
const std::numpunct<CharT>& numpunct_facet = | |
BOOST_USE_FACET(std::numpunct<CharT>, in.getloc()); | |
string_type falsename = numpunct_facet.falsename(); | |
string_type truename = numpunct_facet.truename(); | |
string_type othername; | |
if (BOOST_HAS_FACET(indeterminate_name<CharT>, in.getloc())) { | |
othername = | |
BOOST_USE_FACET(indeterminate_name<CharT>, in.getloc()).name(); | |
} else { | |
othername = get_default_indeterminate_name<CharT>(); | |
} | |
#else | |
string_type falsename = default_false_name<CharT>(); | |
string_type truename = default_true_name<CharT>(); | |
string_type othername = get_default_indeterminate_name<CharT>(); | |
#endif | |
typename string_type::size_type pos = 0; | |
bool falsename_ok = true, truename_ok = true, othername_ok = true; | |
// Modeled after the code from Library DR 17 | |
while (falsename_ok && pos < falsename.size() | |
|| truename_ok && pos < truename.size() | |
|| othername_ok && pos < othername.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 (othername_ok && pos < othername.size()) { | |
if (Traits::eq(Traits::to_char_type(c), othername[pos])) | |
matched = true; | |
else | |
othername_ok = false; | |
} | |
if (matched) { ++pos; } | |
if (pos > falsename.size()) falsename_ok = false; | |
if (pos > truename.size()) truename_ok = false; | |
if (pos > othername.size()) othername_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 (othername_ok) x = 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 = indeterminate; break; | |
default: in.setstate(std::ios_base::failbit); break; | |
} | |
} | |
} | |
return in; | |
} | |
} } // end namespace boost::logic | |
#endif // BOOST_LOGIC_TRIBOOL_IO_HPP |