Darren B
Darren B

Reputation: 3

I-Series RPGLE function to test multiple bits in array for a value

I'm trying to determine if there's a more efficient coding technique I can use for an if statement. I have a bit array that can contain 128 bits, either 0 or 1. Currently, my code looks like this:

if bi(64)='1' or bi(66)='1' or bi(67)='1' or bi(68)='1'
or bi(69)='1' or bi(70)='1' or bi(71)='1' or bi(72)='1'
or bi(73)='1' or bi(74)='1' or bi(75)='1' or bi(76)='1'
or bi(77)='1' or bi(78)='1' or bi(79)='1' or bi(80)='1'
or bi(81)='1';                                         

Obviously this doesn't work, but is there a method I could use to simplify this expression like this or something?

if bi(64) or bi(65) or bi(66) or bi(67) = '1'; 

I have actually tried the statement above, but the compiler doesn't like it.

Upvotes: 0

Views: 252

Answers (5)

jmarkmurphy
jmarkmurphy

Reputation: 11493

RPG doesn't have bit arrays, but it does have character arrays and bit functions. You can write a subprocedure to make something like your proposed syntax workable.

dcl-proc bitSet;
  dcl-pi *n ind;
    bitarr128    char(16);
    ix           int(10);
  end-pi;

  dcl-ds bitarrds;
    bitarr   char(1) dim(16);
  end-ds;
  dcl-ds maskds;
    *n        char(1) inz(x'80');
    *n        char(1) inz(x'40');
    *n        char(1) inz(x'20');
    *n        char(1) inz(x'10');
    *n        char(1) inz(x'08');
    *n        char(1) inz(x'04');
    *n        char(1) inz(x'02');
    *n        char(1) inz(x'01');
    mask      char(1) dim(8) pos(1);
  end-ds;
  dcl-s arrayix    int(10);
  dcl-s maskix     int(10);

  bitarrds = bitarr128;
  arrayix = ((ix-1)/8)+1;
  maskix = %rem((ix-1):8)+1;
  return %bitand(bitarr(arrayix): mask(maskix)) <> x'00';
end-proc;

Then use the function like this

if bitSet(bi:61) or bitSet(bi:62) or bitSet(bi:63) or
   bitSet(bi:64) or bitSet(bi:65) or bitSet(bi:66);

You would have to make sure you didn't pass an out of bounds index, or with a little extra work you could add some exception handling, or even make the function generic enough to handle variable size bit arrays.

Upvotes: 1

Victor Pomortseff
Victor Pomortseff

Reputation: 453

It might work out like this:

128 bits is 16 bytes. Let's assume that the bits are numbered from left to right, starting from 1st to 128th.

Then

  Bit  Byte    M1    M2
  1-8     1  0x00  0x00
  9-16    2  0x00  0x00
 17-24    3  0x00  0x00
 25-32    4  0x00  0x00
 33-40    5  0x00  0x00
 41-48    6  0x00  0x00
 49-56    7  0x00  0x00
 57-64    8  0x01  0x01
 65-72    9  0x7F  0xE0
 73-80   10  0xFF  0x00
 81-88   11  0x80  0x00
 89-96   12  0x00  0x00
 97-104  13  0x00  0x00
105-112  14  0x00  0x00
113-120  15  0x00  0x00
121-128  16  0x00  0x00

M1 set of bytes for the condition

if bi(64)='1' or bi(66)='1' or bi(67)='1' or bi(68)='1'
or bi(69)='1' or bi(70)='1' or bi(71)='1' or bi(72)='1'
or bi(73)='1' or bi(74)='1' or bi(75)='1' or bi(76)='1'
or bi(77)='1' or bi(78)='1' or bi(79)='1' or bi(80)='1'
or bi(81)='1';

and M2 - for the condition

if bi(64) or bi(65) or bi(66) or bi(67) = '1';

define

dcl-c bitMask1   const(x'00000000000000017FFF800000000000');
dcl-c bitMack2   const(x'0000000000000001E000000000000000');

dcl-s bitArr128  char(16);

where bitArr128 is the bit array to be checked.

Then the first condition will be written in the form

if %bitand(bitArr128: bitMask1) <> 0;

and the second - in the form

if %bitand(bitArr128: bitMask2) <> 0;

I’ll say right away that I haven’t tested it myself (personally, it would be easier for me to write such a function in C and include it as a separate module in the RPG program). But try it - it might work.

Naturally, for each check you will need to determine the required bit mask

Upvotes: 0

Victor Pomortseff
Victor Pomortseff

Reputation: 453

Unfortunately, RPG does not support bitmaps.

We can declare an array of "indicators", but each element of the array will occupy one byte with the boolean value *on (character '1' ) or *off (character '0' )

To work with bits in RPGs there are BIFs - %bitand / %bitnot / %bitor / %bitxor - see how suitable they may be for your purposes.

Upvotes: 0

Charles
Charles

Reputation: 23823

You don't include your definitions, but I assume that "bit array" really means "indicator array".

dcl-s bi ind dim(128);

You also don't mention how/why you're picking the elements you've shown. Assuming it's always a contiguous range, the %SUBARR built-in function may be of use. And if you are on a supported version of the OS the IN operator makes this easy.

// note this is 64-81, did you mean to leave 65 out of your example? 
if '1' in %subarr(bi:64:18);
  dsply 'at least one on';
else;
  dsply 'all off';
endif;  

Upvotes: 2

James Allman
James Allman

Reputation: 41208

Something like this should work:

if %scan('1' : bi(64) + bi(65) + bi(66) + bi(67)) > 0;

See the %SCAN function for more information.

Upvotes: 0

Related Questions