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