module BTree.Lookup ( LookupTree
, open
, fromByteString
, lookup
, size
) where
import Prelude hiding (lookup)
import Control.Error
import Control.Lens hiding (children)
import qualified Data.ByteString as BS
import qualified Data.Vector as V
import qualified Data.ByteString.Lazy as LBS
import Data.Binary
import System.IO.MMap
import BTree.Types
fetch :: (Binary a) => LookupTree k e -> OnDisk a -> a
fetch lt (OnDisk offset) =
decode $ LBS.fromStrict $ BS.drop (fromIntegral offset) (lt^.ltData)
fromByteString :: LBS.ByteString -> Either String (LookupTree k e)
fromByteString bs = do
(rest, _, hdr) <- fmapL (\(_,_,e)->e) $ decodeOrFail bs
validateHeader hdr
return $ LookupTree (LBS.toStrict rest) hdr
open :: FilePath -> IO (Either String (LookupTree k e))
open fname = runExceptT $ do
d <- fmapLT show $ tryIO $ mmapFileByteString fname Nothing
ExceptT $ return $ fromByteString (LBS.fromStrict d)
lookup :: (Binary k, Binary e, Ord k)
=> LookupTree k e -> k -> Maybe e
lookup lt k =
case lt ^. ltHeader . btRoot of
Just root -> go $ fetch lt root
Nothing -> Nothing
where
go (Leaf (BLeaf k' e))
| k' == k = Just e
| otherwise = Nothing
go (Node c0 children)
| V.null children = go $ fetch lt c0
| let (k0,_) = V.head children
, k < k0 = go $ fetch lt c0
| otherwise =
case V.takeWhile (\(k',_)->k' <= k) children of
rest
| V.null rest -> Nothing
| otherwise -> go $ fetch lt $ snd $ V.last rest
size :: LookupTree k e -> Size
size = _btSize . _ltHeader