Skip to content

Commit 6a98da6

Browse files
BodigrimLysxia
authored andcommitted
Implement index via measureOff
1 parent 324793f commit 6a98da6

File tree

3 files changed

+47
-12
lines changed

3 files changed

+47
-12
lines changed

src/Data/Text.hs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1845,7 +1845,15 @@ breakOnAll pat src@(Text arr off slen)
18451845

18461846
-- | /O(n)/ 'Text' index (subscript) operator, starting from 0.
18471847
index :: HasCallStack => Text -> Int -> Char
1848-
index t n = S.index (stream t) n
1848+
index t@(Text _ _ lenInBytes) ix
1849+
| ix < 0
1850+
= P.error $ "Data.Text.index: negative index " ++ P.show ix
1851+
| off < 0 || off == lenInBytes
1852+
= P.error $ "Data.Text.index: index " ++ P.show ix ++ " is too large"
1853+
| otherwise = ch
1854+
where
1855+
off = measureOff ix t
1856+
Iter ch _ = iter t off
18491857
{-# INLINE index #-}
18501858

18511859
-- | /O(n)/ The 'findIndex' function takes a predicate and a 'Text'

src/Data/Text/Lazy.hs

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,7 @@ import Prelude (Char, Bool(..), Maybe(..), String,
223223
import qualified Prelude as P
224224
import Control.Arrow (first)
225225
import Control.DeepSeq (NFData(..))
226-
import Data.Bits (finiteBitSize)
226+
import Data.Bits (finiteBitSize, toIntegralSized)
227227
import Data.Int (Int64)
228228
import qualified Data.List as L hiding (head, tail)
229229
import Data.Char (isSpace)
@@ -1808,7 +1808,22 @@ partition p t = (filter p t, filter (not . p) t)
18081808

18091809
-- | /O(n)/ 'Text' index (subscript) operator, starting from 0.
18101810
index :: HasCallStack => Text -> Int64 -> Char
1811-
index t n = S.index (stream t) n
1811+
index lazyText ix
1812+
| ix < 0 = P.error $ "Data.Text.Lazy.index: negative index " ++ P.show ix
1813+
| otherwise = go lazyText ix
1814+
where
1815+
go :: Text -> Int64 -> Char
1816+
go Empty _ = P.error $ "Data.Text.index: index " ++ P.show ix ++ " is too large"
1817+
go (Chunk t@(T.Text _ _ lenInBytes) ts) n = case toIntegralSized n of
1818+
Nothing ->
1819+
go ts (n - fromIntegral (T.length t))
1820+
Just n'
1821+
| off < 0 -> go ts (n + fromIntegral off)
1822+
| off == lenInBytes -> go ts 0
1823+
| otherwise -> ch
1824+
where
1825+
off = T.measureOff n' t
1826+
T.Iter ch _ = T.iter t off
18121827
{-# INLINE index #-}
18131828

18141829
-- | /O(n+m)/ The 'count' function returns the number of times the

tests/Tests/Properties/Text.hs

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,19 @@
11
-- | Tests for operations that don't fit in the other @Test.Properties.*@ modules.
22

3-
{-# LANGUAGE BangPatterns #-}
4-
{-# LANGUAGE CPP #-}
5-
{-# LANGUAGE ViewPatterns #-}
3+
{-# LANGUAGE BangPatterns #-}
4+
{-# LANGUAGE CPP #-}
5+
{-# LANGUAGE ScopedTypeVariables #-}
6+
{-# LANGUAGE ViewPatterns #-}
67

78
{-# OPTIONS_GHC -fno-warn-missing-signatures #-}
9+
{-# OPTIONS_GHC -Wno-unrecognised-pragmas #-}
10+
{-# HLINT ignore "Avoid restricted function" #-}
811

912
module Tests.Properties.Text
1013
( testText
1114
) where
1215

16+
import Control.Exception (SomeException, evaluate, try)
1317
import Data.Char (isLower, isLetter, isUpper)
1418
import Data.Maybe (mapMaybe)
1519
import Data.Text.Internal.Fusion.Size
@@ -263,13 +267,21 @@ tl_partition (applyFun -> p) = L.partition p `eqP` (unpack2 . TL.partition p)
263267
sf_index (applyFun -> p) s i = ((L.filter p s L.!!) `eq` S.index (S.filter p $ packS s)) j
264268
where l = L.length s
265269
j = if l == 0 then 0 else i `mod` (3 * l) - l
266-
t_index s i = ((s L.!!) `eq` T.index (packS s)) j
267-
where l = L.length s
268-
j = if l == 0 then 0 else i `mod` (3 * l) - l
269270

270-
tl_index s i = ((s L.!!) `eq` (TL.index (packS s) . fromIntegral)) j
271-
where l = L.length s
272-
j = if l == 0 then 0 else i `mod` (3 * l) - l
271+
t_index :: T.Text -> Int -> Property
272+
t_index xs i = ioProperty $ do
273+
ch <- try (evaluate (T.index xs i))
274+
pure $ case ch of
275+
Left (_ :: SomeException) -> i < 0 .||. i >= T.length xs
276+
Right c -> i >= 0 .&&. i < T.length xs .&&. c === T.unpack xs L.!! i
277+
278+
tl_index :: TL.Text -> Int -> Property
279+
tl_index xs i = ioProperty $ do
280+
let i' = fromIntegral i
281+
ch <- try (evaluate (TL.index xs i'))
282+
pure $ case ch of
283+
Left (_ :: SomeException) -> i' < 0 .||. i' >= TL.length xs
284+
Right c -> i >= 0 .&&. i' < TL.length xs .&&. c === TL.unpack xs L.!! i
273285

274286
t_findIndex (applyFun -> p) = L.findIndex p `eqP` T.findIndex p
275287
t_count (NotEmpty t) = (subtract 1 . L.length . T.splitOn t) `eq` T.count t

0 commit comments

Comments
 (0)