March 20, 2006
Wolfgang Draxinger wrote:
> Walter Bright wrote:
> 
>> Add two member functions for each:
>>
>>     bool fBinary() { return BITS & 1; }
>>     bool fBinary(bool b) { BITS |= b; return b; }
>>
>>     bool fParity() { return (BITS & 2) != 0; }
>>     bool fParity(bool b) { BITS |= b << 1; return b; }
>>
>> and then, because functions work like properties, you can use
>> them as if they were properties.
> 
> These set functions won't work if b==0, since it's just an OR.
> What's needed is 
> 
> BITS = (BITS & ~(1<<n)) | b ? 1<<n : 0 ;

Or you could do

BITS = (BITS & ~(1<<n)) | (b << n) ;
to remove the need for a branch instruction.
Works just as well for multiple bits, eg for b = 0..7:
BITS = (BITS & ~(7<<n)) | (b << n) ;


I really think it would be worth adding some functions to Phobos for this sort of thing, and it should also duplicate the bit functions from
std.intrinsic. (I don't think the fact that bsr is an intrinsic should be exposed in application code. It might not be true on all processors).

I have a few functions for it in my MathExtra library.
Anyone have any ideas of what it should be called?

"std.bitops"?
"std.bitoperations"?
"std.bitmanip" ?
"std.bittwiddle" ?



March 20, 2006
Walter Bright wrote:

> Add two member functions for each:
> 
>     bool fBinary() { return BITS & 1; }
>     bool fBinary(bool b) { BITS |= b; return b; }
> 
>     bool fParity() { return (BITS & 2) != 0; }
>     bool fParity(bool b) { BITS |= b << 1; return b; }
> 
> and then, because functions work like properties, you can use them as if they were properties. 

You'll need to add some casts, though, for GDC:

"cannot implicitly convert expression (BITS & 1) of type uint to bit"

Or just change it to: return ((BITS & 1) != 0);

--anders
March 20, 2006
On Mon, 20 Mar 2006 04:14:02 -0500, Don Clugston <dac@nospam.com.au> wrote:

> Or you could do
>
> BITS = (BITS & ~(1<<n)) | (b << n) ;
> to remove the need for a branch instruction.
> Works just as well for multiple bits, eg for b = 0..7:
> BITS = (BITS & ~(7<<n)) | (b << n) ;
>
>
> I really think it would be worth adding some functions to Phobos for this sort of thing, and it should also duplicate the bit functions from std.intrinsic. (I don't think the fact that bsr is an intrinsic should be exposed in application code. It might not be true on all processors).
>

I've attached code to simplify this. Here's example usage:

struct FlagTest
{
    uint bits;

    mixin .BitFlag!(uint, bits, 0x1) foo;
    mixin .BitFlag!(uint, bits, 0x2) bar;
    mixin .BitFlag!(uint, bits, 0x4) baz;
}

FlagTest ftest;

ftest.foo.flag = true;
ftest.bar.flag = false;
ftest.baz.flag = true;

assert(ftest.bits == 0b101);
assert(ftest.foo.flag == true);
assert(ftest.bar.flag == false);
assert(ftest.baz.flag == true);


If only the name in the mixin (if matching mixin name) could be promoted to the name of the mixin identifier, it could elegantly become: ftest.foo = true; e.g.:

template Foo() { int Foo = 33; }
mixin Foo bar; // The int Foo in the template could become named bar and
allow:
assert(bar == 33);
bar = 22; // etc..


Note: the attached code would look a bit nicer if it wasn't for the digitalmars.D.bugs I just posted.

March 20, 2006
Don Clugston wrote:

> BITS = (BITS & ~(1<<n)) | (b << n) ;
> to remove the need for a branch instruction.
> Works just as well for multiple bits, eg for b = 0..7:
> BITS = (BITS & ~(7<<n)) | (b << n) ;

Yes, after posting I had the same idea. You see, I'm still thinking a lot in terms of C/C++ where it isn't gauranteed, that a boolean value of "true" also is always the LSB==1.

D is just so cool.

-- 
Wolfgang Draxinger

March 20, 2006
Wolfgang Draxinger wrote:
> Now with SDL I've encountered a problem: SDL makes use of serval bitfields and I've no idea, how to interface them to D.

I would like to make use of this thread and ask Walter why it was chosen to keep bitfields out of D. Since D has C ABI support, inline assembly, structs and unions, it seems natural to have bitfields also, to complement low-level programming capabilities and simplify interfacing with C code.

Recently I needed to parse and construct float numbers, and I had to do all this funny shift stuff in order to translate ieee754.h to a D module. The final result was ugly and also more error-prone compared to C (yes, abusing bit shifts made D code look worse than C).

Something I think that D could improve over C in this field is to take bitfields to the next step and make them endian-aware. If you look into ieee754.h, you will find something like:

union ieee754_float {
    float f;

    struct {
#if	__BYTE_ORDER == __BIG_ENDIAN
	unsigned int negative:1;
	unsigned int exponent:8;
	unsigned int mantissa:23;
#endif
#if	__BYTE_ORDER == __LITTLE_ENDIAN
	unsigned int mantissa:23;
	unsigned int exponent:8;
	unsigned int negative:1;
#endif
      } ieee;
};

This is the raw definition of an IEEE 32-bit float number. Things gets worse for 64-bit and 80-bit floats. The byte-order dependency could be abstracted by a possible D implementation of bitfields by specifying an attribute that defines if bits should be in register order or in memory order. For example:

union ieee754_float {
    float f;

    pragma(bitfield_order, register, 4)
    struct {
        uint negative:1; // most significant bits of a 32-bit register
        uint exponent:8;
        uint mantissa:23; // least significant bits of a 32-bit register
    } ieee;
};

Or, for example, when the position in memory is important (communicating with microcontrolled devices via a serial line):

union my_float {
    byte raw[4];

    pragma(bitfield_order, memory)
    struct {
        uint negative:1; // first bits in memory
        uint exponent:8;
        uint mantissa:23; // last bits in memory
    };
};

Another suggestion, not related to bitfields but related to floats, would be to add these properties (.negative, .mantissa, .exponent and .quiet_nan) to the floating-point types of D.

Best regards,
Miles.
March 21, 2006
Miles wrote:
> Wolfgang Draxinger wrote:
>> Now with SDL I've encountered a problem: SDL makes use of serval
>> bitfields and I've no idea, how to interface them to D.
> 
> I would like to make use of this thread and ask Walter why it was chosen
> to keep bitfields out of D. Since D has C ABI support, inline assembly,
> structs and unions, it seems natural to have bitfields also, to
> complement low-level programming capabilities and simplify interfacing
> with C code.
> 
> Recently I needed to parse and construct float numbers, and I had to do
> all this funny shift stuff in order to translate ieee754.h to a D
> module. The final result was ugly and also more error-prone compared to
> C (yes, abusing bit shifts made D code look worse than C).
> 
> Something I think that D could improve over C in this field is to take
> bitfields to the next step and make them endian-aware. If you look into
> ieee754.h, you will find something like:
> 
> union ieee754_float {
>     float f;
> 
>     struct {
> #if	__BYTE_ORDER == __BIG_ENDIAN
> 	unsigned int negative:1;
> 	unsigned int exponent:8;
> 	unsigned int mantissa:23;
> #endif
> #if	__BYTE_ORDER == __LITTLE_ENDIAN
> 	unsigned int mantissa:23;
> 	unsigned int exponent:8;
> 	unsigned int negative:1;
> #endif
>       } ieee;
> };
> 
> This is the raw definition of an IEEE 32-bit float number. Things gets
> worse for 64-bit and 80-bit floats. The byte-order dependency could be
> abstracted by a possible D implementation of bitfields by specifying an
> attribute that defines if bits should be in register order or in memory
> order. For example:
> 
> union ieee754_float {
>     float f;
> 
>     pragma(bitfield_order, register, 4)
>     struct {
>         uint negative:1; // most significant bits of a 32-bit register
>         uint exponent:8;
>         uint mantissa:23; // least significant bits of a 32-bit register
>     } ieee;
> };
> 
> Or, for example, when the position in memory is important (communicating
> with microcontrolled devices via a serial line):
> 
> union my_float {
>     byte raw[4];
> 
>     pragma(bitfield_order, memory)
>     struct {
>         uint negative:1; // first bits in memory
>         uint exponent:8;
>         uint mantissa:23; // last bits in memory
>     };
> };
> 
> Another suggestion, not related to bitfields but related to floats,
> would be to add these properties (.negative, .mantissa, .exponent and
> .quiet_nan) to the floating-point types of D.

I agree, that would be great, it would allow us to remove the ugly cast(char [])cast(void *).. hacks from std.math.
(It would also allow them to be accessed at compile time, which I would find very useful).
Maybe only the mantissa and exponent are required, the position of the negative bit is fixed in the exponent, isn't it?
(provided that mantissa is an integral type).

Immediate interesting application: efficiently converting random integers into a random real in the range 0..1, just by storing the int into the mantissa of a real.

March 21, 2006
Don Clugston wrote:
> Maybe only the mantissa and exponent are required, the position of the
> negative bit is fixed in the exponent, isn't it?
> (provided that mantissa is an integral type).

I don't think so. The negative bit is not part of the exponent, it is really a separate field. Perhaps you are thinking about the signalling NaN indicator, that is the highest bit of the mantissa.

But sure would be appropriate, with a little overhead, to have better cooked .exponent and .mantissa properties. Only that the user wouldn't be able to detect a negative zero.

> Immediate interesting application: efficiently converting random integers into a random real in the range 0..1, just by storing the int into the mantissa of a real.

Sure!

Too bad Walter didn't seem to notice my previous post.

Best regards.
March 22, 2006
Miles wrote:
> Don Clugston wrote:
>> Maybe only the mantissa and exponent are required, the position of the
>> negative bit is fixed in the exponent, isn't it?
>> (provided that mantissa is an integral type).
> 
> I don't think so. The negative bit is not part of the exponent, it is
> really a separate field. Perhaps you are thinking about the signalling
> NaN indicator, that is the highest bit of the mantissa.

Well, the sign bit is always adjacent to the highest bit of the exponent. I was thinking that the exponent and sign bit could be combined to make a standard-sized D type -- but this only works for 80 bit reals, not float, double, or quadruple.

> But sure would be appropriate, with a little overhead, to have better
> cooked .exponent and .mantissa properties. Only that the user wouldn't
> be able to detect a negative zero.
> 
>> Immediate interesting application: efficiently converting random
>> integers into a random real in the range 0..1, just by storing the int
>> into the mantissa of a real.
> 
> Sure!
> 
> Too bad Walter didn't seem to notice my previous post.

It's not a priority, it's something that could be added later without breaking anything -- just syntactic sugar, really. We can try again later <g>.
November 23, 2007
> It's not a priority, it's something that could be added later without breaking anything -- just syntactic sugar, really. We can try again later <g>.

Curious, Has there been any movement on this issue? Is there a less error-prone way to do this other then manual shifts and masks?

I am looking to write an open-source generic library for hardware design, I thought D would make a much better base then C++. I'm a big fan of what I've seen so far. Sorry to say, but D can't be a serious low-level contender without bitfield support.

I'm not talking about using it once or twice in a project, but thousands of structures for each project, and each structure having dozens of bitfields. Having to do masks and shifts just seems like a nightmare of bad code.

I can't imagine my friends on the firmware side (or any low-level developer) wouldn't agree.

Miles' idea of making D somehow order aware would be a huge win for this close-to-the-hardware stuff. Or even non-order aware bitfields at least isn't worse then what's allready out there.

Comments, ideas welcome.
Richard


November 23, 2007
"Richard Bradley" <darthalias@yahoo.com> wrote in message news:fi5arc$6mu$1@digitalmars.com...
> Comments, ideas welcome.
> Richard

I shall open a bottle of champagne the day we get bitfields in D!