Boost logo

Boost :

From: David Abrahams (dave_at_[hidden])
Date: 2003-10-01 09:27:56


David Abrahams <dave_at_[hidden]> writes:

> I did some research on maps and sets for the upcoming MPL book and
> discovered an approach which essentially provides O(1) lookup, though
> I don't think we have an implementation in the MPL just yet.
> Unfortunately, I no longer have the prototype. I'm sure Aleksey has a
> copy.

Aleksey kindly dug this up for me; hope it helps.

// Copyright 2003 David Abrahams

#include "boost/mpl/apply.hpp"
#include "boost/mpl/void.hpp"
#include "boost/mpl/bool.hpp"
#include "boost/static_assert.hpp"

using namespace boost::mpl;

# if __ICL || _MSC_VER && _MSC_VER <= 1300
# define VC67 1 // Believe it or not, even Intel5,6,7 wants this hack
# endif

typedef char (&no)[2];
template <class T> struct id { id(); typedef T type; };

struct set_base
{
};

# if VC67
template <class X>
no operator%(set_base, X);

template <class T, class B = set_base>
struct set_node : B
{
    friend char operator%(set_node, id<T>);
};

template <class T, class S>
struct member
{
    enum { value = sizeof(S()%id<T>()) == 1 };
};

# else

template <class X>
no check(set_base, X);

template <class T, class B = set_base>
struct set_node : B
{
    friend char check(set_node, id<T>);
};

template <class T, class S>
struct member
{
    static bool const value = sizeof(check(S(),id<T>())) == 1;
};
# endif

typedef set_node<int, set_node<long, set_node<short> > > s;

BOOST_STATIC_ASSERT(( member<int,s>::value ));
BOOST_STATIC_ASSERT(( member<long,s>::value ));
BOOST_STATIC_ASSERT(( member<short,s>::value ));
BOOST_STATIC_ASSERT(( !member<char,s>::value ));
                 
//----------

# if VC67
struct map_base
{
    enum { index = 1 };
};

template <class X>
char operator%(map_base, X);

template <class K, class V, class B = map_base>
struct map_node : B
{
    enum { index = B::index + 1 };
    typedef char (&index_t)[index];
    friend index_t operator%(map_node, id<K>);
    friend id<V> operator*(map_node, id<index_t>);
};

template <class T, class M>
struct index
{
    enum { value = sizeof(M()%id<T>()) - 1 };
};
# else
struct map_base
{
    static unsigned const index = 1;
};

template <class X>
char find(map_base, X);

template <class K, class V, class B = map_base>
struct map_node : B
{
    static unsigned const index = B::index + 1;
    typedef char (&index_t)[index];
    friend index_t find(map_node, id<K>);
    friend id<V> at_(map_node, id<index_t>);
};

template <class T, class M>
struct index
{
    static unsigned const value = sizeof(find(M(), id<T>())) - 1;
};
# endif

typedef map_node<int, int*, map_node<long, long*, map_node<short, short*> > > m;

# if !__BORLANDC__ // no idea why, but Bcc 5.5.1 barfs here.
BOOST_STATIC_ASSERT(( index<int,m>::value == 3 ));
BOOST_STATIC_ASSERT(( index<long,m>::value == 2 ));
BOOST_STATIC_ASSERT(( index<short,m>::value == 1 ));
BOOST_STATIC_ASSERT(( index<char,m>::value == 0 ));
BOOST_STATIC_ASSERT(( index<char*,m>::value == 0 ));
BOOST_STATIC_ASSERT(( index<char*,m>::value == 0 ));
BOOST_STATIC_ASSERT(( index<char**,m>::value == 0 ));
# endif

// ------

# if VC67
template <class T>
int fassert_same(id<T>,id<T>);
template <class X, class Y> struct assert_same
{
    static id<X> a;
    static id<Y> b;
    enum { x = sizeof(fassert_same(a, b)) };
};
# else
template <class, class> struct assert_same;
template <class T> struct assert_same<T,T> {};
# endif

# ifdef __MWERKS__
template <class M, class K>
struct at
{
    typedef char (&ix)[index<K,M>::value + 1];
    typedef __typeof__(at_(M(), id<ix>())) id_;
    typedef typename id_::type type;
};

assert_same<at<m,int>::type,int*> c1;
assert_same<at<m,long>::type,long*> c2;
assert_same<at<m,short>::type,short*> c3;
# endif

// -------------

template <unsigned = 0>
struct unused_;

typedef char (&n1)[1];
typedef char (&n2)[2];
typedef char (&n3)[3];
typedef char (&n4)[4];
typedef char (&n5)[5];

# if !__BORLANDC__ // no idea why, but Bcc 5.5.1 barfs here.
template <
    class K1 = unused_<0>, class V1 = unused_<>
  , class K2 = unused_<1>, class V2 = unused_<>
  , class K3 = unused_<2>, class V3 = unused_<>
  , class K4 = unused_<3>, class V4 = unused_<>
>
struct vmap
{
    typedef V1 v1;
    typedef V2 v2;
    typedef V3 v3;
    typedef V4 v4;
    friend n1 operator%(vmap,id<K1>);
    friend n2 operator%(vmap,id<K2>);
    friend n3 operator%(vmap,id<K3>);
    friend n4 operator%(vmap,id<K4>);
};

template <unsigned N>
struct at_impl;

template <>
struct at_impl<1>
{
    template <class VM>
    struct apply
    {
        typedef typename VM::v1 type;
    };
};

template <>
struct at_impl<2>
{
    template <class VM>
    struct apply
    {
        typedef typename VM::v2 type;
    };
};

template <>
struct at_impl<3>
{
    template <class VM>
    struct apply
    {
        typedef typename VM::v3 type;
    };
};

template <>
struct at_impl<4>
{
    template <class VM>
    struct apply
    {
        typedef typename VM::v4 type;
    };
};

template <class VM, class K>
struct vat
{
    enum { index = sizeof(VM()%id<K>()) };
    typedef at_impl<index> outer;
    typedef typename outer::template apply<VM>::type type;
};

typedef vmap<int*, int, long*, long, short*, short, char, char*> vm;

assert_same<vat<vm,int*>::type, int> d1;
assert_same<vat<vm,long*>::type, long> d2;
assert_same<vat<vm,short*>::type, short> d3;
assert_same<vat<vm,char>::type, char*> d4;
# endif

int main()
{
    return 0;
}

-- 
Dave Abrahams
Boost Consulting
www.boost-consulting.com

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