1
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 // http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13 //
14 // Copyright 2005-2010 Google, Inc.
15 // Author: jpr@google.com (Jake Ratkiewicz)
16
17 // This file defines the registration mechanism for new operations.
18 // These operations are designed to enable scripts to work with FST classes
19 // at a high level.
20
21 // If you have a new arc type and want these operations to work with FSTs
22 // with that arc type, see below for the registration steps
23 // you must take.
24
25 // These methods are only recommended for use in high-level scripting
26 // applications. Most users should use the lower-level templated versions
27 // corresponding to these.
28
29 // If you have a new arc type you'd like these operations to work with,
30 // use the REGISTER_FST_OPERATIONS macro defined in fstcsript.h
31
32 // If you have a custom operation you'd like to define, you need four
33 // components. In the following, assume you want to create a new operation
34 // with the signature
35 //
36 // void Foo(const FstClass &ifst, MutableFstClass *ofst);
37 //
38 // You need:
39 //
40 // 1) A way to bundle the args that your new Foo operation will take, as
41 // a single struct. The template structs in arg-packs.h provide a handy
42 // way to do this. In Foo's case, that might look like this:
43 //
44 // typedef args::Package<const FstClass &,
45 // MutableFstClass *> FooArgs;
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 // // Pull out the actual, arc-templated FSTs
55 // const Fst<Arc> &ifst = args->arg1.GetFst<Arc>();
56 // MutableFst<Arc> *ofst = args->arg2->GetMutableFst<Arc>();
57 //
58 // // actually perform foo on ifst and ofst...
59 // }
60 //
61 // 3) a client-facing function for your operation. This would look like
62 // the following:
63 //
64 // void Foo(const FstClass &ifst, MutableFstClass *ofst) {
65 // // Check that the arc types of the FSTs match
66 // if (!ArcTypesMatch(ifst, *ofst, "Foo")) return;
67 // // package the args
68 // FooArgs args(ifst, ofst);
69 // // Finally, call the operation
70 // Apply<Operation<FooArgs> >("Foo", ifst->ArcType(), &args);
71 // }
72 //
73 // The Apply<> function template takes care of the link between 2 and 3,
74 // provided you also have:
75 //
76 // 4) A registration for your new operation, on the arc types you care about.
77 // This can be provided easily by the REGISTER_FST_OPERATION macro in
78 // operations.h:
79 //
80 // REGISTER_FST_OPERATION(Foo, StdArc, FooArgs);
81 // REGISTER_FST_OPERATION(Foo, MyArc, FooArgs);
82 // // .. etc
83 //
84 //
85 // That's it! Now when you call Foo(const FstClass &, MutableFstClass *),
86 // it dispatches (in #3) via the Apply<> function to the correct
87 // instantiation of the template function in #2.
88 //
89
90
91 #ifndef FST_SCRIPT_SCRIPT_IMPL_H_
92 #define FST_SCRIPT_SCRIPT_IMPL_H_
93
94 //
95 // This file contains general-purpose templates which are used in the
96 // implementation of the operations.
97 //
98
99 #include <utility>
100 using std::pair; using std::make_pair;
101 #include <string>
102
103 #include <fst/script/fst-class.h>
104 #include <fst/generic-register.h>
105 #include <fst/script/arg-packs.h>
106
107 #include <fst/types.h>
108
109 namespace fst {
110 namespace script {
111
112 //
113 // A generic register for operations with various kinds of signatures.
114 // Needed since every function signature requires a new registration class.
115 // The pair<string, string> is understood to be the operation name and arc
116 // type; subclasses (or typedefs) need only provide the operation signature.
117 //
118
119 template<class OperationSignature>
120 class GenericOperationRegister
121 : public GenericRegister<pair<string, string>,
122 OperationSignature,
123 GenericOperationRegister<OperationSignature> > {
124 public:
RegisterOperation(const string & operation_name,const string & arc_type,OperationSignature op)125 void RegisterOperation(const string &operation_name,
126 const string &arc_type,
127 OperationSignature op) {
128 this->SetEntry(make_pair(operation_name, arc_type), op);
129 }
130
GetOperation(const string & operation_name,const string & arc_type)131 OperationSignature GetOperation(
132 const string &operation_name, const string &arc_type) {
133 return this->GetEntry(make_pair(operation_name, arc_type));
134 }
135
136 protected:
ConvertKeyToSoFilename(const pair<string,string> & key)137 virtual string ConvertKeyToSoFilename(
138 const pair<string, string>& key) const {
139 // Just use the old-style FST for now.
140 string legal_type(key.second); // the arc type
141 ConvertToLegalCSymbol(&legal_type);
142
143 return legal_type + "-arc.so";
144 }
145 };
146
147
148 // Operation package - everything you need to register a new type of operation
149
150 // The ArgPack should be the type that's passed into each wrapped function -
151 // for instance, it might be a struct containing all the args.
152 // It's always passed by pointer, so const members should be used to enforce
153 // constness where it's needed. Return values should be implemented as a
154 // member of ArgPack as well.
155
156 template<class ArgPack>
157 struct Operation {
158 typedef ArgPack Args;
159 typedef void (*OpType)(ArgPack *args);
160
161 // The register (hash) type
162 typedef GenericOperationRegister<OpType> Register;
163
164 // The register-er type
165 typedef GenericRegisterer<Register> Registerer;
166 };
167
168
169 // Macro for registering new types of operations.
170
171 #define REGISTER_FST_OPERATION(Op, Arc, ArgPack) \
172 static fst::script::Operation<ArgPack>::Registerer \
173 arc_dispatched_operation_ ## ArgPack ## Op ## Arc ## _registerer( \
174 make_pair(#Op, Arc::Type()), Op<Arc>)
175
176
177 //
178 // Template function to apply an operation by name
179 //
180
181 template<class OpReg>
Apply(const string & op_name,const string & arc_type,typename OpReg::Args * args)182 void Apply(const string &op_name, const string &arc_type,
183 typename OpReg::Args *args) {
184 typename OpReg::Register *reg = OpReg::Register::GetRegister();
185
186 typename OpReg::OpType op = reg->GetOperation(op_name, arc_type);
187
188 if (op == 0) {
189 FSTERROR() << "No operation found for \"" << op_name << "\" on "
190 << "arc type " << arc_type;
191 return;
192 }
193
194 op(args);
195 }
196
197
198 // Helper that logs to ERROR if the arc types of a and b don't match.
199 // The op_name is also printed.
200 bool ArcTypesMatch(const FstClass &a, const FstClass &b,
201 const string &op_name);
202
203 } // namespace script
204 } // namespace fst
205
206 #endif // FST_SCRIPT_SCRIPT_IMPL_H_
207