FST  openfst-1.8.3
OpenFst Library
script-impl.h
Go to the documentation of this file.
1 // Copyright 2005-2024 Google LLC
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 // See www.openfst.org for extensive documentation on this weighted
16 // finite-state transducer library.
17 //
18 // This file defines the registration mechanism for new operations.
19 // These operations are designed to enable scripts to work with FST classes
20 // at a high level.
21 //
22 // If you have a new arc type and want these operations to work with FSTs
23 // with that arc type, see below for the registration steps
24 // you must take.
25 //
26 // These methods are only recommended for use in high-level scripting
27 // applications. Most users should use the lower-level templated versions
28 // corresponding to these.
29 //
30 // If you have a new arc type you'd like these operations to work with,
31 // use the REGISTER_FST_OPERATIONS macro defined in fstscript.h.
32 //
33 // If you have a custom operation you'd like to define, you need four
34 // components. In the following, assume you want to create a new operation
35 // with the signature
36 //
37 // void Foo(const FstClass &ifst, MutableFstClass *ofst);
38 //
39 // You need:
40 //
41 // 1) A way to bundle the args that your new Foo operation will take, as
42 // a single struct. The template structs in arg-packs.h provide a handy
43 // way to do this. In Foo's case, that might look like this:
44 //
45 // using FooArgs = std::pair<const FstClass &, MutableFstClass *>;
46 //
47 // Note: this package of args is going to be passed by non-const pointer.
48 //
49 // 2) A function template that is able to perform Foo, given the args and
50 // arc type. Yours might look like this:
51 //
52 // template<class Arc>
53 // void Foo(FooArgs *args) {
54 // // Pulls out the actual, arc-templated FSTs.
55 // const Fst<Arc> &ifst = std::get<0>(*args).GetFst<Arc>();
56 // MutableFst<Arc> *ofst = std::get<1>(*args)->GetMutableFst<Arc>();
57 // // Actually perform Foo on ifst and ofst.
58 // }
59 //
60 // 3) a client-facing function for your operation. This would look like
61 // the following:
62 //
63 // void Foo(const FstClass &ifst, MutableFstClass *ofst) {
64 // // Check that the arc types of the FSTs match
65 // if (!ArcTypesMatch(ifst, *ofst, "Foo")) return;
66 // // package the args
67 // FooArgs args(ifst, ofst);
68 // // Finally, call the operation
69 // Apply<Operation<FooArgs>>("Foo", ifst->ArcType(), &args);
70 // }
71 //
72 // The Apply<> function template takes care of the link between 2 and 3,
73 // provided you also have:
74 //
75 // 4) A registration for your new operation, on the arc types you care about.
76 // This can be provided easily by the REGISTER_FST_OPERATION macro:
77 //
78 // REGISTER_FST_OPERATION(Foo, StdArc, FooArgs);
79 // REGISTER_FST_OPERATION(Foo, MyArc, FooArgs);
80 // // .. etc
81 //
82 // You can also use REGISTER_FST_OPERATION_3ARCS macro to register an
83 // operation for StdArc, LogArc, and Log64Arc:
84 //
85 // REGISTER_FST_OPERATION_3ARCS(Foo, FooArcs);
86 //
87 // That's it! Now when you call Foo(const FstClass &, MutableFstClass *),
88 // it dispatches (in #3) via the Apply<> function to the correct
89 // instantiation of the template function in #2.
90 //
91 
92 #ifndef FST_SCRIPT_SCRIPT_IMPL_H_
93 #define FST_SCRIPT_SCRIPT_IMPL_H_
94 
95 // This file contains general-purpose templates which are used in the
96 // implementation of the operations.
97 
98 #include <cstdint>
99 #include <memory>
100 #include <string>
101 #include <utility>
102 #include <vector>
103 
104 #include <fst/log.h>
105 #include <fst/arc.h>
106 #include <fst/generic-register.h>
107 #include <fst/util.h>
108 #include <fst/script/fst-class.h>
109 #include <fst/script/weight-class.h>
110 #include <string_view>
111 
112 namespace fst {
113 namespace script {
114 
115 enum class RandArcSelection : uint8_t { UNIFORM, LOG_PROB, FAST_LOG_PROB };
116 
117 // A generic register for operations with various kinds of signatures.
118 // Needed since every function signature requires a new registration class.
119 // The std::pair<std::string, std::string> is understood to be the operation
120 // name and arc type; subclasses (or typedefs) need only provide the operation
121 // signature.
122 template <class OperationSignature>
124  : public GenericRegister<std::pair<std::string_view, std::string_view>,
125  OperationSignature,
126  GenericOperationRegister<OperationSignature>> {
127  public:
128  OperationSignature GetOperation(std::string_view operation_name,
129  std::string_view arc_type) {
130  return this->GetEntry(std::make_pair(operation_name, arc_type));
131  }
132 
133  protected:
135  const std::pair<std::string_view, std::string_view> &key) const final {
136  // Uses the old-style FST for now.
137  std::string legal_type(key.second); // The arc type.
138  ConvertToLegalCSymbol(&legal_type);
139  legal_type.append("-arc.so");
140  return legal_type;
141  }
142 };
143 
144 // Operation package: everything you need to register a new type of operation.
145 // The ArgPack should be the type that's passed into each wrapped function;
146 // for instance, it might be a struct containing all the args. It's always
147 // passed by pointer, so const members should be used to enforce constness where
148 // it's needed. Return values should be implemented as a member of ArgPack as
149 // well.
150 
151 template <class Args>
152 struct Operation {
153  using ArgPack = Args;
154 
155  using OpType = void (*)(ArgPack *args);
156 
157  // The register (hash) type.
159 
160  // The register-er type.
162 };
163 
164 // Macro for registering new types of operations.
165 #define REGISTER_FST_OPERATION(Op, Arc, ArgPack) \
166  static fst::script::Operation<ArgPack>::Registerer \
167  arc_dispatched_operation_##ArgPack##Op##Arc##_registerer \
168  ({#Op, Arc::Type()}, Op<Arc>)
169 
170 // A macro that calls REGISTER_FST_OPERATION for widely-used arc types.
171 #define REGISTER_FST_OPERATION_3ARCS(Op, ArgPack) \
172  REGISTER_FST_OPERATION(Op, StdArc, ArgPack); \
173  REGISTER_FST_OPERATION(Op, LogArc, ArgPack); \
174  REGISTER_FST_OPERATION(Op, Log64Arc, ArgPack)
175 
176 // Template function to apply an operation by name.
177 template <class OpReg>
178 void Apply(const std::string &op_name, const std::string &arc_type,
179  typename OpReg::ArgPack *args) {
180  const auto op =
181  OpReg::Register::GetRegister()->GetOperation(op_name, arc_type);
182  if (!op) {
183  FSTERROR() << op_name << ": No operation found on arc type " << arc_type;
184  return;
185  }
186  op(args);
187 }
188 
189 namespace internal {
190 
191 // Helper that logs to ERROR if the arc types of m and n don't match,
192 // assuming that both m and n implement .ArcType(). The op_name argument is
193 // used to construct the error message.
194 template <class M, class N>
195 bool ArcTypesMatch(const M &m, const N &n, const std::string &op_name) {
196  if (m.ArcType() != n.ArcType()) {
197  FSTERROR() << op_name << ": Arguments with non-matching arc types "
198  << m.ArcType() << " and " << n.ArcType();
199  return false;
200  }
201  return true;
202 }
203 
204 // From untyped to typed weights.
205 template <class Weight>
206 void CopyWeights(const std::vector<WeightClass> &weights,
207  std::vector<Weight> *typed_weights) {
208  typed_weights->clear();
209  typed_weights->reserve(weights.size());
210  for (const auto &weight : weights) {
211  typed_weights->emplace_back(*weight.GetWeight<Weight>());
212  }
213 }
214 
215 // From typed to untyped weights.
216 template <class Weight>
217 void CopyWeights(const std::vector<Weight> &typed_weights,
218  std::vector<WeightClass> *weights) {
219  weights->clear();
220  weights->reserve(typed_weights.size());
221  for (const auto &typed_weight : typed_weights) {
222  weights->emplace_back(typed_weight);
223  }
224 }
225 
226 } // namespace internal
227 
228 // Used for Replace operations.
229 inline std::vector<std::pair<int64_t, const FstClass *>> BorrowPairs(
230  const std::vector<std::pair<int64_t, std::unique_ptr<const FstClass>>>
231  &pairs) {
232  std::vector<std::pair<int64_t, const FstClass *>> borrowed_pairs;
233  borrowed_pairs.reserve(pairs.size());
234  for (const auto &pair : pairs) {
235  borrowed_pairs.emplace_back(pair.first, pair.second.get());
236  }
237  return borrowed_pairs;
238 }
239 
240 } // namespace script
241 } // namespace fst
242 
243 #endif // FST_SCRIPT_SCRIPT_IMPL_H_
void CopyWeights(const std::vector< Weight > &typed_weights, std::vector< WeightClass > *weights)
Definition: script-impl.h:217
void ConvertToLegalCSymbol(std::string *s)
Definition: util.cc:75
std::string ConvertKeyToSoFilename(const std::pair< std::string_view, std::string_view > &key) const final
Definition: script-impl.h:134
void Apply(const std::string &op_name, const std::string &arc_type, typename OpReg::ArgPack *args)
Definition: script-impl.h:178
bool ArcTypesMatch(const M &m, const N &n, const std::string &op_name)
Definition: script-impl.h:195
#define FSTERROR()
Definition: util.h:56
void(*)(ArgPack *args) OpType
Definition: script-impl.h:155
std::vector< std::pair< int64_t, const FstClass * > > BorrowPairs(const std::vector< std::pair< int64_t, std::unique_ptr< const FstClass >>> &pairs)
Definition: script-impl.h:229
OperationSignature GetOperation(std::string_view operation_name, std::string_view arc_type)
Definition: script-impl.h:128