HsHyperEstraier-0.2: Database/QDBM/Cabin/Map.hs
{-# OPTIONS_GHC -optc-D__GLASGOW_HASKELL__=606 #-}
{-# LINE 1 "Database/QDBM/Cabin/Map.hsc" #-}
module Database.QDBM.Cabin.Map
{-# LINE 2 "Database/QDBM/Cabin/Map.hsc" #-}
( Map
, CBMAP
, wrapMap
, unsafePeekMap
, withMapPtr
, newMap
, put
, get
, toList
, fromList
)
where
import qualified Data.ByteString as BS
import Data.ByteString.Base
import Foreign.C.Types
import Foreign.ForeignPtr
import Foreign.Ptr
import Foreign.Storable
import Foreign.Marshal.Alloc
newtype Map = Map (ForeignPtr CBMAP)
data CBMAP
foreign import ccall unsafe "cabin.h cbmapopen"
_open :: IO (Ptr CBMAP)
foreign import ccall unsafe "cabin.h &cbmapclose"
_close :: FunPtr (Ptr CBMAP -> IO ())
foreign import ccall unsafe "cabin.h cbmapput"
_put :: Ptr CBMAP -> Ptr CChar -> CInt -> Ptr CChar -> CInt -> CInt -> IO CInt
foreign import ccall unsafe "cabin.h cbmapget"
_get :: Ptr CBMAP -> Ptr CChar -> CInt -> Ptr CInt -> IO (Ptr CChar)
foreign import ccall unsafe "cabin.h cbmapiterinit"
_iterinit :: Ptr CBMAP -> IO ()
foreign import ccall unsafe "cabin.h cbmapiternext"
_iternext :: Ptr CBMAP -> Ptr CInt -> IO (Ptr CChar)
foreign import ccall unsafe "cabin.h cbmapiterval"
_iterval :: Ptr CChar -> Ptr CInt -> IO (Ptr CChar)
wrapMap :: Ptr CBMAP -> IO Map
wrapMap mapPtr = newForeignPtr _close mapPtr >>= return . Map
unsafePeekMap :: Ptr CBMAP -> IO Map
unsafePeekMap mapPtr = newForeignPtr_ mapPtr >>= return . Map
withMapPtr :: Map -> (Ptr CBMAP -> IO a) -> IO a
withMapPtr (Map m) = withForeignPtr m
newMap :: IO Map
newMap = _open >>= wrapMap
put :: Map -> ByteString -> ByteString -> Bool -> IO Bool
put m key value overwrite
= withMapPtr m $ \ mapPtr ->
BS.useAsCStringLen key $ \ (keyPtr , keyLen ) ->
BS.useAsCStringLen value $ \ (valuePtr, valueLen) ->
_put mapPtr
keyPtr (fromIntegral keyLen )
valuePtr (fromIntegral valueLen)
(fromIntegral $ fromEnum overwrite)
>>= return . (/= 0)
get :: Map -> ByteString -> IO (Maybe ByteString)
get m key
= withMapPtr m $ \ mapPtr ->
BS.useAsCStringLen key $ \ (keyPtr, keyLen) ->
alloca $ \ valLenPtr ->
do valPtr <- _get mapPtr keyPtr (fromIntegral keyLen) valLenPtr
if valPtr == nullPtr then
return Nothing
else
do valLen <- peek valLenPtr
value <- BS.copyCStringLen (valPtr, fromIntegral valLen)
return $ Just value
initIterator :: Map -> IO ()
initIterator m
= withMapPtr m $ \ mapPtr ->
_iterinit mapPtr
iterateNext :: Map -> IO (Maybe (ByteString, ByteString))
iterateNext m
= withMapPtr m $ \ mapPtr ->
alloca $ \ keyLenPtr ->
alloca $ \ valLenPtr ->
do keyPtr <- _iternext mapPtr keyLenPtr
if keyPtr == nullPtr then
return Nothing
else
do keyLen <- peek keyLenPtr
key <- BS.copyCStringLen (keyPtr, fromIntegral keyLen)
-- QDBM のソースを見たら、keyPtr そのものの値からアドレ
-- スを計算してゐた…。良くそんな無茶をやるなあと思ふ。
valPtr <- _iterval keyPtr valLenPtr
valLen <- peek valLenPtr
value <- BS.copyCStringLen (valPtr, fromIntegral valLen)
return $ Just (key, value)
-- iterator の状態は Map 内部に格納されるので、thread-safe でない。だか
-- ら list にするなら正格にしなければならない。
toList :: Map -> IO [(ByteString, ByteString)]
toList m = initIterator m >> loop
where
loop :: IO [(ByteString, ByteString)]
loop = do next <- iterateNext m
case next of
Nothing -> return []
Just pair -> do rest <- loop -- ここで unsafeInterleaveIO したいが出來ない。
return $ pair : rest
fromList :: [(ByteString, ByteString)] -> IO Map
fromList pairs
= do m <- newMap
mapM_ (putPair m) pairs
return m
where
putPair :: Map -> (ByteString, ByteString) -> IO ()
putPair m (key, value) = put m key value True >> return ()