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