Skip to content

Commit

Permalink
update
Browse files Browse the repository at this point in the history
  • Loading branch information
odygrd committed Feb 14, 2025
1 parent 85ca7bf commit 62105df
Show file tree
Hide file tree
Showing 3 changed files with 18 additions and 96 deletions.
9 changes: 4 additions & 5 deletions include/quill/DeferredFormatCodec.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,15 @@ QUILL_BEGIN_NAMESPACE
/**
* @brief Provides serialization (codec) functionality for complex user-defined types.
*
* This codec minimizes overhead on the performance-critical path by directly using memcpy or
* This codec minimizes overhead on the hot-path by directly using memcpy or
* placement new to serialize objects into the SPSC buffer,
*
* This approach avoids expensive string formatting on the hot path.
*
* For a trivially copyable type it requires a default constructor
* For a non trivially copyable type it requires valid copy constructor and move constructor.
*
* Thread-Safety for non trivially copyable type
* For a trivially copyable types it requires a default constructor
* For a non trivially copyable types it requires valid copy constructor and move constructor.
*
* Thread-Safety for non trivially copyable types:
* It is the user's responsibility to ensure that an non trivially copyable type remains
* thread-safe after being copied. For example, if the object contains a `shared_ptr`, ensure that
* its underlying value will not be modified.
Expand Down
74 changes: 1 addition & 73 deletions include/quill/DirectFormatCodec.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ QUILL_BEGIN_NAMESPACE
* @brief Provides codec functionality for serializing complex user-defined types into strings.
*
* This codec is particularly useful for logging user-defined types, it converts an object into a
* string representation using the `fmt::formatter` on the hot path.
* string representation using the `fmt::formatter`on the hot path.
*
* When using this codec, a `fmt::formatter` specialization must exist for the user-defined type.
*
Expand All @@ -36,20 +36,6 @@ QUILL_BEGIN_NAMESPACE
* LOG_INFO(logger, "{}", obj);
* ```
*
* Performance Considerations:
* - Overhead: The string conversion occurs on the hot path, which introduces
* performance overhead. As a result, this codec is better suited for scenarios where performance
* is not critical—e.g., during initialization or for debug-level log statements.
* - For hot-path logging, consider using `CopyConstructibleTypeCodec` or
* `DeferredFormatCodec` instead.
*
* Limitations:
* Nested STL containers are not supported when using this codec. For instance:
* ```cpp
* std::vector<User> users;
* ```
* In such cases, switch to `CopyConstructibleTypeCodec` or `DeferredFormatCodec`.
*
* \code{.cpp}
* class User
* {
Expand Down Expand Up @@ -94,81 +80,23 @@ QUILL_BEGIN_NAMESPACE
* \endcode
*/

namespace detail
{
/***/
template <typename T, typename = void>
struct HasFmtFormatter : std::false_type
{
};

/***/
template <typename T>
struct HasFmtFormatter<T, std::void_t<decltype(fmtquill::formatter<T>())>> : std::true_type
{
};

/***/
template <typename T, typename = void>
struct HasOstreamOperator : std::false_type
{
};

/***/
template <typename T>
struct HasOstreamOperator<T, std::void_t<decltype(std::declval<std::ostream&>() << std::declval<T>())>>
: std::true_type
{
};
} // namespace detail

template <typename T>
struct DirectFormatCodec
{
static constexpr bool has_fmt_formatter = detail::HasFmtFormatter<T>::value;
static constexpr bool has_ostream_operator = detail::HasOstreamOperator<T>::value;

static_assert(has_fmt_formatter || has_ostream_operator,
"DirectFormatCodec requires a fmt::formatter specialization or an overloaded "
"operator<< for the type");

static size_t compute_encoded_size(quill::detail::SizeCacheVector& conditional_arg_size_cache, T const& arg) noexcept
{
if constexpr (has_fmt_formatter)
{
return sizeof(uint32_t) +
conditional_arg_size_cache.push_back(static_cast<uint32_t>(fmtquill::formatted_size("{}", arg)));
}
else
{
std::ostringstream oss;
oss << arg;
return sizeof(uint32_t) + conditional_arg_size_cache.push_back(static_cast<uint32_t>(oss.str().size()));
}
}

static void encode(std::byte*& buffer, quill::detail::SizeCacheVector const& conditional_arg_size_cache,
uint32_t& conditional_arg_size_cache_index, T const& arg) noexcept
{
if constexpr (has_fmt_formatter)
{
uint32_t const len = conditional_arg_size_cache[conditional_arg_size_cache_index++];
std::memcpy(buffer, &len, sizeof(len));
buffer += sizeof(len);
fmtquill::format_to_n(reinterpret_cast<char*>(buffer), len, "{}", arg);
buffer += len;
}
else
{
uint32_t const len = conditional_arg_size_cache[conditional_arg_size_cache_index++];
std::memcpy(buffer, &len, sizeof(len));
buffer += sizeof(len);

std::ostringstream oss;
oss << arg;
std::memcpy(buffer, oss.str().data(), len);
buffer += len;
}
}

static std::string_view decode_arg(std::byte*& buffer)
Expand Down
31 changes: 13 additions & 18 deletions test/integration_tests/UserDefinedTypeLoggingDirectFormatTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,11 +70,6 @@ struct quill::Codec<CustomTypeTC> : quill::DirectFormatCodec<CustomTypeTC>
{
};

static_assert(quill::Codec<CustomTypeTC>::has_fmt_formatter,
"CustomTypeCC should have a fmt formatter");
static_assert(!quill::Codec<CustomTypeTC>::has_ostream_operator,
"CustomTypeCC should not have an ostream operator");

/***/
class CustomTypeCC
{
Expand All @@ -96,14 +91,6 @@ class CustomTypeCC
return this->age == other.age && this->name == other.name && this->surname == other.surname;
}

friend std::ostream& operator<<(std::ostream& os, CustomTypeCC const& user)
{
os << fmtquill::format("Name: {}, Surname: {}, Age: {}, Favorite Colors: {}", user.name,
user.surname, user.age, user.favorite_colors)
.data();
return os;
}

std::string name;
std::string surname;
uint32_t age;
Expand All @@ -125,14 +112,22 @@ struct hash<CustomTypeCC>

/***/
template <>
struct quill::Codec<CustomTypeCC> : quill::DirectFormatCodec<CustomTypeCC>
struct fmtquill::formatter<CustomTypeCC>
{
constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }

auto format(::CustomTypeCC const& user, format_context& ctx) const
{
return fmtquill::format_to(ctx.out(), "Name: {}, Surname: {}, Age: {}, Favorite Colors: {}",
user.name, user.surname, user.age, user.favorite_colors);
}
};

static_assert(!quill::Codec<CustomTypeCC>::has_fmt_formatter,
"CustomTypeCC should not have a fmt formatter");
static_assert(quill::Codec<CustomTypeCC>::has_ostream_operator,
"CustomTypeCC should have an ostream operator");
/***/
template <>
struct quill::Codec<CustomTypeCC> : quill::DirectFormatCodec<CustomTypeCC>
{
};

/***/
TEST_CASE("custom_type_defined_type_direct_format_logging")
Expand Down

0 comments on commit 62105df

Please sign in to comment.