Last active
December 10, 2015 02:48
-
-
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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