Skip to content

Commit

Permalink
Make singleton return a slice of a static buffer (#480)
Browse files Browse the repository at this point in the history
* Make 'singleton' return a slice of a static buffer

* Tweak formatting, update internal documentation

* Elaborate on comment about heap space usage
  • Loading branch information
clyring authored Feb 3, 2022
1 parent 0badf97 commit 8861354
Show file tree
Hide file tree
Showing 2 changed files with 17 additions and 21 deletions.
34 changes: 15 additions & 19 deletions Data/ByteString.hs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE MagicHash #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE TupleSections #-}
{-# OPTIONS_HADDOCK prune #-}
Expand Down Expand Up @@ -276,27 +277,22 @@ import GHC.Word hiding (Word8)

-- | /O(1)/ Convert a 'Word8' into a 'ByteString'
singleton :: Word8 -> ByteString
singleton c = unsafeCreate 1 $ \p -> poke p c
-- Taking a slice of some static data rather than allocating a new
-- buffer for each call is nice for several reasons. Since it doesn't
-- involve any side effects hidden in a 'GHC.Magic.runRW#' call, it
-- can be simplified to a constructor application. This may enable GHC
-- to perform further optimizations after inlining, and also causes a
-- fresh singleton to take only 4 words of heap space instead of 9.
-- (The buffer object itself would take up 3 words: header, size, and
-- 1 word of content. The ForeignPtrContents object used to keep the
-- buffer alive would need two more.)
singleton c = unsafeTake 1 $ unsafeDrop (fromIntegral c) allBytes
{-# INLINE singleton #-}

--
-- XXX The use of unsafePerformIO in allocating functions (unsafeCreate) is critical!
--
-- Otherwise:
--
-- singleton 255 `compare` singleton 127
--
-- is compiled to:
--
-- case mallocByteString 2 of
-- ForeignPtr f internals ->
-- case writeWord8OffAddr# f 0 255 of _ ->
-- case writeWord8OffAddr# f 0 127 of _ ->
-- case eqAddr# f f of
-- False -> case compare (GHC.Prim.plusAddr# f 0)
-- (GHC.Prim.plusAddr# f 0)
--
--
-- | A static blob of all possible bytes (0x00 to 0xff) in order
allBytes :: ByteString
allBytes = unsafePackLenLiteral 0x100
"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"#

-- | /O(n)/ Convert a @['Word8']@ into a 'ByteString'.
--
Expand Down
4 changes: 2 additions & 2 deletions Data/ByteString/Short.hs
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,9 @@ module Data.ByteString.Short (
-- | With GHC, the memory overheads are as follows, expressed in words and
-- in bytes (words are 4 and 8 bytes on 32 or 64bit machines respectively).
--
-- * 'B.ByteString' unshared: 9 words; 36 or 72 bytes.
-- * 'B.ByteString' unshared: 8 words; 32 or 64 bytes.
--
-- * 'B.ByteString' shared substring: 5 words; 20 or 40 bytes.
-- * 'B.ByteString' shared substring: 4 words; 16 or 32 bytes.
--
-- * 'ShortByteString': 4 words; 16 or 32 bytes.
--
Expand Down

0 comments on commit 8861354

Please sign in to comment.