    -- | A game requires the engine provided by the library, perhaps customized,
    -- and game content, defined completely afresh for the particular game.
    -- The possible kinds of content are fixed in the library and all defined
    -- within the library source code directory. On the other hand, game content,
    -- is defined in the directory hosting the particular game definition.
    --
    -- Content of a given kind is just a list of content items.
    -- After the list is verified and the data preprocessed, it's held
    -- in the @ContentData@ datatype.
    module Game.LambdaHack.Definition.ContentData
      ( ContentData
      , validateRarity, validFreqs
      , emptyContentData, makeContentData
      , okind, omemberGroup, oexistsGroup, oisSingletonGroup, ouniqGroup, opick
      , ofoldlWithKey', ofoldlGroup', omapVector, oimapVector, olength
      ) where

    import Prelude ()

    import Game.LambdaHack.Core.Prelude

    import           Data.Function
    import qualified Data.Map.Strict as M
    import qualified Data.Set as S
    import qualified Data.Text as T
    import qualified Data.Vector as V

    import Game.LambdaHack.Core.Frequency
    import Game.LambdaHack.Core.Random
    import Game.LambdaHack.Definition.Defs
    import Game.LambdaHack.Definition.DefsInternal

    -- | Verified and preprocessed content data of a particular kind.
    data ContentData c = ContentData
      { forall c. ContentData c -> Vector c
    contentVector :: V.Vector c
      , forall c.
    ContentData c -> Map (GroupName c) [(Int, (ContentId c, c))]
    groupFreq     :: M.Map (GroupName c) [(Int, (ContentId c, c))]
      }

    maxContentId :: ContentId k
    maxContentId :: forall k. ContentId k
    maxContentId = Word16 -> ContentId k
    forall c. Word16 -> ContentId c
    toContentId Word16
    forall a. Bounded a => a
    maxBound

    validateRarity :: Rarity -> [Text]
    validateRarity :: [(Double, Int)] -> [Text]
    validateRarity [(Double, Int)]
    rarity =
      -- @SortOn@ less efficient here, because function cheap.
      let sortedRarity :: [(Double, Int)]
    sortedRarity = ((Double, Int) -> (Double, Int) -> Ordering)
    -> [(Double, Int)] -> [(Double, Int)]
    forall a. (a -> a -> Ordering) -> [a] -> [a]
    sortBy (((Double, Int) -> Double)
    -> (Double, Int) -> (Double, Int) -> Ordering
    forall a b. Ord a => (b -> a) -> b -> b -> Ordering
    comparing (Double, Int) -> Double
    forall a b. (a, b) -> a
    fst) [(Double, Int)]
    rarity
      in [ Text
    "rarity not sorted" | [(Double, Int)]
    sortedRarity [(Double, Int)] -> [(Double, Int)] -> Bool
    forall a. Eq a => a -> a -> Bool
    /= [(Double, Int)]
    rarity ]
         [Text] -> [Text] -> [Text]
    forall a. [a] -> [a] -> [a]
    ++ [ Text
    "rarity depth thresholds not unique"
            | ([(Double, Int)] -> (Double, Int))
    -> [[(Double, Int)]] -> [(Double, Int)]
    forall a b. (a -> b) -> [a] -> [b]
    map [(Double, Int)] -> (Double, Int)
    forall a. HasCallStack => [a] -> a
    head (((Double, Int) -> (Double, Int) -> Bool)
    -> [(Double, Int)] -> [[(Double, Int)]]
    forall a. (a -> a -> Bool) -> [a] -> [[a]]
    groupBy (Double -> Double -> Bool
    forall a. Eq a => a -> a -> Bool
    (==) (Double -> Double -> Bool)
    -> ((Double, Int) -> Double)
    -> (Double, Int)
    -> (Double, Int)
    -> Bool
    forall b c a. (b -> b -> c) -> (a -> b) -> a -> a -> c
    `on` (Double, Int) -> Double
    forall a b. (a, b) -> a
    fst) [(Double, Int)]
    sortedRarity) [(Double, Int)] -> [(Double, Int)] -> Bool
    forall a. Eq a => a -> a -> Bool
    /= [(Double, Int)]
    sortedRarity ]
         [Text] -> [Text] -> [Text]
    forall a. [a] -> [a] -> [a]
    ++ [ Text
    "rarity depth not positive"
            | case [(Double, Int)]
    sortedRarity of
                ((Double
    lowest, Int
    _) : [(Double, Int)]
    _) -> Double
    lowest Double -> Double -> Bool
    forall a. Ord a => a -> a -> Bool
    <= Double
    0
                [(Double, Int)]
    _ -> Bool
    False ]

    validFreqs :: Freqs a -> Bool
    validFreqs :: forall a. Freqs a -> Bool
    validFreqs Freqs a
    freqs =
      -- Greater or equal to 0 permitted, e.g., to cover embedded template UNKNOWN
      -- items not yet identified by the client, but triggerable nevertheless.
      ((GroupName a, Int) -> Bool) -> Freqs a -> Bool
    forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
    all ((Int -> Int -> Bool
    forall a. Ord a => a -> a -> Bool
    >= Int
    0) (Int -> Bool)
    -> ((GroupName a, Int) -> Int) -> (GroupName a, Int) -> Bool
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (GroupName a, Int) -> Int
    forall a b. (a, b) -> b
    snd) Freqs a
    freqs
      Bool -> Bool -> Bool
    && let groups :: [GroupName a]
    groups = [GroupName a] -> [GroupName a]
    forall a. Ord a => [a] -> [a]
    sort ([GroupName a] -> [GroupName a]) -> [GroupName a] -> [GroupName a]
    forall a b. (a -> b) -> a -> b
    $ ((GroupName a, Int) -> GroupName a) -> Freqs a -> [GroupName a]
    forall a b. (a -> b) -> [a] -> [b]
    map (GroupName a, Int) -> GroupName a
    forall a b. (a, b) -> a
    fst Freqs a
    freqs
             tailOfGroups :: [GroupName a]
    tailOfGroups = if [GroupName a] -> Bool
    forall a. [a] -> Bool
    null [GroupName a]
    groups then [GroupName a]
    groups else [GroupName a] -> [GroupName a]
    forall a. HasCallStack => [a] -> [a]
    tail [GroupName a]
    groups
         in ((GroupName a, GroupName a) -> Bool)
    -> [(GroupName a, GroupName a)] -> Bool
    forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
    all ((GroupName a -> GroupName a -> Bool)
    -> (GroupName a, GroupName a) -> Bool
    forall a b c. (a -> b -> c) -> (a, b) -> c
    uncurry GroupName a -> GroupName a -> Bool
    forall a. Eq a => a -> a -> Bool
    (/=)) ([(GroupName a, GroupName a)] -> Bool)
    -> [(GroupName a, GroupName a)] -> Bool
    forall a b. (a -> b) -> a -> b
    $ [GroupName a] -> [GroupName a] -> [(GroupName a, GroupName a)]
    forall a b. [a] -> [b] -> [(a, b)]
    zip [GroupName a]
    groups [GroupName a]
    tailOfGroups

    emptyContentData :: ContentData a
    emptyContentData :: forall a. ContentData a
    emptyContentData = Vector a
    -> Map (GroupName a) [(Int, (ContentId a, a))] -> ContentData a
    forall c.
    Vector c
    -> Map (GroupName c) [(Int, (ContentId c, c))] -> ContentData c
    ContentData Vector a
    forall a. Vector a
    V.empty Map (GroupName a) [(Int, (ContentId a, a))]
    forall k a. Map k a
    M.empty

    makeContentData :: Show c
                    => String
                    -> (c -> Text)
                         -- ^ name of the content itme, used for validation
                    -> (c -> Freqs c)
                         -- ^ frequency in groups, for validation and preprocessing
                    -> (c -> [Text])
                         -- ^ validate a content item and list all offences
                    -> ([c] -> ContentData c -> [Text])
                         -- ^ validate the whole defined content of this type
                         -- and list all offence
                    -> [c]  -- ^ all content of this type
                    -> [GroupName c]  -- ^ singleton group names for this content
                    -> [GroupName c]  -- ^ remaining group names for this content
                    -> ContentData c
    {-# INLINE makeContentData #-}
    makeContentData :: forall c.
    Show c =>
    String
    -> (c -> Text)
    -> (c -> Freqs c)
    -> (c -> [Text])
    -> ([c] -> ContentData c -> [Text])
    -> [c]
    -> [GroupName c]
    -> [GroupName c]
    -> ContentData c
    makeContentData String
    contentName c -> Text
    getName c -> Freqs c
    getFreq c -> [Text]
    validateSingle [c] -> ContentData c -> [Text]
    validateAll
                    [c]
    content [GroupName c]
    groupNamesSingleton [GroupName c]
    groupNames =
      -- The @force@ is needed for @GHC.Compact@.
      let contentVector :: Vector c
    contentVector = Vector c -> Vector c
    forall a. Vector a -> Vector a
    V.force (Vector c -> Vector c) -> Vector c -> Vector c
    forall a b. (a -> b) -> a -> b
    $ [c] -> Vector c
    forall a. [a] -> Vector a
    V.fromList [c]
    content
          groupFreq :: Map (GroupName c) [(Int, (ContentId c, c))]
    groupFreq =
            let tuples :: [(GroupName c, (Int, (ContentId c, c)))]
    tuples = [ (GroupName c
    cgroup, (Int
    n, (ContentId c
    i, c
    k)))
                         | (ContentId c
    i, c
    k) <- [ContentId c] -> [c] -> [(ContentId c, c)]
    forall a b. [a] -> [b] -> [(a, b)]
    zip ((Word16 -> ContentId c) -> [Word16] -> [ContentId c]
    forall a b. (a -> b) -> [a] -> [b]
    map Word16 -> ContentId c
    forall c. Word16 -> ContentId c
    toContentId [Word16
    0..]) [c]
    content
                         , (GroupName c
    cgroup, Int
    n) <- c -> Freqs c
    getFreq c
    k
                         , Int
    n Int -> Int -> Bool
    forall a. Ord a => a -> a -> Bool
    > Int
    0 ]
                f :: Map k [a] -> (k, a) -> Map k [a]
    f !Map k [a]
    m (!k
    cgroup, !a
    nik) = ([a] -> [a] -> [a]) -> k -> [a] -> Map k [a] -> Map k [a]
    forall k a. Ord k => (a -> a -> a) -> k -> a -> Map k a -> Map k a
    M.insertWith [a] -> [a] -> [a]
    forall a. [a] -> [a] -> [a]
    (++) k
    cgroup [a
    nik] Map k [a]
    m
            in (Map (GroupName c) [(Int, (ContentId c, c))]
     -> (GroupName c, (Int, (ContentId c, c)))
     -> Map (GroupName c) [(Int, (ContentId c, c))])
    -> Map (GroupName c) [(Int, (ContentId c, c))]
    -> [(GroupName c, (Int, (ContentId c, c)))]
    -> Map (GroupName c) [(Int, (ContentId c, c))]
    forall b a. (b -> a -> b) -> b -> [a] -> b
    forall (t :: * -> *) b a.
    Foldable t =>
    (b -> a -> b) -> b -> t a -> b
    foldl' Map (GroupName c) [(Int, (ContentId c, c))]
    -> (GroupName c, (Int, (ContentId c, c)))
    -> Map (GroupName c) [(Int, (ContentId c, c))]
    forall {k} {a}. Ord k => Map k [a] -> (k, a) -> Map k [a]
    f Map (GroupName c) [(Int, (ContentId c, c))]
    forall k a. Map k a
    M.empty [(GroupName c, (Int, (ContentId c, c)))]
    tuples
          contentData :: ContentData c
    contentData = ContentData {Map (GroupName c) [(Int, (ContentId c, c))]
    Vector c
    contentVector :: Vector c
    groupFreq :: Map (GroupName c) [(Int, (ContentId c, c))]
    contentVector :: Vector c
    groupFreq :: Map (GroupName c) [(Int, (ContentId c, c))]
    ..}
          singleOffenders :: [([Text], c)]
    singleOffenders = [ ([Text]
    offences, c
    a)
                            | c
    a <- [c]
    content
                            , let offences :: [Text]
    offences = c -> [Text]
    validateSingle c
    a
                                             [Text] -> [Text] -> [Text]
    forall a. [a] -> [a] -> [a]
    ++ [Text
    "empty name" | Text -> Bool
    T.null (c -> Text
    getName c
    a)]
                            , Bool -> Bool
    not ([Text] -> Bool
    forall a. [a] -> Bool
    null [Text]
    offences) ]
          allOffences :: [Text]
    allOffences = [c] -> ContentData c -> [Text]
    validateAll [c]
    content ContentData c
    contentData
          freqsOffenders :: [c]
    freqsOffenders = (c -> Bool) -> [c] -> [c]
    forall a. (a -> Bool) -> [a] -> [a]
    filter (Bool -> Bool
    not (Bool -> Bool) -> (c -> Bool) -> c -> Bool
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Freqs c -> Bool
    forall a. Freqs a -> Bool
    validFreqs (Freqs c -> Bool) -> (c -> Freqs c) -> c -> Bool
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . c -> Freqs c
    getFreq) [c]
    content
          allGroupNamesEmpty :: [GroupName c]
    allGroupNamesEmpty = (GroupName c -> Bool) -> [GroupName c] -> [GroupName c]
    forall a. (a -> Bool) -> [a] -> [a]
    filter (Text -> Bool
    T.null (Text -> Bool) -> (GroupName c -> Text) -> GroupName c -> Bool
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . GroupName c -> Text
    forall c. GroupName c -> Text
    fromGroupName)
                               ([GroupName c] -> [GroupName c]) -> [GroupName c] -> [GroupName c]
    forall a b. (a -> b) -> a -> b
    $ [GroupName c]
    groupNamesSingleton [GroupName c] -> [GroupName c] -> [GroupName c]
    forall a. [a] -> [a] -> [a]
    ++ [GroupName c]
    groupNames
          allGroupNamesTooLong :: [GroupName c]
    allGroupNamesTooLong = (GroupName c -> Bool) -> [GroupName c] -> [GroupName c]
    forall a. (a -> Bool) -> [a] -> [a]
    filter ((Int -> Int -> Bool
    forall a. Ord a => a -> a -> Bool
    > Int
    30) (Int -> Bool) -> (GroupName c -> Int) -> GroupName c -> Bool
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Text -> Int
    T.length (Text -> Int) -> (GroupName c -> Text) -> GroupName c -> Int
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . GroupName c -> Text
    forall c. GroupName c -> Text
    fromGroupName)
                                 ([GroupName c] -> [GroupName c]) -> [GroupName c] -> [GroupName c]
    forall a b. (a -> b) -> a -> b
    $ [GroupName c]
    groupNamesSingleton [GroupName c] -> [GroupName c] -> [GroupName c]
    forall a. [a] -> [a] -> [a]
    ++ [GroupName c]
    groupNames
          allGroupNamesSorted :: [GroupName c]
    allGroupNamesSorted = [GroupName c] -> [GroupName c]
    forall a. Ord a => [a] -> [a]
    sort ([GroupName c] -> [GroupName c]) -> [GroupName c] -> [GroupName c]
    forall a b. (a -> b) -> a -> b
    $ [GroupName c]
    groupNamesSingleton [GroupName c] -> [GroupName c] -> [GroupName c]
    forall a. [a] -> [a] -> [a]
    ++ [GroupName c]
    groupNames
          allGroupNamesUnique :: [GroupName c]
    allGroupNamesUnique = [GroupName c] -> [GroupName c]
    forall a. Eq a => [a] -> [a]
    nub [GroupName c]
    allGroupNamesSorted
          allGroupNamesNonUnique :: [GroupName c]
    allGroupNamesNonUnique = [GroupName c]
    allGroupNamesSorted [GroupName c] -> [GroupName c] -> [GroupName c]
    forall a. Eq a => [a] -> [a] -> [a]
    \\ [GroupName c]
    allGroupNamesUnique
          missingGroups :: [GroupName c]
    missingGroups = (GroupName c -> Bool) -> [GroupName c] -> [GroupName c]
    forall a. (a -> Bool) -> [a] -> [a]
    filter (Bool -> Bool
    not (Bool -> Bool) -> (GroupName c -> Bool) -> GroupName c -> Bool
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . ContentData c -> GroupName c -> Bool
    forall a. ContentData a -> GroupName a -> Bool
    omemberGroup ContentData c
    contentData)
                                 ([GroupName c]
    groupNamesSingleton [GroupName c] -> [GroupName c] -> [GroupName c]
    forall a. [a] -> [a] -> [a]
    ++ [GroupName c]
    groupNames)
          groupsMoreThanOne :: [GroupName c]
    groupsMoreThanOne = (GroupName c -> Bool) -> [GroupName c] -> [GroupName c]
    forall a. (a -> Bool) -> [a] -> [a]
    filter (Bool -> Bool
    not (Bool -> Bool) -> (GroupName c -> Bool) -> GroupName c -> Bool
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . ContentData c -> GroupName c -> Bool
    forall a. ContentData a -> GroupName a -> Bool
    oisSingletonGroup ContentData c
    contentData)
                                     [GroupName c]
    groupNamesSingleton
          groupsDeclaredSet :: Set (GroupName c)
    groupsDeclaredSet = [GroupName c] -> Set (GroupName c)
    forall a. Eq a => [a] -> Set a
    S.fromAscList [GroupName c]
    allGroupNamesUnique
          groupsNotDeclared :: [GroupName c]
    groupsNotDeclared = (GroupName c -> Bool) -> [GroupName c] -> [GroupName c]
    forall a. (a -> Bool) -> [a] -> [a]
    filter (GroupName c -> Set (GroupName c) -> Bool
    forall a. Ord a => a -> Set a -> Bool
    `S.notMember` Set (GroupName c)
    groupsDeclaredSet)
                              ([GroupName c] -> [GroupName c]) -> [GroupName c] -> [GroupName c]
    forall a b. (a -> b) -> a -> b
    $ Map (GroupName c) [(Int, (ContentId c, c))] -> [GroupName c]
    forall k a. Map k a -> [k]
    M.keys Map (GroupName c) [(Int, (ContentId c, c))]
    groupFreq
      in Bool -> ContentData c -> ContentData c
    forall a. HasCallStack => Bool -> a -> a
    assert ([GroupName c] -> Bool
    forall a. [a] -> Bool
    null [GroupName c]
    allGroupNamesEmpty
                 Bool -> (String, [GroupName c]) -> Bool
    forall v. Show v => Bool -> v -> Bool
    `blame` String
    contentName String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    ": some group names empty"
                 String -> [GroupName c] -> (String, [GroupName c])
    forall v. String -> v -> (String, v)
    `swith` [GroupName c]
    allGroupNamesEmpty) (ContentData c -> ContentData c) -> ContentData c -> ContentData c
    forall a b. (a -> b) -> a -> b
    $
         Bool -> ContentData c -> ContentData c
    forall a. HasCallStack => Bool -> a -> a
    assert ([GroupName c] -> Bool
    forall a. [a] -> Bool
    null [GroupName c]
    allGroupNamesTooLong
                 Bool -> (String, [GroupName c]) -> Bool
    forall v. Show v => Bool -> v -> Bool
    `blame` String
    contentName String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    ": some group names too long"
                 String -> [GroupName c] -> (String, [GroupName c])
    forall v. String -> v -> (String, v)
    `swith` [GroupName c]
    allGroupNamesTooLong) (ContentData c -> ContentData c) -> ContentData c -> ContentData c
    forall a b. (a -> b) -> a -> b
    $
         Bool -> ContentData c -> ContentData c
    forall a. HasCallStack => Bool -> a -> a
    assert ([GroupName c] -> Bool
    forall a. [a] -> Bool
    null [GroupName c]
    allGroupNamesNonUnique
                 Bool -> (String, [GroupName c]) -> Bool
    forall v. Show v => Bool -> v -> Bool
    `blame` String
    contentName String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    ": some group names duplicated"
                 String -> [GroupName c] -> (String, [GroupName c])
    forall v. String -> v -> (String, v)
    `swith` [GroupName c]
    allGroupNamesNonUnique) (ContentData c -> ContentData c) -> ContentData c -> ContentData c
    forall a b. (a -> b) -> a -> b
    $
         Bool -> ContentData c -> ContentData c
    forall a. HasCallStack => Bool -> a -> a
    assert ([GroupName c] -> Bool
    forall a. [a] -> Bool
    null [GroupName c]
    missingGroups
                 Bool -> (String, [GroupName c]) -> Bool
    forall v. Show v => Bool -> v -> Bool
    `blame` String
    contentName String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    ": some group names pertain to no content"
                 String -> [GroupName c] -> (String, [GroupName c])
    forall v. String -> v -> (String, v)
    `swith` [GroupName c]
    missingGroups) (ContentData c -> ContentData c) -> ContentData c -> ContentData c
    forall a b. (a -> b) -> a -> b
    $
         Bool -> ContentData c -> ContentData c
    forall a. HasCallStack => Bool -> a -> a
    assert ([GroupName c] -> Bool
    forall a. [a] -> Bool
    null [GroupName c]
    groupsMoreThanOne
                 Bool -> (String, [GroupName c]) -> Bool
    forall v. Show v => Bool -> v -> Bool
    `blame` String
    contentName String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    ": some group names refer to more than one content, while they shouldn't"
                 String -> [GroupName c] -> (String, [GroupName c])
    forall v. String -> v -> (String, v)
    `swith` [GroupName c]
    groupsMoreThanOne) (ContentData c -> ContentData c) -> ContentData c -> ContentData c
    forall a b. (a -> b) -> a -> b
    $
         Bool -> ContentData c -> ContentData c
    forall a. HasCallStack => Bool -> a -> a
    assert ([GroupName c] -> Bool
    forall a. [a] -> Bool
    null [GroupName c]
    groupsNotDeclared
                 Bool -> (String, [GroupName c]) -> Bool
    forall v. Show v => Bool -> v -> Bool
    `blame` String
    contentName String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    ": some group names are not included in group name lists, neither singleton nor duplicable"
                 String -> [GroupName c] -> (String, [GroupName c])
    forall v. String -> v -> (String, v)
    `swith` [GroupName c]
    groupsNotDeclared) (ContentData c -> ContentData c) -> ContentData c -> ContentData c
    forall a b. (a -> b) -> a -> b
    $
         Bool -> ContentData c -> ContentData c
    forall a. HasCallStack => Bool -> a -> a
    assert ([c] -> Bool
    forall a. [a] -> Bool
    null [c]
    freqsOffenders
                 Bool -> (String, [c]) -> Bool
    forall v. Show v => Bool -> v -> Bool
    `blame` String
    contentName String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    ": some Freqs values not valid"
                 String -> [c] -> (String, [c])
    forall v. String -> v -> (String, v)
    `swith` [c]
    freqsOffenders) (ContentData c -> ContentData c) -> ContentData c -> ContentData c
    forall a b. (a -> b) -> a -> b
    $
         Bool -> ContentData c -> ContentData c
    forall a. HasCallStack => Bool -> a -> a
    assert ([([Text], c)] -> Bool
    forall a. [a] -> Bool
    null [([Text], c)]
    singleOffenders
                 Bool -> (String, [([Text], c)]) -> Bool
    forall v. Show v => Bool -> v -> Bool
    `blame` String
    contentName String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    ": some content items not valid"
                 String -> [([Text], c)] -> (String, [([Text], c)])
    forall v. String -> v -> (String, v)
    `swith` [([Text], c)]
    singleOffenders) (ContentData c -> ContentData c) -> ContentData c -> ContentData c
    forall a b. (a -> b) -> a -> b
    $
         Bool -> ContentData c -> ContentData c
    forall a. HasCallStack => Bool -> a -> a
    assert ([Text] -> Bool
    forall a. [a] -> Bool
    null [Text]
    allOffences
                 Bool -> (String, [Text]) -> Bool
    forall v. Show v => Bool -> v -> Bool
    `blame` String
    contentName String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    ": the content set is not valid"
                 String -> [Text] -> (String, [Text])
    forall v. String -> v -> (String, v)
    `swith` [Text]
    allOffences) (ContentData c -> ContentData c) -> ContentData c -> ContentData c
    forall a b. (a -> b) -> a -> b
    $
         Bool -> ContentData c -> ContentData c
    forall a. HasCallStack => Bool -> a -> a
    assert (Vector c -> Int
    forall a. Vector a -> Int
    V.length Vector c
    contentVector Int -> Int -> Bool
    forall a. Ord a => a -> a -> Bool
    <= ContentId (ZonkAny 0) -> Int
    forall c. ContentId c -> Int
    contentIdIndex ContentId (ZonkAny 0)
    forall k. ContentId k
    maxContentId
                 Bool -> String -> Bool
    forall v. Show v => Bool -> v -> Bool
    `blame` String
    contentName String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    ": the content has too many elements")
         ContentData c
    contentData

    -- | Content element at given id.
    okind :: ContentData a -> ContentId a -> a
    {-# INLINE okind #-}
    okind :: forall a. ContentData a -> ContentId a -> a
    okind ContentData{Vector a
    contentVector :: forall c. ContentData c -> Vector c
    contentVector :: Vector a
    contentVector} !ContentId a
    i = Vector a
    contentVector Vector a -> Int -> a
    forall a. Vector a -> Int -> a
    V.! ContentId a -> Int
    forall c. ContentId c -> Int
    contentIdIndex ContentId a
    i

    omemberGroup :: ContentData a -> GroupName a -> Bool
    omemberGroup :: forall a. ContentData a -> GroupName a -> Bool
    omemberGroup ContentData{Map (GroupName a) [(Int, (ContentId a, a))]
    groupFreq :: forall c.
    ContentData c -> Map (GroupName c) [(Int, (ContentId c, c))]
    groupFreq :: Map (GroupName a) [(Int, (ContentId a, a))]
    groupFreq} GroupName a
    cgroup = GroupName a
    cgroup GroupName a -> Map (GroupName a) [(Int, (ContentId a, a))] -> Bool
    forall k a. Ord k => k -> Map k a -> Bool
    `M.member` Map (GroupName a) [(Int, (ContentId a, a))]
    groupFreq

    oexistsGroup :: ContentData a -> GroupName a -> Bool
    oexistsGroup :: forall a. ContentData a -> GroupName a -> Bool
    oexistsGroup ContentData{Map (GroupName a) [(Int, (ContentId a, a))]
    groupFreq :: forall c.
    ContentData c -> Map (GroupName c) [(Int, (ContentId c, c))]
    groupFreq :: Map (GroupName a) [(Int, (ContentId a, a))]
    groupFreq} GroupName a
    cgroup = case GroupName a
    -> Map (GroupName a) [(Int, (ContentId a, a))]
    -> Maybe [(Int, (ContentId a, a))]
    forall k a. Ord k => k -> Map k a -> Maybe a
    M.lookup GroupName a
    cgroup Map (GroupName a) [(Int, (ContentId a, a))]
    groupFreq of
      Maybe [(Int, (ContentId a, a))]
    Nothing -> Bool
    False
      Just [(Int, (ContentId a, a))]
    l -> ((Int, (ContentId a, a)) -> Bool)
    -> [(Int, (ContentId a, a))] -> Bool
    forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
    all ((Int -> Int -> Bool
    forall a. Ord a => a -> a -> Bool
    > Int
    0) (Int -> Bool)
    -> ((Int, (ContentId a, a)) -> Int)
    -> (Int, (ContentId a, a))
    -> Bool
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (Int, (ContentId a, a)) -> Int
    forall a b. (a, b) -> a
    fst) [(Int, (ContentId a, a))]
    l

    oisSingletonGroup :: ContentData a -> GroupName a -> Bool
    oisSingletonGroup :: forall a. ContentData a -> GroupName a -> Bool
    oisSingletonGroup ContentData{Map (GroupName a) [(Int, (ContentId a, a))]
    groupFreq :: forall c.
    ContentData c -> Map (GroupName c) [(Int, (ContentId c, c))]
    groupFreq :: Map (GroupName a) [(Int, (ContentId a, a))]
    groupFreq} GroupName a
    cgroup =
      case GroupName a
    -> Map (GroupName a) [(Int, (ContentId a, a))]
    -> Maybe [(Int, (ContentId a, a))]
    forall k a. Ord k => k -> Map k a -> Maybe a
    M.lookup GroupName a
    cgroup Map (GroupName a) [(Int, (ContentId a, a))]
    groupFreq of
        Just [(Int, (ContentId a, a))
    _] -> Bool
    True
        Maybe [(Int, (ContentId a, a))]
    _ -> Bool
    False

    -- | The id of the unique member of a singleton content group.
    ouniqGroup :: Show a => ContentData a -> GroupName a -> ContentId a
    ouniqGroup :: forall a. Show a => ContentData a -> GroupName a -> ContentId a
    ouniqGroup ContentData{Map (GroupName a) [(Int, (ContentId a, a))]
    groupFreq :: forall c.
    ContentData c -> Map (GroupName c) [(Int, (ContentId c, c))]
    groupFreq :: Map (GroupName a) [(Int, (ContentId a, a))]
    groupFreq} !GroupName a
    cgroup =
      let freq :: [(Int, (ContentId a, a))]
    freq = let assFail :: [(Int, (ContentId a, a))]
    assFail = String -> [(Int, (ContentId a, a))]
    forall a. HasCallStack => String -> a
    error (String -> [(Int, (ContentId a, a))])
    -> String -> [(Int, (ContentId a, a))]
    forall a b. (a -> b) -> a -> b
    $ String
    "no unique group"
                                       String
    -> (GroupName a, Map (GroupName a) [(Int, (ContentId a, a))])
    -> String
    forall v. Show v => String -> v -> String
    `showFailure` (GroupName a
    cgroup, Map (GroupName a) [(Int, (ContentId a, a))]
    groupFreq)
                 in [(Int, (ContentId a, a))]
    -> GroupName a
    -> Map (GroupName a) [(Int, (ContentId a, a))]
    -> [(Int, (ContentId a, a))]
    forall k a. Ord k => a -> k -> Map k a -> a
    M.findWithDefault [(Int, (ContentId a, a))]
    assFail GroupName a
    cgroup Map (GroupName a) [(Int, (ContentId a, a))]
    groupFreq
      in case [(Int, (ContentId a, a))]
    freq of
        [(Int
    n, (ContentId a
    i, a
    _))] | Int
    n Int -> Int -> Bool
    forall a. Ord a => a -> a -> Bool
    > Int
    0 -> ContentId a
    i
        [(Int, (ContentId a, a))]
    l -> String -> ContentId a
    forall a. HasCallStack => String -> a
    error (String -> ContentId a) -> String -> ContentId a
    forall a b. (a -> b) -> a -> b
    $ String
    "not unique" String -> (GroupName a, [(Int, (ContentId a, a))]) -> String
    forall v. Show v => String -> v -> String
    `showFailure` (GroupName a
    cgroup, [(Int, (ContentId a, a))]
    l)

    -- | Pick a random id belonging to a group and satisfying a predicate.
    opick :: Show a
          => ContentData a
          -> GroupName a -> (a -> Bool) -> Rnd (Maybe (ContentId a))
    opick :: forall a.
    Show a =>
    ContentData a
    -> GroupName a -> (a -> Bool) -> Rnd (Maybe (ContentId a))
    opick ContentData{Map (GroupName a) [(Int, (ContentId a, a))]
    groupFreq :: forall c.
    ContentData c -> Map (GroupName c) [(Int, (ContentId c, c))]
    groupFreq :: Map (GroupName a) [(Int, (ContentId a, a))]
    groupFreq} !GroupName a
    cgroup !a -> Bool
    p =
      case GroupName a
    -> Map (GroupName a) [(Int, (ContentId a, a))]
    -> Maybe [(Int, (ContentId a, a))]
    forall k a. Ord k => k -> Map k a -> Maybe a
    M.lookup GroupName a
    cgroup Map (GroupName a) [(Int, (ContentId a, a))]
    groupFreq of
        Just [(Int, (ContentId a, a))]
    freqRaw ->
          let freq :: Frequency (ContentId a, a)
    freq = Text -> [(Int, (ContentId a, a))] -> Frequency (ContentId a, a)
    forall a. Text -> [(Int, a)] -> Frequency a
    toFreq Text
    "opick" ([(Int, (ContentId a, a))] -> Frequency (ContentId a, a))
    -> [(Int, (ContentId a, a))] -> Frequency (ContentId a, a)
    forall a b. (a -> b) -> a -> b
    $ ((Int, (ContentId a, a)) -> Bool)
    -> [(Int, (ContentId a, a))] -> [(Int, (ContentId a, a))]
    forall a. (a -> Bool) -> [a] -> [a]
    filter (a -> Bool
    p (a -> Bool)
    -> ((Int, (ContentId a, a)) -> a)
    -> (Int, (ContentId a, a))
    -> Bool
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (ContentId a, a) -> a
    forall a b. (a, b) -> b
    snd ((ContentId a, a) -> a)
    -> ((Int, (ContentId a, a)) -> (ContentId a, a))
    -> (Int, (ContentId a, a))
    -> a
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (Int, (ContentId a, a)) -> (ContentId a, a)
    forall a b. (a, b) -> b
    snd) [(Int, (ContentId a, a))]
    freqRaw
          in if Frequency (ContentId a, a) -> Bool
    forall a. Frequency a -> Bool
    nullFreq Frequency (ContentId a, a)
    freq
             then Maybe (ContentId a) -> Rnd (Maybe (ContentId a))
    forall a. a -> StateT SMGen Identity a
    forall (m :: * -> *) a. Monad m => a -> m a
    return Maybe (ContentId a)
    forall a. Maybe a
    Nothing
             else ContentId a -> Maybe (ContentId a)
    forall a. a -> Maybe a
    Just (ContentId a -> Maybe (ContentId a))
    -> ((ContentId a, a) -> ContentId a)
    -> (ContentId a, a)
    -> Maybe (ContentId a)
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (ContentId a, a) -> ContentId a
    forall a b. (a, b) -> a
    fst ((ContentId a, a) -> Maybe (ContentId a))
    -> StateT SMGen Identity (ContentId a, a)
    -> Rnd (Maybe (ContentId a))
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> Frequency (ContentId a, a)
    -> StateT SMGen Identity (ContentId a, a)
    forall a. Show a => Frequency a -> Rnd a
    frequency Frequency (ContentId a, a)
    freq
        Maybe [(Int, (ContentId a, a))]
    _ -> Maybe (ContentId a) -> Rnd (Maybe (ContentId a))
    forall a. a -> StateT SMGen Identity a
    forall (m :: * -> *) a. Monad m => a -> m a
    return Maybe (ContentId a)
    forall a. Maybe a
    Nothing

    -- | Fold strictly over all content @a@.
    ofoldlWithKey' :: ContentData a -> (b -> ContentId a -> a -> b) -> b -> b
    ofoldlWithKey' :: forall a b. ContentData a -> (b -> ContentId a -> a -> b) -> b -> b
    ofoldlWithKey' ContentData{Vector a
    contentVector :: forall c. ContentData c -> Vector c
    contentVector :: Vector a
    contentVector} b -> ContentId a -> a -> b
    f b
    z =
      (b -> Int -> a -> b) -> b -> Vector a -> b
    forall a b. (a -> Int -> b -> a) -> a -> Vector b -> a
    V.ifoldl' (\ !b
    a !Int
    i !a
    c -> b -> ContentId a -> a -> b
    f b
    a (Word16 -> ContentId a
    forall c. Word16 -> ContentId c
    toContentId (Word16 -> ContentId a) -> Word16 -> ContentId a
    forall a b. (a -> b) -> a -> b
    $ Int -> Word16
    forall a. Enum a => Int -> a
    toEnum Int
    i) a
    c) b
    z Vector a
    contentVector

    -- | Fold over the given group only.
    ofoldlGroup' :: ContentData a
                 -> GroupName a
                 -> (b -> Int -> ContentId a -> a -> b) -> b -> b
    ofoldlGroup' :: forall a b.
    ContentData a
    -> GroupName a -> (b -> Int -> ContentId a -> a -> b) -> b -> b
    ofoldlGroup' ContentData{Map (GroupName a) [(Int, (ContentId a, a))]
    groupFreq :: forall c.
    ContentData c -> Map (GroupName c) [(Int, (ContentId c, c))]
    groupFreq :: Map (GroupName a) [(Int, (ContentId a, a))]
    groupFreq} GroupName a
    cgroup b -> Int -> ContentId a -> a -> b
    f b
    z =
      case GroupName a
    -> Map (GroupName a) [(Int, (ContentId a, a))]
    -> Maybe [(Int, (ContentId a, a))]
    forall k a. Ord k => k -> Map k a -> Maybe a
    M.lookup GroupName a
    cgroup Map (GroupName a) [(Int, (ContentId a, a))]
    groupFreq of
        Just [(Int, (ContentId a, a))]
    freq -> (b -> (Int, (ContentId a, a)) -> b)
    -> b -> [(Int, (ContentId a, a))] -> b
    forall b a. (b -> a -> b) -> b -> [a] -> b
    forall (t :: * -> *) b a.
    Foldable t =>
    (b -> a -> b) -> b -> t a -> b
    foldl' (\ !b
    acc (!Int
    p, (!ContentId a
    i, !a
    a)) -> b -> Int -> ContentId a -> a -> b
    f b
    acc Int
    p ContentId a
    i a
    a) b
    z [(Int, (ContentId a, a))]
    freq
        Maybe [(Int, (ContentId a, a))]
    _ -> String -> b
    forall a. HasCallStack => String -> a
    error (String -> b) -> String -> b
    forall a b. (a -> b) -> a -> b
    $ String
    "no group '" String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ GroupName a -> String
    forall a. Show a => a -> String
    show GroupName a
    cgroup
                                  String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    "' among content that has groups "
                                  String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ [GroupName a] -> String
    forall a. Show a => a -> String
    show (Map (GroupName a) [(Int, (ContentId a, a))] -> [GroupName a]
    forall k a. Map k a -> [k]
    M.keys Map (GroupName a) [(Int, (ContentId a, a))]
    groupFreq)
                     String -> () -> String
    forall v. Show v => String -> v -> String
    `showFailure` ()

    omapVector :: ContentData a -> (a -> b) -> V.Vector b
    omapVector :: forall a b. ContentData a -> (a -> b) -> Vector b
    omapVector ContentData a
    d a -> b
    f = (a -> b) -> Vector a -> Vector b
    forall a b. (a -> b) -> Vector a -> Vector b
    V.map a -> b
    f (Vector a -> Vector b) -> Vector a -> Vector b
    forall a b. (a -> b) -> a -> b
    $ ContentData a -> Vector a
    forall c. ContentData c -> Vector c
    contentVector ContentData a
    d

    oimapVector :: ContentData a -> (ContentId a -> a -> b) -> V.Vector b
    oimapVector :: forall a b. ContentData a -> (ContentId a -> a -> b) -> Vector b
    oimapVector ContentData a
    d ContentId a -> a -> b
    f = (Int -> a -> b) -> Vector a -> Vector b
    forall a b. (Int -> a -> b) -> Vector a -> Vector b
    V.imap (\Int
    i a
    a -> ContentId a -> a -> b
    f (Word16 -> ContentId a
    forall c. Word16 -> ContentId c
    toContentId (Word16 -> ContentId a) -> Word16 -> ContentId a
    forall a b. (a -> b) -> a -> b
    $ Int -> Word16
    forall a. Enum a => Int -> a
    toEnum Int
    i) a
    a)
                             (ContentData a -> Vector a
    forall c. ContentData c -> Vector c
    contentVector ContentData a
    d)

    -- | Size of content @a@.
    olength :: ContentData a -> Int
    olength :: forall a. ContentData a -> Int
    olength ContentData{Vector a
    contentVector :: forall c. ContentData c -> Vector c
    contentVector :: Vector a
    contentVector} = Vector a -> Int
    forall a. Vector a -> Int
    V.length Vector a
    contentVector