| 
<?php
 /**
 * This class provides a simple way to manage bitfields
 *
 *<code>
 *    $bits = new Bitfield("01110100");
 *    echo $bits->get(0); # 0
 *    echo $bits->get(1); # 1
 *    echo $bits->toggle(2); # 0
 *    echo $bits->toString(); # 01010100
 *    echo $bits->toString(8); # 124
 *</code>
 */
 class Bitfield implements IteratorAggregate, Serializable {
 
 /**
 * to store the bits
 *
 * @var int
 */
 private $_bits = 0;
 
 /**
 */
 static function factory($mask) {
 return new self($mask);
 }
 
 /**
 * Creates a new Bitfield instance
 * Additionaly you can set the bits in tow formats: int or bin-string
 *
 *<code>
 *    $bit = new Bitfield(0xf0c5); # set as int
 *    echo $bit;
 *
 *    $bit = new Bitfield('1110110101001010'); # set as bin-string
 *    echo $bit;
 *
 *    $bit = new Bitfield('7523', 8); # using a different base
 *    echo $bit;
 *</code>
 *
 * @param int|string $mask
 * @param int $base
 */
 function __construct (/*int|string*/$mask=false, /*int*/ $base=2) {
 
 if (is_string($mask)) {
 $this->fromBase($mask, $base);
 }
 elseif (is_int($mask)) {
 $this->_bits = $mask;
 } elseif (false !== $mask) {
 throw new Exception('invalid $mask type, given ' . gettype($mask));
 }
 }
 
 /**
 * @return string
 */
 function __toString (/*void*/) {
 return $this->toBin();
 }
 
 /**
 * @return int
 */
 function valueOf () {
 return $this->_bits;
 }
 
 #-------------------------------------------------------------------------#
 # Methods required by interfaces
 
 /**
 * @return ArrayIterator
 */
 function getIterator (/*void*/) {
 return new ArrayIterator($this->toArray());
 }
 
 /**
 * @return string
 */
 function serialize (/*void*/) {
 return strval($this->_bits);
 }
 
 /**
 * @param string $serialized
 * @return Bitfield
 */
 function unserialize (/*string*/$serialized) {
 return $this->fromBin($serialized);
 }
 
 #-------------------------------------------------------------------------#
 # Bit Operations
 
 /**
 * Get the value of the bit at the $offset
 *
 * @param int $offset
 * @return boolean
 */
 function get (/*int*/$offset) {
 $mask = 1 << $offset;
 return ($mask & $this->_bits) == $mask;
 }
 
 /**
 * Set the bit at $offset to true
 *
 * @param int $offset
 * @return Bitfield
 */
 function set (/*int*/$offset) {
 $this->_bits |= 1 << $offset;
 return $this;
 }
 
 /**
 * Reset the bit at $offset.
 *
 * @param int $offset
 * @return Bitfield
 */
 function reset (/*int*/$offset) {
 $this->_bits &= ~ (1 << $offset);
 return $this;
 }
 
 /**
 * Toggle the bit at $offset.
 * If the bit is set then reset it, and viceversa.
 *
 * @param int $offset
 * @return Bitfield
 */
 function toggle (/*int*/$offset) {
 $this->_bits ^= 1 << $offset;
 return $this->get($offset);
 }
 
 /**
 * @param int $word_size
 */
 function reverse ($word_size=8) {
 $size = (strlen($this->toBin()) % $word_size + 1) * $word_size;
 return $this->fromString(strrev($this->toString(2, $size)));
 }
 
 #-------------------------------------------------------------------------#
 # Conversion - Inputs
 
 /**
 * @deprecated
 *
 * @param int $number
 * @return Bitfield
 */
 function fromNumber (/*int*/$number){
 $this->_bits = (int) $number;
 return $this;
 }
 
 /**
 * @deprecated
 *
 * @param string $string
 * @return Bitfield
 */
 function fromString (/*string*/$string){
 $this->_bits = bindec($string);
 return $this;
 }
 
 /**
 * Set the bits from a $number.
 * The $number must be in $base
 *
 *<code>
 *    $b = new Bitfield();
 *    $b->fromBase('753', 8); # set to 111 101 011
 *    echo $b->toOct();
 *</code>
 *
 * @param string $number
 * @param int $base
 * @return Bitfield
 */
 function fromBase (/*string*/$number,/*int*/$base) {
 $this->_bits = base_convert($number, $base, 10);
 return $this;
 }
 
 /**
 * Set the bits from a string with an $hex number ([0-9a-fA-F]+)
 *
 * @see Bitfield::fromBase
 *
 * @param int $number
 * @param int $base
 * @return Bitfield
 */
 function fromHex (/*string*/$hex) {
 $this->_bits = $this->fromBase($hex, 16);
 return $this;
 }
 
 /**
 * Set the bits from a string with an $oct number ([0-7]+)
 *
 * @see Bitfield::fromBase
 *
 * @param int $number
 * @return Bitfield
 */
 function fromOct (/*string*/$oct)
 {
 $this->_bits = $this->fromBase($oct, 8);
 return $this;
 }
 
 /**
 * Set the bits from a string with an $bin number ([01]+)
 *
 * @see Bitfield::fromBase
 *
 * @param int $bin
 * @return Bitfield
 */
 function fromBin (/*string*/$bin)
 {
 $this->_bits = $this->fromBase($bin, 2);
 return $this;
 }
 
 #-------------------------------------------------------------------------#
 # Conversion - Outputs
 
 /**
 * Return the bits in a numeric representation
 *
 *<code>
 *    $b = new Bitfield('10010110'); # set to 150
 *    echo $b->toNumber();
 *</code>
 *
 * @return int
 */
 function toNumber (/*void*/) {
 return $this->_bits;
 }
 
 /**
 * Return the bits in a string representation
 *
 * If $max_size is given it will pad the bits with 0's
 *
 *<code>
 *    $b = new Bitfield(150); # set to 10010110
 *    echo $b->toString(16);
 *</code>
 *
 * @param int $max_size
 * @param int $max_size
 * @return string
 */
 function toString (/*int*/$base=2, /*int*/$max_size=false) {
 
 $result = $this->toBase($base);
 
 if (!is_int($max_size)) {
 return $result;
 }
 
 return str_pad($result, $max_size, 0, STR_PAD_LEFT) ;
 }
 
 /**
 * Returns an array of ints, where each position holds true or false
 *
 *<code>
 *    $bits = new Bitfield(0xF0); # set to 1111 0000
 *    $bitsArray = $bits->toArray();
 *
 *    print_r($bitsArray); # => array(true, true, true, true, false, false, false, false);
 *
 *</code>
 *
 * @return array
 */
 function toArray (/*void*/) {
 return str_split(strrev($this->toBin()));
 }
 
 /**
 * Returns the bits as a string with a numeric representation in $base
 *
 *<code>
 *    $b = new Bitfield();
 *    $b->fromBase('112233', 4);
 *    echo $b->toBase(4);
 *</code>
 *
 * @param int $base
 * @return string
 */
 function toBase (/*int*/$base) {
 return base_convert($this->_bits, 10, $base);
 }
 
 /**
 * Returns the bits as a hexdecimal-string number
 *
 * @see Bitfield::toBase
 *
 * @return string
 */
 function toHex (/*void*/) {
 return $this->toBase(16);
 }
 
 /**
 * Returns the bits as a octal-string number
 *
 * @see Bitfield::toBase
 *
 * @return string
 */
 function toOct (/*void*/) {
 return $this->toBase(8);
 }
 
 /**
 * Returns the bits as a binary-string number
 *
 * @see Bitfield::toBase
 *
 * @return string
 */
 function toBin (/*void*/) {
 return $this->toBase(2);
 }
 }
 
 |