module TByteVector ( TByteVector , newTByteVector , append , read ) where import Control.Concurrent.STM import Control.Monad import Data.ByteString as B hiding (append) import Data.Text as T hiding (append) import Data.Text.Encoding import Data.Vector.Unboxed.Mutable (IOVector) import qualified Data.Vector.Unboxed.Mutable as V import Data.Word import GHC.Conc import Prelude hiding (read) data TByteVector = TByteVector { usedLength :: TVar Word , uVector :: TVar (IOVector Word8) } newTByteVector :: IO TByteVector newTByteVector = do ic <- newTVarIO 0 vec <- V.unsafeNew 0 v <- newTVarIO vec return $ TByteVector { usedLength = ic , uVector = v } writeList :: IOVector Word8 -> Int -> [Word8] -> IO () writeList _ _ [] = return () writeList vec offset (x:xs) = do V.unsafeWrite vec offset x writeList vec (offset + 1) xs toList :: IOVector Word8 -> IO [Word8] toList vec = if V.null vec then return [] else do h <- V.unsafeRead vec 0 l <- toList $ V.tail vec return $ h : l append :: TByteVector -> Text -> IO () append (TByteVector _ v) str = do vec <- atomically $ readTVar v nv <- do let veclen = V.length vec let bs = encodeUtf8 str let len = B.length bs nv <- V.unsafeGrow vec len let wordlist = B.unpack bs writeList nv veclen wordlist return nv atomically $ writeTVar v nv read :: TByteVector -> Word -> Word -> STM ByteString read (TByteVector _ v) offset len = do vec <- readTVar v let veclen = V.length vec let vecoffset = if offset > fromIntegral veclen then fromIntegral veclen else fromIntegral offset let slicelen = if vecoffset + fromIntegral len > veclen then veclen - vecoffset else fromIntegral len rv <- unsafeIOToSTM $ do wordlist <- toList $ V.slice vecoffset slicelen vec return $ B.pack wordlist return rv