packages feed

symbolize 1.0.1.0 → 1.0.2.0

raw patch · 5 files changed

+110/−27 lines, 5 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

+ Symbolize: internUnsafe :: Textual str => str -> Symbol
+ Symbolize: internUnsafe# :: Textual str => str -> Symbol#
+ Symbolize.Textual: toShortTextUnsafe :: Textual a => a -> ShortText

Files

CHANGELOG.md view
@@ -8,6 +8,12 @@  ## Unreleased +## 1.0.2.0++- Adds `Textual.toShortTextUnsafe` and related `internUnsafe` and `internUnsafe#`; these skip UTF-8 validity checks. Very useful when working with trusted serialized data.+  - rename `intern##` to `internUnsafe##` (the old name is marked as deprecated.)+- Cleans up `mkWeakSymbol` to be slightly less sketchy in the presence of `accursedUnutterablePerformIO`; thanks @fatho!+ ## 1.0.1.0  - Add `Data.Data` instance
src/Symbolize.hs view
@@ -123,6 +123,7 @@   ( -- * Symbol     Symbol (..),     intern,+    internUnsafe,     unintern,     lookup, @@ -134,6 +135,7 @@     -- * manipulate unlifted Symbols directly     Symbol#,     intern#,+    internUnsafe#,     intern##,     unintern#,     unintern##,@@ -166,7 +168,6 @@ import Prelude hiding (lookup) import Data.Data qualified import Data.Binary qualified-import Data.Text.Short (ShortText)  -- | A string-like type with O(1) equality and comparison. --@@ -293,10 +294,28 @@ {-# INLINE intern# #-} intern# !str = intern## (textualToBA# str) --- | Version of `intern` that directly works on an unlifted `ByteArray#` and returns an unlifted `Symbol#`++-- | Like `intern`, but skips any potential UTF-8 validation+internUnsafe :: (Textual str) => str -> Symbol+{-# INLINE internUnsafe #-}+internUnsafe !str = Symbol (internUnsafe# str)++-- | Like `intern#`, but skips any potential UTF-8 validation+internUnsafe# :: (Textual str) => str -> Symbol#+{-# INLINE internUnsafe# #-}+internUnsafe# !str = intern## (textualToBAUnsafe# str)++{-# DEPRECATED intern## "Renamed to `internUnsafe##`" #-} intern## :: ByteArray# -> Symbol# {-# INLINE intern## #-}-intern## ba# =+intern## = internUnsafe##++-- | Version of `intern`/`internUnsafe` that directly works on an unlifted `ByteArray#` and returns an unlifted `Symbol#`+--+-- Does not do any checking for UTF-8 validity on the `ByteArray#` beforehand.+internUnsafe## :: ByteArray# -> Symbol#+{-# INLINE internUnsafe## #-}+internUnsafe## ba# =   -- SAFETY: We're actually happy with let-floating/combining   -- since the result is 'outwardly pure' and doing less work is better!   let !(ByteArray ba2#) = Accursed.accursedUnutterablePerformIO (SymbolTable.insertGlobal ba#)@@ -390,6 +409,12 @@ {-# INLINE textualToBA# #-} textualToBA# !str =   let !(SBS ba#) = Text.Short.toShortByteString (Textual.toShortText str)+   in ba#++textualToBAUnsafe# :: (Textual str) => str -> ByteArray#+{-# INLINE textualToBAUnsafe# #-}+textualToBAUnsafe# !str =+  let !(SBS ba#) = Text.Short.toShortByteString (Textual.toShortTextUnsafe str)    in ba#  textualFromBA# :: (Textual str) => ByteArray# -> str
src/Symbolize/SymbolTable.hs view
@@ -78,7 +78,13 @@ insertGlobal ba# = do   GlobalSymbolTable gsymtab sipkey <- globalSymbolTable   let !key = calculateHash sipkey ba#-  let !weak = mkWeakSymbol ba# (removeGlobal key)+  -- SAFETY: If the table IORef contested, +  -- this might trigger `weak` creation for the same bytestring from multiple threads+  -- at the same time.+  -- But finalization is idempotent, and only when a thread finally wins the Compare-and-Swap+  -- will its `weak` pointer be inserted (or alternatively another previously-inserted `ba` returned).+  -- So once this function returns, we can be sure we've returned a deduplicated ByteArray+  !weak <- mkWeakSymbol ba# (removeGlobal key)   IORef.atomicModifyIORef' gsymtab $ \table ->     case lookup ba# sipkey table of       Just ba -> (table, ba)@@ -134,7 +140,7 @@   let (SipHash.SipHash word) = SipHash.hash sipkey (ByteArray ba#)    in Hash (fromIntegral word) -mkWeakSymbol :: ByteArray# -> IO () -> WeakSymbol+mkWeakSymbol :: ByteArray# -> IO () -> IO WeakSymbol {-# INLINE mkWeakSymbol #-} mkWeakSymbol ba# (IO finalizer#) =      -- SAFETY: This should even be safe@@ -142,7 +148,6 @@     --     -- because the result is outwardly pure     -- and the finalizer we use is idempotent-    Symbolize.Accursed.accursedUnutterablePerformIO $   IO $ \s1 -> case mkWeak# ba# ba# finalizer# s1 of     (# s2, weak# #) ->       case makeStableName# ba# s2 of
src/Symbolize/Textual.hs view
@@ -1,4 +1,6 @@ {-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE ViewPatterns #-}+{-# LANGUAGE InstanceSigs #-}  -- NOTE: FlexibleInstances is needed to support `String` instance :-( @@ -13,10 +15,10 @@ import qualified Data.Text.Encoding as Text.Encoding import qualified Data.Text.Encoding.Error as Text.Encoding.Error import qualified Data.Text.Lazy as LText-import Data.Text.Lazy.Builder (Builder)-import qualified Data.Text.Lazy.Builder as Builder+import qualified Data.Text.Lazy.Builder as Text.Builder import Data.Text.Short (ShortText) import qualified Data.Text.Short as ShortText+import qualified Data.Text.Short.Unsafe as ShortText.Unsafe  -- | Implemented by any String-like types. -- The symbol table uses `ShortText` for its internal storage, so any type which can be converted to it@@ -25,82 +27,127 @@ -- Instance should handle potential invalid UTF-8 by using the Unicode replacement character, -- c.f. `Data.Text.Encoding.Error.lenientDecode`. class Textual a where+  -- | Turns this text value into a `ShortText`, performing UTF-8 checking if necessary   toShortText :: a -> ShortText++  -- | Turns this text value into a `ShortText`, potentially skipping UTF-8 checks+  toShortTextUnsafe :: a -> ShortText+  toShortTextUnsafe = toShortText++  -- | Turns a `ShortText` value into a different textual value   fromShortText :: ShortText -> a  -- | -- - O(0) conversion (a no-op) instance Textual ShortText where-  toShortText = id+  toShortText :: ShortText -> ShortText   {-# INLINE toShortText #-}-  fromShortText = id+  toShortText = id++  toShortTextUnsafe :: ShortText -> ShortText+  {-# INLINE toShortTextUnsafe #-}+  toShortTextUnsafe = id++  fromShortText :: ShortText -> ShortText   {-# INLINE fromShortText #-}+  fromShortText = id  -- | -- - O(1) conversion instance Textual Text where-  toShortText = ShortText.fromText+  toShortText :: Text -> ShortText   {-# INLINE toShortText #-}-  fromShortText = ShortText.toText+  toShortText = ShortText.fromText++  fromShortText :: ShortText -> Text   {-# INLINE fromShortText #-}+  fromShortText = ShortText.toText  -- | -- - O(n) conversion instance Textual String where-  toShortText = ShortText.fromString+  toShortText :: String -> ShortText   {-# INLINE toShortText #-}-  fromShortText = ShortText.toString+  toShortText = ShortText.fromString++  fromShortText :: ShortText -> String   {-# INLINE fromShortText #-}+  fromShortText = ShortText.toString  -- | -- - O(1) conversion instance Textual LText.Text where-  toShortText = ShortText.fromText . LText.toStrict+  toShortText :: LText.Text -> ShortText   {-# INLINE toShortText #-}-  fromShortText = LText.fromStrict . ShortText.toText+  toShortText = ShortText.fromText . LText.toStrict++  fromShortText :: ShortText -> LText.Text   {-# INLINE fromShortText #-}+  fromShortText = LText.fromStrict . ShortText.toText  -- | -- - toShortText: O(n). Evaluates the entire builder. -- - fromShortText: O(1)-instance Textual Builder where-  toShortText = ShortText.fromText . LText.toStrict . Builder.toLazyText+instance Textual Text.Builder.Builder where+  toShortText :: Text.Builder.Builder -> ShortText   {-# INLINE toShortText #-}-  fromShortText = Builder.fromText . ShortText.toText+  toShortText = ShortText.fromText . LText.toStrict . Text.Builder.toLazyText++  fromShortText :: ShortText -> Text.Builder.Builder   {-# INLINE fromShortText #-}+  fromShortText = Text.Builder.fromText . ShortText.toText  -- | -- - toShortText: O(n). Turns invalid UTF-8 into the Unicode replacement character. -- - fromShortText: O(0) no-op instance Textual ShortByteString where+  toShortText :: ShortByteString -> ShortText+  {-# INLINE toShortText #-}   toShortText byteString =     byteString       & ShortByteString.fromShort       & Text.Encoding.decodeUtf8With Text.Encoding.Error.lenientDecode       & ShortText.fromText-  {-# INLINE toShortText #-} -  fromShortText = ShortText.toShortByteString+  toShortTextUnsafe :: ShortByteString -> ShortText+  {-# INLINE toShortTextUnsafe #-}+  toShortTextUnsafe = ShortText.Unsafe.fromShortByteStringUnsafe++  fromShortText :: ShortText -> ShortByteString   {-# INLINE fromShortText #-}+  fromShortText = ShortText.toShortByteString  -- | -- - toShortText: O(n). Turns invalid UTF-8 into the Unicode replacement character. -- - fromShortText: O(n). instance Textual ByteString where+  toShortText :: ByteString -> ShortText+  {-# INLINE toShortText #-}   toShortText byteString =     byteString       & Text.Encoding.decodeUtf8With Text.Encoding.Error.lenientDecode       & ShortText.fromText-  {-# INLINE toShortText #-} -  fromShortText = ShortText.toByteString+  toShortTextUnsafe :: ByteString -> ShortText+  {-# INLINE toShortTextUnsafe #-}+  toShortTextUnsafe = toShortTextUnsafe . ShortByteString.toShort++  fromShortText :: ShortText -> ByteString   {-# INLINE fromShortText #-}+  fromShortText = ShortText.toByteString  -- | -- - toShortText: O(n). Turns invalid UTF-8 into the Unicode replacement character. -- - fromShortText: O(0) no-op instance Textual ByteArray where+  toShortText :: ByteArray -> ShortText+  {-# INLINE toShortText #-}   toShortText (ByteArray ba) = toShortText (ShortByteString.SBS ba)-  fromShortText short =-    let !(ShortByteString.SBS ba) = fromShortText short-     in ByteArray ba++  toShortTextUnsafe :: ByteArray -> ShortText+  {-# INLINE toShortTextUnsafe #-}+  toShortTextUnsafe (ByteArray ba) = toShortTextUnsafe (ShortByteString.SBS ba)++  fromShortText :: ShortText -> ByteArray+  {-# INLINE fromShortText #-}+  fromShortText (fromShortText -> ShortByteString.SBS ba) = ByteArray ba
symbolize.cabal view
@@ -5,7 +5,7 @@ -- see: https://github.com/sol/hpack  name:           symbolize-version:        1.0.1.0+version:        1.0.2.0 synopsis:       Efficient global Symbol table, with Garbage Collection. description:    Symbols, also known as Atoms or Interned Strings, are a common technique                 to reduce memory usage and improve performance when using many small strings: