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