Help With Bitwise Operations

Do you have a question? Post it now! No Registration Necessary.  Now with pictures!

•  Subject
• Author
• Posted on
I'm attempting to do some work around existing code that uses bitwise
operations to manage flags passed into a function and I'm quite
frankly unequipped to do so.  I've never done much with bitwise
operations and all the reading I've done today doesn't appear to be
helping me much.  I'm hoping someone here can provide a remedial
lesson.  Given the following constants:

define('FLAG_1, 1);
define('FLAG_2', 2);
define('FLAG_3', 4);
define('FLAG_4', 8);
define('FLAG_5', 16);
define('FLAG_6', 32);
define('FLAG_7', 64);
define('FLAG_8', 128);
define('FLAG_9', 256);
define('FLAG_10', 512);
define('FLAG_11', 1024);
define('FLAG_12', 2048);

I'm making this call:

\$foo = my_function ( 'arg1', 'arg2', FLAG_1|FLAG_6|FLAG_4 );

To this function signature:

function my_function ( \$arg1, \$arg2='blah', \$flags=NULL )

Inside the function, if I just echo the value of \$args I get "41".

Is that correct?  From my reading, it doesn't seem correct, but it may
just be my ignorance in this area.  Any assistance reading and
understanding this stuff would be much appreciated.

Thanks.

Rob

Re: Help With Bitwise Operations

FLAG_1 = 1  = 000001
FLAG_6 = 32 = 100000
FLAG_4 = 8  = 001000

If we OR them all together we get 101001 = 41.  So that's correct.

Inside your function if you want to check if any particular flag was
set you would do it like this:

if(\$flags & FLAG_6) {
echo 'FLAG_6 was set';
}
else {
echo 'FLAG_6 was not set';
}

So, in your example, \$flags & FLAG_6 would be true because:

\$flags = 41 = 101001
FLAG_6 = 32 = 100000

If we AND them together we have 100000 which, inside an if statement,
evaluates to true.

Re: Help With Bitwise Operations

Interesting.  Then I have more learning to do.  The function is one
that I'm trying to move into an object oriented context and, given
your validation that the input is correct, what I'm finding is the my
method is doing the right thing for the wrong reasons while the
original function that has always worked is doing the wrong thing for
the right reasons.  Enigmatic.

I may have to follow up on this thread, but I have to do my own due
diligence even to know what question to ask.

Thanks for your help.

Re: Help With Bitwise Operations

Okay, I figured out what I was doing wrong and have both functions
behaving exactly the same.  Almost.  The difference is that when the
function is called, the constants are available to it and the bitwise
expression is passed in as just that - a bitwise expression (is it
properly called an "expression"?).  The method, though, is forced to
pass the expression in as a string for evaluation within the method
itself.

So the function gets FLAG_1|FLAG_6|FLAG_4 (evaluating to 41), while
the method gets 'FLAG_1|FLAG_6|FLAG_4' (no evaluation done).  In the
method, I split the string, apply the constant values and get the
correct output (1|32|8), but it's still a string.  How can I evaluate
that string to get 41?

Thanks again for the help.

Re: Help With Bitwise Operations

Rob Wilkerson wrote:

Rob,

Your method should be getting the bitwise expression, also.  Just
because it's a method in a class doesn't make any difference as to
what's being called.

How about some code?

--
==================
Remove the "x" from my email address
Jerry Stuckle
JDS Computer Training Corp.
jstucklex@attglobal.net
==================

Re: Help With Bitwise Operations

The code is all kind of up there.  I think maybe I haven't done a very
good job of describing the context so let me try to do better.

In the standalone function solution, the function exists in a file
that is included.  That file also includes the constant definitions
(outside the function).  When the file containing the constants and
functions is included any code calling the function can use the
constants when passing parameters to the function.

The method, on the other hand, will be part of a class that exists as
a singleton.  I'll make the singleton available to other objects (in a
manner I haven't decided yet) and call the method from within that
object as MyClass::getInstance()->my_method ( ... ).  At the time the
call is made, the flags will not be available as constants, but I'd
still like to be able to pass the human readable syntax.  To do that,
I've moved the constants into my_method() with the intent of
translating the flag's variable name into its bit value at the top of
the method.  That's done and I get the expression I'm expecting (1|32|
8), but not the evaluated value I need.  Here's a snippet from the
method that _might_ help:

\$result = \$myobj->my_method ( 'arg1', 'arg2', 'PREG_FIND_RECURSIVE|
PREG_FIND_RETURNASSOC' );

At the top of the function, I have the following code to re-evaluate
the flags into their bits:

\$tmp     = preg_split ( '/([|&^~])/', \$args,
-1 ,PREG_SPLIT_DELIM_CAPTURE );
\$args    = '';

foreach ( \$tmp as \$arg ) {
\$args .= defined ( "self::\$arg" ) ? constant ( "self::\$arg" ) : \$arg;
}

At this point, I have '1|32|8' rather than 41.  I'm not sure how to
make that next step or, alternatively, to process the string more
effectively as a bit expression.

I hope that helps a little.  Thanks again.

Re: Help With Bitwise Operations

Rob Wilkerson wrote:

No, let's see your entire method - and more importantly, the code that's
calling it.  You shouldn't need to do any of the stuff you're doing
here.  You have something else wrong, but my crystal ball is broken.
So, without the code it's impossible to see what you've got.

--
==================
Remove the "x" from my email address
Jerry Stuckle
JDS Computer Training Corp.
jstucklex@attglobal.net
==================

Re: Help With Bitwise Operations

Okay, then you need a little more background, maybe.  I'm working to
adapt someone else's custom function into an object oriented
architecture.  The original function (and definition of constants) can
be found at http://www.pgregg.com/projects/php/preg_find/preg_find.phps .

My object oriented translation requires just a few changes to the
function itself and they're really just syntax changes - except for
translating the bitwise expression.

CALLING THE METHOD:

require_once ( 'org/client/file/finder.php' );
\$finder = new Finder();
\$result = \$finder->preg_find ( '/image\.php\$/', '/path/to/my/includes/
org/client/content', 'PREG_FIND_RECURSIVE|PREG_FIND_RETURNASSOC' );
new PHPDump ( \$result );
exit();

Note that the flag definitions do not exist yet.  If the single quotes
in the third argument are removed then the normal (and expected)
"constant not defined" errors are thrown.  Nor, for that matter, do I
*want* them to exist here.  I want to keep them with the code where
they matter rather than defining them everywhere they're used.
Similarly, I want to continue to be able to use the flags because
they're more readable than passing in the bit values themselves.

METHOD CHANGES:

class Finder {
const PREG_FIND_RECURSIVE     = 1;
const PREG_FIND_DIRMATCH      = 2;
const PREG_FIND_FULLPATH      = 4;
const PREG_FIND_NEGATE        = 8;

/**
* All of the additional flag constants defined similarly
*
* SNIP -->
*/

public function preg_find ( \$pattern, \$start_dir='.', \$args=NULL ) {
/**
* Go through the business of evaluating the bit string.
*/
\$args_in = \$args;    /** Save off the input string */
\$tmp     = preg_split ( '/([|&^~])/', \$args,
-1 ,PREG_SPLIT_DELIM_CAPTURE );
\$args    = '';

foreach ( \$tmp as \$arg ) {
\$args .= defined ( "self::\$arg" ) ? constant ( "self::\$arg" ) :
\$arg;
}

/**
* Back to doing what we need to do using the bitwise expression
that is expected.
*/
static \$depth = -1;
++\$depth;

/**
* SNIP -->
*/
}
}

Aside from the code shown at the top of the method, only the following
changes from the original were made:

- The syntax of all references to a flag within the method was changed
to "self::FLAG_NAME".
- In the recursive call to the method, the arguments being passed are
the original arguments saved off at the top of the method.

I've found no other changes that are required thus far.

Once again, I appreciate your help.

Re: Help With Bitwise Operations

Rob Wilkerson wrote:

The flags do exist in your code, because you've defined them.  Your
problem is in how you're using them.

You defined the constants in the class, so you need to scope them to the
class, i.e. Finder::PREG_FIND_RECURSIVE.

--
==================
Remove the "x" from my email address
Jerry Stuckle
JDS Computer Training Corp.
jstucklex@attglobal.net
==================

Re: Help With Bitwise Operations

Bingo.  I didn't realize constants could be accessed that way.  And,
as is usually the case, I find it clearly spelled out that way in the
docs once I kind of understand what I'm looking for.

Thanks for your help.

Re: Help With Bitwise Operations

you can think of it like so

"if it is in a and b then put a 1"

so what does
a & b
give you

"if it is in a and b then put a 1"
convert a and b to binary bits if needed
then think of the bits in both,
and run your mental eye down the columns,
put a 1 where the bit is set for both a and b, and a 0 where it isn't
then convert the result into decimal if needed.

17 & 8
10001
01000

so the answer is
10001
01000
00000 (no 1 appears in the any once column)
0 in decimal

how about 7 & 8
0111
1000
again 0

8 & 9
01000
01001
01000
8

with | it's similar

"if it is in a OR b" then put a 1

17 | 8
10001
01000
11001
25
notice this could almost be seen as adding up but it isn't, here's 8
and 9 again:

8 | 9
01000
01001
01001
9
where the two 1 occur twice in the same column we don't end up
doubling it, we just put a 1 in the column if there is a 1 in the
other column in EITHER row.