$include_dir="/home/hyper-archives/boost-commit/include"; include("$include_dir/msg-header.inc") ?>
Subject: [Boost-commit] svn:boost r71371 - trunk/boost/math/special_functions
From: pbristow_at_[hidden]
Date: 2011-04-18 12:19:49
Author: pbristow
Date: 2011-04-18 12:19:48 EDT (Mon, 18 Apr 2011)
New Revision: 71371
URL: http://svn.boost.org/trac/boost/changeset/71371
Log:
nonfinite facets
Added:
   trunk/boost/math/special_functions/nonfinite_num_facets.hpp   (contents, props changed)
Added: trunk/boost/math/special_functions/nonfinite_num_facets.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/math/special_functions/nonfinite_num_facets.hpp	2011-04-18 12:19:48 EDT (Mon, 18 Apr 2011)
@@ -0,0 +1,540 @@
+#ifndef BOOST_MATH_NONFINITE_NUM_FACETS_HPP
+#define BOOST_MATH_NONFINITE_NUM_FACETS_HPP
+
+// Copyright (c) 2006 Johan Rade
+// Copyright 2011 Paul A. Bristow (comments)
+
+// Distributed under 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)
+
+/*
+\file
+
+\brief non_finite_num facets for C99 standard output of infinity and NaN.
+
+\details See fuller documentation at Boost.Math Facets
+  for Floating-Point Infinities and NaNs.
+*/
+
+#include <cstring>
+#include <ios>
+#include <limits>
+#include <locale>
+
+#include <boost/version.hpp>
+
+#include <boost/math/special_functions/fpclassify.hpp>
+#include <boost/math/special_functions/sign.hpp>
+
+#ifdef _MSC_VER
+#   pragma warning(push)
+#   pragma warning(disable : 4127) // conditional expression is constant.
+#   pragma warning(disable : 4706) // assignment within conditional expression.
+#   pragma warning(disable : 4224) // formal parameter 'version' was previously defined as a type.
+#endif
+
+namespace boost {
+  namespace math {
+
+    // flags (enums can be ORed together)       -----------------------------------
+
+    const int legacy = 0x1; //!< get facet will recognize most string representations of infinity and NaN.
+    const int signed_zero = 0x2; //!< put facet will distinguish between positive and negative zero.
+    const int trap_infinity = 0x4; /*!< put facet will throw an exception of type std::ios_base::failure
+       when an attempt is made to format positive or negative infinity.
+       get will set the fail bit of the stream when an attempt is made 
+       to parse a string that represents positive or negative sign infinity.
+    */
+    const int trap_nan = 0x8; /*!< put facet will throw an exception of type std::ios_base::failure
+       when an attempt is made to format positive or negative NaN.
+       get will set the fail bit of the stream when an attempt is made 
+       to parse a string that represents positive or negative sign infinity.
+       */
+
+    // class nonfinite_num_put -----------------------------------------------------
+
+    template<
+      class CharType,
+      class OutputIterator = std::ostreambuf_iterator<CharType>
+            >
+    class nonfinite_num_put : public std::num_put<CharType, OutputIterator>
+    {
+    public:
+      explicit nonfinite_num_put(int flags = 0) : flags_(flags) {}
+
+    protected:
+      virtual OutputIterator do_put(
+        OutputIterator it, std::ios_base& iosb,
+        CharType fill, double val) const
+      {
+        put_and_reset_width(it, iosb, fill, val);
+        return it;
+      }
+
+      virtual OutputIterator do_put(
+        OutputIterator it, std::ios_base& iosb,
+        CharType fill, long double val) const
+      {
+        put_and_reset_width(it, iosb, fill, val);
+        return it;
+      }
+
+    private:
+      template<class ValType> void put_and_reset_width(
+        OutputIterator& it, std::ios_base& iosb,
+        CharType fill, ValType val) const
+      {
+        put_impl(it, iosb, fill, val);
+        iosb.width(0);
+      }
+
+      template<class ValType> void put_impl(
+        OutputIterator& it, std::ios_base& iosb,
+        CharType fill, ValType val) const
+      {
+        switch((boost::math::fpclassify)(val)) {
+
+        case FP_INFINITE:
+          if(flags_ & trap_infinity)
+            throw std::ios_base::failure("Infinity");
+          else if((boost::math::signbit)(val))
+            put_num_and_fill(it, iosb, "-", "inf", fill);
+          else if(iosb.flags() & std::ios_base::showpos)
+            put_num_and_fill(it, iosb, "+", "inf", fill);
+          else
+            put_num_and_fill(it, iosb, "", "inf", fill);
+          break;
+
+        case FP_NAN:
+          if(flags_ & trap_nan)
+            throw std::ios_base::failure("NaN");
+          else if((boost::math::signbit)(val))
+            put_num_and_fill(it, iosb, "-", "nan", fill);
+          else if(iosb.flags() & std::ios_base::showpos)
+            put_num_and_fill(it, iosb, "+", "nan", fill);
+          else
+            put_num_and_fill(it, iosb, "", "nan", fill);
+          break;
+
+        case FP_ZERO:
+          if(flags_ & signed_zero) {
+            if((boost::math::signbit)(val))
+              put_num_and_fill(it, iosb, "-", "0", fill);
+            else if(iosb.flags() & std::ios_base::showpos)
+              put_num_and_fill(it, iosb, "+", "0", fill);
+            else
+              put_num_and_fill(it, iosb, "", "0", fill);
+          }
+          else
+            put_num_and_fill(it, iosb, "", "0", fill);
+          break;
+
+        default:
+          it = std::num_put<CharType, OutputIterator>::do_put(
+            it, iosb, fill, val);
+          break;
+        }
+      }
+
+      void put_num_and_fill(
+        OutputIterator& it, std::ios_base& iosb, const char* prefix,
+        const char* body, CharType fill) const
+      {
+        int width = (int)strlen(prefix) + (int)strlen(body);
+        std::ios_base::fmtflags adjust
+          = iosb.flags() & std::ios_base::adjustfield;
+        const std::ctype<CharType>& ct
+          = std::use_facet<std::ctype<CharType> >(iosb.getloc());
+
+        if(adjust != std::ios_base::internal && adjust != std::ios_base::left)
+          put_fill(it, iosb, fill, width);
+
+        while(*prefix)
+          *it = ct.widen(*(prefix++));
+
+        if(adjust == std::ios_base::internal)
+          put_fill(it, iosb, fill, width);
+
+        if(iosb.flags() & std::ios_base::uppercase) {
+          while(*body)
+            *it = ct.toupper(ct.widen(*(body++)));
+        }
+        else {
+          while(*body)
+            *it = ct.widen(*(body++));
+        }
+
+        if(adjust == std::ios_base::left)
+          put_fill(it, iosb, fill, width);
+      }
+
+      void put_fill(
+        OutputIterator& it, std::ios_base& iosb,
+        CharType fill, int width) const
+      {
+        for(std::streamsize i = iosb.width() - static_cast<std::streamsize>(width); i > 0; --i)
+          *it = fill;
+      }
+
+    private:
+      const int flags_;
+    };
+
+
+    // class nonfinite_num_get ------------------------------------------------------
+
+    template<
+      class CharType,
+      class InputIterator = std::istreambuf_iterator<CharType>
+    >
+    class nonfinite_num_get : public std::num_get<CharType, InputIterator>
+    {
+
+    public:
+      explicit nonfinite_num_get(int flags = 0) : flags_(flags)
+      {}
+
+    protected:
+      virtual InputIterator do_get(
+        InputIterator it, InputIterator end, std::ios_base& iosb,
+        std::ios_base::iostate& state, float& val) const
+      {
+        get_and_check_eof(it, end, iosb, state, val);
+        return it;
+      }
+
+      virtual InputIterator do_get(
+        InputIterator it, InputIterator end, std::ios_base& iosb,
+        std::ios_base::iostate& state, double& val) const
+      {
+        get_and_check_eof(it, end, iosb, state, val);
+        return it;
+      }
+
+      virtual InputIterator do_get(
+        InputIterator it, InputIterator end, std::ios_base& iosb,
+        std::ios_base::iostate& state, long double& val) const
+      {
+        get_and_check_eof(it, end, iosb, state, val);
+        return it;
+      }
+
+      //..............................................................................
+
+    private:
+      template<class ValType> static ValType positive_nan()
+      {
+        // On some platforms quiet_NaN() may be negative.
+        return (boost::math::copysign)(
+          std::numeric_limits<ValType>::quiet_NaN(), static_cast<ValType>(1)
+          );
+        // static_cast<ValType>(1) added Paul A. Bristow 5 Apr 11
+      }
+
+      template<class ValType> void get_and_check_eof
+      (
+        InputIterator& it, InputIterator end, std::ios_base& iosb,
+        std::ios_base::iostate& state, ValType& val
+      ) const
+      {
+        get_signed(it, end, iosb, state, val);
+        if(it == end)
+          state |= std::ios_base::eofbit;
+      }
+
+      template<class ValType> void get_signed
+      (
+        InputIterator& it, InputIterator end, std::ios_base& iosb,
+        std::ios_base::iostate& state, ValType& val
+      ) const
+      {
+        const std::ctype<CharType>& ct
+          = std::use_facet<std::ctype<CharType> >(iosb.getloc());
+
+        char c = peek_char(it, end, ct);
+
+        bool negative = (c == '-');
+
+        if(negative || c == '+')
+        {
+          ++it;
+          c = peek_char(it, end, ct);
+          if(c == '-' || c == '+')
+          { // Without this check, "++5" etc would be accepted.
+            state |= std::ios_base::failbit;
+            return;
+          }
+        }
+
+        get_unsigned(it, end, iosb, ct, state, val);
+
+        if(negative)
+        {
+          val = (boost::math::changesign)(val);
+        }
+      } // void get_signed
+
+      template<class ValType> void get_unsigned
+      ( // get an unsigned value into val
+        InputIterator& it, InputIterator end, std::ios_base& iosb,
+        const std::ctype<CharType>& ct,
+        std::ios_base::iostate& state, ValType& val
+      ) const
+      {
+        switch(peek_char(it, end, ct))
+        {
+        case 'i':
+          get_i(it, end, ct, state, val);
+          break;
+
+        case 'n':
+          get_n(it, end, ct, state, val);
+          break;
+
+        case 'q':
+        case 's':
+          get_q(it, end, ct, state, val);
+          break;
+
+        default:
+          it = std::num_get<CharType, InputIterator>::do_get(
+            it, end, iosb, state, val);
+          if((flags_ & legacy) && val == static_cast<ValType>(1)
+            && peek_char(it, end, ct) == '#')
+            get_one_hash(it, end, ct, state, val);
+          break;
+        }
+      } //  get_unsigned
+
+      //..........................................................................
+
+      template<class ValType> void get_i
+      ( // Get the rest of all strings starting with 'i', expect "inf", "infinity".
+        InputIterator& it, InputIterator end, const std::ctype<CharType>& ct,
+        std::ios_base::iostate& state, ValType& val
+      ) const
+      {
+        if(!std::numeric_limits<ValType>::has_infinity
+          || (flags_ & trap_infinity))
+        {
+            state |= std::ios_base::failbit;
+            return;
+        }
+
+        ++it;
+        if(!match_string(it, end, ct, "nf"))
+        {
+          state |= std::ios_base::failbit;
+          return;
+        }
+
+        if(peek_char(it, end, ct) != 'i')
+        {
+          val = std::numeric_limits<ValType>::infinity();  // "inf"
+          return;
+        }
+
+        ++it;
+        if(!match_string(it, end, ct, "nity"))
+        { // Expected "infinity"
+          state |= std::ios_base::failbit;
+          return;
+        }
+
+        val = std::numeric_limits<ValType>::infinity(); // "infinity"
+      } // void get_i
+
+      template<class ValType> void get_n
+      ( // Get expected strings after 'n', "nan", "nanq", "nans", "nan(...)" 
+        InputIterator& it, InputIterator end, const std::ctype<CharType>& ct,
+        std::ios_base::iostate& state, ValType& val
+      ) const
+      {
+        if(!std::numeric_limits<ValType>::has_quiet_NaN
+          || (flags_ & trap_nan)) {
+            state |= std::ios_base::failbit;
+            return;
+        }
+
+        ++it;
+        if(!match_string(it, end, ct, "an"))
+        {
+          state |= std::ios_base::failbit;
+          return;
+        }
+
+        switch(peek_char(it, end, ct)) {
+        case 'q':
+        case 's':
+          if(flags_ && legacy)
+            ++it;
+          break;  // "nanq", "nans"
+
+        case '(':   // Optional payload field in (...) follows.
+         {
+            ++it;
+            char c;
+            while((c = peek_char(it, end, ct))
+              && c != ')' && c != ' ' && c != '\n' && c != '\t')
+              ++it;
+            if(c != ')')
+            { // Optional payload field terminator missing!
+              state |= std::ios_base::failbit;
+              return;
+            }
+            ++it;
+            break;  // "nan(...)" 
+          }
+
+        default:
+          break;  // "nan"
+        }
+
+        val = positive_nan<ValType>();
+      } // void get_n
+
+      template<class ValType> void get_q
+      ( // Get expected rest of string starting with 'q': "qnan".
+        InputIterator& it, InputIterator end, const std::ctype<CharType>& ct,
+        std::ios_base::iostate& state, ValType& val
+      ) const
+      {
+        if(!std::numeric_limits<ValType>::has_quiet_NaN
+          || (flags_ & trap_nan) || !(flags_ & legacy))
+        {
+          state |= std::ios_base::failbit;
+          return;
+        }
+
+        ++it;
+        if(!match_string(it, end, ct, "nan"))
+        {
+          state |= std::ios_base::failbit;
+          return;
+        }
+
+        val = positive_nan<ValType>(); // "QNAN"
+      } //  void get_q
+
+      template<class ValType> void get_one_hash
+      ( // Get expected string after having read "1.#": "1.#IND", "1.#QNAN", "1.#SNAN".
+        InputIterator& it, InputIterator end, const std::ctype<CharType>& ct,
+        std::ios_base::iostate& state, ValType& val
+      ) const
+      {
+
+        ++it;
+        switch(peek_char(it, end, ct))
+        {
+        case 'i': // from IND (indeterminate), considered same a QNAN.
+          get_one_hash_i(it, end, ct, state, val); // "1.#IND"
+          return;
+
+        case 'q': // from QNAN
+        case 's': // from SNAN - treated the same as QNAN.
+          if(std::numeric_limits<ValType>::has_quiet_NaN
+            && !(flags_ & trap_nan))
+          {
+            ++it;
+            if(match_string(it, end, ct, "nan"))
+            { // "1.#QNAN", "1.#SNAN"
+ //             ++it; // removed as caused assert() cannot increment iterator).
+// (match_string consumes string, so not needed?).
+// https://svn.boost.org/trac/boost/ticket/5467
+// Change in nonfinite_num_facet.hpp Paul A. Bristow 11 Apr 11 makes legacy_test.cpp work OK.
+              val = positive_nan<ValType>(); // "1.#QNAN"
+              return;
+            }
+          }
+          break;
+
+        default:
+          break;
+        }
+
+        state |= std::ios_base::failbit;
+      } //  void get_one_hash
+
+      template<class ValType> void get_one_hash_i
+      ( // Get expected strings after 'i', "1.#INF", 1.#IND".
+        InputIterator& it, InputIterator end, const std::ctype<CharType>& ct,
+        std::ios_base::iostate& state, ValType& val
+      ) const
+      {
+        ++it;
+
+        if(peek_char(it, end, ct) == 'n')
+        {
+          ++it;
+          switch(peek_char(it, end, ct))
+          {
+          case 'f':  // "1.#INF"
+            if(std::numeric_limits<ValType>::has_infinity
+              && !(flags_ & trap_infinity))
+            {
+                ++it;
+                val = std::numeric_limits<ValType>::infinity();
+                return;
+            }
+            break;
+
+          case 'd':   // 1.#IND"
+            if(std::numeric_limits<ValType>::has_quiet_NaN
+              && !(flags_ & trap_nan))
+            {
+                ++it;
+                val = positive_nan<ValType>();
+                return;
+            }
+            break;
+
+          default:
+            break;
+          }
+        }
+
+        state |= std::ios_base::failbit;
+      } //  void get_one_hash_i
+
+      //..........................................................................
+
+      char peek_char
+      ( // Return next char (from input buffer).
+        InputIterator& it, InputIterator end,
+        const std::ctype<CharType>& ct
+      ) const
+      {
+        if(it == end) return 0;
+        return ct.narrow(ct.tolower(*it), 0); // Always tolower to ensure case insensitive.
+      }
+
+      bool match_string
+      ( // Match remaining chars to expected string (case insensitive).
+        InputIterator& it, InputIterator end,
+        const std::ctype<CharType>& ct,
+        const char* s
+      ) const
+      {
+        while(it != end && *s && *s == ct.narrow(ct.tolower(*it), 0))
+        {
+          ++s;
+          ++it;
+        }
+        return !*s;
+      } //  char peek_char
+
+    private:
+      const int flags_;
+    }; // 
+
+    //------------------------------------------------------------------------------
+
+  }   // namespace math
+}   // namespace boost
+
+#ifdef _MSC_VER
+#   pragma warning(pop)
+#endif
+
+#endif