Skip to content

Instantly share code, notes, and snippets.

@dacr
Last active May 27, 2023 06:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dacr/eb11a5bffb6f7f4ff0386cd7c8a61fb8 to your computer and use it in GitHub Desktop.
Save dacr/eb11a5bffb6f7f4ff0386cd7c8a61fb8 to your computer and use it in GitHub Desktop.
encode/decode 4 component vector into an integer / published by https://github.com/dacr/code-examples-manager #e3887820-4329-4e6d-94fe-bb37ef830d1f/eba5b6050697615fab94ee1edf30f3634891923d
// summary : encode/decode 4 component vector into an integer
// keywords : scala, vector, conversions, @testable
// publish : gist
// authors : David Crosson
// license : Apache NON-AI License Version 2.0 (https://raw.githubusercontent.com/non-ai-licenses/non-ai-licenses/main/NON-AI-APACHE2)
// id : e3887820-4329-4e6d-94fe-bb37ef830d1f
// created-on : 2020-11-21T10:54:55Z
// managed-by : https://github.com/dacr/code-examples-manager
// run-with : scala-cli $file
// ---------------------
//> using scala "3.3.0"
//> using dep "org.scalatest::scalatest:3.2.16"
//> using objectWrapper
// ---------------------
import org.scalatest._, flatspec._, matchers._
// Vector of 4 bytes encoded into a single 32 bits Integer
type Vect4 = Int
def v4enc(a: Int, b: Int, c: Int, d: Int): Vect4 =
((a + 128) << 24) + ((b + 128) << 16) + ((c + 128) << 8) + (d + 128)
def v4dec(vect: Vect4): Array[Int] = Array(
(vect >>> 24 & 0xFF) - 128,
(vect >>> 16 & 0xFF) - 128,
(vect >>> 8 & 0xFF) - 128,
(vect & 0xFF) - 128
)
def v4get(vect: Vect4, i: Int): Int = {
if (i == 0) (vect >>> 24 & 0xFF) - 128
else if (i == 1) (vect >>> 16 & 0xFF) - 128
else if (i == 2) (vect >>> 8 & 0xFF) - 128
else (vect & 0xFF) - 128
}
//// GENERATES MANY BOX / UNBOX
def v4monoOp(a: Vect4, op: Int => Int): Vect4 = {
v4enc(
op((a >>> 24 & 0xFF) - 128),
op((a >>> 16 & 0xFF) - 128),
op((a >>> 8 & 0xFF) - 128),
op((a & 0xFF) - 128),
)
}
def v4biOp(a: Vect4, b: Vect4, op: (Int, Int) => Int): Vect4 = {
v4enc(
op((a >>> 24 & 0xFF) - 128, (b >>> 24 & 0xFF) - 128),
op((a >>> 16 & 0xFF) - 128, (b >>> 16 & 0xFF) - 128),
op((a >>> 8 & 0xFF) - 128, (b >>> 8 & 0xFF) - 128),
op((a & 0xFF) - 128, (b & 0xFF) - 128),
)
}
def v4addVect(a: Vect4, b: Vect4): Vect4 = {
//v4biOp(a, b, _ + _)
v4enc(
(a >>> 24 & 0xFF) - 128 + (b >>> 24 & 0xFF) - 128,
(a >>> 16 & 0xFF) - 128 + (b >>> 16 & 0xFF) - 128,
(a >>> 8 & 0xFF) - 128 + (b >>> 8 & 0xFF) - 128,
(a & 0xFF) - 128 + (b & 0xFF) - 128,
)
}
def v4minusVect(a: Vect4, b: Vect4): Vect4 = {
//v4biOp(a, b, _ - _)
v4enc(
((a >>> 24 & 0xFF) - 128) - ((b >>> 24 & 0xFF) - 128),
((a >>> 16 & 0xFF) - 128) - ((b >>> 16 & 0xFF) - 128),
((a >>> 8 & 0xFF) - 128) - ((b >>> 8 & 0xFF) - 128),
((a & 0xFF) - 128) - ((b & 0xFF) - 128),
)
}
def v4add(a: Vect4, b: Int): Vect4 = {
//v4monoOp(a, _ + b)
v4enc(
((a >>> 24 & 0xFF) - 128) + b,
((a >>> 16 & 0xFF) - 128) + b,
((a >>> 8 & 0xFF) - 128) + b,
((a & 0xFF) - 128) + b,
)
}
def v4add0(a: Vect4, b: Int): Vect4 = {
(a & 0x00FFFFFF) + ((((a >>> 24) - 128) + b + 128) << 24)
}
def v4minus(a: Vect4, b: Int): Vect4 = {
//v4monoOp(a, _ - b)
v4enc(
((a >>> 24 & 0xFF) - 128) - b,
((a >>> 16 & 0xFF) - 128) - b,
((a >>> 8 & 0xFF) - 128) - b,
((a & 0xFF) - 128) - b,
)
}
def v4mult(a: Vect4, b: Int): Vect4 = {
//v4monoOp(a, _ * b)
v4enc(
((a >>> 24 & 0xFF) - 128) * b,
((a >>> 16 & 0xFF) - 128) * b,
((a >>> 8 & 0xFF) - 128) * b,
((a & 0xFF) - 128) * b,
)
}
def v4eq(a: Vect4, b: Vect4): Boolean = a == b
val v4zero = v4enc(0, 0, 0, 0)
def v4map[T](vect: Vect4, process: (Int, Int, Int, Int) => T): T = {
process((vect >>> 24 & 0xFF) - 128,
(vect >>> 16 & 0xFF) - 128,
(vect >>> 8 & 0xFF) - 128,
(vect & 0xFF) - 128)
}
// is positive ? (zero is not considerated as positive)
def v4positive(vect: Vect4): Boolean = {
//!v4map(vect, (a, b, c, d) => a < 0 || b < 0 || c < 0 || d < 0) && vect != v4zero
vect != v4zero && !(
(((vect >>> 24 & 0xFF) - 128) < 0) ||
(((vect >>> 16 & 0xFF) - 128) < 0) ||
(((vect >>> 8 & 0xFF) - 128) < 0) ||
(((vect & 0xFF) - 128) < 0)
)
}
def v4negative(vect: Vect4): Boolean = {
//v4map(vect, (a, b, c, d) => a < 0 || b < 0 || c < 0 || d < 0)
(((vect >>> 24 & 0xFF) - 128) < 0) ||
(((vect >>> 16 & 0xFF) - 128) < 0) ||
(((vect >>> 8 & 0xFF) - 128) < 0) ||
(((vect & 0xFF) - 128) < 0)
}
// sum each vector component
def v4sum(vect: Vect4): Int = {
//v4map(vect, (a, b, c, d) => a + b + c + d)
(((vect >>> 24 & 0xFF) - 128)) +
(((vect >>> 16 & 0xFF) - 128)) +
(((vect >>> 8 & 0xFF) - 128)) +
(((vect & 0xFF) - 128))
}
// vect4 to string
def v4toString(vect: Vect4): String = {
v4map(vect, (a, b, c, d) => s"[$a,$b,$c,$d]")
}
class Vect4Test extends AnyFlatSpec with should.Matchers {
"vect4" should "decode" in {
def selfTest(data:Byte*):Unit =
v4dec(v4enc(data(0), data(1), data(2), data(3))) should contain theSameElementsAs data
selfTest(0,0,0,0)
selfTest(1,1,1,1)
selfTest(0,0,0,42)
selfTest(42,0,0,0)
selfTest(0,0,0,-42)
selfTest(-42,0,0,0)
selfTest(-1,-1,-1,-1)
selfTest(127,127,127,127)
selfTest(-128,-128,-128,-128)
}
it should "support mathematical operations between vectors" in {
v4addVect(v4enc(0,0,0,0), v4enc(0,0,0,1)) shouldBe v4enc(0,0,0,1)
v4addVect(v4enc(1,1,1,1), v4enc(1,1,1,1)) shouldBe v4enc(2,2,2,2)
v4addVect(v4enc(-1,-1,-1,-1), v4enc(1,1,1,1)) shouldBe v4enc(0,0,0,0)
v4addVect(v4enc(-128,-128,-128,-128), v4enc(1,1,1,1)) shouldBe v4enc(-127,-127,-127,-127)
v4minusVect(v4enc(127,127,127,127), v4enc(1,1,1,1)) shouldBe v4enc(126,126,126,126)
v4minusVect(v4enc(127,127,127,127), v4enc(127,127,127,127)) shouldBe v4enc(0,0,0,0)
}
it should "support mathematical operations with values" in {
v4add(v4enc(0,0,0,1), 1) shouldBe v4enc(1,1,1,2)
v4minus(v4enc(0,0,0,1), 10) shouldBe v4enc(-10,-10,-10,-9)
v4mult(v4enc(1,2,0,3), 2) shouldBe v4enc(2,4,0,6)
}
it should "be comparable" in {
v4positive(v4enc(0,0,0,0)) shouldBe false
v4positive(v4enc(0,0,0,1)) shouldBe true
}
it should "be summable" in {
v4sum(v4enc(0,0,0,0)) shouldBe 0
v4sum(v4enc(1,2,3,4)) shouldBe 10
v4sum(v4enc(127,127,127,127)) shouldBe 127*4
v4sum(v4enc(-1,-1,-1,-1)) shouldBe -4
v4sum(v4enc(-128,-128,-128,-128)) shouldBe -128*4
}
it should "be stringable" in {
v4toString(v4enc(0,0,0,0)) shouldBe "[0,0,0,0]"
v4toString(v4enc(1,2,3,4)) shouldBe "[1,2,3,4]"
v4toString(v4enc(-1,-2,-3,-4)) shouldBe "[-1,-2,-3,-4]"
}
it should "be possible to get parts" in {
val va = v4enc(100,101,102,103)
v4get(va,0) shouldBe 100
v4get(va,1) shouldBe 101
v4get(va,2) shouldBe 102
v4get(va,3) shouldBe 103
val vb = v4enc(-100,-101,-102,-103)
v4get(vb,0) shouldBe -100
v4get(vb,1) shouldBe -101
v4get(vb,2) shouldBe -102
v4get(vb,3) shouldBe -103
}
it should "provide some math helpers" in {
v4add0(v4enc(1,0,0,0), 1) shouldBe v4enc(2,0,0,0)
v4add0(v4enc(10,0,0,0), -11) shouldBe v4enc(-1,0,0,0)
v4add0(v4enc(-42,0,0,0), -11) shouldBe v4enc(-53,0,0,0)
}
}
org.scalatest.tools.Runner.main(Array("-oDF", "-s", classOf[Vect4Test].getName))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment