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@google.com (Jake Ratkiewicz) 16 17 #ifndef FST_LIB_GENERIC_REGISTER_H_ 18 #define FST_LIB_GENERIC_REGISTER_H_ 19 20 #ifndef FST_NO_DYNAMIC_LINKING 21 #include <fst/compat.h> 22 #endif 23 #include <map> 24 #include <string> 25 26 #include <fst/types.h> 27 28 // Generic class representing a globally-stored correspondence between 29 // objects of KeyType and EntryType. 30 // KeyType must: 31 // a) be such as can be stored as a key in a map<> 32 // b) be concatenable with a const char* with the + operator 33 // (or you must subclass and redefine LoadEntryFromSharedObject) 34 // EntryType must be default constructible. 35 // 36 // The third template parameter should be the type of a subclass of this class 37 // (think CRTP). This is to allow GetRegister() to instantiate and return 38 // an object of the appropriate type. 39 40 namespace fst { 41 42 template<class KeyType, class EntryType, class RegisterType> 43 class GenericRegister { 44 public: 45 typedef KeyType Key; 46 typedef EntryType Entry; 47 GetRegister()48 static RegisterType *GetRegister() { 49 FstOnceInit(®ister_init_, 50 &RegisterType::Init); 51 52 return register_; 53 } 54 SetEntry(const KeyType & key,const EntryType & entry)55 void SetEntry(const KeyType &key, 56 const EntryType &entry) { 57 MutexLock l(register_lock_); 58 59 register_table_.insert(make_pair(key, entry)); 60 } 61 GetEntry(const KeyType & key)62 EntryType GetEntry(const KeyType &key) const { 63 const EntryType *entry = LookupEntry(key); 64 if (entry) { 65 return *entry; 66 } else { 67 return LoadEntryFromSharedObject(key); 68 } 69 } 70 ~GenericRegister()71 virtual ~GenericRegister() { } 72 73 protected: 74 // Override this if you want to be able to load missing definitions from 75 // shared object files. LoadEntryFromSharedObject(const KeyType & key)76 virtual EntryType LoadEntryFromSharedObject(const KeyType &key) const { 77 #ifdef FST_NO_DYNAMIC_LINKING 78 return EntryType(); 79 #else 80 string so_filename = ConvertKeyToSoFilename(key); 81 82 void *handle = dlopen(so_filename.c_str(), RTLD_LAZY); 83 if (handle == 0) { 84 LOG(ERROR) << "GenericRegister::GetEntry : " << dlerror(); 85 return EntryType(); 86 } 87 88 // We assume that the DSO constructs a static object in its global 89 // scope that does the registration. Thus we need only load it, not 90 // call any methods. 91 const EntryType *entry = this->LookupEntry(key); 92 if (entry == 0) { 93 LOG(ERROR) << "GenericRegister::GetEntry : " 94 << "lookup failed in shared object: " << so_filename; 95 return EntryType(); 96 } 97 return *entry; 98 #endif // FST_NO_DYNAMIC_LINKING 99 } 100 101 // Override this to define how to turn a key into an SO filename. 102 virtual string ConvertKeyToSoFilename(const KeyType& key) const = 0; 103 LookupEntry(const KeyType & key)104 virtual const EntryType *LookupEntry( 105 const KeyType &key) const { 106 MutexLock l(register_lock_); 107 108 typename RegisterMapType::const_iterator it = register_table_.find(key); 109 110 if (it != register_table_.end()) { 111 return &it->second; 112 } else { 113 return 0; 114 } 115 } 116 117 private: 118 typedef map<KeyType, EntryType> RegisterMapType; 119 Init()120 static void Init() { 121 register_lock_ = new Mutex; 122 register_ = new RegisterType; 123 } 124 125 static FstOnceType register_init_; 126 static Mutex *register_lock_; 127 static RegisterType *register_; 128 129 RegisterMapType register_table_; 130 }; 131 132 template<class KeyType, class EntryType, class RegisterType> 133 FstOnceType GenericRegister<KeyType, EntryType, 134 RegisterType>::register_init_ = FST_ONCE_INIT; 135 136 template<class KeyType, class EntryType, class RegisterType> 137 Mutex *GenericRegister<KeyType, EntryType, RegisterType>::register_lock_ = 0; 138 139 template<class KeyType, class EntryType, class RegisterType> 140 RegisterType *GenericRegister<KeyType, EntryType, RegisterType>::register_ = 0; 141 142 // 143 // GENERIC REGISTRATION 144 // 145 146 // Generic register-er class capable of creating new register entries in the 147 // given RegisterType template parameter. This type must define types Key 148 // and Entry, and have appropriate static GetRegister() and instance 149 // SetEntry() functions. An easy way to accomplish this is to have RegisterType 150 // be the type of a subclass of GenericRegister. 151 template<class RegisterType> 152 class GenericRegisterer { 153 public: 154 typedef typename RegisterType::Key Key; 155 typedef typename RegisterType::Entry Entry; 156 GenericRegisterer(Key key,Entry entry)157 GenericRegisterer(Key key, Entry entry) { 158 RegisterType *reg = RegisterType::GetRegister(); 159 reg->SetEntry(key, entry); 160 } 161 }; 162 163 } // namespace fst 164 165 #endif // FST_LIB_GENERIC_REGISTER_H_ 166