1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
|
package main.utils
object ByteUtils {
trait SizedNumeric[T] {
def manifest: Manifest[T]
def byteSize: Int
def bitSize: Int
def fromLong(l: Long): T
def toLong(l: T): Long
def buildFrom[U : SizedNumeric](from: U): T = fromLong(from.toLong)
def truncate[U : SizedNumeric](from: U): T = buildFrom(from)
override def toString = s"SizedNumeric[${manifest}]"
}
trait BitOps[T] {
def @>>>(t: T, x: Int): T
def @<<(t: T, x: Int): T
def @|(a: T, b: T): T
def @&(a: T, b: T): T
def @+(a: T, b: T): T
}
implicit val byteOps: BitOps[Byte] = new BitOps[Byte] {
def @>>>(t: Byte, x: Int): Byte = (t >>> x).toByte
def @<<(t: Byte, x: Int): Byte = (t << x).toByte
def @|(a: Byte, b: Byte): Byte = (a | b).toByte
def @&(a: Byte, b: Byte): Byte = (a & b).toByte
def @+(a: Byte, b: Byte): Byte = (a + b).toByte
}
implicit val intOps: BitOps[Int] = new BitOps[Int] {
def @>>>(t: Int, x: Int): Int = t >>> x
def @<<(t: Int, x: Int): Int = (t << x)
def @|(a: Int, b: Int): Int = a | b
def @&(a: Int, b: Int): Int = a & b
def @+(a: Int, b: Int): Int = a + b
}
implicit class WithBitOpts[T : BitOps](x: T) {
def @>>>(b: Int): T = implicitly[BitOps[T]].@>>>(x, b)
def @<<(b: Int): T = implicitly[BitOps[T]].@<<(x, b)
def @|(b: T): T = implicitly[BitOps[T]].@|(x, b)
def @&(b: T): T = implicitly[BitOps[T]].@&(x, b)
def @+(b: T): T = implicitly[BitOps[T]].@+(x, b)
}
implicit class SizedWithByteInfo[T : SizedNumeric](x: T) {
def byteSize = implicitly[SizedNumeric[T]].byteSize
def bitSize = implicitly[SizedNumeric[T]].bitSize
def toLong = implicitly[SizedNumeric[T]].toLong(x)
def liftedTo[U : SizedNumeric]: U = {
val uSize = implicitly[SizedNumeric[U]]
val tSize = implicitly[SizedNumeric[T]]
if (uSize.byteSize < tSize.byteSize) {
throw new RuntimeException(s"Target size ($uSize) is smaller than the source size ($tSize)")
}
uSize.buildFrom(x)
}
def truncatedTo[U : SizedNumeric]: U = {
implicitly[SizedNumeric[U]].truncate(x)
}
}
implicit class RichArrayOfBytes(b: Array[Byte]) {
def to[T : SizedNumeric : BitOps]: T = {
val numeric = implicitly[SizedNumeric[T]]
if(b.length < numeric.byteSize) {
throw new RuntimeException("Byte input is not long enough")
}
var out: Long = b(0)
for(i <- 1 until numeric.byteSize) {
out << 8
out = b(i) | out
}
numeric.fromLong(out)
}
}
def sizedNumeric[T : Manifest](bytes: Int)(from: Long => T)(to: T => Long) = new SizedNumeric[T] {
def manifest = implicitly[Manifest[T]]
def byteSize = bytes
def bitSize = bytes * 8
def toLong(t: T) = to(t)
def fromLong(l: Long) = from(l)
}
implicit val intSized = sizedNumeric(4) { x: Long => x.toInt } { _.toLong }
implicit val shortized = sizedNumeric(2) { x: Long => x.toShort } { _.toLong }
implicit val byteSized = sizedNumeric(1) { x: Long => x.toByte } { _.toLong }
def toArrayBuf[T : SizedNumeric : BitOps](x: T): Array[Byte] = {
val buf = new Array[Byte](x.byteSize)
for(i <- 0 until x.byteSize) {
val shiftAmount: Int = (x.byteSize - i - 1) << 3
buf(i) = (x @>>> shiftAmount).truncatedTo[Byte]
}
buf
}
def toBinaryString[T : SizedNumeric](x: T)(implicit a: BitOps[T]): String = {
val buf = new StringBuilder(x.bitSize)
for(i <- 0 until x.bitSize) {
val shiftAmount: Int = x.bitSize - i - 1
buf.append((x @>>> shiftAmount) @& 0x01.liftedTo[T])
}
buf.toString()
}
}
|