Imported Upstream version 1.57.0
[platform/upstream/boost.git] / boost / archive / basic_text_oprimitive.hpp
index 06885ad..73a0a62 100644 (file)
@@ -2,7 +2,7 @@
 #define BOOST_ARCHIVE_BASIC_TEXT_OPRIMITIVE_HPP
 
 // MS compatible compilers support #pragma once
-#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#if defined(_MSC_VER)
 # pragma once
 #endif
 
 
 #include <iomanip>
 #include <locale>
-#include <boost/config/no_tr1/cmath.hpp> // isnan
 #include <boost/assert.hpp>
 #include <cstddef> // size_t
 
 #include <boost/config.hpp>
 #include <boost/static_assert.hpp>
 #include <boost/detail/workaround.hpp>
+#include <boost/io/ios_state.hpp>
+
 #if BOOST_WORKAROUND(BOOST_DINKUMWARE_STDLIB, == 1)
 #include <boost/archive/dinkumware.hpp>
 #endif
@@ -46,6 +47,8 @@ namespace std{
 } // namespace std
 #endif
 
+#include <boost/type_traits/is_floating_point.hpp>
+#include <boost/mpl/bool.hpp>
 #include <boost/limits.hpp>
 #include <boost/integer.hpp>
 #include <boost/io/ios_state.hpp>
@@ -65,11 +68,7 @@ class save_access;
 template<class OStream>
 class basic_text_oprimitive
 {
-#ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS
 protected:
-#else
-public:
-#endif
     OStream &os;
     io::ios_flags_saver flags_saver;
     io::ios_precision_saver precision_saver;
@@ -77,21 +76,11 @@ public:
     #ifndef BOOST_NO_STD_LOCALE
     boost::scoped_ptr<std::locale> archive_locale;
     basic_streambuf_locale_saver<
-        BOOST_DEDUCED_TYPENAME OStream::char_type, 
-        BOOST_DEDUCED_TYPENAME OStream::traits_type
+        typename OStream::char_type, 
+        typename OStream::traits_type
     > locale_saver;
     #endif
 
-    // default saving of primitives.
-    template<class T>
-    void save(const T &t){
-        if(os.fail())
-            boost::serialization::throw_exception(
-                archive_exception(archive_exception::output_stream_error)
-            );
-        os << t;
-    }
-
     /////////////////////////////////////////////////////////
     // fundamental types that need special treatment
     void save(const bool t){
@@ -123,33 +112,77 @@ public:
         save(static_cast<int>(t));
     }
     #endif
-    void save(const float t)
-    {
-        // must be a user mistake - can't serialize un-initialized data
+
+    /////////////////////////////////////////////////////////
+    // saving of any types not listed above
+
+    template<class T>
+    void save_impl(const T &t, boost::mpl::bool_<false> &){
         if(os.fail())
             boost::serialization::throw_exception(
                 archive_exception(archive_exception::output_stream_error)
             );
-        os << std::setprecision(std::numeric_limits<float>::digits10 + 2);
         os << t;
     }
-    void save(const double t)
-    {
+
+    /////////////////////////////////////////////////////////
+    // floating point types need even more special treatment
+    // the following determines whether the type T is some sort
+    // of floating point type.  Note that we then assume that
+    // the stream << operator is defined on that type - if not
+    // we'll get a compile time error. This is meant to automatically
+    // support synthesized types which support floating point
+    // operations. Also it should handle compiler dependent types
+    // such long double.  Due to John Maddock.
+
+    template<class T>
+    struct is_float {
+        typedef typename mpl::bool_< 
+            boost::is_floating_point<T>::value 
+            || (std::numeric_limits<T>::is_specialized
+            && !std::numeric_limits<T>::is_integer
+            && !std::numeric_limits<T>::is_exact
+            && std::numeric_limits<T>::max_exponent) 
+        >::type type;
+    };
+
+    template<class T>
+    void save_impl(const T &t, boost::mpl::bool_<true> &){
         // must be a user mistake - can't serialize un-initialized data
         if(os.fail())
             boost::serialization::throw_exception(
                 archive_exception(archive_exception::output_stream_error)
             );
-        os << std::setprecision(std::numeric_limits<double>::digits10 + 2);
-        os << t;
+        // The formulae for the number of decimla digits required is given in
+        // http://www2.open-std.org/JTC1/SC22/WG21/docs/papers/2005/n1822.pdf
+        // which is derived from Kahan's paper:
+        // www.eecs.berkeley.edu/~wkahan/ieee754status/ieee754.ps
+        // const unsigned int digits = (std::numeric_limits<T>::digits * 3010) / 10000;
+        // note: I've commented out the above because I didn't get good results.  e.g.
+        // in one case I got a difference of 19 units.
+        #ifndef BOOST_NO_CXX11_NUMERIC_LIMITS
+            const unsigned int digits = std::numeric_limits<T>::max_digits10;
+        #else
+            const unsigned int digits = std::numeric_limits<T>::digits10 + 2;
+        #endif
+        os << std::setprecision(digits) << std::scientific << t;
     }
+
+    template<class T>
+    void save(const T & t){
+        boost::io::ios_flags_saver fs(os);
+        boost::io::ios_precision_saver ps(os);
+        typename is_float<T>::type tf;
+        save_impl(t, tf);
+    }
+
     BOOST_ARCHIVE_OR_WARCHIVE_DECL(BOOST_PP_EMPTY())
     basic_text_oprimitive(OStream & os, bool no_codecvt);
     BOOST_ARCHIVE_OR_WARCHIVE_DECL(BOOST_PP_EMPTY()) 
     ~basic_text_oprimitive();
 public:
     // unformatted append of one character
-    void put(BOOST_DEDUCED_TYPENAME OStream::char_type c){
+    void put(typename OStream::char_type c){
         if(os.fail())
             boost::serialization::throw_exception(
                 archive_exception(archive_exception::output_stream_error)