$include_dir="/home/hyper-archives/boost-commit/include"; include("$include_dir/msg-header.inc") ?>
Subject: [Boost-commit] svn:boost r86486 - in trunk/boost/archive: . detail impl
From: ramey_at_[hidden]
Date: 2013-10-27 16:38:43
Author: ramey
Date: 2013-10-27 16:38:43 EDT (Sun, 27 Oct 2013)
New Revision: 86486
URL: http://svn.boost.org/trac/boost/changeset/86486
Log:
correct rounding
fix memory leak for constructor failure in load_construct_data
fix another bug in loading pointers
Text files modified: 
   trunk/boost/archive/basic_text_oprimitive.hpp      |    70 +++++++++++++++-------                  
   trunk/boost/archive/detail/iserializer.hpp         |   122 +++++++++++++++++++++++++++++++++++---- 
   trunk/boost/archive/impl/basic_text_oprimitive.ipp |     1                                         
   trunk/boost/archive/impl/xml_oarchive_impl.ipp     |     2                                         
   trunk/boost/archive/impl/xml_wiarchive_impl.ipp    |     2                                         
   trunk/boost/archive/impl/xml_woarchive_impl.ipp    |     2                                         
   6 files changed, 159 insertions(+), 40 deletions(-)
Modified: trunk/boost/archive/basic_text_oprimitive.hpp
==============================================================================
--- trunk/boost/archive/basic_text_oprimitive.hpp	Sun Oct 27 16:37:44 2013	(r86485)
+++ trunk/boost/archive/basic_text_oprimitive.hpp	2013-10-27 16:38:43 EDT (Sun, 27 Oct 2013)	(r86486)
@@ -26,7 +26,7 @@
 
 #include <iomanip>
 #include <locale>
-#include <boost/config/no_tr1/cmath.hpp> // isnan
+//#include <boost/config/no_tr1/cmath.hpp> // isnan
 #include <boost/assert.hpp>
 #include <cstddef> // size_t
 
@@ -46,6 +46,8 @@
 } // 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>
@@ -82,16 +84,6 @@
     > 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,32 +115,62 @@
         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)
             );
-        // 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:
-        // http://http.cs.berkley.edu/~wkahan/ieee754status/ieee754.ps
-        unsigned int digits = std::numeric_limits<float>::digits * 3010;
-        digits /= 10000;
-        os << std::setprecision(digits);
         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 Maddoc.
+
+    template<class T>
+    struct is_float {
+        typedef BOOST_DEDUCED_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);
+        // 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:
+        // http://http.cs.berkley.edu/~wkahan/ieee754status/ieee754.ps
+        const unsigned int digits = (std::numeric_limits<float>::digits * 3010) / 10000;
+        os << std::setprecision(digits);
         os << t;
     }
+
+    template<class T>
+    void save(const T & t){
+        BOOST_DEDUCED_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()) 
Modified: trunk/boost/archive/detail/iserializer.hpp
==============================================================================
--- trunk/boost/archive/detail/iserializer.hpp	Sun Oct 27 16:37:44 2013	(r86485)
+++ trunk/boost/archive/detail/iserializer.hpp	2013-10-27 16:38:43 EDT (Sun, 27 Oct 2013)	(r86486)
@@ -232,6 +232,7 @@
 //    }
 //}
 
+#if 0
 template<class T>
 struct heap_allocator
 {
@@ -288,6 +289,99 @@
 private:
     T* m_p;
 };
+#endif
+
+// the purpose of this code is to allocate memory for an object
+// without requiring the constructor to be called.  Presumably
+// the allocated object will be subsequently initialized with
+// "placement new". 
+// note: we have the boost type trait has_new_operator but we
+// have no corresponding has_delete_operator.  So we presume
+// that the former being true would imply that the a delete
+// operator is also defined for the class T.
+
+template<class T>
+struct heap_allocation {
+    // boost::has_new_operator< T > doesn't work on these compilers
+    #if DONT_USE_HAS_NEW_OPERATOR
+        // This doesn't handle operator new overload for class T
+        static T * invoke_new(){
+            return static_cast<T *>(operator new(sizeof(T)));
+        }
+        static viod invoke_delete(){
+            (operator delete(sizeof(T)));
+        }
+    #else
+        // note: we presume that a true value for has_new_operator
+        // implies the existence of a class specific delete operator as well
+        // as a class specific new operator.
+        struct has_new_operator {
+            static T * invoke_new() {
+                return static_cast<T *>((T::operator new)(sizeof(T)));
+            }
+            static void invoke_delete(T * t) {
+                // if compilation fails here, the likely cause that the class
+                // T has a class specific new operator but no class specific
+                // delete operator which matches the following signature.  Fix
+                // your program to have this.  Note that adding operator delete
+                // with only one parameter doesn't seem correct to me since 
+                // the standard(3.7.4.2) says "
+                // "If a class T has a member deallocation function named
+                // 'operator delete' with exactly one parameter, then that function 
+                // is a usual (non-placement) deallocation function" which I take
+                // to mean that it will call the destructor of type T which we don't
+                // want to do here.
+                // Note: reliance upon automatic conversion from T * to void * here
+                (T::operator delete)(t, sizeof(T));
+            }
+        };
+        struct doesnt_have_new_operator {
+            static T* invoke_new() {
+                return static_cast<T *>(operator new(sizeof(T)));
+            }
+            static void invoke_delete(T * t) {
+                // Note: I'm reliance upon automatic conversion from T * to void * here
+                (operator delete)(t);
+            }
+        };
+        static T * invoke_new() {
+            typedef BOOST_DEDUCED_TYPENAME
+                mpl::eval_if<
+                    boost::has_new_operator< T >,
+                    mpl::identity<has_new_operator >,
+                    mpl::identity<doesnt_have_new_operator >    
+                >::type typex;
+            return typex::invoke_new();
+        }
+        static void invoke_delete(T *t) {
+            typedef BOOST_DEDUCED_TYPENAME
+                mpl::eval_if<
+                    boost::has_new_operator< T >,
+                    mpl::identity<has_new_operator >,
+                    mpl::identity<doesnt_have_new_operator >    
+                >::type typex;
+            typex::invoke_delete(t);
+        }
+    #endif
+    explicit heap_allocation(){
+        m_p = invoke_new();
+    }
+    ~heap_allocation(){
+        if (0 != m_p)
+            invoke_delete(m_p);
+    }
+    T* get() const {
+        return m_p;
+    }
+
+    T* release() {
+        T* p = m_p;
+        m_p = 0;
+        return p;
+    }
+private:
+    T* m_p;
+};
 
 // note: BOOST_DLLEXPORT is so that code for polymorphic class
 // serialized only through base class won't get optimized out
@@ -301,35 +395,37 @@
     Archive & ar_impl = 
         boost::serialization::smart_cast_reference<Archive &>(ar);
 
-    t  = heap_allocator< T >::invoke();
-    if(NULL == t)
-        boost::serialization::throw_exception(std::bad_alloc()) ;
+    heap_allocation<T> h;
+    t = NULL;
+    // note that the above will throw std::bad_alloc if the allocation
+    // fails so we don't have to address this contingency here.
 
     // catch exception during load_construct_data so that we don't
     // automatically delete the t which is most likely not fully
     // constructed
     BOOST_TRY {
-        // this addresses an obscure situtation that occurs when 
+        // this addresses an obscure situation that occurs when 
         // load_constructor de-serializes something through a pointer.
-        ar.next_object_pointer(t);
+        ar.next_object_pointer(h.get());
         boost::serialization::load_construct_data_adl<Archive, T>(
             ar_impl,
-            static_cast<T *>(t), 
+            h.get(), 
             file_version
         );
     }
     BOOST_CATCH(...){
-        // don't destroy the object - because it was never really
-        // constructed.
-        //boost::serialization::access::destroy(t);
-        // just recover the memory
-        delete t;
-        t = NULL;   // don't leave junk in t
+        // if we get here the load_construct failed.  The heap_allocation
+        // will be automatically deleted so we don't have to do anything
+        // special here.
         BOOST_RETHROW;
     }
     BOOST_CATCH_END
 
-    ar_impl >> boost::serialization::make_nvp(NULL, *static_cast<T *>(t));
+    ar_impl >> boost::serialization::make_nvp(NULL, *h.get());
+    // success !!! - release the heap allocation so it
+    // doesn't delete the object we just loaded.
+    t = h.get();
+    h.release();
 }
 
 template<class Archive, class T>
Modified: trunk/boost/archive/impl/basic_text_oprimitive.ipp
==============================================================================
--- trunk/boost/archive/impl/basic_text_oprimitive.ipp	Sun Oct 27 16:37:44 2013	(r86485)
+++ trunk/boost/archive/impl/basic_text_oprimitive.ipp	2013-10-27 16:38:43 EDT (Sun, 27 Oct 2013)	(r86486)
@@ -9,6 +9,7 @@
 //  See http://www.boost.org for updates, documentation, and revision history.
 
 #include <cstddef> // NULL
+#include <algorithm> // std::copy
 #include <boost/serialization/pfto.hpp>
 
 #include <boost/archive/basic_text_oprimitive.hpp>
Modified: trunk/boost/archive/impl/xml_oarchive_impl.ipp
==============================================================================
--- trunk/boost/archive/impl/xml_oarchive_impl.ipp	Sun Oct 27 16:37:44 2013	(r86485)
+++ trunk/boost/archive/impl/xml_oarchive_impl.ipp	2013-10-27 16:38:43 EDT (Sun, 27 Oct 2013)	(r86486)
@@ -8,7 +8,7 @@
 
 #include <ostream>
 #include <iomanip>
-#include <algorithm>
+#include <algorithm> // std::copy
 #include <string>
 
 #include <cstring> // strlen
Modified: trunk/boost/archive/impl/xml_wiarchive_impl.ipp
==============================================================================
--- trunk/boost/archive/impl/xml_wiarchive_impl.ipp	Sun Oct 27 16:37:44 2013	(r86485)
+++ trunk/boost/archive/impl/xml_wiarchive_impl.ipp	2013-10-27 16:38:43 EDT (Sun, 27 Oct 2013)	(r86486)
@@ -21,7 +21,7 @@
 #ifndef BOOST_NO_STD_WSTREAMBUF
 
 #include <boost/assert.hpp>
-#include <algorithm>
+#include <algorithm> // std::copy
 
 #include <boost/detail/workaround.hpp> // Dinkumware and RogueWave
 #if BOOST_WORKAROUND(BOOST_DINKUMWARE_STDLIB, == 1)
Modified: trunk/boost/archive/impl/xml_woarchive_impl.ipp
==============================================================================
--- trunk/boost/archive/impl/xml_woarchive_impl.ipp	Sun Oct 27 16:37:44 2013	(r86485)
+++ trunk/boost/archive/impl/xml_woarchive_impl.ipp	2013-10-27 16:38:43 EDT (Sun, 27 Oct 2013)	(r86486)
@@ -11,7 +11,7 @@
 
 #include <ostream>
 #include <string>
-#include <algorithm>
+#include <algorithm> // std::copy
 #include <locale>
 
 #include <boost/config.hpp> // msvc 6.0 needs this to suppress warnings