1 // fst-register.h
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 //
15 //
16 // \file
17 // Classes for registering derived Fsts for generic reading
18 //
19
20 #ifndef FST_LIB_REGISTER_H__
21 #define FST_LIB_REGISTER_H__
22
23 #include <map>
24
25 #include <dlfcn.h>
26 #include <pthread.h>
27
28 #include "fst/lib/compat.h"
29
30 extern "C" {
31 typedef void (*FstInitFunc)();
32 }
33
34 namespace fst {
35
36 template <class A> class Fst;
37 struct FstReadOptions;
38
39 // This class holds the mapping from Fst name string to its reader
40 // and converter.
41 template <class A>
42 class FstRegister {
43 public:
44 typedef Fst<A> *(*Reader)(istream &strm, const FstReadOptions &opts);
45 typedef Fst<A> *(*Converter)(const Fst<A> &fst);
46
47 struct Entry {
48 Reader reader;
49 Converter converter;
EntryEntry50 Entry() : reader(0), converter(0) {}
51 };
52
GetRegister()53 static FstRegister<A> *GetRegister() {
54 pthread_once(®ister_init_, &FstRegister<A>::Init);
55 return register_;
56 }
57
GetReader(const string & type)58 const Reader GetReader(const string &type) const {
59 return GetEntry(type).reader;
60 }
61
GetConverter(const string & type)62 const Converter GetConverter(const string &type) const {
63 return GetEntry(type).converter;
64 }
65
SetEntry(const string & type,const Entry & entry)66 void SetEntry(const string &type, const Entry &entry) {
67 MutexLock l(register_lock_);
68 fst_table_.insert(make_pair(type, entry));
69 }
70
71 private:
Init()72 static void Init() {
73 register_lock_ = new Mutex;
74 register_ = new FstRegister<A>;
75 }
76
LookupEntry(const string & type)77 Entry LookupEntry(const string &type) const {
78 MutexLock l(register_lock_);
79 typename map<string, Entry>::const_iterator it = fst_table_.find(type);
80 if (it != fst_table_.end())
81 return it->second;
82 else
83 return Entry();
84 }
85
GetEntry(const string & type)86 Entry GetEntry(const string &type) const {
87 #ifdef FST_DL
88 Entry entry = LookupEntry(type);
89 if (entry.reader)
90 return entry;
91 string so_file = type + "-fst.so";
92 void *handle = dlopen(so_file.c_str(), RTLD_LAZY);
93 if (handle == 0) {
94 LOG(ERROR) << "FstRegister::GetEntry: " << dlerror();
95 return entry;
96 }
97 string init_name = type + "_fst_init";
98 FstInitFunc init_func =
99 bit_cast<FstInitFunc>(dlsym(handle, init_name.c_str()));
100 if (init_func == 0) {
101 LOG(ERROR) << "FstRegister::GetEntry: " << dlerror();
102 return entry;
103 }
104 (*init_func)();
105 #endif // FST_DL
106 return LookupEntry(type);
107 }
108
109 static pthread_once_t register_init_; // ensures only called once
110 static Mutex* register_lock_; // multithreading lock
111 static FstRegister<A> *register_;
112
113 map<string, Entry> fst_table_;
114 };
115
116 template <class A>
117 pthread_once_t FstRegister<A>::register_init_ = PTHREAD_ONCE_INIT;
118
119 template <class A>
120 Mutex *FstRegister<A>::register_lock_ = 0;
121
122 template <class A>
123 FstRegister<A> *FstRegister<A>::register_ = 0;
124
125 // This class registers an Fst type for generic reading and creating.
126 // The Fst type must have a default constructor and a copy constructor
127 // from 'Fst<Arc>' for this to work.
128 template <class F>
129 class FstRegisterer {
130 public:
131 typedef typename F::Arc Arc;
132 typedef typename FstRegister<Arc>::Entry Entry;
133 typedef typename FstRegister<Arc>::Reader Reader;
134
FstRegisterer()135 FstRegisterer() {
136 F fst;
137 F *(*reader)(istream &strm,
138 const FstReadOptions &opts) = &F::Read;
139 Entry entry;
140 entry.reader = reinterpret_cast<Reader>(reader);
141 entry.converter = &FstRegisterer<F>::Convert;
142 FstRegister<Arc> *registr = FstRegister<Arc>::GetRegister();
143 registr->SetEntry(fst.Type(), entry);
144 }
145
146 private:
Convert(const Fst<Arc> & fst)147 static Fst<Arc> *Convert(const Fst<Arc> &fst) { return new F(fst); }
148 };
149
150
151 // Convenience macro to generate static FstRegisterer instance.
152 #define REGISTER_FST(F, A) \
153 static fst::FstRegisterer< F<A> > F ## _ ## A ## _registerer
154
155
156 // Converts an fst to type 'type'.
157 template <class A>
Convert(const Fst<A> & fst,const string & ftype)158 Fst<A> *Convert(const Fst<A> &fst, const string &ftype) {
159 FstRegister<A> *registr = FstRegister<A>::GetRegister();
160 const typename FstRegister<A>::Converter
161 converter = registr->GetConverter(ftype);
162 if (!converter) {
163 string atype = A::Type();
164 LOG(ERROR) << "Fst::Convert: Unknown FST type \"" << ftype
165 << "\" (arc type = \"" << atype << "\")";
166 return 0;
167 }
168 return converter(fst);
169 }
170
171 } // namespace fst;
172
173 #endif // FST_LIB_REGISTER_H__
174