@@ -39,8 +39,10 @@ module Data.Text.Internal.Builder
39
39
( -- * Public API
40
40
-- ** The Builder type
41
41
Builder
42
+ , getTexts
42
43
, toLazyText
43
44
, toLazyTextWith
45
+ , starter
44
46
45
47
-- ** Constructing Builders
46
48
, singleton
@@ -91,11 +93,19 @@ import GHC.Stack (HasCallStack)
91
93
newtype Builder = Builder {
92
94
-- Invariant (from Data.Text.Lazy):
93
95
-- The lists include no null Texts.
94
- runBuilder :: forall s . (Buffer s -> ST s [S. Text ])
96
+ runBuilder :: forall s
97
+ . (Int -> (Int -> ST s (A. MArray s )) -> Buffer s -> ST s [S. Text ])
98
+ -> Int -- buffer size
99
+ -> (Int -> ST s (A. MArray s )) -- new array
95
100
-> Buffer s
96
101
-> ST s [S. Text ]
97
102
}
98
103
104
+ getTexts :: Int -> (Int -> ST s (A. MArray s )) -> Builder -> ST s [S. Text ]
105
+ getTexts chunkSize new b =
106
+ newBuffer new chunkSize >>= runBuilder (b `append` flush) starter chunkSize new
107
+
108
+
99
109
instance Semigroup Builder where
100
110
(<>) = append
101
111
{-# INLINE (<>) #-}
@@ -133,7 +143,7 @@ instance Ord Builder where
133
143
-- * @'toLazyText' 'empty' = 'L.empty'@
134
144
--
135
145
empty :: Builder
136
- empty = Builder (\ k buf -> k buf)
146
+ empty = Builder (\ k new buf -> k new buf)
137
147
{-# INLINE empty #-}
138
148
139
149
-- | /O(1)./ A @Builder@ taking a single character, satisfying
@@ -157,6 +167,7 @@ singleton c = writeAtMost 4 $ \ marr o -> unsafeWrite marr o (safe c)
157
167
--
158
168
append :: Builder -> Builder -> Builder
159
169
append (Builder f) (Builder g) = Builder (f . g)
170
+ -- append (Builder f) (Builder g) = Builder $ \ k new buf -> f (g k) new buf
160
171
{-# INLINE [0] append #-}
161
172
162
173
-- TODO: Experiment to find the right threshold.
@@ -193,22 +204,20 @@ fromText t@(Text arr off l)
193
204
--
194
205
-- @since 1.2.0.0
195
206
fromString :: String -> Builder
196
- fromString str = Builder $ \ k (Buffer p0 o0 u0 l0) ->
197
- let loop ! marr ! o ! u ! l [] = k (Buffer marr o u l)
207
+ fromString str = Builder $ \ k chunkSize new (Buffer p0 o0 u0 l0) ->
208
+ let loop ! marr ! o ! u ! l [] = k chunkSize new (Buffer marr o u l)
198
209
loop marr o u l s@ (c: cs)
199
210
| l <= 3 = do
200
211
A. shrinkM marr (o + u)
201
212
arr <- A. unsafeFreeze marr
202
213
let ! t = Text arr o u
203
- marr' <- A. new chunkSize
214
+ marr' <- new chunkSize
204
215
ts <- inlineInterleaveST (loop marr' 0 0 chunkSize s)
205
216
return $ t : ts
206
217
| otherwise = do
207
218
n <- unsafeWrite marr (o+ u) (safe c)
208
219
loop marr o (u+ n) (l- n) cs
209
220
in loop p0 o0 u0 l0 str
210
- where
211
- chunkSize = smallChunkSize
212
221
{-# INLINEABLE fromString #-}
213
222
214
223
-- | /O(1)./ A @Builder@ taking a lazy @Text@, satisfying
@@ -243,18 +252,21 @@ toLazyText = toLazyTextWith smallChunkSize
243
252
-- buffers will be the default buffer size.
244
253
toLazyTextWith :: Int -> Builder -> L. Text
245
254
toLazyTextWith chunkSize m = L. fromChunks (runST $
246
- newBuffer chunkSize >>= runBuilder (m `append` flush) (const (return [] )))
255
+ newBuffer A. new chunkSize >>= runBuilder (m `append` flush) starter smallChunkSize A. new)
256
+
257
+ starter :: Monad m => a -> b -> c -> m [d ]
258
+ starter _ _ _ = return []
247
259
248
260
-- | /O(1)./ Pop the strict @Text@ we have constructed so far, if any,
249
261
-- yielding a new chunk in the result lazy @Text@.
250
262
flush :: Builder
251
- flush = Builder $ \ k buf@ (Buffer p o u l) ->
263
+ flush = Builder $ \ k cs new buf@ (Buffer p o u l) ->
252
264
if u == 0
253
- then k buf
265
+ then k cs new buf
254
266
else do arr <- A. unsafeFreeze p
255
267
let ! b = Buffer p (o+ u) 0 l
256
268
! t = Text arr o u
257
- ts <- inlineInterleaveST (k b)
269
+ ts <- inlineInterleaveST (k cs new b)
258
270
return $! t : ts
259
271
{-# INLINE [1] flush #-}
260
272
-- defer inlining so that flush/flush rule may fire.
@@ -263,18 +275,18 @@ flush = Builder $ \ k buf@(Buffer p o u l) ->
263
275
264
276
-- | Sequence an ST operation on the buffer
265
277
withBuffer :: (forall s . Buffer s -> ST s (Buffer s )) -> Builder
266
- withBuffer f = Builder $ \ k buf -> f buf >>= k
278
+ withBuffer f = Builder $ \ k cs new buf -> f buf >>= k cs new
267
279
{-# INLINE withBuffer #-}
268
280
269
281
-- | Get the size of the buffer
270
282
withSize :: (Int -> Builder ) -> Builder
271
- withSize f = Builder $ \ k buf@ (Buffer _ _ _ l) ->
272
- runBuilder (f l) k buf
283
+ withSize f = Builder $ \ k cs new buf@ (Buffer _ _ _ l) ->
284
+ runBuilder (f l) k cs new buf
273
285
{-# INLINE withSize #-}
274
286
275
287
-- | Map the resulting list of texts.
276
288
mapBuilder :: ([S. Text ] -> [S. Text ]) -> Builder
277
- mapBuilder f = Builder ( fmap f . )
289
+ mapBuilder f = Builder $ \ k cs new b -> f <$> k cs new b
278
290
279
291
------------------------------------------------------------------------
280
292
@@ -283,7 +295,7 @@ ensureFree :: Int -> Builder
283
295
ensureFree ! n = withSize $ \ l ->
284
296
if n <= l
285
297
then empty
286
- else flush `append'` withBuffer ( const ( newBuffer (max n smallChunkSize) ))
298
+ else flush `append'` Builder ( \ k chunkSize new _ -> k chunkSize new =<< newBuffer new (max n chunkSize ))
287
299
{-# INLINE [0] ensureFree #-}
288
300
289
301
writeAtMost :: Int -> (forall s . A. MArray s -> Int -> ST s Int ) -> Builder
@@ -302,9 +314,9 @@ writeBuffer f (Buffer p o u l) = do
302
314
return $! Buffer p o (u+ n) (l- n)
303
315
{-# INLINE writeBuffer #-}
304
316
305
- newBuffer :: Int -> ST s (Buffer s )
306
- newBuffer size = do
307
- arr <- A. new size
317
+ newBuffer :: ( Int -> ST s ( A. MArray s )) -> Int -> ST s (Buffer s )
318
+ newBuffer new size = do
319
+ arr <- new size
308
320
return $! Buffer arr 0 0 size
309
321
{-# INLINE newBuffer #-}
310
322
0 commit comments