Skip to content

Commit

Permalink
Add lookupMin and lookupMax for IntSet
Browse files Browse the repository at this point in the history
These already exist for Set, Map, and IntMap.
Also
* Update docs for lookupMin, lookupMax, findMin, findMax to be
  consistent for all the structures.
* Modify IntMap's lookupMin and lookupMax impls so that Just is
  returned immediately and mark them INLINE. This allows GHC to inline
  and possibly eliminate the Maybe. Set and Map's lookupMin and
  lookupMax are already implemented in this style.
  • Loading branch information
meooow25 committed Jan 13, 2024
1 parent f5d0b13 commit 0b1ffd7
Show file tree
Hide file tree
Showing 5 changed files with 80 additions and 42 deletions.
10 changes: 10 additions & 0 deletions containers-tests/tests/intset-properties.hs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ main = defaultMain $ testGroup "intset-properties"
, testProperty "prop_isSubsetOf2" prop_isSubsetOf2
, testProperty "prop_disjoint" prop_disjoint
, testProperty "prop_size" prop_size
, testProperty "prop_lookupMin" prop_lookupMin
, testProperty "prop_lookupMax" prop_lookupMax
, testProperty "prop_findMax" prop_findMax
, testProperty "prop_findMin" prop_findMin
, testProperty "prop_ord" prop_ord
Expand Down Expand Up @@ -334,6 +336,14 @@ prop_size s = sz === foldl' (\i _ -> i + 1) (0 :: Int) s .&&.
sz === List.length (toList s)
where sz = size s

prop_lookupMin :: IntSet -> Property
prop_lookupMin s =
lookupMin s === if null s then Nothing else Just (minimum (toList s))

prop_lookupMax :: IntSet -> Property
prop_lookupMax s =
lookupMax s === if null s then Nothing else Just (maximum (toList s))

prop_findMax :: IntSet -> Property
prop_findMax s = not (null s) ==> findMax s == maximum (toList s)

Expand Down
36 changes: 18 additions & 18 deletions containers/src/Data/IntMap/Internal.hs
Original file line number Diff line number Diff line change
Expand Up @@ -2266,37 +2266,37 @@ deleteFindMax = fromMaybe (error "deleteFindMax: empty map has no maximal elemen
deleteFindMin :: IntMap a -> ((Key, a), IntMap a)
deleteFindMin = fromMaybe (error "deleteFindMin: empty map has no minimal element") . minViewWithKey

lookupMinSure :: IntMap a -> (Key, a)
lookupMinSure (Tip k v) = (k,v)
lookupMinSure (Bin _ _ l _) = lookupMinSure l
lookupMinSure Nil = error "lookupMinSure Nil"

-- | \(O(\min(n,W))\). The minimal key of the map. Returns 'Nothing' if the map is empty.
lookupMin :: IntMap a -> Maybe (Key, a)
lookupMin Nil = Nothing
lookupMin (Tip k v) = Just (k,v)
lookupMin (Bin _ m l r)
| m < 0 = go r
| otherwise = go l
where go (Tip k v) = Just (k,v)
go (Bin _ _ l' _) = go l'
go Nil = Nothing
lookupMin Nil = Nothing
lookupMin (Tip k v) = Just (k,v)
lookupMin (Bin _ m l r) = Just $! lookupMinSure (if m < 0 then r else l)
{-# INLINE lookupMin #-}

-- | \(O(\min(n,W))\). The minimal key of the map. Calls 'error' if the map is empty.
-- Use 'minViewWithKey' if the map may be empty.
findMin :: IntMap a -> (Key, a)
findMin t
| Just r <- lookupMin t = r
| otherwise = error "findMin: empty map has no minimal element"

lookupMaxSure :: IntMap a -> (Key, a)
lookupMaxSure (Tip k v) = (k,v)
lookupMaxSure (Bin _ _ _ r) = lookupMaxSure r
lookupMaxSure Nil = error "lookupMaxSure Nil"

-- | \(O(\min(n,W))\). The maximal key of the map. Returns 'Nothing' if the map is empty.
lookupMax :: IntMap a -> Maybe (Key, a)
lookupMax Nil = Nothing
lookupMax (Tip k v) = Just (k,v)
lookupMax (Bin _ m l r)
| m < 0 = go l
| otherwise = go r
where go (Tip k v) = Just (k,v)
go (Bin _ _ _ r') = go r'
go Nil = Nothing
lookupMax Nil = Nothing
lookupMax (Tip k v) = Just (k,v)
lookupMax (Bin _ m l r) = Just $! lookupMaxSure (if m < 0 then l else r)
{-# INLINE lookupMax #-}

-- | \(O(\min(n,W))\). The maximal key of the map. Calls 'error' if the map is empty.
-- Use 'maxViewWithKey' if the map may be empty.
findMax :: IntMap a -> (Key, a)
findMax t
| Just r <- lookupMax t = r
Expand Down
2 changes: 2 additions & 0 deletions containers/src/Data/IntSet.hs
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,8 @@ module Data.IntSet (
, fold

-- * Min\/Max
, lookupMin
, lookupMax
, findMin
, findMax
, deleteMin
Expand Down
62 changes: 42 additions & 20 deletions containers/src/Data/IntSet/Internal.hs
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,8 @@ module Data.IntSet.Internal (
, fold

-- * Min\/Max
, lookupMin
, lookupMax
, findMin
, findMax
, deleteMin
Expand Down Expand Up @@ -1001,29 +1003,49 @@ deleteFindMin = fromMaybe (error "deleteFindMin: empty set has no minimal elemen
deleteFindMax :: IntSet -> (Key, IntSet)
deleteFindMax = fromMaybe (error "deleteFindMax: empty set has no maximal element") . maxView

lookupMinSure :: IntSet -> Key
lookupMinSure (Tip kx bm) = kx + lowestBitSet bm
lookupMinSure (Bin _ _ l _) = lookupMinSure l
lookupMinSure Nil = error "lookupMin Nil"

-- | \(O(\min(n,W))\). The minimal element of the set.
-- | \(O(\min(n,W))\). The minimal element of the set. Returns 'Nothing' if the
-- set is empty.
--
-- @since FIXME
lookupMin :: IntSet -> Maybe Key
lookupMin Nil = Nothing
lookupMin (Tip kx bm) = Just $! kx + lowestBitSet bm
lookupMin (Bin _ m l r) = Just $! lookupMinSure (if m < 0 then r else l)
{-# INLINE lookupMin #-}

-- | \(O(\min(n,W))\). The minimal element of the set. Calls 'error' if the set
-- is empty.
findMin :: IntSet -> Key
findMin Nil = error "findMin: empty set has no minimal element"
findMin (Tip kx bm) = kx + lowestBitSet bm
findMin (Bin _ m l r)
| m < 0 = find r
| otherwise = find l
where find (Tip kx bm) = kx + lowestBitSet bm
find (Bin _ _ l' _) = find l'
find Nil = error "findMin Nil"

-- | \(O(\min(n,W))\). The maximal element of a set.
findMax :: IntSet -> Key
findMax Nil = error "findMax: empty set has no maximal element"
findMax (Tip kx bm) = kx + highestBitSet bm
findMax (Bin _ m l r)
| m < 0 = find l
| otherwise = find r
where find (Tip kx bm) = kx + highestBitSet bm
find (Bin _ _ _ r') = find r'
find Nil = error "findMax Nil"
findMin t
| Just r <- lookupMin t = r
| otherwise = error "findMin: empty set has no minimal element"

lookupMaxSure :: IntSet -> Key
lookupMaxSure (Tip kx bm) = kx + highestBitSet bm
lookupMaxSure (Bin _ _ _ r) = lookupMaxSure r
lookupMaxSure Nil = error "lookupMax Nil"

-- | \(O(\min(n,W))\). The maximal element of the set. Returns 'Nothing' if the
-- set is empty.
--
-- @since FIXME
lookupMax :: IntSet -> Maybe Key
lookupMax Nil = Nothing
lookupMax (Tip kx bm) = Just $! kx + highestBitSet bm
lookupMax (Bin _ m l r) = Just $! lookupMaxSure (if m < 0 then l else r)
{-# INLINE lookupMax #-}

-- | \(O(\min(n,W))\). The maximal element of the set. Calls 'error' if the set
-- is empty.
findMax :: IntSet -> Key
findMax t
| Just r <- lookupMax t = r
| otherwise = error "findMax: empty set has no maximal element"

-- | \(O(\min(n,W))\). Delete the minimal element. Returns an empty set if the set is empty.
--
Expand Down
12 changes: 8 additions & 4 deletions containers/src/Data/Set/Internal.hs
Original file line number Diff line number Diff line change
Expand Up @@ -761,15 +761,17 @@ lookupMinSure :: a -> Set a -> a
lookupMinSure x Tip = x
lookupMinSure _ (Bin _ x l _) = lookupMinSure x l

-- | \(O(\log n)\). The minimal element of a set.
-- | \(O(\log n)\). The minimal element of the set. Returns 'Nothing' if the set
-- is empty.
--
-- @since 0.5.9

lookupMin :: Set a -> Maybe a
lookupMin Tip = Nothing
lookupMin (Bin _ x l _) = Just $! lookupMinSure x l

-- | \(O(\log n)\). The minimal element of a set.
-- | \(O(\log n)\). The minimal element of the set. Calls 'error' if the set is
-- empty.
findMin :: Set a -> a
findMin t
| Just r <- lookupMin t = r
Expand All @@ -779,15 +781,17 @@ lookupMaxSure :: a -> Set a -> a
lookupMaxSure x Tip = x
lookupMaxSure _ (Bin _ x _ r) = lookupMaxSure x r

-- | \(O(\log n)\). The maximal element of a set.
-- | \(O(\log n)\). The maximal element of the set. Returns 'Nothing' if the set
-- is empty.
--
-- @since 0.5.9

lookupMax :: Set a -> Maybe a
lookupMax Tip = Nothing
lookupMax (Bin _ x _ r) = Just $! lookupMaxSure x r

-- | \(O(\log n)\). The maximal element of a set.
-- | \(O(\log n)\). The maximal element of the set. Calls 'error' if the set is
-- empty.
findMax :: Set a -> a
findMax t
| Just r <- lookupMax t = r
Expand Down

0 comments on commit 0b1ffd7

Please sign in to comment.