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@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 29namespace fst { 30namespace script { 31 32class 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 42template<class W> 43struct 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 string str; 60 WeightToStr(weight, &str); 61 return 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 77class 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 const string &Type() const { 132 if (impl_) return impl_->Type(); 133 static const string no_type = "none"; 134 return no_type; 135 } 136 137 138 ~WeightClass() { if (impl_) delete impl_; } 139 private: 140 enum ElementType { ZERO, ONE, OTHER }; 141 ElementType element_type_; 142 143 WeightImplBase *impl_; 144 145 explicit WeightClass(ElementType et) : element_type_(et), impl_(0) { } 146 147 friend ostream &operator << (ostream &o, const WeightClass &c); 148}; 149 150template<class W> 151const W* WeightClass::GetWeight() const { 152 // We need to store zero and one as statics, because the weight type 153 // W might return them as temporaries. We're returning a pointer, 154 // and it won't do to get the address of a temporary. 155 static const W zero = W::Zero(); 156 static const W one = W::One(); 157 158 if (element_type_ == ZERO) { 159 return &zero; 160 } else if (element_type_ == ONE) { 161 return &one; 162 } else { 163 if (W::Type() != impl_->Type()) { 164 return NULL; 165 } else { 166 WeightClassImpl<W> *typed_impl = 167 static_cast<WeightClassImpl<W> *>(impl_); 168 return &typed_impl->weight; 169 } 170 } 171} 172 173// 174// Registration for generic weight types. 175// 176 177typedef WeightImplBase* (*StrToWeightImplBaseT)(const string &str, 178 const string &src, 179 size_t nline); 180 181template<class W> 182WeightImplBase* StrToWeightImplBase(const string &str, 183 const string &src, size_t nline) { 184 return new WeightClassImpl<W>(StrToWeight<W>(str, src, nline)); 185} 186 187// The following confuses swig, and doesn't need to be wrapped anyway. 188#ifndef SWIG 189ostream& operator << (ostream &o, const WeightClass &c); 190 191class WeightClassRegister : public GenericRegister<string, 192 StrToWeightImplBaseT, 193 WeightClassRegister> { 194 protected: 195 virtual string ConvertKeyToSoFilename(const string &key) const { 196 return key + ".so"; 197 } 198}; 199 200typedef GenericRegisterer<WeightClassRegister> WeightClassRegisterer; 201#endif 202 203// internal version, needs to be called by wrapper in order for 204// macro args to expand 205#define REGISTER_FST_WEIGHT__(Weight, line) \ 206 static WeightClassRegisterer weight_registerer ## _ ## line( \ 207 Weight::Type(), \ 208 StrToWeightImplBase<Weight>) 209 210// This layer is where __FILE__ and __LINE__ are expanded 211#define REGISTER_FST_WEIGHT_EXPANDER(Weight, line) \ 212 REGISTER_FST_WEIGHT__(Weight, line) 213 214// 215// Macro for registering new weight types. Clients call this. 216// 217#define REGISTER_FST_WEIGHT(Weight) \ 218 REGISTER_FST_WEIGHT_EXPANDER(Weight, __LINE__) 219 220} // namespace script 221} // namespace fst 222 223#endif // FST_SCRIPT_WEIGHT_CLASS_H_ 224