1// flags.h
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//      http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14//
15// Author: riley@google.com (Michael Riley)
16//
17// \file
18// Google-style flag handling declarations and inline definitions.
19
20#ifndef FST_LIB_FLAGS_H__
21#define FST_LIB_FLAGS_H__
22
23#include <iostream>
24#include <map>
25#include <set>
26#include <sstream>
27#include <string>
28
29#include <fst/types.h>
30#include <fst/lock.h>
31
32using std::string;
33
34//
35// FLAGS USAGE:
36//
37// Definition example:
38//
39//    DEFINE_int32(length, 0, "length");
40//
41// This defines variable FLAGS_length, initialized to 0.
42//
43// Declaration example:
44//
45//    DECLARE_int32(length);
46//
47// SET_FLAGS() can be used to set flags from the command line
48// using, for example, '--length=2'.
49//
50// ShowUsage() can be used to print out command and flag usage.
51//
52
53#define DECLARE_bool(name) extern bool FLAGS_ ## name
54#define DECLARE_string(name) extern string FLAGS_ ## name
55#define DECLARE_int32(name) extern int32 FLAGS_ ## name
56#define DECLARE_int64(name) extern int64 FLAGS_ ## name
57#define DECLARE_double(name) extern double FLAGS_ ## name
58
59template <typename T>
60struct FlagDescription {
61  FlagDescription(T *addr, const char *doc, const char *type,
62		  const char *file, const T val)
63      : address(addr),
64    doc_string(doc),
65    type_name(type),
66    file_name(file),
67    default_value(val) {}
68
69  T *address;
70  const char *doc_string;
71  const char *type_name;
72  const char *file_name;
73  const T default_value;
74};
75
76template <typename T>
77class FlagRegister {
78 public:
79  static FlagRegister<T> *GetRegister() {
80    fst::FstOnceInit(&register_init_, &FlagRegister<T>::Init);
81    return register_;
82  }
83
84  const FlagDescription<T> &GetFlagDescription(const string &name) const {
85    fst::MutexLock l(register_lock_);
86    typename std::map< string, FlagDescription<T> >::const_iterator it =
87      flag_table_.find(name);
88    return it != flag_table_.end() ? it->second : 0;
89  }
90  void SetDescription(const string &name,
91                      const FlagDescription<T> &desc) {
92    fst::MutexLock l(register_lock_);
93    flag_table_.insert(make_pair(name, desc));
94  }
95
96  bool SetFlag(const string &val, bool *address) const {
97    if (val == "true" || val == "1" || val.empty()) {
98      *address = true;
99      return true;
100    } else if (val == "false" || val == "0") {
101      *address = false;
102      return true;
103    }
104    else {
105      return false;
106    }
107  }
108  bool SetFlag(const string &val, string *address) const {
109    *address = val;
110    return true;
111  }
112  bool SetFlag(const string &val, int32 *address) const {
113    char *p = 0;
114    *address = strtol(val.c_str(), &p, 0);
115    return !val.empty() && *p == '\0';
116  }
117  bool SetFlag(const string &val, int64 *address) const {
118    char *p = 0;
119    *address = strtoll(val.c_str(), &p, 0);
120    return !val.empty() && *p == '\0';
121  }
122  bool SetFlag(const string &val, double *address) const {
123    char *p = 0;
124    *address = strtod(val.c_str(), &p);
125    return !val.empty() && *p == '\0';
126  }
127
128  bool SetFlag(const string &arg, const string &val) const {
129    for (typename std::map< string, FlagDescription<T> >::const_iterator it =
130           flag_table_.begin();
131         it != flag_table_.end();
132         ++it) {
133      const string &name = it->first;
134      const FlagDescription<T> &desc = it->second;
135      if (arg == name)
136        return SetFlag(val, desc.address);
137    }
138    return false;
139  }
140
141  void GetUsage(std::set< std::pair<string, string> > *usage_set) const {
142    for (typename std::map< string,
143             FlagDescription<T> >::const_iterator it =
144           flag_table_.begin();
145         it != flag_table_.end();
146         ++it) {
147      const string &name = it->first;
148      const FlagDescription<T> &desc = it->second;
149      string usage = "  --" + name;
150      usage += ": type = ";
151      usage += desc.type_name;
152      usage += ", default = ";
153      usage += GetDefault(desc.default_value) + "\n  ";
154      usage += desc.doc_string;
155      usage_set->insert(make_pair(desc.file_name, usage));
156    }
157  }
158
159 private:
160  static void Init() {
161    register_lock_ = new fst::Mutex;
162    register_ = new FlagRegister<T>;
163  }
164
165  std::map< string, FlagDescription<T> > flag_table_;
166
167  string GetDefault(bool default_value) const {
168    return default_value ? "true" : "false";
169  }
170
171  string GetDefault(const string &default_value) const {
172    return "\"" + default_value + "\"";
173  }
174
175  template<typename V> string GetDefault(const V& default_value) const {
176    std::ostringstream strm;
177    strm << default_value;
178    return strm.str();
179  }
180
181  static fst::FstOnceType register_init_;   // ensures only called once
182  static fst::Mutex* register_lock_;        // multithreading lock
183  static FlagRegister<T> *register_;
184};
185
186template <class T>
187fst::FstOnceType FlagRegister<T>::register_init_ = fst::FST_ONCE_INIT;
188
189template <class T>
190fst::Mutex *FlagRegister<T>::register_lock_ = 0;
191
192template <class T>
193FlagRegister<T> *FlagRegister<T>::register_ = 0;
194
195
196template <typename T>
197class FlagRegisterer {
198 public:
199  FlagRegisterer(const string &name, const FlagDescription<T> &desc) {
200    FlagRegister<T> *registr = FlagRegister<T>::GetRegister();
201    registr->SetDescription(name, desc);
202  }
203
204 private:
205  DISALLOW_COPY_AND_ASSIGN(FlagRegisterer);
206};
207
208
209#define DEFINE_VAR(type, name, value, doc)                                \
210  type FLAGS_ ## name = value;                                            \
211  static FlagRegisterer<type>                                             \
212  name ## _flags_registerer(#name, FlagDescription<type>(&FLAGS_ ## name, \
213                                                         doc,             \
214                                                         #type,           \
215                                                         __FILE__,        \
216                                                         value))
217
218#define DEFINE_bool(name, value, doc) DEFINE_VAR(bool, name, value, doc)
219#define DEFINE_string(name, value, doc) \
220  DEFINE_VAR(string, name, value, doc)
221#define DEFINE_int32(name, value, doc) DEFINE_VAR(int32, name, value, doc)
222#define DEFINE_int64(name, value, doc) DEFINE_VAR(int64, name, value, doc)
223#define DEFINE_double(name, value, doc) DEFINE_VAR(double, name, value, doc)
224
225
226// Temporary directory
227DECLARE_string(tmpdir);
228
229void SetFlags(const char *usage, int *argc, char ***argv, bool remove_flags,
230              const char *src = "");
231
232#define SET_FLAGS(usage, argc, argv, rmflags) \
233SetFlags(usage, argc, argv, rmflags, __FILE__)
234
235// Deprecated - for backward compatibility
236inline void InitFst(const char *usage, int *argc, char ***argv, bool rmflags) {
237  return SetFlags(usage, argc, argv, rmflags);
238}
239
240void ShowUsage(bool long_usage = true);
241
242#endif  // FST_LIB_FLAGS_H__
243