1 2 // Licensed under the Apache License, Version 2.0 (the "License"); 3 // you may not use this file except in compliance with the License. 4 // You may obtain a copy of the License at 5 // 6 // http://www.apache.org/licenses/LICENSE-2.0 7 // 8 // Unless required by applicable law or agreed to in writing, software 9 // distributed under the License is distributed on an "AS IS" BASIS, 10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 // 14 // Copyright 2005-2010 Google, Inc. 15 // Author: jpr (at) google.com (Jake Ratkiewicz) 16 17 #ifndef FST_LIB_GENERIC_REGISTER_H_ 18 #define FST_LIB_GENERIC_REGISTER_H_ 19 20 #include <map> 21 #include <string> 22 23 #include <fst/compat.h> 24 #include <fst/types.h> 25 26 // Generic class representing a globally-stored correspondence between 27 // objects of KeyType and EntryType. 28 // KeyType must: 29 // a) be such as can be stored as a key in a map<> 30 // b) be concatenable with a const char* with the + operator 31 // (or you must subclass and redefine LoadEntryFromSharedObject) 32 // EntryType must be default constructible. 33 // 34 // The third template parameter should be the type of a subclass of this class 35 // (think CRTP). This is to allow GetRegister() to instantiate and return 36 // an object of the appropriate type. 37 38 namespace fst { 39 40 template<class KeyType, class EntryType, class RegisterType> 41 class GenericRegister { 42 public: 43 typedef KeyType Key; 44 typedef EntryType Entry; 45 46 static RegisterType *GetRegister() { 47 FstOnceInit(®ister_init_, 48 &RegisterType::Init); 49 50 return register_; 51 } 52 53 void SetEntry(const KeyType &key, 54 const EntryType &entry) { 55 MutexLock l(register_lock_); 56 57 register_table_.insert(make_pair(key, entry)); 58 } 59 60 EntryType GetEntry(const KeyType &key) const { 61 const EntryType *entry = LookupEntry(key); 62 if (entry) { 63 return *entry; 64 } else { 65 return LoadEntryFromSharedObject(key); 66 } 67 } 68 69 virtual ~GenericRegister() { } 70 71 protected: 72 // Override this if you want to be able to load missing definitions from 73 // shared object files. 74 virtual EntryType LoadEntryFromSharedObject(const KeyType &key) const { 75 string so_filename = ConvertKeyToSoFilename(key); 76 77 void *handle = dlopen(so_filename.c_str(), RTLD_LAZY); 78 if (handle == 0) { 79 LOG(ERROR) << "GenericRegister::GetEntry : " << dlerror(); 80 return EntryType(); 81 } 82 83 // We assume that the DSO constructs a static object in its global 84 // scope that does the registration. Thus we need only load it, not 85 // call any methods. 86 const EntryType *entry = this->LookupEntry(key); 87 if (entry == 0) { 88 LOG(ERROR) << "GenericRegister::GetEntry : " 89 << "lookup failed in shared object: " << so_filename; 90 return EntryType(); 91 } 92 return *entry; 93 } 94 95 // Override this to define how to turn a key into an SO filename. 96 virtual string ConvertKeyToSoFilename(const KeyType& key) const = 0; 97 98 virtual const EntryType *LookupEntry( 99 const KeyType &key) const { 100 MutexLock l(register_lock_); 101 102 typename RegisterMapType::const_iterator it = register_table_.find(key); 103 104 if (it != register_table_.end()) { 105 return &it->second; 106 } else { 107 return 0; 108 } 109 } 110 111 private: 112 typedef map<KeyType, EntryType> RegisterMapType; 113 114 static void Init() { 115 register_lock_ = new Mutex; 116 register_ = new RegisterType; 117 } 118 119 static FstOnceType register_init_; 120 static Mutex *register_lock_; 121 static RegisterType *register_; 122 123 RegisterMapType register_table_; 124 }; 125 126 template<class KeyType, class EntryType, class RegisterType> 127 FstOnceType GenericRegister<KeyType, EntryType, 128 RegisterType>::register_init_ = FST_ONCE_INIT; 129 130 template<class KeyType, class EntryType, class RegisterType> 131 Mutex *GenericRegister<KeyType, EntryType, RegisterType>::register_lock_ = 0; 132 133 template<class KeyType, class EntryType, class RegisterType> 134 RegisterType *GenericRegister<KeyType, EntryType, RegisterType>::register_ = 0; 135 136 // 137 // GENERIC REGISTRATION 138 // 139 140 // Generic register-er class capable of creating new register entries in the 141 // given RegisterType template parameter. This type must define types Key 142 // and Entry, and have appropriate static GetRegister() and instance 143 // SetEntry() functions. An easy way to accomplish this is to have RegisterType 144 // be the type of a subclass of GenericRegister. 145 template<class RegisterType> 146 class GenericRegisterer { 147 public: 148 typedef typename RegisterType::Key Key; 149 typedef typename RegisterType::Entry Entry; 150 151 GenericRegisterer(Key key, Entry entry) { 152 RegisterType *reg = RegisterType::GetRegister(); 153 reg->SetEntry(key, entry); 154 } 155 }; 156 157 } // namespace fst 158 159 #endif // FST_LIB_GENERIC_REGISTER_H_ 160