enumset 0.0.1 → 0.0.2
raw patch · 4 files changed
+223/−12 lines, 4 filesdep +data-accessorPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
Dependencies added: data-accessor
API changes (from Hackage documentation)
- Data.EnumSet: instance (Storable word, Enum enum) => Storable (T word enum)
- Data.EnumSet: instance Eq word => Eq (T word enum)
+ Data.EnumSet: (.-.) :: (Enum a, Bits w) => T w a -> T w a -> T w a
+ Data.EnumSet: accessor :: (Enum a, Bits w) => a -> T (T w a) Bool
+ Data.EnumSet: disjoint :: (Enum a, Bits w) => T w a -> T w a -> Bool
+ Data.EnumSet: instance (Enum a, Bits w) => Monoid (T w a)
+ Data.EnumSet: instance (Enum a, Storable w) => Storable (T w a)
+ Data.EnumSet: instance Eq word => Eq (T word index)
+ Data.EnumSet: mostSignificantPosition :: (Bits w, Storable w) => T w a -> Int
+ Data.EnumSet: singleton :: (Enum a, Bits w) => a -> T w a
+ Data.EnumSet: singletonByPosition :: Bits w => Int -> T w a
+ Data.FlagSet: Cons :: word -> T word a
+ Data.FlagSet: Mask :: w -> Mask w a b
+ Data.FlagSet: MaskedValue :: w -> w -> MaskedValue w a
+ Data.FlagSet: Value :: w -> Value w b
+ Data.FlagSet: accessor :: (Enum a, Bits w) => Mask w a b -> T (T w a) (Value w b)
+ Data.FlagSet: class Enum a
+ Data.FlagSet: compose :: (Enum a, Enum a, Bits w) => [a] -> T w a
+ Data.FlagSet: data MaskedValue w a
+ Data.FlagSet: decompose :: (Bounded a, Enum a, Enum a, Bits w) => T w a -> [a]
+ Data.FlagSet: decons :: T word a -> word
+ Data.FlagSet: fromEnum :: (Enum a, Bits w) => a -> MaskedValue w a
+ Data.FlagSet: fromMaskedValue :: MaskedValue w a -> T w a
+ Data.FlagSet: get :: (Enum a, Bits w) => Mask w a b -> T w a -> Value w b
+ Data.FlagSet: instance Bits w => Monoid (MaskedValue w a)
+ Data.FlagSet: instance Eq w => Eq (Mask w a b)
+ Data.FlagSet: instance Eq w => Eq (MaskedValue w a)
+ Data.FlagSet: instance Eq w => Eq (Value w b)
+ Data.FlagSet: instance Eq word => Eq (T word a)
+ Data.FlagSet: instance Show w => Show (Mask w a b)
+ Data.FlagSet: instance Show w => Show (MaskedValue w a)
+ Data.FlagSet: instance Show w => Show (Value w b)
+ Data.FlagSet: instance Storable w => Storable (T w a)
+ Data.FlagSet: maskValue :: Mask w a b -> Value w b -> MaskedValue w a
+ Data.FlagSet: match :: Bits w => T w a -> MaskedValue w a -> Bool
+ Data.FlagSet: newtype Mask w a b
+ Data.FlagSet: newtype T word a
+ Data.FlagSet: newtype Value w b
+ Data.FlagSet: put :: (Enum a, Bits w) => Mask w a b -> Value w b -> T w a -> T w a
+ Data.FlagSet: unmask :: Mask w a b -> w
+ Data.FlagSet: unvalue :: Value w b -> w
- Data.EnumSet: Cons :: word -> T word enum
+ Data.EnumSet: Cons :: word -> T word index
- Data.EnumSet: decons :: T word enum -> word
+ Data.EnumSet: decons :: T word index -> word
- Data.EnumSet: newtype T word enum
+ Data.EnumSet: newtype T word index
Files
- enumset.cabal +9/−6
- src/Data/EnumSet.hs +68/−5
- src/Data/EnumSet/PackedEnum.hs +4/−1
- src/Data/FlagSet.hs +142/−0
enumset.cabal view
@@ -1,5 +1,6 @@+-- would also be useful as type-safe alternative in wx, wxcore Name: enumset-Version: 0.0.1+Version: 0.0.2 License: BSD3 License-File: LICENSE Author: Henning Thielemann <haskell@henning-thielemann.de>@@ -14,17 +15,16 @@ represents a flag set stored in a Word16 that supports the flags @LT@, @EQ@, @GT@. .- This package is similar to the @bitset@ package- the @Data.Edison.Coll.EnumSet@ module in the edison package,+ This package is similar to the @bitset@ package and+ the @Data.Edison.Coll.EnumSet@ module in the @edison@ package, however our implementation allows you to choose the embedding type and thus the maximum size of the set.--- Portability: Haskell98-Cabal-Version: >=1.6+Cabal-Version: >=1.10 Tested-With: GHC==6.10.4, GHC==6.12.3 Build-Type: Simple Source-Repository this- Tag: 0.0.1+ Tag: 0.0.2 Type: darcs Location: http://code.haskell.org/~thielema/enumset/ @@ -33,7 +33,9 @@ Location: http://code.haskell.org/~thielema/enumset/ Library+ Default-Language: Haskell98 Build-Depends:+ data-accessor >=0.2.1 && <0.3, storable-record >=0.0.1 && <0.1, base >= 4 && <5 @@ -42,3 +44,4 @@ Exposed-Modules: Data.EnumSet Data.EnumSet.PackedEnum+ Data.FlagSet
src/Data/EnumSet.hs view
@@ -2,6 +2,9 @@ Similar to Data.Edison.Coll.EnumSet but it allows to choose the underlying type for bit storage. This is really a low-level module for type-safe foreign function interfaces.++The integer representation of the enumeration type+is the bit position of the flag within the bitvector. -} module Data.EnumSet ( T(Cons, decons),@@ -9,14 +12,20 @@ fromEnums, toEnums, intToEnums,+ mostSignificantPosition,+ singletonByPosition, null, empty,+ singleton,+ disjoint, (.&.),+ (.-.), (.|.), xor, unions, get, put,+ accessor, set, clear, flip,@@ -26,23 +35,36 @@ import qualified Data.Bits as B import Data.Bits (Bits, ) +import Data.Monoid (Monoid(mempty, mappend), )+ import qualified Foreign.Storable.Newtype as Store-import Foreign.Storable (Storable(..), )+import Foreign.Storable (Storable(sizeOf, alignment, peek, poke), ) +import qualified Data.Accessor.Basic as Acc+ import qualified Prelude as P import Prelude hiding (fromEnum, toEnum, null, flip, ) -newtype T word enum = Cons {decons :: word}+newtype T word index = Cons {decons :: word} deriving (Eq) -instance (Storable word, Enum enum) => Storable (T word enum) where+instance (Enum a, Storable w) => Storable (T w a) where sizeOf = Store.sizeOf decons alignment = Store.alignment decons peek = Store.peek Cons poke = Store.poke decons +{- |+Since this data type is intended for constructing flags,+we choose the set union as mappend.+For intersection we would also not have a canonical identity element.+-}+instance (Enum a, Bits w) => Monoid (T w a) where+ mempty = empty+ mappend = (.|.) + fromEnum :: (Enum a, Bits w) => a -> T w a fromEnum = Cons . B.bit . P.fromEnum @@ -62,24 +84,59 @@ decons +{- |+floor of binary logarithm -+Intended for getting the position of a single set bit.+This in turn is intended for implementing an 'Enum' instance+if you only know masks but no bit positions.+-}+{-# INLINE mostSignificantPosition #-}+mostSignificantPosition :: (Bits w, Storable w) => T w a -> Int+mostSignificantPosition (Cons x) =+ snd $+ foldl+ (\(x0,pos) testPos ->+ let x1 = B.shiftR x0 testPos+ in if x1 == 0+ then (x0, pos)+ else (x1, pos+testPos))+ (x,0) $+ reverse $+ takeWhile (< sizeOf x * 8) $+ iterate (2*) 1++{- |+set a bit -+Intended for implementing an 'Enum' instance+if you only know masks but no bit positions.+-}+{-# INLINE singletonByPosition #-}+singletonByPosition :: (Bits w) => Int -> T w a+singletonByPosition = Cons . B.setBit 0++ null :: (Enum a, Bits w) => T w a -> Bool null (Cons x) = x==0 empty :: (Enum a, Bits w) => T w a empty = Cons 0 +disjoint :: (Enum a, Bits w) => T w a -> T w a -> Bool+disjoint x y = null (x .&. y) + {-# INLINE lift2 #-} lift2 :: (w -> w -> w) -> (T w a -> T w a -> T w a) lift2 f (Cons x) (Cons y) = Cons (f x y) -- fixities like in Data.Bits-infixl 7 .&.+infixl 7 .&., .-. infixl 5 .|. -(.&.), (.|.), xor :: (Enum a, Bits w) => T w a -> T w a -> T w a+(.&.), (.-.), (.|.), xor :: (Enum a, Bits w) => T w a -> T w a -> T w a (.&.) = lift2 (B..&.) (.|.) = lift2 (B..|.)+(.-.) = lift2 (\x y -> x B..&. B.complement y) xor = lift2 B.xor unions :: (Enum a, Bits w) => [T w a] -> T w a@@ -93,12 +150,18 @@ put n b s = fromBool n b .|. clear n s +accessor :: (Enum a, Bits w) => a -> Acc.T (T w a) Bool+accessor x = Acc.fromSetGet (put x) (get x) + {-# INLINE lift1 #-} lift1 :: (Enum a, Bits w) => (w -> Int -> w) -> (a -> T w a -> T w a) lift1 f n (Cons vec) = Cons (f vec (P.fromEnum n))++singleton :: (Enum a, Bits w) => a -> T w a+singleton = P.flip set empty set :: (Enum a, Bits w) => a -> T w a -> T w a set = lift1 B.setBit
src/Data/EnumSet/PackedEnum.hs view
@@ -1,7 +1,10 @@ {- | Extract and inject an Enum value into an EnumSet. -}-module Data.EnumSet.PackedEnum (T(Cons), unpack, pack, clear, put, ) where+module Data.EnumSet.PackedEnum+ {-# DEPRECATED "use Data.FlagSet instead" #-}+ (T(Cons), unpack, pack, clear, put, )+ where import qualified Data.EnumSet as ES
+ src/Data/FlagSet.hs view
@@ -0,0 +1,142 @@+{- |+A bit vector that represents a record in a bit-packed way.+-}+module Data.FlagSet (+ T(Cons, decons),+ fromMaskedValue, match,+ Enum(fromEnum),+ compose, decompose,+ Mask(Mask, unmask), maskValue,+ Value(Value, unvalue),+ MaskedValue(MaskedValue),+ get, put, accessor,+ ) where++import qualified Data.Bits as B+import Data.Bits (Bits, (.&.), (.|.), )++import Data.Monoid (Monoid(mempty, mappend, mconcat), )++import qualified Foreign.Storable.Newtype as Store+import Foreign.Storable (Storable(sizeOf, alignment, peek, poke), )++import qualified Data.Accessor.Basic as Acc++import qualified Prelude as P+import Prelude hiding (Enum, fromEnum, toEnum, null, flip, )+++{- |+The basic bit vector data type.+It does not provide a lot of functionality,+since that could not be done in a safe way.++The type @a@ identifies the maintained flags.+It may be an empty type+but it may also be an enumeration+of record fields with concrete values.+In the latter case you are encouraged to define an 'Enum' instance+for this enumeration.+Be aware that it is different from 'P.Enum' of Prelude.+-}+newtype T word a = Cons {decons :: word}+ deriving (Eq)++instance (Storable w) => Storable (T w a) where+ sizeOf = Store.sizeOf decons+ alignment = Store.alignment decons+ peek = Store.peek Cons+ poke = Store.poke decons+++{- |+@Mask w a b@ describes a field of a @T w a@ that has type @Value w b@.+On the machine level a 'Mask' value is a vector of bits,+where set bits represent the bits belonging to one record field.+There must be only one mask value for every pair of types @(a,b)@.+-}+newtype Mask w a b = Mask {unmask :: w}+ deriving (Eq, Show)++newtype Value w b = Value {unvalue :: w}+ deriving (Eq, Show)+++get :: (Enum a, Bits w) => Mask w a b -> T w a -> Value w b+get (Mask m) (Cons fs) = Value (m .&. fs)++put :: (Enum a, Bits w) => Mask w a b -> Value w b -> T w a -> T w a+put (Mask m) (Value v) (Cons fs) =+ Cons $ (fs .-. m) .|. v++accessor :: (Enum a, Bits w) => Mask w a b -> Acc.T (T w a) (Value w b)+accessor m = Acc.fromSetGet (put m) (get m)++++{- |+Combines a mask with a value, that matches this mask.+In @MaskedValue mask value@, @value@ must be a subset of @mask@.+-}+data MaskedValue w a = MaskedValue w w+ deriving (Eq, Show)+++fromMaskedValue :: MaskedValue w a -> T w a+fromMaskedValue (MaskedValue _m v) = Cons v++match :: (Bits w) => T w a -> MaskedValue w a -> Bool+match (Cons fs) (MaskedValue m v) =+ m .&. fs == v+++maskValue :: Mask w a b -> Value w b -> MaskedValue w a+maskValue (Mask m) (Value v) = MaskedValue m v+++{- |+@mappend a b@ means that values stored in @b@ overwrite corresponding values in @a@.+-}+instance (Bits w) => Monoid (MaskedValue w a) where+ mempty = MaskedValue 0 0+ mappend (MaskedValue mx vx) (MaskedValue my vy) =+ MaskedValue (mx .|. my) (vx .-. my .|. vy)+++class Enum a where+ {- |+ 'P.fromEnum' should return an integer+ that represents the position of the @a@ value+ in the list of all enumeration items.+ In contrast to that,+ 'fromEnum' must return the according bit pattern.+ -}+ fromEnum :: (Bits w) => a -> MaskedValue w a++{- |+Decompose a flag set into flags.+The flags are generated using the 'Bounded' and 'Enum' instance.+We do not recommend to use the result list for further processing,+since testing of flags is much faster using 'match'.+However you may find it useful to 'show' the list.+-}+decompose :: (Bounded a, Enum a, P.Enum a, Bits w) => T w a -> [a]+decompose x =+ filter (match x . fromEnum) [minBound .. maxBound]++{- |+Compose a flag set from a list of flags.+However you may prefer to assemble flags+using 'mconcat' or 'mappend' on 'MaskedValue's.+-}+compose :: (Enum a, P.Enum a, Bits w) => [a] -> T w a+compose xs =+ fromMaskedValue $ mconcat $ map fromEnum xs++++-- fixity like .&.+infixl 7 .-.++(.-.) :: (Bits w) => w -> w -> w+x .-. y = x .&. B.complement y