tribool_io.hpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343
  1. // Three-state boolean logic library
  2. // Copyright Douglas Gregor 2002-2004. Use, modification and
  3. // distribution is subject to the Boost Software License, Version
  4. // 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  5. // http://www.boost.org/LICENSE_1_0.txt)
  6. #ifndef BOOST_LOGIC_TRIBOOL_IO_HPP
  7. #define BOOST_LOGIC_TRIBOOL_IO_HPP
  8. #include <boost/logic/tribool.hpp>
  9. #include <boost/detail/workaround.hpp>
  10. #include <boost/noncopyable.hpp>
  11. #if defined(_MSC_VER)
  12. # pragma once
  13. #endif
  14. #ifndef BOOST_NO_STD_LOCALE
  15. # include <locale>
  16. #endif
  17. #include <string>
  18. #include <iostream>
  19. namespace boost { namespace logic {
  20. #ifdef BOOST_NO_STD_LOCALE
  21. /**
  22. * \brief Returns a string containing the default name for the \c
  23. * false value of a tribool with the given character type T.
  24. *
  25. * This function only exists when the C++ standard library
  26. * implementation does not support locales.
  27. */
  28. template<typename T> std::basic_string<T> default_false_name();
  29. /**
  30. * \brief Returns the character string "false".
  31. *
  32. * This function only exists when the C++ standard library
  33. * implementation does not support locales.
  34. */
  35. template<>
  36. inline std::basic_string<char> default_false_name<char>()
  37. { return "false"; }
  38. # if !defined(BOOST_NO_CWCHAR)
  39. /**
  40. * \brief Returns the wide character string L"false".
  41. *
  42. * This function only exists when the C++ standard library
  43. * implementation does not support locales.
  44. */
  45. template<>
  46. inline std::basic_string<wchar_t> default_false_name<wchar_t>()
  47. { return L"false"; }
  48. # endif
  49. /**
  50. * \brief Returns a string containing the default name for the \c true
  51. * value of a tribool with the given character type T.
  52. *
  53. * This function only exists when the C++ standard library
  54. * implementation does not support locales.
  55. */
  56. template<typename T> std::basic_string<T> default_true_name();
  57. /**
  58. * \brief Returns the character string "true".
  59. *
  60. * This function only exists when the C++ standard library
  61. * implementation does not support locales.
  62. */
  63. template<>
  64. inline std::basic_string<char> default_true_name<char>()
  65. { return "true"; }
  66. # if !defined(BOOST_NO_CWCHAR)
  67. /**
  68. * \brief Returns the wide character string L"true".
  69. *
  70. * This function only exists * when the C++ standard library
  71. * implementation does not support * locales.
  72. */
  73. template<>
  74. inline std::basic_string<wchar_t> default_true_name<wchar_t>()
  75. { return L"true"; }
  76. # endif
  77. #endif
  78. /**
  79. * \brief Returns a string containing the default name for the indeterminate
  80. * value of a tribool with the given character type T.
  81. *
  82. * This routine is used by the input and output streaming operators
  83. * for tribool when there is no locale support or the stream's locale
  84. * does not contain the indeterminate_name facet.
  85. */
  86. template<typename T> std::basic_string<T> get_default_indeterminate_name();
  87. /// Returns the character string "indeterminate".
  88. template<>
  89. inline std::basic_string<char> get_default_indeterminate_name<char>()
  90. { return "indeterminate"; }
  91. #if !defined(BOOST_NO_CWCHAR)
  92. /// Returns the wide character string L"indeterminate".
  93. template<>
  94. inline std::basic_string<wchar_t> get_default_indeterminate_name<wchar_t>()
  95. { return L"indeterminate"; }
  96. #endif
  97. // http://www.cantrip.org/locale.html
  98. #ifndef BOOST_NO_STD_LOCALE
  99. /**
  100. * \brief A locale facet specifying the name of the indeterminate
  101. * value of a tribool.
  102. *
  103. * The facet is used to perform I/O on tribool values when \c
  104. * std::boolalpha has been specified. This class template is only
  105. * available if the C++ standard library implementation supports
  106. * locales.
  107. */
  108. template<typename CharT>
  109. class indeterminate_name : public std::locale::facet, private boost::noncopyable
  110. {
  111. public:
  112. typedef CharT char_type;
  113. typedef std::basic_string<CharT> string_type;
  114. /// Construct the facet with the default name
  115. indeterminate_name() : name_(get_default_indeterminate_name<CharT>()) {}
  116. /// Construct the facet with the given name for the indeterminate value
  117. explicit indeterminate_name(const string_type& initial_name)
  118. : name_(initial_name) {}
  119. /// Returns the name for the indeterminate value
  120. string_type name() const { return name_; }
  121. /// Uniquily identifies this facet with the locale.
  122. static std::locale::id id;
  123. private:
  124. string_type name_;
  125. };
  126. template<typename CharT> std::locale::id indeterminate_name<CharT>::id;
  127. #endif
  128. /**
  129. * \brief Writes the value of a tribool to a stream.
  130. *
  131. * When the value of @p x is either \c true or \c false, this routine
  132. * is semantically equivalent to:
  133. * \code out << static_cast<bool>(x); \endcode
  134. *
  135. * When @p x has an indeterminate value, it outputs either the integer
  136. * value 2 (if <tt>(out.flags() & std::ios_base::boolalpha) == 0</tt>)
  137. * or the name of the indeterminate value. The name of the
  138. * indeterminate value comes from the indeterminate_name facet (if it
  139. * is defined in the output stream's locale), or from the
  140. * get_default_indeterminate_name function (if it is not defined in the
  141. * locale or if the C++ standard library implementation does not
  142. * support locales).
  143. *
  144. * \returns @p out
  145. */
  146. template<typename CharT, typename Traits>
  147. inline std::basic_ostream<CharT, Traits>&
  148. operator<<(std::basic_ostream<CharT, Traits>& out, tribool x)
  149. {
  150. if (!indeterminate(x)) {
  151. out << static_cast<bool>(x);
  152. } else {
  153. typename std::basic_ostream<CharT, Traits>::sentry cerberus(out);
  154. if (cerberus) {
  155. if (out.flags() & std::ios_base::boolalpha) {
  156. #ifndef BOOST_NO_STD_LOCALE
  157. if (BOOST_HAS_FACET(indeterminate_name<CharT>, out.getloc())) {
  158. const indeterminate_name<CharT>& facet =
  159. BOOST_USE_FACET(indeterminate_name<CharT>, out.getloc());
  160. out << facet.name();
  161. } else {
  162. out << get_default_indeterminate_name<CharT>();
  163. }
  164. #else
  165. out << get_default_indeterminate_name<CharT>();
  166. #endif
  167. }
  168. else
  169. out << 2;
  170. }
  171. }
  172. return out;
  173. }
  174. /**
  175. * \brief Writes the indeterminate tribool value to a stream.
  176. *
  177. * This routine outputs either the integer
  178. * value 2 (if <tt>(out.flags() & std::ios_base::boolalpha) == 0</tt>)
  179. * or the name of the indeterminate value. The name of the
  180. * indeterminate value comes from the indeterminate_name facet (if it
  181. * is defined in the output stream's locale), or from the
  182. * get_default_indeterminate_name function (if it is not defined in the
  183. * locale or if the C++ standard library implementation does not
  184. * support locales).
  185. *
  186. * \returns @p out
  187. */
  188. template<typename CharT, typename Traits>
  189. inline std::basic_ostream<CharT, Traits>&
  190. operator<<(std::basic_ostream<CharT, Traits>& out,
  191. bool (*)(tribool, detail::indeterminate_t))
  192. { return out << tribool(indeterminate); }
  193. /**
  194. * \brief Reads a tribool value from a stream.
  195. *
  196. * When <tt>(out.flags() & std::ios_base::boolalpha) == 0</tt>, this
  197. * function reads a \c long value from the input stream @p in and
  198. * converts that value to a tribool. If that value is 0, @p x becomes
  199. * \c false; if it is 1, @p x becomes \c true; if it is 2, @p becomes
  200. * \c indetermine; otherwise, the operation fails (and the fail bit is
  201. * set on the input stream @p in).
  202. *
  203. * When <tt>(out.flags() & std::ios_base::boolalpha) != 0</tt>, this
  204. * function first determines the names of the false, true, and
  205. * indeterminate values. The false and true names are extracted from
  206. * the \c std::numpunct facet of the input stream's locale (if the C++
  207. * standard library implementation supports locales), or from the \c
  208. * default_false_name and \c default_true_name functions (if there is
  209. * no locale support). The indeterminate name is extracted from the
  210. * appropriate \c indeterminate_name facet (if it is available in the
  211. * input stream's locale), or from the \c get_default_indeterminate_name
  212. * function (if the C++ standard library implementation does not
  213. * support locales, or the \c indeterminate_name facet is not
  214. * specified for this locale object). The input is then matched to
  215. * each of these names, and the tribool @p x is assigned the value
  216. * corresponding to the longest name that matched. If no name is
  217. * matched or all names are empty, the operation fails (and the fail
  218. * bit is set on the input stream @p in).
  219. *
  220. * \returns @p in
  221. */
  222. template<typename CharT, typename Traits>
  223. inline std::basic_istream<CharT, Traits>&
  224. operator>>(std::basic_istream<CharT, Traits>& in, tribool& x)
  225. {
  226. if (in.flags() & std::ios_base::boolalpha) {
  227. typename std::basic_istream<CharT, Traits>::sentry cerberus(in);
  228. if (cerberus) {
  229. typedef std::basic_string<CharT> string_type;
  230. #ifndef BOOST_NO_STD_LOCALE
  231. const std::numpunct<CharT>& numpunct_facet =
  232. BOOST_USE_FACET(std::numpunct<CharT>, in.getloc());
  233. string_type falsename = numpunct_facet.falsename();
  234. string_type truename = numpunct_facet.truename();
  235. string_type othername;
  236. if (BOOST_HAS_FACET(indeterminate_name<CharT>, in.getloc())) {
  237. othername =
  238. BOOST_USE_FACET(indeterminate_name<CharT>, in.getloc()).name();
  239. } else {
  240. othername = get_default_indeterminate_name<CharT>();
  241. }
  242. #else
  243. string_type falsename = default_false_name<CharT>();
  244. string_type truename = default_true_name<CharT>();
  245. string_type othername = get_default_indeterminate_name<CharT>();
  246. #endif
  247. typename string_type::size_type pos = 0;
  248. bool falsename_ok = true, truename_ok = true, othername_ok = true;
  249. // Modeled after the code from Library DR 17
  250. while ((falsename_ok && pos < falsename.size())
  251. || (truename_ok && pos < truename.size())
  252. || (othername_ok && pos < othername.size())) {
  253. typename Traits::int_type c = in.get();
  254. if (c == Traits::eof())
  255. return in;
  256. bool matched = false;
  257. if (falsename_ok && pos < falsename.size()) {
  258. if (Traits::eq(Traits::to_char_type(c), falsename[pos]))
  259. matched = true;
  260. else
  261. falsename_ok = false;
  262. }
  263. if (truename_ok && pos < truename.size()) {
  264. if (Traits::eq(Traits::to_char_type(c), truename[pos]))
  265. matched = true;
  266. else
  267. truename_ok = false;
  268. }
  269. if (othername_ok && pos < othername.size()) {
  270. if (Traits::eq(Traits::to_char_type(c), othername[pos]))
  271. matched = true;
  272. else
  273. othername_ok = false;
  274. }
  275. if (matched) { ++pos; }
  276. if (pos > falsename.size()) falsename_ok = false;
  277. if (pos > truename.size()) truename_ok = false;
  278. if (pos > othername.size()) othername_ok = false;
  279. }
  280. if (pos == 0)
  281. in.setstate(std::ios_base::failbit);
  282. else {
  283. if (falsename_ok) x = false;
  284. else if (truename_ok) x = true;
  285. else if (othername_ok) x = indeterminate;
  286. else in.setstate(std::ios_base::failbit);
  287. }
  288. }
  289. } else {
  290. long value;
  291. if (in >> value) {
  292. switch (value) {
  293. case 0: x = false; break;
  294. case 1: x = true; break;
  295. case 2: x = indeterminate; break;
  296. default: in.setstate(std::ios_base::failbit); break;
  297. }
  298. }
  299. }
  300. return in;
  301. }
  302. } } // end namespace boost::logic
  303. #endif // BOOST_LOGIC_TRIBOOL_IO_HPP