binary-strict-0.3.0: src/Data/Binary/Strict/ByteSet.hs
-- | A ByteSet is a fast Set object for Word8's. The construction of these
-- objects isn't terribly quick, but the member function should be about
-- as good as you can get. Thus, you should use this when @member@ is the
-- most common operation
--
-- This object is designed to be imported qualified:
--
-- > import qualified Data.Binary.Strict.ByteSet as BSet
module Data.Binary.Strict.ByteSet
( ByteSet
-- * Construction
, empty
, full
, singleton
, fromList
, range
-- * Combination
, union
, intersection
, difference
-- * Uniary functions
, complement
, toList
, member
) where
import Data.List (foldl')
import Data.Word (Word8, Word64)
import Data.Array.Base (unsafeAt)
import Data.Array.Unboxed hiding ((!), range)
import Data.Bits ((.&.), (.|.), shiftL, shiftR)
import qualified Data.Bits as Bits
data ByteSet = ByteSet !(UArray Word8 Word64)
-- | We don't import the usual array indexing function from the array
-- modules. Instead, we implement it ourselves and remove the bounds
-- checking
(!) :: UArray Word8 Word64 -> Word8 -> Word64
(!) arr = unsafeAt arr . fromIntegral
instance Show ByteSet where
show = ((++) "ByteSet ") . show . toList
-- | An empty set
empty :: ByteSet
empty = ByteSet $ listArray (0, 3) $ replicate 4 0
-- | The set contained all elements
full :: ByteSet
full = ByteSet $ listArray (0, 3) $ replicate 4 0xffffffffffffffff
-- | A set with a single element
singleton :: Word8 -> ByteSet
singleton n
| n < 64 = ByteSet $ listArray (0, 3) $ [wordsArray ! n, 0, 0, 0]
| n < 128 = ByteSet $ listArray (0, 3) $ [0, wordsArray ! (n - 64), 0, 0]
| n < 196 = ByteSet $ listArray (0, 3) $ [0, 0, wordsArray ! (n - 128), 0]
| otherwise = ByteSet $ listArray (0, 3) $ [0, 0, 0, wordsArray ! (n - 196)]
wordsArray :: UArray Word8 Word64
wordsArray = listArray (0, 63) $ map (\x -> (1 :: Word64) `shiftL` x) [0..63]
-- | A generic binary function
binary :: (Word64 -> Word64 -> Word64) -> ByteSet -> ByteSet -> ByteSet
binary f (ByteSet a) (ByteSet b) =
ByteSet $ listArray (0, 3) [f (a ! 0) (b ! 0), f (a ! 1) (b ! 1), f (a ! 2) (b ! 2), f (a ! 3) (b ! 3)]
union :: ByteSet -> ByteSet -> ByteSet
union = binary (.|.)
intersection :: ByteSet -> ByteSet -> ByteSet
intersection = binary (.&.)
difference :: ByteSet -> ByteSet -> ByteSet
difference = binary (\a b -> a .&. Bits.complement b)
complement :: ByteSet -> ByteSet
complement (ByteSet a) =
ByteSet $ amap Bits.complement a
word64ToList :: Word64 -> [Word8]
word64ToList x = filter (\n -> (x .&. ((1 :: Word64) `shiftL` (fromIntegral n))) /= 0) [0..63]
toList :: ByteSet -> [Word8]
toList (ByteSet a) =
word64ToList (a ! 0) ++ map (+ 64) (word64ToList (a ! 1)) ++ map (+ 128) (word64ToList (a ! 2)) ++ map (+ 196) (word64ToList (a ! 3))
fromList :: [Word8] -> ByteSet
fromList = foldl' union empty . map singleton
-- | Construct a ByteSet containing all the elements from a to b, inclusive.
range :: Word8 -> Word8 -> ByteSet
range a b = fromList [a..b]
member :: ByteSet -> Word8 -> Bool
member (ByteSet a) n = (a ! (n `shiftR` 6)) .&. (wordsArray ! (n .&. 63)) /= 0