mirror of
https://github.com/hasura/graphql-engine.git
synced 2024-12-15 17:31:56 +03:00
f2a5d7cef3
PR-URL: https://github.com/hasura/graphql-engine-mono/pull/6822 Co-authored-by: paritosh-08 <85472423+paritosh-08@users.noreply.github.com> Co-authored-by: Naveen Naidu <30195193+Naveenaidu@users.noreply.github.com> Co-authored-by: Sooraj <8408875+soorajshankar@users.noreply.github.com> Co-authored-by: Varun Choudhary <68095256+Varun-Choudhary@users.noreply.github.com> Co-authored-by: Sean Park-Ross <94021366+seanparkross@users.noreply.github.com> GitOrigin-RevId: 61cfc00a97de88df1ede3f26829a0d78ec9c0bc5
150 lines
5.1 KiB
Haskell
150 lines
5.1 KiB
Haskell
-- | Non-empty hash maps.
|
|
module Data.HashMap.Strict.NonEmpty
|
|
( -- * Type
|
|
NEHashMap,
|
|
|
|
-- * Construction and conversions
|
|
singleton,
|
|
fromHashMap,
|
|
fromList,
|
|
fromNonEmpty,
|
|
toHashMap,
|
|
toList,
|
|
toNonEmpty,
|
|
|
|
-- * Basic interface
|
|
lookup,
|
|
(!?),
|
|
keys,
|
|
elems,
|
|
|
|
-- * Combine
|
|
union,
|
|
unionWith,
|
|
|
|
-- * Transformations
|
|
mapKeys,
|
|
|
|
-- * Predicates
|
|
isInverseOf,
|
|
)
|
|
where
|
|
|
|
import Control.DeepSeq (NFData)
|
|
import Data.Aeson (FromJSON, ToJSON)
|
|
import Data.HashMap.Strict (HashMap)
|
|
import Data.HashMap.Strict qualified as M
|
|
import Data.HashMap.Strict.Extended qualified as Extended
|
|
import Data.Hashable (Hashable)
|
|
import Data.List.NonEmpty (NonEmpty)
|
|
import Data.List.NonEmpty qualified as NE
|
|
import Prelude hiding (lookup)
|
|
|
|
-------------------------------------------------------------------------------
|
|
|
|
-- | A non-empty hashmap is a wrapper around a normal hashmap, that
|
|
-- only provides a restricted set of functionalities. It doesn't
|
|
-- provide a 'Monoid' instance, nor an 'empty' function.
|
|
newtype NEHashMap k v = NEHashMap {unNEHashMap :: HashMap k v}
|
|
deriving newtype (Show, Eq, FromJSON, Hashable, NFData, Ord, Semigroup, ToJSON)
|
|
deriving stock (Functor, Foldable, Traversable)
|
|
|
|
-------------------------------------------------------------------------------
|
|
|
|
-- | Construct a non-empty map with a single element.
|
|
singleton :: Hashable k => k -> v -> NEHashMap k v
|
|
singleton k v = NEHashMap $ M.singleton k v
|
|
|
|
-- | Construct a non-empty map with the supplied mappings.
|
|
-- Returns 'Nothing' if the provided 'HashMap' is empty.
|
|
fromHashMap :: HashMap k v -> Maybe (NEHashMap k v)
|
|
fromHashMap m
|
|
| M.null m = Nothing
|
|
| otherwise = Just $ NEHashMap m
|
|
|
|
-- | Construct a non-empty map with the supplied mappings as follows:
|
|
--
|
|
-- * if the provided list contains duplicate mappings, the later mappings take
|
|
-- precedence;
|
|
-- * if the provided list is empty, returns 'Nothing'.
|
|
fromList :: Hashable k => [(k, v)] -> Maybe (NEHashMap k v)
|
|
fromList [] = Nothing
|
|
fromList v = Just $ NEHashMap $ M.fromList v
|
|
|
|
-- | A variant of 'fromList' that uses 'NonEmpty' inputs.
|
|
fromNonEmpty :: Hashable k => NonEmpty (k, v) -> NEHashMap k v
|
|
fromNonEmpty (x NE.:| xs) = NEHashMap (M.fromList (x : xs))
|
|
|
|
-- | Convert a non-empty map to a 'HashMap'.
|
|
toHashMap :: NEHashMap k v -> HashMap k v
|
|
toHashMap = unNEHashMap
|
|
|
|
-- | Convert a non-empty map to a non-empty list of key/value pairs. The closed
|
|
-- operations of 'NEHashMap' guarantee that this operation won't fail.
|
|
toNonEmpty :: NEHashMap k v -> NonEmpty (k, v)
|
|
toNonEmpty = NE.fromList . M.toList . unNEHashMap
|
|
|
|
-- | Convert a non-empty map to a list of key/value pairs.
|
|
toList :: NEHashMap k v -> [(k, v)]
|
|
toList = M.toList . unNEHashMap
|
|
|
|
-------------------------------------------------------------------------------
|
|
|
|
-- | Return the value to which the specified key is mapped, or 'Nothing' if
|
|
-- this map contains no mapping for the key.
|
|
lookup :: Hashable k => k -> NEHashMap k v -> Maybe v
|
|
lookup k (NEHashMap m) = M.lookup k m
|
|
|
|
-- | Return the value to which the specified key is mapped, or 'Nothing' if
|
|
-- this map contains no mapping for the key.
|
|
--
|
|
-- This is a flipped version of 'lookup'.
|
|
(!?) :: Hashable k => NEHashMap k v -> k -> Maybe v
|
|
(!?) = flip lookup
|
|
|
|
-- | Return a list of this map's keys.
|
|
keys :: NEHashMap k v -> [k]
|
|
keys = M.keys . unNEHashMap
|
|
|
|
-- | Return a list of this map's set of values
|
|
elems :: NEHashMap k v -> [v]
|
|
elems = M.elems . unNEHashMap
|
|
|
|
-------------------------------------------------------------------------------
|
|
|
|
-- | The union of two maps.
|
|
--
|
|
-- If a key occurs in both maps, the left map @m1@ (first argument) will be
|
|
-- preferred.
|
|
union :: Hashable k => NEHashMap k v -> NEHashMap k v -> NEHashMap k v
|
|
union (NEHashMap m1) (NEHashMap m2) = NEHashMap $ M.union m1 m2
|
|
|
|
-- | The union of two maps using a given value-wise union function.
|
|
--
|
|
-- If a key occurs in both maps, the provided function (first argument) will be
|
|
-- used to compute the result.
|
|
unionWith :: Hashable k => (v -> v -> v) -> NEHashMap k v -> NEHashMap k v -> NEHashMap k v
|
|
unionWith fun (NEHashMap m1) (NEHashMap m2) = NEHashMap $ M.unionWith fun m1 m2
|
|
|
|
-------------------------------------------------------------------------------
|
|
|
|
-- | @'mapKeys' f s@ is the map obtained by applying @f@ to each key of @s@.
|
|
--
|
|
-- The size of the result may be smaller if f maps two or more distinct keys to
|
|
-- the same new key. In this case there is no guarantee which of the associated
|
|
-- values is chosen for the conflicting key.
|
|
mapKeys :: Hashable k2 => (k1 -> k2) -> NEHashMap k1 v -> NEHashMap k2 v
|
|
mapKeys fun (NEHashMap m) = NEHashMap $ M.mapKeys fun m
|
|
|
|
-------------------------------------------------------------------------------
|
|
|
|
-- | Determines whether the left-hand-side and the right-hand-side are inverses of each other.
|
|
--
|
|
-- More specifically, for two maps @A@ and @B@, 'isInverseOf' is satisfied when both of the
|
|
-- following are true:
|
|
-- 1. @∀ key ∈ A. A[key] ∈ B ∧ B[A[key]] == key@
|
|
-- 2. @∀ key ∈ B. B[key] ∈ A ∧ A[B[key]] == key@
|
|
isInverseOf ::
|
|
(Hashable k, Hashable v) => NEHashMap k v -> NEHashMap v k -> Bool
|
|
lhs `isInverseOf` rhs = toHashMap lhs `Extended.isInverseOf` toHashMap rhs
|