shrub/pkg/hair/lib/Data/Noun/Atom.hs

153 lines
3.7 KiB
Haskell
Raw Normal View History

2019-05-10 05:45:28 +03:00
{-# LANGUAGE MagicHash, GeneralizedNewtypeDeriving, UnboxedTuples #-}
module Data.Noun.Atom where
import ClassyPrelude
2019-05-11 00:59:45 +03:00
import Control.Lens
-- import Prelude ((^))
2019-05-10 05:45:28 +03:00
import GHC.Integer.GMP.Internals
import GHC.Natural
import GHC.Prim
import GHC.Word
2019-05-11 00:59:45 +03:00
import GHC.Int
import Data.Bits
import Test.QuickCheck.Arbitrary
import Test.QuickCheck.Gen
2019-05-15 08:09:53 +03:00
import Text.Printf
2019-05-11 00:59:45 +03:00
--------------------------------------------------------------------------------
2019-05-10 05:45:28 +03:00
newtype Atom = MkAtom Natural
deriving newtype (Eq, Ord, Num, Bits, Enum, Real, Integral)
2019-05-11 00:59:45 +03:00
instance Show Atom where
show (MkAtom a) = show a
2019-05-11 00:59:45 +03:00
2019-05-13 23:46:05 +03:00
{-
An Atom with a bit-offset.
-}
2019-05-11 00:59:45 +03:00
data Cursor = Cursor
{ _cOffset :: {-# UNPACK #-} !Int
, _cBuffer :: {-# UNPACK #-} !Atom
}
deriving (Eq, Ord, Show)
data Slice = Slice
{ _sOffset :: {-# UNPACK #-} !Int
, _sWidth :: {-# UNPACK #-} !Int
, _sBuffer :: {-# UNPACK #-} !Atom
}
deriving (Eq, Ord, Show)
makeLenses ''Cursor
makeLenses ''Slice
-- Instances -------------------------------------------------------------------
2019-05-15 04:30:44 +03:00
instance Arbitrary Natural where
arbitrary = fromInteger . abs <$> arbitrary
instance Arbitrary Atom where
2019-05-15 04:30:44 +03:00
arbitrary = MkAtom <$> arbitrary
-- Conversion ------------------------------------------------------------------
class IsAtom a where
toAtom :: a -> Atom
fromAtom :: Atom -> a
2019-05-15 04:30:44 +03:00
instance IsAtom Natural where
toAtom = MkAtom
fromAtom (MkAtom a) = a
2019-05-15 08:09:53 +03:00
instance IsAtom Word where
toAtom = fromIntegral
fromAtom = fromIntegral
instance IsAtom Int where
toAtom = fromIntegral
fromAtom = fromIntegral
2019-05-15 04:30:44 +03:00
instance IsAtom Integer where
toAtom = fromIntegral
fromAtom = fromIntegral
2019-05-11 00:59:45 +03:00
--------------------------------------------------------------------------------
2019-05-10 05:45:28 +03:00
2019-05-13 23:46:05 +03:00
{-
TODO Support 32-bit archetectures.
-}
2019-05-10 05:45:28 +03:00
wordBitWidth :: Word# -> Word#
wordBitWidth w = minusWord# 64## (clz# w)
bigNatBitWidth :: BigNat -> Word#
bigNatBitWidth nat =
lswBits `plusWord#` ((int2Word# lastIdx) `timesWord#` 64##)
where
(# lastIdx, _ #) = subIntC# (sizeofBigNat# nat) 1#
lswBits = wordBitWidth (indexBigNat# nat lastIdx)
2019-05-11 00:59:45 +03:00
bitWidth :: Atom -> Int
bitWidth (MkAtom (NatS# gl)) = I# (word2Int# (wordBitWidth gl))
bitWidth (MkAtom (NatJ# bn)) = I# (word2Int# (bigNatBitWidth bn))
2019-05-11 00:59:45 +03:00
--------------------------------------------------------------------------------
cursor :: Atom -> Atom -> Cursor
cursor offset buf = Cursor (fromIntegral offset) buf
fromCursor :: Cursor -> Atom
fromCursor (Cursor off buf) = shiftR buf off
bumpCursor :: Word -> Cursor -> Cursor
bumpCursor off = over cOffset (+ fromIntegral off)
--------------------------------------------------------------------------------
slice :: (Atom, Atom) -> Atom -> Atom
slice (offset, size) buf =
fromSlice (Slice (fromAtom offset) (fromAtom size) buf)
2019-05-11 00:59:45 +03:00
fromSlice :: Slice -> Atom
fromSlice (Slice off wid buf) = mask .&. (shiftR buf off)
where mask = shiftL (MkAtom 1) wid - 1
2019-05-11 00:59:45 +03:00
--------------------------------------------------------------------------------
takeBits :: Int -> Atom -> Atom
2019-05-11 00:59:45 +03:00
takeBits wid buf = mask .&. buf
where mask = shiftL (MkAtom 1) wid - 1
2019-05-11 00:59:45 +03:00
bitIdx :: Int -> Atom -> Bool
bitIdx idx buf = testBit buf idx
bitConcat :: Atom -> Atom -> Atom
2019-05-15 04:30:44 +03:00
bitConcat x y = x .|. shiftL y (bitWidth x)
2019-05-15 08:09:53 +03:00
-- Bit Buffers -----------------------------------------------------------------
data Buf = Buf !Int !Atom
instance Show Buf where
show (Buf sz bits) = "0b"
<> replicate (sz - bitWidth bits) '0'
<> printf "%b (%d bits)" (toInteger bits) sz
instance Semigroup Buf where
Buf xSz xBuf <> Buf ySz yBuf = Buf (xSz+ySz) (xBuf .|. shiftL yBuf xSz)
instance Monoid Buf where
mempty = Buf 0 0
instance IsAtom Buf where
toAtom (Buf _ bits) = bits
fromAtom bits = Buf (bitWidth bits) bits