Z-Data 0.8.7.0 → 0.8.8.0
raw patch · 27 files changed
+638/−187 lines, 27 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
+ Z.Data.Vector: replicateMVec :: (Applicative f, Vec v a) => Int -> f a -> f (v a)
+ Z.Data.Vector.Base: replicateMVec :: (Applicative f, Vec v a) => Int -> f a -> f (v a)
+ Z.Foreign.CPtr: addCPtrDep :: CPtr a -> b -> IO ()
+ Z.Foreign.CPtr: withCPtrForever :: CPtr a -> (Ptr a -> IO b) -> IO b
Files
- ChangeLog.md +6/−0
- README.md +8/−1
- Z-Data.cabal +38/−29
- Z/Data/Builder/Numeric.hs +2/−2
- Z/Data/CBytes.hs +1/−0
- Z/Data/Parser/Numeric.hs +1/−2
- Z/Data/Vector.hs +1/−0
- Z/Data/Vector/Base.hs +42/−35
- Z/Data/Vector/Hex.hs +0/−2
- Z/Foreign/CPtr.hs +46/−3
- cbits/bytes.c +15/−15
- cbits/dtoa.c +9/−6
- cbits/text.c +14/−14
- third_party/fastvalidate-utf-8/include/simdasciicheck_avx512.h +29/−0
- third_party/fastvalidate-utf-8/include/simdutf8check_avx512.h +297/−0
- third_party/re2/re2/compile.cc +48/−28
- third_party/re2/re2/dfa.cc +7/−4
- third_party/re2/re2/nfa.cc +1/−1
- third_party/re2/re2/perl_groups.cc +34/−34
- third_party/re2/re2/re2.h +3/−2
- third_party/re2/re2/regexp.cc +10/−4
- third_party/re2/re2/regexp.h +2/−1
- third_party/re2/re2/set.cc +3/−0
- third_party/re2/re2/tostring.cc +1/−1
- third_party/re2/util/mutex.h +1/−1
- third_party/utf8rewind/include/utf8rewind/utf8rewind.h +1/−0
- third_party/utf8rewind/source/utf8rewind.c +18/−2
ChangeLog.md view
@@ -1,5 +1,11 @@ # Revision history for Z-Data +## 0.8.8.0 -- 2021-06-13++* Add `withCPtrForever` and `addCPtrDep` to `Z.Foreign.CPtr` module.+* Add `replicateMVec` to `Z.Data.Vector`.+* Fix AVX512 text validate header building with C11.+ ## 0.8.7.0 -- 2021-06-12 * Add `use-avx2` and `use-avx512` flags(default to False) to enable avx2 or avx512 base64 codec, UTF8 validator, etc.
README.md view
@@ -19,7 +19,14 @@ ## Requirements -* A working haskell compiler system, GHC(>=8.6), cabal-install(>=2.4), hsc2hs.+* A working haskell compiler system, GHC(>=8.6), cabal-install(>=2.4), here're some options:+ * Mac users can get them via [homebew](//brew.sh/): `brew install ghc cabal-install`.+ * Windows users can get them via [chocolatey](//chocolatey.org): `choco install ghc cabal`.+ * Ubuntu users are recommended to use this [ppa](//launchpad.net/~hvr/+archive/ubuntu/ghc).+* A working C/C++ compiler support C++11, here're some options:+ * Mac users can use the `clang` comes with the [XCode Command Line Tools](https://developer.apple.com/downloads).+ * Windows users can use the mingw's one comes with GHC, you can use it by adding `your_path_to_ghc\mingw\bin` to your `PATH`.+ * Ubuntu users can install `gcc/g++` by running `sudo apt install build-essential`. * Tests need [hspec-discover](https://hackage.haskell.org/package/hspec-discover). ## Example usage
Z-Data.cabal view
@@ -1,6 +1,6 @@ cabal-version: 2.4 name: Z-Data-version: 0.8.7.0+version: 0.8.8.0 synopsis: Array, vector and text description: This package provides array, slice and text operations license: BSD-3-Clause@@ -23,6 +23,8 @@ README.md third_party/fastvalidate-utf-8/include/simdasciicheck.h third_party/fastvalidate-utf-8/include/simdutf8check.h+ third_party/fastvalidate-utf-8/include/simdasciicheck_avx512.h+ third_party/fastvalidate-utf-8/include/simdutf8check_avx512.h third_party/fastbase64/include/chromiumbase64.h third_party/fastbase64/include/fastavxbase64.h third_party/fastbase64/src/fastavxbase64.c@@ -119,7 +121,7 @@ flag use-avx512 description:- Use AVX512 instructions(utf8 validation, base64 codec, etc).+ Use AVX512(AVX512F, AVX512VL, AVX512BW, AVX512VBMI) instructions(utf8 validation, base64 codec, etc). default: False manual: True@@ -202,21 +204,24 @@ third_party/re2 includes:- simdasciicheck.h- simdutf8check.h utf8rewind.h chromiumbase64.h - if flag(use-avx2)- includes:- fastavxbase64.h+ if arch(x86_64)+ includes:+ simdasciicheck.h+ simdutf8check.h - if flag(use-avx512)- includes:- simdasciicheck_avx512.h- simdutf8check_avx512.h- fastavx512bwbase64.h+ if flag(use-avx2)+ includes:+ fastavxbase64.h + if flag(use-avx512)+ includes:+ simdasciicheck_avx512.h+ simdutf8check_avx512.h+ fastavx512bwbase64.h+ c-sources: cbits/bytes.c cbits/dtoa.c@@ -233,13 +238,14 @@ third_party/utf8rewind/source/unicodedatabase.c third_party/utf8rewind/source/utf8rewind.c - if flag(use-avx2)- c-sources:- third_party/fastbase64/src/fastavxbase64.c+ if arch(x86_64)+ if flag(use-avx2)+ c-sources:+ third_party/fastbase64/src/fastavxbase64.c - if flag(use-avx512)- c-sources:- third_party/fastbase64/src/fastavx512bwbase64.c+ if flag(use-avx512)+ c-sources:+ third_party/fastbase64/src/fastavx512bwbase64.c cxx-sources: cbits/regex.cc@@ -269,22 +275,25 @@ default-language: Haskell2010 build-tool-depends: hsc2hs:hsc2hs -any - cc-options: -std=c11 -Wno-sign-compare+ cc-options: -std=c11 -Wall -Wno-pointer-to-int-cast+ cxx-options: -std=c++11 - if flag(use-avx512)- cc-options: -march=cannonlake -DZ_USE_AVX512- else- if flag(use-avx2)- cc-options: -mavx2 -DZ_USE_AVX2+ if arch(x86_64)+ if flag(use-avx512)+ cc-options: -march=cannonlake+ cxx-options: -march=cannonlake else- cc-options: -msse4.2-- cxx-options: -std=c++11+ if flag(use-avx2)+ cc-options: -mavx2+ cxx-options: -mavx2+ else+ cc-options: -msse4.2+ cxx-options: -msse4.2 if os(windows) extra-libraries: stdc++ cc-options: -DWIN32_LEAN_AND_MEAN -D_WIN32_WINNT=0x0600- cxx-options: -DWIN32_LEAN_AND_MEAN -D_WIN32_WINNT=0x0600+ cxx-options: -DWIN32_LEAN_AND_MEAN -D_WIN32_WINNT=0x0600 else if os(osx) extra-libraries:@@ -306,7 +315,7 @@ -- we work around this issue using Setup.hs ghc-options:- -Wall -Wno-unticked-promoted-constructors -Wno-incomplete-patterns+ -Wall -Wno-unticked-promoted-constructors -Wno-incomplete-patterns default-extensions: BangPatterns
Z/Data/Builder/Numeric.hs view
@@ -516,7 +516,7 @@ let !i = fromIntegral v .&. 0xFF; !j = i + i writePrimArray marr off $ indexOffPtr hexDigitTable j writePrimArray marr (off + 1) $ indexOffPtr hexDigitTable (j+1)- | d < 0 = do -- for FiniteBits instances which has extra bits+ | otherwise = do -- for FiniteBits instances which has extra bits let !i = fromIntegral v .&. 0x0F :: Int writePrimArray marr off $ i2wHex i @@ -538,7 +538,7 @@ let !i = fromIntegral v .&. 0xFF; !j = i + i writePrimArray marr off $ indexOffPtr hexDigitTableUpper j writePrimArray marr (off + 1) $ indexOffPtr hexDigitTableUpper (j+1)- | d < 0 = do -- for FiniteBits instances which has extra bits+ | otherwise = do -- for FiniteBits instances which has extra bits let !i = fromIntegral v .&. 0x0F :: Int writePrimArray marr off $ i2wHexUpper i
Z/Data/CBytes.hs view
@@ -355,6 +355,7 @@ let i' = i + l writePrimArray mba i' w8 copy bs (i'+1) mba+ copy _ _ _ = error "Z.Data.CBytes.intercalateElem: impossible" instance IsString CBytes where {-# INLINE fromString #-}
Z/Data/Parser/Numeric.hs view
@@ -108,8 +108,7 @@ w2iHex w | w <= 57 = fromIntegral w - 48 | w <= 70 = fromIntegral w - 55- | w <= 102 = fromIntegral w - 87-+ | otherwise = fromIntegral w - 87 -- | Same with 'uint', but sliently cast in case of overflow. uint_ :: forall a. (Integral a, Bounded a) => Parser a
Z/Data/Vector.hs view
@@ -96,6 +96,7 @@ , mapAccumR -- ** Generating and unfolding vector , replicate+ , replicateMVec , cycleN , unfoldr , unfoldrN
Z/Data/Vector/Base.hs view
@@ -56,6 +56,7 @@ , mapAccumR -- ** Generating and unfolding vector , replicate+ , replicateMVec , cycleN , unfoldr , unfoldrN@@ -85,6 +86,7 @@ import Control.Exception import Control.Monad import Control.Monad.ST+import Control.Monad.Primitive import Data.Bits import Data.Char (ord) import qualified Data.Foldable as F@@ -338,51 +340,33 @@ | i >= end = salt | otherwise = go (h salt (indexArr arr i)) (i+1) --- | Traverse vector and gather result in another vector,+-- | Traverse vector and gather result in another vector.+--+-- There're rules to optimize the intermedia list away when @f@ is an instance of 'PrimMoand',+-- such as 'IO', 'ST' or 'Z.Data.Parser.Parser'. traverseVec :: (Vec v a, Vec u b, Applicative f) => (a -> f b) -> v a -> f (u b) {-# INLINE [1] traverseVec #-}-{-# RULES "traverseVec/ST" forall f. traverseVec f = traverseWithIndexST (const f) #-}-{-# RULES "traverseVec/IO" forall f. traverseVec f = traverseWithIndexIO (const f) #-}+{-# RULES "traverseVec/PrimMonad" forall (f :: PrimMonad m => a -> m b). traverseVec f = traverseWithIndexPM (const f) #-} traverseVec f v = packN (length v) <$> T.traverse f (unpack v) --- | Traverse vector and gather result in another vector,+-- | Traverse vector and gather result in another vector. traverseWithIndex :: (Vec v a, Vec u b, Applicative f) => (Int -> a -> f b) -> v a -> f (u b) {-# INLINE [1] traverseWithIndex #-}-{-# RULES "traverseWithIndex/ST" traverseWithIndex = traverseWithIndexST #-}-{-# RULES "traverseWithIndex/IO" traverseWithIndex = traverseWithIndexIO #-}+{-# RULES "traverseWithIndex/PrimMonad" forall (f :: PrimMonad m => Int -> a -> m b). traverseWithIndex f = traverseWithIndexPM f #-} traverseWithIndex f v = packN (length v) <$> zipWithM f [0..] (unpack v) -traverseWithIndexST :: forall v u a b s. (Vec v a, Vec u b) => (Int -> a -> ST s b) -> v a -> ST s (u b)-{-# INLINE traverseWithIndexST #-}-traverseWithIndexST f (Vec arr s l)- | l == 0 = return empty- | otherwise = do- marr <- newArr l- go marr 0- ba <- unsafeFreezeArr marr- return $! fromArr ba 0 l- where- go :: MArr (IArray u) s b -> Int -> ST s ()- go !marr !i- | i >= l = return ()- | otherwise = do- x <- indexArrM arr (i+s)- writeArr marr i =<< f i x- go marr (i+1)--traverseWithIndexIO :: forall v u a b. (Vec v a, Vec u b) => (Int -> a -> IO b) -> v a -> IO (u b)-{-# INLINE traverseWithIndexIO #-}-traverseWithIndexIO f (Vec arr s l)+traverseWithIndexPM :: forall m v u a b. (PrimMonad m, Vec v a, Vec u b) => (Int -> a -> m b) -> v a -> m (u b)+{-# INLINE traverseWithIndexPM #-}+traverseWithIndexPM f (Vec arr s l) | l == 0 = return empty | otherwise = do marr <- newArr l- go marr 0- ba <- unsafeFreezeArr marr+ ba <- go marr 0 return $! fromArr ba 0 l where- go :: MArr (IArray u) RealWorld b -> Int -> IO ()+ go :: MArr (IArray u) (PrimState m) b -> Int -> m (IArray u b) go !marr !i- | i >= l = return ()+ | i >= l = unsafeFreezeArr marr | otherwise = do x <- indexArrM arr (i+s) writeArr marr i =<< f i x@@ -563,9 +547,7 @@ -- | /O(n)/, pack an ASCII 'String', multi-bytes char WILL BE CHOPPED! packASCII :: String -> Bytes {-# INLINE CONLIKE [0] packASCII #-}-{-# RULES- "packASCII/packASCIIAddr" forall addr . packASCII (unpackCString# addr) = packASCIIAddr addr- #-}+{-# RULES "packASCII/packASCIIAddr" forall addr . packASCII (unpackCString# addr) = packASCIIAddr addr #-} packASCII = pack . fmap (fromIntegral . ord) packASCIIAddr :: Addr# -> Bytes@@ -735,7 +717,7 @@ -- This function is a /good consumer/ in the sense of build/foldr fusion. -- packN :: forall v a. Vec v a => Int -> [a] -> v a-{-# INLINE packN #-}+{-# INLINE [1] packN #-} packN n0 = \ ws0 -> runST (do let n = max 4 n0 marr <- newArr n (IPair i marr') <- foldM go (IPair 0 marr) ws0@@ -755,6 +737,31 @@ !marr' <- resizeMutableArr marr n' writeArr marr' i x return (IPair (i+1) marr')+++-- | A version of 'replicateM' which works on 'Vec', with specialized rules under 'PrimMonad'.+--+-- There're rules to optimize the intermedia list away when m is an instance of 'PrimMoand',+-- such as 'IO', 'ST' or 'Z.Data.Parser.Parser'.+replicateMVec :: (Applicative f, Vec v a) => Int -> f a -> f (v a)+{-# INLINE [1] replicateMVec #-}+{-# RULES "replicateMVec/PrimMonad" forall n (x :: IO a). replicateMVec n x = replicatePMVec n x #-}+replicateMVec n f = packN n <$> replicateM n f++-- | A version of 'replicateM' which works on 'PrimMonad' and 'Vec'.+replicatePMVec :: (PrimMonad m, Vec v a) => Int -> m a -> m (v a)+{-# INLINE replicatePMVec #-}+replicatePMVec n f = do+ marr <- newArr n+ ba <- go marr 0+ (return $! fromArr ba 0 n)+ where+ go marr i+ | i >= n = unsafeFreezeArr marr+ | otherwise = do+ x <- f+ writeArr marr i x+ go marr (i+1) -- | /O(n)/ Convert a list into a vector with given size. --
Z/Data/Vector/Hex.hs view
@@ -34,7 +34,6 @@ import GHC.Stack import System.IO.Unsafe import qualified Z.Data.Vector.Base as V-import qualified Z.Data.Vector.Extra as V import qualified Z.Data.Builder.Base as B import qualified Z.Data.Text.Base as T import qualified Z.Data.Text.Print as T@@ -74,7 +73,6 @@ if upper then hs_hex_encode_upper buf# 0 parr s l else hs_hex_encode buf# 0 parr s l- -- | 'B.Builder' version of 'hexEncode'. hexEncodeBuilder :: Bool -- ^ uppercase?
Z/Foreign/CPtr.hs view
@@ -12,7 +12,9 @@ module Z.Foreign.CPtr ( -- * CPtr type- CPtr, newCPtr', newCPtrUnsafe, newCPtr, withCPtr, withCPtrsUnsafe, withCPtrs+ CPtr, newCPtr', newCPtrUnsafe, newCPtr+ , withCPtr, withCPtrsUnsafe, withCPtrForever, withCPtrs+ , addCPtrDep -- * Ptr type , Ptr , nullPtr@@ -21,11 +23,11 @@ import Control.Monad import Control.Monad.Primitive-import Control.Exception (mask_) import Data.Primitive.PrimArray import qualified Z.Data.Text as T import GHC.Ptr import GHC.Exts+import GHC.IO import Z.Data.Array import Z.Foreign @@ -52,6 +54,7 @@ newCPtr' :: IO (Ptr a) -- ^ initializer -> FunPtr (Ptr a -> IO b) -- ^ finalizer -> IO (CPtr a)+{-# INLINABLE newCPtr' #-} newCPtr' ini (FunPtr fin#) = mask_ $ do mpa <- newPrimArray 1 p@(Ptr addr#) <- ini@@ -70,6 +73,7 @@ newCPtrUnsafe :: (MutableByteArray# RealWorld -> IO r) -- ^ initializer -> FunPtr (Ptr a -> IO b) -- ^ finalizer -> IO (CPtr a, r)+{-# INLINABLE newCPtrUnsafe #-} newCPtrUnsafe ini (FunPtr fin#) = mask_ $ do mpa@(MutablePrimArray mba#) <- newPrimArray 1 r <- ini mba#@@ -88,6 +92,7 @@ newCPtr :: (Ptr (Ptr a) -> IO r) -- ^ initializer -> FunPtr (Ptr a -> IO b) -- ^ finalizer -> IO (CPtr a, r)+{-# INLINABLE newCPtr #-} newCPtr ini (FunPtr fin#) = mask_ $ do mpa <- newPinnedPrimArray 1 r <- ini (mutablePrimArrayContents mpa)@@ -99,15 +104,36 @@ in s2# return (CPtr pa, r) --- | The only way to use 'CPtr' as a 'Ptr' in FFI is to use 'withCPtr'.+-- | Use 'CPtr' as a 'Ptr' in FFI. withCPtr :: CPtr a -> (Ptr a -> IO b) -> IO b+{-# INLINABLE withCPtr #-} withCPtr (CPtr pa@(PrimArray ba#)) f = do r <- f (indexPrimArray pa 0) primitive_ (touch# ba#) return r +-- | Use 'CPtr' as a 'Ptr' in FFI(potentially running forever).+--+-- When you pass a forever loop to 'withCPtr', GHC's simplifier may think the 'touch#'(which keep the 'CPtr' alive) after the loop are unreachable,+-- so it may be optimized away, 'withCPtrForever' solves that.+--+withCPtrForever :: CPtr a -> (Ptr a -> IO b) -> IO b+#if MIN_VERSION_base(4,15,0)+{-# INLINABLE withCPtrForever #-}+withCPtrForever (CPtr pa@(PrimArray ba#)) f = IO $ \ s ->+ case f (indexPrimArray pa 0) of+ IO action# -> keepAlive# ba# s action#+#else+{-# NOINLINE withCPtrForever #-}+withCPtrForever (CPtr pa@(PrimArray ba#)) f = do+ r <- f (indexPrimArray pa 0)+ primitive_ (touch# ba#)+ return r+#endif+ -- | Pass a list of 'CPtr Foo' as @foo**@. USE THIS FUNCTION WITH UNSAFE FFI ONLY! withCPtrsUnsafe :: forall a b. [CPtr a] -> (BA# (Ptr a) -> Int -> IO b) -> IO b+{-# INLINABLE withCPtrsUnsafe #-} withCPtrsUnsafe cptrs f = do mpa <- newPrimArray @IO @(Ptr a) len foldM_ (\ !i (CPtr pa) ->@@ -120,6 +146,7 @@ -- | Pass a list of 'CPtr Foo' as @foo**@. withCPtrs :: forall a b. [CPtr a] -> (Ptr (Ptr a) -> Int -> IO b) -> IO b+{-# INLINABLE withCPtrs #-} withCPtrs cptrs f = do mpa <- newPinnedPrimArray @IO @(Ptr a) len foldM_ (\ !i (CPtr pa) ->@@ -128,3 +155,19 @@ primitive_ (touch# cptrs) return r where len = length cptrs++-- | @addCPtrDep a b@ make @b@\'s life depends on @a@\'s, so that @b@ is guaranteed to outlive @a@.+--+-- This function is useful when you want to create life dependency among 'CPtr's,+-- be careful about the cost of collecting weak pointers though, see+-- <http://blog.ezyang.com/2014/05/the-cost-of-weak-pointers-and-finalizers-in-ghc/>.+-- e.g. If three 'CPtr's form a dependency chain, the dead weak list may get traversed three times.+-- So instead of adding dependencies in a chain or one by one, you should add them in a single call+-- with a tuple like @addCPtrDep root (fieldA, fieldB, ...)@.+--+addCPtrDep :: CPtr a -> b -> IO ()+{-# INLINABLE addCPtrDep #-}+addCPtrDep (CPtr (PrimArray ba#)) b =+ primitive_ $ \ s0# ->+ let !(# s1#, _ #) = mkWeakNoFinalizer# ba# b s0#+ in s1#
cbits/bytes.c view
@@ -36,9 +36,9 @@ #if defined(__x86_64__) #include <x86intrin.h> #endif-#if defined(Z_USE_AVX512)+#if defined(__AVX512BW__) #include <fastavx512bwbase64.h>-#elif defined(Z_USE_AVX2)+#elif defined(__AVX2__) #include <fastavxbase64.h> #endif @@ -142,12 +142,12 @@ mask = mask << 16 | mask; for (i = 32; i < LBLOCKSIZE * 8; i <<= 1) mask = (mask << i) | mask;- while (length >= LBLOCKSIZE) {- if (DETECTCHAR (*asrc, mask))- break;- length -= LBLOCKSIZE;- asrc--;- }+ while (length >= LBLOCKSIZE) {+ if (DETECTCHAR (*asrc, mask))+ break;+ length -= LBLOCKSIZE;+ asrc--;+ } /* If there are fewer than LBLOCKSIZE characters left, then we resort to the bytewise loop. */ src = (unsigned char *) asrc + LBLOCKSIZE - 1;@@ -293,9 +293,9 @@ // Base64 codec void hs_base64_encode(char* output, HsInt output_off, const char* input, HsInt off, HsInt len){-#if defined(Z_USE_AVX512)+#if defined(__AVX512BW__) fast_avx512bw_base64_encode(output+output_off, input+off, len);-#elif defined(Z_USE_AVX2)+#elif defined(__AVX2__) fast_avx2_base64_encode(output+output_off, input+off, len); #else chromium_base64_encode(output+output_off, input+off, len);@@ -303,9 +303,9 @@ } HsInt hs_base64_decode(char* output, const char* input, HsInt off, HsInt len){-#if defined(Z_USE_AVX512)+#if defined(__AVX512BW__) size_t r = fast_avx512bw_base64_decode(output, input+off, len);-#elif defined(Z_USE_AVX2)+#elif defined(__AVX2__) size_t r = fast_avx2_base64_decode(output, input+off, len); #else size_t r = chromium_base64_decode(output, input+off, len);@@ -352,7 +352,7 @@ // this function should be called with large enough len, otherwise underflow will happen. size_t hs_count_simd(unsigned char *str, size_t len, unsigned char w) {-#if defined(Z_USE_AVX2) +#if defined(__AVX2__) __m256i pat = _mm256_set1_epi8(w); size_t prefix = 0, res = 0; size_t i = 0;@@ -457,7 +457,7 @@ } HsInt hs_count_ba(unsigned char *str, HsInt off, HsInt len, unsigned char w) {-#if defined(__SSE4_2__) || defined(Z_USE_AVX2) || defined(Z_USE_AVX512)+#if defined(__SSE4_2__) || defined(__AVX2__) if (len >= 1024) return (HsInt)hs_count_simd(str+off, len, w); else { #endif@@ -466,7 +466,7 @@ for (res = 0; len-- != 0; ++str) res += *str == w; return res;-#if defined(__SSE4_2__) || defined(Z_USE_AVX2) || defined(Z_USE_AVX512)+#if defined(__SSE4_2__) || defined(__AVX2__) } #endif }
cbits/dtoa.c view
@@ -32,6 +32,7 @@ #include <stdint.h> // uint64_t etc. #include <assert.h> // assert #include <math.h> // ceil+#include <string.h> // memcpy #ifdef _MSC_VER #pragma warning(disable : 4204) // nonstandard extension used : non-constant aggregate initializer@@ -54,8 +55,6 @@ #define MIN_TARGET_EXP -60 #define MASK32 0xFFFFFFFFULL -#define CAST_U64(d) (*(uint64_t*)&d)-#define CAST_U32(d) (*(uint32_t*)&d) #define MIN(x,y) ((x) <= (y) ? (x) : (y)) #define MAX(x,y) ((x) >= (y) ? (x) : (y)) @@ -207,7 +206,8 @@ static diy_fp double2diy_fp(double d) { diy_fp fp;- uint64_t u64 = CAST_U64(d);+ uint64_t u64;+ memcpy(&u64, &d, sizeof(double)); if (!(u64 & D64_EXP_MASK)) { fp.f = u64 & D64_FRACT_MASK; fp.e = 1 - D64_EXP_BIAS;@@ -222,7 +222,8 @@ static diy_fp float2diy_fp(float d) { diy_fp fp;- uint32_t u32 = CAST_U32(d);+ uint32_t u32;+ memcpy(&u32, &d, sizeof(float)); if (!(u32 & D32_EXP_MASK)) { fp.f = (uint64_t)u32 & D32_FRACT_MASK; fp.e = 1 - D32_EXP_BIAS; @@ -315,7 +316,8 @@ diy_fp b_plus = normalize_diy_fp(t); diy_fp b_minus; diy_fp c_mk; // Cached power of ten: 10^-k- uint64_t u64 = CAST_U64(v);+ uint64_t u64;+ memcpy(&u64, &v, sizeof(double)); assert(v > 0 && v <= 1.7976931348623157e308); // Grisu only handles strictly positive finite numbers. if (!(u64 & D64_FRACT_MASK) && (u64 & D64_EXP_MASK) != 0) { b_minus.f = (dfp.f << 2) - 1; b_minus.e = dfp.e - 2;@@ -346,7 +348,8 @@ diy_fp b_plus = normalize_diy_fp(t); diy_fp b_minus; diy_fp c_mk; // Cached power of ten: 10^-k- uint64_t u32 = CAST_U32(v);+ uint64_t u32;+ memcpy(&u32, &v, sizeof(float)); assert(v > 0 && v <= 3.4028235e38); // Grisu only handles strictly positive finite numbers. if (!(u32 & D32_FRACT_MASK) && (u32 & D32_EXP_MASK) != 0) { b_minus.f = (dfp.f << 2) - 1; b_minus.e = dfp.e - 2;
cbits/text.c view
@@ -30,21 +30,21 @@ #include <utf8rewind.h> #include <codepoint.h> -#if defined(Z_USE_AVX512)+#if defined(__AVX512F__) && defined(__AVX512VL__) && defined(__AVX512VBMI__) #include <simdasciicheck_avx512.h> #include <simdutf8check_avx512.h>-#else+#elif defined(__SSSE3__) #include <simdasciicheck.h> #include <simdutf8check.h> #endif HsInt ascii_validate(const char* p, HsInt off, HsInt len){ const char* q = p + off;-#if defined(Z_USE_AVX512)+#if defined(AVX512_IMPLEMENTATION) return (HsInt)validate_ascii_fast_avx512(q, (size_t)len);-#elif defined(Z_USE_AVX2)+#elif defined(__AVX2__) return (HsInt)validate_ascii_fast_avx(q, (size_t)len);-#elif defined(__SSE2__)+#elif defined(__SSSE3__) return (HsInt)validate_ascii_fast(q, (size_t)len); #else return (HsInt)ascii_u64(q, (size_t)len);@@ -53,11 +53,11 @@ // for some reason unknown, on windows we have to supply a seperated version of ascii_validate // otherwise we got segfault if we import the same FFI with different type (Addr# vs ByteArray#) HsInt ascii_validate_addr(const char* p, HsInt len){-#if defined(Z_USE_AVX512)+#if defined(AVX512_IMPLEMENTATION) return (HsInt)validate_ascii_fast_avx512(p, (size_t)len);-#elif defined(Z_USE_AVX2)+#elif defined(__AVX2__) return (HsInt)validate_ascii_fast_avx(p, (size_t)len);-#elif defined(__SSE2__)+#elif defined(__SSSE3__) return (HsInt)validate_ascii_fast(p, (size_t)len); #else return (HsInt)ascii_u64(p, (size_t)len);@@ -66,11 +66,11 @@ HsInt utf8_validate(const char* p, HsInt off, HsInt len){ const char* q = p + off;-#if defined(Z_USE_AVX512)+#if defined(AVX512_IMPLEMENTATION) return (HsInt)validate_utf8_fast_avx512(q, (size_t)len);-#elif defined(Z_USE_AVX2)+#elif defined(__AVX2__) return (HsInt)validate_utf8_fast_avx(q, (size_t)len);-#elif defined(__SSE2__)+#elif defined(__SSSE3__) return (HsInt)validate_utf8_fast(q, (size_t)len); #else return utf8_validate_slow(q, (size_t)len);@@ -79,11 +79,11 @@ // for some reason unknown, on windows we have to supply a seperated version of utf8_validate // otherwise we got segfault if we import the same FFI with different type (Addr# vs ByteArray#) HsInt utf8_validate_addr(const char* p, HsInt len){-#if defined(Z_USE_AVX512)+#if defined(AVX512_IMPLEMENTATION) return (HsInt)validate_utf8_fast_avx512(p, (size_t)len);-#elif defined(Z_USE_AVX2)+#elif defined(__AVX2__) return (HsInt)validate_utf8_fast_avx(p, (size_t)len);-#elif defined(__SSE2__)+#elif defined(__SSSE3__) return (HsInt)validate_utf8_fast(p, (size_t)len); #else return utf8_validate_slow(p, (size_t)len);
+ third_party/fastvalidate-utf-8/include/simdasciicheck_avx512.h view
@@ -0,0 +1,29 @@+#ifndef SIMDASCIICHECK_AXV512_H+#define SIMDASCIICHECK_AXV512_H++#ifdef __AVX512F__+#include <stdbool.h> // c99 bool+#include <stddef.h> // size_t+#include <x86intrin.h>+// The function returns true (1) if all chars passed in src are+// 7-bit values (0x00..0x7F). Otherwise, it returns false (0).+static bool validate_ascii_fast_avx512(const char *src, size_t len) {+ size_t i = 0;+ __m512i has_error = _mm512_setzero_si512();+ if (len >= 64) {+ for (; i <= len - 64; i += 64) {+ __m512i current_bytes = _mm512_loadu_si512((const __m512i *)(src + i));+ has_error = _mm512_or_si512(has_error, current_bytes);+ }+ }+ int reduced = _mm512_reduce_or_epi32(has_error);++ for (; i < len; i++) {+ reduced |= src[i];+ }++ return !(reduced & 0x80808080);+}+#endif++#endif
+ third_party/fastvalidate-utf-8/include/simdutf8check_avx512.h view
@@ -0,0 +1,297 @@+#ifndef SIMDUTF8CHECK_AXV512_H+#define SIMDUTF8CHECK_AXV512_H++#include <stdbool.h>+#include <stddef.h>+#include <stdint.h>+#include <string.h>+#include <x86intrin.h>+/*+ * legal utf-8 byte sequence+ * http://www.unicode.org/versions/Unicode6.0.0/ch03.pdf - page 94+ *+ * Code Points 1st 2s 3s 4s+ * U+0000..U+007F 00..7F+ * U+0080..U+07FF C2..DF 80..BF+ * U+0800..U+0FFF E0 A0..BF 80..BF+ * U+1000..U+CFFF E1..EC 80..BF 80..BF+ * U+D000..U+D7FF ED 80..9F 80..BF+ * U+E000..U+FFFF EE..EF 80..BF 80..BF+ * U+10000..U+3FFFF F0 90..BF 80..BF 80..BF+ * U+40000..U+FFFFF F1..F3 80..BF 80..BF 80..BF+ * U+100000..U+10FFFF F4 80..8F 80..BF 80..BF+ *+ */++#if defined(__AVX512F__) && defined(__AVX512VL__) && defined(__AVX512VBMI__)+#define AVX512_IMPLEMENTATION+#endif++#ifdef AVX512_IMPLEMENTATION++/*****************************/+static inline __m512i avx512_push_last_byte_of_a_to_b(__m512i a, __m512i b) {+ __m512i indexes = _mm512_set_epi64(0x3E3D3C3B3A393837, 0x363534333231302F,+ 0x2E2D2C2B2A292827, 0x262524232221201F,+ 0x1E1D1C1B1A191817, 0x161514131211100F,+ 0x0E0D0C0B0A090807, 0x060504030201007F);+ return _mm512_permutex2var_epi8(b, indexes, a);+}++static inline __m512i avx512_push_last_2bytes_of_a_to_b(__m512i a, __m512i b) {+ __m512i indexes = _mm512_set_epi64(0x3D3C3B3A39383736, 0x3534333231302F2E,+ 0x2D2C2B2A29282726, 0x2524232221201F1E,+ 0x1D1C1B1A19181716, 0x1514131211100F0E,+ 0x0D0C0B0A09080706, 0x0504030201007F7E);+ return _mm512_permutex2var_epi8(b, indexes, a);+}++// all byte values must be no larger than 0xF4+static inline void avx512_checkSmallerThan0xF4(__m512i current_bytes,+ __mmask64 *has_error) {+ *has_error =+ _kor_mask64(*has_error, _mm512_cmpgt_epu8_mask(current_bytes,+ _mm512_set1_epi8(0xF4)));+}++static inline __m512i avx512_continuationLengths(__m512i high_nibbles) {+ return _mm512_shuffle_epi8(+ _mm512_setr4_epi32(0x01010101, 0x01010101, 0x00000000,+ 0x04030202), // see avx2 version for clarity+ high_nibbles);+}++static inline __m512i avx512_carryContinuations(__m512i initial_lengths,+ __m512i previous_carries) {++ __m512i right1 = _mm512_subs_epu8(+ avx512_push_last_byte_of_a_to_b(previous_carries, initial_lengths),+ _mm512_set1_epi8(1));+ __m512i sum = _mm512_add_epi8(initial_lengths, right1);++ __m512i right2 =+ _mm512_subs_epu8(avx512_push_last_2bytes_of_a_to_b(previous_carries, sum),+ _mm512_set1_epi8(2));+ return _mm512_add_epi8(sum, right2);+}++static inline void avx512_checkContinuations(__m512i initial_lengths,+ __m512i carries,+ __mmask64 *has_error) {+ // overlap || underlap+ // carry > length && length > 0 || !(carry > length) && !(length > 0)+ // (carries > length) == (lengths > 0)+ *has_error = _kor_mask64(+ *has_error,+ _kxnor_mask64(+ _mm512_cmpgt_epi8_mask(carries, initial_lengths),+ _mm512_cmpgt_epi8_mask(initial_lengths, _mm512_setzero_si512())));+}++// when 0xED is found, next byte must be no larger than 0x9F+// when 0xF4 is found, next byte must be no larger than 0x8F+// next byte must be continuation, ie sign bit is set, so signed < is ok+static inline void avx512_checkFirstContinuationMax(__m512i current_bytes,+ __m512i off1_current_bytes,+ __mmask64 *has_error) {+ __mmask64 maskED =+ _mm512_cmpeq_epi8_mask(off1_current_bytes, _mm512_set1_epi8(0xED));+ __mmask64 maskF4 =+ _mm512_cmpeq_epi8_mask(off1_current_bytes, _mm512_set1_epi8(0xF4));+ __mmask64 badfollowED = _kand_mask64(+ _mm512_cmpgt_epi8_mask(current_bytes, _mm512_set1_epi8(0x9F)), maskED);+ __mmask64 badfollowF4 = _kand_mask64(+ _mm512_cmpgt_epi8_mask(current_bytes, _mm512_set1_epi8(0x8F)), maskF4);++ *has_error = _kor_mask64(*has_error, _kor_mask64(badfollowED, badfollowF4));+}++// map off1_hibits => error condition+// hibits off1 cur+// C => < C2 && true+// E => < E1 && < A0+// F => < F1 && < 90+// else false && false+static inline void avx512_checkOverlong(__m512i current_bytes,+ __m512i off1_current_bytes,+ __m512i hibits, __m512i previous_hibits,+ __mmask64 *has_error) {+ __m512i off1_hibits =+ avx512_push_last_byte_of_a_to_b(previous_hibits, hibits);+ __m512i initial_mins = _mm512_shuffle_epi8(+ _mm512_setr4_epi32(0x80808080, 0x80808080, 0x80808080,+ 0xF1E180C2), // see avx2 version for clarity+ off1_hibits);++ __mmask64 initial_under =+ _mm512_cmpgt_epi8_mask(initial_mins, off1_current_bytes);++ __m512i second_mins = _mm512_shuffle_epi8(+ _mm512_setr4_epi32(0x80808080, 0x80808080, 0x80808080,+ 0x90A07F7F), // see avx2 version for clarity+ off1_hibits);+ __mmask64 second_under = _mm512_cmpgt_epi8_mask(second_mins, current_bytes);+ *has_error =+ _kor_mask64(*has_error, _kand_mask64(initial_under, second_under));+}++struct avx512_processed_utf_bytes {+ __m512i rawbytes;+ __m512i high_nibbles;+ __m512i carried_continuations;+};++static inline void+avx512_count_nibbles(__m512i bytes, struct avx512_processed_utf_bytes *answer) {+ answer->rawbytes = bytes;+ answer->high_nibbles =+ _mm512_and_si512(_mm512_srli_epi16(bytes, 4), _mm512_set1_epi8(0x0F));+}++// check whether the current bytes are valid UTF-8+// at the end of the function, previous gets updated+static struct avx512_processed_utf_bytes+avx512_checkUTF8Bytes(__m512i current_bytes,+ struct avx512_processed_utf_bytes *previous,+ __mmask64 *has_error) {+ struct avx512_processed_utf_bytes pb;+ avx512_count_nibbles(current_bytes, &pb);++ avx512_checkSmallerThan0xF4(current_bytes, has_error);++ __m512i initial_lengths = avx512_continuationLengths(pb.high_nibbles);++ pb.carried_continuations = avx512_carryContinuations(+ initial_lengths, previous->carried_continuations);++ avx512_checkContinuations(initial_lengths, pb.carried_continuations,+ has_error);++ __m512i off1_current_bytes =+ avx512_push_last_byte_of_a_to_b(previous->rawbytes, pb.rawbytes);+ avx512_checkFirstContinuationMax(current_bytes, off1_current_bytes,+ has_error);++ avx512_checkOverlong(current_bytes, off1_current_bytes, pb.high_nibbles,+ previous->high_nibbles, has_error);+ return pb;+}++// check whether the current bytes are valid UTF-8+// at the end of the function, previous gets updated+static struct avx512_processed_utf_bytes+avx512_checkUTF8Bytes_asciipath(__m512i current_bytes,+ struct avx512_processed_utf_bytes *previous,+ __mmask64 *has_error) {+ if (!_mm512_cmpge_epu8_mask(current_bytes,+ _mm512_set1_epi8(0x80))) { // fast ascii path+ *has_error = _kor_mask64(+ *has_error,+ _mm512_cmpgt_epi8_mask(+ previous->carried_continuations,+ _mm512_setr_epi32(0x09090909, 0x09090909, 0x09090909, 0x09090909,+ 0x09090909, 0x09090909, 0x09090909, 0x09090909,+ 0x09090909, 0x09090909, 0x09090909, 0x09090909,+ 0x09090909, 0x09090909, 0x09090909, 0x01090909)));+ return *previous;+ }++ struct avx512_processed_utf_bytes pb;+ avx512_count_nibbles(current_bytes, &pb);++ avx512_checkSmallerThan0xF4(current_bytes, has_error);++ __m512i initial_lengths = avx512_continuationLengths(pb.high_nibbles);++ pb.carried_continuations = avx512_carryContinuations(+ initial_lengths, previous->carried_continuations);++ avx512_checkContinuations(initial_lengths, pb.carried_continuations,+ has_error);++ __m512i off1_current_bytes =+ avx512_push_last_byte_of_a_to_b(previous->rawbytes, pb.rawbytes);+ avx512_checkFirstContinuationMax(current_bytes, off1_current_bytes,+ has_error);++ avx512_checkOverlong(current_bytes, off1_current_bytes, pb.high_nibbles,+ previous->high_nibbles, has_error);+ return pb;+}++static bool validate_utf8_fast_avx512_asciipath(const char *src, size_t len) {+ size_t i = 0;+ __mmask64 has_error = 0;+ struct avx512_processed_utf_bytes previous = {+ .rawbytes = _mm512_setzero_si512(),+ .high_nibbles = _mm512_setzero_si512(),+ .carried_continuations = _mm512_setzero_si512()+ };+ if (len >= 64) {+ for (; i <= len - 64; i += 64) {+ __m512i current_bytes = _mm512_loadu_si512((const __m512i *)(src + i));+ previous =+ avx512_checkUTF8Bytes_asciipath(current_bytes, &previous, &has_error);+ }+ }++ // last part+ if (i < len) {+ char buffer[64];+ memset(buffer, 0, 64);+ memcpy(buffer, src + i, len - i);+ __m512i current_bytes = _mm512_loadu_si512((const __m512i *)(buffer));+ previous = avx512_checkUTF8Bytes(current_bytes, &previous, &has_error);+ } else {+ has_error = _kor_mask64(+ has_error,+ _mm512_cmpgt_epi8_mask(+ previous.carried_continuations,+ _mm512_setr_epi32(0x09090909, 0x09090909, 0x09090909, 0x09090909,+ 0x09090909, 0x09090909, 0x09090909, 0x09090909,+ 0x09090909, 0x09090909, 0x09090909, 0x09090909,+ 0x09090909, 0x09090909, 0x09090909, 0x01090909)));+ }++ return !has_error;+}++static bool validate_utf8_fast_avx512(const char *src, size_t len) {+ size_t i = 0;+ __mmask64 has_error = 0;+ struct avx512_processed_utf_bytes previous = {+ .rawbytes = _mm512_setzero_si512(),+ .high_nibbles = _mm512_setzero_si512(),+ .carried_continuations = _mm512_setzero_si512()+ };+ if (len >= 64) {+ for (; i <= len - 64; i += 64) {+ __m512i current_bytes = _mm512_loadu_si512((const __m512i *)(src + i));+ previous = avx512_checkUTF8Bytes(current_bytes, &previous, &has_error);+ }+ }++ // last part+ if (i < len) {+ char buffer[64];+ memset(buffer, 0, 64);+ memcpy(buffer, src + i, len - i);+ __m512i current_bytes = _mm512_loadu_si512((const __m512i *)(buffer));+ previous = avx512_checkUTF8Bytes(current_bytes, &previous, &has_error);+ } else {+ has_error = _kor_mask64(+ has_error,+ _mm512_cmpgt_epi8_mask(+ previous.carried_continuations,+ _mm512_setr_epi32(0x09090909, 0x09090909, 0x09090909, 0x09090909,+ 0x09090909, 0x09090909, 0x09090909, 0x09090909,+ 0x09090909, 0x09090909, 0x09090909, 0x09090909,+ 0x09090909, 0x09090909, 0x09090909, 0x01090909)));+ }++ return !has_error;+}++#endif // AVX512_IMPLEMENTATION++#endif // SIMDUTF8CHECK_AXV512_H
third_party/re2/re2/compile.cc view
@@ -79,9 +79,11 @@ struct Frag { uint32_t begin; PatchList end;+ bool nullable; - Frag() : begin(0) { end.head = 0; } // needed so Frag can go in vector- Frag(uint32_t begin, PatchList end) : begin(begin), end(end) {}+ Frag() : begin(0), end(kNullPatchList), nullable(false) {}+ Frag(uint32_t begin, PatchList end, bool nullable)+ : begin(begin), end(end), nullable(nullable) {} }; // Input encodings.@@ -264,7 +266,7 @@ // Returns an unmatchable fragment. Frag Compiler::NoMatch() {- return Frag(0, kNullPatchList);+ return Frag(); } // Is a an unmatchable fragment?@@ -290,11 +292,11 @@ // To run backward over string, reverse all concatenations. if (reversed_) { PatchList::Patch(inst_.data(), b.end, a.begin);- return Frag(b.begin, a.end);+ return Frag(b.begin, a.end, b.nullable && a.nullable); } PatchList::Patch(inst_.data(), a.end, b.begin);- return Frag(a.begin, b.end);+ return Frag(a.begin, b.end, a.nullable && b.nullable); } // Given fragments for a and b, returns fragment for a|b.@@ -310,7 +312,8 @@ return NoMatch(); inst_[id].InitAlt(a.begin, b.begin);- return Frag(id, PatchList::Append(inst_.data(), a.end, b.end));+ return Frag(id, PatchList::Append(inst_.data(), a.end, b.end),+ a.nullable || b.nullable); } // When capturing submatches in like-Perl mode, a kOpAlt Inst@@ -320,27 +323,44 @@ // then the operator is greedy. If out1_ is the repetition // (and out_ moves forward), then the operator is non-greedy. -// Given a fragment a, returns a fragment for a* or a*? (if nongreedy)-Frag Compiler::Star(Frag a, bool nongreedy) {+// Given a fragment for a, returns a fragment for a+ or a+? (if nongreedy)+Frag Compiler::Plus(Frag a, bool nongreedy) { int id = AllocInst(1); if (id < 0) return NoMatch();- inst_[id].InitAlt(0, 0);- PatchList::Patch(inst_.data(), a.end, id);+ PatchList pl; if (nongreedy) {- inst_[id].out1_ = a.begin;- return Frag(id, PatchList::Mk(id << 1));+ inst_[id].InitAlt(0, a.begin);+ pl = PatchList::Mk(id << 1); } else {- inst_[id].set_out(a.begin);- return Frag(id, PatchList::Mk((id << 1) | 1));+ inst_[id].InitAlt(a.begin, 0);+ pl = PatchList::Mk((id << 1) | 1); }+ PatchList::Patch(inst_.data(), a.end, id);+ return Frag(a.begin, pl, a.nullable); } -// Given a fragment for a, returns a fragment for a+ or a+? (if nongreedy)-Frag Compiler::Plus(Frag a, bool nongreedy) {- // a+ is just a* with a different entry point.- Frag f = Star(a, nongreedy);- return Frag(a.begin, f.end);+// Given a fragment for a, returns a fragment for a* or a*? (if nongreedy)+Frag Compiler::Star(Frag a, bool nongreedy) {+ // When the subexpression is nullable, one Alt isn't enough to guarantee+ // correct priority ordering within the transitive closure. The simplest+ // solution is to handle it as (a+)? instead, which adds the second Alt.+ if (a.nullable)+ return Quest(Plus(a, nongreedy), nongreedy);++ int id = AllocInst(1);+ if (id < 0)+ return NoMatch();+ PatchList pl;+ if (nongreedy) {+ inst_[id].InitAlt(0, a.begin);+ pl = PatchList::Mk(id << 1);+ } else {+ inst_[id].InitAlt(a.begin, 0);+ pl = PatchList::Mk((id << 1) | 1);+ }+ PatchList::Patch(inst_.data(), a.end, id);+ return Frag(id, pl, true); } // Given a fragment for a, returns a fragment for a? or a?? (if nongreedy)@@ -358,7 +378,7 @@ inst_[id].InitAlt(a.begin, 0); pl = PatchList::Mk((id << 1) | 1); }- return Frag(id, PatchList::Append(inst_.data(), pl, a.end));+ return Frag(id, PatchList::Append(inst_.data(), pl, a.end), true); } // Returns a fragment for the byte range lo-hi.@@ -367,7 +387,7 @@ if (id < 0) return NoMatch(); inst_[id].InitByteRange(lo, hi, foldcase, 0);- return Frag(id, PatchList::Mk(id << 1));+ return Frag(id, PatchList::Mk(id << 1), false); } // Returns a no-op fragment. Sometimes unavoidable.@@ -376,7 +396,7 @@ if (id < 0) return NoMatch(); inst_[id].InitNop(0);- return Frag(id, PatchList::Mk(id << 1));+ return Frag(id, PatchList::Mk(id << 1), true); } // Returns a fragment that signals a match.@@ -385,7 +405,7 @@ if (id < 0) return NoMatch(); inst_[id].InitMatch(match_id);- return Frag(id, kNullPatchList);+ return Frag(id, kNullPatchList, false); } // Returns a fragment matching a particular empty-width op (like ^ or $)@@ -394,7 +414,7 @@ if (id < 0) return NoMatch(); inst_[id].InitEmptyWidth(empty, 0);- return Frag(id, PatchList::Mk(id << 1));+ return Frag(id, PatchList::Mk(id << 1), true); } // Given a fragment a, returns a fragment with capturing parens around a.@@ -408,7 +428,7 @@ inst_[id+1].InitCapture(2*n+1, 0); PatchList::Patch(inst_.data(), a.end, id+1); - return Frag(id, PatchList::Mk((id+1) << 1));+ return Frag(id, PatchList::Mk((id+1) << 1), a.nullable); } // A Rune is a name for a Unicode code point.@@ -567,7 +587,7 @@ Frag Compiler::FindByteRange(int root, int id) { if (inst_[root].opcode() == kInstByteRange) { if (ByteRangeEqual(root, id))- return Frag(root, kNullPatchList);+ return Frag(root, kNullPatchList, false); else return NoMatch(); }@@ -575,7 +595,7 @@ while (inst_[root].opcode() == kInstAlt) { int out1 = inst_[root].out1(); if (ByteRangeEqual(out1, id))- return Frag(root, PatchList::Mk((root << 1) | 1));+ return Frag(root, PatchList::Mk((root << 1) | 1), false); // CharClass is a sorted list of ranges, so if out1 of the root Alt wasn't // what we're looking for, then we can stop immediately. Unfortunately, we@@ -587,7 +607,7 @@ if (inst_[out].opcode() == kInstAlt) root = out; else if (ByteRangeEqual(out, id))- return Frag(root, PatchList::Mk(root << 1));+ return Frag(root, PatchList::Mk(root << 1), false); else return NoMatch(); }
third_party/re2/re2/dfa.cc view
@@ -167,6 +167,9 @@ typedef std::unordered_set<State*, StateHash, StateEqual> StateSet; private:+ // Make it easier to swap in a scalable reader-writer mutex.+ using CacheMutex = Mutex;+ enum { // Indices into start_ for unanchored searches. // Add kStartAnchored for anchored searches.@@ -331,7 +334,7 @@ // while holding cache_mutex_ for writing, to avoid interrupting other // readers. Any State* pointers are only valid while cache_mutex_ // is held.- Mutex cache_mutex_;+ CacheMutex cache_mutex_; int64_t mem_budget_; // Total memory budget for all States. int64_t state_budget_; // Amount of memory remaining for new States. StateSet state_cache_; // All States computed so far.@@ -1106,7 +1109,7 @@ class DFA::RWLocker { public:- explicit RWLocker(Mutex* mu);+ explicit RWLocker(CacheMutex* mu); ~RWLocker(); // If the lock is only held for reading right now,@@ -1116,14 +1119,14 @@ void LockForWriting(); private:- Mutex* mu_;+ CacheMutex* mu_; bool writing_; RWLocker(const RWLocker&) = delete; RWLocker& operator=(const RWLocker&) = delete; }; -DFA::RWLocker::RWLocker(Mutex* mu) : mu_(mu), writing_(false) {+DFA::RWLocker::RWLocker(CacheMutex* mu) : mu_(mu), writing_(false) { mu_->ReaderLock(); }
third_party/re2/re2/nfa.cc view
@@ -600,7 +600,7 @@ // by simply not continuing the loop. // This complements the special case in NFA::Step(). if (p == NULL) {- (void)Step(runq, nextq, p < etext_ ? p[0] & 0xFF : -1, context, p);+ (void) Step(runq, nextq, -1, context, p); DCHECK_EQ(runq->size(), 0); using std::swap; swap(nextq, runq);
third_party/re2/re2/perl_groups.cc view
@@ -20,12 +20,12 @@ { 0x61, 0x7a }, }; const UGroup perl_groups[] = {- { "\\d", +1, code1, 1 },- { "\\D", -1, code1, 1 },- { "\\s", +1, code2, 3 },- { "\\S", -1, code2, 3 },- { "\\w", +1, code3, 4 },- { "\\W", -1, code3, 4 },+ { "\\d", +1, code1, 1, 0, 0 },+ { "\\D", -1, code1, 1, 0, 0 },+ { "\\s", +1, code2, 3, 0, 0 },+ { "\\S", -1, code2, 3, 0, 0 },+ { "\\w", +1, code3, 4, 0, 0 },+ { "\\W", -1, code3, 4, 0, 0 }, }; const int num_perl_groups = 6; static const URange16 code4[] = { /* [:alnum:] */@@ -85,34 +85,34 @@ { 0x61, 0x66 }, }; const UGroup posix_groups[] = {- { "[:alnum:]", +1, code4, 3 },- { "[:^alnum:]", -1, code4, 3 },- { "[:alpha:]", +1, code5, 2 },- { "[:^alpha:]", -1, code5, 2 },- { "[:ascii:]", +1, code6, 1 },- { "[:^ascii:]", -1, code6, 1 },- { "[:blank:]", +1, code7, 2 },- { "[:^blank:]", -1, code7, 2 },- { "[:cntrl:]", +1, code8, 2 },- { "[:^cntrl:]", -1, code8, 2 },- { "[:digit:]", +1, code9, 1 },- { "[:^digit:]", -1, code9, 1 },- { "[:graph:]", +1, code10, 1 },- { "[:^graph:]", -1, code10, 1 },- { "[:lower:]", +1, code11, 1 },- { "[:^lower:]", -1, code11, 1 },- { "[:print:]", +1, code12, 1 },- { "[:^print:]", -1, code12, 1 },- { "[:punct:]", +1, code13, 4 },- { "[:^punct:]", -1, code13, 4 },- { "[:space:]", +1, code14, 2 },- { "[:^space:]", -1, code14, 2 },- { "[:upper:]", +1, code15, 1 },- { "[:^upper:]", -1, code15, 1 },- { "[:word:]", +1, code16, 4 },- { "[:^word:]", -1, code16, 4 },- { "[:xdigit:]", +1, code17, 3 },- { "[:^xdigit:]", -1, code17, 3 },+ { "[:alnum:]", +1, code4, 3, 0, 0 },+ { "[:^alnum:]", -1, code4, 3, 0, 0 },+ { "[:alpha:]", +1, code5, 2, 0, 0 },+ { "[:^alpha:]", -1, code5, 2, 0, 0 },+ { "[:ascii:]", +1, code6, 1, 0, 0 },+ { "[:^ascii:]", -1, code6, 1, 0, 0 },+ { "[:blank:]", +1, code7, 2, 0, 0 },+ { "[:^blank:]", -1, code7, 2, 0, 0 },+ { "[:cntrl:]", +1, code8, 2, 0, 0 },+ { "[:^cntrl:]", -1, code8, 2, 0, 0 },+ { "[:digit:]", +1, code9, 1, 0, 0 },+ { "[:^digit:]", -1, code9, 1, 0, 0 },+ { "[:graph:]", +1, code10, 1, 0, 0 },+ { "[:^graph:]", -1, code10, 1, 0, 0 },+ { "[:lower:]", +1, code11, 1, 0, 0 },+ { "[:^lower:]", -1, code11, 1, 0, 0 },+ { "[:print:]", +1, code12, 1, 0, 0 },+ { "[:^print:]", -1, code12, 1, 0, 0 },+ { "[:punct:]", +1, code13, 4, 0, 0 },+ { "[:^punct:]", -1, code13, 4, 0, 0 },+ { "[:space:]", +1, code14, 2, 0, 0 },+ { "[:^space:]", -1, code14, 2, 0, 0 },+ { "[:upper:]", +1, code15, 1, 0, 0 },+ { "[:^upper:]", -1, code15, 1, 0, 0 },+ { "[:word:]", +1, code16, 4, 0, 0 },+ { "[:^word:]", -1, code16, 4, 0, 0 },+ { "[:xdigit:]", +1, code17, 3, 0, 0 },+ { "[:^xdigit:]", -1, code17, 3, 0, 0 }, }; const int num_posix_groups = 28;
third_party/re2/re2/re2.h view
@@ -830,8 +830,9 @@ #if !defined(_MSC_VER) template <typename T> using CanParseFrom = typename std::enable_if<- std::is_member_function_pointer<decltype(- (bool (T::*)(const char*, size_t))&T::ParseFrom)>::value,+ std::is_member_function_pointer<+ decltype(static_cast<bool (T::*)(const char*, size_t)>(+ &T::ParseFrom))>::value, int>::type; #endif
third_party/re2/re2/regexp.cc view
@@ -722,8 +722,14 @@ *foldcase = false; // No need for a walker: the regexp must either begin with or be- // a literal char or string.+ // a literal char or string. We "see through" capturing groups,+ // but make no effort to glue multiple prefix fragments together. Regexp* re = op_ == kRegexpConcat && nsub_ > 0 ? sub()[0] : this;+ while (re->op_ == kRegexpCapture) {+ re = re->sub()[0];+ if (re->op_ == kRegexpConcat && re->nsub_ > 0)+ re = re->sub()[0];+ } if (re->op_ != kRegexpLiteral && re->op_ != kRegexpLiteralString) return false;@@ -913,7 +919,7 @@ // The ranges are allocated in the same block as the header, // necessitating a special allocator and Delete method. -CharClass* CharClass::New(int maxranges) {+CharClass* CharClass::New(size_t maxranges) { CharClass* cc; uint8_t* data = new uint8_t[sizeof *cc + maxranges*sizeof cc->ranges_[0]]; cc = reinterpret_cast<CharClass*>(data);@@ -930,7 +936,7 @@ } CharClass* CharClass::Negate() {- CharClass* cc = CharClass::New(nranges_+1);+ CharClass* cc = CharClass::New(static_cast<size_t>(nranges_+1)); cc->folds_ascii_ = folds_ascii_; cc->nrunes_ = Runemax + 1 - nrunes_; int n = 0;@@ -967,7 +973,7 @@ } CharClass* CharClassBuilder::GetCharClass() {- CharClass* cc = CharClass::New(static_cast<int>(ranges_.size()));+ CharClass* cc = CharClass::New(ranges_.size()); int n = 0; for (iterator it = begin(); it != end(); ++it) cc->ranges_[n++] = *it;
third_party/re2/re2/regexp.h view
@@ -86,6 +86,7 @@ // form accessible to clients, so that client code can analyze the // parsed regular expressions. +#include <stddef.h> #include <stdint.h> #include <map> #include <set>@@ -259,7 +260,7 @@ private: CharClass(); // not implemented ~CharClass(); // not implemented- static CharClass* New(int maxranges);+ static CharClass* New(size_t maxranges); friend class CharClassBuilder;
third_party/re2/re2/set.cc view
@@ -133,6 +133,9 @@ error_info->kind = kNotCompiled; return false; }+#ifdef RE2_HAVE_THREAD_LOCAL+ hooks::context = NULL;+#endif bool dfa_failed = false; std::unique_ptr<SparseSet> matches; if (v != NULL) {
third_party/re2/re2/tostring.cc view
@@ -291,7 +291,7 @@ // There's no syntax accepted by the parser to generate // this node (it is generated by RE2::Set) so make something // up that is readable but won't compile.- t_->append("(?HaveMatch:%d)", re->match_id());+ t_->append(StringPrintf("(?HaveMatch:%d)", re->match_id())); break; }
third_party/re2/util/mutex.h view
@@ -12,6 +12,7 @@ #ifdef _WIN32 // Requires Windows Vista or Windows Server 2008 at minimum.+#include <windows.h> #if defined(WINVER) && WINVER >= 0x0600 #define MUTEX_IS_WIN32_SRWLOCK #endif@@ -26,7 +27,6 @@ #endif #if defined(MUTEX_IS_WIN32_SRWLOCK)-#include <windows.h> typedef SRWLOCK MutexType; #elif defined(MUTEX_IS_PTHREAD_RWLOCK) #include <pthread.h>
third_party/utf8rewind/include/utf8rewind/utf8rewind.h view
@@ -62,6 +62,7 @@ Custom type definitions used throughout the library. */ +#include <ctype.h> #include <locale.h> #include <stddef.h> #include <stdio.h>
third_party/utf8rewind/source/utf8rewind.c view
@@ -549,6 +549,22 @@ } } +// internal helper to avoid the use of non-standard strncasecmp +int __strncasecmp(const char* s1, const char* s2, size_t n) { + if (n == 0) + return 0; + + do { + if (tolower((unsigned char) *s1) != tolower((unsigned char) *s2++)) + return (int)tolower((unsigned char)*s1) - + (int) tolower((unsigned char) *--s2); + if (*s1++ == 0) + break; + } while (--n != 0); + + return 0; +} + UTF8_API size_t utf8envlocale() { /* @@ -562,7 +578,7 @@ */ #define UTF8_LOCALE_CHECK(_name) \ - !strncasecmp(locale, _name, 5) + !__strncasecmp(locale, _name, 5) #if WIN32 || _WINDOWS WCHAR localeW[LOCALE_NAME_MAX_LENGTH]; @@ -1376,4 +1392,4 @@ } return src - input; -}+}