case-insensitive 0.4.0.4 → 1.0
raw patch · 7 files changed
+208/−40 lines, 7 filesdep +HUnitdep +case-insensitivedep +criterionsetup-changedPVP ok
version bump matches the API change (PVP)
Dependencies added: HUnit, case-insensitive, criterion, deepseq, test-framework, test-framework-hunit
API changes (from Hackage documentation)
- Data.CaseInsensitive: instance FoldCase ShowS
- Data.CaseInsensitive: instance FoldCase String
+ Data.CaseInsensitive: instance FoldCase Char
+ Data.CaseInsensitive: instance FoldCase a => FoldCase [a]
+ Data.CaseInsensitive: instance NFData s => NFData (CI s)
- Data.CaseInsensitive: class FoldCase s
+ Data.CaseInsensitive: class FoldCase s where foldCaseList = map foldCase
Files
- Data/CaseInsensitive.hs +66/−34
- LICENSE +1/−1
- Setup.hs +0/−2
- Setup.lhs +3/−0
- bench/bench.hs +24/−0
- case-insensitive.cabal +32/−3
- test/test.hs +82/−0
Data/CaseInsensitive.hs view
@@ -1,10 +1,4 @@-{-# LANGUAGE CPP- , NoImplicitPrelude- , UnicodeSyntax- , TypeSynonymInstances- , DeriveDataTypeable- , FlexibleInstances- #-}+{-# LANGUAGE CPP, NoImplicitPrelude, DeriveDataTypeable #-} #if __GLASGOW_HASKELL__ >= 702 {-# LANGUAGE Trustworthy #-}@@ -13,7 +7,7 @@ ----------------------------------------------------------------------------- -- | -- Module : Data.CaseInsensitive--- Copyright : (c) 2011-2012 Bas van Dijk+-- Copyright : (c) 2011-2013 Bas van Dijk -- License : BSD-style (see the file LICENSE) -- Maintainer : Bas van Dijk <v.dijk.bas@gmail.com> --@@ -24,6 +18,9 @@ -- import qualified Data.CaseInsensitive as CI -- @ --+-- /Note that the FoldCase instance for ByteStrings is only/+-- /guaranteed to be correct for ISO-8859-1 encoded strings!/+-- ----------------------------------------------------------------------------- module Data.CaseInsensitive ( CI@@ -40,25 +37,31 @@ -- from base: import Data.Bool ( (||) )+import Data.Char ( Char, toLower ) import Data.Eq ( Eq, (==) )-import Data.Ord ( Ord, compare ) import Data.Function ( on ) import Data.Monoid ( Monoid, mempty, mappend )+import Data.Ord ( Ord, compare ) import Data.String ( IsString, fromString ) import Data.Typeable ( Typeable ) import Data.Word ( Word8 ) import Prelude ( String, (.), fmap, (&&), (+), (<=), (>=), otherwise ) import Text.Read ( Read, readPrec )-import Text.Show ( Show, showsPrec, ShowS )+import Text.Show ( Show, showsPrec ) +import qualified Data.List as L ( map )+ -- from bytestring:-import qualified Data.ByteString as B ( ByteString, map )-import qualified Data.ByteString.Lazy as BL ( ByteString, map )+import qualified Data.ByteString as B ( ByteString, map )+import qualified Data.ByteString.Lazy as BL ( ByteString, map ) -- from text: import qualified Data.Text as T ( Text, toCaseFold ) import qualified Data.Text.Lazy as TL ( Text, toCaseFold, pack, unpack ) +-- from deepseq:+import Control.DeepSeq ( NFData, rnf, deepseq )+ -- from hashable: import Data.Hashable ( Hashable, hashWithSalt ) @@ -67,7 +70,7 @@ -------------------------------------------------------------------------------- {-| A @CI s@ provides /C/ase /I/nsensitive comparison for the string-like type-@s@ (for example: 'String', 'T.Text', 'B.ByteString', 'ShowS', etc.).+@s@ (for example: 'String', 'T.Text', 'B.ByteString', etc.). Note that @CI s@ has an instance for 'IsString' which together with the @OverloadedStrings@ language extension allows you to write case insensitive@@ -79,42 +82,44 @@ @ -}-data CI s = CI { original ∷ !s -- ^ Retrieve the original string-like value.- , foldedCase ∷ !s -- ^ Retrieve the case folded string-like value.- -- (Also see 'foldCase').+data CI s = CI { original :: !s -- ^ Retrieve the original string-like value.+ , foldedCase :: !s -- ^ Retrieve the case folded string-like value.+ -- (Also see 'foldCase'). } deriving Typeable -- | Make the given string-like value case insensitive.-mk ∷ FoldCase s ⇒ s → CI s+mk :: FoldCase s => s -> CI s mk s = CI s (foldCase s) -- | Transform the original string-like value but keep it case insensitive.-map ∷ FoldCase s2 ⇒ (s1 → s2) → (CI s1 → CI s2)+map :: FoldCase s2 => (s1 -> s2) -> (CI s1 -> CI s2) map f = mk . f . original -instance (IsString s, FoldCase s) ⇒ IsString (CI s) where+instance (IsString s, FoldCase s) => IsString (CI s) where fromString = mk . fromString -instance Monoid s ⇒ Monoid (CI s) where+instance Monoid s => Monoid (CI s) where mempty = CI mempty mempty CI o1 l1 `mappend` CI o2 l2 = CI (o1 `mappend` o2) (l1 `mappend` l2) -instance Eq s ⇒ Eq (CI s) where+instance Eq s => Eq (CI s) where (==) = (==) `on` foldedCase -instance Ord s ⇒ Ord (CI s) where+instance Ord s => Ord (CI s) where compare = compare `on` foldedCase -instance (Read s, FoldCase s) ⇒ Read (CI s) where+instance (Read s, FoldCase s) => Read (CI s) where readPrec = fmap mk readPrec -instance Show s ⇒ Show (CI s) where+instance Show s => Show (CI s) where showsPrec prec = showsPrec prec . original instance Hashable s => Hashable (CI s) where- hashWithSalt salt = hashWithSalt salt . foldedCase+ hashWithSalt salt = hashWithSalt salt . foldedCase +instance NFData s => NFData (CI s) where+ rnf (CI o f) = o `deepseq` f `deepseq` () -------------------------------------------------------------------------------- -- Folding (lowering) cases@@ -127,23 +132,50 @@ -- Programs that require locale sensitivity should use appropriate versions of -- the case mapping functions from the @text-icu@ package: -- <http://hackage.haskell.org/package/text-icu>-class FoldCase s where foldCase ∷ s → s+class FoldCase s where+ foldCase :: s -> s --- | Note that @foldCase = 'B.map' toLower@ which is only guaranteed to be correct for ASCII encoded strings!-instance FoldCase B.ByteString where foldCase = B.map toLower+ foldCaseList :: [s] -> [s]+ foldCaseList = L.map foldCase --- | Note that @foldCase = 'BL.map' toLower@ which is only guaranteed to be correct for ASCII encoded strings!-instance FoldCase BL.ByteString where foldCase = BL.map toLower+instance FoldCase a => FoldCase [a] where+ foldCase = foldCaseList -instance FoldCase String where foldCase = TL.unpack . TL.toCaseFold . TL.pack+-- | Note that @foldCase@ on @'B.ByteString's@ is only guaranteed to be correct for ISO-8859-1 encoded strings!+instance FoldCase B.ByteString where foldCase = B.map toLower8++-- | Note that @foldCase@ on @'BL.ByteString's@ is only guaranteed to be correct for ISO-8859-1 encoded strings!+instance FoldCase BL.ByteString where foldCase = BL.map toLower8++instance FoldCase Char where+ foldCase = toLower+ foldCaseList = TL.unpack . TL.toCaseFold . TL.pack+ instance FoldCase T.Text where foldCase = T.toCaseFold instance FoldCase TL.Text where foldCase = TL.toCaseFold-instance FoldCase ShowS where foldCase = (foldCase .) instance FoldCase (CI s) where foldCase (CI _ l) = CI l l -toLower :: Word8 -> Word8-toLower w+toLower8 :: Word8 -> Word8+toLower8 w | 65 <= w && w <= 90 || 192 <= w && w <= 214 || 216 <= w && w <= 222 = w + 32 | otherwise = w++--------------------------------------------------------------------------------+-- Rewrite RULES+--------------------------------------------------------------------------------++{-# RULES+ "mk/ByteString" forall (bs :: B.ByteString). mk bs = CI bs (foldCaseBS bs)+ #-}++foldCaseBS :: B.ByteString -> B.ByteString+foldCaseBS bs = B.map toLower8' bs+ where+ toLower8' :: Word8 -> Word8+ toLower8' w+ | 65 <= w && w <= 90 ||+ 192 <= w && w <= 214 ||+ 216 <= w && w <= 222 = w + 32+ | otherwise = w
LICENSE view
@@ -1,4 +1,4 @@-Copyright (c) 2011-2012 Bas van Dijk+Copyright (c) 2011-2013 Bas van Dijk All rights reserved.
− Setup.hs
@@ -1,2 +0,0 @@-import Distribution.Simple-main = defaultMain
+ Setup.lhs view
@@ -0,0 +1,3 @@+#!/usr/bin/env runhaskell+> import Distribution.Simple+> main = defaultMain
+ bench/bench.hs view
@@ -0,0 +1,24 @@+{-# LANGUAGE CPP #-}+{-# OPTIONS_GHC -fno-warn-orphans #-}++module Main ( main) where++import Criterion.Main ( defaultMain, bcompare, bench, nf )+import qualified Data.ByteString as B ( readFile )+import qualified Data.CaseInsensitive as CI ( mk )+import qualified NoClass as NC ( mk )++#if !MIN_VERSION_bytestring(0,10,0)+import Control.DeepSeq ( NFData )+instance NFData ByteString+#endif++main :: IO ()+main = do+ bs <- B.readFile "data/pg2189.txt"+ defaultMain+ [ bcompare+ [ bench "no-class" $ nf (\s -> NC.mk s) bs+ , bench "case-insensitive" $ nf (\s -> CI.mk s) bs+ ]+ ]
case-insensitive.cabal view
@@ -1,6 +1,6 @@ name: case-insensitive-version: 0.4.0.4-cabal-version: >=1.6+version: 1.0+cabal-version: >=1.8 build-type: Simple license: BSD3 license-file: LICENSE@@ -24,9 +24,38 @@ Location: git://github.com/basvandijk/case-insensitive.git Library- GHC-Options: -Wall+ ghc-options: -Wall build-depends: base >= 3 && < 4.7 , bytestring >= 0.9 && < 0.11 , text >= 0.3 && < 0.12+ , deepseq >= 1.1 && < 1.4 , hashable >= 1.0 && < 1.3 exposed-modules: Data.CaseInsensitive++test-suite test-case-insensitive+ type: exitcode-stdio-1.0+ main-is: test.hs+ hs-source-dirs: test++ build-depends: case-insensitive+ , base >= 3 && < 4.7+ , bytestring >= 0.9 && < 0.11+ , text >= 0.3 && < 0.12+ , HUnit >= 1.2.2 && < 1.3+ , test-framework >= 0.2.4 && < 0.9+ , test-framework-hunit >= 0.2.4 && < 0.4++ ghc-options: -Wall++benchmark bench-case-insensitive+ type: exitcode-stdio-1.0+ main-is: bench.hs+ hs-source-dirs: bench++ ghc-options: -Wall -O2++ build-depends: case-insensitive+ , base >= 3 && < 4.7+ , bytestring >= 0.9 && < 0.11+ , criterion >= 0.6.1 && < 0.7+ , deepseq >= 1.1 && < 1.4
+ test/test.hs view
@@ -0,0 +1,82 @@+module Main ( main ) where++import Data.ByteString ( ByteString )+import qualified Data.ByteString.Char8 as BC8 ( pack, map )+import qualified Data.ByteString.Lazy as Lazy ( ByteString )+import qualified Data.ByteString.Lazy.Char8 as BLC8 ( pack, map )+import qualified Data.CaseInsensitive as CI ( mk )+import Data.Char ( toUpper, chr )+import Data.Text ( Text )+import qualified Data.Text as T ( pack, toUpper )+import qualified Data.Text.Lazy as Lazy ( Text )+import qualified Data.Text.Lazy as TL ( pack, toUpper )+import Test.Framework ( defaultMain, testGroup )+import Test.Framework.Providers.HUnit ( testCase )+import Test.HUnit ( assertEqual )++main :: IO ()+main = defaultMain+ [ testGroup "ASCII"+ [ testCase "String" $ assertEqual "" (CI.mk asciiStr)+ (CI.mk ( map toUpper asciiStr))+ , testCase "ByteString" $ assertEqual "" (CI.mk asciiBs)+ (CI.mk ( BC8.map toUpper asciiBs))+ , testCase "Lazy.ByteString" $ assertEqual "" (CI.mk asciiLBs)+ (CI.mk (BLC8.map toUpper asciiLBs))+ , testCase "Text" $ assertEqual "" (CI.mk asciiTxt)+ (CI.mk ( T.toUpper asciiTxt))+ , testCase "Lazy.Text" $ assertEqual "" (CI.mk asciiLTxt)+ (CI.mk ( TL.toUpper asciiLTxt))+ ]+ , testGroup "ISO-8859-1"+ [ testCase "String" $ assertEqual "" (CI.mk iso_8859_1Str)+ (CI.mk ( map toUpper iso_8859_1Str))+ , testCase "ByteString" $ assertEqual "" (CI.mk iso_8859_1Bs)+ (CI.mk ( BC8.map toUpper' iso_8859_1Bs))+ , testCase "Lazy.ByteString" $ assertEqual "" (CI.mk iso_8859_1LBs)+ (CI.mk (BLC8.map toUpper' iso_8859_1LBs))+ , testCase "Text" $ assertEqual "" (CI.mk iso_8859_1Txt)+ (CI.mk ( T.toUpper iso_8859_1Txt))+ , testCase "Lazy.Text" $ assertEqual "" (CI.mk iso_8859_1LTxt)+ (CI.mk ( TL.toUpper iso_8859_1LTxt))+ ]+ ]+++asciiLTxt :: Lazy.Text+asciiLTxt = TL.pack asciiStr++asciiTxt :: Text+asciiTxt = T.pack asciiStr++asciiLBs :: Lazy.ByteString+asciiLBs = BLC8.pack asciiStr++asciiBs :: ByteString+asciiBs = BC8.pack asciiStr++asciiStr :: String+asciiStr = map chr [0..127]+++iso_8859_1LTxt :: Lazy.Text+iso_8859_1LTxt = TL.pack iso_8859_1Str++iso_8859_1Txt :: Text+iso_8859_1Txt = T.pack iso_8859_1Str++iso_8859_1LBs :: Lazy.ByteString+iso_8859_1LBs = BLC8.pack iso_8859_1Str++iso_8859_1Bs :: ByteString+iso_8859_1Bs = BC8.pack iso_8859_1Str++iso_8859_1Str :: String+iso_8859_1Str = asciiStr ++ map chr [128..255]+++-- | Upper-casing some characters in ISO 8859-1 move them outside the 0-255 range.+toUpper' :: Char -> Char+toUpper' 'µ' = 'µ' -- toUpper 'µ' (code point: 181) == 'Μ' (code point: 924)+toUpper' 'ÿ' = 'ÿ' -- toUpper 'ÿ' (code point: 255) == 'Ÿ' (code point: 376)+toUpper' c = toUpper c