Dermot wrote:
Hi All,

Hello,

I have been trying to write this email for a day or two but the
content keeps shifting as my understanding of the problem develops.

I have encountered a bit of code that I am struggling to understand
completely. The code is for dealing with database fields that are
bigint(20) type.

| allowcountry1       | bigint(20)              | NO   |     | -1
   |       |
| allowcountry2       | bigint(20)              | NO   |     | -1
   |       |
| allowcountry3       | bigint(20)              | NO   |     | -1
   |       |
| allowcountry5       | bigint(20)              | NO   |     | -1
   |       |
| allowcountry4       | bigint(20)              | NO   |     | -1
   |       |
| allowcountry6       | bigint(20)              | NO   |     | -1
   |       |
| allowcountry7       | bigint(20)              | NO   |     | -1
   |       |
| allowcountry0       | bigint(20)              | NO   |     | -1
   |       |

The DB table is for a product. The product can only be sold in
particularly countries and I think these fields/columns use a bit
pattern to represent that.

I have tracked down a piece of code that I believe insert the data
into each column. I have taken as small a snippet as possible and
tried to test it. It produces this:

$VAR1 = {
          'allowcountry6' => '0xffffffffffffffff',
          'allowcountry1' => '0xffffffffffffffff',
          'allowcountry5' => '0xffffffffffffffff',
          'allowcountry2' => '0xffffffffffffffff',
          'allowcountry3' => '0xffffffffffffffff',
          'allowcountry4' => '0xffffffffffffffff',
          'allowcountry0' => '0xffffffffefffffff',
          'allowcountry7' => '0xffffffffffffffff'
        };


The code that produced this is below and it should run as stood alone.
I can understand parts of it but the overall logic is...well, I think
beyond me.
The routine expect a countryid (156) in this case and a string within
a set of tags. The string can be negated so

RS.CY1> ANTARCTICA</  means available in all countries EXCEPT ANTARCTICA
RS.CY1>* ANTARCTICA</ mean only IN ANTARCTICA.

I have put some questions inline and I would really appreciate an help
understanding the logic behind this. There are problems elsewhere in
the program and I can't really tackling them until I understand how
this bit pattern works. Also if anyone has an pointers to reference
material that might help with this sort of programming, I'd appreciate
it. Mastrering Perl does touch on it but not to this extent.

Thanx in advance.
Dp.


#!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper;

my %hr;
my $countryid = 156;
my $val = '<RS.CY1> ANTARCTICA</RS.CY1>';

create_bit_mask($val, $countryid, \%hr);

print Dumper(\%hr);

sub create_bit_mask {

    my $DEBUG = 1;
    my $val = shift;
    my $countryid=shift;
    my $hr = shift;
    my $isinclude = 0;

    # Figure out whether this is an 'allow' or 'deny' entry
    if( $val =~ /\*/ ){
        $val =~ s/\*//;

There is no need to search for the pattern twice:

     if ( $val =~ s/\*// ) {


        $val =~ s/^\s+(\S.*)/$1/;
        $isinclude = 1;
        print STDERR "ProcessCountry ISINC $isinclude\n" if ($DEBUG == 1);
    }

    # Have we already got bitmaps?  (Authors' comment)
    if( not exists $hr->{'allowcountry0'} )

If you want to test whether %$hr is empty ot not then:

    unless ( %$hr ) {


    {
      ## Is this how the pattern is negated?
        my $bmval = $isinclude?               ## So it's hex not base 2?
            '0x0000000000000000'
            :'0xFFFFFFFFFFFFFFFF';

You are using strings which doesn't make sense in this context. Perhaps you meant:

    my $bmval = $isinclude ? 0 : 0xFFFFFFFFFFFFFFFF;



        for(my $i=0;$i<8;$i++)                ## Set all the field to there
default; either all 0's or F's

That is usually written as:

for my $i ( 0 .. 7 ) ## Set all the field to their default; either all 0's or F's


        {
            $hr->{'allowcountry'.$i} = $bmval;
        }
    }

Or, more compactly:

%$hr = map { "allowcountry$_" => $bmval } 0 .. 7 unless %$hr;


                                                        # The highest
countryid is 243. How can fieldno ever be greater than 3?
    my $fieldno=int($countryid/64);     # 156/64 2.43, fieldno=2
    my $str="";
    my $currentno=$fieldno*64;          # 2 * 64

What this is doing is clearing out the lowest 6 bits to 0.

$ perl -le'
my $x = 243;
printf "%16b\n", $x;
my $y = int $x / 64;
printf "%16b\n", $y;
my $z = $y * 64;
printf "%16b\n", $z;
'
        11110011
              11
        11000000

The same thing could be done using bit-wise operators instead of arithmetic operators:

$ perl -le'
my $x = 243;
printf "%16b\n", $x;
my $y = int $x >> 6;
printf "%16b\n", $y;
my $z = $y << 6;
printf "%16b\n", $z;
'
        11110011
              11
        11000000

$ perl -le'
my $x = 243;
printf "%16b\n", $x;
my $y = $x & 0xFFC0;
printf "%16b\n", $y;
'
        11110011
        11000000


    # Amend the bitmaps. This is necessarily a bit ugly. (Authors comment).
    for(my $i=0;$i<8;$i++)

That is usually written as:

     for my $i ( 0 .. 7 )


    {
        my $digits=$hr->{"allowcountry$i"};    ##  Changing the bit pattern !!!
        for(my $j=0;$j<16;$j++)

That is usually written as:

        for my $j ( 0 .. 15 )


        {
            my $bits=hex( substr($digits,17-$j,1));

$bits will be the numerical value of the characters of the string '0x0000000000000000' or '0xFFFFFFFFFFFFFFFF', starting at the right of the string and moving leftward for each loop iteration, so the value will be either 0 or 15.


            if(($countryid - $currentno) < 4 && ($countryid >= $currentno))

$currentno changes inside the loop, but you are testing $countryid two bits at a time for the lowest 6 bits of $countryid, and this only happens for the 'allowcountry0' key of the hash as $currentno is never reset after the first key/value is modified.


            {
                if($isinclude)
                {
                    $bits |= 1<< ($countryid - $currentno);                 ### 
What
is this left shift doing? Is that a or complement?

Left shift moves all the bits in the number (in this case 1) $countryid - $currentno places to the left. So this sets the bits in $bits to 1 at location $countryid - $currentno.


                }
                else
                {
                    $bits &= 15- (1<< ($countryid - $currentno));      ### ditto

This sets the bits in $bits to 0 at location $countryid - $currentno.


                }
            }
            $currentno+=4;
            substr($digits,17-$j,1,sprintf("%1x",$bits));

This converts the number back to a text character and stores it in the correct place in $digits.


        }
        $hr->{"allowcountry$i"}=$digits;
        print STDERR "allowed ", $digits, "\n";
    }
}

Your code is using a combination of arithmetic and bit-wise operations on strings and numbers which would probably be better if you just stuck to bit-wise operators on numbers throughout.




John
--
Those people who think they know everything are a great
annoyance to those of us who do.        -- Isaac Asimov

--
To unsubscribe, e-mail: beginners-unsubscr...@perl.org
For additional commands, e-mail: beginners-h...@perl.org
http://learn.perl.org/


Reply via email to