ptr-poker 0.1.1.1 → 0.1.1.2
raw patch · 4 files changed
+128/−6 lines, 4 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
Files
- library/PtrPoker/Poke.hs +65/−3
- library/PtrPoker/Size.hs +20/−0
- library/PtrPoker/Write.hs +42/−2
- ptr-poker.cabal +1/−1
library/PtrPoker/Poke.hs view
@@ -14,6 +14,11 @@ Poke $ \ p -> foldM (\ p (Poke poker) -> poker p) p foldable #-} +{-|+Abstraction over an IO action,+which takes a pointer, populates it and+produces a pointer right after the populated data.+-} newtype Poke = Poke { pokePtr :: Ptr Word8 -> IO (Ptr Word8) } @@ -31,36 +36,55 @@ mconcat = concat +{-|+Reuses the IsString instance of 'ByteString'.+-} instance IsString Poke where fromString = byteString . fromString +{-|+Concatenate a foldable of pokes.+-} {-# INLINE[1] concat #-} concat :: Foldable f => f Poke -> Poke concat pokers = Poke (\ p -> foldM (\ p (Poke io) -> io p) p pokers) +{-|+Efficiently copy the contents of ByteString using @memcpy@.+-} {-# INLINE byteString #-} byteString :: ByteString -> Poke byteString bs = Poke $ \ ptr -> inline ByteStringIO.pokeByteString ptr bs +{-|+Encode Word8 as byte, incrementing the pointer by 1.+-} {-# INLINE[1] word8 #-} word8 :: Word8 -> Poke word8 a = Poke (\ p -> PrimIO.pokeWord8 p a $> plusPtr p 1) -{-| Little-endian Word64 poker. -}+{-|+Encode Word64 in Little-endian.+-} {-# INLINE[1] lWord64 #-} lWord64 :: Word64 -> Poke lWord64 a = Poke (\ p -> PrimIO.pokeLEWord64 p a $> plusPtr p 8) -{-| Big-endian Word64 poker. -}+{-|+Encode Word64 in Big-endian.+-} {-# INLINE[1] bWord64 #-} bWord64 :: Word64 -> Poke bWord64 a = Poke (\ p -> PrimIO.pokeBEWord64 p a $> plusPtr p 8) +{-|+Encode Text in UTF8.+-} {-# INLINE textUtf8 #-} textUtf8 :: Text -> Poke textUtf8 (Text.Text arr off len) =@@ -70,56 +94,89 @@ -- * ASCII integers ------------------------- +{-|+Encode Int8 as a signed ASCII decimal.+-} {-# INLINE[1] int8AsciiDec #-} int8AsciiDec :: Int8 -> Poke int8AsciiDec a = Poke (Ffi.pokeIntInDec (fromIntegral a)) +{-|+Encode Int16 as a signed ASCII decimal.+-} {-# INLINE[1] int16AsciiDec #-} int16AsciiDec :: Int16 -> Poke int16AsciiDec a = Poke (Ffi.pokeIntInDec (fromIntegral a)) +{-|+Encode Int32 as a signed ASCII decimal.+-} {-# INLINE[1] int32AsciiDec #-} int32AsciiDec :: Int32 -> Poke int32AsciiDec a = Poke (Ffi.pokeIntInDec (fromIntegral a)) +{-|+Encode Int64 as a signed ASCII decimal.+-} {-# INLINE[1] int64AsciiDec #-} int64AsciiDec :: Int64 -> Poke int64AsciiDec a = Poke (Ffi.pokeLongLongIntInDec (fromIntegral a)) +{-|+Encode Int as a signed ASCII decimal.+-} {-# INLINE[1] intAsciiDec #-} intAsciiDec :: Int -> Poke intAsciiDec a = Poke (Ffi.pokeLongLongIntInDec (fromIntegral a)) +{-|+Encode Word8 as an unsigned ASCII decimal.+-} {-# INLINE[1] word8AsciiDec #-} word8AsciiDec :: Word8 -> Poke word8AsciiDec a = Poke (Ffi.pokeUIntInDec (fromIntegral a)) +{-|+Encode Word16 as an unsigned ASCII decimal.+-} {-# INLINE[1] word16AsciiDec #-} word16AsciiDec :: Word16 -> Poke word16AsciiDec a = Poke (Ffi.pokeUIntInDec (fromIntegral a)) +{-|+Encode Word32 as an unsigned ASCII decimal.+-} {-# INLINE[1] word32AsciiDec #-} word32AsciiDec :: Word32 -> Poke word32AsciiDec a = Poke (Ffi.pokeUIntInDec (fromIntegral a)) +{-|+Encode Word64 as an unsigned ASCII decimal.+-} {-# INLINE[1] word64AsciiDec #-} word64AsciiDec :: Word64 -> Poke word64AsciiDec a = Poke (Ffi.pokeLongLongUIntInDec (fromIntegral a)) +{-|+Encode Word as an unsigned ASCII decimal.+-} {-# INLINE[1] wordAsciiDec #-} wordAsciiDec :: Word -> Poke wordAsciiDec a = Poke (Ffi.pokeLongLongUIntInDec (fromIntegral a)) +{-|+Encode Double as a signed ASCII decimal.+-} {-# INLINE doubleAsciiDec #-} doubleAsciiDec :: Double -> Poke doubleAsciiDec a =@@ -133,7 +190,12 @@ {-| Having the amount of bytes to be written precomputed,-executes an action, which fills the pointer going downward.+executes an action,+which fills the pointer going downward,+starting from the pointer that follows the chunk.+I.e., you have to decrement the pointer+before writing the first byte,+decrement it again before writing the second byte and so on. -} {-# INLINE sizedReverse #-} sizedReverse :: Int -> (Ptr Word8 -> IO a) -> Poke
library/PtrPoker/Size.hs view
@@ -10,6 +10,14 @@ import qualified PtrPoker.Ffi as Ffi +{-|+Efficiently count the amount of bytes required to encode Word64+as a decimal number in ASCII.++Implemented as a balanced tree of \"ifs\"+centered around the middle of the range.+This is much faster than anything based on logarithms.+-} {-# INLINE word64AsciiDec #-} word64AsciiDec :: Word64 -> Int word64AsciiDec x =@@ -53,6 +61,14 @@ then 2 else 1 +{-|+Efficiently count the amount of bytes required to encode Int64+as a signed decimal number in ASCII.++Implemented as a balanced tree of \"ifs\"+centered around the middle of the range.+This is much faster than anything based on logarithms.+-} {-# INLINE int64AsciiDec #-} int64AsciiDec :: Int64 -> Int int64AsciiDec x =@@ -132,6 +148,10 @@ then 2 else 1 +{-|+Efficiently count the amount of bytes required to encode Text+in UTF8.+-} {-# INLINE textUtf8 #-} textUtf8 :: Text -> Int textUtf8 (Text.Text arr off len) =
library/PtrPoker/Write.hs view
@@ -12,13 +12,16 @@ import qualified Data.ByteString.Internal as ByteString +{-|+Execute Write, producing strict ByteString.+-} {-# INLINABLE writeToByteString #-} writeToByteString :: Write -> ByteString writeToByteString Write{..} = ByteString.unsafeCreate writeSize (void . Poke.pokePtr writePoke) {-|-Specification of how much bytes to allocate and how to populate them.+Specification of how many bytes to allocate and how to populate them. Useful for creating strict bytestrings and tasks like that. -}@@ -38,16 +41,25 @@ mempty = Write 0 mempty +{-|+Reuses the IsString instance of 'ByteString'.+-} instance IsString Write where {-# INLINE fromString #-} fromString = byteString . fromString +{-|+Render Word8 as byte.+-} {-# INLINE word8 #-} word8 :: Word8 -> Write word8 a = Write 1 (Poke.word8 a) +{-|+Render Word64 in ASCII decimal.+-} {-# INLINE word64AsciiDec #-} word64AsciiDec :: Word64 -> Write word64AsciiDec a =@@ -58,11 +70,17 @@ poke = Poke.sizedReverse size (Ffi.revPokeUInt64 (fromIntegral a)) +{-|+Render Word in ASCII decimal.+-} {-# INLINE wordAsciiDec #-} wordAsciiDec :: Word -> Write wordAsciiDec = word64AsciiDec . fromIntegral +{-|+Render Int64 in ASCII decimal.+-} {-# INLINE int64AsciiDec #-} int64AsciiDec :: Int64 -> Write int64AsciiDec a =@@ -73,6 +91,9 @@ poke = Poke.sizedReverse size (Ffi.revPokeInt64 (fromIntegral a)) +{-|+Render Int in ASCII decimal.+-} {-# INLINE intAsciiDec #-} intAsciiDec :: Int -> Write intAsciiDec =@@ -112,18 +133,37 @@ then word8 45 <> byteString (ByteString.double (negate a)) else byteString (ByteString.double a) +{-|+Render Scientific in ASCII decimal.+-} {-# INLINE scientificAsciiDec #-} scientificAsciiDec :: Scientific -> Write scientificAsciiDec = byteString . ByteString.scientific +{-|+Efficiently copy the contents of ByteString using @memcpy@.+-} {-# INLINE byteString #-} byteString :: ByteString -> Write byteString a = Write (ByteString.length a) (inline Poke.byteString a) {-|-Benchmark results in comparison to @Data.Text.Encoding.'Data.Text.Encoding.decodeUtf8'@.+Render Text in UTF8.++Does pretty much the same as 'Data.Text.Encoding.encodeUtf8',+both implementation and performance-wise,+while allowing you to avoid redundant @memcpy@+compared to @('byteString' . 'Data.Text.Encoding.encodeUtf8')@.++Following are the benchmark results comparing the performance of+@('writeToByteString' . 'textUtf8')@ with+@Data.Text.Encoding.'Data.Text.Encoding.encodeUtf8'@+on inputs in Latin and Greek (requiring different number of surrogate bytes).+The results show that they are quite similar.++=== __Benchmark results__ > textUtf8/ptr-poker/latin/1 mean 57.06 ns ( +- 3.283 ns ) > textUtf8/ptr-poker/latin/10 mean 214.1 ns ( +- 8.601 ns )
ptr-poker.cabal view
@@ -1,5 +1,5 @@ name: ptr-poker-version: 0.1.1.1+version: 0.1.1.2 synopsis: Pointer poking action construction and composition toolkit homepage: https://github.com/nikita-volkov/ptr-poker bug-reports: https://github.com/nikita-volkov/ptr-poker/issues