Get rid of unnecessary thread_local storage

This commit is contained in:
Ivan Shynkarenka 2016-09-19 19:15:15 +03:00
parent 24aa82a2c6
commit 01a61b547b
2 changed files with 27 additions and 52 deletions

View File

@ -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
/** /**

View File

@ -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