packages feed

crucible-0.7: src/Lang/Crucible/Utils/BitSet.hs

------------------------------------------------------------------------
-- |
-- Module           : Lang.Crucible.Utils.BitSet
-- Description      : Encode a set of enumerable elements using the bit-positions
--                    in an Integer
-- Copyright        : (c) Galois, Inc 2015-2016
-- License          : BSD3
-- Maintainer       : Joe Hendrix <jhendrix@galois.com>
-- Stability        : provisional
--
-- This module provides a simple bitset datastructure
-- built on top of GHC-native Integers.
------------------------------------------------------------------------
module Lang.Crucible.Utils.BitSet
( BitSet
, getBits
, empty
, null
, singleton
, insert
, remove
, size
, member
, isSubsetOf
, difference
, intersection
, union
, toList
, foldr
, foldl
, foldl'
) where

import Data.Bits
import Data.Word
import Data.Hashable
import qualified Data.List as List
import Prelude hiding (null, foldr, foldl)

newtype BitSet a = BitSet { getBits :: Integer }
 deriving (Show, Eq, Ord)

instance Hashable (BitSet a) where
  hashWithSalt s (BitSet x) = hashWithSalt s x

empty :: BitSet a
empty = BitSet zeroBits

null :: BitSet a -> Bool
null = (0==) . getBits

singleton :: Enum a => a -> BitSet a
singleton a = BitSet (bit (fromEnum a))

insert :: Enum a => a -> BitSet a -> BitSet a
insert a (BitSet x) = BitSet (setBit x (fromEnum a))

remove :: Enum a => a -> BitSet a -> BitSet a
remove a (BitSet x) = BitSet (clearBit x (fromEnum a))

union :: BitSet a -> BitSet a -> BitSet a
union (BitSet x) (BitSet y) = BitSet (x .|. y)

intersection :: BitSet a -> BitSet a -> BitSet a
intersection (BitSet x) (BitSet y) = BitSet (x .&. y)

difference :: BitSet a -> BitSet a -> BitSet a
difference (BitSet x) (BitSet y) = BitSet (x .&. complement y)

isSubsetOf :: BitSet a -> BitSet a -> Bool
isSubsetOf (BitSet x) (BitSet y) = x .|. y == y

member :: Enum a => a -> BitSet a -> Bool
member a (BitSet x) = testBit x (fromEnum a)

size :: BitSet a -> Int
size (BitSet x) = popCount x

toList :: Enum a => BitSet a -> [a]
toList (BitSet bs) = go bs 0
  where go :: Enum a => Integer -> Int -> [a]
        go 0 _ = []
        go x i
           | y .&. 0xffffffff == 0 = go (shiftR x 32) $! (i+32)
           | y .&. 0x0000ffff == 0 = go (shiftR x 16) $! (i+16)
           | y .&. 0x000000ff == 0 = go (shiftR x  8) $! (i+ 8)
           | otherwise = concat
               [ if testBit y 0 then [toEnum (i+0)] else []
               , if testBit y 1 then [toEnum (i+1)] else []
               , if testBit y 2 then [toEnum (i+2)] else []
               , if testBit y 3 then [toEnum (i+3)] else []
               , if testBit y 4 then [toEnum (i+4)] else []
               , if testBit y 5 then [toEnum (i+5)] else []
               , if testBit y 6 then [toEnum (i+6)] else []
               , if testBit y 7 then [toEnum (i+7)] else []
               , go (shiftR x 8) $! (i+8)
               ]

          where y :: Word32
                y = fromInteger x

foldl' :: Enum a => (b -> a -> b) -> b -> BitSet a -> b
foldl' f z = List.foldl' f z . toList

foldl :: Enum a => (b -> a -> b) -> b -> BitSet a -> b
foldl f z = List.foldl f z . toList

foldr :: Enum a => (a -> b -> b) -> b -> BitSet a -> b
foldr f z = List.foldr f z . toList