-
Notifications
You must be signed in to change notification settings - Fork 54
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Move slice to Partial, add sliceMaybe function #201
base: master
Are you sure you want to change the base?
Changes from all commits
67994da
1932046
71922d7
27ed332
0e59957
8673eb7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,6 +17,7 @@ module RIO.Vector.Partial | |
-- ** Extracting subvectors | ||
, Data.Vector.Generic.init | ||
, Data.Vector.Generic.tail | ||
, slice -- Pending <https://gitlab.haskell.org/ghc/ghc/issues/17233> | ||
|
||
-- * Modifying vectors | ||
-- ** Bulk updates | ||
|
@@ -62,3 +63,23 @@ module RIO.Vector.Partial | |
) where | ||
|
||
import qualified Data.Vector.Generic | ||
|
||
-- | /O(1)/ Yield a slice of the vector without copying it. The vector must | ||
-- contain at least @i+n@ elements. | ||
slice :: Data.Vector.Generic.Vector v a | ||
=> Int -- ^ @i@ starting index | ||
-> Int -- ^ @n@ length | ||
-> v a | ||
-> v a | ||
slice i n v = if i > 0 && n > 0 && i + n < 0 -- `i+n` overflows | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd rather see a patch like this land in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. OK, I will remove 8673eb7 then. |
||
-- Special case handling for cases when `i+n` overflows. This is | ||
-- required due to <https://gitlab.haskell.org/ghc/ghc/issues/17233>. | ||
-- Once that GHC issue is closed this function can be replaced by | ||
-- `Data.Vector.Generic.slice`. | ||
-- (Negative overflow is not an issue as an `Date.Vector.Generic.slice` | ||
-- throws an exception is thrown for negative arguments.) | ||
then error $ "slice: invalid slice (" | ||
++ show i ++ "," | ||
++ show n ++ "," | ||
++ show (Data.Vector.Generic.length v) ++ ")" | ||
else Data.Vector.Generic.slice i n v |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
{-# LANGUAGE NoImplicitPrelude #-} | ||
module RIO.VectorSpec where | ||
|
||
import Test.Hspec | ||
import Test.Hspec.QuickCheck (prop) | ||
import qualified Test.QuickCheck as QC | ||
import RIO | ||
import qualified RIO.Vector as V | ||
import qualified RIO.Vector.Partial as V' | ||
|
||
spec :: Spec | ||
spec = | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Some quickchecks/property tests would be a great addition here. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah, I didn't write any because I didn't see any in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I was about to replace all the tests with: spec :: Spec
spec =
describe "sliceMaybe" $ do
prop "is consistent with `slice` (pathological cases)" $
\(QC.Large i) (QC.Large n) v
-> sliceProp i n (DV.fromList v)
prop "is consistent with `slice` (less pathological cases)" $
\(QC.NonNegative i) (QC.NonNegative n) (QC.NonEmpty v)
-> sliceProp i n (DV.fromList v)
where
sliceProp :: Int -> Int -> DV.Vector Char -> QC.Property
sliceProp i n v = QC.withMaxSuccess 10000 $ case VB.sliceMaybe i n v of
Just v' -> DV.slice i n v `shouldBe` v'
Nothing -> evaluate (DV.slice i n v) `shouldThrow` anyException (The second property could be skipped since it is implicit in the first and the number of cases could be reduced to the default of 100, but the coverage may not be extensive.) However, these tests resulted in:
Further investigation led me to open https://gitlab.haskell.org/ghc/ghc/issues/17233. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What makes you think this is a GHC bug instead of a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I just used the heuristic that if it is a segfault or the error message says Please report this as a GHC bug it should be reported here. But it may well be (probably is?) a vector bug so I reported it as haskell/vector#257 too. |
||
describe "sliceMaybe" $ do | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think it's necessary to replace the unit tests with property tests, I was just hoping to include property tests as well. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That was understood. However, I felt the property test was more to the point and completely specified the intended behavior of Things became a bit complicated with the revealed bug of course. |
||
prop "is consistent with `slice` (pathological cases)" $ | ||
\(QC.Large i) (QC.Large n) v | ||
-> sliceTest i n (V.fromList v) | ||
-- The next property is a subset of the previous one but with | ||
-- significantly greater likelyhood of having "realistic" | ||
-- arguments to `slice`. | ||
prop "is consistent with `slice` (more realistic cases)" $ | ||
\(QC.NonNegative i) (QC.NonNegative n) (QC.NonEmpty v) | ||
-> sliceTest i n (V.fromList v) | ||
where | ||
sliceTest :: Int -> Int -> Vector Char -> QC.Property | ||
sliceTest i n v = QC.withMaxSuccess 1000 $ case V.sliceMaybe i n v of | ||
Just v' -> V'.slice i n v `shouldBe` v' | ||
Nothing -> evaluate (V'.slice i n v) `shouldThrow` anyException |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since we're doing the checking ourselves, moving to
unsafeSlice
is a good idea.