syntax highlight

Tuesday, 31 August 2010

Template Metaprogramming XIII: Heart of Darkness

Last time we had a virtual template dispatch problem... we got to the point of knowing which was the index of the cache we were searching for, now we need to actually retrieve an instance of that cache. That's a problem. Why? To begin with, there are no instances, only types!

The next logical step would be to create a Map device, to map a list of types to a list of instances... let's see how can we do that, in pseudocode

instances( H|T ) <- [ create_instance(H), instances(T) ]
instances( NIL ) <- NIL

Looks easy. How can we map that to c++?

template <class Lst> struct Instance {
    typedef typename Lst::head Elm;
    Elm instance;
    Instance< typename Lst::tail > next;
};
template <> struct Instance<NIL> {};

#include <iostream>
using std::cout;

int main() {
    typedef LST<int, LST<char, LST<float> > > Lst;
    Instance<Lst> lst;
    lst.instance = 1;
    lst.next.instance = 'a';
    lst.next.next.instance = 3.1;
    std::cout << lst.next.instance << "n";
    return 0;
}

All those next.next.next.instance look ugly. Let's use some more meta-magic to get the Nth instance (why not a [] operator? several reasons, you can't mix non-const ints with templates nicely, there would be problems to define the return type... all those options are workable but it's easier if we do this in another device.

template <typename LST> struct Nth {
	typedef typename LST::tail Tail;
	typedef typename Nth::result result;
};
template <typename LST> struct Nth {
	typedef typename LST::head result;
};
Remember that one from the toolbox? Now we know how to get a specific index position, yet getting the instance is a different problem (the Nth device returns a type, not an instance). We should do something different, the problem is knowing the return type. What's the return type for the Nth instance of the Instances list?
   type <- Nth(TypesLst, Type)
   type var <- NthInstance(InstancesLst, N)
Not so easy, right? This is the translated C++:

template <int N, typename TypeLst> struct NthInstance {
    // This one isnt easy...
    
    // This is the next type in the list
    typedef typename TypeLst::tail TypeNext;

    //  * Nth::result is the Nth type in Lst (i.e. char, int, ...)
    typedef typename NthInstance<N-1, TypeLst>::NthInstanceType NthInstanceType;

    //  * typename Nth::result & is a reference to said type and the ret type
    template <InstancesLst>
    static NthInstanceType& get(InstancesLst &instances_lst) {
        return NthInstance::get(instances_lst.next);
    }
};

// Remember, just for fun we choose a 1-based system (wtf..)
template <typename TypeLst> struct NthInstance<1, TypeLst> {
    typedef typename TypeLst::head NthInstanceType;

    template <InstancesLst>
    static NthInstanceType& get(InstancesLst &instances_lst) {
        return instances_lst.instance;
    }
};
And the code from fetching the instance itself is even more difficult, so I'll leave that for next time.

Thursday, 26 August 2010

Date time WTF

Another one to add to my growing list of bad things about Ubuntu. For some reason my clock froze. I only noticed it when it started to be dark outside, for me the time had frozen at about 17pm.

Tuesday, 24 August 2010

Template Metaprogramming XII: You Really Got a Hold on Me

Remember our virtual template method problem, from the other time? (I know, I said the answer was scheduled for a week after that post, but then I just forgot about it). May be we could avoid the virtual part by keeping a list of all our caches... how would we know which one should we dispatch the message to? Easy, using templates.

Instead of a list let's keep two, for twice the fun. One for the rows cache, another for the PKs. We can use PK to know which ROW Cache should we choose. Let's try to write a pseudo code for it:

ROW get_row(PK id) {
    pos <- Position of PK in pks_lst
    return cache[ pos ].get_row( id )
}

Doesn't look too hard. Building on our previous toolbox, let's use Eq, Position and the definition of a list:

struct NIL {
    typedef NIL head;
    typedef NIL tail;
};

template < class H, class T=NIL> struct LST {
    typedef H head;
    typedef T tail;
};

template <class X, class Y> struct Eq { static const bool result = false; };
template <class X> struct Eq<X, X> { static const bool result = true; };

template <class Elm, class LST> struct Position {
    private:
    typedef typename LST::head H;
    typedef typename LST::tail T;
    static const bool found = Eq<H, Elm>::result;
    public:
    static const int result = found? 1 : 1 + Position<Elm, T>::result;
};

template <class Elm> struct Position<Elm, NIL> {
    static const int result = 0;
};

class Facade {
    typedef LST<int, LST<char, LST<float> > > Lst;

    public:
    template <class PK> int find(PK) {
        return Position< PK, Lst >::result;
    }
};

#include <iostream>
using std::cout;

int main() {
    Facade f;
    std::cout << f.find(1.0) << "\n";
    return 0;
}

Great, now we can find an element on a list of types. The real virtual dispatch for the next entry :D

Thursday, 19 August 2010

MySQL upsert, Oracle merge

How many times have you seen this "pattern"?

unsigned int row_count = foo->update();
if (row_count == 0) {
   foo->insert();
}

Wouldn't it be nice if you could write all that in a single line? Say, something like

foo->update_or_insert_if_it_doesnt_exists();
Well, good news, you can! Obviously it's not standard SQL, nothing useful ever is, but even so I think using an upsert (who comes up with those names?) can be quite good for your health.

So, how do you use it? It's easy;

INSERT INTO Table ( col1, col2 )
SELECT 'a', 'b'
ON DUPLICATE KEY UPDATE col1 = 'a', col2 = 'b';
Go on, try it, I'll wait. What? It didn't work? Oh, I forgot, you need to create a unique key so the engine can recognize when there is a duplicate key (say, 'create index unique on col1'). Try it now.

Nice, isn't it? Oracle has its own version of upsert, called merge (at least the name is better) but it itches a little bit when I write about Oracle, so go and check this page instead.

Tuesday, 3 August 2010

C++ Namespaces and g++

Have you ever tried to leave open a C++ namespace after EOF (that is, openning a namespace in a headerfile but forgetting to close it). It's a little bit like getting your balls caught by the door. The compiler will throw at you an incredible number of seemingly unrelated errors, all of which occur in a different file than the offending header.

Reaching EOF on a C++ file without closing all its namespaces should be ilegal; or at least you should have better error reporting, because right now it's almost impossible to know what's the source of the error (for g++, that is).