/*
This file is part of TON Blockchain Library.
TON Blockchain Library is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
TON Blockchain Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see .
Copyright 2017-2020 Telegram Systems LLP
*/
#pragma once
#include "td/utils/common.h"
#include "td/utils/invoke.h" // for tuple_for_each
#include "td/utils/Slice.h"
#include "td/utils/StringBuilder.h"
#include
#include
#include
namespace td {
namespace format {
/*** HexDump ***/
template
struct HexDumpSize {
const unsigned char *data;
};
inline char hex_digit(int x) {
return "0123456789abcdef"[x];
}
template
StringBuilder &operator<<(StringBuilder &builder, const HexDumpSize &dump) {
const unsigned char *ptr = dump.data;
// TODO: append unsafe
for (std::size_t i = 0; i < size; i++) {
int xy = ptr[is_reversed ? size - 1 - i : i];
int x = xy >> 4;
int y = xy & 15;
builder << hex_digit(x) << hex_digit(y);
}
return builder;
}
template
struct HexDumpSlice {
Slice slice;
};
template
StringBuilder &operator<<(StringBuilder &builder, const HexDumpSlice &dump) {
const auto str = dump.slice;
const auto size = str.size();
builder << '\n';
const std::size_t first_part_size = size % align;
if (first_part_size) {
builder << HexDumpSlice<1>{str.substr(0, first_part_size)} << '\n';
}
for (std::size_t i = first_part_size; i < size; i += align) {
builder << HexDumpSize{str.ubegin() + i};
if (((i / align) & 15) == 15 || i + align >= size) {
builder << '\n';
} else {
builder << ' ';
}
}
return builder;
}
inline StringBuilder &operator<<(StringBuilder &builder, const HexDumpSlice<0> &dump) {
auto size = dump.slice.size();
const uint8 *ptr = dump.slice.ubegin();
for (size_t i = 0; i < size; i++) {
builder << HexDumpSize<1>{ptr + i};
}
return builder;
}
template
HexDumpSlice as_hex_dump(Slice slice) {
return HexDumpSlice{slice};
}
template
HexDumpSlice as_hex_dump(MutableSlice slice) {
return HexDumpSlice{slice};
}
template
HexDumpSlice as_hex_dump(const T &value) {
return HexDumpSlice{Slice(&value, sizeof(value))};
}
template
HexDumpSize as_hex_dump(const T &value) {
return HexDumpSize{reinterpret_cast(&value)};
}
/*** Hex ***/
template
struct Hex {
const T &value;
};
template
Hex as_hex(const T &value) {
return Hex{value};
}
template
StringBuilder &operator<<(StringBuilder &builder, const Hex &hex) {
builder << "0x" << as_hex_dump(hex.value);
return builder;
}
/*** Binary ***/
template
struct Binary {
const T &value;
};
template
Binary as_binary(const T &value) {
return Binary{value};
}
template
StringBuilder &operator<<(StringBuilder &builder, const Binary &hex) {
for (size_t i = 0; i < sizeof(T) * 8; i++) {
builder << ((hex.value >> i) & 1 ? '1' : '0');
}
return builder;
}
/*** Escaped ***/
struct Escaped {
Slice str;
};
inline StringBuilder &operator<<(StringBuilder &builder, const Escaped &escaped) {
Slice str = escaped.str;
for (unsigned char c : str) {
if (c > 31 && c < 127 && c != '"' && c != '\\') {
builder << static_cast(c);
} else {
const char *oct = "01234567";
builder << '\\' << oct[c >> 6] << oct[(c >> 3) & 7] << oct[c & 7];
}
}
return builder;
}
inline Escaped escaped(Slice slice) {
return Escaped{slice};
}
/*** Time to string ***/
struct Time {
double seconds_;
};
inline StringBuilder &operator<<(StringBuilder &logger, Time t) {
struct NamedValue {
const char *name;
double value;
};
static constexpr NamedValue durations[] = {{"ns", 1e-9}, {"us", 1e-6}, {"ms", 1e-3}, {"s", 1}};
static constexpr size_t durations_n = sizeof(durations) / sizeof(NamedValue);
size_t i = 0;
while (i + 1 < durations_n && t.seconds_ > 10 * durations[i + 1].value) {
i++;
}
logger << StringBuilder::FixedDouble(t.seconds_ / durations[i].value, 1) << durations[i].name;
return logger;
}
inline Time as_time(double seconds) {
return Time{seconds};
}
/*** Size to string ***/
struct Size {
uint64 size_;
};
inline StringBuilder &operator<<(StringBuilder &logger, Size t) {
struct NamedValue {
const char *name;
uint64 value;
};
static constexpr NamedValue sizes[] = {{"B", 1}, {"KB", 1 << 10}, {"MB", 1 << 20}, {"GB", 1 << 30}};
static constexpr size_t sizes_n = sizeof(sizes) / sizeof(NamedValue);
size_t i = 0;
while (i + 1 < sizes_n && t.size_ > 10 * sizes[i + 1].value) {
i++;
}
logger << t.size_ / sizes[i].value << sizes[i].name;
return logger;
}
inline Size as_size(uint64 size) {
return Size{size};
}
/*** Array to string ***/
template
struct Array {
const ArrayT &ref;
};
template
StringBuilder &operator<<(StringBuilder &stream, const Array &array) {
bool first = true;
stream << Slice("{");
for (auto &x : array.ref) {
if (!first) {
stream << Slice(", ");
}
stream << x;
first = false;
}
return stream << Slice("}");
}
inline StringBuilder &operator<<(StringBuilder &stream, const Array> &array) {
bool first = true;
stream << Slice("{");
for (bool x : array.ref) {
if (!first) {
stream << Slice(", ");
}
stream << x;
first = false;
}
return stream << Slice("}");
}
template
Array as_array(const ArrayT &array) {
return Array{array};
}
/*** Tagged ***/
template
struct Tagged {
Slice tag;
const ValueT &ref;
};
template
StringBuilder &operator<<(StringBuilder &stream, const Tagged &tagged) {
return stream << "[" << tagged.tag << ":" << tagged.ref << "]";
}
template
Tagged tag(Slice tag, const ValueT &ref) {
return Tagged{tag, ref};
}
/*** Cond ***/
inline StringBuilder &operator<<(StringBuilder &sb, Unit) {
return sb;
}
template
struct Cond {
bool flag;
const TrueT &on_true;
const FalseT &on_false;
};
template
StringBuilder &operator<<(StringBuilder &sb, const Cond &cond) {
if (cond.flag) {
return sb << cond.on_true;
} else {
return sb << cond.on_false;
}
}
template
Cond cond(bool flag, const TrueT &on_true, const FalseT &on_false = FalseT()) {
return Cond{flag, on_true, on_false};
}
/*** Concat ***/
template
struct Concat {
T args;
};
template
StringBuilder &operator<<(StringBuilder &sb, const Concat &concat) {
tuple_for_each(concat.args, [&sb](auto &x) { sb << x; });
return sb;
}
template
auto concat(const ArgsT &... args) {
return Concat{std::tie(args...)};
}
template
struct Lambda {
const F &f;
};
template
StringBuilder &operator<<(StringBuilder &sb, const Lambda &f) {
f.f(sb);
return sb;
}
template
Lambda lambda(const LambdaT &lambda) {
return Lambda{lambda};
}
} // namespace format
using format::tag;
template
StringBuilder &operator<<(StringBuilder &sb, const std::pair &p) {
return sb << "[" << p.first << ";" << p.second << "]";
}
template
StringBuilder &operator<<(StringBuilder &stream, const vector &vec) {
return stream << format::as_array(vec);
}
template
StringBuilder &operator<<(StringBuilder &stream, const std::set &vec) {
return stream << format::as_array(vec);
}
} // namespace td