Re: [boost] Interest in a binary_int template for binary literals?

Greetings, I wrote in part:
Prompted by some discussion on comp.sdt.c++.moderated, I have a small template that allows the user to declare an integer literal in binary.
Usage looks like:
#include "binary_int.hpp"
unsigned int binary = binary_int<1001,0011,1011,0000>::b;
Thanks for all the responses. Here are answers to some of the questions I got. ------------------------ Pavel Vozenilek asked:
* How does it deal with bit values like 0111? This is octal value.
Right. There are specilizations for decimal and octal values. This means there is some aliasing. A few non-binary decimal and octal values leak through. For example 0111 (octal) is 73 decimal and, for that matter, 0x49 hex. So the template accepts all of these values. It's not perfect, but it's the best I could figure out.
* Does it check that the digits are 0 or 1 during compile time?
It doesn't check individual digits. It checks for specific numeric values which would be good at representing a 4-bit binary value. See the binary_nibble specializations in the appended code.
* Would it work with hex values like: bits<unsigned, 0xF,0x8>::value;
No, not as it is currently implemented. ------------------------ Vladimir Prus responded:
Why is that better than
unsigned x = strtoul("1010010001000010000001", 0, 2);
? I believe that 'strtoul' is part of C99.
Not a bad approach. The binary_int template does the translation at compile time rather than at run time. It does the check (as best it can) for valid binary values at compile time as well. ----------------------- Paul A Bristow replied:
Can you post reference to discussion...
I'm not very clever with URLs but the discussion, according to Google Groups, was titled "Power of 2 Enumerations" in comp.std.c++. The discussion in question started with a post by David Abrahams on November 1st, 2004 where he wrote:
You can even write a simple template that makes these into compile-time constants:
const feature_t FEATURE1 = binary<001>::value; const feature_t FEATURE2 = binary<010>::value; const feature_t FEATURE3 = binary<100>::value;
Paul also asked:
and perhaps append the binary_int.hpp file as it sounds quite short?
Yes, the template is only 150 lines or so including comments. I've appended it, in its current state, to the end of this response. I did some editing of the template in an attempt to make it boost compatible, although I didn't put it in the Boost name space. Even though it says it's a boost file, I'm fully aware that it isn't. Sorry about that. Thanks for everyone's attention. Scott Schurr binary_int.hpp -------------------------------------------------------------- // Boost general library binary_int.hpp header file -------------------------// // Copyright Credence Systems 2005, as submitted by Scott Schurr. Use, // modification, and distribution are subject to 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_BINARY_INT_HPP #define BOOST_BINARY_INT_HPP // Make a couple of templates to help catch bad binary_nibble parameters template <bool> struct binary_nibble_VALID_VALUES_BINARY_0000_THROUGH_1111; template <> struct binary_nibble_VALID_VALUES_BINARY_0000_THROUGH_1111<true> { }; // Write a 4-bit integer value as binary. // // Usage: // unsigned int n = binary_nibble<1011>::b // // The tricky part is remembering to include the '::b' at the end. // For example: // // #include "binary_int.h" // ... // int regValue = binary_nibble<1001>::b; // // Make a general binary_nibble type that causes a failure. Only // the specializations are valid usages. template <unsigned int v> struct binary_nibble { binary_nibble_VALID_VALUES_BINARY_0000_THROUGH_1111<false> t; enum { b = 0 }; }; // Specialize the binary_nibble template for values we allow. // The following values work for both decimal and octal. template<> struct binary_nibble<0> { enum { b = 0x0 }; }; template<> struct binary_nibble<1> { enum { b = 0x1 }; }; // Decimal values. template<> struct binary_nibble<10> { enum { b = 0x2 }; }; template<> struct binary_nibble<11> { enum { b = 0x3 }; }; template<> struct binary_nibble<100> { enum { b = 0x4 }; }; template<> struct binary_nibble<101> { enum { b = 0x5 }; }; template<> struct binary_nibble<110> { enum { b = 0x6 }; }; template<> struct binary_nibble<111> { enum { b = 0x7 }; }; template<> struct binary_nibble<1000> { enum { b = 0x8 }; }; template<> struct binary_nibble<1001> { enum { b = 0x9 }; }; template<> struct binary_nibble<1010> { enum { b = 0xA }; }; template<> struct binary_nibble<1011> { enum { b = 0xB }; }; template<> struct binary_nibble<1100> { enum { b = 0xC }; }; template<> struct binary_nibble<1101> { enum { b = 0xD }; }; template<> struct binary_nibble<1110> { enum { b = 0xE }; }; template<> struct binary_nibble<1111> { enum { b = 0xF }; }; // Octal values. template<> struct binary_nibble<010> { enum { b = 0x2 }; }; template<> struct binary_nibble<011> { enum { b = 0x3 }; }; template<> struct binary_nibble<0100> { enum { b = 0x4 }; }; template<> struct binary_nibble<0101> { enum { b = 0x5 }; }; template<> struct binary_nibble<0110> { enum { b = 0x6 }; }; template<> struct binary_nibble<0111> { enum { b = 0x7 }; }; // The following helper template determines the behavior of the // binary_int template when default arguments are passed in. // A default argument (0ul-1) will leave the previously calculated // value unchanged. A non-default argument multiplies the previously // calculated value by 16 and adds in the new (non-default) argument. template<unsigned int v> struct binary_int_arg { enum { b = binary_nibble<v>::b, mul = 16, }; }; template<> struct binary_int_arg<0ul-1> { enum { b = 0, mul = 1, }; }; // Declare a binary value in the following form: // // int i = binary_int<1100,1010,0001>::b // // Usage: // // unsigned int = binary_int<up to 16 binary_nibble>::b // // Write an integer as a binary value composed of up to 16 nibbles. // The tricky part is remembering to include the '::b' at the end. // For example: // // #include "binary_int.h" // ... // int regValue = binary_int<1000,1001,0011,0000>::b; // // One to 16 nibble-sized arguments are allowed, which allows for word // lengths up to 64 bits. If it's not working for you make sure that // you are including the closing '::b'. template<unsigned int b15, unsigned int b14 = 0ul-1, unsigned int b13 = 0ul-1, unsigned int b12 = 0ul-1, unsigned int b11 = 0ul-1, unsigned int b10 = 0ul-1, unsigned int b9 = 0ul-1, unsigned int b8 = 0ul-1, unsigned int b7 = 0ul-1, unsigned int b6 = 0ul-1, unsigned int b5 = 0ul-1, unsigned int b4 = 0ul-1, unsigned int b3 = 0ul-1, unsigned int b2 = 0ul-1, unsigned int b1 = 0ul-1, unsigned int b0 = 0ul-1> struct binary_int { private: enum { v15_ = binary_int_arg<b15>::b, v14_ = (v15_ * binary_int_arg<b14>::mul) + binary_int_arg<b14>::b, v13_ = (v14_ * binary_int_arg<b13>::mul) + binary_int_arg<b13>::b, v12_ = (v13_ * binary_int_arg<b12>::mul) + binary_int_arg<b12>::b, v11_ = (v12_ * binary_int_arg<b11>::mul) + binary_int_arg<b11>::b, v10_ = (v11_ * binary_int_arg<b10>::mul) + binary_int_arg<b10>::b, v9_ = (v10_ * binary_int_arg<b9>::mul) + binary_int_arg<b9>::b, v8_ = (v9_ * binary_int_arg<b8>::mul) + binary_int_arg<b8>::b, v7_ = (v8_ * binary_int_arg<b7>::mul) + binary_int_arg<b7>::b, v6_ = (v7_ * binary_int_arg<b6>::mul) + binary_int_arg<b6>::b, v5_ = (v6_ * binary_int_arg<b5>::mul) + binary_int_arg<b5>::b, v4_ = (v5_ * binary_int_arg<b4>::mul) + binary_int_arg<b4>::b, v3_ = (v4_ * binary_int_arg<b3>::mul) + binary_int_arg<b3>::b, v2_ = (v3_ * binary_int_arg<b2>::mul) + binary_int_arg<b2>::b, v1_ = (v2_ * binary_int_arg<b1>::mul) + binary_int_arg<b1>::b, v0_ = (v1_ * binary_int_arg<b0>::mul) + binary_int_arg<b0>::b, }; public: enum { b = v0_ }; }; #endif // BOOST_BINARY_INT_HPP

Scott Schurr <scott_schurr@credence.com> writes:
* How does it deal with bit values like 0111? This is octal value.
Right. There are specilizations for decimal and octal values. This means there is some aliasing. A few non-binary decimal and octal values leak through. For example 0111 (octal) is 73 decimal and, for that matter, 0x49 hex. So the template accepts all of these values. It's not perfect, but it's the best I could figure out.
I think the answer is confusing. I don't know what "aliasing" means in this case, but: aside from zero, the decimal numerals containing all 1s and 0s have distinct values from the octal numerals containing all 1s and 0s, at least up to something like 16 bits. There's no ambiguity. -- Dave Abrahams Boost Consulting www.boost-consulting.com

At 10:21 AM -0400 7/14/05, David Abrahams wrote:
Scott Schurr <scott_schurr@credence.com> writes:
There are specilizations for decimal and octal values. This means there is some aliasing. ...
I think the answer is confusing. I don't know what "aliasing" means in this case, ...
With the proposed implementation, I believe all of the following have a value of 7: binary_int<0111>::b binary_int<73>::b binary_int<0x49>::b That's presumably what was meant by "there is some aliasing". Doesn't seem like a particularly serious problem though.

| -----Original Message----- | From: boost-bounces@lists.boost.org | [mailto:boost-bounces@lists.boost.org] On Behalf Of Scott Schurr | Sent: 13 July 2005 19:13 | To: boost@lists.boost.org | Subject: Re: [boost] Interest in a binary_int template for | binary literals? | ----------------------- | Paul A Bristow replied: | | > and perhaps append the binary_int.hpp file Thanks. | I did some editing of the template in an attempt to make it | boost compatible, although I didn't put it in the Boost name | space. Even though it says it's a boost file, I'm fully aware | that it isn't. Sorry about that. There is no problem about it using Boost licence, but my understanding of some resent discussion is that it is considered good form to include something like 'candidate' or 'submitted to' to show that it has not yet emerged from the intense light (and heat) and of concerted Boosters scrutiny. This seems quite neat and a welcome workaround for the lack of a proper binary (Ada's any power seems a bit overkill - anyone seriously missing base 7, base 13? But its separators are shown to be useful here). But have there been no proposals for a language solution in C++0X? 0b1010? Is this for lack of a , or other separator between the groups of 1010s? Paul Paul A Bristow Prizet Farmhouse, Kendal, Cumbria UK LA8 8AB +44 1539 561830 +44 7714 330204 mailto: pbristow@hetp.u-net.com
participants (4)
-
David Abrahams
-
Kim Barrett
-
Paul A Bristow
-
Scott Schurr