#ifndef FF_FSA_DYNAMIC_H #define FF_FSA_DYNAMIC_H struct SentenceMetadata; #include "ff_fsa_data.h" #include "hg.h" // can't forward declare nested Hypergraph::Edge class #include // the type-erased interface //FIXME: diamond inheritance problem. make a copy of the fixed data? or else make the dynamic version not wrap but rather be templated CRTP base (yuck) struct FsaFeatureFunction : public FsaFeatureFunctionData { static const bool simple_phrase_score=false; virtual int markov_order() const = 0; // see ff_fsa.h - FsaFeatureFunctionBase gives you reasonable impls of these if you override just ScanAccum virtual void ScanAccum(SentenceMetadata const& smeta,Hypergraph::Edge const& edge, WordID w,void const* state,void *next_state,Accum *a) const = 0; virtual void ScanPhraseAccum(SentenceMetadata const& smeta,Hypergraph::Edge const & edge, WordID const* i, WordID const* end, void const* state,void *next_state,Accum *accum) const = 0; virtual void ScanPhraseAccumOnly(SentenceMetadata const& smeta,Hypergraph::Edge const& edge, WordID const* i, WordID const* end, void const* state,Accum *accum) const = 0; virtual void *ScanPhraseAccumBounce(SentenceMetadata const& smeta,Hypergraph::Edge const& edge,WordID const* i, WordID const* end,void *cs,void *ns,Accum *accum) const = 0; virtual int early_score_words(SentenceMetadata const& smeta,Hypergraph::Edge const& edge,WordID const* i, WordID const* end,Accum *accum) const { return 0; } // called after constructor, before use virtual void Init() = 0; virtual std::string usage_v(bool param,bool verbose) const { return FeatureFunction::usage_helper("unnamed_dynamic_fsa_feature","","",param,verbose); } virtual void init_name_debug(std::string const& n,bool debug) { FsaFeatureFunctionData::init_name_debug(n,debug); } virtual void print_state(std::ostream &o,void const*state) const { FsaFeatureFunctionData::print_state(o,state); } virtual std::string describe() const { return "[FSA unnamed_dynamic_fsa_feature]"; } //end_phrase() virtual ~FsaFeatureFunction() {} // no need to override: std::string describe_state(void const* state) const { std::ostringstream o; print_state(o,state); return o.str(); } }; // conforming to above interface, type erases FsaImpl // you might be wondering: why do this? answer: it's cool, and it means that the bottom-up ff over ff_fsa wrapper doesn't go through multiple layers of dynamic dispatch // usage: typedef FsaFeatureFunctionDynamic MyFsaDyn; template struct FsaFeatureFunctionDynamic : public FsaFeatureFunction { static const bool simple_phrase_score=Impl::simple_phrase_score; Impl& d() { return impl;//static_cast(*this); } Impl const& d() const { return impl; //static_cast(*this); } int markov_order() const { return d().markov_order(); } std::string describe() const { return d().describe(); } virtual void ScanAccum(SentenceMetadata const& smeta,Hypergraph::Edge const& edge, WordID w,void const* state,void *next_state,Accum *a) const { return d().ScanAccum(smeta,edge,w,state,next_state,a); } virtual void ScanPhraseAccum(SentenceMetadata const& smeta,Hypergraph::Edge const & edge, WordID const* i, WordID const* end, void const* state,void *next_state,Accum *a) const { return d().ScanPhraseAccum(smeta,edge,i,end,state,next_state,a); } virtual void ScanPhraseAccumOnly(SentenceMetadata const& smeta,Hypergraph::Edge const& edge, WordID const* i, WordID const* end, void const* state,Accum *a) const { return d().ScanPhraseAccumOnly(smeta,edge,i,end,state,a); } virtual void *ScanPhraseAccumBounce(SentenceMetadata const& smeta,Hypergraph::Edge const& edge,WordID const* i, WordID const* end,void *cs,void *ns,Accum *a) const { return d().ScanPhraseAccumBounce(smeta,edge,i,end,cs,ns,a); } virtual int early_score_words(SentenceMetadata const& smeta,Hypergraph::Edge const& edge,WordID const* i, WordID const* end,Accum *accum) const { return d().early_score_words(smeta,edge,i,end,accum); } static std::string usage(bool param,bool verbose) { return Impl::usage(param,verbose); } std::string usage_v(bool param,bool verbose) const { return Impl::usage(param,verbose); } virtual void print_state(std::ostream &o,void const*state) const { return d().print_state(o,state); } void init_name_debug(std::string const& n,bool debug) { FsaFeatureFunction::init_name_debug(n,debug); d().init_name_debug(n,debug); } virtual void Init() { d().sync_to_=(FsaFeatureFunctionData*)this; d().Init(); d().sync(); } template FsaFeatureFunctionDynamic(I const& param) : impl(param) { Init(); } private: Impl impl; }; // constructor takes ptr or shared_ptr to Impl, otherwise same as above - note: not virtual template struct FsaFeatureFunctionPimpl : public FsaFeatureFunctionData { typedef boost::shared_ptr Pimpl; static const bool simple_phrase_score=Impl::simple_phrase_score; Impl const& d() const { return *p_; } int markov_order() const { return d().markov_order(); } std::string describe() const { return d().describe(); } void ScanAccum(SentenceMetadata const& smeta,Hypergraph::Edge const& edge, WordID w,void const* state,void *next_state,Accum *a) const { return d().ScanAccum(smeta,edge,w,state,next_state,a); } void ScanPhraseAccum(SentenceMetadata const& smeta,Hypergraph::Edge const & edge, WordID const* i, WordID const* end, void const* state,void *next_state,Accum *a) const { return d().ScanPhraseAccum(smeta,edge,i,end,state,next_state,a); } void ScanPhraseAccumOnly(SentenceMetadata const& smeta,Hypergraph::Edge const& edge, WordID const* i, WordID const* end, void const* state,Accum *a) const { return d().ScanPhraseAccumOnly(smeta,edge,i,end,state,a); } void *ScanPhraseAccumBounce(SentenceMetadata const& smeta,Hypergraph::Edge const& edge,WordID const* i, WordID const* end,void *cs,void *ns,Accum *a) const { return d().ScanPhraseAccumBounce(smeta,edge,i,end,cs,ns,a); } int early_score_words(SentenceMetadata const& smeta,Hypergraph::Edge const& edge,WordID const* i, WordID const* end,Accum *accum) const { return d().early_score_words(smeta,edge,i,end,accum); } static std::string usage(bool param,bool verbose) { return Impl::usage(param,verbose); } std::string usage_v(bool param,bool verbose) const { return Impl::usage(param,verbose); } void print_state(std::ostream &o,void const*state) const { return d().print_state(o,state); } #if 0 // this and Init() don't touch p_ because we want to leave the original alone. void init_name_debug(std::string const& n,bool debug) { FsaFeatureFunctionData::init_name_debug(n,debug); } #endif void Init() { p_=hold_pimpl_.get(); #if 0 d().sync_to_=static_cast(this); d().Init(); #endif *static_cast(this)=d(); } FsaFeatureFunctionPimpl(Impl const* const p) : hold_pimpl_(p,null_deleter()) { Init(); } FsaFeatureFunctionPimpl(Pimpl const& p) : hold_pimpl_(p) { Init(); } private: Impl const* p_; Pimpl hold_pimpl_; }; typedef FsaFeatureFunctionPimpl FsaFeatureFunctionFwd; // allow ff_from_fsa for an existing dynamic-type ff (as opposed to usual register a wrapped known-type FSA in ff_register, which is more efficient) //typedef FsaFeatureFunctionDynamic DynamicFsaFeatureFunctionFwd; //if you really need to have a dynamic fsa facade that's also a dynamic fsa //TODO: combine 2 (or N) FsaFeatureFunction (type erased) #endif