summaryrefslogtreecommitdiff
path: root/tools/thirdparty/OpenFst/fst/lib/register.h
blob: 172799dd69d90cc1f0d51e9073fdd871a59fb523 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
// fst-register.h
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
//
// \file
// Classes for registering derived Fsts for generic reading
//

#ifndef FST_LIB_REGISTER_H__
#define FST_LIB_REGISTER_H__

#include <map>

#include <dlfcn.h>
#include <pthread.h>

#include "fst/lib/compat.h"

extern "C" {
  typedef void (*FstInitFunc)();
}

namespace fst {

template <class A> class Fst;
struct FstReadOptions;

// This class holds the mapping from Fst name string to its reader
// and converter.
template <class A>
class FstRegister {
 public:
  typedef Fst<A> *(*Reader)(istream &strm, const FstReadOptions &opts);
  typedef Fst<A> *(*Converter)(const Fst<A> &fst);

  struct Entry {
    Reader reader;
    Converter converter;
    Entry() : reader(0), converter(0) {}
  };

  static FstRegister<A> *GetRegister() {
    pthread_once(&register_init_, &FstRegister<A>::Init);
    return register_;
  }

  Reader GetReader(const string &type) const {
    return GetEntry(type).reader;
  }

  Converter GetConverter(const string &type) const {
    return GetEntry(type).converter;
  }

  void SetEntry(const string &type, const Entry &entry) {
    MutexLock l(register_lock_);
    fst_table_.insert(make_pair(type, entry));
  }

 private:
  static void Init() {
    register_lock_ = new Mutex;
    register_ = new FstRegister<A>;
  }

  Entry LookupEntry(const string &type) const {
    MutexLock l(register_lock_);
    typename map<string, Entry>::const_iterator it = fst_table_.find(type);
    if (it != fst_table_.end())
      return it->second;
    else
      return Entry();
  }

  Entry GetEntry(const string &type) const {
#ifdef FST_DL
    Entry entry = LookupEntry(type);
    if (entry.reader)
      return entry;
    string so_file = type + "-fst.so";
    void *handle = dlopen(so_file.c_str(), RTLD_LAZY);
    if (handle == 0) {
      LOG(ERROR) << "FstRegister::GetEntry: " << dlerror();
      return entry;
    }
    string init_name = type + "_fst_init";
    FstInitFunc init_func =
        bit_cast<FstInitFunc>(dlsym(handle, init_name.c_str()));
    if (init_func == 0) {
      LOG(ERROR) << "FstRegister::GetEntry: " << dlerror();
      return entry;
    }
    (*init_func)();
#endif  // FST_DL
    return LookupEntry(type);
  }

  static pthread_once_t register_init_;   // ensures only called once
  static Mutex* register_lock_;           // multithreading lock
  static FstRegister<A> *register_;

  map<string, Entry> fst_table_;
};

template <class A>
pthread_once_t FstRegister<A>::register_init_ = PTHREAD_ONCE_INIT;

template <class A>
Mutex *FstRegister<A>::register_lock_ = 0;

template <class A>
FstRegister<A> *FstRegister<A>::register_ = 0;

// This class registers an Fst type for generic reading and creating.
// The Fst type must have a default constructor and a copy constructor
// from 'Fst<Arc>' for this to work.
template <class F>
class FstRegisterer {
 public:
  typedef typename F::Arc Arc;
  typedef typename FstRegister<Arc>::Entry Entry;
  typedef typename FstRegister<Arc>::Reader Reader;

  FstRegisterer() {
    F fst;
    F *(*reader)(istream &strm,
                 const FstReadOptions &opts) = &F::Read;
    Entry entry;
    entry.reader = reinterpret_cast<Reader>(reader);
    entry.converter = &FstRegisterer<F>::Convert;
    FstRegister<Arc> *registr = FstRegister<Arc>::GetRegister();
    registr->SetEntry(fst.Type(), entry);
  }

 private:
  static Fst<Arc> *Convert(const Fst<Arc> &fst) { return new F(fst); }
};


// Convenience macro to generate static FstRegisterer instance.
#define REGISTER_FST(F, A) \
static fst::FstRegisterer< F<A> > F ## _ ## A ## _registerer


// Converts an fst to type 'type'.
template <class A>
Fst<A> *Convert(const Fst<A> &fst, const string &ftype) {
  FstRegister<A> *registr = FstRegister<A>::GetRegister();
  const typename FstRegister<A>::Converter
      converter = registr->GetConverter(ftype);
  if (!converter) {
    string atype = A::Type();
    LOG(ERROR) << "Fst::Convert: Unknown FST type \"" << ftype
               << "\" (arc type = \"" << atype << "\")";
    return 0;
  }
  return converter(fst);
}

}  // namespace fst;

#endif  // FST_LIB_REGISTER_H__