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 BOOST_WORKAROUND(_MSC_VER, >= 1200) |
---|
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<> |
---|
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<> |
---|
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<> |
---|
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<> |
---|
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<> |
---|
104 | inline std::basic_string<char> get_default_indeterminate_name<char>() |
---|
105 | { return "indeterminate"; } |
---|
106 | |
---|
107 | #if BOOST_WORKAROUND(BOOST_MSVC, < 1300) |
---|
108 | // VC++ 6.0 chokes on the specialization below, so we're stuck without |
---|
109 | // wchar_t support. What a pain. TODO: it might just need a the template |
---|
110 | // parameter as function parameter... |
---|
111 | #else |
---|
112 | # ifndef BOOST_NO_WCHAR_T |
---|
113 | /// Returns the wide character string L"indeterminate". |
---|
114 | template<> |
---|
115 | inline std::basic_string<wchar_t> get_default_indeterminate_name<wchar_t>() |
---|
116 | { return L"indeterminate"; } |
---|
117 | # endif |
---|
118 | #endif |
---|
119 | |
---|
120 | // http://www.cantrip.org/locale.html |
---|
121 | |
---|
122 | #ifndef BOOST_NO_STD_LOCALE |
---|
123 | /** |
---|
124 | * \brief A locale facet specifying the name of the indeterminate |
---|
125 | * value of a tribool. |
---|
126 | * |
---|
127 | * The facet is used to perform I/O on tribool values when \c |
---|
128 | * std::boolalpha has been specified. This class template is only |
---|
129 | * available if the C++ standard library implementation supports |
---|
130 | * locales. |
---|
131 | */ |
---|
132 | template<typename CharT> |
---|
133 | class indeterminate_name : public std::locale::facet, private boost::noncopyable |
---|
134 | { |
---|
135 | public: |
---|
136 | typedef CharT char_type; |
---|
137 | typedef std::basic_string<CharT> string_type; |
---|
138 | |
---|
139 | /// Construct the facet with the default name |
---|
140 | indeterminate_name() : name_(get_default_indeterminate_name<CharT>()) {} |
---|
141 | |
---|
142 | /// Construct the facet with the given name for the indeterminate value |
---|
143 | explicit indeterminate_name(const string_type& name) : name_(name) {} |
---|
144 | |
---|
145 | /// Returns the name for the indeterminate value |
---|
146 | string_type name() const { return name_; } |
---|
147 | |
---|
148 | /// Uniquily identifies this facet with the locale. |
---|
149 | static std::locale::id id; |
---|
150 | |
---|
151 | private: |
---|
152 | string_type name_; |
---|
153 | }; |
---|
154 | |
---|
155 | template<typename CharT> std::locale::id indeterminate_name<CharT>::id; |
---|
156 | #endif |
---|
157 | |
---|
158 | /** |
---|
159 | * \brief Writes the value of a tribool to a stream. |
---|
160 | * |
---|
161 | * When the value of @p x is either \c true or \c false, this routine |
---|
162 | * is semantically equivalent to: |
---|
163 | * \code out << static_cast<bool>(x); \endcode |
---|
164 | * |
---|
165 | * When @p x has an indeterminate value, it outputs either the integer |
---|
166 | * value 2 (if <tt>(out.flags() & std::ios_base::boolalpha) == 0</tt>) |
---|
167 | * or the name of the indeterminate value. The name of the |
---|
168 | * indeterminate value comes from the indeterminate_name facet (if it |
---|
169 | * is defined in the output stream's locale), or from the |
---|
170 | * get_default_indeterminate_name function (if it is not defined in the |
---|
171 | * locale or if the C++ standard library implementation does not |
---|
172 | * support locales). |
---|
173 | * |
---|
174 | * \returns @p out |
---|
175 | */ |
---|
176 | template<typename CharT, typename Traits> |
---|
177 | inline std::basic_ostream<CharT, Traits>& |
---|
178 | operator<<(std::basic_ostream<CharT, Traits>& out, tribool x) |
---|
179 | { |
---|
180 | if (!indeterminate(x)) { |
---|
181 | out << static_cast<bool>(x); |
---|
182 | } else { |
---|
183 | typename std::basic_ostream<CharT, Traits>::sentry cerberus(out); |
---|
184 | if (cerberus) { |
---|
185 | if (out.flags() & std::ios_base::boolalpha) { |
---|
186 | #ifndef BOOST_NO_STD_LOCALE |
---|
187 | if (BOOST_HAS_FACET(indeterminate_name<CharT>, out.getloc())) { |
---|
188 | const indeterminate_name<CharT>& facet = |
---|
189 | BOOST_USE_FACET(indeterminate_name<CharT>, out.getloc()); |
---|
190 | out << facet.name(); |
---|
191 | } else { |
---|
192 | out << get_default_indeterminate_name<CharT>(); |
---|
193 | } |
---|
194 | #else |
---|
195 | out << get_default_indeterminate_name<CharT>(); |
---|
196 | #endif |
---|
197 | } |
---|
198 | else |
---|
199 | out << 2; |
---|
200 | } |
---|
201 | } |
---|
202 | return out; |
---|
203 | } |
---|
204 | |
---|
205 | /** |
---|
206 | * \brief Writes the indeterminate tribool value to a stream. |
---|
207 | * |
---|
208 | * This routine outputs either the integer |
---|
209 | * value 2 (if <tt>(out.flags() & std::ios_base::boolalpha) == 0</tt>) |
---|
210 | * or the name of the indeterminate value. The name of the |
---|
211 | * indeterminate value comes from the indeterminate_name facet (if it |
---|
212 | * is defined in the output stream's locale), or from the |
---|
213 | * get_default_indeterminate_name function (if it is not defined in the |
---|
214 | * locale or if the C++ standard library implementation does not |
---|
215 | * support locales). |
---|
216 | * |
---|
217 | * \returns @p out |
---|
218 | */ |
---|
219 | template<typename CharT, typename Traits> |
---|
220 | inline std::basic_ostream<CharT, Traits>& |
---|
221 | operator<<(std::basic_ostream<CharT, Traits>& out, |
---|
222 | bool (*)(tribool, detail::indeterminate_t)) |
---|
223 | { return out << tribool(indeterminate); } |
---|
224 | |
---|
225 | /** |
---|
226 | * \brief Reads a tribool value from a stream. |
---|
227 | * |
---|
228 | * When <tt>(out.flags() & std::ios_base::boolalpha) == 0</tt>, this |
---|
229 | * function reads a \c long value from the input stream @p in and |
---|
230 | * converts that value to a tribool. If that value is 0, @p x becomes |
---|
231 | * \c false; if it is 1, @p x becomes \c true; if it is 2, @p becomes |
---|
232 | * \c indetermine; otherwise, the operation fails (and the fail bit is |
---|
233 | * set on the input stream @p in). |
---|
234 | * |
---|
235 | * When <tt>(out.flags() & std::ios_base::boolalpha) != 0</tt>, this |
---|
236 | * function first determines the names of the false, true, and |
---|
237 | * indeterminate values. The false and true names are extracted from |
---|
238 | * the \c std::numpunct facet of the input stream's locale (if the C++ |
---|
239 | * standard library implementation supports locales), or from the \c |
---|
240 | * default_false_name and \c default_true_name functions (if there is |
---|
241 | * no locale support). The indeterminate name is extracted from the |
---|
242 | * appropriate \c indeterminate_name facet (if it is available in the |
---|
243 | * input stream's locale), or from the \c get_default_indeterminate_name |
---|
244 | * function (if the C++ standard library implementation does not |
---|
245 | * support locales, or the \c indeterminate_name facet is not |
---|
246 | * specified for this locale object). The input is then matched to |
---|
247 | * each of these names, and the tribool @p x is assigned the value |
---|
248 | * corresponding to the longest name that matched. If no name is |
---|
249 | * matched or all names are empty, the operation fails (and the fail |
---|
250 | * bit is set on the input stream @p in). |
---|
251 | * |
---|
252 | * \returns @p in |
---|
253 | */ |
---|
254 | template<typename CharT, typename Traits> |
---|
255 | inline std::basic_istream<CharT, Traits>& |
---|
256 | operator>>(std::basic_istream<CharT, Traits>& in, tribool& x) |
---|
257 | { |
---|
258 | if (in.flags() & std::ios_base::boolalpha) { |
---|
259 | typename std::basic_istream<CharT, Traits>::sentry cerberus(in); |
---|
260 | if (cerberus) { |
---|
261 | typedef std::basic_string<CharT> string_type; |
---|
262 | |
---|
263 | #ifndef BOOST_NO_STD_LOCALE |
---|
264 | const std::numpunct<CharT>& numpunct_facet = |
---|
265 | BOOST_USE_FACET(std::numpunct<CharT>, in.getloc()); |
---|
266 | |
---|
267 | string_type falsename = numpunct_facet.falsename(); |
---|
268 | string_type truename = numpunct_facet.truename(); |
---|
269 | |
---|
270 | string_type othername; |
---|
271 | if (BOOST_HAS_FACET(indeterminate_name<CharT>, in.getloc())) { |
---|
272 | othername = |
---|
273 | BOOST_USE_FACET(indeterminate_name<CharT>, in.getloc()).name(); |
---|
274 | } else { |
---|
275 | othername = get_default_indeterminate_name<CharT>(); |
---|
276 | } |
---|
277 | #else |
---|
278 | string_type falsename = default_false_name<CharT>(); |
---|
279 | string_type truename = default_true_name<CharT>(); |
---|
280 | string_type othername = get_default_indeterminate_name<CharT>(); |
---|
281 | #endif |
---|
282 | |
---|
283 | typename string_type::size_type pos = 0; |
---|
284 | bool falsename_ok = true, truename_ok = true, othername_ok = true; |
---|
285 | |
---|
286 | // Modeled after the code from Library DR 17 |
---|
287 | while (falsename_ok && pos < falsename.size() |
---|
288 | || truename_ok && pos < truename.size() |
---|
289 | || othername_ok && pos < othername.size()) { |
---|
290 | typename Traits::int_type c = in.get(); |
---|
291 | if (c == Traits::eof()) |
---|
292 | return in; |
---|
293 | |
---|
294 | bool matched = false; |
---|
295 | if (falsename_ok && pos < falsename.size()) { |
---|
296 | if (Traits::eq(Traits::to_char_type(c), falsename[pos])) |
---|
297 | matched = true; |
---|
298 | else |
---|
299 | falsename_ok = false; |
---|
300 | } |
---|
301 | |
---|
302 | if (truename_ok && pos < truename.size()) { |
---|
303 | if (Traits::eq(Traits::to_char_type(c), truename[pos])) |
---|
304 | matched = true; |
---|
305 | else |
---|
306 | truename_ok = false; |
---|
307 | } |
---|
308 | |
---|
309 | if (othername_ok && pos < othername.size()) { |
---|
310 | if (Traits::eq(Traits::to_char_type(c), othername[pos])) |
---|
311 | matched = true; |
---|
312 | else |
---|
313 | othername_ok = false; |
---|
314 | } |
---|
315 | |
---|
316 | if (matched) { ++pos; } |
---|
317 | if (pos > falsename.size()) falsename_ok = false; |
---|
318 | if (pos > truename.size()) truename_ok = false; |
---|
319 | if (pos > othername.size()) othername_ok = false; |
---|
320 | } |
---|
321 | |
---|
322 | if (pos == 0) |
---|
323 | in.setstate(std::ios_base::failbit); |
---|
324 | else { |
---|
325 | if (falsename_ok) x = false; |
---|
326 | else if (truename_ok) x = true; |
---|
327 | else if (othername_ok) x = indeterminate; |
---|
328 | else in.setstate(std::ios_base::failbit); |
---|
329 | } |
---|
330 | } |
---|
331 | } else { |
---|
332 | long value; |
---|
333 | if (in >> value) { |
---|
334 | switch (value) { |
---|
335 | case 0: x = false; break; |
---|
336 | case 1: x = true; break; |
---|
337 | case 2: x = indeterminate; break; |
---|
338 | default: in.setstate(std::ios_base::failbit); break; |
---|
339 | } |
---|
340 | } |
---|
341 | } |
---|
342 | |
---|
343 | return in; |
---|
344 | } |
---|
345 | |
---|
346 | } } // end namespace boost::logic |
---|
347 | |
---|
348 | #endif // BOOST_LOGIC_TRIBOOL_IO_HPP |
---|