// add-on.h // 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: riley@google.com (Michael Riley) // // \file // Fst implementation class to attach an arbitrary object with a // read/write method to an FST and its file rep. The FST is given a // new type name. #ifndef FST_LIB_ADD_ON_FST_H__ #define FST_LIB_ADD_ON_FST_H__ #include #include #include namespace fst { // Identifies stream data as an add-on fst. static const int32 kAddOnMagicNumber = 446681434; // // Some useful add-on objects. // // Nothing to save. class NullAddOn { public: NullAddOn() {} static NullAddOn *Read(istream &istrm) { return new NullAddOn(); }; bool Write(ostream &ostrm) const { return true; } int RefCount() const { return ref_count_.count(); } int IncrRefCount() { return ref_count_.Incr(); } int DecrRefCount() { return ref_count_.Decr(); } private: RefCounter ref_count_; DISALLOW_COPY_AND_ASSIGN(NullAddOn); }; // Create a new add-on from a pair of add-ons. template class AddOnPair { public: // Argument reference count incremented. AddOnPair(A1 *a1, A2 *a2) : a1_(a1), a2_(a2) { if (a1_) a1_->IncrRefCount(); if (a2_) a2_->IncrRefCount(); } ~AddOnPair() { if (a1_ && !a1_->DecrRefCount()) delete a1_; if (a2_ && !a2_->DecrRefCount()) delete a2_; } A1 *First() const { return a1_; } A2 *Second() const { return a2_; } static AddOnPair *Read(istream &istrm) { A1 *a1 = 0; bool have_addon1 = false; ReadType(istrm, &have_addon1); if (have_addon1) a1 = A1::Read(istrm); A2 *a2 = 0; bool have_addon2 = false; ReadType(istrm, &have_addon2); if (have_addon2) a2 = A2::Read(istrm); AddOnPair *a = new AddOnPair(a1, a2); if (a1) a1->DecrRefCount(); if (a2) a2->DecrRefCount(); return a; }; bool Write(ostream &ostrm) const { bool have_addon1 = a1_; WriteType(ostrm, have_addon1); if (have_addon1) a1_->Write(ostrm); bool have_addon2 = a2_; WriteType(ostrm, have_addon2); if (have_addon2) a2_->Write(ostrm); return true; } int RefCount() const { return ref_count_.count(); } int IncrRefCount() { return ref_count_.Incr(); } int DecrRefCount() { return ref_count_.Decr(); } private: A1 *a1_; A2 *a2_; RefCounter ref_count_; DISALLOW_COPY_AND_ASSIGN(AddOnPair); }; // Add to an Fst F a type T object. T must have a 'T* Read(istream &)', // a 'bool Write(ostream &)' method, and 'int RecCount(), 'int IncrRefCount()' // and 'int DecrRefCount()' methods (e.g. 'MatcherData' in matcher-fst.h). // The result is a new Fst implemenation with type name 'type'. template class AddOnImpl : public FstImpl { public: typedef typename F::Arc Arc; typedef typename Arc::Label Label; typedef typename Arc::Weight Weight; typedef typename Arc::StateId StateId; using FstImpl::SetType; using FstImpl::SetProperties; using FstImpl::WriteHeader; // If 't' is non-zero, its reference count is incremented. AddOnImpl(const F &fst, const string &type, T *t = 0) : fst_(fst), t_(t) { SetType(type); SetProperties(fst_.Properties(kFstProperties, false)); if (t_) t_->IncrRefCount(); } // If 't' is non-zero, its reference count is incremented. AddOnImpl(const Fst &fst, const string &type, T *t = 0) : fst_(fst), t_(t) { SetType(type); SetProperties(fst_.Properties(kFstProperties, false)); if (t_) t_->IncrRefCount(); } AddOnImpl(const AddOnImpl &impl) : fst_(impl.fst_), t_(impl.t_) { SetType(impl.Type()); SetProperties(fst_.Properties(kCopyProperties, false)); if (t_) t_->IncrRefCount(); } ~AddOnImpl() { if (t_ && !t_->DecrRefCount()) delete t_; } StateId Start() const { return fst_.Start(); } Weight Final(StateId s) const { return fst_.Final(s); } size_t NumArcs(StateId s) const { return fst_.NumArcs(s); } size_t NumInputEpsilons(StateId s) const { return fst_.NumInputEpsilons(s); } size_t NumOutputEpsilons(StateId s) const { return fst_.NumOutputEpsilons(s); } size_t NumStates() const { return fst_.NumStates(); } static AddOnImpl *Read(istream &strm, const FstReadOptions &opts) { FstReadOptions nopts(opts); FstHeader hdr; if (!nopts.header) { hdr.Read(strm, nopts.source); nopts.header = &hdr; } AddOnImpl *impl = new AddOnImpl(nopts.header->FstType()); if (!impl->ReadHeader(strm, nopts, kMinFileVersion, &hdr)) return 0; delete impl; // Used here only for checking types. int32 magic_number = 0; ReadType(strm, &magic_number); // Ensures this is an add-on Fst. if (magic_number != kAddOnMagicNumber) { LOG(ERROR) << "AddOnImpl::Read: Bad add-on header: " << nopts.source; return 0; } FstReadOptions fopts(opts); fopts.header = 0; // Contained header was written out. F *fst = F::Read(strm, fopts); if (!fst) return 0; T *t = 0; bool have_addon = false; ReadType(strm, &have_addon); if (have_addon) { // Read add-on object if present. t = T::Read(strm); if (!t) return 0; } impl = new AddOnImpl(*fst, nopts.header->FstType(), t); delete fst; if (t) t->DecrRefCount(); return impl; } bool Write(ostream &strm, const FstWriteOptions &opts) const { FstHeader hdr; FstWriteOptions nopts(opts); nopts.write_isymbols = false; // Let contained FST hold any symbols. nopts.write_osymbols = false; WriteHeader(strm, nopts, kFileVersion, &hdr); WriteType(strm, kAddOnMagicNumber); // Ensures this is an add-on Fst. FstWriteOptions fopts(opts); fopts.write_header = true; // Force writing contained header. if (!fst_.Write(strm, fopts)) return false; bool have_addon = t_; WriteType(strm, have_addon); if (have_addon) // Write add-on object if present. t_->Write(strm); return true; } void InitStateIterator(StateIteratorData *data) const { fst_.InitStateIterator(data); } void InitArcIterator(StateId s, ArcIteratorData *data) const { fst_.InitArcIterator(s, data); } F &GetFst() { return fst_; } const F &GetFst() const { return fst_; } T *GetAddOn() const { return t_; } // If 't' is non-zero, its reference count is incremented. void SetAddOn(T *t) { if (t == t_) return; if (t_ && !t_->DecrRefCount()) delete t_; t_ = t; if (t_) t_->IncrRefCount(); } private: explicit AddOnImpl(const string &type) : t_(0) { SetType(type); SetProperties(kExpanded); } // Current file format version static const int kFileVersion = 1; // Minimum file format version supported static const int kMinFileVersion = 1; F fst_; T *t_; void operator=(const AddOnImpl &fst); // Disallow }; template const int AddOnImpl::kFileVersion; template const int AddOnImpl::kMinFileVersion; } // namespace fst #endif // FST_LIB_ADD_ON_FST_H__