From 59c79ecb750e79faae5c20810969ac94f195e4e2 Mon Sep 17 00:00:00 2001 From: bemandawes Date: Fri, 30 May 2008 15:26:33 +0000 Subject: [PATCH] Initial commit, corresponding to endian-0.8 git-svn-id: http://svn.boost.org/svn/boost/sandbox/endian@45953 b8fc166d-592f-0410-95f2-cb63ce0dd405 --- boost/integer/cover_operators.hpp | 77 +++ boost/integer/endian.hpp | 346 ++++++++++ libs/integer/doc/endian.html | 525 ++++++++++++++++ libs/integer/example/endian_example.cpp | 75 +++ libs/integer/test/Jamfile.v2 | 13 + .../test/endian-in-sandbox/common.vsprops | 13 + .../endian-in-sandbox/endian-in-sandbox.sln | 20 + .../endian_test/endian_test.vcproj | 193 ++++++ libs/integer/test/endian_test.cpp | 593 ++++++++++++++++++ libs/integer/test/test.bat | 11 + libs/integer/zip-endian.bat | 33 + 11 files changed, 1899 insertions(+) create mode 100644 boost/integer/cover_operators.hpp create mode 100644 boost/integer/endian.hpp create mode 100644 libs/integer/doc/endian.html create mode 100644 libs/integer/example/endian_example.cpp create mode 100644 libs/integer/test/Jamfile.v2 create mode 100644 libs/integer/test/endian-in-sandbox/common.vsprops create mode 100644 libs/integer/test/endian-in-sandbox/endian-in-sandbox.sln create mode 100644 libs/integer/test/endian-in-sandbox/endian_test/endian_test.vcproj create mode 100644 libs/integer/test/endian_test.cpp create mode 100644 libs/integer/test/test.bat create mode 100644 libs/integer/zip-endian.bat diff --git a/boost/integer/cover_operators.hpp b/boost/integer/cover_operators.hpp new file mode 100644 index 0000000..46bb819 --- /dev/null +++ b/boost/integer/cover_operators.hpp @@ -0,0 +1,77 @@ +// boost/integer/cover_operators.hpp ----------------------------------------// + +// (C) Copyright Darin Adler 2000 + +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +//----------------------------------------------------------------------------// + +#ifndef BOOST_INTEGER_COVER_OPERATORS_HPP +#define BOOST_INTEGER_COVER_OPERATORS_HPP + +#include +#include + +namespace boost +{ + namespace integer + { + + // A class that adds integer operators to an integer cover class + + template + class cover_operators : boost::operators + { + // The other operations take advantage of the type conversion that's + // built into unary +. + + // Unary operations. + friend IntegerType operator+(const T& x) { return x; } + friend IntegerType operator-(const T& x) { return -+x; } + friend IntegerType operator~(const T& x) { return ~+x; } + friend IntegerType operator!(const T& x) { return !+x; } + + // The basic ordering operations. + friend bool operator==(const T& x, IntegerType y) { return +x == y; } + friend bool operator<(const T& x, IntegerType y) { return +x < y; } + + // The basic arithmetic operations. + friend T& operator+=(T& x, IntegerType y) { return x = +x + y; } + friend T& operator-=(T& x, IntegerType y) { return x = +x - y; } + friend T& operator*=(T& x, IntegerType y) { return x = +x * y; } + friend T& operator/=(T& x, IntegerType y) { return x = +x / y; } + friend T& operator%=(T& x, IntegerType y) { return x = +x % y; } + friend T& operator&=(T& x, IntegerType y) { return x = +x & y; } + friend T& operator|=(T& x, IntegerType y) { return x = +x | y; } + friend T& operator^=(T& x, IntegerType y) { return x = +x ^ y; } + friend T& operator<<=(T& x, IntegerType y) { return x = +x << y; } + friend T& operator>>=(T& x, IntegerType y) { return x = +x >> y; } + + // A few binary arithmetic operations not covered by operators base class. + friend IntegerType operator<<(const T& x, IntegerType y) { return +x << y; } + friend IntegerType operator>>(const T& x, IntegerType y) { return +x >> y; } + + // Auto-increment and auto-decrement can be defined in terms of the + // arithmetic operations. + friend T& operator++(T& x) { return x += 1; } + friend T& operator--(T& x) { return x -= 1; } + + /// TODO: stream I/O needs to be templatized on the stream type, so will + /// work with wide streams, etc. + + // Stream input and output. + friend std::ostream& operator<<(std::ostream& s, const T& x) + { return s << +x; } + friend std::istream& operator>>(std::istream& s, T& x) + { + IntegerType i; + if (s >> i) + x = i; + return s; + } + }; + } // namespace integer +} // namespace boost + +#endif // BOOST_INTEGER_COVER_OPERATORS_HPP diff --git a/boost/integer/endian.hpp b/boost/integer/endian.hpp new file mode 100644 index 0000000..a996538 --- /dev/null +++ b/boost/integer/endian.hpp @@ -0,0 +1,346 @@ +// Boost endian.hpp header file (proposed) ----------------------------------// + +// (C) Copyright Darin Adler 2000 +// (C) Copyright Beman Dawes 2006 + +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See library home page at http://www.boost.org/libs/endian + +//----------------------------------------------------------------------------// + +// Original design developed by Darin Adler based on classes developed by Mark +// Borgerding. Four original class templates combined into a single endian +// class template by Beman Dawes, who also added the unrolled_byte_loops sign +// partial specialization to correctly extend the sign when cover integer size +// differs from endian representation size. + +// TODO: +// * Use C++0x scoped enums if available +// * Use C++0x defaulted default constructor if available +// * Propose, use, BOOST_CONSTEXPR. +// * Propose BOOST_EXPLICIT, apply if needed +// * Should there be a conversion to bool? + +#ifndef BOOST_ENDIAN_HPP +#define BOOST_ENDIAN_HPP + +#include +#include +#include +#include +#include +#include +#include + +# if CHAR_BIT != 8 +# error Platforms with CHAR_BIT != 8 are not supported +# endif + +namespace boost +{ + namespace detail + { + // Unrolled loops for loading and storing streams of bytes. + + template ::value > + struct unrolled_byte_loops + { + typedef unrolled_byte_loops next; + + static T load_big(const unsigned char* bytes) + { return *(bytes - 1) | (next::load_big(bytes - 1) << 8); } + static T load_little(const unsigned char* bytes) + { return *bytes | (next::load_little(bytes + 1) << 8); } + + static void store_big(char* bytes, T value) + { + *(bytes - 1) = static_cast(value); + next::store_big(bytes - 1, value >> 8); + } + static void store_little(char* bytes, T value) + { + *bytes = static_cast(value); + next::store_little(bytes + 1, value >> 8); + } + }; + + template + struct unrolled_byte_loops + { + static T load_big(const unsigned char* bytes) + { return *(bytes - 1); } + static T load_little(const unsigned char* bytes) + { return *bytes; } + static void store_big(char* bytes, T value) + { *(bytes - 1) = static_cast(value); } + static void store_little(char* bytes, T value) + { *bytes = static_cast(value); } + + }; + + template + struct unrolled_byte_loops + { + static T load_big(const unsigned char* bytes) + { return *reinterpret_cast(bytes - 1); } + static T load_little(const unsigned char* bytes) + { return *reinterpret_cast(bytes); } + static void store_big(char* bytes, T value) + { *(bytes - 1) = static_cast(value); } + static void store_little(char* bytes, T value) + { *bytes = static_cast(value); } + }; + + template + inline + T load_big_endian(const void* bytes) + { + return unrolled_byte_loops::load_big + (static_cast(bytes) + n_bytes); + } + + template + inline + T load_little_endian(const void* bytes) + { + return unrolled_byte_loops::load_little + (static_cast(bytes)); + } + + template + inline + void store_big_endian(void* bytes, T value) + { + unrolled_byte_loops::store_big + (static_cast(bytes) + n_bytes, value); + } + + template + inline + void store_little_endian(void* bytes, T value) + { + unrolled_byte_loops::store_little + (static_cast(bytes), value); + } + + } // namespace detail + + namespace integer + { + + // endian class template and specializations -----------------------------// + + // simulate C++0x scoped enums + namespace endianness { enum enum_t { big, little, native }; } + namespace alignment { enum enum_t { unaligned, aligned }; } + + template + class endian; + + // Specializations that represent unaligned bytes. + // Taking an integer type as a parameter provides a nice way to pass both + // the size and signedness of the desired integer and get the appropriate + // corresponding integer type for the interface. + + template + class endian< endianness::big, T, n_bits, alignment::unaligned > + : cover_operators< endian< endianness::big, T, n_bits >, T > + { + BOOST_STATIC_ASSERT( (n_bits/8)*8 == n_bits ); + public: + typedef T value_type; + endian() {} + endian(T val) { detail::store_big_endian(bytes, val); } + endian & operator=(T val) { detail::store_big_endian(bytes, val); return *this; } + operator T() const { return detail::load_big_endian(bytes); } + private: + char bytes[n_bits/8]; + }; + + template + class endian< endianness::little, T, n_bits, alignment::unaligned > + : cover_operators< endian< endianness::little, T, n_bits >, T > + { + BOOST_STATIC_ASSERT( (n_bits/8)*8 == n_bits ); + public: + typedef T value_type; + endian() {} + endian(T val) { detail::store_little_endian(bytes, val); } + endian & operator=(T val) { detail::store_little_endian(bytes, val); return *this; } + operator T() const { return detail::load_little_endian(bytes); } + private: + char bytes[n_bits/8]; + }; + + template + class endian< endianness::native, T, n_bits, alignment::unaligned > + : cover_operators< endian< endianness::native, T, n_bits >, T > + { + BOOST_STATIC_ASSERT( (n_bits/8)*8 == n_bits ); + public: + typedef T value_type; + endian() {} +# ifdef BOOST_BIG_ENDIAN + endian(T val) { detail::store_big_endian(bytes, val); } + endian & operator=(T val) { detail::store_big_endian(bytes, val); return *this; } + operator T() const { return detail::load_big_endian(bytes); } +# else + endian(T val) { detail::store_little_endian(bytes, val); } + endian & operator=(T val) { detail::store_little_endian(bytes, val); return *this; } + operator T() const { return detail::load_little_endian(bytes); } +# endif + private: + char bytes[n_bits/8]; + }; + + // Specializations that mimic built-in integer types. + // These typically have the same alignment as the underlying types. + + template + class endian< endianness::big, T, n_bits, alignment::aligned > + : cover_operators< endian< endianness::big, T, n_bits, alignment::aligned >, T > + { + BOOST_STATIC_ASSERT( (n_bits/8)*8 == n_bits ); + BOOST_STATIC_ASSERT( sizeof(T) == n_bits/8 ); + public: + typedef T value_type; + endian() {} + #ifdef BOOST_BIG_ENDIAN + endian(T val) : integer(val) { } + endian & operator=(T val) { integer = val); return *this; } + operator T() const { return integer; } + #else + endian(T val) { detail::store_big_endian(&integer, val); } + endian & operator=(T val) { detail::store_big_endian(&integer, val); return *this; } + operator T() const { return detail::load_big_endian(&integer); } + #endif + private: + T integer; + }; + + template + class endian< endianness::little, T, n_bits, alignment::aligned > + : cover_operators< endian< endianness::little, T, n_bits, alignment::aligned >, T > + { + BOOST_STATIC_ASSERT( (n_bits/8)*8 == n_bits ); + BOOST_STATIC_ASSERT( sizeof(T) == n_bits/8 ); + public: + typedef T value_type; + endian() {} + #ifdef BOOST_LITTLE_ENDIAN + endian(T val) : integer(val) { } + endian & operator=(T val) { integer = val; return *this; } + operator T() const { return integer; } + #else + endian(T val) { detail::store_little_endian(&integer, val); } + endian & operator=(T val) { detail::store_little_endian(&integer, val); return *this; } + operator T() const { return detail::load_little_endian(&integer); } + #endif + private: + T integer; + }; + + // naming convention typedefs --------------------------------------------// + + // unaligned big endian signed integer types + typedef endian< endianness::big, int_least8_t, 8 > big8_t; + typedef endian< endianness::big, int_least16_t, 16 > big16_t; + typedef endian< endianness::big, int_least32_t, 24 > big24_t; + typedef endian< endianness::big, int_least32_t, 32 > big32_t; + typedef endian< endianness::big, int_least64_t, 40 > big40_t; + typedef endian< endianness::big, int_least64_t, 48 > big48_t; + typedef endian< endianness::big, int_least64_t, 56 > big56_t; + typedef endian< endianness::big, int_least64_t, 64 > big64_t; + + // unaligned big endian unsigned integer types + typedef endian< endianness::big, uint_least8_t, 8 > ubig8_t; + typedef endian< endianness::big, uint_least16_t, 16 > ubig16_t; + typedef endian< endianness::big, uint_least32_t, 24 > ubig24_t; + typedef endian< endianness::big, uint_least32_t, 32 > ubig32_t; + typedef endian< endianness::big, uint_least64_t, 40 > ubig40_t; + typedef endian< endianness::big, uint_least64_t, 48 > ubig48_t; + typedef endian< endianness::big, uint_least64_t, 56 > ubig56_t; + typedef endian< endianness::big, uint_least64_t, 64 > ubig64_t; + + // unaligned little endian signed integer types + typedef endian< endianness::little, int_least8_t, 8 > little8_t; + typedef endian< endianness::little, int_least16_t, 16 > little16_t; + typedef endian< endianness::little, int_least32_t, 24 > little24_t; + typedef endian< endianness::little, int_least32_t, 32 > little32_t; + typedef endian< endianness::little, int_least64_t, 40 > little40_t; + typedef endian< endianness::little, int_least64_t, 48 > little48_t; + typedef endian< endianness::little, int_least64_t, 56 > little56_t; + typedef endian< endianness::little, int_least64_t, 64 > little64_t; + + // unaligned little endian unsigned integer types + typedef endian< endianness::little, uint_least8_t, 8 > ulittle8_t; + typedef endian< endianness::little, uint_least16_t, 16 > ulittle16_t; + typedef endian< endianness::little, uint_least32_t, 24 > ulittle24_t; + typedef endian< endianness::little, uint_least32_t, 32 > ulittle32_t; + typedef endian< endianness::little, uint_least64_t, 40 > ulittle40_t; + typedef endian< endianness::little, uint_least64_t, 48 > ulittle48_t; + typedef endian< endianness::little, uint_least64_t, 56 > ulittle56_t; + typedef endian< endianness::little, uint_least64_t, 64 > ulittle64_t; + + // unaligned native endian signed integer types + typedef endian< endianness::native, int_least8_t, 8 > native8_t; + typedef endian< endianness::native, int_least16_t, 16 > native16_t; + typedef endian< endianness::native, int_least32_t, 24 > native24_t; + typedef endian< endianness::native, int_least32_t, 32 > native32_t; + typedef endian< endianness::native, int_least64_t, 40 > native40_t; + typedef endian< endianness::native, int_least64_t, 48 > native48_t; + typedef endian< endianness::native, int_least64_t, 56 > native56_t; + typedef endian< endianness::native, int_least64_t, 64 > native64_t; + + // unaligned native endian unsigned integer types + typedef endian< endianness::native, uint_least8_t, 8 > unative8_t; + typedef endian< endianness::native, uint_least16_t, 16 > unative16_t; + typedef endian< endianness::native, uint_least32_t, 24 > unative24_t; + typedef endian< endianness::native, uint_least32_t, 32 > unative32_t; + typedef endian< endianness::native, uint_least64_t, 40 > unative40_t; + typedef endian< endianness::native, uint_least64_t, 48 > unative48_t; + typedef endian< endianness::native, uint_least64_t, 56 > unative56_t; + typedef endian< endianness::native, uint_least64_t, 64 > unative64_t; + +#define BOOST_HAS_INT16_T +#define BOOST_HAS_INT32_T +#define BOOST_HAS_INT64_T + + // These types only present if platform has exact size integers: + // aligned big endian signed integer types + // aligned big endian unsigned integer types + // aligned little endian signed integer types + // aligned little endian unsigned integer types + + // aligned native endian typedefs are not provided because + // types are superior for this use case + +# if defined(BOOST_HAS_INT16_T) + typedef endian< endianness::big, int16_t, 16, alignment::aligned > aligned_big16_t; + typedef endian< endianness::big, uint16_t, 16, alignment::aligned > aligned_ubig16_t; + typedef endian< endianness::little, int16_t, 16, alignment::aligned > aligned_little16_t; + typedef endian< endianness::little, uint16_t, 16, alignment::aligned > aligned_ulittle16_t; +# endif + +# if defined(BOOST_HAS_INT32_T) + typedef endian< endianness::big, int32_t, 32, alignment::aligned > aligned_big32_t; + typedef endian< endianness::big, uint32_t, 32, alignment::aligned > aligned_ubig32_t; + typedef endian< endianness::little, int32_t, 32, alignment::aligned > aligned_little32_t; + typedef endian< endianness::little, uint32_t, 32, alignment::aligned > aligned_ulittle32_t; +# endif + +# if defined(BOOST_HAS_INT64_T) + typedef endian< endianness::big, int64_t, 64, alignment::aligned > aligned_big64_t; + typedef endian< endianness::big, uint64_t, 64, alignment::aligned > aligned_ubig64_t; + typedef endian< endianness::little, int64_t, 64, alignment::aligned > aligned_little64_t; + typedef endian< endianness::little, uint64_t, 64, alignment::aligned > aligned_ulittle64_t; +# endif + + } // namespace integer +} // namespace boost + +#endif // BOOST_ENDIAN_HPP diff --git a/libs/integer/doc/endian.html b/libs/integer/doc/endian.html new file mode 100644 index 0000000..89d85d9 --- /dev/null +++ b/libs/integer/doc/endian.html @@ -0,0 +1,525 @@ + + + + + + + +Boost Endian Integers + + + + +

Boost Endian Integers (boost/integer/endian.hpp)

+ +

Introduction
+Limitations
+Feature set
+Typedefs
+    Comment on naming
+Class template endian
+    +Synopsis
+    Members
+FAQ
+Example
+Design
+Experience
+Acknowledgements

+

Introduction

+

The boost/integer/endian.hpp header provides +integer-like byte-holder binary types with explicit control over +byte order, value type, size, and alignment. Typedefs provide easy-to-use names +for common configurations.

+

These types provide portable byte-holders for integer data, independent of +particular computer architectures. Use cases almost always involve I/O, either via files or +network connections. Although portability is the primary motivation, these +integer byte-holders may +also be used to reduce memory use, file size, or network activity since they +provide binary integer sizes not otherwise available.

+

Such integer byte-holder types are traditionally called +endian types. See the Wikipedia for +a full +exploration of endianness, including definitions of big +endian and little endian.

+

Boost endian integers provide the same full set of C++ assignment, +arithmetic, and relational operators as C++ standard integral types, with +the standard semantics, plus operators << and >> for +stream insertion and extraction.

+

Unary arithmetic operators are +, -, ~, +!, prefix and postfix -- and ++. Binary +arithmetic operators are +, +=, -, +-=, *, *=, /, /=, +%/ %=, &, &=, |, |=, +^, ^=, <<, <<=, >>, +>>=. Binary relational operators are ==, !=, +<, <=, >, >=.

+

Automatic conversion are provided to and from the underlying integer value type.

+

Limitations

+

Requires <climits> CHAR_BIT == 8. If CHAR_BIT +is some other value, compilation will result in an #error. This +restriction is in place because the design, implementation, testing, and +documentation has only considered issues related to 8-bit bytes, and there have +been no real-world use cases presented for other sizes.

+

In C++03, endian does not meet the requirements for POD types +because it has constructors, private data members, and a base class. This means +that common use cases are relying on unspecified behavior in that the C++ +Standard does not guarantee memory layout for non-POD types. This has not been a +problem in practice since all known C++ compilers do layout memory as if +endian were a POD type. In C++0x, it will be possible to specify the +default constructor as trivial, and private data members and base classes will +no longer disqualify a type from being a POD. Thus under C++0x, endian +will no longer be relying on unspecified behavior.

+

Feature set

+
    +
  • Big endian| little endian | native endian byte ordering.
  • +
  • Signed | unsigned
  • +
  • Unaligned | aligned
  • +
  • 1-8 byte (unaligned) | 2, 4, 8 byte (aligned)
  • +
  • Choice of integer value type
  • +
+

Typedefs

+

One class template is provided:

+
+
template <endianness::enum_t E, typename T, std::size_t n_bytes,
+  alignment::enum_t A = alignment::unaligned>
+class endian;
+
+
+

Sixty typedefs, such as big32_t, provide convenient naming +conventions for common use cases:

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameEndiannessSignSizes in bits (n)Alignment
bign_tbigsigned8,16,24,32,40,48,56,64unaligned
ubign_tbigunsigned8,16,24,32,40,48,56,64unaligned
littlen_tlittlesigned8,16,24,32,40,48,56,64unaligned
ulittlen_tlittleunsigned8,16,24,32,40,48,56,64unaligned
nativen_tnativesigned8,16,24,32,40,48,56,64unaligned
unativen_tnativeunsigned8,16,24,32,40,48,56,64unaligned
aligned_bign_tbigsigned16,32,64aligned
aligned_ubign_tbigunsigned16,32,64aligned
aligned_littlen_tlittlesigned16,32,64aligned
aligned_ulittlen_tlittleunsigned16,32,64aligned
+
+

The unaligned types do not cause compilers to insert padding bytes in classes +and structs. This is an important characteristic that can be exploited to minimize wasted space in +memory, files, and network transmissions.

+

Warning: +Code that uses aligned types is inherently non-portable because alignment +requirements vary between hardware architectures and because alignment may be +affected by compiler switches or pragmas. Furthermore, aligned types +are only available on architectures with 16, 32, and 64-bit integer types.

+

Note: One-byte big-endian, little-endian, and native-endian types provide identical +functionality. All three names are provided to improve code readability and searchability.

+

Comment on naming

+

When first exposed to endian types, programmers often fit them into a mental model +based on the <cstdint> types. Using that model, it is natural to +expect a 56-bit big-endian signed integer to be named int_big56_t +rather than big56_t.

+

As experience using these type grows, the realization creeps in that they are +lousy arithmetic integers - they are really byte holders that for convenience +support arithmetic operations - and that for use in internal interfaces or +anything more than trivial arithmetic computations it is far better to convert +values of these endian types to traditional integer types.

+

That seems to lead to formation of a new mental model specific to endian byte-holder types. In that model, the endianness +is the key feature, and the integer aspect is downplayed. +Once that mental transition is made, a name like big56_t is a good +reflection of the mental model

+

Class template endian

+

An endian is an integer byte-holder with user-specified +endianness, value type, size, and alignment. The +usual operations on integers are supplied.

+

Synopsis

+
namespace boost
+{
+  namespace integer
+  {
+     
+    namespace endianness { enum enum_t { big, little, native }; } // simulate C++0x scoped enum
+    namespace alignment  { enum enum_t { unaligned, aligned }; }  // simulate C++0x scoped enum
+
+    template <endianness::enum_t E, typename T, std::size_t n_bits,
+      alignment::enum_t A = alignment::unaligned>
+    class endian : integer_cover_operators< endian<E, T, n_bits, A>, T >
+    {
+    public:
+      typedef T value_type;
+      endian(){}
+      endian(T v);
+      endian & operator=(T v);
+      operator T() const;
+    };
+
+    // unaligned big endian signed integer types
+    typedef endian< endianness::big, int_least8_t, 8 >   big8_t;
+    typedef endian< endianness::big, int_least16_t, 16 > big16_t;
+    typedef endian< endianness::big, int_least32_t, 24 > big24_t;
+    typedef endian< endianness::big, int_least32_t, 32 > big32_t;
+    typedef endian< endianness::big, int_least64_t, 40 > big40_t;
+    typedef endian< endianness::big, int_least64_t, 48 > big48_t;
+    typedef endian< endianness::big, int_least64_t, 56 > big56_t;
+    typedef endian< endianness::big, int_least64_t, 64 > big64_t;
+
+    // unaligned big endian unsigned integer types
+    typedef endian< endianness::big, uint_least8_t, 8 >   ubig8_t;
+    typedef endian< endianness::big, uint_least16_t, 16 > ubig16_t;
+    typedef endian< endianness::big, uint_least32_t, 24 > ubig24_t;
+    typedef endian< endianness::big, uint_least32_t, 32 > ubig32_t;
+    typedef endian< endianness::big, uint_least64_t, 40 > ubig40_t;
+    typedef endian< endianness::big, uint_least64_t, 48 > ubig48_t;
+    typedef endian< endianness::big, uint_least64_t, 56 > ubig56_t;
+    typedef endian< endianness::big, uint_least64_t, 64 > ubig64_t;
+
+    // unaligned little endian signed integer types
+    typedef endian< endianness::little, int_least8_t, 8 >   little8_t;
+    typedef endian< endianness::little, int_least16_t, 16 > little16_t;
+    typedef endian< endianness::little, int_least32_t, 24 > little24_t;
+    typedef endian< endianness::little, int_least32_t, 32 > little32_t;
+    typedef endian< endianness::little, int_least64_t, 40 > little40_t;
+    typedef endian< endianness::little, int_least64_t, 48 > little48_t;
+    typedef endian< endianness::little, int_least64_t, 56 > little56_t;
+    typedef endian< endianness::little, int_least64_t, 64 > little64_t;
+
+    // unaligned little endian unsigned integer types
+    typedef endian< endianness::little, uint_least8_t, 8 >   ulittle8_t;
+    typedef endian< endianness::little, uint_least16_t, 16 > ulittle16_t;
+    typedef endian< endianness::little, uint_least32_t, 24 > ulittle24_t;
+    typedef endian< endianness::little, uint_least32_t, 32 > ulittle32_t;
+    typedef endian< endianness::little, uint_least64_t, 40 > ulittle40_t;
+    typedef endian< endianness::little, uint_least64_t, 48 > ulittle48_t;
+    typedef endian< endianness::little, uint_least64_t, 56 > ulittle56_t;
+    typedef endian< endianness::little, uint_least64_t, 64 > ulittle64_t;
+
+    // unaligned native endian signed integer types
+    typedef endian< endianness::native, int_least8_t, 8 >   native8_t;
+    typedef endian< endianness::native, int_least16_t, 16 > native16_t;
+    typedef endian< endianness::native, int_least32_t, 24 > native24_t;
+    typedef endian< endianness::native, int_least32_t, 32 > native32_t;
+    typedef endian< endianness::native, int_least64_t, 40 > native40_t;
+    typedef endian< endianness::native, int_least64_t, 48 > native48_t;
+    typedef endian< endianness::native, int_least64_t, 56 > native56_t;
+    typedef endian< endianness::native, int_least64_t, 64 > native64_t;
+
+    // unaligned native endian unsigned integer types
+    typedef endian< endianness::native, uint_least8_t, 8 >   unative8_t;
+    typedef endian< endianness::native, uint_least16_t, 16 > unative16_t;
+    typedef endian< endianness::native, uint_least32_t, 24 > unative24_t;
+    typedef endian< endianness::native, uint_least32_t, 32 > unative32_t;
+    typedef endian< endianness::native, uint_least64_t, 40 > unative40_t;
+    typedef endian< endianness::native, uint_least64_t, 48 > unative48_t;
+    typedef endian< endianness::native, uint_least64_t, 56 > unative56_t;
+    typedef endian< endianness::native, uint_least64_t, 64 > unative64_t;
+
+    // These types only present if platform has exact size integers:
+
+    // aligned big endian signed integer types
+    typedef endian< endianness::big, int16_t, 16, alignment::aligned >  aligned_big16_t;
+    typedef endian< endianness::big, int32_t, 32, alignment::aligned >  aligned_big32_t;
+    typedef endian< endianness::big, int64_t, 64, alignment::aligned >  aligned_big64_t;
+
+    // aligned big endian unsigned integer types
+    typedef endian< endianness::big, uint16_t, 16, alignment::aligned > aligned_ubig16_t;
+    typedef endian< endianness::big, uint32_t, 32, alignment::aligned > aligned_ubig32_t;
+    typedef endian< endianness::big, uint64_t, 64, alignment::aligned > aligned_ubig64_t;
+
+    // aligned little endian signed integer types
+    typedef endian< endianness::little, int16_t, 16, alignment::aligned > aligned_little2_t;
+    typedef endian< endianness::little, int32_t, 32, alignment::aligned > aligned_little4_t;
+    typedef endian< endianness::little, int64_t, 64, alignment::aligned > aligned_little8_t;
+
+    // aligned little endian unsigned integer types
+    typedef endian< endianness::little, uint16_t, 16, alignment::aligned > aligned_ulittle2_t;
+    typedef endian< endianness::little, uint32_t, 32, alignment::aligned > aligned_ulittle4_t;
+    typedef endian< endianness::little, uint64_t, 64, alignment::aligned > aligned_ulittle8_t;
+
+
+    // aligned native endian typedefs are not provided because
+    // <cstdint> types are superior for this use case
+
+  } // namespace integer
+} // namespace boost
+

Members

+

endian(){}

+
+

Effects: Constructs an object of type endian<E, T, n_bits, A>.

+
+

endian(T v);

+
+

Effects: Constructs an object of type endian<E, T, n_bits, A>.

+

Postcondition: x == v, where x is the +constructed object.

+
+

endian & operator=(T v);

+
+

Postcondition: x == v, where x is the + constructed object.

+

Returns: *this.

+
+

operator T() const;

+
+

Returns: The current value stored in *this, converted to +value_type.

+
+

Other operators

+

All other operators on endian objects are forwarded to the equivalent +operator on value_type.

+

FAQ

+

Why bother with endian types? External data portability and both speed +and space efficiency. Availability +of additional binary integer sizes and alignments is important in some +applications.

+

Why not just use Boost.Serialization? Serialization involves a +conversion for every object involved in I/O. Endian objects require no +conversion or copying. They are already in the desired format for binary I/O. +Thus they can be read or written in bulk.

+

Why bother with binary I/O? Why not just use C++ Standard Library stream +inserters and extractors? Using binary rather than character representations +can be more space efficient, with a side benefit of faster I/O. CPU time is +minimized because conversions to and from string are eliminated. +Furthermore, binary integers are fixed size, and so fixed-size disk records +are possible, easing sorting and allowing direct access. Disadvantages, such as the inability to use +text utilities on the resulting files, limit usefulness to applications where +the +binary I/O advantages are paramount.

+

Do these types have any uses outside of I/O? Probably not, except for +native endianness which can be used for fine grained control over size and +alignment.

+

Is there is a performance hit when doing arithmetic using these types? Yes, for sure, +compared to arithmetic operations on native integer types. However, these types +are usually be faster, and sometimes much faster, for I/O compared to stream +inserters and extractors, or to serialization.

+

Are endian types POD's? In C++03, no. For C++0x, yes, after applying + += +default to the default constructor.

+

What are the implications of C++03 endian types not being POD's? They +can't be used in unions. In theory, compilers aren't required to align or lay +out storage in portable ways, although this problem has never been observed in a +real compiler.

+

Which is better, big-endian or little-endian? Big-endian tends to be a +bit more of an industry standard, but little-endian may be preferred for +applications that run primarily on x86 (Intel/AMD) and other little-endian +CPU's. The Wikipedia article +gives more pros and cons.

+

What good is native endianness? It provides alignment and +size guarantees not available from the built-in types. It eases generic +programming.

+

Why bother with the aligned endian types? Aligned integer operations +may be faster (20 times, in one measurement) if the endianness and alignment of +the type matches the endianness and alignment requirements of the machine. On +common CPU architectures, that optimization is only available for aligned types. +That allows I/O of maximally efficient types on an application's primary +platform, yet produces data files are portable to all platforms. The code, +however, is +likely to be more fragile and less portable than with the unaligned types.

+

These types are really just byte-holders. Why provide the arithmetic +operations at all? Providing a full set of operations reduces program +clutter and makes code both easier to write and to read. Consider +incrementing a variable in a record. It is very convenient to write:

+
    ++record.foo;
+

Rather than:

+
    int temp( record.foo);
+    ++temp;
+    record.foo = temp;
+

Example

+

The endian_example.cpp program writes a +binary file containing four byte big-endian and little-endian integers:

+
+
#include <iostream>
+#include <cassert>
+#include <cstdio>
+#include <boost/integer/endian.hpp>
+
+using boost::integer::big32_t;
+using boost::integer::little32_t;
+
+namespace 
+{
+  // This is a portion of a widely used GIS file format. I have no idea why
+  // anyone would mix big and little endians in the same format - but it is
+  // a real format and users wishing to write code manipulating files in that
+  // format have to deal with it.
+
+  struct header
+  {
+    big32_t     file_code;
+    big32_t     file_length;
+    little32_t  version;
+    little32_t  shape_type;
+  };
+
+  const char * filename = "test.dat";
+}
+
+int main()
+{
+  assert( sizeof( header ) == 16 );
+
+  header h;
+
+  h.file_code   = 0x04030201;
+  h.file_length = sizeof( header );
+  h.version     = -1;
+  h.shape_type  = 0x04030201;
+
+  // Low-level I/O such as POSIX read/write or <cstdio> fread/fwrite is
+  // typically used for binary file operations. Such I/O is often performed in
+  // some C++ wrapper class, but to drive home the point that endian integers
+  // are usually used in fairly low-level code, <cstdio> fopen/fwrite is used
+  // for I/O in this example.
+
+  std::FILE * fi;
+
+  if ( !(fi = std::fopen( filename, "wb" )) )
+  {
+    std::cout << "could not open " << filename << '\n';
+    return 1;
+  }
+
+  if ( std::fwrite( &h, sizeof( header ), 1, fi ) != 1 ) 
+  {
+    std::cout << "write failure for " << filename << '\n';
+    return 1;
+  }
+
+  std::fclose( fi );
+  std::cout << "created file " << filename << '\n';
+  return 0;
+}
+
+

After compiling and executing endian_example.cpp, a hex dump of test.dat shows:

+
+
0403 0201 0000 0010 ffff ffff 0102 0304
+
+

Design considerations for Boost.Endian

+
    +
  • Must be suitable for I/O - in other words, must be memcpyable.
  • +
  • Must provide exactly the size and internal byte ordering specified.
  • +
  • Must work correctly when the internal integer representation has more bits + that the sum of the bits in the external byte representation. Sign extension + must work correctly when the internal integer representation type has more + bits than the sum of the bits in the external bytes. For example, using + a 64-bit integer internally to represent 40-bit (5 byte) numbers must work for + both positive and negative values.
  • +
  • Must work correctly (including using the same defined external + representation) regardless of whether a compiler treats char as signed or + unsigned.
  • +
  • Unaligned types must not cause compilers to insert padding bytes.
  • +
  • The implementation should supply optimizations only in very limited + circumstances. Experience has shown that optimizations of endian + integers often become pessimizations. While this may be obvious when changing + machines or compilers, it also happens when changing compiler switches, + compiler versions, or CPU models of the same architecture.
  • +
  • It is better software engineering if the same implementation works regardless + of the CPU endianness. In other words, #ifdefs should be avoided where + possible.
  • +
+

Experience

+

Classes with similar functionality have been independently developed by +several Boost programmers and used very successful in high-value, high-use +applications for many years. These independently developed endian libraries +often evolved from C libraries that were also widely used. Endian integers have proven widely useful across a wide +range of computer architectures and applications.

+

Acknowledgements

+

Original design developed by Darin Adler based on classes developed by Mark +Borgerding. Four original class templates combined into a single endian +class template by Beman Dawes, who put the library together, provided +documentation, and added the typedefs. He also added the unrolled_byte_loops +sign partial specialization to correctly extend the sign when cover integer size +differs from endian representation size.

+

Comments and suggestions were +received from +Benaka Moorthi, +Christopher Kohlhoff, +Cliff Green, +Gennaro Proto, +Jeff Flinn, +John Maddock, +Kim Barrett, +Marsh Ray, +Martin Bonner, +Matias Capeletto, +Rene Rivera, +Scott McMurray, +Sebastian Redl, +Tomas Puverle, and +Yuval Ronen.

+
+

Last revised: +26 May, 2008

+

© Copyright Beman Dawes, 2006

+

Distributed under the Boost Software License, Version 1.0. (See accompanying +file LICENSE_1_0.txt or copy at +www.boost.org/ LICENSE_1_0.txt)

+ + + + \ No newline at end of file diff --git a/libs/integer/example/endian_example.cpp b/libs/integer/example/endian_example.cpp new file mode 100644 index 0000000..05a994f --- /dev/null +++ b/libs/integer/example/endian_example.cpp @@ -0,0 +1,75 @@ +// endian_example.cpp -------------------------------------------------------// + +// Copyright Beman Dawes, 2006 + +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See library home page at http://www.boost.org/libs/endian + +//----------------------------------------------------------------------------// + +#define _CRT_SECURE_NO_DEPRECATE // quiet VC++ 8.0 foolishness + +#include +#include +#include +#include + +using boost::integer::big32_t; +using boost::integer::little32_t; + +namespace +{ + // This is an extract from a very widely used GIS file format. I have no idea + // why a designer would mix big and little endians in the same file - but + // this is a real format and users wishing to write low level code + // manipulating these files have to deal with the mixed endianness. + + struct header + { + big32_t file_code; + big32_t file_length; + little32_t version; + little32_t shape_type; + }; + + const char * filename = "test.dat"; +} + +int main() +{ + assert( sizeof( header ) == 16 ); + + header h; + + h.file_code = 0x04030201; + h.file_length = sizeof( header ); + h.version = -1; + h.shape_type = 0x04030201; + + // Low-level I/O such as POSIX read/write or fread/fwrite is + // typically used for binary file operations. Such I/O is often performed in + // some C++ wrapper class, but to drive home the point that endian integers + // are usually used in fairly low-level code, fopen/fwrite is used + // for I/O in this example. + + std::FILE * fi; + + if ( !(fi = std::fopen( filename, "wb" )) ) + { + std::cout << "could not open " << filename << '\n'; + return 1; + } + + if ( std::fwrite( &h, sizeof( header ), 1, fi ) != 1 ) + { + std::cout << "write failure for " << filename << '\n'; + return 1; + } + + std::fclose( fi ); + + std::cout << "created file " << filename << '\n'; + return 0; +} diff --git a/libs/integer/test/Jamfile.v2 b/libs/integer/test/Jamfile.v2 new file mode 100644 index 0000000..73478c9 --- /dev/null +++ b/libs/integer/test/Jamfile.v2 @@ -0,0 +1,13 @@ +# Boost Endian Library test Jamfile + +# Copyright Beman Dawes 2006 + +# Distributed under the Boost Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +# See library home page at http://www.boost.org/libs/endian + + + test-suite "endian" + : [ run libs/integer/test/endian_test.cpp ] + ; diff --git a/libs/integer/test/endian-in-sandbox/common.vsprops b/libs/integer/test/endian-in-sandbox/common.vsprops new file mode 100644 index 0000000..2f84c92 --- /dev/null +++ b/libs/integer/test/endian-in-sandbox/common.vsprops @@ -0,0 +1,13 @@ + + + + diff --git a/libs/integer/test/endian-in-sandbox/endian-in-sandbox.sln b/libs/integer/test/endian-in-sandbox/endian-in-sandbox.sln new file mode 100644 index 0000000..eaf71e5 --- /dev/null +++ b/libs/integer/test/endian-in-sandbox/endian-in-sandbox.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual C++ Express 2008 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "endian_test", "endian_test\endian_test.vcproj", "{74C201F3-8308-40BE-BC0F-24974DEAF405}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {74C201F3-8308-40BE-BC0F-24974DEAF405}.Debug|Win32.ActiveCfg = Debug|Win32 + {74C201F3-8308-40BE-BC0F-24974DEAF405}.Debug|Win32.Build.0 = Debug|Win32 + {74C201F3-8308-40BE-BC0F-24974DEAF405}.Release|Win32.ActiveCfg = Release|Win32 + {74C201F3-8308-40BE-BC0F-24974DEAF405}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/libs/integer/test/endian-in-sandbox/endian_test/endian_test.vcproj b/libs/integer/test/endian-in-sandbox/endian_test/endian_test.vcproj new file mode 100644 index 0000000..bbc12c1 --- /dev/null +++ b/libs/integer/test/endian-in-sandbox/endian_test/endian_test.vcproj @@ -0,0 +1,193 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/libs/integer/test/endian_test.cpp b/libs/integer/test/endian_test.cpp new file mode 100644 index 0000000..40ad189 --- /dev/null +++ b/libs/integer/test/endian_test.cpp @@ -0,0 +1,593 @@ +// endian_test.cpp ---------------------------------------------------------// + +// Copyright Beman Dawes, 1999-2006 + +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See library home page at http://www.boost.org/libs/endian + +//----------------------------------------------------------------------------// + +#include +#include +#include + +#include +#include +#include +#include // for atoi(), exit() +#include // for memcmp() + +using namespace std; // not the best programming practice, but I +using namespace boost; // want to verify this combination of using +using namespace boost::integer; // namespaces works. + +#define VERIFY(predicate) verify( predicate, __LINE__ ) +#define VERIFY_SIZE(actual, expected) verify_size( actual, expected, __LINE__ ) +#define VERIFY_VALUE_AND_OPS(endian_t,expected_t,expected) verify_value_and_ops( expected, __LINE__ ) +#define VERIFY_BIG_REPRESENTATION(t) verify_representation( true, __LINE__ ) +#define VERIFY_LITTLE_REPRESENTATION(t) verify_representation( false, __LINE__ ) +#define VERIFY_NATIVE_REPRESENTATION(t) verify_native_representation( __LINE__ ) + +namespace +{ + int err_count; + + void verify( bool x, int line ) + { + if ( x ) return; + ++err_count; + cout << "Error: verify failed on line " << line << endl; + } + + void verify_size( size_t actual, size_t expected, int line ) + { + if ( actual == expected ) return; + ++err_count; + cout << "Error: verify failed on line " << line << endl; + cout << " A structure with an expected sizeof() " << expected + << " had an actual sizeof() " << actual + << "\n This will cause common uses of to fail\n"; + } + + template + void verify_value_and_ops( const Base & expected, int line ) + { + Endian v( expected ); + verify( v == expected, line ); + + Endian v2; + v2.operator=( expected ); + verify( v2 == expected, line ); + + ++v; // verify integer_cover_operators being applied to this type - + // will fail to compile if no endian<> specialization is present + } + + const char * big_rep = "\x12\x34\x56\x78\x9A\xBC\xDE\xF0"; + const char * little_rep = "\xF0\xDE\xBC\x9A\x78\x56\x34\x12"; + + template + void verify_representation( bool is_big, int line ) + { + int silence = 0; + Endian x = static_cast + (0x123456789abcdef0LL + silence); // will truncate + + if ( is_big ) + verify( memcmp( &x, + reinterpret_cast(big_rep)+8-sizeof(Endian), + sizeof(Endian) ) == 0, line ); + else + verify( memcmp( &x, little_rep, sizeof(Endian) ) == 0, line ); + } + + template + inline void verify_native_representation( int line ) + { +# ifdef BOOST_BIG_ENDIAN + verify_representation( true, line ); +# else + verify_representation( false, line ); +# endif + } + + + + // detect_endianness -----------------------------------------------------// + + void detect_endianness() + { + union View + { + long long i; + unsigned char c[8]; + }; + + View v = { 0x0102030405060708LL }; // initialize v.i + + if ( memcmp( v.c, "\10\7\6\5\4\3\2\1", 8) == 0 ) + { + cout << "This machine is little-endian.\n"; + # ifdef BOOST_BIG_INTEGER_OPERATORS + cout << "yet boost/detail/endian.hpp defines BOOST_BIG_INTEGER_OPERATORS.\n" + "You must fix boost/detail/endian.hpp for boost/endian.hpp to work correctly.\n" + "Please report the fix to the Boost mailing list.\n"; + exit(1); + # endif + } + else if ( memcmp( v.c, "\1\2\3\4\5\6\7\10", 8) == 0 ) + { + cout << "This machine is big-endian.\n"; + # ifdef BOOST_LITTLE_INTEGER_OPERATORS + cout << "yet boost/detail/endian.hpp defines BOOST__LITTLE_INTEGER_OPERATORS.\n" + "You must fix boost/detail/endian.hpp for boost/endian.hpp to work correctly.\n" + "Please report the fix to the Boost mailing list.\n"; + exit(1); + # endif + } + else + { + cout << "This machine is neither strict big-endian nor strict little-endian\n" + "You must modify boost/endian.hpp for it to work correctly.\n"; + exit(1); + } + cout << "That should not matter and is presented for your information only.\n"; + } // detect_endianness + + // check_size ------------------------------------------------------------// + + void check_size() + { + VERIFY( numeric_limits::digits == 7 ); + VERIFY( numeric_limits::digits == 8 ); + + VERIFY( sizeof( big8_t ) == 1 ); + VERIFY( sizeof( big16_t ) == 2 ); + VERIFY( sizeof( big24_t ) == 3 ); + VERIFY( sizeof( big32_t ) == 4 ); + VERIFY( sizeof( big40_t ) == 5 ); + VERIFY( sizeof( big48_t ) == 6 ); + VERIFY( sizeof( big56_t ) == 7 ); + VERIFY( sizeof( big64_t ) == 8 ); + + VERIFY( sizeof( ubig8_t ) == 1 ); + VERIFY( sizeof( ubig16_t ) == 2 ); + VERIFY( sizeof( ubig24_t ) == 3 ); + VERIFY( sizeof( ubig32_t ) == 4 ); + VERIFY( sizeof( ubig40_t ) == 5 ); + VERIFY( sizeof( ubig48_t ) == 6 ); + VERIFY( sizeof( ubig56_t ) == 7 ); + VERIFY( sizeof( ubig64_t ) == 8 ); + + VERIFY( sizeof( little8_t ) == 1 ); + VERIFY( sizeof( little16_t ) == 2 ); + VERIFY( sizeof( little24_t ) == 3 ); + VERIFY( sizeof( little32_t ) == 4 ); + VERIFY( sizeof( little40_t ) == 5 ); + VERIFY( sizeof( little48_t ) == 6 ); + VERIFY( sizeof( little56_t ) == 7 ); + VERIFY( sizeof( little64_t ) == 8 ); + + VERIFY( sizeof( ulittle8_t ) == 1 ); + VERIFY( sizeof( ulittle16_t ) == 2 ); + VERIFY( sizeof( ulittle24_t ) == 3 ); + VERIFY( sizeof( ulittle32_t ) == 4 ); + VERIFY( sizeof( ulittle40_t ) == 5 ); + VERIFY( sizeof( ulittle48_t ) == 6 ); + VERIFY( sizeof( ulittle56_t ) == 7 ); + VERIFY( sizeof( ulittle64_t ) == 8 ); + + VERIFY( sizeof( native8_t ) == 1 ); + VERIFY( sizeof( native16_t ) == 2 ); + VERIFY( sizeof( native24_t ) == 3 ); + VERIFY( sizeof( native32_t ) == 4 ); + VERIFY( sizeof( native40_t ) == 5 ); + VERIFY( sizeof( native48_t ) == 6 ); + VERIFY( sizeof( native56_t ) == 7 ); + VERIFY( sizeof( native64_t ) == 8 ); + + VERIFY( sizeof( unative8_t ) == 1 ); + VERIFY( sizeof( unative16_t ) == 2 ); + VERIFY( sizeof( unative24_t ) == 3 ); + VERIFY( sizeof( unative32_t ) == 4 ); + VERIFY( sizeof( unative40_t ) == 5 ); + VERIFY( sizeof( unative48_t ) == 6 ); + VERIFY( sizeof( unative56_t ) == 7 ); + VERIFY( sizeof( unative64_t ) == 8 ); + + VERIFY( sizeof( aligned_big16_t ) == 2 ); + VERIFY( sizeof( aligned_big32_t ) == 4 ); + VERIFY( sizeof( aligned_big64_t ) == 8 ); + + VERIFY( sizeof( aligned_ubig16_t ) == 2 ); + VERIFY( sizeof( aligned_ubig32_t ) == 4 ); + VERIFY( sizeof( aligned_ubig64_t ) == 8 ); + + VERIFY( sizeof( aligned_little16_t ) == 2 ); + VERIFY( sizeof( aligned_little32_t ) == 4 ); + VERIFY( sizeof( aligned_little64_t ) == 8 ); + + VERIFY( sizeof( aligned_ulittle16_t ) == 2 ); + VERIFY( sizeof( aligned_ulittle32_t ) == 4 ); + VERIFY( sizeof( aligned_ulittle64_t ) == 8 ); + } // check_size + + // check_alignment -------------------------------------------------------// + + void check_alignment() + { + // structs with offsets % 2 == 1 for type of size > 1 to ensure no alignment + // bytes added for any size > 1 + + struct big_struct + { + big8_t v0; + big16_t v1; + big24_t v3; + char v6; + big32_t v7; + big40_t v11; + char v16; + big48_t v17; + big56_t v23; + char v30; + big64_t v31; + }; + + struct ubig_struct + { + ubig8_t v0; + ubig16_t v1; + ubig24_t v3; + char v6; + ubig32_t v7; + ubig40_t v11; + char v16; + ubig48_t v17; + ubig56_t v23; + char v30; + ubig64_t v31; + }; + + struct little_struct + { + little8_t v0; + little16_t v1; + little24_t v3; + char v6; + little32_t v7; + little40_t v11; + char v16; + little48_t v17; + little56_t v23; + char v30; + little64_t v31; + }; + + struct ulittle_struct + { + ulittle8_t v0; + ulittle16_t v1; + ulittle24_t v3; + char v6; + ulittle32_t v7; + ulittle40_t v11; + char v16; + ulittle48_t v17; + ulittle56_t v23; + char v30; + ulittle64_t v31; + }; + + struct native_struct + { + native8_t v0; + native16_t v1; + native24_t v3; + char v6; + native32_t v7; + native40_t v11; + char v16; + native48_t v17; + native56_t v23; + char v30; + native64_t v31; + }; + + struct unative_struct + { + unative8_t v0; + unative16_t v1; + unative24_t v3; + char v6; + unative32_t v7; + unative40_t v11; + char v16; + unative48_t v17; + unative56_t v23; + char v30; + unative64_t v31; + }; + + int saved_err_count = err_count; + + VERIFY_SIZE( sizeof(big_struct), 39 ); + VERIFY_SIZE( sizeof(ubig_struct), 39 ); + VERIFY_SIZE( sizeof(little_struct), 39 ); + VERIFY_SIZE( sizeof(ulittle_struct), 39 ); + VERIFY_SIZE( sizeof(native_struct), 39 ); + VERIFY_SIZE( sizeof(unative_struct), 39 ); + + if ( saved_err_count == err_count ) + { + cout << + "Size and alignment for structures of endian types are as expected.\n"; + } + } // check_alignment + + // check_representation_and_range_and_ops --------------------------------// + + void check_representation_and_range_and_ops() + { + + VERIFY_BIG_REPRESENTATION( big8_t ); + VERIFY_VALUE_AND_OPS( big8_t, int_least8_t, 0x7f ); + VERIFY_VALUE_AND_OPS( big8_t, int_least8_t, -0x80 ); + + VERIFY_BIG_REPRESENTATION( big16_t ); + VERIFY_VALUE_AND_OPS( big16_t, int_least16_t, 0x7fff ); + VERIFY_VALUE_AND_OPS( big16_t, int_least16_t, -0x8000 ); + + VERIFY_BIG_REPRESENTATION( big24_t ); + VERIFY_VALUE_AND_OPS( big24_t, int_least32_t, 0x7fffff ); + VERIFY_VALUE_AND_OPS( big24_t, int_least32_t, -0x800000 ); + + VERIFY_BIG_REPRESENTATION( big32_t ); + VERIFY_VALUE_AND_OPS( big32_t, int_least32_t, 0x7fffffff ); + VERIFY_VALUE_AND_OPS( big32_t, int_least32_t, -0x7fffffff-1 ); + + VERIFY_BIG_REPRESENTATION( big40_t ); + VERIFY_VALUE_AND_OPS( big40_t, int_least64_t, 0x7fffffffffLL ); + VERIFY_VALUE_AND_OPS( big40_t, int_least64_t, -0x8000000000LL ); + + VERIFY_BIG_REPRESENTATION( big48_t ); + VERIFY_VALUE_AND_OPS( big48_t, int_least64_t, 0x7fffffffffffLL ); + VERIFY_VALUE_AND_OPS( big48_t, int_least64_t, -0x800000000000LL ); + + VERIFY_BIG_REPRESENTATION( big56_t ); + VERIFY_VALUE_AND_OPS( big56_t, int_least64_t, 0x7fffffffffffffLL ); + VERIFY_VALUE_AND_OPS( big56_t, int_least64_t, -0x80000000000000LL ); + + VERIFY_BIG_REPRESENTATION( big64_t ); + VERIFY_VALUE_AND_OPS( big64_t, int_least64_t, 0x7fffffffffffffffLL ); + VERIFY_VALUE_AND_OPS( big64_t, int_least64_t, -0x7fffffffffffffffLL-1 ); + + VERIFY_BIG_REPRESENTATION( ubig8_t ); + VERIFY_VALUE_AND_OPS( ubig8_t, uint_least8_t, 0xff ); + + VERIFY_BIG_REPRESENTATION( ubig16_t ); + VERIFY_VALUE_AND_OPS( ubig16_t, uint_least16_t, 0xffff ); + + VERIFY_BIG_REPRESENTATION( ubig24_t ); + VERIFY_VALUE_AND_OPS( ubig24_t, uint_least32_t, 0xffffff ); + + VERIFY_BIG_REPRESENTATION( ubig32_t ); + VERIFY_VALUE_AND_OPS( ubig32_t, uint_least32_t, 0xffffffff ); + + VERIFY_BIG_REPRESENTATION( ubig40_t ); + VERIFY_VALUE_AND_OPS( ubig40_t, uint_least64_t, 0xffffffffffLL ); + + VERIFY_BIG_REPRESENTATION( ubig48_t ); + VERIFY_VALUE_AND_OPS( ubig48_t, uint_least64_t, 0xffffffffffffLL ); + + VERIFY_BIG_REPRESENTATION( ubig56_t ); + VERIFY_VALUE_AND_OPS( ubig56_t, uint_least64_t, 0xffffffffffffffLL ); + + VERIFY_BIG_REPRESENTATION( ubig64_t ); + VERIFY_VALUE_AND_OPS( ubig64_t, uint_least64_t, 0xffffffffffffffffLL ); + + VERIFY_LITTLE_REPRESENTATION( little8_t ); + VERIFY_VALUE_AND_OPS( little8_t, int_least8_t, 0x7f ); + VERIFY_VALUE_AND_OPS( little8_t, int_least8_t, -0x80 ); + + VERIFY_LITTLE_REPRESENTATION( little16_t ); + VERIFY_VALUE_AND_OPS( little16_t, int_least16_t, 0x7fff ); + VERIFY_VALUE_AND_OPS( little16_t, int_least16_t, -0x8000 ); + + VERIFY_LITTLE_REPRESENTATION( little24_t ); + VERIFY_VALUE_AND_OPS( little24_t, int_least32_t, 0x7fffff ); + VERIFY_VALUE_AND_OPS( little24_t, int_least32_t, -0x800000 ); + + VERIFY_LITTLE_REPRESENTATION( little32_t ); + VERIFY_VALUE_AND_OPS( little32_t, int_least32_t, 0x7fffffff ); + VERIFY_VALUE_AND_OPS( little32_t, int_least32_t, -0x7fffffff-1 ); + + VERIFY_LITTLE_REPRESENTATION( little40_t ); + VERIFY_VALUE_AND_OPS( little40_t, int_least64_t, 0x7fffffffffLL ); + VERIFY_VALUE_AND_OPS( little40_t, int_least64_t, -0x8000000000LL ); + + VERIFY_LITTLE_REPRESENTATION( little48_t ); + VERIFY_VALUE_AND_OPS( little48_t, int_least64_t, 0x7fffffffffffLL ); + VERIFY_VALUE_AND_OPS( little48_t, int_least64_t, -0x800000000000LL ); + + VERIFY_LITTLE_REPRESENTATION( little56_t ); + VERIFY_VALUE_AND_OPS( little56_t, int_least64_t, 0x7fffffffffffffLL ); + VERIFY_VALUE_AND_OPS( little56_t, int_least64_t, -0x80000000000000LL ); + + VERIFY_LITTLE_REPRESENTATION( little64_t ); + VERIFY_VALUE_AND_OPS( little64_t, int_least64_t, 0x7fffffffffffffffLL ); + VERIFY_VALUE_AND_OPS( little64_t, int_least64_t, -0x7fffffffffffffffLL-1 ); + + VERIFY_LITTLE_REPRESENTATION( ulittle8_t ); + VERIFY_VALUE_AND_OPS( ulittle8_t, uint_least8_t, 0xff ); + + VERIFY_LITTLE_REPRESENTATION( ulittle16_t ); + VERIFY_VALUE_AND_OPS( ulittle16_t, uint_least16_t, 0xffff ); + + VERIFY_LITTLE_REPRESENTATION( ulittle24_t ); + VERIFY_VALUE_AND_OPS( ulittle24_t, uint_least32_t, 0xffffff ); + + VERIFY_LITTLE_REPRESENTATION( ulittle32_t ); + VERIFY_VALUE_AND_OPS( ulittle32_t, uint_least32_t, 0xffffffff ); + + VERIFY_LITTLE_REPRESENTATION( ulittle40_t ); + VERIFY_VALUE_AND_OPS( ulittle40_t, uint_least64_t, 0xffffffffffLL ); + + VERIFY_LITTLE_REPRESENTATION( ulittle48_t ); + VERIFY_VALUE_AND_OPS( ulittle48_t, uint_least64_t, 0xffffffffffffLL ); + + VERIFY_LITTLE_REPRESENTATION( ulittle56_t ); + VERIFY_VALUE_AND_OPS( ulittle56_t, uint_least64_t, 0xffffffffffffffLL ); + + VERIFY_LITTLE_REPRESENTATION( ulittle64_t ); + VERIFY_VALUE_AND_OPS( ulittle64_t, uint_least64_t, 0xffffffffffffffffLL ); + + VERIFY_NATIVE_REPRESENTATION( native8_t ); + VERIFY_VALUE_AND_OPS( native8_t, int_least8_t, 0x7f ); + VERIFY_VALUE_AND_OPS( native8_t, int_least8_t, -0x80 ); + + VERIFY_NATIVE_REPRESENTATION( native16_t ); + VERIFY_VALUE_AND_OPS( native16_t, int_least16_t, 0x7fff ); + VERIFY_VALUE_AND_OPS( native16_t, int_least16_t, -0x8000 ); + + VERIFY_NATIVE_REPRESENTATION( native24_t ); + VERIFY_VALUE_AND_OPS( native24_t, int_least32_t, 0x7fffff ); + VERIFY_VALUE_AND_OPS( native24_t, int_least32_t, -0x800000 ); + + VERIFY_NATIVE_REPRESENTATION( native32_t ); + VERIFY_VALUE_AND_OPS( native32_t, int_least32_t, 0x7fffffff ); + VERIFY_VALUE_AND_OPS( native32_t, int_least32_t, -0x7fffffff-1 ); + + VERIFY_NATIVE_REPRESENTATION( native40_t ); + VERIFY_VALUE_AND_OPS( native40_t, int_least64_t, 0x7fffffffffLL ); + VERIFY_VALUE_AND_OPS( native40_t, int_least64_t, -0x8000000000LL ); + + VERIFY_NATIVE_REPRESENTATION( native48_t ); + VERIFY_VALUE_AND_OPS( native48_t, int_least64_t, 0x7fffffffffffLL ); + VERIFY_VALUE_AND_OPS( native48_t, int_least64_t, -0x800000000000LL ); + + VERIFY_NATIVE_REPRESENTATION( native56_t ); + VERIFY_VALUE_AND_OPS( native56_t, int_least64_t, 0x7fffffffffffffLL ); + VERIFY_VALUE_AND_OPS( native56_t, int_least64_t, -0x80000000000000LL ); + + VERIFY_NATIVE_REPRESENTATION( native64_t ); + VERIFY_VALUE_AND_OPS( native64_t, int_least64_t, 0x7fffffffffffffffLL ); + VERIFY_VALUE_AND_OPS( native64_t, int_least64_t, -0x7fffffffffffffffLL-1 ); + + VERIFY_NATIVE_REPRESENTATION( unative8_t ); + VERIFY_VALUE_AND_OPS( unative8_t, uint_least8_t, 0xff ); + + VERIFY_NATIVE_REPRESENTATION( unative16_t ); + VERIFY_VALUE_AND_OPS( unative16_t, uint_least16_t, 0xffff ); + + VERIFY_NATIVE_REPRESENTATION( unative24_t ); + VERIFY_VALUE_AND_OPS( unative24_t, uint_least32_t, 0xffffff ); + + VERIFY_NATIVE_REPRESENTATION( unative32_t ); + VERIFY_VALUE_AND_OPS( unative32_t, uint_least32_t, 0xffffffff ); + + VERIFY_NATIVE_REPRESENTATION( unative40_t ); + VERIFY_VALUE_AND_OPS( unative40_t, uint_least64_t, 0xffffffffffLL ); + + VERIFY_NATIVE_REPRESENTATION( unative48_t ); + VERIFY_VALUE_AND_OPS( unative48_t, uint_least64_t, 0xffffffffffffLL ); + + VERIFY_NATIVE_REPRESENTATION( unative56_t ); + VERIFY_VALUE_AND_OPS( unative56_t, uint_least64_t, 0xffffffffffffffLL ); + + VERIFY_NATIVE_REPRESENTATION( unative64_t ); + VERIFY_VALUE_AND_OPS( unative64_t, uint_least64_t, 0xffffffffffffffffLL ); + + VERIFY_BIG_REPRESENTATION( aligned_big16_t ); + VERIFY_VALUE_AND_OPS( aligned_big16_t, int_least16_t, 0x7fff ); + VERIFY_VALUE_AND_OPS( aligned_big16_t, int_least16_t, -0x8000 ); + + VERIFY_BIG_REPRESENTATION( aligned_big32_t ); + VERIFY_VALUE_AND_OPS( aligned_big32_t, int_least32_t, 0x7fffffff ); + VERIFY_VALUE_AND_OPS( aligned_big32_t, int_least32_t, -0x7fffffff-1 ); + + VERIFY_BIG_REPRESENTATION( aligned_big64_t ); + VERIFY_VALUE_AND_OPS( aligned_big64_t, int_least64_t, 0x7fffffffffffffffLL ); + VERIFY_VALUE_AND_OPS( aligned_big64_t, int_least64_t, -0x7fffffffffffffffLL-1 ); + + VERIFY_BIG_REPRESENTATION( aligned_ubig16_t ); + VERIFY_VALUE_AND_OPS( aligned_ubig16_t, uint_least16_t, 0xffff ); + + VERIFY_BIG_REPRESENTATION( aligned_ubig32_t ); + VERIFY_VALUE_AND_OPS( aligned_ubig32_t, uint_least32_t, 0xffffffff ); + + VERIFY_BIG_REPRESENTATION( aligned_ubig64_t ); + VERIFY_VALUE_AND_OPS( aligned_ubig64_t, uint_least64_t, 0xffffffffffffffffLL ); + + VERIFY_LITTLE_REPRESENTATION( aligned_little16_t ); + VERIFY_VALUE_AND_OPS( aligned_little16_t, int_least16_t, 0x7fff ); + VERIFY_VALUE_AND_OPS( aligned_little16_t, int_least16_t, -0x8000 ); + + VERIFY_LITTLE_REPRESENTATION( aligned_little32_t ); + VERIFY_VALUE_AND_OPS( aligned_little32_t, int_least32_t, 0x7fffffff ); + VERIFY_VALUE_AND_OPS( aligned_little32_t, int_least32_t, -0x7fffffff-1 ); + + VERIFY_LITTLE_REPRESENTATION( aligned_little64_t ); + VERIFY_VALUE_AND_OPS( aligned_little64_t, int_least64_t, 0x7fffffffffffffffLL ); + VERIFY_VALUE_AND_OPS( aligned_little64_t, int_least64_t, -0x7fffffffffffffffLL-1 ); + + VERIFY_LITTLE_REPRESENTATION( aligned_ulittle16_t ); + VERIFY_VALUE_AND_OPS( aligned_ulittle16_t, uint_least16_t, 0xffff ); + + VERIFY_LITTLE_REPRESENTATION( aligned_ulittle32_t ); + VERIFY_VALUE_AND_OPS( aligned_ulittle32_t, uint_least32_t, 0xffffffff ); + + VERIFY_LITTLE_REPRESENTATION( aligned_ulittle64_t ); + VERIFY_VALUE_AND_OPS( aligned_ulittle64_t, uint_least64_t, 0xffffffffffffffffLL ); + + } // check_representation_and_range + + long iterations = 10000000; + + template< class Endian > + Endian timing_test( const char * s) + { + cout << s << " timing test, " << iterations << " iterations: "; + progress_timer t; + + Endian v = 1; + for ( long i = 0; i < iterations; ++i ) + { + v += 1; + v *= 3; + ++v; + v *= i; + if ( i == 0 ) VERIFY_VALUE_AND_OPS( Endian, typename Endian::value_type, 21 ); + } + return v; + } + +} // unnamed namespace + +int main( int argc, char * argv[] ) +{ + cout << "Usage: " + << argv[0] << " [#],\n where # specifies iteration count\n" + " default iteration count is 1000000" << endl; + + if ( argc > 1 ) + iterations = atol( argv[1] ); + if ( iterations < 1 ) iterations = 1; + + detect_endianness(); + check_size(); + check_alignment(); + check_representation_and_range_and_ops(); + + //timing_test ( "big32_t" ); + //timing_test( "aligned_big32_t" ); + //timing_test ( "little32_t" ); + //timing_test( "aligned_little32_t" ); + + cout << "\n" << err_count << " errors detected\nTest " + << (err_count==0 ? "passed\n\n" : "failed\n\n"); + + return err_count ? 1 : 0; +} // main diff --git a/libs/integer/test/test.bat b/libs/integer/test/test.bat new file mode 100644 index 0000000..d5c72f2 --- /dev/null +++ b/libs/integer/test/test.bat @@ -0,0 +1,11 @@ +set ENDIAN_LOCATE_ROOT=%temp%\endian-regr +md %ENDIAN_LOCATE_ROOT% 2>nul + +echo Begin test processing... +bjam --dump-tests "-sALL_LOCATE_TARGET=%ENDIAN_LOCATE_ROOT%" %* >bjam.log 2>&1 +echo Begin log processing... +process_jam_log %ENDIAN_LOCATE_ROOT% nul +pushd . +mkdir \tmp\%1 +cd \tmp\%1 +md boost\integer +md libs\integer\doc +md libs\integer\example +md libs\integer\test +popd +copy ..\..\boost\integer\endian.hpp \tmp\%1\boost\integer +copy ..\..\boost\integer\cover_operators.hpp \tmp\%1\boost\integer +copy ..\..\libs\integer\doc\endian.html \tmp\%1\libs\integer\doc +copy ..\..\libs\integer\example\endian_example.cpp \tmp\%1\libs\integer\example +copy ..\..\libs\integer\test\endian_test.cpp \tmp\%1\libs\integer\test +copy ..\..\libs\integer\test\Jamfile.* \tmp\%1\libs\integer\test + +pushd \tmp +zip -r %1.zip %1 +popd +move \tmp\%1.zip . + +goto done + +:error +echo usage: zip-endian version +echo version will be used for both the .zip name and the highest level directory name +echo example: zip-endian endian-1.0 + +:done \ No newline at end of file