|
1 |
| -{-# LANGUAGE ScopedTypeVariables, CPP, BangPatterns, RankNTypes, TupleSections #-} |
| 1 | +{-# LANGUAGE ScopedTypeVariables, CPP, BangPatterns, RankNTypes, TupleSections, |
| 2 | + PatternSynonyms #-} |
2 | 3 | {-# LANGUAGE Unsafe #-}
|
3 | 4 | {-# OPTIONS_HADDOCK not-home #-}
|
4 | 5 | -- | Copyright : (c) 2010 - 2011 Simon Meier
|
@@ -137,6 +138,7 @@ import qualified Data.ByteString.Internal.Type as S
|
137 | 138 | import qualified Data.ByteString.Lazy.Internal as L
|
138 | 139 | import qualified Data.ByteString.Short.Internal as Sh
|
139 | 140 |
|
| 141 | +import qualified GHC.Exts |
140 | 142 | import qualified GHC.IO.Buffer as IO (Buffer(..), newByteBuffer)
|
141 | 143 | import GHC.IO.Handle.Internals (wantWritableHandle, flushWriteBuffer)
|
142 | 144 | import GHC.IO.Handle.Types (Handle__, haByteBuffer, haBufferMode)
|
@@ -326,7 +328,31 @@ fillWithBuildStep step fDone fFull fChunk !br = do
|
326 | 328 | -- They are 'Monoid's where
|
327 | 329 | -- 'mempty' is the zero-length sequence and
|
328 | 330 | -- 'mappend' is concatenation, which runs in /O(1)/.
|
| 331 | +#if (MIN_VERSION_base(4,10,0)) |
| 332 | +newtype Builder = Builder' (forall r. BuildStep r -> BuildStep r) |
| 333 | +pattern Builder :: (forall r. BuildStep r -> BuildStep r) -> Builder |
| 334 | +pattern Builder f <- Builder' f |
| 335 | + where |
| 336 | + -- We want to tell the compiler to eta-expand over the BufferRange of a |
| 337 | + -- BuildStep the same as it eta-expands over State# tokens. |
| 338 | + -- This is important for loops such as `foldMap (B.word8 . fromIntegral) xs` |
| 339 | + -- (see https://gitlab.haskell.org/ghc/ghc/-/issues/23822#note_520437) |
| 340 | + -- where otherwise the compiler thinks `empty bs` is worth sharing. |
| 341 | + -- The usual way to do that is via GHC.Exts.oneShot on `\br`. |
| 342 | + -- |
| 343 | + -- By contrast, we refrain from marking the BuildStep argument as one-shot, |
| 344 | + -- because that could lead to undesirable duplication of work in an |
| 345 | + -- expression like |
| 346 | + -- |
| 347 | + -- > let t = expensive 42 in stimes 1000 (Builder $ \bs br -> ... t ...) |
| 348 | + -- |
| 349 | + -- Marking `\bs` one-shot as well tells the compiler that it's fine to float |
| 350 | + -- the definition of `t` inside the builder -- thus executing `expensive` |
| 351 | + -- 1000 times instead of just once. |
| 352 | + Builder f = Builder' (\bs -> GHC.Exts.oneShot $ \br -> f bs br) |
| 353 | +#else |
329 | 354 | newtype Builder = Builder (forall r. BuildStep r -> BuildStep r)
|
| 355 | +#endif |
330 | 356 |
|
331 | 357 | -- | Construct a 'Builder'. In contrast to 'BuildStep's, 'Builder's are
|
332 | 358 | -- referentially transparent.
|
|
0 commit comments