Un semplice unsafeCoerce
non funzionerà, come la disposizione dei costruttori di dati è diverso:
data StorableArray i e = StorableArray !i !i Int !(ForeignPtr e)
vs.
data ByteString = PS {-# UNPACK #-} !(ForeignPtr Word8) -- payload
{-# UNPACK #-} !Int -- offset
{-# UNPACK #-} !Int -- length
È possibile importare Data.Array.Storable.Internals
e Data.ByteString.Internal
per ottenere l'accesso ai costruttori prime e quindi costruirne uno senza copiare i dati:
> let bs = pack [1,2,3]
> bs
"\SOH\STX\ETX"
> let sa = case bs of (PS ptr 0 n) -> StorableArray 0 (n-1) n ptr
> :t sa
sa :: StorableArray Int GHC.Word.Word8
> Data.Array.MArray.readArray sa 1
2
> Data.Array.MArray.readArray sa 0
1
> Data.Array.MArray.readArray sa 3
*** Exception: Ix{Int}.index: Index (3) out of range ((0,2))
(Ho rimosso il prompt piuttosto lungo di Prelude Data.Array.Storable.Internals Data.ByteString.Internal Data.ByteString>
).
Questo non funzionerà per Data.Vector.Unboxed
, perché qui i dati sono nell'heap di Haskell e gestiti dal runtime di GHC, mentre gli altri due gestiscono i dati all'esterno dell'heap di Haskell.
fonte
2013-09-08 17:12:44
In alcuni casi sarebbe utile per copiare. Se i tuoi bytestrings sono brevi segmenti di un originale più lungo, ad es. ('BS.take 10 someLongByteString'), l'intero blocco lungo verrà mantenuto dal' ForeignPtr'. In questo caso la copia è spesso migliore perché utilizzerà molta meno memoria. Questa è una specie di caso specializzato, ma sembra emergere spesso. –