/* ********************************************************************** * Copyright (c) 2001, International Business Machines * Corporation and others. All Rights Reserved. ********************************************************************** * Date Name Description * 08/10/2001 aliu Creation. ********************************************************************** */ #ifndef _TRANSREG_H #define _TRANSREG_H #include "unicode/utypes.h" #include "unicode/uobject.h" #include "unicode/translit.h" #include "hash.h" #include "uvector.h" U_NAMESPACE_BEGIN class Entry; class Spec; class UnicodeString; //------------------------------------------------------------------ // TransliteratorAlias //------------------------------------------------------------------ /** * A TransliteratorAlias object is returned by get() if the given ID * actually translates into something else. The caller then invokes * the create() method on the alias to create the actual * transliterator, and deletes the alias. * * Why all the shenanigans? To prevent circular calls between * the registry code and the transliterator code that deadlocks. */ class TransliteratorAlias : public UObject { public: /** * Construct a simple alias. * @param aliasID the given id. */ TransliteratorAlias(const UnicodeString& aliasID); /** * Construct a compound RBT alias. */ TransliteratorAlias(const UnicodeString& ID, const UnicodeString& idBlock, Transliterator* adopted, int32_t idSplitPoint, const UnicodeSet* compoundFilter); ~TransliteratorAlias(); /** * The whole point of create() is that the caller must invoke * it when the registry mutex is NOT held, to prevent deadlock. * It may only be called once. */ Transliterator* create(UParseError&, UErrorCode&); /** * ICU "poor man's RTTI", returns a UClassID for the actual class. * * @draft ICU 2.2 */ virtual inline UClassID getDynamicClassID() const { return getStaticClassID(); } /** * ICU "poor man's RTTI", returns a UClassID for this class. * * @draft ICU 2.2 */ static inline UClassID getStaticClassID() { return (UClassID)&fgClassID; } private: // We actually come in two flavors: // 1. Simple alias // Here aliasID is the alias string. Everything else is // null, zero, empty. // 2. CompoundRBT // Here ID is the ID, aliasID is the idBlock, trans is the // contained RBT, and idSplitPoint is the offet in aliasID // where the contained RBT goes. compoundFilter is the // compound filter, and it is _not_ owned. UnicodeString ID; UnicodeString aliasID; Transliterator* trans; // owned const UnicodeSet* compoundFilter; // alias int32_t idSplitPoint; /** * The address of this static class variable serves as this class's ID * for ICU "poor man's RTTI". */ static const char fgClassID; }; /** * A registry of system transliterators. This is the data structure * that implements the mapping between transliterator IDs and the data * or function pointers used to create the corresponding * transliterators. There is one instance of the registry that is * created statically. * * The registry consists of a dynamic component -- a hashtable -- and * a static component -- locale resource bundles. The dynamic store * is semantically overlaid on the static store, so the static mapping * can be dynamically overridden. * * This is an internal class that is only used by Transliterator. * Transliterator maintains one static instance of this class and * delegates all registry-related operations to it. * * @author Alan Liu */ class TransliteratorRegistry : public UObject { public: /** * Contructor * @param status Output param set to success/failure code. */ TransliteratorRegistry(UErrorCode& status); /** * Nonvirtual destructor -- this class is not subclassable. */ ~TransliteratorRegistry(); //------------------------------------------------------------------ // Basic public API //------------------------------------------------------------------ /** * Given a simple ID (forward direction, no inline filter, not * compound) attempt to instantiate it from the registry. Return * 0 on failure. * * Return a non-NULL aliasReturn value if the ID points to an alias. * We cannot instantiate it ourselves because the alias may contain * filters or compounds, which we do not understand. Caller should * make aliasReturn NULL before calling. * @param ID the given ID * @param aliasReturn the given TransliteratorAlias * @param parseError Struct to recieve information on position * of error if an error is encountered * @param status Output param set to success/failure code. */ Transliterator* get(const UnicodeString& ID, TransliteratorAlias*& aliasReturn, UParseError& parseError, UErrorCode& status); /** * Register a prototype (adopted). This adds an entry to the * dynamic store, or replaces an existing entry. Any entry in the * underlying static locale resource store is masked. */ void put(Transliterator* adoptedProto, UBool visible); /** * Register an ID and a factory function pointer. This adds an * entry to the dynamic store, or replaces an existing entry. Any * entry in the underlying static locale resource store is masked. */ void put(const UnicodeString& ID, Transliterator::Factory factory, Transliterator::Token context, UBool visible); /** * Register an ID and a resource name. This adds an entry to the * dynamic store, or replaces an existing entry. Any entry in the * underlying static locale resource store is masked. */ void put(const UnicodeString& ID, const UnicodeString& resourceName, UTransDirection dir, UBool visible); /** * Register an ID and an alias ID. This adds an entry to the * dynamic store, or replaces an existing entry. Any entry in the * underlying static locale resource store is masked. */ void put(const UnicodeString& ID, const UnicodeString& alias, UBool visible); /** * Unregister an ID. This removes an entry from the dynamic store * if there is one. The static locale resource store is * unaffected. * @param ID the given ID. */ void remove(const UnicodeString& ID); //------------------------------------------------------------------ // Public ID and spec management //------------------------------------------------------------------ /** * Return the number of IDs currently registered with the system. * To retrieve the actual IDs, call getAvailableID(i) with * i from 0 to countAvailableIDs() - 1. * @return the number of IDs currently registered with the system. * @draft */ int32_t countAvailableIDs(void); /** * Return the index-th available ID. index must be between 0 * and countAvailableIDs() - 1, inclusive. If index is out of * range, the result of getAvailableID(0) is returned. * @param index the given index. * @return the index-th available ID. index must be between 0 * and countAvailableIDs() - 1, inclusive. If index is out of * range, the result of getAvailableID(0) is returned. * @draft */ const UnicodeString& getAvailableID(int32_t index); /** * Return the number of registered source specifiers. * @return the number of registered source specifiers. */ int32_t countAvailableSources(void); /** * Return a registered source specifier. * @param index which specifier to return, from 0 to n-1, where * n = countAvailableSources() * @param result fill-in paramter to receive the source specifier. * If index is out of range, result will be empty. * @return reference to result */ UnicodeString& getAvailableSource(int32_t index, UnicodeString& result); /** * Return the number of registered target specifiers for a given * source specifier. * @param source the given source specifier. * @return the number of registered target specifiers for a given * source specifier. */ int32_t countAvailableTargets(const UnicodeString& source); /** * Return a registered target specifier for a given source. * @param index which specifier to return, from 0 to n-1, where * n = countAvailableTargets(source) * @param source the source specifier * @param result fill-in paramter to receive the target specifier. * If source is invalid or if index is out of range, result will * be empty. * @return reference to result */ UnicodeString& getAvailableTarget(int32_t index, const UnicodeString& source, UnicodeString& result); /** * Return the number of registered variant specifiers for a given * source-target pair. There is always at least one variant: If * just source-target is registered, then the single variant * NO_VARIANT is returned. If source-target/variant is registered * then that variant is returned. * @param source the source specifiers * @param target the target specifiers * @return the number of registered variant specifiers for a given * source-target pair. */ int32_t countAvailableVariants(const UnicodeString& source, const UnicodeString& target); /** * Return a registered variant specifier for a given source-target * pair. If NO_VARIANT is one of the variants, then it will be * at index 0. * @param index which specifier to return, from 0 to n-1, where * n = countAvailableVariants(source, target) * @param source the source specifier * @param target the target specifier * @param result fill-in paramter to receive the variant * specifier. If source is invalid or if target is invalid or if * index is out of range, result will be empty. * @return reference to result */ UnicodeString& getAvailableVariant(int32_t index, const UnicodeString& source, const UnicodeString& target, UnicodeString& result); /** * ICU "poor man's RTTI", returns a UClassID for the actual class. * * @draft ICU 2.2 */ virtual inline UClassID getDynamicClassID() const { return getStaticClassID(); } /** * ICU "poor man's RTTI", returns a UClassID for this class. * * @draft ICU 2.2 */ static inline UClassID getStaticClassID() { return (UClassID)&fgClassID; } private: //---------------------------------------------------------------- // Private implementation //---------------------------------------------------------------- Entry* find(const UnicodeString& ID); Entry* find(UnicodeString& source, UnicodeString& target, UnicodeString& variant); Entry* findInDynamicStore(const Spec& src, const Spec& trg, const UnicodeString& variant); Entry* findInStaticStore(const Spec& src, const Spec& trg, const UnicodeString& variant); static Entry* findInBundle(const Spec& specToOpen, const Spec& specToFind, const UnicodeString& variant, UTransDirection direction); void registerEntry(const UnicodeString& source, const UnicodeString& target, const UnicodeString& variant, Entry* adopted, UBool visible); void registerEntry(const UnicodeString& ID, Entry* adopted, UBool visible); void registerEntry(const UnicodeString& ID, const UnicodeString& source, const UnicodeString& target, const UnicodeString& variant, Entry* adopted, UBool visible); void registerSTV(const UnicodeString& source, const UnicodeString& target, const UnicodeString& variant); void removeSTV(const UnicodeString& source, const UnicodeString& target, const UnicodeString& variant); Transliterator* instantiateEntry(const UnicodeString& ID, Entry *entry, TransliteratorAlias*& aliasReturn, UParseError& parseError, UErrorCode& status); private: /** * Dynamic registry mapping full IDs to Entry objects. This * contains both public and internal entities. The visibility is * controlled by whether an entry is listed in availableIDs and * specDAG or not. */ Hashtable registry; /** * DAG of visible IDs by spec. Hashtable: source => (Hashtable: * target => (UVector: variant)) The UVector of variants is never * empty. For a source-target with no variant, the special * variant NO_VARIANT (the empty string) is stored in slot zero of * the UVector. */ Hashtable specDAG; /** * Vector of public full IDs. */ UVector availableIDs; /** * The address of this static class variable serves as this class's ID * for ICU "poor man's RTTI". */ static const char fgClassID; }; U_NAMESPACE_END #endif //eof