#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. */ { }; #endif