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 (at) 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: 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 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> 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