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
30extern "C" {
31  typedef void (*FstInitFunc)();
32}
33
34namespace fst {
35
36template <class A> class Fst;
37struct FstReadOptions;
38
39// This class holds the mapping from Fst name string to its reader
40// and converter.
41template <class A>
42class 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;
50    Entry() : reader(0), converter(0) {}
51  };
52
53  static FstRegister<A> *GetRegister() {
54    pthread_once(&register_init_, &FstRegister<A>::Init);
55    return register_;
56  }
57
58  const Reader GetReader(const string &type) const {
59    return GetEntry(type).reader;
60  }
61
62  const Converter GetConverter(const string &type) const {
63    return GetEntry(type).converter;
64  }
65
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:
72  static void Init() {
73    register_lock_ = new Mutex;
74    register_ = new FstRegister<A>;
75  }
76
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
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
116template <class A>
117pthread_once_t FstRegister<A>::register_init_ = PTHREAD_ONCE_INIT;
118
119template <class A>
120Mutex *FstRegister<A>::register_lock_ = 0;
121
122template <class A>
123FstRegister<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.
128template <class F>
129class FstRegisterer {
130 public:
131  typedef typename F::Arc Arc;
132  typedef typename FstRegister<Arc>::Entry Entry;
133  typedef typename FstRegister<Arc>::Reader Reader;
134
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:
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) \
153static fst::FstRegisterer< F<A> > F ## _ ## A ## _registerer
154
155
156// Converts an fst to type 'type'.
157template <class A>
158Fst<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