// 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: jpr@google.com (Jake Ratkiewicz) // Represents a generic weight in an FST -- that is, represents a specific // type of weight underneath while hiding that type from a client. #ifndef FST_SCRIPT_WEIGHT_CLASS_H_ #define FST_SCRIPT_WEIGHT_CLASS_H_ #include #include #include namespace fst { namespace script { class WeightImplBase { public: virtual WeightImplBase *Copy() const = 0; virtual void Print(ostream *o) const = 0; virtual const string &Type() const = 0; virtual string to_string() const = 0; virtual bool operator == (const WeightImplBase &other) const = 0; virtual ~WeightImplBase() { } }; template struct WeightClassImpl : public WeightImplBase { W weight; explicit WeightClassImpl(const W& weight) : weight(weight) { } virtual WeightClassImpl *Copy() const { return new WeightClassImpl(weight); } virtual const string &Type() const { return W::Type(); } virtual void Print(ostream *o) const { *o << weight; } virtual string to_string() const { string str; WeightToStr(weight, &str); return str; } virtual bool operator == (const WeightImplBase &other) const { if (Type() != other.Type()) { return false; } else { const WeightClassImpl *typed_other = static_cast *>(&other); return typed_other->weight == weight; } } }; class WeightClass { public: WeightClass() : element_type_(ZERO), impl_(0) { } template explicit WeightClass(const W& weight) : element_type_(OTHER), impl_(new WeightClassImpl(weight)) { } WeightClass(const string &weight_type, const string &weight_str); WeightClass(const WeightClass &other) : element_type_(other.element_type_), impl_(other.impl_ ? other.impl_->Copy() : 0) { } WeightClass &operator = (const WeightClass &other) { if (impl_) delete impl_; impl_ = other.impl_ ? other.impl_->Copy() : 0; element_type_ = other.element_type_; return *this; } template const W* GetWeight() const; string to_string() const { switch (element_type_) { case ZERO: return "ZERO"; case ONE: return "ONE"; default: case OTHER: return impl_->to_string(); } } bool operator == (const WeightClass &other) const { return element_type_ == other.element_type_ && ((impl_ && other.impl_ && (*impl_ == *other.impl_)) || (impl_ == 0 && other.impl_ == 0)); } static const WeightClass &Zero() { static WeightClass w(ZERO); return w; } static const WeightClass &One() { static WeightClass w(ONE); return w; } ~WeightClass() { if (impl_) delete impl_; } private: enum ElementType { ZERO, ONE, OTHER }; ElementType element_type_; WeightImplBase *impl_; explicit WeightClass(ElementType et) : element_type_(et), impl_(0) { } friend ostream &operator << (ostream &o, const WeightClass &c); }; template const W* WeightClass::GetWeight() const { // We need to store zero and one as statics, because the weight type // W might return them as temporaries. We're returning a pointer, // and it won't do to get the address of a temporary. static const W zero = W::Zero(); static const W one = W::One(); if (element_type_ == ZERO) { return &zero; } else if (element_type_ == ONE) { return &one; } else { if (W::Type() != impl_->Type()) { return NULL; } else { WeightClassImpl *typed_impl = static_cast *>(impl_); return &typed_impl->weight; } } } // // Registration for generic weight types. // typedef WeightImplBase* (*StrToWeightImplBaseT)(const string &str, const string &src, size_t nline); template WeightImplBase* StrToWeightImplBase(const string &str, const string &src, size_t nline) { return new WeightClassImpl(StrToWeight(str, src, nline)); } // The following confuses swig, and doesn't need to be wrapped anyway. #ifndef SWIG ostream& operator << (ostream &o, const WeightClass &c); class WeightClassRegister : public GenericRegister { protected: virtual string ConvertKeyToSoFilename(const string &key) const { return key + ".so"; } }; typedef GenericRegisterer WeightClassRegisterer; #endif // internal version, needs to be called by wrapper in order for // macro args to expand #define REGISTER_FST_WEIGHT__(Weight, line) \ static WeightClassRegisterer weight_registerer ## _ ## line( \ Weight::Type(), \ StrToWeightImplBase) // This layer is where __FILE__ and __LINE__ are expanded #define REGISTER_FST_WEIGHT_EXPANDER(Weight, line) \ REGISTER_FST_WEIGHT__(Weight, line) // // Macro for registering new weight types. Clients call this. // #define REGISTER_FST_WEIGHT(Weight) \ REGISTER_FST_WEIGHT_EXPANDER(Weight, __LINE__) } // namespace script } // namespace fst #endif // FST_SCRIPT_WEIGHT_CLASS_H_