A simple Type mechanism for the Smallest Attribute System

The Smallest Attribute System (part 1, part 2) is almost done. This article presents a simple type mechanism that for eliminating the need for using C++ run time type information (RTTI). This modification is necessary because some compilers, especially on game consoles and embedded systems, don’t generate RTTI. The last piece, still to come, is reading and writing attributes from a file.

An int or short can be substituted for the typeid in the Smallest Attribute System. The version presented here is self-priming; an identifier for a type is generated whenever a type is first requested by name. The next time the same type is requested, the generated id will be returned.

class CharPtrPredicate
{
public:
    bool operator()(char const*const& lhs, char const*const& rhs) const
    {
        return strcmp(lhs, rhs) < 0;
    }
};

static std::map<const char*, int, CharPtrPredicate> typeIds;
static std::map<int, const char*> typeNames;

// If a type hasn't been seen before, enumerate it, otherwise return
// the enumerant generated the first time it was seen

int GetTypeId(const char* type)
{
    static int unique = 0;
    std::map<const char*, int, CharPtrPredicate>::const_iterator i = typeIds.find(type);
    int result;
    if (i == typeIds.end())
    {
        typeIds[type] = unique;
        typeNames[unique] = type;
        result = unique;
        ++unique;
    }
    else
    {
        result = i->second;
    }
    return result;
}

// GetTypeId must have been called for every type for this to return a useful value.

const char* GetTypeName(int i)
{
    std::map<int, const char*>::const_iterator j = typeNames.find(i);
    return j == typeNames.end() ? 0 : j->second;
}

The TypeName method needs to be updated.

std::string AttributeBinder::AttributeDescriptor::TypeName() const
{
    return GetTypeName(typeId);
}

Routines that use a particular type should statically initialize their variables to avoid map lookups later. For example:

    static int stringType = GetTypeId("std::string");

    if      (typeId == intType)
        o << "Found an int";

Finally modify the AttributeBinder to store an int as a typeId, instead of the type_info of the original class. The BIND macro needs to be modified as follows, everything else is pretty much the same.

#define BIND(className, val, vartype) \
    binding.bind(#val, #vartype, (ptrdiff_t)&((className*)0)->val)

Post to Twitter Post to Delicious Post to Facebook

  • admin
    It's a mistake for me to say "some compilers don't generate RTTI". In general gcc is used in those kinds of systems, and we manually turn off RTTI with -fno-rtti due to the incredible slowness of typeinfo and dynamic_cast. Sorry I mispoke there!

    Thanks for pointing out the thread-safety issue. I'm doing another pass on the next version to try to spot other thread safety issues.
  • ent
    Hi, been following this interesting group of articles. We have implemented a more complex reflection mechanism (you know, you start simple but the requirements add more and more complexity) and reading you articles allowed me to refresh what we have. :)

    > This modification is necessary because some compilers, especially on game consoles and embedded systems, don’t generate RTTI

    Could you enumerate compilers where you have found this problem? Our reflection system relies in RTTI (static, we compile with RTTI disabled) too.

    > an identifier for a type is generated whenever a type is first requested by name

    This is an important change from your last post. You are now thread-unsafe. You will need to add a mechanism to protect that static data.
blog comments powered by Disqus

Bad Behavior has blocked 801 access attempts in the last 7 days.