• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <cstddef> // size_t
30 
31 #include <boost/config.hpp>
32 #include <boost/static_assert.hpp>
33 #include <boost/io/ios_state.hpp>
34 
35 #include <boost/detail/workaround.hpp>
36 #if BOOST_WORKAROUND(BOOST_DINKUMWARE_STDLIB, == 1)
37 #include <boost/archive/dinkumware.hpp>
38 #endif
39 
40 #if defined(BOOST_NO_STDC_NAMESPACE)
41 namespace std{
42     using ::size_t;
43     #if ! defined(BOOST_DINKUMWARE_STDLIB) && ! defined(__SGI_STL_PORT)
44         using ::locale;
45     #endif
46 } // namespace std
47 #endif
48 
49 #include <boost/type_traits/is_floating_point.hpp>
50 #include <boost/mpl/bool.hpp>
51 #include <boost/limits.hpp>
52 #include <boost/integer.hpp>
53 #include <boost/io/ios_state.hpp>
54 #include <boost/serialization/throw_exception.hpp>
55 #include <boost/archive/basic_streambuf_locale_saver.hpp>
56 #include <boost/archive/codecvt_null.hpp>
57 #include <boost/archive/archive_exception.hpp>
58 #include <boost/archive/detail/abi_prefix.hpp> // must be the last header
59 
60 namespace boost {
61 namespace archive {
62 
63 /////////////////////////////////////////////////////////////////////////
64 // class basic_text_oprimitive - output of prmitives to stream
65 template<class OStream>
66 class BOOST_SYMBOL_VISIBLE basic_text_oprimitive
67 {
68 protected:
69     OStream &os;
70     io::ios_flags_saver flags_saver;
71     io::ios_precision_saver precision_saver;
72 
73     #ifndef BOOST_NO_STD_LOCALE
74     // note order! - if you change this, libstd++ will fail!
75     // a) create new locale with new codecvt facet
76     // b) save current locale
77     // c) change locale to new one
78     // d) use stream buffer
79     // e) change locale back to original
80     // f) destroy new codecvt facet
81     boost::archive::codecvt_null<typename OStream::char_type> codecvt_null_facet;
82     std::locale archive_locale;
83     basic_ostream_locale_saver<
84         typename OStream::char_type,
85         typename OStream::traits_type
86     > locale_saver;
87     #endif
88 
89     /////////////////////////////////////////////////////////
90     // fundamental types that need special treatment
save(const bool t)91     void save(const bool t){
92         // trap usage of invalid uninitialized boolean which would
93         // otherwise crash on load.
94         BOOST_ASSERT(0 == static_cast<int>(t) || 1 == static_cast<int>(t));
95         if(os.fail())
96             boost::serialization::throw_exception(
97                 archive_exception(archive_exception::output_stream_error)
98             );
99         os << t;
100     }
save(const signed char t)101     void save(const signed char t)
102     {
103         save(static_cast<short int>(t));
104     }
save(const unsigned char t)105     void save(const unsigned char t)
106     {
107         save(static_cast<short unsigned int>(t));
108     }
save(const char t)109     void save(const char t)
110     {
111         save(static_cast<short int>(t));
112     }
113     #ifndef BOOST_NO_INTRINSIC_WCHAR_T
save(const wchar_t t)114     void save(const wchar_t t)
115     {
116         BOOST_STATIC_ASSERT(sizeof(wchar_t) <= sizeof(int));
117         save(static_cast<int>(t));
118     }
119     #endif
120 
121     /////////////////////////////////////////////////////////
122     // saving of any types not listed above
123 
124     template<class T>
save_impl(const T & t,boost::mpl::bool_<false> &)125     void save_impl(const T &t, boost::mpl::bool_<false> &){
126         if(os.fail())
127             boost::serialization::throw_exception(
128                 archive_exception(archive_exception::output_stream_error)
129             );
130         os << t;
131     }
132 
133     /////////////////////////////////////////////////////////
134     // floating point types need even more special treatment
135     // the following determines whether the type T is some sort
136     // of floating point type.  Note that we then assume that
137     // the stream << operator is defined on that type - if not
138     // we'll get a compile time error. This is meant to automatically
139     // support synthesized types which support floating point
140     // operations. Also it should handle compiler dependent types
141     // such long double.  Due to John Maddock.
142 
143     template<class T>
144     struct is_float {
145         typedef typename mpl::bool_<
146             boost::is_floating_point<T>::value
147             || (std::numeric_limits<T>::is_specialized
148             && !std::numeric_limits<T>::is_integer
149             && !std::numeric_limits<T>::is_exact
150             && std::numeric_limits<T>::max_exponent)
151         >::type type;
152     };
153 
154     template<class T>
save_impl(const T & t,boost::mpl::bool_<true> &)155     void save_impl(const T &t, boost::mpl::bool_<true> &){
156         // must be a user mistake - can't serialize un-initialized data
157         if(os.fail()){
158             boost::serialization::throw_exception(
159                 archive_exception(archive_exception::output_stream_error)
160             );
161         }
162         // The formulae for the number of decimla digits required is given in
163         // http://www2.open-std.org/JTC1/SC22/WG21/docs/papers/2005/n1822.pdf
164         // which is derived from Kahan's paper:
165         // www.eecs.berkeley.edu/~wkahan/ieee754status/ieee754.ps
166         // const unsigned int digits = (std::numeric_limits<T>::digits * 3010) / 10000;
167         // note: I've commented out the above because I didn't get good results.  e.g.
168         // in one case I got a difference of 19 units.
169         #ifndef BOOST_NO_CXX11_NUMERIC_LIMITS
170             const unsigned int digits = std::numeric_limits<T>::max_digits10;
171         #else
172             const unsigned int digits = std::numeric_limits<T>::digits10 + 2;
173         #endif
174         os << std::setprecision(digits) << std::scientific << t;
175     }
176 
177     template<class T>
save(const T & t)178     void save(const T & t){
179         typename is_float<T>::type tf;
180         save_impl(t, tf);
181     }
182 
183     BOOST_ARCHIVE_OR_WARCHIVE_DECL
184     basic_text_oprimitive(OStream & os, bool no_codecvt);
185     BOOST_ARCHIVE_OR_WARCHIVE_DECL
186     ~basic_text_oprimitive();
187 public:
188     // unformatted append of one character
put(typename OStream::char_type c)189     void put(typename OStream::char_type c){
190         if(os.fail())
191             boost::serialization::throw_exception(
192                 archive_exception(archive_exception::output_stream_error)
193             );
194         os.put(c);
195     }
196     // unformatted append of null terminated string
put(const char * s)197     void put(const char * s){
198         while('\0' != *s)
199             os.put(*s++);
200     }
201     BOOST_ARCHIVE_OR_WARCHIVE_DECL void
202     save_binary(const void *address, std::size_t count);
203 };
204 
205 } //namespace boost
206 } //namespace archive
207 
208 #include <boost/archive/detail/abi_suffix.hpp> // pops abi_suffix.hpp pragmas
209 
210 #endif // BOOST_ARCHIVE_BASIC_TEXT_OPRIMITIVE_HPP
211