summaryrefslogtreecommitdiff
path: root/boost/logic/tribool_io.hpp
blob: 9ee34d4b7597b3214a80e6ea49dec56aa1d9082e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
// 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& initial_name)
  : name_(initial_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