add test for async and fix some pre-c++17 compatibility issues in async

This commit is contained in:
yumeyao 2021-04-25 00:05:39 +08:00
parent bfd84f66be
commit 2703cb0be6
4 changed files with 108 additions and 26 deletions

View File

@ -90,6 +90,7 @@ namespace async {
namespace detail { namespace detail {
namespace detail = fmt::detail; namespace detail = fmt::detail;
template <typename T> using decay_t = typename std::decay<T>::type; template <typename T> using decay_t = typename std::decay<T>::type;
template <typename T> using add_const_t = typename std::add_const<T>::type;
enum class store_method { enum class store_method {
numeric, // stored by libfmt as numeric value, no need for extra storage numeric, // stored by libfmt as numeric value, no need for extra storage
@ -188,7 +189,7 @@ struct arg_transformer {
template <typename Arg, typename Context, typename Type = detail::mapped_type_constant<remove_reference_t<Arg>, Context>> template <typename Arg, typename Context, typename Type = detail::mapped_type_constant<remove_reference_t<Arg>, Context>>
using transformed_arg_type = conditional_t<custom_store_method<Arg, Context>::custom_store, typename custom_store_method<Arg, Context>::transformed_type, using transformed_arg_type = conditional_t<custom_store_method<Arg, Context>::custom_store, typename custom_store_method<Arg, Context>::transformed_type,
conditional_t<stored_as_string<Type>::value && !stored_as_string_object<Type, Arg>::value, basic_string_view<typename Context::char_type>, std::add_const_t<remove_reference_t<Arg>>&> conditional_t<stored_as_string<Type>::value && !stored_as_string_object<Type, Arg>::value, basic_string_view<typename Context::char_type>, add_const_t<remove_reference_t<Arg>>&>
>; >;
template <typename Context, typename... Args> template <typename Context, typename... Args>
@ -205,7 +206,7 @@ struct async_entry_constructor {
private: private:
using range = typename range_builder<0, sizeof...(Args)>::type; using range = typename range_builder<0, sizeof...(Args)>::type;
template <typename S, size_t... Indice> template <typename S, size_t... Indice>
constexpr async_entry_constructor(void* buf, const S& format_str, index_list<Indice...>, Args... args) : pEntry(reinterpret_cast<char*>(buf)), pBuffer(get_buffer_store(buf)) { FMT_CONSTEXPR async_entry_constructor(void* buf, const S& format_str, index_list<Indice...>, Args... args) : pEntry(reinterpret_cast<char*>(buf)), pBuffer(get_buffer_store(buf)) {
auto p = new(buf) Entry(format_str, store<Indice>(std::forward<Args>(args))...); auto p = new(buf) Entry(format_str, store<Indice>(std::forward<Args>(args))...);
p->set_dtor(Dtor::value ? Dtor::destruct : nullptr); p->set_dtor(Dtor::value ? Dtor::destruct : nullptr);
} }
@ -257,7 +258,7 @@ private:
return basic_string_view<typename Context::char_type>(pStart, sv.size()); return basic_string_view<typename Context::char_type>(pStart, sv.size());
} }
static constexpr char* get_buffer_store(void* buf) { static FMT_CONSTEXPR char* get_buffer_store(void* buf) {
char* const pentry = reinterpret_cast<char*>(buf); // entry will be constructed here char* const pentry = reinterpret_cast<char*>(buf); // entry will be constructed here
char* const pobjs = pentry + sizeof(Entry); // objects will be stored starting here char* const pobjs = pentry + sizeof(Entry); // objects will be stored starting here
char* const pbufs = pobjs + get_obj_size(); // buffers will be stored starting here char* const pbufs = pobjs + get_obj_size(); // buffers will be stored starting here

View File

@ -1,23 +0,0 @@
#define FMT_HEADER_ONLY
#include "async.h"
using namespace fmt;
#include <iostream>
int main() {
fmt::print("entry header: {}\n", sizeof(basic_async_entry<format_context>));
auto entry = make_async_entry("The answer is {}\n", 42);
async::print(entry);
char buf[2000];
size_t size = store_async_entry(buf, "This {} is {}{}\n", "answer", std::to_string(4), 2);
fmt::print("entry size: {}\n", size);
auto& entryref1 = entry;
auto& entryref = reinterpret_cast<decltype(entryref1)>(buf[0]);
async::print(entryref);
std::cout << &entryref << "\n" << &(entryref.arg_store_) << "\n" << sizeof(entryref.arg_store_) << std::endl;
}

View File

@ -88,6 +88,7 @@ function(add_fmt_test name)
endfunction() endfunction()
add_fmt_test(assert-test) add_fmt_test(assert-test)
add_fmt_test(async-test)
add_fmt_test(chrono-test) add_fmt_test(chrono-test)
add_fmt_test(color-test) add_fmt_test(color-test)
add_fmt_test(core-test) add_fmt_test(core-test)

103
test/async-test.cc Normal file
View File

@ -0,0 +1,103 @@
#ifdef WIN32
# define _CRT_SECURE_NO_WARNINGS
#endif
#include "fmt/async.h"
#include "gtest-extra.h"
#define TWENTY_ARGS "{} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} "
static const char multiple_brackets[] = TWENTY_ARGS;
static fmt::string_view get_format_string(size_t num_args) { return fmt::string_view(&multiple_brackets[(20 - num_args)*3], num_args * 3); }
namespace trivial_entry_test {
template <typename... Args>
inline void make_async_entry_test(Args&&... args) {
std::string formatted = fmt::format(std::forward<Args>(args)...);
// format_arg_store containing named_args are not copy-constructible, auto&& is required.
auto&& entry = fmt::make_async_entry(std::forward<Args>(args)...);
EXPECT_EQ(formatted, fmt::async::format(entry));
}
template <typename... Args>
inline void make_async_entry_test_args(Args&&... args) {
make_async_entry_test(get_format_string(sizeof...(args)), std::forward<Args>(args)...);
}
void make_async_entry_and_alter(const std::string& s) {
std::string str = s;
std::string formatted = fmt::format("{}", str);
auto entry = fmt::make_async_entry("{}", str);
str.front() = formatted.front() = '#';
str.back() = formatted.back() = '#';
EXPECT_EQ(formatted, fmt::format("{}", str));
EXPECT_EQ(formatted, fmt::async::format(entry));
}
}
namespace stored_entry_test {
static char buf[1 * 1024 * 1024] = {}; // 1M should be enough for this test
static fmt::basic_async_entry<fmt::format_context>& entry = reinterpret_cast<fmt::basic_async_entry<fmt::format_context>&>(buf);
template <typename... Args>
inline void make_async_entry_test(Args&&... args) {
std::string formatted = fmt::format(std::forward<Args>(args)...);
// FIXME: how to test entry_size?
size_t entry_size = fmt::store_async_entry(buf, std::forward<Args>(args)...);
EXPECT_EQ(formatted, fmt::async::format(entry));
}
template <typename... Args>
inline void make_async_entry_test_args(Args&&... args) {
make_async_entry_test(get_format_string(sizeof...(args)), std::forward<Args>(args)...);
}
void make_async_entry_and_alter(const std::string& s) {
std::string str = s;
std::string formatted = fmt::format("{}", str);
size_t entry_size = fmt::store_async_entry(buf, "{}", str);
str.front() = str.back() = '#';
EXPECT_EQ(formatted, fmt::async::format(entry));
formatted.front() = formatted.back() = '#';
EXPECT_EQ(formatted, fmt::format("{}", str));
}
}
TEST(AsyncTest, TrivialEntry) {
using namespace trivial_entry_test;
// basic test
make_async_entry_test("The answer is {}", 42);
// index
make_async_entry_test("The answer of {2}*{1} is {0}", 42, 6, 7);
// named args
using namespace fmt::literals;
make_async_entry_test("The answer of {}*{a} is {product}", 6, "product"_a=42, "a"_a=7);
// long arg list (>=16, as max_packed_args = 15)
make_async_entry_test_args(short(1), (unsigned short)2, 3, 4U, 5L, 6UL, 7LL, 8ULL, 9.0F, 10.0, 11, 12, 13, 14, 15, 16, 17, 18);
make_async_entry_test(TWENTY_ARGS "{narg}", 1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,0/*ignore*/,"narg"_a="bingo");
// this API copies only reference.
make_async_entry_and_alter("[change me]");
}
TEST(AsyncTest, StoredEntry) {
using namespace stored_entry_test;
// basic test
make_async_entry_test("The answer is {}", 42);
// index
make_async_entry_test("The answer of {2}*{1} is {0}", 42, 6, 7);
// named args
using namespace fmt::literals;
// make_async_entry_test("The answer of {}*{a} is {product}", 6, "product"_a=42, "a"_a=7);
// long arg list (>=16, as max_packed_args = 15)
make_async_entry_test_args(short(1), (unsigned short)2, 3, 4U, 5L, 6UL, 7LL, 8ULL, 9.0F, 10.0, 11, 12, 13, 14, 15, 16, 17, 18);
// make_async_entry_test(TWENTY_ARGS "{narg}", 1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,0/*ignore*/,"narg"_a="bingo");
// this API copies only reference.
make_async_entry_and_alter("[change me]");
}