2

I'm using Qi from Boost Spirit to parse VRML 1.0. There is a group node called Separator and immediately under Separator, many different types of nodes can be held. The AST is based upon Boost.Variant and so far is looking lengthy. I'm close to hitting the limit of 20 types in the variant. I know I can extend number of types a variant has, but I'm sure there must be a better way to design this. Ideas welcome.

typedef boost::variant<
    Nil,
    Coordinate3,
    Info,
    Material,
    MaterialBinding,
    Normal,
    NormalBinding,
    Texture2,
    Texture2Transform,
    TextureCoordinate2,
    ShapeHints,
    MatrixTransform,
    Rotation,
    Scale,
    Transform,
    Translation,
    boost::recursive_wrapper<Separator>
> VRML1Node;
sehe
  • 374,641
  • 47
  • 450
  • 633
PeteUK
  • 1,062
  • 12
  • 26

1 Answers1

3

Are you sure you're not optimizing prematurely? In my experience the 'cognitive overhead' of a variant doesn't increase with the number of element types in the variant[1]

You might want to

Use a type sequence to specify bounded types

typedef mpl::vector< Coordinate3 > types_initial;
typedef mpl::push_front< types_initial, Nil >::type types;

boost::make_variant_over< types >::type VRML1Node;

Alternatively

In stead of going for static polymorphism, you could in this case go the dynamic polymorphism route.

Depending on your use, the performance won't necessarily be badly impacted. The main difference would be

  1. to get completely optimizable visitor code, you need to employ dynamic cast where the variant is doing the type eraruse for you now
  2. the locality of memory allocations may be less optimal (allthough a custom allocator might alleviate things for you)
  3. the storage requirements might actually be improved (a variant will have to accomodate the largest element type; when most element types are in fact smaller, less memory will effectively be allocated).

    1. on the practical side, you may have to use Phoenix (semantic actions) to assign the attributes properly

I don't recommend it, but it is clear that you could even use boost::any

struct poorMansVariant
{
      TypeCode discriminator; // TypeCode::Nil, TypeCode::Coordinate3...
      boost::any value;
};

[1] though the situation may get slightly complex when some element types are convertible/assignable, or in general, their constructors become ambiguous. But that's another topic

sehe
  • 374,641
  • 47
  • 450
  • 633
  • sehe, I was hoping you'd answer as I've seen your valuable responses elsewhere! For the first suggestion I'd need to increase the number of types in mpl/variant by changing preprocessor symbols, right? In response to [this question](http://stackoverflow.com/questions/11630823/how-to-use-boost-spirit-with-variant-with-more-than-20-types) you suggested having too many types might be indicative of poor design, hence me trying to figure out the best thing to do. In the alternative suggestion, would my attribute types be pointers and the semantic action performing a new? – PeteUK Feb 15 '13 at 11:19
  • @PeteUK Yes: the alternative approach assumes dynamic instantiation (think _smart_ pointers). Regarding the 'poor design' I'd say that if you designed the grammar yourself. In this case, you just have to deal with it, I guess :) I have no idea what VRML looks like, but that grammar seems to be an unbalanced mix of extreme genericity and high specificity. If you get what I mean. – sehe Feb 15 '13 at 11:28
  • I will attempt to proceed with variant knowing all the concrete node types, increasing the boundaries on the number of types if necessary. I am also considering "collapsing" some of the nodes into the Separator node type. For instance, the ShapeHints and Info could be attributes of the Separator as there'll only be one ShapeHints specified within a Separator AIUI. I guess that will entail semantic actions and poking at locations in Separator's Fusion sequence. Thank you for your responses. – PeteUK Feb 15 '13 at 11:54