• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
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 
GetRegister()46   static RegisterType *GetRegister() {
47     FstOnceInit(&register_init_,
48                    &RegisterType::Init);
49 
50     return register_;
51   }
52 
SetEntry(const KeyType & key,const EntryType & entry)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 
GetEntry(const KeyType & key)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 
~GenericRegister()69   virtual ~GenericRegister() { }
70 
71  protected:
72   // Override this if you want to be able to load missing definitions from
73   // shared object files.
LoadEntryFromSharedObject(const KeyType & key)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 
LookupEntry(const KeyType & key)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 
Init()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 
GenericRegisterer(Key key,Entry entry)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