1 // 2 // Copyright 2020 The Abseil Authors. 3 // 4 // Licensed under the Apache License, Version 2.0 (the "License"); 5 // you may not use this file except in compliance with the License. 6 // You may obtain a copy of the License at 7 // 8 // https://www.apache.org/licenses/LICENSE-2.0 9 // 10 // Unless required by applicable law or agreed to in writing, software 11 // distributed under the License is distributed on an "AS IS" BASIS, 12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 // See the License for the specific language governing permissions and 14 // limitations under the License. 15 // 16 // ----------------------------------------------------------------------------- 17 // File: commandlineflag.h 18 // ----------------------------------------------------------------------------- 19 // 20 // This header file defines the `CommandLineFlag`, which acts as a type-erased 21 // handle for accessing metadata about the Abseil Flag in question. 22 // 23 // Because an actual Abseil flag is of an unspecified type, you should not 24 // manipulate or interact directly with objects of that type. Instead, use the 25 // CommandLineFlag type as an intermediary. 26 #ifndef ABSL_FLAGS_COMMANDLINEFLAG_H_ 27 #define ABSL_FLAGS_COMMANDLINEFLAG_H_ 28 29 #include <memory> 30 #include <string> 31 32 #include "absl/base/config.h" 33 #include "absl/base/internal/fast_type_id.h" 34 #include "absl/flags/internal/commandlineflag.h" 35 #include "absl/strings/string_view.h" 36 #include "absl/types/optional.h" 37 38 namespace absl { 39 ABSL_NAMESPACE_BEGIN 40 namespace flags_internal { 41 class PrivateHandleAccessor; 42 } // namespace flags_internal 43 44 // CommandLineFlag 45 // 46 // This type acts as a type-erased handle for an instance of an Abseil Flag and 47 // holds reflection information pertaining to that flag. Use CommandLineFlag to 48 // access a flag's name, location, help string etc. 49 // 50 // To obtain an absl::CommandLineFlag, invoke `absl::FindCommandLineFlag()` 51 // passing it the flag name string. 52 // 53 // Example: 54 // 55 // // Obtain reflection handle for a flag named "flagname". 56 // const absl::CommandLineFlag* my_flag_data = 57 // absl::FindCommandLineFlag("flagname"); 58 // 59 // // Now you can get flag info from that reflection handle. 60 // std::string flag_location = my_flag_data->Filename(); 61 // ... 62 63 // These are only used as constexpr global objects. 64 // They do not use a virtual destructor to simplify their implementation. 65 // They are not destroyed except at program exit, so leaks do not matter. 66 #if defined(__GNUC__) && !defined(__clang__) 67 #pragma GCC diagnostic push 68 #pragma GCC diagnostic ignored "-Wnon-virtual-dtor" 69 #endif 70 class CommandLineFlag { 71 public: 72 constexpr CommandLineFlag() = default; 73 74 // Not copyable/assignable. 75 CommandLineFlag(const CommandLineFlag&) = delete; 76 CommandLineFlag& operator=(const CommandLineFlag&) = delete; 77 78 // absl::CommandLineFlag::IsOfType() 79 // 80 // Return true iff flag has type T. 81 template <typename T> IsOfType()82 inline bool IsOfType() const { 83 return TypeId() == base_internal::FastTypeId<T>(); 84 } 85 86 // absl::CommandLineFlag::TryGet() 87 // 88 // Attempts to retrieve the flag value. Returns value on success, 89 // absl::nullopt otherwise. 90 template <typename T> TryGet()91 absl::optional<T> TryGet() const { 92 if (IsRetired() || !IsOfType<T>()) { 93 return absl::nullopt; 94 } 95 96 // Implementation notes: 97 // 98 // We are wrapping a union around the value of `T` to serve three purposes: 99 // 100 // 1. `U.value` has correct size and alignment for a value of type `T` 101 // 2. The `U.value` constructor is not invoked since U's constructor does 102 // not do it explicitly. 103 // 3. The `U.value` destructor is invoked since U's destructor does it 104 // explicitly. This makes `U` a kind of RAII wrapper around non default 105 // constructible value of T, which is destructed when we leave the 106 // scope. We do need to destroy U.value, which is constructed by 107 // CommandLineFlag::Read even though we left it in a moved-from state 108 // after std::move. 109 // 110 // All of this serves to avoid requiring `T` being default constructible. 111 union U { 112 T value; 113 U() {} 114 ~U() { value.~T(); } 115 }; 116 U u; 117 118 Read(&u.value); 119 // allow retired flags to be "read", so we can report invalid access. 120 if (IsRetired()) { 121 return absl::nullopt; 122 } 123 return std::move(u.value); 124 } 125 126 // absl::CommandLineFlag::Name() 127 // 128 // Returns name of this flag. 129 virtual absl::string_view Name() const = 0; 130 131 // absl::CommandLineFlag::Filename() 132 // 133 // Returns name of the file where this flag is defined. 134 virtual std::string Filename() const = 0; 135 136 // absl::CommandLineFlag::Help() 137 // 138 // Returns help message associated with this flag. 139 virtual std::string Help() const = 0; 140 141 // absl::CommandLineFlag::IsRetired() 142 // 143 // Returns true iff this object corresponds to retired flag. 144 virtual bool IsRetired() const; 145 146 // absl::CommandLineFlag::DefaultValue() 147 // 148 // Returns the default value for this flag. 149 virtual std::string DefaultValue() const = 0; 150 151 // absl::CommandLineFlag::CurrentValue() 152 // 153 // Returns the current value for this flag. 154 virtual std::string CurrentValue() const = 0; 155 156 // absl::CommandLineFlag::ParseFrom() 157 // 158 // Sets the value of the flag based on specified string `value`. If the flag 159 // was successfully set to new value, it returns true. Otherwise, sets `error` 160 // to indicate the error, leaves the flag unchanged, and returns false. 161 bool ParseFrom(absl::string_view value, std::string* error); 162 163 protected: 164 ~CommandLineFlag() = default; 165 166 private: 167 friend class flags_internal::PrivateHandleAccessor; 168 169 // Sets the value of the flag based on specified string `value`. If the flag 170 // was successfully set to new value, it returns true. Otherwise, sets `error` 171 // to indicate the error, leaves the flag unchanged, and returns false. There 172 // are three ways to set the flag's value: 173 // * Update the current flag value 174 // * Update the flag's default value 175 // * Update the current flag value if it was never set before 176 // The mode is selected based on `set_mode` parameter. 177 virtual bool ParseFrom(absl::string_view value, 178 flags_internal::FlagSettingMode set_mode, 179 flags_internal::ValueSource source, 180 std::string& error) = 0; 181 182 // Returns id of the flag's value type. 183 virtual flags_internal::FlagFastTypeId TypeId() const = 0; 184 185 // Interface to save flag to some persistent state. Returns current flag state 186 // or nullptr if flag does not support saving and restoring a state. 187 virtual std::unique_ptr<flags_internal::FlagStateInterface> SaveState() = 0; 188 189 // Copy-construct a new value of the flag's type in a memory referenced by 190 // the dst based on the current flag's value. 191 virtual void Read(void* dst) const = 0; 192 193 // To be deleted. Used to return true if flag's current value originated from 194 // command line. 195 virtual bool IsSpecifiedOnCommandLine() const = 0; 196 197 // Validates supplied value using validator or parseflag routine 198 virtual bool ValidateInputValue(absl::string_view value) const = 0; 199 200 // Checks that flags default value can be converted to string and back to the 201 // flag's value type. 202 virtual void CheckDefaultValueParsingRoundtrip() const = 0; 203 }; 204 #if defined(__GNUC__) && !defined(__clang__) 205 #pragma GCC diagnostic pop 206 #endif 207 208 ABSL_NAMESPACE_END 209 } // namespace absl 210 211 #endif // ABSL_FLAGS_COMMANDLINEFLAG_H_ 212