2018-05-05 18:23:21 +00:00
|
|
|
package com.htmlism
|
|
|
|
|
2020-08-13 01:18:38 +00:00
|
|
|
import scala.annotation.tailrec
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Given an `Int`, destructure it into smaller `Int`s that use less bits
|
|
|
|
*/
|
2022-02-14 23:11:45 +00:00
|
|
|
trait BitExtractor[A]:
|
2018-05-05 18:23:21 +00:00
|
|
|
self =>
|
|
|
|
|
|
|
|
def length: Int
|
|
|
|
|
|
|
|
def unapply(n: Int): Option[A]
|
|
|
|
|
2020-08-13 01:18:38 +00:00
|
|
|
/**
|
|
|
|
* A combinator for appending one extractor to another
|
|
|
|
*/
|
2018-05-05 18:23:21 +00:00
|
|
|
def >>[B](that: BitExtractor[B]): BitExtractor[(A, B)] =
|
2022-09-07 15:21:22 +00:00
|
|
|
new BitExtractor[(A, B)]:
|
2018-05-05 18:23:21 +00:00
|
|
|
def length: Int = self.length + that.length
|
|
|
|
|
|
|
|
def unapply(n: Int): Option[(A, B)] =
|
2023-10-23 17:56:45 +00:00
|
|
|
for
|
2022-12-02 01:44:59 +00:00
|
|
|
b <- that.unapply(n)
|
2018-05-05 18:23:21 +00:00
|
|
|
shifted = n >> that.length
|
2022-12-02 01:44:59 +00:00
|
|
|
a <- self.unapply(shifted)
|
2023-10-23 17:56:45 +00:00
|
|
|
yield (a, b)
|
2018-05-05 18:23:21 +00:00
|
|
|
|
2022-02-14 23:11:45 +00:00
|
|
|
object AtomExtractor:
|
2020-08-13 01:18:38 +00:00
|
|
|
@tailrec
|
2018-05-05 18:23:21 +00:00
|
|
|
def pow(ex: Int, acc: Int = 1): Int =
|
2023-10-03 20:15:10 +00:00
|
|
|
if ex == 0 then acc
|
|
|
|
else pow(ex - 1, acc * 2)
|
2018-05-05 18:23:21 +00:00
|
|
|
|
2022-02-14 23:11:45 +00:00
|
|
|
abstract class PrimitiveBitExtractor(val length: Int) extends BitExtractor[Int]:
|
2020-08-13 01:18:38 +00:00
|
|
|
private lazy val mask =
|
|
|
|
AtomExtractor.pow(length) - 1
|
2018-05-05 18:23:21 +00:00
|
|
|
|
2020-08-13 01:18:38 +00:00
|
|
|
def unapply(n: Int): Option[Int] =
|
|
|
|
Some(n & mask)
|
2018-05-05 18:23:21 +00:00
|
|
|
|
2022-12-02 01:44:59 +00:00
|
|
|
object OneBit extends PrimitiveBitExtractor(1)
|
|
|
|
object TwoBits extends PrimitiveBitExtractor(2)
|
2018-09-26 02:57:26 +00:00
|
|
|
object ThreeBits extends PrimitiveBitExtractor(3)
|