From 3771d5a70c01befef850aab3899ab14a291904f3 Mon Sep 17 00:00:00 2001 From: Ivan Shynkarenka Date: Mon, 19 Sep 2016 04:05:48 +0300 Subject: [PATCH 01/12] Add Cross-thread serialization facility --- fmt/format.cc | 168 ++++++++++++++++++++++++++++++++++++++++++++++++++ fmt/format.h | 8 +++ 2 files changed, 176 insertions(+) diff --git a/fmt/format.cc b/fmt/format.cc index 9f9d6ae1..dcd8adbb 100644 --- a/fmt/format.cc +++ b/fmt/format.cc @@ -549,6 +549,174 @@ template int internal::CharTraits::format_float( #endif // FMT_HEADER_ONLY +// Cross-thread serialization facility + +void ArgList::serialize(std::vector& buffer) const +{ + const ArgList& args = *this; + + // Calculate the count of format arguments + unsigned count = 1; + while (args[count - 1].type != internal::Arg::NONE) + ++count; + + // Special check for none format arguments + if (count == 1) + 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 full_size = base_size; + for (unsigned i = 0; i < count; ++i) { + internal::Arg arg = args[i]; + if (arg.type == internal::Arg::CSTRING) + full_size += sizeof(std::size_t) + (std::strlen(arg.string.value) + 1) * sizeof(char); + else if (arg.type == internal::Arg::STRING) + full_size += sizeof(std::size_t) + arg.string.size * sizeof(char); + else if (arg.type == internal::Arg::WSTRING) + full_size += sizeof(std::size_t) + arg.wstring.size * sizeof(wchar_t); + else if (arg.type == internal::Arg::CUSTOM) + full_size += arg.custom.size; + } + + // Resize buffer to fit all format arguments + buffer.resize(full_size); + + uint8_t* base_buffer = buffer.data(); + uint8_t* data_buffer = base_buffer + base_size; + + // Serialize the count of format arguments + std::memcpy(base_buffer, &count, sizeof(unsigned)); + base_buffer += sizeof(unsigned); + + // Serialize the base buffer size + std::memcpy(base_buffer, &base_size, sizeof(std::size_t)); + base_buffer += sizeof(std::size_t); + + // Serialize types of format arguments + ULongLong types = args.types(); + std::memcpy(base_buffer, &types, sizeof(ULongLong)); + base_buffer += sizeof(ULongLong); + + // Serialize values of format arguments + for (unsigned i = 0; i < count; ++i) { + internal::Arg arg = args[i]; + + // Serialize argument + std::memcpy(base_buffer, &arg, sizeof(internal::Arg)); + base_buffer += sizeof(internal::Arg); + + // Serialize extra data + if (arg.type == internal::Arg::CSTRING) { + std::size_t size = (std::strlen(arg.string.value) + 1) * sizeof(char); + std::memcpy(data_buffer, &size, sizeof(std::size_t)); + data_buffer += sizeof(std::size_t); + std::memcpy(data_buffer, arg.string.value, size); + data_buffer += size; + } + else if (arg.type == internal::Arg::STRING) { + std::size_t size = arg.string.size * sizeof(char); + std::memcpy(data_buffer, &size, sizeof(std::size_t)); + data_buffer += sizeof(std::size_t); + std::memcpy(data_buffer, arg.string.value, size); + data_buffer += size; + } + else if (arg.type == internal::Arg::WSTRING) { + std::size_t size = arg.wstring.size * sizeof(wchar_t); + std::memcpy(data_buffer, &size, sizeof(std::size_t)); + data_buffer += sizeof(std::size_t); + std::memcpy(data_buffer, arg.wstring.value, size); + data_buffer += size; + } + else if (arg.type == internal::Arg::CUSTOM) { + std::memcpy(data_buffer, arg.custom.value, arg.custom.size); + data_buffer += arg.custom.size; + } + } +} + +ArgList ArgList::deserialize(const std::vector& buffer) +{ + // Special check for empty format arguments list + if (buffer.empty()) + return ArgList(); + + const uint8_t* base_buffer = buffer.data(); + const uint8_t* data_buffer = base_buffer; + + // Deserialize the count of format arguments + unsigned count; + std::memcpy(&count, base_buffer, sizeof(unsigned)); + base_buffer += sizeof(unsigned); + + // Deserialize the base buffer size + std::size_t base_size; + std::memcpy(&base_size, base_buffer, sizeof(std::size_t)); + base_buffer += sizeof(std::size_t); + + // Update the data buffer offset + data_buffer += base_size; + + // Deserialize types of format arguments + ULongLong types; + std::memcpy(&types, base_buffer, sizeof(ULongLong)); + base_buffer += sizeof(ULongLong); + + // Reserve space for format arguments values + thread_local std::vector args; + args.resize(count); + + // Deserialize values of format arguments + for (unsigned i = 0; i < count; ++i) { + // Deserialize argument + std::memcpy(&args[i], base_buffer, sizeof(internal::Arg)); + base_buffer += sizeof(internal::Arg); + + // Deserialize extra data + if (args[i].type == internal::Arg::CSTRING) { + std::size_t size; + std::memcpy(&size, data_buffer, sizeof(std::size_t)); + data_buffer += sizeof(std::size_t); + args[i].string.value = (const char*)data_buffer; + data_buffer += size; + } + else if (args[i].type == internal::Arg::STRING) { + std::size_t size; + std::memcpy(&size, data_buffer, sizeof(std::size_t)); + data_buffer += sizeof(std::size_t); + args[i].string.value = (const char*)data_buffer; + args[i].string.size = size / sizeof(char); + data_buffer += size; + } + else if (args[i].type == internal::Arg::WSTRING) { + std::size_t size; + std::memcpy(&size, data_buffer, sizeof(std::size_t)); + data_buffer += sizeof(std::size_t); + args[i].wstring.value = (const wchar_t*)data_buffer; + args[i].wstring.size = size / sizeof(wchar_t); + data_buffer += size; + } + else if (args[i].type == internal::Arg::CUSTOM) { + args[i].custom.value = data_buffer; + data_buffer += args[i].custom.size; + } + } + + // Prepare arguments list + ArgList args_list(types, args.data()); + + // Special check for arguments list optimization + if (count <= MAX_PACKED_ARGS) + { + thread_local std::vector values(MAX_PACKED_ARGS); + for (std::size_t i = 0; i < args.size(); ++i) + values[i] = static_cast(args[i]); + args_list = ArgList(types, values.data()); + } + + return args_list; +} + } // namespace fmt #ifdef _MSC_VER diff --git a/fmt/format.h b/fmt/format.h index 0f471cc4..934386b0 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -1004,6 +1004,7 @@ struct Value { void *formatter, const void *arg, void *format_str_ptr); struct CustomValue { + std::size_t size; const void *value; FormatFunc format; }; @@ -1303,6 +1304,7 @@ class MakeValue : public Arg { MakeValue(const T &value, typename EnableIf::value>::value, int>::type = 0) { + custom.size = sizeof(T); custom.value = &value; custom.format = &format_custom_arg; } @@ -1397,6 +1399,8 @@ class ArgList { ArgList(ULongLong types, const internal::Arg *args) : types_(types), args_(args) {} + uint64_t types() const { return types_; } + /** Returns the argument at specified index. */ internal::Arg operator[](unsigned index) const { using internal::Arg; @@ -1422,6 +1426,10 @@ class ArgList { } return args_[index]; } + + // Cross-thread serialization facility + void serialize(std::vector& buffer) const; + static ArgList deserialize(const std::vector& buffer); }; #define FMT_DISPATCH(call) static_cast(this)->call From c678ccc91a03cdffc2728227b7bc25625f963d23 Mon Sep 17 00:00:00 2001 From: Ivan Shynkarenka Date: Mon, 19 Sep 2016 17:24:54 +0300 Subject: [PATCH 02/12] Support of named arguments serialization --- fmt/format.cc | 168 ------------------------------------- fmt/format.h | 228 +++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 227 insertions(+), 169 deletions(-) diff --git a/fmt/format.cc b/fmt/format.cc index dcd8adbb..9f9d6ae1 100644 --- a/fmt/format.cc +++ b/fmt/format.cc @@ -549,174 +549,6 @@ template int internal::CharTraits::format_float( #endif // FMT_HEADER_ONLY -// Cross-thread serialization facility - -void ArgList::serialize(std::vector& buffer) const -{ - const ArgList& args = *this; - - // Calculate the count of format arguments - unsigned count = 1; - while (args[count - 1].type != internal::Arg::NONE) - ++count; - - // Special check for none format arguments - if (count == 1) - 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 full_size = base_size; - for (unsigned i = 0; i < count; ++i) { - internal::Arg arg = args[i]; - if (arg.type == internal::Arg::CSTRING) - full_size += sizeof(std::size_t) + (std::strlen(arg.string.value) + 1) * sizeof(char); - else if (arg.type == internal::Arg::STRING) - full_size += sizeof(std::size_t) + arg.string.size * sizeof(char); - else if (arg.type == internal::Arg::WSTRING) - full_size += sizeof(std::size_t) + arg.wstring.size * sizeof(wchar_t); - else if (arg.type == internal::Arg::CUSTOM) - full_size += arg.custom.size; - } - - // Resize buffer to fit all format arguments - buffer.resize(full_size); - - uint8_t* base_buffer = buffer.data(); - uint8_t* data_buffer = base_buffer + base_size; - - // Serialize the count of format arguments - std::memcpy(base_buffer, &count, sizeof(unsigned)); - base_buffer += sizeof(unsigned); - - // Serialize the base buffer size - std::memcpy(base_buffer, &base_size, sizeof(std::size_t)); - base_buffer += sizeof(std::size_t); - - // Serialize types of format arguments - ULongLong types = args.types(); - std::memcpy(base_buffer, &types, sizeof(ULongLong)); - base_buffer += sizeof(ULongLong); - - // Serialize values of format arguments - for (unsigned i = 0; i < count; ++i) { - internal::Arg arg = args[i]; - - // Serialize argument - std::memcpy(base_buffer, &arg, sizeof(internal::Arg)); - base_buffer += sizeof(internal::Arg); - - // Serialize extra data - if (arg.type == internal::Arg::CSTRING) { - std::size_t size = (std::strlen(arg.string.value) + 1) * sizeof(char); - std::memcpy(data_buffer, &size, sizeof(std::size_t)); - data_buffer += sizeof(std::size_t); - std::memcpy(data_buffer, arg.string.value, size); - data_buffer += size; - } - else if (arg.type == internal::Arg::STRING) { - std::size_t size = arg.string.size * sizeof(char); - std::memcpy(data_buffer, &size, sizeof(std::size_t)); - data_buffer += sizeof(std::size_t); - std::memcpy(data_buffer, arg.string.value, size); - data_buffer += size; - } - else if (arg.type == internal::Arg::WSTRING) { - std::size_t size = arg.wstring.size * sizeof(wchar_t); - std::memcpy(data_buffer, &size, sizeof(std::size_t)); - data_buffer += sizeof(std::size_t); - std::memcpy(data_buffer, arg.wstring.value, size); - data_buffer += size; - } - else if (arg.type == internal::Arg::CUSTOM) { - std::memcpy(data_buffer, arg.custom.value, arg.custom.size); - data_buffer += arg.custom.size; - } - } -} - -ArgList ArgList::deserialize(const std::vector& buffer) -{ - // Special check for empty format arguments list - if (buffer.empty()) - return ArgList(); - - const uint8_t* base_buffer = buffer.data(); - const uint8_t* data_buffer = base_buffer; - - // Deserialize the count of format arguments - unsigned count; - std::memcpy(&count, base_buffer, sizeof(unsigned)); - base_buffer += sizeof(unsigned); - - // Deserialize the base buffer size - std::size_t base_size; - std::memcpy(&base_size, base_buffer, sizeof(std::size_t)); - base_buffer += sizeof(std::size_t); - - // Update the data buffer offset - data_buffer += base_size; - - // Deserialize types of format arguments - ULongLong types; - std::memcpy(&types, base_buffer, sizeof(ULongLong)); - base_buffer += sizeof(ULongLong); - - // Reserve space for format arguments values - thread_local std::vector args; - args.resize(count); - - // Deserialize values of format arguments - for (unsigned i = 0; i < count; ++i) { - // Deserialize argument - std::memcpy(&args[i], base_buffer, sizeof(internal::Arg)); - base_buffer += sizeof(internal::Arg); - - // Deserialize extra data - if (args[i].type == internal::Arg::CSTRING) { - std::size_t size; - std::memcpy(&size, data_buffer, sizeof(std::size_t)); - data_buffer += sizeof(std::size_t); - args[i].string.value = (const char*)data_buffer; - data_buffer += size; - } - else if (args[i].type == internal::Arg::STRING) { - std::size_t size; - std::memcpy(&size, data_buffer, sizeof(std::size_t)); - data_buffer += sizeof(std::size_t); - args[i].string.value = (const char*)data_buffer; - args[i].string.size = size / sizeof(char); - data_buffer += size; - } - else if (args[i].type == internal::Arg::WSTRING) { - std::size_t size; - std::memcpy(&size, data_buffer, sizeof(std::size_t)); - data_buffer += sizeof(std::size_t); - args[i].wstring.value = (const wchar_t*)data_buffer; - args[i].wstring.size = size / sizeof(wchar_t); - data_buffer += size; - } - else if (args[i].type == internal::Arg::CUSTOM) { - args[i].custom.value = data_buffer; - data_buffer += args[i].custom.size; - } - } - - // Prepare arguments list - ArgList args_list(types, args.data()); - - // Special check for arguments list optimization - if (count <= MAX_PACKED_ARGS) - { - thread_local std::vector values(MAX_PACKED_ARGS); - for (std::size_t i = 0; i < args.size(); ++i) - values[i] = static_cast(args[i]); - args_list = ArgList(types, values.data()); - } - - return args_list; -} - } // namespace fmt #ifdef _MSC_VER diff --git a/fmt/format.h b/fmt/format.h index 934386b0..0cd9e8b9 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -1428,10 +1428,236 @@ class ArgList { } // Cross-thread serialization facility + template void serialize(std::vector& buffer) const; - static ArgList deserialize(const std::vector& buffer); + template + static ArgList deserialize(std::vector& buffer); + +private: + template + static std::size_t calculate_extra_size(const internal::Arg& arg); + template + static void serialize_extra_data(uint8_t*& data_buffer, const internal::Arg& arg); + template + static void deserialize_extra_data(uint8_t*& data_buffer, internal::Arg& arg); }; +// Cross-thread serialization facility + +template +inline std::size_t ArgList::calculate_extra_size(const internal::Arg& arg) +{ + std::size_t result = 0; + + if (arg.type == internal::Arg::NAMED_ARG) + { + const fmt::internal::NamedArg* named = static_cast*>(arg.pointer); + result = sizeof(fmt::internal::NamedArg) + sizeof(std::size_t) + named->name.size() * sizeof(Char) + calculate_extra_size(*named); + } + else if (arg.type == internal::Arg::CSTRING) + result = sizeof(std::size_t) + (std::strlen(arg.string.value) + 1) * sizeof(char); + else if (arg.type == internal::Arg::STRING) + result = sizeof(std::size_t) + arg.string.size * sizeof(char); + else if (arg.type == internal::Arg::WSTRING) + result = sizeof(std::size_t) + arg.wstring.size * sizeof(wchar_t); + else if (arg.type == internal::Arg::CUSTOM) + result = arg.custom.size; + + return result; +} + +template +inline void ArgList::serialize_extra_data(uint8_t*& data_buffer, const internal::Arg& arg) +{ + // Serialize extra data + if (arg.type == internal::Arg::NAMED_ARG) { + const fmt::internal::NamedArg* named = static_cast*>(arg.pointer); + std::memcpy(data_buffer, named, sizeof(fmt::internal::NamedArg)); + data_buffer += sizeof(fmt::internal::NamedArg); + std::size_t size = named->name.size() * sizeof(Char); + std::memcpy(data_buffer, &size, sizeof(std::size_t)); + data_buffer += sizeof(std::size_t); + std::memcpy(data_buffer, named->name.data(), size); + data_buffer += size; + serialize_extra_data(data_buffer, *named); + } + else if (arg.type == internal::Arg::CSTRING) { + std::size_t size = (std::strlen(arg.string.value) + 1) * sizeof(char); + std::memcpy(data_buffer, &size, sizeof(std::size_t)); + data_buffer += sizeof(std::size_t); + std::memcpy(data_buffer, arg.string.value, size); + data_buffer += size; + } + else if (arg.type == internal::Arg::STRING) { + std::size_t size = arg.string.size * sizeof(char); + std::memcpy(data_buffer, &size, sizeof(std::size_t)); + data_buffer += sizeof(std::size_t); + std::memcpy(data_buffer, arg.string.value, size); + data_buffer += size; + } + else if (arg.type == internal::Arg::WSTRING) { + std::size_t size = arg.wstring.size * sizeof(wchar_t); + std::memcpy(data_buffer, &size, sizeof(std::size_t)); + data_buffer += sizeof(std::size_t); + std::memcpy(data_buffer, arg.wstring.value, size); + data_buffer += size; + } + else if (arg.type == internal::Arg::CUSTOM) { + std::memcpy(data_buffer, arg.custom.value, arg.custom.size); + data_buffer += arg.custom.size; + } +} + +template +inline void ArgList::deserialize_extra_data(uint8_t*& data_buffer, internal::Arg& arg) +{ + // Deserialize extra data + if (arg.type == internal::Arg::NAMED_ARG) { + fmt::internal::NamedArg* named = reinterpret_cast*>(data_buffer); + arg.pointer = named; + data_buffer += sizeof(fmt::internal::NamedArg); + std::size_t size; + std::memcpy(&size, data_buffer, sizeof(std::size_t)); + data_buffer += sizeof(std::size_t); + named->name = BasicStringRef(reinterpret_cast(data_buffer), size); + data_buffer += size; + deserialize_extra_data(data_buffer, *named); + } + else if (arg.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(data_buffer); + data_buffer += size; + } + else if (arg.type == internal::Arg::STRING) { + std::size_t size; + std::memcpy(&size, data_buffer, sizeof(std::size_t)); + data_buffer += sizeof(std::size_t); + arg.string.value = reinterpret_cast(data_buffer); + arg.string.size = size / sizeof(char); + data_buffer += size; + } + else if (arg.type == internal::Arg::WSTRING) { + std::size_t size; + std::memcpy(&size, data_buffer, sizeof(std::size_t)); + data_buffer += sizeof(std::size_t); + arg.wstring.value = reinterpret_cast(data_buffer); + arg.wstring.size = size / sizeof(wchar_t); + data_buffer += size; + } + else if (arg.type == internal::Arg::CUSTOM) { + arg.custom.value = data_buffer; + data_buffer += arg.custom.size; + } +} + +template +inline void ArgList::serialize(std::vector& buffer) const +{ + const ArgList& args = *this; + + // Calculate the count of format arguments + unsigned count = 1; + while (args[count - 1].type != internal::Arg::NONE) + ++count; + + // Special check for none format arguments + if (count == 1) + 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 full_size = base_size; + for (unsigned i = 0; i < count; ++i) + full_size += calculate_extra_size(args[i]); + + // Resize buffer to fit all format arguments + buffer.resize(full_size); + + uint8_t* base_buffer = buffer.data(); + uint8_t* data_buffer = base_buffer + base_size; + + // Serialize the count of format arguments + std::memcpy(base_buffer, &count, sizeof(unsigned)); + base_buffer += sizeof(unsigned); + + // Serialize the base buffer size + std::memcpy(base_buffer, &base_size, sizeof(std::size_t)); + base_buffer += sizeof(std::size_t); + + // Serialize types of format arguments + ULongLong types = args.types(); + std::memcpy(base_buffer, &types, sizeof(ULongLong)); + base_buffer += sizeof(ULongLong); + + // Serialize values of format arguments + 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); + // Serialize extra data + serialize_extra_data(data_buffer, arg); + } +} + +template +inline ArgList ArgList::deserialize(std::vector& buffer) +{ + // Special check for empty format arguments list + if (buffer.empty()) + return ArgList(); + + uint8_t* base_buffer = buffer.data(); + uint8_t* data_buffer = base_buffer; + + // Deserialize the count of format arguments + unsigned count; + std::memcpy(&count, base_buffer, sizeof(unsigned)); + base_buffer += sizeof(unsigned); + + // Deserialize the base buffer size + std::size_t base_size; + std::memcpy(&base_size, base_buffer, sizeof(std::size_t)); + base_buffer += sizeof(std::size_t); + + // Update the data buffer offset + data_buffer += base_size; + + // Deserialize types of format arguments + ULongLong types; + std::memcpy(&types, base_buffer, sizeof(ULongLong)); + base_buffer += sizeof(ULongLong); + + // Reserve space for format arguments values + thread_local std::vector args; + args.resize(count); + + // Deserialize values of format arguments + for (unsigned i = 0; i < count; ++i) { + // Deserialize argument + std::memcpy(&args[i], base_buffer, sizeof(internal::Arg)); + base_buffer += sizeof(internal::Arg); + // Deserialize extra data + deserialize_extra_data(data_buffer, args[i]); + } + + // Prepare arguments list + ArgList args_list(types, args.data()); + + // Special check for arguments list optimization + if (count <= MAX_PACKED_ARGS) + { + thread_local std::vector values(MAX_PACKED_ARGS); + for (std::size_t i = 0; i < args.size(); ++i) + values[i] = static_cast(args[i]); + args_list = ArgList(types, values.data()); + } + + return args_list; +} + #define FMT_DISPATCH(call) static_cast(this)->call /** From 611e81ec2783aad06b10509e64d639addfc28f79 Mon Sep 17 00:00:00 2001 From: Ivan Shynkarenka Date: Mon, 19 Sep 2016 18:10:31 +0300 Subject: [PATCH 03/12] Add AgrList serialization/deserialization unit tests --- test/format-test.cc | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/test/format-test.cc b/test/format-test.cc index 6d246b93..050ce6d6 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -1653,3 +1653,31 @@ FMT_VARIADIC(void, custom_format, const char *) TEST(FormatTest, CustomArgFormatter) { custom_format("{}", 42); } + +std::string serialize_deserialize(const char *format_str, fmt::ArgList args) { + std::vector buffer; + args.serialize(buffer); + args = args.deserialize(buffer); + return fmt::format(format_str, args); +} +FMT_VARIADIC(std::string, serialize_deserialize, const char *) + +TEST(FormatTest, Serialization) { + EXPECT_EQ(serialize_deserialize("{0}, {1}, {2}", -1, 0, 1), "-1, 0, 1"); + EXPECT_EQ(serialize_deserialize("{0}, {1}, {2}", 'a', 'b', 'c'), "a, b, c"); + EXPECT_EQ(serialize_deserialize("{}, {}, {}", 'a', 'b', 'c'), "a, b, c"); + EXPECT_EQ(serialize_deserialize("{2}, {1}, {0}", 'a', 'b', 'c'), "c, b, a"); + EXPECT_EQ(serialize_deserialize("{0}{1}{0}", "abra", "cad"), "abracadabra"); + EXPECT_EQ(serialize_deserialize("{:<30}", "left aligned"), "left aligned "); + EXPECT_EQ(serialize_deserialize("{:>30}", "right aligned"), " right aligned"); + EXPECT_EQ(serialize_deserialize("{:^30}", "centered"), " centered "); + EXPECT_EQ(serialize_deserialize("{:*^30}", "centered"), "***********centered***********"); + EXPECT_EQ(serialize_deserialize("{:+f}; {:+f}", 3.14, -3.14), "+3.140000; -3.140000"); + EXPECT_EQ(serialize_deserialize("{: f}; {: f}", 3.14, -3.14), " 3.140000; -3.140000"); + EXPECT_EQ(serialize_deserialize("{:-f}; {:-f}", 3.14, -3.14), "3.140000; -3.140000"); + EXPECT_EQ(serialize_deserialize("int: {0:d}; hex: {0:x}; oct: {0:o}; bin: {0:b}", 42), "int: 42; hex: 2a; oct: 52; bin: 101010"); + EXPECT_EQ(serialize_deserialize("int: {0:d}; hex: {0:#x}; oct: {0:#o}; bin: {0:#b}", 42), "int: 42; hex: 0x2a; oct: 052; bin: 0b101010"); + EXPECT_EQ(serialize_deserialize("The date is {}", Date(2012, 12, 9)), "The date is 2012-12-9"); + 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"); +} From 24aa82a2c659088f4eaa0c64c8c08a7a8a199c8d Mon Sep 17 00:00:00 2001 From: Ivan Shynkarenka Date: Mon, 19 Sep 2016 18:34:58 +0300 Subject: [PATCH 04/12] Fix compilation error in old compilers --- fmt/format.h | 17 +++++++++++++++++ test/format-test.cc | 4 ++++ 2 files changed, 21 insertions(+) diff --git a/fmt/format.h b/fmt/format.h index 0cd9e8b9..e268eb16 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -156,6 +156,15 @@ typedef __int64 intmax_t; # include // 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 @@ -1427,7 +1436,10 @@ class ArgList { return args_[index]; } +#if FMT_HAS_THREAD_LOCAL + // Cross-thread serialization facility + template void serialize(std::vector& buffer) const; template @@ -1440,8 +1452,11 @@ private: static void serialize_extra_data(uint8_t*& data_buffer, const internal::Arg& arg); template static void deserialize_extra_data(uint8_t*& data_buffer, internal::Arg& arg); +#endif }; +#if FMT_HAS_THREAD_LOCAL + // Cross-thread serialization facility template @@ -1658,6 +1673,8 @@ inline ArgList ArgList::deserialize(std::vector& buffer) return args_list; } +#endif + #define FMT_DISPATCH(call) static_cast(this)->call /** diff --git a/test/format-test.cc b/test/format-test.cc index 050ce6d6..491df150 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -1654,6 +1654,8 @@ TEST(FormatTest, CustomArgFormatter) { custom_format("{}", 42); } +#if FMT_HAS_THREAD_LOCAL + std::string serialize_deserialize(const char *format_str, fmt::ArgList args) { std::vector buffer; args.serialize(buffer); @@ -1681,3 +1683,5 @@ 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 From 01a61b547b5694aa7b7a61ae83685f4bf4798ce3 Mon Sep 17 00:00:00 2001 From: Ivan Shynkarenka Date: Mon, 19 Sep 2016 19:15:15 +0300 Subject: [PATCH 05/12] Get rid of unnecessary thread_local storage --- fmt/format.h | 75 ++++++++++++++++----------------------------- test/format-test.cc | 4 --- 2 files changed, 27 insertions(+), 52 deletions(-) diff --git a/fmt/format.h b/fmt/format.h index e268eb16..c094163f 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -156,15 +156,6 @@ typedef __int64 intmax_t; # include // 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( - (types_ & (mask << shift)) >> shift); + (types & (mask << shift)) >> shift); } template @@ -1436,8 +1430,6 @@ class ArgList { return args_[index]; } -#if FMT_HAS_THREAD_LOCAL - // Cross-thread serialization facility template @@ -1451,12 +1443,9 @@ private: template static void serialize_extra_data(uint8_t*& data_buffer, const internal::Arg& arg); template - 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 @@ -1524,10 +1513,10 @@ inline void ArgList::serialize_extra_data(uint8_t*& data_buffer, const internal: } template -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* named = reinterpret_cast*>(data_buffer); arg.pointer = named; data_buffer += sizeof(fmt::internal::NamedArg); @@ -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(reinterpret_cast(data_buffer), size); data_buffer += size; - deserialize_extra_data(data_buffer, *named); + deserialize_extra_data(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(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& 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(args[i]); @@ -1610,8 +1600,8 @@ inline void ArgList::serialize(std::vector& 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(data_buffer, arg); } @@ -1632,6 +1622,9 @@ inline ArgList ArgList::deserialize(std::vector& 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& buffer) std::memcpy(&types, base_buffer, sizeof(ULongLong)); base_buffer += sizeof(ULongLong); - // Reserve space for format arguments values - thread_local std::vector 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(local_buffer); + local_buffer += item_size; // Deserialize extra data - deserialize_extra_data(data_buffer, args[i]); + deserialize_extra_data(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 values(MAX_PACKED_ARGS); - for (std::size_t i = 0; i < args.size(); ++i) - values[i] = static_cast(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(base_buffer)) : + ArgList(types, reinterpret_cast(base_buffer)); } -#endif - #define FMT_DISPATCH(call) static_cast(this)->call /** diff --git a/test/format-test.cc b/test/format-test.cc index 491df150..050ce6d6 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -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 buffer; args.serialize(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 From 7d5c3e5e0f5395e362b6bfa3ce8eb97b2b4462a0 Mon Sep 17 00:00:00 2001 From: Ivan Shynkarenka Date: Mon, 19 Sep 2016 19:40:20 +0300 Subject: [PATCH 06/12] Fix travis build --- test/format-test.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/format-test.cc b/test/format-test.cc index 050ce6d6..39cd222a 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -1678,6 +1678,5 @@ TEST(FormatTest, Serialization) { EXPECT_EQ(serialize_deserialize("int: {0:d}; hex: {0:x}; oct: {0:o}; bin: {0:b}", 42), "int: 42; hex: 2a; oct: 52; bin: 101010"); EXPECT_EQ(serialize_deserialize("int: {0:d}; hex: {0:#x}; oct: {0:#o}; bin: {0:#b}", 42), "int: 42; hex: 0x2a; oct: 052; bin: 0b101010"); EXPECT_EQ(serialize_deserialize("The date is {}", Date(2012, 12, 9)), "The date is 2012-12-9"); - 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("Elapsed time: {s:.2f} seconds", fmt::arg("s", 1.23)), "Elapsed time: 1.23 seconds"); } From 6f64e50a5ad3eb336274239bb7cd61d67b0877b2 Mon Sep 17 00:00:00 2001 From: Ivan Shynkarenka Date: Mon, 19 Sep 2016 23:13:15 +0300 Subject: [PATCH 07/12] Fix OSx build --- fmt/format.h | 83 +++++++++++++++++++++++++++++----------------------- 1 file changed, 47 insertions(+), 36 deletions(-) diff --git a/fmt/format.h b/fmt/format.h index c094163f..76da68a7 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -1441,7 +1441,7 @@ private: template static std::size_t calculate_extra_size(const internal::Arg& arg); template - static void serialize_extra_data(uint8_t*& data_buffer, const internal::Arg& arg); + static void serialize_extra_data(uint8_t*& data_buffer, internal::Arg::Type type, const internal::Value& arg); template static void deserialize_extra_data(uint8_t*& data_buffer, internal::Arg::Type type, internal::Value& arg); }; @@ -1471,11 +1471,11 @@ inline std::size_t ArgList::calculate_extra_size(const internal::Arg& arg) } template -inline void ArgList::serialize_extra_data(uint8_t*& data_buffer, const internal::Arg& arg) +inline void ArgList::serialize_extra_data(uint8_t*& data_buffer, internal::Arg::Type type, const internal::Value& value) { // Serialize extra data - if (arg.type == internal::Arg::NAMED_ARG) { - const fmt::internal::NamedArg* named = static_cast*>(arg.pointer); + if (type == internal::Arg::NAMED_ARG) { + const fmt::internal::NamedArg* named = static_cast*>(value.pointer); std::memcpy(data_buffer, named, sizeof(fmt::internal::NamedArg)); data_buffer += sizeof(fmt::internal::NamedArg); std::size_t size = named->name.size() * sizeof(Char); @@ -1483,42 +1483,42 @@ inline void ArgList::serialize_extra_data(uint8_t*& data_buffer, const internal: data_buffer += sizeof(std::size_t); std::memcpy(data_buffer, named->name.data(), size); data_buffer += size; - serialize_extra_data(data_buffer, *named); + serialize_extra_data(data_buffer, named->type, *named); } - else if (arg.type == internal::Arg::CSTRING) { - std::size_t size = (std::strlen(arg.string.value) + 1) * sizeof(char); + else if (type == internal::Arg::CSTRING) { + std::size_t size = (std::strlen(value.string.value) + 1) * sizeof(char); std::memcpy(data_buffer, &size, sizeof(std::size_t)); data_buffer += sizeof(std::size_t); - std::memcpy(data_buffer, arg.string.value, size); + std::memcpy(data_buffer, value.string.value, size); data_buffer += size; } - else if (arg.type == internal::Arg::STRING) { - std::size_t size = arg.string.size * sizeof(char); + else if (type == internal::Arg::STRING) { + std::size_t size = value.string.size * sizeof(char); std::memcpy(data_buffer, &size, sizeof(std::size_t)); data_buffer += sizeof(std::size_t); - std::memcpy(data_buffer, arg.string.value, size); + std::memcpy(data_buffer, value.string.value, size); data_buffer += size; } - else if (arg.type == internal::Arg::WSTRING) { - std::size_t size = arg.wstring.size * sizeof(wchar_t); + else if (type == internal::Arg::WSTRING) { + std::size_t size = value.wstring.size * sizeof(wchar_t); std::memcpy(data_buffer, &size, sizeof(std::size_t)); data_buffer += sizeof(std::size_t); - std::memcpy(data_buffer, arg.wstring.value, size); + std::memcpy(data_buffer, value.wstring.value, size); data_buffer += size; } - else if (arg.type == internal::Arg::CUSTOM) { - std::memcpy(data_buffer, arg.custom.value, arg.custom.size); - data_buffer += arg.custom.size; + else if (type == internal::Arg::CUSTOM) { + std::memcpy(data_buffer, value.custom.value, value.custom.size); + data_buffer += value.custom.size; } } template -inline void ArgList::deserialize_extra_data(uint8_t*& data_buffer, internal::Arg::Type type, internal::Value& arg) +inline void ArgList::deserialize_extra_data(uint8_t*& data_buffer, internal::Arg::Type type, internal::Value& value) { // Deserialize extra data if (type == internal::Arg::NAMED_ARG) { fmt::internal::NamedArg* named = reinterpret_cast*>(data_buffer); - arg.pointer = named; + value.pointer = named; data_buffer += sizeof(fmt::internal::NamedArg); std::size_t size; std::memcpy(&size, data_buffer, sizeof(std::size_t)); @@ -1531,28 +1531,28 @@ inline void ArgList::deserialize_extra_data(uint8_t*& data_buffer, internal::Arg std::size_t size; std::memcpy(&size, data_buffer, sizeof(std::size_t)); data_buffer += sizeof(std::size_t); - arg.string.value = reinterpret_cast(data_buffer); + value.string.value = reinterpret_cast(data_buffer); data_buffer += size; } 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); - arg.string.value = reinterpret_cast(data_buffer); - arg.string.size = size / sizeof(char); + value.string.value = reinterpret_cast(data_buffer); + value.string.size = size / sizeof(char); data_buffer += size; } 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); - arg.wstring.value = reinterpret_cast(data_buffer); - arg.wstring.size = size / sizeof(wchar_t); + value.wstring.value = reinterpret_cast(data_buffer); + value.wstring.size = size / sizeof(wchar_t); data_buffer += size; } else if (type == internal::Arg::CUSTOM) { - arg.custom.value = data_buffer; - data_buffer += arg.custom.size; + value.custom.value = data_buffer; + data_buffer += value.custom.size; } } @@ -1600,10 +1600,11 @@ inline void ArgList::serialize(std::vector& buffer) const for (unsigned i = 0; i < count; ++i) { // Serialize argument internal::Arg arg = args[i]; - std::memcpy(base_buffer, &arg, item_size); + internal::Value& value = arg; + std::memcpy(base_buffer, (count > MAX_PACKED_ARGS) ? &arg : &value, item_size); base_buffer += item_size; // Serialize extra data - serialize_extra_data(data_buffer, arg); + serialize_extra_data(data_buffer, arg.type, value); } } @@ -1622,9 +1623,6 @@ inline ArgList ArgList::deserialize(std::vector& 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)); @@ -1638,14 +1636,27 @@ inline ArgList ArgList::deserialize(std::vector& buffer) std::memcpy(&types, base_buffer, sizeof(ULongLong)); base_buffer += sizeof(ULongLong); + // Calculate the item size + std::size_t item_size = (count > MAX_PACKED_ARGS) ? sizeof(internal::Arg) : sizeof(internal::Value); + // Deserialize values of format arguments uint8_t* local_buffer = base_buffer; for (unsigned i = 0; i < count; ++i) { - // Deserialize argument - internal::Value* arg = reinterpret_cast(local_buffer); - local_buffer += item_size; - // Deserialize extra data - deserialize_extra_data(data_buffer, type(types, i), *arg); + if (count > MAX_PACKED_ARGS) + { + // Deserialize argument + internal::Arg* arg = reinterpret_cast(local_buffer); + // Deserialize extra data + deserialize_extra_data(data_buffer, arg->type, *arg); + } + else + { + // Deserialize argument + internal::Value* value = reinterpret_cast(local_buffer); + // Deserialize extra data + deserialize_extra_data(data_buffer, type(types, i), *value); + } + local_buffer += item_size; } // Prepare and return arguments list stored in the provided buffer From f64c9ac188183e5cbc8a487ed55d66e92075668c Mon Sep 17 00:00:00 2001 From: Ivan Shynkarenka Date: Mon, 19 Sep 2016 23:43:01 +0300 Subject: [PATCH 08/12] Rollback OSx fix attempt --- fmt/format.h | 23 ++++++----------------- 1 file changed, 6 insertions(+), 17 deletions(-) diff --git a/fmt/format.h b/fmt/format.h index 76da68a7..1ea52b85 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -1600,11 +1600,10 @@ inline void ArgList::serialize(std::vector& buffer) const for (unsigned i = 0; i < count; ++i) { // Serialize argument internal::Arg arg = args[i]; - internal::Value& value = arg; - std::memcpy(base_buffer, (count > MAX_PACKED_ARGS) ? &arg : &value, item_size); + std::memcpy(base_buffer, &arg, item_size); base_buffer += item_size; // Serialize extra data - serialize_extra_data(data_buffer, arg.type, value); + serialize_extra_data(data_buffer, arg.type, arg); } } @@ -1642,21 +1641,11 @@ inline ArgList ArgList::deserialize(std::vector& buffer) // Deserialize values of format arguments uint8_t* local_buffer = base_buffer; for (unsigned i = 0; i < count; ++i) { - if (count > MAX_PACKED_ARGS) - { - // Deserialize argument - internal::Arg* arg = reinterpret_cast(local_buffer); - // Deserialize extra data - deserialize_extra_data(data_buffer, arg->type, *arg); - } - else - { - // Deserialize argument - internal::Value* value = reinterpret_cast(local_buffer); - // Deserialize extra data - deserialize_extra_data(data_buffer, type(types, i), *value); - } + // Deserialize argument + internal::Value* value = reinterpret_cast(local_buffer); local_buffer += item_size; + // Deserialize extra data + deserialize_extra_data(data_buffer, type(types, i), *value); } // Prepare and return arguments list stored in the provided buffer From 17f31903503674c1f5ac503816d361348bd0e0b4 Mon Sep 17 00:00:00 2001 From: Ivan Shynkarenka Date: Tue, 20 Sep 2016 01:09:35 +0300 Subject: [PATCH 09/12] Experiments --- test/format-test.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/format-test.cc b/test/format-test.cc index 39cd222a..bce1f9a2 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -1677,6 +1677,6 @@ TEST(FormatTest, Serialization) { EXPECT_EQ(serialize_deserialize("{:-f}; {:-f}", 3.14, -3.14), "3.140000; -3.140000"); EXPECT_EQ(serialize_deserialize("int: {0:d}; hex: {0:x}; oct: {0:o}; bin: {0:b}", 42), "int: 42; hex: 2a; oct: 52; bin: 101010"); EXPECT_EQ(serialize_deserialize("int: {0:d}; hex: {0:#x}; oct: {0:#o}; bin: {0:#b}", 42), "int: 42; hex: 0x2a; oct: 052; bin: 0b101010"); - EXPECT_EQ(serialize_deserialize("The date is {}", Date(2012, 12, 9)), "The date is 2012-12-9"); - EXPECT_EQ(serialize_deserialize("Elapsed time: {s:.2f} seconds", fmt::arg("s", 1.23)), "Elapsed time: 1.23 seconds"); + //EXPECT_EQ(serialize_deserialize("The date is {}", Date(2012, 12, 9)), "The date is 2012-12-9"); + //EXPECT_EQ(serialize_deserialize("Elapsed time: {s:.2f} seconds", fmt::arg("s", 1.23)), "Elapsed time: 1.23 seconds"); } From 00ba927dd3d0fd3d5faa6ec9f425043d9ac06453 Mon Sep 17 00:00:00 2001 From: Ivan Shynkarenka Date: Tue, 20 Sep 2016 01:28:54 +0300 Subject: [PATCH 10/12] Experiments --- test/format-test.cc | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/test/format-test.cc b/test/format-test.cc index bce1f9a2..df0d3e93 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -1664,19 +1664,19 @@ FMT_VARIADIC(std::string, serialize_deserialize, const char *) TEST(FormatTest, Serialization) { EXPECT_EQ(serialize_deserialize("{0}, {1}, {2}", -1, 0, 1), "-1, 0, 1"); - EXPECT_EQ(serialize_deserialize("{0}, {1}, {2}", 'a', 'b', 'c'), "a, b, c"); - EXPECT_EQ(serialize_deserialize("{}, {}, {}", 'a', 'b', 'c'), "a, b, c"); - EXPECT_EQ(serialize_deserialize("{2}, {1}, {0}", 'a', 'b', 'c'), "c, b, a"); - EXPECT_EQ(serialize_deserialize("{0}{1}{0}", "abra", "cad"), "abracadabra"); - EXPECT_EQ(serialize_deserialize("{:<30}", "left aligned"), "left aligned "); - EXPECT_EQ(serialize_deserialize("{:>30}", "right aligned"), " right aligned"); - EXPECT_EQ(serialize_deserialize("{:^30}", "centered"), " centered "); - EXPECT_EQ(serialize_deserialize("{:*^30}", "centered"), "***********centered***********"); - EXPECT_EQ(serialize_deserialize("{:+f}; {:+f}", 3.14, -3.14), "+3.140000; -3.140000"); - EXPECT_EQ(serialize_deserialize("{: f}; {: f}", 3.14, -3.14), " 3.140000; -3.140000"); - EXPECT_EQ(serialize_deserialize("{:-f}; {:-f}", 3.14, -3.14), "3.140000; -3.140000"); - EXPECT_EQ(serialize_deserialize("int: {0:d}; hex: {0:x}; oct: {0:o}; bin: {0:b}", 42), "int: 42; hex: 2a; oct: 52; bin: 101010"); - EXPECT_EQ(serialize_deserialize("int: {0:d}; hex: {0:#x}; oct: {0:#o}; bin: {0:#b}", 42), "int: 42; hex: 0x2a; oct: 052; bin: 0b101010"); + //EXPECT_EQ(serialize_deserialize("{0}, {1}, {2}", 'a', 'b', 'c'), "a, b, c"); + //EXPECT_EQ(serialize_deserialize("{}, {}, {}", 'a', 'b', 'c'), "a, b, c"); + //EXPECT_EQ(serialize_deserialize("{2}, {1}, {0}", 'a', 'b', 'c'), "c, b, a"); + //EXPECT_EQ(serialize_deserialize("{0}{1}{0}", "abra", "cad"), "abracadabra"); + //EXPECT_EQ(serialize_deserialize("{:<30}", "left aligned"), "left aligned "); + //EXPECT_EQ(serialize_deserialize("{:>30}", "right aligned"), " right aligned"); + //EXPECT_EQ(serialize_deserialize("{:^30}", "centered"), " centered "); + //EXPECT_EQ(serialize_deserialize("{:*^30}", "centered"), "***********centered***********"); + //EXPECT_EQ(serialize_deserialize("{:+f}; {:+f}", 3.14, -3.14), "+3.140000; -3.140000"); + //EXPECT_EQ(serialize_deserialize("{: f}; {: f}", 3.14, -3.14), " 3.140000; -3.140000"); + //EXPECT_EQ(serialize_deserialize("{:-f}; {:-f}", 3.14, -3.14), "3.140000; -3.140000"); + //EXPECT_EQ(serialize_deserialize("int: {0:d}; hex: {0:x}; oct: {0:o}; bin: {0:b}", 42), "int: 42; hex: 2a; oct: 52; bin: 101010"); + //EXPECT_EQ(serialize_deserialize("int: {0:d}; hex: {0:#x}; oct: {0:#o}; bin: {0:#b}", 42), "int: 42; hex: 0x2a; oct: 052; bin: 0b101010"); //EXPECT_EQ(serialize_deserialize("The date is {}", Date(2012, 12, 9)), "The date is 2012-12-9"); //EXPECT_EQ(serialize_deserialize("Elapsed time: {s:.2f} seconds", fmt::arg("s", 1.23)), "Elapsed time: 1.23 seconds"); } From 27d960bf908090d70302fa81444d0181dd255027 Mon Sep 17 00:00:00 2001 From: Ivan Shynkarenka Date: Tue, 20 Sep 2016 01:48:55 +0300 Subject: [PATCH 11/12] Fix optimizations problems with serialization buffer in unit tests --- test/format-test.cc | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/test/format-test.cc b/test/format-test.cc index df0d3e93..c1195eea 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -1655,7 +1655,7 @@ TEST(FormatTest, CustomArgFormatter) { } std::string serialize_deserialize(const char *format_str, fmt::ArgList args) { - std::vector buffer; + static std::vector buffer; args.serialize(buffer); args = args.deserialize(buffer); return fmt::format(format_str, args); @@ -1664,19 +1664,19 @@ FMT_VARIADIC(std::string, serialize_deserialize, const char *) TEST(FormatTest, Serialization) { EXPECT_EQ(serialize_deserialize("{0}, {1}, {2}", -1, 0, 1), "-1, 0, 1"); - //EXPECT_EQ(serialize_deserialize("{0}, {1}, {2}", 'a', 'b', 'c'), "a, b, c"); - //EXPECT_EQ(serialize_deserialize("{}, {}, {}", 'a', 'b', 'c'), "a, b, c"); - //EXPECT_EQ(serialize_deserialize("{2}, {1}, {0}", 'a', 'b', 'c'), "c, b, a"); - //EXPECT_EQ(serialize_deserialize("{0}{1}{0}", "abra", "cad"), "abracadabra"); - //EXPECT_EQ(serialize_deserialize("{:<30}", "left aligned"), "left aligned "); - //EXPECT_EQ(serialize_deserialize("{:>30}", "right aligned"), " right aligned"); - //EXPECT_EQ(serialize_deserialize("{:^30}", "centered"), " centered "); - //EXPECT_EQ(serialize_deserialize("{:*^30}", "centered"), "***********centered***********"); - //EXPECT_EQ(serialize_deserialize("{:+f}; {:+f}", 3.14, -3.14), "+3.140000; -3.140000"); - //EXPECT_EQ(serialize_deserialize("{: f}; {: f}", 3.14, -3.14), " 3.140000; -3.140000"); - //EXPECT_EQ(serialize_deserialize("{:-f}; {:-f}", 3.14, -3.14), "3.140000; -3.140000"); - //EXPECT_EQ(serialize_deserialize("int: {0:d}; hex: {0:x}; oct: {0:o}; bin: {0:b}", 42), "int: 42; hex: 2a; oct: 52; bin: 101010"); - //EXPECT_EQ(serialize_deserialize("int: {0:d}; hex: {0:#x}; oct: {0:#o}; bin: {0:#b}", 42), "int: 42; hex: 0x2a; oct: 052; bin: 0b101010"); - //EXPECT_EQ(serialize_deserialize("The date is {}", Date(2012, 12, 9)), "The date is 2012-12-9"); - //EXPECT_EQ(serialize_deserialize("Elapsed time: {s:.2f} seconds", fmt::arg("s", 1.23)), "Elapsed time: 1.23 seconds"); + EXPECT_EQ(serialize_deserialize("{0}, {1}, {2}", 'a', 'b', 'c'), "a, b, c"); + EXPECT_EQ(serialize_deserialize("{}, {}, {}", 'a', 'b', 'c'), "a, b, c"); + EXPECT_EQ(serialize_deserialize("{2}, {1}, {0}", 'a', 'b', 'c'), "c, b, a"); + EXPECT_EQ(serialize_deserialize("{0}{1}{0}", "abra", "cad"), "abracadabra"); + EXPECT_EQ(serialize_deserialize("{:<30}", "left aligned"), "left aligned "); + EXPECT_EQ(serialize_deserialize("{:>30}", "right aligned"), " right aligned"); + EXPECT_EQ(serialize_deserialize("{:^30}", "centered"), " centered "); + EXPECT_EQ(serialize_deserialize("{:*^30}", "centered"), "***********centered***********"); + EXPECT_EQ(serialize_deserialize("{:+f}; {:+f}", 3.14, -3.14), "+3.140000; -3.140000"); + EXPECT_EQ(serialize_deserialize("{: f}; {: f}", 3.14, -3.14), " 3.140000; -3.140000"); + EXPECT_EQ(serialize_deserialize("{:-f}; {:-f}", 3.14, -3.14), "3.140000; -3.140000"); + EXPECT_EQ(serialize_deserialize("int: {0:d}; hex: {0:x}; oct: {0:o}; bin: {0:b}", 42), "int: 42; hex: 2a; oct: 52; bin: 101010"); + EXPECT_EQ(serialize_deserialize("int: {0:d}; hex: {0:#x}; oct: {0:#o}; bin: {0:#b}", 42), "int: 42; hex: 0x2a; oct: 052; bin: 0b101010"); + EXPECT_EQ(serialize_deserialize("The date is {}", Date(2012, 12, 9)), "The date is 2012-12-9"); + EXPECT_EQ(serialize_deserialize("Elapsed time: {s:.2f} seconds", fmt::arg("s", 1.23)), "Elapsed time: 1.23 seconds"); } From bebf194de1e3db609db0e32c993ce18c589248a5 Mon Sep 17 00:00:00 2001 From: Ivan Shynkarenka Date: Tue, 20 Sep 2016 02:13:07 +0300 Subject: [PATCH 12/12] Fix optimizations problems with serialization buffer in unit tests --- test/format-test.cc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/format-test.cc b/test/format-test.cc index c1195eea..8d841330 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -1655,10 +1655,12 @@ TEST(FormatTest, CustomArgFormatter) { } std::string serialize_deserialize(const char *format_str, fmt::ArgList args) { - static std::vector buffer; + std::vector buffer; args.serialize(buffer); args = args.deserialize(buffer); - return fmt::format(format_str, args); + std::string result = fmt::format(format_str, args); + buffer.clear(); + return result; } FMT_VARIADIC(std::string, serialize_deserialize, const char *)