Boost logo

Boost :

Subject: Re: [boost] [Review] Boost.Endian - template requirements and scope
From: John Filo (filo_at_[hidden])
Date: 2011-09-09 23:07:21


On 09/07/2011 04:04 PM, Vicente J. Botet Escriba wrote:

> What about enums? Could we use enums as underlying type of boost::endian<>?

That would be nice, but it seems of limited use in C++03; Isn't the
actual size of an enum unspecified and compiler dependent? Scoped enums
in C++0x, with their ability to specify the underlying type, seems much
more usable.

> struct UdpHeader {
> uint16_t source_port; // big
> uint16_t destination_port; // big
> uint16_t length; // big
> uint16_t checksum; // big
> }; // UdpHeader

I'm curious what you mean when you say UDT. Do you want to be able to
say endian<big, UdpHeader>? That seems like a much more difficult
problem and way beyond the scope of what Beman's library is trying to do.

By the way, it's exactly this type of ubiquitous system struct that
makes me think these something like the endian types in Beman's library
should become part of the the C++ (and C) standard. It would allow
programmers to stop worrying about these issues when dealing with
external data.

> quantity<si::length, boost::int_least32_t> x; // little

I would do:

   quantity<si::length, little32_t>

The above scheme (defining the UDT in terms of the endian types instead
of defining an endian type in terms of a UDT) should work in many cases.
  In fact, it seems like the preferred (or even required) approach in
many cases. A small amount of testing seems to indicate that this works
fairly well with the current version of Boost.Endian. I was worried
that code like the following wouldn't compile at all because the
compiler would think QI, QL, and QB were different incompatible types.
But Boost.Units seems to provide the right magic to make the following
work as desired. Unfortunately, Boost.Endian's lack of implicit
conversion to the endian types limits how well this works (see comment
in main() below)

#include <boost/units/systems/si.hpp>
#include <boost/endian/integers.hpp>

#include <cstdio>

using namespace boost::units;
using namespace boost::endian;

int main()
{
     typedef quantity<si::length, int> QI;
     typedef quantity<si::length, big32_t> QB;
     typedef quantity<si::length, little32_t> QL;

     QI qi(0x11223344 * si::meters);
     QL ql(0x22334455 * si::meters);
     QB qb(0x33445566 * si::meters);

     printf("%08x (qi)\n", *((int*)(&qi)));
     printf("%08x (ql)\n", *((int*)(&ql)));
     printf("%08x (qb)\n", *((int*)(&qb)));

     qi = ql;
     printf("%08x (qi=ql)\n", *((int*)(&qi)));

     qi = qb;
     printf("%08x (qi=qb)\n", *((int*)(&qi)));

     // These:
     // qb = qi;
     // ql = qi;
     //
     // don't work because the following fail:
     // BOOST_STATIC_ASSERT((
     // boost::is_convertible<int, big32_t>::value == true));
     // BOOST_STATIC_ASSERT((
     // boost::is_convertible<int, little32_t>::value == true))
     //
     // Likewise for qb=ql and ql=qb;
     //
     // To write to endian types, you have to use the much more clunky:

     ql = QL(qb.value() * si::meters);
     printf("%08x (ql=qb)\n", *((int*)(&qi)));
}

On a little endian machine, the above should produce:

11223344 (qi)
22334455 (ql)
66554433 (qb)
22334455 (qi=ql)
33445566 (qi=qb)
33445566 (ql=qb)

Note that if the endian types supported something like:

    big32_t x = 0x11223344;

Then all the failed cases would work as well. Beman, if you're reading
this, do you consider the above dangerous and prefer requiring the
explicit conversion (i.e. big32_t x = big32_t(0x11223344)), or is adding
support for implicit conversion something that you wouldn't find
objectionable?


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk