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

I converting a peice of C source to Perl. The C has the following construct

switch(len) { case 11: c+=((unsigned int)k[10]<<24); case 10: c+=((unsigned int)k[9]<<16); case 9 : c+=((unsigned int)k[8]<<8); case 8 : b+=((unsigned int)k[7]<<24); case 7 : b+=((unsigned int)k[6]<<16); case 6 : b+=((unsigned int)k[5]<<8); case 5 : b+=k[4]; case 4 : a+=((unsigned int)k[3]<<24); case 3 : a+=((unsigned int)k[2]<<16); case 2 : a+=((unsigned int)k[1]<<8); case 1 : a+=k[0]; /* case 0: nothing left to add */ }

I've elected (for now) to translate this as

goto "LAST".$len; LAST11: $c+= $k[10] <<24; LAST10: $c+= $k[9] <<16; LAST9: $c+= $k[8] <<8; LAST8: $b+= $k[7] <<24; LAST7: $b+= $k[6] <<16; LAST6: $b+= $k[5] <<8; LAST5: $b+= $k[4]; LAST4: $a+= $k[3] <<24; LAST3: $a+= $k[2] <<16; LAST2: $a+= $k[1] <<8; LAST1: $a+= $k[0]; LAST0:

Any offers for a better translation?


Examine what is said, not who speaks.

The 7th Rule of perl club is -- pearl clubs are easily damaged. Use a diamond club instead.

Title edit by tye, see Eek! goto? instead

Replies are listed 'Best First'.
Re: Eek! goto?
by tachyon (Chancellor) on Feb 12, 2003 at 00:18 UTC

    Yukfoo source, what is it for? This is still pretty ugly, possibly easier to understand (but that is arguable), and has the same fall through behaviour. You could map to a string and use eval but that is even more evil than goto....

    my %dispatch = ( 11 => sub{ $c+=$k[10]<<24 }, 10 => sub{ $c+=$k[9] <<16 }, 9 => sub{ $c+=$k[8] <<8 }, 8 => sub{ $b+=$k[7] <<24 }, 7 => sub{ $b+=$k[6] <<16 }, 6 => sub{ $b+=$k[5] <<8 }, 5 => sub{ $b+=$k[4] }, 4 => sub{ $a+=$k[3] <<24 }, 3 => sub{ $a+=$k[2] <<16 }, 2 => sub{ $a+=$k[1] <<8 }, 1 => sub{ $a+=$k[0] } ); &{$dispatch{$_}} for reverse 1..$len;

    cheers

    tachyon

    s&&rsenoyhcatreve&&&s&n.+t&"$'$`$\"$\&"&ee&&y&srve&&d&&print

      Its a hashing algorithm.

      I like the lateral thinking of the reverse, but unless I make $a,$b,$c and @k globals, the additional cost of parameters is a pain.


      Examine what is said, not who speaks.

      The 7th Rule of perl club is -- pearl clubs are easily damaged. Use a diamond club instead.

        ??? - The vars don't need to be any more global than with the goto solution. The reverse 1..10 comes in handy seeing you can't have 10..1 which would be much prettier.

        { my $a; my $var = sub{ $a = 'OK?' }; &$var; print $a }

        cheers

        tachyon

        s&&rsenoyhcatreve&&&s&n.+t&"$'$`$\"$\&"&ee&&y&srve&&d&&print

Re: Eek! goto?
by djantzen (Priest) on Feb 11, 2003 at 23:45 UTC

    This is the construct I generally use, although TheDamian's new switch module is probably better overall.

    SWITCH: for ($num) { /11/ && do { $c += $k[10] << 24; last SWITCH; }; /10/ && do { $c += $k[9] << 16; last SWITCH; }; # ...and so forth. # Default action. }

    "The dead do not recognize context" -- Kai, Lexx

      That doesn't quite work. There are no breasks in the original, it falls through all cases below the starting point. Other than decrementing $num and getting into a !$num tests loops, I can't see how to convert that?


      Examine what is said, not who speaks.

      The 7th Rule of perl club is -- pearl clubs are easily damaged. Use a diamond club instead.

        Oh, okay. Replace last SWITCH with $num-- and goto SWITCH or merely $num-- and you'll fall through.
        "The dead do not recognize context" -- Kai, Lexx
Re: Eek! goto?
by jdporter (Paladin) on Mar 24, 2003 at 06:58 UTC
    # given that @abc[0,1,2] correspond to the C vars a, b, and c, respe +ctively. my $i = $len-1; my $s = $len; $s <= 8 and $s--; $abc[$i/4] += $k[$i] << (($s%4)*8); # or, if you want to be too clever: $abc[$i>>2] += $k[$i] << (($s&3)<<3);

    jdporter
    The 6th Rule of Perl Club is -- There is no Rule #6.

      Erm. Did you omit the loop?


      Examine what is said, not who speaks.
      1) When a distinguished but elderly scientist states that something is possible, he is almost certainly right. When he states that something is impossible, he is very probably wrong.
      2) The only way of discovering the limits of the possible is to venture a little way past them into the impossible
      3) Any sufficiently advanced technology is indistinguishable from magic.
      Arthur C. Clarke.
        Yes. You're referring to the loop my code should have had in order to duplicate the action of the original code, not the loop present in the original code (because there wasn't one!).

        jdporter
        The 6th Rule of Perl Club is -- There is no Rule #6.

Re: Eek! goto?
by Aristotle (Chancellor) on Feb 19, 2003 at 12:32 UTC
    $k is not manipulated during the course of that block, and all operations are additions, with which order does not matter. So you could reverse the order of operations and bail early from the block upon a counter reaching $len, rather than skip the first 11-$len instructions.
    { last if $len == 0; $a+= $k[0]; last if $len == 1; $a+= $k[1] <<8; last if $len == 2; $a+= $k[2] <<16; last if $len == 3; $a+= $k[3] <<24; last if $len == 4; $b+= $k[4]; last if $len == 5; $b+= $k[5] <<8; last if $len == 6; $b+= $k[6] <<16; last if $len == 7; $b+= $k[7] <<24; last if $len == 8; $c+= $k[8] <<8; last if $len == 9; $c+= $k[9] <<16; last if $len == 10; $c+= $k[10] <<24; }
    Admittedly very redundant and not very graceful. Let's look at this another way: you have a basically data driven design here: the target and shift factor depends on the index. So not write it that way?
    my @targ_shift = ( [ \$a, 0 ], [ \$a, 8 ], [ \$a, 16 ], [ \$a, 24 ], [ \$b, 0 ], [ \$b, 8 ], [ \$b, 16 ], [ \$b, 24 ], [ \$c, 8 ], [ \$c, 16 ], [ \$c, 24 ], ); for my $idx (0 .. $len-1) { my ($targ, $shift) = @{$targ_shift[$idx]}; $$targ += $k[$idx] << $shift; }
    or maybe
    { my @targ_shift = ( \$a, 0, \$a, 8, \$a, 16, \$a, 24, \$b, 0, \$b, 8, \$b, 16, \$b, 24, \$c, 8, \$c, 16, \$c, 24, ); for (0 .. $len-1) { my ($targ, $shift) = splice @targ_shift, 0, 2; $$targ += $k[$_] << $shift; } }
    "Capture regularities in code, irregularities in data", the koan of the senior programmer as merlyn so aptly put it.

    Makeshifts last the longest.

      Your first one is essentially similar to demerphq's suggestion at Re: Eek! goto?--which you quite possibly didn't see as I managed to create two root nodes that despite my considering one for deletion, both continue existing.

      The other two are neat, but do you need splice in the latter? Wouldn't this work?

      for (0 .. $len-1) { $$targ_shift[$_] += $k[$targ_shift[$_+1]] << $shift; }

      The downside is speed. If you look at the original C-code you'll see that the whole reason for the switch was to allow a loop to be unwound for performance reasons. In the end, pfaut's realisation that basically the code is unpacking an unsigned long int which lead to the sub hash2() as shown at Re: Re: Eek! goto? using unpack. It came out hands-down winner for performance and I went with that in the end.


      Examine what is said, not who speaks.

      The 7th Rule of perl club is -- pearl clubs are easily damaged. Use a diamond club instead.

        Well no, it would be
        for (0 .. $len-1) { $$targ_shift[$_*2] += $k[$_] << $targ_shift[$_*2+1]; }

        Makeshifts last the longest.

Re: Eek! goto?
by Juerd (Abbot) on Feb 11, 2003 at 23:46 UTC

      And replace 12 lines with approx. 500+ lines (excluding pod) that includes (amongst others) this line:

      $text .= "{ while (1) $code continue { goto C_A_S_E_$casecounter } las +t S_W_I_T_C_H; C_A_S_E_$casecounter: }";

      just to hide a goto?


      Examine what is said, not who speaks.

      The 7th Rule of perl club is -- pearl clubs are easily damaged. Use a diamond club instead.

        Very good point. I also am not too fond of source filters either.

        -Lee

        "To be civilized is to deny one's nature."