Nice addition to Foreign: castAny

View: New views
3 Messages — Rating Filter:   Alert me  

Nice addition to Foreign: castAny

by Maurí­cio CA :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

This could be beside castPtr, castCharToCChar etc.

----

castAny :: (Storable a, Storable b) => a -> b
castAny = unsafePerformIO . genericCast
   where
     genericCast :: (Storable a, Storable b) => a -> IO b
     genericCast v = return undefined >>= \r ->
       allocaBytes (max (sizeOf v) (sizeOf r)) $ \p ->
         poke p v >> if False then return r else peek (castPtr p)

----

GHCi:

    > let a = -1000 :: Int16
    > castAny a :: Word16  -->
    64536
    > castAny a :: Ptr ()
    0xb4c2fc18
    > castAny (castAny a :: Ptr ()) :: Int16
    -1000

    > let b = pi :: CLDouble
    > b
    3.141592653589793
    > castAny b :: CInt
    1413754136
    > castAny b :: Ptr ()
    0x54442d18
    > castAny b :: CFloat
    3.3702806e12
    > castAny b :: Int8
    24


At minimum, this is safer than 'unsafeCoerce'. What do you think?

Best,
Maurício

_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe@...
http://www.haskell.org/mailman/listinfo/haskell-cafe

Re: Nice addition to Foreign: castAny

by John Meacham :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Tue, Oct 27, 2009 at 12:48:32AM -0200, Maurí­cio CA wrote:

> This could be beside castPtr, castCharToCChar etc.
>
> ----
>
> castAny :: (Storable a, Storable b) => a -> b
> castAny = unsafePerformIO . genericCast
>   where
>     genericCast :: (Storable a, Storable b) => a -> IO b
>     genericCast v = return undefined >>= \r ->
>       allocaBytes (max (sizeOf v) (sizeOf r)) $ \p ->
>         poke p v >> if False then return r else peek (castPtr p)
>
> ----
>
> GHCi:
>
>    > let a = -1000 :: Int16
>    > castAny a :: Word16  -->
>    64536
>    > castAny a :: Ptr ()
>    0xb4c2fc18
>    > castAny (castAny a :: Ptr ()) :: Int16
>    -1000
>
>    > let b = pi :: CLDouble
>    > b
>    3.141592653589793
>    > castAny b :: CInt
>    1413754136
>    > castAny b :: Ptr ()
>    0x54442d18
>    > castAny b :: CFloat
>    3.3702806e12
>    > castAny b :: Int8
>    24
>
>
> At minimum, this is safer than 'unsafeCoerce'. What do you think?

Try it on a big endian architecture, or one that has alignment
restrictions, or a different size for HsChar or so forth. Casting by
'punning' (as the C folks like to call it) does have uses, but they are
generally hardware dependent and useful only in certain rare
circumstances that a generic cast probably isn't likely to fill.

        John

--
John Meacham - ⑆repetae.net⑆john⑈ - http://notanumber.net/
_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe@...
http://www.haskell.org/mailman/listinfo/haskell-cafe

Re: Nice addition to Foreign: castAny

by Maurí­cio CA :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

>> castAny :: (Storable a, Storable b) => a -> b
>> castAny = unsafePerformIO . genericCast
>>   where
>>     genericCast :: (Storable a, Storable b) => a -> IO b
>>     genericCast v = return undefined >>= \r ->
>>       allocaBytes (max (sizeOf v) (sizeOf r)) $ \p ->
>>         poke p v >> if False then return r else peek (castPtr p)

>>    > let a = -1000 :: Int16
>>    > castAny a :: Word16  -->
>>    64536
>>    > castAny a :: Ptr ()
>>    0xb4c2fc18

> Try it on a big endian architecture, or one that has alignment
> restrictions, or a different size for HsChar or so forth. Casting by
> 'punning' (as the C folks like to call it) does have uses, but they are
> generally hardware dependent and useful only in certain rare
> circumstances that a generic cast probably isn't likely to fill.

Do you think this could be used as a way to handle
C unions? If I had something like

union example {
   struct firstview {
     char c;
     int n;
   } fv;
   long double ld;
};

and 'firstview' had been mapped in Haskell as, say,

   FirstView {firstViewC :: CChar, firstVewN :: CInt}

I could check what I would get after pokeing values
using:

(firstViewN . unionCast) (pi :: CDouble)

Note that I changed the name from castAny to unionCast
to reflect its use.

Thanks for your comments,
Maurício

_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe@...
http://www.haskell.org/mailman/listinfo/haskell-cafe