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