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