carcassonne has asked for the wisdom of the Perl Monks concerning the following question:

Dear monks,

Is there a way to give names to bits as in a byte bit field whose every bit would have a meaning that could be set by a subroutine, like:

setStatus(powerOn);

... which would set the powerOn bit in a 8-bit status byte. This bit could be the first one, bit 0. Then we could have:

setStatus(lightOn);

Which would set another status bit in the same status byte while not modifying the other set/unset bits. So on so forth.

Is there some kind of enum type in Perl to do that ? Or can it be done using a hash ?

Thanks.

Replies are listed 'Best First'.
Re: Giving names to bits
by Tanktalus (Canon) on Feb 23, 2007 at 03:11 UTC

    A bit of creativity with constant and vec would probably be the way I'd go about it if I wanted precisely the code you had. More likely, though, would be that I'd take strings, and convert to a number in a hash, and then use vec. More likely still, I'd just leave everything as a hash (yeah, waste a lot of memory), and then pack it all together at the last minute when I actually had to send it somewhere in binary format (if such a requirement was actually there). No, I don't concern myself with memory too much these days.

    Example 1:

    use constant powerOn => 0; use constant lightOn => 1; { my $status; sub setStatus { my $bit = shift; vec($status, $bit, 1) = 1; } sub resetStatus { my $bit = shift; vec($status, $bit, 1) = 0; } sub getStatus { my $bit = shift; vec($status, $bit, 1); } }
    Example 2:
    { my $status; my %types = ( powerOn => 0, lightOn => 1 ); sub _bit { if (exists $types{$_[0]}) { $types{$_[0]} } else { die "Unk +nown bit $_[0]"} } sub setStatus { my $bit = _bit(shift); vec($status, $bit, 1) = 1; } # etc. } # call as... setStatus('powerOn');
    I don't think the last one needs an example.

    Update: missing close-brace, as pointed out by fenLisesi.

      Thanks, that works great. The only thing to do there was to initially set the status to 0 (so that vec and by ricochet logic does not complain) and then to add the actual hash set/unset to each subroutine so that it's possible to use the hash for showing the status of the individual bits easily.

      Since a hash is used, wouldn't it be possible to simply use it and let go of the $status variable i.e. when time to do so, to pack the hash 1/0 values in a byte ?

        Serves me right... that was my last option, the one I didn't give an example for ;-)

Re: Giving names to bits
by Zaxo (Archbishop) on Feb 23, 2007 at 03:14 UTC

    The vec function is an lvalue, as well as possessing a setter form, so you can set bitfields with it.

    Added: I was going to add an example, but Tanktalus++ beat me to it.

    After Compline,
    Zaxo

Re: Giving names to bits
by varian (Chaplain) on Feb 23, 2007 at 09:15 UTC
    You could trick Perl a bit by passing the status identifiers as if they were subroutine names. It looks cool yet requires that you turn off strict on subs:
    #!/usr/bin/perl use warnings; use strict; no strict "subs"; my $Status=0; # holds bitwise status sub SetStatus{ my (@bits) = @_; my %StatusBits= ( PowerOn=>1, LightOn =>2, TurboOn=>4 ); $Status |= $StatusBits{$_} foreach (@bits); } SetStatus(PowerOn,TurboOn); print "status = $Status \n";