word8set (empty) → 0.1
raw patch · 4 files changed
+824/−0 lines, 4 filesdep +QuickCheckdep +basedep +deepseq
Dependencies added: QuickCheck, base, deepseq, lattices, template-haskell, wide-word
Files
- CHANGELOG.md +3/−0
- LICENSE +30/−0
- src/Data/Word8Set.hs +745/−0
- word8set.cabal +46/−0
+ CHANGELOG.md view
@@ -0,0 +1,3 @@+## 0.1++* First version. Released on an unsuspecting world.
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright (c) 2023, Oleg Grenrus++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++ * Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.++ * Redistributions in binary form must reproduce the above+ copyright notice, this list of conditions and the following+ disclaimer in the documentation and/or other materials provided+ with the distribution.++ * Neither the name of Oleg Grenrus nor the names of other+ contributors may be used to endorse or promote products derived+ from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ src/Data/Word8Set.hs view
@@ -0,0 +1,745 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE TemplateHaskellQuotes #-}+{-# LANGUAGE Trustworthy #-}+{-# LANGUAGE TypeFamilies #-}+-- | The 'Word8Set' type represents a set of elements of type 'Word8'.+--+-- The interface of this module mimics the "Data.Set" and/or "Data.IntSet"+-- module interfaces from @containers package.+--+-- These module is intended to be imported qualified, to avoid name clashes with Prelude functions, e.g.+--+-- @+-- import Data.Word8Set (Word8Set)+-- import qualified Data.Word8Set as W8S+-- @+--+-- == Implementation+-- The implementation is based on 'Word256' type. 'Word8Set' is 256 bits.+--+module Data.Word8Set (+ -- * Set type+ Word8Set,+ Key,++ -- * Construction+ empty,+ full,+ singleton,+ range,++ -- * Insertion+ insert,++ -- * Deletion+ delete,++ -- * Generalized insertion/deletion+ alterF,++ -- * Query+ member,+ notMember,+ lookupLT,+ lookupGT,+ lookupLE,+ lookupGE,+ null,+ isFull,+ isSingleton,+ isRange,+ size,+ isSubsetOf,+ isProperSubsetOf,+ disjoint,++ -- * Combine+ union,+ unions,+ difference,+ (\\),+ intersection,+ complement,++ -- * Filter+ filter,+ partition,++ -- * Map+ map,++ -- * Folds+ foldr,+ foldl,++ -- ** Strict folds+ foldr',+ foldl',++ -- * Min\/Max+ findMin,+ findMax,+ deleteMin,+ deleteMax,+ maxView,+ minView,++ -- * Conversion+ -- ** to/fromList+ elems,+ toList,+ fromList,+ fromFoldable,++ -- ** to/from Word256+ toWord256,+ fromWord256,++ -- ** to/from ASCII Strings+ toASCII,+ fromASCII,+) where++import Prelude+ (Bool (..), Eq ((==)), Functor (fmap), Int, Maybe (..), Ord, Show (showsPrec), String, fromIntegral, fst, maybe, negate, not,+ otherwise, return, showParen, showString, snd, ($), (&&), (+), (-), (.), (/=), (<=), (>))++import Algebra.Lattice (BoundedJoinSemiLattice (..), BoundedMeetSemiLattice (..), Lattice (..))+import Control.DeepSeq (NFData (..))+import Data.Bits ((.&.), (.|.))+import Data.Char (chr, ord)+import Data.Monoid (Monoid (..))+import Data.Semigroup (Semigroup (..))+import Data.WideWord.Word256 (Word256 (..))+import Data.Word (Word8)+import Test.QuickCheck (Arbitrary (..), CoArbitrary (..), Function (..), functionMap)++import Language.Haskell.TH.Syntax (Lift (..))++import qualified Data.Bits as Bits+import qualified Data.Foldable as F+import qualified GHC.Exts++-- $setup+-- >>> import Prelude (even, (+), flip)++-------------------------------------------------------------------------------+-- Types+-------------------------------------------------------------------------------++-- | A set of 'Word8' numbers.+--+-- Implemented using 'Word256'.+newtype Word8Set = W8S Word256+ deriving (Eq, Ord)++-- | Key of 'Word8Set' is 'Word8'.+type Key = Word8++-------------------------------------------------------------------------------+-- Instances+-------------------------------------------------------------------------------++instance Show Word8Set where+ showsPrec d xs = showParen (d > 10) $ showString "fromList " . showsPrec 11 (toList xs)++instance NFData Word8Set where+ rnf (W8S xs) = rnf xs++instance Lift Word8Set where+ lift (W8S (Word256 a b c d)) =+ [| W8S (Word256 a b c d) |]++#if MIN_VERSION_template_haskell(2,16,0)+ liftTyped (W8S (Word256 a b c d)) =+ [|| W8S (Word256 a b c d) ||]+#endif++instance Semigroup Word8Set where+ (<>) = union++instance Monoid Word8Set where+ mempty = empty+ mappend = (<>)++instance Arbitrary Word8Set where+ arbitrary = do+ a <- arbitrary+ b <- arbitrary+ c <- arbitrary+ d <- arbitrary+ return (W8S (Word256 a b c d))++ shrink xs = fmap fromList (shrink (toList xs)) where++instance CoArbitrary Word8Set where+ coarbitrary (W8S (Word256 a b c d)) = coarbitrary (a,b,c,d)++instance Function Word8Set where+ function = functionMap from to where+ from (W8S (Word256 a b c d)) = (a, b, c, d)+ to (a,b,c,d) = W8S (Word256 a b c d)++instance Lattice Word8Set where+ (\/) = union+ (/\) = intersection++instance BoundedJoinSemiLattice Word8Set where+ bottom = empty++instance BoundedMeetSemiLattice Word8Set where+ top = full++instance GHC.Exts.IsList Word8Set where+ type Item Word8Set = Key+ fromList = fromList+ toList = toList++-------------------------------------------------------------------------------+-- Construction+-------------------------------------------------------------------------------++-- | The empty set.+--+-- >>> empty+-- fromList []+--+empty :: Word8Set+empty = W8S Bits.zeroBits++-- | The full set.+--+-- >>> full+-- fromList [0,1,2,3,4,5,6,7,8,9,10,11,12,...,255]+--+full :: Word8Set+full = W8S ones++ones :: Word256+ones = Bits.complement Bits.zeroBits++-- | A set of one element.+--+-- >>> singleton 127+-- fromList [127]+--+singleton :: Key -> Word8Set+singleton x = W8S (Bits.bit (fromIntegral x))++-- | A set of inclusive range.+--+-- >>> range 10 20+-- fromList [10,11,12,13,14,15,16,17,18,19,20]+--+range :: Key -> Key -> Word8Set+range mi ma+ | mi <= ma = W8S $ Bits.shiftL (Bits.shiftR ones (fromIntegral (negate (1 + ma - mi)))) (fromIntegral mi)+ | otherwise = empty++-------------------------------------------------------------------------------+-- Insertion+-------------------------------------------------------------------------------++-- | Add a value to the set.+--+-- >>> insert 10 (range 15 20)+-- fromList [10,15,16,17,18,19,20]+--+-- >>> insert 10 (range 10 15)+-- fromList [10,11,12,13,14,15]+--+insert :: Key -> Word8Set -> Word8Set+insert x (W8S xs) = W8S (Bits.setBit xs (fromIntegral x))++-------------------------------------------------------------------------------+-- Deletion+-------------------------------------------------------------------------------++-- | Delete a value in the set. Returns the original set when the value was not present.+--+-- >>> delete 10 (range 5 15)+-- fromList [5,6,7,8,9,11,12,13,14,15]+--+-- >>> delete 10 (range 1 10)+-- fromList [1,2,3,4,5,6,7,8,9]+--+delete :: Key -> Word8Set -> Word8Set+delete x (W8S xs) = W8S (Bits.clearBit xs (fromIntegral x))++-------------------------------------------------------------------------------+-- Generalized insertion/deletion+-------------------------------------------------------------------------------++-- | Generalized insetion deletion.+alterF :: Functor f => (Bool -> f Bool) -> Key -> Word8Set -> f Word8Set+alterF f x xs+ | member x xs = fmap (\b -> if b then xs else delete x xs) (f True)+ | otherwise = fmap (\b -> if b then insert x xs else xs) (f False)++-------------------------------------------------------------------------------+-- Query+-------------------------------------------------------------------------------++-- | Is the set empty?+--+-- >>> null empty+-- True+--+-- >>> null (range 10 20)+-- False+--+null :: Word8Set -> Bool+null (W8S xs) = xs == Bits.zeroBits++-- | Is the set full?+--+-- >>> isFull full+-- True+--+-- >>> isFull (range 1 255)+-- False+--+isFull :: Word8Set -> Bool+isFull (W8S xs) = xs == ones++-- | Cardinality of the set.+--+-- >>> size empty+-- 0+--+-- >>> size (union (range 10 20) (range 30 40))+-- 22+--+size :: Word8Set -> Int+size (W8S xs) = Bits.popCount xs++-- | Is the value a member of the set?+--+-- >>> member 5 (range 10 20)+-- False+--+-- >>> member 15 (range 10 20)+-- True+--+member :: Key -> Word8Set -> Bool+member x (W8S xs) = Bits.testBit xs (fromIntegral x)++-- | Is the element not in the set?+--+-- >>> notMember 5 (range 10 20)+-- True+--+-- >>> notMember 15 (range 10 20)+-- False+--+notMember :: Key -> Word8Set -> Bool+notMember x xs = not (member x xs)++-- | Is this a subset? @(s1 `isSubsetOf` s2)@ tells whether s1 is a subset of s2.+--+-- >>> isSubsetOf (range 10 20) (range 5 25)+-- True+--+-- >>> isSubsetOf (range 10 20) (range 10 20)+-- True+--+-- >>> isSubsetOf (range 5 25) (range 10 20)+-- False+--+isSubsetOf :: Word8Set -> Word8Set -> Bool+isSubsetOf a b = b == union a b++-- | Is this a proper subset? Is this a proper subset? (ie. a subset but not equal).+--+-- >>> isProperSubsetOf (range 10 20) (range 5 25)+-- True+--+-- >>> isProperSubsetOf (range 10 20) (range 10 20)+-- False+--+-- >>> isProperSubsetOf (range 5 25) (range 10 20)+-- False+--+isProperSubsetOf :: Word8Set -> Word8Set -> Bool+isProperSubsetOf a b = b == union a b && a /= b++-- | Is set singleton?+--+-- >>> isSingleton empty+-- Nothing+--+-- >>> isSingleton full+-- Nothing+--+-- >>> isSingleton (singleton 5)+-- Just 5+--+-- >>> isSingleton (fromList [3, 5])+-- Nothing+--+isSingleton :: Word8Set -> Maybe Key+isSingleton (W8S ws)+ | Bits.popCount ws /= 1 = Nothing+ | otherwise = Just (fromIntegral (ctz ws))++-- | Is set of the form @'range' l r@?+--+-- >>> isRange empty+-- Nothing+--+-- >>> isRange full+-- Just (0,255)+--+-- >>> isRange (singleton 5)+-- Just (5,5)+--+-- >>> isRange (range 10 20)+-- Just (10,20)+--+-- >>> isRange (fromList [3, 5])+-- Nothing+--+isRange :: Word8Set -> Maybe (Key, Key)+isRange (W8S 0) = Nothing+isRange (W8S ws) = if Bits.popCount ws + l + r == 256 then Just (fromIntegral l, fromIntegral (255 - r)) else Nothing+ where+ r = clz ws+ l = ctz ws++-- | Check whether two sets are disjoint (i.e. their intersection is empty).+--+-- >>> disjoint (range 11 20) (range 21 30)+-- True+--+disjoint :: Word8Set -> Word8Set -> Bool+disjoint xs ys = intersection xs ys == empty++-- | Find largest element smaller than the given one.+--+-- >>> lookupLT 3 (fromList [3, 5])+-- Nothing+-- >>> lookupLT 5 (fromList [3, 5])+-- Just 3+--+-- >>> lookupLT 0 full+-- Nothing+lookupLT :: Key -> Word8Set -> Maybe Key+lookupLT 0 _ = Nothing+lookupLT x xs = lookupLE (x - 1) xs++-- | Find smallest element greater than the given one.+--+-- >>> lookupGT 4 (fromList [3, 5])+-- Just 5+--+-- >>> lookupGT 5 (fromList [3, 5])+-- Nothing+--+-- >>> lookupGT 255 full+-- Nothing+--+lookupGT :: Key -> Word8Set -> Maybe Key+lookupGT 255 _ = Nothing+lookupGT x xs = lookupGE (x + 1) xs++-- | Find largest element smaller or equal to the given one.+--+-- >>> lookupLE 2 (fromList [3, 5])+-- Nothing+--+-- >>> lookupLE 4 (fromList [3, 5])+-- Just 3+--+-- >>> lookupLE 5 (fromList [3, 5])+-- Just 5+--+lookupLE :: Key -> Word8Set -> Maybe Key+lookupLE x xs = fmap fst (maxView (intersection xs (range 0 x)))++-- | Find smallest element greater or equal to the given one.+--+-- >>> lookupGE 3 (fromList [3, 5])+-- Just 3+--+-- >>> lookupGE 4 (fromList [3, 5])+-- Just 5+--+-- >>> lookupGE 6 (fromList [3, 5])+-- Nothing+--+lookupGE :: Key -> Word8Set -> Maybe Key+lookupGE x xs = fmap fst (minView (intersection xs (range x 255)))++-------------------------------------------------------------------------------+-- Combine+-------------------------------------------------------------------------------++-- | The complement of the set.+complement :: Word8Set -> Word8Set+complement (W8S xs) = W8S (Bits.complement xs)++-- | The union of two sets.+union :: Word8Set -> Word8Set -> Word8Set+union (W8S xs) (W8S ys) = W8S (xs .|. ys)++-- | The union of a list of sets.+unions :: F.Foldable f => f Word8Set -> Word8Set+unions xs = F.foldl' union empty xs++-- | The intersection between two sets.+intersection :: Word8Set -> Word8Set -> Word8Set+intersection (W8S xs) (W8S ys) = W8S (xs .&. ys)++-- | Difference between two sets.+difference :: Word8Set -> Word8Set -> Word8Set+difference xs ys = intersection xs (complement ys)++-- | See 'difference'.+(\\) :: Word8Set -> Word8Set -> Word8Set+m1 \\ m2 = difference m1 m2++-------------------------------------------------------------------------------+-- Filter+-------------------------------------------------------------------------------++-- | Filter all elements that satisfy some predicate.+--+-- >>> filter even (range 10 20)+-- fromList [10,12,14,16,18,20]+--+filter :: (Key -> Bool) -> Word8Set -> Word8Set+filter p = foldl' (\acc x -> if p x then insert x acc else acc) empty++-- | Partition the set according to some predicate.+--+-- >>> partition even (range 10 20)+-- (fromList [10,12,14,16,18,20],fromList [11,13,15,17,19])+--+partition :: (Key -> Bool) -> Word8Set -> (Word8Set,Word8Set)+partition p = foldl' (\(l, r) x -> if p x then (insert x l, r) else (l, insert x r)) (empty, empty)++-------------------------------------------------------------------------------+-- Map+-------------------------------------------------------------------------------++-- | @'map' f s@ is the set obtained by applying @f@ to each element of @s@.+--+-- >>> map (+ 1) (fromList [0, 10, 250, 255])+-- fromList [0,1,11,251]+--+map :: (Key -> Key) -> Word8Set -> Word8Set+map f = foldl' (\acc k -> insert (f k) acc) empty++-------------------------------------------------------------------------------+-- Folds+-------------------------------------------------------------------------------++-- | Lazy right fold.+--+-- >>> foldr (:) [] (unions [range 10 20, range 70 73, range 130 132, range 200 202, singleton 255])+-- [10,11,12,13,14,15,16,17,18,19,20,70,71,72,73,130,131,132,200,201,202,255]+--+foldr :: (Key -> b -> b) -> b -> Word8Set -> b+foldr f z0 (W8S (Word256 a0 b0 c0 d0)) = go0 a0 b0 c0 d0 z0 where+ go0 0 !b !c !d acc = go1 b c d acc+ go0 a b c d acc = let !x = clz a in go0 (Bits.clearBit a (63 - x)) b c d (f (255 - fromIntegral x) acc)++ go1 0 !c d acc = go2 c d acc+ go1 b c d acc = let !x = clz b in go1 (Bits.clearBit b (63 - x)) c d (f (191 - fromIntegral x) acc)++ go2 0 !d acc = go3 d acc+ go2 c d acc = let !x = clz c in go2 (Bits.clearBit c (63 - x)) d (f (127 - fromIntegral x) acc)++ go3 0 acc = acc+ go3 a acc = let !x = clz a in go3 (Bits.clearBit a (63 - x)) (f (63 - fromIntegral x) acc)++-- | Strict right fold.+--+foldr' :: (Key -> b -> b) -> b -> Word8Set -> b+foldr' f z0 (W8S (Word256 a0 b0 c0 d0)) = go0 a0 b0 c0 d0 z0 where+ go0 0 !b !c !d !acc = go1 b c d acc+ go0 a b c d acc = let !x = clz a in go0 (Bits.clearBit a (63 - x)) b c d (f (255 - fromIntegral x) acc)++ go1 0 !c d !acc = go2 c d acc+ go1 b c d acc = let !x = clz b in go1 (Bits.clearBit b (63 - x)) c d (f (191 - fromIntegral x) acc)++ go2 0 !d !acc = go3 d acc+ go2 c d acc = let !x = clz c in go2 (Bits.clearBit c (63 - x)) d (f (127 - fromIntegral x) acc)++ go3 0 !acc = acc+ go3 a acc = let !x = clz a in go3 (Bits.clearBit a (63 - x)) (f (63 - fromIntegral x) acc)++-- | Lazy left fold.+--+-- >>> foldl (flip (:)) [] (unions [range 10 20, range 70 73, range 130 132, range 200 202, singleton 255])+-- [255,202,201,200,132,131,130,73,72,71,70,20,19,18,17,16,15,14,13,12,11,10]+--+foldl :: (a -> Key -> a) -> a -> Word8Set -> a+foldl f z0 (W8S (Word256 a0 b0 c0 d0)) = go0 a0 b0 c0 d0 z0 where+ go0 !a !b !c 0 acc = go1 a b c acc+ go0 a b c d acc = let !x = ctz d in go0 a b c (Bits.clearBit d x) (f acc (fromIntegral x))++ go1 !a !b 0 acc = go2 a b acc+ go1 a b c acc = let !x = ctz c in go1 a b (Bits.clearBit c x) (f acc (fromIntegral x + 64))++ go2 !a 0 acc = go3 a acc+ go2 a b acc = let !x = ctz b in go2 a (Bits.clearBit b x) (f acc (fromIntegral x + 128))++ go3 0 acc = acc+ go3 a acc = let !x = ctz a in go3 (Bits.clearBit a x) (f acc (fromIntegral x + 192))++-- | Strict left fold.+--+foldl' :: (a -> Key -> a) -> a -> Word8Set -> a+foldl' f z0 (W8S (Word256 a0 b0 c0 d0)) = go0 a0 b0 c0 d0 z0 where+ go0 !a !b !c 0 !acc = go1 a b c acc+ go0 a b c d acc = let !x = ctz d in go0 a b c (Bits.clearBit d x) (f acc (fromIntegral x))++ go1 !a !b 0 !acc = go2 a b acc+ go1 a b c acc = let !x = ctz c in go1 a b (Bits.clearBit c x) (f acc (fromIntegral x + 64))++ go2 !a 0 !acc = go3 a acc+ go2 a b acc = let !x = ctz b in go2 a (Bits.clearBit b x) (f acc (fromIntegral x + 128))++ go3 0 !acc = acc+ go3 a acc = let !x = ctz a in go3 (Bits.clearBit a x) (f acc (fromIntegral x + 192))++-------------------------------------------------------------------------------+-- Min/Max+-------------------------------------------------------------------------------++-- | The minimal element of the set.+--+-- >>> findMin (fromList [3, 5])+-- 3+--+-- Returns 0 for empty set.+--+-- >>> findMin empty+-- 0+--+findMin :: Word8Set -> Word8+findMin (W8S xs) = fromIntegral (ctz xs)++-- | The maximal element of the set.+--+-- >>> findMax (fromList [3, 5])+-- 5+--+-- Returns 255 for empty set.+--+-- >>> findMax empty+-- 255+--+findMax :: Word8Set -> Word8+findMax (W8S xs) = fromIntegral (255 - clz xs)++-- | Delete the minimal element. Returns an empty set if the set is empty.+deleteMin :: Word8Set -> Word8Set+deleteMin = maybe empty snd . minView++-- | Delete the maximal element. Returns an empty set if the set is empty.+deleteMax :: Word8Set -> Word8Set+deleteMax = maybe empty snd . minView++-- | Retrieves the maximal key of the set, and the set+-- stripped of that element, or 'Nothing' if passed an empty set.+--+-- >>> maxView (fromList [3, 5])+-- Just (5,fromList [3])+--+-- >>> maxView empty+-- Nothing+--+maxView :: Word8Set -> Maybe (Key, Word8Set)+maxView xs+ | null xs = Nothing+ | otherwise = let !x = findMax xs in Just (x, delete x xs)++-- | Retrieves the minimal key of the set, and the set+-- stripped of that element, or 'Nothing' if passed an empty set.+--+-- >>> minView (fromList [3, 5])+-- Just (3,fromList [5])+--+-- >>> minView empty+-- Nothing+--+minView :: Word8Set -> Maybe (Key, Word8Set)+minView xs+ | null xs = Nothing+ | otherwise = let !x = findMin xs in Just (x, delete x xs)++-------------------------------------------------------------------------------+-- List+-------------------------------------------------------------------------------++-- | The elements of a set in ascending order.+elems :: Word8Set -> [Key]+elems = toList++-- | The elements of a set in ascending order.+toList :: Word8Set -> [Key]+toList xs = GHC.Exts.build (\c n -> foldr c n xs)++-- | Create a set from a list of 'Word8's.+fromList :: [Key] -> Word8Set+fromList w8s = F.foldl' (\acc x -> insert x acc) empty w8s++-- | Create a set from a foldable of 'Word8's.+fromFoldable :: F.Foldable f => f Key -> Word8Set+#if MIN_VERSION_base(4,13,0)+fromFoldable = F.foldMap' singleton+#else+fromFoldable = F.foldl' (\acc x -> insert x acc) empty+#endif++-------------------------------------------------------------------------------+-- Word256+-------------------------------------------------------------------------------++-- | Convert set to 'Word256'.+toWord256 :: Word8Set -> Word256+toWord256 (W8S xs) = xs++-- | Create set from 'Word256'.+fromWord256 :: Word256 -> Word8Set+fromWord256 = W8S++-------------------------------------------------------------------------------+-- ASCII+-------------------------------------------------------------------------------++-- | Create ASCII string from a set.+--+-- >>> toASCII (range 100 120)+-- "defghijklmnopqrstuvwx"+--+toASCII :: Word8Set -> String+toASCII = fmap (chr . fromIntegral) . toList++-- | Create set from ASCII string.+--+-- >>> fromASCII "foobar"+-- fromList [97,98,102,111,114]+--+-- Non-ASCII codepoints are truncated:+--+-- >>> fromASCII "\1000"+-- fromList [232]+--+fromASCII :: String -> Word8Set+fromASCII = fromList . fmap (fromIntegral . ord)++-------------------------------------------------------------------------------+-- Helpers+-------------------------------------------------------------------------------++clz :: Bits.FiniteBits a => a -> Int+clz = Bits.countLeadingZeros+{-# INLINE clz #-}++ctz :: Bits.FiniteBits a => a -> Int+ctz = Bits.countTrailingZeros+{-# INLINE ctz #-}
+ word8set.cabal view
@@ -0,0 +1,46 @@+cabal-version: 3.0+name: word8set+version: 0.1+synopsis: Word8 set+description: Set of Word8 numbers. Backed up by Word256.+category: Data+author: Oleg Grenrus <oleg.grenrus@iki.fi>+maintainer: Oleg Grenrus <oleg.grenrus@iki.fi>+homepage: https://github.com/phadej/word8set+bug-reports: https://github.com/phadej/word8set/issues+license: BSD-3-Clause+license-file: LICENSE+build-type: Simple+extra-source-files: CHANGELOG.md+tested-with:+ GHC ==8.0.2+ || ==8.2.2+ || ==8.4.4+ || ==8.6.5+ || ==8.8.4+ || ==8.10.7+ || ==9.0.2+ || ==9.2.7+ || ==9.4.5+ || ==9.6.1++source-repository head+ type: git+ location: https://github.com/phadej/word8set.git++library+ default-language: Haskell2010+ hs-source-dirs: src+ exposed-modules: Data.Word8Set++ -- boot libraries+ build-depends:+ , base >=4.9 && <4.19+ , deepseq >=1.4.2.0 && <1.5+ , template-haskell >=2.11 && <2.21++ -- other dependencies+ build-depends:+ , lattices ^>=2.2+ , QuickCheck ^>=2.14.2+ , wide-word ^>=0.1.5.0