• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 //  Copyright 2019 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: flag.h
18 // -----------------------------------------------------------------------------
19 //
20 // This header file defines the `absl::Flag<T>` type for holding command-line
21 // flag data, and abstractions to create, get and set such flag data.
22 //
23 // It is important to note that this type is **unspecified** (an implementation
24 // detail) and you do not construct or manipulate actual `absl::Flag<T>`
25 // instances. Instead, you define and declare flags using the
26 // `ABSL_FLAG()` and `ABSL_DECLARE_FLAG()` macros, and get and set flag values
27 // using the `absl::GetFlag()` and `absl::SetFlag()` functions.
28 
29 #ifndef ABSL_FLAGS_FLAG_H_
30 #define ABSL_FLAGS_FLAG_H_
31 
32 #include <string>
33 #include <type_traits>
34 
35 #include "absl/base/attributes.h"
36 #include "absl/base/casts.h"
37 #include "absl/base/config.h"
38 #include "absl/flags/config.h"
39 #include "absl/flags/declare.h"
40 #include "absl/flags/internal/commandlineflag.h"
41 #include "absl/flags/internal/flag.h"
42 #include "absl/flags/internal/registry.h"
43 #include "absl/flags/marshalling.h"
44 
45 namespace absl {
46 ABSL_NAMESPACE_BEGIN
47 
48 // Flag
49 //
50 // An `absl::Flag` holds a command-line flag value, providing a runtime
51 // parameter to a binary. Such flags should be defined in the global namespace
52 // and (preferably) in the module containing the binary's `main()` function.
53 //
54 // You should not construct and cannot use the `absl::Flag` type directly;
55 // instead, you should declare flags using the `ABSL_DECLARE_FLAG()` macro
56 // within a header file, and define your flag using `ABSL_FLAG()` within your
57 // header's associated `.cc` file. Such flags will be named `FLAGS_name`.
58 //
59 // Example:
60 //
61 //    .h file
62 //
63 //      // Declares usage of a flag named "FLAGS_count"
64 //      ABSL_DECLARE_FLAG(int, count);
65 //
66 //    .cc file
67 //
68 //      // Defines a flag named "FLAGS_count" with a default `int` value of 0.
69 //      ABSL_FLAG(int, count, 0, "Count of items to process");
70 //
71 // No public methods of `absl::Flag<T>` are part of the Abseil Flags API.
72 #if !defined(_MSC_VER) || defined(__clang__)
73 template <typename T>
74 using Flag = flags_internal::Flag<T>;
75 #else
76 // MSVC debug builds do not implement initialization with constexpr constructors
77 // correctly. To work around this we add a level of indirection, so that the
78 // class `absl::Flag` contains an `internal::Flag*` (instead of being an alias
79 // to that class) and dynamically allocates an instance when necessary. We also
80 // forward all calls to internal::Flag methods via trampoline methods. In this
81 // setup the `absl::Flag` class does not have constructor and virtual methods,
82 // all the data members are public and thus MSVC is able to initialize it at
83 // link time. To deal with multiple threads accessing the flag for the first
84 // time concurrently we use an atomic boolean indicating if flag object is
85 // initialized. We also employ the double-checked locking pattern where the
86 // second level of protection is a global Mutex, so if two threads attempt to
87 // construct the flag concurrently only one wins.
88 // This solution is based on a recomendation here:
89 // https://developercommunity.visualstudio.com/content/problem/336946/class-with-constexpr-constructor-not-using-static.html?childToView=648454#comment-648454
90 
91 namespace flags_internal {
92 absl::Mutex* GetGlobalConstructionGuard();
93 }  // namespace flags_internal
94 
95 template <typename T>
96 class Flag {
97  public:
98   // No constructor and destructor to ensure this is an aggregate type.
99   // Visual Studio 2015 still requires the constructor for class to be
100   // constexpr initializable.
101 #if _MSC_VER <= 1900
102   constexpr Flag(const char* name, const char* filename,
103                  const flags_internal::HelpGenFunc help_gen,
104                  const flags_internal::FlagDfltGenFunc default_value_gen)
105       : name_(name),
106         filename_(filename),
107         help_gen_(help_gen),
108         default_value_gen_(default_value_gen),
109         inited_(false),
110         impl_(nullptr) {}
111 #endif
112 
113   flags_internal::Flag<T>* GetImpl() const {
114     if (!inited_.load(std::memory_order_acquire)) {
115       absl::MutexLock l(flags_internal::GetGlobalConstructionGuard());
116 
117       if (inited_.load(std::memory_order_acquire)) {
118         return impl_;
119       }
120 
121       impl_ =
122           new flags_internal::Flag<T>(name_, filename_,
123                                       {flags_internal::FlagHelpMsg(help_gen_),
124                                        flags_internal::FlagHelpKind::kGenFunc},
125                                       default_value_gen_);
126       inited_.store(true, std::memory_order_release);
127     }
128 
129     return impl_;
130   }
131 
132   // Public methods of `absl::Flag<T>` are NOT part of the Abseil Flags API.
133   // See https://abseil.io/docs/cpp/guides/flags
134   bool IsRetired() const { return GetImpl()->IsRetired(); }
135   bool IsAbseilFlag() const { return GetImpl()->IsAbseilFlag(); }
136   absl::string_view Name() const { return GetImpl()->Name(); }
137   std::string Help() const { return GetImpl()->Help(); }
138   bool IsModified() const { return GetImpl()->IsModified(); }
139   bool IsSpecifiedOnCommandLine() const {
140     return GetImpl()->IsSpecifiedOnCommandLine();
141   }
142   absl::string_view Typename() const { return GetImpl()->Typename(); }
143   std::string Filename() const { return GetImpl()->Filename(); }
144   std::string DefaultValue() const { return GetImpl()->DefaultValue(); }
145   std::string CurrentValue() const { return GetImpl()->CurrentValue(); }
146   template <typename U>
147   inline bool IsOfType() const {
148     return GetImpl()->template IsOfType<U>();
149   }
150   T Get() const { return GetImpl()->Get(); }
151   bool AtomicGet(T* v) const { return GetImpl()->AtomicGet(v); }
152   void Set(const T& v) { GetImpl()->Set(v); }
153   void SetCallback(const flags_internal::FlagCallbackFunc mutation_callback) {
154     GetImpl()->SetCallback(mutation_callback);
155   }
156   void InvokeCallback() { GetImpl()->InvokeCallback(); }
157 
158   // The data members are logically private, but they need to be public for
159   // this to be an aggregate type.
160   const char* name_;
161   const char* filename_;
162   const flags_internal::HelpGenFunc help_gen_;
163   const flags_internal::FlagDfltGenFunc default_value_gen_;
164 
165   mutable std::atomic<bool> inited_;
166   mutable flags_internal::Flag<T>* impl_;
167 };
168 #endif
169 
170 // GetFlag()
171 //
172 // Returns the value (of type `T`) of an `absl::Flag<T>` instance, by value. Do
173 // not construct an `absl::Flag<T>` directly and call `absl::GetFlag()`;
174 // instead, refer to flag's constructed variable name (e.g. `FLAGS_name`).
175 // Because this function returns by value and not by reference, it is
176 // thread-safe, but note that the operation may be expensive; as a result, avoid
177 // `absl::GetFlag()` within any tight loops.
178 //
179 // Example:
180 //
181 //   // FLAGS_count is a Flag of type `int`
182 //   int my_count = absl::GetFlag(FLAGS_count);
183 //
184 //   // FLAGS_firstname is a Flag of type `std::string`
185 //   std::string first_name = absl::GetFlag(FLAGS_firstname);
186 template <typename T>
GetFlag(const absl::Flag<T> & flag)187 ABSL_MUST_USE_RESULT T GetFlag(const absl::Flag<T>& flag) {
188   return flag.Get();
189 }
190 
191 // SetFlag()
192 //
193 // Sets the value of an `absl::Flag` to the value `v`. Do not construct an
194 // `absl::Flag<T>` directly and call `absl::SetFlag()`; instead, use the
195 // flag's variable name (e.g. `FLAGS_name`). This function is
196 // thread-safe, but is potentially expensive. Avoid setting flags in general,
197 // but especially within performance-critical code.
198 template <typename T>
SetFlag(absl::Flag<T> * flag,const T & v)199 void SetFlag(absl::Flag<T>* flag, const T& v) {
200   flag->Set(v);
201 }
202 
203 // Overload of `SetFlag()` to allow callers to pass in a value that is
204 // convertible to `T`. E.g., use this overload to pass a "const char*" when `T`
205 // is `std::string`.
206 template <typename T, typename V>
SetFlag(absl::Flag<T> * flag,const V & v)207 void SetFlag(absl::Flag<T>* flag, const V& v) {
208   T value(v);
209   flag->Set(value);
210 }
211 
212 ABSL_NAMESPACE_END
213 }  // namespace absl
214 
215 
216 // ABSL_FLAG()
217 //
218 // This macro defines an `absl::Flag<T>` instance of a specified type `T`:
219 //
220 //   ABSL_FLAG(T, name, default_value, help);
221 //
222 // where:
223 //
224 //   * `T` is a supported flag type (see the list of types in `marshalling.h`),
225 //   * `name` designates the name of the flag (as a global variable
226 //     `FLAGS_name`),
227 //   * `default_value` is an expression holding the default value for this flag
228 //     (which must be implicitly convertible to `T`),
229 //   * `help` is the help text, which can also be an expression.
230 //
231 // This macro expands to a flag named 'FLAGS_name' of type 'T':
232 //
233 //   absl::Flag<T> FLAGS_name = ...;
234 //
235 // Note that all such instances are created as global variables.
236 //
237 // For `ABSL_FLAG()` values that you wish to expose to other translation units,
238 // it is recommended to define those flags within the `.cc` file associated with
239 // the header where the flag is declared.
240 //
241 // Note: do not construct objects of type `absl::Flag<T>` directly. Only use the
242 // `ABSL_FLAG()` macro for such construction.
243 #define ABSL_FLAG(Type, name, default_value, help) \
244   ABSL_FLAG_IMPL(Type, name, default_value, help)
245 
246 // ABSL_FLAG().OnUpdate()
247 //
248 // Defines a flag of type `T` with a callback attached:
249 //
250 //   ABSL_FLAG(T, name, default_value, help).OnUpdate(callback);
251 //
252 // After any setting of the flag value, the callback will be called at least
253 // once. A rapid sequence of changes may be merged together into the same
254 // callback. No concurrent calls to the callback will be made for the same
255 // flag. Callbacks are allowed to read the current value of the flag but must
256 // not mutate that flag.
257 //
258 // The update mechanism guarantees "eventual consistency"; if the callback
259 // derives an auxiliary data structure from the flag value, it is guaranteed
260 // that eventually the flag value and the derived data structure will be
261 // consistent.
262 //
263 // Note: ABSL_FLAG.OnUpdate() does not have a public definition. Hence, this
264 // comment serves as its API documentation.
265 
266 
267 // -----------------------------------------------------------------------------
268 // Implementation details below this section
269 // -----------------------------------------------------------------------------
270 
271 // ABSL_FLAG_IMPL macro definition conditional on ABSL_FLAGS_STRIP_NAMES
272 
273 #if ABSL_FLAGS_STRIP_NAMES
274 #define ABSL_FLAG_IMPL_FLAGNAME(txt) ""
275 #define ABSL_FLAG_IMPL_FILENAME() ""
276 #if !defined(_MSC_VER) || defined(__clang__)
277 #define ABSL_FLAG_IMPL_REGISTRAR(T, flag) \
278   absl::flags_internal::FlagRegistrar<T, false>(&flag)
279 #else
280 #define ABSL_FLAG_IMPL_REGISTRAR(T, flag) \
281   absl::flags_internal::FlagRegistrar<T, false>(flag.GetImpl())
282 #endif
283 #else
284 #define ABSL_FLAG_IMPL_FLAGNAME(txt) txt
285 #define ABSL_FLAG_IMPL_FILENAME() __FILE__
286 #if !defined(_MSC_VER) || defined(__clang__)
287 #define ABSL_FLAG_IMPL_REGISTRAR(T, flag) \
288   absl::flags_internal::FlagRegistrar<T, true>(&flag)
289 #else
290 #define ABSL_FLAG_IMPL_REGISTRAR(T, flag) \
291   absl::flags_internal::FlagRegistrar<T, true>(flag.GetImpl())
292 #endif
293 #endif
294 
295 // ABSL_FLAG_IMPL macro definition conditional on ABSL_FLAGS_STRIP_HELP
296 
297 #if ABSL_FLAGS_STRIP_HELP
298 #define ABSL_FLAG_IMPL_FLAGHELP(txt) absl::flags_internal::kStrippedFlagHelp
299 #else
300 #define ABSL_FLAG_IMPL_FLAGHELP(txt) txt
301 #endif
302 
303 // AbslFlagHelpGenFor##name is used to encapsulate both immediate (method Const)
304 // and lazy (method NonConst) evaluation of help message expression. We choose
305 // between the two via the call to HelpArg in absl::Flag instantiation below.
306 // If help message expression is constexpr evaluable compiler will optimize
307 // away this whole struct.
308 #define ABSL_FLAG_IMPL_DECLARE_HELP_WRAPPER(name, txt)                     \
309   struct AbslFlagHelpGenFor##name {                                        \
310     template <typename T = void>                                           \
311     static constexpr const char* Const() {                                 \
312       return absl::flags_internal::HelpConstexprWrap(                      \
313           ABSL_FLAG_IMPL_FLAGHELP(txt));                                   \
314     }                                                                      \
315     static std::string NonConst() { return ABSL_FLAG_IMPL_FLAGHELP(txt); } \
316   }
317 
318 #define ABSL_FLAG_IMPL_DECLARE_DEF_VAL_WRAPPER(name, Type, default_value)   \
319   static void* AbslFlagsInitFlag##name() {                                  \
320     return absl::flags_internal::MakeFromDefaultValue<Type>(default_value); \
321   }
322 
323 // ABSL_FLAG_IMPL
324 //
325 // Note: Name of registrar object is not arbitrary. It is used to "grab"
326 // global name for FLAGS_no<flag_name> symbol, thus preventing the possibility
327 // of defining two flags with names foo and nofoo.
328 #if !defined(_MSC_VER) || defined(__clang__)
329 #define ABSL_FLAG_IMPL(Type, name, default_value, help)             \
330   namespace absl /* block flags in namespaces */ {}                 \
331   ABSL_FLAG_IMPL_DECLARE_DEF_VAL_WRAPPER(name, Type, default_value) \
332   ABSL_FLAG_IMPL_DECLARE_HELP_WRAPPER(name, help);                  \
333   ABSL_CONST_INIT absl::Flag<Type> FLAGS_##name{                    \
334       ABSL_FLAG_IMPL_FLAGNAME(#name), ABSL_FLAG_IMPL_FILENAME(),    \
335       absl::flags_internal::HelpArg<AbslFlagHelpGenFor##name>(0),   \
336       &AbslFlagsInitFlag##name};                                    \
337   extern bool FLAGS_no##name;                                       \
338   bool FLAGS_no##name = ABSL_FLAG_IMPL_REGISTRAR(Type, FLAGS_##name)
339 #else
340 // MSVC version uses aggregate initialization. We also do not try to
341 // optimize away help wrapper.
342 #define ABSL_FLAG_IMPL(Type, name, default_value, help)               \
343   namespace absl /* block flags in namespaces */ {}                   \
344   ABSL_FLAG_IMPL_DECLARE_DEF_VAL_WRAPPER(name, Type, default_value)   \
345   ABSL_FLAG_IMPL_DECLARE_HELP_WRAPPER(name, help);                    \
346   ABSL_CONST_INIT absl::Flag<Type> FLAGS_##name{                      \
347       ABSL_FLAG_IMPL_FLAGNAME(#name), ABSL_FLAG_IMPL_FILENAME(),      \
348       &AbslFlagHelpGenFor##name::NonConst, &AbslFlagsInitFlag##name}; \
349   extern bool FLAGS_no##name;                                         \
350   bool FLAGS_no##name = ABSL_FLAG_IMPL_REGISTRAR(Type, FLAGS_##name)
351 #endif
352 
353 // ABSL_RETIRED_FLAG
354 //
355 // Designates the flag (which is usually pre-existing) as "retired." A retired
356 // flag is a flag that is now unused by the program, but may still be passed on
357 // the command line, usually by production scripts. A retired flag is ignored
358 // and code can't access it at runtime.
359 //
360 // This macro registers a retired flag with given name and type, with a name
361 // identical to the name of the original flag you are retiring. The retired
362 // flag's type can change over time, so that you can retire code to support a
363 // custom flag type.
364 //
365 // This macro has the same signature as `ABSL_FLAG`. To retire a flag, simply
366 // replace an `ABSL_FLAG` definition with `ABSL_RETIRED_FLAG`, leaving the
367 // arguments unchanged (unless of course you actually want to retire the flag
368 // type at this time as well).
369 //
370 // `default_value` is only used as a double check on the type. `explanation` is
371 // unused.
372 // TODO(rogeeff): Return an anonymous struct instead of bool, and place it into
373 // the unnamed namespace.
374 #define ABSL_RETIRED_FLAG(type, flagname, default_value, explanation) \
375   ABSL_ATTRIBUTE_UNUSED static const bool ignored_##flagname =        \
376       ([] { return type(default_value); },                            \
377        absl::flags_internal::RetiredFlag<type>(#flagname))
378 
379 #endif  // ABSL_FLAGS_FLAG_H_
380