|
1 | 1 | {-# LANGUAGE Unsafe #-} |
| 2 | +{-# LANGUAGE TypeFamilies #-} |
| 3 | +{-# LANGUAGE NoMonoLocalBinds #-} |
2 | 4 |
|
3 | 5 | {-# OPTIONS_HADDOCK not-home #-} |
4 | 6 |
|
@@ -99,6 +101,7 @@ module Data.ByteString.Builder.Internal ( |
99 | 101 | , lazyByteString |
100 | 102 |
|
101 | 103 | -- ** Execution |
| 104 | + , toLazyByteString |
102 | 105 | , toLazyByteStringWith |
103 | 106 | , AllocationStrategy |
104 | 107 | , safeStrategy |
@@ -129,6 +132,7 @@ module Data.ByteString.Builder.Internal ( |
129 | 132 |
|
130 | 133 | import Control.Arrow (second) |
131 | 134 | import Control.DeepSeq (NFData(..)) |
| 135 | +import GHC.Exts (IsList(..)) |
132 | 136 |
|
133 | 137 | import Data.Semigroup (Semigroup(..)) |
134 | 138 | import Data.List.NonEmpty (NonEmpty(..)) |
@@ -426,6 +430,13 @@ instance Monoid Builder where |
426 | 430 | {-# INLINE mconcat #-} |
427 | 431 | mconcat = foldr mappend mempty |
428 | 432 |
|
| 433 | +-- | For long or infinite lists use 'fromList' because it uses 'LazyByteString' otherwise use 'fromListN' which uses 'StrictByteString'. |
| 434 | +instance IsList Builder where |
| 435 | + type Item Builder = Word8 |
| 436 | + fromList = lazyByteString . fromList |
| 437 | + fromListN n = byteString . fromListN n |
| 438 | + toList = toList . toLazyByteString |
| 439 | + |
429 | 440 | -- | Flush the current buffer. This introduces a chunk boundary. |
430 | 441 | {-# INLINE flush #-} |
431 | 442 | flush :: Builder |
@@ -1052,27 +1063,35 @@ safeStrategy firstSize bufSize = |
1052 | 1063 | nextBuffer Nothing = newBuffer $ sanitize firstSize |
1053 | 1064 | nextBuffer (Just (_, minSize)) = newBuffer minSize |
1054 | 1065 |
|
| 1066 | +-- | Execute a 'Builder' and return the generated chunks as a 'L.LazyByteString'. |
| 1067 | +-- The work is performed lazy, i.e., only when a chunk of the 'L.LazyByteString' |
| 1068 | +-- is forced. |
| 1069 | +{-# NOINLINE toLazyByteString #-} -- ensure code is shared |
| 1070 | +toLazyByteString :: Builder -> L.LazyByteString |
| 1071 | +toLazyByteString = toLazyByteStringWith |
| 1072 | + (safeStrategy L.smallChunkSize L.defaultChunkSize) L.Empty |
| 1073 | + |
1055 | 1074 | -- | /Heavy inlining./ Execute a 'Builder' with custom execution parameters. |
1056 | 1075 | -- |
1057 | 1076 | -- This function is inlined despite its heavy code-size to allow fusing with |
1058 | 1077 | -- the allocation strategy. For example, the default 'Builder' execution |
1059 | | --- function 'Data.ByteString.Builder.toLazyByteString' is defined as follows. |
| 1078 | +-- function 'Data.ByteString.Builder.Internal.toLazyByteString' is defined as follows. |
1060 | 1079 | -- |
1061 | 1080 | -- @ |
1062 | 1081 | -- {-\# NOINLINE toLazyByteString \#-} |
1063 | 1082 | -- toLazyByteString = |
1064 | | --- toLazyByteStringWith ('safeStrategy' 'L.smallChunkSize' 'L.defaultChunkSize') L.empty |
| 1083 | +-- toLazyByteStringWith ('safeStrategy' 'L.smallChunkSize' 'L.defaultChunkSize') L.Empty |
1065 | 1084 | -- @ |
1066 | 1085 | -- |
1067 | | --- where @L.empty@ is the zero-length 'L.LazyByteString'. |
| 1086 | +-- where @L.Empty@ is the zero-length 'L.LazyByteString'. |
1068 | 1087 | -- |
1069 | 1088 | -- In most cases, the parameters used by 'Data.ByteString.Builder.toLazyByteString' give good |
1070 | 1089 | -- performance. A sub-performing case of 'Data.ByteString.Builder.toLazyByteString' is executing short |
1071 | 1090 | -- (<128 bytes) 'Builder's. In this case, the allocation overhead for the first |
1072 | 1091 | -- 4kb buffer and the trimming cost dominate the cost of executing the |
1073 | 1092 | -- 'Builder'. You can avoid this problem using |
1074 | 1093 | -- |
1075 | | --- >toLazyByteStringWith (safeStrategy 128 smallChunkSize) L.empty |
| 1094 | +-- >toLazyByteStringWith (safeStrategy 128 smallChunkSize) L.Empty |
1076 | 1095 | -- |
1077 | 1096 | -- This reduces the allocation and trimming overhead, as all generated |
1078 | 1097 | -- 'L.LazyByteString's fit into the first buffer and there is no trimming |
|
0 commit comments