#ifndef CMM_DISPATCH_H #define CMM_DISPATCH_H #include #include /* These types and functions are usually only used by code generated by the Cmm programme. C-style strings are used to encode type information, including class names and inheritence. The format is not for public use - it is generated by the Cmm programme, and read by functions in cmm's dispatch.cpp library. At the time of writing (jan 2003), it is similar to the name mangling used by C++ compilers: _[] where: is is: _[] where: is E.g.: struct Base {}; struct Derived {}; foo( virtual Base&, virtual Derived&); Then foo() is represented as: 3foo_2_1_4Base_2_4Base_7Derived */ struct cmm_implementation; struct cmm_virtualfn; /* These are not defined here - they are internal only. */ typedef bool (*cmm_matchfn)( const void** params); /* In: params: Array of addresses of objects that can be cast to the virtual types specified in a virtual function. The number of valid elements in the array is not specified - the function should know how many to expect. Returns: True if the implmentation matches the dynamic types of the parameters. Otherwise false. */ typedef void (*cmm_fnptr)( void); /* Generic function pointer. Typically used to represent the actual implementation of a virtual function. */ cmm_virtualfn& cmm_get_virtualfn( const char* virt_spec); /* In: virt_spec String encoding of a virtual function. Returns: Reference to internal singleton object representing the specified virtual function. This can be used later when calling the cmm_lookup* functions. */ cmm_implementation& cmm_register_implementation( const char* virt_spec, const char* impl_spec, cmm_matchfn fn_match, cmm_fnptr fn_call); /* In: virt_spec String encoding of a virtual function. impl_spec String encoding of implementation of the virtual function specified by virt_spec. fn_match Pointer to function that returns true if this implementation can handle a particular set of dynamic types. fn_call Untyped pointer to function that takes the same parameters as the virtual function except that all virtual parameters are passed as base classes, down-casts them and calls the real implementation. Returns: Reference to internal singleton object for this implementation. Registers fn_match/fn_call as an implementation of virtual function specified by `virt_spec'. The signature of the implmentation is specified by `impl_spec'. The returned cmm_implementation singleton isn't really useful for anything at the moment. This function is designed to be easily used in a static initialiser, e.g. see code generated by cmm -s. */ void cmm_unregister_implementation( cmm_implementation& implementation); /* In: Reference to implementation, previously returned from cmm_register_implementation. The deregisters the specified implementation. */ struct cmm_implementation_holder /* Constructor calls cmm_register_implementation, destructor calls cmm_unregister_implementation. Cmm's generated code has static instances of this class, to ensure that implementations are unregistered correctly. */ { cmm_implementation_holder( const char* virt_spec, const char* impl_spec, cmm_matchfn fn_match, cmm_fnptr fn_call); ~cmm_implementation_holder(); cmm_implementation& handle; }; cmm_fnptr cmm_lookup( cmm_virtualfn& virtfn, const void** params, const std::type_info** types); /* Log-time lookup, using std::type_info*'s to identify types. In: virtfn something from previous call to cmm_get_virtualfn(). params Size of this array is the number of virtual params to virtfn. Each element is address of each virtual param casted to the base class and then to void*. types Size of this array is the number of virtual params to virtfn. Each element is a pointer to the type_info for the virtual parameter. This information is used when generating an exception for unmatched or ambiguous dispatch, and as a key for the internal cache. Returns: pointer to the implementation function that is best match of the dynamic types in `params'. Else throws cmm_exception_ambiguous or cmm_exception_unmatched. This function uses an internal cache based on the information in `types', so previously seen dynamic types combinations are dispatched in Log(N) time, where N is the number of dynamic-type combinations seen for the specified virtual function. */ cmm_fnptr cmm_lookup( cmm_virtualfn& virtfn, const void** params, const int* types); /* Constant-time lookup, using small integers to identify types. In: virtfn something from previous call to cmm_get_virtualfn(). params Size of this array is the number of virtual params to virtfn. Each element is address of each virtual param casted to the base class and then to void*. types Size of this array is the number of virtual params to virtfn. Each element is a small integer that uniquely identifies the dynamic type of a virtual parameter. Typically obtained using cmm_create_small_integer(). Returns: pointer to the implementation function that is best match of the dynamic types in `params'. Else throws cmm_exception_ambiguous or cmm_exception_unmatched. This function uses an internal cache based on the information in `types'; previously-seen dynamic type combinations are dispatched in constant time. Note that if dispatch is unmatched/ambiguous, the generated exception will not contain information on the actual dynamic types. */ cmm_fnptr cmm_lookup_nocache( cmm_virtualfn& virtfn, const void** params, const std::type_info** types); /* Params/return are same as for cmm_lookup(). This is mainly for internal use by the cmm_lookup() functions when the required types/fn aren't already cached. Current implementation takes time O(N^2) where N is the number of implementations of the specified virtual function. */ int cmm_create_small_integer( const std::type_info& type); /* Returns a unique integer for each different std::type_info. Calling this function more than one for the same type_info will return the same integer each time. */ struct cmm_small_integer_typeid { }; /* obsolete - won't be required soon. */ void cmm_debug_showall(); /* Outputs debug information about all known virtual functions and their implementations. */ /* Following classes are thrown when a dispatch fails: (actually, the actual exception objects that are thrown are internal-only classes that derive from these classes). The what() methods give fairly complete information about how the dispatch has failed. */ struct cmm_exception : std::exception /* Base class for all Cmm exceptions. */ { }; struct cmm_exception_ambiguous : cmm_exception { }; struct cmm_exception_unmatched : cmm_exception { }; struct cmm_exception_bad_implementation : cmm_exception /* This is thrown when registration of an implementation is attempted for an implementation that doesn't match its virtual function. Hopefully this will never happen via auto-generated code. */ { }; /* things for caller-dispatch support. */ cmm_fnptr cmm_lookup( const char* fnname, const std::type_info* returntype, ... // null terminated list of parameter std::type_info*'s. ); /* searches functions previously registered with cmm_register_fn for one that best matches the std::type_info*'s passed in the variadic list. throws if lookup is ambiguous or unmatched. The caller should cast the returned function pointer to one that takes the base parameters of all polymorphic parameters.*/ int cmm_register_class( const std::type_info* typeinfo, ... // null-terminated list of base class std::type_info*'s. ); /* returns dummy integer so that it can be called from a static initialiser. */ int cmm_register_fn( const char* fnname, cmm_fnptr fnptr, const std::type_info* returntype, ... // null-terminated list of parameter std::type_info*'s. ); /* returns dummy integer so that it can be called from a static initialiser. */ #endif