radfusion/app/Models/Traits/BitmaskFunctionality.php
2025-01-05 12:49:53 +06:00

127 lines
3.0 KiB
PHP

<?php
namespace App\Models\Traits;
use function array_filter;
use function array_reduce;
use function chunk_split;
use function count;
use function sprintf;
use function substr;
/** @psalm-type Int32BitMask = int<0, 2147483647> */
trait BitmaskFunctionality
{
/** @param Int32BitMask $value */
public static function hasCase(int $value): bool
{
return self::tryFrom($value) !== null;
}
/** @return Int32BitMask */
public static function build(self ...$bits): int
{
return self::set(0, ...$bits);
}
/** @return Int32BitMask */
public static function set(int $value, self ...$bits): int
{
return $value | self::mask(...$bits);
}
/** @return Int32BitMask */
public static function mask(self ...$bits): int
{
if (count($bits) === 0) {
return 0;
}
return array_reduce($bits, static fn (?int $sum, self $case) => ($sum ?? 0) | $case->value);
}
/** @return Int32BitMask */
public static function clear(int $value, self ...$bits): int
{
return $value & ~self::mask(...$bits);
}
/** @param Int32BitMask $value */
/** @return Int32BitMask */
public static function toggle(int $value, self ...$bits): int
{
return $value ^ self::mask(...$bits);
}
/** @param Int32BitMask $value */
/** @param Int32BitMask $value */
public static function off(int $value, self $bit): bool
{
return ($value & $bit->value) === 0;
}
/** @param Int32BitMask $value */
/** @param Int32BitMask $value */
public static function any(int $value, self ...$bits): bool
{
if (count($bits) === 0) {
return true;
}
return ($value & self::mask(...$bits)) > 0;
}
/** @param Int32BitMask $value */
public static function all(int $value, self ...$bits): bool
{
if (count($bits) === 0) {
return true;
}
$mask = self::mask(...$bits);
return ($value & $mask) === $mask;
}
/** @param Int32BitMask $value */
public static function none(int $value, self ...$bits): bool
{
if (count($bits) === 0) {
return true;
}
$mask = self::mask(...$bits);
return ($value & $mask) === 0;
}
/**
* @param Int32BitMask $value
* @return list<static>
*/
public static function parse(int $value): array
{
return array_filter(self::cases(), static fn (self $case) => self::on($value, $case));
}
/** @param Int32BitMask $value */
public static function on(int $value, self $bit): bool
{
return ($value & $bit->value) === $bit->value;
}
/** @param Int32BitMask $value */
public static function valueToString(int $value): string
{
return '0b' . substr(chunk_split(sprintf('%\'032b', $value), 4, '_'), 0, -1);
}
public function toString(): string
{
return self::valueToString($this->value);
}
}