Home | History | Annotate | Download | only in script
      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