Skip to content

Commit d1896da

Browse files
committed
Add Data.ByteString.Short.unconsN
Fixes #524
1 parent 2b9416d commit d1896da

File tree

4 files changed

+66
-0
lines changed

4 files changed

+66
-0
lines changed

Data/ByteString/Short.hs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ module Data.ByteString.Short (
8282
last,
8383
tail,
8484
uncons,
85+
unconsN,
8586
head,
8687
init,
8788
unsnoc,

Data/ByteString/Short/Internal.hs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ module Data.ByteString.Short.Internal (
5858
last,
5959
tail,
6060
uncons,
61+
unconsN,
6162
head,
6263
init,
6364
unsnoc,
@@ -743,6 +744,33 @@ uncons = \sbs ->
743744
t = create nl $ \mba -> copyByteArray (asBA sbs) 1 mba 0 nl
744745
in Just (h, t)
745746

747+
-- | /O(n)/ Extract the given number of elements from a ShortByteString and the remainder.
748+
-- Returns 'Nothing' if the ShortByteString is smaller than the requested number of elements.
749+
--
750+
-- >>> unconsN 3 "abcdefg"
751+
-- Just ([97,98,99],"defg")
752+
-- >>> unconsN 11 "abcdefg"
753+
-- Nothing
754+
-- >>> unconsN 0 "abcdefg"
755+
-- Nothing
756+
--
757+
-- Satisfies the following properties:
758+
--
759+
-- > \x i -> unconsN i x == (if length x < i || i < 1 then Nothing else let u = unpack in Just (take i u, pack (drop i u)))
760+
-- > \x -> unconsN 1 x == fmap (\(x, y) -> ([x], y)) (uncons x)
761+
-- > \x i -> maybe i (\(xs, _) -> length xs) (unconsN i x) === i
762+
--
763+
-- @since 0.11.3.2
764+
unconsN :: Int -> ShortByteString -> Maybe ([Word8], ShortByteString)
765+
unconsN n = \sbs ->
766+
let l = length sbs
767+
nl = l - n
768+
ix = n - 1
769+
in if | n < 1 || l <= ix -> Nothing
770+
| otherwise -> let h = List.map (indexWord8Array (asBA sbs)) [0..ix]
771+
t = create nl $ \mba -> copyByteArray (asBA sbs) n mba 0 nl
772+
in Just (h, t)
773+
746774
-- | /O(1)/ Extract the first element of a ShortByteString, which must be non-empty.
747775
-- An exception will be thrown in the case of an empty ShortByteString.
748776
--

bench/BenchShort.hs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,5 +231,31 @@ benchShort = bgroup "ShortByteString"
231231
, bench "FindIndex/inlined" $ nf (S.findIndex (== nl)) absurdlong
232232
, bench "FindIndex/non-inlined" $ nf (S.findIndex (nilEq nl)) absurdlong
233233
]
234+
, bgroup "ShortByteString unpack/uncons comparison" $
235+
[ bench "unpack and look at first 5 elements" $ nf (unpack5) absurdlong
236+
, bench "uncons consecutively 5 times" $ nf (uncons5) absurdlong
237+
, bench "unconsN 5" $ nf (unconsN) absurdlong
238+
]
234239
]
235240

241+
242+
unpack5 :: ShortByteString -> Bool
243+
unpack5 sbs = case S.unpack sbs of
244+
(a:b:c:d:e:_) -> True
245+
_ -> False
246+
247+
248+
uncons5 :: ShortByteString -> Bool
249+
uncons5 sbs
250+
| Just (a, r1) <- S.uncons sbs
251+
, Just (b, r2) <- S.uncons r1
252+
, Just (c, r3) <- S.uncons r2
253+
, Just (d, r4) <- S.uncons r3
254+
, Just (e, xs) <- S.uncons r4 = True
255+
| otherwise = False
256+
257+
unconsN :: ShortByteString -> Bool
258+
unconsN sbs = case S.unconsN 5 sbs of
259+
Just ([a, b, c, d, e], xs) -> True
260+
Just _ -> error "oops"
261+
_ -> False

tests/Properties/ByteString.hs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -655,6 +655,17 @@ tests =
655655
\s -> fromString s == B.pack (map (fromIntegral . ord :: Char -> Word8) s)
656656
, testProperty "fromString literal" $
657657
fromString "\0\1\2\3\4" == B.pack [0,1,2,3,4]
658+
#endif
659+
#ifdef BYTESTRING_SHORT
660+
, testProperty "unconsN == unpack" $
661+
\x i -> B.unconsN i x === (if B.length x < i || i < 1 then Nothing else let u = B.unpack x
662+
l = take i u
663+
r = B.pack (drop i u)
664+
in Just (l, r))
665+
, testProperty "unconsN 1 == uncons" $
666+
\x -> B.unconsN 1 x === fmap (\(x, y) -> ([x], y)) (B.uncons x)
667+
, testProperty "length of items matches input (unconsN)" $
668+
\x i -> maybe i (\(xs, _) -> length xs) (B.unconsN i x) === i
658669
#endif
659670
]
660671

0 commit comments

Comments
 (0)