aboutsummaryrefslogtreecommitdiff
path: root/src/include/fst/script/script-impl.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/include/fst/script/script-impl.h')
-rw-r--r--src/include/fst/script/script-impl.h206
1 files changed, 206 insertions, 0 deletions
diff --git a/src/include/fst/script/script-impl.h b/src/include/fst/script/script-impl.h
new file mode 100644
index 0000000..452c7c5
--- /dev/null
+++ b/src/include/fst/script/script-impl.h
@@ -0,0 +1,206 @@
+
+// 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_