{-# LANGUAGE DeriveDataTypeable, UnboxedTuples, MagicHash, BangPatterns, GeneralizedNewtypeDeriving #-} {-# OPTIONS_HADDOCK not-home #-} module Data.JSString.Internal.Type ( JSString(..) , empty , empty_ , safe , firstf ) where {- -- * Construction , text , textP -- * Safety , safe -- * Code that must be here for accessibility , empty , empty_ -- * Utilities , firstf -- * Checked multiplication , mul , mul32 , mul64 -- * Debugging , showText ) where -} import Control.DeepSeq import Data.Coerce (coerce) import Data.Text (Text) import qualified Data.Text as T (empty) import Data.String (IsString) import Data.Aeson (ToJSON(..), FromJSON(..)) import Data.Data (Data) -- import Data.Text.Internal.Unsafe.Char (ord) import Data.Typeable (Typeable) import Data.Semigroup (Semigroup) import GHC.Exts (Char(..), ord#, andI#, (/=#), isTrue#) -- | A wrapper around a JavaScript string newtype JSString = JSString Text deriving(Show, Read, IsString, Semigroup, Monoid, Ord, Eq, Data, ToJSON, FromJSON, Typeable) instance NFData JSString where rnf !_ = () -- | /O(1)/ The empty 'JSString'. empty :: JSString empty = coerce T.empty {-# INLINE [1] empty #-} -- | A non-inlined version of 'empty'. empty_ :: JSString empty_ = coerce T.empty {-# NOINLINE empty_ #-} safe :: Char -> Char safe c@(C# cc) | isTrue# (andI# (ord# cc) 0x1ff800# /=# 0xd800#) = c | otherwise = '\xfffd' {-# INLINE [0] safe #-} -- | Apply a function to the first element of an optional pair. firstf :: (a -> c) -> Maybe (a,b) -> Maybe (c,b) firstf f (Just (a, b)) = Just (f a, b) firstf _ Nothing = Nothing {- -- | Checked multiplication. Calls 'error' if the result would -- overflow. mul :: Int -> Int -> Int #if WORD_SIZE_IN_BITS == 64 mul a b = fromIntegral $ fromIntegral a `mul64` fromIntegral b #else mul a b = fromIntegral $ fromIntegral a `mul32` fromIntegral b #endif {-# INLINE mul #-} infixl 7 `mul` -- | Checked multiplication. Calls 'error' if the result would -- overflow. mul64 :: Int64 -> Int64 -> Int64 mul64 a b | a >= 0 && b >= 0 = mul64_ a b | a >= 0 = -mul64_ a (-b) | b >= 0 = -mul64_ (-a) b | otherwise = mul64_ (-a) (-b) {-# INLINE mul64 #-} infixl 7 `mul64` mul64_ :: Int64 -> Int64 -> Int64 mul64_ a b | ahi > 0 && bhi > 0 = error "overflow" | top > 0x7fffffff = error "overflow" | total < 0 = error "overflow" | otherwise = total where (# ahi, alo #) = (# a `shiftR` 32, a .&. 0xffffffff #) (# bhi, blo #) = (# b `shiftR` 32, b .&. 0xffffffff #) top = ahi * blo + alo * bhi total = (top `shiftL` 32) + alo * blo {-# INLINE mul64_ #-} -- | Checked multiplication. Calls 'error' if the result would -- overflow. mul32 :: Int32 -> Int32 -> Int32 mul32 a b = case fromIntegral a * fromIntegral b of ab | ab < min32 || ab > max32 -> error "overflow" | otherwise -> fromIntegral ab where min32 = -0x80000000 :: Int64 max32 = 0x7fffffff {-# INLINE mul32 #-} infixl 7 `mul32` -}