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
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;
~WeightImplBase()39 virtual ~WeightImplBase() { }
40 };
41
42 template<class W>
43 struct WeightClassImpl : public WeightImplBase {
44 W weight;
45
WeightClassImplWeightClassImpl46 explicit WeightClassImpl(const W& weight) : weight(weight) { }
47
CopyWeightClassImpl48 virtual WeightClassImpl<W> *Copy() const {
49 return new WeightClassImpl<W>(weight);
50 }
51
TypeWeightClassImpl52 virtual const string &Type() const { return W::Type(); }
53
PrintWeightClassImpl54 virtual void Print(ostream *o) const {
55 *o << weight;
56 }
57
to_stringWeightClassImpl58 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:
WeightClass()79 WeightClass() : element_type_(ZERO), impl_(0) { }
80
81 template<class W>
WeightClass(const W & weight)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
WeightClass(const WeightClass & other)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
to_string()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
Zero()119 static const WeightClass &Zero() {
120 static WeightClass w(ZERO);
121
122 return w;
123 }
124
One()125 static const WeightClass &One() {
126 static WeightClass w(ONE);
127
128 return w;
129 }
130
~WeightClass()131 ~WeightClass() { if (impl_) delete impl_; }
132 private:
133 enum ElementType { ZERO, ONE, OTHER };
134 ElementType element_type_;
135
136 WeightImplBase *impl_;
137
WeightClass(ElementType et)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>
GetWeight()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>
StrToWeightImplBase(const string & str,const string & src,size_t nline)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:
ConvertKeyToSoFilename(const string & key)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