| |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // |
| // Copyright 2005-2010 Google, Inc. |
| // Author: jpr@google.com (Jake Ratkiewicz) |
| |
| #ifndef FST_LIB_GENERIC_REGISTER_H_ |
| #define FST_LIB_GENERIC_REGISTER_H_ |
| |
| #include <map> |
| #include <string> |
| |
| #include <fst/compat.h> |
| #include <fst/types.h> |
| |
| // Generic class representing a globally-stored correspondence between |
| // objects of KeyType and EntryType. |
| // KeyType must: |
| // a) be such as can be stored as a key in a map<> |
| // b) be concatenable with a const char* with the + operator |
| // (or you must subclass and redefine LoadEntryFromSharedObject) |
| // EntryType must be default constructible. |
| // |
| // The third template parameter should be the type of a subclass of this class |
| // (think CRTP). This is to allow GetRegister() to instantiate and return |
| // an object of the appropriate type. |
| |
| namespace fst { |
| |
| template<class KeyType, class EntryType, class RegisterType> |
| class GenericRegister { |
| public: |
| typedef KeyType Key; |
| typedef EntryType Entry; |
| |
| static RegisterType *GetRegister() { |
| FstOnceInit(®ister_init_, |
| &RegisterType::Init); |
| |
| return register_; |
| } |
| |
| void SetEntry(const KeyType &key, |
| const EntryType &entry) { |
| MutexLock l(register_lock_); |
| |
| register_table_.insert(make_pair(key, entry)); |
| } |
| |
| EntryType GetEntry(const KeyType &key) const { |
| const EntryType *entry = LookupEntry(key); |
| if (entry) { |
| return *entry; |
| } else { |
| return LoadEntryFromSharedObject(key); |
| } |
| } |
| |
| virtual ~GenericRegister() { } |
| |
| protected: |
| // Override this if you want to be able to load missing definitions from |
| // shared object files. |
| virtual EntryType LoadEntryFromSharedObject(const KeyType &key) const { |
| string so_filename = ConvertKeyToSoFilename(key); |
| |
| void *handle = dlopen(so_filename.c_str(), RTLD_LAZY); |
| if (handle == 0) { |
| LOG(ERROR) << "GenericRegister::GetEntry : " << dlerror(); |
| return EntryType(); |
| } |
| |
| // We assume that the DSO constructs a static object in its global |
| // scope that does the registration. Thus we need only load it, not |
| // call any methods. |
| const EntryType *entry = this->LookupEntry(key); |
| if (entry == 0) { |
| LOG(ERROR) << "GenericRegister::GetEntry : " |
| << "lookup failed in shared object: " << so_filename; |
| return EntryType(); |
| } |
| return *entry; |
| } |
| |
| // Override this to define how to turn a key into an SO filename. |
| virtual string ConvertKeyToSoFilename(const KeyType& key) const = 0; |
| |
| virtual const EntryType *LookupEntry( |
| const KeyType &key) const { |
| MutexLock l(register_lock_); |
| |
| typename RegisterMapType::const_iterator it = register_table_.find(key); |
| |
| if (it != register_table_.end()) { |
| return &it->second; |
| } else { |
| return 0; |
| } |
| } |
| |
| private: |
| typedef map<KeyType, EntryType> RegisterMapType; |
| |
| static void Init() { |
| register_lock_ = new Mutex; |
| register_ = new RegisterType; |
| } |
| |
| static FstOnceType register_init_; |
| static Mutex *register_lock_; |
| static RegisterType *register_; |
| |
| RegisterMapType register_table_; |
| }; |
| |
| template<class KeyType, class EntryType, class RegisterType> |
| FstOnceType GenericRegister<KeyType, EntryType, |
| RegisterType>::register_init_ = FST_ONCE_INIT; |
| |
| template<class KeyType, class EntryType, class RegisterType> |
| Mutex *GenericRegister<KeyType, EntryType, RegisterType>::register_lock_ = 0; |
| |
| template<class KeyType, class EntryType, class RegisterType> |
| RegisterType *GenericRegister<KeyType, EntryType, RegisterType>::register_ = 0; |
| |
| // |
| // GENERIC REGISTRATION |
| // |
| |
| // Generic register-er class capable of creating new register entries in the |
| // given RegisterType template parameter. This type must define types Key |
| // and Entry, and have appropriate static GetRegister() and instance |
| // SetEntry() functions. An easy way to accomplish this is to have RegisterType |
| // be the type of a subclass of GenericRegister. |
| template<class RegisterType> |
| class GenericRegisterer { |
| public: |
| typedef typename RegisterType::Key Key; |
| typedef typename RegisterType::Entry Entry; |
| |
| GenericRegisterer(Key key, Entry entry) { |
| RegisterType *reg = RegisterType::GetRegister(); |
| reg->SetEntry(key, entry); |
| } |
| }; |
| |
| } // namespace fst |
| |
| #endif // FST_LIB_GENERIC_REGISTER_H_ |