FAST DYNAMIC CASTING 141
The trick lies in finding a function F that satisfies this criterion and in determining the size of the
integer necessary to accommodate realistic software projects. We would prefer 32- or 64-bit integers
so that the function F could be performed efficiently. If the evaluation of the function takes longer than
walking the derivation tree, then nothing has been gained except a few bytes of program space.
Our suggestion for an F function is integer modulo. To construct the type ID, a different prime
number is associated with each class. The type ID for that class will be that prime number times the
prime number for each of its base classes. Thus, the type ID for a class will be evenly divisible by the
type ID of any of its base classes, and only by its base classes. This is guaranteed by the uniqueness of
the factorization of integers into prime factors. Given an arbitrarily large integer type ID, any hierarchy
can be represented this way. We wish to determine how large a hierarchy can be represented using a
machine’s built-in integer types.
This method has the advantage that integer math is very fast for numbers that fit in a machine register
and should be much faster than the usual tree-walking routine. Importantly, the check that one class
derives from another is performed in a known, constant time. If the full type of the object being cast
contains more than one copy of the target class, the cast will be ambiguous. In this case, the ID for the
full type will be divisible by the square of the prime for the target class. Performing a second divisibility
check determines if the cast can be done unambiguously. If the cast can be performed unambiguously,
the address of the returned object must be computed, as described below.
There are a number of heuristic methods for keeping the size of the type ID to a minimum number
of bits. To prevent the type IDs from being any larger than necessary, the classes are sorted according
to priority. The priority for a class is the maximum number of ancestors that any of its descendants has.
The priority reflects the number of prime factors that are multiplied together to form a class’ type ID.
Classes with the highest priority are assigned the smallest prime numbers.
If we had to assign each class a unique prime number, the type IDs would quickly get very large.
However, this is not strictly necessary. While all classes at the root level (those having no base classes)
must be assigned globally unique prime numbers, independent hierarchies can use the same primes for
non-root classes without conflict. Two classes with a common descendant then cannot have the same
prime and none of their children may have the same prime. This also implies that no two children of
a class may have the same prime. In all other cases, the primes can be duplicated across a level of
the hierarchy. For exam ple, in a tree structure two classes on the same level of the tree never have a
common d escendant, so they may have identical sub-trees beneath them without a conflict.
CONFLICTING CLASSES
Figure
2 shows an error that an overly simple a ssignment of prime multipliers could cause.
The proposed scheme avoids this problem. Note that the type ID for class D, 10, divides the type
ID for class E, 210, even though class E does not derive from class D. This has happened because we
assigned the same prime multiplier, 2, to classes C and D, thinking they were independent. They are
not independent because classes A and B share a common descendant, class E. In our terminology,
classes which share a common descendant are said to be in the same group.ClassA and class B are
in the same group. This motivates the rule for assigning primes: if any parent of class F is in the same
group as any parent of class G ,thenclassF and class G must be assigned different prime multipliers.
This rule is probably too strict, but we do not see any obvious way to loosen it.
Copyright
c
2005 John Wiley & Sons, Ltd. Softw. Pract. Exper. 2006; 36:139–156