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>
100using 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
109namespace fst {
110namespace 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
119template<class OperationSignature>
120class GenericOperationRegister
121    : public GenericRegister<pair<string, string>,
122                             OperationSignature,
123                             GenericOperationRegister<OperationSignature> > {
124 public:
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
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:
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
156template<class ArgPack>
157struct 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
181template<class OpReg>
182void 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.
200bool 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