| Class-Bits documentation | Contained in the Class-Bits distribution. |
Class::Bits - Class wrappers around bit vectors
package MyClass;
use Class::Bits;
make_bits( a => 4, # 0..15
b => 1, # 0..1
c => 1, # 0..1
d => 2, # 0..3
e => s4 # -8..7
f => s1 # -1..0
);
package;
$o=MyClass->new(a=>12, d=>2);
print "o->b is ", $o->b, "\n";
print "bit vector is ", unpack("h*", $$o), "\n";
$o2=$o->new();
$o3=MyClass->new($string);
Class::Bits creates class wrappers around bit vectors.
Class::Bits defines classes using bit vectors as storage.
Object attributes are stored in bit fields inside the bit vector. Bit field sizes have to be powers of 2 (1, 2, 4, 8, 16 or 32).
There is a class constructor subroutine:
exports in the calling package a ctor, accessor methods, some utility methods and some constants:
Sizes can be prefixed by s or u to define signedness of the
field. Default is unsigned.
creates a new object with all zeros.
creates a new object over $bitvector.
creates a new object and initializes its fields with the values in
%fields.
clones an object.
gets or sets the value of the bit field $field inside the bit vector.
returns the size in bits of the bit vector used for storage.
returns an array with the names of the object attributes
returns a flatten hash with the object attributes, i.e.:
my %values=$obj->as_hash;
hash with offsets as used by vec perl operator (to get an offset in
bits, the value has to be multiplied by the corresponding bit field
size).
hash with bit field sizes in bits.
hash with signedness of the fields
Bit fields are packed in the bit vector in the order specified as
arguments to make_bits.
Bit fields are padded inside the bit vector, i.e. a class created like
make_bits(A=>1, B=>2, C=>1, D=>4, E=>8, F=>16);
will have the layout
AxBBCxxx DDDDxxxx EEEEEEEE xxxxxxxx FFFFFFFF FFFFFFFF
make_bits
vec in perlfunc, Class::Struct
Salvador Fandiņo, <sfandino@yahoo.com>
Copyright 2003 by Salvador Fandiņo
This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
| Class-Bits documentation | Contained in the Class-Bits distribution. |
package Class::Bits; use 5.006; our $VERSION = '0.05'; # use strict; use warnings::register; use warnings (); use integer; require Exporter; our @ISA = qw(Exporter); our @EXPORT = qw(make_bits); use Carp; use Config; use constant nvsize => $Config{nvsize}*8; my %umax = ( 1 => 1, 2 => 3, 4 => 15, 8 => 255, 16 => 65535, 32 => 4294967295 ); my %smax = ( 1 => 0, 2 => 1, 4 => 7, 8 => 127, 16 => 32767, 32 => 2147483647 ); my %smin = ( 1 => -1, 2 => -2, 4 => -8, 8 => -128, 16 => -32768, 32 => -2147483648 ); my %sext = map { $_ => (~$smax{$_}) } keys(%smax); my %signed = ( 's' => 1, 'u' => 0, '' => 0 ); sub make_bits { @_ & 1 and croak 'Class::Bits::bits called with an even number of arguments'; my %names; my $offset=0; my $pkg=caller(); while(@_) { my $name=shift; exists $names{$name} and croak "repeated name '$name'"; $names{$name}=1; my $spec=shift; $spec=~/^\s*([us]?)\s*(\d+)\s*$/ or croak "invalid Class::Bits specification '$spec' for '$name'"; my $sig=$signed{$1}; my $size=$2; exists $smax{$size} or croak "invalid Class::Bits size '$size' for '$name'"; my $index=int(($offset+$size-1)/$size); $offset=($index+1)*$size; $pkg->{INDEX}{$name}=$index; $pkg->{SIZE}{$name}=$size; $pkg->{SIGNED}{$name}=$sig; # warn "$name: index=>$index, size=>$size, sig=>$sig"; if ($sig) { my $max=$smax{$size}; my $min=$smin{$size}; my $ext=$sext{$size}; *{"${pkg}::$name"}=sub { my $this=shift; if (@_) { my $value=shift; if ($value > $max or $value < $min) { warnings::warn "value $value for " .ref($this) ."::$name out of range [$min, $max]" if warnings::enabled(); } vec ($$this, $index, $size) = $value; } my $value=vec ($$this, $index, $size); if ($value & $ext) { return $ext|$value; } return $value; } } else { my $max=$umax{$size}; *{"${pkg}::$name"}=sub { my $this=shift; if (@_) { my $value=shift; if (!defined($value)) { warnings::warnif('uninitialized', "Uninitialized value passed to $name accessor"); $value=0; } warnings::warnif("value $value for ".ref($this)."::$name out of range [0, $max]") if ($value > $max or $value < 0); vec ($$this, $index, $size) = $value; } else { vec ($$this, $index, $size); } }; } } *{"${pkg}::new"}=sub { my $ref=shift; my ($class, $string); if (ref($ref)) { $class=ref($ref); $string=$$ref; } else { $class=$ref; $string="\0" x ((7+ $offset) >> 3) } $string=shift if @_ & 1; my $this=\$string; bless $this, $class; my %opts=@_; for my $k (keys %opts) { $this->$k($opts{$k}); } return $this; }; *{"${pkg}::length"}=sub { $offset } unless exists $names{lenght}; *{"${pkg}::keys"}=sub { keys %names } unless exists $names{keys}; *{"${pkg}::as_hash"}=sub { my $this=shift; map { ($_, $this->$_ ) } keys %names } unless exists $names{as_hash}; } 1; __END__