9 #include "quill/bundled/fmt/base.h" 11 #include "quill/core/Attributes.h" 12 #include "quill/core/DynamicFormatArgStore.h" 13 #include "quill/core/InlinedVector.h" 19 #include <string_view> 20 #include <type_traits> 28 #if defined(__MINGW32__) 29 #pragma GCC diagnostic push 30 #pragma GCC diagnostic ignored "-Wredundant-decls" 34 QUILL_NODISCARD QUILL_EXPORT QUILL_ATTRIBUTE_USED
extern std::string utf8_encode(std::wstring_view str);
35 QUILL_NODISCARD QUILL_EXPORT QUILL_ATTRIBUTE_USED
extern std::string utf8_encode(std::byte
const* data,
38 #if defined(__MINGW32__) 39 #pragma GCC diagnostic pop 49 typedef std::remove_cv_t<std::remove_reference_t<T>> type;
53 using remove_cvref_t =
typename remove_cvref<T>::type;
56 constexpr
bool always_false_v =
false;
58 template <
typename Arg>
59 void codec_not_found_for_type()
64 "+------------------------------------------------------------------------------+\n" 65 "| Missing Codec for Type 'Arg' |\n" 66 "+------------------------------------------------------------------------------+\n" 68 "Error: A codec for the specified type 'Arg' is not available.\n" 70 "Possible solutions:\n" 71 "1. If Arg is an STL type:\n" 72 " - Ensure you have included the necessary headers for the specific STL type you are using " 73 "from the quill/std folder.\n" 75 "2. If Arg is a user-defined type:\n" 76 " - Use either 'DeferredFormatCodec' or 'DirectFormatCodec'.\n" 77 " - Define a custom Codec for your type.\n" 78 " - Consider converting the value to a string before logging.\n" 80 "Note: The specific type of 'Arg' can be found in the compiler error message.\n" 81 " Look for the instantiation of 'codec_not_found_for_type<Arg>' in the error output.\n" 82 " The compiler should indicate what type 'Arg' represents in this instance.\n" 84 "For more information see https://quillcpp.readthedocs.io/en/latest/recipes.html\n");
88 QUILL_NODISCARD
inline size_t safe_strnlen(
char const* str,
size_t maxlen) noexcept
95 #if defined(__GNUC__) && !defined(__clang__) 97 #pragma GCC diagnostic push 99 #pragma GCC diagnostic ignored "-Wstringop-overread" 103 asm volatile(
"" :
"+r"(maxlen) : :
"memory");
106 auto end =
static_cast<char const*
>(std::memchr(str,
'\0', maxlen));
108 #if defined(__GNUC__) && !defined(__clang__) 109 #pragma GCC diagnostic pop 112 return end ?
static_cast<size_t>(end - str) : maxlen;
116 QUILL_NODISCARD
inline size_t safe_strnlen(
char const* str) noexcept
118 #if defined(__i386__) || defined(__arm__) 122 static constexpr int32_t max_len = INT32_MAX;
124 static constexpr uint32_t max_len = UINT32_MAX;
127 return safe_strnlen(str, max_len);
131 QUILL_NODISCARD QUILL_ATTRIBUTE_HOT
inline uint32_t clamp_encoded_string_length(
size_t len) noexcept
134 constexpr uint32_t max_val = UINT32_MAX - 1u;
135 return (len > max_val) ? max_val :
static_cast<uint32_t
>(len);
138 template <
typename T>
143 template <
typename Allocator>
144 struct is_std_string<
std::basic_string<char, std::char_traits<char>, Allocator>> : std::true_type
167 template <
typename Arg,
typename =
void>
171 QUILL_NODISCARD QUILL_ATTRIBUTE_HOT
static size_t compute_encoded_size(
172 QUILL_MAYBE_UNUSED
detail::SizeCacheVector& conditional_arg_size_cache, QUILL_MAYBE_UNUSED Arg
const& arg) noexcept
174 if constexpr (std::disjunction_v<std::is_arithmetic<Arg>, std::is_enum<Arg>,
175 std::is_same<Arg, void const*>, std::is_same<Arg, void*>>)
179 else if constexpr (std::conjunction_v<std::is_array<Arg>, std::is_same<detail::remove_cvref_t<std::remove_extent_t<Arg>>,
char>>)
181 size_t constexpr N = std::extent_v<Arg>;
182 uint32_t
const len = detail::clamp_encoded_string_length(detail::safe_strnlen(arg, N) + 1u);
183 return conditional_arg_size_cache.push_back(len);
185 else if constexpr (std::disjunction_v<std::is_same<Arg, char*>, std::is_same<Arg, char const*>>)
189 uint32_t
const len = detail::clamp_encoded_string_length(detail::safe_strnlen(arg) + 1u);
190 return conditional_arg_size_cache.push_back(len);
198 return sizeof(uint32_t) + detail::clamp_encoded_string_length(arg.length());
202 detail::codec_not_found_for_type<Arg>();
208 QUILL_ATTRIBUTE_HOT
static void encode(std::byte*& buffer,
210 QUILL_MAYBE_UNUSED uint32_t& conditional_arg_size_cache_index,
211 Arg
const& arg) noexcept
213 if constexpr (std::disjunction_v<std::is_arithmetic<Arg>, std::is_enum<Arg>,
214 std::is_same<Arg, void const*>, std::is_same<Arg, void*>>)
216 std::memcpy(buffer, &arg,
sizeof(Arg));
217 buffer +=
sizeof(Arg);
219 else if constexpr (std::conjunction_v<std::is_array<Arg>, std::is_same<detail::remove_cvref_t<std::remove_extent_t<Arg>>,
char>>)
221 size_t constexpr N = std::extent_v<Arg>;
222 uint32_t
const len = conditional_arg_size_cache[conditional_arg_size_cache_index++];
225 std::byte* buf_ptr = buffer;
227 if (QUILL_UNLIKELY(len > N))
230 QUILL_ASSERT(len == N + 1,
"Invalid length for c array in Codec::encode(), expected N + 1");
231 std::memcpy(buf_ptr, arg, N);
232 buf_ptr[N] = std::byte{
'\0'};
236 std::memcpy(buf_ptr, arg, len);
239 buffer = buf_ptr + len;
241 else if constexpr (std::disjunction_v<std::is_same<Arg, char*>, std::is_same<Arg, char const*>>)
244 uint32_t
const len = conditional_arg_size_cache[conditional_arg_size_cache_index++];
247 std::byte* buf_ptr = buffer;
249 if (QUILL_LIKELY(arg !=
nullptr))
252 std::memcpy(buf_ptr, arg, len - 1);
255 buf_ptr[len - 1] = std::byte{
'\0'};
256 buffer = buf_ptr + len;
262 uint32_t
const len = detail::clamp_encoded_string_length(arg.length());
265 std::byte* buf_ptr = buffer;
266 std::memcpy(buf_ptr, &len,
sizeof(len));
267 buf_ptr +=
sizeof(len);
270 if (QUILL_LIKELY(len != 0))
272 std::memcpy(buf_ptr, arg.data(), len);
275 buffer = buf_ptr + len;
279 detail::codec_not_found_for_type<Arg>();
289 static auto decode_arg(std::byte*& buffer)
291 if constexpr (std::disjunction_v<std::is_arithmetic<Arg>, std::is_enum<Arg>,
292 std::is_same<Arg, void const*>, std::is_same<Arg, void*>>)
295 std::memcpy(&arg, buffer,
sizeof(Arg));
296 buffer +=
sizeof(Arg);
299 else if constexpr (std::disjunction_v<std::is_same<Arg, char*>, std::is_same<Arg, char const*>,
300 std::conjunction<std::is_array<Arg>, std::is_same<detail::remove_cvref_t<std::remove_extent_t<Arg>>,
char>>>)
303 auto arg =
reinterpret_cast<char const*
>(buffer);
305 buffer += detail::safe_strnlen(arg) + 1u;
312 std::memcpy(&len, buffer,
sizeof(len));
313 buffer +=
sizeof(len);
314 auto const arg = std::string_view{
reinterpret_cast<char const*
>(buffer), len};
320 detail::codec_not_found_for_type<Arg>();
328 if constexpr (std::disjunction_v<std::is_arithmetic<Arg>, std::is_enum<Arg>,
329 std::is_same<Arg, void const*>, std::is_same<Arg, void*>>)
331 args_store->
push_back(decode_arg(buffer));
333 else if constexpr (std::disjunction_v<std::is_same<Arg, char*>, std::is_same<Arg, char const*>,
334 std::conjunction<std::is_array<Arg>, std::is_same<detail::remove_cvref_t<std::remove_extent_t<Arg>>,
char>>>)
337 char const* arg = decode_arg(buffer);
342 args_store->
push_back(fmtquill::string_view{arg, detail::safe_strnlen(arg)});
346 std::string_view arg = decode_arg(buffer);
351 args_store->
push_back(fmtquill::string_view{arg.data(), arg.size()});
355 detail::codec_not_found_for_type<Arg>();
369 template <
typename... Args>
371 QUILL_MAYBE_UNUSED
SizeCacheVector& conditional_arg_size_cache, Args
const&... args)
373 if constexpr (!std::conjunction_v<std::disjunction<std::is_arithmetic<remove_cvref_t<Args>>, std::is_same<remove_cvref_t<Args>,
void const*>,
374 std::is_same<remove_cvref_t<Args>,
void*>,
is_std_string<remove_cvref_t<Args>>,
375 std::is_same<remove_cvref_t<Args>, std::string_view>>...>)
379 conditional_arg_size_cache.clear();
396 template <
typename... Args>
400 QUILL_MAYBE_UNUSED uint32_t conditional_arg_size_cache_index{0};
402 static_cast<decltype(args)&&
>(args)),
406 template <
typename... Args>
417 template <
typename... Args>
420 decode_and_store_arg<Args...>(buffer, &args_store);
423 template <
typename... Args>
424 static constexpr
FormatArgsDecoder decoder_ptr = &decode_and_store_args<remove_cvref_t<Args>...>;
429 template <
typename... TMembers>
430 size_t compute_total_encoded_size(
detail::SizeCacheVector& conditional_arg_size_cache, TMembers
const&... members)
432 size_t total_size{0};
439 template <
typename... TMembers>
441 uint32_t& conditional_arg_size_cache_index, TMembers
const&... members)
444 conditional_arg_size_cache_index, members)),
449 template <
typename T,
typename... TMembers>
450 void decode_members(std::byte*&
buffer, T&, TMembers&... members)
Definition: UserDefinedDirectFormatFuzzer.cpp:81
void(*)(std::byte *&data, DynamicFormatArgStore &args_store) FormatArgsDecoder
Decode functions.
Definition: Codec.h:415
QUILL_NODISCARD QUILL_ATTRIBUTE_HOT size_t compute_encoded_size_and_cache_string_lengths(QUILL_MAYBE_UNUSED SizeCacheVector &conditional_arg_size_cache, Args const &... args)
Calculates the total size required to encode the provided arguments.
Definition: Codec.h:370
Setups a signal handler to handle fatal signals.
Definition: BackendManager.h:28
Codec contract notes (apply to this primary template and every specialization, including those in the...
Definition: Codec.h:168
QUILL_ATTRIBUTE_HOT void encode(std::byte *&buffer, SizeCacheVector const &conditional_arg_size_cache, Args &&... args)
Encodes multiple arguments into a buffer.
Definition: Codec.h:397
C++14 implementation of C++20's remove_cvref.
Definition: Codec.h:47
std string detection, ignoring the Allocator type
Definition: Codec.h:139
A contiguous memory buffer with an optional growing ability.
Definition: base.h:1779