Skip to content

Commit

Permalink
Implement GMP Bitwise operations
Browse files Browse the repository at this point in the history
  • Loading branch information
TomK committed Feb 25, 2016
1 parent e3dd381 commit 555b39e
Show file tree
Hide file tree
Showing 6 changed files with 343 additions and 101 deletions.
100 changes: 81 additions & 19 deletions src/BitWise.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,57 +12,119 @@ class BitWise
*/
public static function isSingleBit($bit)
{
if($bit == 1)
if(extension_loaded('gmp'))
{
return true;
return BitWiseGmp::isSingleBit($bit);
}
else
{
return BitWiseInt::isSingleBit($bit);
}
return $bit > 0 && bcmod($bit, 2) == 0 && ($bit & ($bit - 1)) == 0;
}

/**
* @param $mask
* @param $bit
*
* @return string
*/
public static function remove($mask, $bit)
{
return ($mask & $bit) ? ($mask ^ $bit) : $mask;
if(extension_loaded('gmp'))
{
return BitWiseGmp::remove($mask, $bit);
}
else
{
return BitWiseInt::remove($mask, $bit);
}
}

/**
* @param $mask
* @param $bit
*
* @return string
*/
public static function add($mask, $bit)
{
return $mask | $bit;
if(extension_loaded('gmp'))
{
return BitWiseGmp::add($mask, $bit);
}
else
{
return BitWiseInt::add($mask, $bit);
}
}

/**
* @param $mask
* @param $bit
*
* @return string
*/
public static function toggle($mask, $bit)
{
if($mask & $bit)
if(extension_loaded('gmp'))
{
return $mask ^ $bit;
return BitWiseGmp::toggle($mask, $bit);
}
else
{
return $mask | $bit;
return BitWiseInt::toggle($mask, $bit);
}
}

/**
* @param $mask
* @param $bit
*
* @return bool
*/
public static function has($mask, $bit)
{
return ($mask & $bit) === $bit;
if(extension_loaded('gmp'))
{
return BitWiseGmp::has($mask, $bit);
}
else
{
return BitWiseInt::has($mask, $bit);
}
}

/**
* @param $mask
*
* @return string
*/
public static function getBits($mask)
{
$bits = [];
for($i = 1; $i <= $mask; $i = $i * 2)
if(extension_loaded('gmp'))
{
if($i & $mask)
{
$bits[] = $i;
}
return BitWiseGmp::getBits($mask);
}
else
{
return BitWiseInt::getBits($mask);
}

return $bits;
}

/**
* @param $mask
*
* @return string
*/
public static function highest($mask)
{
$bits = static::getBits($mask);
return end($bits);
if(extension_loaded('gmp'))
{
return BitWiseGmp::highest($mask);
}
else
{
return BitWiseInt::highest($mask);
}
}
}
93 changes: 93 additions & 0 deletions src/BitWiseInt.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
<?php
namespace Packaged\Helpers;

class BitWiseInt
{
/**
* Check to see if an integer is a single bit, or a combination
*
* @param int $bit Bit to check
*
* @return bool
*/
public static function isSingleBit($bit)
{
$bit = (int)$bit;
return
($bit === 1)
|| ($bit > 0 && (($bit % 2) == 0) && (($bit & ($bit - 1)) == 0));
}

/**
* @param $mask
* @param $bit
*
* @return string
*/
public static function remove($mask, $bit)
{
return (int)$mask & (~(int)$bit);
}

/**
* @param $mask
* @param $bit
*
* @return string
*/
public static function add($mask, $bit)
{
return (int)$mask | (int)$bit;
}

/**
* @param $mask
* @param $bit
*
* @return string
*/
public static function toggle($mask, $bit)
{
return (int)$mask ^ (int)$bit;
}

/**
* @param $mask
* @param $bit
*
* @return bool
*/
public static function has($mask, $bit)
{
return ((int)$mask & (int)$bit) === (int)$bit;
}

/**
* @param $mask
*
* @return string
*/
public static function getBits($mask)
{
$bits = [];
for($i = 1; $i <= $mask; $i *= 2)
{
if(static::has($mask, $i))
{
$bits[] = $i;
}
}
return $bits;
}

/**
* @param $mask
*
* @return string
*/
public static function highest($mask)
{
$bits = static::getBits($mask);
return end($bits);
}
}
87 changes: 87 additions & 0 deletions tests/BitWiseGmpTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
<?php

use Packaged\Helpers\BitWiseGmp;

class BitWiseGmpTest extends PHPUnit_Framework_TestCase
{
const ONE = '1';
const TWO = '2';
const THREE = '4';
const FOUR = '8';
const FIVE = '16';
const SIX = '32';

protected function setUp()
{
if(!extension_loaded('gmp'))
{
$this->markTestSkipped('The GMP extension is not available.');
}
}

/**
* @large
*/
public function testSingleBit()
{
$this->assertTrue(BitWiseGmp::isSingleBit(1));
$this->assertTrue(BitWiseGmp::isSingleBit("1"));
$this->assertTrue(BitWiseGmp::isSingleBit(2));
$this->assertTrue(BitWiseGmp::isSingleBit("2"));
$this->assertTrue(BitWiseGmp::isSingleBit(4));

$fails = [3, 5, 6, 7, 9, 10, 11, 13, 14, 15];
foreach($fails as $checkBit)
{
$this->assertFalse(BitWiseGmp::isSingleBit($checkBit));
}

$checkBit = 4;
for($i = 0; $i < 10000; $i++)
{
$checkBit = gmp_mul($checkBit, 2);
$this->assertTrue(BitWiseGmp::isSingleBit($checkBit));
$this->assertFalse(BitWiseGmp::isSingleBit(gmp_sub($checkBit, 3)));
}
}

public function testModify()
{
$state = 0;

//Has
$this->assertFalse(BitWiseGmp::has($state, static::ONE));

//Add
$state = BitWiseGmp::add($state, static::ONE);
$this->assertTrue(BitWiseGmp::has($state, static::ONE));
$state = BitWiseGmp::add($state, static::TWO);
$state = BitWiseGmp::add($state, static::TWO);
$this->assertTrue(BitWiseGmp::has($state, static::ONE));
$this->assertTrue(BitWiseGmp::has($state, static::TWO));

//Remove
$state = BitWiseGmp::remove($state, static::ONE);
$state = BitWiseGmp::remove($state, static::ONE);
$this->assertTrue(BitWiseGmp::has($state, static::TWO));
$this->assertFalse(BitWiseGmp::has($state, static::ONE));

//Toggle
$state = BitWiseGmp::toggle($state, static::ONE);
$this->assertTrue(BitWiseGmp::has($state, static::ONE));
$state = BitWiseGmp::toggle($state, static::ONE);
$this->assertFalse(BitWiseGmp::has($state, static::ONE));

//Highest
$state = BitWiseGmp::add($state, static::FOUR);
$this->assertEquals(static::FOUR, BitWiseGmp::highest($state));
$state = BitWiseGmp::add($state, static::SIX);
$this->assertEquals(static::SIX, BitWiseGmp::highest($state));

//Get Bits
$this->assertEquals(
[static::TWO, static::FOUR, static::SIX],
BitWiseGmp::getBits($state)
);
}
}
Loading

0 comments on commit 555b39e

Please sign in to comment.