Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

better char array support #353

Merged
merged 1 commit into from
Oct 31, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions examples/example_trivial.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,19 @@ int main()
std::array<uint32_t, 4> arr = {1, 2, 3, 4};
LOG_INFO(logger, "This is a log info example {}", arr);

union
{
char no_0[2];
char mid_0[6]{'1', '2', '3', '4', '\0', 6};
} char_arrays;

// only output "12" even if there's no '\0' at the end
LOG_INFO(logger, R"(This is a log info example for char array without '\0': {})", char_arrays.no_0);

// output "1234" until the '\0'
LOG_INFO(logger, R"(This is a log info example for char array with '\0' in middle: {})",
char_arrays.mid_0);

// Using a dynamic runtime log level
std::array<quill::LogLevel, 4> const runtime_log_levels = {
quill::LogLevel::Debug, quill::LogLevel::Info, quill::LogLevel::Warning, quill::LogLevel::Error};
Expand Down
48 changes: 46 additions & 2 deletions quill/include/quill/detail/Serialize.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@

#pragma once

#ifndef __STDC_WANT_LIB_EXT1__
#define __STDC_WANT_LIB_EXT1__ 1
#include <string.h>
#endif

#include "misc/Utilities.h"
#include "quill/LogLevel.h"
#include "quill/MacroMetadata.h"
Expand All @@ -23,9 +28,25 @@ namespace quill
namespace detail
{

constexpr auto strnlen =
#ifdef __STDC_LIB_EXT1__
::strnlen_s
#else
::strnlen
#endif
;

/** Forward declaration **/
class LoggerDetails;

template <typename Arg>
QUILL_NODISCARD constexpr bool is_type_of_c_array()
{
using ArgType = detail::remove_cvref_t<Arg>;
return std::is_array<ArgType>::value &&
std::is_same<detail::remove_cvref_t<typename std::remove_extent<ArgType>::type>, char>::value;
}

template <typename Arg>
QUILL_NODISCARD constexpr bool is_type_of_c_string()
{
Expand Down Expand Up @@ -177,7 +198,13 @@ template <size_t CstringIdx, typename Arg, typename... Args>
QUILL_NODISCARD QUILL_ATTRIBUTE_HOT constexpr size_t get_args_sizes(size_t* c_string_sizes,
Arg const& arg, Args const&... args)
{
if constexpr (is_type_of_c_string<Arg>())
if constexpr (is_type_of_c_array<Arg>())
{
size_t const len = strnlen(arg, detail::array_size_v<Arg>) + 1;
c_string_sizes[CstringIdx] = len;
return len + get_args_sizes<CstringIdx + 1>(c_string_sizes, args...);
}
else if constexpr (is_type_of_c_string<Arg>())
{
size_t const len = strlen(arg) + 1;
c_string_sizes[CstringIdx] = len;
Expand Down Expand Up @@ -225,7 +252,24 @@ template <size_t CstringIdx, typename Arg, typename... Args>
QUILL_NODISCARD QUILL_ATTRIBUTE_HOT constexpr std::byte* encode_args(size_t* c_string_sizes, std::byte* out,
Arg&& arg, Args&&... args)
{
if constexpr (is_type_of_c_string<Arg>())
if constexpr (is_type_of_c_array<Arg>())
{
const auto size = c_string_sizes[CstringIdx];
constexpr auto array_size = detail::array_size_v<Arg>;
if (QUILL_UNLIKELY(size > array_size))
{
// no '\0' in c array
assert(size == array_size + 1);
std::memcpy(out, arg, array_size);
out[size - 1] = std::byte{'\0'};
}
else
{
std::memcpy(out, arg, size);
}
return encode_args<CstringIdx + 1>(c_string_sizes, out + size, std::forward<Args>(args)...);
}
else if constexpr (is_type_of_c_string<Arg>())
{
std::memcpy(out, arg, c_string_sizes[CstringIdx]);
return encode_args<CstringIdx + 1>(c_string_sizes, out + c_string_sizes[CstringIdx],
Expand Down
3 changes: 3 additions & 0 deletions quill/include/quill/detail/misc/TypeTraitsCopyable.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,9 @@ struct remove_cvref
template< class T >
using remove_cvref_t = typename remove_cvref<T>::type;

template <typename Arg>
constexpr size_t array_size_v = std::extent<remove_cvref_t<Arg>>::value;

/**
* fmtquill::streamed detection
*/
Expand Down
60 changes: 59 additions & 1 deletion quill/test/LogTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,64 @@ TEST_CASE("default_logger_ints_and_large_string")
quill::detail::remove_file(filename);
}

/***/
TEST_CASE("default_logger_ints_and_c_array")
{
fs::path const filename{"test_default_logger_ints_and_c_array"};
{
LogManager lm;

quill::Config cfg;
cfg.default_handlers.emplace_back(lm.handler_collection().create_handler<FileHandler>(
filename.string(),
[]()
{
quill::FileHandlerConfig cfg;
cfg.set_open_mode('w');
return cfg;
}(),
FileEventNotifier{}));
lm.configure(cfg);

lm.start_backend_worker(false, std::initializer_list<int32_t>{});

std::thread frontend(
[&lm]()
{
Logger* default_logger = lm.logger_collection().get_logger();

union
{
char no_0[2];
char mid_0[6]{'a', 'b', 'c', 'd', '\0', 'e'};
} v;

// log an array so the log message is pushed to the queue
for (int i = 0; i < 2000; ++i)
{
v.no_0[0] = std::to_string(i).back();
LOG_INFO(default_logger, "Logging int: {}, int: {}, no_0: {}, mid_0: {}", i, i * 10, v.no_0, v.mid_0);
}

// Let all log get flushed to the file
lm.flush();
});

frontend.join();

std::vector<std::string> const file_contents = quill::testing::file_contents(filename);

REQUIRE_EQ(file_contents.size(), 2000);
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO root Logging int: 0, int: 0, no_0: 0b, mid_0: 0bcd"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO root Logging int: 1999, int: 19990, no_0: 9b, mid_0: 9bcd"}));

lm.stop_backend_worker();
}
// quill::detail::remove_file(filename);
}

/***/
TEST_CASE("default_logger_ints_and_large_string_dynamic_log_level")
{
Expand Down Expand Up @@ -2273,4 +2331,4 @@ TEST_CASE("default_logger_with_very_large_random_strings")
quill::detail::remove_file(filename);
}

TEST_SUITE_END();
TEST_SUITE_END();
11 changes: 10 additions & 1 deletion quill/test/TypeTraitsCopyableTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -199,4 +199,13 @@ TEST_CASE("are_copyable")
static_assert(!are_copyable_v<int, Enum, std::string, NonTrivial>, "_");
}

TEST_SUITE_END();
TEST_CASE("array_size_v")
{
char a[3];
static_assert(array_size_v<decltype(a)> == 3, "_");

using B = char(&)[1];
static_assert(array_size_v<B> == 1, "_");
}

TEST_SUITE_END();