foundation (empty) → 0.0.1
raw patch · 71 files changed
+9475/−0 lines, 71 filesdep +QuickCheckdep +Win32dep +basesetup-changed
Dependencies added: QuickCheck, Win32, base, criterion, foundation, ghc-prim, mtl, tasty, tasty-hunit, tasty-quickcheck
Files
- Foundation.hs +178/−0
- Foundation/Array.hs +30/−0
- Foundation/Array/Bitmap.hs +435/−0
- Foundation/Array/Boxed.hs +607/−0
- Foundation/Array/Common.hs +46/−0
- Foundation/Array/Internal.hs +20/−0
- Foundation/Array/Unboxed.hs +807/−0
- Foundation/Array/Unboxed/Builder.hs +61/−0
- Foundation/Array/Unboxed/ByteArray.hs +37/−0
- Foundation/Array/Unboxed/Mutable.hs +212/−0
- Foundation/Collection.hs +32/−0
- Foundation/Collection/Element.hs +17/−0
- Foundation/Collection/Foldable.hs +56/−0
- Foundation/Collection/Indexed.hs +42/−0
- Foundation/Collection/InnerFunctor.hs +19/−0
- Foundation/Collection/Keyed.hs +26/−0
- Foundation/Collection/List.hs +60/−0
- Foundation/Collection/Mutable.hs +52/−0
- Foundation/Collection/Sequential.hs +171/−0
- Foundation/Collection/Zippable.hs +278/−0
- Foundation/Convertible.hs +24/−0
- Foundation/Foreign.hs +16/−0
- Foundation/Foreign/MemoryMap.hs +18/−0
- Foundation/Foreign/MemoryMap/Posix.hsc +251/−0
- Foundation/Foreign/MemoryMap/Types.hs +34/−0
- Foundation/Foreign/MemoryMap/Windows.hs +27/−0
- Foundation/IO.hs +25/−0
- Foundation/IO/File.hs +147/−0
- Foundation/IO/FileMap.hs +59/−0
- Foundation/IO/Terminal.hs +23/−0
- Foundation/Internal/Base.hs +74/−0
- Foundation/Internal/Identity.hs +37/−0
- Foundation/Internal/IsList.hs +36/−0
- Foundation/Internal/MonadTrans.hs +49/−0
- Foundation/Internal/PrimTypes.hs +28/−0
- Foundation/Internal/Primitive.hs +144/−0
- Foundation/Internal/Proxy.hs +32/−0
- Foundation/Internal/Types.hs +87/−0
- Foundation/Number.hs +387/−0
- Foundation/Partial.hs +80/−0
- Foundation/Primitive.hs +19/−0
- Foundation/Primitive/FinalPtr.hs +85/−0
- Foundation/Primitive/Monad.hs +117/−0
- Foundation/Primitive/Types.hs +281/−0
- Foundation/Primitive/Utils.hs +72/−0
- Foundation/Strict.hs +37/−0
- Foundation/String.hs +35/−0
- Foundation/String/Encoding/ASCII7.hs +86/−0
- Foundation/String/Encoding/Encoding.hs +102/−0
- Foundation/String/Encoding/ISO_8859_1.hs +62/−0
- Foundation/String/Encoding/UTF16.hs +95/−0
- Foundation/String/Encoding/UTF32.hs +53/−0
- Foundation/String/Internal.hs +10/−0
- Foundation/String/ModifiedUTF8.hs +81/−0
- Foundation/String/UTF8.hs +962/−0
- Foundation/String/UTF8Table.hs +83/−0
- Foundation/System/Info.hs +138/−0
- Foundation/Tuple.hs +98/−0
- Foundation/VFS.hs +32/−0
- Foundation/VFS/FilePath.hs +256/−0
- Foundation/VFS/Path.hs +141/−0
- Foundation/VFS/URI.hs +38/−0
- LICENSE +27/−0
- README.md +65/−0
- Setup.hs +2/−0
- benchs/Array.hs +16/−0
- benchs/ProfBreak.hs +9/−0
- foundation.cabal +156/−0
- tests/Encoding.hs +956/−0
- tests/ForeignUtils.hs +26/−0
- tests/Tests.hs +571/−0
+ Foundation.hs view
@@ -0,0 +1,178 @@+-- |+-- Module : Foundation+-- License : BSD-style+-- Maintainer : Vincent Hanquez <vincent@snarc.org>+-- Stability : experimental+-- Portability : portable+--+-- I tried to picture clusters of information+-- As they moved through the computer+-- What do they look like?+--+-- Alternative Prelude+{-# LANGUAGE CPP #-}+module Foundation+ ( -- * Standard+ -- ** Operators+ (Prelude.$)+ , (Prelude.$!)+ , (Prelude.&&)+ , (Prelude.||)+ , (Control.Category..)+ -- ** Functions+ , Prelude.not+ , Prelude.otherwise+ , module Foundation.Tuple+ , Control.Category.id+ , Prelude.maybe+ , Prelude.either+ , Prelude.flip+ , Prelude.const+ , Prelude.error+ , Foundation.IO.Terminal.putStr+ , Foundation.IO.Terminal.putStrLn+ --, print+ , getArgs+ , Prelude.uncurry+ , Prelude.curry+ , Data.Tuple.swap+ , Prelude.until+ , Prelude.asTypeOf+ , Prelude.undefined+ , Prelude.seq+ -- ** Type classes+ , Prelude.Show (..)+ , Prelude.Ord (..)+ , Prelude.Eq (..)+ , Prelude.Bounded (..)+ , Prelude.Enum (..)+ , Prelude.Functor (..)+ , Control.Applicative.Applicative (..)+ , Prelude.Monad (..)+ , (Control.Monad.=<<)+ --, Foundation.String.IsString (..)+ , IsString(..)+ , IsList(..)+ -- ** Numeric type classes+ , Foundation.Number.Number (..)+ , Foundation.Number.Signed (..)+ , Foundation.Number.Additive (..)+ , Foundation.Number.Subtractive (..)+ , Foundation.Number.Multiplicative (..)+ -- ** Data types+ , Prelude.Maybe (..)+ , Prelude.Ordering (..)+ , Prelude.Bool (..)+ , Prelude.Char+ , Prelude.IO+ , Prelude.Either (..)+ -- ** Numbers+ , Data.Int.Int8, Data.Int.Int16, Data.Int.Int32, Data.Int.Int64+ , Data.Word.Word8, Data.Word.Word16, Data.Word.Word32, Data.Word.Word64, Data.Word.Word+ , Prelude.Int+ , Prelude.Integer+ , Prelude.Rational+ , Prelude.Float+ , Prelude.Double+ -- ** Collection types+ , UArray+ , PrimType+ , Array+ , String+ -- ** Numeric functions+ -- , (Prelude.^)+ , (Prelude.^^)+ , Prelude.fromIntegral+ , Prelude.realToFrac+ -- ** Monoids+ , Monoid (..)+ , (<>)+ -- ** Folds and traversals+ , Data.Foldable.Foldable+ , Data.Foldable.asum+ , Data.Traversable.Traversable+ -- ** Maybe+ , Data.Maybe.mapMaybe+ , Data.Maybe.catMaybes+ , Data.Maybe.fromMaybe+ , Data.Maybe.isJust+ , Data.Maybe.isNothing+ , Data.Maybe.listToMaybe+ , Data.Maybe.maybeToList+ -- ** Either+ , Data.Either.partitionEithers+ , Data.Either.lefts+ , Data.Either.rights+ -- ** Function+ , Data.Function.on+ -- ** Applicative+ , (Control.Applicative.<$>)+ , (Control.Applicative.<|>)+ -- ** Monad+ , (Control.Monad.>=>)+ -- ** Exceptions+ , Control.Exception.Exception (..)+ , Data.Typeable.Typeable+ , Control.Exception.SomeException+ , Control.Exception.IOException+ -- ** Proxy+ , Foundation.Internal.Proxy.Proxy(..)+ , Foundation.Internal.Proxy.asProxyTypeOf+ -- ** Partial+ , Foundation.Partial.Partial+ , Foundation.Partial.partial+ , Foundation.Partial.PartialError+ , Foundation.Partial.fromPartial+ -- ** Old Prelude Strings as [Char] with bridge back and forth+ , LString+ ) where++import qualified Prelude+--import Prelude (Char, (.), Eq, Bool, IO)++import Data.Monoid (Monoid (..))+import Control.Applicative+import qualified Control.Category+import qualified Control.Monad+import qualified Control.Exception+import qualified Data.Typeable++import qualified Data.Foldable+import qualified Data.Traversable++import Data.Word (Word8, Word16, Word32, Word64, Word)+import Data.Int (Int8, Int16, Int32, Int64)+import Foundation.String (String)+import Foundation.Array (UArray, Array, PrimType)+--import Foundation.Collection+import qualified Foundation.IO.Terminal++import GHC.Exts (IsString(..))+import Foundation.Internal.IsList+import qualified Foundation.Internal.Proxy++import qualified Foundation.Number+import qualified Foundation.Partial+import Foundation.Tuple++import qualified Data.Maybe+import qualified Data.Either+import qualified Data.Function+import qualified Data.Tuple++import qualified System.Environment+import qualified Data.List+#if MIN_VERSION_base(4,6,0)+import System.IO.Error+#else+import System.IO.Error hiding (catch, try)+#endif++import Data.Monoid ((<>))++-- | Alias to Prelude String ([Char]) for compatibility purpose+type LString = Prelude.String++-- | Returns a list of the program's command line arguments (not including the program name).+getArgs :: Prelude.IO [String]+getArgs = (Data.List.map fromList <$> System.Environment.getArgs)
+ Foundation/Array.hs view
@@ -0,0 +1,30 @@+-- |+-- Module : Foundation.Array+-- License : BSD-style+-- Maintainer : Vincent Hanquez <vincent@snarc.org>+-- Stability : experimental+-- Portability : portable+--+-- Simple Array and Almost-Array-like data structure+--+-- Generally accessible in o(1)+--+{-# LANGUAGE MagicHash #-}+{-# LANGUAGE UnboxedTuples #-}+module Foundation.Array+ ( Array+ , MArray+ , UArray+ , MUArray+ , Bitmap+ , MutableBitmap+ , PrimType+ -- exceptions+ , OutOfBound+ ) where++import Foundation.Array.Common+import Foundation.Array.Boxed+import Foundation.Array.Unboxed+import Foundation.Array.Unboxed.Mutable+import Foundation.Array.Bitmap
+ Foundation/Array/Bitmap.hs view
@@ -0,0 +1,435 @@+-- |+-- Module : Foundation.Array.Bitmap+-- License : BSD-style+-- Maintainer : Vincent Hanquez <vincent@snarc.org>+-- Stability : experimental+-- Portability : portable+--+-- A simple abstraction to a set of Bits (Bitmap)+--+-- Largely a placeholder for a more performant implementation,+-- most operation goes through the List representation (e.g. [Bool])+-- to conduct even the most trivial operation, leading to a lots of+-- unnecessary churn.+--+{-# LANGUAGE BangPatterns #-}+module Foundation.Array.Bitmap+ ( Bitmap+ , MutableBitmap+ , empty+ , append+ , concat+ , unsafeIndex+ , index+ , read+ , unsafeRead+ , write+ , unsafeWrite+ , snoc+ , cons+ ) where++import Foundation.Array.Unboxed (UArray)+import qualified Foundation.Array.Unboxed as A+import Foundation.Array.Unboxed.Mutable (MUArray)+import Foundation.Array.Common+import Foundation.Internal.Base+import Foundation.Internal.Types+import Foundation.Primitive.Monad+import qualified Foundation.Collection as C+import Foundation.Number+import Data.Bits+import GHC.ST+import qualified Data.List++data Bitmap = Bitmap Int (UArray Word32)++data MutableBitmap st = MutableBitmap Int (MUArray Word32 st)++bitsPerTy :: Int+bitsPerTy = 32++instance Show Bitmap where+ show v = show (toList v)+instance Eq Bitmap where+ (==) = equal+instance Ord Bitmap where+ compare = vCompare+instance Monoid Bitmap where+ mempty = empty+ mappend = append+ mconcat = concat++type instance C.Element Bitmap = Bool++instance IsList Bitmap where+ type Item Bitmap = Bool+ fromList = vFromList+ toList = vToList++instance C.InnerFunctor Bitmap where+ imap = map++instance C.Foldable Bitmap where+ foldl = foldl+ foldr = foldr+ foldl' = foldl'+ foldr' = foldr'++instance C.Sequential Bitmap where+ null = null+ take = take+ drop = drop+ splitAt = splitAt+ revTake n = unoptimised (C.revTake n)+ revDrop n = unoptimised (C.revDrop n)+ splitOn = splitOn+ break = break+ span = span+ filter = filter+ reverse = reverse+ snoc = snoc+ cons = cons+ unsnoc = unsnoc+ uncons = uncons+ intersperse = intersperse+ find = find+ sortBy = sortBy+ length = length+ singleton = fromList . (:[])++instance C.IndexedCollection Bitmap where+ (!) l n+ | n < 0 || n >= length l = Nothing+ | otherwise = Just $ index l n+ findIndex predicate c = loop 0+ where+ !len = length c+ loop i+ | i == len = Nothing+ | predicate (unsafeIndex c i) = Just i+ | otherwise = Nothing++instance C.MutableCollection MutableBitmap where+ type Collection MutableBitmap = Bitmap+ type MutableKey MutableBitmap = Int+ type MutableValue MutableBitmap = Bool++ thaw = thaw+ freeze = freeze+ unsafeThaw = unsafeThaw+ unsafeFreeze = unsafeFreeze++ mutUnsafeWrite = unsafeWrite+ mutUnsafeRead = unsafeRead+ mutWrite = write+ mutRead = read++bitmapIndex :: Int -> (Int, Int)+bitmapIndex !i = i `divMod` bitsPerTy+{-# INLINE bitmapIndex #-}++-- return the index in word32 quantity and mask to a bit in a bitmap+{-+bitmapAddr :: Int -> (# Int , Word #)+bitmapAddr !i = (# idx, mask #)+ where (!idx, !bitIdx) = bitmapIndex i+ !mask = case bitIdx of+ 0 -> 0x1+ 1 -> 0x2+ 2 -> 0x4+ 3 -> 0x8+ 4 -> 0x10+ 5 -> 0x20+ 6 -> 0x40+ 7 -> 0x80+ 8 -> 0x100+ 9 -> 0x200+ 10 -> 0x400+ 11 -> 0x800+ 12 -> 0x1000+ 13 -> 0x2000+ 14 -> 0x4000+ 15 -> 0x8000+ 16 -> 0x10000+ 17 -> 0x20000+ 18 -> 0x40000+ 19 -> 0x80000+ 20 -> 0x100000+ 21 -> 0x200000+ 22 -> 0x400000+ 23 -> 0x800000+ 24 -> 0x1000000+ 25 -> 0x2000000+ 26 -> 0x4000000+ 27 -> 0x8000000+ 28 -> 0x10000000+ 29 -> 0x20000000+ 30 -> 0x40000000+ _ -> 0x80000000+-}++thaw :: PrimMonad prim => Bitmap -> prim (MutableBitmap (PrimState prim))+thaw (Bitmap len ba) = MutableBitmap len `fmap` C.thaw ba++freeze :: PrimMonad prim => MutableBitmap (PrimState prim) -> prim Bitmap+freeze (MutableBitmap len mba) = Bitmap len `fmap` C.freeze mba++unsafeThaw :: PrimMonad prim => Bitmap -> prim (MutableBitmap (PrimState prim))+unsafeThaw (Bitmap len ba) = MutableBitmap len `fmap` C.unsafeThaw ba++unsafeFreeze :: PrimMonad prim => MutableBitmap (PrimState prim) -> prim Bitmap+unsafeFreeze (MutableBitmap len mba) = Bitmap len `fmap` C.unsafeFreeze mba++unsafeWrite :: PrimMonad prim => MutableBitmap (PrimState prim) -> Int -> Bool -> prim ()+unsafeWrite (MutableBitmap _ ma) i v = do+ let (idx, bitIdx) = bitmapIndex i+ w <- A.unsafeRead ma idx+ let w' = if v then setBit w bitIdx else clearBit w bitIdx+ A.unsafeWrite ma idx w'+{-# INLINE unsafeWrite #-}++unsafeRead :: PrimMonad prim => MutableBitmap (PrimState prim) -> Int -> prim Bool+unsafeRead (MutableBitmap _ ma) i = do+ let (idx, bitIdx) = bitmapIndex i+ flip testBit bitIdx `fmap` A.unsafeRead ma idx+{-# INLINE unsafeRead #-}++write :: PrimMonad prim => MutableBitmap (PrimState prim) -> Int -> Bool -> prim ()+write mb n val+ | n < 0 || n >= len = primThrow (OutOfBound OOB_Write n len)+ | otherwise = unsafeWrite mb n val+ where+ len = mutableLength mb+{-# INLINE write #-}++read :: PrimMonad prim => MutableBitmap (PrimState prim) -> Int -> prim Bool+read mb n+ | n < 0 || n >= len = primThrow (OutOfBound OOB_Read n len)+ | otherwise = unsafeRead mb n+ where len = mutableLength mb+{-# INLINE read #-}++-- | Return the element at a specific index from a Bitmap.+--+-- If the index @n is out of bounds, an error is raised.+index :: Bitmap -> Int -> Bool+index bits n+ | n < 0 || n >= len = throw (OutOfBound OOB_Index n len)+ | otherwise = unsafeIndex bits n+ where len = length bits+{-# INLINE index #-}++-- | Return the element at a specific index from an array without bounds checking.+--+-- Reading from invalid memory can return unpredictable and invalid values.+-- use 'index' if unsure.+unsafeIndex :: Bitmap -> Int -> Bool+unsafeIndex (Bitmap _ ba) n =+ let (idx, bitIdx) = bitmapIndex n+ in testBit (A.unsafeIndex ba idx) bitIdx++{-# INLINE unsafeIndex #-}++-----------------------------------------------------------------------+-- higher level collection implementation+-----------------------------------------------------------------------+length :: Bitmap -> Int+length (Bitmap len _) = len++mutableLength :: MutableBitmap st -> Int+mutableLength (MutableBitmap len _) = len++empty :: Bitmap+empty = Bitmap 0 A.empty++-- | make an array from a list of elements.+vFromList :: [Bool] -> Bitmap+vFromList allBools = runST $ do+ mba <- A.new nbElements+ let mbitmap = MutableBitmap len mba+ loop mbitmap 0 allBools+ where+ loop mb _ [] = unsafeFreeze mb+ loop mb i (x:xs) = unsafeWrite mb i x >> loop mb (i+1) xs++{-+ runST $ do+ mba <- A.new nbElements+ ba <- loop mba (0 :: Int) allBools+ return (Bitmap len ba)+ where+ loop mba _ [] = A.unsafeFreeze mba+ loop mba i l = do+ let (l1, l2) = C.splitAt bitsPerTy l+ w = toPacked l1+ A.unsafeWrite mba i w+ loop mba (i+1) l2++ toPacked :: [Bool] -> Word32+ toPacked l =+ C.foldl (.|.) 0 $ Prelude.zipWith (\b w -> if b then (1 `shiftL` w) else 0) l (C.reverse [0..31])+-}++ nbElements :: Size Word32+ nbElements = Size (len `divUp` bitsPerTy)++ divUp a b+ | d == 0 = c+ | otherwise = c+1+ where+ (c,d) = a `divMod` b++ len = C.length allBools++-- | transform an array to a list.+vToList :: Bitmap -> [Bool]+vToList a = loop 0+ where len = length a+ loop i | i == len = []+ | otherwise = unsafeIndex a i : loop (i+1)++-- | Check if two vectors are identical+equal :: Bitmap -> Bitmap -> Bool+equal a b+ | la /= lb = False+ | otherwise = loop 0+ where+ !la = length a+ !lb = length b+ loop n | n == la = True+ | otherwise = (unsafeIndex a n == unsafeIndex b n) && loop (n+1)++-- | Compare 2 vectors+vCompare :: Bitmap -> Bitmap -> Ordering+vCompare a b = loop 0+ where+ !la = length a+ !lb = length b+ loop n+ | n == la = if la == lb then EQ else LT+ | n == lb = GT+ | otherwise =+ case unsafeIndex a n `compare` unsafeIndex b n of+ EQ -> loop (n+1)+ r -> r++-- | Append 2 arrays together by creating a new bigger array+--+-- TODO completely non optimized+append :: Bitmap -> Bitmap -> Bitmap+append a b = fromList $ toList a `mappend` toList b++-- TODO completely non optimized+concat :: [Bitmap] -> Bitmap+concat l = fromList $ mconcat $ fmap toList l++null :: Bitmap -> Bool+null (Bitmap nbBits _) = nbBits == 0++take :: Int -> Bitmap -> Bitmap+take nbElems bits@(Bitmap nbBits ba)+ | nbElems <= 0 = empty+ | nbElems >= nbBits = bits+ | otherwise = Bitmap nbElems ba -- TODO : although it work right now, take on the underlaying ba too++drop :: Int -> Bitmap -> Bitmap+drop nbElems bits@(Bitmap nbBits _)+ | nbElems <= 0 = bits+ | nbElems >= nbBits = empty+ | otherwise = unoptimised (C.drop nbElems) bits+ -- TODO: decide if we have drop easy by having a bit offset in the data structure+ -- or if we need to shift stuff around making all the indexing slighlty more complicated++splitAt :: Int -> Bitmap -> (Bitmap, Bitmap)+splitAt n v = (take n v, drop n v)++-- unoptimised+splitOn :: (Bool -> Bool) -> Bitmap -> [Bitmap]+splitOn f bits = fmap fromList $ C.splitOn f $ toList bits++-- unoptimised+break :: (Bool -> Bool) -> Bitmap -> (Bitmap, Bitmap)+break predicate v = findBreak 0+ where+ findBreak i+ | i == length v = (v, empty)+ | otherwise =+ if predicate (unsafeIndex v i)+ then splitAt i v+ else findBreak (i+1)++span :: (Bool -> Bool) -> Bitmap -> (Bitmap, Bitmap)+span p = break (not . p)++map :: (Bool -> Bool) -> Bitmap -> Bitmap+map f bits = unoptimised (fmap f) bits++--mapIndex :: (Int -> Bool -> Bool) -> Bitmap -> Bitmap+--mapIndex f Bitmap =++cons :: Bool -> Bitmap -> Bitmap+cons v l = unoptimised (C.cons v) l++snoc :: Bitmap -> Bool -> Bitmap+snoc l v = unoptimised (flip C.snoc v) l++-- unoptimised+uncons :: Bitmap -> Maybe (Bool, Bitmap)+uncons b = fmap (\(v, l) -> (v, fromList l)) $ C.uncons $ toList b++-- unoptimised+unsnoc :: Bitmap -> Maybe (Bitmap, Bool)+unsnoc b = fmap (\(l, v) -> (fromList l, v)) $ C.unsnoc $ toList b++intersperse :: Bool -> Bitmap -> Bitmap+intersperse b = unoptimised (C.intersperse b)++find :: (Bool -> Bool) -> Bitmap -> Maybe Bool+find predicate vec = loop 0+ where+ !len = length vec+ loop i+ | i == len = Nothing+ | otherwise =+ let e = unsafeIndex vec i+ in if predicate e then Just e else loop (i+1)++sortBy :: (Bool -> Bool -> Ordering) -> Bitmap -> Bitmap+sortBy by bits = unoptimised (C.sortBy by) bits++filter :: (Bool -> Bool) -> Bitmap -> Bitmap+filter predicate vec = unoptimised (Data.List.filter predicate) vec++reverse :: Bitmap -> Bitmap+reverse bits = unoptimised C.reverse bits++foldl :: (a -> Bool -> a) -> a -> Bitmap -> a+foldl f initialAcc vec = loop 0 initialAcc+ where+ len = length vec+ loop i acc+ | i == len = acc+ | otherwise = loop (i+1) (f acc (unsafeIndex vec i))++foldr :: (Bool -> a -> a) -> a -> Bitmap -> a+foldr f initialAcc vec = loop 0+ where+ len = length vec+ loop i+ | i == len = initialAcc+ | otherwise = unsafeIndex vec i `f` loop (i+1)++foldr' :: (Bool -> a -> a) -> a -> Bitmap -> a+foldr' = foldr++foldl' :: (a -> Bool -> a) -> a -> Bitmap -> a+foldl' f initialAcc vec = loop 0 initialAcc+ where+ len = length vec+ loop i !acc+ | i == len = acc+ | otherwise = loop (i+1) (f acc (unsafeIndex vec i))++unoptimised :: ([Bool] -> [Bool]) -> Bitmap -> Bitmap+unoptimised f = vFromList . f . vToList
+ Foundation/Array/Boxed.hs view
@@ -0,0 +1,607 @@+-- |+-- Module : Foundation.Array.Boxed+-- License : BSD-style+-- Maintainer : Vincent Hanquez <vincent@snarc.org>+-- Stability : experimental+-- Portability : portable+--+-- Simple boxed array abstraction+--+{-# LANGUAGE MagicHash #-}+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE UnboxedTuples #-}+module Foundation.Array.Boxed+ ( Array+ , MArray+ ) where++import GHC.Prim+import GHC.Types+import GHC.ST+import Foundation.Number+import Foundation.Internal.Base+import Foundation.Internal.Types+import Foundation.Primitive.Types+import Foundation.Primitive.Monad+import Foundation.Array.Common+import qualified Foundation.Collection as C+import qualified Prelude++-- | Array of a+data Array a = Array (Array# a)+ deriving (Typeable)++-- | Mutable Array of a+data MArray a st = MArray (MutableArray# st a)+ deriving (Typeable)++instance Functor Array where+ fmap = map++instance Monoid (Array a) where+ mempty = empty+ mappend = append+ mconcat = concat++instance Show a => Show (Array a) where+ show v = show (toList v)++instance Eq a => Eq (Array a) where+ (==) = equal+instance Ord a => Ord (Array a) where+ compare = vCompare++type instance C.Element (Array ty) = ty++instance IsList (Array ty) where+ type Item (Array ty) = ty+ fromList = vFromList+ toList = vToList++instance C.InnerFunctor (Array ty)++instance C.Sequential (Array ty) where+ null = null+ take = take+ drop = drop+ splitAt = splitAt+ revTake = revTake+ revDrop = revDrop+ revSplitAt = revSplitAt+ splitOn = splitOn+ break = break+ intersperse = intersperse+ span = span+ reverse = reverse+ filter = filter+ unsnoc = unsnoc+ uncons = uncons+ snoc = snoc+ cons = cons+ find = find+ sortBy = sortBy+ length = length+ singleton = fromList . (:[])++instance C.MutableCollection (MArray ty) where+ type Collection (MArray ty) = Array ty+ type MutableKey (MArray ty) = Int+ type MutableValue (MArray ty) = ty++ thaw = thaw+ freeze = freeze+ unsafeThaw = unsafeThaw+ unsafeFreeze = unsafeFreeze++ mutUnsafeWrite = unsafeWrite+ mutUnsafeRead = unsafeRead+ mutWrite = write+ mutRead = read++instance C.IndexedCollection (Array ty) where+ (!) l n+ | n < 0 || n >= length l = Nothing+ | otherwise = Just $ index l n+ findIndex predicate c = loop 0+ where+ !len = length c+ loop i+ | i == len = Nothing+ | otherwise =+ if predicate (unsafeIndex c i) then Just i else Nothing++instance C.Zippable (Array ty) where+ -- TODO Use an array builder once available+ zipWith f a b = runST $ do+ mv <- new len+ go mv 0 f (toList a) (toList b)+ unsafeFreeze mv+ where+ !len = Size $ min (C.length a) (C.length b)+ go _ _ _ [] _ = return ()+ go _ _ _ _ [] = return ()+ go mv i f' (a':as') (b':bs') = do+ write mv i (f' a' b')+ go mv (i + 1) f' as' bs'++instance C.BoxedZippable (Array ty)++-- | return the numbers of elements in a mutable array+mutableLength :: MArray ty st -> Int+mutableLength (MArray ma) = I# (sizeofMutableArray# ma)+{-# INLINE mutableLength #-}++-- | Return the element at a specific index from an array.+--+-- If the index @n is out of bounds, an error is raised.+index :: Array ty -> Int -> ty+index array n+ | n < 0 || n >= len = throw (OutOfBound OOB_Index n len)+ | otherwise = unsafeIndex array n+ where len = length array+{-# INLINE index #-}++-- | Return the element at a specific index from an array without bounds checking.+--+-- Reading from invalid memory can return unpredictable and invalid values.+-- use 'index' if unsure.+unsafeIndex :: Array ty -> Int -> ty+unsafeIndex (Array a) (I# n) = let (# v #) = indexArray# a n in v+{-# INLINE unsafeIndex #-}++-- | read a cell in a mutable array.+--+-- If the index is out of bounds, an error is raised.+read :: PrimMonad prim => MArray ty (PrimState prim) -> Int -> prim ty+read array n+ | n < 0 || n >= len = primThrow (OutOfBound OOB_Read n len)+ | otherwise = unsafeRead array n+ where len = mutableLength array+{-# INLINE read #-}++-- | read from a cell in a mutable array without bounds checking.+--+-- Reading from invalid memory can return unpredictable and invalid values.+-- use 'read' if unsure.+unsafeRead :: PrimMonad prim => MArray ty (PrimState prim) -> Int -> prim ty+unsafeRead (MArray ma) (I# i) = primitive $ \s1 -> readArray# ma i s1+--readArray# :: MutableArray# s a -> Int# -> State# s -> (#State# s, a#)+{-# INLINE unsafeRead #-}++-- | Write to a cell in a mutable array.+--+-- If the index is out of bounds, an error is raised.+write :: PrimMonad prim => MArray ty (PrimState prim) -> Int -> ty -> prim ()+write array n val+ | n < 0 || n >= len = primThrow (OutOfBound OOB_Write n len)+ | otherwise = unsafeWrite array n val+ where len = mutableLength array+{-# INLINE write #-}++-- | write to a cell in a mutable array without bounds checking.+--+-- Writing with invalid bounds will corrupt memory and your program will+-- become unreliable. use 'write' if unsure.+unsafeWrite :: PrimMonad prim => MArray ty (PrimState prim) -> Int -> ty -> prim ()+unsafeWrite (MArray ma) (I# i) v = primitive $ \s1 -> let !s2 = writeArray# ma i v s1 in (# s2, () #)+{-# INLINE unsafeWrite #-}++-- | Freeze a mutable array into an array.+--+-- the MArray must not be changed after freezing.+unsafeFreeze :: PrimMonad prim => MArray ty (PrimState prim) -> prim (Array ty)+unsafeFreeze (MArray ma) = primitive $ \s1 ->+ case unsafeFreezeArray# ma s1 of+ (# s2, a #) -> (# s2, Array a #)+{-# INLINE unsafeFreeze #-}++-- | Thaw an immutable array.+--+-- The Array must not be used after thawing.+unsafeThaw :: PrimMonad prim => Array ty -> prim (MArray ty (PrimState prim))+unsafeThaw (Array a) = primitive $ \st -> (# st, MArray (unsafeCoerce# a) #)+{-# INLINE unsafeThaw #-}++-- | Thaw an array to a mutable array.+--+-- the array is not modified, instead a new mutable array is created+-- and every values is copied, before returning the mutable array.+thaw :: PrimMonad prim => Array ty -> prim (MArray ty (PrimState prim))+thaw array = do+ m <- new (lengthSize array)+ unsafeCopyAtRO m (Offset 0) array (Offset 0) (lengthSize array)+ return m+{-# INLINE thaw #-}++freeze :: PrimMonad prim => MArray ty (PrimState prim) -> prim (Array ty)+freeze marray = do+ m <- new sz+ copyAt m (Offset 0) marray (Offset 0) sz+ unsafeFreeze m+ where+ sz = Size $ mutableLength marray++-- | Copy a number of elements from an array to another array with offsets+copyAt :: PrimMonad prim+ => MArray ty (PrimState prim) -- ^ destination array+ -> Offset ty -- ^ offset at destination+ -> MArray ty (PrimState prim) -- ^ source array+ -> Offset ty -- ^ offset at source+ -> Size ty -- ^ number of elements to copy+ -> prim ()+copyAt dst od src os n = loop od os+ where !endIndex = os `offsetPlusE` n+ loop (Offset d) s@(Offset i)+ | s == endIndex = return ()+ | otherwise = unsafeRead src i >>= unsafeWrite dst d >> loop (Offset $ d+1) (Offset $ i+1)++-- | Copy @n@ sequential elements from the specified offset in a source array+-- to the specified position in a destination array.+--+-- This function does not check bounds. Accessing invalid memory can return+-- unpredictable and invalid values.+unsafeCopyAtRO :: PrimMonad prim+ => MArray ty (PrimState prim) -- ^ destination array+ -> Offset ty -- ^ offset at destination+ -> Array ty -- ^ source array+ -> Offset ty -- ^ offset at source+ -> Size ty -- ^ number of elements to copy+ -> prim ()+unsafeCopyAtRO dst od src os n = loop od os+ where !endIndex = os `offsetPlusE` n+ loop (Offset d) s@(Offset i)+ | s == endIndex = return ()+ | otherwise = unsafeWrite dst d (unsafeIndex src i) >> loop (Offset $ d+1) (Offset $ i+1)++-- | Allocate a new array with a fill function that has access to the elements of+-- the source array.+unsafeCopyFrom :: Array ty -- ^ Source array+ -> Size ty -- ^ Length of the destination array+ -> (Array ty -> Offset ty -> MArray ty s -> ST s ())+ -- ^ Function called for each element in the source array+ -> ST s (Array ty) -- ^ Returns the filled new array+unsafeCopyFrom v' newLen f = new newLen >>= fill (Offset 0) f >>= unsafeFreeze+ where len = lengthSize v'+ endIdx = Offset 0 `offsetPlusE` len+ fill i f' r'+ | i == endIdx = return r'+ | otherwise = do f' v' i r'+ fill (i + Offset 1) f' r'++-- | Create a new mutable array of size @n.+--+-- all the cells are uninitialized and could contains invalid values.+--+-- All mutable arrays are allocated on a 64 bits aligned addresses+-- and always contains a number of bytes multiples of 64 bits.+new :: PrimMonad prim => Size ty -> prim (MArray ty (PrimState prim))+new (Size (I# n)) = primitive $ \s1 ->+ case newArray# n (error "vector: internal error uninitialized vector") s1 of+ (# s2, ma #) -> (# s2, MArray ma #)++-- | Create a new array of size @n by settings each cells through the+-- function @f.+create :: Int -- ^ the size of the array+ -> (Int -> ty) -- ^ the function that set the value at the index+ -> Array ty -- ^ the array created+create n initializer = runST (new (Size n) >>= iter initializer)+ where+ iter :: PrimMonad prim => (Int -> ty) -> MArray ty (PrimState prim) -> prim (Array ty)+ iter f ma = loop (Offset 0)+ where+ !end = Offset 0 `offsetPlusE` Size n+ loop s@(Offset i)+ | s == end = unsafeFreeze ma+ | otherwise = unsafeWrite ma i (f i) >> loop (Offset $ i+1)+ {-# INLINE loop #-}+ {-# INLINE iter #-}++-----------------------------------------------------------------------+-- higher level collection implementation+-----------------------------------------------------------------------+equal :: Eq a => Array a -> Array a -> Bool+equal a b = (len == length b) && eachEqual 0+ where+ len = length a+ eachEqual !i+ | i == len = True+ | unsafeIndex a i /= unsafeIndex b i = False+ | otherwise = eachEqual (i+1)++vCompare :: Ord a => Array a -> Array a -> Ordering+vCompare a b = loop 0+ where+ !la = length a+ !lb = length b+ loop n+ | n == la = if la == lb then EQ else LT+ | n == lb = GT+ | otherwise =+ case unsafeIndex a n `compare` unsafeIndex b n of+ EQ -> loop (n+1)+ r -> r++empty :: Array a+empty = runST $ onNewArray 0 (\_ s -> s)++length :: Array a -> Int+length (Array a) = I# (sizeofArray# a)++lengthSize :: Array a -> Size a+lengthSize (Array a) = Size $ I# (sizeofArray# a)++vFromList :: [a] -> Array a+vFromList l = runST (new len >>= loop 0 l)+ where+ len = Size $ C.length l+ loop _ [] ma = unsafeFreeze ma+ loop i (x:xs) ma = unsafeWrite ma i x >> loop (i+1) xs ma++vToList :: Array a -> [a]+vToList v = fmap (unsafeIndex v) [0..(length v - 1)]++-- | Append 2 arrays together by creating a new bigger array+append :: Array ty -> Array ty -> Array ty+append a b = runST $ do+ r <- new (la+lb)+ ma <- unsafeThaw a+ mb <- unsafeThaw b+ copyAt r (Offset 0) ma (Offset 0) la+ copyAt r (sizeAsOffset la) mb (Offset 0) lb+ unsafeFreeze r+ where la = lengthSize a+ lb = lengthSize b++concat :: [Array ty] -> Array ty+concat l = runST $ do+ r <- new (Size $ Prelude.sum $ fmap length l)+ loop r (Offset 0) l+ unsafeFreeze r+ where loop _ _ [] = return ()+ loop r i (x:xs) = do+ mx <- unsafeThaw x+ copyAt r i mx (Offset 0) lx+ loop r (i `offsetPlusE` lx) xs+ where lx = lengthSize x++{-+modify :: PrimMonad m+ => Array a+ -> (MArray (PrimState m) a -> m ())+ -> m (Array a)+modify (Array a) f = primitive $ \st -> do+ case thawArray# a 0# (sizeofArray# a) st of+ (# st2, mv #) ->+ case internal_ (f $ MArray mv) st2 of+ st3 ->+ case unsafeFreezeArray# mv st3 of+ (# st4, a' #) -> (# st4, Array a' #)+-}++-----------------------------------------------------------------------+-- helpers++onNewArray :: PrimMonad m+ => Int+ -> (MutableArray# (PrimState m) a -> State# (PrimState m) -> State# (PrimState m))+ -> m (Array a)+onNewArray (I# len) f = primitive $ \st -> do+ case newArray# len (error "onArray") st of { (# st2, mv #) ->+ case f mv st2 of { st3 ->+ case unsafeFreezeArray# mv st3 of { (# st4, a #) ->+ (# st4, Array a #) }}}++-----------------------------------------------------------------------+++null :: Array ty -> Bool+null = (==) 0 . length++take :: Int -> Array ty -> Array ty+take nbElems v+ | nbElems <= 0 = empty+ | otherwise = runST $ do+ muv <- new n+ unsafeCopyAtRO muv (Offset 0) v (Offset 0) n+ unsafeFreeze muv+ where+ n = Size $ min nbElems (length v)++drop :: Int -> Array ty -> Array ty+drop nbElems v+ | nbElems <= 0 = v+ | otherwise = runST $ do+ muv <- new n+ unsafeCopyAtRO muv (Offset 0) v (Offset offset) n+ unsafeFreeze muv+ where+ offset = min nbElems (length v)+ n = Size (length v - offset)++splitAt :: Int -> Array ty -> (Array ty, Array ty)+splitAt n v = (take n v, drop n v)++revTake :: Int -> Array ty -> Array ty+revTake nbElems v = drop (length v - nbElems) v++revDrop :: Int -> Array ty -> Array ty+revDrop nbElems v = take (length v - nbElems) v++revSplitAt :: Int -> Array ty -> (Array ty, Array ty)+revSplitAt n v = (drop idx v, take idx v)+ where idx = length v - n++splitOn :: (ty -> Bool) -> Array ty -> [Array ty]+splitOn predicate vec+ | len == Size 0 = []+ | otherwise = loop (Offset 0) (Offset 0)+ where+ !len = lengthSize vec+ !endIdx = Offset 0 `offsetPlusE` len+ loop prevIdx idx@(Offset i)+ | idx == endIdx = [runST $ sub vec prevIdx idx]+ | otherwise =+ let e = unsafeIndex vec i+ idx' = idx + Offset 1+ in if predicate e+ then runST (sub vec prevIdx idx) : loop idx' idx'+ else loop prevIdx idx'++sub :: PrimMonad prim => Array ty -> Offset ty -> Offset ty -> prim (Array ty)+sub vec startIdx expectedEndIdx+ | startIdx == endIdx = return empty+ | startIdx >= sizeAsOffset len = return empty+ | otherwise = new sz >>= loop startIdx (Offset 0)+ where+ !len = lengthSize vec+ loop os@(Offset s) od@(Offset d) mv+ | os == endIdx = unsafeFreeze mv+ | otherwise = unsafeWrite mv d (unsafeIndex vec s) >> loop (os+Offset 1) (od+Offset 1) mv+ !sz = endIdx - startIdx+ !endIdx = min expectedEndIdx (sizeAsOffset $ lengthSize vec)++break :: (ty -> Bool) -> Array ty -> (Array ty, Array ty)+break predicate v = findBreak 0+ where+ findBreak i+ | i == length v = (v, empty)+ | otherwise =+ if predicate (unsafeIndex v i)+ then splitAt i v+ else findBreak (i+1)++intersperse :: ty -> Array ty -> Array ty+intersperse sep v+ | len <= Size 1 = v+ | otherwise = runST $ unsafeCopyFrom v ((len + len) - Size 1) (go (Offset 0 `offsetPlusE` (len - Size 1)) sep)+ where len = lengthSize v+ -- terminate 1 before the end++ go :: Offset ty -> ty -> Array ty -> Offset ty -> MArray ty s -> ST s ()+ go endI sep' oldV oldI@(Offset oi) newV+ | oldI == endI = unsafeWrite newV dst e+ | otherwise = do+ unsafeWrite newV dst e+ unsafeWrite newV (dst + 1) sep'+ where+ e = unsafeIndex oldV oi+ (Offset dst) = oldI + oldI++span :: (ty -> Bool) -> Array ty -> (Array ty, Array ty)+span p = break (not . p)++map :: (a -> b) -> Array a -> Array b+map f a = create (length a) (\i -> f $ unsafeIndex a i)++{-+mapIndex :: (Int -> a -> b) -> Array a -> Array b+mapIndex f a = create (length a) (\i -> f i $ unsafeIndex a i)+-}++cons :: ty -> Array ty -> Array ty+cons e vec+ | len == Size 0 = C.singleton e+ | otherwise = runST $ do+ mv <- new (len + Size 1)+ unsafeWrite mv 0 e+ unsafeCopyAtRO mv (Offset 1) vec (Offset 0) len+ unsafeFreeze mv+ where+ !len = lengthSize vec++snoc :: Array ty -> ty -> Array ty+snoc vec e+ | len == Size 0 = C.singleton e+ | otherwise = runST $ do+ mv <- new (len + Size 1)+ unsafeCopyAtRO mv (Offset 0) vec (Offset 0) len+ unsafeWrite mv lastI e+ unsafeFreeze mv+ where+ !len@(Size lastI) = lengthSize vec++uncons :: Array ty -> Maybe (ty, Array ty)+uncons vec+ | len == 0 = Nothing+ | otherwise = Just (unsafeIndex vec 0, drop 1 vec)+ where+ !len = length vec++unsnoc :: Array ty -> Maybe (Array ty, ty)+unsnoc vec+ | len == 0 = Nothing+ | otherwise = Just (take (len - 1) vec, unsafeIndex vec (len-1))+ where+ !len = length vec++find :: (ty -> Bool) -> Array ty -> Maybe ty+find predicate vec = loop 0+ where+ !len = length vec+ loop i+ | i == len = Nothing+ | otherwise =+ let e = unsafeIndex vec i+ in if predicate e then Just e else loop (i+1)++sortBy :: (ty -> ty -> Ordering) -> Array ty -> Array ty+sortBy xford vec = runST (thaw vec >>= doSort xford)+ where+ len = length vec+ doSort :: PrimMonad prim => (ty -> ty -> Ordering) -> MArray ty (PrimState prim) -> prim (Array ty)+ doSort ford ma = qsort 0 (len - 1) >> unsafeFreeze ma+ where+ qsort lo hi+ | lo >= hi = return ()+ | otherwise = do+ p <- partition lo hi+ qsort lo (p-1)+ qsort (p+1) hi+ partition lo hi = do+ pivot <- unsafeRead ma hi+ let loop i j+ | j == hi = return i+ | otherwise = do+ aj <- unsafeRead ma j+ i' <- if ford aj pivot == GT+ then return i+ else do+ ai <- unsafeRead ma i+ unsafeWrite ma j ai+ unsafeWrite ma i aj+ return $ i + 1+ loop i' (j+1)++ i <- loop lo lo+ ai <- unsafeRead ma i+ ahi <- unsafeRead ma hi+ unsafeWrite ma hi ai+ unsafeWrite ma i ahi+ return i++filter :: (ty -> Bool) -> Array ty -> Array ty+filter predicate vec = runST (new len >>= copyFilterFreeze predicate (unsafeIndex vec))+ where+ !len = lengthSize vec+ !end = Offset 0 `offsetPlusE` len+ copyFilterFreeze :: PrimMonad prim => (ty -> Bool) -> (Int -> ty) -> MArray ty (PrimState prim) -> prim (Array ty)+ copyFilterFreeze predi getVec mvec = loop (Offset 0) (Offset 0) >>= freezeUntilIndex mvec+ where+ loop d@(Offset di) s@(Offset si)+ | s == end = return d+ | predi v = unsafeWrite mvec di v >> loop (d+Offset 1) (s+Offset 1)+ | otherwise = loop d (s+Offset 1)+ where+ v = getVec si++freezeUntilIndex :: PrimMonad prim => MArray ty (PrimState prim) -> Offset ty -> prim (Array ty)+freezeUntilIndex mvec d = do+ m <- new (offsetAsSize d)+ copyAt m (Offset 0) mvec (Offset 0) (offsetAsSize d)+ unsafeFreeze m++reverse :: Array ty -> Array ty+reverse a = create len toEnd+ where+ len = length a+ toEnd i = unsafeIndex a (len - i - 1)
+ Foundation/Array/Common.hs view
@@ -0,0 +1,46 @@+-- |+-- Module : Foundation.Array.Common+-- License : BSD-style+-- Maintainer : Vincent Hanquez <vincent@snarc.org>+-- Stability : experimental+-- Portability : portable+--+-- Common part for vectors+--+{-# LANGUAGE DeriveDataTypeable #-}+module Foundation.Array.Common+ ( OutOfBound(..)+ , OutOfBoundOperation(..)++ , InvalidRecast(..)+ , RecastSourceSize(..)+ , RecastDestinationSize(..)+ ) where++import Foundation.Internal.Base++-- | The type of operation that triggers an OutOfBound exception.+--+-- * OOB_Index: reading an immutable vector+-- * OOB_Read: reading a mutable vector+-- * OOB_Write: write a mutable vector+data OutOfBoundOperation = OOB_Read | OOB_Write | OOB_MemSet | OOB_Index+ deriving (Show,Eq,Typeable)++-- | Exception during an operation accessing the vector out of bound+--+-- Represent the type of operation, the index accessed, and the total length of the vector.+data OutOfBound = OutOfBound OutOfBoundOperation Int Int+ deriving (Show,Typeable)++instance Exception OutOfBound++newtype RecastSourceSize = RecastSourceSize Int+ deriving (Show,Eq,Typeable)+newtype RecastDestinationSize = RecastDestinationSize Int+ deriving (Show,Eq,Typeable)++data InvalidRecast = InvalidRecast RecastSourceSize RecastDestinationSize+ deriving (Show,Typeable)++instance Exception InvalidRecast
+ Foundation/Array/Internal.hs view
@@ -0,0 +1,20 @@+-- |+-- Module : Foundation.Array.Internal+-- License : BSD-style+-- Maintainer : Vincent Hanquez <vincent@snarc.org>+-- Stability : experimental+-- Portability : portable+--+-- Give access to Array non public functions which+-- can be used to make certains optimisations.+--+-- Most of what is available here has no guarantees of stability.+-- Anything can be removed and changed.+--+module Foundation.Array.Internal+ ( UArray(..)+ , fromForeignPtr+ , recast+ ) where++import Foundation.Array.Unboxed
+ Foundation/Array/Unboxed.hs view
@@ -0,0 +1,807 @@+-- |+-- Module : Foundation.Array.Unboxed+-- License : BSD-style+-- Maintainer : Vincent Hanquez <vincent@snarc.org>+-- Stability : experimental+-- Portability : portable+--+-- A simple array abstraction that allow to use typed+-- array of bytes where the array is pinned in memory+-- to allow easy use with Foreign interfaces, ByteString+-- and always aligned to 64 bytes.+--+{-# LANGUAGE MagicHash #-}+{-# LANGUAGE UnboxedTuples #-}+{-# LANGUAGE ViewPatterns #-}+module Foundation.Array.Unboxed+ ( UArray(..)+ , PrimType(..)+ -- * methods+ , copy+ , unsafeCopyAtRO+ -- * internal methods+ -- , copyAddr+ , recast+ , unsafeRecast+ , length+ , lengthSize+ , freeze+ , unsafeFreeze+ , thaw+ , unsafeThaw+ -- * Creation+ , new+ , empty+ , create+ , createFromIO+ , sub+ , withPtr+ , withMutablePtr+ , unsafeFreezeShrink+ , freezeShrink+ , unsafeSlide+ -- * accessors+ , update+ , unsafeUpdate+ , unsafeIndex+ , unsafeIndexer+ , unsafeRead+ , unsafeWrite+ -- * Functions+ , map+ , mapIndex+ , findIndex+ , index+ , null+ , take+ , drop+ , splitAt+ , revDrop+ , revTake+ , revSplitAt+ , splitOn+ , splitElem+ , break+ , breakElem+ , intersperse+ , span+ , cons+ , snoc+ , uncons+ , unsnoc+ , find+ , sortBy+ , filter+ , reverse+ , foldl+ , foldr+ , foldl'+ , foreignMem+ , fromForeignPtr+ ) where++import GHC.Prim+import GHC.Types+import GHC.Word+import GHC.ST+import GHC.Ptr+import GHC.ForeignPtr (ForeignPtr)+import qualified Prelude+import Foundation.Internal.Base+import Foundation.Internal.Primitive+import Foundation.Internal.Proxy+import Foundation.Internal.Types+import Foundation.Primitive.Monad+import Foundation.Primitive.Types+import Foundation.Primitive.FinalPtr+import Foundation.Primitive.Utils+import Foundation.Array.Common+import Foundation.Array.Unboxed.Mutable+import Foundation.Number+import qualified Data.List++-- | An array of type built on top of GHC primitive.+--+-- The elements need to have fixed sized and the representation is a+-- packed contiguous array in memory that can easily be passed+-- to foreign interface+data UArray ty =+ UVecBA {-# UNPACK #-} !(Offset ty)+ {-# UNPACK #-} !(Size ty)+ {-# UNPACK #-} !PinnedStatus {- unpinned / pinned flag -}+ ByteArray#+ | UVecAddr {-# UNPACK #-} !(Offset ty)+ {-# UNPACK #-} !(Size ty)+ !(FinalPtr ty)++instance (PrimType ty, Show ty) => Show (UArray ty) where+ show v = show (toList v)+instance (PrimType ty, Eq ty) => Eq (UArray ty) where+ (==) = equal+instance (PrimType ty, Ord ty) => Ord (UArray ty) where+ compare = vCompare++instance PrimType ty => Monoid (UArray ty) where+ mempty = empty+ mappend = append+ mconcat = concat++instance PrimType ty => IsList (UArray ty) where+ type Item (UArray ty) = ty+ fromList = vFromList+ toList = vToList++vectorProxyTy :: UArray ty -> Proxy ty+vectorProxyTy _ = Proxy++-- | Copy every cells of an existing array to a new array+copy :: PrimType ty => UArray ty -> UArray ty+copy array = runST (thaw array >>= unsafeFreeze)++-- | Thaw an array to a mutable array.+--+-- the array is not modified, instead a new mutable array is created+-- and every values is copied, before returning the mutable array.+thaw :: (PrimMonad prim, PrimType ty) => UArray ty -> prim (MUArray ty (PrimState prim))+thaw array = do+ ma <- new (lengthSize array)+ unsafeCopyAtRO ma azero array (Offset 0) (lengthSize array)+ return ma+{-# INLINE thaw #-}++-- | Return the element at a specific index from an array.+--+-- If the index @n is out of bounds, an error is raised.+index :: PrimType ty => UArray ty -> Int -> ty+index array n+ | n < 0 || n >= len = throw (OutOfBound OOB_Index n len)+ | otherwise = unsafeIndex array n+ where len = length array+{-# INLINE index #-}++-- | Return the element at a specific index from an array without bounds checking.+--+-- Reading from invalid memory can return unpredictable and invalid values.+-- use 'index' if unsure.+unsafeIndex :: PrimType ty => UArray ty -> Int -> ty+unsafeIndex (UVecBA start _ _ ba) n = primBaIndex ba (start + Offset n)+unsafeIndex v@(UVecAddr start _ fptr) n = withUnsafeFinalPtr fptr (primAddrIndex' v start)+ where+ primAddrIndex' :: PrimType ty => UArray ty -> Offset ty -> Ptr a -> IO ty+ primAddrIndex' _ start' (Ptr addr) = return (primAddrIndex addr (start' + Offset n))+{-# INLINE unsafeIndex #-}++unsafeIndexer :: (PrimMonad prim, PrimType ty) => UArray ty -> ((Offset ty -> ty) -> prim a) -> prim a+unsafeIndexer (UVecBA start _ _ ba) f = f (\n -> primBaIndex ba (start + n))+unsafeIndexer (UVecAddr start _ fptr) f = withFinalPtr fptr (\ptr -> f (primAddrIndex' start ptr))+ where+ primAddrIndex' :: PrimType ty => Offset ty -> Ptr a -> (Offset ty -> ty)+ primAddrIndex' start' (Ptr addr) = \n -> primAddrIndex addr (start' + n)+ {-# INLINE primAddrIndex' #-}+{-# NOINLINE unsafeIndexer #-}++{-# SPECIALIZE [3] unsafeIndexer :: UArray Word8 -> ((Offset Word8 -> Word8) -> ST s a) -> ST s a #-}++foreignMem :: PrimType ty+ => FinalPtr ty -- ^ the start pointer with a finalizer+ -> Int -- ^ the number of elements (in elements, not bytes)+ -> UArray ty+foreignMem fptr nb = UVecAddr (Offset 0) (Size nb) fptr++fromForeignPtr :: PrimType ty+ => (ForeignPtr ty, Int, Int) -- ForeignPtr, an offset in prim elements, a size in prim elements+ -> UArray ty+fromForeignPtr (fptr, ofs, len) = UVecAddr (Offset ofs) (Size len) (toFinalPtrForeign fptr)++-- | return the number of elements of the array.+length :: PrimType ty => UArray ty -> Int+length a = let (Size len) = lengthSize a in len+{-# INLINE[1] length #-}++lengthSize :: PrimType ty => UArray ty -> Size ty+lengthSize (UVecAddr _ len _) = len+lengthSize (UVecBA _ len _ _) = len+{-# INLINE[1] lengthSize #-}++-- TODO Optimise with copyByteArray#+-- | Copy @n@ sequential elements from the specified offset in a source array+-- to the specified position in a destination array.+--+-- This function does not check bounds. Accessing invalid memory can return+-- unpredictable and invalid values.+unsafeCopyAtRO :: (PrimMonad prim, PrimType ty)+ => MUArray ty (PrimState prim) -- ^ destination array+ -> Offset ty -- ^ offset at destination+ -> UArray ty -- ^ source array+ -> Offset ty -- ^ offset at source+ -> Size ty -- ^ number of elements to copy+ -> prim ()+unsafeCopyAtRO (MUVecMA dstStart _ _ dstMba) ed uvec@(UVecBA srcStart _ _ srcBa) es n =+ primitive $ \st -> (# copyByteArray# srcBa os dstMba od nBytes st, () #)+ where+ sz = primSizeInBytes (vectorProxyTy uvec)+ !(Offset (I# os)) = offsetOfE sz (srcStart+es)+ !(Offset (I# od)) = offsetOfE sz (dstStart+ed)+ !(Size (I# nBytes)) = sizeOfE sz n+unsafeCopyAtRO (MUVecMA dstStart _ _ dstMba) ed uvec@(UVecAddr srcStart _ srcFptr) es n =+ withFinalPtr srcFptr $ \srcPtr ->+ let !(Ptr srcAddr) = srcPtr `plusPtr` os+ in primitive $ \s -> (# compatCopyAddrToByteArray# srcAddr dstMba od nBytes s, () #)+ where+ sz = primSizeInBytes (vectorProxyTy uvec)+ !(Offset os) = offsetOfE sz (srcStart+es)+ !(Offset (I# od)) = offsetOfE sz (dstStart+ed)+ !(Size (I# nBytes)) = sizeOfE sz n+unsafeCopyAtRO dst od src os n = loop od os+ where+ !(Offset endIndex) = os `offsetPlusE` n+ loop (Offset d) (Offset i)+ | i == endIndex = return ()+ | otherwise = unsafeWrite dst d (unsafeIndex src i) >> loop (Offset $ d+1) (Offset $ i+1)++-- | Allocate a new array with a fill function that has access to the elements of+-- the source array.+unsafeCopyFrom :: PrimType ty+ => UArray ty -- ^ Source array+ -> Int -- ^ Length of the destination array+ -> (UArray ty -> Int -> MUArray ty s -> ST s ())+ -- ^ Function called for each element in the source array+ -> ST s (UArray ty) -- ^ Returns the filled new array+unsafeCopyFrom v' newLen f = new (Size newLen) >>= fill 0 f >>= unsafeFreeze+ where len = length v'+ fill i f' r'+ | i == len = return r'+ | otherwise = do f' v' i r'+ fill (i + 1) f' r'++-- | Freeze a mutable array into an array.+--+-- the MUArray must not be changed after freezing.+unsafeFreeze :: PrimMonad prim => MUArray ty (PrimState prim) -> prim (UArray ty)+unsafeFreeze (MUVecMA start len pinnedState mba) = primitive $ \s1 ->+ case unsafeFreezeByteArray# mba s1 of+ (# s2, ba #) -> (# s2, UVecBA start len pinnedState ba #)+unsafeFreeze (MUVecAddr start len fptr) = return $ UVecAddr start len fptr+{-# INLINE unsafeFreeze #-}++unsafeFreezeShrink :: (PrimType ty, PrimMonad prim) => MUArray ty (PrimState prim) -> Size ty -> prim (UArray ty)+unsafeFreezeShrink (MUVecMA start _ pinnedState mba) n = unsafeFreeze (MUVecMA start n pinnedState mba)+unsafeFreezeShrink (MUVecAddr start _ fptr) n = unsafeFreeze (MUVecAddr start n fptr)++freeze :: (PrimType ty, PrimMonad prim) => MUArray ty (PrimState prim) -> prim (UArray ty)+freeze ma = do+ ma' <- new len+ copyAt ma' (Offset 0) ma (Offset 0) len+ unsafeFreeze ma'+ where len = Size $ mutableLength ma++freezeShrink :: (PrimType ty, PrimMonad prim) => MUArray ty (PrimState prim) -> Int -> prim (UArray ty)+freezeShrink ma n = do+ ma' <- new (Size n)+ copyAt ma' (Offset 0) ma (Offset 0) (Size n)+ unsafeFreeze ma'++unsafeSlide :: (PrimType ty, PrimMonad prim) => MUArray ty (PrimState prim) -> Int -> Int -> prim ()+unsafeSlide mua s e = doSlide mua (Offset s) (Offset e)+ where+ doSlide :: (PrimType ty, PrimMonad prim) => MUArray ty (PrimState prim) -> Offset ty -> Offset ty -> prim ()+ doSlide (MUVecMA mbStart _ _ mba) start end =+ primMutableByteArraySlideToStart mba (primOffsetOfE $ mbStart+start) (primOffsetOfE end)+ doSlide (MUVecAddr mbStart _ fptr) start end = withFinalPtr fptr $ \(Ptr addr) ->+ primMutableAddrSlideToStart addr (primOffsetOfE $ mbStart+start) (primOffsetOfE end)++-- | Thaw an immutable array.+--+-- The UArray must not be used after thawing.+unsafeThaw :: (PrimType ty, PrimMonad prim) => UArray ty -> prim (MUArray ty (PrimState prim))+unsafeThaw (UVecBA start len pinnedState ba) = primitive $ \st -> (# st, MUVecMA start len pinnedState (unsafeCoerce# ba) #)+unsafeThaw (UVecAddr start len fptr) = return $ MUVecAddr start len fptr+{-# INLINE unsafeThaw #-}++-- | Create a new array of size @n by settings each cells through the+-- function @f.+create :: PrimType ty+ => Int -- ^ the size of the array+ -> (Int -> ty) -- ^ the function that set the value at the index+ -> UArray ty -- ^ the array created+create n initializer+ | n == 0 = empty+ | otherwise = runST (new (Size n) >>= iter initializer)+ where+ iter :: (PrimType ty, PrimMonad prim) => (Int -> ty) -> MUArray ty (PrimState prim) -> prim (UArray ty)+ iter f ma = loop 0+ where+ loop i+ | i == n = unsafeFreeze ma+ | otherwise = unsafeWrite ma i (f i) >> loop (i+1)+ {-# INLINE loop #-}+ {-# INLINE iter #-}++-- | Create a pinned array that is filled by a 'filler' function (typically an IO call like hGetBuf)+createFromIO :: PrimType ty+ => Int -- ^ the size of the array+ -> (Ptr ty -> IO Int) -- ^ filling function that+ -> IO (UArray ty)+createFromIO size filler+ | size == 0 = return empty+ | otherwise = do+ mba <- newPinned (Size size)+ r <- withMutablePtr mba $ \p -> filler p+ case r of+ 0 -> return empty -- make sure we don't keep our array referenced by using empty+ _ | r < 0 -> error "filler returned negative number"+ | otherwise -> unsafeFreezeShrink mba (Size r)++-----------------------------------------------------------------------+-- higher level collection implementation+-----------------------------------------------------------------------++empty :: PrimType ty => UArray ty+empty = UVecAddr (Offset 0) (Size 0) (FinalPtr $ error "empty de-referenced")++singleton :: PrimType ty => ty -> UArray ty+singleton ty = create 1 (\_ -> ty)++-- | make an array from a list of elements.+vFromList :: PrimType ty => [ty] -> UArray ty+vFromList l = runST $ do+ ma <- new (Size len)+ iter 0 l $ \i x -> unsafeWrite ma i x+ unsafeFreeze ma+ where len = Data.List.length l+ iter _ [] _ = return ()+ iter i (x:xs) z = z i x >> iter (i+1) xs z++-- | transform an array to a list.+vToList :: PrimType ty => UArray ty -> [ty]+vToList a+ | null a = []+ | otherwise = runST (unsafeIndexer a go)+ where+ !len = length a+ go :: (Offset ty -> ty) -> ST s [ty]+ go getIdx = return $ loop azero+ where+ loop i | i == Offset len = []+ | otherwise = getIdx i : loop (i+Offset 1)+ {-# INLINE go #-}++-- | Check if two vectors are identical+equal :: (PrimType ty, Eq ty) => UArray ty -> UArray ty -> Bool+equal a b+ | la /= lb = False+ | otherwise = loop 0+ where+ !la = length a+ !lb = length b+ loop n | n == la = True+ | otherwise = (unsafeIndex a n == unsafeIndex b n) && loop (n+1)++{-+sizeEqual :: PrimType ty => UArray ty -> UArray ty -> Bool+sizeEqual a b = length a == length b -- TODO optimise with direct comparaison of bytes or elements when possible+-}++-- | Compare 2 vectors+vCompare :: (Ord ty, PrimType ty) => UArray ty -> UArray ty -> Ordering+vCompare a b = loop 0+ where+ !la = length a+ !lb = length b+ loop n+ | n == la = if la == lb then EQ else LT+ | n == lb = GT+ | otherwise =+ case unsafeIndex a n `compare` unsafeIndex b n of+ EQ -> loop (n+1)+ r -> r++-- | Append 2 arrays together by creating a new bigger array+append :: PrimType ty => UArray ty -> UArray ty -> UArray ty+append a b+ | la == azero = b+ | lb == azero = a+ | otherwise = runST $ do+ r <- new (la+lb)+ ma <- unsafeThaw a+ mb <- unsafeThaw b+ copyAt r (Offset 0) ma (Offset 0) la+ copyAt r (sizeAsOffset la) mb (Offset 0) lb+ unsafeFreeze r+ where+ !la = lengthSize a+ !lb = lengthSize b++concat :: PrimType ty => [UArray ty] -> UArray ty+concat [] = empty+concat l =+ case filterAndSum (Size 0) [] l of+ (_,[]) -> empty+ (_,[x]) -> x+ (totalLen,chunks) -> runST $ do+ r <- new totalLen+ doCopy r (Offset 0) chunks+ unsafeFreeze r+ where+ -- TODO would go faster not to reverse but pack from the end instead+ filterAndSum !totalLen acc [] = (totalLen, Prelude.reverse acc)+ filterAndSum !totalLen acc (x:xs)+ | len == Size 0 = filterAndSum totalLen acc xs+ | otherwise = filterAndSum (len+totalLen) (x:acc) xs+ where len = lengthSize x++ doCopy _ _ [] = return ()+ doCopy r i (x:xs) = do+ unsafeCopyAtRO r i x (Offset 0) lx+ doCopy r (i `offsetPlusE` lx) xs+ where lx = lengthSize x++-- | update an array by creating a new array with the updates.+--+-- the operation copy the previous array, modify it in place, then freeze it.+update :: PrimType ty+ => UArray ty+ -> [(Int, ty)]+ -> UArray ty+update array modifiers = runST (thaw array >>= doUpdate modifiers)+ where doUpdate l ma = loop l+ where loop [] = unsafeFreeze ma+ loop ((i,v):xs) = write ma i v >> loop xs+ {-# INLINE loop #-}+ {-# INLINE doUpdate #-}++unsafeUpdate :: PrimType ty+ => UArray ty+ -> [(Int, ty)]+ -> UArray ty+unsafeUpdate array modifiers = runST (thaw array >>= doUpdate modifiers)+ where doUpdate l ma = loop l+ where loop [] = unsafeFreeze ma+ loop ((i,v):xs) = unsafeWrite ma i v >> loop xs+ {-# INLINE loop #-}+ {-# INLINE doUpdate #-}++withPtr :: PrimType ty+ => UArray ty+ -> (Ptr ty -> IO a)+ -> IO a+withPtr vec@(UVecAddr start _ fptr) f =+ withFinalPtr fptr (\ptr -> f (ptr `plusPtr` os))+ where+ sz = primSizeInBytes (vectorProxyTy vec)+ !(Offset os) = offsetOfE sz start+withPtr vec@(UVecBA start _ pstatus a) f+ | isPinned pstatus = f (Ptr (byteArrayContents# a) `plusPtr` os)+ | otherwise = do+ -- TODO don't copy the whole vector, and just allocate+copy the slice.+ let !sz# = sizeofByteArray# a+ a' <- primitive $ \s -> do+ case newAlignedPinnedByteArray# sz# 8# s of { (# s2, mba #) ->+ case copyByteArray# a 0# mba 0# sz# s2 of { s3 ->+ case unsafeFreezeByteArray# mba s3 of { (# s4, ba #) ->+ (# s4, Ptr (byteArrayContents# ba) `plusPtr` os #) }}}+ f a'+ where+ sz = primSizeInBytes (vectorProxyTy vec)+ !(Offset os) = offsetOfE sz start++withMutablePtr :: PrimType ty+ => MUArray ty RealWorld+ -> (Ptr ty -> IO a)+ -> IO a+withMutablePtr muvec f = do+ v <- unsafeFreeze muvec+ withPtr v f++recast :: (PrimType a, PrimType b) => UArray a -> UArray b+recast = recast_ Proxy Proxy+ where+ recast_ :: (PrimType a, PrimType b)+ => Proxy a -> Proxy b -> UArray a -> UArray b+ recast_ pa pb array+ | aTypeSize == bTypeSize = unsafeRecast array+ | missing == 0 = unsafeRecast array+ | otherwise = throw $ InvalidRecast+ (RecastSourceSize alen)+ (RecastDestinationSize $ alen + missing)+ where+ aTypeSize@(Size as) = primSizeInBytes pa+ bTypeSize@(Size bs) = primSizeInBytes pb+ alen = length array * as+ missing = alen `mod` bs++unsafeRecast :: (PrimType a, PrimType b) => UArray a -> UArray b+unsafeRecast (UVecBA start len pinStatus b) = UVecBA (primOffsetRecast start) (sizeRecast len) pinStatus b+unsafeRecast (UVecAddr start len a) = UVecAddr (primOffsetRecast start) (sizeRecast len) (castFinalPtr a)++null :: UArray ty -> Bool+null (UVecBA _ sz _ _) = sz == Size 0+null (UVecAddr _ l _) = l == Size 0++take :: PrimType ty => Int -> UArray ty -> UArray ty+take nbElems v+ | nbElems <= 0 = empty+ | n == vlen = v+ | otherwise =+ case v of+ UVecBA start _ pinst ba -> UVecBA start n pinst ba+ UVecAddr start _ fptr -> UVecAddr start n fptr+ where+ n = min (Size nbElems) vlen+ vlen = lengthSize v++drop :: PrimType ty => Int -> UArray ty -> UArray ty+drop nbElems v+ | nbElems <= 0 = v+ | n == vlen = empty+ | otherwise =+ case v of+ UVecBA start len pinst ba -> UVecBA (start `offsetPlusE` n) (len - n) pinst ba+ UVecAddr start len fptr -> UVecAddr (start `offsetPlusE` n) (len - n) fptr+ where+ n = min (Size nbElems) vlen+ vlen = lengthSize v++splitAt :: PrimType ty => Int -> UArray ty -> (UArray ty, UArray ty)+splitAt nbElems v+ | nbElems <= 0 = (empty, v)+ | n == Size vlen = (v, empty)+ | otherwise =+ case v of+ UVecBA start len pinst ba -> ( UVecBA start n pinst ba+ , UVecBA (start `offsetPlusE` n) (len - n) pinst ba)+ UVecAddr start len fptr -> ( UVecAddr start n fptr+ , UVecAddr (start `offsetPlusE` n) (len - n) fptr)+ where+ n = Size $ min nbElems vlen+ vlen = length v++splitElem :: PrimType ty => ty -> UArray ty -> (# UArray ty, UArray ty #)+splitElem !ty r@(UVecBA start len pinst ba)+ | k == end = (# r, empty #)+ | k == start = (# empty, r #)+ | otherwise =+ (# UVecBA start (offsetAsSize k) pinst ba+ , UVecBA (start `offsetPlusE` (offsetAsSize k)) (len - offsetAsSize k) pinst ba+ #)+ where+ !end = start `offsetPlusE` len+ !k = loop start+ loop !i | i < end && t /= ty = loop (i+Offset 1)+ | otherwise = i+ where !t = primBaIndex ba i+splitElem ty r@(UVecAddr start len fptr)+ | k == end = (# r, empty #)+ | otherwise =+ (# UVecAddr start (offsetAsSize k) fptr+ , UVecAddr (start `offsetPlusE` offsetAsSize k) (len - offsetAsSize k) fptr #)+ where+ !(Ptr addr) = withFinalPtrNoTouch fptr id+ !end = start `offsetPlusE` len+ !k = loop start+ loop !i | i < end && t /= ty = loop (i+Offset 1)+ | otherwise = i+ where t = primAddrIndex addr i+{-# SPECIALIZE [3] splitElem :: Word8 -> UArray Word8 -> (# UArray Word8, UArray Word8 #) #-}+{-# SPECIALIZE [3] splitElem :: Word32 -> UArray Word32 -> (# UArray Word32, UArray Word32 #) #-}++revTake :: PrimType ty => Int -> UArray ty -> UArray ty+revTake nbElems v = drop (length v - nbElems) v++revDrop :: PrimType ty => Int -> UArray ty -> UArray ty+revDrop nbElems v = take (length v - nbElems) v++revSplitAt :: PrimType ty => Int -> UArray ty -> (UArray ty, UArray ty)+revSplitAt n v = (drop idx v, take idx v)+ where idx = length v - n++splitOn :: PrimType ty => (ty -> Bool) -> UArray ty -> [UArray ty]+splitOn xpredicate ivec+ | len == 0 = []+ | otherwise = runST $ unsafeIndexer ivec (go ivec xpredicate)+ where+ !len = length ivec+ go :: PrimType ty => UArray ty -> (ty -> Bool) -> (Offset ty -> ty) -> ST s [UArray ty]+ go v predicate getIdx = return (loop azero azero)+ where+ loop !prevIdx@(Offset prevIdxo) !idx@(Offset idxo)+ | idx == Offset len = [sub v prevIdxo idxo]+ | otherwise =+ let e = getIdx idx+ idx' = idx + Offset 1+ in if predicate e+ then sub v prevIdxo idxo : loop idx' idx'+ else loop prevIdx idx'+ {-# INLINE go #-}++sub :: PrimType ty => UArray ty -> Int -> Int -> UArray ty+sub vec startIdx expectedEndIdx+ | startIdx >= endIdx = empty+ | otherwise =+ case vec of+ UVecBA start _ pinst ba -> UVecBA (start + Offset startIdx) newLen pinst ba+ UVecAddr start _ fptr -> UVecAddr (start + Offset startIdx) newLen fptr+ where+ newLen = Offset endIdx - Offset startIdx+ endIdx = min expectedEndIdx len+ len = length vec++findIndex :: PrimType ty => ty -> UArray ty -> Maybe Int+findIndex tyOuter ba = runST $ unsafeIndexer ba (go tyOuter)+ where+ !len = length ba++ go :: PrimType ty => ty -> (Offset ty -> ty) -> ST s (Maybe Int)+ go ty getIdx = loop (Offset 0)+ where+ loop ofs@(Offset i)+ | ofs == Offset len = return Nothing+ | getIdx ofs == ty = return $ Just i+ | otherwise = loop (ofs + Offset 1)+{-# SPECIALIZE [3] findIndex :: Word8 -> UArray Word8 -> Maybe Int #-}++break :: PrimType ty => (ty -> Bool) -> UArray ty -> (UArray ty, UArray ty)+break xpredicate xv+ | len == 0 = (empty, empty)+ | otherwise = runST $ unsafeIndexer xv (go xv xpredicate)+ where+ !len = length xv+ go :: PrimType ty => UArray ty -> (ty -> Bool) -> (Offset ty -> ty) -> ST s (UArray ty, UArray ty)+ go v predicate getIdx = return (findBreak $ Offset 0)+ where+ findBreak !i@(Offset io)+ | i == Offset len = (v, empty)+ | predicate (getIdx i) = splitAt io v+ | otherwise = findBreak (i + Offset 1)+ {-# INLINE findBreak #-}+ {-# INLINE go #-}+{-# NOINLINE [2] break #-}+{-# SPECIALIZE [2] break :: (Word8 -> Bool) -> UArray Word8 -> (UArray Word8, UArray Word8) #-}++{-# RULES "break (== ty)" [3] forall (x :: forall ty . PrimType ty => ty) . break (== x) = breakElem x #-}+{-# RULES "break (ty ==)" [3] forall (x :: forall ty . PrimType ty => ty) . break (x ==) = breakElem x #-}+{-# RULES "break (== ty)" [3] forall (x :: Word8) . break (== x) = breakElem x #-}++breakElem :: PrimType ty => ty -> UArray ty -> (UArray ty, UArray ty)+breakElem xelem xv = let (# v1, v2 #) = splitElem xelem xv in (v1, v2)+{-# SPECIALIZE [2] breakElem :: Word8 -> UArray Word8 -> (UArray Word8, UArray Word8) #-}+{-# SPECIALIZE [2] breakElem :: Word32 -> UArray Word32 -> (UArray Word32, UArray Word32) #-}++intersperse :: PrimType ty => ty -> UArray ty -> UArray ty+intersperse sep v+ | len <= 1 = v+ | otherwise = runST $ unsafeCopyFrom v (len * 2 - 1) (go sep)+ where len = length v+ go :: PrimType ty => ty -> UArray ty -> Int -> MUArray ty s -> ST s ()+ go sep' oldV oldI newV+ | oldI == len - 1 = unsafeWrite newV newI e+ | otherwise = do+ unsafeWrite newV newI e+ unsafeWrite newV (newI + 1) sep'+ where+ e = unsafeIndex oldV oldI+ newI = oldI * 2++span :: PrimType ty => (ty -> Bool) -> UArray ty -> (UArray ty, UArray ty)+span p = break (not . p)++map :: (PrimType a, PrimType b) => (a -> b) -> UArray a -> UArray b+map f a = create (length a) (\i -> f $ unsafeIndex a i)++mapIndex :: (PrimType a, PrimType b) => (Int -> a -> b) -> UArray a -> UArray b+mapIndex f a = create (length a) (\i -> f i $ unsafeIndex a i)++cons :: PrimType ty => ty -> UArray ty -> UArray ty+cons e vec+ | len == Size 0 = singleton e+ | otherwise = runST $ do+ muv <- new (len + Size 1)+ unsafeCopyAtRO muv (Offset 1) vec (Offset 0) len+ unsafeWrite muv 0 e+ unsafeFreeze muv+ where+ !len = lengthSize vec++snoc :: PrimType ty => UArray ty -> ty -> UArray ty+snoc vec e+ | len == Size 0 = singleton e+ | otherwise = runST $ do+ muv <- new (len + Size 1)+ unsafeCopyAtRO muv (Offset 0) vec (Offset 0) len+ unsafeWrite muv (length vec) e+ unsafeFreeze muv+ where+ !len = lengthSize vec++uncons :: PrimType ty => UArray ty -> Maybe (ty, UArray ty)+uncons vec+ | nbElems == 0 = Nothing+ | otherwise = Just (unsafeIndex vec 0, sub vec 1 nbElems)+ where+ !nbElems = length vec++unsnoc :: PrimType ty => UArray ty -> Maybe (UArray ty, ty)+unsnoc vec+ | nbElems == 0 = Nothing+ | otherwise = Just (sub vec 0 lastElem, unsafeIndex vec lastElem)+ where+ !lastElem = nbElems - 1+ !nbElems = length vec++find :: PrimType ty => (ty -> Bool) -> UArray ty -> Maybe ty+find predicate vec = loop 0+ where+ !len = length vec+ loop i+ | i == len = Nothing+ | otherwise =+ let e = unsafeIndex vec i+ in if predicate e then Just e else loop (i+1)++sortBy :: PrimType ty => (ty -> ty -> Ordering) -> UArray ty -> UArray ty+sortBy xford vec = runST (thaw vec >>= doSort xford)+ where+ len = length vec+ doSort :: (PrimType ty, PrimMonad prim) => (ty -> ty -> Ordering) -> MUArray ty (PrimState prim) -> prim (UArray ty)+ doSort ford ma = qsort 0 (len - 1) >> unsafeFreeze ma+ where+ qsort lo hi+ | lo >= hi = return ()+ | otherwise = do+ p <- partition lo hi+ qsort lo (p-1)+ qsort (p+1) hi+ partition lo hi = do+ pivot <- unsafeRead ma hi+ let loop i j+ | j == hi = return i+ | otherwise = do+ aj <- unsafeRead ma j+ i' <- if ford aj pivot == GT+ then return i+ else do+ ai <- unsafeRead ma i+ unsafeWrite ma j ai+ unsafeWrite ma i aj+ return $ i + 1+ loop i' (j+1)++ i <- loop lo lo+ ai <- unsafeRead ma i+ ahi <- unsafeRead ma hi+ unsafeWrite ma hi ai+ unsafeWrite ma i ahi+ return i++filter :: PrimType ty => (ty -> Bool) -> UArray ty -> UArray ty+filter predicate vec = vFromList $ Data.List.filter predicate $ vToList vec++reverse :: PrimType ty => UArray ty -> UArray ty+reverse a = create len toEnd+ where+ len = length a+ toEnd i = unsafeIndex a (len - i - 1)++foldl :: PrimType ty => (a -> ty -> a) -> a -> UArray ty -> a+foldl f initialAcc vec = loop 0 initialAcc+ where+ len = length vec+ loop i acc+ | i == len = acc+ | otherwise = loop (i+1) (f acc (unsafeIndex vec i))++foldr :: PrimType ty => (ty -> a -> a) -> a -> UArray ty -> a+foldr f initialAcc vec = loop 0+ where+ len = length vec+ loop i+ | i == len = initialAcc+ | otherwise = unsafeIndex vec i `f` loop (i+1)++foldl' :: PrimType ty => (a -> ty -> a) -> a -> UArray ty -> a+foldl' f initialAcc vec = loop 0 initialAcc+ where+ len = length vec+ loop i !acc+ | i == len = acc+ | otherwise = loop (i+1) (f acc (unsafeIndex vec i))
+ Foundation/Array/Unboxed/Builder.hs view
@@ -0,0 +1,61 @@+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+module Foundation.Array.Unboxed.Builder+ ( ArrayBuilder+ , appendTy+ , build+ ) where++import Foundation.Array.Unboxed+import Foundation.Array.Unboxed.Mutable+import Foundation.Internal.Base+import Foundation.Internal.MonadTrans+import Foundation.Internal.Types+import Foundation.Number+import Foundation.Primitive.Monad+import Foundation.Primitive.Types+import qualified Data.List++-- | A Array being built chunks by chunks+--+-- The previous buffers are in reverse order, and+-- this contains the current buffer and the state of+-- progress packing ty inside.+data ArrayBuildingState ty st = ArrayBuildingState+ { prevBuffers :: [UArray ty]+ , currentBuffer :: MUArray ty st+ , currentOffset :: !(Offset ty)+ , chunkSize :: !(Size ty)+ }++newtype ArrayBuilder ty st a = ArrayBuilder { runArrayBuilder :: State (ArrayBuildingState ty (PrimState st)) st a }+ deriving (Functor,Applicative,Monad)++appendTy :: (PrimMonad st, PrimType ty, Monad st) => ty -> ArrayBuilder ty st ()+appendTy v = ArrayBuilder $ State $ \st ->+ if offsetAsSize (currentOffset st) == chunkSize st+ then do+ newChunk <- new (chunkSize st)+ cur <- unsafeFreeze (currentBuffer st)+ write newChunk 0 v+ return ((), st { prevBuffers = cur : prevBuffers st+ , currentOffset = Offset 1+ , currentBuffer = newChunk+ })+ else do+ let (Offset ofs) = currentOffset st+ write (currentBuffer st) ofs v+ return ((), st { currentOffset = currentOffset st + Offset 1 })++build :: (PrimMonad prim, PrimType ty)+ => Int -- ^ size of chunks (elements)+ -> ArrayBuilder ty prim () -- ^ ..+ -> prim (UArray ty)+build sizeChunksI origab = call origab (Size sizeChunksI)+ where+ call :: (PrimType ty, PrimMonad prim)+ => ArrayBuilder ty prim () -> Size ty -> prim (UArray ty)+ call ab sizeChunks = do+ m <- new sizeChunks+ ((), st) <- runState (runArrayBuilder ab) (ArrayBuildingState [] m (Offset 0) sizeChunks)+ current <- unsafeFreezeShrink (currentBuffer st) (offsetAsSize $ currentOffset st)+ return $ mconcat $ Data.List.reverse (current:prevBuffers st)
+ Foundation/Array/Unboxed/ByteArray.hs view
@@ -0,0 +1,37 @@+module Foundation.Array.Unboxed.ByteArray+ ( MutableByteArray+ , mutableByteArraySet+ , mutableByteArraySetBetween+ , mutableByteArrayMove+ ) where++import Foundation.Internal.Base+import Foundation.Primitive.Monad+import Foundation.Array.Common+import Foundation.Array.Unboxed.Mutable+import Foundation.Number+import Control.Monad (forM_)+import qualified Foundation.Collection as C++-- | Mutable Byte Array alias+type MutableByteArray st = MUArray Word8 st++mutableByteArraySet :: PrimMonad prim => MUArray Word8 (PrimState prim) -> Word8 -> prim ()+mutableByteArraySet mba val = do+ -- naive haskell way. TODO: call memset or a 32-bit/64-bit method+ forM_ [0..(len-1)] $ \i -> C.mutUnsafeWrite mba i val+ where+ len = mutableLength mba++mutableByteArraySetBetween :: PrimMonad prim => MUArray Word8 (PrimState prim) -> Word8 -> Int -> Int -> prim ()+mutableByteArraySetBetween mba val offset size+ | offset < 0 = throw (OutOfBound OOB_MemSet offset len)+ | offset > len || offset+size > len = throw (OutOfBound OOB_MemSet (offset+size) len)+ | otherwise =+ -- TODO same as mutableByteArraySet+ forM_ [offset..(offset+size-1)] $ \i -> C.mutUnsafeWrite mba i val+ where+ len = mutableLength mba++mutableByteArrayMove :: PrimMonad prim => MUArray Word8 (PrimState prim) -> Int -> Int -> Int -> prim ()+mutableByteArrayMove _mba _ofs _sz = undefined
+ Foundation/Array/Unboxed/Mutable.hs view
@@ -0,0 +1,212 @@+-- |+-- Module : Foundation.Array.Unboxed.Mutable+-- License : BSD-style+-- Maintainer : Vincent Hanquez <vincent@snarc.org>+-- Stability : experimental+-- Portability : portable+--+-- A simple array abstraction that allow to use typed+-- array of bytes where the array is pinned in memory+-- to allow easy use with Foreign interfaces, ByteString+-- and always aligned to 64 bytes.+--+{-# LANGUAGE MagicHash #-}+{-# LANGUAGE UnboxedTuples #-}+module Foundation.Array.Unboxed.Mutable+ ( MUArray(..)+ -- * Property queries+ , sizeInMutableBytesOfContent+ , mutableLength+ , mutableSame+ -- * Allocation & Copy+ , new+ , newPinned+ , newNative+ , mutableForeignMem+ , copyAt+ -- , copyAddr+ -- * Reading and Writing cells+ , unsafeWrite+ , unsafeRead+ , write+ , read+ ) where++import GHC.Prim+import GHC.Types+import GHC.Ptr+import Foundation.Internal.Base+import Foundation.Internal.Types+import Foundation.Internal.Primitive+import Foundation.Internal.Proxy+import Foundation.Primitive.Monad+import Foundation.Primitive.Types+import Foundation.Primitive.FinalPtr+import Foundation.Array.Common+import Foundation.Number+-- import Foreign.Marshal.Utils (copyBytes)++-- | A Mutable array of types built on top of GHC primitive.+--+-- Element in this array can be modified in place.+data MUArray ty st =+ MUVecMA {-# UNPACK #-} !(Offset ty)+ {-# UNPACK #-} !(Size ty)+ {-# UNPACK #-} !PinnedStatus+ (MutableByteArray# st)+ | MUVecAddr {-# UNPACK #-} !(Offset ty)+ {-# UNPACK #-} !(Size ty)+ !(FinalPtr ty)++mutableArrayProxyTy :: MUArray ty st -> Proxy ty+mutableArrayProxyTy _ = Proxy++sizeInMutableBytesOfContent :: PrimType ty => MUArray ty s -> Size8+sizeInMutableBytesOfContent = primSizeInBytes . mutableArrayProxyTy+{-# INLINE sizeInMutableBytesOfContent #-}++-- | read a cell in a mutable array.+--+-- If the index is out of bounds, an error is raised.+read :: (PrimMonad prim, PrimType ty) => MUArray ty (PrimState prim) -> Int -> prim ty+read array n+ | n < 0 || n >= len = primThrow (OutOfBound OOB_Read n len)+ | otherwise = unsafeRead array n+ where len = mutableLength array+{-# INLINE read #-}++-- | read from a cell in a mutable array without bounds checking.+--+-- Reading from invalid memory can return unpredictable and invalid values.+-- use 'read' if unsure.+unsafeRead :: (PrimMonad prim, PrimType ty) => MUArray ty (PrimState prim) -> Int -> prim ty+unsafeRead (MUVecMA start _ _ mba) i = primMbaRead mba (start+.i)+unsafeRead (MUVecAddr start _ fptr) i = withFinalPtr fptr $ \(Ptr addr) -> primAddrRead addr (start+.i)+{-# INLINE unsafeRead #-}++-- | Write to a cell in a mutable array.+--+-- If the index is out of bounds, an error is raised.+write :: (PrimMonad prim, PrimType ty) => MUArray ty (PrimState prim) -> Int -> ty -> prim ()+write array n val+ | n < 0 || n >= len = primThrow (OutOfBound OOB_Write n len)+ | otherwise = unsafeWrite array n val+ where+ len = mutableLength array+{-# INLINE write #-}++-- | write to a cell in a mutable array without bounds checking.+--+-- Writing with invalid bounds will corrupt memory and your program will+-- become unreliable. use 'write' if unsure.+unsafeWrite :: (PrimMonad prim, PrimType ty) => MUArray ty (PrimState prim) -> Int -> ty -> prim ()+unsafeWrite (MUVecMA start _ _ mba) i v = primMbaWrite mba (start+.i) v+unsafeWrite (MUVecAddr start _ fptr) i v = withFinalPtr fptr $ \(Ptr addr) -> primAddrWrite addr (start+.i) v+{-# INLINE unsafeWrite #-}++-- | Create a new pinned mutable array of size @n.+--+-- all the cells are uninitialized and could contains invalid values.+--+-- All mutable arrays are allocated on a 64 bits aligned addresses+newPinned :: (PrimMonad prim, PrimType ty) => Size ty -> prim (MUArray ty (PrimState prim))+newPinned n = newFake n Proxy+ where newFake :: (PrimMonad prim, PrimType ty) => Size ty -> Proxy ty -> prim (MUArray ty (PrimState prim))+ newFake sz ty = primitive $ \s1 ->+ case newAlignedPinnedByteArray# bytes 8# s1 of+ (# s2, mba #) -> (# s2, MUVecMA (Offset 0) sz pinned mba #)+ where+ !(Size (I# bytes)) = sizeOfE (primSizeInBytes ty) sz+ {-# INLINE newFake #-}+{-# INLINE new #-}++newUnpinned :: (PrimMonad prim, PrimType ty) => Size ty -> prim (MUArray ty (PrimState prim))+newUnpinned n = newFake n Proxy+ where newFake :: (PrimMonad prim, PrimType ty) => Size ty -> Proxy ty -> prim (MUArray ty (PrimState prim))+ newFake sz ty = primitive $ \s1 ->+ case newByteArray# bytes s1 of+ (# s2, mba #) -> (# s2, MUVecMA (Offset 0) sz unpinned mba #)+ where+ !(Size (I# bytes)) = sizeOfE (primSizeInBytes ty) sz+ {-# INLINE newFake #-}++-- | Create a new mutable array of size @n.+--+-- TODO: heuristic to allocated unpinned (< 1K for example)+new :: (PrimMonad prim, PrimType ty) => Size ty -> prim (MUArray ty (PrimState prim))+new sz@(Size n)+ | n > 0 = newPinned sz+ | otherwise = newUnpinned sz+++mutableSame :: MUArray ty st -> MUArray ty st -> Bool+mutableSame (MUVecMA sa ea _ ma) (MUVecMA sb eb _ mb) = and [ sa == sb, ea == eb, bool# (sameMutableByteArray# ma mb)]+mutableSame (MUVecAddr s1 e1 f1) (MUVecAddr s2 e2 f2) = and [ s1 == s2, e1 == e2, finalPtrSameMemory f1 f2 ]+mutableSame (MUVecMA {}) (MUVecAddr {}) = False+mutableSame (MUVecAddr {}) (MUVecMA {}) = False+++newNative :: (PrimMonad prim, PrimType ty) => Size ty -> (MutableByteArray# (PrimState prim) -> prim ()) -> prim (MUArray ty (PrimState prim))+newNative n f = do+ muvec <- new n+ case muvec of+ (MUVecMA _ _ _ mba) -> f mba >> return muvec+ (MUVecAddr {}) -> error "internal error: unboxed new only supposed to allocate natively"++mutableForeignMem :: (PrimMonad prim, PrimType ty)+ => FinalPtr ty -- ^ the start pointer with a finalizer+ -> Int -- ^ the number of elements (in elements, not bytes)+ -> prim (MUArray ty (PrimState prim))+mutableForeignMem fptr nb = return $ MUVecAddr (Offset 0) (Size nb) fptr++-- | Copy a number of elements from an array to another array with offsets+copyAt :: (PrimMonad prim, PrimType ty)+ => MUArray ty (PrimState prim) -- ^ destination array+ -> Offset ty -- ^ offset at destination+ -> MUArray ty (PrimState prim) -- ^ source array+ -> Offset ty -- ^ offset at source+ -> Size ty -- ^ number of elements to copy+ -> prim ()+copyAt (MUVecMA dstStart _ _ dstMba) ed uvec@(MUVecMA srcStart _ _ srcBa) es n =+ primitive $ \st -> (# copyMutableByteArray# srcBa os dstMba od nBytes st, () #)+ where+ !sz = primSizeInBytes (mutableArrayProxyTy uvec)+ !(Offset (I# os)) = offsetOfE sz (srcStart + es)+ !(Offset (I# od)) = offsetOfE sz (dstStart + ed)+ !(Size (I# nBytes)) = sizeOfE sz n+copyAt (MUVecMA dstStart _ _ dstMba) ed muvec@(MUVecAddr srcStart _ srcFptr) es n =+ withFinalPtr srcFptr $ \srcPtr ->+ let !(Ptr srcAddr) = srcPtr `plusPtr` os+ in primitive $ \s -> (# compatCopyAddrToByteArray# srcAddr dstMba od nBytes s, () #)+ where+ !sz = primSizeInBytes (mutableArrayProxyTy muvec)+ !(Offset os) = offsetOfE sz (srcStart + es)+ !(Offset (I# od)) = offsetOfE sz (dstStart + ed)+ !(Size (I# nBytes)) = sizeOfE sz n+copyAt dst od src os n = loop od os+ where+ !(Offset endIndex) = os `offsetPlusE` n+ loop !(Offset d) !(Offset i)+ | i == endIndex = return ()+ | otherwise = unsafeRead src i >>= unsafeWrite dst d >> loop (Offset $ d+1) (Offset $ i+1)++{-+copyAddr :: (PrimMonad prim, PrimType ty)+ => MUArray ty (PrimState prim) -- ^ destination array+ -> Offset ty -- ^ offset at destination+ -> Ptr Word8 -- ^ source ptr+ -> Offset ty -- ^ offset at source+ -> Size ty -- ^ number of elements to copy+ -> prim ()+copyAddr (MUVecMA dstStart _ _ dst) dstOfs (Ptr src) srcOfs sz = primitive $ \s ->+ (# compatCopyAddrToByteArray# (plusAddr# src os) dst od sz s, () #)+copyAddr (MUVecAddr start _ fptr) od src os sz =+ withFinalPtr fptr $ \dst ->+ unsafePrimFromIO $ copyBytes (dst `plusPtr` od) (src `plusPtr` os) sz+ --memcpy addr to addr+ -}++-- | return the numbers of elements in a mutable array+mutableLength :: PrimType ty => MUArray ty st -> Int+mutableLength (MUVecMA _ (Size end) _ _) = end+mutableLength (MUVecAddr _ (Size end) _) = end
+ Foundation/Collection.hs view
@@ -0,0 +1,32 @@+-- |+-- Module : Foundation.Collection+-- License : BSD-style+-- Maintainer : Vincent Hanquez <vincent@snarc.org>+-- Stability : experimental+-- Portability : portable+--+-- Different collections (list, vector, string, ..) unified under 1 API.+-- an API to rules them all, and in the darkness bind them.+--+{-# LANGUAGE DefaultSignatures #-}+{-# LANGUAGE FlexibleInstances #-}+module Foundation.Collection+ ( BoxedZippable(..)+ , Element+ , InnerFunctor(..)+ , Foldable(..)+ , Sequential(..)+ , MutableCollection(..)+ , IndexedCollection(..)+ , KeyedCollection(..)+ , Zippable(..)+ ) where++import Foundation.Collection.Element+import Foundation.Collection.Foldable+import Foundation.Collection.Indexed+import Foundation.Collection.InnerFunctor+import Foundation.Collection.Keyed+import Foundation.Collection.Mutable+import Foundation.Collection.Sequential+import Foundation.Collection.Zippable
+ Foundation/Collection/Element.hs view
@@ -0,0 +1,17 @@+-- |+-- Module : Foundation.Array.Element+-- License : BSD-style+-- Maintainer : Vincent Hanquez <vincent@snarc.org>+-- Stability : experimental+-- Portability : portable+--+module Foundation.Collection.Element+ ( Element+ ) where++import Foundation.Array.Unboxed (UArray)++-- | Element type of a collection+type family Element container+type instance Element [a] = a+type instance Element (UArray ty) = ty
+ Foundation/Collection/Foldable.hs view
@@ -0,0 +1,56 @@+-- |+-- Module : Foundation.Primitive.Foldable+-- License : BSD-style+-- Maintainer : Vincent Hanquez <vincent@snarc.org>+-- Stability : experimental+-- Portability : portable+--+-- A mono-morphic re-thinking of the Foldable class+--+module Foundation.Collection.Foldable+ ( Foldable(..)+ ) where++import Foundation.Internal.Base+import Foundation.Collection.Element+import qualified Data.List+import qualified Foundation.Array.Unboxed as UV++-- | Give the ability to fold a collection on itself+class Foldable collection where+ -- | Left-associative fold of a structure.+ --+ -- In the case of lists, foldl, when applied to a binary operator, a starting value (typically the left-identity of the operator), and a list, reduces the list using the binary operator, from left to right:+ --+ -- > foldl f z [x1, x2, ..., xn] == (...((z `f` x1) `f` x2) `f`...) `f` xn+ -- Note that to produce the outermost application of the operator the entire input list must be traversed. This means that foldl' will diverge if given an infinite list.+ --+ -- Also note that if you want an efficient left-fold, you probably want to use foldl' instead of foldl. The reason for this is that latter does not force the "inner" results (e.g. z f x1 in the above example) before applying them to the operator (e.g. to (f x2)). This results in a thunk chain O(n) elements long, which then must be evaluated from the outside-in.+ foldl :: (a -> Element collection -> a) -> a -> collection -> a+++ -- | Left-associative fold of a structure but with strict application of the operator.+ foldl' :: (a -> Element collection -> a) -> a -> collection -> a++ -- | Right-associative fold of a structure.+ --+ -- > foldr f z [x1, x2, ..., xn] == x1 `f` (x2 `f` ... (xn `f` z)...)+ foldr :: (Element collection -> a -> a) -> a -> collection -> a++ -- | Right-associative fold of a structure, but with strict application of the operator.+ foldr' :: (Element collection -> a -> a) -> a -> collection -> a+ foldr' f z0 xs = foldl f' id xs z0 where f' k x z = k $! f x z++----------------------------+-- Foldable instances+----------------------------++instance Foldable [a] where+ foldl = Data.List.foldl+ foldr = Data.List.foldr+ foldl' = Data.List.foldl'++instance UV.PrimType ty => Foldable (UV.UArray ty) where+ foldl = UV.foldl+ foldr = UV.foldr+ foldl' = UV.foldl'
+ Foundation/Collection/Indexed.hs view
@@ -0,0 +1,42 @@+-- |+-- Module : Foundation.Array.Indexed+-- License : BSD-style+-- Maintainer : Vincent Hanquez <vincent@snarc.org>+-- Stability : experimental+-- Portability : portable+--+{-# LANGUAGE DefaultSignatures #-}+{-# LANGUAGE FlexibleInstances #-}+module Foundation.Collection.Indexed+ ( IndexedCollection(..)+ ) where++import Foundation.Internal.Base+import Foundation.Collection.Element+import qualified Data.List+import qualified Foundation.Array.Unboxed as UV++-- | Collection of elements that can indexed by int+class IndexedCollection c where+ (!) :: c -> Int -> Maybe (Element c)+ findIndex :: (Element c -> Bool) -> c -> Maybe Int++instance IndexedCollection [a] where+ (!) l n+ | n < 0 = Nothing+ | otherwise = case Data.List.drop n l of+ [] -> Nothing+ x:_ -> Just x+ findIndex = Data.List.findIndex++instance UV.PrimType ty => IndexedCollection (UV.UArray ty) where+ (!) l n+ | n < 0 || n >= UV.length l = Nothing+ | otherwise = Just $ UV.index l n+ findIndex predicate c = loop 0+ where+ !len = UV.length c+ loop i+ | i == len = Nothing+ | predicate (UV.unsafeIndex c i) = Just i+ | otherwise = Nothing
+ Foundation/Collection/InnerFunctor.hs view
@@ -0,0 +1,19 @@+{-# LANGUAGE DefaultSignatures #-}+module Foundation.Collection.InnerFunctor+ ( InnerFunctor(..)+ ) where++import Foundation.Internal.Base+import Foundation.Collection.Element+import qualified Foundation.Array.Unboxed as UV++-- | A monomorphic functor that maps the inner values to values of the same type+class InnerFunctor c where+ imap :: (Element c -> Element c) -> c -> c+ default imap :: (Functor f, Element (f a) ~ a, f a ~ c) => (a -> a) -> f a -> f a+ imap = fmap++instance InnerFunctor [a]++instance UV.PrimType ty => InnerFunctor (UV.UArray ty) where+ imap = UV.map
+ Foundation/Collection/Keyed.hs view
@@ -0,0 +1,26 @@+-- |+-- Module : Foundation.Array.Keyed+-- License : BSD-style+-- Maintainer : Vincent Hanquez <vincent@snarc.org>+-- Stability : experimental+-- Portability : portable+--+{-# LANGUAGE DefaultSignatures #-}+{-# LANGUAGE FlexibleInstances #-}+module Foundation.Collection.Keyed+ ( KeyedCollection(..)+ ) where++import Foundation.Internal.Base+import qualified Data.List++-- | Collection of things that can be looked up by Key+class KeyedCollection c where+ type Key c+ type Value c+ lookup :: Key c -> c -> Maybe (Value c)++instance Eq k => KeyedCollection [(k, v)] where+ type Key [(k,v)] = k+ type Value [(k,v)] = v+ lookup = Data.List.lookup
+ Foundation/Collection/List.hs view
@@ -0,0 +1,60 @@+-- |+-- Module : Foundation.Array.List+-- License : BSD-style+-- Maintainer : Vincent Hanquez <vincent@snarc.org>+-- Stability : experimental+-- Portability : portable+--+module Foundation.Collection.List+ ( wordsWhen+ , revTake+ , revDrop+ , revSplitAt+ , uncons+ , unsnoc+ ) where++import qualified Data.List+import Data.Tuple (swap)+import Foundation.Internal.Base+import Foundation.Number++-- | Simple helper to split a list repeatly when the predicate match+wordsWhen :: (x -> Bool) -> [x] -> [[x]]+wordsWhen _ [] = []+wordsWhen p is = loop is+ where+ loop s =+ let (w, s') = Data.List.break p s+ in case s' of+ [] -> [w]+ _:xs -> w : loop xs++revTake :: Int -> [a] -> [a]+revTake n l = Data.List.drop (len - n) l+ where+ len = Data.List.length l++revDrop :: Int -> [a] -> [a]+revDrop n l = Data.List.take (len - n) l+ where+ len = Data.List.length l++revSplitAt :: Int -> [a] -> ([a],[a])+revSplitAt n l = swap $ Data.List.splitAt (len - n) l+ where+ len = Data.List.length l++uncons :: [a] -> Maybe (a, [a])+uncons [] = Nothing+uncons (x:xs) = Just (x,xs)++unsnoc :: [a] -> Maybe ([a], a)+unsnoc [] = Nothing+unsnoc [x] = Just ([], x)+unsnoc [x,y] = Just ([x], y)+unsnoc (x:xs@(_:_)) = Just $ loop [x] xs+ where+ loop acc [y] = (Data.List.reverse acc, y)+ loop acc (y:ys) = loop (y:acc) ys+ loop _ _ = error "impossible"
+ Foundation/Collection/Mutable.hs view
@@ -0,0 +1,52 @@+-- |+-- Module : Foundation.Array.Mutable+-- License : BSD-style+-- Maintainer : Vincent Hanquez <vincent@snarc.org>+-- Stability : experimental+-- Portability : portable+--+module Foundation.Collection.Mutable+ ( MutableCollection(..)+ ) where++import Foundation.Primitive.Monad+import Foundation.Internal.Base++import qualified Foundation.Array.Unboxed.Mutable as MUV+import qualified Foundation.Array.Unboxed as UV++-- | Collection of things that can be made mutable, modified and then freezed into an immutable collection+class MutableCollection c where+ -- unfortunately: cannot set mutUnsafeWrite to default to mutWrite .. same for read..+ {-# MINIMAL thaw, freeze, mutWrite, mutRead, mutUnsafeWrite, mutUnsafeRead #-}+ type Collection c+ type MutableKey c+ type MutableValue c++ unsafeThaw :: PrimMonad prim => Collection c -> prim (c (PrimState prim))+ unsafeThaw = thaw+ unsafeFreeze :: PrimMonad prim => c (PrimState prim) -> prim (Collection c)+ unsafeFreeze = freeze++ thaw :: PrimMonad prim => Collection c -> prim (c (PrimState prim))+ freeze :: PrimMonad prim => c (PrimState prim) -> prim (Collection c)++ mutUnsafeWrite :: PrimMonad prim => c (PrimState prim) -> MutableKey c -> MutableValue c -> prim ()+ mutWrite :: PrimMonad prim => c (PrimState prim) -> MutableKey c -> MutableValue c -> prim ()+ mutUnsafeRead :: PrimMonad prim => c (PrimState prim) -> MutableKey c -> prim (MutableValue c)+ mutRead :: PrimMonad prim => c (PrimState prim) -> MutableKey c -> prim (MutableValue c)++instance UV.PrimType ty => MutableCollection (MUV.MUArray ty) where+ type Collection (MUV.MUArray ty) = UV.UArray ty+ type MutableKey (MUV.MUArray ty) = Int+ type MutableValue (MUV.MUArray ty) = ty++ thaw = UV.thaw+ freeze = UV.freeze+ unsafeThaw = UV.unsafeThaw+ unsafeFreeze = UV.unsafeFreeze++ mutUnsafeWrite = MUV.unsafeWrite+ mutUnsafeRead = MUV.unsafeRead+ mutWrite = MUV.write+ mutRead = MUV.read
+ Foundation/Collection/Sequential.hs view
@@ -0,0 +1,171 @@+-- |+-- Module : Foundation.Collection.Sequential+-- License : BSD-style+-- Maintainer : Vincent Hanquez <vincent@snarc.org>+-- Stability : experimental+-- Portability : portable+--+-- Different collections (list, vector, string, ..) unified under 1 API.+-- an API to rules them all, and in the darkness bind them.+--+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE ConstrainedClassMethods #-}+module Foundation.Collection.Sequential+ ( Sequential(..)+ ) where++import Foundation.Internal.Base+import Foundation.Collection.Element+import qualified Foundation.Collection.List as ListExtra+import qualified Data.List+import qualified Foundation.Array.Unboxed as UV++-- | A set of methods for ordered colection+class (IsList c, Item c ~ Element c, Monoid c) => Sequential c where+ {-# MINIMAL null, ((take, drop) | splitAt)+ , ((revTake, revDrop) | revSplitAt)+ , splitOn+ , (break | span)+ , intersperse+ , filter, reverse+ , uncons, unsnoc, snoc, cons+ , find, sortBy, length, singleton #-}++ -- | Check if a collection is empty+ null :: c -> Bool++ -- | Take the first @n elements of a collection+ take :: Int -> c -> c+ take n = fst . splitAt n++ -- | Take the last @n elements of a collection+ revTake :: Int -> c -> c+ revTake n = fst . revSplitAt n++ -- | Drop the first @n elements of a collection+ drop :: Int -> c -> c+ drop n = snd . splitAt n++ -- | Drop the last @n elements of a collection+ revDrop :: Int -> c -> c+ revDrop n = snd . revSplitAt n++ -- | Split the collection at the @n'th elements+ splitAt :: Int -> c -> (c,c)+ splitAt n c = (take n c, drop n c)++ -- | Split the collection at the @n'th elements from the end+ revSplitAt :: Int -> c -> (c,c)+ revSplitAt n c = (revTake n c, revDrop n c)++ -- | Split on a specific elements returning a list of colletion+ splitOn :: (Element c -> Bool) -> c -> [c]++ -- | Split a collection when the predicate return true+ break :: (Element c -> Bool) -> c -> (c,c)+ break predicate = span (not . predicate)++ -- | Split a collection when the predicate return true+ breakElem :: Eq (Element c) => Element c -> c -> (c,c)+ breakElem c = break (== c)++ -- | The 'intersperse' function takes an element and a list and+ -- \`intersperses\' that element between the elements of the list.+ -- For example,+ --+ -- > intersperse ',' "abcde" == "a,b,c,d,e"+ intersperse :: Element c -> c -> c++ -- | 'intercalate' @xs xss@ is equivalent to @('mconcat' ('intersperse' xs xss))@.+ -- It inserts the list @xs@ in between the lists in @xss@ and concatenates the+ -- result.+ intercalate :: Monoid (Item c) => Element c -> c -> Element c+ intercalate xs xss = mconcatCollection (intersperse xs xss)++ -- | Split a collection while the predicate return true+ span :: (Element c -> Bool) -> c -> (c,c)+ span predicate = break (not . predicate)++ -- | Filter all the elements that satisfy the predicate+ filter :: (Element c -> Bool) -> c -> c++ -- | Reverse a collection+ reverse :: c -> c++ -- | Decompose a collection into its first element and the remaining collection.+ -- If the collection is empty, returns Nothing.+ uncons :: c -> Maybe (Element c, c)++ -- | Decompose a collection into a collection without its last element, and the last element+ -- If the collection is empty, returns Nothing.+ unsnoc :: c -> Maybe (c, Element c)++ -- | Prepend an element to an ordered collection+ snoc :: c -> Element c -> c++ -- | Append an element to an ordered collection+ cons :: Element c -> c -> c++ -- | Find an element in an ordered collection+ find :: (Element c -> Bool) -> c -> Maybe (Element c)++ -- | Sort an ordered collection using the specified order function+ sortBy :: (Element c -> Element c -> Ordering) -> c -> c++ -- | Length of a collection (number of Element c)+ length :: c -> Int++ -- | Create a collection with a single element+ singleton :: Element c -> c++-- Temporary utility functions+mconcatCollection :: (Monoid (Item c), Sequential c) => c -> Element c+mconcatCollection c = mconcat (toList c)++instance Sequential [a] where+ null = Data.List.null+ take = Data.List.take+ drop = Data.List.drop+ revTake = ListExtra.revTake+ revDrop = ListExtra.revDrop+ splitAt = Data.List.splitAt+ revSplitAt = ListExtra.revSplitAt+ splitOn = ListExtra.wordsWhen+ break = Data.List.break+ intersperse = Data.List.intersperse+ span = Data.List.span+ filter = Data.List.filter+ reverse = Data.List.reverse+ uncons = ListExtra.uncons+ unsnoc = ListExtra.unsnoc+ snoc c e = c `mappend` [e]+ cons e c = e : c+ find = Data.List.find+ sortBy = Data.List.sortBy+ length = Data.List.length+ singleton = (:[])++instance UV.PrimType ty => Sequential (UV.UArray ty) where+ null = UV.null+ take = UV.take+ revTake = UV.revTake+ drop = UV.drop+ revDrop = UV.revDrop+ splitAt = UV.splitAt+ revSplitAt = UV.revSplitAt+ splitOn = UV.splitOn+ break = UV.break+ breakElem = UV.breakElem+ intersperse = UV.intersperse+ span = UV.span+ filter = UV.filter+ reverse = UV.reverse+ uncons = UV.uncons+ unsnoc = UV.unsnoc+ snoc = UV.snoc+ cons = UV.cons+ find = UV.find+ sortBy = UV.sortBy+ length = UV.length+ singleton = fromList . (:[])
+ Foundation/Collection/Zippable.hs view
@@ -0,0 +1,278 @@+-- |+-- Module : Foundation.Collection.Zippable+-- License : BSD-style+-- Maintainer : foundation+-- Stability : experimental+-- Portability : portable+--+-- Common functions (e. g. 'zip', 'zipWith') that are useful for combining+-- multiple collections.+--+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-}++module Foundation.Collection.Zippable+ ( BoxedZippable(..)+ , Zippable(..)+ ) where++import qualified Foundation.Array.Unboxed as UV+import qualified Foundation.Array.Unboxed.Builder as UVB+import Foundation.Collection.Element+import Foundation.Collection.Sequential+import Foundation.Internal.Base+import Foundation.Number+import qualified Prelude+import GHC.ST++class Sequential col => Zippable col where++ -- | 'zipWith' generalises 'zip' by zipping with the function given as the+ -- first argument, instead of a tupling function. For example, @'zipWith' (+)@+ -- is applied to two collections to produce the collection of corresponding+ -- sums.+ zipWith :: (Sequential a, Sequential b)+ => (Element a -> Element b -> Element col)+ -> a -> b -> col+ zipWith f a b = go f (toList a, toList b)+ where go f' = maybe mempty (\(x, xs) -> uncurry2 f' x `cons` go f' xs) . uncons2++ -- | Like 'zipWith', but works with 3 collections.+ zipWith3 :: (Sequential a, Sequential b, Sequential c)+ => (Element a -> Element b -> Element c -> Element col)+ -> a -> b -> c -> col+ zipWith3 f a b c = go f (toList a, toList b, toList c)+ where go f' = maybe mempty (\(x, xs) -> uncurry3 f' x `cons` go f' xs) . uncons3++ -- | Like 'zipWith', but works with 4 collections.+ zipWith4 :: (Sequential a, Sequential b, Sequential c, Sequential d)+ => (Element a -> Element b -> Element c -> Element d -> Element col)+ -> a -> b -> c -> d -> col+ zipWith4 fn a b c d = go fn (toList a, toList b, toList c, toList d)+ where go f' = maybe mempty (\(x, xs) -> uncurry4 f' x `cons` go f' xs) . uncons4++ -- | Like 'zipWith', but works with 5 collections.+ zipWith5 :: (Sequential a, Sequential b, Sequential c, Sequential d, Sequential e)+ => (Element a -> Element b -> Element c -> Element d -> Element e -> Element col)+ -> a -> b -> c -> d -> e -> col+ zipWith5 fn a b c d e = go fn (toList a, toList b, toList c, toList d, toList e)+ where go f' = maybe mempty (\(x, xs) -> uncurry5 f' x `cons` go f' xs) . uncons5++ -- | Like 'zipWith', but works with 6 collections.+ zipWith6 :: ( Sequential a, Sequential b, Sequential c, Sequential d, Sequential e+ , Sequential f)+ => (Element a -> Element b -> Element c -> Element d -> Element e -> Element f -> Element col)+ -> a -> b -> c -> d -> e -> f -> col+ zipWith6 fn a b c d e f = go fn (toList a, toList b, toList c, toList d, toList e, toList f)+ where go f' = maybe mempty (\(x, xs) -> uncurry6 f' x `cons` go f' xs) . uncons6++ -- | Like 'zipWith', but works with 7 collections.+ zipWith7 :: ( Sequential a, Sequential b, Sequential c, Sequential d, Sequential e+ , Sequential f, Sequential g )+ => (Element a -> Element b -> Element c -> Element d -> Element e -> Element f -> Element g -> Element col)+ -> a -> b -> c -> d -> e -> f -> g -> col+ zipWith7 fn a b c d e f g = go fn (toList a, toList b, toList c, toList d, toList e, toList f, toList g)+ where go f' = maybe mempty (\(x, xs) -> uncurry7 f' x `cons` go f' xs) . uncons7++instance Zippable [c]++instance UV.PrimType ty => Zippable (UV.UArray ty) where+ zipWith f as bs = runST $+ Prelude.uncurry UVB.build $ go f (toList as) (toList bs)+ where+ go _ [] _ = (0, return ())+ go _ _ [] = (0, return ())+ go f' (a':as') (b':bs') =+ let (i, builder) = go f' as' bs'+ in (i + 1, UVB.appendTy (f' a' b') >> builder)++class Zippable col => BoxedZippable col where++ -- | 'zip' takes two collections and returns a collections of corresponding+ -- pairs. If one input collection is short, excess elements of the longer+ -- collection are discarded.+ zip :: ( Sequential a, Sequential b+ , Element col ~ (Element a, Element b) )+ => a -> b -> col+ zip = zipWith (,)++ -- | Like 'zip', but works with 3 collections.+ zip3 :: ( Sequential a, Sequential b, Sequential c+ , Element col ~ (Element a, Element b, Element c) )+ => a -> b -> c -> col+ zip3 = zipWith3 (,,)++ -- | Like 'zip', but works with 4 collections.+ zip4 :: ( Sequential a, Sequential b, Sequential c, Sequential d+ , Element col ~ (Element a, Element b, Element c, Element d) )+ => a -> b -> c -> d -> col+ zip4 = zipWith4 (,,,)++ -- | Like 'zip', but works with 5 collections.+ zip5 :: ( Sequential a, Sequential b, Sequential c, Sequential d, Sequential e+ , Element col ~ (Element a, Element b, Element c, Element d, Element e) )+ => a -> b -> c -> d -> e -> col+ zip5 = zipWith5 (,,,,)++ -- | Like 'zip', but works with 6 collections.+ zip6 :: ( Sequential a, Sequential b, Sequential c, Sequential d, Sequential e, Sequential f+ , Element col ~ (Element a, Element b, Element c, Element d, Element e, Element f) )+ => a -> b -> c -> d -> e -> f -> col+ zip6 = zipWith6 (,,,,,)++ -- | Like 'zip', but works with 7 collections.+ zip7 :: ( Sequential a, Sequential b, Sequential c, Sequential d, Sequential e, Sequential f, Sequential g+ , Element col ~ (Element a, Element b, Element c, Element d, Element e, Element f, Element g) )+ => a -> b -> c -> d -> e -> f -> g -> col+ zip7 = zipWith7 (,,,,,,)++ -- | 'unzip' transforms a collection of pairs into a collection of first+ -- components and a collection of second components.+ unzip :: (Sequential a, Sequential b, Element col ~ (Element a, Element b))+ => col -> (a, b)+ unzip = go . toList+ where go [] = (mempty, mempty)+ go ((a, b):xs) =+ let (as, bs) = go xs+ in (a `cons` as, b `cons` bs)++ -- | Like 'unzip', but works on a collection of 3-element tuples.+ unzip3 :: ( Sequential a, Sequential b, Sequential c+ , Element col ~ (Element a, Element b, Element c) )+ => col -> (a, b, c)+ unzip3 = go . toList+ where go [] = (mempty, mempty, mempty)+ go ((a, b, c):xs) =+ let (as, bs, cs) = go xs+ in (a `cons` as, b `cons` bs, c `cons` cs)++ -- | Like 'unzip', but works on a collection of 4-element tuples.+ unzip4 :: ( Sequential a, Sequential b, Sequential c, Sequential d+ , Element col ~ (Element a, Element b, Element c, Element d) )+ => col -> (a, b, c, d)+ unzip4 = go . toList+ where go [] = (mempty, mempty, mempty, mempty)+ go ((a, b, c, d):xs) =+ let (as, bs, cs, ds) = go xs+ in (a `cons` as, b `cons` bs, c `cons` cs, d `cons` ds)++ -- | Like 'unzip', but works on a collection of 5-element tuples.+ unzip5 :: ( Sequential a, Sequential b, Sequential c, Sequential d, Sequential e+ , Element col ~ (Element a, Element b, Element c, Element d, Element e) )+ => col -> (a, b, c, d, e)+ unzip5 = go . toList+ where go [] = (mempty, mempty, mempty, mempty, mempty)+ go ((a, b, c, d, e):xs) =+ let (as, bs, cs, ds, es) = go xs+ in (a `cons` as, b `cons` bs, c `cons` cs, d `cons` ds, e `cons` es)++ -- | Like 'unzip', but works on a collection of 6-element tuples.+ unzip6 :: ( Sequential a, Sequential b, Sequential c, Sequential d, Sequential e, Sequential f+ , Element col ~ (Element a, Element b, Element c, Element d, Element e, Element f) )+ => col -> (a, b, c, d, e, f)+ unzip6 = go . toList+ where go [] = (mempty, mempty, mempty, mempty, mempty, mempty)+ go ((a, b, c, d, e, f):xs) =+ let (as, bs, cs, ds, es, fs) = go xs+ in (a `cons` as, b `cons` bs, c `cons` cs, d `cons` ds, e `cons` es, f `cons` fs)++ -- | Like 'unzip', but works on a collection of 7-element tuples.+ unzip7 :: ( Sequential a, Sequential b, Sequential c, Sequential d, Sequential e, Sequential f, Sequential g+ , Element col ~ (Element a, Element b, Element c, Element d, Element e, Element f, Element g) )+ => col -> (a, b, c, d, e, f, g)+ unzip7 = go . toList+ where go [] = (mempty, mempty, mempty, mempty, mempty, mempty, mempty)+ go ((a, b, c, d, e, f, g):xs) =+ let (as, bs, cs, ds, es, fs, gs) = go xs+ in (a `cons` as, b `cons` bs, c `cons` cs, d `cons` ds, e `cons` es, f `cons` fs, g `cons` gs)++instance BoxedZippable [a]++-- * Tuple helper functions++uncons2 :: (Sequential a, Sequential b) => (a, b) -> Maybe ((Element a, Element b), (a, b))+uncons2 xs = let (as, bs) = xs+ in do (a', as') <- uncons as+ (b', bs') <- uncons bs+ return ((a', b'), (as', bs'))++uncons3 :: (Sequential a, Sequential b, Sequential c)+ => (a, b, c)+ -> Maybe ((Element a, Element b, Element c), (a, b, c))+uncons3 xs = let (as, bs, cs) = xs+ in do (a', as') <- uncons as+ (b', bs') <- uncons bs+ (c', cs') <- uncons cs+ return ((a', b', c'), (as', bs', cs'))++uncons4 :: (Sequential a, Sequential b, Sequential c, Sequential d)+ => (a, b, c, d)+ -> Maybe ( (Element a, Element b, Element c, Element d)+ , (a, b, c, d) )+uncons4 xs = let (as, bs, cs, ds) = xs+ in do (a', as') <- uncons as+ (b', bs') <- uncons bs+ (c', cs') <- uncons cs+ (d', ds') <- uncons ds+ return ((a', b', c', d'), (as', bs', cs', ds'))++uncons5 :: (Sequential a, Sequential b, Sequential c, Sequential d, Sequential e)+ => (a, b, c, d, e)+ -> Maybe ( (Element a, Element b, Element c, Element d, Element e)+ , (a, b, c, d, e) )+uncons5 xs = let (as, bs, cs, ds, es) = xs+ in do (a', as') <- uncons as+ (b', bs') <- uncons bs+ (c', cs') <- uncons cs+ (d', ds') <- uncons ds+ (e', es') <- uncons es+ return ((a', b', c', d', e'), (as', bs', cs', ds', es'))++uncons6 :: ( Sequential a, Sequential b, Sequential c, Sequential d, Sequential e+ , Sequential f )+ => (a, b, c, d, e, f)+ -> Maybe ( (Element a, Element b, Element c, Element d, Element e, Element f)+ , (a, b, c, d, e, f) )+uncons6 xs = let (as, bs, cs, ds, es, fs) = xs+ in do (a', as') <- uncons as+ (b', bs') <- uncons bs+ (c', cs') <- uncons cs+ (d', ds') <- uncons ds+ (e', es') <- uncons es+ (f', fs') <- uncons fs+ return ((a', b', c', d', e', f'), (as', bs', cs', ds', es', fs'))++uncons7 :: ( Sequential a, Sequential b, Sequential c, Sequential d, Sequential e+ , Sequential f, Sequential g )+ => (a, b, c, d, e, f, g)+ -> Maybe ( (Element a, Element b, Element c, Element d, Element e, Element f+ , Element g)+ , (a, b, c, d, e, f, g) )+uncons7 xs = let (as, bs, cs, ds, es, fs, gs) = xs+ in do (a', as') <- uncons as+ (b', bs') <- uncons bs+ (c', cs') <- uncons cs+ (d', ds') <- uncons ds+ (e', es') <- uncons es+ (f', fs') <- uncons fs+ (g', gs') <- uncons gs+ return ( (a', b', c', d', e', f', g')+ , (as', bs', cs', ds', es', fs', gs') )++uncurry2 :: (a -> b -> c) -> (a, b) -> c+uncurry2 = Prelude.uncurry++uncurry3 :: (a -> b -> c -> d) -> (a, b, c) -> d+uncurry3 fn (a, b, c) = fn a b c++uncurry4 :: (a -> b -> c -> d -> g) -> (a, b, c, d) -> g+uncurry4 fn (a, b, c, d) = fn a b c d++uncurry5 :: (a -> b -> c -> d -> e -> f) -> (a, b, c, d, e) -> f+uncurry5 fn (a, b, c, d, e) = fn a b c d e++uncurry6 :: (a -> b -> c -> d -> e -> f -> g) -> (a, b, c, d, e, f) -> g+uncurry6 fn (a, b, c, d, e, f) = fn a b c d e f++uncurry7 :: (a -> b -> c -> d -> e -> f -> g -> h) -> (a, b, c, d, e, f, g) -> h+uncurry7 fn (a, b, c, d, e, f, g) = fn a b c d e f g
+ Foundation/Convertible.hs view
@@ -0,0 +1,24 @@+-- |+-- Module : Foundation.Convertible+-- License : BSD-style+-- Maintainer : Vincent Hanquez <vincent@snarc.org>+-- Stability : experimental+-- Portability : portable+--+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE FlexibleInstances #-}+module Foundation.Convertible+ ( Convertible(..)+ ) where++import Foundation.Internal.Base+import Foundation.Internal.Proxy++-- | Class of things that can be converted from a to b+class Convertible a b where+ type Convert a b+ convert :: Proxy b -> a -> Convert a b++instance Convertible a a where+ type Convert a a = a+ convert _ = id
+ Foundation/Foreign.hs view
@@ -0,0 +1,16 @@+-- |+-- Module : Foundation.Foreign+-- License : BSD-style+-- Maintainer : Vincent Hanquez <vincent@snarc.org>+-- Stability : experimental+-- Portability : portable+--+module Foundation.Foreign+ ( module Foundation.Primitive.FinalPtr+ , V.foreignMem+ , V.mutableForeignMem+ ) where++import Foundation.Primitive.FinalPtr+import qualified Foundation.Array.Unboxed as V+import qualified Foundation.Array.Unboxed.Mutable as V
+ Foundation/Foreign/MemoryMap.hs view
@@ -0,0 +1,18 @@+{-# LANGUAGE CPP #-}+module Foundation.Foreign.MemoryMap+ ( fileMapRead+ , FileMapping(..)+ , fileMappingToFinalPtr+ ) where++import Foundation.Foreign.MemoryMap.Types+#ifdef mingw32_HOST_OS+import Foundation.Foreign.MemoryMap.Windows+#else+import Foundation.Foreign.MemoryMap.Posix+#endif++{-+fileMap :: Fd -> Int -> IO FileMap+fileMap = undefined+-}
+ Foundation/Foreign/MemoryMap/Posix.hsc view
@@ -0,0 +1,251 @@+-----------------------------------------------------------------------------+-- |+-- Module : Foundation.Foreign.MemoryMap.Posix+-- Copyright : (c) Vincent Hanquez 2014+-- License : BSD-style+--+-- Maintainer : Vincent Hanquez+-- Stability : provisional+-- Portability : non-portable (requires POSIX)+--+-- Functions defined by the POSIX standards for manipulating memory maps+--+-- When a function that calls an underlying POSIX function fails, the errno+-- code is converted to an 'IOError' using 'Foreign.C.Error.errnoToIOError'.+-- For a list of which errno codes may be generated, consult the POSIX+-- documentation for the underlying function.+--+-----------------------------------------------------------------------------++#include <sys/mman.h>+#include <unistd.h>++{-# LANGUAGE ForeignFunctionInterface #-}+{-# LANGUAGE CPP #-}+module Foundation.Foreign.MemoryMap.Posix+ ( memoryMap+ , memoryUnmap+ , memoryAdvise+ , memoryLock+ , memoryUnlock+ , memoryProtect+ , memorySync+ -- * Flags types+ , MemoryMapFlag(..)+ , MemoryProtection(..)+ , MemoryAdvice(..)+ , MemorySyncFlag(..)+ -- * system page size+ , sysconfPageSize+ -- * High level+ , fileMapRead+ ) where++import Foundation.Internal.Base+import Foundation.Internal.Types+import System.Posix.Types+import Foreign.Ptr+import Foreign.C.Types+import Foreign.C.Error+import Data.Bits++import Foundation.Collection.Foldable+import Foundation.VFS+import qualified Prelude (fromIntegral)+import Foundation.Foreign.MemoryMap.Types+import Control.Exception++import GHC.IO.FD+import GHC.IO.IOMode+import qualified GHC.IO.Device as IO++foreign import ccall unsafe "mmap"+ c_mmap :: Ptr a -> CSize -> CInt -> CInt -> CInt -> COff -> IO (Ptr a)++foreign import ccall unsafe "munmap"+ c_munmap :: Ptr a -> CSize -> IO CInt++#if defined(POSIX_MADV_NORMAL)+foreign import ccall unsafe "posix_madvise"+ c_madvise :: Ptr a -> CSize -> CInt -> IO CInt+#else+foreign import ccall unsafe "madvise"+ c_madvise :: Ptr a -> CSize -> CInt -> IO CInt+#endif++foreign import ccall unsafe "msync"+ c_msync :: Ptr a -> CSize -> CInt -> IO CInt++foreign import ccall unsafe "mprotect"+ c_mprotect :: Ptr a -> CSize -> CInt -> IO CInt++#ifndef __HAIKU__+foreign import ccall unsafe "mlock"+ c_mlock :: Ptr a -> CSize -> IO CInt+#else+c_mlock :: Ptr a -> CSize -> IO CInt+c_mlock _ _ = return (-1)+#endif++#ifndef __HAIKU__+foreign import ccall unsafe "munlock"+ c_munlock :: Ptr a -> CSize -> IO CInt+#else+c_munlock :: Ptr a -> CSize -> IO CInt+c_munlock _ _ = return (-1)+#endif++foreign import ccall unsafe "sysconf"+ c_sysconf :: CInt -> CLong++-- | Mapping flag+data MemoryMapFlag =+ MemoryMapShared -- ^ memory changes are shared between process+ | MemoryMapPrivate -- ^ memory changes are private to process+ deriving (Show,Eq)++-- | Memory protection+data MemoryProtection =+ MemoryProtectionNone+ | MemoryProtectionRead+ | MemoryProtectionWrite+ | MemoryProtectionExecute+ deriving (Show,Eq)++-- | Advice to put on memory.+--+-- only define the posix one.+data MemoryAdvice =+ MemoryAdviceNormal -- ^ no specific advice, the default.+ | MemoryAdviceRandom -- ^ Expect page references in random order. No readahead should occur.+ | MemoryAdviceSequential -- ^ Expect page references in sequential order. Page should be readahead aggressively.+ | MemoryAdviceWillNeed -- ^ Expect access in the near future. Probably a good idea to readahead early+ | MemoryAdviceDontNeed -- ^ Do not expect access in the near future.+ deriving (Show,Eq)++-- | Memory synchronization flags+data MemorySyncFlag =+ MemorySyncAsync -- ^ perform asynchronous write.+ | MemorySyncSync -- ^ perform synchronous write.+ | MemorySyncInvalidate -- ^ invalidate cache data.+ deriving (Show,Eq)++cvalueOfMemoryProts :: [MemoryProtection] -> CInt+cvalueOfMemoryProts = foldl (.|.) 0 . fmap toProt+ where toProt :: MemoryProtection -> CInt+ toProt MemoryProtectionNone = (#const PROT_NONE)+ toProt MemoryProtectionRead = (#const PROT_READ)+ toProt MemoryProtectionWrite = (#const PROT_WRITE)+ toProt MemoryProtectionExecute = (#const PROT_EXEC)++cvalueOfMemorySync :: [MemorySyncFlag] -> CInt+cvalueOfMemorySync = foldl (.|.) 0 . fmap toSync+ where toSync MemorySyncAsync = (#const MS_ASYNC)+ toSync MemorySyncSync = (#const MS_SYNC)+ toSync MemorySyncInvalidate = (#const MS_INVALIDATE)++-- | Map pages of memory.+--+-- If fd is present, this memory will represent the file associated.+-- Otherwise, the memory will be an anonymous mapping.+--+-- use 'mmap'+memoryMap :: Maybe (Ptr a) -- ^ The address to map to if MapFixed is used.+ -> CSize -- ^ The length of the mapping+ -> [MemoryProtection] -- ^ the memory protection associated with the mapping+ -> MemoryMapFlag -- ^+ -> Maybe Fd+ -> COff+ -> IO (Ptr a)+memoryMap initPtr sz prots flag mfd off =+ throwErrnoIf (== m1ptr) "mmap" (c_mmap (maybe nullPtr id initPtr) sz cprot cflags fd off)+ where m1ptr = nullPtr `plusPtr` (-1)+ fd = maybe (-1) (\(Fd v) -> v) mfd+ cprot = cvalueOfMemoryProts prots+ cflags = maybe cMapAnon (const 0) mfd+ .|. maybe 0 (const cMapFixed) initPtr+ .|. toMapFlag flag++#ifdef __APPLE__+ cMapAnon = (#const MAP_ANON)+#else+ cMapAnon = (#const MAP_ANONYMOUS)+#endif+ cMapFixed = (#const MAP_FIXED)++ toMapFlag MemoryMapShared = (#const MAP_SHARED)+ toMapFlag MemoryMapPrivate = (#const MAP_PRIVATE)++-- | Unmap pages of memory+--+-- use 'munmap'+memoryUnmap :: Ptr a -> CSize -> IO ()+memoryUnmap ptr sz = throwErrnoIfMinus1_ "munmap" (c_munmap ptr sz)++-- | give advice to the operating system about use of memory+--+-- call 'madvise'+memoryAdvise :: Ptr a -> CSize -> MemoryAdvice -> IO ()+memoryAdvise ptr sz adv = throwErrnoIfMinus1_ "madvise" (c_madvise ptr sz cadv)+ where cadv = toAdvice adv+#if defined(POSIX_MADV_NORMAL)+ toAdvice MemoryAdviceNormal = (#const POSIX_MADV_NORMAL)+ toAdvice MemoryAdviceRandom = (#const POSIX_MADV_RANDOM)+ toAdvice MemoryAdviceSequential = (#const POSIX_MADV_SEQUENTIAL)+ toAdvice MemoryAdviceWillNeed = (#const POSIX_MADV_WILLNEED)+ toAdvice MemoryAdviceDontNeed = (#const POSIX_MADV_DONTNEED)+#else+ toAdvice MemoryAdviceNormal = (#const MADV_NORMAL)+ toAdvice MemoryAdviceRandom = (#const MADV_RANDOM)+ toAdvice MemoryAdviceSequential = (#const MADV_SEQUENTIAL)+ toAdvice MemoryAdviceWillNeed = (#const MADV_WILLNEED)+ toAdvice MemoryAdviceDontNeed = (#const MADV_DONTNEED)+#endif++-- | lock a range of process address space+--+-- call 'mlock'+memoryLock :: Ptr a -> CSize -> IO ()+memoryLock ptr sz = throwErrnoIfMinus1_ "mlock" (c_mlock ptr sz)++-- | unlock a range of process address space+--+-- call 'munlock'+memoryUnlock :: Ptr a -> CSize -> IO ()+memoryUnlock ptr sz = throwErrnoIfMinus1_ "munlock" (c_munlock ptr sz)++-- | set protection of memory mapping+--+-- call 'mprotect'+memoryProtect :: Ptr a -> CSize -> [MemoryProtection] -> IO ()+memoryProtect ptr sz prots = throwErrnoIfMinus1_ "mprotect" (c_mprotect ptr sz cprot)+ where cprot = cvalueOfMemoryProts prots++-- | memorySync synchronize memory with physical storage.+--+-- On an anonymous mapping this function does not have any effect.+-- call 'msync'+memorySync :: Ptr a -> CSize -> [MemorySyncFlag] -> IO ()+memorySync ptr sz flags = throwErrnoIfMinus1_ "msync" (c_msync ptr sz cflags)+ where cflags = cvalueOfMemorySync flags++-- | Return the operating system page size.+--+-- call 'sysconf'+sysconfPageSize :: Int+sysconfPageSize = Prelude.fromIntegral $ c_sysconf (#const _SC_PAGESIZE)++--------------------------------------------------------------------------------++fileSizeToCSize :: FileSize -> CSize+fileSizeToCSize (FileSize sz) = Prelude.fromIntegral sz++fileSizeFromInteger :: Integer -> FileSize+fileSizeFromInteger = FileSize . Prelude.fromIntegral++fileMapRead :: FileMapReadF+fileMapRead fp = bracket (openFile (filePathToLString fp) ReadMode True) (IO.close . fst) $ \(fd,_) -> do+ sz <- fileSizeFromInteger `fmap` IO.getSize fd+ let csz = fileSizeToCSize sz+ p <- memoryMap Nothing csz [MemoryProtectionRead] MemoryMapPrivate (Just $ Fd $ fdFD fd) 0+ return $ FileMapping p sz (memoryUnmap p csz)
+ Foundation/Foreign/MemoryMap/Types.hs view
@@ -0,0 +1,34 @@+-- |+-- Module : Foundation.Foreign.MemoryMap.Types+-- License : BSD-style+-- Maintainer : Vincent Hanquez <vincent@snarc.org>+-- Stability : experimental+-- Portability : portable+--+module Foundation.Foreign.MemoryMap.Types+ ( FileMapping(..)+ , fileMappingToFinalPtr+ , FileMapReadF+ ) where++import GHC.Ptr+import Foundation.Primitive.FinalPtr+import Foundation.Internal.Base+import Foundation.Internal.Types+import Foundation.VFS (FilePath)++-- | Contains all the information related to a file mapping,+-- including the size and the finalizer function.+data FileMapping = FileMapping+ { fileMappingPtr :: Ptr Word8+ , fileMappingSize :: FileSize+ , fileMappingUnmap :: IO ()+ }++-- | From a file mapping, create a final ptr which will automatically+-- unmap memory when the pointer is garbage.+fileMappingToFinalPtr :: FileMapping -> IO (FinalPtr Word8)+fileMappingToFinalPtr (FileMapping ptr _ finalizer) =+ toFinalPtr ptr (\_ -> finalizer)++type FileMapReadF = FilePath -> IO FileMapping
+ Foundation/Foreign/MemoryMap/Windows.hs view
@@ -0,0 +1,27 @@+module Foundation.Foreign.MemoryMap.Windows+ ( fileMapRead+ ) where++import System.Win32.Mem+import System.Win32.File+import System.Win32.FileMapping+import Control.Exception hiding (handle)++import Foundation.Internal.Types+import Foundation.Internal.Base+import Foundation.Primitive.FinalPtr+import Foundation.VFS+import Foundation.Foreign.MemoryMap.Types++fileMapRead :: FileMapReadF+fileMapRead path = bracket doOpen closeHandle doMapping+ where+ doOpen = createFile (filePathToLString path) gENERIC_READ fILE_SHARE_READ Nothing oPEN_EXISTING fILE_ATTRIBUTE_NORMAL Nothing+ doMapping handle = bracket (createFileMapping (Just handle) pAGE_READONLY 0 Nothing)+ closeHandle+ (getSizeAndMap handle)+ getSizeAndMap handle filemap = do+ fileInfo <- getFileInformationByHandle handle+ mask_ $ do+ ptr <- mapViewOfFile filemap fILE_MAP_READ 0 0+ return $ FileMapping ptr (FileSize $ bhfiSize fileInfo) (unmapViewOfFile ptr)
+ Foundation/IO.hs view
@@ -0,0 +1,25 @@+-- |+-- Module : Foundation.IO+-- License : BSD-style+-- Maintainer : Vincent Hanquez <vincent@snarc.org>+-- Stability : experimental+-- Portability : portable+--+-- IO Routine+module Foundation.IO+ (+ -- * Terminal+ Foundation.IO.Terminal.putStrLn+ , Foundation.IO.Terminal.putStr+ -- * File+ , Foundation.IO.File.IOMode(..)+ , Foundation.IO.File.openFile+ , Foundation.IO.File.closeFile+ , Foundation.IO.File.withFile+ , Foundation.IO.File.hGet+ , Foundation.IO.File.readFile+ , Foundation.IO.File.foldTextFile+ ) where++import qualified Foundation.IO.Terminal+import qualified Foundation.IO.File
+ Foundation/IO/File.hs view
@@ -0,0 +1,147 @@+-- |+-- Module : Foundation.IO.File+-- License : BSD-style+-- Maintainer : Foundation+-- Stability : experimental+-- Portability : portable+--+module Foundation.IO.File+ ( openFile+ , closeFile+ , IOMode(..)+ , withFile+ , hGet+ , hGetNonBlocking+ , hGetSome+ , readFile+ , foldTextFile+ ) where++import System.IO (Handle, IOMode)+import System.IO.Error+import qualified System.IO as S+import Foundation.Collection+import Foundation.VFS+import Foundation.Internal.Types+import Foundation.Internal.Base+import Foundation.String+import Foundation.Array+import Foundation.Number+import qualified Foundation.Array.Unboxed.Mutable as V+import qualified Foundation.Array.Unboxed as V+import qualified Foundation.String.UTF8 as S+import Control.Exception (bracket)+import Foreign.Ptr (plusPtr)++-- | list the file name in the given FilePath directory+--+-- TODO: error management and not implemented yet+--getDirectory :: FilePath -> IO [FileName]+--getDirectory = undefined++-- | Open a new handle on the file+openFile :: FilePath -> IOMode -> IO Handle+openFile filepath mode = do+ S.openBinaryFile (filePathToLString filepath) mode++-- | Close a handle+closeFile :: Handle -> IO ()+closeFile = S.hClose++-- | Read binary data directly from the specified 'Handle'.+--+-- First argument is the Handle to read from, and the second is the number of bytes to read.+-- It returns the bytes read, up to the specified size, or an empty array if EOF has been reached.+--+-- 'hGet' is implemented in terms of 'hGetBuf'.+hGet :: Handle -> Int -> IO (UArray Word8)+hGet h size+ | size < 0 = invalidBufferSize "hGet" h size+ | otherwise = V.createFromIO size $ \p -> S.hGetBuf h p size++-- | hGetNonBlocking is similar to 'hGet', except that it will never block+-- waiting for data to become available, instead it returns only whatever data+-- is available. If there is no data available to be read, 'hGetNonBlocking'+-- returns an empty array.+--+-- Note: on Windows, this function behaves identically to 'hGet'.+hGetNonBlocking :: Handle -> Int -> IO (UArray Word8)+hGetNonBlocking h size+ | size < 0 = invalidBufferSize "hGetNonBlocking" h size+ | otherwise = V.createFromIO size $ \p -> S.hGetBufNonBlocking h p size++-- | Like 'hGet', except that a shorter array may be returned+-- if there are not enough bytes immediately available to satisfy the+-- whole request. 'hGetSome' only blocks if there is no data+-- available, and EOF has not yet been reached.+--+hGetSome :: Handle -> Int -> IO (UArray Word8)+hGetSome h size+ | size < 0 = invalidBufferSize "hGetSome" h size+ | otherwise = V.createFromIO size $ \p -> S.hGetBufSome h p size++invalidBufferSize :: [Char] -> Handle -> Int -> IO a+invalidBufferSize functionName handle size =+ ioError $ mkIOError illegalOperationErrorType+ (functionName <> " invalid array size: " <> show size)+ (Just handle)+ Nothing++-- | @'withFile' filepath mode act@ opens a file using the mode@+-- and run act@. the by-product handle will be closed when act finish,+-- either normally or through an exception.+--+-- The value returned is the result of act@+withFile :: FilePath -> IOMode -> (Handle -> IO r) -> IO r+withFile fp mode act = bracket (openFile fp mode) closeFile act++-- | Read a binary file and return the whole content in one contiguous buffer.+readFile :: FilePath -> IO (UArray Word8)+readFile fp = withFile fp S.ReadMode $ \h -> do+ -- TODO filesize is an integer (whyyy ?!), and transforming to Int using+ -- fromIntegral is probably the wrong thing to do here..+ sz <- S.hFileSize h+ mv <- V.newPinned (Size $ fromInteger sz)+ V.withMutablePtr mv $ loop h (fromInteger sz)+ unsafeFreeze mv+ where+ loop h left dst+ | left == 0 = return ()+ | otherwise = do+ let toRead = min blockSize left+ r <- S.hGetBuf h dst toRead+ if r > 0 && r <= toRead+ then loop h (left - r) (dst `plusPtr` r)+ else error "readFile: " -- turn into proper error++-- | Fold over chunks file calling the callback function for each chunks+-- read from the file, until the end of file.+foldTextFile :: (String -> a -> IO a) -- ^ Fold callback function+ -> a -- ^ initial accumulator+ -> FilePath -- ^ File to read+ -> IO a+foldTextFile chunkf ini fp = do+ buf <- V.newPinned (Size blockSize)+ V.withMutablePtr buf $ \ptr ->+ withFile fp S.ReadMode $ doFold buf ptr+ where+ doFold mv ptr handle = loop 0 ini+ where+ loop absPos acc = do+ r <- S.hGetBuf handle ptr blockSize+ if r > 0 && r <= blockSize+ then do+ (pos, validateRet) <- S.mutableValidate mv 0 r+ s <- case validateRet of+ Nothing -> S.fromBytesUnsafe `fmap` V.freezeShrink mv r+ Just S.MissingByte -> do+ sRet <- S.fromBytesUnsafe `fmap` V.freezeShrink mv pos+ V.unsafeSlide mv pos r+ return sRet+ Just _ ->+ error ("foldTextFile: invalid UTF8 sequence: byte position: " <> show (absPos + pos))+ chunkf s acc >>= loop (absPos + r)+ else error ("foldTextFile: read failed") -- FIXME++blockSize :: Int+blockSize = 4096
+ Foundation/IO/FileMap.hs view
@@ -0,0 +1,59 @@+-- |+-- Module : Foundation.IO.FileMap+-- License : BSD-style+-- Maintainer : Vincent Hanquez <vincent@snarc.org>+-- Stability : experimental+-- Portability : portable+--+-- Note that the memory mapping is handled by the system, not at the haskell level.+-- The system can modify the content of the memory as any moment under your feet.+--+-- It also have the limitation of your system, no emulation or nice handling of all+-- those corners cases is attempted here.+--+-- for example mapping a large file (> 4G), on a 32 bits system is likely to just+-- fail or returns inconsistent result.+--+-- In doubt, use 'readFile' or other simple routine that brings+-- the content of the file in IO.+--+module Foundation.IO.FileMap+ ( fileMapRead+ , fileMapReadWith+ ) where++import Control.Exception+import Foundation.Internal.Types+import Foundation.Internal.Base+import Foundation.VFS (FilePath)+import Foundation.Primitive.FinalPtr+import qualified Foundation.Array.Unboxed as V+import qualified Foundation.Foreign.MemoryMap as I+import qualified Prelude++getSize :: I.FileMapping -> Int+getSize fm+ | Prelude.fromIntegral (maxBound :: Int) < sz = error ("cannot map file in entirety as size overflow " <> show sz)+ | otherwise = Prelude.fromIntegral sz+ where+ (FileSize sz) = I.fileMappingSize fm++-- | Map in memory the whole content of a file.+--+-- Once the array goes out of scope, the memory get (eventually) unmap+fileMapRead :: FilePath -> IO (V.UArray Word8)+fileMapRead fp = do+ fileMapping <- I.fileMapRead fp+ fptr <- I.fileMappingToFinalPtr fileMapping+ return $ V.foreignMem fptr (getSize fileMapping)++-- | Map in memory the whole content of a file,++-- the whole map is unmapped at the end of function after the function has been called+-- so any things that is still holding on to this memory will very likely trigger segfault+-- or other really bad behavior.+fileMapReadWith :: FilePath -> (V.UArray Word8 -> IO a) -> IO a+fileMapReadWith fp f = do+ bracket (I.fileMapRead fp) I.fileMappingUnmap $ \fm -> do+ fptr <- toFinalPtr (I.fileMappingPtr fm) (\_ -> return ())+ f (V.foreignMem fptr (getSize fm))
+ Foundation/IO/Terminal.hs view
@@ -0,0 +1,23 @@+-- |+-- Module : Foundation.IO.Terminal+-- License : BSD-style+-- Maintainer : Foundation+-- Stability : experimental+-- Portability : portable+--+module Foundation.IO.Terminal+ ( putStrLn+ , putStr+ ) where++import Foundation.Internal.Base+import Foundation.String+import qualified Prelude++-- | Print a string to standard output+putStr :: String -> IO ()+putStr = Prelude.putStr . toList++-- | Print a string with a newline to standard output+putStrLn :: String -> IO ()+putStrLn = Prelude.putStrLn . toList
+ Foundation/Internal/Base.hs view
@@ -0,0 +1,74 @@+-- |+-- Module : Foundation.Internal.Base+-- License : BSD-style+-- Maintainer : Vincent Hanquez <vincent@snarc.org>+-- Stability : experimental+-- Portability : portable+--+-- internal re-export of all the good base bits+module Foundation.Internal.Base+ ( (Prelude.$)+ , (Prelude.$!)+ , (Prelude.&&)+ , (Prelude.||)+ , (Control.Category..)+ , (Control.Applicative.<$>)+ , Prelude.not+ , Prelude.otherwise+ , Prelude.fst+ , Prelude.snd+ , Control.Category.id+ , Prelude.maybe+ , Prelude.either+ , Prelude.flip+ , Prelude.const+ , Prelude.error+ , Prelude.and+ , Prelude.undefined+ , Prelude.seq+ , Prelude.Show (..)+ , Prelude.Ord (..)+ , Prelude.Eq (..)+ , Prelude.Bounded (..)+ , Prelude.Enum (..)+ , Prelude.Functor (..)+ , Control.Applicative.Applicative (..)+ , Prelude.Monad (..)+ , Prelude.Maybe (..)+ , Prelude.Ordering (..)+ , Prelude.Bool (..)+ , Prelude.Int+ , Prelude.Integer+ , Prelude.Char+ , Data.Int.Int8, Data.Int.Int16, Data.Int.Int32, Data.Int.Int64+ , Data.Word.Word8, Data.Word.Word16, Data.Word.Word32, Data.Word.Word64, Data.Word.Word+ , Prelude.IO+ , Foundation.Internal.IsList.IsList (..)+ , GHC.Exts.IsString (..)+ , GHC.Generics.Generic (..)+ , Prelude.Either (..)+ , Data.Typeable.Typeable+ , Data.Monoid.Monoid (..)+ , (Data.Monoid.<>)+ , Control.Exception.Exception+ , Control.Exception.throw+ , Control.Exception.throwIO+ -- * Errors+ , internalError+ ) where++import qualified Prelude+import qualified Control.Category+import qualified Control.Applicative+import qualified Control.Exception+import qualified Data.Monoid+import qualified Data.Typeable+import qualified Data.Word+import qualified Data.Int+import qualified Foundation.Internal.IsList+import qualified GHC.Exts+import qualified GHC.Generics++-- | Only to use internally for internal error cases+internalError :: [Prelude.Char] -> a+internalError s = Prelude.error ("Internal Error: the impossible happened: " Prelude.++ s)
+ Foundation/Internal/Identity.hs view
@@ -0,0 +1,37 @@+-- |+-- Module : Foundation.Internal.Identity+-- License : BSD-style+-- Maintainer : Vincent Hanquez <vincent@snarc.org>+-- Stability : experimental+-- Portability : portable+--+-- Identity re-export, with a compat wrapper for older version of base that+-- do not have Data.Functor.Identity+{-# LANGUAGE CPP #-}+module Foundation.Internal.Identity+ ( Identity(..)+ ) where++#if MIN_VERSION_base(4,8,0)++import Data.Functor.Identity++#else++import Foundation.Internal.Base++newtype Identity a = Identity { runIdentity :: a }+ deriving (Eq, Ord)++instance Functor Identity where+ fmap f (Identity a) = Identity (f a)++instance Applicative Identity where+ pure a = Identity a+ (<*>) fab fa = Identity $ runIdentity fab (runIdentity fa)++instance Monad Identity where+ return = pure+ ma >>= mb = mb (runIdentity ma)++#endif
+ Foundation/Internal/IsList.hs view
@@ -0,0 +1,36 @@+-- |+-- Module : Foundation.Internal.IsList+-- License : BSD-style+-- Maintainer : Vincent Hanquez <vincent@snarc.org>+-- Stability : experimental+-- Portability : portable+--+-- compat friendly version of IsList+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE CPP #-}+module Foundation.Internal.IsList+ ( IsList(..)+ ) where++#if MIN_VERSION_base(4,7,0)++import GHC.Exts++#else++import qualified Prelude++class IsList l where+ type Item l+ fromList :: [Item l] -> l+ toList :: l -> [Item l]++ fromListN :: Prelude.Int -> [Item l] -> l+ fromListN _ = fromList++instance IsList [a] where+ type Item [a] = a+ fromList = Prelude.id+ toList = Prelude.id++#endif
+ Foundation/Internal/MonadTrans.hs view
@@ -0,0 +1,49 @@+-- |+-- Module : Foundation.Internal.MonadTrans+-- License : BSD-style+-- Maintainer : Psychohistorians+-- Stability : experimental+-- Portability : portable+--+-- An internal and really simple monad transformers,+-- without any bells and whistse.+module Foundation.Internal.MonadTrans+ ( State(..)+ , Reader(..)+ ) where++import Foundation.Internal.Base++-- | Simple State monad+newtype State s m a = State { runState :: s -> m (a, s) }++instance Monad m => Functor (State s m) where+ fmap f fa = State $ \st -> runState fa st >>= \(a, s2) -> return (f a, s2)+instance Monad m => Applicative (State s m) where+ pure a = State $ \st -> return (a,st)+ fab <*> fa = State $ \s1 -> do+ (a,s2) <- runState fa s1+ (ab,s3) <- runState fab s2+ return (ab a, s3)+instance Monad m => Monad (State r m) where+ return a = State $ \st -> return (a,st)+ ma >>= mb = State $ \s1 -> do+ (a,s2) <- runState ma s1+ runState (mb a) s2++-- | Simple Reader monad+newtype Reader r m a = Reader { runReader :: r -> m a }++instance Monad m => Functor (Reader r m) where+ fmap f fa = Reader $ \r -> runReader fa r >>= \a -> return (f a)+instance Monad m => Applicative (Reader r m) where+ pure a = Reader $ \_ -> return a+ fab <*> fa = Reader $ \r -> do+ a <- runReader fa r+ ab <- runReader fab r+ return $ ab a+instance Monad m => Monad (Reader r m) where+ return a = Reader $ \_ -> return a+ ma >>= mb = Reader $ \r -> do+ a <- runReader ma r+ runReader (mb a) r
+ Foundation/Internal/PrimTypes.hs view
@@ -0,0 +1,28 @@+-- |+-- Module : Foundation.Internal.PrimTypes+-- License : BSD-style+-- Maintainer : Vincent Hanquez <vincent@snarc.org>+-- Stability : experimental+-- Portability : portable+--+{-# LANGUAGE MagicHash #-}+module Foundation.Internal.PrimTypes+ ( FileSize#+ , Offset#+ , Size#+ ) where++import GHC.Prim++-- | File size in bytes+type FileSize# = Word64#++-- | Offset in a bytearray, string, type alias+--+-- for code documentation purpose only, just a simple type alias on Int#+type Offset# = Int#++-- | Size in bytes type alias+--+-- for code documentation purpose only, just a simple type alias on Int#+type Size# = Int#
+ Foundation/Internal/Primitive.hs view
@@ -0,0 +1,144 @@+-- |+-- Module : Foundation.Internal.Primitive+-- License : BSD-style+-- Maintainer : Vincent Hanquez <vincent@snarc.org>+-- Stability : experimental+-- Portability : portable+--+{-# LANGUAGE MagicHash #-}+{-# LANGUAGE UnboxedTuples #-}+{-# LANGUAGE CPP #-}+module Foundation.Internal.Primitive+ ( bool#+ , PinnedStatus, pinned, unpinned, isPinned+ , compatAndI#+ , compatQuotRemInt#+ , compatCopyAddrToByteArray#+ , compatMkWeak#+ , compatGetSizeofMutableByteArray#+ , compatShrinkMutableByteArray#+ , compatResizeMutableByteArray#+ , Word(..)+ ) where++import qualified Prelude+import GHC.Prim+import GHC.Word+#if __GLASGOW_HASKELL__ >= 800+import GHC.IO+#endif++-- GHC 8.0 | Base 4.9+-- GHC 7.10 | Base 4.8+-- GHC 7.8 | Base 4.7+-- GHC 7.6 | Base 4.6+-- GHC 7.4 | Base 4.5++-- | Flag record whether a specific byte array is pinned or not+data PinnedStatus = PinnedStatus Int#++isPinned :: PinnedStatus -> Prelude.Bool+isPinned (PinnedStatus 0#) = Prelude.False+isPinned _ = Prelude.True++pinned :: PinnedStatus+pinned = PinnedStatus 1#++unpinned :: PinnedStatus+unpinned = PinnedStatus 0#++-- | turn an Int# into a Bool+--+-- Since GHC 7.8, boolean primitive don't return Bool but Int#.+#if MIN_VERSION_base(4,7,0)+bool# :: Int# -> Prelude.Bool+bool# v = tagToEnum# v+#else+bool# :: Prelude.Bool -> Prelude.Bool+bool# v = v+#endif+{-# INLINE bool# #-}++-- | A version friendly of andI#+compatAndI# :: Int# -> Int# -> Int#+#if !MIN_VERSION_base(4,7,0)+compatAndI# a b = word2Int# (and# (int2Word# a) (int2Word# b))+#else+compatAndI# = andI#+#endif+{-# INLINE compatAndI# #-}++-- | A version friendly of quotRemInt#+compatQuotRemInt# :: Int# -> Int# -> (# Int#, Int# #)+#if !MIN_VERSION_base(4,6,0)+compatQuotRemInt# a b = (# quotInt# a b, remInt# a b #)+#else+compatQuotRemInt# = quotRemInt#+#endif+{-# INLINE compatQuotRemInt# #-}++-- | A version friendly fo copyAddrToByteArray#+--+-- only available from GHC 7.8+compatCopyAddrToByteArray# :: Addr# -> MutableByteArray# s -> Int# -> Int# -> State# s -> State# s+#if MIN_VERSION_base(4,7,0)+compatCopyAddrToByteArray# = copyAddrToByteArray#+#else+compatCopyAddrToByteArray# addr ba ofs sz stini =+ loop ofs 0# stini+ where+ loop o i st+ | bool# (i ==# sz) = st+ | Prelude.otherwise =+ case readWord8OffAddr# addr i st of+ (# st2, w #) -> loop (o +# 1#) (i +# 1#) (writeWord8Array# ba o w st2)+#endif+{-# INLINE compatCopyAddrToByteArray# #-}++-- | A mkWeak# version that keep working on 8.0+--+-- signature change in ghc-prim:+-- * 0.4: mkWeak# :: o -> b -> c -> State# RealWorld -> (#State# RealWorld, Weak# b#)+-- * 0.5 :mkWeak# :: o -> b -> (State# RealWorld -> (#State# RealWorld, c#)) -> State# RealWorld -> (#State# RealWorld, Weak# b#)+--+compatMkWeak# :: o -> b -> Prelude.IO () -> State# RealWorld -> (#State# RealWorld, Weak# b #)+#if __GLASGOW_HASKELL__ >= 800+compatMkWeak# o b c s = mkWeak# o b (case c of { IO f -> f }) s+#else+compatMkWeak# o b c s = mkWeak# o b c s+#endif+{-# INLINE compatMkWeak# #-}++compatGetSizeofMutableByteArray# :: MutableByteArray# s -> State# s -> (#State# s, Int# #)+#if __GLASGOW_HASKELL__ >= 800+compatGetSizeofMutableByteArray# mba s = getSizeofMutableByteArray# mba s+#else+compatGetSizeofMutableByteArray# mba s = (# s, sizeofMutableByteArray# mba #)+#endif+{-# INLINE compatGetSizeofMutableByteArray# #-}++compatShrinkMutableByteArray# :: MutableByteArray# s -> Int# -> State# s -> (# State# s, MutableByteArray# s #)+#if __GLASGOW_HASKELL__ >= 800+compatShrinkMutableByteArray# mba i s =+ case shrinkMutableByteArray# mba i s of { s2 -> (# s2, mba #) }+#else+compatShrinkMutableByteArray# src i s =+ -- not check whether i is smaller than the size of the buffer+ case newAlignedPinnedByteArray# i 8# s of { (# s2, dst #) ->+ case copyMutableByteArray# dst 0# src 0# i s2 of { s3 -> (# s3, dst #) }}+#endif+{-# INLINE compatShrinkMutableByteArray# #-}++--shrinkMutableByteArray# :: MutableByteArray# s -> Int# -> State# s -> State# s+compatResizeMutableByteArray# :: MutableByteArray# s -> Int# -> State# s -> (# State# s, MutableByteArray# s #)+#if __GLASGOW_HASKELL__ >= 800+compatResizeMutableByteArray# mba i s = resizeMutableByteArray# mba i s+#else+compatResizeMutableByteArray# src i s =+ case newAlignedPinnedByteArray# i 8# s of { (# s2, dst #) ->+ case copyMutableByteArray# dst 0# src 0# (if isGrow then len else i) s2 of { s3 -> (# s3, dst #) }}+ where+ isGrow = bool# (i ># len)+ !len = sizeofMutableByteArray# src+#endif+{-# INLINE compatResizeMutableByteArray# #-}
+ Foundation/Internal/Proxy.hs view
@@ -0,0 +1,32 @@+-- |+-- Module : Foundation.Internal.Proxy+-- License : BSD-style+-- Maintainer : Vincent Hanquez <vincent@snarc.org>+-- Stability : experimental+-- Portability : portable+--+{-# LANGUAGE CPP #-}+module Foundation.Internal.Proxy+ ( Proxy(..)+ , asProxyTypeOf+ ) where++#if MIN_VERSION_base(4,7,0)+import Data.Proxy+#else+import qualified Prelude++data Proxy a = Proxy++instance Prelude.Show (Proxy a) where+ showsPrec _ _ = Prelude.showString "Proxy"++-- | 'asProxyTypeOf' is a type-restricted version of 'const'.+-- It is usually used as an infix operator, and its typing forces its first+-- argument (which is usually overloaded) to have the same type as the tag+-- of the second.+asProxyTypeOf :: a -> Proxy a -> a+asProxyTypeOf = Prelude.const+{-# INLINE asProxyTypeOf #-}++#endif
+ Foundation/Internal/Types.hs view
@@ -0,0 +1,87 @@+-- |+-- Module : Foundation.Internal.Types+-- License : BSD-style+-- Maintainer : Vincent Hanquez <vincent@snarc.org>+-- Stability : experimental+-- Portability : portable+--+module Foundation.Internal.Types+ ( FileSize(..)+ , Offset(..)+ , Offset8+ , offsetOfE+ , offsetPlusE+ , offsetMinusE+ , offsetRecast+ , (+.)+ , Size(..)+ , Size8+ , sizeOfE+ ) where++import GHC.Types+import GHC.Word+import Foundation.Internal.Base+import Foundation.Number++-- | File size in bytes+newtype FileSize = FileSize Word64+ deriving (Show,Eq,Ord)++-- | Offset in bytes used for memory addressing (e.g. in a vector, string, ..)+--+-- Int a terrible backing type which is hard to get away+-- considering that GHC/haskell are mostly using this for offset.+-- try to bring some sanity by a lightweight wrapping+--newtype Offset = Offset Int+-- deriving (Show,Eq,Ord)+type Offset8 = Offset Word8++-- | Offset in element of a certain type+newtype Offset ty = Offset Int+ deriving (Show,Eq,Ord)++instance Additive (Offset ty) where+ azero = Offset 0+ (+) (Offset a) (Offset b) = Offset (a+b)++instance Subtractive (Offset ty) where+ type Difference (Offset ty) = Size ty+ (Offset a) - (Offset b) = Size (a-b)++(+.) :: Offset ty -> Int -> Offset ty+(+.) (Offset a) b = Offset (a + b)++offsetOfE :: Size8 -> Offset ty -> Offset8+offsetOfE (Size sz) (Offset ty) = Offset (ty * sz)++offsetPlusE :: Offset ty -> Size ty -> Offset ty+offsetPlusE (Offset ofs) (Size sz) = Offset (ofs + sz)++offsetMinusE :: Offset ty -> Size ty -> Offset ty+offsetMinusE (Offset ofs) (Size sz) = Offset (ofs - sz)++offsetRecast :: Size8 -> Size8 -> Offset ty -> Offset ty2+offsetRecast szTy (Size szTy2) ofs =+ let (Offset bytes) = offsetOfE szTy ofs+ in Offset (bytes `div` szTy2)++-- | Size in bytes+--+-- Same caveat as Offset apply here+type Size8 = Size Word8++instance Additive (Size ty) where+ azero = Size 0+ (+) (Size a) (Size b) = Size (a+b)++instance Subtractive (Size ty) where+ type Difference (Size ty) = Size ty+ (Size a) - (Size b) = Size (a-b)++-- | Size in element+newtype Size ty = Size Int+ deriving (Show,Eq,Ord)++sizeOfE :: Size8 -> Size ty -> Size8+sizeOfE (Size sz) (Size ty) = Size (ty * sz)
+ Foundation/Number.hs view
@@ -0,0 +1,387 @@+-- |+-- Module : Foundation.Number+-- License : BSD-style+-- Maintainer : Vincent Hanquez <vincent@snarc.org>+-- Stability : experimental+-- Portability : portable+--+-- Compared to the Haskell hierarchy of number classes+-- this provide a more flexible approach that is closer to the+-- mathematical foundation (group, field, etc)+--+-- This try to only provide one feature per class, at the expense of+-- the number of classes.+--+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE DefaultSignatures #-}+module Foundation.Number+ ( Number(..)+ , fromInteger+ , Signed(..)+ , Additive(..)+ , Multiplicative(..)+ , Subtractive(..)+ , Divisible(..)+ , Sign(..)+ ) where++import Foundation.Internal.Base+import qualified Prelude++infixl 7 *+infixl 6 +, -+infixr 8 ^++-- | Sign of a signed number+data Sign = Negative | Zero | Positive+ deriving (Eq)++orderingToSign :: Ordering -> Sign+orderingToSign EQ = Zero+orderingToSign GT = Negative+orderingToSign LT = Positive++-- | Number literals, convertible through the generic Integer type.+--+-- all number are Enum'erable, meaning that you can move to+-- next element+class (Eq a, Ord a, Prelude.Num a, Enum a, Additive a, Subtractive a, Difference a ~ a, Multiplicative a, Divisible a) => Number a where+ {-# MINIMAL toInteger #-}+ --fromInteger :: Integer -> a+ toInteger :: a -> Integer++-- | convert an Integer to a type having the Number constraint+fromInteger :: Number a => Integer -> a+fromInteger = Prelude.fromInteger++-- | Number literals that can be negative+class Number a => Signed a where+ {-# MINIMAL abs, signum #-}+ abs :: a -> a+ signum :: a -> Sign++-- | Represent class of things that can be added together,+-- contains a neutral element and is commutative.+--+-- * x + azero = x+-- * azero + x = x+-- * x + y = y + x+--+class Additive a where+ {-# MINIMAL azero, (+) #-}+ azero :: a -- the identity element over addition+ (+) :: a -> a -> a -- the addition++ scale :: Number n => n -> a -> a -- scale: repeated addition+ default scale :: Number n => n -> a -> a+ scale 0 _ = azero+ scale 1 a = a+ scale 2 a = a + a+ scale n a+ | n < 0 = error "cannot scale by negative number"+ | otherwise = a + scale (pred n) a -- TODO optimise. define by group of 2.++-- | Represent class of things that can be multiplied together+--+-- * x * midentity = x+-- * midentity * x = x+class Multiplicative a where+ {-# MINIMAL midentity, (*) #-}+ -- | Identity element over multiplication+ midentity :: a++ -- | Multiplication of 2 elements that result in another element+ (*) :: a -> a -> a++ -- | Raise to power, repeated multiplication+ -- e.g.+ -- > a ^ 2 = a * a+ -- > a ^ 10 = (a ^ 5) * (a ^ 5) ..+ (^) :: Number n => a -> n -> a+ (^) = power++-- | Represent class of things that can be subtracted.+--+-- Note that the result is not necessary of the same type+-- as the operand depending on the actual type.+--+-- For example:+-- e.g. (-) :: Int -> Int -> Int+-- (-) :: DateTime -> DateTime -> Seconds+-- (-) :: Ptr a -> Ptr a -> PtrDiff+class Subtractive a where+ type Difference a+ (-) :: a -> a -> Difference a++-- | Represent class of things that can be divided+--+-- (x ‘div‘ y) * y + (x ‘mod‘ y) == x+class Multiplicative a => Divisible a where+ {-# MINIMAL (div, mod) | divMod #-}+ div :: a -> a -> a+ div a b = fst $ divMod a b+ mod :: a -> a -> a+ mod a b = snd $ divMod a b+ divMod :: a -> a -> (a, a)+ divMod a b = (div a b, mod a b)++instance Number Integer where+ toInteger i = i+instance Number Int where+ toInteger i = Prelude.fromIntegral i+instance Number Int8 where+ toInteger i = Prelude.fromIntegral i+instance Number Int16 where+ toInteger i = Prelude.fromIntegral i+instance Number Int32 where+ toInteger i = Prelude.fromIntegral i+instance Number Int64 where+ toInteger i = Prelude.fromIntegral i++instance Signed Integer where+ abs = Prelude.abs+ signum = orderingToSign . compare 0+instance Signed Int where+ abs = Prelude.abs+ signum = orderingToSign . compare 0+instance Signed Int8 where+ abs = Prelude.abs+ signum = orderingToSign . compare 0+instance Signed Int16 where+ abs = Prelude.abs+ signum = orderingToSign . compare 0+instance Signed Int32 where+ abs = Prelude.abs+ signum = orderingToSign . compare 0+instance Signed Int64 where+ abs = Prelude.abs+ signum = orderingToSign . compare 0++instance Number Word where+ toInteger i = Prelude.fromIntegral i+instance Number Word8 where+ toInteger i = Prelude.fromIntegral i+instance Number Word16 where+ toInteger i = Prelude.fromIntegral i+instance Number Word32 where+ toInteger i = Prelude.fromIntegral i+instance Number Word64 where+ toInteger i = Prelude.fromIntegral i++instance Additive Integer where+ azero = 0+ (+) = (Prelude.+)+ scale = scaleNum+instance Additive Int where+ azero = 0+ (+) = (Prelude.+)+ scale = scaleNum+instance Additive Int8 where+ azero = 0+ (+) = (Prelude.+)+ scale = scaleNum+instance Additive Int16 where+ azero = 0+ (+) = (Prelude.+)+ scale = scaleNum+instance Additive Int32 where+ azero = 0+ (+) = (Prelude.+)+ scale = scaleNum+instance Additive Int64 where+ azero = 0+ (+) = (Prelude.+)+ scale = scaleNum+instance Additive Word where+ azero = 0+ (+) = (Prelude.+)+ scale = scaleNum+instance Additive Word8 where+ azero = 0+ (+) = (Prelude.+)+ scale = scaleNum+instance Additive Word16 where+ azero = 0+ (+) = (Prelude.+)+ scale = scaleNum+instance Additive Word32 where+ azero = 0+ (+) = (Prelude.+)+ scale = scaleNum+instance Additive Word64 where+ azero = 0+ (+) = (Prelude.+)+ scale = scaleNum++scaleNum :: (Prelude.Num a, Number n) => n -> a -> a+scaleNum n a = (Prelude.fromIntegral $ toInteger n) Prelude.* a++instance Subtractive Integer where+ type Difference Integer = Integer+ (-) = (Prelude.-)+instance Subtractive Int where+ type Difference Int = Int+ (-) = (Prelude.-)+instance Subtractive Int8 where+ type Difference Int8 = Int8+ (-) = (Prelude.-)+instance Subtractive Int16 where+ type Difference Int16 = Int16+ (-) = (Prelude.-)+instance Subtractive Int32 where+ type Difference Int32 = Int32+ (-) = (Prelude.-)+instance Subtractive Int64 where+ type Difference Int64 = Int64+ (-) = (Prelude.-)+instance Subtractive Word where+ type Difference Word = Word+ (-) = (Prelude.-)+instance Subtractive Word8 where+ type Difference Word8 = Word8+ (-) = (Prelude.-)+instance Subtractive Word16 where+ type Difference Word16 = Word16+ (-) = (Prelude.-)+instance Subtractive Word32 where+ type Difference Word32 = Word32+ (-) = (Prelude.-)+instance Subtractive Word64 where+ type Difference Word64 = Word64+ (-) = (Prelude.-)++instance Multiplicative Integer where+ midentity = 1+ (*) = (Prelude.*)+ (^) = power+instance Multiplicative Int where+ midentity = 1+ (*) = (Prelude.*)+ (^) = power+instance Multiplicative Int8 where+ midentity = 1+ (*) = (Prelude.*)+ (^) = power+instance Multiplicative Int16 where+ midentity = 1+ (*) = (Prelude.*)+ (^) = power+instance Multiplicative Int32 where+ midentity = 1+ (*) = (Prelude.*)+ (^) = power+instance Multiplicative Int64 where+ midentity = 1+ (*) = (Prelude.*)+ (^) = power+instance Multiplicative Word where+ midentity = 1+ (*) = (Prelude.*)+ (^) = power+instance Multiplicative Word8 where+ midentity = 1+ (*) = (Prelude.*)+ (^) = power+instance Multiplicative Word16 where+ midentity = 1+ (*) = (Prelude.*)+ (^) = power+instance Multiplicative Word32 where+ midentity = 1+ (*) = (Prelude.*)+ (^) = power+instance Multiplicative Word64 where+ midentity = 1+ (*) = (Prelude.*)+ (^) = power++power :: (Number n, Multiplicative a) => a -> n -> a+power a n+ | n < 0 = error "(^): cannot use negative exponent"+ | n == 0 = midentity+ | otherwise = squaring midentity a n+ where+ squaring y x i+ | i == 0 = y+ | i == 1 = x * y+ | even i = squaring y (x*x) (i`div`2)+ | otherwise = squaring (x*y) (x*x) (pred i`div` 2)++--odd n = (n `mod` 2) /= 0+even :: Number n => n -> Bool+even n = (n `mod` 2) == 0++instance Divisible Integer where+ div = Prelude.div+ mod = Prelude.mod+instance Divisible Int where+ div = Prelude.div+ mod = Prelude.mod+instance Divisible Int8 where+ div = Prelude.div+ mod = Prelude.mod+instance Divisible Int16 where+ div = Prelude.div+ mod = Prelude.mod+instance Divisible Int32 where+ div = Prelude.div+ mod = Prelude.mod+instance Divisible Int64 where+ div = Prelude.div+ mod = Prelude.mod+instance Divisible Word where+ div = Prelude.quot+ mod = Prelude.rem+instance Divisible Word8 where+ div = Prelude.quot+ mod = Prelude.rem+instance Divisible Word16 where+ div = Prelude.quot+ mod = Prelude.rem+instance Divisible Word32 where+ div = Prelude.quot+ mod = Prelude.rem+instance Divisible Word64 where+ div = Prelude.quot+ mod = Prelude.rem++-- {-# RULES scaleNum = * #-}++--numUpSize :: a -> b+--numUpSize+-----------------------------------+{- haskell numerical classes:+ -+Prelude> :i Fractional+class Num a => Fractional a where+ (/) :: a -> a -> a+ recip :: a -> a+ fromRational :: Rational -> a+ -- Defined in ‘GHC.Real’+instance Fractional Float -- Defined in ‘GHC.Float’+instance Fractional Double -- Defined in ‘GHC.Float’++Prelude> :i Integral+class (Real a, Enum a) => Integral a where+ quot :: a -> a -> a+ rem :: a -> a -> a+ div :: a -> a -> a+ mod :: a -> a -> a+ quotRem :: a -> a -> (a, a)+ divMod :: a -> a -> (a, a)+ toInteger :: a -> Integer+ -- Defined in ‘GHC.Real’+instance Integral Word -- Defined in ‘GHC.Real’+instance Integral Integer -- Defined in ‘GHC.Real’+instance Integral Int -- Defined in ‘GHC.Real’++Prelude> :i Real+class (Num a, Ord a) => Real a where+ toRational :: a -> Rational+ -- Defined in ‘GHC.Real’+instance Real Word -- Defined in ‘GHC.Real’+instance Real Integer -- Defined in ‘GHC.Real’+instance Real Int -- Defined in ‘GHC.Real’+instance Real Float -- Defined in ‘GHC.Float’+instance Real Double -- Defined in ‘GHC.Float’+-}
+ Foundation/Partial.hs view
@@ -0,0 +1,80 @@+-- |+-- Module : Foundation.Partial+-- License : BSD-style+-- Maintainer : Vincent Hanquez <vincent@snarc.org>+-- Stability : experimental+-- Portability : portable+--+-- Partial give a way to annotate your partial function with+-- a simple wrapper, which can only evaluated using 'fromPartial'+--+-- > fromPartial ( head [] )+--+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+module Foundation.Partial+ ( Partial+ , PartialError+ , partialError+ , partial+ , fromPartial+ , head+ , fromJust+ , fromLeft+ , fromRight+ ) where++import Foundation.Internal.Base+import Foundation.Internal.Identity++-- | Partialiality wrapper.+newtype Partial a = Partial (Identity a)+ deriving (Functor, Applicative, Monad)++-- | An error related to the evaluation of a Partial value that failed.+--+-- it contains the name of the function and the reason for failure+data PartialError = PartialError [Char] [Char]+ deriving (Show,Eq,Typeable)++instance Exception PartialError++-- | Throw an asynchronous PartialError+partialError :: [Char] -> [Char] -> a+partialError lbl exp = throw (PartialError lbl exp)++-- | Create a value that is partial. this can only be+-- unwrap using the 'fromPartial' function+partial :: a -> Partial a+partial = pure++-- | Dewrap a possible partial value+fromPartial :: Partial a -> a+fromPartial (Partial ida) = runIdentity ida++-- | Partial function to get the head of a list+head :: [a] -> Partial a+head l = partial $+ case l of+ [] -> partialError "head" "empty list"+ x:_ -> x++-- | Partial function to grab the value inside a Maybe+fromJust :: Maybe a -> Partial a+fromJust x = partial $+ case x of+ Nothing -> partialError "fromJust" "Nothing"+ Just y -> y++-- Grab the Right value of an Either+fromRight :: Either a b -> Partial b+fromRight x = partial $+ case x of+ Left _ -> partialError "fromRight" "Left"+ Right a -> a++-- Grab the Left value of an Either+fromLeft :: Either a b -> Partial a+fromLeft x = partial $+ case x of+ Right _ -> partialError "fromLeft" "Right"+ Left a -> a
+ Foundation/Primitive.hs view
@@ -0,0 +1,19 @@+-- |+-- Module : Foundation.Primitive+-- License : BSD-style+-- Maintainer : Vincent Hanquez <vincent@snarc.org>+-- Stability : experimental+-- Portability : portable+--+-- Different collections (list, vector, string, ..) unified under 1 API.+-- an API to rules them all, and in the darkness bind them.+--+{-# LANGUAGE DefaultSignatures #-}+{-# LANGUAGE FlexibleInstances #-}+module Foundation.Primitive+ ( PrimType(..)+ , PrimMonad(..)+ ) where++import Foundation.Primitive.Types+import Foundation.Primitive.Monad
+ Foundation/Primitive/FinalPtr.hs view
@@ -0,0 +1,85 @@+-- |+-- Module : Foundation.Primitive.FinalPtr+-- License : BSD-style+-- Maintainer : Vincent Hanquez <vincent@snarc.org>+-- Stability : experimental+-- Portability : portable+--+-- A smaller ForeignPtr reimplementation that work in any prim monad.+--+-- Here be dragon.+--+{-# LANGUAGE MagicHash #-}+{-# LANGUAGE UnboxedTuples #-}+{-# LANGUAGE CPP #-}+module Foundation.Primitive.FinalPtr+ ( FinalPtr(..)+ , finalPtrSameMemory+ , castFinalPtr+ , toFinalPtr+ , toFinalPtrForeign+ , withFinalPtr+ , withUnsafeFinalPtr+ , withFinalPtrNoTouch+ ) where++import GHC.Ptr+import GHC.ForeignPtr+import GHC.IO+import Foundation.Primitive.Monad+import Foundation.Internal.Primitive+import Foundation.Internal.Base (return, Bool(..), (==))++-- | Create a pointer with an associated finalizer+data FinalPtr a = FinalPtr (Ptr a)+ | FinalForeign (ForeignPtr a)++-- | Check if 2 final ptr points on the same memory bits+--+-- it stand to reason that provided a final ptr that is still being referenced+-- and thus have the memory still valid, if 2 final ptrs have the+-- same address, they should be the same final ptr+finalPtrSameMemory :: FinalPtr a -> FinalPtr b -> Bool+finalPtrSameMemory (FinalPtr p1) (FinalPtr p2) = p1 == castPtr p2+finalPtrSameMemory (FinalForeign p1) (FinalForeign p2) = p1 == castForeignPtr p2+finalPtrSameMemory (FinalForeign _) (FinalPtr _) = False+finalPtrSameMemory (FinalPtr _) (FinalForeign _) = False++-- | create a new FinalPtr from a Pointer+toFinalPtr :: PrimMonad prim => Ptr a -> (Ptr a -> IO ()) -> prim (FinalPtr a)+toFinalPtr ptr finalizer = unsafePrimFromIO (primitive makeWithFinalizer)+ where+ makeWithFinalizer s =+ case compatMkWeak# ptr () (finalizer ptr) s of { (# s2, _ #) -> (# s2, FinalPtr ptr #) }++-- | Create a new FinalPtr from a ForeignPtr+toFinalPtrForeign :: ForeignPtr a -> FinalPtr a+toFinalPtrForeign fptr = FinalForeign fptr++-- | Cast a finalized pointer from type a to type b+castFinalPtr :: FinalPtr a -> FinalPtr b+castFinalPtr (FinalPtr a) = FinalPtr (castPtr a)+castFinalPtr (FinalForeign a) = FinalForeign (castForeignPtr a)++withFinalPtrNoTouch :: FinalPtr p -> (Ptr p -> a) -> a+withFinalPtrNoTouch (FinalPtr ptr) f = f ptr+withFinalPtrNoTouch (FinalForeign fptr) f = f (unsafeForeignPtrToPtr fptr)+{-# INLINE withFinalPtrNoTouch #-}++-- | Looks at the raw pointer inside a FinalPtr, making sure the+-- data pointed by the pointer is not finalized during the call to 'f'+withFinalPtr :: PrimMonad prim => FinalPtr p -> (Ptr p -> prim a) -> prim a+withFinalPtr (FinalPtr ptr) f = do+ r <- f ptr+ primTouch ptr+ return r+withFinalPtr (FinalForeign fptr) f = do+ r <- f (unsafeForeignPtrToPtr fptr)+ unsafePrimFromIO (touchForeignPtr fptr)+ return r+{-# INLINE withFinalPtr #-}++-- | Unsafe version of 'withFinalPtr'+withUnsafeFinalPtr :: PrimMonad prim => FinalPtr p -> (Ptr p -> prim a) -> a+withUnsafeFinalPtr fptr f = unsafePerformIO (unsafePrimToIO (withFinalPtr fptr f))+{-# NOINLINE withUnsafeFinalPtr #-}
+ Foundation/Primitive/Monad.hs view
@@ -0,0 +1,117 @@+-- |+-- Module : Foundation.Primitive.Monad+-- License : BSD-style+-- Maintainer : Vincent Hanquez <vincent@snarc.org>+-- Stability : experimental+-- Portability : portable+--+-- Allow to run operation in ST and IO, without having to+-- distinguinsh between the two. Most operations exposes+-- the bare nuts and bolts of how IO and ST actually+-- works, and relatively easy to shoot yourself in the foot+--+-- this is highly similar to the Control.Monad.Primitive+-- in the primitive package+--+{-# LANGUAGE MagicHash #-}+{-# LANGUAGE UnboxedTuples #-}+{-# LANGUAGE ExistentialQuantification #-}+module Foundation.Primitive.Monad+ ( PrimMonad(..)+ , unPrimMonad_+ , unsafePrimCast+ , unsafePrimToST+ , unsafePrimToIO+ , unsafePrimFromIO+ , primTouch+ ) where++import qualified Prelude+import GHC.ST+import GHC.STRef+import GHC.IORef+import GHC.IO+import GHC.Prim+import Foundation.Internal.Base (Exception, (.), ($))++-- | Primitive monad that can handle mutation.+--+-- For example: IO and ST.+class (Prelude.Functor m, Prelude.Monad m) => PrimMonad m where+ -- | type of state token associated with the PrimMonad m+ type PrimState m+ -- | type of variable associated with the PrimMonad m+ type PrimVar m :: * -> *+ -- | Unwrap the State# token to pass to a function a primitive function that returns an unboxed state and a value.+ primitive :: (State# (PrimState m) -> (# State# (PrimState m), a #)) -> m a+ -- | Throw Exception in the primitive monad+ primThrow :: Exception e => e -> m a+ -- | Run a Prim monad from a dedicated state#+ unPrimMonad :: m a -> State# (PrimState m) -> (# State# (PrimState m), a #)++ -- | Build a new variable in the Prim Monad+ primVarNew :: a -> m (PrimVar m a)+ -- | Read the variable in the Prim Monad+ primVarRead :: PrimVar m a -> m a+ -- | Write the variable in the Prim Monad+ primVarWrite :: PrimVar m a -> a -> m ()++-- | just like `unwrapPrimMonad` but throw away the result and return just the new State#+unPrimMonad_ :: PrimMonad m => m () -> State# (PrimState m) -> State# (PrimState m)+unPrimMonad_ p st =+ case unPrimMonad p st of+ (# st', () #) -> st'+{-# INLINE unPrimMonad_ #-}++instance PrimMonad IO where+ type PrimState IO = RealWorld+ type PrimVar IO = IORef+ primitive = IO+ {-# INLINE primitive #-}+ primThrow = throwIO+ unPrimMonad (IO p) = p+ {-# INLINE unPrimMonad #-}+ primVarNew = newIORef+ primVarRead = readIORef+ primVarWrite = writeIORef++instance PrimMonad (ST s) where+ type PrimState (ST s) = s+ type PrimVar (ST s) = STRef s+ primitive = ST+ {-# INLINE primitive #-}+ primThrow = unsafeIOToST . throwIO+ unPrimMonad (ST p) = p+ {-# INLINE unPrimMonad #-}+ primVarNew = newSTRef+ primVarRead = readSTRef+ primVarWrite = writeSTRef++-- | Convert a prim monad to another prim monad.+--+-- The net effect is that it coerce the state repr to another,+-- so the runtime representation should be the same, otherwise+-- hilary ensues.+unsafePrimCast :: (PrimMonad m1, PrimMonad m2) => m1 a -> m2 a+unsafePrimCast m = primitive (unsafeCoerce# (unPrimMonad m))+{-# INLINE unsafePrimCast #-}++-- | Convert any prim monad to an ST monad+unsafePrimToST :: PrimMonad prim => prim a -> ST s a+unsafePrimToST = unsafePrimCast+{-# INLINE unsafePrimToST #-}++-- | Convert any prim monad to an IO monad+unsafePrimToIO :: PrimMonad prim => prim a -> IO a+unsafePrimToIO = unsafePrimCast+{-# INLINE unsafePrimToIO #-}++-- | Convert any IO monad to a prim monad+unsafePrimFromIO :: PrimMonad prim => IO a -> prim a+unsafePrimFromIO = unsafePrimCast+{-# INLINE unsafePrimFromIO #-}++-- | Touch primitive lifted to any prim monad+primTouch :: PrimMonad m => a -> m ()+primTouch x = unsafePrimFromIO $ primitive $ \s -> case touch# x s of { s2 -> (# s2, () #) }+{-# INLINE primTouch #-}
+ Foundation/Primitive/Types.hs view
@@ -0,0 +1,281 @@+-- |+-- Module : Foundation.Primitive.Types+-- License : BSD-style+-- Maintainer : Vincent Hanquez <vincent@snarc.org>+-- Stability : experimental+-- Portability : portable+--+{-# LANGUAGE MagicHash #-}+{-# LANGUAGE UnboxedTuples #-}+module Foundation.Primitive.Types+ ( PrimType(..)+ , primOffsetOfE+ , primOffsetRecast+ , sizeRecast+ , offsetAsSize+ , sizeAsOffset+ ) where++import GHC.Prim+import GHC.Int+import GHC.Types+import GHC.Word+import Foundation.Internal.Proxy+import Foundation.Internal.Base+import Foundation.Internal.Types+import Foundation.Primitive.Monad+import qualified Prelude (quot)++-- | Represent the accessor for types that can be stored in the UArray and MUArray.+--+-- Types need to be a instance of storable and have fixed sized.+class Eq ty => PrimType ty where+ -- | get the size in bytes of a ty element+ primSizeInBytes :: Proxy ty -> Size8++ -----+ -- ByteArray section+ -----++ -- | return the element stored at a specific index+ primBaIndex :: ByteArray# -> Offset ty -> ty++ -----+ -- MutableByteArray section+ -----++ -- | Read an element at an index in a mutable array+ primMbaRead :: PrimMonad prim+ => MutableByteArray# (PrimState prim) -- ^ mutable array to read from+ -> Offset ty -- ^ index of the element to retrieve+ -> prim ty -- ^ the element returned++ -- | Write an element to a specific cell in a mutable array.+ primMbaWrite :: PrimMonad prim+ => MutableByteArray# (PrimState prim) -- ^ mutable array to modify+ -> Offset ty -- ^ index of the element to modify+ -> ty -- ^ the new value to store+ -> prim ()++ -----+ -- Addr# section+ -----++ -- | Read from Address, without a state. the value read should be considered a constant for all+ -- pratical purpose, otherwise bad thing will happens.+ primAddrIndex :: Addr# -> Offset ty -> ty++ -- | Read a value from Addr in a specific primitive monad+ primAddrRead :: PrimMonad prim+ => Addr#+ -> Offset ty+ -> prim ty+ -- | Write a value to Addr in a specific primitive monad+ primAddrWrite :: PrimMonad prim+ => Addr#+ -> Offset ty+ -> ty+ -> prim ()++{-# SPECIALIZE [3] primBaIndex :: ByteArray# -> Offset Word8 -> Word8 #-}++instance PrimType Word8 where+ primSizeInBytes _ = Size 1+ {-# INLINE primSizeInBytes #-}+ primBaIndex ba (Offset (I# n)) = W8# (indexWord8Array# ba n)+ {-# INLINE primBaIndex #-}+ primMbaRead mba (Offset (I# n)) = primitive $ \s1 -> let (# s2, r #) = readWord8Array# mba n s1 in (# s2, W8# r #)+ {-# INLINE primMbaRead #-}+ primMbaWrite mba (Offset (I# n)) (W8# w) = primitive $ \s1 -> (# writeWord8Array# mba n w s1, () #)+ {-# INLINE primMbaWrite #-}+ primAddrIndex addr (Offset (I# n)) = W8# (indexWord8OffAddr# addr n)+ {-# INLINE primAddrIndex #-}+ primAddrRead addr (Offset (I# n)) = primitive $ \s1 -> let (# s2, r #) = readWord8OffAddr# addr n s1 in (# s2, W8# r #)+ {-# INLINE primAddrRead #-}+ primAddrWrite addr (Offset (I# n)) (W8# w) = primitive $ \s1 -> (# writeWord8OffAddr# addr n w s1, () #)+ {-# INLINE primAddrWrite #-}++instance PrimType Word16 where+ primSizeInBytes _ = Size 2+ {-# INLINE primSizeInBytes #-}+ primBaIndex ba (Offset (I# n)) = W16# (indexWord16Array# ba n)+ {-# INLINE primBaIndex #-}+ primMbaRead mba (Offset (I# n)) = primitive $ \s1 -> let (# s2, r #) = readWord16Array# mba n s1 in (# s2, W16# r #)+ {-# INLINE primMbaRead #-}+ primMbaWrite mba (Offset (I# n)) (W16# w) = primitive $ \s1 -> (# writeWord16Array# mba n w s1, () #)+ {-# INLINE primMbaWrite #-}+ primAddrIndex addr (Offset (I# n)) = W16# (indexWord16OffAddr# addr n)+ {-# INLINE primAddrIndex #-}+ primAddrRead addr (Offset (I# n)) = primitive $ \s1 -> let (# s2, r #) = readWord16OffAddr# addr n s1 in (# s2, W16# r #)+ {-# INLINE primAddrRead #-}+ primAddrWrite addr (Offset (I# n)) (W16# w) = primitive $ \s1 -> (# writeWord16OffAddr# addr n w s1, () #)+ {-# INLINE primAddrWrite #-}+instance PrimType Word32 where+ primSizeInBytes _ = Size 4+ {-# INLINE primSizeInBytes #-}+ primBaIndex ba (Offset (I# n)) = W32# (indexWord32Array# ba n)+ {-# INLINE primBaIndex #-}+ primMbaRead mba (Offset (I# n)) = primitive $ \s1 -> let (# s2, r #) = readWord32Array# mba n s1 in (# s2, W32# r #)+ {-# INLINE primMbaRead #-}+ primMbaWrite mba (Offset (I# n)) (W32# w) = primitive $ \s1 -> (# writeWord32Array# mba n w s1, () #)+ {-# INLINE primMbaWrite #-}+ primAddrIndex addr (Offset (I# n)) = W32# (indexWord32OffAddr# addr n)+ {-# INLINE primAddrIndex #-}+ primAddrRead addr (Offset (I# n)) = primitive $ \s1 -> let (# s2, r #) = readWord32OffAddr# addr n s1 in (# s2, W32# r #)+ {-# INLINE primAddrRead #-}+ primAddrWrite addr (Offset (I# n)) (W32# w) = primitive $ \s1 -> (# writeWord32OffAddr# addr n w s1, () #)+ {-# INLINE primAddrWrite #-}+instance PrimType Word64 where+ primSizeInBytes _ = Size 8+ {-# INLINE primSizeInBytes #-}+ primBaIndex ba (Offset (I# n)) = W64# (indexWord64Array# ba n)+ {-# INLINE primBaIndex #-}+ primMbaRead mba (Offset (I# n)) = primitive $ \s1 -> let (# s2, r #) = readWord64Array# mba n s1 in (# s2, W64# r #)+ {-# INLINE primMbaRead #-}+ primMbaWrite mba (Offset (I# n)) (W64# w) = primitive $ \s1 -> (# writeWord64Array# mba n w s1, () #)+ {-# INLINE primMbaWrite #-}+ primAddrIndex addr (Offset (I# n)) = W64# (indexWord64OffAddr# addr n)+ {-# INLINE primAddrIndex #-}+ primAddrRead addr (Offset (I# n)) = primitive $ \s1 -> let (# s2, r #) = readWord64OffAddr# addr n s1 in (# s2, W64# r #)+ {-# INLINE primAddrRead #-}+ primAddrWrite addr (Offset (I# n)) (W64# w) = primitive $ \s1 -> (# writeWord64OffAddr# addr n w s1, () #)+ {-# INLINE primAddrWrite #-}+instance PrimType Int8 where+ primSizeInBytes _ = Size 1+ {-# INLINE primSizeInBytes #-}+ primBaIndex ba (Offset (I# n)) = I8# (indexInt8Array# ba n)+ {-# INLINE primBaIndex #-}+ primMbaRead mba (Offset (I# n)) = primitive $ \s1 -> let (# s2, r #) = readInt8Array# mba n s1 in (# s2, I8# r #)+ {-# INLINE primMbaRead #-}+ primMbaWrite mba (Offset (I# n)) (I8# w) = primitive $ \s1 -> (# writeInt8Array# mba n w s1, () #)+ {-# INLINE primMbaWrite #-}+ primAddrIndex addr (Offset (I# n)) = I8# (indexInt8OffAddr# addr n)+ {-# INLINE primAddrIndex #-}+ primAddrRead addr (Offset (I# n)) = primitive $ \s1 -> let (# s2, r #) = readInt8OffAddr# addr n s1 in (# s2, I8# r #)+ {-# INLINE primAddrRead #-}+ primAddrWrite addr (Offset (I# n)) (I8# w) = primitive $ \s1 -> (# writeInt8OffAddr# addr n w s1, () #)+ {-# INLINE primAddrWrite #-}+instance PrimType Int16 where+ primSizeInBytes _ = Size 2+ {-# INLINE primSizeInBytes #-}+ primBaIndex ba (Offset (I# n)) = I16# (indexInt16Array# ba n)+ {-# INLINE primBaIndex #-}+ primMbaRead mba (Offset (I# n)) = primitive $ \s1 -> let (# s2, r #) = readInt16Array# mba n s1 in (# s2, I16# r #)+ {-# INLINE primMbaRead #-}+ primMbaWrite mba (Offset (I# n)) (I16# w) = primitive $ \s1 -> (# writeInt16Array# mba n w s1, () #)+ {-# INLINE primMbaWrite #-}+ primAddrIndex addr (Offset (I# n)) = I16# (indexInt16OffAddr# addr n)+ {-# INLINE primAddrIndex #-}+ primAddrRead addr (Offset (I# n)) = primitive $ \s1 -> let (# s2, r #) = readInt16OffAddr# addr n s1 in (# s2, I16# r #)+ {-# INLINE primAddrRead #-}+ primAddrWrite addr (Offset (I# n)) (I16# w) = primitive $ \s1 -> (# writeInt16OffAddr# addr n w s1, () #)+ {-# INLINE primAddrWrite #-}+instance PrimType Int32 where+ primSizeInBytes _ = Size 4+ {-# INLINE primSizeInBytes #-}+ primBaIndex ba (Offset (I# n)) = I32# (indexInt32Array# ba n)+ {-# INLINE primBaIndex #-}+ primMbaRead mba (Offset (I# n)) = primitive $ \s1 -> let (# s2, r #) = readInt32Array# mba n s1 in (# s2, I32# r #)+ {-# INLINE primMbaRead #-}+ primMbaWrite mba (Offset (I# n)) (I32# w) = primitive $ \s1 -> (# writeInt32Array# mba n w s1, () #)+ {-# INLINE primMbaWrite #-}+ primAddrIndex addr (Offset (I# n)) = I32# (indexInt32OffAddr# addr n)+ {-# INLINE primAddrIndex #-}+ primAddrRead addr (Offset (I# n)) = primitive $ \s1 -> let (# s2, r #) = readInt32OffAddr# addr n s1 in (# s2, I32# r #)+ {-# INLINE primAddrRead #-}+ primAddrWrite addr (Offset (I# n)) (I32# w) = primitive $ \s1 -> (# writeInt32OffAddr# addr n w s1, () #)+ {-# INLINE primAddrWrite #-}+instance PrimType Int64 where+ primSizeInBytes _ = Size 8+ {-# INLINE primSizeInBytes #-}+ primBaIndex ba (Offset (I# n)) = I64# (indexInt64Array# ba n)+ {-# INLINE primBaIndex #-}+ primMbaRead mba (Offset (I# n)) = primitive $ \s1 -> let (# s2, r #) = readInt64Array# mba n s1 in (# s2, I64# r #)+ {-# INLINE primMbaRead #-}+ primMbaWrite mba (Offset (I# n)) (I64# w) = primitive $ \s1 -> (# writeInt64Array# mba n w s1, () #)+ {-# INLINE primMbaWrite #-}+ primAddrIndex addr (Offset (I# n)) = I64# (indexInt64OffAddr# addr n)+ {-# INLINE primAddrIndex #-}+ primAddrRead addr (Offset (I# n)) = primitive $ \s1 -> let (# s2, r #) = readInt64OffAddr# addr n s1 in (# s2, I64# r #)+ {-# INLINE primAddrRead #-}+ primAddrWrite addr (Offset (I# n)) (I64# w) = primitive $ \s1 -> (# writeInt64OffAddr# addr n w s1, () #)+ {-# INLINE primAddrWrite #-}++instance PrimType Float where+ primSizeInBytes _ = Size 4+ {-# INLINE primSizeInBytes #-}+ primBaIndex ba (Offset (I# n)) = F# (indexFloatArray# ba n)+ {-# INLINE primBaIndex #-}+ primMbaRead mba (Offset (I# n)) = primitive $ \s1 -> let (# s2, r #) = readFloatArray# mba n s1 in (# s2, F# r #)+ {-# INLINE primMbaRead #-}+ primMbaWrite mba (Offset (I# n)) (F# w) = primitive $ \s1 -> (# writeFloatArray# mba n w s1, () #)+ {-# INLINE primMbaWrite #-}+ primAddrIndex addr (Offset (I# n)) = F# (indexFloatOffAddr# addr n)+ {-# INLINE primAddrIndex #-}+ primAddrRead addr (Offset (I# n)) = primitive $ \s1 -> let (# s2, r #) = readFloatOffAddr# addr n s1 in (# s2, F# r #)+ {-# INLINE primAddrRead #-}+ primAddrWrite addr (Offset (I# n)) (F# w) = primitive $ \s1 -> (# writeFloatOffAddr# addr n w s1, () #)+ {-# INLINE primAddrWrite #-}+instance PrimType Double where+ primSizeInBytes _ = Size 8+ {-# INLINE primSizeInBytes #-}+ primBaIndex ba (Offset (I# n)) = D# (indexDoubleArray# ba n)+ {-# INLINE primBaIndex #-}+ primMbaRead mba (Offset (I# n)) = primitive $ \s1 -> let (# s2, r #) = readDoubleArray# mba n s1 in (# s2, D# r #)+ {-# INLINE primMbaRead #-}+ primMbaWrite mba (Offset (I# n)) (D# w) = primitive $ \s1 -> (# writeDoubleArray# mba n w s1, () #)+ {-# INLINE primMbaWrite #-}+ primAddrIndex addr (Offset (I# n)) = D# (indexDoubleOffAddr# addr n)+ {-# INLINE primAddrIndex #-}+ primAddrRead addr (Offset (I# n)) = primitive $ \s1 -> let (# s2, r #) = readDoubleOffAddr# addr n s1 in (# s2, D# r #)+ {-# INLINE primAddrRead #-}+ primAddrWrite addr (Offset (I# n)) (D# w) = primitive $ \s1 -> (# writeDoubleOffAddr# addr n w s1, () #)+ {-# INLINE primAddrWrite #-}++instance PrimType Char where+ primSizeInBytes _ = Size 4+ {-# INLINE primSizeInBytes #-}+ primBaIndex ba (Offset (I# n)) = C# (indexWideCharArray# ba n)+ {-# INLINE primBaIndex #-}+ primMbaRead mba (Offset (I# n)) = primitive $ \s1 -> let (# s2, r #) = readWideCharArray# mba n s1 in (# s2, C# r #)+ {-# INLINE primMbaRead #-}+ primMbaWrite mba (Offset (I# n)) (C# w) = primitive $ \s1 -> (# writeWideCharArray# mba n w s1, () #)+ {-# INLINE primMbaWrite #-}+ primAddrIndex addr (Offset (I# n)) = C# (indexWideCharOffAddr# addr n)+ {-# INLINE primAddrIndex #-}+ primAddrRead addr (Offset (I# n)) = primitive $ \s1 -> let (# s2, r #) = readWideCharOffAddr# addr n s1 in (# s2, C# r #)+ {-# INLINE primAddrRead #-}+ primAddrWrite addr (Offset (I# n)) (C# w) = primitive $ \s1 -> (# writeWideCharOffAddr# addr n w s1, () #)+ {-# INLINE primAddrWrite #-}++-- | Cast a Size linked to type A (Size A) to a Size linked to type B (Size B)+sizeRecast :: (PrimType a, PrimType b) => Size a -> Size b+sizeRecast = doRecast Proxy Proxy+ where doRecast :: (PrimType a, PrimType b) => Proxy a -> Proxy b -> Size a -> Size b+ doRecast pa pb sz =+ let szA = primSizeInBytes pa+ (Size szB) = primSizeInBytes pb+ (Size bytes) = sizeOfE szA sz+ in Size (bytes `Prelude.quot` szB)++primOffsetRecast :: (PrimType a, PrimType b) => Offset a -> Offset b+primOffsetRecast = doRecast Proxy Proxy+ where doRecast :: (PrimType a, PrimType b) => Proxy a -> Proxy b -> Offset a -> Offset b+ doRecast pa pb ofs =+ let szA = primSizeInBytes pa+ (Size szB) = primSizeInBytes pb+ (Offset bytes) = offsetOfE szA ofs+ in Offset (bytes `Prelude.quot` szB)++primOffsetOfE :: PrimType a => Offset a -> Offset8+primOffsetOfE = getOffset Proxy+ where getOffset :: PrimType a => Proxy a -> Offset a -> Offset8+ getOffset proxy = offsetOfE (primSizeInBytes proxy)++sizeAsOffset :: Size a -> Offset a+sizeAsOffset (Size a) = Offset a+{-# INLINE sizeAsOffset #-}++offsetAsSize :: Offset a -> Size a+offsetAsSize (Offset a) = Size a+{-# INLINE offsetAsSize #-}
+ Foundation/Primitive/Utils.hs view
@@ -0,0 +1,72 @@+-- |+-- Module : Foundation.Primitive.Utils+-- License : BSD-style+-- Maintainer : Vincent Hanquez <vincent@snarc.org>+-- Stability : experimental+-- Portability : portable+--+{-# LANGUAGE MagicHash #-}+{-# LANGUAGE UnboxedTuples #-}+module Foundation.Primitive.Utils+ ( primCopyFreezedBytes+ , primCopyFreezedBytesOffset+ , primCopyFreezedW32+ , primCopyFreezedW64+ , primMutableAddrSlideToStart+ , primMutableByteArraySlideToStart+ ) where++import Foundation.Internal.Base+import Foundation.Internal.Types+import Foundation.Internal.Primitive+import Foundation.Primitive.Monad+import GHC.Prim+import GHC.Types++-- | Copy all bytes from a byteArray# to a mutableByteArray#+primCopyFreezedBytes :: PrimMonad m => MutableByteArray# (PrimState m) -> ByteArray# -> m ()+primCopyFreezedBytes mba ba = primitive $ \st ->+ (# copyByteArray# ba 0# mba 0# (sizeofByteArray# ba) st , () #)+{-# INLINE primCopyFreezedBytes #-}++-- | Copy @nbBytes bytes from a byteArray# to a mutableByteArray# starting at an offset+primCopyFreezedBytesOffset :: PrimMonad m => MutableByteArray# (PrimState m) -> Int# -> ByteArray# -> Int# -> m ()+primCopyFreezedBytesOffset mba ofs ba nbBytes = primitive $ \st ->+ (# copyByteArray# ba 0# mba ofs nbBytes st , () #)+{-# INLINE primCopyFreezedBytesOffset #-}++-- | same as 'primCopyFreezedBytes' except copy using 32 bits word+primCopyFreezedW32 :: PrimMonad m => MutableByteArray# (PrimState m) -> ByteArray# -> m ()+primCopyFreezedW32 mba ba = primitive $ \st -> (# loop st 0#, () #)+ where+ !len = quotInt# (sizeofByteArray# ba) 8#+ loop !st !n+ | bool# (n ==# len) = st+ | otherwise = loop (writeWord32Array# mba n (indexWord32Array# ba n) st) (n +# 1#)+ {-# INLINE loop #-}+{-# INLINE primCopyFreezedW32 #-}++-- | same as 'primCopyFreezedBytes' except copy using 64 bits word+primCopyFreezedW64 :: PrimMonad m => MutableByteArray# (PrimState m) -> ByteArray# -> m ()+primCopyFreezedW64 mba ba = primitive $ \st -> (# loop st 0#, () #)+ where+ !len = quotInt# (sizeofByteArray# ba) 8#+ loop !st !n+ | bool# (n ==# len) = st+ | otherwise = loop (writeWord64Array# mba n (indexWord64Array# ba n) st) (n +# 1#)+ {-# INLINE loop #-}+{-# INLINE primCopyFreezedW64 #-}++primMutableByteArraySlideToStart :: PrimMonad m => MutableByteArray# (PrimState m) -> Offset8 -> Offset8 -> m ()+primMutableByteArraySlideToStart mba (Offset (I# ofs)) (Offset (I# end)) = primitive $ \st ->+ (# copyMutableByteArray# mba 0# mba ofs (end -# ofs) st, () #)++primMutableAddrSlideToStart :: PrimMonad m => Addr# -> Offset8 -> Offset8 -> m ()+primMutableAddrSlideToStart addr (Offset (I# ofsIni)) (Offset (I# end)) = primitive $ \st -> (# loop st 0# ofsIni, () #)+ where+ loop !st !dst !ofs+ | bool# (ofs ==# end) = st+ | otherwise =+ case readWord8OffAddr# addr ofs st of { (# st', v #) ->+ case writeWord8OffAddr# addr dst v st' of { st'' ->+ loop st'' (dst +# 1#) (ofs +# 1#) }}
+ Foundation/Strict.hs view
@@ -0,0 +1,37 @@+-- |+-- Module : Foundation.Strict+-- License : BSD-style+-- Maintainer : Foundation+-- Stability : stable+-- Portability : portable+--+-- Enforce strictness when executing lambda+--++module Foundation.Strict+ ( strict1+ , strict2+ , strict3+ , strict4+ , strict5+ , strict6+ ) where++strict1 :: (a -> b) -> a -> b+strict1 f !a = f a++strict2 :: (a -> b -> c) -> a -> b -> c+strict2 f !a !b = f a b++strict3 :: (a -> b -> c -> d) -> a -> b -> c -> d+strict3 f !a !b !c = f a b c++strict4 :: (a -> b -> c -> d -> e) -> a -> b -> c -> d -> e+strict4 f !a !b !c !d = f a b c d++strict5 :: (a -> b -> c -> d -> e -> f) -> a -> b -> c -> d -> e -> f+strict5 f !a !b !c !d !e = f a b c d e++strict6 :: (a -> b -> c -> d -> e -> f -> g) -> a -> b -> c -> d -> e -> f -> g+strict6 f !a !b !c !d !e !g = f a b c d e g+
+ Foundation/String.hs view
@@ -0,0 +1,35 @@+-- |+-- Module : Foundation.String+-- License : BSD-style+-- Maintainer : Vincent Hanquez <vincent@snarc.org>+-- Stability : experimental+-- Portability : portable+--+-- Opaque packed String encoded in UTF8.+--+-- The type is an instance of IsString and IsList, which allow OverloadedStrings+-- for string literal, and 'fromList' to convert a [Char] (Prelude String) to a packed+-- representation+--+-- > {-# LANGUAGE OverloadedStrings #-}+-- > s = "Hello World :: String+--+-- > s = fromList ("Hello World" :: Prelude.String) :: String+--+-- Each unicode code point is represented by a variable encoding of 1 to 4 bytes,+--+-- For more information about UTF8: <https://en.wikipedia.org/wiki/UTF-8>+--+module Foundation.String+ ( String+ , Encoding(..)+ , fromBytes+ , fromBytesLenient+ , fromBytesUnsafe+ , toBytes+ , ValidationFailure(..)+ , lines+ , words+ ) where++import Foundation.String.UTF8
+ Foundation/String/Encoding/ASCII7.hs view
@@ -0,0 +1,86 @@+-- |+-- Module : Foundation.String.Encoding.ASCII7+-- License : BSD-style+-- Maintainer : Foundation+-- Stability : experimental+-- Portability : portable+--++{-# LANGUAGE MagicHash #-}++module Foundation.String.Encoding.ASCII7+ ( ASCII7(..)+ , ASCII7_Invalid(..)+ ) where++import Foundation.Internal.Base+import Foundation.Internal.Types+import Foundation.Number+import Foundation.Primitive.Monad++import GHC.Prim+import GHC.Word+import GHC.Types+import Foundation.Array.Unboxed.Builder++import Foundation.String.Encoding.Encoding++-- | validate a given byte is within ASCII characters encoring size+--+-- This function check the 8th bit is set to 0+--+isAscii :: Word8 -> Bool+isAscii (W8# w) = W8# (and# w 0x80## ) == 0+{-# INLINE isAscii #-}++-- offset of size one+aone :: Offset Word8+aone = Offset 1++data ASCII7_Invalid+ = ByteOutOfBound Word8+ | CharNotAscii Char+ deriving (Typeable, Show, Eq)+instance Exception ASCII7_Invalid++data ASCII7 = ASCII7++instance Encoding ASCII7 where+ type Unit ASCII7 = Word8+ type Error ASCII7 = ASCII7_Invalid+ encodingNext _ = next+ encodingWrite _ = write++-- | consume an Ascii7 char and return the Unicode point and the position+-- of the next possible Ascii7 char+--+next :: (Offset Word8 -> Word8)+ -- ^ method to access a given byte+ -> Offset Word8+ -- ^ index of the byte+ -> Either ASCII7_Invalid (Char, Offset Word8)+ -- ^ either successfully validated the ASCII char and returned the+ -- next index or fail with an error+next getter off+ | isAscii w8 = Right (toChar w, off + aone)+ | otherwise = Left $ ByteOutOfBound w8+ where+ !w8@(W8# w) = getter off+ toChar :: Word# -> Char+ toChar a = C# (chr# (word2Int# a))++-- Write ascii char+--+-- > build 64 $ sequence_ write "this is a simple list of char..."+--+write :: (PrimMonad st, Monad st)+ => Char+ -- ^ expecting it to be a valid Ascii character.+ -- otherwise this function will throw an exception+ -> ArrayBuilder Word8 st ()+write c+ | c < toEnum 0x80 = appendTy $ w8 c+ | otherwise = throw $ CharNotAscii c+ where+ w8 :: Char -> Word8+ w8 (C# ch) = W8# (int2Word# (ord# ch))
+ Foundation/String/Encoding/Encoding.hs view
@@ -0,0 +1,102 @@+-- |+-- Module : Foundation.String.Encoding.Encoding+-- License : BSD-style+-- Maintainer : Foundation+-- Stability : experimental+-- Portability : portable+--++{-# LANGUAGE FlexibleContexts #-}++module Foundation.String.Encoding.Encoding+ ( Encoding(..)+ , convertFromTo+ ) where++import Foundation.Internal.Base+import Foundation.Internal.Types+import Foundation.Primitive.Monad+import Foundation.Primitive.Types+import Foundation.Array.Unboxed.Builder+import Foundation.Number+import qualified Foundation.Collection as C+import Foundation.Array.Unboxed (UArray)+import qualified Foundation.Array.Unboxed as Vec++class Encoding encoding where+ -- | the unit element use for the encoding.+ -- i.e. Word8 for ASCII7 or UTF8, Word16 for UTF16...+ --+ type Unit encoding++ -- | define the type of error handling you want to use for the+ -- next function.+ --+ -- > type Error UTF8 = Either UTF8_Invalid+ --+ type Error encoding++ -- | consume an `Unit encoding` and return the Unicode point and the position+ -- of the next possible `Unit encoding`+ --+ encodingNext :: encoding+ -- ^ only used for type deduction+ -> (Offset (Unit encoding) -> Unit encoding)+ -- ^ method to access a given `Unit encoding`+ -- (see `unsafeIndexer`)+ -> Offset (Unit encoding)+ -- ^ offset of the `Unit encoding` where starts the+ -- encoding of a given unicode+ -> Either (Error encoding) (Char, Offset (Unit encoding))+ -- ^ either successfully validated the `Unit encoding`+ -- and returned the next offset or fail with an+ -- `Error encoding`++ -- Write a unicode point encoded into one or multiple `Unit encoding`+ --+ -- > build 64 $ sequence_ (write UTF8) "this is a simple list of char..."+ --+ encodingWrite :: (PrimMonad st, Monad st)+ => encoding+ -- ^ only used for type deduction+ -> Char+ -- ^ the unicode character to encode+ -> ArrayBuilder (Unit encoding) st ()++-- | helper to convert a given Array in a given encoding into an array+-- with another encoding.+--+-- This is a helper to convert from one String encoding to another.+-- This function is (quite) slow and needs some work.+--+-- ```+-- let s16 = ... -- string in UTF16+-- -- create s8, a UTF8 String+-- let s8 = runST $ convertWith UTF16 UTF8 (toBytes s16)+--+-- print s8+-- ```+--+convertFromTo :: ( PrimMonad st, Monad st+ , Encoding input, PrimType (Unit input)+ , Exception (Error input)+ , Encoding output, PrimType (Unit output)+ )+ => input+ -- ^ Input's encoding type+ -> output+ -- ^ Output's encoding type+ -> UArray (Unit input)+ -- ^ the input raw array+ -> st (UArray (Unit output))+convertFromTo inputEncodingTy outputEncodingTy bytes+ | C.null bytes = return mempty+ | otherwise = Vec.unsafeIndexer bytes $ \t -> build 64 (loop azero t)+ where+ lastUnit = Offset $ C.length bytes++ loop off getter+ | off >= lastUnit = return ()+ | otherwise = case encodingNext inputEncodingTy getter off of+ Left err -> throw err+ Right (c, noff) -> encodingWrite outputEncodingTy c >> loop noff getter
+ Foundation/String/Encoding/ISO_8859_1.hs view
@@ -0,0 +1,62 @@+-- |+-- Module : Foundation.String.Encoding.ISO_8859_1+-- License : BSD-style+-- Maintainer : Foundation+-- Stability : experimental+-- Portability : portable+--++{-# LANGUAGE MagicHash #-}++module Foundation.String.Encoding.ISO_8859_1+ ( ISO_8859_1(..)+ , ISO_8859_1_Invalid(..)+ ) where++import Foundation.Internal.Base+import Foundation.Internal.Types+import Foundation.Number+import Foundation.Primitive.Monad++import GHC.Prim+import GHC.Word+import GHC.Types+import Foundation.Array.Unboxed.Builder++import Foundation.String.Encoding.Encoding++-- offset of size one+aone :: Offset Word8+aone = Offset 1++data ISO_8859_1_Invalid+ = NotISO_8859_1 Char+ deriving (Typeable, Show, Eq)+instance Exception ISO_8859_1_Invalid++data ISO_8859_1 = ISO_8859_1++instance Encoding ISO_8859_1 where+ type Unit ISO_8859_1 = Word8+ type Error ISO_8859_1 = ISO_8859_1_Invalid+ encodingNext _ = next+ encodingWrite _ = write++next :: (Offset Word8 -> Word8)+ -> Offset Word8+ -> Either ISO_8859_1_Invalid (Char, Offset Word8)+next getter off = Right (toChar w, off + aone)+ where+ !(W8# w) = getter off+ toChar :: Word# -> Char+ toChar a = C# (chr# (word2Int# a))++write :: (PrimMonad st, Monad st)+ => Char+ -> ArrayBuilder Word8 st ()+write c@(C# ch)+ | c <= toEnum 0xFF = appendTy (W8# x)+ | otherwise = throw $ NotISO_8859_1 c+ where+ x :: Word#+ !x = int2Word# (ord# ch)
+ Foundation/String/Encoding/UTF16.hs view
@@ -0,0 +1,95 @@+-- |+-- Module : Foundation.String.Encoding.UTF16+-- License : BSD-style+-- Maintainer : Foundation+-- Stability : experimental+-- Portability : portable+--+{-# LANGUAGE MagicHash #-}+module Foundation.String.Encoding.UTF16+ ( UTF16(..)+ , UTF16_Invalid(..)+ ) where++import Foundation.Internal.Base+import Foundation.Internal.Types+import Foundation.Primitive.Monad+import GHC.Prim+import GHC.Word+import GHC.Types+import Foundation.Number+import Data.Bits+import qualified Prelude+import Foundation.Array.Unboxed.Builder++import Foundation.String.Encoding.Encoding++data UTF16_Invalid+ = InvalidContinuation+ | InvalidUnicode Char+ deriving (Show, Eq, Typeable)+instance Exception UTF16_Invalid++data UTF16 = UTF16++instance Encoding UTF16 where+ type Unit UTF16 = Word16+ type Error UTF16 = UTF16_Invalid+ encodingNext _ = next+ encodingWrite _ = write+++--+-- U+0000 to U+D7FF and U+E000 to U+FFFF : 1 bytes+-- U+10000 to U+10FFFF :+-- * 0x010000 is subtracted from the code point, leaving a 20-bit number in the range 0..0x0FFFFF.+-- * The top ten bits (a number in the range 0..0x03FF) are added to 0xD800 to give the first 16-bit code unit+-- or high surrogate, which will be in the range 0xD800..0xDBFF.+-- * The low ten bits (also in the range 0..0x03FF) are added to 0xDC00 to give the second 16-bit code unit+-- or low surrogate, which will be in the range 0xDC00..0xDFFF.++next :: (Offset Word16 -> Word16)+ -> Offset Word16+ -> Either UTF16_Invalid (Char, Offset Word16)+next getter off+ | h < 0xd800 = Right (toChar hh, off + Offset 1)+ | h >= 0xe000 = Right (toChar hh, off + Offset 1)+ | otherwise = nextContinuation+ where+ h :: Word16+ !h@(W16# hh) = getter off+ toChar :: Word# -> Char+ toChar w = C# (chr# (word2Int# w))+ to32 :: Word16 -> Word32+ to32 (W16# w) = W32# w++ nextContinuation+ | cont >= 0xdc00 && cont < 0xe00 =+ let !(W32# w) = ((to32 h .&. 0x3ff) `shiftL` 10)+ .|. (to32 cont .&. 0x3ff)+ in Right (toChar w, off + Offset 2)+ | otherwise = Left InvalidContinuation+ where+ cont :: Word16+ !cont = getter $ off + Offset 1++write :: (PrimMonad st, Monad st)+ => Char+ -> ArrayBuilder Word16 st ()+write c+ | c < toEnum 0xd800 = appendTy $ w16 c+ | c > toEnum 0x10000 = let (w1, w2) = wHigh c in appendTy w1 >> appendTy w2+ | c > toEnum 0x10ffff = throw $ InvalidUnicode c+ | c >= toEnum 0xe000 = appendTy $ w16 c+ | otherwise = throw $ InvalidUnicode c+ where+ w16 :: Char -> Word16+ w16 (C# ch) = W16# (int2Word# (ord# ch))++ to16 :: Word32 -> Word16+ to16 = Prelude.fromIntegral++ wHigh :: Char -> (Word16, Word16)+ wHigh (C# ch) =+ let v = W32# (minusWord# (int2Word# (ord# ch)) 0x10000##)+ in (0xdc00 .|. to16 (v `shiftR` 10), 0xd800 .|. to16 (v .&. 0x3ff))
+ Foundation/String/Encoding/UTF32.hs view
@@ -0,0 +1,53 @@+-- |+-- Module : Foundation.String.Encoding.UTF32+-- License : BSD-style+-- Maintainer : Foundation+-- Stability : experimental+-- Portability : portable+--+{-# LANGUAGE MagicHash #-}+module Foundation.String.Encoding.UTF32+ ( UTF32(..)+ , UTF32_Invalid+ ) where++import Foundation.Internal.Base+import Foundation.Internal.Types+import Foundation.Primitive.Monad+import GHC.Prim+import GHC.Word+import GHC.Types+import Foundation.Number+import Foundation.Array.Unboxed.Builder++import Foundation.String.Encoding.Encoding++data UTF32 = UTF32++data UTF32_Invalid = UTF32_Invalid+ deriving (Typeable, Show, Eq, Ord, Enum, Bounded)+instance Exception UTF32_Invalid++instance Encoding UTF32 where+ type Unit UTF32 = Word32+ type Error UTF32 = UTF32_Invalid+ encodingNext _ = next+ encodingWrite _ = write++next :: (Offset Word32 -> Word32)+ -> Offset Word32+ -> Either UTF32_Invalid (Char, Offset Word32)+next getter off = Right (char, off + Offset 1)+ where+ !(W32# hh) = getter off+ char :: Char+ char = C# (chr# (word2Int# hh))++write :: (PrimMonad st, Monad st)+ => Char+ -> ArrayBuilder Word32 st ()+write c = appendTy w32+ where+ !(C# ch) = c+ w32 :: Word32+ w32 = W32# (int2Word# (ord# ch))
+ Foundation/String/Internal.hs view
@@ -0,0 +1,10 @@+-- |+-- Module : Foundation.String.Internal+-- License : BSD-style+-- Maintainer : Vincent Hanquez <vincent@snarc.org>+-- Stability : experimental+-- Portability : portable+--+module Foundation.String.Internal+ (+ ) where
+ Foundation/String/ModifiedUTF8.hs view
@@ -0,0 +1,81 @@+-- |+-- Module : Foundation.String.ModifiedUTF8+-- License : BSD-style+-- Maintainer : foundation+-- Stability : experimental+-- Portability : portable+--+-- A String type backed by a Modified UTF8 encoded byte array and all the+-- necessary functions to manipulate the string.+--+-- You can think of String as a specialization of a byte array that+-- have element of type Char.+--+-- The String data must contain UTF8 valid data.+--++{-# LANGUAGE MagicHash #-}+module Foundation.String.ModifiedUTF8+ ( fromModified+ ) where++import GHC.ST (runST, ST)+import GHC.Prim (Addr#)+import GHC.Ptr (Ptr(..))+import qualified Control.Monad (mapM)++import Foundation.Internal.Base+import Foundation.Internal.Types+import qualified Foundation.Array.Unboxed as Vec+import Foundation.Array.Unboxed (UArray)+import Foundation.Number+import Foundation.Array.Unboxed.Builder+import Foundation.Primitive.FinalPtr+import Foundation.String.UTF8Table++-- offset of size one+aone :: Offset Word8+aone = Offset 1++-- helper function to read some bytes from the given byte reader+accessBytes :: Offset Word8 -> (Offset Word8 -> Word8) -> ([Word8], Offset Word8)+accessBytes offset getAtIdx = (loop offset, pastEnd)+ where+ nbytes :: Size Word8+ nbytes = Size $ getNbBytes $ getAtIdx offset+ pastEnd :: Offset Word8+ pastEnd = aone + (offset `offsetPlusE` nbytes)+ loop :: Offset Word8 -> [Word8]+ loop off+ | off == pastEnd = []+ | otherwise = getAtIdx off : loop (off + aone)++buildByteArray :: Addr# -> ST st (UArray Word8)+buildByteArray addr = Vec.UVecAddr (Offset 0) (Size 100000) `fmap`+ toFinalPtr (Ptr addr) (\_ -> return ())++-- | assuming the given ByteArray is a valid modified UTF-8 sequence of bytes+--+-- We only modify the given Unicode Null-character (0xC080) into a null bytes+--+-- FIXME: need to evaluate the kind of modified UTF8 GHC is actually expecting+-- it is plausible they only handle the Null Bytes, which this function actually+-- does.+fromModified :: Addr# -> UArray Word8+fromModified addr = runST $ do+ ba <- buildByteArray addr+ Vec.unsafeIndexer ba buildWithBytes+ where+ buildWithBytes getAt = build 64 $ loopBuilder getAt (Offset 0)+ loopBuilder getAt offset =+ let (bs, noffset) = accessBytes offset getAt+ in case bs of+ [] -> internalError "ModifiedUTF8.fromModified"+ [0x00] -> return ()+ [b1,b2] | b1 == 0xC0 && b2 == 0x80 -> appendTy 0x00 >> loopBuilder getAt noffset+ _ -> Control.Monad.mapM appendTy bs >> loopBuilder getAt noffset++{-+toModified :: ByteArray -> ByteArray+toModified = undefined+-}
+ Foundation/String/UTF8.hs view
@@ -0,0 +1,962 @@+-- |+-- Module : Foundation.String.UTF8+-- License : BSD-style+-- Maintainer : Vincent Hanquez <vincent@snarc.org>+-- Stability : experimental+-- Portability : portable+--+-- A String type backed by a UTF8 encoded byte array and all the necessary+-- functions to manipulate the string.+--+-- You can think of String as a specialization of a byte array that+-- have element of type Char.+--+-- The String data must contain UTF8 valid data.+--+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE MagicHash #-}+{-# LANGUAGE NoImplicitPrelude #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE UnboxedTuples #-}+{-# LANGUAGE FlexibleContexts #-}+module Foundation.String.UTF8+ ( String(..)+ --, Buffer+ , create+ , replicate+ -- * Binary conversion+ , Encoding(..)+ , fromBytes+ , fromChunkBytes+ , fromBytesUnsafe+ , fromBytesLenient+ , toBytes+ , mutableValidate+ , ValidationFailure(..)+ -- * Legacy utility+ , lines+ , words+ ) where++import Foundation.Array.Unboxed (UArray)+import qualified Foundation.Array.Unboxed as Vec+import Foundation.Array.Unboxed.ByteArray (MutableByteArray)+import qualified Foundation.Array.Unboxed.Mutable as MVec+import qualified Foundation.Collection as C+import Foundation.Internal.Base+import Foundation.Internal.Primitive+import Foundation.Internal.Types+import Foundation.Number+import Foundation.Primitive.Monad+import Foundation.Primitive.Types+import Foundation.String.UTF8Table+import GHC.Prim+import GHC.ST+import GHC.Types+import GHC.Word+import Foundation.Array.Unboxed.Builder (ArrayBuilder, appendTy)++ -- temporary+import qualified Data.List+import Data.Data+import qualified Prelude++import Foundation.String.ModifiedUTF8 (fromModified)+import GHC.CString (unpackCString#,+ unpackCStringUtf8#)++import qualified Foundation.String.Encoding.Encoding as Encoder+import qualified Foundation.String.Encoding.ASCII7 as Encoder+import qualified Foundation.String.Encoding.UTF16 as Encoder+import qualified Foundation.String.Encoding.UTF32 as Encoder+import qualified Foundation.String.Encoding.ISO_8859_1 as Encoder++-- | Opaque packed array of characters in the UTF8 encoding+newtype String = String (UArray Word8)+ deriving (Typeable, Monoid, Eq, Ord)++newtype MutableString st = MutableString (MutableByteArray st)+ deriving (Typeable)++instance Show String where+ show = show . sToList+instance IsString String where+ fromString = sFromList+instance IsList String where+ type Item String = Char+ fromList = sFromList+ toList = sToList++type instance C.Element String = Char++instance C.InnerFunctor String where+ imap = charMap+instance C.Sequential String where+ null = null+ take = take+ drop = drop+ splitAt = splitAt+ revTake = revTake+ revDrop = revDrop+ revSplitAt = revSplitAt+ splitOn = splitOn+ break = break+ breakElem = breakElem+ intersperse = intersperse+ span = span+ filter = filter+ reverse = reverse+ unsnoc = unsnoc+ uncons = uncons+ snoc = snoc+ cons = cons+ find = find+ sortBy = sortBy+ length = length+ singleton = fromList . (:[])++instance C.Zippable String where+ -- TODO Use a string builder once available+ zipWith f a b = sFromList (C.zipWith f a b)++data ValidationFailure = InvalidHeader+ | InvalidContinuation+ | MissingByte+ deriving (Show,Eq,Typeable)++instance Exception ValidationFailure++data EncoderUTF8 = EncoderUTF8++instance Encoder.Encoding EncoderUTF8 where+ type Unit EncoderUTF8 = Word8+ type Error EncoderUTF8 = ValidationFailure+ encodingNext _ = \ofs -> Right . nextWithIndexer ofs+ encodingWrite _ = writeWithBuilder++-- | Validate a bytearray for UTF8'ness+--+-- On success Nothing is returned+-- On Failure the position along with the failure reason+validate :: UArray Word8+ -> Offset8+ -> Size Word8+ -> (Offset8, Maybe ValidationFailure)+validate ba ofsStart sz = runST (Vec.unsafeIndexer ba go)+ where+ end = ofsStart `offsetPlusE` sz++ go :: (Offset Word8 -> Word8) -> ST s (Offset Word8, Maybe ValidationFailure)+ go getIdx = return $ loop ofsStart+ where+ loop ofs+ | ofs > end = error "validate: internal error: went pass offset"+ | ofs == end = (end, Nothing)+ | otherwise =+ case {-# SCC "validate.one" #-} one ofs of+ (nextOfs, Nothing) -> loop nextOfs+ (pos, Just failure) -> (pos, Just failure)++ one pos =+ case nbConts of+ 0 -> (pos + o1, Nothing)+ 0xff -> (pos, Just InvalidHeader)+ _ | (pos + o1) `offsetPlusE` nbContsE > end -> (pos, Just MissingByte)+ 1 ->+ let c1 = getIdx (pos + o1)+ in if isContinuation c1+ then (pos + Offset 2, Nothing)+ else (pos, Just InvalidContinuation)+ 2 ->+ let c1 = getIdx (pos + o1)+ c2 = getIdx (pos + Offset 2)+ in if isContinuation c1 && isContinuation c2+ then (pos + Offset 3, Nothing)+ else (pos, Just InvalidContinuation)+ 3 ->+ let c1 = getIdx (pos + Offset 1)+ c2 = getIdx (pos + Offset 2)+ c3 = getIdx (pos + Offset 3)+ in if isContinuation c1 && isContinuation c2 && isContinuation c3+ then (pos + Offset 4, Nothing)+ else (pos, Just InvalidContinuation)+ _ -> error "internal error"+ where+ !h = getIdx pos+ !nbContsE@(Size nbConts) = Size $ getNbBytes h+ {-# INLINE go #-}++ o1 = Offset 1++mutableValidate :: PrimMonad prim+ => MutableByteArray (PrimState prim)+ -> Int+ -> Int+ -> prim (Int, Maybe ValidationFailure)+mutableValidate mba ofsStart sz = do+ loop ofsStart+ where+ end = ofsStart + sz++ loop ofs+ | ofs > end = error "mutableValidate: internal error: went pass offset"+ | ofs == end = return (end, Nothing)+ | otherwise = do+ r <- one ofs+ case r of+ (nextOfs, Nothing) -> loop nextOfs+ (pos, Just failure) -> return (pos, Just failure)++ one pos = do+ h <- C.mutUnsafeRead mba pos+ let nbConts = getNbBytes h+ if nbConts == 0xff+ then return (pos, Just InvalidHeader)+ else if pos + 1 + nbConts > end+ then return (pos, Just MissingByte)+ else do+ case nbConts of+ 0 -> return (pos + 1, Nothing)+ 1 -> do+ c1 <- C.mutUnsafeRead mba (pos + 1)+ if isContinuation c1+ then return (pos + 2, Nothing)+ else return (pos, Just InvalidContinuation)+ 2 -> do+ c1 <- C.mutUnsafeRead mba (pos + 1)+ c2 <- C.mutUnsafeRead mba (pos + 2)+ if isContinuation c1 && isContinuation c2+ then return (pos + 3, Nothing)+ else return (pos, Just InvalidContinuation)+ 3 -> do+ c1 <- C.mutUnsafeRead mba (pos + 1)+ c2 <- C.mutUnsafeRead mba (pos + 2)+ c3 <- C.mutUnsafeRead mba (pos + 3)+ if isContinuation c1 && isContinuation c2 && isContinuation c3+ then return (pos + 4, Nothing)+ else return (pos, Just InvalidContinuation)+ _ -> error "internal error"++skipNext :: String -> Int -> Int+skipNext (String ba) n = n + 1 + getNbBytes h+ where+ !h = Vec.unsafeIndex ba n++nextWithIndexer :: (Offset Word8 -> Word8)+ -> Offset Word8+ -> (Char, Offset Word8)+nextWithIndexer getter off =+ case getNbBytes# h of+ 0# -> (toChar h, off + aone)+ 1# -> (toChar (decode2 (getter $ off + aone)), off + atwo)+ 2# -> (toChar (decode3 (getter $ off + aone) (getter $ off + atwo)), off + athree)+ 3# -> (toChar (decode4 (getter $ off + aone) (getter $ off + atwo) (getter $ off + athree))+ , off + afour)+ r -> error ("next: internal error: invalid input: " <> show (I# r) <> " " <> show (W# h))+ where+ aone = Offset 1+ atwo = Offset 2+ athree = Offset 3+ afour = Offset 4+ !(W8# h) = getter off++ toChar :: Word# -> Char+ toChar w = C# (chr# (word2Int# w))++ decode2 :: Word8 -> Word#+ decode2 (W8# c1) =+ or# (uncheckedShiftL# (and# h 0x1f##) 6#)+ (and# c1 0x3f##)++ decode3 :: Word8 -> Word8 -> Word#+ decode3 (W8# c1) (W8# c2) =+ or# (uncheckedShiftL# (and# h 0xf##) 12#)+ (or# (uncheckedShiftL# (and# c1 0x3f##) 6#)+ (and# c2 0x3f##))++ decode4 :: Word8 -> Word8 -> Word8 -> Word#+ decode4 (W8# c1) (W8# c2) (W8# c3) =+ or# (uncheckedShiftL# (and# h 0x7##) 18#)+ (or# (uncheckedShiftL# (and# c1 0x3f##) 12#)+ (or# (uncheckedShiftL# (and# c2 0x3f##) 6#)+ (and# c3 0x3f##))+ )++writeWithBuilder :: (PrimMonad st, Monad st)+ => Char+ -> ArrayBuilder Word8 st ()+writeWithBuilder c =+ if bool# (ltWord# x 0x80## ) then encode1+ else if bool# (ltWord# x 0x800## ) then encode2+ else if bool# (ltWord# x 0x10000##) then encode3+ else encode4+ where+ !(I# xi) = fromEnum c+ !x = int2Word# xi++ encode1 = appendTy (W8# x)++ encode2 = do+ let x1 = or# (uncheckedShiftRL# x 6#) 0xc0##+ x2 = toContinuation x+ appendTy (W8# x1) >> appendTy (W8# x2)++ encode3 = do+ let x1 = or# (uncheckedShiftRL# x 12#) 0xe0##+ x2 = toContinuation (uncheckedShiftRL# x 6#)+ x3 = toContinuation x+ appendTy (W8# x1) >> appendTy (W8# x2) >> appendTy (W8# x3)++ encode4 = do+ let x1 = or# (uncheckedShiftRL# x 18#) 0xf0##+ x2 = toContinuation (uncheckedShiftRL# x 12#)+ x3 = toContinuation (uncheckedShiftRL# x 6#)+ x4 = toContinuation x+ appendTy (W8# x1) >> appendTy (W8# x2) >> appendTy (W8# x3) >> appendTy (W8# x4)++ toContinuation :: Word# -> Word#+ toContinuation w = or# (and# w 0x3f##) 0x80##+++next :: String -> Offset8 -> (# Char, Offset8 #)+next (String ba) (Offset n) =+ case getNbBytes# h of+ 0# -> (# toChar h, Offset $ n + 1 #)+ 1# -> (# toChar (decode2 (Vec.unsafeIndex ba (n + 1))) , Offset $ n + 2 #)+ 2# -> (# toChar (decode3 (Vec.unsafeIndex ba (n + 1))+ (Vec.unsafeIndex ba (n + 2))) , Offset $ n + 3 #)+ 3# -> (# toChar (decode4 (Vec.unsafeIndex ba (n + 1))+ (Vec.unsafeIndex ba (n + 2))+ (Vec.unsafeIndex ba (n + 3))) , Offset $ n + 4 #)+ r -> error ("next: internal error: invalid input: " <> show (I# r) <> " " <> show (W# h))+ where+ !(W8# h) = Vec.unsafeIndex ba n++ toChar :: Word# -> Char+ toChar w = C# (chr# (word2Int# w))++ decode2 :: Word8 -> Word#+ decode2 (W8# c1) =+ or# (uncheckedShiftL# (and# h 0x1f##) 6#)+ (and# c1 0x3f##)++ decode3 :: Word8 -> Word8 -> Word#+ decode3 (W8# c1) (W8# c2) =+ or# (uncheckedShiftL# (and# h 0xf##) 12#)+ (or# (uncheckedShiftL# (and# c1 0x3f##) 6#)+ (and# c2 0x3f##))++ decode4 :: Word8 -> Word8 -> Word8 -> Word#+ decode4 (W8# c1) (W8# c2) (W8# c3) =+ or# (uncheckedShiftL# (and# h 0x7##) 18#)+ (or# (uncheckedShiftL# (and# c1 0x3f##) 12#)+ (or# (uncheckedShiftL# (and# c2 0x3f##) 6#)+ (and# c3 0x3f##))+ )++-- | Different way to encode a Character in UTF8 represented as an ADT+data UTF8Char =+ UTF8_1 {-# UNPACK #-} !Word8+ | UTF8_2 {-# UNPACK #-} !Word8 {-# UNPACK #-} !Word8+ | UTF8_3 {-# UNPACK #-} !Word8 {-# UNPACK #-} !Word8 {-# UNPACK #-} !Word8+ | UTF8_4 {-# UNPACK #-} !Word8 {-# UNPACK #-} !Word8 {-# UNPACK #-} !Word8 {-# UNPACK #-} !Word8++writeBytes :: Char -> UTF8Char+writeBytes c =+ if bool# (ltWord# x 0x80## ) then encode1+ else if bool# (ltWord# x 0x800## ) then encode2+ else if bool# (ltWord# x 0x10000##) then encode3+ else encode4+ where+ !(I# xi) = fromEnum c+ !x = int2Word# xi+ encode1 = UTF8_1 (W8# x)+ encode2 =+ let !x1 = W8# (or# (uncheckedShiftRL# x 6#) 0xc0##)+ !x2 = toContinuation x+ in UTF8_2 x1 x2+ encode3 =+ let !x1 = W8# (or# (uncheckedShiftRL# x 12#) 0xe0##)+ !x2 = toContinuation (uncheckedShiftRL# x 6#)+ !x3 = toContinuation x+ in UTF8_3 x1 x2 x3+ encode4 =+ let !x1 = W8# (or# (uncheckedShiftRL# x 18#) 0xf0##)+ !x2 = toContinuation (uncheckedShiftRL# x 12#)+ !x3 = toContinuation (uncheckedShiftRL# x 6#)+ !x4 = toContinuation x+ in UTF8_4 x1 x2 x3 x4+ toContinuation :: Word# -> Word8+ toContinuation w = W8# (or# (and# w 0x3f##) 0x80##)+ {-# INLINE toContinuation #-}++write :: PrimMonad prim => MutableString (PrimState prim) -> Offset8 -> Char -> prim Offset8+write (MutableString mba) (Offset i) c =+ if bool# (ltWord# x 0x80## ) then encode1+ else if bool# (ltWord# x 0x800## ) then encode2+ else if bool# (ltWord# x 0x10000##) then encode3+ else encode4+ where+ !(I# xi) = fromEnum c+ !x = int2Word# xi++ encode1 = C.mutUnsafeWrite mba i (W8# x) >> return (Offset $ i + 1)++ encode2 = do+ let x1 = or# (uncheckedShiftRL# x 6#) 0xc0##+ x2 = toContinuation x+ C.mutUnsafeWrite mba i (W8# x1)+ C.mutUnsafeWrite mba (i+1) (W8# x2)+ return $ Offset (i + 2)++ encode3 = do+ let x1 = or# (uncheckedShiftRL# x 12#) 0xe0##+ x2 = toContinuation (uncheckedShiftRL# x 6#)+ x3 = toContinuation x+ C.mutUnsafeWrite mba i (W8# x1)+ C.mutUnsafeWrite mba (i+1) (W8# x2)+ C.mutUnsafeWrite mba (i+2) (W8# x3)+ return $ Offset (i + 3)++ encode4 = do+ let x1 = or# (uncheckedShiftRL# x 18#) 0xf0##+ x2 = toContinuation (uncheckedShiftRL# x 12#)+ x3 = toContinuation (uncheckedShiftRL# x 6#)+ x4 = toContinuation x+ C.mutUnsafeWrite mba i (W8# x1)+ C.mutUnsafeWrite mba (i+1) (W8# x2)+ C.mutUnsafeWrite mba (i+2) (W8# x3)+ C.mutUnsafeWrite mba (i+3) (W8# x4)+ return $ Offset (i + 4)++ toContinuation :: Word# -> Word#+ toContinuation w = or# (and# w 0x3f##) 0x80##++freeze :: PrimMonad prim => MutableString (PrimState prim) -> prim String+freeze (MutableString mba) = String `fmap` C.unsafeFreeze mba+{-# INLINE freeze #-}++------------------------------------------------------------------------+-- real functions++sToList :: String -> [Char]+sToList s = loop azero+ where+ !nbBytes = size s+ end = azero `offsetPlusE` nbBytes+ loop idx+ | idx == end = []+ | otherwise =+ let (# c , idx' #) = next s idx in c : loop idx'+++{-# RULES+"String sFromList" forall s .+ sFromList (unpackCString# s) = String $ fromModified s+ #-}+{-# RULES+"String sFromList" forall s .+ sFromList (unpackCStringUtf8# s) = String $ fromModified s+ #-}++sFromList :: [Char] -> String+sFromList l = runST (new bytes >>= copy)+ where+ -- count how many bytes+ !bytes = C.foldl' (+) (Size 0) $ fmap (charToBytes . fromEnum) l++ copy :: MutableString (PrimState (ST st)) -> ST st String+ copy ms = loop azero l+ where+ loop _ [] = freeze ms+ loop idx (c:xs) = write ms idx c >>= \idx' -> loop idx' xs+ -- write those bytes+ --loop :: MutableByteArray# st -> Int# -> State# st -> [Char] -> (# State# st, String #)+{-# INLINE [0] sFromList #-}++null :: String -> Bool+null (String ba) = C.length ba == 0++-- | Create a string composed of a number @n of Chars (Unicode code points).+--+-- if the input @s contains less characters than required, then+take :: Int -> String -> String+take n s = fst $ splitAt n s -- TODO specialize++-- | Create a string with the remaining Chars after dropping @n Chars from the beginning+drop :: Int -> String -> String+drop n s@(String ba)+ | n <= 0 = s+ | otherwise = loop 0 0+ where+ !sz = C.length ba+ loop idx i+ | idx >= sz = mempty+ | i == n = String $ C.drop idx ba+ | otherwise = loop (skipNext s idx) (i + 1)++splitAt :: Int -> String -> (String, String)+splitAt n s@(String ba)+ | n <= 0 = (mempty, s)+ | otherwise = loop 0 0+ where+ !sz = C.length ba+ loop idx i+ | idx >= sz = (s, mempty)+ | i == n = let (v1,v2) = C.splitAt idx ba in (String v1, String v2)+ | otherwise = loop (skipNext s idx) (i + 1)++-- rev{Take,Drop,SplitAt} TODO optimise:+-- we can process the string from the end using a skipPrev instead of getting the length++revTake :: Int -> String -> String+revTake nbElems v = drop (length v - nbElems) v++revDrop :: Int -> String -> String+revDrop nbElems v = take (length v - nbElems) v++revSplitAt :: Int -> String -> (String, String)+revSplitAt n v = (drop idx v, take idx v)+ where idx = length v - n++-- | Split on the input string using the predicate as separator+--+-- e.g.+--+-- > splitOn (== ',') "," == ["",""]+-- > splitOn (== ',') ",abc," == ["","abc",""]+-- > splitOn (== ':') "abc" == ["abc"]+-- > splitOn (== ':') "abc::def" == ["abc","","def"]+-- > splitOn (== ':') "::abc::def" == ["","","abc","","def"]+--+splitOn :: (Char -> Bool) -> String -> [String]+splitOn predicate s+ | sz == Size 0 = []+ | otherwise = loop azero azero+ where+ !sz = size s+ end = azero `offsetPlusE` sz+ loop prevIdx idx+ | idx == end = [sub s prevIdx idx]+ | otherwise =+ let (# c, idx' #) = next s idx+ in if predicate c+ then sub s prevIdx idx : loop idx' idx'+ else loop prevIdx idx'++sub :: String -> Offset8 -> Offset8 -> String+sub (String ba) (Offset start) (Offset end) = String $ Vec.sub ba start end++-- | Split at a given index.+splitIndex :: Offset8 -> String -> (String, String)+splitIndex (Offset idx) (String ba) = (String v1, String v2)+ where (v1,v2) = C.splitAt idx ba++break :: (Char -> Bool) -> String -> (String, String)+break predicate s@(String ba) = runST $ Vec.unsafeIndexer ba go+ where+ !sz = size s+ end = azero `offsetPlusE` sz++ go :: (Offset Word8 -> Word8) -> ST st (String, String)+ go getIdx = loop (Offset 0)+ where+ !nextI = nextWithIndexer getIdx+ loop idx+ | idx == end = return (s, mempty)+ | otherwise = do+ let (c, idx') = nextI idx+ case predicate c of+ True -> return $ splitIndex idx s+ False -> loop idx'+ {-# INLINE loop #-}+{-# INLINE [2] break #-}++{-# RULES "break (== 'c')" [3] forall c . break (== c) = breakElem c #-}++breakElem :: Char -> String -> (String, String)+breakElem !el s@(String ba) =+ case writeBytes el of+ UTF8_1 w -> let (# v1,v2 #) = Vec.splitElem w ba in (String v1, String v2)+ _ -> runST $ Vec.unsafeIndexer ba go+ where+ sz = size s+ end = azero `offsetPlusE` sz++ go :: (Offset Word8 -> Word8) -> ST st (String, String)+ go getIdx = loop (Offset 0)+ where+ !nextI = nextWithIndexer getIdx+ loop idx+ | idx == end = return (s, mempty)+ | otherwise = do+ let (c, idx') = nextI idx+ case el == c of+ True -> return $ splitIndex idx s+ False -> loop idx'++intersperse :: Char -> String -> String+intersperse sep src+ | srcLen <= 1 = src+ | otherwise = runST $ unsafeCopyFrom src dstBytes (go sep)+ where+ !srcBytes = size src+ !srcLen = length src+ dstBytes = srcBytes + ((srcLen - 1) `scale` charToBytes (fromEnum sep))++ lastSrc :: Offset Char+ lastSrc = Offset 0 `offsetPlusE` Size srcLen++ go :: Char -> String -> Offset Char -> Offset8 -> MutableString s -> Offset8 -> ST s (Offset8, Offset8)+ go sep' src' srcI srcIdx dst dstIdx+ | srcI == lastSrc = do+ nextDstIdx <- write dst dstIdx c+ return (nextSrcIdx, nextDstIdx)+ | otherwise = do+ nextDstIdx <- write dst dstIdx c+ nextDstIdx' <- write dst nextDstIdx sep'+ return (nextSrcIdx, nextDstIdx')+ where+ (# c, nextSrcIdx #) = next src' srcIdx++-- | Allocate a new @String@ with a fill function that has access to the characters of+-- the source @String@.+unsafeCopyFrom :: String -- ^ Source string+ -> Size8 -- ^ Length of the destination string in bytes+ -> (String -> Offset Char -> Offset8 -> MutableString s -> Offset8 -> ST s (Offset8, Offset8))+ -- ^ Function called for each character in the source String+ -> ST s String -- ^ Returns the filled new string+unsafeCopyFrom src dstBytes f = new dstBytes >>= fill (Offset 0) (Offset 0) (Offset 0) f >>= freeze+ where+ srcLen = length src+ end = Offset 0 `offsetPlusE` Size srcLen+ fill srcI srcIdx dstIdx f' dst'+ | srcI == end = return dst'+ | otherwise = do (nextSrcIdx, nextDstIdx) <- f' src srcI srcIdx dst' dstIdx+ fill (srcI + Offset 1) nextSrcIdx nextDstIdx f' dst'++span :: (Char -> Bool) -> String -> (String, String)+span predicate s = break (not . predicate) s++-- | size in bytes+size :: String -> Size8+size (String ba) = Size $ C.length ba++length :: String -> Int+length s@(String ba) = loop 0 0+ where+ !sz = C.length ba+ loop idx !i+ | idx == sz = i+ | otherwise =+ let idx' = skipNext s idx+ in loop idx' (i + 1)++replicate :: Int -> Char -> String+replicate n c = runST (new nbBytes >>= fill)+ where+ end = azero `offsetPlusE` nbBytes+ nbBytes = Size $ sz * n+ (Size sz) = charToBytes (fromEnum c)+ fill :: PrimMonad prim => MutableString (PrimState prim) -> prim String+ fill ms = loop (Offset 0)+ where+ loop idx+ | idx == end = freeze ms+ | otherwise = write ms idx c >>= loop++{-+sizeBytes :: String -> Int+sizeBytes (String ba) = I# (sizeofByteArray# ba)+-}++-- | Allocate a MutableString of a specific size in bytes.+new :: PrimMonad prim+ => Size8 -- ^ in number of bytes, not of elements.+ -> prim (MutableString (PrimState prim))+new n = MutableString `fmap` MVec.new n++create :: PrimMonad prim => Int -> (MutableString (PrimState prim) -> prim Int) -> prim String+create sz f = do+ ms <- new (Size sz)+ filled <- f ms+ if filled == sz+ then freeze ms+ else C.take filled `fmap` freeze ms++charToBytes :: Int -> Size8+charToBytes c+ | c < 0x80 = Size 1+ | c < 0x800 = Size 2+ | c < 0x10000 = Size 3+ | c < 0x110000 = Size 4+ | otherwise = error ("invalid code point: " `mappend` show c)++charMap :: (Char -> Char) -> String -> String+charMap f src =+ let !(elems, nbBytes) = allocateAndFill [] (Offset 0) (Size 0)+ in runST $ do+ dest <- new nbBytes+ copyLoop dest elems (Offset 0 `offsetPlusE` nbBytes)+ freeze dest+ where+ !srcSz = size src+ srcEnd = azero `offsetPlusE` srcSz++ allocateAndFill :: [(String, Size8)]+ -> Offset8+ -> Size8+ -> ([(String,Size8)], Size8)+ allocateAndFill acc idx bytesWritten+ | idx == srcEnd = (acc, bytesWritten)+ | otherwise =+ let (el@(_,addBytes), idx') = runST $ do+ -- make sure we allocate at least 4 bytes for the destination for the last few bytes+ -- otherwise allocating less would bring the danger of spinning endlessly+ -- and never succeeding.+ let !diffBytes = srcEnd - idx+ !allocatedBytes = if diffBytes <= Size 4 then Size 4 else diffBytes+ ms <- new allocatedBytes+ (dstIdx, srcIdx) <- fill ms allocatedBytes idx+ s <- freeze ms+ return ((s, dstIdx), srcIdx)+ in allocateAndFill (el : acc) idx' (bytesWritten + addBytes)++ fill :: PrimMonad prim+ => MutableString (PrimState prim)+ -> Size8+ -> Offset8+ -> prim (Size8, Offset8)+ fill mba dsz srcIdxOrig =+ loop (Offset 0) srcIdxOrig+ where+ endDst = (Offset 0) `offsetPlusE` dsz+ loop dstIdx srcIdx+ | srcIdx == srcEnd = return (offsetAsSize dstIdx, srcIdx)+ | dstIdx == endDst = return (offsetAsSize dstIdx, srcIdx)+ | otherwise =+ let (# c, srcIdx' #) = next src srcIdx+ c' = f c -- the mapped char+ !nbBytes = charToBytes (fromEnum c')+ in -- check if we have room in the destination buffer+ if dstIdx `offsetPlusE` nbBytes <= sizeAsOffset dsz+ then do dstIdx' <- write mba dstIdx c'+ loop dstIdx' srcIdx'+ else return (offsetAsSize dstIdx, srcIdx)++ copyLoop _ [] (Offset 0) = return ()+ copyLoop _ [] n = error ("charMap invalid: " <> show n)+ copyLoop ms@(MutableString mba) ((String ba, sz):xs) end = do+ let start = end `offsetMinusE` sz+ Vec.unsafeCopyAtRO mba start ba (Offset 0) sz+ copyLoop ms xs start++snoc :: String -> Char -> String+snoc s@(String ba) c+ | len == Size 0 = C.singleton c+ | otherwise = runST $ do+ ms@(MutableString mba) <- new (len + nbBytes)+ Vec.unsafeCopyAtRO mba (Offset 0) ba (Offset 0) len+ _ <- write ms (azero `offsetPlusE` len) c+ freeze ms+ where+ !len = size s+ !nbBytes = charToBytes (fromEnum c)++cons :: Char -> String -> String+cons c s@(String ba)+ | len == Size 0 = C.singleton c+ | otherwise = runST $ do+ ms@(MutableString mba) <- new (len + nbBytes)+ idx <- write ms (Offset 0) c+ Vec.unsafeCopyAtRO mba idx ba (Offset 0) len+ freeze ms+ where+ !len = size s+ !nbBytes = charToBytes (fromEnum c)++unsnoc :: String -> Maybe (String, Char)+unsnoc s+ | null s = Nothing+ | otherwise =+ let (s1,s2) = revSplitAt 1 s+ in case toList s1 of -- TODO use index instead of toList+ [c] -> Just (s2, c)+ _ -> internalError "unsnoc"++uncons :: String -> Maybe (Char, String)+uncons s+ | null s = Nothing+ | otherwise =+ let (s1,s2) = splitAt 1 s+ in case toList s1 of -- TODO use index instead of ToList+ [c] -> Just (c, s2)+ _ -> internalError "uncons"++find :: (Char -> Bool) -> String -> Maybe Char+find predicate s = loop (Offset 0)+ where+ !sz = size s+ end = Offset 0 `offsetPlusE` sz+ loop idx+ | idx == end = Nothing+ | otherwise =+ let (# c, idx' #) = next s idx+ in case predicate c of+ True -> Just c+ False -> loop idx'++sortBy :: (Char -> Char -> Ordering) -> String -> String+sortBy sortF s = fromList $ Data.List.sortBy sortF $ toList s -- FIXME for tests++filter :: (Char -> Bool) -> String -> String+filter p s = fromList $ Data.List.filter p $ toList s++reverse :: String -> String+reverse s@(String ba) = runST $ do+ ms <- new len+ loop ms (Offset 0) (Offset 0 `offsetPlusE` len)+ where+ !len = size s+ -- write those bytes+ loop :: PrimMonad prim => MutableString (PrimState prim) -> Offset8 -> Offset8 -> prim String+ loop ms@(MutableString mba) sidx@(Offset si) didx+ | didx == Offset 0 = freeze ms+ | otherwise = do+ let !h = Vec.unsafeIndex ba si+ !nb = Size (getNbBytes h + 1)+ didx'@(Offset d) = didx `offsetMinusE` nb+ case nb of+ Size 1 -> C.mutUnsafeWrite mba d h+ Size 2 -> do+ C.mutUnsafeWrite mba d h+ C.mutUnsafeWrite mba (d + 1) (Vec.unsafeIndex ba (si + 1))+ Size 3 -> do+ C.mutUnsafeWrite mba d h+ C.mutUnsafeWrite mba (d + 1) (Vec.unsafeIndex ba (si + 1))+ C.mutUnsafeWrite mba (d + 2) (Vec.unsafeIndex ba (si + 2))+ Size 4 -> do+ C.mutUnsafeWrite mba d h+ C.mutUnsafeWrite mba (d + 1) (Vec.unsafeIndex ba (si + 1))+ C.mutUnsafeWrite mba (d + 2) (Vec.unsafeIndex ba (si + 2))+ C.mutUnsafeWrite mba (d + 3) (Vec.unsafeIndex ba (si + 3))+ _ -> return () -- impossible+ loop ms (sidx `offsetPlusE` nb) didx'++{-+-- | Convert a Byte Array to a string and check UTF8 validity+fromBytes :: Encoding -> UArray Word8 -> Maybe String+fromBytes UTF8 bytes =+ case validate bytes 0 (C.length bytes) of+ (_, Nothing) -> Just $ fromBytesUnsafe bytes+ (_, Just _) -> Nothing+ -}++data Encoding+ = ASCII7+ | UTF8+ | UTF16+ | UTF32+ | ISO_8859_1+ deriving (Typeable, Data, Eq, Ord, Show, Enum, Bounded)++fromEncoderBytes :: ( Encoder.Encoding encoding+ , Exception (Encoder.Error encoding)+ , PrimType (Encoder.Unit encoding)+ )+ => encoding+ -> UArray Word8+ -> (String, Maybe ValidationFailure, UArray Word8)+fromEncoderBytes enc bytes =+ ( String $ runST $ Encoder.convertFromTo enc EncoderUTF8 (Vec.recast bytes)+ , Nothing+ , mempty+ )+++fromBytes :: Encoding -> UArray Word8 -> (String, Maybe ValidationFailure, UArray Word8)+fromBytes ASCII7 bytes = fromEncoderBytes Encoder.ASCII7 bytes+fromBytes ISO_8859_1 bytes = fromEncoderBytes Encoder.ISO_8859_1 bytes+fromBytes UTF16 bytes = fromEncoderBytes Encoder.UTF16 bytes+fromBytes UTF32 bytes = fromEncoderBytes Encoder.UTF32 bytes+fromBytes UTF8 bytes+ | C.null bytes = (mempty, Nothing, mempty)+ | otherwise =+ case validate bytes (Offset 0) (Size $ C.length bytes) of+ (_, Nothing) -> (fromBytesUnsafe bytes, Nothing, mempty)+ (Offset pos, Just vf) ->+ let (b1, b2) = C.splitAt pos bytes+ in (fromBytesUnsafe b1, toErr vf, b2)+ where+ toErr MissingByte = Nothing+ toErr InvalidHeader = Just InvalidHeader+ toErr InvalidContinuation = Just InvalidContinuation++fromBytesLenient :: UArray Word8 -> (String, UArray Word8)+fromBytesLenient bytes+ | C.null bytes = (mempty, mempty)+ | otherwise =+ case validate bytes (Offset 0) (Size $ C.length bytes) of+ (_, Nothing) -> (fromBytesUnsafe bytes, mempty)+ (Offset pos, Just MissingByte) ->+ let (b1,b2) = C.splitAt pos bytes+ in (fromBytesUnsafe b1, b2)+ (Offset pos, Just InvalidHeader) ->+ let (b1,b2) = C.splitAt pos bytes+ (_,b3) = C.splitAt 1 b2+ (s3, r) = fromBytesLenient b3+ in (mconcat [fromBytesUnsafe b1,replacement, s3], r)+ (Offset pos, Just InvalidContinuation) ->+ let (b1,b2) = C.splitAt pos bytes+ (_,b3) = C.splitAt 1 b2+ (s3, r) = fromBytesLenient b3+ in (mconcat [fromBytesUnsafe b1,replacement, s3], r)+ where+ -- This is the replacement character U+FFFD used for any invalid header or continuation+ replacement :: String+ !replacement = fromBytesUnsafe $ fromList [0xef,0xbf,0xbd]++fromChunkBytes :: [UArray Word8] -> [String]+fromChunkBytes l = loop l+ where+ loop [] = []+ loop (bytes:[]) =+ case validate bytes (Offset 0) (Size $ C.length bytes) of+ (_, Nothing) -> [fromBytesUnsafe bytes]+ (_, Just err) -> doErr err+ loop (bytes:cs@(c1:c2)) =+ case validate bytes (Offset 0) (Size $ C.length bytes) of+ (_, Nothing) -> fromBytesUnsafe bytes : loop cs+ (Offset pos, Just MissingByte) ->+ let (b1,b2) = C.splitAt pos bytes+ in fromBytesUnsafe b1 : loop ((b2 `mappend` c1) : c2)+ (_, Just err) -> doErr err+ doErr err = error ("fromChunkBytes: " <> show err)++-- | Convert a Byte Array directly to a string without checking for UTF8 validity+fromBytesUnsafe :: UArray Word8 -> String+fromBytesUnsafe = String++toEncoderBytes :: ( Encoder.Encoding encoding+ , PrimType (Encoder.Unit encoding)+ , Exception (Encoder.Error encoding)+ )+ => encoding+ -> UArray Word8+ -> UArray Word8+toEncoderBytes enc bytes = Vec.recast (runST $ Encoder.convertFromTo EncoderUTF8 enc bytes)++-- | Convert a String to a bytearray+toBytes :: Encoding -> String -> UArray Word8+toBytes UTF8 (String bytes) = bytes+toBytes ASCII7 (String bytes) = toEncoderBytes Encoder.ASCII7 bytes+toBytes ISO_8859_1 (String bytes) = toEncoderBytes Encoder.ISO_8859_1 bytes+toBytes UTF16 (String bytes) = toEncoderBytes Encoder.UTF16 bytes+toBytes UTF32 (String bytes) = toEncoderBytes Encoder.UTF32 bytes++lines :: String -> [String]+lines = fmap fromList . Prelude.lines . toList++words :: String -> [String]+words = fmap fromList . Prelude.words . toList
+ Foundation/String/UTF8Table.hs view
@@ -0,0 +1,83 @@+-- |+-- Module : Foundation.String.UTF8Table+-- License : BSD-style+-- Maintainer : Vincent Hanquez <vincent@snarc.org>+-- Stability : experimental+-- Portability : portable+--+-- UTF8 lookup tables for fast continuation & nb bytes per header queries+{-# LANGUAGE MagicHash #-}+{-# LANGUAGE UnboxedTuples #-}+module Foundation.String.UTF8Table+ ( isContinuation+ , getNbBytes+ , isContinuation#+ , getNbBytes#+ ) where++import GHC.Prim+import GHC.Types+import GHC.Word+import Foundation.Internal.Base++-- | Check if the byte is a continuation byte+isContinuation :: Word8 -> Bool+isContinuation (W8# w) = isContinuation# w+{-# INLINE isContinuation #-}++-- | Get the number of following bytes given the first byte of a UTF8 sequence.+getNbBytes :: Word8 -> Int+getNbBytes (W8# w) = I# (getNbBytes# w)+{-# INLINE getNbBytes #-}++-- | Check if the byte is a continuation byte+isContinuation# :: Word# -> Bool+isContinuation# w = W# (indexWord8OffAddr# (unTable contTable) (word2Int# w)) /= W# 0##+{-# INLINE isContinuation# #-}++-- | Get the number of following bytes given the first byte of a UTF8 sequence.+getNbBytes# :: Word# -> Int#+getNbBytes# w = word2Int# (indexWord8OffAddr# (unTable headTable) (word2Int# w))+{-# INLINE getNbBytes# #-}++data Table = Table { unTable :: !Addr# }++contTable :: Table+contTable = Table+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\+ \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\+ \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\+ \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\+ \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\+ \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\+ \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\+ \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\+ \\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\+ \\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\+ \\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\+ \\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\+ \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\+ \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\+ \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\+ \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"#+{-# NOINLINE contTable #-}++headTable :: Table+headTable = Table+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\+ \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\+ \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\+ \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\+ \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\+ \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\+ \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\+ \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\+ \\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\+ \\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\+ \\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\+ \\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\+ \\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\+ \\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\+ \\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\+ \\x03\x03\x03\x03\x03\x03\x03\x03\xff\xff\xff\xff\xff\xff\xff\xff"#+{-# NOINLINE headTable #-}
+ Foundation/System/Info.hs view
@@ -0,0 +1,138 @@+-- |+-- Module : Foundation.System.Info+-- License : BSD-style+-- Maintainer : foundation+-- Stability : experimental+-- Portability : portable+--++{-# LANGUAGE CPP #-}++module Foundation.System.Info+ (+ -- * Operation System info+ OS(..)+ , os+ -- * CPU info+ , arch+ , cpus+ , Endianness(..)+ , endianness+ -- * Compiler info+ , compilerName+ , System.Info.compilerVersion+ , Data.Version.Version(..)+ ) where++import qualified System.Info+import qualified Data.Version+import Data.Data+import qualified GHC.Conc+import Foundation.String+import Foundation.Internal.Base++#ifdef ARCH_IS_UNKNOWN_ENDIAN+import Foreign.Marshal.Alloc (alloca)+import Foreign.Ptr (castPtr)+import Foreign.Storable (poke, peek)+import Data.Word (Word8, Word32)+import System.IO.Unsafe (unsafePerformIO)+#endif++data OS+ = Windows+ | OSX+ | Linux+ | Android+ | BSD+ deriving (Show, Eq, Ord, Enum, Bounded, Data, Typeable)++-- | get the operating system on which the program is running.+--+-- Either return the known `OS` or a strict `String` of the OS name.+--+-- This function uses the `base`'s `System.Info.os` function.+--+os :: Either String OS+os = case System.Info.os of+ "darwin" -> Right OSX+ "mingw32" -> Right Windows+ "linux" -> Right Linux+ "linux-android" -> Right Android+ "openbsd" -> Right BSD+ "netbsd" -> Right BSD+ "freebsd" -> Right BSD+ str -> Left $ fromList str++-- | Enumeration of the known GHC supported architecture.+--+data Arch+ = I386+ | X86_64+ | PowerPC+ | PowerPC64+ | Sparc+ | Sparc64+ | ARM+ | ARM64+ deriving (Show, Eq, Ord, Enum, Bounded, Data, Typeable)++-- | get the machine architecture on which the program is running+--+-- Either return the known architecture or a Strict `String` of the+-- architecture name.+--+-- This function uses the `base`'s `System.Info.arch` function.+--+arch :: Either String Arch+arch = case System.Info.arch of+ "i386" -> Right I386+ "x86_64" -> Right X86_64+ "powerpc" -> Right PowerPC+ "powerpc64" -> Right PowerPC64+ "powerpc64le" -> Right PowerPC64+ "sparc" -> Right Sparc+ "sparc64" -> Right Sparc64+ "arm" -> Right ARM+ "aarch64" -> Right ARM64+ str -> Left $ fromList str++-- | get the compiler name+--+-- get the compilerName from base package but convert+-- it into a strict String+compilerName :: String+compilerName = fromList System.Info.compilerName++-- | returns the number of CPUs the machine has+cpus :: IO Int+cpus = GHC.Conc.getNumProcessors++data Endianness+ = LittleEndian+ | BigEndian+ deriving (Eq, Show)++-- | endianness of the current architecture+endianness :: Endianness+#ifdef ARCH_IS_LITTLE_ENDIAN+endianness = LittleEndian+#elif ARCH_IS_BIG_ENDIAN+endianness = BigEndian+#else+-- ! ARCH_IS_UNKNOWN_ENDIAN+endianness = unsafePerformIO $ bytesToEndianness <$> word32ToByte input+ where+ input :: Word32+ input = 0x01020304+{-# NOINLINE endianness #-}++word32ToByte :: Word32 -> IO Word8+word32ToByte word = alloca $ \wordPtr -> do+ poke wordPtr word+ peek (castPtr wordPtr)++bytesToEndianness :: Word8 -> Endianness+bytesToEndianness 1 = BigEndian+bytesToEndianness _ = LittleEndian+#endif
+ Foundation/Tuple.hs view
@@ -0,0 +1,98 @@+-- |+-- Module : Foundation.Tuple+-- License : BSD-style+-- Maintainer : Vincent Hanquez <vincent@snarc.org>+-- Stability : experimental+-- Portability : portable+--+{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE DeriveGeneric #-}+module Foundation.Tuple+ ( Tuple2(..)+ , Tuple3(..)+ , Tuple4(..)+ , Fstable(..)+ , Sndable(..)+ , Thdable(..)+ ) where++import Foundation.Internal.Base+import Data.Data++-- | Strict tuple (a,b)+data Tuple2 a b = Tuple2 !a !b+ deriving (Show,Eq,Ord,Typeable,Data,Generic)++-- | Strict tuple (a,b,c)+data Tuple3 a b c = Tuple3 !a !b !c+ deriving (Show,Eq,Ord,Typeable,Data,Generic)++-- | Strict tuple (a,b,c,d)+data Tuple4 a b c d = Tuple4 !a !b !c !d+ deriving (Show,Eq,Ord,Typeable,Data,Generic)++-- | Class of product types that have a first element+class Fstable a where+ type FstTy a+ fst :: a -> FstTy a++-- | Class of product types that have a second element+class Sndable a where+ type SndTy a+ snd :: a -> SndTy a++-- | Class of product types that have a third element+class Thdable a where+ type ThdTy a+ thd :: a -> ThdTy a++instance Fstable (a,b) where+ type FstTy (a,b) = a+ fst (a,_) = a+instance Fstable (a,b,c) where+ type FstTy (a,b,c) = a+ fst (a,_,_) = a+instance Fstable (a,b,c,d) where+ type FstTy (a,b,c,d) = a+ fst (a,_,_,_) = a+instance Fstable (Tuple2 a b) where+ type FstTy (Tuple2 a b) = a+ fst (Tuple2 a _) = a+instance Fstable (Tuple3 a b c) where+ type FstTy (Tuple3 a b c) = a+ fst (Tuple3 a _ _) = a+instance Fstable (Tuple4 a b c d) where+ type FstTy (Tuple4 a b c d) = a+ fst (Tuple4 a _ _ _) = a++instance Sndable (a,b) where+ type SndTy (a,b) = b+ snd (_,b) = b+instance Sndable (a,b,c) where+ type SndTy (a,b,c) = b+ snd (_,b,_) = b+instance Sndable (a,b,c,d) where+ type SndTy (a,b,c,d) = b+ snd (_,b,_,_) = b+instance Sndable (Tuple2 a b) where+ type SndTy (Tuple2 a b) = b+ snd (Tuple2 _ b) = b+instance Sndable (Tuple3 a b c) where+ type SndTy (Tuple3 a b c) = b+ snd (Tuple3 _ b _) = b+instance Sndable (Tuple4 a b c d) where+ type SndTy (Tuple4 a b c d) = b+ snd (Tuple4 _ b _ _) = b++instance Thdable (a,b,c) where+ type ThdTy (a,b,c) = c+ thd (_,_,c) = c+instance Thdable (a,b,c,d) where+ type ThdTy (a,b,c,d) = c+ thd (_,_,c,_) = c+instance Thdable (Tuple3 a b c) where+ type ThdTy (Tuple3 a b c) = c+ thd (Tuple3 _ _ c) = c+instance Thdable (Tuple4 a b c d) where+ type ThdTy (Tuple4 a b c d) = c+ thd (Tuple4 _ _ c _) = c
+ Foundation/VFS.hs view
@@ -0,0 +1,32 @@+-- |+-- Module : Foundation.VFS+-- License : BSD-style+-- Maintainer : foundation+-- Stability : experimental+-- Portability : portable+--+module Foundation.VFS+ ( Path(..)+ , filename+ , parent+ , prefix+ , suffix++ -- * FilePath+ , FilePath+ , FileName+ -- ** conversion+ , filePathToString+ , filePathToLString+ ) where+++import Foundation.VFS.Path+ ( Path(..)+ , filename, parent, suffix, prefix+ )+import Foundation.VFS.FilePath+ ( FilePath, FileName+ , filePathToString+ , filePathToLString+ )
+ Foundation/VFS/FilePath.hs view
@@ -0,0 +1,256 @@+-- |+-- Module : Foundation.VFS.FilePath+-- License : BSD-style+-- Maintainer : foundation+-- Stability : experimental+-- Portability : portable+--+-- # Opaque implementation for FilePath+--+-- The underlying type of a FilePath is a `Foundation.ByteArray`. It is indeed like+-- this because for some systems (Unix systems) a `FilePath` is a null+-- terminated array of bytes.+--+-- # FilePath and FileName for type checking validation+--+-- In order to add some constraint at compile time, it is not possible to+-- append (`</>`) a `FilePath` to another `FilePath`.+-- You can only append (`</>`) a `FileName` to a given `FilePath`.+--++{-# LANGUAGE CPP #-}++module Foundation.VFS.FilePath+ ( FilePath+ , Relativity(..)+ , FileName+ -- * conversion+ , filePathToString+ , filePathToLString++ -- ** unsafe+ , unsafeFilePath+ , unsafeFileName+ , extension+ ) where++import Foundation.Internal.Base+import Foundation.Collection+import Foundation.Array+import Foundation.String (Encoding(..), ValidationFailure, toBytes, fromBytes, String)+import Foundation.VFS.Path(Path(..))++import qualified Data.List+import Foundation.Partial+-- ------------------------------------------------------------------------- --+-- System related helpers --+-- ------------------------------------------------------------------------- --++#ifdef mingw32_HOST_OS+pathSeparatorWINC :: Char+pathSeparatorWINC = '\\'++-- | define the Path separator for Windows systems : '\\'+pathSeparatorWIN :: String+pathSeparatorWIN = fromString [pathSeparatorWINC]+#else+pathSeparatorPOSIXC :: Char+pathSeparatorPOSIXC = '/'++-- | define the Path separator for POSIX systems : '/'+pathSeparatorPOSIX :: String+pathSeparatorPOSIX = fromString [pathSeparatorPOSIXC]+#endif++pathSeparatorC :: Char+pathSeparator :: String+#ifdef mingw32_HOST_OS+pathSeparatorC = pathSeparatorWINC+pathSeparator = pathSeparatorWIN+#else+pathSeparatorC = pathSeparatorPOSIXC+pathSeparator = pathSeparatorPOSIX+#endif++-- ------------------------------------------------------------------------- --+-- FilePath --+-- ------------------------------------------------------------------------- --++-- | information about type of FilePath+--+-- A file path being only `Relative` or `Absolute`.+data Relativity = Absolute | Relative+ deriving (Eq, Show)++-- | FilePath is a collection of FileName+--+-- TODO: Eq and Ord are implemented using Show+-- This is not very efficient and would need to be improved+-- Also, it is possible the ordering is not necessary what we want+-- in this case.+--+-- A FilePath is one of the following:+--+-- * An Absolute:+-- * starts with one of the follwing "/"+-- * A relative:+-- * don't start with a "/"+--+-- * authorised:+-- * "/"+-- * "/file/path"+-- * "."+-- * ".."+-- * "work/haskell/hs-foundation"+--+-- * unauthorised+-- * "path//"+data FilePath = FilePath Relativity [FileName]++instance Show FilePath where+ show = filePathToLString+instance Eq FilePath where+ (==) a b = (==) (show a) (show b)+instance Ord FilePath where+ compare a b = compare (show a) (show b)++-- | error associated to filepath manipulation+data FilePath_Invalid+ = ContiguousPathSeparator+ -- ^ this mean there were 2 contiguous path separators.+ --+ -- This is not valid in Foundation's FilePath specifications+ deriving (Typeable, Show)+instance Exception FilePath_Invalid++instance IsString FilePath where+ fromString [] = FilePath Absolute mempty+ fromString s@(x:xs)+ | hasContigueSeparators s = throw ContiguousPathSeparator+ | otherwise = FilePath relativity $ case relativity of+ Absolute -> fromString <$> splitOn isSeparator xs+ Relative -> fromString <$> splitOn isSeparator s+ where+ relativity :: Relativity+ relativity = if isSeparator x then Absolute else Relative++-- | A filename (or path entity) in the FilePath+--+-- * Authorised+-- * ""+-- * "."+-- * ".."+-- * "foundation"+-- * Unauthorised+-- * "/"+-- * "file/"+-- * "/file"+-- * "file/path"+--+data FileName = FileName (UArray Word8)+ deriving (Eq)+-- | errors related to FileName manipulation+data FileName_Invalid+ = ContainsNullByte+ -- ^ this means a null byte was found in the FileName+ | ContainsSeparator+ -- ^ this means a path separator was found in the FileName+ | EncodingError ValidationFailure+ -- ^ encoding error+ | UnknownTrailingBytes (UArray Word8)+ -- ^ some unknown trainling bytes found+ deriving (Typeable, Show)+instance Exception FileName_Invalid++instance Show FileName where+ show = fileNameToLString+instance IsString FileName where+ fromString [] = FileName mempty+ fromString xs | hasNullByte xs = throw ContainsNullByte+ | hasSeparator xs = throw ContainsSeparator+ | otherwise = FileName $ toBytes UTF8 $ fromString xs++hasNullByte :: [Char] -> Bool+hasNullByte = Data.List.elem '\0'++hasSeparator :: [Char] -> Bool+hasSeparator = Data.List.elem pathSeparatorC++isSeparator :: Char -> Bool+isSeparator = (==) pathSeparatorC++hasContigueSeparators :: [Char] -> Bool+hasContigueSeparators [] = False+hasContigueSeparators [_] = False+hasContigueSeparators (x1:x2:xs) =+ (isSeparator x1 && x1 == x2) || hasContigueSeparators xs++instance Monoid FileName where+ mempty = FileName mempty+ mappend (FileName a) (FileName b) = FileName $ a `mappend` b++instance Path FilePath where+ type PathEnt FilePath = FileName+ type PathPrefix FilePath = Relativity+ type PathSuffix FilePath = ()+ (</>) = join+ splitPath (FilePath r xs) = (r, xs, ())+ buildPath (r, xs , _) = FilePath r xs++-- compare to the original </>, this type disallow to be able to append an absolute filepath to a filepath+join :: FilePath -> FileName -> FilePath+join p (FileName x) | null x = p+join (FilePath r xs) x = FilePath r $ snoc xs x++filePathToString :: FilePath -> String+filePathToString (FilePath Absolute []) = fromString [pathSeparatorC]+filePathToString (FilePath Relative []) = fromString "."+filePathToString (FilePath Absolute fns) = cons pathSeparatorC $ filenameIntercalate fns+filePathToString (FilePath Relative fns) = filenameIntercalate fns++filenameIntercalate :: [FileName] -> String+filenameIntercalate = mconcat . Data.List.intersperse pathSeparator . fmap fileNameToString++-- | convert a FileName into a String+--+-- This function may throw an exception associated to the encoding+fileNameToString :: FileName -> String+fileNameToString (FileName fp) =+ -- FIXME probably incorrect considering windows.+ -- this is just to get going to be able to be able to reuse System.IO functions which+ -- works on [Char]+ case fromBytes UTF8 fp of+ (s, Nothing, bs)+ | null bs -> s+ | otherwise -> throw $ UnknownTrailingBytes bs+ (_, Just err, _) -> throw $ EncodingError err++-- | conversion of FileName into a list of Char+--+-- this function may throw exceptions+fileNameToLString :: FileName -> [Char]+fileNameToLString = toList . fileNameToString++-- | conversion of a FilePath into a list of Char+--+-- this function may throw exceptions+filePathToLString :: FilePath -> [Char]+filePathToLString = toList . filePathToString++-- | build a file path from a given list of filename+--+-- this is unsafe and is mainly needed for testing purpose+unsafeFilePath :: Relativity -> [FileName] -> FilePath+unsafeFilePath = FilePath++-- | build a file name from a given ByteArray+--+-- this is unsafe and is mainly needed for testing purpose+unsafeFileName :: UArray Word8 -> FileName+unsafeFileName = FileName++extension :: FileName -> Maybe FileName+extension (FileName fn) = case splitOn (\c -> c == 0x2E) fn of+ [] -> Nothing+ [_] -> Nothing+ xs -> Just $ FileName $ fromPartial $ head $ reverse xs
+ Foundation/VFS/Path.hs view
@@ -0,0 +1,141 @@+-- |+-- Module : Foundation.VFS.Path+-- License : BSD-style+-- Maintainer : foundation+-- Stability : experimental+-- Portability : portable+--++{-# LANGUAGE FlexibleContexts #-}++module Foundation.VFS.Path+ (+ -- * Path class+ Path(..)++ , parent+ , filename+ , prefix+ , suffix+ ) where++import Foundation.Internal.Base++-- | Path type class+--+-- defines the Path associated types and basic functions to implement related+-- to the path manipulation+--+-- # TODO, add missing enhancement:+--+-- ```+-- splitExtension :: PathEnt path -> (PathEnt path, PathEnt path)+-- addExtension :: PathEnt path -> PathEnt path -> PathEnt path+-- (<.>) :: path -> PathEnt path -> path+-- (-<.>) :: path -> PathEnt path -> path+-- ```+--+class Path path where+ -- | the associated PathEntity of the given `path`+ -- this type is the minimal element contained in the Path+ -- a Path is not a collection but it is possible to see this+ -- associated type equivalent to the `Foundation.Collection.Element` type family+ type PathEnt path++ -- | the associated prefix of the given `path`+ --+ -- in the case of a `FilePath`, it is a void (i.e. `()`)+ -- in the case of an `URI`, it is the schema, host, port...+ type PathPrefix path++ -- | the associated suffix of the given path+ --+ -- in the case of the `FilePath`, it is a void (i.e. `()`)+ -- in the case of the `URI`, it is a the query, the fragment+ type PathSuffix path++ -- | join a path entity to a given path+ (</>) :: path -> PathEnt path -> path++ -- | split the path into the associated elements+ splitPath :: path -> ( PathPrefix path+ , [PathEnt path]+ , PathSuffix path+ )+ -- | build the path from the associated elements+ buildPath :: ( PathPrefix path+ , [PathEnt path]+ , PathSuffix path+ )+ -> path+++-- | parent is only going to drop the filename.+--+-- if you actually want to reference to the parent directory, simply uses:+--+-- ```+-- parent "." /= "." </> ".."+-- ```+parent :: Path path => path -> path+parent path = buildPath (p, init ps, s)+ where+ (p, ps , s) = splitPath path+++-- | get the filename of the given path+--+-- If there is no filename, you will receive the mempty of the PathEnt+filename :: (Path path, Monoid (PathEnt path)) => path -> PathEnt path+filename path = case ps of+ [] -> mempty+ _ -> last ps+ where+ (_, ps , _) = splitPath path++-- TODO: this might be better in Sequential ?+init :: [a] -> [a]+init [] = []+init [_] = []+init (x:xs) = x : init xs++-- TODO: this might be better in Sequential ?+last :: [a] -> a+last [] = undefined+last [x] = x+last (_:xs) = last xs+++-- | get the path prefix information+--+-- ```+-- prefix "/home/tab" == ()+-- ```+--+-- or for URI (TODO, not yet accurate)+--+-- ```+-- prefix "http://github.com/vincenthz/hs-foundation?w=1"+-- == URISchema http Nothing Nothing "github.com" Nothing+-- ```+prefix :: Path path => path -> PathPrefix path+prefix p = pre+ where+ (pre, _, _) = splitPath p++-- | get the path suffix information+--+-- ```+-- suffix "/home/tab" == ()+-- ```+--+-- or for URI (TODO, not yet accurate)+--+-- ```+-- suffix "http://github.com/vincenthz/hs-foundation?w=1"+-- == URISuffix (["w", "1"], Nothing)+-- ```+suffix :: Path path => path -> PathSuffix path+suffix p = suf+ where+ (_, _, suf) = splitPath p
+ Foundation/VFS/URI.hs view
@@ -0,0 +1,38 @@+-- |+-- Module : Foundation.VFS.URI+-- License : BSD-style+-- Maintainer : foundation+-- Stability : experimental+-- Portability : portable+--++module Foundation.VFS.URI+ ( URI(..)+ , URISchema(..)+ , URIAuthority(..)+ , URIQuery(..)+ , URIFragment(..)+ , URIPath(..)+ ) where++import Foundation.Internal.Base+import Foundation.VFS.Path(Path(..))++-- ------------------------------------------------------------------------- --+-- URI --+-- ------------------------------------------------------------------------- --++-- | TODO this is not implemented yet+data URI = URI+data URISchema = URISchema+data URIAuthority = URIAuthority+data URIQuery = URIQuery+data URIFragment = URIFragment+data URIPath = URIPath+instance Path URI where+ type PathEnt URI = URIPath+ type PathPrefix URI = (URISchema, URIAuthority)+ type PathSuffix URI = (URIQuery, URIFragment)+ (</>) = undefined+ splitPath = undefined+ buildPath = undefined
+ LICENSE view
@@ -0,0 +1,27 @@+Copyright (c) 2015-2016 Vincent Hanquez <vincent@snarc.org>++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions+are met:+1. Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.+2. 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.+3. Neither the name of the author nor the names of his contributors+ may be used to endorse or promote products derived from this software+ without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 AUTHORS 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.
+ README.md view
@@ -0,0 +1,65 @@+Foundation+==========++[](https://travis-ci.org/haskell-foundation/foundation)+[](http://en.wikipedia.org/wiki/BSD_licenses)+[](http://haskell.org)++Documentation: [foundation on hackage](http://hackage.haskell.org/package/foundation)++Goals+=====++* provide a base like set of modules that provide a consistent set of features and bugfixes across multiple versions of GHC (unlike base).+* provide a better and more efficient prelude than base's prelude.+* be self-sufficient: no external dependencies apart from base (or ghc packages).+* provide better data-types: packed unicode string by default, arrays.+* Better numerical classes that better represent mathematical things (No more all-in-one Num).++How to use+==========++Disable the built-in prelude at the top of your file:++```haskell+{-# LANGUAGE NoImplicitPrelude #-}+```++Or directly in your project cabal file:++```haskell+Default-Extensions: NoImplicitPrelude+```++Then in your modules:++```haskell+import Foundation+```++How to contribute+=================++Any contributions is welcome, but a short list includes:++* Improve the code base+* Report an issue+* Fix an issue+* Improve the documentation+* Make tutorial on how to use foundation+* Make your project use foundation instead of base, report the missing coverage (IO, types, etc.), or what functionality is missing to make a succesful transition+++Design+======++Foundation started on the simple idea of trying to put everything I need in one+simple and consistent package. The amazing haskell ecosystem is extremely+fragmented and maintained by different people with different goals, free time,+and style. The overall scare of not trying to change anything relatively+central (base, bytestring, text, vector ..) for a promise of stability has pushed+many people to work on their own thing, leading to unnecessary work duplication+and further fragmentation.+++Foundation uses and abuses type families.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ benchs/Array.hs view
@@ -0,0 +1,16 @@+module Main where++import Foundation+import Foundation.Collection+import Criterion.Main++main = defaultMain+ [ bgroup "Uarray"+ [ bench "fromList [Word8]" $ whnf (fromList :: [Word8] -> UArray Word8) [1..255]+ , bench "fromList [Word16]" $ whnf (fromList :: [Word16] -> UArray Word16) [1..1024]+ , bench "break" $ whnf (break (== 255)) input+ ]+ ]+ where+ input :: UArray Word8+ input = fromList ([1..255] <> [1..255])
+ benchs/ProfBreak.hs view
@@ -0,0 +1,9 @@+module Main where++import Foundation+import Foundation.Collection++main = do+ let v = fromList [1..255] :: UArray Word8+ let (v1,v2) = break ((==) 128) v+ putStrLn $ (fromList $ show v1) <> (fromList $ show v2)
+ foundation.cabal view
@@ -0,0 +1,156 @@+Name: foundation+Version: 0.0.1+Synopsis: Alternative prelude with batteries and no dependencies+Description:+ A custom prelude with no dependencies apart from base.+ .+ This package has the following goals:+ .+ * provide a base like sets of modules that provide a consistent set of features and bugfixes across multiple versions of GHC (unlike base).+ .+ * provide a better and more efficient prelude than base's prelude.+ .+ * be self-sufficient: no external dependencies apart from base.+ .+ * provide better data-types: packed unicode string by default, arrays.+ .+ * Better numerical classes that better represent mathematical thing (No more all-in-one Num).+ .+ * Better I/O system with less Lazy IO+ .+ * Usual partial functions distinguished through type system+License: BSD3+License-file: LICENSE+Copyright: Vincent Hanquez <vincent@snarc.org>+Author: Vincent Hanquez <vincent@snarc.org>+Maintainer: vincent@snarc.org+Category: foundation+Stability: experimental+Build-Type: Simple+Homepage: https://github.com/haskell-foundation/foundation+Bug-Reports: https://github.com/haskell-foundation/foundation/issues+Cabal-Version: >=1.10+tested-with: GHC == 7.4.2, GHC == 7.6.3, GHC == 7.8.4, GHC == 7.10.3, GHC == 8.0.1+extra-source-files: README.md++source-repository head+ type: git+ location: https://github.com/haskell-foundation/foundation++Library+ Exposed-modules: Foundation+ Foundation.Number+ Foundation.Array+ Foundation.Array.Internal+ Foundation.Convertible+ Foundation.String+ Foundation.IO+ Foundation.IO.FileMap+ Foundation.VFS+ Foundation.VFS.Path+ Foundation.VFS.FilePath+ Foundation.VFS.URI+ Foundation.Foreign+ Foundation.Collection+ Foundation.Primitive+ Foundation.System.Info+ Foundation.Strict+ Other-modules: Foundation.String.Internal+ Foundation.String.UTF8+ Foundation.String.Encoding.Encoding+ Foundation.String.Encoding.UTF16+ Foundation.String.Encoding.UTF32+ Foundation.String.Encoding.ASCII7+ Foundation.String.Encoding.ISO_8859_1+ Foundation.String.UTF8Table+ Foundation.String.ModifiedUTF8+ Foundation.Tuple+ Foundation.Collection.List+ Foundation.Collection.Element+ Foundation.Collection.InnerFunctor+ Foundation.Collection.Sequential+ Foundation.Collection.Keyed+ Foundation.Collection.Indexed+ Foundation.Collection.Foldable+ Foundation.Collection.Mutable+ Foundation.Collection.Zippable+ Foundation.Internal.Base+ Foundation.Internal.Primitive+ Foundation.Internal.IsList+ Foundation.Internal.Identity+ Foundation.Internal.Proxy+ Foundation.Internal.Types+ Foundation.Internal.PrimTypes+ Foundation.Internal.MonadTrans+ Foundation.IO.File+ Foundation.IO.Terminal+ Foundation.Primitive.Types+ Foundation.Primitive.Monad+ Foundation.Primitive.Utils+ Foundation.Primitive.FinalPtr+ Foundation.Array.Common+ Foundation.Array.Unboxed+ Foundation.Array.Unboxed.Builder+ Foundation.Array.Unboxed.Mutable+ Foundation.Array.Unboxed.ByteArray+ Foundation.Array.Boxed+ Foundation.Array.Bitmap+ Foundation.Foreign.MemoryMap+ Foundation.Foreign.MemoryMap.Types+ Foundation.Partial+ if os(windows)+ Other-modules: Foundation.Foreign.MemoryMap.Windows+ else+ Other-modules: Foundation.Foreign.MemoryMap.Posix+ Default-Extensions: NoImplicitPrelude+ TypeFamilies+ BangPatterns+ DeriveDataTypeable+ Build-depends: base >= 4 && < 5+ , ghc-prim+ -- FIXME add suport for armel mipsel+ -- CPP-options: -DARCH_IS_LITTLE_ENDIAN+ -- FIXME add support for powerpc powerpc64 armeb mipseb+ -- CPP-options: -DARCH_IS_BIG_ENDIAN+ if (arch(i386) || arch(x86_64))+ CPP-options: -DARCH_IS_LITTLE_ENDIAN+ else+ CPP-options: -DARCH_IS_UNKNOWN_ENDIAN+ if os(windows)+ Build-depends: Win32+ ghc-options: -Wall -fwarn-tabs+ default-language: Haskell2010++Test-Suite test-foundation+ type: exitcode-stdio-1.0+ hs-source-dirs: tests+ Main-is: Tests.hs+ Other-modules: ForeignUtils+ Encoding+ Build-Depends: base >= 3 && < 5+ , mtl+ , QuickCheck+ , tasty+ , tasty-quickcheck+ , tasty-hunit+ , foundation+ ghc-options: -Wall -fno-warn-orphans -fno-warn-missing-signatures+ default-language: Haskell2010++Benchmark bench-array+ Main-Is: Array.hs+ hs-source-dirs: benchs+ default-language: Haskell2010+ type: exitcode-stdio-1.0+ Default-Extensions: NoImplicitPrelude+ BangPatterns+ Build-depends: base >= 4, criterion, foundation++Benchmark bench-profile-break+ Main-Is: ProfBreak.hs+ hs-source-dirs: benchs+ default-language: Haskell2010+ type: exitcode-stdio-1.0+ Default-Extensions: NoImplicitPrelude+ BangPatterns+ Build-depends: foundation
+ tests/Encoding.hs view
@@ -0,0 +1,956 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE NoImplicitPrelude #-}++module Encoding+ ( EncodedString(..)+ , sample0+ , sample1+ , sample2++ , testEncodings+ ) where++import Foundation+import Foundation.String (Encoding(..), fromBytes, toBytes)+import Foundation.Array.Internal (recast)++import Test.Tasty+import Test.Tasty.HUnit++data EncodedString = EncodedString Encoding (UArray Word8)++testEncodings :: ([EncodedString], String) -> [TestTree]+testEncodings ([] , _ ) = []+testEncodings (x:xs, expected) = testEncoding x expected <> testEncodings (xs, expected)++testEncoding :: EncodedString -> String -> [TestTree]+testEncoding (EncodedString encoding ba) expected =+ [ testCase (show encoding <> " -> UTF8") $ testFromBytes+ , testCase ("UTF8 -> " <> show encoding) $ testToBytes+ ]+ where+ testFromBytes :: Assertion+ testFromBytes = case fromBytes encoding ba of+ (str, _, _) -> assertEqual "testFromBytes: " expected str+ testToBytes :: Assertion+ testToBytes =+ let bytes = toBytes encoding expected+ in assertEqual "testToBytes: " ba bytes++-- -------------------------- Sample 0 ------------------------------------- --++sample0 :: ([EncodedString], String)+sample0 = ( [sample0_ASCII7, sample0_UTF8, sample0_UTF16, sample0_ISO_8859_1]+ , sample0_String+ )++sample0_String :: String+sample0_String =+ "Called forth to stand trial on Trantor for allegations of treason (for\n\+ \foreshadowing the decline of the Galactic Empire), Seldon explains that his\n\+ \science of psychohistory foresees many alternatives, all of which result in the\n\+ \Galactic Empire eventually falling. If humanity follows its current path, the\n\+ \Empire will fall and 30,000 years of turmoil will overcome humanity before a\n\+ \second Empire arises. However, an alternative path allows for the intervening\n\+ \years to be only one thousand, if Seldon is allowed to collect the most\n\+ \intelligent minds and create a compendium of all human knowledge, entitled\n\+ \Encyclopedia Galactica. The board is still wary but allows Seldon to assemble\n\+ \whomever he needs, provided he and the \"Encyclopedists\" be exiled to a remote\n\+ \planet, Terminus. Seldon agrees to set up his own collection of Encyclopedists,\n\+ \and also secretly implements a contingency plan-a second Foundation-at the\n\+ \\"opposite end\" of the galaxy.\n"++sample0_ASCII7 :: EncodedString+sample0_ASCII7 = EncodedString ASCII7 $ fromList+ [ 0x43, 0x61, 0x6c, 0x6c, 0x65, 0x64, 0x20, 0x66, 0x6f, 0x72, 0x74, 0x68, 0x20, 0x74, 0x6f, 0x20+ , 0x73, 0x74, 0x61, 0x6e, 0x64, 0x20, 0x74, 0x72, 0x69, 0x61, 0x6c, 0x20, 0x6f, 0x6e, 0x20, 0x54+ , 0x72, 0x61, 0x6e, 0x74, 0x6f, 0x72, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x61, 0x6c, 0x6c, 0x65, 0x67+ , 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x72, 0x65, 0x61, 0x73, 0x6f+ , 0x6e, 0x20, 0x28, 0x66, 0x6f, 0x72, 0x0a, 0x66, 0x6f, 0x72, 0x65, 0x73, 0x68, 0x61, 0x64, 0x6f+ , 0x77, 0x69, 0x6e, 0x67, 0x20, 0x74, 0x68, 0x65, 0x20, 0x64, 0x65, 0x63, 0x6c, 0x69, 0x6e, 0x65+ , 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x47, 0x61, 0x6c, 0x61, 0x63, 0x74, 0x69, 0x63+ , 0x20, 0x45, 0x6d, 0x70, 0x69, 0x72, 0x65, 0x29, 0x2c, 0x20, 0x53, 0x65, 0x6c, 0x64, 0x6f, 0x6e+ , 0x20, 0x65, 0x78, 0x70, 0x6c, 0x61, 0x69, 0x6e, 0x73, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x68+ , 0x69, 0x73, 0x0a, 0x73, 0x63, 0x69, 0x65, 0x6e, 0x63, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x70, 0x73+ , 0x79, 0x63, 0x68, 0x6f, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x20, 0x66, 0x6f, 0x72, 0x65+ , 0x73, 0x65, 0x65, 0x73, 0x20, 0x6d, 0x61, 0x6e, 0x79, 0x20, 0x61, 0x6c, 0x74, 0x65, 0x72, 0x6e+ , 0x61, 0x74, 0x69, 0x76, 0x65, 0x73, 0x2c, 0x20, 0x61, 0x6c, 0x6c, 0x20, 0x6f, 0x66, 0x20, 0x77+ , 0x68, 0x69, 0x63, 0x68, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x20, 0x69, 0x6e, 0x20, 0x74+ , 0x68, 0x65, 0x0a, 0x47, 0x61, 0x6c, 0x61, 0x63, 0x74, 0x69, 0x63, 0x20, 0x45, 0x6d, 0x70, 0x69+ , 0x72, 0x65, 0x20, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x75, 0x61, 0x6c, 0x6c, 0x79, 0x20, 0x66, 0x61+ , 0x6c, 0x6c, 0x69, 0x6e, 0x67, 0x2e, 0x20, 0x49, 0x66, 0x20, 0x68, 0x75, 0x6d, 0x61, 0x6e, 0x69+ , 0x74, 0x79, 0x20, 0x66, 0x6f, 0x6c, 0x6c, 0x6f, 0x77, 0x73, 0x20, 0x69, 0x74, 0x73, 0x20, 0x63+ , 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x20, 0x70, 0x61, 0x74, 0x68, 0x2c, 0x20, 0x74, 0x68, 0x65+ , 0x0a, 0x45, 0x6d, 0x70, 0x69, 0x72, 0x65, 0x20, 0x77, 0x69, 0x6c, 0x6c, 0x20, 0x66, 0x61, 0x6c+ , 0x6c, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x33, 0x30, 0x2c, 0x30, 0x30, 0x30, 0x20, 0x79, 0x65, 0x61+ , 0x72, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x75, 0x72, 0x6d, 0x6f, 0x69, 0x6c, 0x20, 0x77, 0x69+ , 0x6c, 0x6c, 0x20, 0x6f, 0x76, 0x65, 0x72, 0x63, 0x6f, 0x6d, 0x65, 0x20, 0x68, 0x75, 0x6d, 0x61+ , 0x6e, 0x69, 0x74, 0x79, 0x20, 0x62, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x20, 0x61, 0x0a, 0x73, 0x65+ , 0x63, 0x6f, 0x6e, 0x64, 0x20, 0x45, 0x6d, 0x70, 0x69, 0x72, 0x65, 0x20, 0x61, 0x72, 0x69, 0x73+ , 0x65, 0x73, 0x2e, 0x20, 0x48, 0x6f, 0x77, 0x65, 0x76, 0x65, 0x72, 0x2c, 0x20, 0x61, 0x6e, 0x20+ , 0x61, 0x6c, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x74, 0x69, 0x76, 0x65, 0x20, 0x70, 0x61, 0x74, 0x68+ , 0x20, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x73, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20+ , 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x65, 0x6e, 0x69, 0x6e, 0x67, 0x0a, 0x79, 0x65, 0x61, 0x72+ , 0x73, 0x20, 0x74, 0x6f, 0x20, 0x62, 0x65, 0x20, 0x6f, 0x6e, 0x6c, 0x79, 0x20, 0x6f, 0x6e, 0x65+ , 0x20, 0x74, 0x68, 0x6f, 0x75, 0x73, 0x61, 0x6e, 0x64, 0x2c, 0x20, 0x69, 0x66, 0x20, 0x53, 0x65+ , 0x6c, 0x64, 0x6f, 0x6e, 0x20, 0x69, 0x73, 0x20, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x20+ , 0x74, 0x6f, 0x20, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6d+ , 0x6f, 0x73, 0x74, 0x0a, 0x69, 0x6e, 0x74, 0x65, 0x6c, 0x6c, 0x69, 0x67, 0x65, 0x6e, 0x74, 0x20+ , 0x6d, 0x69, 0x6e, 0x64, 0x73, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65+ , 0x20, 0x61, 0x20, 0x63, 0x6f, 0x6d, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x75, 0x6d, 0x20, 0x6f, 0x66+ , 0x20, 0x61, 0x6c, 0x6c, 0x20, 0x68, 0x75, 0x6d, 0x61, 0x6e, 0x20, 0x6b, 0x6e, 0x6f, 0x77, 0x6c+ , 0x65, 0x64, 0x67, 0x65, 0x2c, 0x20, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x64, 0x0a, 0x45+ , 0x6e, 0x63, 0x79, 0x63, 0x6c, 0x6f, 0x70, 0x65, 0x64, 0x69, 0x61, 0x20, 0x47, 0x61, 0x6c, 0x61+ , 0x63, 0x74, 0x69, 0x63, 0x61, 0x2e, 0x20, 0x54, 0x68, 0x65, 0x20, 0x62, 0x6f, 0x61, 0x72, 0x64+ , 0x20, 0x69, 0x73, 0x20, 0x73, 0x74, 0x69, 0x6c, 0x6c, 0x20, 0x77, 0x61, 0x72, 0x79, 0x20, 0x62+ , 0x75, 0x74, 0x20, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x73, 0x20, 0x53, 0x65, 0x6c, 0x64, 0x6f, 0x6e+ , 0x20, 0x74, 0x6f, 0x20, 0x61, 0x73, 0x73, 0x65, 0x6d, 0x62, 0x6c, 0x65, 0x0a, 0x77, 0x68, 0x6f+ , 0x6d, 0x65, 0x76, 0x65, 0x72, 0x20, 0x68, 0x65, 0x20, 0x6e, 0x65, 0x65, 0x64, 0x73, 0x2c, 0x20+ , 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x64, 0x20, 0x68, 0x65, 0x20, 0x61, 0x6e, 0x64, 0x20+ , 0x74, 0x68, 0x65, 0x20, 0x22, 0x45, 0x6e, 0x63, 0x79, 0x63, 0x6c, 0x6f, 0x70, 0x65, 0x64, 0x69+ , 0x73, 0x74, 0x73, 0x22, 0x20, 0x62, 0x65, 0x20, 0x65, 0x78, 0x69, 0x6c, 0x65, 0x64, 0x20, 0x74+ , 0x6f, 0x20, 0x61, 0x20, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x0a, 0x70, 0x6c, 0x61, 0x6e, 0x65+ , 0x74, 0x2c, 0x20, 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x75, 0x73, 0x2e, 0x20, 0x53, 0x65, 0x6c+ , 0x64, 0x6f, 0x6e, 0x20, 0x61, 0x67, 0x72, 0x65, 0x65, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x73, 0x65+ , 0x74, 0x20, 0x75, 0x70, 0x20, 0x68, 0x69, 0x73, 0x20, 0x6f, 0x77, 0x6e, 0x20, 0x63, 0x6f, 0x6c+ , 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6f, 0x66, 0x20, 0x45, 0x6e, 0x63, 0x79, 0x63+ , 0x6c, 0x6f, 0x70, 0x65, 0x64, 0x69, 0x73, 0x74, 0x73, 0x2c, 0x0a, 0x61, 0x6e, 0x64, 0x20, 0x61+ , 0x6c, 0x73, 0x6f, 0x20, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x6c, 0x79, 0x20, 0x69, 0x6d, 0x70+ , 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x20, 0x61, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x69, 0x6e+ , 0x67, 0x65, 0x6e, 0x63, 0x79, 0x20, 0x70, 0x6c, 0x61, 0x6e, 0x2d, 0x61, 0x20, 0x73, 0x65, 0x63+ , 0x6f, 0x6e, 0x64, 0x20, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2d, 0x61+ , 0x74, 0x20, 0x74, 0x68, 0x65, 0x0a, 0x22, 0x6f, 0x70, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x65, 0x20+ , 0x65, 0x6e, 0x64, 0x22, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x67, 0x61, 0x6c, 0x61+ , 0x78, 0x79, 0x2e, 0x0a+ ]+++sample0_UTF8 :: EncodedString+sample0_UTF8 = EncodedString UTF8 $ fromList+ [ 0x43, 0x61, 0x6c, 0x6c, 0x65, 0x64, 0x20, 0x66, 0x6f, 0x72, 0x74, 0x68, 0x20, 0x74, 0x6f, 0x20+ , 0x73, 0x74, 0x61, 0x6e, 0x64, 0x20, 0x74, 0x72, 0x69, 0x61, 0x6c, 0x20, 0x6f, 0x6e, 0x20, 0x54+ , 0x72, 0x61, 0x6e, 0x74, 0x6f, 0x72, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x61, 0x6c, 0x6c, 0x65, 0x67+ , 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x72, 0x65, 0x61, 0x73, 0x6f+ , 0x6e, 0x20, 0x28, 0x66, 0x6f, 0x72, 0x0a, 0x66, 0x6f, 0x72, 0x65, 0x73, 0x68, 0x61, 0x64, 0x6f+ , 0x77, 0x69, 0x6e, 0x67, 0x20, 0x74, 0x68, 0x65, 0x20, 0x64, 0x65, 0x63, 0x6c, 0x69, 0x6e, 0x65+ , 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x47, 0x61, 0x6c, 0x61, 0x63, 0x74, 0x69, 0x63+ , 0x20, 0x45, 0x6d, 0x70, 0x69, 0x72, 0x65, 0x29, 0x2c, 0x20, 0x53, 0x65, 0x6c, 0x64, 0x6f, 0x6e+ , 0x20, 0x65, 0x78, 0x70, 0x6c, 0x61, 0x69, 0x6e, 0x73, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x68+ , 0x69, 0x73, 0x0a, 0x73, 0x63, 0x69, 0x65, 0x6e, 0x63, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x70, 0x73+ , 0x79, 0x63, 0x68, 0x6f, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x20, 0x66, 0x6f, 0x72, 0x65+ , 0x73, 0x65, 0x65, 0x73, 0x20, 0x6d, 0x61, 0x6e, 0x79, 0x20, 0x61, 0x6c, 0x74, 0x65, 0x72, 0x6e+ , 0x61, 0x74, 0x69, 0x76, 0x65, 0x73, 0x2c, 0x20, 0x61, 0x6c, 0x6c, 0x20, 0x6f, 0x66, 0x20, 0x77+ , 0x68, 0x69, 0x63, 0x68, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x20, 0x69, 0x6e, 0x20, 0x74+ , 0x68, 0x65, 0x0a, 0x47, 0x61, 0x6c, 0x61, 0x63, 0x74, 0x69, 0x63, 0x20, 0x45, 0x6d, 0x70, 0x69+ , 0x72, 0x65, 0x20, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x75, 0x61, 0x6c, 0x6c, 0x79, 0x20, 0x66, 0x61+ , 0x6c, 0x6c, 0x69, 0x6e, 0x67, 0x2e, 0x20, 0x49, 0x66, 0x20, 0x68, 0x75, 0x6d, 0x61, 0x6e, 0x69+ , 0x74, 0x79, 0x20, 0x66, 0x6f, 0x6c, 0x6c, 0x6f, 0x77, 0x73, 0x20, 0x69, 0x74, 0x73, 0x20, 0x63+ , 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x20, 0x70, 0x61, 0x74, 0x68, 0x2c, 0x20, 0x74, 0x68, 0x65+ , 0x0a, 0x45, 0x6d, 0x70, 0x69, 0x72, 0x65, 0x20, 0x77, 0x69, 0x6c, 0x6c, 0x20, 0x66, 0x61, 0x6c+ , 0x6c, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x33, 0x30, 0x2c, 0x30, 0x30, 0x30, 0x20, 0x79, 0x65, 0x61+ , 0x72, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x75, 0x72, 0x6d, 0x6f, 0x69, 0x6c, 0x20, 0x77, 0x69+ , 0x6c, 0x6c, 0x20, 0x6f, 0x76, 0x65, 0x72, 0x63, 0x6f, 0x6d, 0x65, 0x20, 0x68, 0x75, 0x6d, 0x61+ , 0x6e, 0x69, 0x74, 0x79, 0x20, 0x62, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x20, 0x61, 0x0a, 0x73, 0x65+ , 0x63, 0x6f, 0x6e, 0x64, 0x20, 0x45, 0x6d, 0x70, 0x69, 0x72, 0x65, 0x20, 0x61, 0x72, 0x69, 0x73+ , 0x65, 0x73, 0x2e, 0x20, 0x48, 0x6f, 0x77, 0x65, 0x76, 0x65, 0x72, 0x2c, 0x20, 0x61, 0x6e, 0x20+ , 0x61, 0x6c, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x74, 0x69, 0x76, 0x65, 0x20, 0x70, 0x61, 0x74, 0x68+ , 0x20, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x73, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20+ , 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x65, 0x6e, 0x69, 0x6e, 0x67, 0x0a, 0x79, 0x65, 0x61, 0x72+ , 0x73, 0x20, 0x74, 0x6f, 0x20, 0x62, 0x65, 0x20, 0x6f, 0x6e, 0x6c, 0x79, 0x20, 0x6f, 0x6e, 0x65+ , 0x20, 0x74, 0x68, 0x6f, 0x75, 0x73, 0x61, 0x6e, 0x64, 0x2c, 0x20, 0x69, 0x66, 0x20, 0x53, 0x65+ , 0x6c, 0x64, 0x6f, 0x6e, 0x20, 0x69, 0x73, 0x20, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x20+ , 0x74, 0x6f, 0x20, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6d+ , 0x6f, 0x73, 0x74, 0x0a, 0x69, 0x6e, 0x74, 0x65, 0x6c, 0x6c, 0x69, 0x67, 0x65, 0x6e, 0x74, 0x20+ , 0x6d, 0x69, 0x6e, 0x64, 0x73, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65+ , 0x20, 0x61, 0x20, 0x63, 0x6f, 0x6d, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x75, 0x6d, 0x20, 0x6f, 0x66+ , 0x20, 0x61, 0x6c, 0x6c, 0x20, 0x68, 0x75, 0x6d, 0x61, 0x6e, 0x20, 0x6b, 0x6e, 0x6f, 0x77, 0x6c+ , 0x65, 0x64, 0x67, 0x65, 0x2c, 0x20, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x64, 0x0a, 0x45+ , 0x6e, 0x63, 0x79, 0x63, 0x6c, 0x6f, 0x70, 0x65, 0x64, 0x69, 0x61, 0x20, 0x47, 0x61, 0x6c, 0x61+ , 0x63, 0x74, 0x69, 0x63, 0x61, 0x2e, 0x20, 0x54, 0x68, 0x65, 0x20, 0x62, 0x6f, 0x61, 0x72, 0x64+ , 0x20, 0x69, 0x73, 0x20, 0x73, 0x74, 0x69, 0x6c, 0x6c, 0x20, 0x77, 0x61, 0x72, 0x79, 0x20, 0x62+ , 0x75, 0x74, 0x20, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x73, 0x20, 0x53, 0x65, 0x6c, 0x64, 0x6f, 0x6e+ , 0x20, 0x74, 0x6f, 0x20, 0x61, 0x73, 0x73, 0x65, 0x6d, 0x62, 0x6c, 0x65, 0x0a, 0x77, 0x68, 0x6f+ , 0x6d, 0x65, 0x76, 0x65, 0x72, 0x20, 0x68, 0x65, 0x20, 0x6e, 0x65, 0x65, 0x64, 0x73, 0x2c, 0x20+ , 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x64, 0x20, 0x68, 0x65, 0x20, 0x61, 0x6e, 0x64, 0x20+ , 0x74, 0x68, 0x65, 0x20, 0x22, 0x45, 0x6e, 0x63, 0x79, 0x63, 0x6c, 0x6f, 0x70, 0x65, 0x64, 0x69+ , 0x73, 0x74, 0x73, 0x22, 0x20, 0x62, 0x65, 0x20, 0x65, 0x78, 0x69, 0x6c, 0x65, 0x64, 0x20, 0x74+ , 0x6f, 0x20, 0x61, 0x20, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x0a, 0x70, 0x6c, 0x61, 0x6e, 0x65+ , 0x74, 0x2c, 0x20, 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x75, 0x73, 0x2e, 0x20, 0x53, 0x65, 0x6c+ , 0x64, 0x6f, 0x6e, 0x20, 0x61, 0x67, 0x72, 0x65, 0x65, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x73, 0x65+ , 0x74, 0x20, 0x75, 0x70, 0x20, 0x68, 0x69, 0x73, 0x20, 0x6f, 0x77, 0x6e, 0x20, 0x63, 0x6f, 0x6c+ , 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6f, 0x66, 0x20, 0x45, 0x6e, 0x63, 0x79, 0x63+ , 0x6c, 0x6f, 0x70, 0x65, 0x64, 0x69, 0x73, 0x74, 0x73, 0x2c, 0x0a, 0x61, 0x6e, 0x64, 0x20, 0x61+ , 0x6c, 0x73, 0x6f, 0x20, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x6c, 0x79, 0x20, 0x69, 0x6d, 0x70+ , 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x20, 0x61, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x69, 0x6e+ , 0x67, 0x65, 0x6e, 0x63, 0x79, 0x20, 0x70, 0x6c, 0x61, 0x6e, 0x2d, 0x61, 0x20, 0x73, 0x65, 0x63+ , 0x6f, 0x6e, 0x64, 0x20, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2d, 0x61+ , 0x74, 0x20, 0x74, 0x68, 0x65, 0x0a, 0x22, 0x6f, 0x70, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x65, 0x20+ , 0x65, 0x6e, 0x64, 0x22, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x67, 0x61, 0x6c, 0x61+ , 0x78, 0x79, 0x2e, 0x0a+ ]++sample0_UTF16 :: EncodedString+sample0_UTF16 = EncodedString UTF16 $ recast array+ where+ array :: UArray Word16+ array = fromList+ [ 0x0043, 0x0061, 0x006c, 0x006c, 0x0065, 0x0064, 0x0020, 0x0066+ , 0x006f, 0x0072, 0x0074, 0x0068, 0x0020, 0x0074, 0x006f, 0x0020+ , 0x0073, 0x0074, 0x0061, 0x006e, 0x0064, 0x0020, 0x0074, 0x0072+ , 0x0069, 0x0061, 0x006c, 0x0020, 0x006f, 0x006e, 0x0020, 0x0054+ , 0x0072, 0x0061, 0x006e, 0x0074, 0x006f, 0x0072, 0x0020, 0x0066+ , 0x006f, 0x0072, 0x0020, 0x0061, 0x006c, 0x006c, 0x0065, 0x0067+ , 0x0061, 0x0074, 0x0069, 0x006f, 0x006e, 0x0073, 0x0020, 0x006f+ , 0x0066, 0x0020, 0x0074, 0x0072, 0x0065, 0x0061, 0x0073, 0x006f+ , 0x006e, 0x0020, 0x0028, 0x0066, 0x006f, 0x0072, 0x000a, 0x0066+ , 0x006f, 0x0072, 0x0065, 0x0073, 0x0068, 0x0061, 0x0064, 0x006f+ , 0x0077, 0x0069, 0x006e, 0x0067, 0x0020, 0x0074, 0x0068, 0x0065+ , 0x0020, 0x0064, 0x0065, 0x0063, 0x006c, 0x0069, 0x006e, 0x0065+ , 0x0020, 0x006f, 0x0066, 0x0020, 0x0074, 0x0068, 0x0065, 0x0020+ , 0x0047, 0x0061, 0x006c, 0x0061, 0x0063, 0x0074, 0x0069, 0x0063+ , 0x0020, 0x0045, 0x006d, 0x0070, 0x0069, 0x0072, 0x0065, 0x0029+ , 0x002c, 0x0020, 0x0053, 0x0065, 0x006c, 0x0064, 0x006f, 0x006e+ , 0x0020, 0x0065, 0x0078, 0x0070, 0x006c, 0x0061, 0x0069, 0x006e+ , 0x0073, 0x0020, 0x0074, 0x0068, 0x0061, 0x0074, 0x0020, 0x0068+ , 0x0069, 0x0073, 0x000a, 0x0073, 0x0063, 0x0069, 0x0065, 0x006e+ , 0x0063, 0x0065, 0x0020, 0x006f, 0x0066, 0x0020, 0x0070, 0x0073+ , 0x0079, 0x0063, 0x0068, 0x006f, 0x0068, 0x0069, 0x0073, 0x0074+ , 0x006f, 0x0072, 0x0079, 0x0020, 0x0066, 0x006f, 0x0072, 0x0065+ , 0x0073, 0x0065, 0x0065, 0x0073, 0x0020, 0x006d, 0x0061, 0x006e+ , 0x0079, 0x0020, 0x0061, 0x006c, 0x0074, 0x0065, 0x0072, 0x006e+ , 0x0061, 0x0074, 0x0069, 0x0076, 0x0065, 0x0073, 0x002c, 0x0020+ , 0x0061, 0x006c, 0x006c, 0x0020, 0x006f, 0x0066, 0x0020, 0x0077+ , 0x0068, 0x0069, 0x0063, 0x0068, 0x0020, 0x0072, 0x0065, 0x0073+ , 0x0075, 0x006c, 0x0074, 0x0020, 0x0069, 0x006e, 0x0020, 0x0074+ , 0x0068, 0x0065, 0x000a, 0x0047, 0x0061, 0x006c, 0x0061, 0x0063+ , 0x0074, 0x0069, 0x0063, 0x0020, 0x0045, 0x006d, 0x0070, 0x0069+ , 0x0072, 0x0065, 0x0020, 0x0065, 0x0076, 0x0065, 0x006e, 0x0074+ , 0x0075, 0x0061, 0x006c, 0x006c, 0x0079, 0x0020, 0x0066, 0x0061+ , 0x006c, 0x006c, 0x0069, 0x006e, 0x0067, 0x002e, 0x0020, 0x0049+ , 0x0066, 0x0020, 0x0068, 0x0075, 0x006d, 0x0061, 0x006e, 0x0069+ , 0x0074, 0x0079, 0x0020, 0x0066, 0x006f, 0x006c, 0x006c, 0x006f+ , 0x0077, 0x0073, 0x0020, 0x0069, 0x0074, 0x0073, 0x0020, 0x0063+ , 0x0075, 0x0072, 0x0072, 0x0065, 0x006e, 0x0074, 0x0020, 0x0070+ , 0x0061, 0x0074, 0x0068, 0x002c, 0x0020, 0x0074, 0x0068, 0x0065+ , 0x000a, 0x0045, 0x006d, 0x0070, 0x0069, 0x0072, 0x0065, 0x0020+ , 0x0077, 0x0069, 0x006c, 0x006c, 0x0020, 0x0066, 0x0061, 0x006c+ , 0x006c, 0x0020, 0x0061, 0x006e, 0x0064, 0x0020, 0x0033, 0x0030+ , 0x002c, 0x0030, 0x0030, 0x0030, 0x0020, 0x0079, 0x0065, 0x0061+ , 0x0072, 0x0073, 0x0020, 0x006f, 0x0066, 0x0020, 0x0074, 0x0075+ , 0x0072, 0x006d, 0x006f, 0x0069, 0x006c, 0x0020, 0x0077, 0x0069+ , 0x006c, 0x006c, 0x0020, 0x006f, 0x0076, 0x0065, 0x0072, 0x0063+ , 0x006f, 0x006d, 0x0065, 0x0020, 0x0068, 0x0075, 0x006d, 0x0061+ , 0x006e, 0x0069, 0x0074, 0x0079, 0x0020, 0x0062, 0x0065, 0x0066+ , 0x006f, 0x0072, 0x0065, 0x0020, 0x0061, 0x000a, 0x0073, 0x0065+ , 0x0063, 0x006f, 0x006e, 0x0064, 0x0020, 0x0045, 0x006d, 0x0070+ , 0x0069, 0x0072, 0x0065, 0x0020, 0x0061, 0x0072, 0x0069, 0x0073+ , 0x0065, 0x0073, 0x002e, 0x0020, 0x0048, 0x006f, 0x0077, 0x0065+ , 0x0076, 0x0065, 0x0072, 0x002c, 0x0020, 0x0061, 0x006e, 0x0020+ , 0x0061, 0x006c, 0x0074, 0x0065, 0x0072, 0x006e, 0x0061, 0x0074+ , 0x0069, 0x0076, 0x0065, 0x0020, 0x0070, 0x0061, 0x0074, 0x0068+ , 0x0020, 0x0061, 0x006c, 0x006c, 0x006f, 0x0077, 0x0073, 0x0020+ , 0x0066, 0x006f, 0x0072, 0x0020, 0x0074, 0x0068, 0x0065, 0x0020+ , 0x0069, 0x006e, 0x0074, 0x0065, 0x0072, 0x0076, 0x0065, 0x006e+ , 0x0069, 0x006e, 0x0067, 0x000a, 0x0079, 0x0065, 0x0061, 0x0072+ , 0x0073, 0x0020, 0x0074, 0x006f, 0x0020, 0x0062, 0x0065, 0x0020+ , 0x006f, 0x006e, 0x006c, 0x0079, 0x0020, 0x006f, 0x006e, 0x0065+ , 0x0020, 0x0074, 0x0068, 0x006f, 0x0075, 0x0073, 0x0061, 0x006e+ , 0x0064, 0x002c, 0x0020, 0x0069, 0x0066, 0x0020, 0x0053, 0x0065+ , 0x006c, 0x0064, 0x006f, 0x006e, 0x0020, 0x0069, 0x0073, 0x0020+ , 0x0061, 0x006c, 0x006c, 0x006f, 0x0077, 0x0065, 0x0064, 0x0020+ , 0x0074, 0x006f, 0x0020, 0x0063, 0x006f, 0x006c, 0x006c, 0x0065+ , 0x0063, 0x0074, 0x0020, 0x0074, 0x0068, 0x0065, 0x0020, 0x006d+ , 0x006f, 0x0073, 0x0074, 0x000a, 0x0069, 0x006e, 0x0074, 0x0065+ , 0x006c, 0x006c, 0x0069, 0x0067, 0x0065, 0x006e, 0x0074, 0x0020+ , 0x006d, 0x0069, 0x006e, 0x0064, 0x0073, 0x0020, 0x0061, 0x006e+ , 0x0064, 0x0020, 0x0063, 0x0072, 0x0065, 0x0061, 0x0074, 0x0065+ , 0x0020, 0x0061, 0x0020, 0x0063, 0x006f, 0x006d, 0x0070, 0x0065+ , 0x006e, 0x0064, 0x0069, 0x0075, 0x006d, 0x0020, 0x006f, 0x0066+ , 0x0020, 0x0061, 0x006c, 0x006c, 0x0020, 0x0068, 0x0075, 0x006d+ , 0x0061, 0x006e, 0x0020, 0x006b, 0x006e, 0x006f, 0x0077, 0x006c+ , 0x0065, 0x0064, 0x0067, 0x0065, 0x002c, 0x0020, 0x0065, 0x006e+ , 0x0074, 0x0069, 0x0074, 0x006c, 0x0065, 0x0064, 0x000a, 0x0045+ , 0x006e, 0x0063, 0x0079, 0x0063, 0x006c, 0x006f, 0x0070, 0x0065+ , 0x0064, 0x0069, 0x0061, 0x0020, 0x0047, 0x0061, 0x006c, 0x0061+ , 0x0063, 0x0074, 0x0069, 0x0063, 0x0061, 0x002e, 0x0020, 0x0054+ , 0x0068, 0x0065, 0x0020, 0x0062, 0x006f, 0x0061, 0x0072, 0x0064+ , 0x0020, 0x0069, 0x0073, 0x0020, 0x0073, 0x0074, 0x0069, 0x006c+ , 0x006c, 0x0020, 0x0077, 0x0061, 0x0072, 0x0079, 0x0020, 0x0062+ , 0x0075, 0x0074, 0x0020, 0x0061, 0x006c, 0x006c, 0x006f, 0x0077+ , 0x0073, 0x0020, 0x0053, 0x0065, 0x006c, 0x0064, 0x006f, 0x006e+ , 0x0020, 0x0074, 0x006f, 0x0020, 0x0061, 0x0073, 0x0073, 0x0065+ , 0x006d, 0x0062, 0x006c, 0x0065, 0x000a, 0x0077, 0x0068, 0x006f+ , 0x006d, 0x0065, 0x0076, 0x0065, 0x0072, 0x0020, 0x0068, 0x0065+ , 0x0020, 0x006e, 0x0065, 0x0065, 0x0064, 0x0073, 0x002c, 0x0020+ , 0x0070, 0x0072, 0x006f, 0x0076, 0x0069, 0x0064, 0x0065, 0x0064+ , 0x0020, 0x0068, 0x0065, 0x0020, 0x0061, 0x006e, 0x0064, 0x0020+ , 0x0074, 0x0068, 0x0065, 0x0020, 0x0022, 0x0045, 0x006e, 0x0063+ , 0x0079, 0x0063, 0x006c, 0x006f, 0x0070, 0x0065, 0x0064, 0x0069+ , 0x0073, 0x0074, 0x0073, 0x0022, 0x0020, 0x0062, 0x0065, 0x0020+ , 0x0065, 0x0078, 0x0069, 0x006c, 0x0065, 0x0064, 0x0020, 0x0074+ , 0x006f, 0x0020, 0x0061, 0x0020, 0x0072, 0x0065, 0x006d, 0x006f+ , 0x0074, 0x0065, 0x000a, 0x0070, 0x006c, 0x0061, 0x006e, 0x0065+ , 0x0074, 0x002c, 0x0020, 0x0054, 0x0065, 0x0072, 0x006d, 0x0069+ , 0x006e, 0x0075, 0x0073, 0x002e, 0x0020, 0x0053, 0x0065, 0x006c+ , 0x0064, 0x006f, 0x006e, 0x0020, 0x0061, 0x0067, 0x0072, 0x0065+ , 0x0065, 0x0073, 0x0020, 0x0074, 0x006f, 0x0020, 0x0073, 0x0065+ , 0x0074, 0x0020, 0x0075, 0x0070, 0x0020, 0x0068, 0x0069, 0x0073+ , 0x0020, 0x006f, 0x0077, 0x006e, 0x0020, 0x0063, 0x006f, 0x006c+ , 0x006c, 0x0065, 0x0063, 0x0074, 0x0069, 0x006f, 0x006e, 0x0020+ , 0x006f, 0x0066, 0x0020, 0x0045, 0x006e, 0x0063, 0x0079, 0x0063+ , 0x006c, 0x006f, 0x0070, 0x0065, 0x0064, 0x0069, 0x0073, 0x0074+ , 0x0073, 0x002c, 0x000a, 0x0061, 0x006e, 0x0064, 0x0020, 0x0061+ , 0x006c, 0x0073, 0x006f, 0x0020, 0x0073, 0x0065, 0x0063, 0x0072+ , 0x0065, 0x0074, 0x006c, 0x0079, 0x0020, 0x0069, 0x006d, 0x0070+ , 0x006c, 0x0065, 0x006d, 0x0065, 0x006e, 0x0074, 0x0073, 0x0020+ , 0x0061, 0x0020, 0x0063, 0x006f, 0x006e, 0x0074, 0x0069, 0x006e+ , 0x0067, 0x0065, 0x006e, 0x0063, 0x0079, 0x0020, 0x0070, 0x006c+ , 0x0061, 0x006e, 0x002d, 0x0061, 0x0020, 0x0073, 0x0065, 0x0063+ , 0x006f, 0x006e, 0x0064, 0x0020, 0x0046, 0x006f, 0x0075, 0x006e+ , 0x0064, 0x0061, 0x0074, 0x0069, 0x006f, 0x006e, 0x002d, 0x0061+ , 0x0074, 0x0020, 0x0074, 0x0068, 0x0065, 0x000a, 0x0022, 0x006f+ , 0x0070, 0x0070, 0x006f, 0x0073, 0x0069, 0x0074, 0x0065, 0x0020+ , 0x0065, 0x006e, 0x0064, 0x0022, 0x0020, 0x006f, 0x0066, 0x0020+ , 0x0074, 0x0068, 0x0065, 0x0020, 0x0067, 0x0061, 0x006c, 0x0061+ , 0x0078, 0x0079, 0x002e, 0x000a+ ]++sample0_ISO_8859_1 :: EncodedString+sample0_ISO_8859_1 = EncodedString ISO_8859_1 $ fromList+ [ 0x43, 0x61, 0x6c, 0x6c, 0x65, 0x64, 0x20, 0x66, 0x6f, 0x72, 0x74, 0x68, 0x20, 0x74, 0x6f, 0x20+ , 0x73, 0x74, 0x61, 0x6e, 0x64, 0x20, 0x74, 0x72, 0x69, 0x61, 0x6c, 0x20, 0x6f, 0x6e, 0x20, 0x54+ , 0x72, 0x61, 0x6e, 0x74, 0x6f, 0x72, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x61, 0x6c, 0x6c, 0x65, 0x67+ , 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x72, 0x65, 0x61, 0x73, 0x6f+ , 0x6e, 0x20, 0x28, 0x66, 0x6f, 0x72, 0x0a, 0x66, 0x6f, 0x72, 0x65, 0x73, 0x68, 0x61, 0x64, 0x6f+ , 0x77, 0x69, 0x6e, 0x67, 0x20, 0x74, 0x68, 0x65, 0x20, 0x64, 0x65, 0x63, 0x6c, 0x69, 0x6e, 0x65+ , 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x47, 0x61, 0x6c, 0x61, 0x63, 0x74, 0x69, 0x63+ , 0x20, 0x45, 0x6d, 0x70, 0x69, 0x72, 0x65, 0x29, 0x2c, 0x20, 0x53, 0x65, 0x6c, 0x64, 0x6f, 0x6e+ , 0x20, 0x65, 0x78, 0x70, 0x6c, 0x61, 0x69, 0x6e, 0x73, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x68+ , 0x69, 0x73, 0x0a, 0x73, 0x63, 0x69, 0x65, 0x6e, 0x63, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x70, 0x73+ , 0x79, 0x63, 0x68, 0x6f, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x20, 0x66, 0x6f, 0x72, 0x65+ , 0x73, 0x65, 0x65, 0x73, 0x20, 0x6d, 0x61, 0x6e, 0x79, 0x20, 0x61, 0x6c, 0x74, 0x65, 0x72, 0x6e+ , 0x61, 0x74, 0x69, 0x76, 0x65, 0x73, 0x2c, 0x20, 0x61, 0x6c, 0x6c, 0x20, 0x6f, 0x66, 0x20, 0x77+ , 0x68, 0x69, 0x63, 0x68, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x20, 0x69, 0x6e, 0x20, 0x74+ , 0x68, 0x65, 0x0a, 0x47, 0x61, 0x6c, 0x61, 0x63, 0x74, 0x69, 0x63, 0x20, 0x45, 0x6d, 0x70, 0x69+ , 0x72, 0x65, 0x20, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x75, 0x61, 0x6c, 0x6c, 0x79, 0x20, 0x66, 0x61+ , 0x6c, 0x6c, 0x69, 0x6e, 0x67, 0x2e, 0x20, 0x49, 0x66, 0x20, 0x68, 0x75, 0x6d, 0x61, 0x6e, 0x69+ , 0x74, 0x79, 0x20, 0x66, 0x6f, 0x6c, 0x6c, 0x6f, 0x77, 0x73, 0x20, 0x69, 0x74, 0x73, 0x20, 0x63+ , 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x20, 0x70, 0x61, 0x74, 0x68, 0x2c, 0x20, 0x74, 0x68, 0x65+ , 0x0a, 0x45, 0x6d, 0x70, 0x69, 0x72, 0x65, 0x20, 0x77, 0x69, 0x6c, 0x6c, 0x20, 0x66, 0x61, 0x6c+ , 0x6c, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x33, 0x30, 0x2c, 0x30, 0x30, 0x30, 0x20, 0x79, 0x65, 0x61+ , 0x72, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x75, 0x72, 0x6d, 0x6f, 0x69, 0x6c, 0x20, 0x77, 0x69+ , 0x6c, 0x6c, 0x20, 0x6f, 0x76, 0x65, 0x72, 0x63, 0x6f, 0x6d, 0x65, 0x20, 0x68, 0x75, 0x6d, 0x61+ , 0x6e, 0x69, 0x74, 0x79, 0x20, 0x62, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x20, 0x61, 0x0a, 0x73, 0x65+ , 0x63, 0x6f, 0x6e, 0x64, 0x20, 0x45, 0x6d, 0x70, 0x69, 0x72, 0x65, 0x20, 0x61, 0x72, 0x69, 0x73+ , 0x65, 0x73, 0x2e, 0x20, 0x48, 0x6f, 0x77, 0x65, 0x76, 0x65, 0x72, 0x2c, 0x20, 0x61, 0x6e, 0x20+ , 0x61, 0x6c, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x74, 0x69, 0x76, 0x65, 0x20, 0x70, 0x61, 0x74, 0x68+ , 0x20, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x73, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20+ , 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x65, 0x6e, 0x69, 0x6e, 0x67, 0x0a, 0x79, 0x65, 0x61, 0x72+ , 0x73, 0x20, 0x74, 0x6f, 0x20, 0x62, 0x65, 0x20, 0x6f, 0x6e, 0x6c, 0x79, 0x20, 0x6f, 0x6e, 0x65+ , 0x20, 0x74, 0x68, 0x6f, 0x75, 0x73, 0x61, 0x6e, 0x64, 0x2c, 0x20, 0x69, 0x66, 0x20, 0x53, 0x65+ , 0x6c, 0x64, 0x6f, 0x6e, 0x20, 0x69, 0x73, 0x20, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x20+ , 0x74, 0x6f, 0x20, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6d+ , 0x6f, 0x73, 0x74, 0x0a, 0x69, 0x6e, 0x74, 0x65, 0x6c, 0x6c, 0x69, 0x67, 0x65, 0x6e, 0x74, 0x20+ , 0x6d, 0x69, 0x6e, 0x64, 0x73, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65+ , 0x20, 0x61, 0x20, 0x63, 0x6f, 0x6d, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x75, 0x6d, 0x20, 0x6f, 0x66+ , 0x20, 0x61, 0x6c, 0x6c, 0x20, 0x68, 0x75, 0x6d, 0x61, 0x6e, 0x20, 0x6b, 0x6e, 0x6f, 0x77, 0x6c+ , 0x65, 0x64, 0x67, 0x65, 0x2c, 0x20, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x64, 0x0a, 0x45+ , 0x6e, 0x63, 0x79, 0x63, 0x6c, 0x6f, 0x70, 0x65, 0x64, 0x69, 0x61, 0x20, 0x47, 0x61, 0x6c, 0x61+ , 0x63, 0x74, 0x69, 0x63, 0x61, 0x2e, 0x20, 0x54, 0x68, 0x65, 0x20, 0x62, 0x6f, 0x61, 0x72, 0x64+ , 0x20, 0x69, 0x73, 0x20, 0x73, 0x74, 0x69, 0x6c, 0x6c, 0x20, 0x77, 0x61, 0x72, 0x79, 0x20, 0x62+ , 0x75, 0x74, 0x20, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x73, 0x20, 0x53, 0x65, 0x6c, 0x64, 0x6f, 0x6e+ , 0x20, 0x74, 0x6f, 0x20, 0x61, 0x73, 0x73, 0x65, 0x6d, 0x62, 0x6c, 0x65, 0x0a, 0x77, 0x68, 0x6f+ , 0x6d, 0x65, 0x76, 0x65, 0x72, 0x20, 0x68, 0x65, 0x20, 0x6e, 0x65, 0x65, 0x64, 0x73, 0x2c, 0x20+ , 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x64, 0x20, 0x68, 0x65, 0x20, 0x61, 0x6e, 0x64, 0x20+ , 0x74, 0x68, 0x65, 0x20, 0x22, 0x45, 0x6e, 0x63, 0x79, 0x63, 0x6c, 0x6f, 0x70, 0x65, 0x64, 0x69+ , 0x73, 0x74, 0x73, 0x22, 0x20, 0x62, 0x65, 0x20, 0x65, 0x78, 0x69, 0x6c, 0x65, 0x64, 0x20, 0x74+ , 0x6f, 0x20, 0x61, 0x20, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x0a, 0x70, 0x6c, 0x61, 0x6e, 0x65+ , 0x74, 0x2c, 0x20, 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x75, 0x73, 0x2e, 0x20, 0x53, 0x65, 0x6c+ , 0x64, 0x6f, 0x6e, 0x20, 0x61, 0x67, 0x72, 0x65, 0x65, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x73, 0x65+ , 0x74, 0x20, 0x75, 0x70, 0x20, 0x68, 0x69, 0x73, 0x20, 0x6f, 0x77, 0x6e, 0x20, 0x63, 0x6f, 0x6c+ , 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6f, 0x66, 0x20, 0x45, 0x6e, 0x63, 0x79, 0x63+ , 0x6c, 0x6f, 0x70, 0x65, 0x64, 0x69, 0x73, 0x74, 0x73, 0x2c, 0x0a, 0x61, 0x6e, 0x64, 0x20, 0x61+ , 0x6c, 0x73, 0x6f, 0x20, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x6c, 0x79, 0x20, 0x69, 0x6d, 0x70+ , 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x20, 0x61, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x69, 0x6e+ , 0x67, 0x65, 0x6e, 0x63, 0x79, 0x20, 0x70, 0x6c, 0x61, 0x6e, 0x2d, 0x61, 0x20, 0x73, 0x65, 0x63+ , 0x6f, 0x6e, 0x64, 0x20, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2d, 0x61+ , 0x74, 0x20, 0x74, 0x68, 0x65, 0x0a, 0x22, 0x6f, 0x70, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x65, 0x20+ , 0x65, 0x6e, 0x64, 0x22, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x67, 0x61, 0x6c, 0x61+ , 0x78, 0x79, 0x2e, 0x0a+ ]++-- -------------------------- Sample 1 ------------------------------------- --++sample1 :: ([EncodedString], String)+sample1 = ( [sample1_UTF8, sample1_UTF16, sample1_ISO_8859_1]+ , sample1_String+ )++sample1_String :: String+sample1_String =+ "In French:\n\+ \\n\+ \1. un robot ne peut porter atteinte à un être humain, ni, en restant passif, permettre qu'un être humain soit exposé au danger ;\n\+ \2. un robot doit obéir aux ordres qui lui sont donnés par un être humain, sauf si de tels ordres entrent en conflit avec la première loi ;\n\+ \3. un robot doit protéger son existence tant que cette protection n'entre pas en conflit avec la première ou la deuxième loi.\n\+ \\n\+ \In Danish:\n\+ \\n\+ \1. En robot må ikke gøre et menneske fortræd, eller, ved ikke at gøre noget, lade et menneske komme til skade\n\+ \2. En robot skal adlyde ordrer givet af mennesker, så længe disse ikke er i konflikt med første lov\n\+ \3. En robot skal beskytte sin egen eksistens, så længe dette ikke er i konflikt med første eller anden lov\n"++sample1_UTF8 :: EncodedString+sample1_UTF8 = EncodedString UTF8 $ fromList+ [ 0x49, 0x6e, 0x20, 0x46, 0x72, 0x65, 0x6e, 0x63, 0x68, 0x3a, 0x0a, 0x0a, 0x31, 0x2e, 0x20, 0x75+ , 0x6e, 0x20, 0x72, 0x6f, 0x62, 0x6f, 0x74, 0x20, 0x6e, 0x65, 0x20, 0x70, 0x65, 0x75, 0x74, 0x20+ , 0x70, 0x6f, 0x72, 0x74, 0x65, 0x72, 0x20, 0x61, 0x74, 0x74, 0x65, 0x69, 0x6e, 0x74, 0x65, 0x20+ , 0xc3, 0xa0, 0x20, 0x75, 0x6e, 0x20, 0xc3, 0xaa, 0x74, 0x72, 0x65, 0x20, 0x68, 0x75, 0x6d, 0x61+ , 0x69, 0x6e, 0x2c, 0x20, 0x6e, 0x69, 0x2c, 0x20, 0x65, 0x6e, 0x20, 0x72, 0x65, 0x73, 0x74, 0x61+ , 0x6e, 0x74, 0x20, 0x70, 0x61, 0x73, 0x73, 0x69, 0x66, 0x2c, 0x20, 0x70, 0x65, 0x72, 0x6d, 0x65+ , 0x74, 0x74, 0x72, 0x65, 0x20, 0x71, 0x75, 0x27, 0x75, 0x6e, 0x20, 0xc3, 0xaa, 0x74, 0x72, 0x65+ , 0x20, 0x68, 0x75, 0x6d, 0x61, 0x69, 0x6e, 0x20, 0x73, 0x6f, 0x69, 0x74, 0x20, 0x65, 0x78, 0x70+ , 0x6f, 0x73, 0xc3, 0xa9, 0x20, 0x61, 0x75, 0x20, 0x64, 0x61, 0x6e, 0x67, 0x65, 0x72, 0x20, 0x3b+ , 0x0a, 0x32, 0x2e, 0x20, 0x75, 0x6e, 0x20, 0x72, 0x6f, 0x62, 0x6f, 0x74, 0x20, 0x64, 0x6f, 0x69+ , 0x74, 0x20, 0x6f, 0x62, 0xc3, 0xa9, 0x69, 0x72, 0x20, 0x61, 0x75, 0x78, 0x20, 0x6f, 0x72, 0x64+ , 0x72, 0x65, 0x73, 0x20, 0x71, 0x75, 0x69, 0x20, 0x6c, 0x75, 0x69, 0x20, 0x73, 0x6f, 0x6e, 0x74+ , 0x20, 0x64, 0x6f, 0x6e, 0x6e, 0xc3, 0xa9, 0x73, 0x20, 0x70, 0x61, 0x72, 0x20, 0x75, 0x6e, 0x20+ , 0xc3, 0xaa, 0x74, 0x72, 0x65, 0x20, 0x68, 0x75, 0x6d, 0x61, 0x69, 0x6e, 0x2c, 0x20, 0x73, 0x61+ , 0x75, 0x66, 0x20, 0x73, 0x69, 0x20, 0x64, 0x65, 0x20, 0x74, 0x65, 0x6c, 0x73, 0x20, 0x6f, 0x72+ , 0x64, 0x72, 0x65, 0x73, 0x20, 0x65, 0x6e, 0x74, 0x72, 0x65, 0x6e, 0x74, 0x20, 0x65, 0x6e, 0x20+ , 0x63, 0x6f, 0x6e, 0x66, 0x6c, 0x69, 0x74, 0x20, 0x61, 0x76, 0x65, 0x63, 0x20, 0x6c, 0x61, 0x20+ , 0x70, 0x72, 0x65, 0x6d, 0x69, 0xc3, 0xa8, 0x72, 0x65, 0x20, 0x6c, 0x6f, 0x69, 0x20, 0x3b, 0x0a+ , 0x33, 0x2e, 0x20, 0x75, 0x6e, 0x20, 0x72, 0x6f, 0x62, 0x6f, 0x74, 0x20, 0x64, 0x6f, 0x69, 0x74+ , 0x20, 0x70, 0x72, 0x6f, 0x74, 0xc3, 0xa9, 0x67, 0x65, 0x72, 0x20, 0x73, 0x6f, 0x6e, 0x20, 0x65+ , 0x78, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x63, 0x65, 0x20, 0x74, 0x61, 0x6e, 0x74, 0x20, 0x71, 0x75+ , 0x65, 0x20, 0x63, 0x65, 0x74, 0x74, 0x65, 0x20, 0x70, 0x72, 0x6f, 0x74, 0x65, 0x63, 0x74, 0x69+ , 0x6f, 0x6e, 0x20, 0x6e, 0x27, 0x65, 0x6e, 0x74, 0x72, 0x65, 0x20, 0x70, 0x61, 0x73, 0x20, 0x65+ , 0x6e, 0x20, 0x63, 0x6f, 0x6e, 0x66, 0x6c, 0x69, 0x74, 0x20, 0x61, 0x76, 0x65, 0x63, 0x20, 0x6c+ , 0x61, 0x20, 0x70, 0x72, 0x65, 0x6d, 0x69, 0xc3, 0xa8, 0x72, 0x65, 0x20, 0x6f, 0x75, 0x20, 0x6c+ , 0x61, 0x20, 0x64, 0x65, 0x75, 0x78, 0x69, 0xc3, 0xa8, 0x6d, 0x65, 0x20, 0x6c, 0x6f, 0x69, 0x2e+ , 0x0a, 0x0a, 0x49, 0x6e, 0x20, 0x44, 0x61, 0x6e, 0x69, 0x73, 0x68, 0x3a, 0x0a, 0x0a, 0x31, 0x2e+ , 0x20, 0x45, 0x6e, 0x20, 0x72, 0x6f, 0x62, 0x6f, 0x74, 0x20, 0x6d, 0xc3, 0xa5, 0x20, 0x69, 0x6b+ , 0x6b, 0x65, 0x20, 0x67, 0xc3, 0xb8, 0x72, 0x65, 0x20, 0x65, 0x74, 0x20, 0x6d, 0x65, 0x6e, 0x6e+ , 0x65, 0x73, 0x6b, 0x65, 0x20, 0x66, 0x6f, 0x72, 0x74, 0x72, 0xc3, 0xa6, 0x64, 0x2c, 0x20, 0x65+ , 0x6c, 0x6c, 0x65, 0x72, 0x2c, 0x20, 0x76, 0x65, 0x64, 0x20, 0x69, 0x6b, 0x6b, 0x65, 0x20, 0x61+ , 0x74, 0x20, 0x67, 0xc3, 0xb8, 0x72, 0x65, 0x20, 0x6e, 0x6f, 0x67, 0x65, 0x74, 0x2c, 0x20, 0x6c+ , 0x61, 0x64, 0x65, 0x20, 0x65, 0x74, 0x20, 0x6d, 0x65, 0x6e, 0x6e, 0x65, 0x73, 0x6b, 0x65, 0x20+ , 0x6b, 0x6f, 0x6d, 0x6d, 0x65, 0x20, 0x74, 0x69, 0x6c, 0x20, 0x73, 0x6b, 0x61, 0x64, 0x65, 0x0a+ , 0x32, 0x2e, 0x20, 0x45, 0x6e, 0x20, 0x72, 0x6f, 0x62, 0x6f, 0x74, 0x20, 0x73, 0x6b, 0x61, 0x6c+ , 0x20, 0x61, 0x64, 0x6c, 0x79, 0x64, 0x65, 0x20, 0x6f, 0x72, 0x64, 0x72, 0x65, 0x72, 0x20, 0x67+ , 0x69, 0x76, 0x65, 0x74, 0x20, 0x61, 0x66, 0x20, 0x6d, 0x65, 0x6e, 0x6e, 0x65, 0x73, 0x6b, 0x65+ , 0x72, 0x2c, 0x20, 0x73, 0xc3, 0xa5, 0x20, 0x6c, 0xc3, 0xa6, 0x6e, 0x67, 0x65, 0x20, 0x64, 0x69+ , 0x73, 0x73, 0x65, 0x20, 0x69, 0x6b, 0x6b, 0x65, 0x20, 0x65, 0x72, 0x20, 0x69, 0x20, 0x6b, 0x6f+ , 0x6e, 0x66, 0x6c, 0x69, 0x6b, 0x74, 0x20, 0x6d, 0x65, 0x64, 0x20, 0x66, 0xc3, 0xb8, 0x72, 0x73+ , 0x74, 0x65, 0x20, 0x6c, 0x6f, 0x76, 0x0a, 0x33, 0x2e, 0x20, 0x45, 0x6e, 0x20, 0x72, 0x6f, 0x62+ , 0x6f, 0x74, 0x20, 0x73, 0x6b, 0x61, 0x6c, 0x20, 0x62, 0x65, 0x73, 0x6b, 0x79, 0x74, 0x74, 0x65+ , 0x20, 0x73, 0x69, 0x6e, 0x20, 0x65, 0x67, 0x65, 0x6e, 0x20, 0x65, 0x6b, 0x73, 0x69, 0x73, 0x74+ , 0x65, 0x6e, 0x73, 0x2c, 0x20, 0x73, 0xc3, 0xa5, 0x20, 0x6c, 0xc3, 0xa6, 0x6e, 0x67, 0x65, 0x20+ , 0x64, 0x65, 0x74, 0x74, 0x65, 0x20, 0x69, 0x6b, 0x6b, 0x65, 0x20, 0x65, 0x72, 0x20, 0x69, 0x20+ , 0x6b, 0x6f, 0x6e, 0x66, 0x6c, 0x69, 0x6b, 0x74, 0x20, 0x6d, 0x65, 0x64, 0x20, 0x66, 0xc3, 0xb8+ , 0x72, 0x73, 0x74, 0x65, 0x20, 0x65, 0x6c, 0x6c, 0x65, 0x72, 0x20, 0x61, 0x6e, 0x64, 0x65, 0x6e+ , 0x20, 0x6c, 0x6f, 0x76, 0x0a+ ]++sample1_UTF16 :: EncodedString+sample1_UTF16 = EncodedString UTF16 $ recast array+ where+ array :: UArray Word16+ array = fromList+ [ 0x0049, 0x006e, 0x0020, 0x0046, 0x0072, 0x0065, 0x006e, 0x0063+ , 0x0068, 0x003a, 0x000a, 0x000a, 0x0031, 0x002e, 0x0020, 0x0075+ , 0x006e, 0x0020, 0x0072, 0x006f, 0x0062, 0x006f, 0x0074, 0x0020+ , 0x006e, 0x0065, 0x0020, 0x0070, 0x0065, 0x0075, 0x0074, 0x0020+ , 0x0070, 0x006f, 0x0072, 0x0074, 0x0065, 0x0072, 0x0020, 0x0061+ , 0x0074, 0x0074, 0x0065, 0x0069, 0x006e, 0x0074, 0x0065, 0x0020+ , 0x00e0, 0x0020, 0x0075, 0x006e, 0x0020, 0x00ea, 0x0074, 0x0072+ , 0x0065, 0x0020, 0x0068, 0x0075, 0x006d, 0x0061, 0x0069, 0x006e+ , 0x002c, 0x0020, 0x006e, 0x0069, 0x002c, 0x0020, 0x0065, 0x006e+ , 0x0020, 0x0072, 0x0065, 0x0073, 0x0074, 0x0061, 0x006e, 0x0074+ , 0x0020, 0x0070, 0x0061, 0x0073, 0x0073, 0x0069, 0x0066, 0x002c+ , 0x0020, 0x0070, 0x0065, 0x0072, 0x006d, 0x0065, 0x0074, 0x0074+ , 0x0072, 0x0065, 0x0020, 0x0071, 0x0075, 0x0027, 0x0075, 0x006e+ , 0x0020, 0x00ea, 0x0074, 0x0072, 0x0065, 0x0020, 0x0068, 0x0075+ , 0x006d, 0x0061, 0x0069, 0x006e, 0x0020, 0x0073, 0x006f, 0x0069+ , 0x0074, 0x0020, 0x0065, 0x0078, 0x0070, 0x006f, 0x0073, 0x00e9+ , 0x0020, 0x0061, 0x0075, 0x0020, 0x0064, 0x0061, 0x006e, 0x0067+ , 0x0065, 0x0072, 0x0020, 0x003b, 0x000a, 0x0032, 0x002e, 0x0020+ , 0x0075, 0x006e, 0x0020, 0x0072, 0x006f, 0x0062, 0x006f, 0x0074+ , 0x0020, 0x0064, 0x006f, 0x0069, 0x0074, 0x0020, 0x006f, 0x0062+ , 0x00e9, 0x0069, 0x0072, 0x0020, 0x0061, 0x0075, 0x0078, 0x0020+ , 0x006f, 0x0072, 0x0064, 0x0072, 0x0065, 0x0073, 0x0020, 0x0071+ , 0x0075, 0x0069, 0x0020, 0x006c, 0x0075, 0x0069, 0x0020, 0x0073+ , 0x006f, 0x006e, 0x0074, 0x0020, 0x0064, 0x006f, 0x006e, 0x006e+ , 0x00e9, 0x0073, 0x0020, 0x0070, 0x0061, 0x0072, 0x0020, 0x0075+ , 0x006e, 0x0020, 0x00ea, 0x0074, 0x0072, 0x0065, 0x0020, 0x0068+ , 0x0075, 0x006d, 0x0061, 0x0069, 0x006e, 0x002c, 0x0020, 0x0073+ , 0x0061, 0x0075, 0x0066, 0x0020, 0x0073, 0x0069, 0x0020, 0x0064+ , 0x0065, 0x0020, 0x0074, 0x0065, 0x006c, 0x0073, 0x0020, 0x006f+ , 0x0072, 0x0064, 0x0072, 0x0065, 0x0073, 0x0020, 0x0065, 0x006e+ , 0x0074, 0x0072, 0x0065, 0x006e, 0x0074, 0x0020, 0x0065, 0x006e+ , 0x0020, 0x0063, 0x006f, 0x006e, 0x0066, 0x006c, 0x0069, 0x0074+ , 0x0020, 0x0061, 0x0076, 0x0065, 0x0063, 0x0020, 0x006c, 0x0061+ , 0x0020, 0x0070, 0x0072, 0x0065, 0x006d, 0x0069, 0x00e8, 0x0072+ , 0x0065, 0x0020, 0x006c, 0x006f, 0x0069, 0x0020, 0x003b, 0x000a+ , 0x0033, 0x002e, 0x0020, 0x0075, 0x006e, 0x0020, 0x0072, 0x006f+ , 0x0062, 0x006f, 0x0074, 0x0020, 0x0064, 0x006f, 0x0069, 0x0074+ , 0x0020, 0x0070, 0x0072, 0x006f, 0x0074, 0x00e9, 0x0067, 0x0065+ , 0x0072, 0x0020, 0x0073, 0x006f, 0x006e, 0x0020, 0x0065, 0x0078+ , 0x0069, 0x0073, 0x0074, 0x0065, 0x006e, 0x0063, 0x0065, 0x0020+ , 0x0074, 0x0061, 0x006e, 0x0074, 0x0020, 0x0071, 0x0075, 0x0065+ , 0x0020, 0x0063, 0x0065, 0x0074, 0x0074, 0x0065, 0x0020, 0x0070+ , 0x0072, 0x006f, 0x0074, 0x0065, 0x0063, 0x0074, 0x0069, 0x006f+ , 0x006e, 0x0020, 0x006e, 0x0027, 0x0065, 0x006e, 0x0074, 0x0072+ , 0x0065, 0x0020, 0x0070, 0x0061, 0x0073, 0x0020, 0x0065, 0x006e+ , 0x0020, 0x0063, 0x006f, 0x006e, 0x0066, 0x006c, 0x0069, 0x0074+ , 0x0020, 0x0061, 0x0076, 0x0065, 0x0063, 0x0020, 0x006c, 0x0061+ , 0x0020, 0x0070, 0x0072, 0x0065, 0x006d, 0x0069, 0x00e8, 0x0072+ , 0x0065, 0x0020, 0x006f, 0x0075, 0x0020, 0x006c, 0x0061, 0x0020+ , 0x0064, 0x0065, 0x0075, 0x0078, 0x0069, 0x00e8, 0x006d, 0x0065+ , 0x0020, 0x006c, 0x006f, 0x0069, 0x002e, 0x000a, 0x000a, 0x0049+ , 0x006e, 0x0020, 0x0044, 0x0061, 0x006e, 0x0069, 0x0073, 0x0068+ , 0x003a, 0x000a, 0x000a, 0x0031, 0x002e, 0x0020, 0x0045, 0x006e+ , 0x0020, 0x0072, 0x006f, 0x0062, 0x006f, 0x0074, 0x0020, 0x006d+ , 0x00e5, 0x0020, 0x0069, 0x006b, 0x006b, 0x0065, 0x0020, 0x0067+ , 0x00f8, 0x0072, 0x0065, 0x0020, 0x0065, 0x0074, 0x0020, 0x006d+ , 0x0065, 0x006e, 0x006e, 0x0065, 0x0073, 0x006b, 0x0065, 0x0020+ , 0x0066, 0x006f, 0x0072, 0x0074, 0x0072, 0x00e6, 0x0064, 0x002c+ , 0x0020, 0x0065, 0x006c, 0x006c, 0x0065, 0x0072, 0x002c, 0x0020+ , 0x0076, 0x0065, 0x0064, 0x0020, 0x0069, 0x006b, 0x006b, 0x0065+ , 0x0020, 0x0061, 0x0074, 0x0020, 0x0067, 0x00f8, 0x0072, 0x0065+ , 0x0020, 0x006e, 0x006f, 0x0067, 0x0065, 0x0074, 0x002c, 0x0020+ , 0x006c, 0x0061, 0x0064, 0x0065, 0x0020, 0x0065, 0x0074, 0x0020+ , 0x006d, 0x0065, 0x006e, 0x006e, 0x0065, 0x0073, 0x006b, 0x0065+ , 0x0020, 0x006b, 0x006f, 0x006d, 0x006d, 0x0065, 0x0020, 0x0074+ , 0x0069, 0x006c, 0x0020, 0x0073, 0x006b, 0x0061, 0x0064, 0x0065+ , 0x000a, 0x0032, 0x002e, 0x0020, 0x0045, 0x006e, 0x0020, 0x0072+ , 0x006f, 0x0062, 0x006f, 0x0074, 0x0020, 0x0073, 0x006b, 0x0061+ , 0x006c, 0x0020, 0x0061, 0x0064, 0x006c, 0x0079, 0x0064, 0x0065+ , 0x0020, 0x006f, 0x0072, 0x0064, 0x0072, 0x0065, 0x0072, 0x0020+ , 0x0067, 0x0069, 0x0076, 0x0065, 0x0074, 0x0020, 0x0061, 0x0066+ , 0x0020, 0x006d, 0x0065, 0x006e, 0x006e, 0x0065, 0x0073, 0x006b+ , 0x0065, 0x0072, 0x002c, 0x0020, 0x0073, 0x00e5, 0x0020, 0x006c+ , 0x00e6, 0x006e, 0x0067, 0x0065, 0x0020, 0x0064, 0x0069, 0x0073+ , 0x0073, 0x0065, 0x0020, 0x0069, 0x006b, 0x006b, 0x0065, 0x0020+ , 0x0065, 0x0072, 0x0020, 0x0069, 0x0020, 0x006b, 0x006f, 0x006e+ , 0x0066, 0x006c, 0x0069, 0x006b, 0x0074, 0x0020, 0x006d, 0x0065+ , 0x0064, 0x0020, 0x0066, 0x00f8, 0x0072, 0x0073, 0x0074, 0x0065+ , 0x0020, 0x006c, 0x006f, 0x0076, 0x000a, 0x0033, 0x002e, 0x0020+ , 0x0045, 0x006e, 0x0020, 0x0072, 0x006f, 0x0062, 0x006f, 0x0074+ , 0x0020, 0x0073, 0x006b, 0x0061, 0x006c, 0x0020, 0x0062, 0x0065+ , 0x0073, 0x006b, 0x0079, 0x0074, 0x0074, 0x0065, 0x0020, 0x0073+ , 0x0069, 0x006e, 0x0020, 0x0065, 0x0067, 0x0065, 0x006e, 0x0020+ , 0x0065, 0x006b, 0x0073, 0x0069, 0x0073, 0x0074, 0x0065, 0x006e+ , 0x0073, 0x002c, 0x0020, 0x0073, 0x00e5, 0x0020, 0x006c, 0x00e6+ , 0x006e, 0x0067, 0x0065, 0x0020, 0x0064, 0x0065, 0x0074, 0x0074+ , 0x0065, 0x0020, 0x0069, 0x006b, 0x006b, 0x0065, 0x0020, 0x0065+ , 0x0072, 0x0020, 0x0069, 0x0020, 0x006b, 0x006f, 0x006e, 0x0066+ , 0x006c, 0x0069, 0x006b, 0x0074, 0x0020, 0x006d, 0x0065, 0x0064+ , 0x0020, 0x0066, 0x00f8, 0x0072, 0x0073, 0x0074, 0x0065, 0x0020+ , 0x0065, 0x006c, 0x006c, 0x0065, 0x0072, 0x0020, 0x0061, 0x006e+ , 0x0064, 0x0065, 0x006e, 0x0020, 0x006c, 0x006f, 0x0076, 0x000a+ ]++sample1_ISO_8859_1 :: EncodedString+sample1_ISO_8859_1 = EncodedString ISO_8859_1 $ fromList+ [ 0x49, 0x6e, 0x20, 0x46, 0x72, 0x65, 0x6e, 0x63, 0x68, 0x3a, 0x0a, 0x0a, 0x31, 0x2e, 0x20, 0x75+ , 0x6e, 0x20, 0x72, 0x6f, 0x62, 0x6f, 0x74, 0x20, 0x6e, 0x65, 0x20, 0x70, 0x65, 0x75, 0x74, 0x20+ , 0x70, 0x6f, 0x72, 0x74, 0x65, 0x72, 0x20, 0x61, 0x74, 0x74, 0x65, 0x69, 0x6e, 0x74, 0x65, 0x20+ , 0xe0, 0x20, 0x75, 0x6e, 0x20, 0xea, 0x74, 0x72, 0x65, 0x20, 0x68, 0x75, 0x6d, 0x61, 0x69, 0x6e+ , 0x2c, 0x20, 0x6e, 0x69, 0x2c, 0x20, 0x65, 0x6e, 0x20, 0x72, 0x65, 0x73, 0x74, 0x61, 0x6e, 0x74+ , 0x20, 0x70, 0x61, 0x73, 0x73, 0x69, 0x66, 0x2c, 0x20, 0x70, 0x65, 0x72, 0x6d, 0x65, 0x74, 0x74+ , 0x72, 0x65, 0x20, 0x71, 0x75, 0x27, 0x75, 0x6e, 0x20, 0xea, 0x74, 0x72, 0x65, 0x20, 0x68, 0x75+ , 0x6d, 0x61, 0x69, 0x6e, 0x20, 0x73, 0x6f, 0x69, 0x74, 0x20, 0x65, 0x78, 0x70, 0x6f, 0x73, 0xe9+ , 0x20, 0x61, 0x75, 0x20, 0x64, 0x61, 0x6e, 0x67, 0x65, 0x72, 0x20, 0x3b, 0x0a, 0x32, 0x2e, 0x20+ , 0x75, 0x6e, 0x20, 0x72, 0x6f, 0x62, 0x6f, 0x74, 0x20, 0x64, 0x6f, 0x69, 0x74, 0x20, 0x6f, 0x62+ , 0xe9, 0x69, 0x72, 0x20, 0x61, 0x75, 0x78, 0x20, 0x6f, 0x72, 0x64, 0x72, 0x65, 0x73, 0x20, 0x71+ , 0x75, 0x69, 0x20, 0x6c, 0x75, 0x69, 0x20, 0x73, 0x6f, 0x6e, 0x74, 0x20, 0x64, 0x6f, 0x6e, 0x6e+ , 0xe9, 0x73, 0x20, 0x70, 0x61, 0x72, 0x20, 0x75, 0x6e, 0x20, 0xea, 0x74, 0x72, 0x65, 0x20, 0x68+ , 0x75, 0x6d, 0x61, 0x69, 0x6e, 0x2c, 0x20, 0x73, 0x61, 0x75, 0x66, 0x20, 0x73, 0x69, 0x20, 0x64+ , 0x65, 0x20, 0x74, 0x65, 0x6c, 0x73, 0x20, 0x6f, 0x72, 0x64, 0x72, 0x65, 0x73, 0x20, 0x65, 0x6e+ , 0x74, 0x72, 0x65, 0x6e, 0x74, 0x20, 0x65, 0x6e, 0x20, 0x63, 0x6f, 0x6e, 0x66, 0x6c, 0x69, 0x74+ , 0x20, 0x61, 0x76, 0x65, 0x63, 0x20, 0x6c, 0x61, 0x20, 0x70, 0x72, 0x65, 0x6d, 0x69, 0xe8, 0x72+ , 0x65, 0x20, 0x6c, 0x6f, 0x69, 0x20, 0x3b, 0x0a, 0x33, 0x2e, 0x20, 0x75, 0x6e, 0x20, 0x72, 0x6f+ , 0x62, 0x6f, 0x74, 0x20, 0x64, 0x6f, 0x69, 0x74, 0x20, 0x70, 0x72, 0x6f, 0x74, 0xe9, 0x67, 0x65+ , 0x72, 0x20, 0x73, 0x6f, 0x6e, 0x20, 0x65, 0x78, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x63, 0x65, 0x20+ , 0x74, 0x61, 0x6e, 0x74, 0x20, 0x71, 0x75, 0x65, 0x20, 0x63, 0x65, 0x74, 0x74, 0x65, 0x20, 0x70+ , 0x72, 0x6f, 0x74, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6e, 0x27, 0x65, 0x6e, 0x74, 0x72+ , 0x65, 0x20, 0x70, 0x61, 0x73, 0x20, 0x65, 0x6e, 0x20, 0x63, 0x6f, 0x6e, 0x66, 0x6c, 0x69, 0x74+ , 0x20, 0x61, 0x76, 0x65, 0x63, 0x20, 0x6c, 0x61, 0x20, 0x70, 0x72, 0x65, 0x6d, 0x69, 0xe8, 0x72+ , 0x65, 0x20, 0x6f, 0x75, 0x20, 0x6c, 0x61, 0x20, 0x64, 0x65, 0x75, 0x78, 0x69, 0xe8, 0x6d, 0x65+ , 0x20, 0x6c, 0x6f, 0x69, 0x2e, 0x0a, 0x0a, 0x49, 0x6e, 0x20, 0x44, 0x61, 0x6e, 0x69, 0x73, 0x68+ , 0x3a, 0x0a, 0x0a, 0x31, 0x2e, 0x20, 0x45, 0x6e, 0x20, 0x72, 0x6f, 0x62, 0x6f, 0x74, 0x20, 0x6d+ , 0xe5, 0x20, 0x69, 0x6b, 0x6b, 0x65, 0x20, 0x67, 0xf8, 0x72, 0x65, 0x20, 0x65, 0x74, 0x20, 0x6d+ , 0x65, 0x6e, 0x6e, 0x65, 0x73, 0x6b, 0x65, 0x20, 0x66, 0x6f, 0x72, 0x74, 0x72, 0xe6, 0x64, 0x2c+ , 0x20, 0x65, 0x6c, 0x6c, 0x65, 0x72, 0x2c, 0x20, 0x76, 0x65, 0x64, 0x20, 0x69, 0x6b, 0x6b, 0x65+ , 0x20, 0x61, 0x74, 0x20, 0x67, 0xf8, 0x72, 0x65, 0x20, 0x6e, 0x6f, 0x67, 0x65, 0x74, 0x2c, 0x20+ , 0x6c, 0x61, 0x64, 0x65, 0x20, 0x65, 0x74, 0x20, 0x6d, 0x65, 0x6e, 0x6e, 0x65, 0x73, 0x6b, 0x65+ , 0x20, 0x6b, 0x6f, 0x6d, 0x6d, 0x65, 0x20, 0x74, 0x69, 0x6c, 0x20, 0x73, 0x6b, 0x61, 0x64, 0x65+ , 0x0a, 0x32, 0x2e, 0x20, 0x45, 0x6e, 0x20, 0x72, 0x6f, 0x62, 0x6f, 0x74, 0x20, 0x73, 0x6b, 0x61+ , 0x6c, 0x20, 0x61, 0x64, 0x6c, 0x79, 0x64, 0x65, 0x20, 0x6f, 0x72, 0x64, 0x72, 0x65, 0x72, 0x20+ , 0x67, 0x69, 0x76, 0x65, 0x74, 0x20, 0x61, 0x66, 0x20, 0x6d, 0x65, 0x6e, 0x6e, 0x65, 0x73, 0x6b+ , 0x65, 0x72, 0x2c, 0x20, 0x73, 0xe5, 0x20, 0x6c, 0xe6, 0x6e, 0x67, 0x65, 0x20, 0x64, 0x69, 0x73+ , 0x73, 0x65, 0x20, 0x69, 0x6b, 0x6b, 0x65, 0x20, 0x65, 0x72, 0x20, 0x69, 0x20, 0x6b, 0x6f, 0x6e+ , 0x66, 0x6c, 0x69, 0x6b, 0x74, 0x20, 0x6d, 0x65, 0x64, 0x20, 0x66, 0xf8, 0x72, 0x73, 0x74, 0x65+ , 0x20, 0x6c, 0x6f, 0x76, 0x0a, 0x33, 0x2e, 0x20, 0x45, 0x6e, 0x20, 0x72, 0x6f, 0x62, 0x6f, 0x74+ , 0x20, 0x73, 0x6b, 0x61, 0x6c, 0x20, 0x62, 0x65, 0x73, 0x6b, 0x79, 0x74, 0x74, 0x65, 0x20, 0x73+ , 0x69, 0x6e, 0x20, 0x65, 0x67, 0x65, 0x6e, 0x20, 0x65, 0x6b, 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e+ , 0x73, 0x2c, 0x20, 0x73, 0xe5, 0x20, 0x6c, 0xe6, 0x6e, 0x67, 0x65, 0x20, 0x64, 0x65, 0x74, 0x74+ , 0x65, 0x20, 0x69, 0x6b, 0x6b, 0x65, 0x20, 0x65, 0x72, 0x20, 0x69, 0x20, 0x6b, 0x6f, 0x6e, 0x66+ , 0x6c, 0x69, 0x6b, 0x74, 0x20, 0x6d, 0x65, 0x64, 0x20, 0x66, 0xf8, 0x72, 0x73, 0x74, 0x65, 0x20+ , 0x65, 0x6c, 0x6c, 0x65, 0x72, 0x20, 0x61, 0x6e, 0x64, 0x65, 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x0a+ ]++-- -------------------------- Sample 2 ------------------------------------- --++sample2 :: ([EncodedString], String)+sample2 = ( [sample2_UTF8, sample2_UTF16]+ , sample2_String+ )++sample2_String :: String+sample2_String =+ "The sample text below has been taken from Wikipedia:\n\+ \https://zh.wikipedia.org/wiki/%E5%9F%BA%E5%9C%B0%E7%B3%BB%E5%88%97\n\+ \\n\+ \基地系列(The Foundation Series)是一部經典科幻小說系列,創作時間橫跨美國作家以撒·艾西莫夫49個寫作年頭,一共10冊(包括別人續寫3冊),彼此間劇情獨立,卻又緊密關聯。「基地系列」通常也將處在同一架空宇宙的「機器人系列」和「銀河帝國系列」包括進來,總計起來整個「大基地系列」作品共有14冊長篇,和數不清的短篇小說,另外6冊由其他作家在他死後續寫。「基地系列」備受讚譽,1965年得過雨果獎「史上最佳科幻小說系列」。\n\+ \\n\+ \《基地》原本是一系列8篇的短篇小說,在1942年5月到1950年1月期間發表於《驚奇雜誌》(Astounding Magazine)。艾西莫夫在自傳中表示,《基地》是在他拜訪編輯約翰·坎貝爾(John W. Campbell)的路上,天馬行空聯想自愛德華·吉本的《羅馬帝國衰亡史》,之後與坎貝爾兩相討論下,整體概念遂而成形[1]。\n\+ \\n\+ \「基地系列」第一部《基地》包含4篇短篇小說,劇情各自獨立,單行本發行於1951年。其它4篇中篇小說兩兩相對,分別收錄在《基地與帝國》和《第二基地》,成為名聞遐邇的「基地三部曲」。1981年,「基地三部曲」早已是世所公認最重要的現代科幻作品,艾西莫夫終於被出版商說服續寫「基地系列」第四部《基地邊緣》[2]。接下來他又寫了一部續集《基地與地球》,5年後發表兩部前傳《基地前奏》和《基地締造者》,在這幾年中,艾西莫夫將「基地系列」與其它系列相結合,將所有系列作品同置於一個「基地宇宙」架構下。\n\+ \\n\+ \艾西莫夫和坎貝爾聯手為「基地系列」打造出一門全新的統計科學,稱之為“心理史學”,這門學問由書中数學家哈里·謝頓窮盡畢生之力創建,根據大規模的人類活動數據,預測未來走向,規模一旦小於一顆星球或是一座帝國,結果就會失準。謝頓運用此一科學,預見銀河帝國的殞落,整片銀河將因此進入長達三萬年的黑暗時期,直到第二帝國建立。\n\+ \\n\+ \於是謝頓建立兩座基地,藉以縮減蠻荒時期,一座遠在邊陲,是藝術與科學的避風港,相對的另一座則在“群星的盡頭”。「基地三部曲」的主要焦點就在端點星上的基地。端點星上的學者為了搶在衰退期之前,保存人類物理科學的知識,努力編輯著一部全方位的《银河百科全书》,對謝頓真正的意圖毫不知情(如果他們知道,就會產生無法控制的變數)。基地的位置也是刻意選定的,千年後就是第二帝國的首都(並非三萬年後的那個帝國)\n"++sample2_UTF8 :: EncodedString+sample2_UTF8 = EncodedString UTF8 $ fromList+ [ 0x54, 0x68, 0x65, 0x20, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x20, 0x74, 0x65, 0x78, 0x74, 0x20+ , 0x62, 0x65, 0x6c, 0x6f, 0x77, 0x20, 0x68, 0x61, 0x73, 0x20, 0x62, 0x65, 0x65, 0x6e, 0x20, 0x74+ , 0x61, 0x6b, 0x65, 0x6e, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x57, 0x69, 0x6b, 0x69, 0x70, 0x65+ , 0x64, 0x69, 0x61, 0x3a, 0x0a, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x7a, 0x68, 0x2e+ , 0x77, 0x69, 0x6b, 0x69, 0x70, 0x65, 0x64, 0x69, 0x61, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x77, 0x69+ , 0x6b, 0x69, 0x2f, 0x25, 0x45, 0x35, 0x25, 0x39, 0x46, 0x25, 0x42, 0x41, 0x25, 0x45, 0x35, 0x25+ , 0x39, 0x43, 0x25, 0x42, 0x30, 0x25, 0x45, 0x37, 0x25, 0x42, 0x33, 0x25, 0x42, 0x42, 0x25, 0x45+ , 0x35, 0x25, 0x38, 0x38, 0x25, 0x39, 0x37, 0x0a, 0x0a, 0xe5, 0x9f, 0xba, 0xe5, 0x9c, 0xb0, 0xe7+ , 0xb3, 0xbb, 0xe5, 0x88, 0x97, 0xef, 0xbc, 0x88, 0x54, 0x68, 0x65, 0x20, 0x46, 0x6f, 0x75, 0x6e+ , 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x53, 0x65, 0x72, 0x69, 0x65, 0x73, 0xef, 0xbc, 0x89+ , 0xe6, 0x98, 0xaf, 0xe4, 0xb8, 0x80, 0xe9, 0x83, 0xa8, 0xe7, 0xb6, 0x93, 0xe5, 0x85, 0xb8, 0xe7+ , 0xa7, 0x91, 0xe5, 0xb9, 0xbb, 0xe5, 0xb0, 0x8f, 0xe8, 0xaa, 0xaa, 0xe7, 0xb3, 0xbb, 0xe5, 0x88+ , 0x97, 0xef, 0xbc, 0x8c, 0xe5, 0x89, 0xb5, 0xe4, 0xbd, 0x9c, 0xe6, 0x99, 0x82, 0xe9, 0x96, 0x93+ , 0xe6, 0xa9, 0xab, 0xe8, 0xb7, 0xa8, 0xe7, 0xbe, 0x8e, 0xe5, 0x9c, 0x8b, 0xe4, 0xbd, 0x9c, 0xe5+ , 0xae, 0xb6, 0xe4, 0xbb, 0xa5, 0xe6, 0x92, 0x92, 0xc2, 0xb7, 0xe8, 0x89, 0xbe, 0xe8, 0xa5, 0xbf+ , 0xe8, 0x8e, 0xab, 0xe5, 0xa4, 0xab, 0x34, 0x39, 0xe5, 0x80, 0x8b, 0xe5, 0xaf, 0xab, 0xe4, 0xbd+ , 0x9c, 0xe5, 0xb9, 0xb4, 0xe9, 0xa0, 0xad, 0xef, 0xbc, 0x8c, 0xe4, 0xb8, 0x80, 0xe5, 0x85, 0xb1+ , 0x31, 0x30, 0xe5, 0x86, 0x8a, 0xef, 0xbc, 0x88, 0xe5, 0x8c, 0x85, 0xe6, 0x8b, 0xac, 0xe5, 0x88+ , 0xa5, 0xe4, 0xba, 0xba, 0xe7, 0xba, 0x8c, 0xe5, 0xaf, 0xab, 0x33, 0xe5, 0x86, 0x8a, 0xef, 0xbc+ , 0x89, 0xef, 0xbc, 0x8c, 0xe5, 0xbd, 0xbc, 0xe6, 0xad, 0xa4, 0xe9, 0x96, 0x93, 0xe5, 0x8a, 0x87+ , 0xe6, 0x83, 0x85, 0xe7, 0x8d, 0xa8, 0xe7, 0xab, 0x8b, 0xef, 0xbc, 0x8c, 0xe5, 0x8d, 0xbb, 0xe5+ , 0x8f, 0x88, 0xe7, 0xb7, 0x8a, 0xe5, 0xaf, 0x86, 0xe9, 0x97, 0x9c, 0xe8, 0x81, 0xaf, 0xe3, 0x80+ , 0x82, 0xe3, 0x80, 0x8c, 0xe5, 0x9f, 0xba, 0xe5, 0x9c, 0xb0, 0xe7, 0xb3, 0xbb, 0xe5, 0x88, 0x97+ , 0xe3, 0x80, 0x8d, 0xe9, 0x80, 0x9a, 0xe5, 0xb8, 0xb8, 0xe4, 0xb9, 0x9f, 0xe5, 0xb0, 0x87, 0xe8+ , 0x99, 0x95, 0xe5, 0x9c, 0xa8, 0xe5, 0x90, 0x8c, 0xe4, 0xb8, 0x80, 0xe6, 0x9e, 0xb6, 0xe7, 0xa9+ , 0xba, 0xe5, 0xae, 0x87, 0xe5, 0xae, 0x99, 0xe7, 0x9a, 0x84, 0xe3, 0x80, 0x8c, 0xe6, 0xa9, 0x9f+ , 0xe5, 0x99, 0xa8, 0xe4, 0xba, 0xba, 0xe7, 0xb3, 0xbb, 0xe5, 0x88, 0x97, 0xe3, 0x80, 0x8d, 0xe5+ , 0x92, 0x8c, 0xe3, 0x80, 0x8c, 0xe9, 0x8a, 0x80, 0xe6, 0xb2, 0xb3, 0xe5, 0xb8, 0x9d, 0xe5, 0x9c+ , 0x8b, 0xe7, 0xb3, 0xbb, 0xe5, 0x88, 0x97, 0xe3, 0x80, 0x8d, 0xe5, 0x8c, 0x85, 0xe6, 0x8b, 0xac+ , 0xe9, 0x80, 0xb2, 0xe4, 0xbe, 0x86, 0xef, 0xbc, 0x8c, 0xe7, 0xb8, 0xbd, 0xe8, 0xa8, 0x88, 0xe8+ , 0xb5, 0xb7, 0xe4, 0xbe, 0x86, 0xe6, 0x95, 0xb4, 0xe5, 0x80, 0x8b, 0xe3, 0x80, 0x8c, 0xe5, 0xa4+ , 0xa7, 0xe5, 0x9f, 0xba, 0xe5, 0x9c, 0xb0, 0xe7, 0xb3, 0xbb, 0xe5, 0x88, 0x97, 0xe3, 0x80, 0x8d+ , 0xe4, 0xbd, 0x9c, 0xe5, 0x93, 0x81, 0xe5, 0x85, 0xb1, 0xe6, 0x9c, 0x89, 0x31, 0x34, 0xe5, 0x86+ , 0x8a, 0xe9, 0x95, 0xb7, 0xe7, 0xaf, 0x87, 0xef, 0xbc, 0x8c, 0xe5, 0x92, 0x8c, 0xe6, 0x95, 0xb8+ , 0xe4, 0xb8, 0x8d, 0xe6, 0xb8, 0x85, 0xe7, 0x9a, 0x84, 0xe7, 0x9f, 0xad, 0xe7, 0xaf, 0x87, 0xe5+ , 0xb0, 0x8f, 0xe8, 0xaa, 0xaa, 0xef, 0xbc, 0x8c, 0xe5, 0x8f, 0xa6, 0xe5, 0xa4, 0x96, 0x36, 0xe5+ , 0x86, 0x8a, 0xe7, 0x94, 0xb1, 0xe5, 0x85, 0xb6, 0xe4, 0xbb, 0x96, 0xe4, 0xbd, 0x9c, 0xe5, 0xae+ , 0xb6, 0xe5, 0x9c, 0xa8, 0xe4, 0xbb, 0x96, 0xe6, 0xad, 0xbb, 0xe5, 0xbe, 0x8c, 0xe7, 0xba, 0x8c+ , 0xe5, 0xaf, 0xab, 0xe3, 0x80, 0x82, 0xe3, 0x80, 0x8c, 0xe5, 0x9f, 0xba, 0xe5, 0x9c, 0xb0, 0xe7+ , 0xb3, 0xbb, 0xe5, 0x88, 0x97, 0xe3, 0x80, 0x8d, 0xe5, 0x82, 0x99, 0xe5, 0x8f, 0x97, 0xe8, 0xae+ , 0x9a, 0xe8, 0xad, 0xbd, 0xef, 0xbc, 0x8c, 0x31, 0x39, 0x36, 0x35, 0xe5, 0xb9, 0xb4, 0xe5, 0xbe+ , 0x97, 0xe9, 0x81, 0x8e, 0xe9, 0x9b, 0xa8, 0xe6, 0x9e, 0x9c, 0xe7, 0x8d, 0x8e, 0xe3, 0x80, 0x8c+ , 0xe5, 0x8f, 0xb2, 0xe4, 0xb8, 0x8a, 0xe6, 0x9c, 0x80, 0xe4, 0xbd, 0xb3, 0xe7, 0xa7, 0x91, 0xe5+ , 0xb9, 0xbb, 0xe5, 0xb0, 0x8f, 0xe8, 0xaa, 0xaa, 0xe7, 0xb3, 0xbb, 0xe5, 0x88, 0x97, 0xe3, 0x80+ , 0x8d, 0xe3, 0x80, 0x82, 0x0a, 0x0a, 0xe3, 0x80, 0x8a, 0xe5, 0x9f, 0xba, 0xe5, 0x9c, 0xb0, 0xe3+ , 0x80, 0x8b, 0xe5, 0x8e, 0x9f, 0xe6, 0x9c, 0xac, 0xe6, 0x98, 0xaf, 0xe4, 0xb8, 0x80, 0xe7, 0xb3+ , 0xbb, 0xe5, 0x88, 0x97, 0x38, 0xe7, 0xaf, 0x87, 0xe7, 0x9a, 0x84, 0xe7, 0x9f, 0xad, 0xe7, 0xaf+ , 0x87, 0xe5, 0xb0, 0x8f, 0xe8, 0xaa, 0xaa, 0xef, 0xbc, 0x8c, 0xe5, 0x9c, 0xa8, 0x31, 0x39, 0x34+ , 0x32, 0xe5, 0xb9, 0xb4, 0x35, 0xe6, 0x9c, 0x88, 0xe5, 0x88, 0xb0, 0x31, 0x39, 0x35, 0x30, 0xe5+ , 0xb9, 0xb4, 0x31, 0xe6, 0x9c, 0x88, 0xe6, 0x9c, 0x9f, 0xe9, 0x96, 0x93, 0xe7, 0x99, 0xbc, 0xe8+ , 0xa1, 0xa8, 0xe6, 0x96, 0xbc, 0xe3, 0x80, 0x8a, 0xe9, 0xa9, 0x9a, 0xe5, 0xa5, 0x87, 0xe9, 0x9b+ , 0x9c, 0xe8, 0xaa, 0x8c, 0xe3, 0x80, 0x8b, 0xef, 0xbc, 0x88, 0x41, 0x73, 0x74, 0x6f, 0x75, 0x6e+ , 0x64, 0x69, 0x6e, 0x67, 0x20, 0x4d, 0x61, 0x67, 0x61, 0x7a, 0x69, 0x6e, 0x65, 0xef, 0xbc, 0x89+ , 0xe3, 0x80, 0x82, 0xe8, 0x89, 0xbe, 0xe8, 0xa5, 0xbf, 0xe8, 0x8e, 0xab, 0xe5, 0xa4, 0xab, 0xe5+ , 0x9c, 0xa8, 0xe8, 0x87, 0xaa, 0xe5, 0x82, 0xb3, 0xe4, 0xb8, 0xad, 0xe8, 0xa1, 0xa8, 0xe7, 0xa4+ , 0xba, 0xef, 0xbc, 0x8c, 0xe3, 0x80, 0x8a, 0xe5, 0x9f, 0xba, 0xe5, 0x9c, 0xb0, 0xe3, 0x80, 0x8b+ , 0xe6, 0x98, 0xaf, 0xe5, 0x9c, 0xa8, 0xe4, 0xbb, 0x96, 0xe6, 0x8b, 0x9c, 0xe8, 0xa8, 0xaa, 0xe7+ , 0xb7, 0xa8, 0xe8, 0xbc, 0xaf, 0xe7, 0xb4, 0x84, 0xe7, 0xbf, 0xb0, 0xc2, 0xb7, 0xe5, 0x9d, 0x8e+ , 0xe8, 0xb2, 0x9d, 0xe7, 0x88, 0xbe, 0xef, 0xbc, 0x88, 0x4a, 0x6f, 0x68, 0x6e, 0x20, 0x57, 0x2e+ , 0x20, 0x43, 0x61, 0x6d, 0x70, 0x62, 0x65, 0x6c, 0x6c, 0xef, 0xbc, 0x89, 0xe7, 0x9a, 0x84, 0xe8+ , 0xb7, 0xaf, 0xe4, 0xb8, 0x8a, 0xef, 0xbc, 0x8c, 0xe5, 0xa4, 0xa9, 0xe9, 0xa6, 0xac, 0xe8, 0xa1+ , 0x8c, 0xe7, 0xa9, 0xba, 0xe8, 0x81, 0xaf, 0xe6, 0x83, 0xb3, 0xe8, 0x87, 0xaa, 0xe6, 0x84, 0x9b+ , 0xe5, 0xbe, 0xb7, 0xe8, 0x8f, 0xaf, 0xc2, 0xb7, 0xe5, 0x90, 0x89, 0xe6, 0x9c, 0xac, 0xe7, 0x9a+ , 0x84, 0xe3, 0x80, 0x8a, 0xe7, 0xbe, 0x85, 0xe9, 0xa6, 0xac, 0xe5, 0xb8, 0x9d, 0xe5, 0x9c, 0x8b+ , 0xe8, 0xa1, 0xb0, 0xe4, 0xba, 0xa1, 0xe5, 0x8f, 0xb2, 0xe3, 0x80, 0x8b, 0xef, 0xbc, 0x8c, 0xe4+ , 0xb9, 0x8b, 0xe5, 0xbe, 0x8c, 0xe8, 0x88, 0x87, 0xe5, 0x9d, 0x8e, 0xe8, 0xb2, 0x9d, 0xe7, 0x88+ , 0xbe, 0xe5, 0x85, 0xa9, 0xe7, 0x9b, 0xb8, 0xe8, 0xa8, 0x8e, 0xe8, 0xab, 0x96, 0xe4, 0xb8, 0x8b+ , 0xef, 0xbc, 0x8c, 0xe6, 0x95, 0xb4, 0xe9, 0xab, 0x94, 0xe6, 0xa6, 0x82, 0xe5, 0xbf, 0xb5, 0xe9+ , 0x81, 0x82, 0xe8, 0x80, 0x8c, 0xe6, 0x88, 0x90, 0xe5, 0xbd, 0xa2, 0x5b, 0x31, 0x5d, 0xe3, 0x80+ , 0x82, 0x0a, 0x0a, 0xe3, 0x80, 0x8c, 0xe5, 0x9f, 0xba, 0xe5, 0x9c, 0xb0, 0xe7, 0xb3, 0xbb, 0xe5+ , 0x88, 0x97, 0xe3, 0x80, 0x8d, 0xe7, 0xac, 0xac, 0xe4, 0xb8, 0x80, 0xe9, 0x83, 0xa8, 0xe3, 0x80+ , 0x8a, 0xe5, 0x9f, 0xba, 0xe5, 0x9c, 0xb0, 0xe3, 0x80, 0x8b, 0xe5, 0x8c, 0x85, 0xe5, 0x90, 0xab+ , 0x34, 0xe7, 0xaf, 0x87, 0xe7, 0x9f, 0xad, 0xe7, 0xaf, 0x87, 0xe5, 0xb0, 0x8f, 0xe8, 0xaa, 0xaa+ , 0xef, 0xbc, 0x8c, 0xe5, 0x8a, 0x87, 0xe6, 0x83, 0x85, 0xe5, 0x90, 0x84, 0xe8, 0x87, 0xaa, 0xe7+ , 0x8d, 0xa8, 0xe7, 0xab, 0x8b, 0xef, 0xbc, 0x8c, 0xe5, 0x96, 0xae, 0xe8, 0xa1, 0x8c, 0xe6, 0x9c+ , 0xac, 0xe7, 0x99, 0xbc, 0xe8, 0xa1, 0x8c, 0xe6, 0x96, 0xbc, 0x31, 0x39, 0x35, 0x31, 0xe5, 0xb9+ , 0xb4, 0xe3, 0x80, 0x82, 0xe5, 0x85, 0xb6, 0xe5, 0xae, 0x83, 0x34, 0xe7, 0xaf, 0x87, 0xe4, 0xb8+ , 0xad, 0xe7, 0xaf, 0x87, 0xe5, 0xb0, 0x8f, 0xe8, 0xaa, 0xaa, 0xe5, 0x85, 0xa9, 0xe5, 0x85, 0xa9+ , 0xe7, 0x9b, 0xb8, 0xe5, 0xb0, 0x8d, 0xef, 0xbc, 0x8c, 0xe5, 0x88, 0x86, 0xe5, 0x88, 0xa5, 0xe6+ , 0x94, 0xb6, 0xe9, 0x8c, 0x84, 0xe5, 0x9c, 0xa8, 0xe3, 0x80, 0x8a, 0xe5, 0x9f, 0xba, 0xe5, 0x9c+ , 0xb0, 0xe8, 0x88, 0x87, 0xe5, 0xb8, 0x9d, 0xe5, 0x9c, 0x8b, 0xe3, 0x80, 0x8b, 0xe5, 0x92, 0x8c+ , 0xe3, 0x80, 0x8a, 0xe7, 0xac, 0xac, 0xe4, 0xba, 0x8c, 0xe5, 0x9f, 0xba, 0xe5, 0x9c, 0xb0, 0xe3+ , 0x80, 0x8b, 0xef, 0xbc, 0x8c, 0xe6, 0x88, 0x90, 0xe7, 0x82, 0xba, 0xe5, 0x90, 0x8d, 0xe8, 0x81+ , 0x9e, 0xe9, 0x81, 0x90, 0xe9, 0x82, 0x87, 0xe7, 0x9a, 0x84, 0xe3, 0x80, 0x8c, 0xe5, 0x9f, 0xba+ , 0xe5, 0x9c, 0xb0, 0xe4, 0xb8, 0x89, 0xe9, 0x83, 0xa8, 0xe6, 0x9b, 0xb2, 0xe3, 0x80, 0x8d, 0xe3+ , 0x80, 0x82, 0x31, 0x39, 0x38, 0x31, 0xe5, 0xb9, 0xb4, 0xef, 0xbc, 0x8c, 0xe3, 0x80, 0x8c, 0xe5+ , 0x9f, 0xba, 0xe5, 0x9c, 0xb0, 0xe4, 0xb8, 0x89, 0xe9, 0x83, 0xa8, 0xe6, 0x9b, 0xb2, 0xe3, 0x80+ , 0x8d, 0xe6, 0x97, 0xa9, 0xe5, 0xb7, 0xb2, 0xe6, 0x98, 0xaf, 0xe4, 0xb8, 0x96, 0xe6, 0x89, 0x80+ , 0xe5, 0x85, 0xac, 0xe8, 0xaa, 0x8d, 0xe6, 0x9c, 0x80, 0xe9, 0x87, 0x8d, 0xe8, 0xa6, 0x81, 0xe7+ , 0x9a, 0x84, 0xe7, 0x8f, 0xbe, 0xe4, 0xbb, 0xa3, 0xe7, 0xa7, 0x91, 0xe5, 0xb9, 0xbb, 0xe4, 0xbd+ , 0x9c, 0xe5, 0x93, 0x81, 0xef, 0xbc, 0x8c, 0xe8, 0x89, 0xbe, 0xe8, 0xa5, 0xbf, 0xe8, 0x8e, 0xab+ , 0xe5, 0xa4, 0xab, 0xe7, 0xb5, 0x82, 0xe6, 0x96, 0xbc, 0xe8, 0xa2, 0xab, 0xe5, 0x87, 0xba, 0xe7+ , 0x89, 0x88, 0xe5, 0x95, 0x86, 0xe8, 0xaa, 0xaa, 0xe6, 0x9c, 0x8d, 0xe7, 0xba, 0x8c, 0xe5, 0xaf+ , 0xab, 0xe3, 0x80, 0x8c, 0xe5, 0x9f, 0xba, 0xe5, 0x9c, 0xb0, 0xe7, 0xb3, 0xbb, 0xe5, 0x88, 0x97+ , 0xe3, 0x80, 0x8d, 0xe7, 0xac, 0xac, 0xe5, 0x9b, 0x9b, 0xe9, 0x83, 0xa8, 0xe3, 0x80, 0x8a, 0xe5+ , 0x9f, 0xba, 0xe5, 0x9c, 0xb0, 0xe9, 0x82, 0x8a, 0xe7, 0xb7, 0xa3, 0xe3, 0x80, 0x8b, 0x5b, 0x32+ , 0x5d, 0xe3, 0x80, 0x82, 0xe6, 0x8e, 0xa5, 0xe4, 0xb8, 0x8b, 0xe4, 0xbe, 0x86, 0xe4, 0xbb, 0x96+ , 0xe5, 0x8f, 0x88, 0xe5, 0xaf, 0xab, 0xe4, 0xba, 0x86, 0xe4, 0xb8, 0x80, 0xe9, 0x83, 0xa8, 0xe7+ , 0xba, 0x8c, 0xe9, 0x9b, 0x86, 0xe3, 0x80, 0x8a, 0xe5, 0x9f, 0xba, 0xe5, 0x9c, 0xb0, 0xe8, 0x88+ , 0x87, 0xe5, 0x9c, 0xb0, 0xe7, 0x90, 0x83, 0xe3, 0x80, 0x8b, 0xef, 0xbc, 0x8c, 0x35, 0xe5, 0xb9+ , 0xb4, 0xe5, 0xbe, 0x8c, 0xe7, 0x99, 0xbc, 0xe8, 0xa1, 0xa8, 0xe5, 0x85, 0xa9, 0xe9, 0x83, 0xa8+ , 0xe5, 0x89, 0x8d, 0xe5, 0x82, 0xb3, 0xe3, 0x80, 0x8a, 0xe5, 0x9f, 0xba, 0xe5, 0x9c, 0xb0, 0xe5+ , 0x89, 0x8d, 0xe5, 0xa5, 0x8f, 0xe3, 0x80, 0x8b, 0xe5, 0x92, 0x8c, 0xe3, 0x80, 0x8a, 0xe5, 0x9f+ , 0xba, 0xe5, 0x9c, 0xb0, 0xe7, 0xb7, 0xa0, 0xe9, 0x80, 0xa0, 0xe8, 0x80, 0x85, 0xe3, 0x80, 0x8b+ , 0xef, 0xbc, 0x8c, 0xe5, 0x9c, 0xa8, 0xe9, 0x80, 0x99, 0xe5, 0xb9, 0xbe, 0xe5, 0xb9, 0xb4, 0xe4+ , 0xb8, 0xad, 0xef, 0xbc, 0x8c, 0xe8, 0x89, 0xbe, 0xe8, 0xa5, 0xbf, 0xe8, 0x8e, 0xab, 0xe5, 0xa4+ , 0xab, 0xe5, 0xb0, 0x87, 0xe3, 0x80, 0x8c, 0xe5, 0x9f, 0xba, 0xe5, 0x9c, 0xb0, 0xe7, 0xb3, 0xbb+ , 0xe5, 0x88, 0x97, 0xe3, 0x80, 0x8d, 0xe8, 0x88, 0x87, 0xe5, 0x85, 0xb6, 0xe5, 0xae, 0x83, 0xe7+ , 0xb3, 0xbb, 0xe5, 0x88, 0x97, 0xe7, 0x9b, 0xb8, 0xe7, 0xb5, 0x90, 0xe5, 0x90, 0x88, 0xef, 0xbc+ , 0x8c, 0xe5, 0xb0, 0x87, 0xe6, 0x89, 0x80, 0xe6, 0x9c, 0x89, 0xe7, 0xb3, 0xbb, 0xe5, 0x88, 0x97+ , 0xe4, 0xbd, 0x9c, 0xe5, 0x93, 0x81, 0xe5, 0x90, 0x8c, 0xe7, 0xbd, 0xae, 0xe6, 0x96, 0xbc, 0xe4+ , 0xb8, 0x80, 0xe5, 0x80, 0x8b, 0xe3, 0x80, 0x8c, 0xe5, 0x9f, 0xba, 0xe5, 0x9c, 0xb0, 0xe5, 0xae+ , 0x87, 0xe5, 0xae, 0x99, 0xe3, 0x80, 0x8d, 0xe6, 0x9e, 0xb6, 0xe6, 0xa7, 0x8b, 0xe4, 0xb8, 0x8b+ , 0xe3, 0x80, 0x82, 0x0a, 0x0a, 0xe8, 0x89, 0xbe, 0xe8, 0xa5, 0xbf, 0xe8, 0x8e, 0xab, 0xe5, 0xa4+ , 0xab, 0xe5, 0x92, 0x8c, 0xe5, 0x9d, 0x8e, 0xe8, 0xb2, 0x9d, 0xe7, 0x88, 0xbe, 0xe8, 0x81, 0xaf+ , 0xe6, 0x89, 0x8b, 0xe7, 0x82, 0xba, 0xe3, 0x80, 0x8c, 0xe5, 0x9f, 0xba, 0xe5, 0x9c, 0xb0, 0xe7+ , 0xb3, 0xbb, 0xe5, 0x88, 0x97, 0xe3, 0x80, 0x8d, 0xe6, 0x89, 0x93, 0xe9, 0x80, 0xa0, 0xe5, 0x87+ , 0xba, 0xe4, 0xb8, 0x80, 0xe9, 0x96, 0x80, 0xe5, 0x85, 0xa8, 0xe6, 0x96, 0xb0, 0xe7, 0x9a, 0x84+ , 0xe7, 0xb5, 0xb1, 0xe8, 0xa8, 0x88, 0xe7, 0xa7, 0x91, 0xe5, 0xad, 0xb8, 0xef, 0xbc, 0x8c, 0xe7+ , 0xa8, 0xb1, 0xe4, 0xb9, 0x8b, 0xe7, 0x82, 0xba, 0xe2, 0x80, 0x9c, 0xe5, 0xbf, 0x83, 0xe7, 0x90+ , 0x86, 0xe5, 0x8f, 0xb2, 0xe5, 0xad, 0xb8, 0xe2, 0x80, 0x9d, 0xef, 0xbc, 0x8c, 0xe9, 0x80, 0x99+ , 0xe9, 0x96, 0x80, 0xe5, 0xad, 0xb8, 0xe5, 0x95, 0x8f, 0xe7, 0x94, 0xb1, 0xe6, 0x9b, 0xb8, 0xe4+ , 0xb8, 0xad, 0xe6, 0x95, 0xb0, 0xe5, 0xad, 0xb8, 0xe5, 0xae, 0xb6, 0xe5, 0x93, 0x88, 0xe9, 0x87+ , 0x8c, 0xc2, 0xb7, 0xe8, 0xac, 0x9d, 0xe9, 0xa0, 0x93, 0xe7, 0xaa, 0xae, 0xe7, 0x9b, 0xa1, 0xe7+ , 0x95, 0xa2, 0xe7, 0x94, 0x9f, 0xe4, 0xb9, 0x8b, 0xe5, 0x8a, 0x9b, 0xe5, 0x89, 0xb5, 0xe5, 0xbb+ , 0xba, 0xef, 0xbc, 0x8c, 0xe6, 0xa0, 0xb9, 0xe6, 0x93, 0x9a, 0xe5, 0xa4, 0xa7, 0xe8, 0xa6, 0x8f+ , 0xe6, 0xa8, 0xa1, 0xe7, 0x9a, 0x84, 0xe4, 0xba, 0xba, 0xe9, 0xa1, 0x9e, 0xe6, 0xb4, 0xbb, 0xe5+ , 0x8b, 0x95, 0xe6, 0x95, 0xb8, 0xe6, 0x93, 0x9a, 0xef, 0xbc, 0x8c, 0xe9, 0xa0, 0x90, 0xe6, 0xb8+ , 0xac, 0xe6, 0x9c, 0xaa, 0xe4, 0xbe, 0x86, 0xe8, 0xb5, 0xb0, 0xe5, 0x90, 0x91, 0xef, 0xbc, 0x8c+ , 0xe8, 0xa6, 0x8f, 0xe6, 0xa8, 0xa1, 0xe4, 0xb8, 0x80, 0xe6, 0x97, 0xa6, 0xe5, 0xb0, 0x8f, 0xe6+ , 0x96, 0xbc, 0xe4, 0xb8, 0x80, 0xe9, 0xa1, 0x86, 0xe6, 0x98, 0x9f, 0xe7, 0x90, 0x83, 0xe6, 0x88+ , 0x96, 0xe6, 0x98, 0xaf, 0xe4, 0xb8, 0x80, 0xe5, 0xba, 0xa7, 0xe5, 0xb8, 0x9d, 0xe5, 0x9c, 0x8b+ , 0xef, 0xbc, 0x8c, 0xe7, 0xb5, 0x90, 0xe6, 0x9e, 0x9c, 0xe5, 0xb0, 0xb1, 0xe6, 0x9c, 0x83, 0xe5+ , 0xa4, 0xb1, 0xe6, 0xba, 0x96, 0xe3, 0x80, 0x82, 0xe8, 0xac, 0x9d, 0xe9, 0xa0, 0x93, 0xe9, 0x81+ , 0x8b, 0xe7, 0x94, 0xa8, 0xe6, 0xad, 0xa4, 0xe4, 0xb8, 0x80, 0xe7, 0xa7, 0x91, 0xe5, 0xad, 0xb8+ , 0xef, 0xbc, 0x8c, 0xe9, 0xa0, 0x90, 0xe8, 0xa6, 0x8b, 0xe9, 0x8a, 0x80, 0xe6, 0xb2, 0xb3, 0xe5+ , 0xb8, 0x9d, 0xe5, 0x9c, 0x8b, 0xe7, 0x9a, 0x84, 0xe6, 0xae, 0x9e, 0xe8, 0x90, 0xbd, 0xef, 0xbc+ , 0x8c, 0xe6, 0x95, 0xb4, 0xe7, 0x89, 0x87, 0xe9, 0x8a, 0x80, 0xe6, 0xb2, 0xb3, 0xe5, 0xb0, 0x87+ , 0xe5, 0x9b, 0xa0, 0xe6, 0xad, 0xa4, 0xe9, 0x80, 0xb2, 0xe5, 0x85, 0xa5, 0xe9, 0x95, 0xb7, 0xe9+ , 0x81, 0x94, 0xe4, 0xb8, 0x89, 0xe8, 0x90, 0xac, 0xe5, 0xb9, 0xb4, 0xe7, 0x9a, 0x84, 0xe9, 0xbb+ , 0x91, 0xe6, 0x9a, 0x97, 0xe6, 0x99, 0x82, 0xe6, 0x9c, 0x9f, 0xef, 0xbc, 0x8c, 0xe7, 0x9b, 0xb4+ , 0xe5, 0x88, 0xb0, 0xe7, 0xac, 0xac, 0xe4, 0xba, 0x8c, 0xe5, 0xb8, 0x9d, 0xe5, 0x9c, 0x8b, 0xe5+ , 0xbb, 0xba, 0xe7, 0xab, 0x8b, 0xe3, 0x80, 0x82, 0x0a, 0x0a, 0xe6, 0x96, 0xbc, 0xe6, 0x98, 0xaf+ , 0xe8, 0xac, 0x9d, 0xe9, 0xa0, 0x93, 0xe5, 0xbb, 0xba, 0xe7, 0xab, 0x8b, 0xe5, 0x85, 0xa9, 0xe5+ , 0xba, 0xa7, 0xe5, 0x9f, 0xba, 0xe5, 0x9c, 0xb0, 0xef, 0xbc, 0x8c, 0xe8, 0x97, 0x89, 0xe4, 0xbb+ , 0xa5, 0xe7, 0xb8, 0xae, 0xe6, 0xb8, 0x9b, 0xe8, 0xa0, 0xbb, 0xe8, 0x8d, 0x92, 0xe6, 0x99, 0x82+ , 0xe6, 0x9c, 0x9f, 0xef, 0xbc, 0x8c, 0xe4, 0xb8, 0x80, 0xe5, 0xba, 0xa7, 0xe9, 0x81, 0xa0, 0xe5+ , 0x9c, 0xa8, 0xe9, 0x82, 0x8a, 0xe9, 0x99, 0xb2, 0xef, 0xbc, 0x8c, 0xe6, 0x98, 0xaf, 0xe8, 0x97+ , 0x9d, 0xe8, 0xa1, 0x93, 0xe8, 0x88, 0x87, 0xe7, 0xa7, 0x91, 0xe5, 0xad, 0xb8, 0xe7, 0x9a, 0x84+ , 0xe9, 0x81, 0xbf, 0xe9, 0xa2, 0xa8, 0xe6, 0xb8, 0xaf, 0xef, 0xbc, 0x8c, 0xe7, 0x9b, 0xb8, 0xe5+ , 0xb0, 0x8d, 0xe7, 0x9a, 0x84, 0xe5, 0x8f, 0xa6, 0xe4, 0xb8, 0x80, 0xe5, 0xba, 0xa7, 0xe5, 0x89+ , 0x87, 0xe5, 0x9c, 0xa8, 0xe2, 0x80, 0x9c, 0xe7, 0xbe, 0xa4, 0xe6, 0x98, 0x9f, 0xe7, 0x9a, 0x84+ , 0xe7, 0x9b, 0xa1, 0xe9, 0xa0, 0xad, 0xe2, 0x80, 0x9d, 0xe3, 0x80, 0x82, 0xe3, 0x80, 0x8c, 0xe5+ , 0x9f, 0xba, 0xe5, 0x9c, 0xb0, 0xe4, 0xb8, 0x89, 0xe9, 0x83, 0xa8, 0xe6, 0x9b, 0xb2, 0xe3, 0x80+ , 0x8d, 0xe7, 0x9a, 0x84, 0xe4, 0xb8, 0xbb, 0xe8, 0xa6, 0x81, 0xe7, 0x84, 0xa6, 0xe9, 0xbb, 0x9e+ , 0xe5, 0xb0, 0xb1, 0xe5, 0x9c, 0xa8, 0xe7, 0xab, 0xaf, 0xe9, 0xbb, 0x9e, 0xe6, 0x98, 0x9f, 0xe4+ , 0xb8, 0x8a, 0xe7, 0x9a, 0x84, 0xe5, 0x9f, 0xba, 0xe5, 0x9c, 0xb0, 0xe3, 0x80, 0x82, 0xe7, 0xab+ , 0xaf, 0xe9, 0xbb, 0x9e, 0xe6, 0x98, 0x9f, 0xe4, 0xb8, 0x8a, 0xe7, 0x9a, 0x84, 0xe5, 0xad, 0xb8+ , 0xe8, 0x80, 0x85, 0xe7, 0x82, 0xba, 0xe4, 0xba, 0x86, 0xe6, 0x90, 0xb6, 0xe5, 0x9c, 0xa8, 0xe8+ , 0xa1, 0xb0, 0xe9, 0x80, 0x80, 0xe6, 0x9c, 0x9f, 0xe4, 0xb9, 0x8b, 0xe5, 0x89, 0x8d, 0xef, 0xbc+ , 0x8c, 0xe4, 0xbf, 0x9d, 0xe5, 0xad, 0x98, 0xe4, 0xba, 0xba, 0xe9, 0xa1, 0x9e, 0xe7, 0x89, 0xa9+ , 0xe7, 0x90, 0x86, 0xe7, 0xa7, 0x91, 0xe5, 0xad, 0xb8, 0xe7, 0x9a, 0x84, 0xe7, 0x9f, 0xa5, 0xe8+ , 0xad, 0x98, 0xef, 0xbc, 0x8c, 0xe5, 0x8a, 0xaa, 0xe5, 0x8a, 0x9b, 0xe7, 0xb7, 0xa8, 0xe8, 0xbc+ , 0xaf, 0xe8, 0x91, 0x97, 0xe4, 0xb8, 0x80, 0xe9, 0x83, 0xa8, 0xe5, 0x85, 0xa8, 0xe6, 0x96, 0xb9+ , 0xe4, 0xbd, 0x8d, 0xe7, 0x9a, 0x84, 0xe3, 0x80, 0x8a, 0xe9, 0x93, 0xb6, 0xe6, 0xb2, 0xb3, 0xe7+ , 0x99, 0xbe, 0xe7, 0xa7, 0x91, 0xe5, 0x85, 0xa8, 0xe4, 0xb9, 0xa6, 0xe3, 0x80, 0x8b, 0xef, 0xbc+ , 0x8c, 0xe5, 0xb0, 0x8d, 0xe8, 0xac, 0x9d, 0xe9, 0xa0, 0x93, 0xe7, 0x9c, 0x9f, 0xe6, 0xad, 0xa3+ , 0xe7, 0x9a, 0x84, 0xe6, 0x84, 0x8f, 0xe5, 0x9c, 0x96, 0xe6, 0xaf, 0xab, 0xe4, 0xb8, 0x8d, 0xe7+ , 0x9f, 0xa5, 0xe6, 0x83, 0x85, 0xef, 0xbc, 0x88, 0xe5, 0xa6, 0x82, 0xe6, 0x9e, 0x9c, 0xe4, 0xbb+ , 0x96, 0xe5, 0x80, 0x91, 0xe7, 0x9f, 0xa5, 0xe9, 0x81, 0x93, 0xef, 0xbc, 0x8c, 0xe5, 0xb0, 0xb1+ , 0xe6, 0x9c, 0x83, 0xe7, 0x94, 0xa2, 0xe7, 0x94, 0x9f, 0xe7, 0x84, 0xa1, 0xe6, 0xb3, 0x95, 0xe6+ , 0x8e, 0xa7, 0xe5, 0x88, 0xb6, 0xe7, 0x9a, 0x84, 0xe8, 0xae, 0x8a, 0xe6, 0x95, 0xb8, 0xef, 0xbc+ , 0x89, 0xe3, 0x80, 0x82, 0xe5, 0x9f, 0xba, 0xe5, 0x9c, 0xb0, 0xe7, 0x9a, 0x84, 0xe4, 0xbd, 0x8d+ , 0xe7, 0xbd, 0xae, 0xe4, 0xb9, 0x9f, 0xe6, 0x98, 0xaf, 0xe5, 0x88, 0xbb, 0xe6, 0x84, 0x8f, 0xe9+ , 0x81, 0xb8, 0xe5, 0xae, 0x9a, 0xe7, 0x9a, 0x84, 0xef, 0xbc, 0x8c, 0xe5, 0x8d, 0x83, 0xe5, 0xb9+ , 0xb4, 0xe5, 0xbe, 0x8c, 0xe5, 0xb0, 0xb1, 0xe6, 0x98, 0xaf, 0xe7, 0xac, 0xac, 0xe4, 0xba, 0x8c+ , 0xe5, 0xb8, 0x9d, 0xe5, 0x9c, 0x8b, 0xe7, 0x9a, 0x84, 0xe9, 0xa6, 0x96, 0xe9, 0x83, 0xbd, 0xef+ , 0xbc, 0x88, 0xe4, 0xb8, 0xa6, 0xe9, 0x9d, 0x9e, 0xe4, 0xb8, 0x89, 0xe8, 0x90, 0xac, 0xe5, 0xb9+ , 0xb4, 0xe5, 0xbe, 0x8c, 0xe7, 0x9a, 0x84, 0xe9, 0x82, 0xa3, 0xe5, 0x80, 0x8b, 0xe5, 0xb8, 0x9d+ , 0xe5, 0x9c, 0x8b, 0xef, 0xbc, 0x89, 0x0a+ ]++++sample2_UTF16 :: EncodedString+sample2_UTF16 = EncodedString UTF16 $ recast array+ where+ array :: UArray Word16+ array = fromList+ [ 0x0054, 0x0068, 0x0065, 0x0020, 0x0073, 0x0061, 0x006d, 0x0070+ , 0x006c, 0x0065, 0x0020, 0x0074, 0x0065, 0x0078, 0x0074, 0x0020+ , 0x0062, 0x0065, 0x006c, 0x006f, 0x0077, 0x0020, 0x0068, 0x0061+ , 0x0073, 0x0020, 0x0062, 0x0065, 0x0065, 0x006e, 0x0020, 0x0074+ , 0x0061, 0x006b, 0x0065, 0x006e, 0x0020, 0x0066, 0x0072, 0x006f+ , 0x006d, 0x0020, 0x0057, 0x0069, 0x006b, 0x0069, 0x0070, 0x0065+ , 0x0064, 0x0069, 0x0061, 0x003a, 0x000a, 0x0068, 0x0074, 0x0074+ , 0x0070, 0x0073, 0x003a, 0x002f, 0x002f, 0x007a, 0x0068, 0x002e+ , 0x0077, 0x0069, 0x006b, 0x0069, 0x0070, 0x0065, 0x0064, 0x0069+ , 0x0061, 0x002e, 0x006f, 0x0072, 0x0067, 0x002f, 0x0077, 0x0069+ , 0x006b, 0x0069, 0x002f, 0x0025, 0x0045, 0x0035, 0x0025, 0x0039+ , 0x0046, 0x0025, 0x0042, 0x0041, 0x0025, 0x0045, 0x0035, 0x0025+ , 0x0039, 0x0043, 0x0025, 0x0042, 0x0030, 0x0025, 0x0045, 0x0037+ , 0x0025, 0x0042, 0x0033, 0x0025, 0x0042, 0x0042, 0x0025, 0x0045+ , 0x0035, 0x0025, 0x0038, 0x0038, 0x0025, 0x0039, 0x0037, 0x000a+ , 0x000a, 0x57fa, 0x5730, 0x7cfb, 0x5217, 0xff08, 0x0054, 0x0068+ , 0x0065, 0x0020, 0x0046, 0x006f, 0x0075, 0x006e, 0x0064, 0x0061+ , 0x0074, 0x0069, 0x006f, 0x006e, 0x0020, 0x0053, 0x0065, 0x0072+ , 0x0069, 0x0065, 0x0073, 0xff09, 0x662f, 0x4e00, 0x90e8, 0x7d93+ , 0x5178, 0x79d1, 0x5e7b, 0x5c0f, 0x8aaa, 0x7cfb, 0x5217, 0xff0c+ , 0x5275, 0x4f5c, 0x6642, 0x9593, 0x6a6b, 0x8de8, 0x7f8e, 0x570b+ , 0x4f5c, 0x5bb6, 0x4ee5, 0x6492, 0x00b7, 0x827e, 0x897f, 0x83ab+ , 0x592b, 0x0034, 0x0039, 0x500b, 0x5beb, 0x4f5c, 0x5e74, 0x982d+ , 0xff0c, 0x4e00, 0x5171, 0x0031, 0x0030, 0x518a, 0xff08, 0x5305+ , 0x62ec, 0x5225, 0x4eba, 0x7e8c, 0x5beb, 0x0033, 0x518a, 0xff09+ , 0xff0c, 0x5f7c, 0x6b64, 0x9593, 0x5287, 0x60c5, 0x7368, 0x7acb+ , 0xff0c, 0x537b, 0x53c8, 0x7dca, 0x5bc6, 0x95dc, 0x806f, 0x3002+ , 0x300c, 0x57fa, 0x5730, 0x7cfb, 0x5217, 0x300d, 0x901a, 0x5e38+ , 0x4e5f, 0x5c07, 0x8655, 0x5728, 0x540c, 0x4e00, 0x67b6, 0x7a7a+ , 0x5b87, 0x5b99, 0x7684, 0x300c, 0x6a5f, 0x5668, 0x4eba, 0x7cfb+ , 0x5217, 0x300d, 0x548c, 0x300c, 0x9280, 0x6cb3, 0x5e1d, 0x570b+ , 0x7cfb, 0x5217, 0x300d, 0x5305, 0x62ec, 0x9032, 0x4f86, 0xff0c+ , 0x7e3d, 0x8a08, 0x8d77, 0x4f86, 0x6574, 0x500b, 0x300c, 0x5927+ , 0x57fa, 0x5730, 0x7cfb, 0x5217, 0x300d, 0x4f5c, 0x54c1, 0x5171+ , 0x6709, 0x0031, 0x0034, 0x518a, 0x9577, 0x7bc7, 0xff0c, 0x548c+ , 0x6578, 0x4e0d, 0x6e05, 0x7684, 0x77ed, 0x7bc7, 0x5c0f, 0x8aaa+ , 0xff0c, 0x53e6, 0x5916, 0x0036, 0x518a, 0x7531, 0x5176, 0x4ed6+ , 0x4f5c, 0x5bb6, 0x5728, 0x4ed6, 0x6b7b, 0x5f8c, 0x7e8c, 0x5beb+ , 0x3002, 0x300c, 0x57fa, 0x5730, 0x7cfb, 0x5217, 0x300d, 0x5099+ , 0x53d7, 0x8b9a, 0x8b7d, 0xff0c, 0x0031, 0x0039, 0x0036, 0x0035+ , 0x5e74, 0x5f97, 0x904e, 0x96e8, 0x679c, 0x734e, 0x300c, 0x53f2+ , 0x4e0a, 0x6700, 0x4f73, 0x79d1, 0x5e7b, 0x5c0f, 0x8aaa, 0x7cfb+ , 0x5217, 0x300d, 0x3002, 0x000a, 0x000a, 0x300a, 0x57fa, 0x5730+ , 0x300b, 0x539f, 0x672c, 0x662f, 0x4e00, 0x7cfb, 0x5217, 0x0038+ , 0x7bc7, 0x7684, 0x77ed, 0x7bc7, 0x5c0f, 0x8aaa, 0xff0c, 0x5728+ , 0x0031, 0x0039, 0x0034, 0x0032, 0x5e74, 0x0035, 0x6708, 0x5230+ , 0x0031, 0x0039, 0x0035, 0x0030, 0x5e74, 0x0031, 0x6708, 0x671f+ , 0x9593, 0x767c, 0x8868, 0x65bc, 0x300a, 0x9a5a, 0x5947, 0x96dc+ , 0x8a8c, 0x300b, 0xff08, 0x0041, 0x0073, 0x0074, 0x006f, 0x0075+ , 0x006e, 0x0064, 0x0069, 0x006e, 0x0067, 0x0020, 0x004d, 0x0061+ , 0x0067, 0x0061, 0x007a, 0x0069, 0x006e, 0x0065, 0xff09, 0x3002+ , 0x827e, 0x897f, 0x83ab, 0x592b, 0x5728, 0x81ea, 0x50b3, 0x4e2d+ , 0x8868, 0x793a, 0xff0c, 0x300a, 0x57fa, 0x5730, 0x300b, 0x662f+ , 0x5728, 0x4ed6, 0x62dc, 0x8a2a, 0x7de8, 0x8f2f, 0x7d04, 0x7ff0+ , 0x00b7, 0x574e, 0x8c9d, 0x723e, 0xff08, 0x004a, 0x006f, 0x0068+ , 0x006e, 0x0020, 0x0057, 0x002e, 0x0020, 0x0043, 0x0061, 0x006d+ , 0x0070, 0x0062, 0x0065, 0x006c, 0x006c, 0xff09, 0x7684, 0x8def+ , 0x4e0a, 0xff0c, 0x5929, 0x99ac, 0x884c, 0x7a7a, 0x806f, 0x60f3+ , 0x81ea, 0x611b, 0x5fb7, 0x83ef, 0x00b7, 0x5409, 0x672c, 0x7684+ , 0x300a, 0x7f85, 0x99ac, 0x5e1d, 0x570b, 0x8870, 0x4ea1, 0x53f2+ , 0x300b, 0xff0c, 0x4e4b, 0x5f8c, 0x8207, 0x574e, 0x8c9d, 0x723e+ , 0x5169, 0x76f8, 0x8a0e, 0x8ad6, 0x4e0b, 0xff0c, 0x6574, 0x9ad4+ , 0x6982, 0x5ff5, 0x9042, 0x800c, 0x6210, 0x5f62, 0x005b, 0x0031+ , 0x005d, 0x3002, 0x000a, 0x000a, 0x300c, 0x57fa, 0x5730, 0x7cfb+ , 0x5217, 0x300d, 0x7b2c, 0x4e00, 0x90e8, 0x300a, 0x57fa, 0x5730+ , 0x300b, 0x5305, 0x542b, 0x0034, 0x7bc7, 0x77ed, 0x7bc7, 0x5c0f+ , 0x8aaa, 0xff0c, 0x5287, 0x60c5, 0x5404, 0x81ea, 0x7368, 0x7acb+ , 0xff0c, 0x55ae, 0x884c, 0x672c, 0x767c, 0x884c, 0x65bc, 0x0031+ , 0x0039, 0x0035, 0x0031, 0x5e74, 0x3002, 0x5176, 0x5b83, 0x0034+ , 0x7bc7, 0x4e2d, 0x7bc7, 0x5c0f, 0x8aaa, 0x5169, 0x5169, 0x76f8+ , 0x5c0d, 0xff0c, 0x5206, 0x5225, 0x6536, 0x9304, 0x5728, 0x300a+ , 0x57fa, 0x5730, 0x8207, 0x5e1d, 0x570b, 0x300b, 0x548c, 0x300a+ , 0x7b2c, 0x4e8c, 0x57fa, 0x5730, 0x300b, 0xff0c, 0x6210, 0x70ba+ , 0x540d, 0x805e, 0x9050, 0x9087, 0x7684, 0x300c, 0x57fa, 0x5730+ , 0x4e09, 0x90e8, 0x66f2, 0x300d, 0x3002, 0x0031, 0x0039, 0x0038+ , 0x0031, 0x5e74, 0xff0c, 0x300c, 0x57fa, 0x5730, 0x4e09, 0x90e8+ , 0x66f2, 0x300d, 0x65e9, 0x5df2, 0x662f, 0x4e16, 0x6240, 0x516c+ , 0x8a8d, 0x6700, 0x91cd, 0x8981, 0x7684, 0x73fe, 0x4ee3, 0x79d1+ , 0x5e7b, 0x4f5c, 0x54c1, 0xff0c, 0x827e, 0x897f, 0x83ab, 0x592b+ , 0x7d42, 0x65bc, 0x88ab, 0x51fa, 0x7248, 0x5546, 0x8aaa, 0x670d+ , 0x7e8c, 0x5beb, 0x300c, 0x57fa, 0x5730, 0x7cfb, 0x5217, 0x300d+ , 0x7b2c, 0x56db, 0x90e8, 0x300a, 0x57fa, 0x5730, 0x908a, 0x7de3+ , 0x300b, 0x005b, 0x0032, 0x005d, 0x3002, 0x63a5, 0x4e0b, 0x4f86+ , 0x4ed6, 0x53c8, 0x5beb, 0x4e86, 0x4e00, 0x90e8, 0x7e8c, 0x96c6+ , 0x300a, 0x57fa, 0x5730, 0x8207, 0x5730, 0x7403, 0x300b, 0xff0c+ , 0x0035, 0x5e74, 0x5f8c, 0x767c, 0x8868, 0x5169, 0x90e8, 0x524d+ , 0x50b3, 0x300a, 0x57fa, 0x5730, 0x524d, 0x594f, 0x300b, 0x548c+ , 0x300a, 0x57fa, 0x5730, 0x7de0, 0x9020, 0x8005, 0x300b, 0xff0c+ , 0x5728, 0x9019, 0x5e7e, 0x5e74, 0x4e2d, 0xff0c, 0x827e, 0x897f+ , 0x83ab, 0x592b, 0x5c07, 0x300c, 0x57fa, 0x5730, 0x7cfb, 0x5217+ , 0x300d, 0x8207, 0x5176, 0x5b83, 0x7cfb, 0x5217, 0x76f8, 0x7d50+ , 0x5408, 0xff0c, 0x5c07, 0x6240, 0x6709, 0x7cfb, 0x5217, 0x4f5c+ , 0x54c1, 0x540c, 0x7f6e, 0x65bc, 0x4e00, 0x500b, 0x300c, 0x57fa+ , 0x5730, 0x5b87, 0x5b99, 0x300d, 0x67b6, 0x69cb, 0x4e0b, 0x3002+ , 0x000a, 0x000a, 0x827e, 0x897f, 0x83ab, 0x592b, 0x548c, 0x574e+ , 0x8c9d, 0x723e, 0x806f, 0x624b, 0x70ba, 0x300c, 0x57fa, 0x5730+ , 0x7cfb, 0x5217, 0x300d, 0x6253, 0x9020, 0x51fa, 0x4e00, 0x9580+ , 0x5168, 0x65b0, 0x7684, 0x7d71, 0x8a08, 0x79d1, 0x5b78, 0xff0c+ , 0x7a31, 0x4e4b, 0x70ba, 0x201c, 0x5fc3, 0x7406, 0x53f2, 0x5b78+ , 0x201d, 0xff0c, 0x9019, 0x9580, 0x5b78, 0x554f, 0x7531, 0x66f8+ , 0x4e2d, 0x6570, 0x5b78, 0x5bb6, 0x54c8, 0x91cc, 0x00b7, 0x8b1d+ , 0x9813, 0x7aae, 0x76e1, 0x7562, 0x751f, 0x4e4b, 0x529b, 0x5275+ , 0x5efa, 0xff0c, 0x6839, 0x64da, 0x5927, 0x898f, 0x6a21, 0x7684+ , 0x4eba, 0x985e, 0x6d3b, 0x52d5, 0x6578, 0x64da, 0xff0c, 0x9810+ , 0x6e2c, 0x672a, 0x4f86, 0x8d70, 0x5411, 0xff0c, 0x898f, 0x6a21+ , 0x4e00, 0x65e6, 0x5c0f, 0x65bc, 0x4e00, 0x9846, 0x661f, 0x7403+ , 0x6216, 0x662f, 0x4e00, 0x5ea7, 0x5e1d, 0x570b, 0xff0c, 0x7d50+ , 0x679c, 0x5c31, 0x6703, 0x5931, 0x6e96, 0x3002, 0x8b1d, 0x9813+ , 0x904b, 0x7528, 0x6b64, 0x4e00, 0x79d1, 0x5b78, 0xff0c, 0x9810+ , 0x898b, 0x9280, 0x6cb3, 0x5e1d, 0x570b, 0x7684, 0x6b9e, 0x843d+ , 0xff0c, 0x6574, 0x7247, 0x9280, 0x6cb3, 0x5c07, 0x56e0, 0x6b64+ , 0x9032, 0x5165, 0x9577, 0x9054, 0x4e09, 0x842c, 0x5e74, 0x7684+ , 0x9ed1, 0x6697, 0x6642, 0x671f, 0xff0c, 0x76f4, 0x5230, 0x7b2c+ , 0x4e8c, 0x5e1d, 0x570b, 0x5efa, 0x7acb, 0x3002, 0x000a, 0x000a+ , 0x65bc, 0x662f, 0x8b1d, 0x9813, 0x5efa, 0x7acb, 0x5169, 0x5ea7+ , 0x57fa, 0x5730, 0xff0c, 0x85c9, 0x4ee5, 0x7e2e, 0x6e1b, 0x883b+ , 0x8352, 0x6642, 0x671f, 0xff0c, 0x4e00, 0x5ea7, 0x9060, 0x5728+ , 0x908a, 0x9672, 0xff0c, 0x662f, 0x85dd, 0x8853, 0x8207, 0x79d1+ , 0x5b78, 0x7684, 0x907f, 0x98a8, 0x6e2f, 0xff0c, 0x76f8, 0x5c0d+ , 0x7684, 0x53e6, 0x4e00, 0x5ea7, 0x5247, 0x5728, 0x201c, 0x7fa4+ , 0x661f, 0x7684, 0x76e1, 0x982d, 0x201d, 0x3002, 0x300c, 0x57fa+ , 0x5730, 0x4e09, 0x90e8, 0x66f2, 0x300d, 0x7684, 0x4e3b, 0x8981+ , 0x7126, 0x9ede, 0x5c31, 0x5728, 0x7aef, 0x9ede, 0x661f, 0x4e0a+ , 0x7684, 0x57fa, 0x5730, 0x3002, 0x7aef, 0x9ede, 0x661f, 0x4e0a+ , 0x7684, 0x5b78, 0x8005, 0x70ba, 0x4e86, 0x6436, 0x5728, 0x8870+ , 0x9000, 0x671f, 0x4e4b, 0x524d, 0xff0c, 0x4fdd, 0x5b58, 0x4eba+ , 0x985e, 0x7269, 0x7406, 0x79d1, 0x5b78, 0x7684, 0x77e5, 0x8b58+ , 0xff0c, 0x52aa, 0x529b, 0x7de8, 0x8f2f, 0x8457, 0x4e00, 0x90e8+ , 0x5168, 0x65b9, 0x4f4d, 0x7684, 0x300a, 0x94f6, 0x6cb3, 0x767e+ , 0x79d1, 0x5168, 0x4e66, 0x300b, 0xff0c, 0x5c0d, 0x8b1d, 0x9813+ , 0x771f, 0x6b63, 0x7684, 0x610f, 0x5716, 0x6beb, 0x4e0d, 0x77e5+ , 0x60c5, 0xff08, 0x5982, 0x679c, 0x4ed6, 0x5011, 0x77e5, 0x9053+ , 0xff0c, 0x5c31, 0x6703, 0x7522, 0x751f, 0x7121, 0x6cd5, 0x63a7+ , 0x5236, 0x7684, 0x8b8a, 0x6578, 0xff09, 0x3002, 0x57fa, 0x5730+ , 0x7684, 0x4f4d, 0x7f6e, 0x4e5f, 0x662f, 0x523b, 0x610f, 0x9078+ , 0x5b9a, 0x7684, 0xff0c, 0x5343, 0x5e74, 0x5f8c, 0x5c31, 0x662f+ , 0x7b2c, 0x4e8c, 0x5e1d, 0x570b, 0x7684, 0x9996, 0x90fd, 0xff08+ , 0x4e26, 0x975e, 0x4e09, 0x842c, 0x5e74, 0x5f8c, 0x7684, 0x90a3+ , 0x500b, 0x5e1d, 0x570b, 0xff09, 0x000a+ ]
+ tests/ForeignUtils.hs view
@@ -0,0 +1,26 @@+module ForeignUtils+ ( Ptr+ , Storable+ , createPtr+ , free+ ) where++import Foreign.Marshal.Alloc++import Foreign.Ptr+import Foreign.Storable+import Foundation+import Prelude (length, head, zip, null)+import Control.Monad (forM_)++import Foundation.Foreign++createPtr :: Storable e => [e] -> IO (FinalPtr e)+createPtr l+ | null l = toFinalPtr nullPtr (\_ -> return ())+ | otherwise = do+ let szElem = sizeOf (head l)+ nbBytes = szElem * length l+ ptr <- mallocBytes nbBytes+ forM_ (zip [0..] l) $ \(o, e) -> pokeElemOff ptr o e+ toFinalPtr ptr (\p -> free p)
+ tests/Tests.hs view
@@ -0,0 +1,571 @@+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE NoImplicitPrelude #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeFamilies #-}+module Main where++import Test.Tasty+--import Test.Tasty.Options+import Control.Monad+import Test.QuickCheck.Monadic+import Test.Tasty.HUnit+import Test.Tasty.QuickCheck++import Foundation+import Foundation.Array+import Foundation.Collection+import Foundation.Foreign+import Foundation.String+import Foundation.VFS (Path (..), filename, parent)+import Foundation.VFS.FilePath+import qualified Data.List as L+import qualified Prelude++import ForeignUtils+import Encoding++data Unicode = Unicode { unUnicode :: LString }+ deriving (Show)++data Split = Split Unicode Char+ deriving (Show)++data CharMap = CharMap Unicode Prelude.Int+ deriving (Show)++addChar :: Prelude.Int -> Char -> Char+addChar n c = toEnum ((fromEnum c + n) `Prelude.mod` 0x10ffff)++--instance Show Unicode where+-- show = unUnicode+--+data ListElement a = ListElement [a]++--instance Element a => Arbitrary ListElement where++-- | A better version of arbitrary for Char+arbitraryChar :: Gen Char+arbitraryChar =+ toEnum <$> oneof [choose (1, 0xff), choose (0x100, 0x1000), choose (0x100, 0x10000), choose (0x1, 0x1000)]++instance Arbitrary Unicode where+ arbitrary = do+ n <- choose (0,49)+ oneof+ [ Unicode <$> replicateM n (toEnum <$> choose (1, 0xff))+ , Unicode <$> replicateM n (toEnum <$> choose (0x100, 0x1000))+ , Unicode <$> replicateM n (toEnum <$> choose (0x100, 0x10000))+ , Unicode <$> replicateM n (toEnum <$> choose (0x1, 0x1000))+ ]++instance Arbitrary Split where+ arbitrary = do+ ch <- oneof [ toEnum <$> choose (0,0x7f), toEnum <$> choose (0x100, 0x10000) ]+ l <- choose (0,4) >>= \n -> fmap unUnicode <$> replicateM n arbitrary+ return (Split (Unicode $ L.intercalate [ch] l) ch)++instance Arbitrary CharMap where+ arbitrary =+ CharMap <$> arbitrary <*> choose (1,12)++instance Arbitrary FileName where+ arbitrary = do+ s <- choose (1, 30)+ unsafeFileName . fromList <$> vectorOf s genChar+ where+ genChar :: Gen Word8+ genChar = frequency+ [ (10, pure 0x2e) -- '.'+ , (10, choose (0x41, 0x5A)) -- [A-Z]+ , (10, choose (0x61, 0x7A)) -- [a-z]+ , (5, choose (0x30, 0x39)) -- [a-z]+ , (5, elements [0x2d, 0x5f]) -- [-_]+ ]++instance Arbitrary Relativity where+ arbitrary = elements [ Absolute, Relative ]++instance Arbitrary FilePath where+ arbitrary = do+ s <- choose (0, 10)+ unsafeFilePath <$> arbitrary+ <*> vectorOf s arbitrary++transEq :: Eq a => (t -> t1) -> (t1 -> a) -> (t1 -> a) -> t -> Bool+transEq unWrap f g s =+ let s' = unWrap s in f s' == g s'++--stringEq :: Eq a => (b -> a) -> (String -> b) -> (LString -> a) -> Unicode -> Bool+--stringEq back f g s =++assertEq :: (Eq a, Show a) => a -> a -> Bool+assertEq got expected+ | got == expected = True+ | otherwise = error ("got: " <> show got <> " expected: " <> show expected)++listOfElement :: Gen e -> Gen [e]+listOfElement e = choose (0,49) >>= flip replicateM e++listOfElementMaxN :: Int -> Gen e -> Gen [e]+listOfElementMaxN n e = choose (0,n) >>= flip replicateM e++-- | Set in front of tests to make them verbose+qcv :: TestTree -> TestTree+qcv = adjustOption (\(QuickCheckVerbose _) -> QuickCheckVerbose True)++-- | Set the number of tests+qcnSet :: Int -> TestTree -> TestTree+qcnSet n = adjustOption (\(QuickCheckTests _) -> QuickCheckTests n)++-- | Scale the number of tests+qcnScale :: Int -> TestTree -> TestTree+qcnScale n = adjustOption (\(QuickCheckTests actual) -> QuickCheckTests (actual * n))++testEq :: (Show e, Eq e, Eq a, Element a ~ e, IsList a, Item a ~ Element a) => Proxy a -> Gen e -> [TestTree]+testEq proxy genElement =+ [ testProperty "x == x" $ withElements $ \l -> let col = fromListP proxy l in col == col+ , testProperty "x == y" $ with2Elements $ \(l1, l2) ->+ (fromListP proxy l1 == fromListP proxy l2) == (l1 == l2)+ ]+ where+ withElements f = forAll (listOfElement genElement) f+ with2Elements f = forAll ((,) <$> listOfElement genElement <*> listOfElement genElement) f++testOrd :: (Show e, Ord a, Ord e, Element a ~ e, IsList a, Item a ~ Element a) => Proxy a -> Gen e -> [TestTree]+testOrd proxy genElement =+ [ testProperty "x `compare` y" $ with2Elements $ \(l1, l2) ->+ (fromListP proxy l1 `compare` fromListP proxy l2) == (l1 `compare` l2)+ ]+ where+ with2Elements f = forAll ((,) <$> listOfElement genElement <*> listOfElement genElement) f++testMonoid :: (Show a, Show e, Ord a, Ord e, Monoid a, Element a ~ e, IsList a, Item a ~ Element a) => Proxy a -> Gen e -> [TestTree]+testMonoid proxy genElement =+ testEq proxy genElement <>+ testOrd proxy genElement <>+ --[ testProperty "mempty <> mempty == mempty" $ \l ->+ [ testProperty "mempty <> x == x" $ withElements $ \l -> let col = fromListP proxy l in (col <> mempty) === col+ , testProperty "x <> mempty == x" $ withElements $ \l -> let col = fromListP proxy l in (mempty <> col) === col+ , testProperty "x1 <> x2 == x1|x2" $ with2Elements $ \(l1,l2) ->+ (fromListP proxy l1 <> fromListP proxy l2) === fromListP proxy (l1 <> l2)+ , testProperty "mconcat [map fromList [e]] = fromList (concat [e])" $ withNElements $ \l ->+ mconcat (fmap (fromListP proxy) l) === fromListP proxy (mconcat l)+ ]+ where+ withElements f = forAll (listOfElement genElement) f+ with2Elements f = forAll ((,) <$> listOfElement genElement <*> listOfElement genElement) f+ withNElements f = forAll (listOfElementMaxN 5 (listOfElement genElement)) f++testCollectionProps :: (Show a, Sequential a, Eq a, e ~ Item a) => Proxy a -> Gen e -> [TestTree]+testCollectionProps proxy genElement =+ [ testProperty "splitAt == (take, drop)" $ withCollection2 $ \(col, n) ->+ splitAt n col == (take n col, drop n col)+ , testProperty "revSplitAt == (revTake, revDrop)" $ withCollection2 $ \(col, n) ->+ revSplitAt n col == (revTake n col, revDrop n col)+ ]+ where+ withCollection2 f = forAll ((,) <$> (fromListP proxy <$> listOfElement genElement) <*> arbitrary) f++testCaseFilePath :: [TestTree]+testCaseFilePath = Prelude.map (makeTestCases . (\x -> (show x, x)))+ [ "/"+ , "."+ , ".."+ , "C:" </> "Users" </> "haskell-lang"+ , "/home"+ , "/home" </> "haskell-lang" </> "new hope" </> "foundation"+ , "~" </> "new hope" </> "foundation"+ , "new hope" </> "foundation"+ , "new hope" </> "foundation" </> ".."+ , "." </> "new hope" </> ".." </> ".." </> "haskell-lang" </> "new hope"+ ]+ where+ makeTestCases :: ([Char], FilePath) -> TestTree+ makeTestCases (title, p) = testGroup title+ [ testCase "buildPath . splitPath == id)" $ assertBuildSplitIdemPotent p+ , testCase "p == (parent p </> filename p)" $ assertParentFilenameIdemPotent p+ ]++ assertParentFilenameIdemPotent :: FilePath -> Assertion+ assertParentFilenameIdemPotent p =+ unless (assertEq (parent p </> filename p) p) $+ error "assertion failed"+ assertBuildSplitIdemPotent :: FilePath -> Assertion+ assertBuildSplitIdemPotent p =+ unless (assertEq (buildPath $ splitPath p) p) $+ error "assertion failed"++testPath :: (Path path, Show path, Eq path)+ => Gen path+ -> [TestTree]+testPath genElement =+ [ testProperty "buildPath . splitPath == id" $ withElements $ \l -> (buildPath $ splitPath l) === l+ ]+ where+ withElements f = forAll genElement f++testCollection :: (Sequential a, Show a, Show (Element a), Eq (Element a), Ord a, Ord (Item a))+ => Proxy a -> Gen (Element a) -> [TestTree]+testCollection proxy genElement =+ testMonoid proxy genElement <>+ [ testProperty "c == [Element(c)]" $ withElements $ \l -> (toList $ fromListP proxy l) === l+ , testProperty "length" $ withElements $ \l -> (length $ fromListP proxy l) === length l+ , testProperty "take" $ withElements2 $ \(l, n) -> toList (take n $ fromListP proxy l) === (take n) l+ , testProperty "drop" $ withElements2 $ \(l, n) -> toList (drop n $ fromListP proxy l) === (drop n) l+ , testProperty "splitAt" $ withElements2 $ \(l, n) -> toList2 (splitAt n $ fromListP proxy l) === (splitAt n) l+ , testProperty "revTake" $ withElements2 $ \(l, n) -> toList (revTake n $ fromListP proxy l) === (revTake n) l+ , testProperty "revDrop" $ withElements2 $ \(l, n) -> toList (revDrop n $ fromListP proxy l) === (revDrop n) l+ , testProperty "revSplitAt" $ withElements2 $ \(l, n) -> toList2 (revSplitAt n $ fromListP proxy l) === (revSplitAt n) l+ , testProperty "break" $ withElements2E $ \(l, c) -> toList2 (break (== c) $ fromListP proxy l) === (break (== c)) l+ , testProperty "breakElem" $ withElements2E $ \(l, c) -> toList2 (breakElem c $ fromListP proxy l) === (breakElem c) l+ , testProperty "snoc" $ withElements2E $ \(l, c) -> toList (snoc (fromListP proxy l) c) === (l <> [c])+ , testProperty "cons" $ withElements2E $ \(l, c) -> toList (cons c (fromListP proxy l)) === (c : l)+ , testProperty "unsnoc" $ withElements $ \l -> fmap toListFirst (unsnoc (fromListP proxy l)) === unsnoc l+ , testProperty "uncons" $ withElements $ \l -> fmap toListSecond (uncons (fromListP proxy l)) === uncons l+ , testProperty "splitOn" $ withElements2E $ \(l, ch) ->+ fmap toList (splitOn (== ch) (fromListP proxy l)) === splitOn (== ch) l+ , testProperty "intersperse" $ withElements2E $ \(l, c) ->+ toList (intersperse c (fromListP proxy l)) === intersperse c l+ , testProperty "intercalate" $ withElements2E $ \(l, c) ->+ let ls = Prelude.replicate 5 l+ cs = Prelude.replicate 5 c+ in toList (intercalate (fromListP proxy cs) (fromListP proxy <$> ls)) === intercalate cs ls+ , testProperty "sortBy" $ withElements $ \l ->+ (sortBy compare $ fromListP proxy l) === fromListP proxy (sortBy compare l)+ , testProperty "reverse" $ withElements $ \l ->+ (reverse $ fromListP proxy l) === fromListP proxy (reverse l)+ -- stress slicing+ , testProperty "take . take" $ withElements3 $ \(l, n1, n2) -> toList (take n2 $ take n1 $ fromListP proxy l) === (take n2 $ take n1 l)+ , testProperty "drop . take" $ withElements3 $ \(l, n1, n2) -> toList (drop n2 $ take n1 $ fromListP proxy l) === (drop n2 $ take n1 l)+ , testProperty "drop . drop" $ withElements3 $ \(l, n1, n2) -> toList (drop n2 $ drop n1 $ fromListP proxy l) === (drop n2 $ drop n1 l)+ , testProperty "drop . take" $ withElements3 $ \(l, n1, n2) -> toList (drop n2 $ take n1 $ fromListP proxy l) === (drop n2 $ take n1 l)+ , testProperty "second take . splitAt" $ withElements3 $ \(l, n1, n2) ->+ (toList2 $ (second (take n1) . splitAt n2) $ fromListP proxy l) === (second (take n1) . splitAt n2) l+ ]+ <> testCollectionProps proxy genElement+{-+ , testProperty "imap" $ \(CharMap (Unicode u) i) ->+ (imap (addChar i) (fromList u) :: String) `assertEq` fromList (Prelude.map (addChar i) u)+ ]+-}+ where+ toList2 (x,y) = (toList x, toList y)+ toListFirst (x,y) = (toList x, y)+ toListSecond (x,y) = (x, toList y)+ withElements f = forAll (listOfElement genElement) f+ withElements2 f = forAll ((,) <$> listOfElement genElement <*> arbitrary) f+ withElements3 f = forAll ((,,) <$> listOfElement genElement <*> arbitrary <*> arbitrary) f+ withElements2E f = forAll ((,) <$> listOfElement genElement <*> genElement) f++testBoxedZippable :: ( Eq (Element col) , Show (Item a), Show (Item b)+ , BoxedZippable col, Zippable a, Zippable b+ , Element col ~ (Item a, Item b) )+ => Proxy a -> Proxy b -> Proxy col -> Gen (Element a) -> Gen (Element b) -> [TestTree]+testBoxedZippable proxyA proxyB proxyCol genElementA genElementB =+ [ testProperty "zip" $ withList2 $ \(as, bs) ->+ toListP proxyCol (zip (fromListP proxyA as) (fromListP proxyB bs)) == zip as bs+ , testProperty "zip . unzip == id" $ withListOfTuples $ \xs ->+ let (as, bs) = unzip (fromListP proxyCol xs)+ in toListP proxyCol (zip (as `asProxyTypeOf` proxyA) (bs `asProxyTypeOf` proxyB)) == xs+ ]+ where+ withList2 = forAll ((,) <$> listOfElement genElementA <*> listOfElement genElementB)+ withListOfTuples = forAll (listOfElement ((,) <$> genElementA <*> genElementB))++testZippable :: ( Eq (Element col), Show (Item col), Show (Item a), Show (Item b)+ , Zippable col, Zippable a, Zippable b )+ => Proxy a -> Proxy b -> Proxy col -> Gen (Element a) -> Gen (Element b) -> Gen (Element col) -> [TestTree]+testZippable proxyA proxyB proxyCol genElementA genElementB genElementCol =+ [ testProperty "zipWith" $ withList2AndE $ \(as, bs, c) ->+ toListP proxyCol (zipWith (const (const c)) (fromListP proxyA as) (fromListP proxyB bs)+ ) == Prelude.replicate (Prelude.min (length as) (length bs)) c+ ]+ where+ withList2AndE = forAll ( (,,) <$> listOfElement genElementA <*> listOfElement genElementB+ <*> genElementCol )++testZippableProps :: (Eq (Item a), Eq (Item b), Show (Item a), Show (Item b), Zippable a, Zippable b)+ => Proxy a -> Proxy b -> Gen (Element a) -> Gen (Element b) -> [TestTree]+testZippableProps proxyA proxyB genElementA genElementB =+ [ testProperty "zipWith ⊥ [] xs == []" $ withList $ \as ->+ toListP proxyA (zipWith undefined [] (fromListP proxyA as)) == []+ , testProperty "zipWith f a b == zipWith (flip f) b a" $ withList2 $ \(as, bs) ->+ let f = ignore1+ as' = fromListP proxyA as+ bs' = fromListP proxyB bs+ in toListP proxyB (zipWith f as' bs')+ == toListP proxyB (zipWith (flip f) bs' as')+ , testProperty "zipWith3 f […] xs == zipWith id (zipWith f […]) xs)" $ withList2 $ \(as, bs) ->+ let f = ignore2+ as' = fromListP proxyA as+ bs' = fromListP proxyB bs+ in toListP proxyB (zipWith3 f as' as' bs')+ == Prelude.zipWith id (zipWith f as as) bs+ , testProperty "zipWith4 f […] xs == zipWith id (zipWith3 f […]) xs)" $ withList2 $ \(as, bs) ->+ let f = ignore3+ as' = fromListP proxyA as+ bs' = fromListP proxyB bs+ in toListP proxyB (zipWith4 f as' as' as' bs')+ == Prelude.zipWith id (zipWith3 f as as as) bs+ , testProperty "zipWith5 f […] xs == zipWith id (zipWith4 f […]) xs)" $ withList2 $ \(as, bs) ->+ let f = ignore4+ as' = fromListP proxyA as+ bs' = fromListP proxyB bs+ in toListP proxyB (zipWith5 f as' as' as' as' bs')+ == Prelude.zipWith id (zipWith4 f as as as as) bs+ , testProperty "zipWith6 f […] xs == zipWith id (zipWith5 f […]) xs)" $ withList2 $ \(as, bs) ->+ let f = ignore5+ as' = fromListP proxyA as+ bs' = fromListP proxyB bs+ in toListP proxyB (zipWith6 f as' as' as' as' as' bs')+ == Prelude.zipWith id (zipWith5 f as as as as as) bs+ , testProperty "zipWith7 f […] xs == zipWith id (zipWith6 f […]) xs)" $ withList2 $ \(as, bs) ->+ let f = ignore6+ as' = fromListP proxyA as+ bs' = fromListP proxyB bs+ in toListP proxyB (zipWith7 f as' as' as' as' as' as' bs')+ == Prelude.zipWith id (zipWith6 f as as as as as as) bs+ ]+ where+ -- ignore the first n arguments+ ignore1 = flip const+ ignore2 = const . ignore1+ ignore3 = const . ignore2+ ignore4 = const . ignore3+ ignore5 = const . ignore4+ ignore6 = const . ignore5+ withList = forAll (listOfElement genElementA)+ withList2 = forAll ((,) <$> listOfElement genElementA <*> listOfElement genElementB)++testUnboxedForeign :: (PrimType e, Show e, Element a ~ e, Storable e)+ => Proxy a -> Gen e -> [TestTree]+testUnboxedForeign proxy genElement =+ [ testProperty "equal" $ withElementsM $ \fptr l ->+ return $ toArrayP proxy l == foreignMem fptr (length l)+ , testProperty "take" $ withElementsM $ \fptr l -> do+ n <- pick arbitrary+ return $ take n (toArrayP proxy l) == take n (foreignMem fptr (length l))+ , testProperty "take" $ withElementsM $ \fptr l -> do+ n <- pick arbitrary+ return $ drop n (toArrayP proxy l) == drop n (foreignMem fptr (length l))+ ]+ where+ withElementsM f = monadicIO $ forAllM (listOfElement genElement) $ \l -> run (createPtr l) >>= \fptr -> f fptr l+ toArrayP :: PrimType (Element c) => Proxy c -> [Element c] -> UArray (Element c)+ toArrayP _ l = fromList l++fromListP :: (IsList c, Item c ~ Element c) => Proxy c -> [Element c] -> c+fromListP p = \x -> asProxyTypeOf (fromList x) p++toListP :: (IsList c, Item c ~ Element c) => Proxy c -> c -> [Element c]+toListP p x = toList (asProxyTypeOf x p)++data RandomList = RandomList [Int]+ deriving (Show,Eq)++instance Arbitrary RandomList where+ arbitrary = RandomList <$> (choose (100,400) >>= flip replicateM (choose (0,8)))++chunks :: Sequential c => RandomList -> c -> [c]+chunks (RandomList randomInts) = loop (randomInts <> [1..])+ where+ loop rx c+ | null c = []+ | otherwise =+ case rx of+ r:rs ->+ let (c1,c2) = splitAt r c+ in c1 : loop rs c2+ [] ->+ loop randomInts c+++testStringCases :: [TestTree]+testStringCases =+ [ testGroup "Validation"+ [ testProperty "fromBytes . toBytes == valid" $ \(Unicode l) ->+ let s = fromList l+ in (fromBytes UTF8 $ toBytes UTF8 s) === (s, Nothing, mempty)+ , testProperty "Streaming" $ \(Unicode l, randomInts) ->+ let wholeS = fromList l+ wholeBA = toBytes UTF8 wholeS+ reconstruct (prevBa, errs, acc) ba =+ let ba' = prevBa `mappend` ba+ (s, merr, nextBa) = fromBytes UTF8 ba'+ in (nextBa, merr : errs, s : acc)++ (remainingBa, allErrs, chunkS) = foldl reconstruct (mempty, [], []) $ chunks randomInts wholeBA+ in (catMaybes allErrs === []) .&&. (remainingBa === mempty) .&&. (mconcat (reverse chunkS) === wholeS)+ ]+ , testGroup "Cases"+ [ testGroup "Invalid-UTF8"+ [ testCase "ff" $ expectFromBytesErr ("", Just InvalidHeader, 0) (fromList [0xff])+ , testCase "80" $ expectFromBytesErr ("", Just InvalidHeader, 0) (fromList [0x80])+ , testCase "E2 82 0C" $ expectFromBytesErr ("", Just InvalidContinuation, 0) (fromList [0xE2,0x82,0x0c])+ , testCase "30 31 E2 82 0C" $ expectFromBytesErr ("01", Just InvalidContinuation, 2) (fromList [0x30,0x31,0xE2,0x82,0x0c])+ ]+ ]+ ]+ where+ expectFromBytesErr (expectedString,expectedErr,positionErr) ba = do+ let (s', merr, ba') = fromBytes UTF8 ba+ assertEqual "error" expectedErr merr+ assertEqual "remaining" (drop positionErr ba) ba'+ assertEqual "string" expectedString (toList s')++tests :: [TestTree]+tests =+ [ testGroup "Array"+ [ testGroup "Unboxed"+ [ testGroup "UArray(W8)" (testCollection (Proxy :: Proxy (UArray Word8)) arbitrary)+ , testGroup "UArray(W16)" (testCollection (Proxy :: Proxy (UArray Word16)) arbitrary)+ , testGroup "UArray(W32)" (testCollection (Proxy :: Proxy (UArray Word32)) arbitrary)+ , testGroup "UArray(W64)" (testCollection (Proxy :: Proxy (UArray Word64)) arbitrary)+ , testGroup "UArray(I8)" (testCollection (Proxy :: Proxy (UArray Int8)) arbitrary)+ , testGroup "UArray(I16)" (testCollection (Proxy :: Proxy (UArray Int16)) arbitrary)+ , testGroup "UArray(I32)" (testCollection (Proxy :: Proxy (UArray Int32)) arbitrary)+ , testGroup "UArray(I64)" (testCollection (Proxy :: Proxy (UArray Int64)) arbitrary)+ , testGroup "UArray(F32)" (testCollection (Proxy :: Proxy (UArray Float)) arbitrary)+ , testGroup "UArray(F64)" (testCollection (Proxy :: Proxy (UArray Double)) arbitrary)+ ]+ , testGroup "Unboxed-Foreign"+ [ testGroup "UArray(W8)" (testUnboxedForeign (Proxy :: Proxy (UArray Word8)) arbitrary)+ , testGroup "UArray(W16)" (testUnboxedForeign (Proxy :: Proxy (UArray Word16)) arbitrary)+ , testGroup "UArray(W32)" (testUnboxedForeign (Proxy :: Proxy (UArray Word32)) arbitrary)+ , testGroup "UArray(W64)" (testUnboxedForeign (Proxy :: Proxy (UArray Word64)) arbitrary)+ , testGroup "UArray(I8)" (testUnboxedForeign (Proxy :: Proxy (UArray Int8)) arbitrary)+ , testGroup "UArray(I16)" (testUnboxedForeign (Proxy :: Proxy (UArray Int16)) arbitrary)+ , testGroup "UArray(I32)" (testUnboxedForeign (Proxy :: Proxy (UArray Int32)) arbitrary)+ , testGroup "UArray(I64)" (testUnboxedForeign (Proxy :: Proxy (UArray Int64)) arbitrary)+ , testGroup "UArray(F32)" (testUnboxedForeign (Proxy :: Proxy (UArray Float)) arbitrary)+ , testGroup "UArray(F64)" (testUnboxedForeign (Proxy :: Proxy (UArray Double)) arbitrary)+ ]+ , testGroup "Boxed"+ [ testGroup "Array(W8)" (testCollection (Proxy :: Proxy (Array Word8)) arbitrary)+ , testGroup "Array(W16)" (testCollection (Proxy :: Proxy (Array Word16)) arbitrary)+ , testGroup "Array(W32)" (testCollection (Proxy :: Proxy (Array Word32)) arbitrary)+ , testGroup "Array(W64)" (testCollection (Proxy :: Proxy (Array Word64)) arbitrary)+ , testGroup "Array(I8)" (testCollection (Proxy :: Proxy (Array Int8)) arbitrary)+ , testGroup "Array(I16)" (testCollection (Proxy :: Proxy (Array Int16)) arbitrary)+ , testGroup "Array(I32)" (testCollection (Proxy :: Proxy (Array Int32)) arbitrary)+ , testGroup "Array(I64)" (testCollection (Proxy :: Proxy (Array Int64)) arbitrary)+ , testGroup "Array(F32)" (testCollection (Proxy :: Proxy (Array Float)) arbitrary)+ , testGroup "Array(F64)" (testCollection (Proxy :: Proxy (Array Double)) arbitrary)+ , testGroup "Array(Int)" (testCollection (Proxy :: Proxy (Array Int)) arbitrary)+ , testGroup "Array(Int,Int)" (testCollection (Proxy :: Proxy (Array (Int,Int))) arbitrary)+ , testGroup "Array(Integer)" (testCollection (Proxy :: Proxy (Array Integer)) arbitrary)+ ]+ , testGroup "Bitmap" (testCollection (Proxy :: Proxy (Bitmap)) arbitrary)+ ]+ , testGroup "String"+ ( testCollection (Proxy :: Proxy String) arbitraryChar+ <> testStringCases+ <> [ testGroup "Encoding Sample0" (testEncodings sample0)+ , testGroup "Encoding Sample1" (testEncodings sample1)+ , testGroup "Encoding Sample2" (testEncodings sample2)+ ]+ )+ , testGroup "VFS"+ [ testGroup "FilePath" $ testCaseFilePath <> (testPath (arbitrary :: Gen FilePath))+ ]+ , testGroup "Number"+ [ testGroup "Precedence"+ [ testProperty "+ and - (1)" $ \a (b :: Int) (c :: Int) -> (a + b - c) === ((a + b) - c)+ , testProperty "+ and - (2)" $ \a (b :: Int) (c :: Int) -> (a - b + c) === ((a - b) + c)+ , testProperty "+ and * (1)" $ \a b (c :: Int) -> (a + b * c) === (a + (b * c))+ , testProperty "+ and * (2)" $ \a b (c :: Int) -> (a * b + c) === ((a * b) + c)+ , testProperty "- and * (1)" $ \a b (c :: Int) -> (a - b * c) === (a - (b * c))+ , testProperty "- and * (2)" $ \a b (c :: Int) -> (a * b - c) === ((a * b) - c)+ , testProperty "* and ^ (1)" $ \a (Positive b :: Positive Int) (c :: Int) -> (a ^ b * c) === ((a ^ b) * c)+ , testProperty "* and ^ (2)" $ \a (b :: Int) (Positive c :: Positive Int) -> (a * b ^ c) === (a * (b ^ c))+ ]+ ]+ , testGroup "ModifiedUTF8"+ [ testCase "The foundation Serie" $ testCaseModifiedUTF8 "基地系列" "基地系列"+ , testCase "has null bytes" $ testCaseModifiedUTF8 "let's\0 do \0 it" "let's\0 do \0 it"+ , testCase "Vincent's special" $ testCaseModifiedUTF8 "abc\0안, 蠀\0, ☃" "abc\0안, 蠀\0, ☃"+ , testCase "Long string" $ testCaseModifiedUTF8+ "this is only a simple string but quite longer than the 64 bytes used in the modified UTF8 parser"+ "this is only a simple string but quite longer than the 64 bytes used in the modified UTF8 parser"+ ]+ , testGroup "BoxedZippable"+ [ testGroup "Array"+ [ testGroup "from Array Int"+ ( testBoxedZippable+ (Proxy :: Proxy (Array Int)) (Proxy :: Proxy (Array Int))+ (Proxy :: Proxy (Array (Int, Int))) arbitrary arbitrary )+ , testGroup "from String"+ ( testBoxedZippable+ (Proxy :: Proxy String) (Proxy :: Proxy String)+ (Proxy :: Proxy (Array (Char, Char))) arbitrary arbitrary )+ , testGroup "from String and Array Char"+ ( testBoxedZippable+ (Proxy :: Proxy String) (Proxy :: Proxy (Array Char))+ (Proxy :: Proxy (Array (Char, Char))) arbitrary arbitrary )+ , testGroup "from Array Int and Array Char"+ ( testBoxedZippable+ (Proxy :: Proxy (Array Int)) (Proxy :: Proxy (Array Char))+ (Proxy :: Proxy (Array (Int, Char))) arbitrary arbitrary )+ ]+ ]+ , testGroup "Zippable"+ [ testGroup "String"+ [ testGroup "from String"+ ( testZippable+ (Proxy :: Proxy String) (Proxy :: Proxy String)+ (Proxy :: Proxy String) arbitrary arbitrary arbitrary )+ , testGroup "from Array Char"+ ( testZippable+ (Proxy :: Proxy (Array Char)) (Proxy :: Proxy (Array Char))+ (Proxy :: Proxy String) arbitrary arbitrary arbitrary )+ , testGroup "from UArray Word8 and Array Int"+ ( testZippable+ (Proxy :: Proxy (UArray Word8)) (Proxy :: Proxy (Array Int))+ (Proxy :: Proxy String) arbitrary arbitrary arbitrary )+ ]+ , testGroup "Array"+ [ testGroup "from String"+ ( testZippable+ (Proxy :: Proxy String) (Proxy :: Proxy String)+ (Proxy :: Proxy (Array Int)) arbitrary arbitrary arbitrary )+ , testGroup "from Array Char"+ ( testZippable+ (Proxy :: Proxy (Array Char)) (Proxy :: Proxy (Array Char))+ (Proxy :: Proxy (Array Char)) arbitrary arbitrary arbitrary )+ , testGroup "from UArray Word8 and Array Int"+ ( testZippable+ (Proxy :: Proxy (UArray Word8)) (Proxy :: Proxy (Array Int))+ (Proxy :: Proxy (Array Int)) arbitrary arbitrary arbitrary )+ ]+ , testGroup "UArray"+ [ testGroup "from String"+ ( testZippable+ (Proxy :: Proxy String) (Proxy :: Proxy String)+ (Proxy :: Proxy (UArray Word8)) arbitrary arbitrary arbitrary )+ , testGroup "from Array Char"+ ( testZippable+ (Proxy :: Proxy (Array Char)) (Proxy :: Proxy (Array Char))+ (Proxy :: Proxy (UArray Word16)) arbitrary arbitrary arbitrary )+ , testGroup "from UArray Word8 and Array Int"+ ( testZippable+ (Proxy :: Proxy (UArray Word8)) (Proxy :: Proxy (Array Int))+ (Proxy :: Proxy (UArray Word32)) arbitrary arbitrary arbitrary )+ ]+ , testGroup "Properties"+ ( testZippableProps (Proxy :: Proxy (Array Int)) (Proxy :: Proxy (Array Char))+ arbitrary arbitrary )+ ]+ ]++testCaseModifiedUTF8 :: [Char] -> String -> Assertion+testCaseModifiedUTF8 ghcStr str+ | ghcStr == fStr = return ()+ | otherwise = assertFailure $+ "expecting: " <> show ghcStr <> " received: " <> show fStr+ where+ fStr :: [Char]+ fStr = toList str++main :: IO ()+main = defaultMain $ testGroup "foundation" tests