packages feed

text-builder (empty) → 0.4

raw patch · 9 files changed

+506/−0 lines, 9 filesdep +basedep +base-preludedep +bytestringsetup-changed

Dependencies added: base, base-prelude, bytestring, criterion, quickcheck-instances, rerebase, semigroups, tasty, tasty-hunit, tasty-quickcheck, tasty-smallcheck, text, text-builder

Files

+ LICENSE view
@@ -0,0 +1,22 @@+Copyright (c) 2015, Nikita Volkov++Permission is hereby granted, free of charge, to any person+obtaining a copy of this software and associated documentation+files (the "Software"), to deal in the Software without+restriction, including without limitation the rights to use,+copy, modify, merge, publish, distribute, sublicense, and/or sell+copies of the Software, and to permit persons to whom the+Software is furnished to do so, subject to the following+conditions:++The above copyright notice and this permission notice shall be+included in all copies or substantial portions of the Software.++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT+HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR+OTHER DEALINGS IN THE SOFTWARE.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ char-benchmark/Main.hs view
@@ -0,0 +1,65 @@+module Main where++import Prelude+import Criterion.Main+import qualified Text.Builder as A+import qualified Data.Text.Lazy.Builder as B+import qualified Data.Text.Lazy as C+import qualified Data.Text as D+++main =+  defaultMain $+  [+    subjectBenchmark "builderSubject" builderSubject+    ,+    subjectBenchmark "lazyTextBuilderSubject" lazyTextBuilderSubject+    ,+    subjectBenchmark "plainTextPackingSubject" plainTextPackingSubject+  ]++subjectBenchmark :: String -> Subject -> Benchmark+subjectBenchmark title subject =+  bgroup title $+  [+    benchmark "Small input" smallInput subject+    ,+    benchmark "Medium input" mediumInput subject+    ,+    benchmark "Large input" largeInput subject+  ]++benchmark :: String -> [Int] -> Subject -> Benchmark+benchmark title input subject =+  bench title $ nf subject $ input++type Subject =+  [Int] -> Text++builderSubject :: Subject+builderSubject =+  A.run . A.string . map chr++lazyTextBuilderSubject :: Subject+lazyTextBuilderSubject =+  C.toStrict . B.toLazyText . B.fromString . map chr++plainTextPackingSubject :: Subject+plainTextPackingSubject =+  D.pack . map chr++{-# NOINLINE smallInput #-}+smallInput :: [Int]+!smallInput =+  map ord ['a', 'b', 'Ф', '漢', chr 0x11000]++{-# NOINLINE mediumInput #-}+mediumInput :: [Int]+!mediumInput =+  mconcat (replicate 1000 smallInput)++{-# NOINLINE largeInput #-}+largeInput :: [Int]+!largeInput =+  mconcat (replicate 100000 smallInput)+
+ library/Text/Builder.hs view
@@ -0,0 +1,129 @@+module Text.Builder+(+  Builder,+  run,+  char,+  text,+  string,+  utf16CodeUnits1,+  utf16CodeUnits2,+  utf8CodeUnits1,+  utf8CodeUnits2,+  utf8CodeUnits3,+  utf8CodeUnits4,+)+where++import Text.Builder.Prelude+import qualified Data.Text.Array as B+import qualified Data.Text.Internal as C+import qualified Text.Builder.UTF16 as D+++newtype Action =+  Action (forall s. B.MArray s -> Int -> ST s ())++data Builder =+  Builder !Action !Int++instance Monoid Builder where+  {-# INLINE mempty #-}+  mempty =+    Builder (Action (\_ _ -> return ())) 0+  {-# INLINABLE mappend #-}+  mappend (Builder (Action action1) size1) (Builder (Action action2) size2) =+    Builder action size+    where+      action =+        Action $ \array offset -> do+          action1 array offset+          action2 array (offset + size1)+      size =+        size1 + size2+  {-# INLINE mconcat #-}+  mconcat list =+    Builder action size+    where+      action =+        Action $ \array offset -> foldlM (step array) offset list $> ()+        where+          step array offset (Builder (Action action) size) =+            action array offset $> offset + size+      size =+        sum (map (\(Builder _ x) -> x) list)++instance Semigroup Builder++{-# INLINE char #-}+char :: Char -> Builder+char x =+  unicodeCodePoint (ord x)++{-# INLINE unicodeCodePoint #-}+unicodeCodePoint :: Int -> Builder+unicodeCodePoint x =+  D.unicodeCodePoint x utf16CodeUnits1 utf16CodeUnits2++{-# INLINABLE utf16CodeUnits1 #-}+utf16CodeUnits1 :: Word16 -> Builder+utf16CodeUnits1 unit =+  Builder action 1+  where+    action =+      Action $ \array offset -> B.unsafeWrite array offset unit++{-# INLINABLE utf16CodeUnits2 #-}+utf16CodeUnits2 :: Word16 -> Word16 -> Builder+utf16CodeUnits2 unit1 unit2 =+  Builder action 2+  where+    action =+      Action $ \array offset -> do+        B.unsafeWrite array offset unit1+        B.unsafeWrite array (succ offset) unit2++{-# INLINE utf8CodeUnits1 #-}+utf8CodeUnits1 :: Word8 -> Builder+utf8CodeUnits1 unit1 =+  D.utf8CodeUnits1 unit1 utf16CodeUnits1 utf16CodeUnits2++{-# INLINE utf8CodeUnits2 #-}+utf8CodeUnits2 :: Word8 -> Word8 -> Builder+utf8CodeUnits2 unit1 unit2 =+  D.utf8CodeUnits2 unit1 unit2 utf16CodeUnits1 utf16CodeUnits2++{-# INLINE utf8CodeUnits3 #-}+utf8CodeUnits3 :: Word8 -> Word8 -> Word8 -> Builder+utf8CodeUnits3 unit1 unit2 unit3 =+  D.utf8CodeUnits3 unit1 unit2 unit3 utf16CodeUnits1 utf16CodeUnits2++{-# INLINE utf8CodeUnits4 #-}+utf8CodeUnits4 :: Word8 -> Word8 -> Word8 -> Word8 -> Builder+utf8CodeUnits4 unit1 unit2 unit3 unit4 =+  D.utf8CodeUnits4 unit1 unit2 unit3 unit4 utf16CodeUnits1 utf16CodeUnits2++{-# INLINABLE text #-}+text :: Text -> Builder+text (C.Text array offset length) =+  Builder action actualLength+  where+    action =+      Action $ \builderArray builderOffset -> do+        B.copyI builderArray builderOffset array offset (builderOffset + actualLength)+    actualLength =+      length - offset++{-# INLINE string #-}+string :: String -> Builder+string =+  foldMap char++run :: Builder -> Text+run (Builder (Action action) size) =+  C.text array 0 size+  where+    array =+      runST $ do+        array <- B.new size+        action array 0+        B.unsafeFreeze array
+ library/Text/Builder/Prelude.hs view
@@ -0,0 +1,22 @@+module Text.Builder.Prelude+( +  module Exports,+)+where+++-- base-prelude+-------------------------+import BasePrelude as Exports hiding (assert, left, right, isLeft, isRight, error, First(..), Last(..), (<>))++-- semigroup+-------------------------+import Data.Semigroup as Exports++-- bytestring+-------------------------+import Data.ByteString as Exports (ByteString)++-- text+-------------------------+import Data.Text as Exports (Text)
+ library/Text/Builder/UTF16.hs view
@@ -0,0 +1,61 @@+module Text.Builder.UTF16+where++import Text.Builder.Prelude+++{-|+A matching function, which chooses the continuation to run.+-}+type UTF16View =+  forall x. (Word16 -> x) -> (Word16 -> Word16 -> x) -> x++{-# INLINE char #-}+char :: Char -> UTF16View+char =+  unicodeCodePoint . ord++{-# INLINE unicodeCodePoint #-}+unicodeCodePoint :: Int -> UTF16View+unicodeCodePoint x case1 case2 =+  if x < 0x10000+    then case1 (fromIntegral x)+    else case2 case2Unit1 case2Unit2+  where+    m =+      x - 0x10000+    case2Unit1 =+      fromIntegral (shiftR m 10 + 0xD800)+    case2Unit2 =+      fromIntegral ((m .&. 0x3FF) + 0xDC00)++{-# INLINE utf8CodeUnits1 #-}+utf8CodeUnits1 :: Word8 -> UTF16View+utf8CodeUnits1 x case1 _ =+  case1 (fromIntegral x)++{-# INLINE utf8CodeUnits2 #-}+utf8CodeUnits2 :: Word8 -> Word8 -> UTF16View+utf8CodeUnits2 byte1 byte2 case1 _ =+  case1 (shiftL (fromIntegral byte1 - 0xC0) 6 + fromIntegral byte2 - 0x80)++{-# INLINE utf8CodeUnits3 #-}+utf8CodeUnits3 :: Word8 -> Word8 -> Word8 -> UTF16View+utf8CodeUnits3 byte1 byte2 byte3 case1 case2 =+  unicodeCodePoint unicode case1 case2+  where+    unicode =+      shiftL (fromIntegral byte1 - 0xE0) 12 ++      shiftL (fromIntegral byte2 - 0x80) 6 ++      fromIntegral byte3 - 0x80++{-# INLINE utf8CodeUnits4 #-}+utf8CodeUnits4 :: Word8 -> Word8 -> Word8 -> Word8 -> UTF16View+utf8CodeUnits4 byte1 byte2 byte3 byte4 case1 case2 =+  unicodeCodePoint unicode case1 case2+  where+    unicode =+      shiftL (fromIntegral byte1 - 0xE0) 18 ++      shiftL (fromIntegral byte2 - 0x80) 12 ++      shiftL (fromIntegral byte3 - 0x80) 6 ++      fromIntegral byte4 - 0x80
+ tests/Main.hs view
@@ -0,0 +1,25 @@+module Main where++import Prelude+import Test.QuickCheck.Instances+import Test.Tasty+import Test.Tasty.HUnit+import Test.Tasty.QuickCheck+import qualified Data.Text as A+import qualified Text.Builder as B+++main =+  defaultMain $+  testGroup "All tests" $+  [+    testProperty "Packing a list of chars is isomorphic to appending a list of builders" $+    \chars ->+      A.pack chars ===+      B.run (foldMap B.char chars)+    ,+    testProperty "Concatting a list of texts is isomorphic to concatting a list of builders" $+    \texts ->+      mconcat texts ===+      B.run (foldMap B.text texts)+  ]
+ text-benchmark/Main.hs view
@@ -0,0 +1,58 @@+module Main where++import Prelude+import Criterion.Main+import qualified Text.Builder as A+import qualified Data.Text.Lazy.Builder as B+import qualified Data.Text.Lazy as C+import qualified Data.Text as D+++main =+  defaultMain $+  [+    subjectBenchmark "builderSubject" builderSubject+    ,+    subjectBenchmark "lazyTextBuilderSubject" lazyTextBuilderSubject+  ]++subjectBenchmark :: String -> Subject -> Benchmark+subjectBenchmark title subject =+  bgroup title $+  [+    benchmark "Small input" smallSample subject+    ,+    benchmark "Large input" largeSample subject+  ]++benchmark :: String -> Sample -> Subject -> Benchmark+benchmark title sample subject =+  bench title $ nf sample $ subject++data Subject =+  forall a. Subject (Text -> a) (a -> a -> a) a (a -> Text)++type Sample =+  Subject -> Text++builderSubject :: Subject+builderSubject =+  Subject A.text mappend mempty A.run++lazyTextBuilderSubject :: Subject+lazyTextBuilderSubject =+  Subject B.fromText mappend mempty (C.toStrict . B.toLazyText)++{-# NOINLINE smallSample #-}+smallSample :: Sample+smallSample (Subject text (<>) mempty run) =+  run $+  text "abcd" <> (text "ABCD" <> text "Фываолдж") <> text "漢"++{-# NOINLINE largeSample #-}+largeSample :: Sample+largeSample (Subject text (<>) mempty run) =+  run $+  foldl' (<>) mempty $ replicate 100000 $+  text "abcd" <> (text "ABCD" <> text "Фываолдж") <> text "漢"+
+ text-builder.cabal view
@@ -0,0 +1,122 @@+name:+  text-builder+version:+  0.4+category:+  Text+synopsis:+  An efficient strict text builder+homepage:+  https://github.com/nikita-volkov/text-builder +bug-reports:+  https://github.com/nikita-volkov/text-builder/issues +author:+  Nikita Volkov <nikita.y.volkov@mail.ru>+maintainer:+  Nikita Volkov <nikita.y.volkov@mail.ru>+copyright:+  (c) 2017, Nikita Volkov+license:+  MIT+license-file:+  LICENSE+build-type:+  Simple+cabal-version:+  >=1.10++source-repository head+  type:+    git+  location:+    git://github.com/nikita-volkov/text-builder.git++library+  hs-source-dirs:+    library+  ghc-options:+  default-extensions:+    Arrows, BangPatterns, ConstraintKinds, DataKinds, DefaultSignatures, DeriveDataTypeable, DeriveFoldable, DeriveFunctor, DeriveGeneric, DeriveTraversable, EmptyDataDecls, FlexibleContexts, FlexibleInstances, FunctionalDependencies, GADTs, GeneralizedNewtypeDeriving, LambdaCase, LiberalTypeSynonyms, MagicHash, MultiParamTypeClasses, MultiWayIf, NoImplicitPrelude, NoMonomorphismRestriction, OverloadedStrings, PatternGuards, ParallelListComp, QuasiQuotes, RankNTypes, RecordWildCards, ScopedTypeVariables, StandaloneDeriving, TemplateHaskell, TupleSections, TypeFamilies, TypeOperators, UnboxedTuples+  default-language:+    Haskell2010+  exposed-modules:+    Text.Builder+  other-modules:+    Text.Builder.UTF16+    Text.Builder.Prelude+  build-depends:+    semigroups >= 0.18 && < 0.19,+    bytestring >= 0.10 && < 0.11,+    text >= 1 && < 2,+    base-prelude < 2,+    base >= 4.6 && < 5++test-suite tests+  type:+    exitcode-stdio-1.0+  hs-source-dirs:+    tests+  main-is:+    Main.hs+  default-extensions:+    Arrows, BangPatterns, ConstraintKinds, DataKinds, DefaultSignatures, DeriveDataTypeable, DeriveFoldable, DeriveFunctor, DeriveGeneric, DeriveTraversable, EmptyDataDecls, FlexibleContexts, FlexibleInstances, FunctionalDependencies, GADTs, GeneralizedNewtypeDeriving, LambdaCase, LiberalTypeSynonyms, MagicHash, MultiParamTypeClasses, MultiWayIf, NoImplicitPrelude, NoMonomorphismRestriction, OverloadedStrings, PatternGuards, ParallelListComp, QuasiQuotes, RankNTypes, RecordWildCards, ScopedTypeVariables, StandaloneDeriving, TemplateHaskell, TupleSections, TypeFamilies, TypeOperators, UnboxedTuples+  default-language:+    Haskell2010+  build-depends:+    text-builder,+    -- testing:+    tasty == 0.11.*,+    tasty-quickcheck == 0.8.*,+    tasty-smallcheck == 0.8.*,+    tasty-hunit == 0.9.*,+    quickcheck-instances >= 0.3.11 && < 0.4,+    -- general:+    rerebase == 1.*++benchmark text-benchmark+  type: +    exitcode-stdio-1.0+  hs-source-dirs:+    text-benchmark+  main-is:+    Main.hs+  ghc-options:+    -O2+    -threaded+    "-with-rtsopts=-N"+    -funbox-strict-fields+  default-extensions:+    Arrows, BangPatterns, ConstraintKinds, DataKinds, DefaultSignatures, DeriveDataTypeable, DeriveFoldable, DeriveFunctor, DeriveTraversable, DeriveGeneric, EmptyDataDecls, FlexibleContexts, FlexibleInstances, FunctionalDependencies, GADTs, GeneralizedNewtypeDeriving, LambdaCase, LiberalTypeSynonyms, MagicHash, MultiParamTypeClasses, MultiWayIf, NoImplicitPrelude, NoMonomorphismRestriction, OverloadedStrings, PatternGuards, ParallelListComp, QuasiQuotes, RankNTypes, RecordWildCards, ScopedTypeVariables, StandaloneDeriving, TemplateHaskell, TupleSections, TypeFamilies, TypeOperators, UnboxedTuples+  default-language:+    Haskell2010+  build-depends:+    -- +    text-builder,+    -- benchmarking:+    criterion == 1.1.*,+    -- general:+    rerebase == 1.*++benchmark char-benchmark+  type: +    exitcode-stdio-1.0+  hs-source-dirs:+    char-benchmark+  main-is:+    Main.hs+  ghc-options:+    -O2+    -threaded+    "-with-rtsopts=-N"+    -funbox-strict-fields+  default-extensions:+    Arrows, BangPatterns, ConstraintKinds, DataKinds, DefaultSignatures, DeriveDataTypeable, DeriveFoldable, DeriveFunctor, DeriveTraversable, DeriveGeneric, EmptyDataDecls, FlexibleContexts, FlexibleInstances, FunctionalDependencies, GADTs, GeneralizedNewtypeDeriving, LambdaCase, LiberalTypeSynonyms, MagicHash, MultiParamTypeClasses, MultiWayIf, NoImplicitPrelude, NoMonomorphismRestriction, OverloadedStrings, PatternGuards, ParallelListComp, QuasiQuotes, RankNTypes, RecordWildCards, ScopedTypeVariables, StandaloneDeriving, TemplateHaskell, TupleSections, TypeFamilies, TypeOperators, UnboxedTuples+  default-language:+    Haskell2010+  build-depends:+    -- +    text-builder,+    -- benchmarking:+    criterion == 1.1.*,+    -- general:+    rerebase == 1.*