Boost logo

Boost Users :

Subject: Re: [Boost-users] sizeof(boost::fusion:map)
From: Larry Evans (cppljevans_at_[hidden])
Date: 2010-11-06 05:30:42


On 11/05/10 13:01, Robert Lupton the Good wrote:
> I was very excited to find the boost::fusion library, expecting that
> I could use it to implement structs with introspection. I still
> think I can, but I was disappointed to see that I'm paying a size
> penalty. I'd have expected all the book-keeping to be handled at
> compile time.

>
> The following code prints
> sizeof(Foo) = 12 sizeof(FooS) = 4
> with g++ 4.2 or 4.4 on an os/x 10.6 or Centos box.
>
> Here Foo is
> boost::fusion::map<boost::fusion::pair<Name, int> >
>
> Where are the extra 8 bytes going? With more complex boost::fusion
> objects I see an overhead of up to 16 bytes. gdb indicates that
> foo.data.vec has the desired size, but foo.data is larger, and foo
> is larger still; however, it doesn't indicate any data members ---
> is this some sort of alignment issue?
>
> Is there a way to generate a "packed boost::fusion::map" without
> this space overhead?
>

Robert,

I'm not familiar with fusion::map and don't have any idea how to make
a "packed boost::fusion::map"; however, I think the
container template specialization found here:

http://svn.boost.org/svn/boost/sandbox/variadic_templates/boost/composite_storage/pack
    /container_all_of_aligned.hpp

could be modified to provide what you want. The modification would
simply replace the current "enum keys" with whatever key you might
desire. Let me explain "enum keys". Currently, the container template
in container_all_of_aligned.hpp is much like a boost::fusion::vector;
however, the syntax for accessing the component values is a bit different.
For fusion vector, the components are accessed with:

  at_c<KeyValue>(fusion_vector)

[where KeyValue is some integral constant, say of type unsigned,
between 0 and size(fusion_vector)-1]

In contrast, a container_all_of_aligned accesses it's components with
a templated member function:

  aligned_container.project<KeyValue>()

where KeyValue is some integral type suitable as the 2nd argument to
the boost::mpl::integral_c template. For example, the Index0 argument
to the template:

  template
  < class Index0
  , typename... Components
>
container
  < tags::all_of_aligned
  , Index0
  , Components...
>

located here:

https://svn.boost.org/trac/boost/browser/sandbox/variadic_templates/boost/composite_storage/pack/container_all_of_aligned.hpp#L29

is actually an instance of boost::mpl_integral_c<KeyType,KeyValue>
where the KeyValue corresonds to the 0-th component. KeyType could be
unsigned (corresponding to the KeyType for fusion::vector) or, to be
more user friendly, an enum type, e.g.

  enum component_indices
  { index_0
  , index_1
  ...
  , index_n
  };

Now, the method used by:

  aligned_container.project<KeyValue>()

to access the component is just to call the overloaded project method:

      static
    TailComponent const&
  project
    ( index_part index_arg
    , char const* buffer_composite
    )
          {
        void const*
      tail_buffer=buffer_composite+comp_part::offset;
              TailComponent const*
      tail_ptr=static_cast<TailComponentconst*>(tail_buffer);
      return *tail_ptr;
    }

located here:

https://svn.boost.org/trac/boost/browser/sandbox/variadic_templates/boost/composite_storage/layout/operators_all_of_aligned.hpp#L168

where index_part might be
boost::mpl::integral_c<component_indices,index_0>. The actual
component values are stored at offsets in the 2nd arg,
buffer_composite, to the project static function. That offset,
comp_part::offset, is a compile-time function of index_part.

Now, intead of:

  boost::mpl::integral_c<KeyType,KeyValue>

any type could used. The only important thing is that, because it's
passed by value to project, it should be easy to copy or just empty,
which boost::mpl::integral_c<KeyType,KeyValue> is. However, any other
type can easily be adapted to this purpose by simply wrapping it in
some templated empty type, such as that in
boost/mpl/aux_/type_wrapper.hpp. Thus, instead of:

       typedef
     boost::mpl::integral_c<KeyType,KeyValue>
   index_part;

for some KeyType, and KeyValue which is a KeyType, an index_part could
be:

       typedef
     boost::mpl::aux::type_wrapper<KeyClassType>
   index_part;

for some KeyClassType which would be the first element of one of the
fusion::pair<KeyClassType,ValueType>'s making up the map. Actually,
since no value is used, instead of fusion::pair, an mpl::pair could be
used.

Thus, since KeyClassType would not occur in any data structure, but
only as a template argument to a function, it could cause no memory
use (except maybe in the call stack, I guess). IOW, the algorithm
used to calculate the size of buffer_composite does not depend in any
way on the KeyClassType.

Of course with this change, the layout_composite<,,C...>::scanned:

https://svn.boost.org/trac/boost/browser/sandbox/variadic_templates/boost/composite_storage/pack/layout_composite.hpp#L52

would have to be changed to take mpl::pair's instead of just
components as the pack argument, C... .

Robert, if you're interested in this approach, I'll start adding
something similar to fusion::map to composite_storage. If not, then
I'll just wait a while before doing that (I've been planning on doing
it anyway).

-regards,
Larry


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net