• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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(&register_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