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#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 38namespace fst { 39 40template<class KeyType, class EntryType, class RegisterType> 41class 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 126template<class KeyType, class EntryType, class RegisterType> 127FstOnceType GenericRegister<KeyType, EntryType, 128 RegisterType>::register_init_ = FST_ONCE_INIT; 129 130template<class KeyType, class EntryType, class RegisterType> 131Mutex *GenericRegister<KeyType, EntryType, RegisterType>::register_lock_ = 0; 132 133template<class KeyType, class EntryType, class RegisterType> 134RegisterType *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. 145template<class RegisterType> 146class 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