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
#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.
#if defined(__GNUC__) && !defined(__EXCEPTIONS)
# define FMT_EXCEPTIONS 0
@ -1388,10 +1379,13 @@ class ArgList {
};
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;
uint64_t mask = 0xf;
return static_cast<internal::Arg::Type>(
(types_ & (mask << shift)) >> shift);
(types & (mask << shift)) >> shift);
}
template <typename Char>
@ -1436,8 +1430,6 @@ class ArgList {
return args_[index];
}
#if FMT_HAS_THREAD_LOCAL
// Cross-thread serialization facility
template <typename Char>
@ -1451,12 +1443,9 @@ private:
template <typename Char>
static void serialize_extra_data(uint8_t*& data_buffer, const internal::Arg& arg);
template <typename Char>
static void deserialize_extra_data(uint8_t*& data_buffer, internal::Arg& arg);
#endif
static void deserialize_extra_data(uint8_t*& data_buffer, internal::Arg::Type type, internal::Value& arg);
};
#if FMT_HAS_THREAD_LOCAL
// Cross-thread serialization facility
template <typename Char>
@ -1524,10 +1513,10 @@ inline void ArgList::serialize_extra_data(uint8_t*& data_buffer, const internal:
}
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
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);
arg.pointer = named;
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);
named->name = BasicStringRef<Char>(reinterpret_cast<const Char*>(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::memcpy(&size, data_buffer, sizeof(std::size_t));
data_buffer += sizeof(std::size_t);
arg.string.value = reinterpret_cast<const char*>(data_buffer);
data_buffer += size;
}
else if (arg.type == internal::Arg::STRING) {
else if (type == internal::Arg::STRING) {
std::size_t size;
std::memcpy(&size, 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);
data_buffer += size;
}
else if (arg.type == internal::Arg::WSTRING) {
else if (type == internal::Arg::WSTRING) {
std::size_t size;
std::memcpy(&size, 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);
data_buffer += size;
}
else if (arg.type == internal::Arg::CUSTOM) {
else if (type == internal::Arg::CUSTOM) {
arg.custom.value = data_buffer;
data_buffer += arg.custom.size;
}
@ -1582,7 +1571,8 @@ inline void ArgList::serialize(std::vector<uint8_t>& buffer) const
return;
// 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;
for (unsigned i = 0; i < count; ++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) {
// Serialize argument
internal::Arg arg = args[i];
std::memcpy(base_buffer, &arg, sizeof(internal::Arg));
base_buffer += sizeof(internal::Arg);
std::memcpy(base_buffer, &arg, item_size);
base_buffer += item_size;
// Serialize extra data
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));
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
std::size_t base_size;
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));
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
uint8_t* local_buffer = base_buffer;
for (unsigned i = 0; i < count; ++i) {
// Deserialize argument
std::memcpy(&args[i], base_buffer, sizeof(internal::Arg));
base_buffer += sizeof(internal::Arg);
internal::Value* arg = reinterpret_cast<internal::Value*>(local_buffer);
local_buffer += item_size;
// Deserialize extra data
deserialize_extra_data<Char>(data_buffer, args[i]);
deserialize_extra_data<Char>(data_buffer, type(types, i), *arg);
}
// Prepare arguments list
ArgList args_list(types, args.data());
// Special check for arguments list optimization
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;
// Prepare and return arguments list stored in the provided buffer
return (count > MAX_PACKED_ARGS) ?
ArgList(types, reinterpret_cast<const internal::Arg*>(base_buffer)) :
ArgList(types, reinterpret_cast<const internal::Value*>(base_buffer));
}
#endif
#define FMT_DISPATCH(call) static_cast<Impl*>(this)->call
/**

View File

@ -1654,8 +1654,6 @@ TEST(FormatTest, CustomArgFormatter) {
custom_format("{}", 42);
}
#if FMT_HAS_THREAD_LOCAL
std::string serialize_deserialize(const char *format_str, fmt::ArgList args) {
std::vector<uint8_t> 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("The answer is {}"_format(42).c_str()), "The answer is 42");
}
#endif