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 class CommandLineFlag { 63 public: 64 constexpr CommandLineFlag() = default; 65 66 // Not copyable/assignable. 67 CommandLineFlag(const CommandLineFlag&) = delete; 68 CommandLineFlag& operator=(const CommandLineFlag&) = delete; 69 70 // absl::CommandLineFlag::IsOfType() 71 // 72 // Return true iff flag has type T. 73 template <typename T> IsOfType()74 inline bool IsOfType() const { 75 return TypeId() == base_internal::FastTypeId<T>(); 76 } 77 78 // absl::CommandLineFlag::TryGet() 79 // 80 // Attempts to retrieve the flag value. Returns value on success, 81 // absl::nullopt otherwise. 82 template <typename T> TryGet()83 absl::optional<T> TryGet() const { 84 if (IsRetired() || !IsOfType<T>()) { 85 return absl::nullopt; 86 } 87 88 // Implementation notes: 89 // 90 // We are wrapping a union around the value of `T` to serve three purposes: 91 // 92 // 1. `U.value` has correct size and alignment for a value of type `T` 93 // 2. The `U.value` constructor is not invoked since U's constructor does 94 // not do it explicitly. 95 // 3. The `U.value` destructor is invoked since U's destructor does it 96 // explicitly. This makes `U` a kind of RAII wrapper around non default 97 // constructible value of T, which is destructed when we leave the 98 // scope. We do need to destroy U.value, which is constructed by 99 // CommandLineFlag::Read even though we left it in a moved-from state 100 // after std::move. 101 // 102 // All of this serves to avoid requiring `T` being default constructible. 103 union U { 104 T value; 105 U() {} 106 ~U() { value.~T(); } 107 }; 108 U u; 109 110 Read(&u.value); 111 // allow retired flags to be "read", so we can report invalid access. 112 if (IsRetired()) { 113 return absl::nullopt; 114 } 115 return std::move(u.value); 116 } 117 118 // absl::CommandLineFlag::Name() 119 // 120 // Returns name of this flag. 121 virtual absl::string_view Name() const = 0; 122 123 // absl::CommandLineFlag::Filename() 124 // 125 // Returns name of the file where this flag is defined. 126 virtual std::string Filename() const = 0; 127 128 // absl::CommandLineFlag::Help() 129 // 130 // Returns help message associated with this flag. 131 virtual std::string Help() const = 0; 132 133 // absl::CommandLineFlag::IsRetired() 134 // 135 // Returns true iff this object corresponds to retired flag. 136 virtual bool IsRetired() const; 137 138 // absl::CommandLineFlag::DefaultValue() 139 // 140 // Returns the default value for this flag. 141 virtual std::string DefaultValue() const = 0; 142 143 // absl::CommandLineFlag::CurrentValue() 144 // 145 // Returns the current value for this flag. 146 virtual std::string CurrentValue() const = 0; 147 148 // absl::CommandLineFlag::ParseFrom() 149 // 150 // Sets the value of the flag based on specified string `value`. If the flag 151 // was successfully set to new value, it returns true. Otherwise, sets `error` 152 // to indicate the error, leaves the flag unchanged, and returns false. 153 bool ParseFrom(absl::string_view value, std::string* error); 154 155 protected: 156 ~CommandLineFlag() = default; 157 158 private: 159 friend class flags_internal::PrivateHandleAccessor; 160 161 // Sets the value of the flag based on specified string `value`. If the flag 162 // was successfully set to new value, it returns true. Otherwise, sets `error` 163 // to indicate the error, leaves the flag unchanged, and returns false. There 164 // are three ways to set the flag's value: 165 // * Update the current flag value 166 // * Update the flag's default value 167 // * Update the current flag value if it was never set before 168 // The mode is selected based on `set_mode` parameter. 169 virtual bool ParseFrom(absl::string_view value, 170 flags_internal::FlagSettingMode set_mode, 171 flags_internal::ValueSource source, 172 std::string& error) = 0; 173 174 // Returns id of the flag's value type. 175 virtual flags_internal::FlagFastTypeId TypeId() const = 0; 176 177 // Interface to save flag to some persistent state. Returns current flag state 178 // or nullptr if flag does not support saving and restoring a state. 179 virtual std::unique_ptr<flags_internal::FlagStateInterface> SaveState() = 0; 180 181 // Copy-construct a new value of the flag's type in a memory referenced by 182 // the dst based on the current flag's value. 183 virtual void Read(void* dst) const = 0; 184 185 // To be deleted. Used to return true if flag's current value originated from 186 // command line. 187 virtual bool IsSpecifiedOnCommandLine() const = 0; 188 189 // Validates supplied value usign validator or parseflag routine 190 virtual bool ValidateInputValue(absl::string_view value) const = 0; 191 192 // Checks that flags default value can be converted to string and back to the 193 // flag's value type. 194 virtual void CheckDefaultValueParsingRoundtrip() const = 0; 195 }; 196 197 ABSL_NAMESPACE_END 198 } // namespace absl 199 200 #endif // ABSL_FLAGS_COMMANDLINEFLAG_H_ 201