Use enum to specify flag value type.

This commit is contained in:
dreamer.dead 2016-07-26 12:56:24 +03:00
parent fe57e5af4d
commit 7b43ae0f40
3 changed files with 92 additions and 34 deletions

View file

@ -191,7 +191,7 @@ static void ReportError(DieWhenReporting should_die, const char* format, ...) {
class CommandLineFlag;
class FlagValue {
public:
FlagValue(void* valbuf, const char* type, bool transfer_ownership_of_value);
FlagValue(void* valbuf, FlagValueType type, bool transfer_ownership_of_value);
~FlagValue();
bool ParseFrom(const char* spec);
@ -201,7 +201,7 @@ class FlagValue {
friend class CommandLineFlag; // for many things, including Validate()
friend class GFLAGS_NAMESPACE::FlagSaverImpl; // calls New()
friend class FlagRegistry; // checks value_buffer_ for flags_by_ptr_ map
template <typename T> friend T GetFromEnv(const char*, const char*, T);
template <typename T> friend T GetFromEnv(const char*, T);
friend bool TryParseLocked(const CommandLineFlag*, FlagValue*,
const char*, string*); // for New(), CopyFrom()
@ -215,6 +215,11 @@ class FlagValue {
FV_STRING = 6,
FV_MAX_INDEX = 6,
};
friend ValueType FromFlagValueType(FlagValueType flag_type);
FlagValue(void* valbuf, ValueType type, bool transfer_ownership_of_value);
const char* TypeName() const;
bool Equal(const FlagValue& x) const;
FlagValue* New() const; // creates a new one with default value
@ -228,13 +233,19 @@ class FlagValue {
bool Validate(const char* flagname, ValidateFnProto validate_fn_proto) const;
void* value_buffer_; // points to the buffer holding our data
int8 type_; // how to interpret value_
const int8 type_; // how to interpret value_
bool owns_value_; // whether to free value on destruct
FlagValue(const FlagValue&); // no copying!
void operator=(const FlagValue&);
};
inline FlagValue::ValueType FromFlagValueType(FlagValueType flag_type) {
COMPILE_ASSERT((int)FVT_MAX_INDEX == (int)FlagValue::FV_MAX_INDEX,
FlagValueType_enum_is_out_of_sync_with_ValueType_enum);
return static_cast<FlagValue::ValueType>(flag_type);
}
// This could be a templated method of FlagValue, but doing so adds to the
// size of the .o. Since there's no type-safety here anyway, macro is ok.
@ -242,18 +253,21 @@ class FlagValue {
#define OTHER_VALUE_AS(fv, type) *reinterpret_cast<type*>(fv.value_buffer_)
#define SET_VALUE_AS(type, value) VALUE_AS(type) = (value)
FlagValue::FlagValue(void* valbuf, const char* type,
FlagValue::FlagValue(void* valbuf, FlagValueType type,
bool transfer_ownership_of_value)
: value_buffer_(valbuf),
type_(FromFlagValueType(type)),
owns_value_(transfer_ownership_of_value) {
for (type_ = 0; type_ <= FV_MAX_INDEX; ++type_) {
if (!strcmp(type, TypeName())) {
break;
}
}
assert(type_ <= FV_MAX_INDEX); // Unknown typename
}
FlagValue::FlagValue(void* valbuf, FlagValue::ValueType type,
bool transfer_ownership_of_value)
: value_buffer_(valbuf),
type_(type),
owns_value_(transfer_ownership_of_value) {
}
FlagValue::~FlagValue() {
if (!owns_value_) {
return;
@ -438,7 +452,7 @@ bool FlagValue::Equal(const FlagValue& x) const {
}
FlagValue* FlagValue::New() const {
const char *type = TypeName();
const ValueType type = static_cast<ValueType>(type_);
switch (type_) {
case FV_BOOL: return new FlagValue(new bool(false), type, true);
case FV_INT32: return new FlagValue(new int32(0), type, true);
@ -1163,8 +1177,8 @@ string CommandLineFlagParser::ProcessFromenvLocked(const string& flagval,
}
const string envname = string("FLAGS_") + string(flagname);
string envval;
if (!SafeGetEnv(envname.c_str(), envval)) {
string envval;
if (!SafeGetEnv(envname.c_str(), envval)) {
if (errors_are_fatal) {
error_flags_[flagname] = (string(kError) + envname +
" not found in environment\n");
@ -1362,14 +1376,14 @@ string CommandLineFlagParser::ProcessOptionsFromStringLocked(
// --------------------------------------------------------------------
template<typename T>
T GetFromEnv(const char *varname, const char* type, T dflt) {
T GetFromEnv(const char *varname, T dflt) {
std::string valstr;
if (SafeGetEnv(varname, valstr)) {
FlagValue ifv(new T, type, true);
FlagValue ifv(new T, FlagTraits<T>::Type(), true);
if (!ifv.ParseFrom(valstr.c_str())) {
ReportError(DIE, "ERROR: error parsing env variable '%s' with value '%s'\n",
varname, valstr.c_str());
}
}
return OTHER_VALUE_AS(ifv, T);
} else return dflt;
}
@ -1416,15 +1430,12 @@ bool AddFlagValidator(const void* flag_ptr, ValidateFnProto validate_fn_proto) {
// values in a global destructor.
// --------------------------------------------------------------------
FlagRegisterer::FlagRegisterer(const char* name, const char* type,
FlagRegisterer::FlagRegisterer(const char* name, FlagValueType type,
const char* help, const char* filename,
void* current_storage, void* defvalue_storage) {
if (help == NULL)
help = "";
// FlagValue expects the type-name to not include any namespace
// components, so we get rid of those, if any.
if (strchr(type, ':'))
type = strrchr(type, ':') + 1;
FlagValue* current = new FlagValue(current_storage, type, false);
FlagValue* defvalue = new FlagValue(defvalue_storage, type, false);
// Importantly, flag_ will never be deleted, so storage is always good.
@ -1820,22 +1831,22 @@ bool ReadFromFlagsFile(const string& filename, const char* prog_name,
// --------------------------------------------------------------------
bool BoolFromEnv(const char *v, bool dflt) {
return GetFromEnv(v, "bool", dflt);
return GetFromEnv(v, dflt);
}
int32 Int32FromEnv(const char *v, int32 dflt) {
return GetFromEnv(v, "int32", dflt);
return GetFromEnv(v, dflt);
}
uint32 Uint32FromEnv(const char *v, uint32 dflt) {
return GetFromEnv(v, "uint32", dflt);
return GetFromEnv(v, dflt);
}
int64 Int64FromEnv(const char *v, int64 dflt) {
return GetFromEnv(v, "int64", dflt);
return GetFromEnv(v, dflt);
}
uint64 Uint64FromEnv(const char *v, uint64 dflt) {
return GetFromEnv(v, "uint64", dflt);
return GetFromEnv(v, dflt);
}
double DoubleFromEnv(const char *v, double dflt) {
return GetFromEnv(v, "double", dflt);
return GetFromEnv(v, dflt);
}
#ifdef _MSC_VER

View file

@ -429,11 +429,57 @@ extern GFLAGS_DLL_DECL void ShutDownCommandLineFlags();
// people can't DECLARE_int32 something that they DEFINE_bool'd
// elsewhere.
enum FlagValueType {
FVT_BOOL = 0,
FVT_INT32 = 1,
FVT_UINT32 = 2,
FVT_INT64 = 3,
FVT_UINT64 = 4,
FVT_DOUBLE = 5,
FVT_STRING = 6,
FVT_MAX_INDEX = 6
};
template <typename T, const FlagValueType type>
class FlagTraitsBase {
public:
typedef T ValueType;
static FlagValueType Type() { return type; }
};
template <typename T>
class FlagTraits;
template <>
class FlagTraits<bool> : public FlagTraitsBase<bool, FVT_BOOL> {};
template <>
class FlagTraits<int32> : public FlagTraitsBase<int32, FVT_INT32> {};
template <>
class FlagTraits<int64> : public FlagTraitsBase<int64, FVT_INT64> {};
template <>
class FlagTraits<uint32> : public FlagTraitsBase<uint32, FVT_UINT32> {};
template <>
class FlagTraits<uint64> : public FlagTraitsBase<uint64, FVT_UINT64> {};
template <>
class FlagTraits<double> : public FlagTraitsBase<double, FVT_DOUBLE> {};
template <>
class FlagTraits<std::string> : public FlagTraitsBase<std::string, FVT_STRING> {
};
class GFLAGS_DLL_DECL FlagRegisterer {
public:
FlagRegisterer(const char* name, const char* type,
FlagRegisterer(const char* name, FlagValueType type,
const char* help, const char* filename,
void* current_storage, void* defvalue_storage);
template <typename T>
FlagRegisterer(const char* name, const char* help, const char* filename,
T* current_storage, T* defvalue_storage) {
// Create a temporary value to call proper constructor.
(void)FlagRegisterer(name, FlagTraits<T>::Type(), help, filename,
current_storage, defvalue_storage);
}
};
// If your application #defines STRIP_FLAG_HELP to a non-zero value
@ -475,7 +521,7 @@ extern GFLAGS_DLL_DECL const char kStrippedFlagHelp[];
GFLAGS_DLL_DEFINE_FLAG type FLAGS_##name = FLAGS_nono##name; \
type FLAGS_no##name = FLAGS_nono##name; \
static GFLAGS_NAMESPACE::FlagRegisterer o_##name( \
#name, #type, MAYBE_STRIPPED_HELP(help), __FILE__, \
#name, MAYBE_STRIPPED_HELP(help), __FILE__, \
&FLAGS_##name, &FLAGS_no##name); \
} \
using fL##shorttype::FLAGS_##name
@ -581,7 +627,8 @@ public:
dont_pass0toDEFINE_string(s_##name[0].s, \
val); \
static GFLAGS_NAMESPACE::FlagRegisterer o_##name( \
#name, "string", MAYBE_STRIPPED_HELP(txt), __FILE__, \
#name, GFLAGS_NAMESPACE::FlagTraits<std::string>::Type(), \
MAYBE_STRIPPED_HELP(txt), __FILE__, \
s_##name[0].s, new (s_##name[1].s) clstring(*FLAGS_no##name)); \
static StringFlagDestructor d_##name(s_##name[0].s, s_##name[1].s); \
extern GFLAGS_DLL_DEFINE_FLAG clstring& FLAGS_##name; \

View file

@ -216,7 +216,7 @@ namespace fLI {
int32 FLAGS_tldflag1 = FLAGS_nonotldflag1;
int32 FLAGS_notldflag1 = FLAGS_nonotldflag1;
static FlagRegisterer o_tldflag1(
"tldflag1", "int32",
"tldflag1", GFLAGS_NAMESPACE::FlagTraits<int32>::Type(),
"should show up in --helpshort", "gflags_unittest.cc",
&FLAGS_tldflag1, &FLAGS_notldflag1);
}
@ -227,7 +227,7 @@ namespace fLI {
int32 FLAGS_tldflag2 = FLAGS_nonotldflag2;
int32 FLAGS_notldflag2 = FLAGS_nonotldflag2;
static FlagRegisterer o_tldflag2(
"tldflag2", "int32",
"tldflag2", GFLAGS_NAMESPACE::FlagTraits<int32>::Type(),
"should show up in --helpshort", "gflags_unittest.",
&FLAGS_tldflag2, &FLAGS_notldflag2);
}
@ -1353,9 +1353,9 @@ TEST(ParseCommandLineFlagsWrongFields,
// command line flags' values. If these are on the stack, then when
// later tests attempt to save and restore their values, the stack
// addresses of these variables will be overwritten... Stack smash!
static bool current_storage;
static bool defvalue_storage;
FlagRegisterer fr("flag_name", "bool", 0, "filename",
static int32 current_storage;
static int32 defvalue_storage;
FlagRegisterer fr("flag_name", NULL, "filename",
&current_storage, &defvalue_storage);
CommandLineFlagInfo fi;
EXPECT_TRUE(GetCommandLineFlagInfo("flag_name", &fi));