• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Copyright 2018 The TensorFlow Authors. All Rights Reserved.
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 
16 #ifndef TENSORFLOW_LITE_TOOLS_COMMAND_LINE_FLAGS_H_
17 #define TENSORFLOW_LITE_TOOLS_COMMAND_LINE_FLAGS_H_
18 
19 #include <functional>
20 #include <string>
21 #include <vector>
22 
23 namespace tflite {
24 // A simple command-line argument parsing module.
25 // Dependency free simplified port of core/util/command_line_flags.
26 // This class is written for benchmarks and uses inefficient string
27 // concatenation. This was written to avoid dependency on tensorflow/core/util
28 // which transitively brings in a lot of other dependencies that are not
29 // necessary for tflite benchmarking code.
30 // The recommended way of using it is with local variables and an initializer
31 // list of Flag objects, for example:
32 //
33 // int some_int = 10;
34 // bool some_switch = false;
35 // std::string some_name = "something";
36 //
37 // std::vector<tensorFlow::Flag> flag_list = {
38 //   Flag::CreateFlag("some_int", &some_int, "an integer that affects X"),
39 //   Flag::CreateFlag("some_switch", &some_switch, "a bool that affects Y"),
40 //   Flag::CreateFlag("some_name", &some_name, "a string that affects Z")
41 // };
42 // // Get usage message before ParseFlags() to capture default values.
43 // std::string usage = Flag::Usage(argv[0], flag_list);
44 // bool parsed_values_ok = Flags::Parse(&argc, argv, flag_list);
45 //
46 // tensorflow::port::InitMain(usage.c_str(), &argc, &argv);
47 // if (argc != 1 || !parsed_values_ok) {
48 //    ...output usage and error message...
49 // }
50 //
51 // The argc and argv values are adjusted by the Parse function so all that
52 // remains is the program name (at argv[0]) and any unknown arguments fill the
53 // rest of the array. This means you can check for flags that weren't understood
54 // by seeing if argv is greater than 1.
55 // The result indicates if there were any errors parsing the values that were
56 // passed to the command-line switches. For example, --some_int=foo would return
57 // false because the argument is expected to be an integer.
58 //
59 // NOTE: Unlike gflags-style libraries, this library is intended to be
60 // used in the `main()` function of your binary. It does not handle
61 // flag definitions that are scattered around the source code.
62 
63 // A description of a single command line flag, holding its name, type, usage
64 // text, and a pointer to the corresponding variable.
65 class Flag {
66  public:
67   enum FlagType {
68     kPositional = 0,
69     kRequired,
70     kOptional,
71   };
72 
73   // The order of the positional flags is the same as they are added.
74   // Positional flags are supposed to be required.
75   template <typename T>
76   static Flag CreateFlag(const char* name, T* val, const char* usage,
77                          FlagType flag_type = kOptional) {
78     return Flag(
79         name, [val](const T& v) { *val = v; }, *val, usage, flag_type);
80   }
81 
82 // "flag_T" is same as "default_value_T" for trivial types, like int32, bool
83 // etc. But when it's a complex type, "default_value_T" is generally a const
84 // reference "flag_T".
85 #define CONSTRUCTOR_WITH_ARGV_INDEX(flag_T, default_value_T)         \
86   Flag(const char* name,                                             \
87        const std::function<void(const flag_T& /*flag_val*/,          \
88                                 int /*argv_position*/)>& hook,       \
89        default_value_T default_value, const std::string& usage_text, \
90        FlagType flag_type);
91 
92 #define CONSTRUCTOR_WITHOUT_ARGV_INDEX(flag_T, default_value_T)            \
93   Flag(const char* name, const std::function<void(const flag_T&)>& hook,   \
94        default_value_T default_value, const std::string& usage_text,       \
95        FlagType flag_type)                                                 \
96       : Flag(                                                              \
97             name, [hook](const flag_T& flag_val, int) { hook(flag_val); }, \
98             default_value, usage_text, flag_type) {}
99 
CONSTRUCTOR_WITH_ARGV_INDEX(int32_t,int32_t)100   CONSTRUCTOR_WITH_ARGV_INDEX(int32_t, int32_t)
101   CONSTRUCTOR_WITHOUT_ARGV_INDEX(int32_t, int32_t)
102 
103   CONSTRUCTOR_WITH_ARGV_INDEX(int64_t, int64_t)
104   CONSTRUCTOR_WITHOUT_ARGV_INDEX(int64_t, int64_t)
105 
106   CONSTRUCTOR_WITH_ARGV_INDEX(float, float)
107   CONSTRUCTOR_WITHOUT_ARGV_INDEX(float, float)
108 
109   CONSTRUCTOR_WITH_ARGV_INDEX(bool, bool)
110   CONSTRUCTOR_WITHOUT_ARGV_INDEX(bool, bool)
111 
112   CONSTRUCTOR_WITH_ARGV_INDEX(std::string, const std::string&)
113   CONSTRUCTOR_WITHOUT_ARGV_INDEX(std::string, const std::string&)
114 
115 #undef CONSTRUCTOR_WITH_ARGV_INDEX
116 #undef CONSTRUCTOR_WITHOUT_ARGV_INDEX
117 
118   FlagType GetFlagType() const { return flag_type_; }
119 
120  private:
121   friend class Flags;
122 
123   bool Parse(const std::string& arg, int argv_position,
124              bool* value_parsing_ok) const;
125 
126   std::string name_;
127   enum {
128     TYPE_INT32,
129     TYPE_INT64,
130     TYPE_BOOL,
131     TYPE_STRING,
132     TYPE_FLOAT,
133   } type_;
134 
135   std::string GetTypeName() const;
136 
137   std::function<bool(const std::string& /*read_value*/, int /*argv_position*/)>
138       value_hook_;
139   std::string default_for_display_;
140 
141   std::string usage_text_;
142   FlagType flag_type_;
143 };
144 
145 class Flags {
146  public:
147   // Parse the command line represented by argv[0, ..., (*argc)-1] to find flag
148   // instances matching flags in flaglist[].  Update the variables associated
149   // with matching flags, and remove the matching arguments from (*argc, argv).
150   // Return true iff all recognized flag values were parsed correctly, and the
151   // first remaining argument is not "--help".
152   // Note:
153   // 1. when there are duplicate args in argv for the same flag, the flag value
154   // and the parse result will be based on the 1st arg.
155   // 2. when there are duplicate flags in flag_list (i.e. two flags having the
156   // same name), all of them will be checked against the arg list and the parse
157   // result will be false if any of the parsing fails.
158   // See *Duplicate* unit tests in command_line_flags_test.cc for the
159   // illustration of such behaviors.
160   static bool Parse(int* argc, const char** argv,
161                     const std::vector<Flag>& flag_list);
162 
163   // Return a usage message with command line cmdline, and the
164   // usage_text strings in flag_list[].
165   static std::string Usage(const std::string& cmdline,
166                            const std::vector<Flag>& flag_list);
167 
168   // Return a space separated string containing argv[1, ..., argc-1].
169   static std::string ArgsToString(int argc, const char** argv);
170 };
171 }  // namespace tflite
172 
173 #endif  // TENSORFLOW_LITE_TOOLS_COMMAND_LINE_FLAGS_H_
174