| |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // |
| // Copyright 2005-2010 Google, Inc. |
| // Author: jpr@google.com (Jake Ratkiewicz) |
| |
| // This file defines the registration mechanism for new operations. |
| // These operations are designed to enable scripts to work with FST classes |
| // at a high level. |
| |
| // If you have a new arc type and want these operations to work with FSTs |
| // with that arc type, see below for the registration steps |
| // you must take. |
| |
| // These methods are only recommended for use in high-level scripting |
| // applications. Most users should use the lower-level templated versions |
| // corresponding to these. |
| |
| // If you have a new arc type you'd like these operations to work with, |
| // use the REGISTER_FST_OPERATIONS macro defined in fstcsript.h |
| |
| // If you have a custom operation you'd like to define, you need four |
| // components. In the following, assume you want to create a new operation |
| // with the signature |
| // |
| // void Foo(const FstClass &ifst, MutableFstClass *ofst); |
| // |
| // You need: |
| // |
| // 1) A way to bundle the args that your new Foo operation will take, as |
| // a single struct. The template structs in arg-packs.h provide a handy |
| // way to do this. In Foo's case, that might look like this: |
| // |
| // typedef args::Package<const FstClass &, |
| // MutableFstClass *> FooArgs; |
| // |
| // Note: this package of args is going to be passed by non-const pointer. |
| // |
| // 2) A function template that is able to perform Foo, given the args and |
| // arc type. Yours might look like this: |
| // |
| // template<class Arc> |
| // void Foo(FooArgs *args) { |
| // // Pull out the actual, arc-templated FSTs |
| // const Fst<Arc> &ifst = args->arg1.GetFst<Arc>(); |
| // MutableFst<Arc> *ofst = args->arg2->GetMutableFst<Arc>(); |
| // |
| // // actually perform foo on ifst and ofst... |
| // } |
| // |
| // 3) a client-facing function for your operation. This would look like |
| // the following: |
| // |
| // void Foo(const FstClass &ifst, MutableFstClass *ofst) { |
| // // Check that the arc types of the FSTs match |
| // if (!ArcTypesMatch(ifst, *ofst, "Foo")) return; |
| // // package the args |
| // FooArgs args(ifst, ofst); |
| // // Finally, call the operation |
| // Apply<Operation<FooArgs> >("Foo", ifst->ArcType(), &args); |
| // } |
| // |
| // The Apply<> function template takes care of the link between 2 and 3, |
| // provided you also have: |
| // |
| // 4) A registration for your new operation, on the arc types you care about. |
| // This can be provided easily by the REGISTER_FST_OPERATION macro in |
| // operations.h: |
| // |
| // REGISTER_FST_OPERATION(Foo, StdArc, FooArgs); |
| // REGISTER_FST_OPERATION(Foo, MyArc, FooArgs); |
| // // .. etc |
| // |
| // |
| // That's it! Now when you call Foo(const FstClass &, MutableFstClass *), |
| // it dispatches (in #3) via the Apply<> function to the correct |
| // instantiation of the template function in #2. |
| // |
| |
| |
| #ifndef FST_SCRIPT_SCRIPT_IMPL_H_ |
| #define FST_SCRIPT_SCRIPT_IMPL_H_ |
| |
| // |
| // This file contains general-purpose templates which are used in the |
| // implementation of the operations. |
| // |
| |
| #include <utility> |
| using std::pair; using std::make_pair; |
| #include <string> |
| |
| #include <fst/script/fst-class.h> |
| #include <fst/generic-register.h> |
| #include <fst/script/arg-packs.h> |
| |
| #include <fst/types.h> |
| |
| namespace fst { |
| namespace script { |
| |
| // |
| // A generic register for operations with various kinds of signatures. |
| // Needed since every function signature requires a new registration class. |
| // The pair<string, string> is understood to be the operation name and arc |
| // type; subclasses (or typedefs) need only provide the operation signature. |
| // |
| |
| template<class OperationSignature> |
| class GenericOperationRegister |
| : public GenericRegister<pair<string, string>, |
| OperationSignature, |
| GenericOperationRegister<OperationSignature> > { |
| public: |
| void RegisterOperation(const string &operation_name, |
| const string &arc_type, |
| OperationSignature op) { |
| this->SetEntry(make_pair(operation_name, arc_type), op); |
| } |
| |
| OperationSignature GetOperation( |
| const string &operation_name, const string &arc_type) { |
| return this->GetEntry(make_pair(operation_name, arc_type)); |
| } |
| |
| protected: |
| virtual string ConvertKeyToSoFilename( |
| const pair<string, string>& key) const { |
| // Just use the old-style FST for now. |
| string legal_type(key.second); // the arc type |
| ConvertToLegalCSymbol(&legal_type); |
| |
| return legal_type + "-arc.so"; |
| } |
| }; |
| |
| |
| // Operation package - everything you need to register a new type of operation |
| |
| // The ArgPack should be the type that's passed into each wrapped function - |
| // for instance, it might be a struct containing all the args. |
| // It's always passed by pointer, so const members should be used to enforce |
| // constness where it's needed. Return values should be implemented as a |
| // member of ArgPack as well. |
| |
| template<class ArgPack> |
| struct Operation { |
| typedef ArgPack Args; |
| typedef void (*OpType)(ArgPack *args); |
| |
| // The register (hash) type |
| typedef GenericOperationRegister<OpType> Register; |
| |
| // The register-er type |
| typedef GenericRegisterer<Register> Registerer; |
| }; |
| |
| |
| // Macro for registering new types of operations. |
| |
| #define REGISTER_FST_OPERATION(Op, Arc, ArgPack) \ |
| static fst::script::Operation<ArgPack>::Registerer \ |
| arc_dispatched_operation_ ## ArgPack ## Op ## Arc ## _registerer( \ |
| make_pair(#Op, Arc::Type()), Op<Arc>) |
| |
| |
| // |
| // Template function to apply an operation by name |
| // |
| |
| template<class OpReg> |
| void Apply(const string &op_name, const string &arc_type, |
| typename OpReg::Args *args) { |
| typename OpReg::Register *reg = OpReg::Register::GetRegister(); |
| |
| typename OpReg::OpType op = reg->GetOperation(op_name, arc_type); |
| |
| if (op == 0) { |
| FSTERROR() << "No operation found for \"" << op_name << "\" on " |
| << "arc type " << arc_type; |
| return; |
| } |
| |
| op(args); |
| } |
| |
| |
| // Helper that logs to ERROR if the arc types of a and b don't match. |
| // The op_name is also printed. |
| bool ArcTypesMatch(const FstClass &a, const FstClass &b, |
| const string &op_name); |
| |
| } // namespace script |
| } // namespace fst |
| |
| #endif // FST_SCRIPT_SCRIPT_IMPL_H_ |