// Copyright 2005-2024 Google LLC
|
|
//
|
|
// 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.
|
|
//
|
|
// See www.openfst.org for extensive documentation on this weighted
|
|
// finite-state transducer library.
|
|
//
|
|
// Simple concrete, mutable FST whose states and arcs are stored in STL vectors.
|
|
|
|
#ifndef FST_VECTOR_FST_H_
|
|
#define FST_VECTOR_FST_H_
|
|
|
|
#include <algorithm>
|
|
#include <atomic>
|
|
#include <cstddef>
|
|
#include <cstdint>
|
|
#include <ios>
|
|
#include <iosfwd>
|
|
#include <istream>
|
|
#include <memory>
|
|
#include <new>
|
|
#include <ostream>
|
|
#include <string>
|
|
#include <utility>
|
|
#include <vector>
|
|
|
|
#include <fst/log.h>
|
|
#include <fst/arc.h>
|
|
#include <fst/expanded-fst.h>
|
|
#include <fst/float-weight.h>
|
|
#include <fst/fst-decl.h> // For optional argument declarations
|
|
#include <fst/fst.h>
|
|
#include <fst/mutable-fst.h>
|
|
#include <fst/properties.h>
|
|
#include <fst/util.h>
|
|
#include <string_view>
|
|
|
|
namespace fst {
|
|
|
|
template <class A, class S>
|
|
class VectorFst;
|
|
|
|
template <class F, class G>
|
|
void Cast(const F &, G *);
|
|
|
|
// Arcs (of type A) implemented by an STL vector per state. M specifies Arc
|
|
// allocator (default declared in fst-decl.h).
|
|
template <class A, class M /* = std::allocator<A> */>
|
|
class VectorState {
|
|
public:
|
|
using Arc = A;
|
|
using StateId = typename Arc::StateId;
|
|
using Weight = typename Arc::Weight;
|
|
using ArcAllocator = M;
|
|
using StateAllocator = typename std::allocator_traits<
|
|
ArcAllocator>::template rebind_alloc<VectorState<Arc, M>>;
|
|
|
|
// Provide STL allocator for arcs.
|
|
explicit VectorState(const ArcAllocator &alloc) : arcs_(alloc) {}
|
|
|
|
VectorState(const VectorState<A, M> &state, const ArcAllocator &alloc)
|
|
: final_weight_(state.Final()),
|
|
niepsilons_(state.NumInputEpsilons()),
|
|
noepsilons_(state.NumOutputEpsilons()),
|
|
arcs_(state.arcs_.begin(), state.arcs_.end(), alloc) {}
|
|
|
|
void Reset() {
|
|
final_weight_ = Weight::Zero();
|
|
niepsilons_ = 0;
|
|
noepsilons_ = 0;
|
|
arcs_.clear();
|
|
}
|
|
|
|
Weight Final() const { return final_weight_; }
|
|
|
|
size_t NumInputEpsilons() const { return niepsilons_; }
|
|
|
|
size_t NumOutputEpsilons() const { return noepsilons_; }
|
|
|
|
size_t NumArcs() const { return arcs_.size(); }
|
|
|
|
const Arc &GetArc(size_t n) const { return arcs_[n]; }
|
|
|
|
const Arc *Arcs() const { return !arcs_.empty() ? &arcs_[0] : nullptr; }
|
|
|
|
Arc *MutableArcs() { return !arcs_.empty() ? &arcs_[0] : nullptr; }
|
|
|
|
void ReserveArcs(size_t n) { arcs_.reserve(n); }
|
|
|
|
void SetFinal(Weight weight) { final_weight_ = std::move(weight); }
|
|
|
|
void SetNumInputEpsilons(size_t n) { niepsilons_ = n; }
|
|
|
|
void SetNumOutputEpsilons(size_t n) { noepsilons_ = n; }
|
|
|
|
void AddArc(const Arc &arc) {
|
|
IncrementNumEpsilons(arc);
|
|
arcs_.push_back(arc);
|
|
}
|
|
|
|
void AddArc(Arc &&arc) {
|
|
IncrementNumEpsilons(arc);
|
|
arcs_.push_back(std::move(arc));
|
|
}
|
|
|
|
template <class... T>
|
|
void EmplaceArc(T &&...ctor_args) {
|
|
arcs_.emplace_back(std::forward<T>(ctor_args)...);
|
|
IncrementNumEpsilons(arcs_.back());
|
|
}
|
|
|
|
void SetArc(const Arc &arc, size_t n) {
|
|
if (arcs_[n].ilabel == 0) --niepsilons_;
|
|
if (arcs_[n].olabel == 0) --noepsilons_;
|
|
IncrementNumEpsilons(arc);
|
|
arcs_[n] = arc;
|
|
}
|
|
|
|
void DeleteArcs() {
|
|
niepsilons_ = 0;
|
|
noepsilons_ = 0;
|
|
arcs_.clear();
|
|
}
|
|
|
|
void DeleteArcs(size_t n) {
|
|
for (size_t i = 0; i < n; ++i) {
|
|
if (arcs_.back().ilabel == 0) --niepsilons_;
|
|
if (arcs_.back().olabel == 0) --noepsilons_;
|
|
arcs_.pop_back();
|
|
}
|
|
}
|
|
|
|
// For state class allocation.
|
|
void *operator new(size_t size, StateAllocator *alloc) {
|
|
return alloc->allocate(1);
|
|
}
|
|
|
|
// For state destruction and memory freeing.
|
|
static void Destroy(VectorState<A, M> *state, StateAllocator *alloc) {
|
|
if (state) {
|
|
state->~VectorState<A, M>();
|
|
alloc->deallocate(state, 1);
|
|
}
|
|
}
|
|
|
|
private:
|
|
// Update the number of epsilons as a result of having added an arc.
|
|
void IncrementNumEpsilons(const Arc &arc) {
|
|
if (arc.ilabel == 0) ++niepsilons_;
|
|
if (arc.olabel == 0) ++noepsilons_;
|
|
}
|
|
|
|
Weight final_weight_ = Weight::Zero(); // Final weight.
|
|
size_t niepsilons_ = 0; // # of input epsilons
|
|
size_t noepsilons_ = 0; // # of output epsilons
|
|
std::vector<A, ArcAllocator> arcs_; // Arc container.
|
|
};
|
|
|
|
namespace internal {
|
|
|
|
// States are implemented by STL vectors, templated on the
|
|
// State definition. This does not manage the Fst properties.
|
|
template <class S>
|
|
class VectorFstBaseImpl : public FstImpl<typename S::Arc> {
|
|
public:
|
|
using State = S;
|
|
using Arc = typename State::Arc;
|
|
using StateId = typename Arc::StateId;
|
|
using Weight = typename Arc::Weight;
|
|
|
|
VectorFstBaseImpl() = default;
|
|
|
|
~VectorFstBaseImpl() override {
|
|
for (auto *state : states_) State::Destroy(state, &state_alloc_);
|
|
}
|
|
|
|
// Copying is not permitted.
|
|
VectorFstBaseImpl(const VectorFstBaseImpl<S> &) = delete;
|
|
VectorFstBaseImpl &operator=(const VectorFstBaseImpl &) = delete;
|
|
|
|
// Moving is permitted.
|
|
VectorFstBaseImpl(VectorFstBaseImpl &&impl) noexcept
|
|
: FstImpl<typename S::Arc>(),
|
|
states_(std::move(impl.states_)),
|
|
start_(impl.start_) {
|
|
impl.states_.clear();
|
|
impl.start_ = kNoStateId;
|
|
}
|
|
|
|
VectorFstBaseImpl &operator=(VectorFstBaseImpl &&impl) noexcept {
|
|
for (auto *state : states_) {
|
|
State::Destroy(state, &state_alloc_);
|
|
}
|
|
states_.clear();
|
|
std::swap(states_, impl.states_);
|
|
start_ = impl.start_;
|
|
impl.start_ = kNoStateId;
|
|
return *this;
|
|
}
|
|
|
|
StateId Start() const { return start_; }
|
|
|
|
Weight Final(StateId state) const { return states_[state]->Final(); }
|
|
|
|
StateId NumStates() const { return states_.size(); }
|
|
|
|
size_t NumArcs(StateId state) const { return states_[state]->NumArcs(); }
|
|
|
|
size_t NumInputEpsilons(StateId state) const {
|
|
return GetState(state)->NumInputEpsilons();
|
|
}
|
|
|
|
size_t NumOutputEpsilons(StateId state) const {
|
|
return GetState(state)->NumOutputEpsilons();
|
|
}
|
|
|
|
void SetStart(StateId state) { start_ = state; }
|
|
|
|
void SetFinal(StateId state, Weight weight) {
|
|
states_[state]->SetFinal(std::move(weight));
|
|
}
|
|
|
|
StateId AddState(State *state) {
|
|
states_.push_back(state);
|
|
return states_.size() - 1;
|
|
}
|
|
|
|
StateId AddState() { return AddState(CreateState()); }
|
|
|
|
void AddStates(size_t n) {
|
|
const auto curr_num_states = NumStates();
|
|
states_.resize(n + curr_num_states);
|
|
std::generate(states_.begin() + curr_num_states, states_.end(),
|
|
[this] { return CreateState(); });
|
|
}
|
|
|
|
void AddArc(StateId state, const Arc &arc) { states_[state]->AddArc(arc); }
|
|
|
|
void AddArc(StateId state, Arc &&arc) {
|
|
states_[state]->AddArc(std::move(arc));
|
|
}
|
|
|
|
template <class... T>
|
|
void EmplaceArc(StateId state, T &&...ctor_args) {
|
|
states_[state]->EmplaceArc(std::forward<T>(ctor_args)...);
|
|
}
|
|
|
|
void DeleteStates(const std::vector<StateId> &dstates) {
|
|
std::vector<StateId> newid(states_.size(), 0);
|
|
for (size_t i = 0; i < dstates.size(); ++i) newid[dstates[i]] = kNoStateId;
|
|
StateId nstates = 0;
|
|
for (StateId state = 0; state < states_.size(); ++state) {
|
|
if (newid[state] != kNoStateId) {
|
|
newid[state] = nstates;
|
|
if (state != nstates) states_[nstates] = states_[state];
|
|
++nstates;
|
|
} else {
|
|
State::Destroy(states_[state], &state_alloc_);
|
|
}
|
|
}
|
|
states_.resize(nstates);
|
|
for (StateId state = 0; state < states_.size(); ++state) {
|
|
auto *arcs = states_[state]->MutableArcs();
|
|
size_t narcs = 0;
|
|
auto nieps = states_[state]->NumInputEpsilons();
|
|
auto noeps = states_[state]->NumOutputEpsilons();
|
|
for (size_t i = 0; i < states_[state]->NumArcs(); ++i) {
|
|
const auto t = newid[arcs[i].nextstate];
|
|
if (t != kNoStateId) {
|
|
arcs[i].nextstate = t;
|
|
if (i != narcs) arcs[narcs] = arcs[i];
|
|
++narcs;
|
|
} else {
|
|
if (arcs[i].ilabel == 0) --nieps;
|
|
if (arcs[i].olabel == 0) --noeps;
|
|
}
|
|
}
|
|
states_[state]->DeleteArcs(states_[state]->NumArcs() - narcs);
|
|
states_[state]->SetNumInputEpsilons(nieps);
|
|
states_[state]->SetNumOutputEpsilons(noeps);
|
|
}
|
|
if (Start() != kNoStateId) SetStart(newid[Start()]);
|
|
}
|
|
|
|
void DeleteStates() {
|
|
for (size_t state = 0; state < states_.size(); ++state) {
|
|
State::Destroy(states_[state], &state_alloc_);
|
|
}
|
|
states_.clear();
|
|
SetStart(kNoStateId);
|
|
}
|
|
|
|
void DeleteArcs(StateId state, size_t n) { states_[state]->DeleteArcs(n); }
|
|
|
|
void DeleteArcs(StateId state) { states_[state]->DeleteArcs(); }
|
|
|
|
State *GetState(StateId state) { return states_[state]; }
|
|
|
|
const State *GetState(StateId state) const { return states_[state]; }
|
|
|
|
void SetState(StateId state, State *vstate) { states_[state] = vstate; }
|
|
|
|
void ReserveStates(size_t n) { states_.reserve(n); }
|
|
|
|
void ReserveArcs(StateId state, size_t n) { states_[state]->ReserveArcs(n); }
|
|
|
|
// Provide information needed for generic state iterator.
|
|
void InitStateIterator(StateIteratorData<Arc> *data) const {
|
|
data->base = nullptr;
|
|
data->nstates = states_.size();
|
|
}
|
|
|
|
// Provide information needed for generic arc iterator.
|
|
void InitArcIterator(StateId state, ArcIteratorData<Arc> *data) const {
|
|
data->base = nullptr;
|
|
data->narcs = states_[state]->NumArcs();
|
|
data->arcs = states_[state]->Arcs();
|
|
data->ref_count = nullptr;
|
|
}
|
|
|
|
private:
|
|
State *CreateState() { return new (&state_alloc_) State(arc_alloc_); }
|
|
|
|
std::vector<State *> states_;
|
|
StateId start_ = kNoStateId;
|
|
typename State::StateAllocator state_alloc_;
|
|
typename State::ArcAllocator arc_alloc_;
|
|
};
|
|
|
|
// This is a VectorFstBaseImpl container that holds VectorStates and manages FST
|
|
// properties.
|
|
template <class S>
|
|
class VectorFstImpl : public VectorFstBaseImpl<S> {
|
|
public:
|
|
using State = S;
|
|
using Arc = typename State::Arc;
|
|
using Label = typename Arc::Label;
|
|
using StateId = typename Arc::StateId;
|
|
using Weight = typename Arc::Weight;
|
|
|
|
using FstImpl<Arc>::SetInputSymbols;
|
|
using FstImpl<Arc>::SetOutputSymbols;
|
|
using FstImpl<Arc>::SetType;
|
|
using FstImpl<Arc>::SetProperties;
|
|
using FstImpl<Arc>::Properties;
|
|
|
|
using VectorFstBaseImpl<S>::Start;
|
|
using VectorFstBaseImpl<S>::NumStates;
|
|
using VectorFstBaseImpl<S>::GetState;
|
|
using VectorFstBaseImpl<S>::ReserveArcs;
|
|
|
|
friend class MutableArcIterator<VectorFst<Arc, S>>;
|
|
|
|
using BaseImpl = VectorFstBaseImpl<S>;
|
|
|
|
VectorFstImpl() {
|
|
SetType("vector");
|
|
SetProperties(kNullProperties | kStaticProperties);
|
|
}
|
|
|
|
explicit VectorFstImpl(const Fst<Arc> &fst);
|
|
|
|
static VectorFstImpl *Read(std::istream &strm, const FstReadOptions &opts);
|
|
|
|
void SetStart(StateId state) {
|
|
BaseImpl::SetStart(state);
|
|
SetProperties(SetStartProperties(Properties()));
|
|
}
|
|
|
|
void SetFinal(StateId state, Weight weight) {
|
|
const auto old_weight = BaseImpl::Final(state);
|
|
const auto properties =
|
|
SetFinalProperties(Properties(), old_weight, weight);
|
|
BaseImpl::SetFinal(state, std::move(weight));
|
|
SetProperties(properties);
|
|
}
|
|
|
|
StateId AddState() {
|
|
const auto state = BaseImpl::AddState();
|
|
SetProperties(AddStateProperties(Properties()));
|
|
return state;
|
|
}
|
|
|
|
void AddStates(size_t n) {
|
|
BaseImpl::AddStates(n);
|
|
SetProperties(AddStateProperties(Properties()));
|
|
}
|
|
|
|
void AddArc(StateId state, const Arc &arc) {
|
|
BaseImpl::AddArc(state, arc);
|
|
UpdatePropertiesAfterAddArc(state);
|
|
}
|
|
|
|
void AddArc(StateId state, Arc &&arc) {
|
|
BaseImpl::AddArc(state, std::move(arc));
|
|
UpdatePropertiesAfterAddArc(state);
|
|
}
|
|
|
|
template <class... T>
|
|
void EmplaceArc(StateId state, T &&...ctor_args) {
|
|
BaseImpl::EmplaceArc(state, std::forward<T>(ctor_args)...);
|
|
UpdatePropertiesAfterAddArc(state);
|
|
}
|
|
|
|
void DeleteStates(const std::vector<StateId> &dstates) {
|
|
BaseImpl::DeleteStates(dstates);
|
|
SetProperties(DeleteStatesProperties(Properties()));
|
|
}
|
|
|
|
void DeleteStates() {
|
|
BaseImpl::DeleteStates();
|
|
SetProperties(DeleteAllStatesProperties(Properties(), kStaticProperties));
|
|
}
|
|
|
|
void DeleteArcs(StateId state, size_t n) {
|
|
BaseImpl::DeleteArcs(state, n);
|
|
SetProperties(DeleteArcsProperties(Properties()));
|
|
}
|
|
|
|
void DeleteArcs(StateId state) {
|
|
BaseImpl::DeleteArcs(state);
|
|
SetProperties(DeleteArcsProperties(Properties()));
|
|
}
|
|
|
|
// Properties always true of this FST class
|
|
static constexpr uint64_t kStaticProperties = kExpanded | kMutable;
|
|
|
|
private:
|
|
void UpdatePropertiesAfterAddArc(StateId state) {
|
|
auto *vstate = GetState(state);
|
|
const size_t num_arcs{vstate->NumArcs()};
|
|
if (num_arcs) {
|
|
const auto &arc = vstate->GetArc(num_arcs - 1);
|
|
const auto *parc =
|
|
(num_arcs < 2) ? nullptr : &(vstate->GetArc(num_arcs - 2));
|
|
SetProperties(AddArcProperties(Properties(), state, arc, parc));
|
|
}
|
|
}
|
|
|
|
// Minimum file format version supported.
|
|
static constexpr int kMinFileVersion = 2;
|
|
};
|
|
|
|
template <class S>
|
|
VectorFstImpl<S>::VectorFstImpl(const Fst<Arc> &fst) {
|
|
SetType("vector");
|
|
SetInputSymbols(fst.InputSymbols());
|
|
SetOutputSymbols(fst.OutputSymbols());
|
|
BaseImpl::SetStart(fst.Start());
|
|
if (std::optional<StateId> num_states = fst.NumStatesIfKnown()) {
|
|
BaseImpl::ReserveStates(*num_states);
|
|
}
|
|
for (StateIterator<Fst<Arc>> siter(fst); !siter.Done(); siter.Next()) {
|
|
const auto state = siter.Value();
|
|
BaseImpl::AddState();
|
|
BaseImpl::SetFinal(state, fst.Final(state));
|
|
ReserveArcs(state, fst.NumArcs(state));
|
|
for (ArcIterator<Fst<Arc>> aiter(fst, state); !aiter.Done(); aiter.Next()) {
|
|
const auto &arc = aiter.Value();
|
|
BaseImpl::AddArc(state, arc);
|
|
}
|
|
}
|
|
SetProperties(fst.Properties(kCopyProperties, false) | kStaticProperties);
|
|
}
|
|
|
|
template <class S>
|
|
VectorFstImpl<S> *VectorFstImpl<S>::Read(std::istream &strm,
|
|
const FstReadOptions &opts) {
|
|
auto impl = std::make_unique<VectorFstImpl>();
|
|
FstHeader hdr;
|
|
if (!impl->ReadHeader(strm, opts, kMinFileVersion, &hdr)) return nullptr;
|
|
impl->BaseImpl::SetStart(hdr.Start());
|
|
if (hdr.NumStates() != kNoStateId) impl->ReserveStates(hdr.NumStates());
|
|
StateId state = 0;
|
|
for (; hdr.NumStates() == kNoStateId || state < hdr.NumStates(); ++state) {
|
|
Weight weight;
|
|
if (!weight.Read(strm)) break;
|
|
impl->BaseImpl::AddState();
|
|
auto *vstate = impl->GetState(state);
|
|
vstate->SetFinal(weight);
|
|
int64_t narcs;
|
|
ReadType(strm, &narcs);
|
|
if (!strm) {
|
|
LOG(ERROR) << "VectorFst::Read: Read failed: " << opts.source;
|
|
return nullptr;
|
|
}
|
|
impl->ReserveArcs(state, narcs);
|
|
for (int64_t i = 0; i < narcs; ++i) {
|
|
Arc arc;
|
|
ReadType(strm, &arc.ilabel);
|
|
ReadType(strm, &arc.olabel);
|
|
arc.weight.Read(strm);
|
|
ReadType(strm, &arc.nextstate);
|
|
if (!strm) {
|
|
LOG(ERROR) << "VectorFst::Read: Read failed: " << opts.source;
|
|
return nullptr;
|
|
}
|
|
impl->BaseImpl::AddArc(state, std::move(arc));
|
|
}
|
|
}
|
|
if (hdr.NumStates() != kNoStateId && state != hdr.NumStates()) {
|
|
LOG(ERROR) << "VectorFst::Read: Unexpected end of file: " << opts.source;
|
|
return nullptr;
|
|
}
|
|
return impl.release();
|
|
}
|
|
|
|
} // namespace internal
|
|
|
|
// Simple concrete, mutable FST. This class attaches interface to implementation
|
|
// and handles reference counting, delegating most methods to ImplToMutableFst.
|
|
// Also supports ReserveStates and ReserveArcs methods (cf. STL vector methods).
|
|
// The second optional template argument gives the State definition.
|
|
//
|
|
// VectorFst is thread-compatible.
|
|
template <class A, class S /* = VectorState<A> */>
|
|
class VectorFst : public ImplToMutableFst<internal::VectorFstImpl<S>> {
|
|
public:
|
|
using Arc = A;
|
|
using StateId = typename Arc::StateId;
|
|
|
|
using State = S;
|
|
using Impl = internal::VectorFstImpl<State>;
|
|
|
|
friend class StateIterator<VectorFst<Arc, State>>;
|
|
friend class ArcIterator<VectorFst<Arc, State>>;
|
|
friend class MutableArcIterator<VectorFst<A, S>>;
|
|
|
|
template <class F, class G>
|
|
friend void Cast(const F &, G *);
|
|
|
|
VectorFst() : ImplToMutableFst<Impl>(std::make_shared<Impl>()) {}
|
|
|
|
explicit VectorFst(const Fst<Arc> &fst)
|
|
: ImplToMutableFst<Impl>(std::make_shared<Impl>(fst)) {}
|
|
|
|
VectorFst(const VectorFst &fst, bool unused_safe = false)
|
|
: ImplToMutableFst<Impl>(fst.GetSharedImpl()) {}
|
|
|
|
VectorFst(VectorFst &&) noexcept;
|
|
|
|
// Get a copy of this VectorFst. See Fst<>::Copy() for further doc.
|
|
VectorFst *Copy(bool safe = false) const override {
|
|
return new VectorFst(*this, safe);
|
|
}
|
|
|
|
VectorFst &operator=(const VectorFst &) = default;
|
|
|
|
VectorFst &operator=(VectorFst &&) noexcept;
|
|
|
|
VectorFst &operator=(const Fst<Arc> &fst) override {
|
|
if (this != &fst) SetImpl(std::make_shared<Impl>(fst));
|
|
return *this;
|
|
}
|
|
|
|
template <class... T>
|
|
void EmplaceArc(StateId state, T &&...ctor_args) {
|
|
MutateCheck();
|
|
GetMutableImpl()->EmplaceArc(state, std::forward<T>(ctor_args)...);
|
|
}
|
|
|
|
// Reads a VectorFst from an input stream, returning nullptr on error.
|
|
static VectorFst *Read(std::istream &strm, const FstReadOptions &opts) {
|
|
auto *impl = Impl::Read(strm, opts);
|
|
return impl ? new VectorFst(std::shared_ptr<Impl>(impl)) : nullptr;
|
|
}
|
|
|
|
// Read a VectorFst from a file, returning nullptr on error; empty source
|
|
// reads from standard input.
|
|
static VectorFst *Read(std::string_view source) {
|
|
auto *impl = ImplToExpandedFst<Impl, MutableFst<Arc>>::Read(source);
|
|
return impl ? new VectorFst(std::shared_ptr<Impl>(impl)) : nullptr;
|
|
}
|
|
|
|
bool Write(std::ostream &strm, const FstWriteOptions &opts) const override {
|
|
return WriteFst(*this, strm, opts);
|
|
}
|
|
|
|
bool Write(const std::string &source) const override {
|
|
return Fst<Arc>::WriteFile(source);
|
|
}
|
|
|
|
template <class FST>
|
|
static bool WriteFst(const FST &fst, std::ostream &strm,
|
|
const FstWriteOptions &opts);
|
|
|
|
void InitStateIterator(StateIteratorData<Arc> *data) const override {
|
|
GetImpl()->InitStateIterator(data);
|
|
}
|
|
|
|
void InitArcIterator(StateId s, ArcIteratorData<Arc> *data) const override {
|
|
GetImpl()->InitArcIterator(s, data);
|
|
}
|
|
|
|
inline void InitMutableArcIterator(StateId s,
|
|
MutableArcIteratorData<Arc> *) override;
|
|
|
|
using ImplToMutableFst<Impl, MutableFst<Arc>>::ReserveArcs;
|
|
using ImplToMutableFst<Impl, MutableFst<Arc>>::ReserveStates;
|
|
|
|
private:
|
|
using ImplToMutableFst<Impl, MutableFst<Arc>>::GetImpl;
|
|
using ImplToMutableFst<Impl, MutableFst<Arc>>::GetMutableImpl;
|
|
using ImplToMutableFst<Impl, MutableFst<Arc>>::MutateCheck;
|
|
using ImplToMutableFst<Impl, MutableFst<Arc>>::SetImpl;
|
|
|
|
explicit VectorFst(std::shared_ptr<Impl> impl)
|
|
: ImplToMutableFst<Impl>(impl) {}
|
|
};
|
|
|
|
template <class Arc, class State>
|
|
inline VectorFst<Arc, State>::VectorFst(VectorFst &&fst) noexcept = default;
|
|
|
|
template <class Arc, class State>
|
|
inline VectorFst<Arc, State> &VectorFst<Arc, State>::operator=(
|
|
VectorFst &&fst) noexcept = default;
|
|
|
|
// Writes FST to file in Vector format, potentially with a pass over the machine
|
|
// before writing to compute number of states.
|
|
template <class Arc, class State>
|
|
template <class FST>
|
|
bool VectorFst<Arc, State>::WriteFst(const FST &fst, std::ostream &strm,
|
|
const FstWriteOptions &opts) {
|
|
static constexpr int file_version = 2;
|
|
bool update_header = true;
|
|
FstHeader hdr;
|
|
hdr.SetStart(fst.Start());
|
|
hdr.SetNumStates(kNoStateId);
|
|
std::streampos start_offset = 0;
|
|
if (fst.Properties(kExpanded, false) || opts.stream_write ||
|
|
(start_offset = strm.tellp()) != -1) {
|
|
hdr.SetNumStates(CountStates(fst));
|
|
update_header = false;
|
|
}
|
|
const auto properties =
|
|
fst.Properties(kCopyProperties, false) | Impl::kStaticProperties;
|
|
internal::FstImpl<Arc>::WriteFstHeader(fst, strm, opts, file_version,
|
|
"vector", properties, &hdr);
|
|
StateId num_states = 0;
|
|
for (StateIterator<FST> siter(fst); !siter.Done(); siter.Next()) {
|
|
const auto s = siter.Value();
|
|
fst.Final(s).Write(strm);
|
|
const int64_t narcs = fst.NumArcs(s);
|
|
WriteType(strm, narcs);
|
|
for (ArcIterator<FST> aiter(fst, s); !aiter.Done(); aiter.Next()) {
|
|
const auto &arc = aiter.Value();
|
|
WriteType(strm, arc.ilabel);
|
|
WriteType(strm, arc.olabel);
|
|
arc.weight.Write(strm);
|
|
WriteType(strm, arc.nextstate);
|
|
}
|
|
++num_states;
|
|
}
|
|
strm.flush();
|
|
if (!strm) {
|
|
LOG(ERROR) << "VectorFst::Write: Write failed: " << opts.source;
|
|
return false;
|
|
}
|
|
if (update_header) {
|
|
hdr.SetNumStates(num_states);
|
|
return internal::FstImpl<Arc>::UpdateFstHeader(
|
|
fst, strm, opts, file_version, "vector", properties, &hdr,
|
|
start_offset);
|
|
} else {
|
|
if (num_states != hdr.NumStates()) {
|
|
LOG(ERROR) << "Inconsistent number of states observed during write";
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// Specialization for VectorFst; see generic version in fst.h for sample usage
|
|
// (but use the VectorFst type instead). This version should inline.
|
|
template <class Arc, class State>
|
|
class StateIterator<VectorFst<Arc, State>> {
|
|
public:
|
|
using StateId = typename Arc::StateId;
|
|
|
|
explicit StateIterator(const VectorFst<Arc, State> &fst)
|
|
: nstates_(fst.GetImpl()->NumStates()) {}
|
|
|
|
bool Done() const { return s_ >= nstates_; }
|
|
|
|
StateId Value() const { return s_; }
|
|
|
|
void Next() { ++s_; }
|
|
|
|
void Reset() { s_ = 0; }
|
|
|
|
private:
|
|
const StateId nstates_;
|
|
StateId s_ = 0;
|
|
};
|
|
|
|
// Specialization for VectorFst; see generic version in fst.h for sample usage
|
|
// (but use the VectorFst type instead). This version should inline.
|
|
template <class Arc, class State>
|
|
class ArcIterator<VectorFst<Arc, State>> {
|
|
public:
|
|
using StateId = typename Arc::StateId;
|
|
|
|
ArcIterator(const VectorFst<Arc, State> &fst, StateId s)
|
|
: arcs_(fst.GetImpl()->GetState(s)->Arcs()),
|
|
narcs_(fst.GetImpl()->GetState(s)->NumArcs()) {}
|
|
|
|
bool Done() const { return i_ >= narcs_; }
|
|
|
|
const Arc &Value() const { return arcs_[i_]; }
|
|
|
|
void Next() { ++i_; }
|
|
|
|
void Reset() { i_ = 0; }
|
|
|
|
void Seek(size_t a) { i_ = a; }
|
|
|
|
size_t Position() const { return i_; }
|
|
|
|
constexpr uint8_t Flags() const { return kArcValueFlags; }
|
|
|
|
void SetFlags(uint8_t, uint8_t) {}
|
|
|
|
private:
|
|
const Arc *arcs_;
|
|
size_t narcs_;
|
|
size_t i_ = 0;
|
|
};
|
|
|
|
// Specialization for VectorFst; see generic version in mutable-fst.h for sample
|
|
// usage (but use the VectorFst type instead). This version should inline.
|
|
template <class Arc, class State>
|
|
class MutableArcIterator<VectorFst<Arc, State>>
|
|
: public MutableArcIteratorBase<Arc> {
|
|
public:
|
|
using StateId = typename Arc::StateId;
|
|
using Weight = typename Arc::Weight;
|
|
|
|
MutableArcIterator(VectorFst<Arc, State> *fst, StateId s) {
|
|
fst->MutateCheck();
|
|
state_ = fst->GetMutableImpl()->GetState(s);
|
|
properties_ = &fst->GetImpl()->properties_;
|
|
}
|
|
|
|
bool Done() const final { return i_ >= state_->NumArcs(); }
|
|
|
|
const Arc &Value() const final { return state_->GetArc(i_); }
|
|
|
|
void Next() final { ++i_; }
|
|
|
|
size_t Position() const final { return i_; }
|
|
|
|
void Reset() final { i_ = 0; }
|
|
|
|
void Seek(size_t a) final { i_ = a; }
|
|
|
|
void SetValue(const Arc &arc) final {
|
|
const auto &oarc = state_->GetArc(i_);
|
|
uint64_t properties = properties_->load(std::memory_order_relaxed);
|
|
if (oarc.ilabel != oarc.olabel) properties &= ~kNotAcceptor;
|
|
if (oarc.ilabel == 0) {
|
|
properties &= ~kIEpsilons;
|
|
if (oarc.olabel == 0) properties &= ~kEpsilons;
|
|
}
|
|
if (oarc.olabel == 0) properties &= ~kOEpsilons;
|
|
if (oarc.weight != Weight::Zero() && oarc.weight != Weight::One()) {
|
|
properties &= ~kWeighted;
|
|
}
|
|
state_->SetArc(arc, i_);
|
|
if (arc.ilabel != arc.olabel) {
|
|
properties |= kNotAcceptor;
|
|
properties &= ~kAcceptor;
|
|
}
|
|
if (arc.ilabel == 0) {
|
|
properties |= kIEpsilons;
|
|
properties &= ~kNoIEpsilons;
|
|
if (arc.olabel == 0) {
|
|
properties |= kEpsilons;
|
|
properties &= ~kNoEpsilons;
|
|
}
|
|
}
|
|
if (arc.olabel == 0) {
|
|
properties |= kOEpsilons;
|
|
properties &= ~kNoOEpsilons;
|
|
}
|
|
if (arc.weight != Weight::Zero() && arc.weight != Weight::One()) {
|
|
properties |= kWeighted;
|
|
properties &= ~kUnweighted;
|
|
}
|
|
properties &= kSetArcProperties | kAcceptor | kNotAcceptor | kEpsilons |
|
|
kNoEpsilons | kIEpsilons | kNoIEpsilons | kOEpsilons |
|
|
kNoOEpsilons | kWeighted | kUnweighted;
|
|
properties_->store(properties, std::memory_order_relaxed);
|
|
}
|
|
|
|
uint8_t Flags() const final { return kArcValueFlags; }
|
|
|
|
void SetFlags(uint8_t, uint8_t) final {}
|
|
|
|
private:
|
|
State *state_;
|
|
std::atomic<uint64_t> *properties_;
|
|
size_t i_ = 0;
|
|
};
|
|
|
|
// Provides information needed for the generic mutable arc iterator.
|
|
template <class Arc, class State>
|
|
inline void VectorFst<Arc, State>::InitMutableArcIterator(
|
|
StateId s, MutableArcIteratorData<Arc> *data) {
|
|
data->base =
|
|
std::make_unique<MutableArcIterator<VectorFst<Arc, State>>>(this, s);
|
|
}
|
|
|
|
// A useful alias when using StdArc.
|
|
using StdVectorFst = VectorFst<StdArc>;
|
|
|
|
} // namespace fst
|
|
|
|
#endif // FST_VECTOR_FST_H_
|