Boost logo

Boost-Commit :

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


Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk