1 // See www.openfst.org for extensive documentation on this weighted
2 // finite-state transducer library.
4 // FST abstract base class definition, state and arc iterator interface, and
5 // suggested base implementation.
10 #include <sys/types.h>
21 #include <fst/compat.h>
22 #include <fst/types.h>
23 #include <fst/flags.h>
28 #include <fst/memory.h>
29 #include <fst/properties.h>
30 #include <fst/register.h>
31 #include <fst/symbol-table.h>
35 DECLARE_bool(fst_align);
39 bool IsFstHeader(std::istream &, const string &);
44 struct StateIteratorData;
47 struct ArcIteratorData;
52 struct FstReadOptions {
53 // FileReadMode(s) are advisory, there are many conditions than prevent a
54 // file from being mapped, READ mode will be selected in these cases with
55 // a warning indicating why it was chosen.
56 enum FileReadMode { READ, MAP };
58 string source; // Where you're reading from.
59 const FstHeader *header; // Pointer to FST header; if non-zero, use
60 // this info (don't read a stream header).
61 const SymbolTable *isymbols; // Pointer to input symbols; if non-zero, use
62 // this info (read and skip stream isymbols)
63 const SymbolTable *osymbols; // Pointer to output symbols; if non-zero, use
64 // this info (read and skip stream osymbols)
65 FileReadMode mode; // Read or map files (advisory, if possible)
66 bool read_isymbols; // Read isymbols, if any (default: true).
67 bool read_osymbols; // Read osymbols, if any (default: true).
69 explicit FstReadOptions(const string &source = "<unspecified>",
70 const FstHeader *header = nullptr,
71 const SymbolTable *isymbols = nullptr,
72 const SymbolTable *osymbols = nullptr);
74 explicit FstReadOptions(const string &source, const SymbolTable *isymbols,
75 const SymbolTable *osymbols = nullptr);
77 // Helper function to convert strings FileReadModes into their enum value.
78 static FileReadMode ReadMode(const string &mode);
80 // Outputs a debug string for the FstReadOptions object.
81 string DebugString() const;
84 struct FstWriteOptions {
85 string source; // Where you're writing to.
86 bool write_header; // Write the header?
87 bool write_isymbols; // Write input symbols?
88 bool write_osymbols; // Write output symbols?
89 bool align; // Write data aligned (may fail on pipes)?
90 bool stream_write; // Avoid seek operations in writing.
92 explicit FstWriteOptions(const string &source = "<unspecifed>",
93 bool write_header = true, bool write_isymbols = true,
94 bool write_osymbols = true,
95 bool align = FLAGS_fst_align,
96 bool stream_write = false)
98 write_header(write_header),
99 write_isymbols(write_isymbols),
100 write_osymbols(write_osymbols),
102 stream_write(stream_write) {}
107 // This is the recommended file header representation.
112 HAS_ISYMBOLS = 0x1, // Has input symbol table.
113 HAS_OSYMBOLS = 0x2, // Has output symbol table.
114 IS_ALIGNED = 0x4, // Memory-aligned (where appropriate).
117 FstHeader() : version_(0), flags_(0), properties_(0), start_(-1),
118 numstates_(0), numarcs_(0) {}
120 const string &FstType() const { return fsttype_; }
122 const string &ArcType() const { return arctype_; }
124 int32 Version() const { return version_; }
126 int32 GetFlags() const { return flags_; }
128 uint64 Properties() const { return properties_; }
130 int64 Start() const { return start_; }
132 int64 NumStates() const { return numstates_; }
134 int64 NumArcs() const { return numarcs_; }
136 void SetFstType(const string &type) { fsttype_ = type; }
138 void SetArcType(const string &type) { arctype_ = type; }
140 void SetVersion(int32 version) { version_ = version; }
142 void SetFlags(int32 flags) { flags_ = flags; }
144 void SetProperties(uint64 properties) { properties_ = properties; }
146 void SetStart(int64 start) { start_ = start; }
148 void SetNumStates(int64 numstates) { numstates_ = numstates; }
150 void SetNumArcs(int64 numarcs) { numarcs_ = numarcs; }
152 bool Read(std::istream &strm, const string &source,
153 bool rewind = false);
155 bool Write(std::ostream &strm, const string &source) const;
157 // Outputs a debug string for the FstHeader object.
158 string DebugString() const;
161 string fsttype_; // E.g. "vector".
162 string arctype_; // E.g. "standard".
163 int32 version_; // Type version number.
164 int32 flags_; // File format bits.
165 uint64 properties_; // FST property bits.
166 int64 start_; // Start state.
167 int64 numstates_; // # of states.
168 int64 numarcs_; // # of arcs.
171 // Specifies matcher action.
173 MATCH_INPUT = 1, // Match input label.
174 MATCH_OUTPUT = 2, // Match output label.
175 MATCH_BOTH = 3, // Match input or output label.
176 MATCH_NONE = 4, // Match nothing.
178 }; // Otherwise, match type unknown.
180 constexpr int kNoStateId = -1; // Not a valid state ID.
181 constexpr int kNoLabel = -1; // Not a valid label.
183 // A generic FST, templated on the arc definition, with common-demoninator
184 // methods (use StateIterator and ArcIterator to iterate over its states and
190 using StateId = typename Arc::StateId;
191 using Weight = typename Arc::Weight;
196 virtual StateId Start() const = 0;
198 // State's final weight.
199 virtual Weight Final(StateId) const = 0;
201 // State's arc count.
202 virtual size_t NumArcs(StateId) const = 0;
204 // State's input epsilon count.
205 virtual size_t NumInputEpsilons(StateId) const = 0;
207 // State's output epsilon count.
208 virtual size_t NumOutputEpsilons(StateId) const = 0;
210 // Property bits. If test = false, return stored properties bits for mask
211 // (some possibly unknown); if test = true, return property bits for mask
212 // (computing o.w. unknown).
213 virtual uint64 Properties(uint64 mask, bool test) const = 0;
216 virtual const string &Type() const = 0;
218 // Gets a copy of this Fst. The copying behaves as follows:
220 // (1) The copying is constant time if safe = false or if safe = true
221 // and is on an otherwise unaccessed FST.
223 // (2) If safe = true, the copy is thread-safe in that the original
224 // and copy can be safely accessed (but not necessarily mutated) by
225 // separate threads. For some FST types, 'Copy(true)' should only be
226 // called on an FST that has not otherwise been accessed. Behavior is
227 // otherwise undefined.
229 // (3) If a MutableFst is copied and then mutated, then the original is
230 // unmodified and vice versa (often by a copy-on-write on the initial
231 // mutation, which may not be constant time).
232 virtual Fst<Arc> *Copy(bool safe = false) const = 0;
234 // Reads an FST from an input stream; returns nullptr on error.
235 static Fst<Arc> *Read(std::istream &strm, const FstReadOptions &opts) {
236 FstReadOptions ropts(opts);
241 if (!hdr.Read(strm, opts.source)) return nullptr;
244 const auto &fst_type = hdr.FstType();
245 const auto reader = FstRegister<Arc>::GetRegister()->GetReader(fst_type);
247 LOG(ERROR) << "Fst::Read: Unknown FST type " << fst_type
248 << " (arc type = " << Arc::Type() << "): " << ropts.source;
251 return reader(strm, ropts);
254 // Reads an FST from a file; returns nullptr on error. An empty filename
255 // results in reading from standard input.
256 static Fst<Arc> *Read(const string &filename) {
257 if (!filename.empty()) {
258 std::ifstream strm(filename,
259 std::ios_base::in | std::ios_base::binary);
261 LOG(ERROR) << "Fst::Read: Can't open file: " << filename;
264 return Read(strm, FstReadOptions(filename));
266 return Read(std::cin, FstReadOptions("standard input"));
270 // Writes an FST to an output stream; returns false on error.
271 virtual bool Write(std::ostream &strm, const FstWriteOptions &opts) const {
272 LOG(ERROR) << "Fst::Write: No write stream method for " << Type()
277 // Writes an FST to a file; returns false on error; an empty filename
278 // results in writing to standard output.
279 virtual bool Write(const string &filename) const {
280 LOG(ERROR) << "Fst::Write: No write filename method for " << Type()
285 // Returns input label symbol table; return nullptr if not specified.
286 virtual const SymbolTable *InputSymbols() const = 0;
288 // Return output label symbol table; return nullptr if not specified.
289 virtual const SymbolTable *OutputSymbols() const = 0;
291 // For generic state iterator construction (not normally called directly by
292 // users). Does not copy the FST.
293 virtual void InitStateIterator(StateIteratorData<Arc> *data) const = 0;
295 // For generic arc iterator construction (not normally called directly by
296 // users). Does not copy the FST.
297 virtual void InitArcIterator(StateId s, ArcIteratorData<Arc> *data) const = 0;
299 // For generic matcher construction (not normally called directly by users).
300 // Does not copy the FST.
301 virtual MatcherBase<Arc> *InitMatcher(MatchType match_type) const;
304 bool WriteFile(const string &filename) const {
305 if (!filename.empty()) {
306 std::ofstream strm(filename,
307 std::ios_base::out | std::ios_base::binary);
309 LOG(ERROR) << "Fst::Write: Can't open file: " << filename;
312 bool val = Write(strm, FstWriteOptions(filename));
313 if (!val) LOG(ERROR) << "Fst::Write failed: " << filename;
316 return Write(std::cout, FstWriteOptions("standard output"));
321 // A useful alias when using StdArc.
322 using StdFst = Fst<StdArc>;
324 // State and arc iterator definitions.
326 // State iterator interface templated on the Arc definition; used for
327 // StateIterator specializations returned by the InitStateIterator FST method.
329 class StateIteratorBase {
331 using StateId = typename Arc::StateId;
333 virtual ~StateIteratorBase() {}
336 virtual bool Done() const = 0;
337 // Returns current state (when !Done()).
338 virtual StateId Value() const = 0;
339 // Advances to next state (when !Done()).
340 virtual void Next() = 0;
341 // Resets to initial condition.
342 virtual void Reset() = 0;
345 // StateIterator initialization data.
348 struct StateIteratorData {
349 using StateId = typename Arc::StateId;
351 // Specialized iterator if non-zero.
352 StateIteratorBase<Arc> *base;
353 // Otherwise, the total number of states.
356 StateIteratorData() : base(nullptr), nstates(0) {}
358 StateIteratorData(const StateIteratorData &) = delete;
359 StateIteratorData &operator=(const StateIteratorData &) = delete;
362 // Generic state iterator, templated on the FST definition (a wrapper
363 // around a pointer to a specific one). Here is a typical use:
365 // for (StateIterator<StdFst> siter(fst);
368 // StateId s = siter.Value();
371 // There is no copying of the FST.
373 class StateIterator {
375 using Arc = typename FST::Arc;
376 using StateId = typename Arc::StateId;
378 explicit StateIterator(const FST &fst) : s_(0) {
379 fst.InitStateIterator(&data_);
382 ~StateIterator() { delete data_.base; }
385 return data_.base ? data_.base->Done() : s_ >= data_.nstates;
388 StateId Value() const { return data_.base ? data_.base->Value() : s_; }
407 StateIteratorData<Arc> data_;
411 // Flags to control the behavior on an arc iterator.
412 static constexpr uint32 kArcILabelValue =
413 0x0001; // Value() gives valid ilabel.
414 static constexpr uint32 kArcOLabelValue = 0x0002; // " " " olabel.
415 static constexpr uint32 kArcWeightValue = 0x0004; // " " " weight.
416 static constexpr uint32 kArcNextStateValue =
417 0x0008; // " " " nextstate.
418 static constexpr uint32 kArcNoCache = 0x0010; // No need to cache arcs.
420 static constexpr uint32 kArcValueFlags =
421 kArcILabelValue | kArcOLabelValue | kArcWeightValue | kArcNextStateValue;
423 static constexpr uint32 kArcFlags = kArcValueFlags | kArcNoCache;
425 // Arc iterator interface, templated on the arc definition; used for arc
426 // iterator specializations that are returned by the InitArcIterator FST method.
428 class ArcIteratorBase {
430 using StateId = typename Arc::StateId;
432 virtual ~ArcIteratorBase() {}
435 virtual bool Done() const = 0;
436 // Returns current arc (when !Done()).
437 virtual const Arc &Value() const = 0;
438 // Advances to next arc (when !Done()).
439 virtual void Next() = 0;
440 // Returns current position.
441 virtual size_t Position() const = 0;
442 // Returns to initial condition.
443 virtual void Reset() = 0;
444 // Advances to arbitrary arc by position.
445 virtual void Seek(size_t) = 0;
446 // Returns current behavorial flags
447 virtual uint32 Flags() const = 0;
448 // Sets behavorial flags.
449 virtual void SetFlags(uint32, uint32) = 0;
452 // ArcIterator initialization data.
454 struct ArcIteratorData {
456 : base(nullptr), arcs(nullptr), narcs(0), ref_count(nullptr) {}
458 ArcIteratorData(const ArcIteratorData &) = delete;
460 ArcIteratorData &operator=(const ArcIteratorData &) = delete;
462 ArcIteratorBase<Arc> *base; // Specialized iterator if non-zero.
463 const Arc *arcs; // O.w. arcs pointer
464 size_t narcs; // ... and arc count.
465 int *ref_count; // ... and reference count if non-zero.
468 // Generic arc iterator, templated on the FST definition (a wrapper around a
469 // pointer to a specific one). Here is a typical use:
471 // for (ArcIterator<StdFst> aiter(fst, s);
474 // StdArc &arc = aiter.Value();
477 // There is no copying of the FST.
481 using Arc = typename FST::Arc;
482 using StateId = typename Arc::StateId;
484 ArcIterator(const FST &fst, StateId s) : i_(0) {
485 fst.InitArcIterator(s, &data_);
488 explicit ArcIterator(const ArcIteratorData<Arc> &data) : data_(data), i_(0) {
489 if (data_.ref_count) ++(*data_.ref_count);
495 } else if (data_.ref_count) {
496 --(*data_.ref_count);
501 return data_.base ? data_.base->Done() : i_ >= data_.narcs;
504 const Arc &Value() const {
505 return data_.base ? data_.base->Value() : data_.arcs[i_];
524 void Seek(size_t a) {
532 size_t Position() const { return data_.base ? data_.base->Position() : i_; }
534 uint32 Flags() const {
536 return data_.base->Flags();
538 return kArcValueFlags;
542 void SetFlags(uint32 flags, uint32 mask) {
543 if (data_.base) data_.base->SetFlags(flags, mask);
547 ArcIteratorData<Arc> data_;
553 // ArcIterator placement operator new and destroy function; new needs to be in
554 // the global namespace.
557 void *operator new(size_t size,
558 fst::MemoryPool<fst::ArcIterator<FST>> *pool) {
559 return pool->Allocate();
565 void Destroy(ArcIterator<FST> *aiter, MemoryPool<ArcIterator<FST>> *pool) {
567 aiter->~ArcIterator<FST>();
572 // Matcher definitions.
575 MatcherBase<Arc> *Fst<Arc>::InitMatcher(MatchType match_type) const {
576 return nullptr; // One should just use the default matcher.
579 // FST accessors, useful in high-performance applications.
583 // General case, requires non-abstract, 'final' methods. Use for inlining.
586 inline typename F::Arc::Weight Final(const F &fst, typename F::Arc::StateId s) {
587 return fst.F::Final(s);
591 inline ssize_t NumArcs(const F &fst, typename F::Arc::StateId s) {
592 return fst.F::NumArcs(s);
596 inline ssize_t NumInputEpsilons(const F &fst, typename F::Arc::StateId s) {
597 return fst.F::NumInputEpsilons(s);
601 inline ssize_t NumOutputEpsilons(const F &fst, typename F::Arc::StateId s) {
602 return fst.F::NumOutputEpsilons(s);
605 // Fst<Arc> case, abstract methods.
608 inline typename Arc::Weight Final(const Fst<Arc> &fst,
609 typename Arc::StateId s) {
614 inline size_t NumArcs(const Fst<Arc> &fst, typename Arc::StateId s) {
615 return fst.NumArcs(s);
619 inline size_t NumInputEpsilons(const Fst<Arc> &fst, typename Arc::StateId s) {
620 return fst.NumInputEpsilons(s);
624 inline size_t NumOutputEpsilons(const Fst<Arc> &fst, typename Arc::StateId s) {
625 return fst.NumOutputEpsilons(s);
628 // FST implementation base.
630 // This is the recommended FST implementation base class. It will handle
631 // reference counts, property bits, type information and symbols.
633 // Users are discouraged, but not prohibited, from subclassing this outside the
638 using StateId = typename Arc::StateId;
639 using Weight = typename Arc::Weight;
641 FstImpl() : properties_(0), type_("null") {}
643 FstImpl(const FstImpl<Arc> &impl)
644 : properties_(impl.properties_),
646 isymbols_(impl.isymbols_ ? impl.isymbols_->Copy() : nullptr),
647 osymbols_(impl.osymbols_ ? impl.osymbols_->Copy() : nullptr) {}
649 virtual ~FstImpl() {}
651 const string &Type() const { return type_; }
653 void SetType(const string &type) { type_ = type; }
655 virtual uint64 Properties() const { return properties_; }
657 virtual uint64 Properties(uint64 mask) const { return properties_ & mask; }
659 void SetProperties(uint64 props) {
660 properties_ &= kError; // kError can't be cleared.
661 properties_ |= props;
664 void SetProperties(uint64 props, uint64 mask) {
665 properties_ &= ~mask | kError; // kError can't be cleared.
666 properties_ |= props & mask;
669 // Allows (only) setting error bit on const FST implementations.
670 void SetProperties(uint64 props, uint64 mask) const {
671 if (mask != kError) {
672 FSTERROR() << "FstImpl::SetProperties() const: Can only set kError";
674 properties_ |= kError;
677 const SymbolTable *InputSymbols() const { return isymbols_.get(); }
679 const SymbolTable *OutputSymbols() const { return osymbols_.get(); }
681 SymbolTable *InputSymbols() { return isymbols_.get(); }
683 SymbolTable *OutputSymbols() { return osymbols_.get(); }
685 void SetInputSymbols(const SymbolTable *isyms) {
686 isymbols_.reset(isyms ? isyms->Copy() : nullptr);
689 void SetOutputSymbols(const SymbolTable *osyms) {
690 osymbols_.reset(osyms ? osyms->Copy() : nullptr);
693 // Reads header and symbols from input stream, initializes FST, and returns
694 // the header. If opts.header is non-null, skips reading and uses the option
695 // value instead. If opts.[io]symbols is non-null, reads in (if present), but
696 // uses the option value.
697 bool ReadHeader(std::istream &strm, const FstReadOptions &opts,
698 int min_version, FstHeader *hdr);
700 // Writes header and symbols to output stream. If opts.header is false, skips
701 // writing header. If opts.[io]symbols is false, skips writing those symbols.
702 // This method is needed for implementations that implement Write methods.
703 void WriteHeader(std::ostream &strm, const FstWriteOptions &opts,
704 int version, FstHeader *hdr) const {
705 if (opts.write_header) {
706 hdr->SetFstType(type_);
707 hdr->SetArcType(Arc::Type());
708 hdr->SetVersion(version);
709 hdr->SetProperties(properties_);
710 int32 file_flags = 0;
711 if (isymbols_ && opts.write_isymbols) {
712 file_flags |= FstHeader::HAS_ISYMBOLS;
714 if (osymbols_ && opts.write_osymbols) {
715 file_flags |= FstHeader::HAS_OSYMBOLS;
717 if (opts.align) file_flags |= FstHeader::IS_ALIGNED;
718 hdr->SetFlags(file_flags);
719 hdr->Write(strm, opts.source);
721 if (isymbols_ && opts.write_isymbols) isymbols_->Write(strm);
722 if (osymbols_ && opts.write_osymbols) osymbols_->Write(strm);
725 // Writes out header and symbols to output stream. If opts.header is false,
726 // skips writing header. If opts.[io]symbols is false, skips writing those
727 // symbols. `type` is the FST type being written. This method is used in the
728 // cross-type serialization methods Fst::WriteFst.
729 static void WriteFstHeader(const Fst<Arc> &fst, std::ostream &strm,
730 const FstWriteOptions &opts, int version,
731 const string &type, uint64 properties,
733 if (opts.write_header) {
734 hdr->SetFstType(type);
735 hdr->SetArcType(Arc::Type());
736 hdr->SetVersion(version);
737 hdr->SetProperties(properties);
738 int32 file_flags = 0;
739 if (fst.InputSymbols() && opts.write_isymbols) {
740 file_flags |= FstHeader::HAS_ISYMBOLS;
742 if (fst.OutputSymbols() && opts.write_osymbols) {
743 file_flags |= FstHeader::HAS_OSYMBOLS;
745 if (opts.align) file_flags |= FstHeader::IS_ALIGNED;
746 hdr->SetFlags(file_flags);
747 hdr->Write(strm, opts.source);
749 if (fst.InputSymbols() && opts.write_isymbols) {
750 fst.InputSymbols()->Write(strm);
752 if (fst.OutputSymbols() && opts.write_osymbols) {
753 fst.OutputSymbols()->Write(strm);
757 // In serialization routines where the header cannot be written until after
758 // the machine has been serialized, this routine can be called to seek to the
759 // beginning of the file an rewrite the header with updated fields. It
760 // repositions the file pointer back at the end of the file. Returns true on
761 // success, false on failure.
762 static bool UpdateFstHeader(const Fst<Arc> &fst, std::ostream &strm,
763 const FstWriteOptions &opts, int version,
764 const string &type, uint64 properties,
765 FstHeader *hdr, size_t header_offset) {
766 strm.seekp(header_offset);
768 LOG(ERROR) << "Fst::UpdateFstHeader: Write failed: " << opts.source;
771 WriteFstHeader(fst, strm, opts, version, type, properties, hdr);
773 LOG(ERROR) << "Fst::UpdateFstHeader: Write failed: " << opts.source;
776 strm.seekp(0, std::ios_base::end);
778 LOG(ERROR) << "Fst::UpdateFstHeader: Write failed: " << opts.source;
785 mutable uint64 properties_; // Property bits.
788 string type_; // Unique name of FST class.
789 std::unique_ptr<SymbolTable> isymbols_;
790 std::unique_ptr<SymbolTable> osymbols_;
794 bool FstImpl<Arc>::ReadHeader(std::istream &strm, const FstReadOptions &opts,
795 int min_version, FstHeader *hdr) {
798 } else if (!hdr->Read(strm, opts.source)) {
802 LOG(INFO) << "FstImpl::ReadHeader: source: " << opts.source
803 << ", fst_type: " << hdr->FstType()
804 << ", arc_type: " << Arc::Type()
805 << ", version: " << hdr->Version()
806 << ", flags: " << hdr->GetFlags();
808 if (hdr->FstType() != type_) {
809 LOG(ERROR) << "FstImpl::ReadHeader: FST not of type " << type_
810 << ": " << opts.source;
813 if (hdr->ArcType() != Arc::Type()) {
814 LOG(ERROR) << "FstImpl::ReadHeader: Arc not of type " << Arc::Type()
815 << ": " << opts.source;
818 if (hdr->Version() < min_version) {
819 LOG(ERROR) << "FstImpl::ReadHeader: Obsolete " << type_
820 << " FST version: " << opts.source;
823 properties_ = hdr->Properties();
824 if (hdr->GetFlags() & FstHeader::HAS_ISYMBOLS) {
825 isymbols_.reset(SymbolTable::Read(strm, opts.source));
827 // Deletes input symbol table.
828 if (!opts.read_isymbols) SetInputSymbols(nullptr);
829 if (hdr->GetFlags() & FstHeader::HAS_OSYMBOLS) {
830 osymbols_.reset(SymbolTable::Read(strm, opts.source));
832 // Deletes output symbol table.
833 if (!opts.read_osymbols) SetOutputSymbols(nullptr);
835 isymbols_.reset(opts.isymbols->Copy());
838 osymbols_.reset(opts.osymbols->Copy());
843 } // namespace internal
846 uint64 TestProperties(const Fst<Arc> &fst, uint64 mask, uint64 *known);
848 // This is a helper class template useful for attaching an FST interface to
849 // its implementation, handling reference counting.
850 template <class Impl, class FST = Fst<typename Impl::Arc>>
851 class ImplToFst : public FST {
853 using Arc = typename Impl::Arc;
854 using StateId = typename Arc::StateId;
855 using Weight = typename Arc::Weight;
856 using FST::operator=;
858 StateId Start() const override { return impl_->Start(); }
860 Weight Final(StateId s) const override { return impl_->Final(s); }
862 size_t NumArcs(StateId s) const override { return impl_->NumArcs(s); }
864 size_t NumInputEpsilons(StateId s) const override {
865 return impl_->NumInputEpsilons(s);
868 size_t NumOutputEpsilons(StateId s) const override {
869 return impl_->NumOutputEpsilons(s);
872 uint64 Properties(uint64 mask, bool test) const override {
874 uint64 knownprops, testprops = TestProperties(*this, mask, &knownprops);
875 impl_->SetProperties(testprops, knownprops);
876 return testprops & mask;
878 return impl_->Properties(mask);
882 const string &Type() const override { return impl_->Type(); }
884 const SymbolTable *InputSymbols() const override {
885 return impl_->InputSymbols();
888 const SymbolTable *OutputSymbols() const override {
889 return impl_->OutputSymbols();
893 explicit ImplToFst(std::shared_ptr<Impl> impl) : impl_(std::move(impl)) {}
895 // This constructor presumes there is a copy constructor for the
897 ImplToFst(const ImplToFst<Impl, FST> &fst, bool safe) {
899 impl_ = std::make_shared<Impl>(*(fst.impl_));
905 // Returns raw pointers to the shared object.
906 const Impl *GetImpl() const { return impl_.get(); }
908 Impl *GetMutableImpl() const { return impl_.get(); }
910 // Returns a ref-counted smart poiner to the implementation.
911 std::shared_ptr<Impl> GetSharedImpl() const { return impl_; }
913 bool Unique() const { return impl_.unique(); }
915 void SetImpl(std::shared_ptr<Impl> impl) { impl_ = impl; }
918 template <class IFST, class OFST>
919 friend void Cast(const IFST &ifst, OFST *ofst);
921 std::shared_ptr<Impl> impl_;
924 // Converts FSTs by casting their implementations, where this makes sense
925 // (which excludes implementations with weight-dependent virtual methods).
926 // Must be a friend of the FST classes involved (currently the concrete FSTs:
927 // ConstFst, CompactFst, and VectorFst). This can only be safely used for arc
928 // types that have identical storage characteristics. As with an FST
929 // copy constructor and Copy() method, this is a constant time operation
930 // (but subject to copy-on-write if it is a MutableFst and modified).
931 template <class IFST, class OFST>
932 void Cast(const IFST &ifst, OFST *ofst) {
933 using OImpl = typename OFST::Impl;
934 ofst->impl_ = std::shared_ptr<OImpl>(ifst.impl_,
935 reinterpret_cast<OImpl *>(ifst.impl_.get()));
938 // FST serialization.
941 string FstToString(const Fst<Arc> &fst,
942 const FstWriteOptions &options =
943 FstWriteOptions("FstToString")) {
944 std::ostringstream ostrm;
945 fst.Write(ostrm, options);
950 void FstToString(const Fst<Arc> &fst, string *result) {
951 *result = FstToString(fst);
955 void FstToString(const Fst<Arc> &fst, string *result,
956 const FstWriteOptions &options) {
957 *result = FstToString(fst, options);
961 Fst<Arc> *StringToFst(const string &s) {
962 std::istringstream istrm(s);
963 return Fst<Arc>::Read(istrm, FstReadOptions("StringToFst"));