From 793e21594c36e925253bd65bd6f9f531b3b3a258 Mon Sep 17 00:00:00 2001 From: bemandawes Date: Fri, 22 Apr 2011 20:34:30 +0000 Subject: [PATCH] A fresh approach for binary_stream.hpp git-svn-id: http://svn.boost.org/svn/boost/sandbox/endian@71421 b8fc166d-592f-0410-95f2-cb63ce0dd405 --- boost/binary_stream.hpp | 157 ++++++----------------- libs/integer/doc/binary_stream.html | 89 +++++++++++++ libs/integer/test/binary_stream_test.cpp | 133 +++++++++---------- 3 files changed, 193 insertions(+), 186 deletions(-) create mode 100644 libs/integer/doc/binary_stream.html diff --git a/boost/binary_stream.hpp b/boost/binary_stream.hpp index 1f7528b..624c206 100644 --- a/boost/binary_stream.hpp +++ b/boost/binary_stream.hpp @@ -1,6 +1,6 @@ // boost/binary_stream.hpp ----------------------------------------------------------// -// Copyright Beman Dawes 2009 +// Copyright Beman Dawes 2009, 2011 // Distributed under the Boost Software License, Version 1.0. // See http://www.boost.org/LICENSE_1_0.txt @@ -20,7 +20,7 @@ # include // for wcslen #endif -// unformatted binary (as opposed to formatted character-set) input and output +// unformatted binary (as opposed to formatted character) input and output // Caution: Use only on streams opened with filemode std::ios_base::binary. Thus // unformatted binary I/O should not be with the standard streams (cout, cin, etc.) @@ -28,127 +28,54 @@ // results, such as insertion of unwanted characters or premature end-of-file. // For example, on Windows 0x0D would become 0x0D, 0x0A. -// Caution: When mixing formatted (i.e. operator << or >>) and unformatted (i.e. -// operator <= or >=) be aware that << and >> take precedence over <= and >=. Use -// parentheses to force correct order of evaluation. For example: -// -// my_stream << foo <= bar; // no parentheses needed -// (my_stream <= foo) << bar; // parentheses required - -// This implementation uses reinterpret_cast<>() when needed to convert one pointer -// type to another. See 5.2.10 [expr.reinterpret.cast], Reinterpret cast, para 7. - namespace boost { - // built-in types ------------------------------------------------------------------// +namespace detail +{ + template + struct const_binary_data + { + const char* ptr; + explicit const_binary_data(const T& x) : ptr(reinterpret_cast(&x)) {} + }; + template + struct binary_data + { + char* ptr; + explicit binary_data(T& x) : ptr(reinterpret_cast(&x)) {} + }; +} - // omission of bool and void* is deliberate; any semantics would be questionable +template +inline detail::const_binary_data bin(const T& x) +{ + return detail::const_binary_data(x); +} - inline std::ostream& operator<=(std::ostream& os, short v) - { return os.write( reinterpret_cast(&v), sizeof(v) ); } - inline std::istream& operator>=(std::istream& is, short& v) - { return is.read( reinterpret_cast(&v), sizeof(v) ); } +template +inline detail::binary_data bin(T& x) +{ + return detail::binary_data(x); +} - inline std::ostream& operator<=(std::ostream& os, unsigned short v) - { return os.write( reinterpret_cast(&v), sizeof(v) ); } - inline std::istream& operator>=(std::istream& is, unsigned short& v) - { return is.read( reinterpret_cast(&v), sizeof(v) ); } +template +inline std::ostream& operator<<(std::ostream& os, detail::const_binary_data x) +{ + return os.write(x.ptr, sizeof(T)); +} - inline std::ostream& operator<=(std::ostream& os, int v) - { return os.write( reinterpret_cast(&v), sizeof(v) ); } - inline std::istream& operator>=(std::istream& is, int& v) - { return is.read( reinterpret_cast(&v), sizeof(v) ); } +template +inline std::ostream& operator<<(std::ostream& os, detail::binary_data x) +{ + return os.write(x.ptr, sizeof(T)); +} - inline std::ostream& operator<=(std::ostream& os, unsigned int v) - { return os.write( reinterpret_cast(&v), sizeof(v) ); } - inline std::istream& operator>=(std::istream& is, unsigned int& v) - { return is.read( reinterpret_cast(&v), sizeof(v) ); } - - inline std::ostream& operator<=(std::ostream& os, long v) - { return os.write( reinterpret_cast(&v), sizeof(v) ); } - inline std::istream& operator>=(std::istream& is, long& v) - { return is.read( reinterpret_cast(&v), sizeof(v) ); } - - inline std::ostream& operator<=(std::ostream& os, unsigned long v) - { return os.write( reinterpret_cast(&v), sizeof(v) ); } - inline std::istream& operator>=(std::istream& is, unsigned long& v) - { return is.read( reinterpret_cast(&v), sizeof(v) ); } - - inline std::ostream& operator<=(std::ostream& os, long long v) - { return os.write( reinterpret_cast(&v), sizeof(v) ); } - inline std::istream& operator>=(std::istream& is, long long& v) - { return is.read( reinterpret_cast(&v), sizeof(v) ); } - - inline std::ostream& operator<=(std::ostream& os, unsigned long long v) - { return os.write( reinterpret_cast(&v), sizeof(v) ); } - inline std::istream& operator>=(std::istream& is, unsigned long long& v) - { return is.read( reinterpret_cast(&v), sizeof(v) ); } - - inline std::ostream& operator<=(std::ostream& os, float v) - { return os.write( reinterpret_cast(&v), sizeof(v) ); } - inline std::istream& operator>=(std::istream& is, float& v) - { return is.read( reinterpret_cast(&v), sizeof(v) ); } - - inline std::ostream& operator<=(std::ostream& os, double v) - { return os.write( reinterpret_cast(&v), sizeof(v) ); } - inline std::istream& operator>=(std::istream& is, double& v) - { return is.read( reinterpret_cast(&v), sizeof(v) ); } - - inline std::ostream& operator<=(std::ostream& os, long double v) - { return os.write( reinterpret_cast(&v), sizeof(v) ); } - inline std::istream& operator>=(std::istream& is, long double& v) - { return is.read( reinterpret_cast(&v), sizeof(v) ); } - - inline std::ostream& operator<=(std::ostream& os, char c) - { return os.put( c ); } - inline std::istream& operator>=(std::istream& is, char& c) - { return is.get( c ); } - - inline std::ostream& operator<=(std::ostream& os, signed char c) - { return os.put( c ); } - inline std::istream& operator>=(std::istream& is, signed char& c) - { return is.get( reinterpret_cast(c) ); } - - inline std::ostream& operator<=(std::ostream& os, unsigned char c) - { return os.put( c ); } - inline std::istream& operator>=(std::istream& is, unsigned char& c) - { return is.get( reinterpret_cast(c) ); } - - inline std::ostream& operator<=(std::ostream& os, wchar_t v) - { return os.write( reinterpret_cast(&v), sizeof(v) ); } - inline std::istream& operator>=(std::istream& is, wchar_t& v) - { return is.read( reinterpret_cast(&v), sizeof(v) ); } - - // strings -------------------------------------------------------------------------// - - inline std::ostream& operator<=(std::ostream& os, const char* p) - { return os.write( p, std::strlen(p)+1 ); } - - inline std::ostream& operator<=(std::ostream& os, const signed char* p) - { return os.write( reinterpret_cast(p), std::strlen(reinterpret_cast(p))+1 ); } - - inline std::ostream& operator<=(std::ostream& os, const unsigned char* p) - { return os.write( reinterpret_cast(p), std::strlen(reinterpret_cast(p))+1 ); } - -#ifndef BOOST_NO_CWCHAR - inline std::ostream& operator<=(std::ostream& os, const wchar_t* p) - { return os.write( reinterpret_cast(p), (std::wcslen(p)+1)*sizeof(wchar_t) ); } -#endif - - // Caution: note the asymmetry between output and input; a string with embedded - // nulls will be output with the embedded nulls, but input will stop at the first null. - // So it probably isn't a good idea to use these functions for strings with nulls. - inline std::ostream& operator<=(std::ostream& os, const std::string& s) - { return os.write( s.c_str(), s.size()+1 ); } - inline std::istream& operator>=(std::istream& is, std::string& s) - { return getline(is, s, '\0'); } - -#ifndef BOOST_NO_STD_WSTRING - inline std::ostream& operator<=(std::ostream& os, const std::wstring& s) - { return os.write( reinterpret_cast(s.c_str()), (s.size()+1)*sizeof(wchar_t) ); } - // TODO: provide input function -#endif +template +inline std::istream& operator>>(std::istream& is, detail::binary_data x) +{ + return is.read(x.ptr, sizeof(T)); +} } // namespace boost diff --git a/libs/integer/doc/binary_stream.html b/libs/integer/doc/binary_stream.html new file mode 100644 index 0000000..a3563e5 --- /dev/null +++ b/libs/integer/doc/binary_stream.html @@ -0,0 +1,89 @@ + + + + + + + +Binary Stream I/O + + + + + +

Proposal for Enhanced Binary Stream I/O

+

Introduction

+

The C++ standard library's stream I/O facilities are type-safe and very +convenient for performing formatted (i.e. human readable) I/O, but offer only +rudimentary and not very type-safe operations for performing binary I/O.  +Although formatted I/O is often preferable, some applications need the speed and +storage efficiency of binary I/O or need to interoperate with third-party +applications that require binary file or network data formats.

+

Standard library streams can be opened with filemode +std::ios_base::binary, so binary I/O is possible. But the only +unformatted I/O functions available are get(), put(), +read(), and write(). These operate only on char +or array of char (with length explicitly specified), so require the +user to write casts, are hard to use, and are error prone.

+

There have been many requests on Boost and various C++ newsgroups for +unformatted binary I/O. For example, in 2003 Neal Becker wrote:

+
+

I wonder if anyone has code for implementing unformatted I/O?  What I +have in mind is for the simple case where the application that reads data knows +the data types, so this is not as complicated as the general marshalling +situation.

+
+

This proposal provides a simple solution that works will standard library +input and output streams. The one caveat is that they should be open with +filemode std::ios_base::binary.

+

Synopsis

+
+
namespace boost
+{
+  template <class T>
+  unspecified-type-1<T> bin(const T& x);
+
+  template <class T>
+  unspecified-type-2<T> bin(T& x);
+
+  template <class T>
+  std::ostream& operator<<(std::ostream& os, unspecified-type-1<T> x);
+
+  template <class T>
+  std::ostream& operator<<(std::ostream& os, unspecified-type-2<T> x);
+
+  template <class T>
+  std::istream& operator>>(std::istream& is, unspecified-type-2<T> x);
+}
+
+

unspecified-type-1 and unspecified-type-2 +are implementation supplied types.

+

Example

+
+
int main()
+{
+  int i = 0x41424344;
+  std::cout << std::hex << i << " " << bin(i) << '\n';
+  return 0;
+}
+
+

On a little-endian machine, the output is:

+
+
41424344 DCBA
+
+

 

+
+

Last revised: +22 April, 2011

+

© Copyright Beman Dawes, 2009, 2011

+

Distributed under the Boost Software License, Version 1.0. See +www.boost.org/ LICENSE_1_0.txt

+ +

 

+

 

+

 

+

 

+ + + + \ No newline at end of file diff --git a/libs/integer/test/binary_stream_test.cpp b/libs/integer/test/binary_stream_test.cpp index 633669a..97c88ee 100644 --- a/libs/integer/test/binary_stream_test.cpp +++ b/libs/integer/test/binary_stream_test.cpp @@ -9,113 +9,104 @@ #include #include #include +#include using namespace boost; using namespace std; -namespace -{ - int errors = 0; - - void verify( bool x, const char * file, int line ) - { - if ( x ) return; - ++errors; - cout << file << "(" << line << ") : error: predicate is false\n" << endl; - } - -} - -#define BOOST_VERIFY(predicate) verify( predicate, __FILE__, __LINE__ ) - - int main() { std::stringstream ss( std::ios_base::in | std::ios_base::out | std::ios_base::binary ); short short_1(0x0102), short_2; - ss <= short_1; - ss >= short_2; - BOOST_VERIFY( short_1 == short_2 ); + ss.clear(); + ss << bin(short_1); + ss >> bin(short_2); + BOOST_TEST( short_1 == short_2 ); unsigned short ushort_1(0x0102), ushort_2; - ss <= ushort_1; - ss >= ushort_2; - BOOST_VERIFY( ushort_1 == ushort_2 ); + ss.clear(); + ss << bin(ushort_1); + ss >> bin(ushort_2); + BOOST_TEST( ushort_1 == ushort_2 ); int int_1(0x01020304), int_2; - ss <= int_1; - ss >= int_2; - BOOST_VERIFY( int_1 == int_2 ); + ss.clear(); + ss << bin(int_1); + ss >> bin(int_2); + BOOST_TEST( int_1 == int_2 ); unsigned int uint_1(0x01020304), uint_2; - ss <= uint_1; - ss >= uint_2; - BOOST_VERIFY( uint_1 == uint_2 ); + ss.clear(); + ss << bin(uint_1); + ss >> bin(uint_2); + BOOST_TEST( uint_1 == uint_2 ); long long_1(0x01020304L), long_2; - ss <= long_1; - ss >= long_2; - BOOST_VERIFY( long_1 == long_2 ); + ss.clear(); + ss << bin(long_1); + ss >> bin(long_2); + BOOST_TEST( long_1 == long_2 ); unsigned long ulong_1(0x01020304UL), ulong_2; - ss <= ulong_1; - ss >= ulong_2; - BOOST_VERIFY( ulong_1 == ulong_2 ); + ss.clear(); + ss << bin(ulong_1); + ss >> bin(ulong_2); + BOOST_TEST( ulong_1 == ulong_2 ); long long long_long_1(0x0102030405060708LL), long_long_2; - ss <= long_long_1; - ss >= long_long_2; - BOOST_VERIFY( long_long_1 == long_long_2 ); + ss.clear(); + ss << bin(long_long_1); + ss >> bin(long_long_2); + BOOST_TEST( long_long_1 == long_long_2 ); unsigned long long ulong_long_1(0x0102030405060708ULL), ulong_long_2; - ss <= ulong_long_1; - ss >= ulong_long_2; - BOOST_VERIFY( ulong_long_1 == ulong_long_2 ); + ss.clear(); + ss << bin(ulong_long_1); + ss >> bin(ulong_long_2); + BOOST_TEST( ulong_long_1 == ulong_long_2 ); float float_1(1.2F), float_2; - ss <= float_1; - ss >= float_2; - BOOST_VERIFY( float_1 == float_2 ); + ss.clear(); + ss << bin(float_1); + ss >> bin(float_2); + BOOST_TEST( float_1 == float_2 ); double double_1(1.2), double_2; - ss <= double_1; - ss >= double_2; - BOOST_VERIFY( double_1 == double_2 ); + ss.clear(); + ss << bin(double_1); + ss >> bin(double_2); + BOOST_TEST( double_1 == double_2 ); long double long_double_1(1.2), long_double_2; - ss <= long_double_1; - ss >= long_double_2; - BOOST_VERIFY( long_double_1 == long_double_2 ); + ss.clear(); + ss << bin(long_double_1); + ss >> bin(long_double_2); + BOOST_TEST( long_double_1 == long_double_2 ); char char_1(0x01), char_2; - ss <= char_1; - ss >= char_2; - BOOST_VERIFY( char_1 == char_2 ); + ss.clear(); + ss << bin(char_1); + ss >> bin(char_2); + BOOST_TEST( char_1 == char_2 ); signed char schar_1(0x01), schar_2; - ss <= schar_1; - ss >= schar_2; - BOOST_VERIFY( schar_1 == schar_2 ); + ss.clear(); + ss << bin(schar_1); + ss >> bin(schar_2); + BOOST_TEST( schar_1 == schar_2 ); unsigned char uchar_1(0x01), uchar_2; - ss <= uchar_1; - ss >= uchar_2; - BOOST_VERIFY( uchar_1 == uchar_2 ); + ss.clear(); + ss << bin(uchar_1); + ss >> bin(uchar_2); + BOOST_TEST( uchar_1 == uchar_2 ); wchar_t wchar_t_1(L'1'), wchar_t_2; - ss <= wchar_t_1; - ss >= wchar_t_2; - BOOST_VERIFY( wchar_t_1 == wchar_t_2 ); + ss.clear(); + ss << bin(wchar_t_1); + ss >> bin(wchar_t_2); + BOOST_TEST( wchar_t_1 == wchar_t_2 ); - string string_1("foobar"), string_2; - ss <= string_1.c_str(); - ss >= string_2; - BOOST_VERIFY( string_1 == string_2 ); - ss <= string_1; - ss >= string_2; - BOOST_VERIFY( string_1 == string_2 ); - - cout << errors << " error(s) detected\n"; - return errors; + return ::boost::report_errors(); }