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(const char* name, const std::function<void(const int32_t&)>& hook, 83 int32_t default_value, const std::string& usage_text, 84 FlagType flag_type); 85 Flag(const char* name, const std::function<void(const int64_t&)>& hook, 86 int64_t default_value, const std::string& usage_text, 87 FlagType flag_type); 88 Flag(const char* name, const std::function<void(const float&)>& hook, 89 float default_value, const std::string& usage_text, FlagType flag_type); 90 Flag(const char* name, const std::function<void(const bool&)>& hook, 91 bool default_value, const std::string& usage_text, FlagType flag_type); 92 Flag(const char* name, const std::function<void(const std::string&)>& hook, 93 const std::string& default_value, const std::string& usage_text, 94 FlagType flag_type); 95 GetFlagType()96 FlagType GetFlagType() const { return flag_type_; } 97 98 private: 99 friend class Flags; 100 101 bool Parse(const std::string& arg, bool* value_parsing_ok) const; 102 103 std::string name_; 104 enum { 105 TYPE_INT32, 106 TYPE_INT64, 107 TYPE_BOOL, 108 TYPE_STRING, 109 TYPE_FLOAT, 110 } type_; 111 112 std::string GetTypeName() const; 113 114 std::function<bool(const std::string&)> value_hook_; 115 std::string default_for_display_; 116 117 std::string usage_text_; 118 FlagType flag_type_; 119 }; 120 121 class Flags { 122 public: 123 // Parse the command line represented by argv[0, ..., (*argc)-1] to find flag 124 // instances matching flags in flaglist[]. Update the variables associated 125 // with matching flags, and remove the matching arguments from (*argc, argv). 126 // Return true iff all recognized flag values were parsed correctly, and the 127 // first remaining argument is not "--help". 128 // Note: 129 // 1. when there are duplicate args in argv for the same flag, the flag value 130 // and the parse result will be based on the 1st arg. 131 // 2. when there are duplicate flags in flag_list (i.e. two flags having the 132 // same name), all of them will be checked against the arg list and the parse 133 // result will be false if any of the parsing fails. 134 // See *Duplicate* unit tests in command_line_flags_test.cc for the 135 // illustration of such behaviors. 136 static bool Parse(int* argc, const char** argv, 137 const std::vector<Flag>& flag_list); 138 139 // Return a usage message with command line cmdline, and the 140 // usage_text strings in flag_list[]. 141 static std::string Usage(const std::string& cmdline, 142 const std::vector<Flag>& flag_list); 143 144 // Return a space separated string containing argv[1, ..., argc-1]. 145 static std::string ArgsToString(int argc, const char** argv); 146 }; 147 } // namespace tflite 148 149 #endif // TENSORFLOW_LITE_TOOLS_COMMAND_LINE_FLAGS_H_ 150