Friday, 28 March 2014

Fast casting of C# Structs with no unsafe code (but still kind of "unsafe")

C++ allows us to perform any casting between memory pointers. It's basically up to you to ensure the correct types are casted to prevent memory problems.

C# however doesn't allow to do this out of the box, unless you go into using unsafe code and perform the pointer conversion yourself, pretty much like in C++.

Problem is that unsafe code is not supported in all platforms, and generally it's a good idea to avoid using it as long as you can.

So, imagine we have two structs like this:


    public struct STA
    {
        public int CustomerID;
        public float CustomerRate;
    }
    public struct STB
    {
        public int CustomerID;
        public float CustomerRate;
    }

One of them is yours, and the other one comes from an APIs or legacy software you don't have access to. Now, imagine you need to convert one into another. How would you face that?

Obviously, if you try to simply assign them, it just won't work:



Of course, the most evident (ans safest) solution is to create a new struct of the type STB and copy the contents from STA to STB:

struct_a = new STA(struct_b.CustomerID, struct_b.CustomerRate);

The drawback is that this approach is slow and implies a memory overhead, what might not be an option sometimes.

If performance is a critical issue, you are sure that both structs are 100% compatible and share the exact same memory layout, and that both come from compatible platforms... Why not fooling the compiler and make it just assume that they are compatible types? 

As we mentioned, in unsafe C# code this can be simply achieved by casting pointers, just like in C++. But if you mark your C# code as unsafe, it can be rejected in some platforms. Is there a way to do that without using unsafe code? Yes, there is.

C# StructLayout to the rescue

Perfectly safe C# code allows you to explicitly define the offset of struct members, using attributes from System.Runtime.InteropServices, just like this:


    [StructLayout(LayoutKind.Explicit)]
    public struct STA
    {
        [FieldOffset(0)]
        public int CustomerID;
        [FieldOffset(4)]
        public float CustomerRate;
    }

This allows you to do tricky things like settings two different members of the struct at the same offset, creating something similar to C++ Unions:


    [StructLayout(LayoutKind.Explicit)]
    public struct Union
    {
        [FieldOffset(0)]
        public STA StructA;
        [FieldOffset(0)]
        public STB StructB;
    }

Note that both StructA and StructB are at the same field offset, and therefore will occupy the exact same location in memory. As both share the same memory layout, the result is that you have ONE single object in memory, and two different references (kind of pointers) to them, each one using a different type. 

Now, we can do the following:


            STA struct_a;
            STB struct_b;
            ...
            Union stu = new Union();
            stu.StructB = struct_b;
            struct_a = stu.StructA;

As you can see, no new STA has been created in memory, and we have saved all the process of copying data from one struct to another.

However, please be aware that this is kind of cheating... You are fooling the compiler to accept that, but in practice you are performing a classical pointer conversion, even if you are using purely safe code.

PLEASE BE AWARE that this approach doesn't take into account endianness. Different platforms, with different byte endianness, may store bytes in the opposite way. For example, if STA comes from a big-endian platform, and STB works in a little-endian platform (or just the opposite), bytes will be reversed when doing this operation. It doesn't take into account differences in data types either, so you must be very careful to ensure that all types have the same size in one struct and the other.

So, remember:
if(same endiannes & same data types) 
                              you are good to go !

Functional improvements

The Union struct we have created can be made much more comfortable to use if you add operators to it.

For example, comparison operators like this:

 public static bool operator ==(STA left, Union right)
        {
            return left == right.StructA;
        }
        public static bool operator ==(STB left, Union right)
        {
            return left == right.StructB;
        }

Will allow you to simply compare Unions with the original types:

if(union == struct_a)

And even more comfortable, adding implicit operators like this:

        public static implicit operator Union(STA value)
        {
            Union ret = new Union();
            ret.StructA = value;
            return ret;
        }

Will allow you to simply assign one type to the other like this:

            STA struct_a;
            ...
            Union union = struct_a;

Memory footprint improvements

One small drawback of this approach is the need to create structs of the type Union, each time you want to perform a conversion of this kind. A simple solution is to perform the operation in a static Union object. It's a bit messy, but it works. For instance, if you declare the class like this:

    [StructLayout(LayoutKind.Explicit)]
    public struct Union
    {
        [FieldOffset(0)]
        public STA StructA;
        [FieldOffset(0)]
        public STB StructB;

        public static Union StaticRef = new Union();

        public static STA ToSTA(STB pStructB)
        {
            StaticRef.StructB = pStructB;
            return StaticRef.StructA;
        }
        public static STB ToSTB(STA pStructA)
        {
            StaticRef.StructA = pStructA;
            return StaticRef.StructB;
        }
    }

You can now re-use the same static object over and over again, doing things like:

            STA struct_a;
            STB struct_b;
            ...
            struct_a = Union.ToSTA(struct_b);

Hope it helps!! Cheers...

Wednesday, 29 January 2014

El lobo de Wall Street [Opinión]

Ayer por fin fuimos a ver El lobo de Wall Street… No sé si es porque llevo semanas escuchando lo fabulosa que es, pero a mí me ha resultado decepcionante. En mi opinión, Martin Scorsese lleva 14 años tratando de sacar un pelotazo como los de antes. No me refiero a un pelotazo en taquilla, ya que ésta está arransando, sino a una película que sorprenda.



Desde Gangs of New York (que puede gustarte o no, pero resulta sorprendente), nunca ha conseguido recrear esa tensión en pantalla que lo caracterizaba. Esas escenas que te dejaban con el culo pegado a la silla y los ojos bien abiertos… Ni El Aviador, ni Infiltrados, ni Shutter Island, ni ésta última están a la altura, en mi opinión…

Al final, El Lobo de Wall Street ni es una comedia, ni es un drama, ni es de acción, ni es un Thriller, ni resulta tan espectacular, ni es tan sobrada como dicen. Me resultó más bien anodina y nada que no hubiera visto antes: un idiota, drogas, putas y fiesta, todo en contextos muy predecibles. 

Se deja ver, pero no sorprende ni una sola vez, y la verdad no veo justificación para que dure 3 horas. Las actuaciones son muy buenas, eso sí… pero lo demás, bah… Una mezcla extraña entre las partes aburridas de Wall Street, American Psycho, Casino y Trainspotting…


Mi recomendación: no os gastéis 10 euros en ir a verla al cine. Si acaso, como mucho alquiladla en DVD o NetFlix cuando salga… 

Tuesday, 28 January 2014

HLSL code editing in Notepad ++

There are several HLSL syntax highlight add-ins for Visual Studio out there, but if you prefer to use the great NotePad++ to author or edit your shaders, my fellow DirectX MVP Matt Pettineo has written a Notepad++ add-in to allow doing this.

You just need to download the HLSL.xml file from his GoogleDrive account, and in Notepad ++ click Language->Define Your Language->Import and then select the downloaded file. After restarting notepad++, you´ll find a new entry in the Language menu item like this:


By clicking in that new item when you load an HLSL file, you´ll get the following result:


According to him, it supports even SM 5.0 profiles.

Great job Matt !!! :)

Monday, 27 January 2014

Como, que no ponen la película: El Lobo de Wall Steet?

Ayer me pasó algo curioso. Fuimos al cine a ver El lobo de Wall Street, y para mi sorpresa... no la ponían !


Se me hacía muy muy raro, ya que eran unos mega-cines de esos de 1800 salas. Más concretamente los Heron City de Las Rozas.

En los 2 minutos que estuvimos en la taquilla, vi al menos a 3 personas preguntar por esa película, y la pobre chica que estaba allí decía... "lo siento, pero no la ponemos".

Como tengo ganas de verla, busqué alternativas, y decidí mirar la cartelera de otros cines que nos pillaban de camino hacia casa: Los Cines Manoteras. Para mi (doble) sorpresa, tampoco la ponían... Demasiada coincidencia, sobre todo al ver que ambos cines son de la cadena Cinesa...

Informándome sobre el asunto esta mañana, me entero de que ni Cinesa ni Kinépolis ha estrenado esa película, por diferencias con la distribuidora Universal.

Alucinante!

Nunca me había tocado algo así... No se quién tendrá razón, pero no deja de resultar sorprendente que paguemos por ir al cine 4 veces más que hace 15 años, y aún así no les salga rentable... Y si, entonces también había super-producciones...

En fin... que no me parece la mejor forma de luchar así contra la piratería, y más cuando esta película ya está disponible por ahí...