packages feed

hw-balancedparens 0.3.1.0 → 0.4.0.0

raw patch · 24 files changed

+641/−87 lines, 24 filesdep +bytestringdep +generic-lensdep +lensnew-component:exe:hw-balancedparensPVP ok

version bump matches the API change (PVP)

Dependencies added: bytestring, generic-lens, lens, mmap, optparse-applicative

API changes (from Hackage documentation)

- HaskellWorks.Data.BalancedParens.Broadword.Word16: findCloseFar :: Word16 -> Word16 -> Word16
- HaskellWorks.Data.BalancedParens.Broadword.Word32: findCloseFar :: Word32 -> Word32 -> Word32
- HaskellWorks.Data.BalancedParens.Broadword.Word64: findClose :: Word64 -> Word64
- HaskellWorks.Data.BalancedParens.Broadword.Word64: findCloseFar :: Word64 -> Word64 -> Word64
- HaskellWorks.Data.BalancedParens.Broadword.Word8: findCloseFar :: Word8 -> Word8 -> Word8
- HaskellWorks.Data.BalancedParens.Internal.Slow.Word16: findCloseFar :: Word16 -> Word16 -> Word16
- HaskellWorks.Data.BalancedParens.Internal.Slow.Word32: findCloseFar :: Word32 -> Word32 -> Word32
- HaskellWorks.Data.BalancedParens.Internal.Slow.Word64: findCloseFar :: Word64 -> Word64 -> Word64
- HaskellWorks.Data.BalancedParens.Internal.Slow.Word8: findCloseFar :: Word8 -> Word8 -> Word8
+ HaskellWorks.Data.BalancedParens.Broadword.Word16: findUnmatchedCloseFar :: Word16 -> Word16 -> Word16
+ HaskellWorks.Data.BalancedParens.Broadword.Word32: findUnmatchedCloseFar :: Word32 -> Word32 -> Word32
+ HaskellWorks.Data.BalancedParens.Broadword.Word64: findUnmatchedCloseFar :: Word64 -> Word64 -> Word64
+ HaskellWorks.Data.BalancedParens.Broadword.Word8: findUnmatchedCloseFar :: Word8 -> Word8 -> Word8
+ HaskellWorks.Data.BalancedParens.Internal.Broadword.Word64: findUnmatchedClose :: Word64 -> Word64
+ HaskellWorks.Data.BalancedParens.Internal.Slow.Word16: findUnmatchedCloseFar :: Word16 -> Word16 -> Word16
+ HaskellWorks.Data.BalancedParens.Internal.Slow.Word32: findUnmatchedCloseFar :: Word32 -> Word32 -> Word32
+ HaskellWorks.Data.BalancedParens.Internal.Slow.Word64: findUnmatchedCloseFar :: Word64 -> Word64 -> Word64
+ HaskellWorks.Data.BalancedParens.Internal.Slow.Word8: findUnmatchedCloseFar :: Word8 -> Word8 -> Word8

Files

README.md view
@@ -1,3 +1,9 @@ # hw-balancedparens  [![CircleCI](https://circleci.com/gh/haskell-works/hw-balancedparens.svg?style=svg)](https://circleci.com/gh/haskell-works/hw-balancedparens)++# Resources++* [Broadword Implementation of Parenthesis Queries][1], Sebastiano Vigna, 2013++[1]: https://arxiv.org/pdf/1301.5468.pdf
+ app/App/Commands.hs view
@@ -0,0 +1,12 @@+module App.Commands where++import App.Commands.BitsToParens+import App.Commands.ParensToBits+import App.Commands.Positions+import Options.Applicative++cmdOpts :: Parser (IO ())+cmdOpts = subparser $ mempty+  <>  cmdParensToBits+  <>  cmdBitsToParens+  <>  cmdPositions
+ app/App/Commands/BitsToParens.hs view
@@ -0,0 +1,72 @@+{-# LANGUAGE DataKinds           #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeApplications    #-}++module App.Commands.BitsToParens+  ( cmdBitsToParens+  ) where++import Control.Lens+import Data.Generics.Product.Any+import Data.Word+import HaskellWorks.Data.Bits.BitWise+import Options.Applicative            hiding (columns)++import qualified App.Commands.Options.Type as Z+import qualified App.IO                    as IO+import qualified Data.ByteString.Builder   as B+import qualified Data.ByteString.Lazy      as LBS++{-# ANN module ("HLint: ignore Redundant do"      :: String) #-}+{-# ANN module ("HLint: ignore Redundant return"  :: String) #-}++bitString :: Word8 -> B.Builder+bitString w =+  go ((w .>. 0) .&. 1) <>+  go ((w .>. 1) .&. 1) <>+  go ((w .>. 2) .&. 1) <>+  go ((w .>. 3) .&. 1) <>+  go ((w .>. 4) .&. 1) <>+  go ((w .>. 5) .&. 1) <>+  go ((w .>. 6) .&. 1) <>+  go ((w .>. 7) .&. 1)+  where go :: Word8 -> B.Builder+        go 1 = B.word8 40+        go _ = B.word8 41++parensBuilder :: LBS.ByteString -> B.Builder+parensBuilder lbs = case LBS.uncons lbs of+  Just (w, rs) -> bitString w <> parensBuilder rs+  Nothing      -> mempty++parens :: LBS.ByteString -> LBS.ByteString+parens = B.toLazyByteString . parensBuilder++runBitsToParens :: Z.BitsToParensOptions -> IO ()+runBitsToParens opts = do+  let inputFile   = opts ^. the @"inputFile"+  let outputFile  = opts ^. the @"outputFile"++  lbs <- IO.readInputFile inputFile++  IO.writeOutputFile outputFile $ parens lbs++  return ()++optsBitsToParens :: Parser Z.BitsToParensOptions+optsBitsToParens = Z.BitsToParensOptions+  <$> strOption+      (   long "input"+      <>  help "Input file"+      <>  metavar "FILE"+      <>  value "-"+      )+  <*> strOption+      (   long "output"+      <>  help "Output file"+      <>  metavar "FILE"+      <>  value "-"+      )++cmdBitsToParens :: Mod CommandFields (IO ())+cmdBitsToParens = command "bits-to-parens"  $ flip info idm $ runBitsToParens <$> optsBitsToParens
+ app/App/Commands/Options/Type.hs view
@@ -0,0 +1,20 @@+{-# LANGUAGE DeriveGeneric         #-}+{-# LANGUAGE DuplicateRecordFields #-}++module App.Commands.Options.Type where++import GHC.Generics++newtype PositionsOptions = PositionsOptions+  { inputFile :: FilePath+  } deriving (Eq, Show, Generic)++data BitsToParensOptions = BitsToParensOptions+  { inputFile  :: FilePath+  , outputFile :: FilePath+  } deriving (Eq, Show, Generic)++data ParensToBitsOptions = ParensToBitsOptions+  { inputFile  :: FilePath+  , outputFile :: FilePath+  } deriving (Eq, Show, Generic)
+ app/App/Commands/ParensToBits.hs view
@@ -0,0 +1,65 @@+{-# LANGUAGE DataKinds           #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TupleSections       #-}+{-# LANGUAGE TypeApplications    #-}++module App.Commands.ParensToBits+  ( cmdParensToBits+  ) where++import Control.Lens+import Data.Generics.Product.Any+import Data.Word+import HaskellWorks.Data.Bits.BitWise+import HaskellWorks.Data.Positioning+import Options.Applicative            hiding (columns)++import qualified App.Commands.Options.Type as Z+import qualified App.IO                    as IO+import qualified Data.ByteString.Lazy      as LBS++{-# ANN module ("HLint: ignore Redundant do"      :: String) #-}+{-# ANN module ("HLint: ignore Redundant return"  :: String) #-}++unparens :: LBS.ByteString -> LBS.ByteString+unparens = LBS.unfoldr go . (0, 0, )+  where go :: (Word8, Count, LBS.ByteString) -> Maybe (Word8, (Word8, Count, LBS.ByteString))+        go (w, c, lbs) = case LBS.uncons lbs of+          Nothing -> if c > 0+            then Just (w, (0, 0, LBS.empty))+            else Nothing+          Just (a, as) -> case a of+            40 -> if c < 8+              then go (w .|. (1 .<. c), c + 1, as)+              else Just (w, (1, 1, as))+            41 -> if c < 8+              then go (w, c + 1, as)+              else Just (w, (0, 1, as))+            _ -> go (w, c, as)++runParensToBits :: Z.ParensToBitsOptions -> IO ()+runParensToBits opts = do+  let inputFile   = opts ^. the @"inputFile"+  let outputFile  = opts ^. the @"outputFile"++  lbs <- IO.readInputFile inputFile++  IO.writeOutputFile outputFile (unparens lbs)++optsParensToBits :: Parser Z.ParensToBitsOptions+optsParensToBits = Z.ParensToBitsOptions+  <$> strOption+      (   long "input"+      <>  help "Input file"+      <>  metavar "FILE"+      <>  value "-"+      )+  <*> strOption+      (   long "output"+      <>  help "Output file"+      <>  metavar "FILE"+      <>  value "-"+      )++cmdParensToBits :: Mod CommandFields (IO ())+cmdParensToBits = command "parens-to-bits"  $ flip info idm $ runParensToBits <$> optsParensToBits
+ app/App/Commands/Positions.hs view
@@ -0,0 +1,55 @@+{-# LANGUAGE DataKinds           #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeApplications    #-}++module App.Commands.Positions+  ( cmdPositions+  ) where++import Control.Lens+import Control.Monad+import Data.Generics.Product.Any+import Data.Word+import HaskellWorks.Data.BalancedParens.FindClose+import HaskellWorks.Data.BalancedParens.OpenAt+import HaskellWorks.Data.Positioning+import Options.Applicative                        hiding (columns)++import qualified App.Commands.Options.Type           as Z+import qualified Data.Vector.Storable                as DVS+import qualified HaskellWorks.Data.FromForeignRegion as IO+import qualified System.IO                           as IO++{-# ANN module ("HLint: ignore Redundant do"      :: String) #-}+{-# ANN module ("HLint: ignore Redundant return"  :: String) #-}++openCloses :: (FindClose v, OpenAt v) => v -> [(Count, Count)]+openCloses v = go 1 v []+  where go :: (FindClose v, OpenAt v) => Count -> v -> [(Count, Count)] -> [(Count, Count)]+        go p w = if openAt w p+          then case findClose w p of+            Just q  -> ((p, q):) . go (p + 1) w . go (q + 1) w+            Nothing -> id+          else id++runPositions :: Z.PositionsOptions -> IO ()+runPositions opts = do+  let inputFile   = opts ^. the @"inputFile"++  v :: DVS.Vector Word64 <- IO.mmapFromForeignRegion inputFile++  forM_ (openCloses v) $ \(o, c) -> do+    IO.putStrLn $ show o <> "," <> show c++  return ()++optsPositions :: Parser Z.PositionsOptions+optsPositions = Z.PositionsOptions+  <$> strOption+      (   long "input"+      <>  help "Input file"+      <>  metavar "FILE"+      )++cmdPositions :: Mod CommandFields (IO ())+cmdPositions = command "positions"  $ flip info idm $ runPositions <$> optsPositions
+ app/App/IO.hs view
@@ -0,0 +1,12 @@+module App.IO where++import qualified Data.ByteString.Lazy as LBS+import qualified System.IO            as IO++readInputFile :: FilePath -> IO LBS.ByteString+readInputFile "-"      = LBS.hGetContents IO.stdin+readInputFile filePath = LBS.readFile filePath++writeOutputFile :: FilePath -> LBS.ByteString -> IO ()+writeOutputFile "-"      bs = LBS.hPut IO.stdout bs+writeOutputFile filePath bs = LBS.writeFile filePath bs
+ app/Main.hs view
@@ -0,0 +1,10 @@+module Main where++import App.Commands+import Control.Monad+import Options.Applicative++main :: IO ()+main = join $ customExecParser+  (prefs $ showHelpOnEmpty <> showHelpOnError)+  (info (cmdOpts <**> helper) idm)
bench/Main.hs view
@@ -54,8 +54,8 @@   where mkBenchWord64Group :: Word64 -> [Benchmark]         mkBenchWord64Group p = let q = (1 .<. p) - 1 in           [ bgroup "Word64"-            [ bench ("Broadword find close " <> bitShow q) (whnf (BW64.findCloseFar 0) q)-            , bench ("Naive     find close " <> bitShow q) (whnf (SW64.findCloseFar 0) q)+            [ bench ("Broadword find close " <> bitShow q) (whnf (BW64.findUnmatchedCloseFar 0) q)+            , bench ("Naive     find close " <> bitShow q) (whnf (SW64.findUnmatchedCloseFar 0) q)             ]           ] 
hw-balancedparens.cabal view
@@ -1,7 +1,7 @@ cabal-version: 2.2  name:                   hw-balancedparens-version:                0.3.1.0+version:                0.4.0.0 synopsis:               Balanced parentheses description:            Balanced parentheses. category:               Data, Bit, Succinct Data Structures, Data Structures@@ -22,10 +22,12 @@  common base                       { build-depends: base                       >= 4.11       && < 5      } +common bytestring                 { build-depends: bytestring                 >= 0.9        && < 0.11   } common criterion                  { build-depends: criterion                  >= 1.2        && < 1.6    } common deepseq                    { build-depends: deepseq                    >= 1.4.2.0    && < 1.5    } common doctest                    { build-depends: doctest                    >= 0.16.2     && < 0.17   } common doctest-discover           { build-depends: doctest-discover           >= 0.2        && < 0.3    }+common generic-lens               { build-depends: generic-lens               >= 1.2.0.0    && < 1.3    } common hedgehog                   { build-depends: hedgehog                   >= 1.0        && < 1.1    } common hspec                      { build-depends: hspec                      >= 2.2        && < 3.0    } common hw-hspec-hedgehog          { build-depends: hw-hspec-hedgehog          >= 0.1        && < 0.2    }@@ -34,6 +36,9 @@ common hw-fingertree              { build-depends: hw-fingertree              >= 0.1.1.0    && < 0.2    } common hw-prim                    { build-depends: hw-prim                    >= 0.6.2.25   && < 0.7    } common hw-rankselect-base         { build-depends: hw-rankselect-base         >= 0.3.2.1    && < 0.4    }+common lens                       { build-depends: lens                       >= 4          && < 5      }+common mmap                       { build-depends: mmap                       >= 0.5.9      && < 0.6    }+common optparse-applicative       { build-depends: optparse-applicative       >= 0.14       && < 0.16   } common transformers               { build-depends: transformers               >= 0.5.2      && < 0.6    } common vector                     { build-depends: vector                     >= 0.12       && < 0.13   } @@ -68,6 +73,7 @@                         HaskellWorks.Data.BalancedParens.FindCloseN                         HaskellWorks.Data.BalancedParens.FindOpen                         HaskellWorks.Data.BalancedParens.FindOpenN+                        HaskellWorks.Data.BalancedParens.Internal.Broadword.Word64                         HaskellWorks.Data.BalancedParens.Internal.List                         HaskellWorks.Data.BalancedParens.Internal.ParensSeq                         HaskellWorks.Data.BalancedParens.Internal.RoseTree@@ -106,6 +112,28 @@   exposed-modules:      HaskellWorks.Data.BalancedParens.Gen   hs-source-dirs:       gen +executable hw-balancedparens+  import:               base, config+                      , bytestring+                      , generic-lens+                      , hw-balancedparens+                      , hw-bits+                      , hw-prim+                      , lens+                      , mmap+                      , optparse-applicative+                      , vector+  main-is:              Main.hs+  hs-source-dirs:       app+  ghc-options:          -threaded -rtsopts -with-rtsopts=-N+  other-modules:        App.Commands+                        App.Commands.BitsToParens+                        App.Commands.Options.Type+                        App.Commands.ParensToBits+                        App.Commands.Positions+                        App.IO+                        Paths_hw_balancedparens+ test-suite hw-balancedparens-test   import:               base, config                       , hedgehog@@ -154,7 +182,7 @@                       , hw-balancedparens   default-language:     Haskell2010   type:                 exitcode-stdio-1.0-  ghc-options:          -threaded+  ghc-options:          -threaded -rtsopts -with-rtsopts=-N   main-is:              DoctestDriver.hs   HS-Source-Dirs:       doctest   build-tool-depends:   doctest-discover:doctest-discover
src/HaskellWorks/Data/BalancedParens/Broadword/Word16.hs view
@@ -4,7 +4,7 @@ {-# LANGUAGE ScopedTypeVariables #-}  module HaskellWorks.Data.BalancedParens.Broadword.Word16-  ( findCloseFar+  ( findUnmatchedCloseFar   ) where  import Data.Int@@ -24,8 +24,13 @@ muk3 = 0x00ff {-# INLINE muk3 #-} -findCloseFar :: Word16 -> Word16 -> Word16-findCloseFar p w =+-- | Find the position of the first unmatch parenthesis.+--+-- This is the broadword implementation of 'HaskellWorks.Data.BalancedParens.Internal.Slow.Word16.findCloseFor'.+--+-- See [Broadword Implementation of Parenthesis Queries](https://arxiv.org/pdf/1301.5468.pdf), Sebastiano Vigna, 2013+findUnmatchedCloseFar :: Word16 -> Word16 -> Word16+findUnmatchedCloseFar p w =   let x     = w .>. fromIntegral p                                                        in   let wsz   = 16 :: Int16                                                                 in   let k1    = 1                                                                           in@@ -117,4 +122,4 @@   let rrr   = sbk1 + pck1 + (((x .>. fromIntegral sbk1) .&. ((pck1 .<. 1) .|. 1)) .<. 1)  in    rrr + p-{-# INLINE findCloseFar #-}+{-# INLINE findUnmatchedCloseFar #-}
src/HaskellWorks/Data/BalancedParens/Broadword/Word32.hs view
@@ -4,7 +4,7 @@ {-# LANGUAGE ScopedTypeVariables #-}  module HaskellWorks.Data.BalancedParens.Broadword.Word32-  ( findCloseFar+  ( findUnmatchedCloseFar   ) where  import Data.Int@@ -28,8 +28,13 @@ muk4 = 0x0000ffff {-# INLINE muk4 #-} -findCloseFar :: Word32 -> Word32 -> Word32-findCloseFar p w =+-- | Find the position of the first unmatch parenthesis.+--+-- This is the broadword implementation of 'HaskellWorks.Data.BalancedParens.Internal.Slow.Word32.findCloseFor'.+--+-- See [Broadword Implementation of Parenthesis Queries](https://arxiv.org/pdf/1301.5468.pdf), Sebastiano Vigna, 2013+findUnmatchedCloseFar :: Word32 -> Word32 -> Word32+findUnmatchedCloseFar p w =   let x     = w .>. fromIntegral p                                                        in   let wsz   = 32 :: Int32                                                                 in   let k1    = 1                                                                           in@@ -143,4 +148,4 @@   let rrr   = sbk1 + pck1 + (((x .>. fromIntegral sbk1) .&. ((pck1 .<. 1) .|. 1)) .<. 1)  in    rrr + p-{-# INLINE findCloseFar #-}+{-# INLINE findUnmatchedCloseFar #-}
src/HaskellWorks/Data/BalancedParens/Broadword/Word64.hs view
@@ -1,19 +1,16 @@-{-# LANGUAGE BangPatterns        #-} {-# LANGUAGE FlexibleContexts    #-} {-# LANGUAGE FlexibleInstances   #-} {-# LANGUAGE InstanceSigs        #-} {-# LANGUAGE ScopedTypeVariables #-}  module HaskellWorks.Data.BalancedParens.Broadword.Word64-  ( findClose-  , findCloseFar+  ( findUnmatchedCloseFar   ) where  import Data.Int import Data.Word import HaskellWorks.Data.Bits.BitWise import HaskellWorks.Data.Bits.Broadword.Word64-import HaskellWorks.Data.Bits.Word64  muk1 :: Word64 muk1 = 0x3333333333333333@@ -35,8 +32,13 @@ muk5 = 0x00000000ffffffff {-# INLINE muk5 #-} -findCloseFar :: Word64 -> Word64 -> Word64-findCloseFar p w =+-- | Find the position of the first unmatch parenthesis.+--+-- This is the broadword implementation of 'HaskellWorks.Data.BalancedParens.Internal.Slow.Word64.findCloseFor'.+--+-- See [Broadword Implementation of Parenthesis Queries](https://arxiv.org/pdf/1301.5468.pdf), Sebastiano Vigna, 2013+findUnmatchedCloseFar :: Word64 -> Word64 -> Word64+findUnmatchedCloseFar p w =   let x     = w .>. p                                                                     in   let wsz   = 64 :: Int64                                                                 in   let k1    = 1                                                                           in@@ -172,39 +174,4 @@   let rrr   = sbk1 + pck1 + (((x .>. fromIntegral sbk1) .&. ((pck1 .<. 1) .|. 1)) .<. 1)  in    rrr + p-{-# INLINE findCloseFar #-}---- Source:---    Broadword Implementation of Parenthesis Queries---    Sebastiano Vigna---    Dipartimento di Scienze dell’Informazione---    Università degli Studi di Milano, Italy-findClose :: Word64 -> Word64-findClose x =-  let !b00 = x - ((x .&. 0xaaaaaaaaaaaaaaaa) .>. 1)                                               in-  let !b01 = (b00 .&. 0x3333333333333333) + ((b00 .>. 2) .&. 0x3333333333333333)                  in-  let !b02 = (b01 + (b01 .>. 4)) .&. 0x0f0f0f0f0f0f0f0f                                           in-  let !b03 = (b02 * 0x0101010101010101) .<. 1                                                     in-  let !b04 = kBitDiffUnsafe 8 (h 8 .|. 0x4038302820181008) b03                                    in-  let !u00 = (((((b04 .|. h 8) - l 8) .>. 7) .&. l 8) .|. h 8) - l 8                              in-  let !z00 =                         ((h 8 .>. 1) .|. (l 8 * 7)) .&. u00                          in--  let !d10 = (l 8 * 2 - (((x .>. 6) .&. (l 8 .<. 1)) + ((x .>. 5) .&. (l 8 .<. 1))))              in-  let !b10 = b04 - d10                                                                            in-  let !u10 = (((((b10 .|. h 8) - l 8) .>. 7) .&. l 8) .|. h 8) - l 8                              in-  let !z10 = (z00 .&. comp u10) .|. (((h 8 .>. 1) .|. (l 8 * 5)) .&. u10)                         in--  let !d20 = (l 8 * 2 - (((x .>. 4) .&. (l 8 .<. 1)) + ((x .>. 3) .&. (l 8 .<. 1))))              in-  let !b20 = b10 - d20                                                                            in-  let !u20 = (((((b20 .|. h 8) - l 8) .>. 7) .&. l 8) .|. h 8) - l 8                              in-  let !z20 = (z10 .&. comp u20) .|. (((h 8 .>. 1) .|. (l 8 * 3)) .&. u20)                         in--  let !d30 = (l 8 * 2 - (((x .>. 2) .&. (l 8 .<. 1)) + ((x .>. 1) .&. (l 8 .<. 1))))              in-  let !b30 = b20 - d30                                                                            in-  let !u30 = (((((b30 .|. h 8) - l 8) .>. 7) .&. l 8) .|. h 8) - l 8                              in-  let !z30 = (z20 .&. comp u30) .|. (((h 8 .>. 1) .|.  l 8     ) .&. u30)                         in--  let !p00 = lsb (z30 .>. 6 .&. l 8)                                                              in-  let !r00 = ((p00 + ((z30 .>. fromIntegral (p00 .&. 0x3f)) .&. 0x3f)) .|. (p00 .>. 8)) .&. 0x7f  in-  r00-{-# INLINE findClose #-}+{-# INLINE findUnmatchedCloseFar #-}
src/HaskellWorks/Data/BalancedParens/Broadword/Word8.hs view
@@ -4,7 +4,7 @@ {-# LANGUAGE ScopedTypeVariables #-}  module HaskellWorks.Data.BalancedParens.Broadword.Word8-  ( findCloseFar+  ( findUnmatchedCloseFar   ) where  import Data.Int@@ -20,8 +20,13 @@ muk2 = 0x0f {-# INLINE muk2 #-} -findCloseFar :: Word8 -> Word8 -> Word8-findCloseFar p w =+-- | Find the position of the first unmatch parenthesis.+--+-- This is the broadword implementation of 'HaskellWorks.Data.BalancedParens.Internal.Slow.Word8.findCloseFor'.+--+-- See [Broadword Implementation of Parenthesis Queries](https://arxiv.org/pdf/1301.5468.pdf), Sebastiano Vigna, 2013+findUnmatchedCloseFar :: Word8 -> Word8 -> Word8+findUnmatchedCloseFar p w =   let x     = w .>. fromIntegral p                                                        in   let wsz   = 8 :: Int8                                                                   in   let k1    = 1                                                                           in@@ -91,4 +96,4 @@   let rrr   = sbk1 + pck1 + (((x .>. fromIntegral sbk1) .&. ((pck1 .<. 1) .|. 1)) .<. 1)  in    rrr + p-{-# INLINE findCloseFar #-}+{-# INLINE findUnmatchedCloseFar #-}
src/HaskellWorks/Data/BalancedParens/FindClose.hs view
@@ -13,8 +13,8 @@ import HaskellWorks.Data.Naive import HaskellWorks.Data.Positioning -import qualified Data.Vector.Storable                              as DVS-import qualified HaskellWorks.Data.BalancedParens.Broadword.Word64 as W64+import qualified Data.Vector.Storable                                       as DVS+import qualified HaskellWorks.Data.BalancedParens.Internal.Broadword.Word64 as W64  class FindClose v where   findClose   :: v -> Count -> Maybe Count@@ -65,7 +65,7 @@  instance FindClose (Broadword Word64) where   findClose (Broadword w) p = let x = w .>. (p - 1) in-    case negate (x .&. 1) .&. W64.findClose x of+    case negate (x .&. 1) .&. W64.findUnmatchedClose x of       127 -> Nothing       r   -> let r' = fromIntegral r + p in if r' > 64 then Nothing else Just r'   {-# INLINE findClose #-}
+ src/HaskellWorks/Data/BalancedParens/Internal/Broadword/Word64.hs view
@@ -0,0 +1,47 @@+{-# LANGUAGE BangPatterns        #-}+{-# LANGUAGE FlexibleContexts    #-}+{-# LANGUAGE FlexibleInstances   #-}+{-# LANGUAGE InstanceSigs        #-}+{-# LANGUAGE ScopedTypeVariables #-}++module HaskellWorks.Data.BalancedParens.Internal.Broadword.Word64+  ( findUnmatchedClose+  ) where++import Data.Word+import HaskellWorks.Data.Bits.BitWise+import HaskellWorks.Data.Bits.Broadword.Word64+import HaskellWorks.Data.Bits.Word64++-- | Find the position of the first unmatch parenthesis within a word.+--+-- See [Broadword Implementation of Parenthesis Queries](https://arxiv.org/pdf/1301.5468.pdf), Sebastiano Vigna, 2013+findUnmatchedClose :: Word64 -> Word64+findUnmatchedClose x =+  let !b00 = x - ((x .&. 0xaaaaaaaaaaaaaaaa) .>. 1)                                               in+  let !b01 = (b00 .&. 0x3333333333333333) + ((b00 .>. 2) .&. 0x3333333333333333)                  in+  let !b02 = (b01 + (b01 .>. 4)) .&. 0x0f0f0f0f0f0f0f0f                                           in+  let !b03 = (b02 * 0x0101010101010101) .<. 1                                                     in+  let !b04 = kBitDiffUnsafe 8 (h 8 .|. 0x4038302820181008) b03                                    in+  let !u00 = (((((b04 .|. h 8) - l 8) .>. 7) .&. l 8) .|. h 8) - l 8                              in+  let !z00 =                         ((h 8 .>. 1) .|. (l 8 * 7)) .&. u00                          in++  let !d10 = (l 8 * 2 - (((x .>. 6) .&. (l 8 .<. 1)) + ((x .>. 5) .&. (l 8 .<. 1))))              in+  let !b10 = b04 - d10                                                                            in+  let !u10 = (((((b10 .|. h 8) - l 8) .>. 7) .&. l 8) .|. h 8) - l 8                              in+  let !z10 = (z00 .&. comp u10) .|. (((h 8 .>. 1) .|. (l 8 * 5)) .&. u10)                         in++  let !d20 = (l 8 * 2 - (((x .>. 4) .&. (l 8 .<. 1)) + ((x .>. 3) .&. (l 8 .<. 1))))              in+  let !b20 = b10 - d20                                                                            in+  let !u20 = (((((b20 .|. h 8) - l 8) .>. 7) .&. l 8) .|. h 8) - l 8                              in+  let !z20 = (z10 .&. comp u20) .|. (((h 8 .>. 1) .|. (l 8 * 3)) .&. u20)                         in++  let !d30 = (l 8 * 2 - (((x .>. 2) .&. (l 8 .<. 1)) + ((x .>. 1) .&. (l 8 .<. 1))))              in+  let !b30 = b20 - d30                                                                            in+  let !u30 = (((((b30 .|. h 8) - l 8) .>. 7) .&. l 8) .|. h 8) - l 8                              in+  let !z30 = (z20 .&. comp u30) .|. (((h 8 .>. 1) .|.  l 8     ) .&. u30)                         in++  let !p00 = lsb (z30 .>. 6 .&. l 8)                                                              in+  let !r00 = ((p00 + ((z30 .>. fromIntegral (p00 .&. 0x3f)) .&. 0x3f)) .|. (p00 .>. 8)) .&. 0x7f  in+  r00+{-# INLINE findUnmatchedClose #-}
src/HaskellWorks/Data/BalancedParens/Internal/Slow/Word16.hs view
@@ -1,14 +1,75 @@ {-# LANGUAGE LambdaCase #-}  module HaskellWorks.Data.BalancedParens.Internal.Slow.Word16-  ( findCloseFar+  ( findUnmatchedCloseFar   ) where  import Data.Word import HaskellWorks.Data.Bits.BitWise -findCloseFar :: Word16 -> Word16 -> Word16-findCloseFar = go 0+-- | Find the position of the first unmatch parenthesis.+--+-- The digits 1 and 0 are treated as an open parenthesis and closing parenthesis respectively.+--+-- All positions are indexed from zero.  If the search runs out of bits, then continue as if there remain an infinite+-- string of zeros.+--+-- >>> import HaskellWorks.Data.Bits.BitRead+-- >>> import Data.Maybe+--+-- The following scans for the first unmatched closing parenthesis from the beginning of the bit string:+--+-- >>> findUnmatchedCloseFar 0 $ fromJust $ bitRead "00000000 00000000"+-- 0+--+-- The following scans for the first unmatched closing parenthesis after skipping one bit from the beginning of the+-- bit string:+--+-- >>> findUnmatchedCloseFar 1 $ fromJust $ bitRead "00000000 00000000"+-- 1+--+-- The following scans for the first unmatched closing parenthesis from the beginning of the bit string.  To find+-- unmatched parenthesis, the scan passes over the first parent of matching parentheses:+--+-- >>> findUnmatchedCloseFar 0 $ fromJust $ bitRead "10000000 00000000"+-- 2+--+-- The following scans for the first unmatched closing parenthesis from the beginning of the bit string, but runs+-- out of bits.  The scan continues as if there an inifinite string of zero bits follows, the first of which is at+-- position 64, which also happens to be the position of the unmatched parenthesis.+--+-- >>> findUnmatchedCloseFar 0 $ fromJust $ bitRead "11111111 00000000"+-- 16+--+-- The following scans for the first unmatched closing parenthesis from the beginning of the bit string, but runs+-- out of bits.  The scan continues as if there an inifinite string of zero bits follows and we don't get to the+-- unmatched parenthesis until position 128.+--+-- >>> findUnmatchedCloseFar 0 $ fromJust $ bitRead "11111111 11111111"+-- 32+--+-- Following are some more examples:+--+-- >>> findUnmatchedCloseFar 0 $ fromJust $ bitRead "11110000 11110000"+-- 16+-- >>> findUnmatchedCloseFar 1 $ fromJust $ bitRead "11110000 11110000"+-- 7+-- >>> findUnmatchedCloseFar 2 $ fromJust $ bitRead "11110000 11110000"+-- 6+-- >>> findUnmatchedCloseFar 3 $ fromJust $ bitRead "11110000 11110000"+-- 5+-- >>> findUnmatchedCloseFar 4 $ fromJust $ bitRead "11110000 11110000"+-- 4+-- >>> findUnmatchedCloseFar 5 $ fromJust $ bitRead "11110000 11110000"+-- 5+-- >>> findUnmatchedCloseFar 6 $ fromJust $ bitRead "11110000 11110000"+-- 6+-- >>> findUnmatchedCloseFar 7 $ fromJust $ bitRead "11110000 11110000"+-- 7+-- >>> findUnmatchedCloseFar 8 $ fromJust $ bitRead "11110000 11110000"+-- 16+findUnmatchedCloseFar :: Word16 -> Word16 -> Word16+findUnmatchedCloseFar = go 0   where go :: Word16 -> Word16 -> Word16 -> Word16         go d 16 _ = 16 + d         go d i w = case (w .>. fromIntegral i) .&. 1 of
src/HaskellWorks/Data/BalancedParens/Internal/Slow/Word32.hs view
@@ -1,14 +1,75 @@ {-# LANGUAGE LambdaCase #-}  module HaskellWorks.Data.BalancedParens.Internal.Slow.Word32-  ( findCloseFar+  ( findUnmatchedCloseFar   ) where  import Data.Word import HaskellWorks.Data.Bits.BitWise -findCloseFar :: Word32 -> Word32 -> Word32-findCloseFar = go 0+-- | Find the position of the first unmatch parenthesis.+--+-- The digits 1 and 0 are treated as an open parenthesis and closing parenthesis respectively.+--+-- All positions are indexed from zero.  If the search runs out of bits, then continue as if there remain an infinite+-- string of zeros.+--+-- >>> import HaskellWorks.Data.Bits.BitRead+-- >>> import Data.Maybe+--+-- The following scans for the first unmatched closing parenthesis from the beginning of the bit string:+--+-- >>> findUnmatchedCloseFar 0 $ fromJust $ bitRead "00000000 00000000 00000000 00000000"+-- 0+--+-- The following scans for the first unmatched closing parenthesis after skipping one bit from the beginning of the+-- bit string:+--+-- >>> findUnmatchedCloseFar 1 $ fromJust $ bitRead "00000000 00000000 00000000 00000000"+-- 1+--+-- The following scans for the first unmatched closing parenthesis from the beginning of the bit string.  To find+-- unmatched parenthesis, the scan passes over the first parent of matching parentheses:+--+-- >>> findUnmatchedCloseFar 0 $ fromJust $ bitRead "10000000 00000000 00000000 00000000"+-- 2+--+-- The following scans for the first unmatched closing parenthesis from the beginning of the bit string, but runs+-- out of bits.  The scan continues as if there an inifinite string of zero bits follows, the first of which is at+-- position 64, which also happens to be the position of the unmatched parenthesis.+--+-- >>> findUnmatchedCloseFar 0 $ fromJust $ bitRead "11111111 11111111 00000000 00000000"+-- 32+--+-- The following scans for the first unmatched closing parenthesis from the beginning of the bit string, but runs+-- out of bits.  The scan continues as if there an inifinite string of zero bits follows and we don't get to the+-- unmatched parenthesis until position 128.+--+-- >>> findUnmatchedCloseFar 0 $ fromJust $ bitRead "11111111 11111111 11111111 11111111"+-- 64+--+-- Following are some more examples:+--+-- >>> findUnmatchedCloseFar 0 $ fromJust $ bitRead "11110000 11110000 11110000 11110000"+-- 32+-- >>> findUnmatchedCloseFar 1 $ fromJust $ bitRead "11110000 11110000 11110000 11110000"+-- 7+-- >>> findUnmatchedCloseFar 2 $ fromJust $ bitRead "11110000 11110000 11110000 11110000"+-- 6+-- >>> findUnmatchedCloseFar 3 $ fromJust $ bitRead "11110000 11110000 11110000 11110000"+-- 5+-- >>> findUnmatchedCloseFar 4 $ fromJust $ bitRead "11110000 11110000 11110000 11110000"+-- 4+-- >>> findUnmatchedCloseFar 5 $ fromJust $ bitRead "11110000 11110000 11110000 11110000"+-- 5+-- >>> findUnmatchedCloseFar 6 $ fromJust $ bitRead "11110000 11110000 11110000 11110000"+-- 6+-- >>> findUnmatchedCloseFar 7 $ fromJust $ bitRead "11110000 11110000 11110000 11110000"+-- 7+-- >>> findUnmatchedCloseFar 8 $ fromJust $ bitRead "11110000 11110000 11110000 11110000"+-- 32+findUnmatchedCloseFar :: Word32 -> Word32 -> Word32+findUnmatchedCloseFar = go 0   where go :: Word32 -> Word32 -> Word32 -> Word32         go d 32 _ = 32 + d         go d i w = case (w .>. fromIntegral i) .&. 1 of
src/HaskellWorks/Data/BalancedParens/Internal/Slow/Word64.hs view
@@ -1,14 +1,75 @@ {-# LANGUAGE LambdaCase #-}  module HaskellWorks.Data.BalancedParens.Internal.Slow.Word64-  ( findCloseFar+  ( findUnmatchedCloseFar   ) where  import Data.Word import HaskellWorks.Data.Bits.BitWise -findCloseFar :: Word64 -> Word64 -> Word64-findCloseFar = go 0+-- | Find the position of the first unmatch parenthesis.+--+-- The digits 1 and 0 are treated as an open parenthesis and closing parenthesis respectively.+--+-- All positions are indexed from zero.  If the search runs out of bits, then continue as if there remain an infinite+-- string of zeros.+--+-- >>> import HaskellWorks.Data.Bits.BitRead+-- >>> import Data.Maybe+--+-- The following scans for the first unmatched closing parenthesis from the beginning of the bit string:+--+-- >>> findUnmatchedCloseFar 0 $ fromJust $ bitRead "00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000"+-- 0+--+-- The following scans for the first unmatched closing parenthesis after skipping one bit from the beginning of the+-- bit string:+--+-- >>> findUnmatchedCloseFar 1 $ fromJust $ bitRead "00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000"+-- 1+--+-- The following scans for the first unmatched closing parenthesis from the beginning of the bit string.  To find+-- unmatched parenthesis, the scan passes over the first parent of matching parentheses:+--+-- >>> findUnmatchedCloseFar 0 $ fromJust $ bitRead "10000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000"+-- 2+--+-- The following scans for the first unmatched closing parenthesis from the beginning of the bit string, but runs+-- out of bits.  The scan continues as if there an inifinite string of zero bits follows, the first of which is at+-- position 64, which also happens to be the position of the unmatched parenthesis.+--+-- >>> findUnmatchedCloseFar 0 $ fromJust $ bitRead "11111111 11111111 11111111 11111111 00000000 00000000 00000000 00000000"+-- 64+--+-- The following scans for the first unmatched closing parenthesis from the beginning of the bit string, but runs+-- out of bits.  The scan continues as if there an inifinite string of zero bits follows and we don't get to the+-- unmatched parenthesis until position 128.+--+-- >>> findUnmatchedCloseFar 0 $ fromJust $ bitRead "11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111"+-- 128+--+-- Following are some more examples:+--+-- >>> findUnmatchedCloseFar 0 $ fromJust $ bitRead "11110000 11110000 11110000 11110000 11110000 11110000 11110000 11110000"+-- 64+-- >>> findUnmatchedCloseFar 1 $ fromJust $ bitRead "11110000 11110000 11110000 11110000 11110000 11110000 11110000 11110000"+-- 7+-- >>> findUnmatchedCloseFar 2 $ fromJust $ bitRead "11110000 11110000 11110000 11110000 11110000 11110000 11110000 11110000"+-- 6+-- >>> findUnmatchedCloseFar 3 $ fromJust $ bitRead "11110000 11110000 11110000 11110000 11110000 11110000 11110000 11110000"+-- 5+-- >>> findUnmatchedCloseFar 4 $ fromJust $ bitRead "11110000 11110000 11110000 11110000 11110000 11110000 11110000 11110000"+-- 4+-- >>> findUnmatchedCloseFar 5 $ fromJust $ bitRead "11110000 11110000 11110000 11110000 11110000 11110000 11110000 11110000"+-- 5+-- >>> findUnmatchedCloseFar 6 $ fromJust $ bitRead "11110000 11110000 11110000 11110000 11110000 11110000 11110000 11110000"+-- 6+-- >>> findUnmatchedCloseFar 7 $ fromJust $ bitRead "11110000 11110000 11110000 11110000 11110000 11110000 11110000 11110000"+-- 7+-- >>> findUnmatchedCloseFar 8 $ fromJust $ bitRead "11110000 11110000 11110000 11110000 11110000 11110000 11110000 11110000"+-- 64+findUnmatchedCloseFar :: Word64 -> Word64 -> Word64+findUnmatchedCloseFar = go 0   where go :: Word64 -> Word64 -> Word64 -> Word64         go d 64 _ = 64 + d         go d i w = case (w .>. fromIntegral i) .&. 1 of@@ -16,3 +77,4 @@           _ -> if d == 0             then i             else go (d - 1) (i + 1) w+{-# INLINE findUnmatchedCloseFar #-}
src/HaskellWorks/Data/BalancedParens/Internal/Slow/Word8.hs view
@@ -1,14 +1,75 @@ {-# LANGUAGE LambdaCase #-}  module HaskellWorks.Data.BalancedParens.Internal.Slow.Word8-  ( findCloseFar+  ( findUnmatchedCloseFar   ) where  import Data.Word import HaskellWorks.Data.Bits.BitWise -findCloseFar :: Word8 -> Word8 -> Word8-findCloseFar = go 0+-- | Find the position of the first unmatch parenthesis.+--+-- The digits 1 and 0 are treated as an open parenthesis and closing parenthesis respectively.+--+-- All positions are indexed from zero.  If the search runs out of bits, then continue as if there remain an infinite+-- string of zeros.+--+-- >>> import HaskellWorks.Data.Bits.BitRead+-- >>> import Data.Maybe+--+-- The following scans for the first unmatched closing parenthesis from the beginning of the bit string:+--+-- >>> findUnmatchedCloseFar 0 $ fromJust $ bitRead "00000000"+-- 0+--+-- The following scans for the first unmatched closing parenthesis after skipping one bit from the beginning of the+-- bit string:+--+-- >>> findUnmatchedCloseFar 1 $ fromJust $ bitRead "00000000"+-- 1+--+-- The following scans for the first unmatched closing parenthesis from the beginning of the bit string.  To find+-- unmatched parenthesis, the scan passes over the first parent of matching parentheses:+--+-- >>> findUnmatchedCloseFar 0 $ fromJust $ bitRead "10000000"+-- 2+--+-- The following scans for the first unmatched closing parenthesis from the beginning of the bit string, but runs+-- out of bits.  The scan continues as if there an inifinite string of zero bits follows, the first of which is at+-- position 64, which also happens to be the position of the unmatched parenthesis.+--+-- >>> findUnmatchedCloseFar 0 $ fromJust $ bitRead "11110000"+-- 8+--+-- The following scans for the first unmatched closing parenthesis from the beginning of the bit string, but runs+-- out of bits.  The scan continues as if there an inifinite string of zero bits follows and we don't get to the+-- unmatched parenthesis until position 128.+--+-- >>> findUnmatchedCloseFar 0 $ fromJust $ bitRead "11111111"+-- 16+--+-- Following are some more examples:+--+-- >>> findUnmatchedCloseFar 0 $ fromJust $ bitRead "11110000"+-- 8+-- >>> findUnmatchedCloseFar 1 $ fromJust $ bitRead "11110000"+-- 7+-- >>> findUnmatchedCloseFar 2 $ fromJust $ bitRead "11110000"+-- 6+-- >>> findUnmatchedCloseFar 3 $ fromJust $ bitRead "11110000"+-- 5+-- >>> findUnmatchedCloseFar 4 $ fromJust $ bitRead "11110000"+-- 4+-- >>> findUnmatchedCloseFar 5 $ fromJust $ bitRead "11110000"+-- 5+-- >>> findUnmatchedCloseFar 6 $ fromJust $ bitRead "11110000"+-- 6+-- >>> findUnmatchedCloseFar 7 $ fromJust $ bitRead "11110000"+-- 7+-- >>> findUnmatchedCloseFar 8 $ fromJust $ bitRead "11110000"+-- 8+findUnmatchedCloseFar :: Word8 -> Word8 -> Word8+findUnmatchedCloseFar = go 0   where go :: Word8 -> Word8 -> Word8 -> Word8         go d 8 _ = 8 + d         go d i w = case (w .>. fromIntegral i) .&. 1 of
test/HaskellWorks/Data/BalancedParens/Broadword/Word16Spec.hs view
@@ -21,15 +21,15 @@  spec :: Spec spec = describe "HaskellWorks.Data.BalancedParens.Broadword.Word16Spec" $ do-  it "findCloseFar 0 [11111111 11110100]" $ requireTest $ do+  it "findUnmatchedCloseFar 0 [11111111 11110100]" $ requireTest $ do     p <- forAll $ pure 0     w <- forAll $ pure $ fromJust $ bitRead "11111111 11110100"     annotateShow $ bitShow w     annotateShow $ showHex w ""-    W16.findCloseFar p w === SW16.findCloseFar p w+    W16.findUnmatchedCloseFar p w === SW16.findUnmatchedCloseFar p w -  it "findCloseFar" $ require $ withTests 1000 $ property $ do+  it "findUnmatchedCloseFar" $ require $ withTests 1000 $ property $ do     p <- forAll $ G.word16 (R.linear 0 16)     w <- forAll $ G.word16 R.constantBounded     annotateShow $ bitShow w-    W16.findCloseFar p w === SW16.findCloseFar p w+    W16.findUnmatchedCloseFar p w === SW16.findUnmatchedCloseFar p w
test/HaskellWorks/Data/BalancedParens/Broadword/Word32Spec.hs view
@@ -8,7 +8,7 @@ import Hedgehog import Test.Hspec -import qualified HaskellWorks.Data.BalancedParens.Broadword.Word32     as W32+import qualified HaskellWorks.Data.BalancedParens.Broadword.Word32     as BW32 import qualified HaskellWorks.Data.BalancedParens.Internal.Slow.Word32 as SW32 import qualified Hedgehog.Gen                                          as G import qualified Hedgehog.Range                                        as R@@ -18,13 +18,13 @@  spec :: Spec spec = describe "HaskellWorks.Data.BalancedParens.Broadword.Word32Spec" $ do-  it "findCloseFar" $ requireTest $ do+  it "findUnmatchedCloseFar" $ requireTest $ do     p <- forAll $ pure 0     w <- forAll $ pure 0xe9f6e7ff     annotateShow $ bitShow w-    W32.findCloseFar p w === SW32.findCloseFar p w-  it "findCloseFar" $ require $ withTests 10000 $ property $ do+    BW32.findUnmatchedCloseFar p w === SW32.findUnmatchedCloseFar p w+  it "findUnmatchedCloseFar" $ require $ withTests 10000 $ property $ do     p <- forAll $ G.word32 (R.linear 0 32)     w <- forAll $ G.word32 R.constantBounded     annotateShow $ bitShow w-    W32.findCloseFar p w === SW32.findCloseFar p w+    BW32.findUnmatchedCloseFar p w === SW32.findUnmatchedCloseFar p w
test/HaskellWorks/Data/BalancedParens/Broadword/Word64Spec.hs view
@@ -8,7 +8,7 @@ import Hedgehog import Test.Hspec -import qualified HaskellWorks.Data.BalancedParens.Broadword.Word64     as W64+import qualified HaskellWorks.Data.BalancedParens.Broadword.Word64     as BW64 import qualified HaskellWorks.Data.BalancedParens.Internal.Slow.Word64 as SW64 import qualified Hedgehog.Gen                                          as G import qualified Hedgehog.Range                                        as R@@ -18,8 +18,8 @@  spec :: Spec spec = describe "HaskellWorks.Data.BalancedParens.Broadword.Word64Spec" $ do-  it "findCloseFar" $ require $ withTests 100000 $ property $ do+  it "findUnmatchedCloseFar" $ require $ withTests 100000 $ property $ do     p <- forAll $ G.word64 (R.linear 0 64)     w <- forAll $ G.word64 R.constantBounded     annotateShow $ bitShow w-    W64.findCloseFar p w === SW64.findCloseFar p w+    BW64.findUnmatchedCloseFar p w === SW64.findUnmatchedCloseFar p w
test/HaskellWorks/Data/BalancedParens/Broadword/Word8Spec.hs view
@@ -17,10 +17,10 @@  spec :: Spec spec = describe "HaskellWorks.Data.BalancedParens.Broadword.Word8Spec" $ do-  describe "findCloseFar" $ do+  describe "findUnmatchedCloseFar" $ do     forM_ [0 .. 8] $ \p0 -> do       forM_ [0 .. 0xff] $ \w0 -> do         it ("word " <> bitShow w0) $ requireTest $ do           p <- forAll $ pure p0           w <- forAll $ pure w0-          W8.findCloseFar p w === SW8.findCloseFar p w+          W8.findUnmatchedCloseFar p w === SW8.findUnmatchedCloseFar p w