|
1 | | -{-# LANGUAGE BangPatterns, CPP, ScopedTypeVariables #-} |
| 1 | +{-# LANGUAGE BangPatterns, ScopedTypeVariables #-} |
2 | 2 | {-# LANGUAGE MagicHash, UnboxedTuples, PatternGuards #-} |
3 | 3 | {-# OPTIONS_GHC -fno-warn-unused-imports #-} |
4 | 4 | {-# LANGUAGE Trustworthy #-} |
@@ -433,8 +433,8 @@ module Data.ByteString.Builder.Prim ( |
433 | 433 | -- a decimal number with UTF-8 encoded characters. |
434 | 434 | , charUtf8 |
435 | 435 |
|
436 | | - , cstring |
437 | | - , cstringUtf8 |
| 436 | + , cstring -- Backwards-compatibility re-exports from Internal.hs |
| 437 | + , cstringUtf8 -- these no longer make use of the BoundPrim API. |
438 | 438 |
|
439 | 439 | {- |
440 | 440 | -- * Testing support |
@@ -468,6 +468,7 @@ import Data.ByteString.Builder.Prim.ASCII |
468 | 468 |
|
469 | 469 | import Foreign |
470 | 470 | import Foreign.C.Types |
| 471 | +import Foreign.C.String (CString) |
471 | 472 | import Foreign.ForeignPtr.Unsafe (unsafeForeignPtrToPtr) |
472 | 473 | import GHC.Int (Int (..)) |
473 | 474 | import GHC.Word (Word8 (..)) |
@@ -664,97 +665,6 @@ primMapLazyByteStringBounded w = |
664 | 665 | L.foldrChunks (\x b -> primMapByteStringBounded w x `mappend` b) mempty |
665 | 666 |
|
666 | 667 |
|
667 | | ------------------------------------------------------------------------------- |
668 | | --- Raw CString encoding |
669 | | ------------------------------------------------------------------------------- |
670 | | - |
671 | | --- | A null-terminated ASCII encoded 'Foreign.C.String.CString'. |
672 | | --- Null characters are not representable. |
673 | | --- |
674 | | --- @since 0.11.0.0 |
675 | | -cstring :: Addr# -> Builder |
676 | | -cstring = \addr0 -> builder $ \k br -> do |
677 | | -#if __GLASGOW_HASKELL__ >= 811 |
678 | | - let len = cstringLength# addr0 |
679 | | -#else |
680 | | - (I# len) <- fromIntegral <$> S.c_strlen (Ptr addr0) |
681 | | -#endif |
682 | | - cstring_step addr0 len k br |
683 | | -{-# INLINE cstring #-} |
684 | | - |
685 | | -cstring_step :: Addr# -> Int# -> BuildStep r -> BuildStep r |
686 | | -cstring_step !addr !len !k br@(BufferRange op0 ope) |
687 | | - -- String is empty, process the continuation |
688 | | - | (I# len) == 0 = k br |
689 | | - -- Buffer is full, allocate some more... We ask for just one more |
690 | | - -- byte, but the builder allocation strategy will in practice give |
691 | | - -- us more space, which we'll consume in a single step. |
692 | | - | op0 == ope = |
693 | | - return $ bufferFull 1 op0 (cstring_step addr len k) |
694 | | - -- Copy as much of the string as fits into the available buffer space. |
695 | | - -- If the string is long enough, we may have asked for less than its |
696 | | - -- full length, filling the buffer with the rest will go into the next |
697 | | - -- builder step. |
698 | | - | otherwise = do |
699 | | - let !avail@(I# avail#) = min (I# len) (ope `minusPtr` op0) |
700 | | - br' = BufferRange (op0 `plusPtr` avail) ope |
701 | | - addr' = addr `plusAddr#` avail# |
702 | | - len' = len -# avail# |
703 | | - S.memcpy op0 (Ptr addr) avail |
704 | | - cstring_step addr' len' k br' |
705 | | - |
706 | | --- | A null-terminated UTF-8 encoded 'Foreign.C.String.CString'. |
707 | | --- Null characters can be encoded as @0xc0 0x80@. |
708 | | --- |
709 | | --- @since 0.11.0.0 |
710 | | -cstringUtf8 :: Addr# -> Builder |
711 | | -cstringUtf8 = \addr0 -> builder $ \k br -> do |
712 | | -#if __GLASGOW_HASKELL__ >= 811 |
713 | | - let len = cstringLength# addr0 |
714 | | -#else |
715 | | - (I# len) <- fromIntegral <$> S.c_strlen (Ptr addr0) |
716 | | -#endif |
717 | | - nullAt <- S.c_strstr (Ptr addr0) (Ptr "\xc0\x80"#) |
718 | | - cstringUtf8_step addr0 len nullAt k br |
719 | | -{-# INLINE cstringUtf8 #-} |
720 | | - |
721 | | -cstringUtf8_step :: Addr# -> Int# -> Ptr Word8 -> BuildStep r -> BuildStep r |
722 | | -cstringUtf8_step !addr !len !nullAt !k br@(BufferRange op0@(Ptr op0#) ope) |
723 | | - -- String is empty, process the continuation |
724 | | - | (I# len) == 0 = k br |
725 | | - -- Contains no encoded nulls, use simpler 'cstring' code |
726 | | - | nullPtr == nullAt = |
727 | | - cstring_step addr len k br |
728 | | - -- Buffer is full, allocate some more... We ask for just one more |
729 | | - -- byte, but the builder allocation strategy will in practice give |
730 | | - -- us more space, which we'll consume in a single step. |
731 | | - | op0 == ope = |
732 | | - return $ bufferFull 1 op0 (cstringUtf8_step addr len nullAt k) |
733 | | - -- We're at the encoded null-byte, append a '\0' to the buffer and |
734 | | - -- continue with the rest of the input string, after locating the |
735 | | - -- next encoded null-byte, if any. |
736 | | - | (Ptr addr) == nullAt = do |
737 | | - let !(W8# nullByte#) = 0 |
738 | | - IO $ \s -> case writeWord8OffAddr# op0# 0# nullByte# s of |
739 | | - s' -> (# s', () #) |
740 | | - let br' = BufferRange (op0 `plusPtr` 1) ope |
741 | | - addr' = addr `plusAddr#` 2# |
742 | | - len' = len -# 2# |
743 | | - nullAt' <- S.c_strstr (Ptr addr') (Ptr "\xc0\x80"#) |
744 | | - cstringUtf8_step addr' len' nullAt' k br' |
745 | | - -- Copy as much of the null-free portion of the string as fits into the |
746 | | - -- available buffer space. If the string is long enough, we may have asked |
747 | | - -- for less than its full length, filling the buffer with the rest will go |
748 | | - -- into the next builder step. |
749 | | - | otherwise = do |
750 | | - let !nullFree = nullAt `minusPtr` (Ptr addr) |
751 | | - !avail@(I# avail#) = min nullFree (ope `minusPtr` op0) |
752 | | - br' = BufferRange (op0 `plusPtr` avail) ope |
753 | | - addr' = addr `plusAddr#` avail# |
754 | | - len' = len -# avail# |
755 | | - S.memcpy op0 (Ptr addr) avail |
756 | | - cstringUtf8_step addr' len' nullAt k br' |
757 | | - |
758 | 668 | ------------------------------------------------------------------------------ |
759 | 669 | -- Char8 encoding |
760 | 670 | ------------------------------------------------------------------------------ |
|
0 commit comments