summaryrefslogtreecommitdiff
path: root/kaldi_io/src/tools/openfst/include/fst/edit-fst.h
diff options
context:
space:
mode:
Diffstat (limited to 'kaldi_io/src/tools/openfst/include/fst/edit-fst.h')
-rw-r--r--kaldi_io/src/tools/openfst/include/fst/edit-fst.h779
1 files changed, 779 insertions, 0 deletions
diff --git a/kaldi_io/src/tools/openfst/include/fst/edit-fst.h b/kaldi_io/src/tools/openfst/include/fst/edit-fst.h
new file mode 100644
index 0000000..bd33b9d
--- /dev/null
+++ b/kaldi_io/src/tools/openfst/include/fst/edit-fst.h
@@ -0,0 +1,779 @@
+
+// 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: dbikel@google.com (Dan Bikel)
+//
+// An \ref Fst implementation that allows non-destructive edit operations on an
+// existing fst.
+
+#ifndef FST_LIB_EDIT_FST_H_
+#define FST_LIB_EDIT_FST_H_
+
+#include <vector>
+using std::vector;
+
+#include <fst/cache.h>
+
+#include <tr1/unordered_map>
+using std::tr1::unordered_map;
+using std::tr1::unordered_multimap;
+
+namespace fst {
+
+// The EditFst class enables non-destructive edit operations on a wrapped
+// ExpandedFst. The implementation uses copy-on-write semantics at the node
+// level: if a user has an underlying fst on which he or she wants to perform a
+// relatively small number of edits (read: mutations), then this implementation
+// will copy the edited node to an internal MutableFst and perform any edits in
+// situ on that copied node. This class supports all the methods of MutableFst
+// except for DeleteStates(const vector<StateId> &); thus, new nodes may also be
+// added, and one may add transitions from existing nodes of the wrapped fst to
+// new nodes.
+//
+// N.B.: The documentation for Fst::Copy(true) says that its behavior is
+// undefined if invoked on an fst that has already been accessed. This class
+// requires that the Fst implementation it wraps provides consistent, reliable
+// behavior when its Copy(true) method is invoked, where consistent means
+// the graph structure, graph properties and state numbering and do not change.
+// VectorFst and CompactFst, for example, are both well-behaved in this regard.
+
+// The EditFstData class is a container for all mutable data for EditFstImpl;
+// also, this class provides most of the actual implementation of what EditFst
+// does (that is, most of EditFstImpl's methods delegate to methods in this, the
+// EditFstData class). Instances of this class are reference-counted and can be
+// shared between otherwise independent EditFstImpl instances. This scheme
+// allows EditFstImpl to implement the thread-safe, copy-on-write semantics
+// required by Fst::Copy(true).
+//
+// template parameters:
+// A the type of arc to use
+// WrappedFstT the type of fst wrapped by the EditFst instance that
+// this EditFstData instance is backing
+// MutableFstT the type of mutable fst to use internally for edited states;
+// crucially, MutableFstT::Copy(false) *must* yield an fst that is
+// thread-safe for reading (VectorFst, for example, has this property)
+template <typename A,
+ typename WrappedFstT = ExpandedFst<A>,
+ typename MutableFstT = VectorFst<A> >
+class EditFstData {
+ public:
+ typedef A Arc;
+ typedef typename A::Weight Weight;
+ typedef typename A::StateId StateId;
+ typedef typename unordered_map<StateId, StateId>::const_iterator
+ IdMapIterator;
+ typedef typename unordered_map<StateId, Weight>::const_iterator
+ FinalWeightIterator;
+
+
+ EditFstData() : num_new_states_(0) {
+ SetEmptyAndDeleteKeysForInternalMaps();
+ }
+
+ EditFstData(const EditFstData &other) :
+ edits_(other.edits_),
+ external_to_internal_ids_(other.external_to_internal_ids_),
+ edited_final_weights_(other.edited_final_weights_),
+ num_new_states_(other.num_new_states_) {
+ }
+
+ ~EditFstData() {
+ }
+
+ static EditFstData<A, WrappedFstT, MutableFstT> *Read(istream &strm,
+ const FstReadOptions &opts);
+
+ bool Write(ostream &strm, const FstWriteOptions &opts) const {
+ // Serialize all private data members of this class.
+ FstWriteOptions edits_opts(opts);
+ edits_opts.write_header = true; // Force writing contained header.
+ edits_.Write(strm, edits_opts);
+ WriteType(strm, external_to_internal_ids_);
+ WriteType(strm, edited_final_weights_);
+ WriteType(strm, num_new_states_);
+ if (!strm) {
+ LOG(ERROR) << "EditFstData::Write: write failed: " << opts.source;
+ return false;
+ }
+ return true;
+ }
+
+ int RefCount() const { return ref_count_.count(); }
+ int IncrRefCount() { return ref_count_.Incr(); }
+ int DecrRefCount() { return ref_count_.Decr(); }
+
+ StateId NumNewStates() const {
+ return num_new_states_;
+ }
+
+ // accessor methods for the fst holding edited states
+ StateId EditedStart() const {
+ return edits_.Start();
+ }
+
+ Weight Final(StateId s, const WrappedFstT *wrapped) const {
+ FinalWeightIterator final_weight_it = GetFinalWeightIterator(s);
+ if (final_weight_it == NotInFinalWeightMap()) {
+ IdMapIterator it = GetEditedIdMapIterator(s);
+ return it == NotInEditedMap() ?
+ wrapped->Final(s) : edits_.Final(it->second);
+ }
+ else {
+ return final_weight_it->second;
+ }
+ }
+
+ size_t NumArcs(StateId s, const WrappedFstT *wrapped) const {
+ IdMapIterator it = GetEditedIdMapIterator(s);
+ return it == NotInEditedMap() ?
+ wrapped->NumArcs(s) : edits_.NumArcs(it->second);
+ }
+
+ size_t NumInputEpsilons(StateId s, const WrappedFstT *wrapped) const {
+ IdMapIterator it = GetEditedIdMapIterator(s);
+ return it == NotInEditedMap() ?
+ wrapped->NumInputEpsilons(s) :
+ edits_.NumInputEpsilons(it->second);
+ }
+
+ size_t NumOutputEpsilons(StateId s, const WrappedFstT *wrapped) const {
+ IdMapIterator it = GetEditedIdMapIterator(s);
+ return it == NotInEditedMap() ?
+ wrapped->NumOutputEpsilons(s) :
+ edits_.NumOutputEpsilons(it->second);
+ }
+
+ void SetEditedProperties(uint64 props, uint64 mask) {
+ edits_.SetProperties(props, mask);
+ }
+
+ // non-const MutableFst operations
+
+ // Sets the start state for this fst.
+ void SetStart(StateId s) {
+ edits_.SetStart(s);
+ }
+
+ // Sets the final state for this fst.
+ Weight SetFinal(StateId s, Weight w, const WrappedFstT *wrapped) {
+ Weight old_weight = Final(s, wrapped);
+ IdMapIterator it = GetEditedIdMapIterator(s);
+ // if we haven't already edited state s, don't add it to edited_ (which can
+ // be expensive if s has many transitions); just use the
+ // edited_final_weights_ map
+ if (it == NotInEditedMap()) {
+ edited_final_weights_[s] = w;
+ }
+ else {
+ edits_.SetFinal(GetEditableInternalId(s, wrapped), w);
+ }
+ return old_weight;
+ }
+
+ // Adds a new state to this fst, initially with no arcs.
+ StateId AddState(StateId curr_num_states) {
+ StateId internal_state_id = edits_.AddState();
+ StateId external_state_id = curr_num_states;
+ external_to_internal_ids_[external_state_id] = internal_state_id;
+ num_new_states_++;
+ return external_state_id;
+ }
+
+ // Adds the specified arc to the specified state of this fst.
+ const A *AddArc(StateId s, const Arc &arc, const WrappedFstT *wrapped) {
+ StateId internal_id = GetEditableInternalId(s, wrapped);
+
+ size_t num_arcs = edits_.NumArcs(internal_id);
+ ArcIterator<MutableFstT> arc_it(edits_, internal_id);
+ const A *prev_arc = NULL;
+ if (num_arcs > 0) {
+ // grab the final arc associated with this state in edits_
+ arc_it.Seek(num_arcs - 1);
+ prev_arc = &(arc_it.Value());
+ }
+ edits_.AddArc(internal_id, arc);
+ return prev_arc;
+ }
+
+ void DeleteStates() {
+ edits_.DeleteStates();
+ num_new_states_ = 0;
+ external_to_internal_ids_.clear();
+ edited_final_weights_.clear();
+ }
+
+ // Removes all but the first n outgoing arcs of the specified state.
+ void DeleteArcs(StateId s, size_t n, const WrappedFstT *wrapped) {
+ edits_.DeleteArcs(GetEditableInternalId(s, wrapped), n);
+ }
+
+ // Removes all outgoing arcs from the specified state.
+ void DeleteArcs(StateId s, const WrappedFstT *wrapped) {
+ edits_.DeleteArcs(GetEditableInternalId(s, wrapped));
+ }
+
+ // end methods for non-const MutableFst operations
+
+ // Provides information for the generic arc iterator.
+ void InitArcIterator(StateId s, ArcIteratorData<Arc> *data,
+ const WrappedFstT *wrapped) const {
+ IdMapIterator id_map_it = GetEditedIdMapIterator(s);
+ if (id_map_it == NotInEditedMap()) {
+ VLOG(3) << "EditFstData::InitArcIterator: iterating on state "
+ << s << " of original fst";
+ wrapped->InitArcIterator(s, data);
+ } else {
+ VLOG(2) << "EditFstData::InitArcIterator: iterating on edited state "
+ << s << " (internal state id: " << id_map_it->second << ")";
+ edits_.InitArcIterator(id_map_it->second, data);
+ }
+ }
+
+ // Provides information for the generic mutable arc iterator.
+ void InitMutableArcIterator(StateId s, MutableArcIteratorData<A> *data,
+ const WrappedFstT *wrapped) {
+ data->base =
+ new MutableArcIterator<MutableFstT>(&edits_,
+ GetEditableInternalId(s, wrapped));
+ }
+
+ // Prints out the map from external to internal state id's (for debugging
+ // purposes).
+ void PrintMap() {
+ for (IdMapIterator map_it = external_to_internal_ids_.begin();
+ map_it != NotInEditedMap(); ++map_it) {
+ LOG(INFO) << "(external,internal)=("
+ << map_it->first << "," << map_it->second << ")";
+ }
+ }
+
+
+ private:
+ void SetEmptyAndDeleteKeysForInternalMaps() {
+ }
+
+ // Returns the iterator of the map from external to internal state id's
+ // of edits_ for the specified external state id.
+ IdMapIterator GetEditedIdMapIterator(StateId s) const {
+ return external_to_internal_ids_.find(s);
+ }
+ IdMapIterator NotInEditedMap() const {
+ return external_to_internal_ids_.end();
+ }
+
+ FinalWeightIterator GetFinalWeightIterator(StateId s) const {
+ return edited_final_weights_.find(s);
+ }
+ FinalWeightIterator NotInFinalWeightMap() const {
+ return edited_final_weights_.end();
+ }
+
+ // Returns the internal state id of the specified external id if the state has
+ // already been made editable, or else copies the state from wrapped_
+ // to edits_ and returns the state id of the newly editable state in edits_.
+ //
+ // \return makes the specified state editable if it isn't already and returns
+ // its state id in edits_
+ StateId GetEditableInternalId(StateId s, const WrappedFstT *wrapped) {
+ IdMapIterator id_map_it = GetEditedIdMapIterator(s);
+ if (id_map_it == NotInEditedMap()) {
+ StateId new_internal_id = edits_.AddState();
+ VLOG(2) << "EditFstData::GetEditableInternalId: editing state " << s
+ << " of original fst; new internal state id:" << new_internal_id;
+ external_to_internal_ids_[s] = new_internal_id;
+ for (ArcIterator< Fst<A> > arc_iterator(*wrapped, s);
+ !arc_iterator.Done();
+ arc_iterator.Next()) {
+ edits_.AddArc(new_internal_id, arc_iterator.Value());
+ }
+ // copy the final weight
+ FinalWeightIterator final_weight_it = GetFinalWeightIterator(s);
+ if (final_weight_it == NotInFinalWeightMap()) {
+ edits_.SetFinal(new_internal_id, wrapped->Final(s));
+ } else {
+ edits_.SetFinal(new_internal_id, final_weight_it->second);
+ edited_final_weights_.erase(s);
+ }
+ return new_internal_id;
+ } else {
+ return id_map_it->second;
+ }
+ }
+
+ // A mutable fst (by default, a VectorFst) to contain new states, and/or
+ // copies of states from a wrapped ExpandedFst that have been modified in
+ // some way.
+ MutableFstT edits_;
+ // A mapping from external state id's to the internal id's of states that
+ // appear in edits_.
+ unordered_map<StateId, StateId> external_to_internal_ids_;
+ // A mapping from external state id's to final state weights assigned to
+ // those states. The states in this map are *only* those whose final weight
+ // has been modified; if any other part of the state has been modified,
+ // the entire state is copied to edits_, and all modifications reside there.
+ unordered_map<StateId, Weight> edited_final_weights_;
+ // The number of new states added to this mutable fst impl, which is <= the
+ // number of states in edits_ (since edits_ contains both edited *and* new
+ // states).
+ StateId num_new_states_;
+ RefCounter ref_count_;
+};
+
+// EditFstData method implementations: just the Read method.
+template <typename A, typename WrappedFstT, typename MutableFstT>
+EditFstData<A, WrappedFstT, MutableFstT> *
+EditFstData<A, WrappedFstT, MutableFstT>::Read(istream &strm,
+ const FstReadOptions &opts) {
+ EditFstData<A, WrappedFstT, MutableFstT> *data =
+ new EditFstData<A, WrappedFstT, MutableFstT>();
+ // next read in MutabelFstT machine that stores edits
+ FstReadOptions edits_opts(opts);
+ edits_opts.header = 0; // Contained header was written out, so read it in.
+
+ // Because our internal representation of edited states is a solid object
+ // of type MutableFstT (defaults to VectorFst<A>) and not a pointer,
+ // and because the static Read method allocates a new object on the heap,
+ // we need to call Read, check if there was a failure, use
+ // MutableFstT::operator= to assign the object (not the pointer) to the
+ // edits_ data member (which will increase the ref count by 1 on the impl)
+ // and, finally, delete the heap-allocated object.
+ MutableFstT *edits = MutableFstT::Read(strm, edits_opts);
+ if (!edits) {
+ return 0;
+ }
+ data->edits_ = *edits;
+ delete edits;
+ // finally, read in rest of private data members
+ ReadType(strm, &data->external_to_internal_ids_);
+ ReadType(strm, &data->edited_final_weights_);
+ ReadType(strm, &data->num_new_states_);
+ if (!strm) {
+ LOG(ERROR) << "EditFst::Read: read failed: " << opts.source;
+ return 0;
+ }
+ return data;
+}
+
+// This class enables non-destructive edit operations on a wrapped ExpandedFst.
+// The implementation uses copy-on-write semantics at the node level: if a user
+// has an underlying fst on which he or she wants to perform a relatively small
+// number of edits (read: mutations), then this implementation will copy the
+// edited node to an internal MutableFst and perform any edits in situ on that
+// copied node. This class supports all the methods of MutableFst except for
+// DeleteStates(const vector<StateId> &); thus, new nodes may also be added, and
+// one may add transitions from existing nodes of the wrapped fst to new nodes.
+//
+// template parameters:
+// A the type of arc to use
+// WrappedFstT the type of fst wrapped by the EditFst instance that
+// this EditFstImpl instance is backing
+// MutableFstT the type of mutable fst to use internally for edited states;
+// crucially, MutableFstT::Copy(false) *must* yield an fst that is
+// thread-safe for reading (VectorFst, for example, has this property)
+template <typename A,
+ typename WrappedFstT = ExpandedFst<A>,
+ typename MutableFstT = VectorFst<A> >
+class EditFstImpl : public FstImpl<A> {
+ public:
+ using FstImpl<A>::SetProperties;
+ using FstImpl<A>::SetInputSymbols;
+ using FstImpl<A>::SetOutputSymbols;
+ using FstImpl<A>::WriteHeader;
+
+ typedef A Arc;
+ typedef typename Arc::Weight Weight;
+ typedef typename Arc::StateId StateId;
+
+ // Constructs an editable fst implementation with no states. Effectively,
+ // this initially-empty fst will in every way mimic the behavior of
+ // a VectorFst--more precisely, a VectorFstImpl instance--but with slightly
+ // slower performance (by a constant factor), due to the fact that
+ // this class maintains a mapping between external state id's and
+ // their internal equivalents.
+ EditFstImpl() {
+ FstImpl<A>::SetType("edit");
+ wrapped_ = new MutableFstT();
+ InheritPropertiesFromWrapped();
+ data_ = new EditFstData<A, WrappedFstT, MutableFstT>();
+ }
+
+ // Wraps the specified ExpandedFst. This constructor requires that the
+ // specified Fst is an ExpandedFst instance. This requirement is only enforced
+ // at runtime. (See below for the reason.)
+ //
+ // This library uses the pointer-to-implementation or "PIMPL" design pattern.
+ // In particular, to make it convenient to bind an implementation class to its
+ // interface, there are a pair of template "binder" classes, one for immutable
+ // and one for mutable fst's (ImplToFst and ImplToMutableFst, respectively).
+ // As it happens, the API for the ImplToMutableFst<I,F> class requires that
+ // the implementation class--the template parameter "I"--have a constructor
+ // taking a const Fst<A> reference. Accordingly, the constructor here must
+ // perform a static_cast to the WrappedFstT type required by EditFst and
+ // therefore EditFstImpl.
+ explicit EditFstImpl(const Fst<A> &wrapped)
+ : wrapped_(static_cast<WrappedFstT *>(wrapped.Copy())) {
+ FstImpl<A>::SetType("edit");
+
+ data_ = new EditFstData<A, WrappedFstT, MutableFstT>();
+ // have edits_ inherit all properties from wrapped_
+ data_->SetEditedProperties(wrapped_->Properties(kFstProperties, false),
+ kFstProperties);
+ InheritPropertiesFromWrapped();
+ }
+
+ // A copy constructor for this implementation class, used to implement
+ // the Copy() method of the Fst interface.
+ EditFstImpl(const EditFstImpl &impl)
+ : FstImpl<A>(),
+ wrapped_(static_cast<WrappedFstT *>(impl.wrapped_->Copy(true))),
+ data_(impl.data_) {
+ data_->IncrRefCount();
+ SetProperties(impl.Properties());
+ }
+
+ ~EditFstImpl() {
+ delete wrapped_;
+ if (!data_->DecrRefCount()) {
+ delete data_;
+ }
+ }
+
+ // const Fst/ExpandedFst operations, declared in the Fst and ExpandedFst
+ // interfaces
+ StateId Start() const {
+ StateId edited_start = data_->EditedStart();
+ return edited_start == kNoStateId ? wrapped_->Start() : edited_start;
+ }
+
+ Weight Final(StateId s) const {
+ return data_->Final(s, wrapped_);
+ }
+
+ size_t NumArcs(StateId s) const {
+ return data_->NumArcs(s, wrapped_);
+ }
+
+ size_t NumInputEpsilons(StateId s) const {
+ return data_->NumInputEpsilons(s, wrapped_);
+ }
+
+ size_t NumOutputEpsilons(StateId s) const {
+ return data_->NumOutputEpsilons(s, wrapped_);
+ }
+
+ StateId NumStates() const {
+ return wrapped_->NumStates() + data_->NumNewStates();
+ }
+
+ static EditFstImpl<A, WrappedFstT, MutableFstT> *
+ Read(istream &strm,
+ const FstReadOptions &opts);
+
+ bool Write(ostream &strm, const FstWriteOptions &opts) const {
+ FstHeader hdr;
+ hdr.SetStart(Start());
+ hdr.SetNumStates(NumStates());
+ FstWriteOptions header_opts(opts);
+ header_opts.write_isymbols = false; // Let contained FST hold any symbols.
+ header_opts.write_osymbols = false;
+ WriteHeader(strm, header_opts, kFileVersion, &hdr);
+
+ // First, serialize wrapped fst to stream.
+ FstWriteOptions wrapped_opts(opts);
+ wrapped_opts.write_header = true; // Force writing contained header.
+ wrapped_->Write(strm, wrapped_opts);
+
+ data_->Write(strm, opts);
+
+ strm.flush();
+ if (!strm) {
+ LOG(ERROR) << "EditFst::Write: write failed: " << opts.source;
+ return false;
+ }
+ return true;
+ }
+ // end const Fst operations
+
+ // non-const MutableFst operations
+
+ // Sets the start state for this fst.
+ void SetStart(StateId s) {
+ MutateCheck();
+ data_->SetStart(s);
+ SetProperties(SetStartProperties(FstImpl<A>::Properties()));
+ }
+
+ // Sets the final state for this fst.
+ void SetFinal(StateId s, Weight w) {
+ MutateCheck();
+ Weight old_weight = data_->SetFinal(s, w, wrapped_);
+ SetProperties(SetFinalProperties(FstImpl<A>::Properties(), old_weight, w));
+ }
+
+ // Adds a new state to this fst, initially with no arcs.
+ StateId AddState() {
+ MutateCheck();
+ SetProperties(AddStateProperties(FstImpl<A>::Properties()));
+ return data_->AddState(NumStates());
+ }
+
+ // Adds the specified arc to the specified state of this fst.
+ void AddArc(StateId s, const Arc &arc) {
+ MutateCheck();
+ const A *prev_arc = data_->AddArc(s, arc, wrapped_);
+ SetProperties(AddArcProperties(FstImpl<A>::Properties(), s, arc, prev_arc));
+ }
+
+ void DeleteStates(const vector<StateId>& dstates) {
+ FSTERROR() << ": EditFstImpl::DeleteStates(const std::vector<StateId>&): "
+ << " not implemented";
+ SetProperties(kError, kError);
+ }
+
+ // Deletes all states in this fst.
+ void DeleteStates();
+
+ // Removes all but the first n outgoing arcs of the specified state.
+ void DeleteArcs(StateId s, size_t n) {
+ MutateCheck();
+ data_->DeleteArcs(s, n, wrapped_);
+ SetProperties(DeleteArcsProperties(FstImpl<A>::Properties()));
+ }
+
+ // Removes all outgoing arcs from the specified state.
+ void DeleteArcs(StateId s) {
+ MutateCheck();
+ data_->DeleteArcs(s, wrapped_);
+ SetProperties(DeleteArcsProperties(FstImpl<A>::Properties()));
+ }
+
+ void ReserveStates(StateId s) {
+ }
+
+ void ReserveArcs(StateId s, size_t n) {
+ }
+
+ // end non-const MutableFst operations
+
+ // Provides information for the generic state iterator.
+ void InitStateIterator(StateIteratorData<Arc> *data) const {
+ data->base = 0;
+ data->nstates = NumStates();
+ }
+
+ // Provides information for the generic arc iterator.
+ void InitArcIterator(StateId s, ArcIteratorData<Arc> *data) const {
+ data_->InitArcIterator(s, data, wrapped_);
+ }
+
+ // Provides information for the generic mutable arc iterator.
+ void InitMutableArcIterator(StateId s, MutableArcIteratorData<A> *data) {
+ MutateCheck();
+ data_->InitMutableArcIterator(s, data, wrapped_);
+ }
+
+ private:
+ typedef typename unordered_map<StateId, StateId>::const_iterator
+ IdMapIterator;
+ typedef typename unordered_map<StateId, Weight>::const_iterator
+ FinalWeightIterator;
+ // Properties always true of this Fst class
+ static const uint64 kStaticProperties = kExpanded | kMutable;
+ // Current file format version
+ static const int kFileVersion = 2;
+ // Minimum file format version supported
+ static const int kMinFileVersion = 2;
+
+ // Causes this fst to inherit all the properties from its wrapped fst, except
+ // for the two properties that always apply to EditFst instances: kExpanded
+ // and kMutable.
+ void InheritPropertiesFromWrapped() {
+ SetProperties(wrapped_->Properties(kCopyProperties, false) |
+ kStaticProperties);
+ SetInputSymbols(wrapped_->InputSymbols());
+ SetOutputSymbols(wrapped_->OutputSymbols());
+ }
+
+ // This method ensures that any operations that alter the mutable data
+ // portion of this EditFstImpl cause the data_ member to be copied when its
+ // reference count is greater than 1. Note that this method is distinct from
+ // MutableFst::Mutate, which gets invoked whenever one of the basic mutation
+ // methods defined in MutableFst is invoked, such as SetInputSymbols.
+ // The MutateCheck here in EditFstImpl is invoked whenever one of the
+ // mutating methods specifically related to the types of edits provided
+ // by EditFst is performed, such as changing an arc of an existing state
+ // of the wrapped fst via a MutableArcIterator, or adding a new state via
+ // AddState().
+ void MutateCheck() {
+ if (data_->RefCount() > 1) {
+ EditFstData<A, WrappedFstT, MutableFstT> *data_copy =
+ new EditFstData<A, WrappedFstT, MutableFstT>(*data_);
+ if (data_ && !data_->DecrRefCount()) {
+ delete data_;
+ }
+ data_ = data_copy;
+ }
+ }
+
+ // The fst that this fst wraps. The purpose of this class is to enable
+ // non-destructive edits on this wrapped fst.
+ const WrappedFstT *wrapped_;
+ // The mutable data for this EditFst instance, with delegates for all the
+ // methods that can mutate data.
+ EditFstData<A, WrappedFstT, MutableFstT> *data_;
+};
+
+template <typename A, typename WrappedFstT, typename MutableFstT>
+const uint64 EditFstImpl<A, WrappedFstT, MutableFstT>::kStaticProperties;
+
+// EditFstImpl IMPLEMENTATION STARTS HERE
+
+template<typename A, typename WrappedFstT, typename MutableFstT>
+inline void EditFstImpl<A, WrappedFstT, MutableFstT>::DeleteStates() {
+ data_->DeleteStates();
+ delete wrapped_;
+ // we are deleting all states, so just forget about pointer to wrapped_
+ // and do what default constructor does: set wrapped_ to a new VectorFst
+ wrapped_ = new MutableFstT();
+ uint64 newProps = DeleteAllStatesProperties(FstImpl<A>::Properties(),
+ kStaticProperties);
+ FstImpl<A>::SetProperties(newProps);
+}
+
+template <typename A, typename WrappedFstT, typename MutableFstT>
+EditFstImpl<A, WrappedFstT, MutableFstT> *
+EditFstImpl<A, WrappedFstT, MutableFstT>::Read(istream &strm,
+ const FstReadOptions &opts) {
+ EditFstImpl<A, WrappedFstT, MutableFstT> *impl = new EditFstImpl();
+ FstHeader hdr;
+ if (!impl->ReadHeader(strm, opts, kMinFileVersion, &hdr)) {
+ return 0;
+ }
+ impl->SetStart(hdr.Start());
+
+ // first, read in wrapped fst
+ FstReadOptions wrapped_opts(opts);
+ wrapped_opts.header = 0; // Contained header was written out, so read it in.
+ Fst<A> *wrapped_fst = Fst<A>::Read(strm, wrapped_opts);
+ if (!wrapped_fst) {
+ return 0;
+ }
+ impl->wrapped_ = static_cast<WrappedFstT *>(wrapped_fst);
+
+ impl->data_ = EditFstData<A, WrappedFstT, MutableFstT>::Read(strm, opts);
+
+ if (!impl->data_) {
+ delete wrapped_fst;
+ return 0;
+ }
+
+ return impl;
+}
+
+// END EditFstImpl IMPLEMENTATION
+
+// Concrete, editable FST. This class attaches interface to implementation.
+template <typename A,
+ typename WrappedFstT = ExpandedFst<A>,
+ typename MutableFstT = VectorFst<A> >
+class EditFst :
+ public ImplToMutableFst< EditFstImpl<A, WrappedFstT, MutableFstT> > {
+ public:
+ friend class MutableArcIterator< EditFst<A, WrappedFstT, MutableFstT> >;
+
+ typedef A Arc;
+ typedef typename A::StateId StateId;
+ typedef EditFstImpl<A, WrappedFstT, MutableFstT> Impl;
+
+ EditFst() : ImplToMutableFst<Impl>(new Impl()) {}
+
+ explicit EditFst(const Fst<A> &fst) :
+ ImplToMutableFst<Impl>(new Impl(fst)) {}
+
+ explicit EditFst(const WrappedFstT &fst) :
+ ImplToMutableFst<Impl>(new Impl(fst)) {}
+
+ // See Fst<>::Copy() for doc.
+ EditFst(const EditFst<A, WrappedFstT, MutableFstT> &fst, bool safe = false) :
+ ImplToMutableFst<Impl>(fst, safe) {}
+
+ virtual ~EditFst() {}
+
+ // Get a copy of this EditFst. See Fst<>::Copy() for further doc.
+ virtual EditFst<A, WrappedFstT, MutableFstT> *Copy(bool safe = false) const {
+ return new EditFst<A, WrappedFstT, MutableFstT>(*this, safe);
+ }
+
+ EditFst<A, WrappedFstT, MutableFstT> &
+ operator=(const EditFst<A, WrappedFstT, MutableFstT> &fst) {
+ SetImpl(fst.GetImpl(), false);
+ return *this;
+ }
+
+ virtual EditFst<A, WrappedFstT, MutableFstT> &operator=(const Fst<A> &fst) {
+ if (this != &fst) {
+ SetImpl(new Impl(fst));
+ }
+ return *this;
+ }
+
+ // Read an EditFst from an input stream; return NULL on error.
+ static EditFst<A, WrappedFstT, MutableFstT> *
+ Read(istream &strm,
+ const FstReadOptions &opts) {
+ Impl* impl = Impl::Read(strm, opts);
+ return impl ? new EditFst<A>(impl) : 0;
+ }
+
+ // Read an EditFst from a file; return NULL on error.
+ // Empty filename reads from standard input.
+ static EditFst<A, WrappedFstT, MutableFstT> *Read(const string &filename) {
+ Impl* impl = ImplToExpandedFst<Impl, MutableFst<A> >::Read(filename);
+ return impl ? new EditFst<A, WrappedFstT, MutableFstT>(impl) : 0;
+ }
+
+ virtual bool Write(ostream &strm, const FstWriteOptions &opts) const {
+ return GetImpl()->Write(strm, opts);
+ }
+
+ virtual bool Write(const string &filename) const {
+ return Fst<A>::WriteFile(filename);
+ }
+
+ virtual void InitStateIterator(StateIteratorData<Arc> *data) const {
+ GetImpl()->InitStateIterator(data);
+ }
+
+ virtual void InitArcIterator(StateId s, ArcIteratorData<Arc> *data) const {
+ GetImpl()->InitArcIterator(s, data);
+ }
+
+ virtual
+ void InitMutableArcIterator(StateId s, MutableArcIteratorData<A> *data) {
+ GetImpl()->InitMutableArcIterator(s, data);
+ }
+ private:
+ explicit EditFst(Impl *impl) : ImplToMutableFst<Impl>(impl) {}
+
+ // Makes visible to friends.
+ Impl *GetImpl() const { return ImplToFst< Impl, MutableFst<A> >::GetImpl(); }
+
+ void SetImpl(Impl *impl, bool own_impl = true) {
+ ImplToFst< Impl, MutableFst<A> >::SetImpl(impl, own_impl);
+ }
+};
+
+} // namespace fst
+
+#endif // FST_LIB_EDIT_FST_H_