module Foreign.Extra.BitSet
  ( fromBitSet
  , toBitSet
  ) where

import Data.Bits (Bits, (.&.), (.|.), complement)
import Data.Set (Set, empty, insert, toList)

fromBitSet :: (Ord h, Bits c, Num c) => [(h, c)] -> (c -> h) -> c -> Set h
fromBitSet spec unknown bits
  | unmatched == 0 = matched
  | otherwise = insert (unknown unmatched) matched
  where
    (matched, unmatched) = foldr test (empty, bits) spec
    test (h, v) (m, um)
      | v == v .&. um = (insert h m, um .&. complement v)
      | otherwise     = (m, um)

toBitSet ::(Eq h, Bits c, Num c) => [(h, c)] -> (h -> Bool) -> (h -> c) -> Set h -> c
toBitSet spec isUnknown unUnknown = foldr (.|.) 0 . map f . toList
  where
    f h
      | isUnknown h = unUnknown h
      | otherwise = case h `lookup` spec of
          Just c -> c
          Nothing -> error "toBitSet"