Skip to content

Instantly share code, notes, and snippets.

@adrian-enspired
Last active December 10, 2015 02:48
Show Gist options
  • Save adrian-enspired/4370584 to your computer and use it in GitHub Desktop.
Save adrian-enspired/4370584 to your computer and use it in GitHub Desktop.
A utility class to create, manipulate, and check bitmasks (use powers of 2 for your values!). Written and tested with php5.4; should be compatible with 5.1+. Exception-based error handling. Released under the MIT license. See example usage below class definition.
<?php
/**
* models a bitfield and provides manipulation & comparison methods.
*
* @author Adrian Testa-Avila <[email protected]>
* @copyright 2012
* @license MIT License [http://opensource.org/licenses/MIT]
*/
class Bitfield{
/** int set() flags to add or remove bit from bitmask. */
const setbit_off = 0;
const setbit_on = 1;
/** int current bitfield value. */
private $_bitfield;
/** int original (constructed) bitfield value. */
private $_bitfield_original;
/**
* sets bitfield to an initial value.
*
* @throws InvalidArgumentException if $b is not an integer
*/
public function __construct( $b ){
if( !is_integer( $b ) ){
throw new InvalidArgumentException( 'bitfield must be an integer',E_USER_ERROR );
$b = 0;
}
$this->_bitfield = $this->_bitfield_original = $b;
}
/**
* checks if the current bitfield value matches the original.
*
* @return bool true if current bitfield matches original; false otherwise.
*/
public function changed(){
return ($this->_bitfield !== $this->_bitfield_original);
}
/**
* checks the current bitfield against a given value.
*
* @param int $b value to check against
* @throws InvalidArgumentException if $b is not an integer
* @return bool true if $b is contaned in current bitmask; false otherwise
*/
public function contains( $b ){
if( !is_integer( $b ) ){
throw new InvalidArgumentException( 'bitmask values must be integers',E_USER_NOTICE );
return false;
}
return (($this->_bitfield & $b) == $b);
}
/**
* checks the entire current bitfield, optionally against a given value.
*
* @param int $b the bitfield to check against
* @throws InvalidArgumentException if $b is not an integer
* @return int|bool true if provided $b matches the current bitfield, false if not;
* the bitfield otherwise
*/
public function equals( $b=null ){
if( $b === null ){
return $this->_bitfield;
}
if( !is_integer( $b ) ){
throw new InvalidArgumentException( 'bitfield must be an integer',E_USER_NOTICE );
return false;
}
return ($this->_bitfield === $b);
}
/**
* turns bits on or off.
*
* @param int $b value to set/remove
* @throws InvalidArgumentException if $b is not an integer
* @throws InvalidArgumentException if $mode is not 1 or 0
* @return bool true if value was modified; false otherwise
*/
public function modify( $b,$mode=self::setbit_on ){
if( !is_integer( $b ) ){
throw new InvalidArgumentException( 'bitmask values must be integers',E_USER_NOTICE );
return false;
}
if( ($mode != 1) && ($mode != 0) ){
throw new InvalidArgumentException( "'mode' must be '1' or '0'",E_USER_NOTICE );
return false;
}
$unmod = $this->_bitfield;
$mode?
$this->_bitfield = $this->_bitfield & ~$b | $b:
$this->_bitfield = $this->_bitfield & ~$b
;
return !($this->equals( $unmod ));
}
/**
* replaces the current bitfield with a new one.
*
* @param int $b value to set
* @throws InvalidArgumentException if $b is not an integer
* @return bool true if new bitfield set; false otherwise
*/
public function replace( $b ){
if( !is_integer( $b ) ){
throw new InvalidArgumentException( 'bitfield must be an integer',E_USER_NOTICE );
return false;
}
$this->bitfield = $b;
return true;
}
/** restores the original (constructed) bitfield value. */
public function reset(){
$this->_bitfield = $this->_bitfield_original;
}
}
// EXAMPLE USAGE //
/*
print "creating a new bitmask from 1|4...\n";
$b = new bitfield( 1|4 );
print "-> b is set to ".$b->equals()."\n\n";
print "checking if b contains 4...\n";
print $b->contains( 4 )? "-> b contains 4\n": "-> b is missing 4\n";
print "adding 4...\ndid b change? ";
print $b->modify( 4,true )? "-> yes\n\n": "-> no\n\n";
print "removing 4...\n";
$b->modify( 4,false );
print $b->contains( 4 )? "-> b now contains 4\n": "-> b is now missing 4\n\n";
print "checking if b contains 16...\n";
print $b->contains( 16 )? "-> b contains 16\n": "-> b is missing 16\n\n";
print "adding 16...\n";
$b->modify( 16,true );
print $b->contains( 16 )? "-> b now contains 16\n": "-> b is now missing 16\n\n";
print "checking if the current b matches the original b...\n";
print $b->changed()? "-> b has changed from initial value\n\n": "-> b is still the same\n\n";
print "replacing b with 2|8|32...\n";
$b->replace( 2|8|32 );
print "-> b is now ".$b->equals()."\n\n";
print "resetting b to original value...\n";
$b->reset();
print "-> b is now reset to ".$b->equals();
/* outputs:
creating a new bitmask from 1|4...
-> b is set to 5
checking if b contains 4...
-> b contains 4
adding 4...
did b change? -> no
removing 4...
-> b is now missing 4
checking if b contains 16...
-> b is missing 16
adding 16...
-> b now contains 16
checking if the current b matches the original b...
-> b has changed from initial value
replacing b with 2|8|32...
-> b is now 17
resetting b to original value...
-> b is now reset to 5
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment