summaryrefslogtreecommitdiff
path: root/absl/flags/flag.h
blob: 185bd8aba2a27a2bdd7c7d53782a59276369dc72 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
//
//  Copyright 2019 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// -----------------------------------------------------------------------------
// File: flag.h
// -----------------------------------------------------------------------------
//
// This header file defines the `absl::Flag<T>` type for holding command-line
// flag data, and abstractions to create, get and set such flag data.
//
// It is important to note that this type is **unspecified** (an implementation
// detail) and you do not construct or manipulate actual `absl::Flag<T>`
// instances. Instead, you define and declare flags using the
// `ABSL_FLAG()` and `ABSL_DECLARE_FLAG()` macros, and get and set flag values
// using the `absl::GetFlag()` and `absl::SetFlag()` functions.

#ifndef ABSL_FLAGS_FLAG_H_
#define ABSL_FLAGS_FLAG_H_

#include "absl/base/attributes.h"
#include "absl/base/casts.h"
#include "absl/flags/config.h"
#include "absl/flags/declare.h"
#include "absl/flags/internal/commandlineflag.h"
#include "absl/flags/internal/flag.h"
#include "absl/flags/marshalling.h"

namespace absl {

// Flag
//
// An `absl::Flag` holds a command-line flag value, providing a runtime
// parameter to a binary. Such flags should be defined in the global namespace
// and (preferably) in the module containing the binary's `main()` function.
//
// You should not construct and cannot use the `absl::Flag` type directly;
// instead, you should declare flags using the `ABSL_DECLARE_FLAG()` macro
// within a header file, and define your flag using `ABSL_FLAG()` within your
// header's associated `.cc` file. Such flags will be named `FLAGS_name`.
//
// Example:
//
//    .h file
//
//      // Declares usage of a flag named "FLAGS_count"
//      ABSL_DECLARE_FLAG(int, count);
//
//    .cc file
//
//      // Defines a flag named "FLAGS_count" with a default `int` value of 0.
//      ABSL_FLAG(int, count, 0, "Count of items to process");
//
// No public methods of `absl::Flag<T>` are part of the Abseil Flags API.
template <typename T>
using Flag = flags_internal::Flag<T>;

// GetFlag()
//
// Returns the value (of type `T`) of an `absl::Flag<T>` instance, by value. Do
// not construct an `absl::Flag<T>` directly and call `absl::GetFlag()`;
// instead, refer to flag's constructed variable name (e.g. `FLAGS_name`).
// Because this function returns by value and not by reference, it is
// thread-safe, but note that the operation may be expensive; as a result, avoid
// `absl::GetFlag()` within any tight loops.
//
// Example:
//
//   // FLAGS_count is a Flag of type `int`
//   int my_count = absl::GetFlag(FLAGS_count);
//
//   // FLAGS_firstname is a Flag of type `std::string`
//   std::string first_name = absl::GetFlag(FLAGS_firstname);
template <typename T>
T GetFlag(const absl::Flag<T>& flag) {
#define ABSL_FLAGS_INTERNAL_LOCK_FREE_VALIDATE(BIT) \
  static_assert(                                    \
      !std::is_same<T, BIT>::value,                 \
      "Do not specify explicit template parameters to absl::GetFlag");
  ABSL_FLAGS_INTERNAL_FOR_EACH_LOCK_FREE(ABSL_FLAGS_INTERNAL_LOCK_FREE_VALIDATE)
#undef ABSL_FLAGS_INTERNAL_LOCK_FREE_VALIDATE

  // Implementation notes:
  //
  // We are wrapping a union around the value of `T` to serve three purposes:
  //
  //  1. `U.value` has correct size and alignment for a value of type `T`
  //  2. The `U.value` constructor is not invoked since U's constructor does not
  //     do it explicitly.
  //  3. The `U.value` destructor is invoked since U's destructor does it
  //     explicitly. This makes `U` a kind of RAII wrapper around non default
  //     constructible value of T, which is destructed when we leave the scope.
  //     We do need to destroy U.value, which is constructed by
  //     CommandLineFlag::Read even though we left it in a moved-from state
  //     after std::move.
  //
  // All of this serves to avoid requiring `T` being default constructible.
  union U {
    T value;
    U() {}
    ~U() { value.~T(); }
  };
  U u;

  flag.internal.Read(&u.value, &flags_internal::FlagOps<T>);
  return std::move(u.value);
}

// Overload for `GetFlag()` for types that support lock-free reads.
#define ABSL_FLAGS_INTERNAL_LOCK_FREE_EXPORT(T) \
  extern T GetFlag(const absl::Flag<T>& flag);
ABSL_FLAGS_INTERNAL_FOR_EACH_LOCK_FREE(ABSL_FLAGS_INTERNAL_LOCK_FREE_EXPORT)
#undef ABSL_FLAGS_INTERNAL_LOCK_FREE_EXPORT

// SetFlag()
//
// Sets the value of an `absl::Flag` to the value `v`. Do not construct an
// `absl::Flag<T>` directly and call `absl::SetFlag()`; instead, use the
// flag's variable name (e.g. `FLAGS_name`). This function is
// thread-safe, but is potentially expensive. Avoid setting flags in general,
// but especially within performance-critical code.
template <typename T>
void SetFlag(absl::Flag<T>* flag, const T& v) {
  flag->internal.Write(&v, &flags_internal::FlagOps<T>);
}

// Overload of `SetFlag()` to allow callers to pass in a value that is
// convertible to `T`. E.g., use this overload to pass a "const char*" when `T`
// is `std::string`.
template <typename T, typename V>
void SetFlag(absl::Flag<T>* flag, const V& v) {
  T value(v);
  SetFlag<T>(flag, value);
}

}  // namespace absl


// ABSL_FLAG()
//
// This macro defines an `absl::Flag<T>` instance of a specified type `T`:
//
//   ABSL_FLAG(T, name, default_value, help);
//
// where:
//
//   * `T` is a supported flag type (see `marshalling.h`),
//   * `name` designates the name of the flag (as a global variable
//     `FLAGS_name`),
//   * `default_value` is an expression holding the default value for this flag
//     (which must be implicitly convertible to `T`),
//   * `help` is the help text, which can also be an expression.
//
// This macro expands to a flag named 'FLAGS_name' of type 'T':
//
//   absl::Flag<T> FLAGS_name = ...;
//
// Note that all such instances are created as global variables.
//
// For `ABSL_FLAG()` values that you wish to expose to other translation units,
// it is recommended to define those flags within the `.cc` file associated with
// the header where the flag is declared.
//
// Note: do not construct objects of type `absl::Flag<T>` directly. Only use the
// `ABSL_FLAG()` macro for such construction.
#define ABSL_FLAG(Type, name, default_value, help) \
  ABSL_FLAG_IMPL(Type, name, default_value, help)

// ABSL_FLAG().OnUpdate()
//
// Defines a flag of type `T` with a callback attached:
//
//   ABSL_FLAG(T, name, default_value, help).OnUpdate(callback);
//
// After any setting of the flag value, the callback will be called at least
// once. A rapid sequence of changes may be merged together into the same
// callback. No concurrent calls to the callback will be made for the same
// flag. Callbacks are allowed to read the current value of the flag but must
// not mutate that flag.
//
// The update mechanism guarantees "eventual consistency"; if the callback
// derives an auxiliary data structure from the flag value, it is guaranteed
// that eventually the flag value and the derived data structure will be
// consistent.
//
// Note: ABSL_FLAG.OnUpdate() does not have a public definition. Hence, this
// comment serves as its API documentation.


// -----------------------------------------------------------------------------
// Implementation details below this section
// -----------------------------------------------------------------------------

// ABSL_FLAG_IMPL macro definition conditional on ABSL_FLAGS_STRIP_NAMES

#if ABSL_FLAGS_STRIP_NAMES
#define ABSL_FLAG_IMPL_FLAGNAME(txt) ""
#define ABSL_FLAG_IMPL_FILENAME() ""
#define ABSL_FLAG_IMPL_REGISTRAR(T, flag) \
  absl::flags_internal::FlagRegistrar<T, false>(&flag)
#else
#define ABSL_FLAG_IMPL_FLAGNAME(txt) txt
#define ABSL_FLAG_IMPL_FILENAME() __FILE__
#define ABSL_FLAG_IMPL_REGISTRAR(T, flag) \
  absl::flags_internal::FlagRegistrar<T, true>(&flag)
#endif

// ABSL_FLAG_IMPL macro definition conditional on ABSL_FLAGS_STRIP_HELP

#if ABSL_FLAGS_STRIP_HELP
#define ABSL_FLAG_IMPL_FLAGHELP(txt) absl::flags_internal::kStrippedFlagHelp
#else
#define ABSL_FLAG_IMPL_FLAGHELP(txt) txt
#endif

#define ABSL_FLAG_IMPL_DECLARE_HELP_WRAPPER(name, txt) \
  static std::string AbslFlagsWrapHelp##name() {       \
    return ABSL_FLAG_IMPL_FLAGHELP(txt);               \
  }

#define ABSL_FLAG_IMPL_DECLARE_DEF_VAL_WRAPPER(name, Type, default_value)   \
  static void* AbslFlagsInitFlag##name() {                                  \
    return absl::flags_internal::MakeFromDefaultValue<Type>(default_value); \
  }

// ABSL_FLAG_IMPL
//
// Note: Name of registrar object is not arbitrary. It is used to "grab"
// global name for FLAGS_no<flag_name> symbol, thus preventing the possibility
// of defining two flags with names foo and nofoo.
#define ABSL_FLAG_IMPL(Type, name, default_value, help)                   \
  namespace absl {}                                                       \
  ABSL_FLAG_IMPL_DECLARE_DEF_VAL_WRAPPER(name, Type, default_value)       \
  ABSL_FLAG_IMPL_DECLARE_HELP_WRAPPER(name, help)                         \
  absl::Flag<Type> FLAGS_##name(                                          \
      ABSL_FLAG_IMPL_FLAGNAME(#name),                                     \
      &AbslFlagsWrapHelp##name,                                           \
      ABSL_FLAG_IMPL_FILENAME(),                                          \
      &absl::flags_internal::FlagMarshallingOps<Type>,                    \
      &AbslFlagsInitFlag##name);                                          \
  extern bool FLAGS_no##name;                                             \
  bool FLAGS_no##name = ABSL_FLAG_IMPL_REGISTRAR(Type, FLAGS_##name)

// ABSL_RETIRED_FLAG
//
// Designates the flag (which is usually pre-existing) as "retired." A retired
// flag is a flag that is now unused by the program, but may still be passed on
// the command line, usually by production scripts. A retired flag is ignored
// and code can't access it at runtime.
//
// This macro registers a retired flag with given name and type, with a name
// identical to the name of the original flag you are retiring. The retired
// flag's type can change over time, so that you can retire code to support a
// custom flag type.
//
// This macro has the same signature as `ABSL_FLAG`. To retire a flag, simply
// replace an `ABSL_FLAG` definition with `ABSL_RETIRED_FLAG`, leaving the
// arguments unchanged (unless of course you actually want to retire the flag
// type at this time as well).
//
// `default_value` is only used as a double check on the type. `explanation` is
// unused.
// TODO(rogeeff): Return an anonymous struct instead of bool, and place it into
// the unnamed namespace.
#define ABSL_RETIRED_FLAG(type, flagname, default_value, explanation) \
  ABSL_ATTRIBUTE_UNUSED static const bool ignored_##flagname =        \
      ([] { return type(default_value); },                            \
       absl::flags_internal::RetiredFlag<type>(#flagname))

#endif  // ABSL_FLAGS_FLAG_H_