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(&register_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