]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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<> | |
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 | #ifndef BOOST_NO_WCHAR_T | |
108 | /// Returns the wide character string L"indeterminate". | |
109 | template<> | |
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 | |
134 | indeterminate_name() : name_(get_default_indeterminate_name<CharT>()) {} | |
135 | ||
136 | /// Construct the facet with the given name for the indeterminate value | |
137 | explicit indeterminate_name(const string_type& initial_name) | |
138 | : name_(initial_name) {} | |
139 | ||
140 | /// Returns the name for the indeterminate value | |
141 | 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>& | |
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>& | |
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>& | |
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 |