{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE MultiWayIf #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
module BTree.Store
( BTree
, Initialize(..)
, Deinitialize(..)
, Decision(..)
, new
, free
, with
, with_
, lookup
, insert
, modifyWithM_
, modifyWithM
, modifyWithPtr
, foldrWithKey
, toAscList
, index
, indexNode
, inlineModifyWithPtr
, inlineModifyWithM
) where
import Initialize
import Prelude hiding (lookup)
import Foreign.Storable
import Foreign.Ptr
import Foreign.Marshal.Alloc hiding (free)
import Foreign.Marshal.Array
import Data.Bits
import Data.Word
import Data.Int
import GHC.Ptr (Ptr(..))
import GHC.Magic (inline)
import qualified Data.Primitive.Addr as PA
import qualified Foreign.Marshal.Alloc as FMA
data BTree k v = BTree
!Int
!(Ptr (Node k v))
data Node k v
instance Storable (BTree k v) where
sizeOf _ = 2 * sizeOf (undefined :: Int)
alignment _ = alignment (undefined :: Int)
peek ptr = do
height <- peekElemOff (castPtr ptr :: Ptr Int) 0
root <- peekElemOff (castPtr ptr :: Ptr (Ptr (Node k v))) 1
return (BTree height root)
poke ptr (BTree height root) = do
pokeElemOff (castPtr ptr :: Ptr Int) 0 height
pokeElemOff (castPtr ptr :: Ptr (Ptr (Node k v))) 1 root
instance Initialize (BTree k v) where
initialize ptr = do
pokeElemOff (castPtr ptr :: Ptr Int) 0 (0 :: Int)
pokeElemOff (castPtr ptr :: Ptr (Ptr (Node k v))) 1 =<< newNode 0
instance (Storable k, Deinitialize v) => Deinitialize (BTree k v) where
deinitialize ptr = do
bt <- peek ptr
free bt
ptrToAddr :: Ptr a -> PA.Addr
ptrToAddr (Ptr x) = PA.Addr x
newtype Arr a = Arr { getArr :: Ptr a }
data KeysValues k v = KeysValues !(Arr k) !(Arr v)
data KeysNodes k v = KeysNodes !(Arr k) !(Arr (Ptr (Node k v)))
new :: forall k v. (Storable k, Storable v) => IO (BTree k v)
new = do
let childDegree = calcChildDegree (undefined :: Ptr (Node k v))
branchDegree = calcBranchDegree (undefined :: Ptr (Node k v))
if childDegree < minimumDegree
then fail $ "Btree.new: child degree cannot be less than " ++ show minimumDegree
else return ()
if branchDegree < minimumDegree
then fail $ "Btree.new: branch degree cannot be less than " ++ show minimumDegree
else return ()
ptr <- newNode 0
return (BTree 0 ptr)
minimumDegree :: Int
minimumDegree = 6
free :: forall k v. (Storable k, Deinitialize v) => BTree k v -> IO ()
free (BTree height root) = go height root
where
branchDegree :: Int
!branchDegree = calcBranchDegree root
childDegree :: Int
!childDegree = calcChildDegree root
go :: Int -> Ptr (Node k v) -> IO ()
go n ptrNode = if n > 0
then do
sz <- readNodeSize ptrNode
let KeysNodes _ nodes = readNodeKeysNodes branchDegree ptrNode
arrMapM_ (go (n - 1)) (sz + 1) nodes
FMA.free ptrNode
else do
sz <- readNodeSize ptrNode
let KeysValues _ values = readNodeKeysValues childDegree ptrNode
deinitializeElems (getArr values) sz
FMA.free ptrNode
with :: (Storable k, Initialize v, Deinitialize v) => (BTree k v -> IO (a, BTree k v)) -> IO a
with f = do
initial <- new
(a,final) <- f initial
free final
return a
with_ :: (Storable k, Initialize v, Deinitialize v) => (BTree k v -> IO (BTree k v)) -> IO ()
with_ f = do
initial <- new
final <- f initial
free final
newNode ::
Int
-> IO (Ptr (Node k v))
newNode n = do
ptr <- mallocBytes maxSize
poke ptr n
return (castPtr ptr)
readArr :: Storable a => Arr a -> Int -> IO a
readArr (Arr ptr) ix = peekElemOff ptr ix
writeArr :: Storable a => Arr a -> Int -> a -> IO ()
writeArr (Arr ptr) ix a = pokeElemOff ptr ix a
readNodeSize :: Ptr (Node k v) -> IO Int
readNodeSize ptr = peek (castPtr ptr)
writeNodeSize :: Ptr (Node k v) -> Int -> IO ()
writeNodeSize ptr sz = poke (castPtr ptr) sz
readNodeKeys :: forall k v. Storable k => Ptr (Node k v) -> Arr k
readNodeKeys ptr1 =
let ptr2 = plusPtr ptr1 (sizeOf (undefined :: Int))
ptr3 = alignPtr ptr2 (alignment (undefined :: k))
in Arr ptr3
readNodeKeysValues :: forall k v. Storable k => Int -> Ptr (Node k v) -> KeysValues k v
readNodeKeysValues degree ptr1 =
let keys = readNodeKeys ptr1
ptr2 = plusPtr (getArr keys) (sizeOf (undefined :: k) * (degree - 1))
ptr3 = alignPtr ptr2 (alignment (undefined :: k))
in KeysValues keys (Arr ptr3)
readNodeKeysNodes :: forall k v. Storable k => Int -> Ptr (Node k v) -> KeysNodes k v
readNodeKeysNodes degree ptr1 =
let keys = readNodeKeys ptr1
ptr2 = plusPtr (getArr keys) (sizeOf (undefined :: k) * (degree - 1))
ptr3 = alignPtr ptr2 (alignment (undefined :: (Ptr (Node k v))))
in KeysNodes keys (Arr ptr3)
maxSize :: Int
maxSize = 4096 - 2 * sizeOf (undefined :: Int)
{-# INLINE calcBranchDegree #-}
calcBranchDegree :: forall k v. (Storable k, Storable v) => Ptr (Node k v) -> Int
calcBranchDegree _ = calcBranchDegreeInt (sizeOf (undefined :: k)) (alignment (undefined :: k))
{-# INLINE calcBranchDegreeInt #-}
calcBranchDegreeInt :: Int -> Int -> Int
calcBranchDegreeInt keySz keyAlignment =
let space = maxSize - max (sizeOf (undefined :: Int)) keyAlignment - sizeOf (undefined :: Ptr a)
allowedNodes = quot space (sizeOf (undefined :: Ptr a) + keySz)
in allowedNodes
{-# INLINE calcChildDegree #-}
calcChildDegree :: forall k v. (Storable k, Storable v) => Ptr (Node k v) -> Int
calcChildDegree _ = calcChildDegreeInt
(sizeOf (undefined :: k))
(alignment (undefined :: k))
(sizeOf (undefined :: v))
{-# INLINE calcChildDegreeInt #-}
calcChildDegreeInt :: Int -> Int -> Int -> Int
calcChildDegreeInt keySz keyAlignment valueSz =
let space = maxSize - max (sizeOf (undefined :: Int)) keyAlignment - valueSz
allowedValues = quot space (valueSz + keySz)
in allowedValues + 1
{-# INLINABLE lookup #-}
lookup :: forall k v. (Ord k, Storable k, Storable v)
=> BTree k v -> k -> IO (Maybe v)
lookup (BTree height rootNode) k = go height rootNode
where
branchDegree :: Int
!branchDegree = calcBranchDegree rootNode
childDegree :: Int
childDegree = calcChildDegree rootNode
go :: Int -> Ptr (Node k v) -> IO (Maybe v)
go !n !ptrNode = if n > 0
then do
!sz <- readNodeSize ptrNode
let !(KeysNodes keys nodes) = readNodeKeysNodes branchDegree ptrNode
!ix <- findIndexOfGtElem keys k sz
!node <- readArr nodes ix
go (n - 1) node
else do
!sz <- readNodeSize ptrNode
let !(KeysValues keys values) = readNodeKeysValues childDegree ptrNode
!ix <- findIndex keys k sz
if ix < 0
then return Nothing
else do
!v <- readArr values ix
return (Just v)
index :: forall k v. (Storable k, Storable v) => BTree k v -> (Int -> Int) -> Int -> IO v
index (BTree height rootNode) f = go height rootNode
where
branchDegree :: Int
!branchDegree = calcBranchDegree rootNode
go :: Int -> Ptr (Node k v) -> Int -> IO v
go !n !ptrNode !k = if n > 0
then do
!sz <- readNodeSize ptrNode
let !ix = mod k sz
let !(KeysNodes keys nodes) = readNodeKeysNodes branchDegree ptrNode
!node <- readArr nodes ix
go (n - 1) node (f k)
else do
!sz <- readNodeSize ptrNode
let !(KeysValues keys !values) = readNodeKeysValues (calcChildDegree rootNode) ptrNode
readArr values (mod k sz)
indexNode :: forall k v. (Storable k, Storable v) => BTree k v -> (Int -> Int) -> Int -> IO (Ptr v, Int)
indexNode (BTree height rootNode) f = go height rootNode
where
branchDegree :: Int
!branchDegree = calcBranchDegree rootNode
go :: Int -> Ptr (Node k v) -> Int -> IO (Ptr v, Int)
go !n !ptrNode !k = if n > 0
then do
!sz <- readNodeSize ptrNode
let !ix = mod k sz
let !(KeysNodes keys nodes) = readNodeKeysNodes branchDegree ptrNode
!node <- readArr nodes ix
go (n - 1) node (f k)
else do
!sz <- readNodeSize ptrNode
let !(KeysValues keys !values) = readNodeKeysValues (calcChildDegree rootNode) ptrNode
return (getArr values, sz)
data Insert k v r
= Ok !r
| Split !(Ptr (Node k v)) !k !r
| TooSmall !r
| TotallyEmpty !(Ptr (Node k v)) !r
{-# INLINE insert #-}
insert :: (Ord k, Storable k, Initialize v)
=> BTree k v
-> k
-> v
-> IO (BTree k v)
insert !m !k !v = do
!(!(),!node) <- modifyWithPtr m k
(Right (\ptr ix -> pokeElemOff ptr ix v))
(\ptr ix -> pokeElemOff ptr ix v >> return ((),Keep))
return node
data Decision = Keep | Delete
{-# INLINE modifyWithM_ #-}
modifyWithM_ :: forall k v. (Ord k, Storable k, Initialize v)
=> BTree k v
-> k
-> (v -> IO v)
-> IO (BTree k v)
modifyWithM_ bt k alter = do
(_, bt') <- modifyWithPtr bt k
(Right (\ptr ix -> peekElemOff ptr ix >>= alter >>= pokeElemOff ptr ix))
(\ptr ix -> peekElemOff ptr ix >>= alter >>= pokeElemOff ptr ix >>= \_ -> return ((),Keep))
return bt'
{-# INLINE modifyWithM #-}
modifyWithM :: forall k v a. (Ord k, Storable k, Initialize v)
=> BTree k v
-> k
-> (v -> IO (a, v))
-> IO (a, BTree k v)
modifyWithM bt k alter = do
(a, bt') <- modifyWithPtr bt k
(Right (\ptr ix -> do
(a,v') <- alter =<< peekElemOff ptr ix
pokeElemOff ptr ix v'
return a
))
(\ptr ix -> do
(a,v') <- alter =<< peekElemOff ptr ix
pokeElemOff ptr ix v'
return (a,Keep)
)
return (a,bt')
{-# INLINE inlineModifyWithM #-}
inlineModifyWithM :: forall k v a. (Ord k, Storable k, Initialize v)
=> BTree k v
-> k
-> (v -> IO (a, v))
-> IO (a, BTree k v)
inlineModifyWithM bt k alter = do
(a, bt') <- inlineModifyWithPtr bt k
(Right (\ptr ix -> do
(a,v') <- alter =<< peekElemOff ptr ix
pokeElemOff ptr ix v'
return a
))
(\ptr ix -> do
(a,v') <- alter =<< peekElemOff ptr ix
pokeElemOff ptr ix v'
return (a,Keep)
)
return (a,bt')
{-# NOINLINE modifyWithPtr #-}
modifyWithPtr :: forall k v r. (Ord k, Storable k, Initialize v)
=> BTree k v
-> k
-> (Either r (Ptr v -> Int -> IO r))
-> (Ptr v -> Int -> IO (r,Decision))
-> IO (r, BTree k v)
modifyWithPtr a b c d = inlineModifyWithPtr a b c d
{-# INLINE inlineModifyWithPtr #-}
inlineModifyWithPtr :: forall k v r. (Ord k, Storable k, Initialize v)
=> BTree k v
-> k
-> (Either r (Ptr v -> Int -> IO r))
-> (Ptr v -> Int -> IO (r,Decision))
-> IO (r, BTree k v)
inlineModifyWithPtr (BTree !height !root) !k !mpostInitializeElemOff alterElemOff = do
!ins <- go height root
case ins of
Ok !r -> return (r, BTree height root)
TotallyEmpty child r -> do
FMA.free root
return (r, BTree (height - 1) child)
TooSmall !r -> return (r, BTree 0 root)
Split !rightNode !newRootKey !v -> do
newRoot <- newNode 1
let KeysNodes keys nodes = readNodeKeysNodes branchDegree newRoot
leftNode = root
writeArr keys 0 newRootKey
writeArr nodes 0 leftNode
writeArr nodes 1 rightNode
return (v,BTree (height + 1) newRoot)
where
childDegree :: Int
!childDegree = calcChildDegree root
branchDegree :: Int
!branchDegree = calcBranchDegree root
go :: Int -> Ptr (Node k v) -> IO (Insert k v r)
go n ptrNode = if n > 0
then do
sz <- readNodeSize ptrNode
let KeysNodes keys nodes = readNodeKeysNodes branchDegree ptrNode
!gtIx <- findIndexOfGtElem keys k sz
!node <- readArr nodes gtIx
!ins <- go (n - 1) node
case ins of
Ok !r -> return (Ok r)
TotallyEmpty _ _ -> fail "TotallyEmpty: handle this in go"
TooSmall !r -> do
if n == 1
then
if | gtIx >= sz -> do
if (gtIx /= sz) then fail "bad logic found: gtIx must be sz" else return ()
childSz <- readNodeSize node
let KeysValues childKeys childValues = readNodeKeysValues childDegree node
prevPtrNode <- readArr nodes (gtIx - 1)
prevSz <- readNodeSize prevPtrNode
let KeysValues prevKeys prevValues = readNodeKeysValues childDegree prevPtrNode
if childSz + prevSz < childDegree
then do
mergeIntoLeft prevKeys prevValues prevSz childKeys childValues childSz
writeNodeSize prevPtrNode (childSz + prevSz)
FMA.free node
if sz < 2
then do
return (TotallyEmpty prevPtrNode r)
else do
_ <- fail "merging arrays"
removeArr sz (sz - 1) keys
removeArr (sz + 1) sz nodes
writeNodeSize ptrNode (sz - 1)
continue
else do
(newPrevSz,newChildSz) <- balanceArrays prevKeys prevValues prevSz childKeys childValues childSz
writeNodeSize prevPtrNode newPrevSz
writeNodeSize node newChildSz
readArr childKeys 0 >>= writeArr keys (sz - 1)
continue
| gtIx > 0 -> fail "write me now"
| otherwise -> do
if (gtIx /= 0) then fail "bad logic found" else return ()
childSz <- readNodeSize node
let KeysValues childKeys childValues = readNodeKeysValues childDegree node
nextPtrNode <- readArr nodes 1
nextSz <- readNodeSize nextPtrNode
let KeysValues nextKeys nextValues = readNodeKeysValues childDegree nextPtrNode
if childSz + nextSz < childDegree
then do
mergeIntoLeft childKeys childValues childSz nextKeys nextValues nextSz
writeNodeSize node (childSz + nextSz)
FMA.free nextPtrNode
if sz < 2
then do
return (TotallyEmpty node r)
else do
_ <- fail "merging arrays"
removeArr sz 0 keys
removeArr (sz + 1) 1 nodes
writeNodeSize ptrNode (sz - 1)
continue
else do
_ <- fail "balancing arrays"
(newChildSz,newNextSz) <- balanceArrays childKeys childValues childSz nextKeys nextValues nextSz
writeNodeSize nextPtrNode newNextSz
writeNodeSize node newChildSz
readArr nextKeys 0 >>= writeArr keys 0
continue
else fail "write code for branch handling a branch merge"
where
continue :: IO (Insert k v r)
continue = do
newSz <- readNodeSize ptrNode
let minimumBranchSz = half branchDegree - 1
if newSz < minimumBranchSz
then return (TooSmall r)
else return (Ok r)
Split !rightNode !propagated !v -> if sz < branchDegree - 1
then do
insertArr sz gtIx propagated keys
insertArr (sz + 1) (gtIx + 1) rightNode nodes
writeNodeSize ptrNode (sz + 1)
return (Ok v)
else do
let !middleIx = half sz
!leftKeys = keys
!leftNodes = nodes
!middleKey <- readArr keys middleIx
let !leftSize = middleIx
!rightSize = sz - leftSize
(!actualLeftSz,!actualRightSz) = if middleIx >= gtIx
then (leftSize + 1, rightSize - 1)
else (leftSize, rightSize)
newNodePtr <- newNode actualRightSz
writeNodeSize ptrNode actualLeftSz
let KeysNodes rightKeys rightNodes = readNodeKeysNodes branchDegree newNodePtr
if middleIx >= gtIx
then do
copyArr rightKeys 0 leftKeys (leftSize + 1) (rightSize - 1)
copyArr rightNodes 0 leftNodes (leftSize + 1) rightSize
insertArr leftSize gtIx propagated leftKeys
insertArr (leftSize + 1) (gtIx + 1) rightNode leftNodes
else do
copyArr rightKeys 0 leftKeys (leftSize + 1) (rightSize - 1)
copyArr rightNodes 0 leftNodes (leftSize + 1) rightSize
insertArr (rightSize - 1) (gtIx - leftSize - 1) propagated rightKeys
insertArr rightSize (gtIx - leftSize) rightNode rightNodes
return (Split newNodePtr middleKey v)
else do
sz <- readNodeSize ptrNode
let !(KeysValues !keys !values) = readNodeKeysValues childDegree ptrNode
!ix <- findIndex keys k sz
if ix < 0
then case mpostInitializeElemOff of
Left r -> return (Ok r)
Right postInitializeElemOff -> do
let !gtIx = decodeGtIndex ix
if sz < childDegree - 1
then do
insertArr sz gtIx k keys
r <- insertInitArr sz gtIx values $ \thePtr theIx -> do
initializeElemOff thePtr theIx
postInitializeElemOff thePtr theIx
writeNodeSize ptrNode (sz + 1)
return (Ok r)
else do
let !leftSize = half sz
!rightSize = sz - leftSize
!leftKeys = keys
!leftValues = values
let (newLeftSz,actualRightSz) = if gtIx < leftSize
then (leftSize + 1, rightSize)
else (leftSize,rightSize + 1)
newNodePtr <- newNode actualRightSz
writeNodeSize ptrNode newLeftSz
let KeysValues rightKeys rightValues = readNodeKeysValues childDegree newNodePtr
r <- if gtIx < leftSize
then do
copyArr rightKeys 0 leftKeys leftSize rightSize
copyArr rightValues 0 leftValues leftSize rightSize
insertArr leftSize gtIx k leftKeys
insertInitArr leftSize gtIx leftValues $ \thePtr theIx -> do
initializeElemOff thePtr theIx
postInitializeElemOff thePtr theIx
else do
copyArr rightKeys 0 leftKeys leftSize rightSize
copyArr rightValues 0 leftValues leftSize rightSize
insertArr rightSize (gtIx - leftSize) k rightKeys
insertInitArr rightSize (gtIx - leftSize) rightValues $ \thePtr theIx -> do
initializeElemOff thePtr theIx
postInitializeElemOff thePtr theIx
!propagated <- readArr rightKeys 0
return (Split newNodePtr propagated r)
else do
!(r,dec) <- alterElemOff (getArr values) ix
case dec of
Keep -> return (Ok r)
Delete -> fail "write the delete code for b tree"
{-# INLINE balanceArrays #-}
balanceArrays :: (Storable k, Storable v) => Arr k -> Arr v -> Int -> Arr k -> Arr v -> Int -> IO (Int,Int)
balanceArrays arrA valA szA arrB valB szB = do
let newSzA = half (szA + szB)
newSzB = szA + szB - newSzA
deltaA = newSzA - szA
deltaB = negate deltaA
if deltaA > 0
then do
copyArr arrA szA arrB 0 deltaA
copyArr arrB 0 arrB deltaA (szB - deltaA)
copyArr valA szA valB 0 deltaA
copyArr valB 0 valB deltaA (szB - deltaA)
else do
copyArr arrB deltaB arrB 0 szB
copyArr arrB 0 arrA (szA - deltaB) deltaB
copyArr valB deltaB valB 0 szB
copyArr valB 0 valA (szA - deltaB) deltaB
return (newSzA,newSzB)
{-# INLINE mergeIntoLeft #-}
mergeIntoLeft :: (Storable k, Storable v)
=> Arr k -> Arr v -> Int -> Arr k -> Arr v -> Int -> IO ()
mergeIntoLeft arrA valA szA arrB valB szB = do
copyArr arrA szA arrB 0 szB
copyArr valA szA valB 0 szB
{-# INLINE copyArr #-}
copyArr :: forall a. Storable a
=> Arr a
-> Int
-> Arr a
-> Int
-> Int
-> IO ()
copyArr (Arr dest) doff (Arr src) soff len = moveArray
(advancePtr dest doff)
(advancePtr src soff)
len
{-# INLINE insertArr #-}
insertArr :: Storable a
=> Int
-> Int
-> a
-> Arr a
-> IO ()
insertArr !sz !i !x !arr = do
copyArr arr (i + 1) arr i (sz - i)
writeArr arr i x
{-# INLINE removeArr #-}
removeArr :: Storable a
=> Int
-> Int
-> Arr a
-> IO ()
removeArr !sz !i !arr = do
copyArr arr i arr (i + 1) (sz - i - 1)
{-# INLINE insertInitArr #-}
insertInitArr :: forall a r. Storable a
=> Int
-> Int
-> Arr a
-> (Ptr a -> Int -> IO r)
-> IO r
insertInitArr !sz !i !arr@(Arr ptr0) f = do
copyArr arr (i + 1) arr i (sz - i)
f ptr0 i
{-# INLINE findIndexOfGtElem #-}
findIndexOfGtElem :: (Ord a, Storable a) => Arr a -> a -> Int -> IO Int
findIndexOfGtElem v needle sz = go 0 (sz - 1)
where
go :: Int -> Int -> IO Int
go !lo !hi = if lo <= hi
then do
let !mid = lo + half (hi - lo)
!val <- readArr v mid
if | val == needle -> return (mid + 1)
| val < needle -> go (mid + 1) hi
| otherwise -> go lo (mid - 1)
else return lo
{-# INLINE findIndex #-}
findIndex :: (Ord a, Storable a)
=> Arr a
-> a
-> Int
-> IO Int
findIndex !marr !needle !sz = go 0
where
{-# INLINE go #-}
go :: Int -> IO Int
go !i = if i < sz
then do
!a <- readArr marr i
case inline (compare a needle) of
LT -> go (i + 1)
EQ -> return i
GT -> return (encodeGtIndex i)
else return (encodeGtIndex i)
foldrWithKey :: forall k v b. (Ord k, Storable k, Storable v)
=> (k -> v -> b -> IO b)
-> b
-> BTree k v
-> IO b
foldrWithKey f b0 (BTree height root) = go height root b0
where
branchDegree :: Int
!branchDegree = calcBranchDegree root
childDegree :: Int
childDegree = calcChildDegree root
go :: Int -> Ptr (Node k v) -> b -> IO b
go !n !ptrNode b = do
sz <- readNodeSize ptrNode
if n > 0
then do
let KeysNodes _ nodes = readNodeKeysNodes branchDegree ptrNode
foldrArray (sz + 1) (go (n - 1)) b nodes
else do
let KeysValues keys values = readNodeKeysValues childDegree ptrNode
foldrPrimArrayPairs sz f b keys values
foldrPrimArrayPairs :: forall k v b. (Ord k, Storable k, Storable v)
=> Int
-> (k -> v -> b -> IO b)
-> b
-> Arr k
-> Arr v
-> IO b
foldrPrimArrayPairs len f b0 ks vs = go (len - 1) b0
where
go :: Int -> b -> IO b
go !ix !b1 = if ix >= 0
then do
k <- readArr ks ix
v <- readArr vs ix
b2 <- f k v b1
go (ix - 1) b2
else return b1
foldrArray :: forall a b. Storable a
=> Int
-> (a -> b -> IO b)
-> b
-> Arr a
-> IO b
foldrArray len f b0 arr = go (len - 1) b0
where
go :: Int -> b -> IO b
go !ix !b1 = if ix >= 0
then do
a <- readArr arr ix
b2 <- f a b1
go (ix - 1) b2
else return b1
arrMapM_ :: (Storable a) => (a -> IO b) -> Int -> Arr a -> IO ()
arrMapM_ f len arr = go 0
where
go :: Int -> IO ()
go i = if i < len
then do
_ <- f =<< readArr arr i
go (i + 1)
else return ()
{-# INLINE encodeGtIndex #-}
encodeGtIndex :: Int -> Int
encodeGtIndex i = negate i - 1
{-# INLINE decodeGtIndex #-}
decodeGtIndex :: Int -> Int
decodeGtIndex x = negate x - 1
{-# INLINE half #-}
half :: Int -> Int
half x = unsafeShiftR x 1
toAscList :: forall k v. (Ord k, Storable k, Storable v)
=> BTree k v
-> IO [(k,v)]
toAscList = foldrWithKey f []
where
f :: k -> v -> [(k,v)] -> IO [(k,v)]
f k v xs = return ((k,v) : xs)