1 #ifndef BOOST_ARCHIVE_BASIC_TEXT_OPRIMITIVE_HPP
2 #define BOOST_ARCHIVE_BASIC_TEXT_OPRIMITIVE_HPP
3 
4 // MS compatible compilers support #pragma once
5 #if defined(_MSC_VER)
6 # pragma once
7 #endif
8 
9 /////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
10 // basic_text_oprimitive.hpp
11 
12 // (C) Copyright 2002 Robert Ramey - http://www.rrsd.com .
13 // Use, modification and distribution is subject to the Boost Software
14 // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
15 // http://www.boost.org/LICENSE_1_0.txt)
16 
17 //  See http://www.boost.org for updates, documentation, and revision history.
18 
19 // archives stored as text - note these ar templated on the basic
20 // stream templates to accommodate wide (and other?) kind of characters
21 //
22 // note the fact that on libraries without wide characters, ostream is
23 // is not a specialization of basic_ostream which in fact is not defined
24 // in such cases.   So we can't use basic_ostream<OStream::char_type> but rather
25 // use two template parameters
26 
27 #include <iomanip>
28 #include <locale>
29 #include <boost/assert.hpp>
30 #include <cstddef> // size_t
31 
32 #include <boost/config.hpp>
33 #include <boost/static_assert.hpp>
34 #include <boost/detail/workaround.hpp>
35 #include <boost/io/ios_state.hpp>
36 
37 #if BOOST_WORKAROUND(BOOST_DINKUMWARE_STDLIB, == 1)
38 #include <boost/archive/dinkumware.hpp>
39 #endif
40 
41 #if defined(BOOST_NO_STDC_NAMESPACE)
42 namespace std{
43     using ::size_t;
44     #if ! defined(BOOST_DINKUMWARE_STDLIB) && ! defined(__SGI_STL_PORT)
45         using ::locale;
46     #endif
47 } // namespace std
48 #endif
49 
50 #include <boost/type_traits/is_floating_point.hpp>
51 #include <boost/mpl/bool.hpp>
52 #include <boost/limits.hpp>
53 #include <boost/integer.hpp>
54 #include <boost/io/ios_state.hpp>
55 #include <boost/scoped_ptr.hpp>
56 #include <boost/serialization/throw_exception.hpp>
57 #include <boost/archive/archive_exception.hpp>
58 #include <boost/archive/basic_streambuf_locale_saver.hpp>
59 #include <boost/archive/detail/abi_prefix.hpp> // must be the last header
60 
61 namespace boost {
62 namespace archive {
63 
64 /////////////////////////////////////////////////////////////////////////
65 // class basic_text_oprimitive - output of prmitives to stream
66 template<class OStream>
67 class BOOST_SYMBOL_VISIBLE basic_text_oprimitive
68 {
69 protected:
70     OStream &os;
71     io::ios_flags_saver flags_saver;
72     io::ios_precision_saver precision_saver;
73 
74     #ifndef BOOST_NO_STD_LOCALE
75     boost::scoped_ptr<std::locale> archive_locale;
76     basic_streambuf_locale_saver<
77         typename OStream::char_type,
78         typename OStream::traits_type
79     > locale_saver;
80     #endif
81 
82     /////////////////////////////////////////////////////////
83     // fundamental types that need special treatment
save(const bool t)84     void save(const bool t){
85         // trap usage of invalid uninitialized boolean which would
86         // otherwise crash on load.
87         BOOST_ASSERT(0 == static_cast<int>(t) || 1 == static_cast<int>(t));
88         if(os.fail())
89             boost::serialization::throw_exception(
90                 archive_exception(archive_exception::output_stream_error)
91             );
92         os << t;
93     }
save(const signed char t)94     void save(const signed char t)
95     {
96         save(static_cast<short int>(t));
97     }
save(const unsigned char t)98     void save(const unsigned char t)
99     {
100         save(static_cast<short unsigned int>(t));
101     }
save(const char t)102     void save(const char t)
103     {
104         save(static_cast<short int>(t));
105     }
106     #ifndef BOOST_NO_INTRINSIC_WCHAR_T
save(const wchar_t t)107     void save(const wchar_t t)
108     {
109         BOOST_STATIC_ASSERT(sizeof(wchar_t) <= sizeof(int));
110         save(static_cast<int>(t));
111     }
112     #endif
113 
114     /////////////////////////////////////////////////////////
115     // saving of any types not listed above
116 
117     template<class T>
save_impl(const T & t,boost::mpl::bool_<false> &)118     void save_impl(const T &t, boost::mpl::bool_<false> &){
119         if(os.fail())
120             boost::serialization::throw_exception(
121                 archive_exception(archive_exception::output_stream_error)
122             );
123         os << t;
124     }
125 
126     /////////////////////////////////////////////////////////
127     // floating point types need even more special treatment
128     // the following determines whether the type T is some sort
129     // of floating point type.  Note that we then assume that
130     // the stream << operator is defined on that type - if not
131     // we'll get a compile time error. This is meant to automatically
132     // support synthesized types which support floating point
133     // operations. Also it should handle compiler dependent types
134     // such long double.  Due to John Maddock.
135 
136     template<class T>
137     struct is_float {
138         typedef typename mpl::bool_<
139             boost::is_floating_point<T>::value
140             || (std::numeric_limits<T>::is_specialized
141             && !std::numeric_limits<T>::is_integer
142             && !std::numeric_limits<T>::is_exact
143             && std::numeric_limits<T>::max_exponent)
144         >::type type;
145     };
146 
147     template<class T>
save_impl(const T & t,boost::mpl::bool_<true> &)148     void save_impl(const T &t, boost::mpl::bool_<true> &){
149         // must be a user mistake - can't serialize un-initialized data
150         if(os.fail())
151             boost::serialization::throw_exception(
152                 archive_exception(archive_exception::output_stream_error)
153             );
154         // The formulae for the number of decimla digits required is given in
155         // http://www2.open-std.org/JTC1/SC22/WG21/docs/papers/2005/n1822.pdf
156         // which is derived from Kahan's paper:
157         // www.eecs.berkeley.edu/~wkahan/ieee754status/ieee754.ps
158         // const unsigned int digits = (std::numeric_limits<T>::digits * 3010) / 10000;
159         // note: I've commented out the above because I didn't get good results.  e.g.
160         // in one case I got a difference of 19 units.
161         #ifndef BOOST_NO_CXX11_NUMERIC_LIMITS
162             const unsigned int digits = std::numeric_limits<T>::max_digits10;
163         #else
164             const unsigned int digits = std::numeric_limits<T>::digits10 + 2;
165         #endif
166         os << std::setprecision(digits) << std::scientific << t;
167     }
168 
169     template<class T>
save(const T & t)170     void save(const T & t){
171         boost::io::ios_flags_saver fs(os);
172         boost::io::ios_precision_saver ps(os);
173         typename is_float<T>::type tf;
174         save_impl(t, tf);
175     }
176 
177     BOOST_ARCHIVE_OR_WARCHIVE_DECL
178     basic_text_oprimitive(OStream & os, bool no_codecvt);
179     BOOST_ARCHIVE_OR_WARCHIVE_DECL
180     ~basic_text_oprimitive();
181 public:
182     // unformatted append of one character
put(typename OStream::char_type c)183     void put(typename OStream::char_type c){
184         if(os.fail())
185             boost::serialization::throw_exception(
186                 archive_exception(archive_exception::output_stream_error)
187             );
188         os.put(c);
189     }
190     // unformatted append of null terminated string
put(const char * s)191     void put(const char * s){
192         while('\0' != *s)
193             os.put(*s++);
194     }
195     BOOST_ARCHIVE_OR_WARCHIVE_DECL void
196     save_binary(const void *address, std::size_t count);
197 };
198 
199 } //namespace boost
200 } //namespace archive
201 
202 #include <boost/archive/detail/abi_suffix.hpp> // pops abi_suffix.hpp pragmas
203 
204 #endif // BOOST_ARCHIVE_BASIC_TEXT_OPRIMITIVE_HPP
205