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