<?php
namespace SmartData;
abstract class Unit
{
// Formats
// Bit 31 16 0
// +--+----------------------------------+-------------------------------------+
// Digital |0 | type | lenght |
// +--+----------------------------------+-------------------------------------+
// Bit 31 29 27 24 21 18 15 12 9 6 3 0
// +--+----+----+------+------+------+------+------+------+------+------+------+
// SI |1 |NUM |MOD |sr+4 |rad+4 |m+4 |kg+4 |s+4 |A+4 |K+4 |mol+4 |cd+4 |
// +--+----+----+------+------+------+------+------+------+------+------+------+
// Bits 1 2 2 3 3 3 3 3 3 3 3 3
// Valid values for field SI
public const DIGITAL = 0 << 31;
public const SI = 1 << 31;
// Valid values for field NUM
public const I32 = 0 << 29; // Value is an integral number stored in the 32 last significant bits of a 32-bit little-endian integer.
public const I64 = 1 << 29; // Value is an integral number stored in the 64 last significant bits of a 64-bit little-endian integer.
public const F32 = 2 << 29; // Value is a real number stored as an IEEE 754 binary32 little-endian floating point.
public const D64 = 3 << 29; // Value is a real number stored as an IEEE 754 binary64 little-endian double precision floating point.
public const NUM = self::D64; // AND mask to select NUM bits
// Valid values for field MOD
public const DIR = 0 << 27; // Unit is described by the product of SI base units raised to the powers recorded in the remaining fields.
public const DIV = 1 << 27; // Unit is U/U, where U is described by the product SI base units raised to the powers recorded in the remaining fields.
public const LOG = 2 << 27; // Unit is log_e(U), where U is described by the product of SI base units raised to the powers recorded in the remaining fields.
public const LOG_DIV = 3 << 27; // Unit is log_e(U/U), where U is described by the product of SI base units raised to the powers recorded in the remaining fields.
public const MOD = self::D64; // AND mask to select MOD bits
// Masks to select the SI units
public const SR = 7 << 24;
public const RAD = 7 << 21;
public const M = 7 << 18;
public const KG = 7 << 15;
public const S = 7 << 12;
public const A = 7 << 9;
public const K = 7 << 6;
public const MOL = 7 << 3;
public const CD = 7 << 0;
// Masks to digital fields
public const LENGHT = (0xFFFF);
public const TYPE = (self::LENGHT << 16);
public const SIZE = 4; // bytes
public function __construct($u){
$this->_unit = $u;
}
public static function interpret($u) {
switch ($u & (1 << 31)) {
case self::DIGITAL:
return new Digital_Unit($u);
break;
case self::SI:
return new SI_Unit($u);
break;
default:
throw new InvalidUnitException("Invalid Unit: ".$u);
}
return null;
}
public static function unpack($u) {
return self::interpret(unpack('V', $u)[1]);
}
public function is_digital() : bool {
return (($this->_unit & (1 << 31)) == self::DIGITAL);
}
protected $_unit;
}
// Typical SI Quantities
final class TypicalUnit extends Unit
{
// si | mod | sr | rad | m | kg | s | A | K | mol | cd
const Length = 1<<31 | 0<<27 | (4+0)<<24 | (4+0)<<21 | (4+1)<<18 | (4+0)<<15 | (4+0)<<12 | (4+0)<<9 | (4+0)<<6 | (4+0)<<3 | (4+0);
const Mass = 1<<31 | 0<<27 | (4+0)<<24 | (4+0)<<21 | (4+0)<<18 | (4+1)<<15 | (4+0)<<12 | (4+0)<<9 | (4+0)<<6 | (4+0)<<3 | (4+0);
const Time = 1<<31 | 0<<27 | (4+0)<<24 | (4+0)<<21 | (4+0)<<18 | (4+0)<<15 | (4+1)<<12 | (4+0)<<9 | (4+0)<<6 | (4+0)<<3 | (4+0);
const Current = 1<<31 | 0<<27 | (4+0)<<24 | (4+0)<<21 | (4+0)<<18 | (4+0)<<15 | (4+0)<<12 | (4+1)<<9 | (4+0)<<6 | (4+0)<<3 | (4+0);
const Electric_Current = Typical::Current;
const Temperature = 1<<31 | 0<<27 | (4+0)<<24 | (4+0)<<21 | (4+0)<<18 | (4+0)<<15 | (4+0)<<12 | (4+0)<<9 | (4+1)<<6 | (4+0)<<3 | (4+0);
const Amount_of_Substance = 1<<31 | 0<<27 | (4+0)<<24 | (4+0)<<21 | (4+0)<<18 | (4+0)<<15 | (4+0)<<12 | (4+0)<<9 | (4+0)<<6 | (4+1)<<3 | (4+0);
const Luminous_Intensity = 1<<31 | 0<<27 | (4+0)<<24 | (4+0)<<21 | (4+0)<<18 | (4+0)<<15 | (4+0)<<12 | (4+0)<<9 | (4+0)<<6 | (4+0)<<3 | (4+1);
const Area = 1<<31 | 0<<27 | (4+0)<<24 | (4+0)<<21 | (4+2)<<18 | (4+0)<<15 | (4+0)<<12 | (4+0)<<9 | (4+0)<<6 | (4+0)<<3 | (4+0);
const Volume = 1<<31 | 0<<27 | (4+0)<<24 | (4+0)<<21 | (4+3)<<18 | (4+0)<<15 | (4+0)<<12 | (4+0)<<9 | (4+0)<<6 | (4+0)<<3 | (4+0);
const Speed = 1<<31 | 0<<27 | (4+0)<<24 | (4+0)<<21 | (4+1)<<18 | (4+0)<<15 | (4-1)<<12 | (4+0)<<9 | (4+0)<<6 | (4+0)<<3 | (4+0);
const Velocity = Typical::Speed;
const Acceleration = 1<<31 | 0<<27 | (4+0)<<24 | (4+0)<<21 | (4+1)<<18 | (4+0)<<15 | (4-2)<<12 | (4+0)<<9 | (4+0)<<6 | (4+0)<<3 | (4+0);
}
class Digital_Unit extends Unit
{
public function __get($property) {
switch ($property) {
case 'cod':
return $this->_unit;
case 'type':
return (($this->_unit & self::TYPE) >> 16);
case 'lenght':
return ($this->_unit & self::LENGHT);
default:
return null;
}
}
public function __toString() {
return "{{$this->unit}, D, t={$this->type}, l={$this->lenght}}";
}
}
class SI_Unit extends Unit
{
public function __get($property) {
switch ($property) {
case 'cod':
return $this->_unit;
case 'num':
return (($this->_unit & self::NUM) >> 29);
case 'mod':
return (($this->_unit & self::MOD) >> 27);
case 'sr':
return (($this->_unit & self::SR) >> 24) - 4;
case 'rad':
return (($this->_unit & self::RAD) >> 21) - 4;
case 'm':
return (($this->_unit & self::M) >> 18) - 4;
case 'kg':
return (($this->_unit & self::KG) >> 15) - 4;
case 's':
return (($this->_unit & self::S) >> 12) - 4;
case 'a':
return (($this->_unit & self::A) >> 9) - 4;
case 'k':
return (($this->_unit & self::K) >> 6) - 4;
case 'mol':
return (($this->_unit & self::MOL) >> 3) - 4;
case 'cd':
return (($this->_unit & self::CD) >> 0) - 4;
default:
return null;
}
}
public function __toString() {
$string = "{{$this->cod}, SI, n={$this->num}, m={$this->mod}, ";
$string .= ($this->sr != 0) ? "sr^{$this->sr}" : '';
$string .= ($this->rad != 0) ? "rad^{$this->rad}" : '';
$string .= ($this->m != 0) ? "m^{$this->m}" : '';
$string .= ($this->kg != 0) ? "kg^{$this->kg}" : '';
$string .= ($this->s != 0) ? "s^{$this->s}" : '';
$string .= ($this->a != 0) ? "A^{$this->a}" : '';
$string .= ($this->k != 0) ? "K^{$this->k}" : '';
$string .= ($this->mol != 0) ? "mol^{$this->mol}" : '';
$string .= ($this->cd != 0) ? "cd^{$this->cd}" : '';
$string .= '}';
return $string;
}
}