{-# OPTIONS_HADDOCK not-home #-}
module Database.LSMTree.Internal.Index.Compact (
IndexCompact (..)
, search
, sizeInPages
, countClashes
, hasClashes
, toLBS
, headerLBS
, finalLBS
, word64VectorToChunk
, fromSBS
) where
import Control.DeepSeq (NFData (..))
import Control.Monad (when)
import Control.Monad.ST
import Data.Bit hiding (flipBit)
import Data.Bits (unsafeShiftR, (.&.))
import qualified Data.ByteString.Builder as BB
import qualified Data.ByteString.Builder.Extra as BB
import qualified Data.ByteString.Lazy as LBS
import Data.ByteString.Short (ShortByteString (..))
import Data.Map.Strict (Map)
import qualified Data.Map.Strict as Map
import Data.Maybe (fromMaybe)
import Data.Primitive.ByteArray (ByteArray (..), indexByteArray,
sizeofByteArray)
import Data.Primitive.Types (sizeOf)
import qualified Data.Vector.Algorithms.Search as VA
import qualified Data.Vector.Generic as VG
import qualified Data.Vector.Primitive as VP
import qualified Data.Vector.Unboxed as VU
import qualified Data.Vector.Unboxed.Base as VU
import Data.Word
import Database.LSMTree.Internal.BitMath
import Database.LSMTree.Internal.ByteString (byteArrayFromTo)
import Database.LSMTree.Internal.Chunk (Chunk (Chunk))
import qualified Database.LSMTree.Internal.Chunk as Chunk (toByteString)
import Database.LSMTree.Internal.Entry (NumEntries (..))
import Database.LSMTree.Internal.Map.Range (Bound (..))
import Database.LSMTree.Internal.Page
import Database.LSMTree.Internal.Serialise
import Database.LSMTree.Internal.Unsliced
import Database.LSMTree.Internal.Vector
data IndexCompact = IndexCompact {
IndexCompact -> Vector Word64
icPrimary :: {-# UNPACK #-} !(VU.Vector Word64)
, IndexCompact -> Vector Bit
icClashes :: {-# UNPACK #-} !(VU.Vector Bit)
, IndexCompact -> Map (Unsliced SerialisedKey) PageNo
icTieBreaker :: !(Map (Unsliced SerialisedKey) PageNo)
, IndexCompact -> Vector Bit
icLargerThanPage :: {-# UNPACK #-} !(VU.Vector Bit)
}
deriving stock (Int -> IndexCompact -> ShowS
[IndexCompact] -> ShowS
IndexCompact -> String
(Int -> IndexCompact -> ShowS)
-> (IndexCompact -> String)
-> ([IndexCompact] -> ShowS)
-> Show IndexCompact
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> IndexCompact -> ShowS
showsPrec :: Int -> IndexCompact -> ShowS
$cshow :: IndexCompact -> String
show :: IndexCompact -> String
$cshowList :: [IndexCompact] -> ShowS
showList :: [IndexCompact] -> ShowS
Show, IndexCompact -> IndexCompact -> Bool
(IndexCompact -> IndexCompact -> Bool)
-> (IndexCompact -> IndexCompact -> Bool) -> Eq IndexCompact
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: IndexCompact -> IndexCompact -> Bool
== :: IndexCompact -> IndexCompact -> Bool
$c/= :: IndexCompact -> IndexCompact -> Bool
/= :: IndexCompact -> IndexCompact -> Bool
Eq)
instance NFData IndexCompact where
rnf :: IndexCompact -> ()
rnf IndexCompact
ic = Vector Word64 -> ()
forall a. NFData a => a -> ()
rnf Vector Word64
a () -> () -> ()
forall a b. a -> b -> b
`seq` Vector Bit -> ()
forall a. NFData a => a -> ()
rnf Vector Bit
b () -> () -> ()
forall a b. a -> b -> b
`seq` Map (Unsliced SerialisedKey) PageNo -> ()
forall a. NFData a => a -> ()
rnf Map (Unsliced SerialisedKey) PageNo
c () -> () -> ()
forall a b. a -> b -> b
`seq` Vector Bit -> ()
forall a. NFData a => a -> ()
rnf Vector Bit
d
where IndexCompact Vector Word64
a Vector Bit
b Map (Unsliced SerialisedKey) PageNo
c Vector Bit
d = IndexCompact
ic
search :: SerialisedKey -> IndexCompact -> PageSpan
search :: SerialisedKey -> IndexCompact -> PageSpan
search SerialisedKey
k IndexCompact{Vector Word64
Vector Bit
Map (Unsliced SerialisedKey) PageNo
icPrimary :: IndexCompact -> Vector Word64
icClashes :: IndexCompact -> Vector Bit
icTieBreaker :: IndexCompact -> Map (Unsliced SerialisedKey) PageNo
icLargerThanPage :: IndexCompact -> Vector Bit
icPrimary :: Vector Word64
icClashes :: Vector Bit
icTieBreaker :: Map (Unsliced SerialisedKey) PageNo
icLargerThanPage :: Vector Bit
..} =
let !primbits :: Word64
primbits = SerialisedKey -> Word64
keyTopBits64 SerialisedKey
k in
case Word64 -> Vector Word64 -> Maybe Int
forall (v :: * -> *) e.
(Vector v e, Ord e) =>
e -> v e -> Maybe Int
unsafeSearchLE Word64
primbits Vector Word64
icPrimary of
Maybe Int
Nothing ->
if Vector Bit -> Int
forall a. Unbox a => Vector a -> Int
VU.length Vector Bit
icLargerThanPage Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0 then PageNo -> PageSpan
singlePage (Int -> PageNo
PageNo Int
0) else
let !i :: Int
i = Bound Int -> Bound Int -> Bit -> Vector Bit -> Int
bitLongestPrefixFromTo (Int -> Bound Int
forall k. k -> Bound k
BoundExclusive Int
0) Bound Int
forall k. Bound k
NoBound (Bool -> Bit
Bit Bool
True) Vector Bit
icLargerThanPage
in PageNo -> PageNo -> PageSpan
multiPage (Int -> PageNo
PageNo Int
0) (Int -> PageNo
PageNo Int
i)
Just !Int
i ->
if Bit -> Bool
unBit (Bit -> Bool) -> Bit -> Bool
forall a b. (a -> b) -> a -> b
$ Vector Bit
icClashes Vector Bit -> Int -> Bit
forall a. Unbox a => Vector a -> Int -> a
VU.! Int
i then
let
!i1 :: PageNo
i1 = Int -> PageNo
PageNo (Int -> PageNo) -> Int -> PageNo
forall a b. (a -> b) -> a -> b
$ Int -> Maybe Int -> Int
forall a. a -> Maybe a -> a
fromMaybe Int
0 (Maybe Int -> Int) -> Maybe Int -> Int
forall a b. (a -> b) -> a -> b
$
Bound Int -> Bound Int -> Bit -> Vector Bit -> Maybe Int
bitIndexFromToRev (Int -> Bound Int
forall k. k -> Bound k
BoundInclusive Int
0) (Int -> Bound Int
forall k. k -> Bound k
BoundInclusive Int
i) (Bool -> Bit
Bit Bool
False) Vector Bit
icClashes
!i2 :: PageNo
i2 = PageNo
-> ((Unsliced SerialisedKey, PageNo) -> PageNo)
-> Maybe (Unsliced SerialisedKey, PageNo)
-> PageNo
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (Int -> PageNo
PageNo Int
0) (Unsliced SerialisedKey, PageNo) -> PageNo
forall a b. (a, b) -> b
snd (Maybe (Unsliced SerialisedKey, PageNo) -> PageNo)
-> Maybe (Unsliced SerialisedKey, PageNo) -> PageNo
forall a b. (a -> b) -> a -> b
$
Unsliced SerialisedKey
-> Map (Unsliced SerialisedKey) PageNo
-> Maybe (Unsliced SerialisedKey, PageNo)
forall k v. Ord k => k -> Map k v -> Maybe (k, v)
Map.lookupLE (SerialisedKey -> Unsliced SerialisedKey
makeUnslicedKey SerialisedKey
k) Map (Unsliced SerialisedKey) PageNo
icTieBreaker
PageNo !Int
i3 = PageNo -> PageNo -> PageNo
forall a. Ord a => a -> a -> a
max PageNo
i1 PageNo
i2
!i4 :: Int
i4 = Bound Int -> Bound Int -> Bit -> Vector Bit -> Int
bitLongestPrefixFromTo (Int -> Bound Int
forall k. k -> Bound k
BoundExclusive Int
i3) (Int -> Bound Int
forall k. k -> Bound k
BoundInclusive Int
i) (Bool -> Bit
Bit Bool
True) Vector Bit
icLargerThanPage
in PageNo -> PageNo -> PageSpan
multiPage (Int -> PageNo
PageNo Int
i3) (Int -> PageNo
PageNo Int
i4)
else
PageNo -> PageSpan
singlePage (Int -> PageNo
PageNo Int
i)
countClashes :: IndexCompact -> Int
countClashes :: IndexCompact -> Int
countClashes = Map (Unsliced SerialisedKey) PageNo -> Int
forall k a. Map k a -> Int
Map.size (Map (Unsliced SerialisedKey) PageNo -> Int)
-> (IndexCompact -> Map (Unsliced SerialisedKey) PageNo)
-> IndexCompact
-> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. IndexCompact -> Map (Unsliced SerialisedKey) PageNo
icTieBreaker
hasClashes :: IndexCompact -> Bool
hasClashes :: IndexCompact -> Bool
hasClashes = Bool -> Bool
not (Bool -> Bool) -> (IndexCompact -> Bool) -> IndexCompact -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Map (Unsliced SerialisedKey) PageNo -> Bool
forall k a. Map k a -> Bool
Map.null (Map (Unsliced SerialisedKey) PageNo -> Bool)
-> (IndexCompact -> Map (Unsliced SerialisedKey) PageNo)
-> IndexCompact
-> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. IndexCompact -> Map (Unsliced SerialisedKey) PageNo
icTieBreaker
sizeInPages :: IndexCompact -> NumPages
sizeInPages :: IndexCompact -> NumPages
sizeInPages = Word -> NumPages
NumPages (Word -> NumPages)
-> (IndexCompact -> Word) -> IndexCompact -> NumPages
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> Word
forall a. Enum a => Int -> a
toEnum (Int -> Word) -> (IndexCompact -> Int) -> IndexCompact -> Word
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Vector Word64 -> Int
forall a. Unbox a => Vector a -> Int
VU.length (Vector Word64 -> Int)
-> (IndexCompact -> Vector Word64) -> IndexCompact -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. IndexCompact -> Vector Word64
icPrimary
toLBS :: NumEntries -> IndexCompact -> LBS.ByteString
toLBS :: NumEntries -> IndexCompact -> ByteString
toLBS NumEntries
numEntries IndexCompact
index =
ByteString
headerLBS
ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString -> ByteString
LBS.fromStrict (Chunk -> ByteString
Chunk.toByteString (Vector Word64 -> Chunk
word64VectorToChunk (IndexCompact -> Vector Word64
icPrimary IndexCompact
index)))
ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> NumEntries -> IndexCompact -> ByteString
finalLBS NumEntries
numEntries IndexCompact
index
supportedTypeAndVersion :: Word32
supportedTypeAndVersion :: Word32
supportedTypeAndVersion = Word32
0x0001
headerLBS :: LBS.ByteString
=
AllocationStrategy -> ByteString -> Builder -> ByteString
BB.toLazyByteStringWith (Int -> Int -> AllocationStrategy
BB.safeStrategy Int
4 Int
BB.smallChunkSize) ByteString
forall a. Monoid a => a
mempty (Builder -> ByteString) -> Builder -> ByteString
forall a b. (a -> b) -> a -> b
$
Word32 -> Builder
BB.word32Host Word32
supportedTypeAndVersion Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Word32 -> Builder
BB.word32Host Word32
0
finalLBS :: NumEntries -> IndexCompact -> LBS.ByteString
finalLBS :: NumEntries -> IndexCompact -> ByteString
finalLBS (NumEntries Int
numEntries) IndexCompact {Vector Word64
Vector Bit
Map (Unsliced SerialisedKey) PageNo
icPrimary :: IndexCompact -> Vector Word64
icClashes :: IndexCompact -> Vector Bit
icTieBreaker :: IndexCompact -> Map (Unsliced SerialisedKey) PageNo
icLargerThanPage :: IndexCompact -> Vector Bit
icPrimary :: Vector Word64
icClashes :: Vector Bit
icTieBreaker :: Map (Unsliced SerialisedKey) PageNo
icLargerThanPage :: Vector Bit
..} =
Builder -> ByteString
BB.toLazyByteString (Builder -> ByteString) -> Builder -> ByteString
forall a b. (a -> b) -> a -> b
$
Vector Bit -> Builder
putBitVec Vector Bit
icClashes
Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Vector Bit -> Builder
putBitVec Vector Bit
icLargerThanPage
Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Map (Unsliced SerialisedKey) PageNo -> Builder
putTieBreaker Map (Unsliced SerialisedKey) PageNo
icTieBreaker
Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Word64 -> Builder
BB.word64Host (Int -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
numPages)
Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Word64 -> Builder
BB.word64Host (Int -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
numEntries)
where
numPages :: Int
numPages = Vector Word64 -> Int
forall a. Unbox a => Vector a -> Int
VU.length Vector Word64
icPrimary
word64VectorToChunk :: VU.Vector Word64 -> Chunk
word64VectorToChunk :: Vector Word64 -> Chunk
word64VectorToChunk (VU.V_Word64 (VP.Vector Int
off Int
len ByteArray
ba)) =
Vector Word8 -> Chunk
Chunk (Int -> Int -> ByteArray -> Vector Word8
forall a. Prim a => Int -> Int -> ByteArray -> Vector a
mkPrimVector (Int -> Int
forall a. Bits a => a -> a
mul8 Int
off) (Int -> Int
forall a. Bits a => a -> a
mul8 Int
len) ByteArray
ba)
putBitVec :: VU.Vector Bit -> BB.Builder
putBitVec :: Vector Bit -> Builder
putBitVec (BitVec Int
offsetBits Int
lenBits ByteArray
ba)
| Int -> Int
forall a. (Bits a, Num a) => a -> a
mod8 Int
offsetBits Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
/= Int
0 = String -> Builder
forall a. HasCallStack => String -> a
error String
"putBitVec: not byte aligned"
| Bool
otherwise =
Int -> Int -> ByteArray -> Builder
byteArrayFromTo Int
offsetBytes Int
offsetLastByte ByteArray
ba
Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> (if Int
remainingBits Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
/= Int
0 then
Word8 -> Builder
BB.word8 (ByteArray -> Int -> Word8
forall a. Prim a => ByteArray -> Int -> a
indexByteArray ByteArray
ba Int
offsetLastByte Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
bitmaskLastByte)
else
Builder
forall a. Monoid a => a
mempty)
Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Int -> Builder
putPaddingTo64 Int
totalBytesWritten
where
offsetBytes :: Int
offsetBytes = Int -> Int
forall a. Bits a => a -> a
div8 Int
offsetBits
offsetLastByte :: Int
offsetLastByte = Int
offsetBytes Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int -> Int
forall a. Bits a => a -> a
div8 Int
lenBits
totalBytesWritten :: Int
totalBytesWritten = Int -> Int
forall a. (Bits a, Num a) => a -> a
ceilDiv8 Int
lenBits
bitmaskLastByte :: Word8
bitmaskLastByte = Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
unsafeShiftR Word8
0xFF (Int
8 Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
remainingBits)
remainingBits :: Int
remainingBits = Int -> Int
forall a. (Bits a, Num a) => a -> a
mod8 Int
lenBits
putTieBreaker :: Map (Unsliced SerialisedKey) PageNo -> BB.Builder
putTieBreaker :: Map (Unsliced SerialisedKey) PageNo -> Builder
putTieBreaker Map (Unsliced SerialisedKey) PageNo
m =
Word64 -> Builder
BB.word64Host (Int -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Map (Unsliced SerialisedKey) PageNo -> Int
forall k a. Map k a -> Int
Map.size Map (Unsliced SerialisedKey) PageNo
m))
Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> ((Unsliced SerialisedKey, PageNo) -> Builder)
-> [(Unsliced SerialisedKey, PageNo)] -> Builder
forall m a. Monoid m => (a -> m) -> [a] -> m
forall (t :: * -> *) m a.
(Foldable t, Monoid m) =>
(a -> m) -> t a -> m
foldMap (Unsliced SerialisedKey, PageNo) -> Builder
putEntry (Map (Unsliced SerialisedKey) PageNo
-> [(Unsliced SerialisedKey, PageNo)]
forall k a. Map k a -> [(k, a)]
Map.assocs Map (Unsliced SerialisedKey) PageNo
m)
where
putEntry :: (Unsliced SerialisedKey, PageNo) -> BB.Builder
putEntry :: (Unsliced SerialisedKey, PageNo) -> Builder
putEntry (Unsliced SerialisedKey -> SerialisedKey
fromUnslicedKey -> SerialisedKey
k, PageNo Int
pageNo) =
Word32 -> Builder
BB.word32Host (Int -> Word32
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
pageNo)
Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Word32 -> Builder
BB.word32Host (Int -> Word32
forall a b. (Integral a, Num b) => a -> b
fromIntegral (SerialisedKey -> Int
sizeofKey SerialisedKey
k))
Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> SerialisedKey -> Builder
serialisedKey SerialisedKey
k
Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Int -> Builder
putPaddingTo64 (SerialisedKey -> Int
sizeofKey SerialisedKey
k)
putPaddingTo64 :: Int -> BB.Builder
putPaddingTo64 :: Int -> Builder
putPaddingTo64 Int
written
| Int -> Int
forall a. (Bits a, Num a) => a -> a
mod8 Int
written Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0 = Builder
forall a. Monoid a => a
mempty
| Bool
otherwise = (Word8 -> Builder) -> [Word8] -> Builder
forall m a. Monoid m => (a -> m) -> [a] -> m
forall (t :: * -> *) m a.
(Foldable t, Monoid m) =>
(a -> m) -> t a -> m
foldMap Word8 -> Builder
BB.word8 (Int -> Word8 -> [Word8]
forall a. Int -> a -> [a]
replicate (Int
8 Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int -> Int
forall a. (Bits a, Num a) => a -> a
mod8 Int
written) Word8
0)
fromSBS :: ShortByteString -> Either String (NumEntries, IndexCompact)
fromSBS :: ShortByteString -> Either String (NumEntries, IndexCompact)
fromSBS (SBS ByteArray#
ba') = do
let ba :: ByteArray
ba = ByteArray# -> ByteArray
ByteArray ByteArray#
ba'
let len8 :: Int
len8 = ByteArray -> Int
sizeofByteArray ByteArray
ba
Bool -> Either String () -> Either String ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Int -> Int
forall a. (Bits a, Num a) => a -> a
mod8 Int
len8 Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
/= Int
0) (Either String () -> Either String ())
-> Either String () -> Either String ()
forall a b. (a -> b) -> a -> b
$ String -> Either String ()
forall a b. a -> Either a b
Left String
"Length is not multiple of 64 bit"
Bool -> Either String () -> Either String ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Int
len8 Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
24) (Either String () -> Either String ())
-> Either String () -> Either String ()
forall a b. (a -> b) -> a -> b
$ String -> Either String ()
forall a b. a -> Either a b
Left String
"Doesn't contain header and footer"
let typeAndVersion :: Word32
typeAndVersion = ByteArray -> Int -> Word32
forall a. Prim a => ByteArray -> Int -> a
indexByteArray ByteArray
ba Int
0 :: Word32
Bool -> Either String () -> Either String ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Word32
typeAndVersion Word32 -> Word32 -> Bool
forall a. Eq a => a -> a -> Bool
== Word32 -> Word32
byteSwap32 Word32
supportedTypeAndVersion)
(String -> Either String ()
forall a b. a -> Either a b
Left String
"Non-matching endianness")
Bool -> Either String () -> Either String ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Word32
typeAndVersion Word32 -> Word32 -> Bool
forall a. Eq a => a -> a -> Bool
/= Word32
supportedTypeAndVersion)
(String -> Either String ()
forall a b. a -> Either a b
Left String
"Unsupported type or version")
let len64 :: Int
len64 = Int -> Int
forall a. Bits a => a -> a
div8 Int
len8
let getPositive :: Int -> Either String Int
getPositive Int
off64 = do
let w :: Word64
w = ByteArray -> Int -> Word64
forall a. Prim a => ByteArray -> Int -> a
indexByteArray ByteArray
ba Int
off64 :: Word64
Bool -> Either String () -> Either String ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Word64
w Word64 -> Word64 -> Bool
forall a. Ord a => a -> a -> Bool
> Int -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int
forall a. Bounded a => a
maxBound :: Int)) (Either String () -> Either String ())
-> Either String () -> Either String ()
forall a b. (a -> b) -> a -> b
$
String -> Either String ()
forall a b. a -> Either a b
Left String
"Size information is too large for Int"
Int -> Either String Int
forall a. a -> Either String a
forall (m :: * -> *) a. Monad m => a -> m a
return (Word64 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word64
w)
Int
numPages <- Int -> Either String Int
getPositive (Int
len64 Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
2)
Int
numEntries <- Int -> Either String Int
getPositive (Int
len64 Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1)
let off1_64 :: Int
off1_64 = Int
1
(!Int
off2_64, Vector Word64
icPrimary) <- String
-> ByteArray -> Int -> Int -> Either String (Int, Vector Word64)
getVec64 String
"Primary array" ByteArray
ba Int
off1_64 Int
numPages
let !off3 :: Int
off3 = Int
off2_64
(!Int
off4, Vector Bit
icClashes) <- String
-> ByteArray -> Int -> Int -> Either String (Int, Vector Bit)
getBitVec String
"Clash bit vector" ByteArray
ba Int
off3 Int
numPages
(!Int
off5, Vector Bit
icLargerThanPage) <- String
-> ByteArray -> Int -> Int -> Either String (Int, Vector Bit)
getBitVec String
"LTP bit vector" ByteArray
ba Int
off4 Int
numPages
(!Int
off6, Map (Unsliced SerialisedKey) PageNo
icTieBreaker) <- ByteArray
-> Int -> Either String (Int, Map (Unsliced SerialisedKey) PageNo)
getTieBreaker ByteArray
ba Int
off5
let bytesUsed :: Int
bytesUsed = Int -> Int
forall a. Bits a => a -> a
mul8 (Int
off6 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
2)
Bool -> Either String () -> Either String ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Int
bytesUsed Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> ByteArray -> Int
sizeofByteArray ByteArray
ba) (Either String () -> Either String ())
-> Either String () -> Either String ()
forall a b. (a -> b) -> a -> b
$
String -> Either String ()
forall a b. a -> Either a b
Left String
"Byte array is too small for components"
Bool -> Either String () -> Either String ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Int
bytesUsed Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< ByteArray -> Int
sizeofByteArray ByteArray
ba) (Either String () -> Either String ())
-> Either String () -> Either String ()
forall a b. (a -> b) -> a -> b
$
String -> Either String ()
forall a b. a -> Either a b
Left String
"Byte array is too large for components"
(NumEntries, IndexCompact)
-> Either String (NumEntries, IndexCompact)
forall a. a -> Either String a
forall (m :: * -> *) a. Monad m => a -> m a
return (Int -> NumEntries
NumEntries Int
numEntries, IndexCompact {Vector Word64
Vector Bit
Map (Unsliced SerialisedKey) PageNo
icPrimary :: Vector Word64
icClashes :: Vector Bit
icTieBreaker :: Map (Unsliced SerialisedKey) PageNo
icLargerThanPage :: Vector Bit
icPrimary :: Vector Word64
icClashes :: Vector Bit
icLargerThanPage :: Vector Bit
icTieBreaker :: Map (Unsliced SerialisedKey) PageNo
..})
type Offset32 = Int
type Offset64 = Int
getVec64 ::
String -> ByteArray -> Offset32 -> Int
-> Either String (Offset64, VU.Vector Word64)
getVec64 :: String
-> ByteArray -> Int -> Int -> Either String (Int, Vector Word64)
getVec64 String
name ByteArray
ba Int
off64 Int
numEntries =
case Int -> Int -> ByteArray -> Maybe (Vector Word64)
forall a. Prim a => Int -> Int -> ByteArray -> Maybe (Vector a)
checkedPrimVec Int
off64 Int
numEntries ByteArray
ba of
Maybe (Vector Word64)
Nothing -> String -> Either String (Int, Vector Word64)
forall a b. a -> Either a b
Left (String
name String -> ShowS
forall a. Semigroup a => a -> a -> a
<> String
" is out of bounds")
Just Vector Word64
vec -> (Int, Vector Word64) -> Either String (Int, Vector Word64)
forall a b. b -> Either a b
Right (Int
off64 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
numEntries, Vector Word64 -> Vector Word64
VU.V_Word64 Vector Word64
vec)
getBitVec ::
String -> ByteArray -> Offset64 -> Int
-> Either String (Offset64, VU.Vector Bit)
getBitVec :: String
-> ByteArray -> Int -> Int -> Either String (Int, Vector Bit)
getBitVec String
name ByteArray
ba Int
off Int
numEntries =
case Int -> Int -> ByteArray -> Maybe (Vector Bit)
checkedBitVec (Int -> Int
forall a. Bits a => a -> a
mul64 Int
off) Int
numEntries ByteArray
ba of
Maybe (Vector Bit)
Nothing -> String -> Either String (Int, Vector Bit)
forall a b. a -> Either a b
Left (String
name String -> ShowS
forall a. Semigroup a => a -> a -> a
<> String
" is out of bounds")
Just Vector Bit
vec -> (Int, Vector Bit) -> Either String (Int, Vector Bit)
forall a b. b -> Either a b
Right (Int
off Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int -> Int
forall a. (Bits a, Num a) => a -> a
ceilDiv64 Int
numEntries, Vector Bit
vec)
getTieBreaker ::
ByteArray -> Offset64
-> Either String (Offset64, Map (Unsliced SerialisedKey) PageNo)
getTieBreaker :: ByteArray
-> Int -> Either String (Int, Map (Unsliced SerialisedKey) PageNo)
getTieBreaker ByteArray
ba = \Int
off -> do
Bool -> Either String () -> Either String ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Int -> Int
forall a. Bits a => a -> a
mul8 Int
off Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= ByteArray -> Int
sizeofByteArray ByteArray
ba) (Either String () -> Either String ())
-> Either String () -> Either String ()
forall a b. (a -> b) -> a -> b
$
String -> Either String ()
forall a b. a -> Either a b
Left String
"Tie breaker is out of bounds"
let size :: Int
size = Word64 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (ByteArray -> Int -> Word64
forall a. Prim a => ByteArray -> Int -> a
indexByteArray ByteArray
ba Int
off :: Word64)
(Int
off', [(Unsliced SerialisedKey, PageNo)]
pairs) <- Int
-> Int
-> [(Unsliced SerialisedKey, PageNo)]
-> Either String (Int, [(Unsliced SerialisedKey, PageNo)])
go Int
size (Int
off Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) []
(Int, Map (Unsliced SerialisedKey) PageNo)
-> Either String (Int, Map (Unsliced SerialisedKey) PageNo)
forall a. a -> Either String a
forall (m :: * -> *) a. Monad m => a -> m a
return (Int
off', [(Unsliced SerialisedKey, PageNo)]
-> Map (Unsliced SerialisedKey) PageNo
forall k a. Ord k => [(k, a)] -> Map k a
Map.fromList [(Unsliced SerialisedKey, PageNo)]
pairs)
where
go :: Int -> Offset64 -> [(Unsliced SerialisedKey, PageNo)]
-> Either String (Offset64, [(Unsliced SerialisedKey, PageNo)])
go :: Int
-> Int
-> [(Unsliced SerialisedKey, PageNo)]
-> Either String (Int, [(Unsliced SerialisedKey, PageNo)])
go Int
0 Int
off [(Unsliced SerialisedKey, PageNo)]
pairs = (Int, [(Unsliced SerialisedKey, PageNo)])
-> Either String (Int, [(Unsliced SerialisedKey, PageNo)])
forall a. a -> Either String a
forall (m :: * -> *) a. Monad m => a -> m a
return (Int
off, [(Unsliced SerialisedKey, PageNo)]
pairs)
go Int
n Int
off [(Unsliced SerialisedKey, PageNo)]
pairs = do
Bool -> Either String () -> Either String ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Int -> Int
forall a. Bits a => a -> a
mul8 Int
off Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= ByteArray -> Int
sizeofByteArray ByteArray
ba) (Either String () -> Either String ())
-> Either String () -> Either String ()
forall a b. (a -> b) -> a -> b
$
String -> Either String ()
forall a b. a -> Either a b
Left String
"Clash map entry is out of bounds"
let off32 :: Int
off32 = Int -> Int
forall a. Bits a => a -> a
mul2 Int
off
let !pageNo :: Int
pageNo = Word32 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (ByteArray -> Int -> Word32
forall a. Prim a => ByteArray -> Int -> a
indexByteArray ByteArray
ba Int
off32 :: Word32)
let keyLen8 :: Int
keyLen8 = Word32 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (ByteArray -> Int -> Word32
forall a. Prim a => ByteArray -> Int -> a
indexByteArray ByteArray
ba (Int
off32 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) :: Word32)
(Int
off', Unsliced SerialisedKey
key) <- Int -> Int -> Either String (Int, Unsliced SerialisedKey)
getKey (Int
off Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) Int
keyLen8
Int
-> Int
-> [(Unsliced SerialisedKey, PageNo)]
-> Either String (Int, [(Unsliced SerialisedKey, PageNo)])
go (Int
n Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1) Int
off' ((Unsliced SerialisedKey
key, Int -> PageNo
PageNo Int
pageNo) (Unsliced SerialisedKey, PageNo)
-> [(Unsliced SerialisedKey, PageNo)]
-> [(Unsliced SerialisedKey, PageNo)]
forall a. a -> [a] -> [a]
: [(Unsliced SerialisedKey, PageNo)]
pairs)
getKey :: Offset64 -> Int -> Either String (Offset64, Unsliced SerialisedKey)
getKey :: Int -> Int -> Either String (Int, Unsliced SerialisedKey)
getKey Int
off Int
len8 = do
let off8 :: Int
off8 = Int -> Int
forall a. Bits a => a -> a
mul8 Int
off
!SerialisedKey
key <- case Int -> Int -> ByteArray -> Maybe (Vector Word8)
forall a. Prim a => Int -> Int -> ByteArray -> Maybe (Vector a)
checkedPrimVec Int
off8 Int
len8 ByteArray
ba of
Maybe (Vector Word8)
Nothing -> String -> Either String SerialisedKey
forall a b. a -> Either a b
Left (String
"Clash map key is out of bounds")
Just Vector Word8
vec -> SerialisedKey -> Either String SerialisedKey
forall a b. b -> Either a b
Right (Vector Word8 -> SerialisedKey
SerialisedKey' Vector Word8
vec)
(Int, Unsliced SerialisedKey)
-> Either String (Int, Unsliced SerialisedKey)
forall a. a -> Either String a
forall (m :: * -> *) a. Monad m => a -> m a
return (Int
off Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int -> Int
forall a. (Bits a, Num a) => a -> a
ceilDiv8 Int
len8, SerialisedKey -> Unsliced SerialisedKey
makeUnslicedKey SerialisedKey
key)
checkedPrimVec :: forall a.
VP.Prim a => Int -> Int -> ByteArray -> Maybe (VP.Vector a)
checkedPrimVec :: forall a. Prim a => Int -> Int -> ByteArray -> Maybe (Vector a)
checkedPrimVec Int
off Int
len ByteArray
ba
| Int
off Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
0, a -> Int
forall a. Prim a => a -> Int
sizeOf (a
forall a. HasCallStack => a
undefined :: a) Int -> Int -> Int
forall a. Num a => a -> a -> a
* (Int
off Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
len) Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= ByteArray -> Int
sizeofByteArray ByteArray
ba =
Vector a -> Maybe (Vector a)
forall a. a -> Maybe a
Just (Int -> Int -> ByteArray -> Vector a
forall a. Prim a => Int -> Int -> ByteArray -> Vector a
mkPrimVector Int
off Int
len ByteArray
ba)
| Bool
otherwise =
Maybe (Vector a)
forall a. Maybe a
Nothing
checkedBitVec :: Int -> Int -> ByteArray -> Maybe (VU.Vector Bit)
checkedBitVec :: Int -> Int -> ByteArray -> Maybe (Vector Bit)
checkedBitVec Int
off Int
len ByteArray
ba
| Int
off Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
0, Int
off Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
len Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int -> Int
forall a. Bits a => a -> a
mul8 (ByteArray -> Int
sizeofByteArray ByteArray
ba) =
Vector Bit -> Maybe (Vector Bit)
forall a. a -> Maybe a
Just (Int -> Int -> ByteArray -> Vector Bit
BitVec Int
off Int
len ByteArray
ba)
| Bool
otherwise =
Maybe (Vector Bit)
forall a. Maybe a
Nothing
unsafeSearchLE ::
(VG.Vector v e, Ord e)
=> e -> v e -> Maybe Int
unsafeSearchLE :: forall (v :: * -> *) e.
(Vector v e, Ord e) =>
e -> v e -> Maybe Int
unsafeSearchLE e
e v e
vec = (forall s. ST s (Maybe Int)) -> Maybe Int
forall a. (forall s. ST s a) -> a
runST ((forall s. ST s (Maybe Int)) -> Maybe Int)
-> (forall s. ST s (Maybe Int)) -> Maybe Int
forall a b. (a -> b) -> a -> b
$ do
Mutable v s e
vec' <- v e -> ST s (Mutable v (PrimState (ST s)) e)
forall (m :: * -> *) (v :: * -> *) a.
(PrimMonad m, Vector v a) =>
v a -> m (Mutable v (PrimState m) a)
VG.unsafeThaw v e
vec
Int
i <- (e -> Bool) -> Mutable v (PrimState (ST s)) e -> ST s Int
forall (m :: * -> *) (v :: * -> * -> *) e.
(PrimMonad m, MVector v e) =>
(e -> Bool) -> v (PrimState m) e -> m Int
VA.gallopingSearchLeftP (e -> e -> Bool
forall a. Ord a => a -> a -> Bool
> e
e) Mutable v s e
Mutable v (PrimState (ST s)) e
vec'
Maybe Int -> ST s (Maybe Int)
forall a. a -> ST s a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Maybe Int -> ST s (Maybe Int)) -> Maybe Int -> ST s (Maybe Int)
forall a b. (a -> b) -> a -> b
$ if Int
i Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0 then Maybe Int
forall a. Maybe a
Nothing else Int -> Maybe Int
forall a. a -> Maybe a
Just (Int
i Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1)
bitIndexFromToRev :: Bound Int -> Bound Int -> Bit -> VU.Vector Bit -> Maybe Int
bitIndexFromToRev :: Bound Int -> Bound Int -> Bit -> Vector Bit -> Maybe Int
bitIndexFromToRev Bound Int
lb Bound Int
ub Bit
b Vector Bit
v = Int -> Int
reverseIx (Int -> Int) -> Maybe Int -> Maybe Int
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Bit -> Vector Bit -> Maybe Int
bitIndex Bit
b (Vector Bit -> Vector Bit
forall a. Unbox a => Vector a -> Vector a
VU.reverse (Vector Bit -> Vector Bit) -> Vector Bit -> Vector Bit
forall a b. (a -> b) -> a -> b
$ Int -> Int -> Vector Bit -> Vector Bit
forall a. Unbox a => Int -> Int -> Vector a -> Vector a
VU.slice Int
lb' (Int
ub' Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
lb' Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) Vector Bit
v)
where
reverseIx :: Int -> Int
reverseIx Int
x = Int
ub' Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
x
lb' :: Int
lb' = Bound Int -> Int
vectorLowerBound Bound Int
lb
ub' :: Int
ub' = Vector Bit -> Bound Int -> Int
forall (v :: * -> *) a. Vector v a => v a -> Bound Int -> Int
vectorUpperBound Vector Bit
v Bound Int
ub
bitIndexFromTo :: Bound Int -> Bound Int -> Bit -> VU.Vector Bit -> Maybe Int
bitIndexFromTo :: Bound Int -> Bound Int -> Bit -> Vector Bit -> Maybe Int
bitIndexFromTo Bound Int
lb Bound Int
ub Bit
b Vector Bit
v = Int -> Int
shiftIx (Int -> Int) -> Maybe Int -> Maybe Int
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Bit -> Vector Bit -> Maybe Int
bitIndex Bit
b (Int -> Int -> Vector Bit -> Vector Bit
forall a. Unbox a => Int -> Int -> Vector a -> Vector a
VU.slice Int
lb' (Int
ub' Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
lb' Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) Vector Bit
v)
where
shiftIx :: Int -> Int
shiftIx = (Int
lb'+)
lb' :: Int
lb' = Bound Int -> Int
vectorLowerBound Bound Int
lb
ub' :: Int
ub' = Vector Bit -> Bound Int -> Int
forall (v :: * -> *) a. Vector v a => v a -> Bound Int -> Int
vectorUpperBound Vector Bit
v Bound Int
ub
bitLongestPrefixFromTo :: Bound Int -> Bound Int -> Bit -> Vector Bit -> Int
bitLongestPrefixFromTo :: Bound Int -> Bound Int -> Bit -> Vector Bit -> Int
bitLongestPrefixFromTo Bound Int
lb Bound Int
ub Bit
b Vector Bit
v = Int -> (Int -> Int) -> Maybe Int -> Int
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Int
ub' (Int -> Int -> Int
forall a. Num a => a -> a -> a
subtract Int
1) (Maybe Int -> Int) -> Maybe Int -> Int
forall a b. (a -> b) -> a -> b
$ Bound Int -> Bound Int -> Bit -> Vector Bit -> Maybe Int
bitIndexFromTo Bound Int
lb Bound Int
ub (Bit -> Bit
toggle Bit
b) Vector Bit
v
where
toggle :: Bit -> Bit
toggle (Bit Bool
x) = Bool -> Bit
Bit (Bool -> Bool
not Bool
x)
ub' :: Int
ub' = Vector Bit -> Bound Int -> Int
forall (v :: * -> *) a. Vector v a => v a -> Bound Int -> Int
vectorUpperBound Vector Bit
v Bound Int
ub
vectorLowerBound :: Bound Int -> Int
vectorLowerBound :: Bound Int -> Int
vectorLowerBound = \case
Bound Int
NoBound -> Int
0
BoundExclusive Int
i -> Int
i Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1
BoundInclusive Int
i -> Int
i
vectorUpperBound :: VG.Vector v a => v a -> Bound Int -> Int
vectorUpperBound :: forall (v :: * -> *) a. Vector v a => v a -> Bound Int -> Int
vectorUpperBound v a
v = \case
Bound Int
NoBound -> v a -> Int
forall (v :: * -> *) a. Vector v a => v a -> Int
VG.length v a
v Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1
BoundExclusive Int
i -> Int
i Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1
BoundInclusive Int
i -> Int
i