Boost logo

Boost :

Subject: Re: [boost] [any] new version
From: Artyom Beilis (artyomtnk_at_[hidden])
Date: 2011-09-03 10:25:18


> From: Martin Bidlingmaier <Martin.Bidlingmaier_at_[hidden]>
>
> I've written a new version of boost::any. It does not
> depend on rtti and uses a static integer value instead of
> std::type_info to store type information.

Instead of reinventing the RTTI wheel.

See following:

There are 5 implementations of any using different
methods

      linux windows
boost 8.45 70.8 boost.any 1.46
any1 8.45 31.4 virtual impl->type() == typeid(Cast)
any2 3.9 17.1 *this->type_ == typeid(Cast)
any3 10.15 35.2 strcmp(this->type_->name(),typeid(Cast).name()) == 0
any4 4.5 12.5 this->type_ == &typeid(Cast) || *this->type_ == typeid(Cast)

The first any implements the Boost.Any method - virtual call to get type
compare to casted type and then cast.

Other any2 to any 4 store pointer to typeid in the any object
itself eliminating needless virtual call so any looks like

 {
   std::type_info const *type_;
   clone_ptr<impl> *impl;
 }

3 methods proposed:

any2. compare types as is
any3. compare names
any4. compare pointer and then types.

The 4th one should has the same efficiency as comparing integers
and in fact on windows it was the fastest and on Linux
comparing typeids was the fastest.

What is good about it?

1. No virtual function calls at all
2. It is as fast as comparison of pointers or integers
3. It is fully dll/thread/standard safe and use native RTTI

So...

You want to improve any? Keep RTTI just
use it in a smart way.

Artyom Beilis
--------------
CppCMS - C++ Web Framework: http://cppcms.sf.net/
CppDB - C++ SQL Connectivity: http://cppcms.sf.net/sql/cppdb/

-----------------------

any.h
--------

#include <booster/clone_ptr.h>
#include <typeinfo>
#include <iostream>
#include <string.h>

#ifdef USE_BOOST
#include <boost/any.hpp>
using boost::any;
using boost::any_cast;
#elif defined(USE_ANY1)

class any {
        struct impl {
                virtual std::type_info const &type() const = 0;
                virtual impl *clone() const = 0;
                virtual ~impl() {}
        };
        template<typename T>
        struct impl_of : public impl{
                impl_of(T const &v) : v_(v) {}
                virtual impl *clone() const
                { return new impl_of(*this); }
                virtual std::type_info const &type() const
                {
                        return typeid(T);
                }
                T v_;
        };
public:
        template<typename T>
        any(T const &v) : o(new impl_of<T>(v))
        {
        }
        any(any const &other) : o(other.o) {}
        any const &operator=(any const &other)
        {
                o = other.o;
                return *this;
        }
        template<typename V>
        V &cast()
        {
                if(o->type() == typeid(V))
                        return static_cast<impl_of<V> *>(o.get())->v_;
                throw std::bad_cast();
        }
private:
        booster::clone_ptr<impl> o;
};

template<typename T>
T &any_cast(any &v) { return v.cast<T>(); }

#elif defined USE_ANY2 || defined USE_ANY3 || defined USE_ANY4
class any {
        struct impl {
                virtual impl *clone() const = 0;
                virtual ~impl() {}
        };
        template<typename T>
        struct impl_of : public impl{
                impl_of(T const &v) : v_(v) {}
                virtual impl *clone() const
                { return new impl_of(*this); }
                T v_;
        };
public:
        template<typename T>
        any(T const &v) : o(new impl_of<T>(v)), type(&typeid(T))
        {
        }
        any(any const &other) : o(other.o) {}
        any const &operator=(any const &other)
        {
                o = other.o;
                return *this;
        }
        template<typename V>
        V &cast()
        {
#ifdef USE_ANY3
                if(strcmp(type->name(),typeid(V).name())==0)
#elif defined(USE_ANY2)
                if(*type==typeid(V))
#elif defined USE_ANY4
                if(type == &typeid(V) || *type==typeid(V))
#else
#error
#endif
                        return static_cast<impl_of<V> *>(o.get())->v_;
                throw std::bad_cast();
        }
private:
        booster::clone_ptr<impl> o;
        std::type_info const *type;
};
template<typename T>
T &any_cast(any &v) { return v.cast<T>(); }

#endif

test.cpp
----------

#include "any.h"

// prevent inlining
int get_val(any &v);

int main()
{
        any a=int(2);
        int sum=0;
        for(int i=0;i<1000000000;i++) {
                sum+= get_val(a);
        }
        std::cout << sum << std::endl;
}

getval.cpp
----------
#include "any.h"

int get_val(any &v)
{
        return any_cast<int>(v);
}


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