xref: /aosp_15_r20/external/abseil-cpp/absl/flags/commandlineflag.h (revision 9356374a3709195abf420251b3e825997ff56c0f)
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