Copyright | (C) Koz Ross 2019 |
---|---|
License | GPL version 3.0 or later |
Maintainer | koz.ross@retro-freedom.nz |
Stability | Experimental |
Portability | GHC only |
Safe Haskell | Trustworthy |
Language | Haskell2010 |
If a type a
is Finitary
, each inhabitant of a
has an index, which can
be represented as a byte string of a fixed length (as the number of indexes
is finite). Essentially, we can represent any value of a
as a fixed-length
string over an alphabet of cardinality \(256\). Based on this, we can derive
a Unbox
instance, representing a Vector
as a large byte string.
This also allows us to provide a Storable
instance for a
.
This encoding is fairly tight in terms of space use, especially for types whose cardinalities are large. Additionally, byte-access is considerably faster than bit-access on most architectures. If your types have large cardinalities, and minimal space use isn't a concern, this encoding is good.
Some architectures prefer whole-word access - on these, there can be some
overheads using this encoding. Additionally, the encoding and decoding step
for this encoding is longer than the one for Data.Finitary.PackWords. If
Cardinality a < Cardinality Word
, you should
consider a different encoding - in particular, check Data.Finitary.PackInto,
which is more flexible and faster, with greater control over space usage.
Documentation
data PackBytes (a :: Type) Source #
An opaque wrapper around a
, representing each value as a byte string.
Instances
(Finitary a, 1 <= Cardinality a) => MVector MVector (PackBytes a) Source # | |
Defined in Data.Finitary.PackBytes basicLength :: MVector s (PackBytes a) -> Int basicUnsafeSlice :: Int -> Int -> MVector s (PackBytes a) -> MVector s (PackBytes a) basicOverlaps :: MVector s (PackBytes a) -> MVector s (PackBytes a) -> Bool basicUnsafeNew :: PrimMonad m => Int -> m (MVector (PrimState m) (PackBytes a)) basicInitialize :: PrimMonad m => MVector (PrimState m) (PackBytes a) -> m () basicUnsafeReplicate :: PrimMonad m => Int -> PackBytes a -> m (MVector (PrimState m) (PackBytes a)) basicUnsafeRead :: PrimMonad m => MVector (PrimState m) (PackBytes a) -> Int -> m (PackBytes a) basicUnsafeWrite :: PrimMonad m => MVector (PrimState m) (PackBytes a) -> Int -> PackBytes a -> m () basicClear :: PrimMonad m => MVector (PrimState m) (PackBytes a) -> m () basicSet :: PrimMonad m => MVector (PrimState m) (PackBytes a) -> PackBytes a -> m () basicUnsafeCopy :: PrimMonad m => MVector (PrimState m) (PackBytes a) -> MVector (PrimState m) (PackBytes a) -> m () basicUnsafeMove :: PrimMonad m => MVector (PrimState m) (PackBytes a) -> MVector (PrimState m) (PackBytes a) -> m () basicUnsafeGrow :: PrimMonad m => MVector (PrimState m) (PackBytes a) -> Int -> m (MVector (PrimState m) (PackBytes a)) | |
(Finitary a, 1 <= Cardinality a) => Vector Vector (PackBytes a) Source # | |
Defined in Data.Finitary.PackBytes basicUnsafeFreeze :: PrimMonad m => Mutable Vector (PrimState m) (PackBytes a) -> m (Vector (PackBytes a)) basicUnsafeThaw :: PrimMonad m => Vector (PackBytes a) -> m (Mutable Vector (PrimState m) (PackBytes a)) basicLength :: Vector (PackBytes a) -> Int basicUnsafeSlice :: Int -> Int -> Vector (PackBytes a) -> Vector (PackBytes a) basicUnsafeIndexM :: Monad m => Vector (PackBytes a) -> Int -> m (PackBytes a) basicUnsafeCopy :: PrimMonad m => Mutable Vector (PrimState m) (PackBytes a) -> Vector (PackBytes a) -> m () | |
(Finitary a, 1 <= Cardinality a) => Bounded (PackBytes a) Source # | |
Eq (PackBytes a) Source # | |
Ord (PackBytes a) Source # | |
Defined in Data.Finitary.PackBytes | |
Show (PackBytes a) Source # | |
(Finitary a, 1 <= Cardinality a) => Storable (PackBytes a) Source # | |
Defined in Data.Finitary.PackBytes sizeOf :: PackBytes a -> Int # alignment :: PackBytes a -> Int # peekElemOff :: Ptr (PackBytes a) -> Int -> IO (PackBytes a) # pokeElemOff :: Ptr (PackBytes a) -> Int -> PackBytes a -> IO () # peekByteOff :: Ptr b -> Int -> IO (PackBytes a) # pokeByteOff :: Ptr b -> Int -> PackBytes a -> IO () # | |
Binary (PackBytes a) Source # | |
NFData (PackBytes a) Source # | |
Defined in Data.Finitary.PackBytes | |
(Finitary a, 1 <= Cardinality a) => Finitary (PackBytes a) Source # | |
Defined in Data.Finitary.PackBytes | |
(Finitary a, 1 <= Cardinality a) => Unbox (PackBytes a) Source # | |
Defined in Data.Finitary.PackBytes | |
Hashable (PackBytes a) Source # | |
Defined in Data.Finitary.PackBytes | |
newtype MVector s (PackBytes a) Source # | |
Defined in Data.Finitary.PackBytes | |
type Cardinality (PackBytes a) Source # | |
Defined in Data.Finitary.PackBytes type Cardinality (PackBytes a) = Cardinality a | |
newtype Vector (PackBytes a) Source # | |
Defined in Data.Finitary.PackBytes |
pattern Packed :: forall (a :: Type). (Finitary a, 1 <= Cardinality a) => PackBytes a -> a Source #
To provide (something that resembles a) data constructor for PackBytes
, we
provide the following pattern. It can be used like any other data
constructor:
import Data.Finitary.PackBytes anInt :: PackBytes Int anInt = Packed 10 isPackedEven :: PackBytes Int -> Bool isPackedEven (Packed x) = even x
Every pattern match, and data constructor call, performs a
\(\Theta(\log_{256}(\texttt{Cardinality a}))\) encoding or decoding of a
.
Use with this in mind.