11{-# LANGUAGE CPP, RankNTypes, MagicHash, BangPatterns #-}
22{-# LANGUAGE Trustworthy #-}
3+ {-# LANGUAGE UnboxedTuples #-}
34
45#if defined(__GLASGOW_HASKELL__) && !defined(__HADDOCK__)
56#include "MachDeps.h"
67#endif
78
9+ #if defined(MIN_VERSION_GLASGOW_HASKELL) && MIN_VERSION_GLASGOW_HASKELL(9,10,0,0)
10+ #define HS_UNALIGNED_ADDR_PRIMOPS_AVAILABLE
11+ #endif
12+
813-----------------------------------------------------------------------------
914-- |
1015-- Module : Data.Binary.Get
@@ -234,6 +239,13 @@ import qualified Data.Binary.Get.Internal as I
234239-- needed for casting words to float/double
235240import Data.Binary.FloatCast (wordToFloat , wordToDouble )
236241
242+ #if defined(HS_UNALIGNED_ADDR_PRIMOPS_AVAILABLE)
243+ import GHC.Exts
244+ import GHC.IO
245+ import GHC.Int
246+ import GHC.Word
247+ #endif
248+
237249-- $lazyinterface
238250-- The lazy interface consumes a single lazy 'L.ByteString'. It's the easiest
239251-- interface to get started with, but it doesn't support interleaving I\/O and
@@ -426,9 +438,11 @@ getRemainingLazyByteString = withInputChunks () consumeAll L.fromChunks resumeOn
426438-- helper, get a raw Ptr onto a strict ByteString copied out of the
427439-- underlying lazy byteString.
428440
441+ #if !defined(HS_UNALIGNED_ADDR_PRIMOPS_AVAILABLE)
429442getPtr :: Storable a => Int -> Get a
430443getPtr n = readNWith n peek
431444{-# INLINE getPtr #-}
445+ #endif
432446
433447-- | Read a Word8 from the monad state
434448getWord8 :: Get Word8
@@ -444,125 +458,116 @@ getInt8 = fromIntegral <$> getWord8
444458-- force GHC to inline getWordXX
445459{-# RULES
446460"getWord8/readN" getWord8 = readN 1 B.unsafeHead
447- "getWord16be/readN" getWord16be = readN 2 word16be
448- "getWord16le/readN" getWord16le = readN 2 word16le
449- "getWord32be/readN" getWord32be = readN 4 word32be
450- "getWord32le/readN" getWord32le = readN 4 word32le
451- "getWord64be/readN" getWord64be = readN 8 word64be
452- "getWord64le/readN" getWord64le = readN 8 word64le #-}
461+ #-}
453462
454463-- | Read a Word16 in big endian format
455464getWord16be :: Get Word16
456- getWord16be = readN 2 word16be
457-
458- word16be :: B. ByteString -> Word16
459- word16be = \ s ->
460- (fromIntegral (s `B.unsafeIndex` 0 ) `unsafeShiftL` 8 ) .|.
461- (fromIntegral (s `B.unsafeIndex` 1 ))
462- {-# INLINE [2] getWord16be #-}
463- {-# INLINE word16be #-}
465+ #if defined(WORDS_BIGENDIAN)
466+ getWord16be = getWord16host
467+ #else
468+ getWord16be = byteSwap16 <$> getWord16host
469+ #endif
470+ {-# INLINE getWord16be #-}
464471
465472-- | Read a Word16 in little endian format
466473getWord16le :: Get Word16
467- getWord16le = readN 2 word16le
468-
469- word16le :: B. ByteString -> Word16
470- word16le = \ s ->
471- (fromIntegral (s `B.unsafeIndex` 1 ) `unsafeShiftL` 8 ) .|.
472- (fromIntegral (s `B.unsafeIndex` 0 ) )
473- {-# INLINE [2] getWord16le #-}
474- {-# INLINE word16le #-}
474+ #if defined(WORDS_BIGENDIAN)
475+ getWord16le = byteSwap16 <$> getWord16host
476+ #else
477+ getWord16le = getWord16host
478+ #endif
479+ {-# INLINE getWord16le #-}
475480
476481-- | Read a Word32 in big endian format
477482getWord32be :: Get Word32
478- getWord32be = readN 4 word32be
479-
480- word32be :: B. ByteString -> Word32
481- word32be = \ s ->
482- (fromIntegral (s `B.unsafeIndex` 0 ) `unsafeShiftL` 24 ) .|.
483- (fromIntegral (s `B.unsafeIndex` 1 ) `unsafeShiftL` 16 ) .|.
484- (fromIntegral (s `B.unsafeIndex` 2 ) `unsafeShiftL` 8 ) .|.
485- (fromIntegral (s `B.unsafeIndex` 3 ) )
486- {-# INLINE [2] getWord32be #-}
487- {-# INLINE word32be #-}
483+ #if defined(WORDS_BIGENDIAN)
484+ getWord32be = getWord32host
485+ #else
486+ getWord32be = byteSwap32 <$> getWord32host
487+ #endif
488+ {-# INLINE getWord32be #-}
488489
489490-- | Read a Word32 in little endian format
490491getWord32le :: Get Word32
491- getWord32le = readN 4 word32le
492-
493- word32le :: B. ByteString -> Word32
494- word32le = \ s ->
495- (fromIntegral (s `B.unsafeIndex` 3 ) `unsafeShiftL` 24 ) .|.
496- (fromIntegral (s `B.unsafeIndex` 2 ) `unsafeShiftL` 16 ) .|.
497- (fromIntegral (s `B.unsafeIndex` 1 ) `unsafeShiftL` 8 ) .|.
498- (fromIntegral (s `B.unsafeIndex` 0 ) )
499- {-# INLINE [2] getWord32le #-}
500- {-# INLINE word32le #-}
492+ #if defined(WORDS_BIGENDIAN)
493+ getWord32le = byteSwap32 <$> getWord32host
494+ #else
495+ getWord32le = getWord32host
496+ #endif
497+ {-# INLINE getWord32le #-}
501498
502499-- | Read a Word64 in big endian format
503500getWord64be :: Get Word64
504- getWord64be = readN 8 word64be
505-
506- word64be :: B. ByteString -> Word64
507- word64be = \ s ->
508- (fromIntegral (s `B.unsafeIndex` 0 ) `unsafeShiftL` 56 ) .|.
509- (fromIntegral (s `B.unsafeIndex` 1 ) `unsafeShiftL` 48 ) .|.
510- (fromIntegral (s `B.unsafeIndex` 2 ) `unsafeShiftL` 40 ) .|.
511- (fromIntegral (s `B.unsafeIndex` 3 ) `unsafeShiftL` 32 ) .|.
512- (fromIntegral (s `B.unsafeIndex` 4 ) `unsafeShiftL` 24 ) .|.
513- (fromIntegral (s `B.unsafeIndex` 5 ) `unsafeShiftL` 16 ) .|.
514- (fromIntegral (s `B.unsafeIndex` 6 ) `unsafeShiftL` 8 ) .|.
515- (fromIntegral (s `B.unsafeIndex` 7 ) )
516- {-# INLINE [2] getWord64be #-}
517- {-# INLINE word64be #-}
501+ #if defined(WORDS_BIGENDIAN)
502+ getWord64be = getWord64host
503+ #else
504+ getWord64be = byteSwap64 <$> getWord64host
505+ #endif
506+ {-# INLINE getWord64be #-}
518507
519508-- | Read a Word64 in little endian format
520509getWord64le :: Get Word64
521- getWord64le = readN 8 word64le
522-
523- word64le :: B. ByteString -> Word64
524- word64le = \ s ->
525- (fromIntegral (s `B.unsafeIndex` 7 ) `unsafeShiftL` 56 ) .|.
526- (fromIntegral (s `B.unsafeIndex` 6 ) `unsafeShiftL` 48 ) .|.
527- (fromIntegral (s `B.unsafeIndex` 5 ) `unsafeShiftL` 40 ) .|.
528- (fromIntegral (s `B.unsafeIndex` 4 ) `unsafeShiftL` 32 ) .|.
529- (fromIntegral (s `B.unsafeIndex` 3 ) `unsafeShiftL` 24 ) .|.
530- (fromIntegral (s `B.unsafeIndex` 2 ) `unsafeShiftL` 16 ) .|.
531- (fromIntegral (s `B.unsafeIndex` 1 ) `unsafeShiftL` 8 ) .|.
532- (fromIntegral (s `B.unsafeIndex` 0 ) )
533- {-# INLINE [2] getWord64le #-}
534- {-# INLINE word64le #-}
510+ #if defined(WORDS_BIGENDIAN)
511+ getWord64le = byteSwap64 <$> getWord64host
512+ #else
513+ getWord64le = getWord64host
514+ #endif
515+ {-# INLINE getWord64le #-}
535516
536517
537518-- | Read an Int16 in big endian format.
538519getInt16be :: Get Int16
520+ #if defined(WORDS_BIGENDIAN)
521+ getInt16be = getInt16host
522+ #else
539523getInt16be = fromIntegral <$> getWord16be
524+ #endif
540525{-# INLINE getInt16be #-}
541526
542527-- | Read an Int32 in big endian format.
543528getInt32be :: Get Int32
529+ #if defined(WORDS_BIGENDIAN)
530+ getInt32be = getInt32host
531+ #else
544532getInt32be = fromIntegral <$> getWord32be
533+ #endif
545534{-# INLINE getInt32be #-}
546535
547536-- | Read an Int64 in big endian format.
548537getInt64be :: Get Int64
538+ #if defined(WORDS_BIGENDIAN)
539+ getInt64be = getInt64host
540+ #else
549541getInt64be = fromIntegral <$> getWord64be
542+ #endif
550543{-# INLINE getInt64be #-}
551544
552545
553546-- | Read an Int16 in little endian format.
554547getInt16le :: Get Int16
548+ #if defined(WORDS_BIGENDIAN)
555549getInt16le = fromIntegral <$> getWord16le
550+ #else
551+ getInt16le = getInt16host
552+ #endif
556553{-# INLINE getInt16le #-}
557554
558555-- | Read an Int32 in little endian format.
559556getInt32le :: Get Int32
557+ #if defined(WORDS_BIGENDIAN)
560558getInt32le = fromIntegral <$> getWord32le
559+ #else
560+ getInt32le = getInt32host
561+ #endif
561562{-# INLINE getInt32le #-}
562563
563564-- | Read an Int64 in little endian format.
564565getInt64le :: Get Int64
566+ #if defined(WORDS_BIGENDIAN)
565567getInt64le = fromIntegral <$> getWord64le
568+ #else
569+ getInt64le = getInt64host
570+ #endif
566571{-# INLINE getInt64le #-}
567572
568573
@@ -573,43 +578,91 @@ getInt64le = fromIntegral <$> getWord64le
573578-- host order, host endian form, for the machine you're on. On a 64 bit
574579-- machine the Word is an 8 byte value, on a 32 bit machine, 4 bytes.
575580getWordhost :: Get Word
581+ #if defined(HS_UNALIGNED_ADDR_PRIMOPS_AVAILABLE)
582+ getWordhost = readNWith SIZEOF_HSWORD $ \ (Ptr p# ) ->
583+ IO $ \ s -> case readWord8OffAddrAsWord# p# 0 # s of
584+ (# s', w# # ) -> (# s', W # w# # )
585+ #else
576586getWordhost = getPtr (sizeOf (undefined :: Word ))
587+ #endif
577588{-# INLINE getWordhost #-}
578589
579590-- | /O(1)./ Read a 2 byte Word16 in native host order and host endianness.
580- getWord16host :: Get Word16
581- getWord16host = getPtr (sizeOf (undefined :: Word16 ))
591+ getWord16host :: Get Word16
592+ #if defined(HS_UNALIGNED_ADDR_PRIMOPS_AVAILABLE)
593+ getWord16host = readNWith 2 $ \ (Ptr p# ) ->
594+ IO $ \ s -> case readWord8OffAddrAsWord16# p# 0 # s of
595+ (# s', w16# # ) -> (# s', W16 # w16# # )
596+ #else
597+ getWord16host = getPtr (sizeOf (undefined :: Word16 ))
598+ #endif
582599{-# INLINE getWord16host #-}
583600
584601-- | /O(1)./ Read a Word32 in native host order and host endianness.
585- getWord32host :: Get Word32
602+ getWord32host :: Get Word32
603+ #if defined(HS_UNALIGNED_ADDR_PRIMOPS_AVAILABLE)
604+ getWord32host = readNWith 4 $ \ (Ptr p# ) ->
605+ IO $ \ s -> case readWord8OffAddrAsWord32# p# 0 # s of
606+ (# s', w32# # ) -> (# s', W32 # w32# # )
607+ #else
586608getWord32host = getPtr (sizeOf (undefined :: Word32 ))
609+ #endif
587610{-# INLINE getWord32host #-}
588611
589612-- | /O(1)./ Read a Word64 in native host order and host endianness.
590613getWord64host :: Get Word64
614+ #if defined(HS_UNALIGNED_ADDR_PRIMOPS_AVAILABLE)
615+ getWord64host = readNWith 8 $ \ (Ptr p# ) ->
616+ IO $ \ s -> case readWord8OffAddrAsWord64# p# 0 # s of
617+ (# s', w64# # ) -> (# s', W64 # w64# # )
618+ #else
591619getWord64host = getPtr (sizeOf (undefined :: Word64 ))
620+ #endif
592621{-# INLINE getWord64host #-}
593622
594623-- | /O(1)./ Read a single native machine word in native host
595624-- order. It works in the same way as 'getWordhost'.
596625getInthost :: Get Int
626+ #if defined(HS_UNALIGNED_ADDR_PRIMOPS_AVAILABLE)
627+ getInthost = readNWith SIZEOF_HSINT $ \ (Ptr p# ) ->
628+ IO $ \ s -> case readWord8OffAddrAsInt# p# 0 # s of
629+ (# s', i# # ) -> (# s', I # i# # )
630+ #else
597631getInthost = getPtr (sizeOf (undefined :: Int ))
632+ #endif
598633{-# INLINE getInthost #-}
599634
600635-- | /O(1)./ Read a 2 byte Int16 in native host order and host endianness.
601636getInt16host :: Get Int16
637+ #if defined(HS_UNALIGNED_ADDR_PRIMOPS_AVAILABLE)
638+ getInt16host = readNWith 2 $ \ (Ptr p# ) ->
639+ IO $ \ s -> case readWord8OffAddrAsInt16# p# 0 # s of
640+ (# s', i16# # ) -> (# s', I16 # i16# # )
641+ #else
602642getInt16host = getPtr (sizeOf (undefined :: Int16 ))
643+ #endif
603644{-# INLINE getInt16host #-}
604645
605646-- | /O(1)./ Read an Int32 in native host order and host endianness.
606647getInt32host :: Get Int32
648+ #if defined(HS_UNALIGNED_ADDR_PRIMOPS_AVAILABLE)
649+ getInt32host = readNWith 4 $ \ (Ptr p# ) ->
650+ IO $ \ s -> case readWord8OffAddrAsInt32# p# 0 # s of
651+ (# s', i32# # ) -> (# s', I32 # i32# # )
652+ #else
607653getInt32host = getPtr (sizeOf (undefined :: Int32 ))
654+ #endif
608655{-# INLINE getInt32host #-}
609656
610657-- | /O(1)./ Read an Int64 in native host order and host endianness.
611658getInt64host :: Get Int64
659+ #if defined(HS_UNALIGNED_ADDR_PRIMOPS_AVAILABLE)
660+ getInt64host = readNWith 8 $ \ (Ptr p# ) ->
661+ IO $ \ s -> case readWord8OffAddrAsInt64# p# 0 # s of
662+ (# s', i64# # ) -> (# s', I64 # i64# # )
663+ #else
612664getInt64host = getPtr (sizeOf (undefined :: Int64 ))
665+ #endif
613666{-# INLINE getInt64host #-}
614667
615668
@@ -618,30 +671,58 @@ getInt64host = getPtr (sizeOf (undefined :: Int64))
618671
619672-- | Read a 'Float' in big endian IEEE-754 format.
620673getFloatbe :: Get Float
674+ #if defined(WORDS_BIGENDIAN)
675+ getFloatbe = getFloathost
676+ #else
621677getFloatbe = wordToFloat <$> getWord32be
678+ #endif
622679{-# INLINE getFloatbe #-}
623680
624681-- | Read a 'Float' in little endian IEEE-754 format.
625682getFloatle :: Get Float
683+ #if defined(WORDS_BIGENDIAN)
626684getFloatle = wordToFloat <$> getWord32le
685+ #else
686+ getFloatle = getFloathost
687+ #endif
627688{-# INLINE getFloatle #-}
628689
629690-- | Read a 'Float' in IEEE-754 format and host endian.
630691getFloathost :: Get Float
692+ #if defined(HS_UNALIGNED_ADDR_PRIMOPS_AVAILABLE)
693+ getFloathost = readNWith 4 $ \ (Ptr p# ) ->
694+ IO $ \ s -> case readWord8OffAddrAsFloat# p# 0 # s of
695+ (# s', f# # ) -> (# s', F # f# # )
696+ #else
631697getFloathost = wordToFloat <$> getWord32host
698+ #endif
632699{-# INLINE getFloathost #-}
633700
634701-- | Read a 'Double' in big endian IEEE-754 format.
635702getDoublebe :: Get Double
703+ #if defined(WORDS_BIGENDIAN)
704+ getDoublebe = getDoublehost
705+ #else
636706getDoublebe = wordToDouble <$> getWord64be
707+ #endif
637708{-# INLINE getDoublebe #-}
638709
639710-- | Read a 'Double' in little endian IEEE-754 format.
640711getDoublele :: Get Double
712+ #if defined(WORDS_BIGENDIAN)
641713getDoublele = wordToDouble <$> getWord64le
714+ #else
715+ getDoublele = getDoublehost
716+ #endif
642717{-# INLINE getDoublele #-}
643718
644719-- | Read a 'Double' in IEEE-754 format and host endian.
645720getDoublehost :: Get Double
721+ #if defined(HS_UNALIGNED_ADDR_PRIMOPS_AVAILABLE)
722+ getDoublehost = readNWith 8 $ \ (Ptr p# ) ->
723+ IO $ \ s -> case readWord8OffAddrAsDouble# p# 0 # s of
724+ (# s', d# # ) -> (# s', D # d# # )
725+ #else
646726getDoublehost = wordToDouble <$> getWord64host
727+ #endif
647728{-# INLINE getDoublehost #-}
0 commit comments