in reply to Re: Bit string manipulation made easy with Bit::Manip
in thread Bit string manipulation made easy with Bit::Manip

I've done a mock up of what I think you're after. The function that handles the out of order sequence is bit_set_seq() below, and the one that'll handle missing bits (and leave them as is) is bit_set_skip(). Let me know if the output is what you expected. The implementation details aren't really relevant right now, as I just wanted to ensure the output was correct before I made it better.

use warnings; use strict; use feature 'say'; use Bit::Manip qw(:all); # out of order sequence for (0..11){ bit_set_seq(0x00, [3, 1, 2, 0], $_); } # skip over for (0..11){ my $b = $_; $b = bit_on($b, 1); $b = bit_on($b, 2); bit_set_skip($b, [0, 3], $_); } sub bit_set_seq { my ($b, $seq, $val) = @_; my $lsb = (sort @$seq)[0]; my $msb = (sort @$seq)[-1]; my $nbits = ($msb - $lsb); $b = bit_set($b, $lsb, $nbits, $val); say "** $val"; printf("seq before: %b\n", $b); my $x = $b; for (0..$nbits){ my $o = bit_get($b, $_, $_); my $s = bit_get($b, $seq->[$_], $seq->[$_]); if ($o != $s){ $x = bit_set($x, $_, 1, $s); } } printf("seq after %b\n\n", $x); } sub bit_set_skip { my ($b, $seq, $val) = @_; my $lsb = (sort @$seq)[0]; my $msb = (sort @$seq)[-1]; my @leave_bits = map $seq->[$_-1]+1..$seq->[$_]-1, 1..@$seq-1; my %leave_vals = map {$_ => bit_get($b, $_, $_)} @leave_bits; my $nbits = ($msb - $lsb) + 1; $b = bit_set($b, $lsb, $nbits, $val); say "** $val"; printf("skip before: %b\n", $b); for (keys %leave_vals){ $b = bit_set($b, $_, 1, $leave_vals{$_}); } printf("skip after: %b\n\n", $b); }

output:

** 0 seq before: 0 seq after 0 ** 1 seq before: 1 seq after 1000 ** 2 seq before: 10 seq after 10 ** 3 seq before: 11 seq after 1010 ** 4 seq before: 100 seq after 100 ** 5 seq before: 101 seq after 1100 ** 6 seq before: 110 seq after 110 ** 7 seq before: 111 seq after 1110 ** 8 seq before: 1000 seq after 1 ** 9 seq before: 1001 seq after 1001 ** 10 seq before: 1010 seq after 11 ** 11 seq before: 1011 seq after 1011 ** 0 skip before: 0 skip after: 110 ** 1 skip before: 1 skip after: 111 ** 2 skip before: 10 skip after: 110 ** 3 skip before: 11 skip after: 111 ** 4 skip before: 100 skip after: 110 ** 5 skip before: 101 skip after: 111 ** 6 skip before: 110 skip after: 110 ** 7 skip before: 111 skip after: 111 ** 8 skip before: 1000 skip after: 1110 ** 9 skip before: 1001 skip after: 1111 ** 10 skip before: 1010 skip after: 1110 ** 11 skip before: 1011 skip after: 1111

Replies are listed 'Best First'.
Re^3: Bit string manipulation made easy with Bit::Manip
by pryrt (Abbot) on Feb 01, 2017 at 22:55 UTC

    I'm not sure I correctly interpreted your intended API on bit_set_seq(), and I know I didn't on bit_set_skip.

    For bit_set_seq(), I interpreted the index to the array-ref as the bit number of the output, and the value at that index as the bit number for the input. If you intended the other way around, my tests below should work for exp0123 and exp3210, but won't be right for exp0312. But since my tests are completely failing, there's probably something I'm missing about the way you intended it to be used.

    use Bit::Manip qw(:all); use Test::More; # out of order sequence my @exp0123 = (0..15); my @exp3210 = reverse(0..15); my @exp0312 = (0b0000,0b0001,0b0100,0b0101,0b1000,0b1001,0b1100,0b1101 +,0b0010,0b0011,0b0110,0b0111,0b1010,0b1011,0b1110,0b1111); for (0 .. 15) { is( bit_set(0x00, 2, 4, $_), $_ << 2, "nomal set, shifted up 2" ); is( bit_set_seq(0x00, [0,1,2,3], $_), $exp0123[$_], "[0,1,2,3]: I +expect bit 0 [LSB] of input to be transferred to bit 0 [LSB] of outpu +t -- ie, same order"); is( bit_set_seq(0x00, [3,2,1,0], $_), $exp3210[$_], "[3,2,1,0]: I +expect bit 3 [MSB] of input to be transferred to bit 0 [LSB] of outpu +t, in2 -> out1, in1 -> out2, in0 -> out3 -- ie, reverse the bits"); is( bit_set_seq(0x00, [0,3,1,2], $_), $exp0312[$_], "[0,3,1,2]: I +expect in0 -> out0, in3->out1, in1->out2, in2->out3"); } ... # your subs go below, not quoted here...

    For bit_set_skip, I couldn't interpret it at all... What I would want would be a feature where I could put arbitrary gaps, for example, $out = bit_set_skip( $in, $seq, $val ). I would want to break $val into chunks based on seq, and put it into $in to create out. For this table: K means "keep the same bit value as in input", whereas a 1 or 0 means that I want that value there, regardless of what was originally in INPUT. I couldn't figure out the $seq necessary to do this, but below my table is the API I would have guessed to set this...

    # INPUT VAL DESIRED OUTPUT # 0bKKKK_KKKK 0b0000_0000 0bKKK0_K000 # 0bKKKK_KKKK 0b0000_0001 0bKKK0_K001 # 0bKKKK_KKKK 0b0000_0010 0bKKK0_K010 # 0bKKKK_KKKK 0b0000_0011 0bKKK0_K011 # 0bKKKK_KKKK 0b0000_0100 0bKKK0_K100 # 0bKKKK_KKKK 0b0000_0101 0bKKK0_K101 # 0bKKKK_KKKK 0b0000_0110 0bKKK0_K110 # 0bKKKK_KKKK 0b0000_0111 0bKKK0_K111 # 0bKKKK_KKKK 0b0000_1000 0bKKK1_K000 # 0bKKKK_KKKK 0b0000_1001 0bKKK1_K001 # 0bKKKK_KKKK 0b0000_1010 0bKKK1_K010 # 0bKKKK_KKKK 0b0000_1011 0bKKK1_K011 # 0bKKKK_KKKK 0b0000_1100 0bKKK1_K100 # 0bKKKK_KKKK 0b0000_1101 0bKKK1_K101 # 0bKKKK_KKKK 0b0000_1110 0bKKK1_K110 # 0bKKKK_KKKK 0b0000_1111 0bKKK1_K111 for (0 .. 15) { is( bit_set_skip( 0x00, [0,1,2,4], $_), (($_ & 0x08)<<1) | (($_ & +0x07)<<0), "put a gap between the MSB and the lower three bits"); }

      I didn't quite grasp what you were after, but I think I have a bit better of an idea now. As I said, most of this stuff is new to me. Besides, I haven't run into a register with offset bits and such, so this is another new rabbit hole :)

      I'll review this and play around, and if I have questions, I'll send a /msg. Thanks!