{-# LANGUAGE DataKinds #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeOperators #-}
module Database.Immutable
(
DB
, ByteStringIndex
, Word32Index
, Id(Id)
, Limit(Limit)
, length
, zeroId
, incId
, addLimit
, subIds
, (!)
, slice
, lookup
) where
import qualified Data.ByteString as B
import Data.Either (either)
import qualified Data.Vector.Storable as V
import qualified Data.Serialize as S
import Database.Immutable.Internal
import System.IO.Unsafe (unsafePerformIO)
import Prelude hiding (length, lookup)
length :: DB indexes a -> Limit a
length (DB _ _ offsets) = Limit (fromIntegral $ V.length offsets)
(!) :: S.Serialize a => DB indexes a -> Id a -> Maybe a
(!) (DB _ contents offsets) (Id index)
| Just count' <- count
, Just offset' <- offset = either (const Nothing) Just $ S.decode
$ B.take (fromIntegral count')
$ B.drop (fromIntegral offset') contents
| otherwise = Nothing
where
count = offsets V.!? fromIntegral index
offset
| index == 0 = Just 0
| otherwise = offsets V.!? (fromIntegral index - 1)
unsafeIndex :: S.Serialize a => DB indexes a -> Id a -> a
unsafeIndex (DB _ contents offsets) (Id index)
= either (error "unsafeIndex") id $ S.decode
$ B.take (fromIntegral count)
$ B.drop (fromIntegral offset) contents
where
count = offsets V.! fromIntegral index
offset
| index == 0 = 0
| otherwise = offsets V.! (fromIntegral index - 1)
slice :: S.Serialize a => Id a -> Limit a -> DB indexes a -> [a]
slice (Id index) (Limit limit) db@(DB _ _ offsets) = map
((db `unsafeIndex`) . Id . fromIntegral)
[index'..max index' (min (V.length offsets) (index' + fromIntegral limit)) - 1]
where
index' = fromIntegral $ max index 0
lookup
:: forall indexes s v a
. S.Serialize a
=> LookupIndex indexes s v a
=> Name s
-> v
-> DB indexes a
-> [a]
lookup name t db@(DB indexes _ _)
= map ((db `unsafeIndex`) . Id . fromIntegral) is
where
is = unsafePerformIO
$ lookupIndex (Indexes' indexes :: Indexes' indexes a) name t