Export of internal Abseil changes

--
832be2d52d7695cf72fd70248909791fb8ad1003 by Gennadiy Rozental <rogeeff@google.com>:

Migrate some FlagImpl fields to bit fields.

To save padding space we are migrating some fields representing bool and enums into bit fields. Eventually we'll use remaining padding space for call_once control flag.

No other semantic changes made in this CL.

PiperOrigin-RevId: 293878165

--
09162bba5fd8eddacfd732d46fcfeb33074a259f by Samuel Benzaquen <sbenza@google.com>:

Correctly initialize the `length_mod` member.
Now that it is a raw enum, the default initialization is not enough.

PiperOrigin-RevId: 293827817

--
842b7b805d75c5ab670c52ccd7368cdeba11853d by Matthew Brown <matthewbr@google.com>:

Move str_format_internal::LengthMod from extension.h to parser.h; change to enum

PiperOrigin-RevId: 293697274
GitOrigin-RevId: 832be2d52d7695cf72fd70248909791fb8ad1003
Change-Id: I90899519e9480543e22638616fdf31a41e7f75c0
This commit is contained in:
Abseil Team 2020-02-07 13:06:07 -08:00 committed by Andy Getz
parent 24713a7036
commit d95d156716
9 changed files with 120 additions and 132 deletions

View file

@ -120,7 +120,7 @@ void FlagImpl::Destroy() {
if (value_.dynamic) Delete(op_, value_.dynamic);
// Release the dynamically allocated default value if any.
if (def_kind_ == FlagDefaultSrcKind::kDynamicValue) {
if (DefaultKind() == FlagDefaultKind::kDynamicValue) {
Delete(op_, default_src_.dynamic_value);
}
@ -135,7 +135,7 @@ void FlagImpl::Destroy() {
std::unique_ptr<void, DynValueDeleter> FlagImpl::MakeInitValue() const {
void* res = nullptr;
if (def_kind_ == FlagDefaultSrcKind::kDynamicValue) {
if (DefaultKind() == FlagDefaultKind::kDynamicValue) {
res = Clone(op_, default_src_.dynamic_value);
} else {
res = (*default_src_.gen_func)();
@ -150,8 +150,8 @@ std::string FlagImpl::Filename() const {
}
std::string FlagImpl::Help() const {
return help_source_kind_ == FlagHelpKind::kLiteral ? help_.literal
: help_.gen_func();
return HelpSourceKind() == FlagHelpKind::kLiteral ? help_.literal
: help_.gen_func();
}
bool FlagImpl::IsModified() const {
@ -364,7 +364,7 @@ bool FlagImpl::SetFromString(absl::string_view value, FlagSettingMode set_mode,
break;
}
case SET_FLAGS_DEFAULT: {
if (def_kind_ == FlagDefaultSrcKind::kDynamicValue) {
if (DefaultKind() == FlagDefaultKind::kDynamicValue) {
if (!TryParse(&default_src_.dynamic_value, value, err)) {
return false;
}
@ -375,7 +375,7 @@ bool FlagImpl::SetFromString(absl::string_view value, FlagSettingMode set_mode,
}
default_src_.dynamic_value = new_default_val;
def_kind_ = FlagDefaultSrcKind::kDynamicValue;
def_kind_ = static_cast<uint8_t>(FlagDefaultKind::kDynamicValue);
}
if (!modified_) {

View file

@ -87,7 +87,7 @@ union FlagHelpMsg {
HelpGenFunc gen_func;
};
enum class FlagHelpKind : int8_t { kLiteral, kGenFunc };
enum class FlagHelpKind : uint8_t { kLiteral = 0, kGenFunc = 1 };
struct FlagHelpArg {
FlagHelpMsg source;
@ -147,7 +147,7 @@ union FlagDefaultSrc {
FlagDfltGenFunc gen_func;
};
enum class FlagDefaultSrcKind : int8_t { kDynamicValue, kGenFunc };
enum class FlagDefaultKind : uint8_t { kDynamicValue = 0, kGenFunc = 1 };
///////////////////////////////////////////////////////////////////////////////
// Flag current value auxiliary structs.
@ -279,8 +279,14 @@ class FlagImpl {
op_(op),
marshalling_op_(marshalling_op),
help_(help.source),
help_source_kind_(help.kind),
def_kind_(FlagDefaultSrcKind::kGenFunc),
help_source_kind_(static_cast<uint8_t>(help.kind)),
def_kind_(static_cast<uint8_t>(FlagDefaultKind::kGenFunc)),
is_data_guard_inited_(false),
modified_(false),
on_command_line_(false),
inited_(false),
counter_(0),
callback_(nullptr),
default_src_(default_value_gen),
data_guard_{} {}
@ -370,6 +376,14 @@ class FlagImpl {
// Lazy initialization of the Flag's data.
void Init();
FlagHelpKind HelpSourceKind() const {
return static_cast<FlagHelpKind>(help_source_kind_);
}
FlagDefaultKind DefaultKind() const
ABSL_EXCLUSIVE_LOCKS_REQUIRED(*DataGuard()) {
return static_cast<FlagDefaultKind>(def_kind_);
}
// Immutable flag's state.
// Flags name passed to ABSL_FLAG as second arg.
@ -383,35 +397,31 @@ class FlagImpl {
// Help message literal or function to generate it.
const FlagHelpMsg help_;
// Indicates if help message was supplied as literal or generator func.
const FlagHelpKind help_source_kind_;
// Indicates that the Flag state is initialized.
std::atomic<bool> inited_{false};
const uint8_t help_source_kind_ : 1;
// Mutable flag's state (guarded by `data_guard_`).
// Protects against multiple concurrent constructions of `data_guard_`.
bool is_data_guard_inited_ = false;
// Has this flag's value been modified?
bool modified_ ABSL_GUARDED_BY(*DataGuard()) = false;
// Has this flag been specified on command line.
bool on_command_line_ ABSL_GUARDED_BY(*DataGuard()) = false;
// Mutation counter
int64_t counter_ ABSL_GUARDED_BY(*DataGuard()) = 0;
// Optional flag's callback and absl::Mutex to guard the invocations.
FlagCallback* callback_ ABSL_GUARDED_BY(*DataGuard()) = nullptr;
// If def_kind_ == kDynamicValue, default_src_ holds a dynamically allocated
// value.
FlagDefaultSrcKind def_kind_ ABSL_GUARDED_BY(*DataGuard());
uint8_t def_kind_ : 1 ABSL_GUARDED_BY(*DataGuard());
// Protects against multiple concurrent constructions of `data_guard_`.
bool is_data_guard_inited_ : 1;
// Has this flag's value been modified?
bool modified_ : 1 ABSL_GUARDED_BY(*DataGuard());
// Has this flag been specified on command line.
bool on_command_line_ : 1 ABSL_GUARDED_BY(*DataGuard());
// Indicates that the flag state is initialized.
std::atomic<bool> inited_;
// Mutation counter
int64_t counter_ ABSL_GUARDED_BY(*DataGuard());
// Optional flag's callback and absl::Mutex to guard the invocations.
FlagCallback* callback_ ABSL_GUARDED_BY(*DataGuard());
// Either a pointer to the function generating the default value based on the
// value specified in ABSL_FLAG or pointer to the dynamically set default
// value via SetCommandLineOptionWithMode. def_kind_ is used to distinguish
// these two cases.
FlagDefaultSrc default_src_ ABSL_GUARDED_BY(*DataGuard());
// Current Flag Value
FlagValue value_;

View file

@ -77,7 +77,6 @@ inline bool ArgContext::Bind(const UnboundConversion* unbound,
bound->set_precision(-1);
}
bound->set_length_mod(unbound->length_mod);
bound->set_conv(unbound->conv);
bound->set_arg(arg);
return true;
@ -143,7 +142,7 @@ class SummarizingConverter {
ss << "{" << Streamable(spec, {*bound.arg()}) << ":" << bound.flags();
if (bound.width() >= 0) ss << bound.width();
if (bound.precision() >= 0) ss << "." << bound.precision();
ss << bound.length_mod() << bound.conv() << "}";
ss << bound.conv() << "}";
Append(ss.str());
return true;
}

View file

@ -113,18 +113,18 @@ TEST_F(FormatBindTest, FormatPack) {
FormatArgImpl(ia[2]), FormatArgImpl(ia[3]),
FormatArgImpl(ia[4])};
const Expectation kExpect[] = {
{__LINE__, "a%4db%dc", "a{10:4d}b{20:d}c"},
{__LINE__, "a%.4db%dc", "a{10:.4d}b{20:d}c"},
{__LINE__, "a%4.5db%dc", "a{10:4.5d}b{20:d}c"},
{__LINE__, "a%db%4.5dc", "a{10:d}b{20:4.5d}c"},
{__LINE__, "a%db%*.*dc", "a{10:d}b{40:20.30d}c"},
{__LINE__, "a%.*fb", "a{20:.10f}b"},
{__LINE__, "a%1$db%2$*3$.*4$dc", "a{10:d}b{20:30.40d}c"},
{__LINE__, "a%4$db%3$*2$.*1$dc", "a{40:d}b{30:20.10d}c"},
{__LINE__, "a%04ldb", "a{10:04ld}b"},
{__LINE__, "a%-#04lldb", "a{10:-#04lld}b"},
{__LINE__, "a%1$*5$db", "a{10:-10d}b"},
{__LINE__, "a%1$.*5$db", "a{10:d}b"},
{__LINE__, "a%4db%dc", "a{10:4d}b{20:d}c"},
{__LINE__, "a%.4db%dc", "a{10:.4d}b{20:d}c"},
{__LINE__, "a%4.5db%dc", "a{10:4.5d}b{20:d}c"},
{__LINE__, "a%db%4.5dc", "a{10:d}b{20:4.5d}c"},
{__LINE__, "a%db%*.*dc", "a{10:d}b{40:20.30d}c"},
{__LINE__, "a%.*fb", "a{20:.10f}b"},
{__LINE__, "a%1$db%2$*3$.*4$dc", "a{10:d}b{20:30.40d}c"},
{__LINE__, "a%4$db%3$*2$.*1$dc", "a{40:d}b{30:20.10d}c"},
{__LINE__, "a%04ldb", "a{10:04d}b"},
{__LINE__, "a%-#04lldb", "a{10:-#04d}b"},
{__LINE__, "a%1$*5$db", "a{10:-10d}b"},
{__LINE__, "a%1$.*5$db", "a{10:d}b"},
};
for (const Expectation &e : kExpect) {
absl::string_view fmt = e.fmt;

View file

@ -22,28 +22,6 @@
namespace absl {
ABSL_NAMESPACE_BEGIN
namespace str_format_internal {
namespace {
// clang-format off
#define ABSL_LENGTH_MODS_EXPAND_ \
X_VAL(h) X_SEP \
X_VAL(hh) X_SEP \
X_VAL(l) X_SEP \
X_VAL(ll) X_SEP \
X_VAL(L) X_SEP \
X_VAL(j) X_SEP \
X_VAL(z) X_SEP \
X_VAL(t) X_SEP \
X_VAL(q)
// clang-format on
} // namespace
const LengthMod::Spec LengthMod::kSpecs[] = {
#define X_VAL(id) { LengthMod::id, #id, strlen(#id) }
#define X_SEP ,
ABSL_LENGTH_MODS_EXPAND_, {LengthMod::none, "", 0}
#undef X_VAL
#undef X_SEP
};
const ConversionChar::Spec ConversionChar::kSpecs[] = {
#define X_VAL(id) { ConversionChar::id, #id[0] }
@ -64,8 +42,6 @@ std::string Flags::ToString() const {
return s;
}
const size_t LengthMod::kNumValues;
const size_t ConversionChar::kNumValues;
bool FormatSinkImpl::PutPaddedString(string_view v, int w, int p, bool l) {

View file

@ -136,54 +136,6 @@ struct Flags {
}
};
struct ABSL_DLL LengthMod {
public:
enum Id : uint8_t {
h, hh, l, ll, L, j, z, t, q, none
};
static const size_t kNumValues = none + 1;
LengthMod() : id_(none) {}
// Index into the opaque array of LengthMod enums.
// Requires: i < kNumValues
static LengthMod FromIndex(size_t i) {
return LengthMod(kSpecs[i].value);
}
static LengthMod FromId(Id id) { return LengthMod(id); }
// The length modifier std::string associated with a specified LengthMod.
string_view name() const {
const Spec& spec = kSpecs[id_];
return {spec.name, spec.name_length};
}
Id id() const { return id_; }
friend bool operator==(const LengthMod& a, const LengthMod& b) {
return a.id() == b.id();
}
friend bool operator!=(const LengthMod& a, const LengthMod& b) {
return !(a == b);
}
friend std::ostream& operator<<(std::ostream& os, const LengthMod& v) {
return os << v.name();
}
private:
struct Spec {
Id value;
const char *name;
size_t name_length;
};
static const Spec kSpecs[];
explicit LengthMod(Id id) : id_(id) {}
Id id_;
};
// clang-format off
#define ABSL_CONVERSION_CHARS_EXPAND_(X_VAL, X_SEP) \
/* text */ \
@ -306,7 +258,6 @@ struct ABSL_DLL ConversionChar {
class ConversionSpec {
public:
Flags flags() const { return flags_; }
LengthMod length_mod() const { return length_mod_; }
ConversionChar conv() const {
// Keep this field first in the struct . It generates better code when
// accessing it when ConversionSpec is passed by value in registers.
@ -322,7 +273,6 @@ class ConversionSpec {
int precision() const { return precision_; }
void set_flags(Flags f) { flags_ = f; }
void set_length_mod(LengthMod lm) { length_mod_ = lm; }
void set_conv(ConversionChar c) { conv_ = c; }
void set_width(int w) { width_ = w; }
void set_precision(int p) { precision_ = p; }
@ -331,7 +281,6 @@ class ConversionSpec {
private:
ConversionChar conv_;
Flags flags_;
LengthMod length_mod_;
int width_;
int precision_;
};

View file

@ -18,7 +18,8 @@ ABSL_NAMESPACE_BEGIN
namespace str_format_internal {
using CC = ConversionChar::Id;
using LM = LengthMod::Id;
using LM = LengthMod;
ABSL_CONST_INIT const ConvTag kTags[256] = {
{}, {}, {}, {}, {}, {}, {}, {}, // 00-07
{}, {}, {}, {}, {}, {}, {}, {}, // 08-0f
@ -205,11 +206,11 @@ flags_done:
using str_format_internal::LengthMod;
LengthMod length_mod = tag.as_length();
ABSL_FORMAT_PARSER_INTERNAL_GET_CHAR();
if (c == 'h' && length_mod.id() == LengthMod::h) {
conv->length_mod = LengthMod::FromId(LengthMod::hh);
if (c == 'h' && length_mod == LengthMod::h) {
conv->length_mod = LengthMod::hh;
ABSL_FORMAT_PARSER_INTERNAL_GET_CHAR();
} else if (c == 'l' && length_mod.id() == LengthMod::l) {
conv->length_mod = LengthMod::FromId(LengthMod::ll);
} else if (c == 'l' && length_mod == LengthMod::l) {
conv->length_mod = LengthMod::ll;
ABSL_FORMAT_PARSER_INTERNAL_GET_CHAR();
} else {
conv->length_mod = length_mod;
@ -228,6 +229,32 @@ flags_done:
} // namespace
std::string LengthModToString(LengthMod v) {
switch (v) {
case LengthMod::h:
return "h";
case LengthMod::hh:
return "hh";
case LengthMod::l:
return "l";
case LengthMod::ll:
return "ll";
case LengthMod::L:
return "L";
case LengthMod::j:
return "j";
case LengthMod::z:
return "z";
case LengthMod::t:
return "t";
case LengthMod::q:
return "q";
case LengthMod::none:
return "";
}
return "";
}
const char *ConsumeUnboundConversion(const char *p, const char *end,
UnboundConversion *conv, int *next_arg) {
if (*next_arg < 0) return ConsumeConversion<true>(p, end, conv, next_arg);

View file

@ -6,10 +6,12 @@
#include <stdlib.h>
#include <cassert>
#include <cstdint>
#include <initializer_list>
#include <iosfwd>
#include <iterator>
#include <memory>
#include <string>
#include <vector>
#include "absl/strings/internal/str_format/checker.h"
@ -19,6 +21,10 @@ namespace absl {
ABSL_NAMESPACE_BEGIN
namespace str_format_internal {
enum class LengthMod : std::uint8_t { h, hh, l, ll, L, j, z, t, q, none };
std::string LengthModToString(LengthMod v);
// The analyzed properties of a single specified conversion.
struct UnboundConversion {
UnboundConversion()
@ -60,7 +66,7 @@ struct UnboundConversion {
InputValue precision;
Flags flags;
LengthMod length_mod;
LengthMod length_mod = LengthMod::none;
ConversionChar conv;
};
@ -79,7 +85,8 @@ class ConvTag {
constexpr ConvTag(ConversionChar::Id id) : tag_(id) {} // NOLINT
// We invert the length modifiers to make them negative so that we can easily
// test for them.
constexpr ConvTag(LengthMod::Id id) : tag_(~id) {} // NOLINT
constexpr ConvTag(LengthMod length_mod) // NOLINT
: tag_(~static_cast<std::int8_t>(length_mod)) {}
// Everything else is -128, which is negative to make is_conv() simpler.
constexpr ConvTag() : tag_(-128) {}
@ -91,7 +98,7 @@ class ConvTag {
}
LengthMod as_length() const {
assert(is_length());
return LengthMod::FromId(static_cast<LengthMod::Id>(~tag_));
return static_cast<LengthMod>(~tag_);
}
private:

View file

@ -17,7 +17,7 @@ using testing::Pair;
TEST(LengthModTest, Names) {
struct Expectation {
int line;
LengthMod::Id id;
LengthMod mod;
const char *name;
};
const Expectation kExpect[] = {
@ -32,12 +32,10 @@ TEST(LengthModTest, Names) {
{__LINE__, LengthMod::t, "t" },
{__LINE__, LengthMod::q, "q" },
};
EXPECT_EQ(ABSL_ARRAYSIZE(kExpect), LengthMod::kNumValues);
EXPECT_EQ(ABSL_ARRAYSIZE(kExpect), 10);
for (auto e : kExpect) {
SCOPED_TRACE(e.line);
LengthMod mod = LengthMod::FromId(e.id);
EXPECT_EQ(e.id, mod.id());
EXPECT_EQ(e.name, mod.name());
EXPECT_EQ(e.name, LengthModToString(e.mod));
}
}
@ -127,7 +125,6 @@ TEST_F(ConsumeUnboundConversionTest, BasicConversion) {
EXPECT_FALSE(o.precision.is_from_arg());
EXPECT_LT(o.precision.value(), 0);
EXPECT_EQ(1, o.arg_position);
EXPECT_EQ(LengthMod::none, o.length_mod.id());
}
TEST_F(ConsumeUnboundConversionTest, ArgPosition) {
@ -290,6 +287,29 @@ TEST_F(ConsumeUnboundConversionTest, BasicFlag) {
}
}
TEST_F(ConsumeUnboundConversionTest, LengthMod) {
EXPECT_TRUE(Run("d"));
EXPECT_EQ(LengthMod::none, o.length_mod);
EXPECT_TRUE(Run("hd"));
EXPECT_EQ(LengthMod::h, o.length_mod);
EXPECT_TRUE(Run("hhd"));
EXPECT_EQ(LengthMod::hh, o.length_mod);
EXPECT_TRUE(Run("ld"));
EXPECT_EQ(LengthMod::l, o.length_mod);
EXPECT_TRUE(Run("lld"));
EXPECT_EQ(LengthMod::ll, o.length_mod);
EXPECT_TRUE(Run("Lf"));
EXPECT_EQ(LengthMod::L, o.length_mod);
EXPECT_TRUE(Run("qf"));
EXPECT_EQ(LengthMod::q, o.length_mod);
EXPECT_TRUE(Run("jd"));
EXPECT_EQ(LengthMod::j, o.length_mod);
EXPECT_TRUE(Run("zd"));
EXPECT_EQ(LengthMod::z, o.length_mod);
EXPECT_TRUE(Run("td"));
EXPECT_EQ(LengthMod::t, o.length_mod);
}
struct SummarizeConsumer {
std::string* out;
explicit SummarizeConsumer(std::string* out) : out(out) {}