Skip to content

Commit acf18b6

Browse files
BodigrimLysxia
authored andcommitted
Implement cons, snoc, head, isSingleton, isPrefixOf directly, without resorting to streaming framework
1 parent 0cce33e commit acf18b6

File tree

2 files changed

+55
-11
lines changed

2 files changed

+55
-11
lines changed

src/Data/Text.hs

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -508,7 +508,15 @@ compareText (Text arrA offA lenA) (Text arrB offB lenB) =
508508
-- copying a new array. Performs replacement on
509509
-- invalid scalar values.
510510
cons :: Char -> Text -> Text
511-
cons c = unstream . S.cons (safe c) . stream
511+
cons c (Text srcArr srcOff srcLen) = runST $ do
512+
let ch = safe c
513+
chLen = utf8Length ch
514+
totalLen = chLen + srcLen
515+
marr <- A.new totalLen
516+
_ <- unsafeWrite marr 0 ch
517+
A.copyI srcLen marr chLen srcArr srcOff
518+
arr <- A.unsafeFreeze marr
519+
pure $ Text arr 0 totalLen
512520
{-# INLINE [1] cons #-}
513521

514522
infixr 5 `cons`
@@ -517,13 +525,23 @@ infixr 5 `cons`
517525
-- entire array in the process.
518526
-- Performs replacement on invalid scalar values.
519527
snoc :: Text -> Char -> Text
520-
snoc t c = unstream (S.snoc (stream t) (safe c))
528+
snoc (Text srcArr srcOff srcLen) c = runST $ do
529+
let ch = safe c
530+
chLen = utf8Length ch
531+
totalLen = srcLen + chLen
532+
marr <- A.new totalLen
533+
A.copyI srcLen marr 0 srcArr srcOff
534+
_ <- unsafeWrite marr srcLen ch
535+
arr <- A.unsafeFreeze marr
536+
pure $ Text arr 0 totalLen
521537
{-# INLINE snoc #-}
522538

523539
-- | /O(1)/ Returns the first character of a 'Text', which must be
524540
-- non-empty. This is a partial function, consider using 'uncons' instead.
525541
head :: HasCallStack => Text -> Char
526-
head t = S.head (stream t)
542+
head t
543+
| null t = emptyError "head"
544+
| otherwise = let Iter c _ = iter t 0 in c
527545
{-# INLINE head #-}
528546

529547
-- | /O(1)/ Returns the first character and rest of a 'Text', or
@@ -615,7 +633,8 @@ infixl 5 :>
615633

616634
-- | /O(1)/ Tests whether a 'Text' contains exactly one character.
617635
isSingleton :: Text -> Bool
618-
isSingleton = S.isSingleton . stream
636+
isSingleton (Text arr off len) =
637+
len == utf8LengthByLeader (A.unsafeIndex arr off)
619638
{-# INLINE isSingleton #-}
620639

621640
-- | /O(n)/ Returns the number of characters in a 'Text'.
@@ -1975,18 +1994,21 @@ unwords = intercalate (singleton ' ')
19751994
-- | /O(n)/ The 'isPrefixOf' function takes two 'Text's and returns
19761995
-- 'True' if and only if the first is a prefix of the second.
19771996
isPrefixOf :: Text -> Text -> Bool
1978-
isPrefixOf a@(Text _ _ alen) b@(Text _ _ blen) =
1979-
alen <= blen && S.isPrefixOf (stream a) (stream b)
1997+
isPrefixOf a@(Text _aArr _aOff aLen) b@(Text bArr bOff bLen) =
1998+
d >= 0 && a == b'
1999+
where d = bLen - aLen
2000+
b' | d == 0 = b
2001+
| otherwise = Text bArr bOff aLen
19802002
{-# INLINE [1] isPrefixOf #-}
19812003

19822004
-- | /O(n)/ The 'isSuffixOf' function takes two 'Text's and returns
19832005
-- 'True' if and only if the first is a suffix of the second.
19842006
isSuffixOf :: Text -> Text -> Bool
1985-
isSuffixOf a@(Text _aarr _aoff alen) b@(Text barr boff blen) =
2007+
isSuffixOf a@(Text _aArr _aOff aLen) b@(Text bArr bOff bLen) =
19862008
d >= 0 && a == b'
1987-
where d = blen - alen
2009+
where d = bLen - aLen
19882010
b' | d == 0 = b
1989-
| otherwise = Text barr (boff+d) alen
2011+
| otherwise = Text bArr (bOff+d) aLen
19902012
{-# INLINE isSuffixOf #-}
19912013

19922014
-- | /O(n+m)/ The 'isInfixOf' function takes two 'Text's and returns

src/Data/Text/Array.hs

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -308,14 +308,36 @@ copyToPointer (ByteArray src#) srcOff@(I# srcOff#) (Ptr dst#) count@(I# count#)
308308

309309
-- | Compare portions of two arrays for equality. No bounds checking
310310
-- is performed.
311-
equal :: Array -> Int -> Array -> Int -> Int -> Bool
311+
equal
312+
:: Array
313+
-- ^ First array
314+
-> Int
315+
-- ^ Offset in the first array
316+
-> Array
317+
-- ^ Second array
318+
-> Int
319+
-- ^ Offset in the second array
320+
-> Int
321+
-- ^ How many bytes to compare?
322+
-> Bool
312323
equal src1 off1 src2 off2 count = compareInternal src1 off1 src2 off2 count == 0
313324
{-# INLINE equal #-}
314325

315326
-- | Compare portions of two arrays. No bounds checking is performed.
316327
--
317328
-- @since 2.0
318-
compare :: Array -> Int -> Array -> Int -> Int -> Ordering
329+
compare
330+
:: Array
331+
-- ^ First array
332+
-> Int
333+
-- ^ Offset in the first array
334+
-> Array
335+
-- ^ Second array
336+
-> Int
337+
-- ^ Offset in the second array
338+
-> Int
339+
-- ^ How many bytes to compare?
340+
-> Ordering
319341
compare src1 off1 src2 off2 count = compareInternal src1 off1 src2 off2 count `Prelude.compare` 0
320342
{-# INLINE compare #-}
321343

0 commit comments

Comments
 (0)