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.