packages feed

Z-Data 0.7.0.0 → 0.7.1.0

raw patch · 11 files changed

+350/−139 lines, 11 filesdep ~QuickCheckPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependency ranges changed: QuickCheck

API changes (from Hackage documentation)

+ Z.Data.ASCII: toLower :: Word8 -> Word8
+ Z.Data.ASCII: toLowerLatin :: Word8 -> Word8
+ Z.Data.ASCII: toUpper :: Word8 -> Word8
+ Z.Data.ASCII: toUpperLatin :: Word8 -> Word8
+ Z.Data.Parser: anyChar7 :: Parser Char
+ Z.Data.Parser: anyCharUTF8 :: Parser Char
+ Z.Data.Parser: char7 :: Char -> Parser ()
+ Z.Data.Parser: charUTF8 :: Char -> Parser ()
+ Z.Data.Parser: takeN :: (Word8 -> Bool) -> Int -> Parser Bytes
+ Z.Data.Parser.Base: anyChar7 :: Parser Char
+ Z.Data.Parser.Base: anyCharUTF8 :: Parser Char
+ Z.Data.Parser.Base: char7 :: Char -> Parser ()
+ Z.Data.Parser.Base: charUTF8 :: Char -> Parser ()
+ Z.Foreign.CPtr: data CPtr a
+ Z.Foreign.CPtr: data FunPtr a
+ Z.Foreign.CPtr: data Ptr a
+ Z.Foreign.CPtr: instance GHC.Classes.Eq (Z.Foreign.CPtr.CPtr a)
+ Z.Foreign.CPtr: instance GHC.Classes.Ord (Z.Foreign.CPtr.CPtr a)
+ Z.Foreign.CPtr: instance GHC.Show.Show (Z.Foreign.CPtr.CPtr a)
+ Z.Foreign.CPtr: instance Z.Data.Text.Print.Print (Z.Foreign.CPtr.CPtr a)
+ Z.Foreign.CPtr: newCPtr :: (Ptr (Ptr a) -> IO r) -> FunPtr (Ptr a -> IO b) -> IO (CPtr a, r)
+ Z.Foreign.CPtr: newCPtrUnsafe :: (MutableByteArray# RealWorld -> IO r) -> FunPtr (Ptr a -> IO b) -> IO (CPtr a, r)
+ Z.Foreign.CPtr: nullPtr :: Ptr a
+ Z.Foreign.CPtr: withCPtr :: CPtr a -> (Ptr a -> IO b) -> IO b
- Z.Data.Array: -- | Mutable version of this array type.
+ Z.Data.Array: -- | The mutable version of this array type.
- Z.Data.Array: class Arr (arr :: * -> *) a where {
+ Z.Data.Array: class Arr (arr :: Type -> Type) a where {
- Z.Data.Array: type family MArr arr = (mar :: * -> * -> *) | mar -> arr;
+ Z.Data.Array: type family MArr arr = (mar :: Type -> Type -> Type) | mar -> arr;
- Z.Data.Array.Checked: class Arr (arr :: * -> *) a
+ Z.Data.Array.Checked: class Arr (arr :: Type -> Type) a
- Z.Data.Array.Checked: type family MArr arr = (mar :: * -> * -> *) | mar -> arr
+ Z.Data.Array.Checked: type family MArr arr = (mar :: Type -> Type -> Type) | mar -> arr
- Z.Data.Vector: type family IArray v :: * -> *;
+ Z.Data.Vector: type family IArray v :: Type -> Type;
- Z.Data.Vector.Base: type family IArray v :: * -> *;
+ Z.Data.Vector.Base: type family IArray v :: Type -> Type;

Files

ChangeLog.md view
@@ -1,5 +1,10 @@ # Revision history for Z-Data +## 0.7.1.0  -- 2020-03-03++* Add `CPtr` type, a more lightweight foreign pointer.+* Add `toLower/toUpper/toLowerLatin/toUpperLatin` to `Z.Data.ASCII`.+ ## 0.7.0.0  -- 2020-03-03  * Add more patterns to `Z.Data.ASCII`.
Z-Data.cabal view
@@ -1,6 +1,6 @@ cabal-version:      2.4 name:               Z-Data-version:            0.7.0.0+version:            0.7.1.0 synopsis:           Array, vector and text description:        This package provides array, slice and text operations license:            BSD-3-Clause@@ -164,6 +164,7 @@     Z.Data.Vector.Search     Z.Data.Vector.Sort     Z.Foreign+    Z.Foreign.CPtr    build-depends:     , base                  >=4.12   && <5.0
Z/Data/ASCII.hs view
@@ -43,6 +43,38 @@ {-# INLINE isLower #-} isLower w =  w - LETTER_a <= 25 +-- | @A ~ Z@ => @a ~ z@+toLower :: Word8 -> Word8+{-# INLINE toLower #-}+toLower w+  | 65 <= w && w <=  90 = w + 32+  | otherwise           = w++-- | @a ~ z@ => @A ~ Z@+toUpper :: Word8 -> Word8+{-# INLINE toUpper #-}+toUpper w+  | 97 <= w && w <= 122 = w - 32+  | otherwise           = w++-- | @A ~ Z@ => @a ~ z@, @À ~ Ö@ => @à ~ ö@, @Ø ~ Þ@ => @ø ~ þ@+toLowerLatin :: Word8 -> Word8+{-# INLINE toLowerLatin #-}+toLowerLatin w+  |  65 <= w && w <=  90 ||+    192 <= w && w <= 214 ||+    216 <= w && w <= 222 = w + 32+  | otherwise            = w++-- | @a ~ z@ => @A ~ Z@, @à ~ ö@ => @À ~ Ö@, @ø ~ þ@ => @Ø ~ Þ@+toUpperLatin :: Word8 -> Word8+{-# INLINE toUpperLatin #-}+toUpperLatin w+  | 97  <= w && w <= 122 ||+    224 <= w && w <= 246 ||+    248 <= w && w <= 254 = w - 32+  | otherwise            = w+ -- | @ISO-8859-1@ control letter. isControl :: Word8 -> Bool {-# INLINE isControl #-}
Z/Data/Array.hs view
@@ -9,15 +9,17 @@  Unified unboxed and boxed array operations using type family. -All operations are NOT bound checked, if you need checked operations please use "Z.Data.Array.Checked".-It exports exactly same APIs so that you can switch between without pain.+NONE of the operations are bound checked, if you need checked operations please use "Z.Data.Array.Checked" instead.+It exports the exact same APIs ,so it requires no extra effort to switch between them.  Some mnemonics: -  * 'newArr', 'newArrWith' return mutable array, 'readArr', 'writeArr' works on them, 'setArr' fill elements-     with offset and length.+  * 'newArr' and 'newArrWith' return mutable array.+    'readArr' and 'writeArr' perform read and write actions on mutable arrays.+    'setArr' fills the elements with offset and length. -  * 'indexArr' works on immutable one, use 'indexArr'' to avoid indexing thunk.+  * 'indexArr' can only work on immutable Array.+     Use 'indexArr'' to avoid thunks building up in the heap.    * The order of arguements of 'copyArr', 'copyMutableArr' and 'moveArr' are always target and its offset     come first, and source and source offset follow, copying length comes last.@@ -39,7 +41,7 @@   , PrimArray(..)   , MutablePrimArray(..)   , Prim(..)-  -- * Primitive Array operations+  -- * Primitive array operations   , newPinnedPrimArray, newAlignedPinnedPrimArray   , copyPrimArrayToPtr, copyMutablePrimArrayToPtr, copyPtrToMutablePrimArray   , primArrayContents, mutablePrimArrayContents, withPrimArrayContents, withMutablePrimArrayContents@@ -58,14 +60,15 @@   , sizeOf   ) where -import           Control.Exception            (ArrayException (..), throw)+import           Control.Exception              (ArrayException (..), throw) import           Control.Monad import           Control.Monad.Primitive import           Control.Monad.ST+import           Data.Kind                      (Type) import           Data.Primitive.Array import           Data.Primitive.ByteArray import           Data.Primitive.PrimArray-import           Data.Primitive.Ptr           (copyPtrToMutablePrimArray)+import           Data.Primitive.Ptr             (copyPtrToMutablePrimArray) import           Data.Primitive.SmallArray import           Data.Primitive.Types import           GHC.Exts@@ -74,35 +77,35 @@   -- | Bottom value (@throw ('UndefinedElement' 'Data.Array.uninitialized')@)--- for initialize new boxed array('Array', 'SmallArray'..).+-- for new boxed array('Array', 'SmallArray'..) initialization. -- uninitialized :: a uninitialized = throw (UndefinedElement "Data.Array.uninitialized")  --- | A typeclass to unify box & unboxed, mutable & immutable array operations.+-- | The typeclass that unifies box & unboxed and mutable & immutable array operations. ----- Most of these functions simply wrap their primitive counterpart, if there's no primitive ones,--- we polyfilled using other operations to get the same semantics.+-- Most of these functions simply wrap their primitive counterpart.+-- When there are no primitive ones, we fulfilled the semantic with other operations. ----- One exception is that 'shrinkMutableArr' only perform closure resizing on 'PrimArray' because--- current RTS support only that, 'shrinkMutableArr' will do nothing on other array type.+-- One exception is 'shrinkMutableArr' which only performs closure resizing on 'PrimArray', because+-- currently, RTS only supports that. 'shrinkMutableArr' won't do anything on other array types. ----- It's reasonable to trust GHC with specializing & inlining these polymorphric functions.--- They are used across this package and perform identical to their monomophric counterpart.+-- It's reasonable to trust GHC to specialize & inline these polymorphic functions.+-- They are used across this package and perform identically to their monomorphic counterpart. ---class Arr (arr :: * -> * ) a where+class Arr (arr :: Type -> Type) a where  -    -- | Mutable version of this array type.+    -- | The mutable version of this array type.     ---    type MArr arr = (mar :: * -> * -> *) | mar -> arr+    type MArr arr = (mar :: Type -> Type -> Type) | mar -> arr  -    -- | Make a new array with given size.+    -- | Make a new array with a given size.     ---    -- For boxed array, all elements are 'uninitialized' which shall not be accessed.-    -- For primitive array, elements are just random garbage.+    -- For boxed arrays, all elements are 'uninitialized' , which shall not be accessed.+    -- For primitive arrays, elements are just random garbage.     newArr :: (PrimMonad m, PrimState m ~ s) => Int -> m (MArr arr s a)  @@ -110,97 +113,123 @@     newArrWith :: (PrimMonad m, PrimState m ~ s) => Int -> a -> m (MArr arr s a)  -    -- | Index mutable array in a primitive monad.+    -- | Read from specified index of mutable array in a primitive monad.     readArr :: (PrimMonad m, PrimState m ~ s) => MArr arr s a -> Int -> m a  -    -- | Write mutable array in a primitive monad.+    -- | Write to specified index of mutable array in a primitive monad.     writeArr :: (PrimMonad m, PrimState m ~ s) => MArr arr s a -> Int -> a -> m ()  -    -- | Fill mutable array with a given value.+    -- | Fill the mutable array with a given value.     setArr :: (PrimMonad m, PrimState m ~ s) => MArr arr s a -> Int -> Int -> a -> m ()  -    -- | Index immutable array, which is a pure operation. This operation often-    -- result in an indexing thunk for lifted arrays, use 'indexArr\'' or 'indexArrM'-    -- if that's not desired.+    -- | Read from the specified index of an immutable array. It's pure and often+    -- results in an indexing thunk for lifted arrays, use 'indexArr\'' or 'indexArrM' to avoid this.     indexArr :: arr a -> Int -> a  -    -- | Index immutable array, pattern match on the unboxed unit tuple to force-    -- indexing (without forcing the element).+    -- | Read from the specified index of an immutable array. The result is packaged into an unboxed unary tuple; the result itself is not yet evaluated.+    -- Pattern matching on the tuple forces the indexing of the array to happen but does not evaluate the element itself.+    -- Evaluating the thunk prevents additional thunks from building up on the heap.+    -- Avoiding these thunks, in turn, reduces references to the argument array, allowing it to be garbage collected more promptly.     indexArr' :: arr a -> Int -> (# a #)  -    -- | Index immutable array in a primitive monad, this helps in situations that-    -- you want your indexing result is not a thunk referencing whole array.+    -- | Monadically read a value from the immutable array at the given index.+    -- This allows us to be strict in the array while remaining lazy in the read+    -- element which is very useful for collective operations. Suppose we want to+    -- copy an array. We could do something like this:+    --+    -- > copy marr arr ... = do ...+    -- >                        writeArray marr i (indexArray arr i) ...+    -- >                        ...+    --+    -- But since primitive arrays are lazy, the calls to 'indexArray' will not be+    -- evaluated. Rather, @marr@ will be filled with thunks each of which would+    -- retain a reference to @arr@. This is definitely not what we want!+    --+    -- With 'indexArrayM', we can instead write+    --+    -- > copy marr arr ... = do ...+    -- >                        x <- indexArrayM arr i+    -- >                        writeArray marr i x+    -- >                        ...+    --+    -- Now, indexing is executed immediately although the returned element is+    -- still not evaluated.+    --+    -- /Note:/ this function does not do bounds checking.     indexArrM :: (Monad m) => arr a -> Int -> m a  -    -- | Safely freeze mutable array by make a immutable copy of its slice.+    -- | Create an immutable copy of a slice of an array.+    -- This operation makes a copy of the specified section, so it is safe to continue using the mutable array afterward.     freezeArr :: (PrimMonad m, PrimState m ~ s) => MArr arr s a -> Int -> Int -> m (arr a)  -    -- | Safely thaw immutable array by make a mutable copy of its slice.+    -- | Create a mutable array from a slice of an immutable array.+    -- This operation makes a copy of the specified slice, so it is safe to use the immutable array afterward.     thawArr :: (PrimMonad m, PrimState m ~ s) => arr a -> Int -> Int -> m (MArr arr s a)  -    -- | In place freeze a mutable array, the original mutable array can not be used-    -- anymore.+    -- | Convert a mutable array to an immutable one without copying.+    -- The array should not be modified after the conversion.     unsafeFreezeArr :: (PrimMonad m, PrimState m ~ s) => MArr arr s a -> m (arr a)  -    -- | In place thaw a immutable array, the original immutable array can not be used-    -- anymore.++    -- | Convert a mutable array to an immutable one without copying. The+    -- array should not be modified after the conversion.     unsafeThawArr :: (PrimMonad m, PrimState m ~ s) => arr a -> m (MArr arr s a)  -    -- | Copy a slice of immutable array to mutable array at given offset.+    -- | Copy a slice of an immutable array to a mutable array at given offset.     copyArr ::  (PrimMonad m, PrimState m ~ s)             => MArr arr s a -- ^ target-            -> Int          -- ^ target offset+            -> Int          -- ^ offset into target array             -> arr a        -- ^ source-            -> Int          -- ^ source offset-            -> Int          -- ^ source length+            -> Int          -- ^ offset into source array+            -> Int          -- ^ number of elements to copy             -> m ()  -    -- | Copy a slice of mutable array to mutable array at given offset.-    -- The two mutable arrays shall no be the same one.+    -- | Copy a slice of a mutable array to another mutable array at given offset.+    -- The two mutable arrays must not be the same.     copyMutableArr :: (PrimMonad m, PrimState m ~ s)                    => MArr arr s a  -- ^ target-                   -> Int           -- ^ target offset+                   -> Int           -- ^ offset into target array                    -> MArr arr s a  -- ^ source-                   -> Int           -- ^ source offset-                   -> Int           -- ^ source length+                   -> Int           -- ^ offset into source array+                   -> Int           -- ^ number of elements to copy                    -> m ()  -    -- | Copy a slice of mutable array to mutable array at given offset.-    -- The two mutable arrays may be the same one.+    -- | Copy a slice of a mutable array to a mutable array at given offset.+    -- The two mutable arrays can be the same.     moveArr :: (PrimMonad m, PrimState m ~ s)             => MArr arr s a  -- ^ target-            -> Int           -- ^ target offset+            -> Int           -- ^ offset into target array             -> MArr arr s a  -- ^ source-            -> Int           -- ^ source offset-            -> Int           -- ^ source length+            -> Int           -- ^ offset into source array+            -> Int           -- ^ number of elements to copy             -> m ()  -    -- | Create immutable copy.+    -- | Create an immutable copy with the given subrange of the original array.     cloneArr :: arr a -> Int -> Int -> arr a  -    -- | Create mutable copy.+    -- | Create a mutable copy the given subrange of the original array.     cloneMutableArr :: (PrimMonad m, PrimState m ~ s) => MArr arr s a -> Int -> Int -> m (MArr arr s a)  -    -- | Resize mutable array to given size.+    -- | Resize a mutable array to the given size.     resizeMutableArr :: (PrimMonad m, PrimState m ~ s) => MArr arr s a -> Int -> m (MArr arr s a)  -    -- | Shrink mutable array to given size. This operation only works on primitive arrays.+    -- | Shrink a mutable array to the given size. This operation only works on primitive arrays.     -- For some array types, this is a no-op, e.g. 'sizeOfMutableArr' will not change.     shrinkMutableArr :: (PrimMonad m, PrimState m ~ s) => MArr arr s a -> Int -> m () @@ -209,21 +238,21 @@     sameMutableArr :: MArr arr s a -> MArr arr s a -> Bool  -    -- | Size of immutable array.+    -- | Size of the immutable array.     sizeofArr :: arr a -> Int  -    -- | Size of mutable array.+    -- | Size of the mutable array.     sizeofMutableArr :: (PrimMonad m, PrimState m ~ s) => MArr arr s a -> m Int  -    -- | Is two immutable array are referencing the same one.+    -- | Check whether the two immutable arrays refer to the same memory block     ---    -- Note that 'sameArr' 's result may change depending on compiler's optimizations, for example+    -- Note that the result of 'sameArr' may change depending on compiler's optimizations, for example,     -- @let arr = runST ... in arr `sameArr` arr@ may return false if compiler decides to     -- inline it.     ---    -- See https://ghc.haskell.org/trac/ghc/ticket/13908 for more background.+    -- See https://ghc.haskell.org/trac/ghc/ticket/13908 for more context.     --     sameArr :: arr a -> arr a -> Bool @@ -553,10 +582,10 @@  -------------------------------------------------------------------------------- --- | Yield a pointer to the array's data and do computation with it.+-- | Obtain the pointer to the content of an array, and the pointer should only be used during the IO action. ----- This operation is only safe on /pinned/ primitive arrays allocated by 'newPinnedPrimArray' or--- 'newAlignedPinnedPrimArray'.+-- This operation is only safe on /pinned/ primitive arrays (Arrays allocated by 'newPinnedPrimArray' or+-- 'newAlignedPinnedPrimArray'). -- -- Don't pass a forever loop to this function, see <https://ghc.haskell.org/trac/ghc/ticket/14346 #14346>. withPrimArrayContents :: PrimArray a -> (Ptr a -> IO b) -> IO b@@ -568,10 +597,10 @@     primitive_ (touch# ba#)     return b --- | Yield a pointer to the array's data and do computation with it.+-- | Obtain the pointer to the content of an mutable array, and the pointer should only be used during the IO action. ----- This operation is only safe on /pinned/ primitive arrays allocated by 'newPinnedPrimArray' or--- 'newAlignedPinnedPrimArray'.+-- This operation is only safe on /pinned/ primitive arrays (Arrays allocated by 'newPinnedPrimArray' or+-- 'newAlignedPinnedPrimArray'). -- -- Don't pass a forever loop to this function, see <https://ghc.haskell.org/trac/ghc/ticket/14346 #14346>. withMutablePrimArrayContents :: MutablePrimArray RealWorld a -> (Ptr a -> IO b) -> IO b@@ -608,7 +637,8 @@     writeArr marr 1 y     unsafeFreezeArr marr --- | Modify(strictly) an immutable array's element at given index to produce a new array.+-- | Modify(strictly) an immutable some elements of an array with specified subrange.+-- This function will produce a new array. modifyIndexArr :: Arr arr a                => arr a                -> Int        -- ^ offset@@ -623,13 +653,13 @@     writeArr marr ix v     unsafeFreezeArr marr --- | Insert an immutable array's element at given index to produce a new array.+-- | Insert a value to an immutable array at given index. This function will produce a new array. insertIndexArr :: Arr arr a                => arr a                -> Int        -- ^ offset                -> Int        -- ^ length                -> Int        -- ^ insert index in new array-               -> a          -- ^ element to be inserted+               -> a          -- ^ value to be inserted                -> arr a {-# INLINE insertIndexArr #-} insertIndexArr arr s l i x = runST $ do@@ -638,12 +668,12 @@     when (i<l) $ copyArr marr (i+1) arr (i+s) (l-i)     unsafeFreezeArr marr --- | Delete an immutable array's element at given index to produce a new array.+-- | Delete an element of the immutable array's at given index. This function will produce a new array. deleteIndexArr :: Arr arr a                => arr a                -> Int        -- ^ offset                -> Int        -- ^ length-               -> Int        -- ^ drop index in new array+               -> Int        -- ^ the index of the element to delete                -> arr a {-# INLINE deleteIndexArr #-} deleteIndexArr arr s l i = runST $ do
Z/Data/Builder/Base.hs view
@@ -55,6 +55,7 @@ import           Control.Monad import           Control.Monad.Primitive import           Data.Bits                          (unsafeShiftL, unsafeShiftR, (.&.))+import           Data.Primitive.Ptr                 (copyPtrToMutablePrimArray) import           Data.Word import           Data.Int import           GHC.CString                        (unpackCString#, unpackCStringUtf8#)@@ -67,7 +68,6 @@ import qualified Z.Data.Text.UTF8Codec            as T import qualified Z.Data.Vector.Base               as V import qualified Z.Data.Array                     as A-import           Z.Foreign import           System.IO.Unsafe import           Test.QuickCheck.Arbitrary (Arbitrary(..), CoArbitrary(..)) 
Z/Data/Parser.hs view
@@ -39,8 +39,9 @@   , decodePrimLE, decodePrimBE     -- * More parsers   , scan, scanChunks, peekMaybe, peek, satisfy, satisfyWith-  , anyWord8, word8, anyChar8, char8, skipWord8, endOfLine, skip, skipWhile, skipSpaces-  , take, takeTill, takeWhile, takeWhile1, takeRemaining, bytes, bytesCI+  , anyWord8, word8, char8, anyChar8, anyCharUTF8, charUTF8, char7, anyChar7+  , skipWord8, endOfLine, skip, skipWhile, skipSpaces+  , take, takeN, takeTill, takeWhile, takeWhile1, takeRemaining, bytes, bytesCI   , text     -- * Numeric parsers     -- ** Decimal
Z/Data/Parser/Base.hs view
@@ -28,7 +28,8 @@   , decodePrimLE, decodePrimBE     -- * More parsers   , scan, scanChunks, peekMaybe, peek, satisfy, satisfyWith-  , anyWord8, word8, anyChar8, char8, skipWord8, endOfLine, skip, skipWhile, skipSpaces+  , anyWord8, word8, char8, anyChar8, anyCharUTF8, charUTF8, char7, anyChar7+  , skipWord8, endOfLine, skip, skipWhile, skipSpaces   , take, takeN, takeTill, takeWhile, takeWhile1, takeRemaining, bytes, bytesCI   , text     -- * Misc@@ -42,13 +43,16 @@ import qualified Data.Primitive.PrimArray           as A import           Data.Int import           Data.Word+import           Data.Bits                          ((.&.)) import           GHC.Types import           Prelude                            hiding (take, takeWhile) import           Z.Data.Array.Unaligned import           Z.Data.ASCII-import qualified Z.Data.Text.Base                 as T-import qualified Z.Data.Vector.Base               as V-import qualified Z.Data.Vector.Extra              as V+import qualified Z.Data.Text.Base                   as T+import qualified Z.Data.Text.Extra                  as T+import qualified Z.Data.Text.UTF8Codec              as T+import qualified Z.Data.Vector.Base                 as V+import qualified Z.Data.Vector.Extra                as V  -- | Simple parsing result, that represent respectively: --@@ -479,6 +483,18 @@ {-# INLINE char8 #-} char8 = word8 . c2w +-- | Match a specific 7bit char.+--+char7 :: Char -> Parser ()+{-# INLINE char7 #-}+char7 chr = word8 (c2w chr .&. 0x7F)++-- | Match a specific UTF8 char.+--+charUTF8 :: Char -> Parser ()+{-# INLINE charUTF8 #-}+charUTF8 = text . T.singleton+ -- | Take a byte and return as a 8bit char. -- anyChar8 :: Parser Char@@ -486,6 +502,40 @@ anyChar8 = do     w <- anyWord8     return $! w2c w++-- | Take a byte and return as a 7bit char, fail if exceeds @0x7F@.+--+anyChar7 :: Parser Char+{-# INLINE anyChar7 #-}+anyChar7 = do+    w <- anyWord8+    if w > 0x7f+    then fail' "Z.Data.Parser.anyChar7: byte exceeds 0x7F"+    else return $! w2c w++-- | Decode next few bytes as an UTF8 char.+--+-- Don't use this method as UTF8 decoder, it's slower than 'T.validate'.+anyCharUTF8 :: Parser Char+{-# INLINABLE anyCharUTF8 #-}+anyCharUTF8 = do+    r <- Parser $ \ kf k inp -> do+        let (V.PrimVector arr s l) = inp+        if l > 0+        then+            let l' = T.decodeCharLen arr s+            in if l' > l+            then k (Left l') inp+            else do+                case T.validateMaybe (V.unsafeTake l' inp) of+                    Just t -> k (Right $! T.head t) $! V.unsafeDrop l' inp+                    _ -> kf ["Z.Data.Parser.Base.anyCharUTF8: invalid UTF8 bytes"] inp+        else k (Left 1) inp+    case r of+        Left d -> do+            ensureN d ["Z.Data.Parser.Base.anyCharUTF8: not enough bytes"]+            anyCharUTF8+        Right c -> return c  -- | Match either a single newline byte @\'\\n\'@, or a carriage -- return followed by a newline byte @\"\\r\\n\"@.
Z/Data/Text/Regex.hs view
@@ -28,25 +28,26 @@   , extract   ) where -import Z.Foreign import Control.Exception+import Control.Monad import Data.Int import Data.Word import GHC.Stack import GHC.Generics-import Foreign.ForeignPtr import Foreign.Marshal.Utils            (fromBool) import System.IO.Unsafe import qualified Z.Data.Text.Base       as T import qualified Z.Data.Text.Print      as T import qualified Z.Data.Vector.Base     as V import qualified Z.Data.Array           as A+import Z.Foreign.CPtr+import Z.Foreign  -- | A compiled RE2 regex. data Regex = Regex-    { regexPtr   :: {-# UNPACK #-} !(ForeignPtr Regex)-    , regexCaptureNum :: {-# UNPACK #-} !Int        -- ^ capturing group number(including @\\0@)-    , regexPattern :: T.Text                        -- ^ Get back regex's pattern.+    { regexPtr        :: {-# UNPACK #-} !(CPtr Regex)+    , regexCaptureNum :: {-# UNPACK #-} !Int            -- ^ capturing group number(including @\\0@)+    , regexPattern    :: T.Text                         -- ^ Get back regex's pattern.     } deriving (Show, Generic)       deriving anyclass T.Print @@ -113,44 +114,44 @@ regex :: HasCallStack => T.Text -> Regex {-# NOINLINE regex #-} regex t = unsafePerformIO $ do-    r <- withPrimVectorUnsafe (T.getUTF8Bytes t) hs_re2_compile_pattern_default+    (cp, r) <- newCPtrUnsafe (\ mba# ->+        (withPrimVectorUnsafe (T.getUTF8Bytes t) (hs_re2_compile_pattern_default mba#)))+        p_hs_re2_delete_pattern++    when (r == nullPtr) (throwIO (InvalidRegexPattern t callStack))     ok <- hs_re2_ok r-    if ok /= 0-    then do-        p <- newForeignPtr p_hs_re2_delete_pattern r-        n <- hs_num_capture_groups r-        return (Regex p n t)-    else do-        hs_re2_delete_pattern r-        throwIO (InvalidRegexPattern t callStack)+    when (ok == 0) (throwIO (InvalidRegexPattern t callStack)) +    n <- withCPtr cp hs_num_capture_groups+    return (Regex cp n t)+ -- | Compile a regex pattern withOptions, throw 'InvalidRegexPattern' in case of illegal patterns. regexOpts :: HasCallStack => RegexOpts -> T.Text -> Regex {-# NOINLINE regexOpts #-} regexOpts RegexOpts{..} t = unsafePerformIO $ do-    r <- withPrimVectorUnsafe (T.getUTF8Bytes t) $ \ p o l ->-        hs_re2_compile_pattern p o l-            (fromBool posix_syntax  )-            (fromBool longest_match )-            max_mem-            (fromBool literal       )-            (fromBool never_nl      )-            (fromBool dot_nl        )-            (fromBool never_capture )-            (fromBool case_sensitive)-            (fromBool perl_classes  )-            (fromBool word_boundary )-            (fromBool one_line      )+    (cp, r) <- newCPtrUnsafe ( \ mba# ->+        (withPrimVectorUnsafe (T.getUTF8Bytes t) $ \ p o l ->+            hs_re2_compile_pattern mba# p o l+                (fromBool posix_syntax  )+                (fromBool longest_match )+                max_mem+                (fromBool literal       )+                (fromBool never_nl      )+                (fromBool dot_nl        )+                (fromBool never_capture )+                (fromBool case_sensitive)+                (fromBool perl_classes  )+                (fromBool word_boundary )+                (fromBool one_line      )))+        p_hs_re2_delete_pattern++    when (r == nullPtr) (throwIO (InvalidRegexPattern t callStack))     ok <- hs_re2_ok r-    if ok /= 0-    then do-        p <- newForeignPtr p_hs_re2_delete_pattern r-        n <- hs_num_capture_groups r-        return (Regex p n t)-    else do-        hs_re2_delete_pattern r-        throwIO (InvalidRegexPattern t callStack)+    when (ok == 0) (throwIO (InvalidRegexPattern t callStack)) +    n <- withCPtr cp hs_num_capture_groups+    return (Regex cp n t)+ -- | Escape a piece of text literal so that it can be safely used in regex pattern. -- -- >>> escape "(\\d+)"@@ -165,7 +166,7 @@ test :: Regex -> T.Text -> Bool {-# INLINABLE test #-} test (Regex fp _ _) (T.Text bs) = unsafePerformIO $ do-    withForeignPtr fp $ \ p ->+    withCPtr fp $ \ p ->         withPrimVectorUnsafe bs $ \ ba# s l -> do             r <- hs_re2_test p ba# s l             return $! r /= 0@@ -181,7 +182,7 @@ match :: Regex -> T.Text -> (T.Text, [Maybe T.Text], T.Text) {-# INLINABLE match #-} match (Regex fp n _) t@(T.Text bs@(V.PrimVector ba _ _)) = unsafePerformIO $ do-    withForeignPtr fp $ \ p ->+    withCPtr fp $ \ p ->         withPrimVectorUnsafe bs $ \ ba# s l -> do             (starts, (lens, r)) <- allocPrimArrayUnsafe n $ \ p_starts ->                 allocPrimArrayUnsafe n $ \ p_ends ->@@ -216,7 +217,7 @@         -> T.Text {-# INLINABLE replace #-} replace (Regex fp _ _) g inp rew = T.Text . unsafePerformIO $ do-    withForeignPtr fp $ \ p ->+    withCPtr fp $ \ p ->         withPrimVectorUnsafe (T.getUTF8Bytes inp) $ \ inpp inpoff inplen ->             withPrimVectorUnsafe (T.getUTF8Bytes rew) $ \ rewp rewoff rewlen ->                 fromStdString ((if g then hs_re2_replace_g else hs_re2_replace)@@ -234,16 +235,20 @@         -> T.Text {-# INLINABLE extract #-} extract (Regex fp _ _) inp rew = T.Text . unsafePerformIO $ do-    withForeignPtr fp $ \ p ->+    withCPtr fp $ \ p ->         withPrimVectorUnsafe (T.getUTF8Bytes inp) $ \ inpp inpoff inplen ->             withPrimVectorUnsafe (T.getUTF8Bytes rew) $ \ rewp rewoff rewlen ->                 fromStdString (hs_re2_extract p inpp inpoff inplen rewp rewoff rewlen)  -------------------------------------------------------------------------------- -foreign import ccall unsafe hs_re2_compile_pattern_default :: BA# Word8 -> Int -> Int -> IO (Ptr Regex)+foreign import ccall unsafe hs_re2_compile_pattern_default+    :: MBA# (Ptr Regex) -> BA# Word8 -> Int -> Int+    -> IO (Ptr Regex)+ foreign import ccall unsafe hs_re2_compile_pattern-    :: BA# Word8 -> Int -> Int+    :: MBA# (Ptr Regex)+    -> BA# Word8 -> Int -> Int     -> CBool -- ^ posix_syntax     -> CBool -- ^ longest_match     -> Int64 -- ^ max_mem@@ -257,8 +262,7 @@     -> CBool -- ^ one_line     -> IO (Ptr Regex) -foreign import ccall unsafe "&hs_re2_delete_pattern" p_hs_re2_delete_pattern :: FinalizerPtr Regex-foreign import ccall unsafe hs_re2_delete_pattern :: Ptr Regex -> IO ()+foreign import ccall unsafe "&hs_re2_delete_pattern" p_hs_re2_delete_pattern :: FunPtr (Ptr Regex -> IO ())  foreign import ccall unsafe hs_re2_ok :: Ptr Regex -> IO CInt foreign import ccall unsafe hs_num_capture_groups :: Ptr Regex -> IO Int
Z/Data/Vector/Base.hs view
@@ -88,6 +88,7 @@ import           Data.Bits import           Data.Char                      (ord) import qualified Data.Foldable                  as F+import           Data.Kind                      (Type) import           Data.Hashable                  (Hashable(..)) import           Data.Hashable.Lifted           (Hashable1(..), hashWithSalt1) import qualified Data.List                      as List@@ -114,6 +115,7 @@ import           System.IO.Unsafe               (unsafeDupablePerformIO)  import           Z.Data.Array+import           Z.Data.ASCII                   (toLower)  -- | Typeclass for box and unboxed vectors, which are created by slicing arrays. --@@ -127,7 +129,7 @@ -- 'toArr' will always return offset 0 and whole array length, and 'fromArr' is O(n) 'copyArr'. class (Arr (IArray v) a) => Vec v a where     -- | Vector's immutable array type-    type IArray v :: * -> *+    type IArray v :: Type -> Type     -- | Get underline array and slice range(offset and length).     toArr :: v a -> (IArray v a, Int, Int)     -- | Create a vector by slicing an array(with offset and length).@@ -547,16 +549,10 @@     {-# INLINE fromListN #-}     fromListN = packN +-- | This instance assume ASCII encoded bytes instance CI.FoldCase Bytes where     {-# INLINE foldCase #-}-    foldCase = map toLower8-      where-        toLower8 :: Word8 -> Word8-        toLower8 w-          |  65 <= w && w <=  90 ||-            192 <= w && w <= 214 ||-            216 <= w && w <= 222 = w + 32-          | otherwise            = w+    foldCase = map toLower  -- | /O(n)/, pack an ASCII 'String', multi-bytes char WILL BE CHOPPED! packASCII :: String -> Bytes@@ -750,7 +746,7 @@         if i < n         then do writeArr marr i x                 return (IPair (i+1) marr)-        else do let !n' = n `shiftL` 1+        else do let !n' = n `unsafeShiftL` 1                 !marr' <- resizeMutableArr marr n'                 writeArr marr' i x                 return (IPair (i+1) marr')@@ -804,7 +800,7 @@         if i >= 0         then do writeArr marr i x                 return (IPair (i-1) marr)-        else do let !n' = n `shiftL` 1  -- double the buffer+        else do let !n' = n `unsafeShiftL` 1  -- double the buffer                 !marr' <- newArr n'                 copyMutableArr marr' n marr 0 n                 writeArr marr' (n-1) x
+ Z/Foreign/CPtr.hs view
@@ -0,0 +1,88 @@+{-|+Module      : Z.Foreign.CPtr+Description : Lightweight foreign pointer+Copyright   : (c) Dong Han, 2020+License     : BSD+Maintainer  : winterland1989@gmail.com+Stability   : experimental+Portability : non-portable++This module provide a lightweight foreign pointer, support c initializer and finalizer only.+-}++module Z.Foreign.CPtr (+  -- * CPtr type+    CPtr, newCPtrUnsafe, newCPtr, withCPtr+  -- * Ptr type+  , Ptr+  , nullPtr+  , FunPtr+  ) where++import Control.Monad.Primitive+import Control.Exception        (mask_)+import Data.Primitive.PrimArray+import Z.Data.Text              as T+import GHC.Ptr+import GHC.Exts++-- | Lightweight foreign pointers.+newtype CPtr a = CPtr (PrimArray (Ptr a))++instance Eq (CPtr a) where+    {-# INLINE (==) #-}+    CPtr a == CPtr b = indexPrimArray a 0 == indexPrimArray b 0++instance Ord (CPtr a) where+    {-# INLINE compare #-}+    CPtr a `compare` CPtr b = indexPrimArray a 0 `compare` indexPrimArray b 0++instance Show (CPtr a) where+    show = toString++instance T.Print (CPtr a) where+    {-# INLINE toUTF8BuilderP #-}+    toUTF8BuilderP _ (CPtr mpa) = T.toUTF8BuilderP 0 (indexPrimArray mpa 0)++-- | Initialize a 'CPtr' with initializer(must be unsafe FFI) and finalizer.+--+-- The initializer will receive a pointer of pointer so that it can do allocation and+-- write pointer back.+newCPtrUnsafe :: (MutableByteArray# RealWorld -> IO r) -- ^ initializer+              -> FunPtr (Ptr a -> IO b) -- ^ finalizer+              -> IO (CPtr a, r)+newCPtrUnsafe ini (FunPtr fin#) = mask_ $ do+    mpa@(MutablePrimArray mba#) <- newPrimArray 1+    r <- ini mba#+    (Ptr addr#) <- readPrimArray mpa 0+    pa@(PrimArray ba#) <- unsafeFreezePrimArray mpa+    primitive_ $ \ s0# ->+        let !(# s1#, w# #) = mkWeakNoFinalizer# ba# () s0#+            !(# s2#, _ #) = addCFinalizerToWeak# fin# addr# 0# addr# w# s1#+        in s2#+    return (CPtr pa, r)++-- | Initialize a 'CPtr' with initializer and finalizer.+--+-- The initializer will receive a pointer of pointer so that it can do allocation and+-- write pointer back.+newCPtr :: (Ptr (Ptr a) -> IO r) -- ^ initializer+        -> FunPtr (Ptr a -> IO b) -- ^ finalizer+        -> IO (CPtr a, r)+newCPtr ini (FunPtr fin#) = mask_ $ do+    mpa <- newPinnedPrimArray 1+    r <- ini (mutablePrimArrayContents mpa)+    (Ptr addr#) <- readPrimArray mpa 0+    pa@(PrimArray ba#) <- unsafeFreezePrimArray mpa+    primitive_ $ \ s0# ->+        let !(# s1#, w# #) = mkWeakNoFinalizer# ba# () s0#+            !(# s2#, _ #) = addCFinalizerToWeak# fin# addr# 0# addr# w# s1#+        in s2#+    return (CPtr pa, r)++-- | The only way to use 'CPtr' as a 'Ptr' in FFI is to use 'withCPtr'.+withCPtr :: CPtr a -> (Ptr a -> IO b) -> IO b+withCPtr (CPtr pa@(PrimArray ba#)) f = do+    r <- f (indexPrimArray pa 0)+    primitive_ (touch# ba#)+    return r
cbits/regex.cc view
@@ -28,6 +28,7 @@ #include <HsFFI.h> #include <cstddef> #include <cstdlib>+#include <new> #include <re2/re2.h> #include <re2/set.h> @@ -37,7 +38,7 @@     return re2::RE2::Options::kDefaultMaxMem; } -re2::RE2 *hs_re2_compile_pattern(const char *input, HsInt off, HsInt input_len+re2::RE2* hs_re2_compile_pattern(re2::RE2** re, const char *input, HsInt off, HsInt input_len      , bool    posix_syntax                        , bool    longest_match                       , int64_t max_mem                       @@ -48,7 +49,7 @@      , bool    case_sensitive                      , bool    perl_classes                        , bool    word_boundary                 -     , bool    one_line ){   +     , bool    one_line ){     re2::RE2::Options opts;     opts.set_posix_syntax  ( posix_syntax  );      opts.set_longest_match ( longest_match );@@ -61,11 +62,14 @@     opts.set_perl_classes  ( perl_classes  );     opts.set_word_boundary ( word_boundary );     opts.set_one_line      ( one_line      );-	return new re2::RE2(re2::StringPiece(input+off, input_len), opts);++    *re = new (std::nothrow) re2::RE2(re2::StringPiece(input+off, input_len), opts);+	return *re; } -re2::RE2 *hs_re2_compile_pattern_default(const char *input, HsInt off, HsInt input_len) {-	return new re2::RE2(re2::StringPiece(input+off, input_len));+re2::RE2* hs_re2_compile_pattern_default(re2::RE2** re, const char *input, HsInt off, HsInt input_len) {+	*re = new (std::nothrow) re2::RE2(re2::StringPiece(input+off, input_len));+    return *re; }  void hs_re2_delete_pattern(re2::RE2 *regex) {