Boost logo

Boost :

From: Steven Watanabe (watanabesj_at_[hidden])
Date: 2007-09-08 14:02:18


AMDG

"Marco Costalba" <mcostalba_at_[hidden]> wrote:

> Sorry, but I don't understand, could you please post an example of how
> to use the dispatcher so to see 'struct implicit_conversion' at work ?
>
> Thanks
> Marco
>

The code I posted was not well thought out. The set of implicit conversions
should probably be global. I would want to write

make_implicit_conversion<double, int>();
make_implicit_conversion<int, double>();

Somewhere during initialization to say that int is convertible
to double and double to int.

Here's a more complete implementation (warning untested)
I'm not showing how to register functions. That would involve
creating a function object that casts from void* to the actual type.
A real implementation would probably also use Boost.Function
instead of function pointers.

struct wrap_typeinfo {
    friend bool operator<(const wrap_typeinfo& lhs, const wrap_typeinfo&
rhs) {
        return(lhs.key.before(rhs.key));
    }
    const std::type_info* impl;
};

struct implicit_conversion {
    friend bool operator<(const implicit_conversion& lhs, const
implicit_conversion& rhs) {
        return(lhs.from.before(rhs.from));
    }
    const std::type_info* to;
    void* (*convert)(void*);
    void (*destroy)(void*);
};

static std::multi_map<wrap_typeinfo, implicit_conversion> all_conversions;

void* ignore_convert(void* x) {
    return(x);
}

void ignore_destroy(void*) {}

static implicit_conversion no_conversion = {
    0,
    0,
    &ignore_convert
    &ignore_destroy
};

template<class To>
void destroy(void* victim) {
    delete static_cast<To*>(victim);
}

template<class From, class To>
void* convert(void* from) {
    return new To(*static_cast<From*>(from));
}

template<class From, class To>
void make_implicit_conversion() {
    wrap_typeinfo from = { &typeid(From) };
    implicit_conversion result = {
        &typeid(To),
        &convert<From, To>,
        &destroy<From, To>
    };
    all_conversions.insert(std::make_pair(from, result));
}

template<class R>
struct dispatcher0 {
public:
    R operator()() const {
        return(f0());
    }
private:
    R (*f0)();
};

template<class F>
F get_function(F f, const std::type_info**, const implicit_conversion**) {
    return(f);
}

template<class F, class T>
F get_function(const std::map<wrap_typeinfo, T>& m, wrap_typeinfo*
types, const implicit_conversion** out) {
    std::map<wrap_typeinfo, T>::iterator iter = m.find(*types);
    if(iter != m.end()) {
        ++types;
        *out++ = &no_conversion;
        return(get_function<F>(t.value, types, out));
    } else {
        BOOST_FOR_EACH(const implicit_conversion& conversion,
all_conversions.equal_range(*types)) {
            std::map<wrap_typeinfo, T>::iterator iter =
m.find(*conversion.from);
            if(iter != m.end()) {
                ++types;
                *out++ = &conversion;
                return(get_function<F>(iter->second, types, out));
            }
        }
    }
    return(0);
}

template<int N>
struct cleanup_array : cleanup_array<N - 1> {
    cleanup_array(implicit_conversion* c, void** data) : cleanup_array<N
- 1>(c) {
        x = c[N - 1].convert(data[N-1]);
    }
    ~cleanup_array() {
        cleanup_array<N - 1>::conversions[N-1].destroy(x);
    }
    void* x;
};

template<>
struct cleanup_array<0> {
    implicit_conversion* conversions;
    cleanup_array(implicit_conversion* c, void**) : conversions(c) {}
};

template<int N, int N2>
void* get(cleanup_array<N2>& from) {
    return(static_cast<cleanup_array<N+1>&>(from).x);
}

template<class R>
struct dispatcher1 {
public:
    template<class T0>
    R operator()(T0 t0) const {
        wrap_typeinfo types[1] = { &typeid(T0) };
        implicit_conversion* conversions[1];
        R (*f)(void*) = get_function<R(*)(void*)>(f1, types, conversions);
        void* elements[1] = { &t0 };
        cleanup_array<1> data(conversions, elements);
        return(f(get<0>(data)));
    }
private:
    std::map<wrap_typeinfo, R(*)(void*)> f1;
};

template<class R>
struct dispatcher2 {
public:
    template<class T0, class T1>
    R operator()(T0 t0, T1 t1) const {
        wrap_typeinfo types[2] = { &typeid(T0), &typeid(T2) };
        implicit_conversion* conversions[2];
        R (*f)(void*) = get_function<R(*)(void*, void*)>(f2, types,
conversions);
        void* elements[2] = { &t0, &t1 };
        cleanup_array<2> data(conversions, elements);
        return(f(get<0>(data), get<1>(data)));
    }
private:
    std::map<wrap_typeinfo, std::map<wrap_typeinfo, R(*)(void*, void*)>
> f2;
};

In Christ,
Steven Watanabe


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk