text-short 0.1.2 → 0.1.3
raw patch · 5 files changed
+101/−11 lines, 5 filesdep ~basedep ~bytestringdep ~ghc-prim
Dependency ranges changed: base, bytestring, ghc-prim
Files
- ChangeLog.md +10/−0
- src-test/Tests.hs +7/−0
- src/Data/Text/Short.hs +4/−0
- src/Data/Text/Short/Internal.hs +74/−5
- text-short.cabal +6/−6
ChangeLog.md view
@@ -1,3 +1,13 @@+## 0.1.3++ * Add `Data ShortText` instance+ * Define `Typeable ShortText` also for GHC 7.8 as well+ (NB: for GHC 7.10.3 and up `Typeable` instances are automatically+ defined even when not mentioned explicitly in a `deriving` clause)+ * Add equivalent verb `Data.Text.split` to `Data.Text.Short` API++ split :: (Char -> Bool) -> ShortText -> [ShortText]+ ## 0.1.2 * Add `IsList ShortText` and `PrintfArg ShortText` instances
src-test/Tests.hs view
@@ -72,6 +72,9 @@ let t' = IUT.fromText t mapBoth f (x,y) = (f x, f y) in and [ mapBoth IUT.toText (IUT.splitAt i t') == T.splitAt i t | i <- [-5 .. 5+T.length t ] ]+ , QC.testProperty "intercalate/split" $ \t c ->+ let t' = IUT.fromText t+ in IUT.intercalate (IUT.singleton c) (IUT.split (== c) t') == t' , QC.testProperty "intersperse" $ \t c -> IUT.intersperse c (IUT.fromText t) == IUT.fromText (T.intersperse c t) , QC.testProperty "intercalate" $ \t1 t2 -> IUT.intercalate (IUT.fromText t1) (map IUT.fromText t2) == IUT.fromText (T.intercalate t1 t2)@@ -166,6 +169,10 @@ , testCase "singleton" $ [ c | c <- [minBound..maxBound], IUT.singleton c /= IUT.fromText (T.singleton c) ] @?= [] , testCase "splitAtEnd" $ IUT.splitAtEnd 1 "€€" @?= ("€","€")+ , testCase "split#1" $ IUT.split (== 'a') "aabbaca" @?= ["", "", "bb", "c", ""]+ , testCase "split#2" $ IUT.split (const False) "aabbaca" @?= ["aabbaca"]+ , testCase "split#3" $ IUT.split (const True) "abc" @?= ["","","",""]+ , testCase "split#4" $ IUT.split (const True) "" @?= [""] , testCase "literal0" $ IUT.unpack testLit0 @?= [] , testCase "literal1" $ IUT.unpack testLit1 @?= ['€','\0','€','\0']
src/Data/Text/Short.hs view
@@ -76,6 +76,9 @@ , spanEnd , breakEnd + -- ** Breaking into many substrings+ , split+ -- ** Suffix & Prefix operations , stripPrefix , stripSuffix@@ -321,6 +324,7 @@ -- @since 0.1.2 dropWhileEnd :: (Char -> Bool) -> ShortText -> ShortText dropWhileEnd p = fst . spanEnd p+ -- $setup -- >>> :set -XOverloadedStrings
src/Data/Text/Short/Internal.hs view
@@ -1,5 +1,6 @@ {-# LANGUAGE BangPatterns #-} {-# LANGUAGE CPP #-}+{-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE MagicHash #-} {-# LANGUAGE RankNTypes #-}@@ -48,6 +49,7 @@ , span , spanEnd+ , split , intersperse , intercalate@@ -108,7 +110,11 @@ import qualified Data.ByteString.Short as BSS import qualified Data.ByteString.Short.Internal as BSSI import Data.Char (ord)+import Data.Data (Data(..),constrIndex, Constr,+ mkConstr, DataType, mkDataType,+ Fixity(Prefix)) import Data.Hashable (Hashable)+import Data.Typeable (Typeable) import qualified Data.List as List import Data.Maybe (fromMaybe, isNothing) import Data.Semigroup@@ -150,10 +156,31 @@ -- In comparison, the footprint of a boxed 'ShortText' is only 4 words (i.e. 32 bytes on 64-bit systems) plus 1, 2, 3, or 4 bytes per code-point (due to the internal UTF-8 representation). -- It can be shown that for realistic data <http://utf8everywhere.org/#asian UTF-16 has a space overhead of 50% over UTF-8>. --+-- __NOTE__: The `Typeable` instance isn't defined for GHC 7.8 (and older) prior to @text-short-0.1.3@+-- -- @since 0.1 newtype ShortText = ShortText ShortByteString- deriving (Monoid,Data.Semigroup.Semigroup,Hashable,NFData)+ deriving (Hashable,Monoid,NFData,Data.Semigroup.Semigroup,Typeable) +-- | It exposes a similar 'Data' instance abstraction as 'T.Text' (see+-- discussion referenced there for more details), preserving the+-- @[Char]@ data abstraction at the cost of inefficiency.+--+-- @since 0.1.3+instance Data ShortText where+ gfoldl f z txt = z fromString `f` (toString txt)+ toConstr _ = packConstr+ gunfold k z c = case constrIndex c of+ 1 -> k (z fromString)+ _ -> error "gunfold"+ dataTypeOf _ = shortTextDataType++packConstr :: Constr+packConstr = mkConstr shortTextDataType "fromString" [] Prefix++shortTextDataType :: DataType+shortTextDataType = mkDataType "Data.Text.Short" [packConstr]+ instance Eq ShortText where {-# INLINE (==) #-} (==) x y@@ -326,13 +353,41 @@ !sz = toB st ++-- | \(\mathcal{O}(n)\) Splits a string into components delimited by separators,+-- where the predicate returns True for a separator element. The+-- resulting components do not contain the separators. Two adjacent+-- separators result in an empty component in the output. eg.+--+-- >>> split (=='a') "aabbaca"+-- ["","","bb","c",""]+--+-- >>> split (=='a') ""+-- [""]+--+-- prop> intercalate (singleton c) (split (== c) t) = t+--+-- __NOTE__: 'split' never returns an empty list to match the semantics of its counterpart from "Data.Text".+--+-- @since 0.1.3+split :: (Char -> Bool) -> ShortText -> [ShortText]+split p st0 = go 0+ where+ go !ofs0 = case findOfs' p st0 ofs0 of+ Just (ofs1,ofs2) -> slice st0 ofs0 (ofs1-ofs0) : go ofs2+ Nothing+ | ofs0 == 0 -> st0 : []+ | otherwise -> slice st0 ofs0 (maxOfs-ofs0) : []++ !maxOfs = toB st0+ -- internal helper {-# INLINE findOfs #-} findOfs :: (Char -> Bool) -> ShortText -> B -> Maybe B findOfs p st = go where go :: B -> Maybe B- go !ofs | ofs >= sz = Nothing+ go !ofs | ofs >= sz = Nothing go !ofs | p c = Just ofs | otherwise = go ofs' where@@ -340,6 +395,20 @@ !sz = toB st +{-# INLINE findOfs' #-}+findOfs' :: (Char -> Bool) -> ShortText -> B -> Maybe (B,B)+findOfs' p st = go+ where+ go :: B -> Maybe (B,B)+ go !ofs | ofs >= sz = Nothing+ go !ofs | p c = Just (ofs,ofs')+ | otherwise = go ofs'+ where+ (c,ofs') = decodeCharAtOfs st ofs++ !sz = toB st++ {-# INLINE findOfsRev #-} findOfsRev :: (Char -> Bool) -> ShortText -> B -> Maybe B findOfsRev p st = go@@ -744,7 +813,7 @@ -- | \(\mathcal{O}(n)\) Split 'ShortText' into two halves. ----- @'splitAtOfs n t@ returns a pair of 'ShortText' with the following properties:+-- @'splitAt' n t@ returns a pair of 'ShortText' with the following properties: -- -- prop> length (fst (splitAt n t)) == min (length t) (max 0 n) --@@ -803,7 +872,7 @@ splitAtOfs :: B -> ShortText -> (ShortText,ShortText) splitAtOfs ofs st | ofs == 0 = (mempty,st)- | ofs > stsz = (st,mempty)+ | ofs >= stsz = (st,mempty) | otherwise = (slice st 0 ofs, slice st ofs (stsz-ofs)) where !stsz = toB st@@ -1451,7 +1520,7 @@ -- | __Note__: Surrogate pairs (@[U+D800 .. U+DFFF]@) in string literals are replaced by U+FFFD. ----- This matches the behaviour of 'IsString' instance for 'T.Text'.+-- This matches the behaviour of 'S.IsString' instance for 'T.Text'. instance S.IsString ShortText where fromString = fromStringLit
text-short.cabal view
@@ -1,7 +1,7 @@ cabal-version: 1.18 name: text-short-version: 0.1.2+version: 0.1.3 synopsis: Memory-efficient representation of Unicode text strings license: BSD3 license-file: LICENSE@@ -14,7 +14,7 @@ . The main difference between 'Text' and 'ShortText' is that 'ShortText' uses UTF-8 instead of UTF-16 internally and also doesn't support zero-copy slicing (thereby saving 2 words). Consequently, the memory footprint of a (boxed) 'ShortText' value is 4 words (2 words when unboxed) plus the length of the UTF-8 encoded payload. -tested-with: GHC==8.4.1, GHC==8.2.2, GHC==8.0.2, GHC==7.10.3, GHC==7.8.4+tested-with: GHC==8.6.5, GHC==8.4.4, GHC==8.2.2, GHC==8.0.2, GHC==7.10.3, GHC==7.8.4 extra-source-files: ChangeLog.md Source-Repository head@@ -33,16 +33,16 @@ other-modules: Data.Text.Short.Internal - build-depends: base >= 4.7 && < 4.12+ build-depends: base >= 4.7 && < 4.13 , bytestring >= 0.10.4 && < 0.11- , hashable >= 1.2.6 && < 1.3+ , hashable >= 1.2.6 && < 1.4 , deepseq >= 1.3 && < 1.5 , text >= 1.0 && < 1.3 , binary >= 0.7.1 && < 0.9 , ghc-prim >= 0.3.1 && < 0.6 if !impl(ghc >= 8.0)- build-depends: semigroups >= 0.18.2 && < 0.19+ build-depends: semigroups >= 0.18.2 && < 0.20 -- GHC version specific PrimOps if impl(ghc >= 8.4)@@ -82,7 +82,7 @@ , text , text-short -- deps which don't inherit constraints from library stanza:- , tasty >= 1.0.0 && < 1.1+ , tasty >= 1.0.0 && < 1.3 , tasty-quickcheck >= 0.10 && < 0.11 , tasty-hunit >= 0.10.0 && < 0.11 , quickcheck-instances >= 0.3.14 && < 0.4