45 template<
typename... Args>
49 [this, format, capturedArgs = std::forward_as_tuple(arguments...)]() -> const char*
55 [
this, format](
auto&&... args)
57 LogWriter writer(message);
58 Printf(message, writer, 0, format, std::forward<Args>(args)...);
60 std::move(capturedArgs));
62 catch (
const std::exception& e)
64 message +=
"<exception during logging: ";
68 return message.c_str();
91 std::function<
const char*()> compose;
93 class LogWriter :
public Writer
98 if (arrayIndex > 0 && objectIndex == 0)
100 arraySize[arrayIndex - 1]++;
102 if (arraySize[arrayIndex - 1] > actualMaxArraySize)
107 isValueInObject[arrayIndex - 1] =
true;
110 auto name = std::string_view(n);
120 text.erase(text.end() - 1, text.end());
124 text += ObjectValueDelimiter;
126 if (arrayIndex > 0 && objectIndex == 0)
128 isValueInObject[arrayIndex - 1] =
false;
129 text += ArrayValueDelimiter;
132 void WriteRoot(Serializable& )
final
136 void Write(
const char* name,
const char* value)
final
145 if (!isValueInObject[arrayIndex - 1])
147 arraySize[arrayIndex - 1]++;
150 if (arraySize[arrayIndex - 1] <= actualMaxArraySize)
152 WriteString(name, value);
153 text += ArrayValueDelimiter;
159 WriteString(name, value);
164 text += ObjectValueDelimiter;
168 void WriteNull(
const char* name)
final
172 void Write(
const char* name,
int value)
final
174 Write(name, std::to_string(value).c_str());
176 void Write(
const char* name,
unsigned int value)
final
178 Write(name, std::to_string(value).c_str());
180 void Write(
const char* name,
double value)
final
182 Write(name, std::to_string(value).c_str());
184 void Write(
const char* name, int64_t value)
final
186 Write(name, std::to_string(value).c_str());
188 void Write(
const char* name, uint64_t value)
final
190 Write(name, std::to_string(value).c_str());
192 void Write(
const char* name,
const std::shared_ptr<Image>& value)
final
194 if (value !=
nullptr)
196 const std::string imageDescription =
197 "[w:" + std::to_string(value->Width()) +
" h:" + std::to_string(value->Height()) +
198 " d:" + std::to_string(
static_cast<unsigned int>(value->Dpi())) +
"]";
199 Write(name, imageDescription.c_str());
207 LogWriter(
const LogWriter&) =
delete;
208 LogWriter(LogWriter&&) =
delete;
209 LogWriter& operator=(
const LogWriter&) =
delete;
210 LogWriter& operator=(LogWriter&&) =
delete;
211 LogWriter() =
delete;
212 explicit LogWriter(std::string& t)
213 : actualMaxArraySize(MaxArraySize)
219 virtual ~LogWriter() =
default;
221 static const unsigned int MaxArraySize = 10;
225 unsigned int actualMaxArraySize;
232 unsigned int arrayIndex;
233 std::vector<unsigned int> arraySize;
234 std::vector<bool> isValueInObject;
235 unsigned int objectIndex;
236 static const char ObjectValueDelimiter =
' ';
237 static const char ArrayValueDelimiter =
',';
239 void StartArray(
const char* n)
final
241 auto name = std::string_view(n);
243 if (not name.empty())
249 arraySize.insert(arraySize.begin() + arrayIndex, 0);
250 isValueInObject.insert(isValueInObject.begin() + arrayIndex,
false);
254 void EndArray() final
257 if (text[text.length() - 1] ==
',')
259 text.erase(text.end() - 1, text.end());
263 if (arraySize[arrayIndex] > actualMaxArraySize)
265 text += ArrayValueDelimiter;
266 text +=
"...(" + std::to_string(arraySize[arrayIndex]) +
")";
268 arraySize[arrayIndex] = 0;
274 text += ArrayValueDelimiter;
281 text += ObjectValueDelimiter;
286 void WriteString(
const char* n,
const char* v)
288 auto name = std::string_view(n);
289 auto value = std::string_view(v);
291 if (not name.empty())
301 requires IsIterable<T>
302 void WriteInWriter(Writer& writer, T& value)
const
307 requires(IsNotIterable<T> && !std::is_scalar_v<T>)
308 void WriteInWriter(Writer& writer, T& value)
const
310 writer.
Write(
static_cast<const char*
>(
""), value);
316 requires(std::is_scalar_v<T> &&
317 (std::is_same_v<T, const char*> || std::is_same_v<T, int> || std::is_same_v<T, unsigned int> ||
318 std::is_same_v<T, double> || std::is_same_v<T, int64_t> || std::is_same_v<T, uint64_t>))
319 void WriteInWriter(Writer& writer, T& value)
const
321 writer.
Write(
"", value);
327 requires(std::is_scalar_v<T> &&
328 !(std::is_same_v<T, const char*> || std::is_same_v<T, int> || std::is_same_v<T, unsigned int> ||
329 std::is_same_v<T, double> || std::is_same_v<T, int64_t> || std::is_same_v<T, uint64_t>))
330 void WriteInWriter(Writer& writer, T& )
const
332 writer.
Write(
"",
"??");
337 void Printf(std::string& text, LogWriter& ,
int ,
const char* format)
const
342 template<
typename T,
typename... Args>
345 void Printf(std::string& text,
350 Args&&... args)
const
355 Printf(text, writer, ignoreCount - 1, format, args...);
361 for (
const auto* formatIt = format; *formatIt !=
'\0'; std::advance(formatIt, 1))
363 if (*formatIt ==
'%')
365 auto sprintfFormatArray = GetFormatForOneValueAndMoveToNext(formatIt);
366 auto sprintfFormat = std::string_view(sprintfFormatArray.data());
368 if (!sprintfFormat.empty())
370 if (IsWriter(sprintfFormat.back()))
372 auto arrayLength = GetWriterArrayLength(sprintfFormat);
374 ComposeInWriter(writer, arrayLength, value);
376 else if (IsPercentage(sprintfFormat.at(1)))
384 stars = GetStarsInFormat(sprintfFormat);
386 ComposeInPrintf(sprintfFormat, stars, value, std::forward<Args>(args)...);
387 text += sprintfText.data();
395 Printf(text, writer, stars, std::next(formatIt, 1), args...);
402 static constexpr int MaxSprintfFormatSize = 21;
403 static std::array<char, MaxSprintfFormatSize> GetFormatForOneValueAndMoveToNext(
const char*& formatIt)
405 std::advance(formatIt, 1);
406 static constexpr int MaxSprintfFormatLength = MaxSprintfFormatSize - 1;
407 std::array<char, MaxSprintfFormatLength + 1> sprintfFormat = {};
408 sprintfFormat[0] =
'%';
410 for (; *formatIt !=
'\0' && !IsSpecifier(*formatIt); std::advance(formatIt, 1), i++)
412 if (i < MaxSprintfFormatLength)
414 sprintfFormat.at(i) = *formatIt;
418 if (*formatIt !=
'\0' && i <= MaxSprintfFormatLength)
421 sprintfFormat.at(i++) = *formatIt;
422 sprintfFormat.at(i) =
'\0';
425 if (i > MaxSprintfFormatLength)
429 sprintfFormat.at(0) =
'\0';
432 return sprintfFormat;
435 static unsigned int GetWriterArrayLength(std::string_view format)
438 if (format.length() <= 2)
440 return LogWriter::MaxArraySize;
444 static constexpr int Base = 10;
445 const char* start = std::next(format.data(), 1);
446 const char* end = std::next(format.data(),
static_cast<ptrdiff_t
>(format.length() - 1));
447 std::from_chars(start, end, i, Base);
452 void ComposeInWriter(LogWriter& writer,
unsigned int arrayLength, T&& value)
const
454 writer.actualMaxArraySize = arrayLength;
455 WriteInWriter(writer, std::forward<T>(value));
458 static int GetStarsInFormat(std::string_view format)
462 for (
const auto c : format)
472 static constexpr int MaxSprintfTextSize = 101;
473 template<
typename T,
typename... Args>
474 std::array<char, MaxSprintfTextSize> ComposeInPrintf(
475 std::string_view& format,
486 static constexpr int MaxSprintfTextLength = MaxSprintfTextSize - 1;
487 auto sprintfText = std::array<char, MaxSprintfTextSize>{};
494 totalLength = WriteInSprintf(sprintfText.data(), MaxSprintfTextLength, format.data(), value);
500 totalLength = WriteInSprintf(sprintfText.data(), MaxSprintfTextLength, format.data(), value, args...);
503 if (totalLength > MaxSprintfTextLength)
505 sprintfText[MaxSprintfTextLength - 1] =
'.';
506 sprintfText[MaxSprintfTextLength - 2] =
'.';
507 sprintfText[MaxSprintfTextLength - 3] =
'.';
508 sprintfText[MaxSprintfTextLength] =
'\0';
512 sprintfText.at(totalLength) =
'\0';
518 template<
typename T,
typename... Args>
519 requires(std::is_trivially_copyable_v<T>)
520 int WriteInSprintf(
char* sprintfText,
522 const char* sprintfFormat,
529 return snprintf(sprintfText, sprintfTextSize, sprintfFormat, value);
531 template<
typename W,
typename T,
typename... Args>
532 requires(std::is_trivially_copyable_v<T> && std::is_integral_v<W>)
533 int WriteInSprintf(
char* sprintfText,
535 const char* sprintfFormat,
543 return snprintf(sprintfText, sprintfTextSize, sprintfFormat, width, value);
545 template<
typename W,
typename P,
typename T,
typename... Args>
546 requires(std::is_trivially_copyable_v<T> && std::is_integral_v<W> && std::is_integral_v<P>)
547 int WriteInSprintf(
char* sprintfText,
549 const char* sprintfFormat,
558 return snprintf(sprintfText, sprintfTextSize, sprintfFormat, width, precision, value);
560 template<
typename T,
typename... Args>
561 requires(!std::is_trivially_copyable_v<T>)
562 int WriteInSprintf(
char* sprintfText,
571 sprintfText[0] =
'\0';
575 static constexpr bool IsSpecifier(
char sign)
577 return sign ==
'd' || sign ==
'i' || sign ==
'u' || sign ==
'o' || sign ==
'x' || sign ==
'X' ||
578 sign ==
'f' || sign ==
'F' || sign ==
'e' || sign ==
'E' || sign ==
'g' || sign ==
'G' ||
579 sign ==
'a' || sign ==
'A' || sign ==
'c' || sign ==
's' || sign ==
'p' || sign ==
'n' ||
580 sign ==
'%' || sign ==
'v';
582 static constexpr bool IsWriter(
char sign)
586 static constexpr bool IsPercentage(
char sign)