[Review] Boost.Endian - template requirements and scope

Hi, I have not found the requiremenst of the endian class template parapeter T and conversion functions. What are they? Could them be added to the documentation? I have not found a tutorial on how to use the endian conversions. Could you give an example that shows how easy is to use them with UDT? Collections of UDT? Could the user overload the conversion functions for UDT? While the predefined endian types are useful I guess that the user could instantiate the endian class with a UDT, isn't it? Could you post a working example and add it to the documentation? The scope of Boost.Endian is integer types. Aren't floating point types and endianness related? If the scope of the library is limited to integers, maybe Integer.Endian could be a better name? Best, Vicente

Le 06/09/11 21:39, Vicente J. Botet Escriba a écrit :
Hi,
I have not found the requiremenst of the endian class template parapeter T and conversion functions. What are they? Could them be added to the documentation?
I have not found a tutorial on how to use the endian conversions. Could you give an example that shows how easy is to use them with UDT? Collections of UDT?
Could the user overload the conversion functions for UDT?
Collections, Tuples, arrays? Best, Vicente

On Tue, Sep 6, 2011 at 3:39 PM, Vicente J. Botet Escriba <vicente.botet@wanadoo.fr> wrote:
Hi,
I have not found the requiremenst of the endian class template parapeter T and conversion functions. What are they?
For class endian, T must be an signed or unsigned integer type. See 3.9.1. A UDT that provided the same operations would work, but I'm no sure that it is possible to write such a class. Support for promotion might be difficult, for example. Since I know of no real-world use cases for UDT's, I don't want to waste a lot of time trying to determine if they work or not. If we had concepts it would be a different story, but that's water over the dam. For the conversion functions, the answer is more up-in-the-air. In light of comments received, there may be some interface churn with these functions.
Could them be added to the documentation?
Definitely. Added to do-list.
I have not found a tutorial on how to use the endian conversions. Could you give an example that shows how easy is to use them with UDT? Collections of UDT?
They weren't designed with UDT's in mind, but there are likely to be only a few requirements, and those requirements could probably be met by a UDT.
Could the user overload the conversion functions for UDT?
While the predefined endian types are useful I guess that the user could instantiate the endian class with a UDT, isn't it? Could you post a working example and add it to the documentation?
See above. I really want to see real-world use cases before putting in any effort.
The scope of Boost.Endian is integer types. Aren't floating point types and endianness related? If the scope of the library is limited to integers, maybe Integer.Endian could be a better name?
That was the original plan, but I found it easier to not try to integrate with the stuff that is already in integer. No big thing one way or the other. Good questions - thanks, --Beman

Le 07/09/11 21:17, Beman Dawes a écrit :
On Tue, Sep 6, 2011 at 3:39 PM, Vicente J. Botet Escriba <vicente.botet@wanadoo.fr> wrote:
Hi,
I have not found the requiremenst of the endian class template parapeter T and conversion functions. What are they? For class endian, T must be an signed or unsigned integer type. See 3.9.1. A UDT that provided the same operations would work, but I'm no sure that it is possible to write such a class. Support for promotion might be difficult, for example. Since I know of no real-world use cases for UDT's, I don't want to waste a lot of time trying to determine if they work or not. If we had concepts it would be a different story, but that's water over the dam. I was thinking for example to a integer range class or a value constrained interger class.
What about enums? Could we use enums as underlying type of boost::endian<>?
For the conversion functions, the answer is more up-in-the-air. In light of comments received, there may be some interface churn with these functions.
Could them be added to the documentation? Definitely. Added to do-list.
I have not found a tutorial on how to use the endian conversions. Could you give an example that shows how easy is to use them with UDT? Collections of UDT? They weren't designed with UDT's in mind, but there are likely to be only a few requirements, and those requirements could probably be met by a UDT. My question was if you can add an example of a UDT that needs to be converted from native to the network endian. For example
struct IpHeader { uint8_t versionHeaderLength; // big uint8_t differentiated_services; // big uint16_t total_length; // big ///////////////////////////// uint16_t identification; //big uint16_t flags_frag; // big ///////////////////////////// uint8_t time_to_live; // big uint8_t protocol; // big uint16_t header_checksum; // big ///////////////////////////// uint32_t source_address; // big ///////////////////////////// uint32_t destination_address; // big }; // IpHeader struct UdpHeader { uint16_t source_port; // big uint16_t destination_port; // big uint16_t length; // big uint16_t checksum; // big }; // UdpHeader struct UserMessage { system_clock::time_point timestamp; // little uint32_t aircraft_id; // little struct Position { // little quantity<si::length, boost::int_least32_t> x; // little quantity<si::length, boost::int_least32_t> y; // little quantity<si::length, boost::int_least32_t> z; // little } position; struct Attitude { quantity<si::plane_angle, boost::int_least8_t> heading; // little quantity<si::plane_angle, boost::int_least8_t> pitch; // little quantity<si::plane_angle, boost::int_least8_t> roll; // little } attitude; }; // UserMessage struct Packet { IpHeader ipHeader; UdpHeader udpHeader; UserMessage userMessage; }; // Packet
Could the user overload the conversion functions for UDT?
While the predefined endian types are useful I guess that the user could instantiate the endian class with a UDT, isn't it? Could you post a working example and add it to the documentation? See above. I really want to see real-world use cases before putting in any effort. Showing how we can manage with concrete examples as the preceding one could show if the interface is good for the every day user work.
The scope of Boost.Endian is integer types. Aren't floating point types and endianness related? If the scope of the library is limited to integers, maybe Integer.Endian could be a better name? That was the original plan, but I found it easier to not try to integrate with the stuff that is already in integer. No big thing one way or the other.
Maybe you can add some words in the documentation that describe more preciselly the scope. Best, Vicente

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?

Le 10/09/11 05:07, John Filo a écrit :
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?
You are right. C++03 enums doesn't allows to specify the underlying type.
Scoped enums in C++0x, with their ability to specify the underlying type, seems much more usable.
Beman, what could be the best way to use C++11 scoped enums and endiannes?
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.
No, of course. The parameter should be a model of an integer type with sizeof a sizeof managed by boost::endian. I give already give some cases, for example, what If I recover a specific range/interval class from a 3rd party such as *month* that constraints the values to 1..12 that fix internally the underlying type to int16_t. Could I be able to month as underlying type if month is POD? endian<...., month> If not, does it means that I need to create a template class that behaves as the 3rd party month class but that allows to specify the underlying type? Beman, do you think that such an example could show how the endian class could be used when you have UDT that behaves *like an integer* ?
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.
This is the correct way to use it when you are working with templates that have as parameter the underlying type. I use it when I want Boost.Bitfield to be endian-safe. I think just that it will be great if examples as the preceding one that show interaction with Boost.Chrono, Boost::Units could be added to a tutorial. Best, Vicente
participants (3)
-
Beman Dawes
-
John Filo
-
Vicente J. Botet Escriba