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: dbikel@google.com (Dan Bikel)
16 //
17 // An \ref Fst implementation that allows non-destructive edit operations on an
18 // existing fst.
19
20 #ifndef FST_LIB_EDIT_FST_H_
21 #define FST_LIB_EDIT_FST_H_
22
23 #include <vector>
24 using std::vector;
25
26 #include <fst/cache.h>
27
28 namespace fst {
29
30 // The EditFst class enables non-destructive edit operations on a wrapped
31 // ExpandedFst. The implementation uses copy-on-write semantics at the node
32 // level: if a user has an underlying fst on which he or she wants to perform a
33 // relatively small number of edits (read: mutations), then this implementation
34 // will copy the edited node to an internal MutableFst and perform any edits in
35 // situ on that copied node. This class supports all the methods of MutableFst
36 // except for DeleteStates(const vector<StateId> &); thus, new nodes may also be
37 // added, and one may add transitions from existing nodes of the wrapped fst to
38 // new nodes.
39 //
40 // N.B.: The documentation for Fst::Copy(true) says that its behavior is
41 // undefined if invoked on an fst that has already been accessed. This class
42 // requires that the Fst implementation it wraps provides consistent, reliable
43 // behavior when its Copy(true) method is invoked, where consistent means
44 // the graph structure, graph properties and state numbering and do not change.
45 // VectorFst and CompactFst, for example, are both well-behaved in this regard.
46
47 // The EditFstData class is a container for all mutable data for EditFstImpl;
48 // also, this class provides most of the actual implementation of what EditFst
49 // does (that is, most of EditFstImpl's methods delegate to methods in this, the
50 // EditFstData class). Instances of this class are reference-counted and can be
51 // shared between otherwise independent EditFstImpl instances. This scheme
52 // allows EditFstImpl to implement the thread-safe, copy-on-write semantics
53 // required by Fst::Copy(true).
54 //
55 // template parameters:
56 // A the type of arc to use
57 // WrappedFstT the type of fst wrapped by the EditFst instance that
58 // this EditFstData instance is backing
59 // MutableFstT the type of mutable fst to use internally for edited states;
60 // crucially, MutableFstT::Copy(false) *must* yield an fst that is
61 // thread-safe for reading (VectorFst, for example, has this property)
62 template <typename A,
63 typename WrappedFstT = ExpandedFst<A>,
64 typename MutableFstT = VectorFst<A> >
65 class EditFstData {
66 public:
67 typedef A Arc;
68 typedef typename A::Weight Weight;
69 typedef typename A::StateId StateId;
70 typedef typename unordered_map<StateId, StateId>::const_iterator
71 IdMapIterator;
72 typedef typename unordered_map<StateId, Weight>::const_iterator
73 FinalWeightIterator;
74
75
EditFstData()76 EditFstData() : num_new_states_(0) {
77 SetEmptyAndDeleteKeysForInternalMaps();
78 }
79
EditFstData(const EditFstData & other)80 EditFstData(const EditFstData &other) :
81 edits_(other.edits_),
82 external_to_internal_ids_(other.external_to_internal_ids_),
83 edited_final_weights_(other.edited_final_weights_),
84 num_new_states_(other.num_new_states_) {
85 }
86
~EditFstData()87 ~EditFstData() {
88 }
89
90 static EditFstData<A, WrappedFstT, MutableFstT> *Read(istream &strm,
91 const FstReadOptions &opts);
92
Write(ostream & strm,const FstWriteOptions & opts)93 bool Write(ostream &strm, const FstWriteOptions &opts) const {
94 // Serialize all private data members of this class.
95 FstWriteOptions edits_opts(opts);
96 edits_opts.write_header = true; // Force writing contained header.
97 edits_.Write(strm, edits_opts);
98 WriteType(strm, external_to_internal_ids_);
99 WriteType(strm, edited_final_weights_);
100 WriteType(strm, num_new_states_);
101 if (!strm) {
102 LOG(ERROR) << "EditFstData::Write: write failed: " << opts.source;
103 return false;
104 }
105 return true;
106 }
107
RefCount()108 int RefCount() const { return ref_count_.count(); }
IncrRefCount()109 int IncrRefCount() { return ref_count_.Incr(); }
DecrRefCount()110 int DecrRefCount() { return ref_count_.Decr(); }
111
NumNewStates()112 StateId NumNewStates() const {
113 return num_new_states_;
114 }
115
116 // accessor methods for the fst holding edited states
EditedStart()117 StateId EditedStart() const {
118 return edits_.Start();
119 }
120
Final(StateId s,const WrappedFstT * wrapped)121 Weight Final(StateId s, const WrappedFstT *wrapped) const {
122 FinalWeightIterator final_weight_it = GetFinalWeightIterator(s);
123 if (final_weight_it == NotInFinalWeightMap()) {
124 IdMapIterator it = GetEditedIdMapIterator(s);
125 return it == NotInEditedMap() ?
126 wrapped->Final(s) : edits_.Final(it->second);
127 }
128 else {
129 return final_weight_it->second;
130 }
131 }
132
NumArcs(StateId s,const WrappedFstT * wrapped)133 size_t NumArcs(StateId s, const WrappedFstT *wrapped) const {
134 IdMapIterator it = GetEditedIdMapIterator(s);
135 return it == NotInEditedMap() ?
136 wrapped->NumArcs(s) : edits_.NumArcs(it->second);
137 }
138
NumInputEpsilons(StateId s,const WrappedFstT * wrapped)139 size_t NumInputEpsilons(StateId s, const WrappedFstT *wrapped) const {
140 IdMapIterator it = GetEditedIdMapIterator(s);
141 return it == NotInEditedMap() ?
142 wrapped->NumInputEpsilons(s) :
143 edits_.NumInputEpsilons(it->second);
144 }
145
NumOutputEpsilons(StateId s,const WrappedFstT * wrapped)146 size_t NumOutputEpsilons(StateId s, const WrappedFstT *wrapped) const {
147 IdMapIterator it = GetEditedIdMapIterator(s);
148 return it == NotInEditedMap() ?
149 wrapped->NumOutputEpsilons(s) :
150 edits_.NumOutputEpsilons(it->second);
151 }
152
SetEditedProperties(uint64 props,uint64 mask)153 void SetEditedProperties(uint64 props, uint64 mask) {
154 edits_.SetProperties(props, mask);
155 }
156
157 // non-const MutableFst operations
158
159 // Sets the start state for this fst.
SetStart(StateId s)160 void SetStart(StateId s) {
161 edits_.SetStart(s);
162 }
163
164 // Sets the final state for this fst.
SetFinal(StateId s,Weight w,const WrappedFstT * wrapped)165 Weight SetFinal(StateId s, Weight w, const WrappedFstT *wrapped) {
166 Weight old_weight = Final(s, wrapped);
167 IdMapIterator it = GetEditedIdMapIterator(s);
168 // if we haven't already edited state s, don't add it to edited_ (which can
169 // be expensive if s has many transitions); just use the
170 // edited_final_weights_ map
171 if (it == NotInEditedMap()) {
172 edited_final_weights_[s] = w;
173 }
174 else {
175 edits_.SetFinal(GetEditableInternalId(s, wrapped), w);
176 }
177 return old_weight;
178 }
179
180 // Adds a new state to this fst, initially with no arcs.
AddState(StateId curr_num_states)181 StateId AddState(StateId curr_num_states) {
182 StateId internal_state_id = edits_.AddState();
183 StateId external_state_id = curr_num_states;
184 external_to_internal_ids_[external_state_id] = internal_state_id;
185 num_new_states_++;
186 return external_state_id;
187 }
188
189 // Adds the specified arc to the specified state of this fst.
AddArc(StateId s,const Arc & arc,const WrappedFstT * wrapped)190 const A *AddArc(StateId s, const Arc &arc, const WrappedFstT *wrapped) {
191 StateId internal_id = GetEditableInternalId(s, wrapped);
192
193 size_t num_arcs = edits_.NumArcs(internal_id);
194 ArcIterator<MutableFstT> arc_it(edits_, internal_id);
195 const A *prev_arc = NULL;
196 if (num_arcs > 0) {
197 // grab the final arc associated with this state in edits_
198 arc_it.Seek(num_arcs - 1);
199 prev_arc = &(arc_it.Value());
200 }
201 edits_.AddArc(internal_id, arc);
202 return prev_arc;
203 }
204
DeleteStates()205 void DeleteStates() {
206 edits_.DeleteStates();
207 num_new_states_ = 0;
208 external_to_internal_ids_.clear();
209 edited_final_weights_.clear();
210 }
211
212 // Removes all but the first n outgoing arcs of the specified state.
DeleteArcs(StateId s,size_t n,const WrappedFstT * wrapped)213 void DeleteArcs(StateId s, size_t n, const WrappedFstT *wrapped) {
214 edits_.DeleteArcs(GetEditableInternalId(s, wrapped), n);
215 }
216
217 // Removes all outgoing arcs from the specified state.
DeleteArcs(StateId s,const WrappedFstT * wrapped)218 void DeleteArcs(StateId s, const WrappedFstT *wrapped) {
219 edits_.DeleteArcs(GetEditableInternalId(s, wrapped));
220 }
221
222 // end methods for non-const MutableFst operations
223
224 // Provides information for the generic arc iterator.
InitArcIterator(StateId s,ArcIteratorData<Arc> * data,const WrappedFstT * wrapped)225 void InitArcIterator(StateId s, ArcIteratorData<Arc> *data,
226 const WrappedFstT *wrapped) const {
227 IdMapIterator id_map_it = GetEditedIdMapIterator(s);
228 if (id_map_it == NotInEditedMap()) {
229 VLOG(3) << "EditFstData::InitArcIterator: iterating on state "
230 << s << " of original fst";
231 wrapped->InitArcIterator(s, data);
232 } else {
233 VLOG(2) << "EditFstData::InitArcIterator: iterating on edited state "
234 << s << " (internal state id: " << id_map_it->second << ")";
235 edits_.InitArcIterator(id_map_it->second, data);
236 }
237 }
238
239 // Provides information for the generic mutable arc iterator.
InitMutableArcIterator(StateId s,MutableArcIteratorData<A> * data,const WrappedFstT * wrapped)240 void InitMutableArcIterator(StateId s, MutableArcIteratorData<A> *data,
241 const WrappedFstT *wrapped) {
242 data->base =
243 new MutableArcIterator<MutableFstT>(&edits_,
244 GetEditableInternalId(s, wrapped));
245 }
246
247 // Prints out the map from external to internal state id's (for debugging
248 // purposes).
PrintMap()249 void PrintMap() {
250 for (IdMapIterator map_it = external_to_internal_ids_.begin();
251 map_it != NotInEditedMap(); ++map_it) {
252 LOG(INFO) << "(external,internal)=("
253 << map_it->first << "," << map_it->second << ")";
254 }
255 }
256
257
258 private:
SetEmptyAndDeleteKeysForInternalMaps()259 void SetEmptyAndDeleteKeysForInternalMaps() {
260 }
261
262 // Returns the iterator of the map from external to internal state id's
263 // of edits_ for the specified external state id.
GetEditedIdMapIterator(StateId s)264 IdMapIterator GetEditedIdMapIterator(StateId s) const {
265 return external_to_internal_ids_.find(s);
266 }
NotInEditedMap()267 IdMapIterator NotInEditedMap() const {
268 return external_to_internal_ids_.end();
269 }
270
GetFinalWeightIterator(StateId s)271 FinalWeightIterator GetFinalWeightIterator(StateId s) const {
272 return edited_final_weights_.find(s);
273 }
NotInFinalWeightMap()274 FinalWeightIterator NotInFinalWeightMap() const {
275 return edited_final_weights_.end();
276 }
277
278 // Returns the internal state id of the specified external id if the state has
279 // already been made editable, or else copies the state from wrapped_
280 // to edits_ and returns the state id of the newly editable state in edits_.
281 //
282 // \return makes the specified state editable if it isn't already and returns
283 // its state id in edits_
GetEditableInternalId(StateId s,const WrappedFstT * wrapped)284 StateId GetEditableInternalId(StateId s, const WrappedFstT *wrapped) {
285 IdMapIterator id_map_it = GetEditedIdMapIterator(s);
286 if (id_map_it == NotInEditedMap()) {
287 StateId new_internal_id = edits_.AddState();
288 VLOG(2) << "EditFstData::GetEditableInternalId: editing state " << s
289 << " of original fst; new internal state id:" << new_internal_id;
290 external_to_internal_ids_[s] = new_internal_id;
291 for (ArcIterator< Fst<A> > arc_iterator(*wrapped, s);
292 !arc_iterator.Done();
293 arc_iterator.Next()) {
294 edits_.AddArc(new_internal_id, arc_iterator.Value());
295 }
296 // copy the final weight
297 FinalWeightIterator final_weight_it = GetFinalWeightIterator(s);
298 if (final_weight_it == NotInFinalWeightMap()) {
299 edits_.SetFinal(new_internal_id, wrapped->Final(s));
300 } else {
301 edits_.SetFinal(new_internal_id, final_weight_it->second);
302 edited_final_weights_.erase(s);
303 }
304 return new_internal_id;
305 } else {
306 return id_map_it->second;
307 }
308 }
309
310 // A mutable fst (by default, a VectorFst) to contain new states, and/or
311 // copies of states from a wrapped ExpandedFst that have been modified in
312 // some way.
313 MutableFstT edits_;
314 // A mapping from external state id's to the internal id's of states that
315 // appear in edits_.
316 unordered_map<StateId, StateId> external_to_internal_ids_;
317 // A mapping from external state id's to final state weights assigned to
318 // those states. The states in this map are *only* those whose final weight
319 // has been modified; if any other part of the state has been modified,
320 // the entire state is copied to edits_, and all modifications reside there.
321 unordered_map<StateId, Weight> edited_final_weights_;
322 // The number of new states added to this mutable fst impl, which is <= the
323 // number of states in edits_ (since edits_ contains both edited *and* new
324 // states).
325 StateId num_new_states_;
326 RefCounter ref_count_;
327 };
328
329 // EditFstData method implementations: just the Read method.
330 template <typename A, typename WrappedFstT, typename MutableFstT>
331 EditFstData<A, WrappedFstT, MutableFstT> *
Read(istream & strm,const FstReadOptions & opts)332 EditFstData<A, WrappedFstT, MutableFstT>::Read(istream &strm,
333 const FstReadOptions &opts) {
334 EditFstData<A, WrappedFstT, MutableFstT> *data =
335 new EditFstData<A, WrappedFstT, MutableFstT>();
336 // next read in MutabelFstT machine that stores edits
337 FstReadOptions edits_opts(opts);
338 edits_opts.header = 0; // Contained header was written out, so read it in.
339
340 // Because our internal representation of edited states is a solid object
341 // of type MutableFstT (defaults to VectorFst<A>) and not a pointer,
342 // and because the static Read method allocates a new object on the heap,
343 // we need to call Read, check if there was a failure, use
344 // MutableFstT::operator= to assign the object (not the pointer) to the
345 // edits_ data member (which will increase the ref count by 1 on the impl)
346 // and, finally, delete the heap-allocated object.
347 MutableFstT *edits = MutableFstT::Read(strm, edits_opts);
348 if (!edits) {
349 return 0;
350 }
351 data->edits_ = *edits;
352 delete edits;
353 // finally, read in rest of private data members
354 ReadType(strm, &data->external_to_internal_ids_);
355 ReadType(strm, &data->edited_final_weights_);
356 ReadType(strm, &data->num_new_states_);
357 if (!strm) {
358 LOG(ERROR) << "EditFst::Read: read failed: " << opts.source;
359 return 0;
360 }
361 return data;
362 }
363
364 // This class enables non-destructive edit operations on a wrapped ExpandedFst.
365 // The implementation uses copy-on-write semantics at the node level: if a user
366 // has an underlying fst on which he or she wants to perform a relatively small
367 // number of edits (read: mutations), then this implementation will copy the
368 // edited node to an internal MutableFst and perform any edits in situ on that
369 // copied node. This class supports all the methods of MutableFst except for
370 // DeleteStates(const vector<StateId> &); thus, new nodes may also be added, and
371 // one may add transitions from existing nodes of the wrapped fst to new nodes.
372 //
373 // template parameters:
374 // A the type of arc to use
375 // WrappedFstT the type of fst wrapped by the EditFst instance that
376 // this EditFstImpl instance is backing
377 // MutableFstT the type of mutable fst to use internally for edited states;
378 // crucially, MutableFstT::Copy(false) *must* yield an fst that is
379 // thread-safe for reading (VectorFst, for example, has this property)
380 template <typename A,
381 typename WrappedFstT = ExpandedFst<A>,
382 typename MutableFstT = VectorFst<A> >
383 class EditFstImpl : public FstImpl<A> {
384 public:
385 using FstImpl<A>::SetProperties;
386 using FstImpl<A>::SetInputSymbols;
387 using FstImpl<A>::SetOutputSymbols;
388 using FstImpl<A>::WriteHeader;
389
390 typedef A Arc;
391 typedef typename Arc::Weight Weight;
392 typedef typename Arc::StateId StateId;
393
394 // Constructs an editable fst implementation with no states. Effectively,
395 // this initially-empty fst will in every way mimic the behavior of
396 // a VectorFst--more precisely, a VectorFstImpl instance--but with slightly
397 // slower performance (by a constant factor), due to the fact that
398 // this class maintains a mapping between external state id's and
399 // their internal equivalents.
EditFstImpl()400 EditFstImpl() {
401 FstImpl<A>::SetType("edit");
402 wrapped_ = new MutableFstT();
403 InheritPropertiesFromWrapped();
404 data_ = new EditFstData<A, WrappedFstT, MutableFstT>();
405 }
406
407 // Wraps the specified ExpandedFst. This constructor requires that the
408 // specified Fst is an ExpandedFst instance. This requirement is only enforced
409 // at runtime. (See below for the reason.)
410 //
411 // This library uses the pointer-to-implementation or "PIMPL" design pattern.
412 // In particular, to make it convenient to bind an implementation class to its
413 // interface, there are a pair of template "binder" classes, one for immutable
414 // and one for mutable fst's (ImplToFst and ImplToMutableFst, respectively).
415 // As it happens, the API for the ImplToMutableFst<I,F> class requires that
416 // the implementation class--the template parameter "I"--have a constructor
417 // taking a const Fst<A> reference. Accordingly, the constructor here must
418 // perform a static_cast to the WrappedFstT type required by EditFst and
419 // therefore EditFstImpl.
EditFstImpl(const Fst<A> & wrapped)420 explicit EditFstImpl(const Fst<A> &wrapped)
421 : wrapped_(static_cast<WrappedFstT *>(wrapped.Copy())) {
422 FstImpl<A>::SetType("edit");
423
424 data_ = new EditFstData<A, WrappedFstT, MutableFstT>();
425 // have edits_ inherit all properties from wrapped_
426 data_->SetEditedProperties(wrapped_->Properties(kFstProperties, false),
427 kFstProperties);
428 InheritPropertiesFromWrapped();
429 }
430
431 // A copy constructor for this implementation class, used to implement
432 // the Copy() method of the Fst interface.
EditFstImpl(const EditFstImpl & impl)433 EditFstImpl(const EditFstImpl &impl)
434 : wrapped_(static_cast<WrappedFstT *>(impl.wrapped_->Copy(true))),
435 data_(impl.data_) {
436 data_->IncrRefCount();
437 SetProperties(impl.Properties());
438 }
439
~EditFstImpl()440 ~EditFstImpl() {
441 delete wrapped_;
442 if (!data_->DecrRefCount()) {
443 delete data_;
444 }
445 }
446
447 // const Fst/ExpandedFst operations, declared in the Fst and ExpandedFst
448 // interfaces
Start()449 StateId Start() const {
450 StateId edited_start = data_->EditedStart();
451 return edited_start == kNoStateId ? wrapped_->Start() : edited_start;
452 }
453
Final(StateId s)454 Weight Final(StateId s) const {
455 return data_->Final(s, wrapped_);
456 }
457
NumArcs(StateId s)458 size_t NumArcs(StateId s) const {
459 return data_->NumArcs(s, wrapped_);
460 }
461
NumInputEpsilons(StateId s)462 size_t NumInputEpsilons(StateId s) const {
463 return data_->NumInputEpsilons(s, wrapped_);
464 }
465
NumOutputEpsilons(StateId s)466 size_t NumOutputEpsilons(StateId s) const {
467 return data_->NumOutputEpsilons(s, wrapped_);
468 }
469
NumStates()470 StateId NumStates() const {
471 return wrapped_->NumStates() + data_->NumNewStates();
472 }
473
474 static EditFstImpl<A, WrappedFstT, MutableFstT> *
475 Read(istream &strm,
476 const FstReadOptions &opts);
477
Write(ostream & strm,const FstWriteOptions & opts)478 bool Write(ostream &strm, const FstWriteOptions &opts) const {
479 FstHeader hdr;
480 hdr.SetStart(Start());
481 hdr.SetNumStates(NumStates());
482 FstWriteOptions header_opts(opts);
483 header_opts.write_isymbols = false; // Let contained FST hold any symbols.
484 header_opts.write_osymbols = false;
485 WriteHeader(strm, header_opts, kFileVersion, &hdr);
486
487 // First, serialize wrapped fst to stream.
488 FstWriteOptions wrapped_opts(opts);
489 wrapped_opts.write_header = true; // Force writing contained header.
490 wrapped_->Write(strm, wrapped_opts);
491
492 data_->Write(strm, opts);
493
494 strm.flush();
495 if (!strm) {
496 LOG(ERROR) << "EditFst::Write: write failed: " << opts.source;
497 return false;
498 }
499 return true;
500 }
501 // end const Fst operations
502
503 // non-const MutableFst operations
504
505 // Sets the start state for this fst.
SetStart(StateId s)506 void SetStart(StateId s) {
507 MutateCheck();
508 data_->SetStart(s);
509 SetProperties(SetStartProperties(FstImpl<A>::Properties()));
510 }
511
512 // Sets the final state for this fst.
SetFinal(StateId s,Weight w)513 void SetFinal(StateId s, Weight w) {
514 MutateCheck();
515 Weight old_weight = data_->SetFinal(s, w, wrapped_);
516 SetProperties(SetFinalProperties(FstImpl<A>::Properties(), old_weight, w));
517 }
518
519 // Adds a new state to this fst, initially with no arcs.
AddState()520 StateId AddState() {
521 MutateCheck();
522 SetProperties(AddStateProperties(FstImpl<A>::Properties()));
523 return data_->AddState(NumStates());
524 }
525
526 // Adds the specified arc to the specified state of this fst.
AddArc(StateId s,const Arc & arc)527 void AddArc(StateId s, const Arc &arc) {
528 MutateCheck();
529 const A *prev_arc = data_->AddArc(s, arc, wrapped_);
530 SetProperties(AddArcProperties(FstImpl<A>::Properties(), s, arc, prev_arc));
531 }
532
DeleteStates(const vector<StateId> & dstates)533 void DeleteStates(const vector<StateId>& dstates) {
534 FSTERROR() << ": EditFstImpl::DeleteStates(const std::vector<StateId>&): "
535 << " not implemented";
536 SetProperties(kError, kError);
537 }
538
539 // Deletes all states in this fst.
540 void DeleteStates();
541
542 // Removes all but the first n outgoing arcs of the specified state.
DeleteArcs(StateId s,size_t n)543 void DeleteArcs(StateId s, size_t n) {
544 MutateCheck();
545 data_->DeleteArcs(s, n, wrapped_);
546 SetProperties(DeleteArcsProperties(FstImpl<A>::Properties()));
547 }
548
549 // Removes all outgoing arcs from the specified state.
DeleteArcs(StateId s)550 void DeleteArcs(StateId s) {
551 MutateCheck();
552 data_->DeleteArcs(s, wrapped_);
553 SetProperties(DeleteArcsProperties(FstImpl<A>::Properties()));
554 }
555
ReserveStates(StateId s)556 void ReserveStates(StateId s) {
557 }
558
ReserveArcs(StateId s,size_t n)559 void ReserveArcs(StateId s, size_t n) {
560 }
561
562 // end non-const MutableFst operations
563
564 // Provides information for the generic state iterator.
InitStateIterator(StateIteratorData<Arc> * data)565 void InitStateIterator(StateIteratorData<Arc> *data) const {
566 data->base = 0;
567 data->nstates = NumStates();
568 }
569
570 // Provides information for the generic arc iterator.
InitArcIterator(StateId s,ArcIteratorData<Arc> * data)571 void InitArcIterator(StateId s, ArcIteratorData<Arc> *data) const {
572 data_->InitArcIterator(s, data, wrapped_);
573 }
574
575 // Provides information for the generic mutable arc iterator.
InitMutableArcIterator(StateId s,MutableArcIteratorData<A> * data)576 void InitMutableArcIterator(StateId s, MutableArcIteratorData<A> *data) {
577 MutateCheck();
578 data_->InitMutableArcIterator(s, data, wrapped_);
579 }
580
581 private:
582 typedef typename unordered_map<StateId, StateId>::const_iterator
583 IdMapIterator;
584 typedef typename unordered_map<StateId, Weight>::const_iterator
585 FinalWeightIterator;
586 // Properties always true of this Fst class
587 static const uint64 kStaticProperties = kExpanded | kMutable;
588 // Current file format version
589 static const int kFileVersion = 2;
590 // Minimum file format version supported
591 static const int kMinFileVersion = 2;
592
593 // Causes this fst to inherit all the properties from its wrapped fst, except
594 // for the two properties that always apply to EditFst instances: kExpanded
595 // and kMutable.
InheritPropertiesFromWrapped()596 void InheritPropertiesFromWrapped() {
597 SetProperties(wrapped_->Properties(kCopyProperties, false) |
598 kStaticProperties);
599 SetInputSymbols(wrapped_->InputSymbols());
600 SetOutputSymbols(wrapped_->OutputSymbols());
601 }
602
603 // This method ensures that any operations that alter the mutable data
604 // portion of this EditFstImpl cause the data_ member to be copied when its
605 // reference count is greater than 1. Note that this method is distinct from
606 // MutableFst::Mutate, which gets invoked whenever one of the basic mutation
607 // methods defined in MutableFst is invoked, such as SetInputSymbols.
608 // The MutateCheck here in EditFstImpl is invoked whenever one of the
609 // mutating methods specifically related to the types of edits provided
610 // by EditFst is performed, such as changing an arc of an existing state
611 // of the wrapped fst via a MutableArcIterator, or adding a new state via
612 // AddState().
MutateCheck()613 void MutateCheck() {
614 if (data_->RefCount() > 1) {
615 EditFstData<A, WrappedFstT, MutableFstT> *data_copy =
616 new EditFstData<A, WrappedFstT, MutableFstT>(*data_);
617 if (data_ && !data_->DecrRefCount()) {
618 delete data_;
619 }
620 data_ = data_copy;
621 }
622 }
623
624 // The fst that this fst wraps. The purpose of this class is to enable
625 // non-destructive edits on this wrapped fst.
626 const WrappedFstT *wrapped_;
627 // The mutable data for this EditFst instance, with delegates for all the
628 // methods that can mutate data.
629 EditFstData<A, WrappedFstT, MutableFstT> *data_;
630 };
631
632 template <typename A, typename WrappedFstT, typename MutableFstT>
633 const uint64 EditFstImpl<A, WrappedFstT, MutableFstT>::kStaticProperties;
634
635 // EditFstImpl IMPLEMENTATION STARTS HERE
636
637 template<typename A, typename WrappedFstT, typename MutableFstT>
DeleteStates()638 inline void EditFstImpl<A, WrappedFstT, MutableFstT>::DeleteStates() {
639 data_->DeleteStates();
640 delete wrapped_;
641 // we are deleting all states, so just forget about pointer to wrapped_
642 // and do what default constructor does: set wrapped_ to a new VectorFst
643 wrapped_ = new MutableFstT();
644 uint64 newProps = DeleteAllStatesProperties(FstImpl<A>::Properties(),
645 kStaticProperties);
646 FstImpl<A>::SetProperties(newProps);
647 }
648
649 template <typename A, typename WrappedFstT, typename MutableFstT>
650 EditFstImpl<A, WrappedFstT, MutableFstT> *
Read(istream & strm,const FstReadOptions & opts)651 EditFstImpl<A, WrappedFstT, MutableFstT>::Read(istream &strm,
652 const FstReadOptions &opts) {
653 EditFstImpl<A, WrappedFstT, MutableFstT> *impl = new EditFstImpl();
654 FstHeader hdr;
655 if (!impl->ReadHeader(strm, opts, kMinFileVersion, &hdr)) {
656 return 0;
657 }
658 impl->SetStart(hdr.Start());
659
660 // first, read in wrapped fst
661 FstReadOptions wrapped_opts(opts);
662 wrapped_opts.header = 0; // Contained header was written out, so read it in.
663 Fst<A> *wrapped_fst = Fst<A>::Read(strm, wrapped_opts);
664 if (!wrapped_fst) {
665 return 0;
666 }
667 impl->wrapped_ = static_cast<WrappedFstT *>(wrapped_fst);
668
669 impl->data_ = EditFstData<A, WrappedFstT, MutableFstT>::Read(strm, opts);
670
671 if (!impl->data_) {
672 delete wrapped_fst;
673 return 0;
674 }
675
676 return impl;
677 }
678
679 // END EditFstImpl IMPLEMENTATION
680
681 // Concrete, editable FST. This class attaches interface to implementation.
682 template <typename A,
683 typename WrappedFstT = ExpandedFst<A>,
684 typename MutableFstT = VectorFst<A> >
685 class EditFst :
686 public ImplToMutableFst< EditFstImpl<A, WrappedFstT, MutableFstT> > {
687 public:
688 friend class MutableArcIterator< EditFst<A, WrappedFstT, MutableFstT> >;
689
690 typedef A Arc;
691 typedef typename A::StateId StateId;
692 typedef EditFstImpl<A, WrappedFstT, MutableFstT> Impl;
693
EditFst()694 EditFst() : ImplToMutableFst<Impl>(new Impl()) {}
695
EditFst(const Fst<A> & fst)696 explicit EditFst(const Fst<A> &fst) :
697 ImplToMutableFst<Impl>(new Impl(fst)) {}
698
EditFst(const WrappedFstT & fst)699 explicit EditFst(const WrappedFstT &fst) :
700 ImplToMutableFst<Impl>(new Impl(fst)) {}
701
702 // See Fst<>::Copy() for doc.
703 EditFst(const EditFst<A, WrappedFstT, MutableFstT> &fst, bool safe = false) :
704 ImplToMutableFst<Impl>(fst, safe) {}
705
~EditFst()706 virtual ~EditFst() {}
707
708 // Get a copy of this EditFst. See Fst<>::Copy() for further doc.
709 virtual EditFst<A, WrappedFstT, MutableFstT> *Copy(bool safe = false) const {
710 return new EditFst<A, WrappedFstT, MutableFstT>(*this, safe);
711 }
712
713 EditFst<A, WrappedFstT, MutableFstT> &
714 operator=(const EditFst<A, WrappedFstT, MutableFstT> &fst) {
715 SetImpl(fst.GetImpl(), false);
716 return *this;
717 }
718
719 virtual EditFst<A, WrappedFstT, MutableFstT> &operator=(const Fst<A> &fst) {
720 if (this != &fst) {
721 SetImpl(new Impl(fst));
722 }
723 return *this;
724 }
725
726 // Read an EditFst from an input stream; return NULL on error.
727 static EditFst<A, WrappedFstT, MutableFstT> *
Read(istream & strm,const FstReadOptions & opts)728 Read(istream &strm,
729 const FstReadOptions &opts) {
730 Impl* impl = Impl::Read(strm, opts);
731 return impl ? new EditFst<A>(impl) : 0;
732 }
733
734 // Read an EditFst from a file; return NULL on error.
735 // Empty filename reads from standard input.
Read(const string & filename)736 static EditFst<A, WrappedFstT, MutableFstT> *Read(const string &filename) {
737 Impl* impl = ImplToExpandedFst<Impl, MutableFst<A> >::Read(filename);
738 return impl ? new EditFst<A, WrappedFstT, MutableFstT>(impl) : 0;
739 }
740
Write(ostream & strm,const FstWriteOptions & opts)741 virtual bool Write(ostream &strm, const FstWriteOptions &opts) const {
742 return GetImpl()->Write(strm, opts);
743 }
744
Write(const string & filename)745 virtual bool Write(const string &filename) const {
746 return Fst<A>::WriteFile(filename);
747 }
748
InitStateIterator(StateIteratorData<Arc> * data)749 virtual void InitStateIterator(StateIteratorData<Arc> *data) const {
750 GetImpl()->InitStateIterator(data);
751 }
752
InitArcIterator(StateId s,ArcIteratorData<Arc> * data)753 virtual void InitArcIterator(StateId s, ArcIteratorData<Arc> *data) const {
754 GetImpl()->InitArcIterator(s, data);
755 }
756
757 virtual
InitMutableArcIterator(StateId s,MutableArcIteratorData<A> * data)758 void InitMutableArcIterator(StateId s, MutableArcIteratorData<A> *data) {
759 GetImpl()->InitMutableArcIterator(s, data);
760 }
761 private:
EditFst(Impl * impl)762 explicit EditFst(Impl *impl) : ImplToMutableFst<Impl>(impl) {}
763
764 // Makes visible to friends.
GetImpl()765 Impl *GetImpl() const { return ImplToFst< Impl, MutableFst<A> >::GetImpl(); }
766
767 void SetImpl(Impl *impl, bool own_impl = true) {
768 ImplToFst< Impl, MutableFst<A> >::SetImpl(impl, own_impl);
769 }
770 };
771
772 } // namespace fst
773
774 #endif // FST_LIB_EDIT_FST_H_
775