1 2 // Licensed under the Apache License, Version 2.0 (the "License"); 3 // you may not use this file except in compliance with the License. 4 // You may obtain a copy of the License at 5 // 6 // http://www.apache.org/licenses/LICENSE-2.0 7 // 8 // Unless required by applicable law or agreed to in writing, software 9 // distributed under the License is distributed on an "AS IS" BASIS, 10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 // 14 // Copyright 2005-2010 Google, Inc. 15 // Author: jpr (at) google.com (Jake Ratkiewicz) 16 17 // Represents a generic weight in an FST -- that is, represents a specific 18 // type of weight underneath while hiding that type from a client. 19 20 21 #ifndef FST_SCRIPT_WEIGHT_CLASS_H_ 22 #define FST_SCRIPT_WEIGHT_CLASS_H_ 23 24 #include <string> 25 26 #include <fst/generic-register.h> 27 #include <fst/util.h> 28 29 namespace fst { 30 namespace script { 31 32 class WeightImplBase { 33 public: 34 virtual WeightImplBase *Copy() const = 0; 35 virtual void Print(ostream *o) const = 0; 36 virtual const string &Type() const = 0; 37 virtual string to_string() const = 0; 38 virtual bool operator == (const WeightImplBase &other) const = 0; 39 virtual ~WeightImplBase() { } 40 }; 41 42 template<class W> 43 struct WeightClassImpl : public WeightImplBase { 44 W weight; 45 46 explicit WeightClassImpl(const W& weight) : weight(weight) { } 47 48 virtual WeightClassImpl<W> *Copy() const { 49 return new WeightClassImpl<W>(weight); 50 } 51 52 virtual const string &Type() const { return W::Type(); } 53 54 virtual void Print(ostream *o) const { 55 *o << weight; 56 } 57 58 virtual string to_string() const { 59 ostringstream s; 60 s << weight; 61 return s.str(); 62 } 63 64 virtual bool operator == (const WeightImplBase &other) const { 65 if (Type() != other.Type()) { 66 return false; 67 } else { 68 const WeightClassImpl<W> *typed_other = 69 static_cast<const WeightClassImpl<W> *>(&other); 70 71 return typed_other->weight == weight; 72 } 73 } 74 }; 75 76 77 class WeightClass { 78 public: 79 WeightClass() : element_type_(ZERO), impl_(0) { } 80 81 template<class W> 82 explicit WeightClass(const W& weight) 83 : element_type_(OTHER), impl_(new WeightClassImpl<W>(weight)) { } 84 85 WeightClass(const string &weight_type, const string &weight_str); 86 87 WeightClass(const WeightClass &other) : 88 element_type_(other.element_type_), 89 impl_(other.impl_ ? other.impl_->Copy() : 0) { } 90 91 WeightClass &operator = (const WeightClass &other) { 92 if (impl_) delete impl_; 93 impl_ = other.impl_ ? other.impl_->Copy() : 0; 94 element_type_ = other.element_type_; 95 return *this; 96 } 97 98 template<class W> 99 const W* GetWeight() const; 100 101 string to_string() const { 102 switch (element_type_) { 103 case ZERO: 104 return "ZERO"; 105 case ONE: 106 return "ONE"; 107 default: 108 case OTHER: 109 return impl_->to_string(); 110 } 111 } 112 113 bool operator == (const WeightClass &other) const { 114 return element_type_ == other.element_type_ && 115 ((impl_ && other.impl_ && (*impl_ == *other.impl_)) || 116 (impl_ == 0 && other.impl_ == 0)); 117 } 118 119 static const WeightClass &Zero() { 120 static WeightClass w(ZERO); 121 122 return w; 123 } 124 125 static const WeightClass &One() { 126 static WeightClass w(ONE); 127 128 return w; 129 } 130 131 ~WeightClass() { if (impl_) delete impl_; } 132 private: 133 enum ElementType { ZERO, ONE, OTHER }; 134 ElementType element_type_; 135 136 WeightImplBase *impl_; 137 138 explicit WeightClass(ElementType et) : element_type_(et), impl_(0) { } 139 140 friend ostream &operator << (ostream &o, const WeightClass &c); 141 }; 142 143 template<class W> 144 const W* WeightClass::GetWeight() const { 145 // We need to store zero and one as statics, because the weight type 146 // W might return them as temporaries. We're returning a pointer, 147 // and it won't do to get the address of a temporary. 148 static const W zero = W::Zero(); 149 static const W one = W::One(); 150 151 if (element_type_ == ZERO) { 152 return &zero; 153 } else if (element_type_ == ONE) { 154 return &one; 155 } else { 156 if (W::Type() != impl_->Type()) { 157 return NULL; 158 } else { 159 WeightClassImpl<W> *typed_impl = 160 static_cast<WeightClassImpl<W> *>(impl_); 161 return &typed_impl->weight; 162 } 163 } 164 } 165 166 // 167 // Registration for generic weight types. 168 // 169 170 typedef WeightImplBase* (*StrToWeightImplBaseT)(const string &str, 171 const string &src, 172 size_t nline); 173 174 template<class W> 175 WeightImplBase* StrToWeightImplBase(const string &str, 176 const string &src, size_t nline) { 177 return new WeightClassImpl<W>(StrToWeight<W>(str, src, nline)); 178 } 179 180 // The following confuses swig, and doesn't need to be wrapped anyway. 181 #ifndef SWIG 182 ostream& operator << (ostream &o, const WeightClass &c); 183 184 class WeightClassRegister : public GenericRegister<string, 185 StrToWeightImplBaseT, 186 WeightClassRegister> { 187 protected: 188 virtual string ConvertKeyToSoFilename(const string &key) const { 189 return key + ".so"; 190 } 191 }; 192 193 typedef GenericRegisterer<WeightClassRegister> WeightClassRegisterer; 194 #endif 195 196 // internal version, needs to be called by wrapper in order for 197 // macro args to expand 198 #define REGISTER_FST_WEIGHT__(Weight, line) \ 199 static WeightClassRegisterer weight_registerer ## _ ## line( \ 200 Weight::Type(), \ 201 StrToWeightImplBase<Weight>) 202 203 // This layer is where __FILE__ and __LINE__ are expanded 204 #define REGISTER_FST_WEIGHT_EXPANDER(Weight, line) \ 205 REGISTER_FST_WEIGHT__(Weight, line) 206 207 // 208 // Macro for registering new weight types. Clients call this. 209 // 210 #define REGISTER_FST_WEIGHT(Weight) \ 211 REGISTER_FST_WEIGHT_EXPANDER(Weight, __LINE__) 212 213 } // namespace script 214 } // namespace fst 215 216 #endif // FST_SCRIPT_WEIGHT_CLASS_H_ 217