-- Code for reading and writing reference counts. module Database.VCache.Refct ( readRefctBytes , toRefctBytes , writeRefctBytes , Refct ) where import Control.Exception import Data.Word import Data.Bits import Foreign.Ptr import Foreign.Storable import Database.LMDB.Raw type Refct = Int -- simple variable-width encoding for reference counts. Encoding is -- base256 then adding 1. (The lead byte should always be non-zero, -- but that isn't checked here.) readRefctBytes :: MDB_val -> IO Refct readRefctBytes v = rd (mv_data v) (mv_size v) 0 where rd _ 0 rc = return (rc + 1) rd p n rc = do w8 <- peek p let rc' = (rc `shiftL` 8) .|. (fromIntegral w8) rd (p `plusPtr` 1) (n - 1) rc' -- compute list of bytes for a big-endian encoding. -- Reference count must be positive! toRefctBytes :: Refct -> [Word8] toRefctBytes = rcb [] . subtract 1 . assertPositive where rcb l 0 = l rcb l rc = rcb (fromIntegral rc : l) (rc `shiftR` 8) assertPositive n = assert (n > 0) n -- write a reference variable-width count into an MDB_val. -- -- Note: given buffer should be large enough for any reference count. writeRefctBytes :: Ptr Word8 -> Refct -> IO MDB_val writeRefctBytes p0 = wrcb p0 0 . toRefctBytes where wrcb _ n [] = return $! MDB_val { mv_data = p0, mv_size = n } wrcb p n (b:bs) = do { poke p b ; wrcb (p `plusPtr` 1) (n + 1) bs }