Get rid of unnecessary thread_local storage
This commit is contained in:
parent
24aa82a2c6
commit
01a61b547b
75
fmt/format.h
75
fmt/format.h
@ -156,15 +156,6 @@ typedef __int64 intmax_t;
|
|||||||
# include <utility> // for std::move
|
# include <utility> // for std::move
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef FMT_HAS_THREAD_LOCAL
|
|
||||||
// Thread local storage are available in GCC since version 4.8
|
|
||||||
// (https://gcc.gnu.org/projects/cxx-status.html) and in Visual C++
|
|
||||||
// since version 2015.
|
|
||||||
# define FMT_HAS_THREAD_LOCAL \
|
|
||||||
(FMT_HAS_FEATURE(cxx_thread_local) || \
|
|
||||||
(FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11) || FMT_MSC_VER >= 1900)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Check if exceptions are disabled.
|
// Check if exceptions are disabled.
|
||||||
#if defined(__GNUC__) && !defined(__EXCEPTIONS)
|
#if defined(__GNUC__) && !defined(__EXCEPTIONS)
|
||||||
# define FMT_EXCEPTIONS 0
|
# define FMT_EXCEPTIONS 0
|
||||||
@ -1388,10 +1379,13 @@ class ArgList {
|
|||||||
};
|
};
|
||||||
|
|
||||||
internal::Arg::Type type(unsigned index) const {
|
internal::Arg::Type type(unsigned index) const {
|
||||||
|
return type(types_, index);
|
||||||
|
}
|
||||||
|
static internal::Arg::Type type(uint64_t types, unsigned index) {
|
||||||
unsigned shift = index * 4;
|
unsigned shift = index * 4;
|
||||||
uint64_t mask = 0xf;
|
uint64_t mask = 0xf;
|
||||||
return static_cast<internal::Arg::Type>(
|
return static_cast<internal::Arg::Type>(
|
||||||
(types_ & (mask << shift)) >> shift);
|
(types & (mask << shift)) >> shift);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Char>
|
template <typename Char>
|
||||||
@ -1436,8 +1430,6 @@ class ArgList {
|
|||||||
return args_[index];
|
return args_[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
#if FMT_HAS_THREAD_LOCAL
|
|
||||||
|
|
||||||
// Cross-thread serialization facility
|
// Cross-thread serialization facility
|
||||||
|
|
||||||
template <typename Char>
|
template <typename Char>
|
||||||
@ -1451,12 +1443,9 @@ private:
|
|||||||
template <typename Char>
|
template <typename Char>
|
||||||
static void serialize_extra_data(uint8_t*& data_buffer, const internal::Arg& arg);
|
static void serialize_extra_data(uint8_t*& data_buffer, const internal::Arg& arg);
|
||||||
template <typename Char>
|
template <typename Char>
|
||||||
static void deserialize_extra_data(uint8_t*& data_buffer, internal::Arg& arg);
|
static void deserialize_extra_data(uint8_t*& data_buffer, internal::Arg::Type type, internal::Value& arg);
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#if FMT_HAS_THREAD_LOCAL
|
|
||||||
|
|
||||||
// Cross-thread serialization facility
|
// Cross-thread serialization facility
|
||||||
|
|
||||||
template <typename Char>
|
template <typename Char>
|
||||||
@ -1524,10 +1513,10 @@ inline void ArgList::serialize_extra_data(uint8_t*& data_buffer, const internal:
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename Char>
|
template <typename Char>
|
||||||
inline void ArgList::deserialize_extra_data(uint8_t*& data_buffer, internal::Arg& arg)
|
inline void ArgList::deserialize_extra_data(uint8_t*& data_buffer, internal::Arg::Type type, internal::Value& arg)
|
||||||
{
|
{
|
||||||
// Deserialize extra data
|
// Deserialize extra data
|
||||||
if (arg.type == internal::Arg::NAMED_ARG) {
|
if (type == internal::Arg::NAMED_ARG) {
|
||||||
fmt::internal::NamedArg<Char>* named = reinterpret_cast<fmt::internal::NamedArg<Char>*>(data_buffer);
|
fmt::internal::NamedArg<Char>* named = reinterpret_cast<fmt::internal::NamedArg<Char>*>(data_buffer);
|
||||||
arg.pointer = named;
|
arg.pointer = named;
|
||||||
data_buffer += sizeof(fmt::internal::NamedArg<Char>);
|
data_buffer += sizeof(fmt::internal::NamedArg<Char>);
|
||||||
@ -1536,16 +1525,16 @@ inline void ArgList::deserialize_extra_data(uint8_t*& data_buffer, internal::Arg
|
|||||||
data_buffer += sizeof(std::size_t);
|
data_buffer += sizeof(std::size_t);
|
||||||
named->name = BasicStringRef<Char>(reinterpret_cast<const Char*>(data_buffer), size);
|
named->name = BasicStringRef<Char>(reinterpret_cast<const Char*>(data_buffer), size);
|
||||||
data_buffer += size;
|
data_buffer += size;
|
||||||
deserialize_extra_data<Char>(data_buffer, *named);
|
deserialize_extra_data<Char>(data_buffer, named->type, *named);
|
||||||
}
|
}
|
||||||
else if (arg.type == internal::Arg::CSTRING) {
|
else if (type == internal::Arg::CSTRING) {
|
||||||
std::size_t size;
|
std::size_t size;
|
||||||
std::memcpy(&size, data_buffer, sizeof(std::size_t));
|
std::memcpy(&size, data_buffer, sizeof(std::size_t));
|
||||||
data_buffer += sizeof(std::size_t);
|
data_buffer += sizeof(std::size_t);
|
||||||
arg.string.value = reinterpret_cast<const char*>(data_buffer);
|
arg.string.value = reinterpret_cast<const char*>(data_buffer);
|
||||||
data_buffer += size;
|
data_buffer += size;
|
||||||
}
|
}
|
||||||
else if (arg.type == internal::Arg::STRING) {
|
else if (type == internal::Arg::STRING) {
|
||||||
std::size_t size;
|
std::size_t size;
|
||||||
std::memcpy(&size, data_buffer, sizeof(std::size_t));
|
std::memcpy(&size, data_buffer, sizeof(std::size_t));
|
||||||
data_buffer += sizeof(std::size_t);
|
data_buffer += sizeof(std::size_t);
|
||||||
@ -1553,7 +1542,7 @@ inline void ArgList::deserialize_extra_data(uint8_t*& data_buffer, internal::Arg
|
|||||||
arg.string.size = size / sizeof(char);
|
arg.string.size = size / sizeof(char);
|
||||||
data_buffer += size;
|
data_buffer += size;
|
||||||
}
|
}
|
||||||
else if (arg.type == internal::Arg::WSTRING) {
|
else if (type == internal::Arg::WSTRING) {
|
||||||
std::size_t size;
|
std::size_t size;
|
||||||
std::memcpy(&size, data_buffer, sizeof(std::size_t));
|
std::memcpy(&size, data_buffer, sizeof(std::size_t));
|
||||||
data_buffer += sizeof(std::size_t);
|
data_buffer += sizeof(std::size_t);
|
||||||
@ -1561,7 +1550,7 @@ inline void ArgList::deserialize_extra_data(uint8_t*& data_buffer, internal::Arg
|
|||||||
arg.wstring.size = size / sizeof(wchar_t);
|
arg.wstring.size = size / sizeof(wchar_t);
|
||||||
data_buffer += size;
|
data_buffer += size;
|
||||||
}
|
}
|
||||||
else if (arg.type == internal::Arg::CUSTOM) {
|
else if (type == internal::Arg::CUSTOM) {
|
||||||
arg.custom.value = data_buffer;
|
arg.custom.value = data_buffer;
|
||||||
data_buffer += arg.custom.size;
|
data_buffer += arg.custom.size;
|
||||||
}
|
}
|
||||||
@ -1582,7 +1571,8 @@ inline void ArgList::serialize(std::vector<uint8_t>& buffer) const
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
// Caclulate base & full buffer sizes
|
// Caclulate base & full buffer sizes
|
||||||
std::size_t base_size = sizeof(count) + sizeof(std::size_t) + sizeof(ULongLong) + count * sizeof(internal::Arg);
|
std::size_t item_size = (count > MAX_PACKED_ARGS) ? sizeof(internal::Arg) : sizeof(internal::Value);
|
||||||
|
std::size_t base_size = sizeof(count) + sizeof(std::size_t) + sizeof(ULongLong) + count * item_size;
|
||||||
std::size_t full_size = base_size;
|
std::size_t full_size = base_size;
|
||||||
for (unsigned i = 0; i < count; ++i)
|
for (unsigned i = 0; i < count; ++i)
|
||||||
full_size += calculate_extra_size<Char>(args[i]);
|
full_size += calculate_extra_size<Char>(args[i]);
|
||||||
@ -1610,8 +1600,8 @@ inline void ArgList::serialize(std::vector<uint8_t>& buffer) const
|
|||||||
for (unsigned i = 0; i < count; ++i) {
|
for (unsigned i = 0; i < count; ++i) {
|
||||||
// Serialize argument
|
// Serialize argument
|
||||||
internal::Arg arg = args[i];
|
internal::Arg arg = args[i];
|
||||||
std::memcpy(base_buffer, &arg, sizeof(internal::Arg));
|
std::memcpy(base_buffer, &arg, item_size);
|
||||||
base_buffer += sizeof(internal::Arg);
|
base_buffer += item_size;
|
||||||
// Serialize extra data
|
// Serialize extra data
|
||||||
serialize_extra_data<Char>(data_buffer, arg);
|
serialize_extra_data<Char>(data_buffer, arg);
|
||||||
}
|
}
|
||||||
@ -1632,6 +1622,9 @@ inline ArgList ArgList::deserialize(std::vector<uint8_t>& buffer)
|
|||||||
std::memcpy(&count, base_buffer, sizeof(unsigned));
|
std::memcpy(&count, base_buffer, sizeof(unsigned));
|
||||||
base_buffer += sizeof(unsigned);
|
base_buffer += sizeof(unsigned);
|
||||||
|
|
||||||
|
// Calculate the item size
|
||||||
|
std::size_t item_size = (count > MAX_PACKED_ARGS) ? sizeof(internal::Arg) : sizeof(internal::Value);
|
||||||
|
|
||||||
// Deserialize the base buffer size
|
// Deserialize the base buffer size
|
||||||
std::size_t base_size;
|
std::size_t base_size;
|
||||||
std::memcpy(&base_size, base_buffer, sizeof(std::size_t));
|
std::memcpy(&base_size, base_buffer, sizeof(std::size_t));
|
||||||
@ -1645,36 +1638,22 @@ inline ArgList ArgList::deserialize(std::vector<uint8_t>& buffer)
|
|||||||
std::memcpy(&types, base_buffer, sizeof(ULongLong));
|
std::memcpy(&types, base_buffer, sizeof(ULongLong));
|
||||||
base_buffer += sizeof(ULongLong);
|
base_buffer += sizeof(ULongLong);
|
||||||
|
|
||||||
// Reserve space for format arguments values
|
|
||||||
thread_local std::vector<internal::Arg> args;
|
|
||||||
args.resize(count);
|
|
||||||
|
|
||||||
// Deserialize values of format arguments
|
// Deserialize values of format arguments
|
||||||
|
uint8_t* local_buffer = base_buffer;
|
||||||
for (unsigned i = 0; i < count; ++i) {
|
for (unsigned i = 0; i < count; ++i) {
|
||||||
// Deserialize argument
|
// Deserialize argument
|
||||||
std::memcpy(&args[i], base_buffer, sizeof(internal::Arg));
|
internal::Value* arg = reinterpret_cast<internal::Value*>(local_buffer);
|
||||||
base_buffer += sizeof(internal::Arg);
|
local_buffer += item_size;
|
||||||
// Deserialize extra data
|
// Deserialize extra data
|
||||||
deserialize_extra_data<Char>(data_buffer, args[i]);
|
deserialize_extra_data<Char>(data_buffer, type(types, i), *arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prepare arguments list
|
// Prepare and return arguments list stored in the provided buffer
|
||||||
ArgList args_list(types, args.data());
|
return (count > MAX_PACKED_ARGS) ?
|
||||||
|
ArgList(types, reinterpret_cast<const internal::Arg*>(base_buffer)) :
|
||||||
// Special check for arguments list optimization
|
ArgList(types, reinterpret_cast<const internal::Value*>(base_buffer));
|
||||||
if (count <= MAX_PACKED_ARGS)
|
|
||||||
{
|
|
||||||
thread_local std::vector<internal::Value> values(MAX_PACKED_ARGS);
|
|
||||||
for (std::size_t i = 0; i < args.size(); ++i)
|
|
||||||
values[i] = static_cast<internal::Value>(args[i]);
|
|
||||||
args_list = ArgList(types, values.data());
|
|
||||||
}
|
|
||||||
|
|
||||||
return args_list;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define FMT_DISPATCH(call) static_cast<Impl*>(this)->call
|
#define FMT_DISPATCH(call) static_cast<Impl*>(this)->call
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -1654,8 +1654,6 @@ TEST(FormatTest, CustomArgFormatter) {
|
|||||||
custom_format("{}", 42);
|
custom_format("{}", 42);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if FMT_HAS_THREAD_LOCAL
|
|
||||||
|
|
||||||
std::string serialize_deserialize(const char *format_str, fmt::ArgList args) {
|
std::string serialize_deserialize(const char *format_str, fmt::ArgList args) {
|
||||||
std::vector<uint8_t> buffer;
|
std::vector<uint8_t> buffer;
|
||||||
args.serialize<char>(buffer);
|
args.serialize<char>(buffer);
|
||||||
@ -1683,5 +1681,3 @@ TEST(FormatTest, Serialization) {
|
|||||||
EXPECT_EQ(serialize_deserialize("Elapsed time: {s:.2f} seconds", "s"_a = 1.23), "Elapsed time: 1.23 seconds");
|
EXPECT_EQ(serialize_deserialize("Elapsed time: {s:.2f} seconds", "s"_a = 1.23), "Elapsed time: 1.23 seconds");
|
||||||
EXPECT_EQ(serialize_deserialize("The answer is {}"_format(42).c_str()), "The answer is 42");
|
EXPECT_EQ(serialize_deserialize("The answer is {}"_format(42).c_str()), "The answer is 42");
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user