All Classes Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
tribool.hpp
1 // The MIT License (MIT)
2 
3 // Copyright (c) 2012-2014 Danny Y., Rapptz
4 
5 // Permission is hereby granted, free of charge, to any person obtaining a copy of
6 // this software and associated documentation files (the "Software"), to deal in
7 // the Software without restriction, including without limitation the rights to
8 // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 // the Software, and to permit persons to whom the Software is furnished to do so,
10 // subject to the following conditions:
11 
12 // The above copyright notice and this permission notice shall be included in all
13 // copies or substantial portions of the Software.
14 
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17 // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 
22 #ifndef GEARS_UTILITY_TRIBOOL_HPP
23 #define GEARS_UTILITY_TRIBOOL_HPP
24 
25 #include <utility>
26 #ifndef GEARS_NO_IOSTREAM
27 #include <iosfwd>
28 #include <locale>
29 #include <string>
30 #endif // GEARS_NO_IOSTREAM
31 
32 namespace gears {
33 namespace utility {
34 struct indeterminate_t {
35  constexpr indeterminate_t() {}
36 };
37 
42 constexpr indeterminate_t indeterminate{};
43 
99 struct tribool {
100 private:
101  enum class state : char {
102  true_, false_, unknown
103  } value;
104 public:
108  constexpr tribool() noexcept: value(state::unknown) {}
109 
113  constexpr tribool(indeterminate_t) noexcept: value(state::unknown) {}
114 
118  constexpr tribool(bool v) noexcept: value(v ? state::true_ : state::false_) {}
119 
124  explicit constexpr operator bool() const noexcept {
125  return value == state::true_;
126  }
127 
133  friend constexpr bool is_true(const tribool& tri) noexcept {
134  return tri.value == state::true_;
135  }
136 
142  friend constexpr bool is_false(const tribool& tri) noexcept {
143  return tri.value == state::false_;
144  }
145 
151  friend constexpr bool is_indeterminate(const tribool& tri) noexcept {
152  return tri.value == state::unknown;
153  }
154 
169  constexpr tribool operator==(const tribool& rhs) const noexcept {
170  return (value == state::unknown || rhs.value == state::unknown) ?
171  tribool(indeterminate) : tribool(value == rhs.value);
172  }
173 
188  constexpr tribool operator!=(const tribool& rhs) const noexcept {
189  return (value == state::unknown || rhs.value == state::unknown) ?
190  tribool(indeterminate) : tribool(value != rhs.value);
191  }
192 
207  constexpr tribool operator!() const noexcept {
208  return value == state::unknown ? tribool(indeterminate) : tribool(!(value == state::true_));
209  }
210 };
211 
231 constexpr tribool operator&&(const tribool& lhs, const tribool& rhs) noexcept {
232  return is_false(lhs) || is_false(rhs) ? tribool(false) :
233  is_indeterminate(lhs) || is_indeterminate(rhs) ? tribool(indeterminate) : tribool(true);
234 }
235 
236 constexpr tribool operator&&(const tribool& lhs, bool b) noexcept {
237  return lhs && tribool(b);
238 }
239 
240 constexpr tribool operator&&(bool b, const tribool& rhs) noexcept {
241  return tribool(b) && rhs;
242 }
243 
263 constexpr tribool operator||(const tribool& lhs, const tribool& rhs) noexcept {
264  return is_true(lhs) || is_true(rhs) ? tribool(true) :
265  is_indeterminate(lhs) || is_indeterminate(rhs) ? tribool(indeterminate) : tribool(false);
266 }
267 
268 constexpr tribool operator||(const tribool& lhs, bool b) noexcept {
269  return lhs || tribool(b);
270 }
271 
272 constexpr tribool operator||(bool b, const tribool& rhs) noexcept {
273  return tribool(b) || rhs;
274 }
275 
276 #ifndef GEARS_NO_IOSTREAM
277 
291 template<typename CharT>
292 constexpr const CharT* get_default_indeterminate_name() noexcept;
293 
294 template<>
295 constexpr const char* get_default_indeterminate_name<char>() noexcept {
296  return "indeterminate";
297 }
298 
299 template<>
300 constexpr const wchar_t* get_default_indeterminate_name<wchar_t>() noexcept {
301  return L"indeterminate";
302 }
303 
316 template<typename CharT>
317 struct indeterminate_name : public std::locale::facet {
318 public:
319  using char_type = CharT;
320  using string_type = std::basic_string<CharT>;
321 private:
322  string_type name_ = get_default_indeterminate_name<CharT>();
323 public:
327  indeterminate_name() = default;
328 
332  explicit constexpr indeterminate_name(string_type name) noexcept: name_(std::move(name)) {}
333 
337  constexpr string_type name() const noexcept {
338  return name_;
339  }
340 
341  static std::locale::id id;
342 };
343 
344 template<typename CharT>
345 std::locale::id indeterminate_name<CharT>::id;
346 
380 template<typename CharT, typename Traits>
381 inline auto operator<<(std::basic_ostream<CharT, Traits>& out, const tribool& tri) -> decltype(out) {
382  if(!is_indeterminate(tri)) {
383  return out << static_cast<bool>(tri);
384  }
385 
386  typename std::basic_ostream<CharT, Traits>::sentry sentry(out);
387  if(sentry) {
388  if(out.flags() & std::ios_base::boolalpha) {
389  if(std::has_facet<indeterminate_name<CharT>>(out.getloc())) {
390  auto&& facet = std::use_facet<indeterminate_name<CharT>>(out.getloc());
391  out << facet.name();
392  }
393  else {
394  out << get_default_indeterminate_name<CharT>();
395  }
396  }
397  else {
398  out << 2;
399  }
400  }
401 
402  return out;
403 }
404 
424 template<typename CharT, typename Traits>
425 inline auto operator>>(std::basic_istream<CharT, Traits>& in, tribool& tri) -> decltype(in) {
426  if(in.flags() & std::ios_base::boolalpha) {
427  typename std::basic_istream<CharT, Traits>::sentry sentry(in);
428  if(sentry) {
429  auto&& loc = in.getloc();
430  auto&& numpunct_facet = std::use_facet<std::numpunct<CharT>>(loc);
431  auto&& false_name = numpunct_facet.falsename();
432  auto&& true_name = numpunct_facet.truename();
433 
434  using other_facet = indeterminate_name<CharT>;
435  std::basic_string<CharT> other_name = get_default_indeterminate_name<CharT>();
436  if(std::has_facet<other_facet>(loc)) {
437  auto&& facet = std::use_facet<other_facet>(loc);
438  other_name = facet.name();
439  }
440 
441  std::basic_string<CharT> str;
442  if(in >> str) {
443  if(str == false_name) {
444  tri = false;
445  }
446  else if(str == true_name) {
447  tri = true;
448  }
449  else if(str == other_name) {
450  tri = indeterminate;
451  }
452  else {
453  in.setstate(std::ios_base::failbit);
454  }
455  }
456  return in;
457  }
458  }
459  else {
460  int x;
461  if(in >> x) {
462  switch(x) {
463  case 0: tri = false; break;
464  case 1: tri = true; break;
465  case 2: tri = indeterminate; break;
466  default:
467  in.setstate(std::ios_base::failbit);
468  break;
469  }
470  }
471  }
472  return in;
473 }
474 
475 #endif // GEARS_NO_IOSTREAM
476 } // utility
477 } // gears
478 
479 #endif // GEARS_UTILITY_TRIBOOL_HPP