2020-09-19 19:15:16 +00:00
|
|
|
#include <cstring>
|
|
|
|
#include <cmath>
|
|
|
|
#include <string>
|
2021-10-02 07:13:14 +00:00
|
|
|
#include <base/types.h>
|
|
|
|
#include <base/arithmeticOverflow.h>
|
2020-09-19 19:15:16 +00:00
|
|
|
#include <Common/Exception.h>
|
|
|
|
#include <Common/UnicodeBar.h>
|
2021-01-02 20:40:15 +00:00
|
|
|
#include <Common/NaNUtils.h>
|
2020-09-19 19:15:16 +00:00
|
|
|
|
2021-01-02 20:40:15 +00:00
|
|
|
#include <iostream>
|
2020-09-19 19:15:16 +00:00
|
|
|
|
2022-12-20 01:21:23 +00:00
|
|
|
namespace DB
|
|
|
|
{
|
|
|
|
namespace ErrorCodes
|
|
|
|
{
|
|
|
|
extern const int LOGICAL_ERROR;
|
|
|
|
}
|
|
|
|
}
|
2020-09-19 19:15:16 +00:00
|
|
|
|
|
|
|
namespace UnicodeBar
|
|
|
|
{
|
2021-01-02 20:40:15 +00:00
|
|
|
double getWidth(double x, double min, double max, double max_width)
|
2020-09-19 19:15:16 +00:00
|
|
|
{
|
2021-01-15 10:17:09 +00:00
|
|
|
if (isNaN(x) || isNaN(min) || isNaN(max))
|
2021-01-02 20:40:15 +00:00
|
|
|
return 0;
|
|
|
|
|
2020-09-19 19:15:16 +00:00
|
|
|
if (x <= min)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (x >= max)
|
|
|
|
return max_width;
|
|
|
|
|
2021-01-02 20:40:15 +00:00
|
|
|
return (x - min) / (max - min) * max_width;
|
2020-09-19 19:15:16 +00:00
|
|
|
}
|
|
|
|
|
2022-12-20 16:02:30 +00:00
|
|
|
namespace
|
|
|
|
{
|
|
|
|
/// We use the following Unicode characters to draw the bar:
|
|
|
|
/// U+2588 "█" Full block
|
|
|
|
/// U+2589 "▉" Left seven eighths block
|
|
|
|
/// U+258A "▊" Left three quarters block
|
|
|
|
/// U+258B "▋" Left five eighths block
|
|
|
|
/// U+258C "▌" Left half block
|
|
|
|
/// U+258D "▍" Left three eighths block
|
|
|
|
/// U+258E "▎" Left one quarter block
|
|
|
|
/// U+258F "▏" Left one eighth block
|
|
|
|
constexpr size_t GRADES_IN_FULL_BAR = 8;
|
|
|
|
constexpr char FULL_BAR[] = "█";
|
|
|
|
constexpr char FRACTIONAL_BARS[] = "▏▎▍▌▋▊▉"; /// 7 elements: 1/8, 2/8, 3/8, 4/8, 5/8, 6/8, 7/8
|
|
|
|
}
|
2022-12-20 01:21:23 +00:00
|
|
|
|
2020-09-19 19:15:16 +00:00
|
|
|
size_t getWidthInBytes(double width)
|
|
|
|
{
|
2022-12-20 16:02:30 +00:00
|
|
|
Int64 int_width = static_cast<Int64>(width * GRADES_IN_FULL_BAR);
|
2022-12-20 01:21:23 +00:00
|
|
|
return (int_width / GRADES_IN_FULL_BAR) * UNICODE_BAR_CHAR_SIZE + (int_width % GRADES_IN_FULL_BAR ? UNICODE_BAR_CHAR_SIZE : 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static char* checkedCopy(const char * src, size_t src_size, char * dst, const char * dst_end)
|
|
|
|
{
|
|
|
|
if (dst + src_size > dst_end)
|
|
|
|
throw DB::Exception(
|
|
|
|
DB::ErrorCodes::LOGICAL_ERROR,
|
|
|
|
"Not enough space in buffer for UnicodeBar::render, required: {}, got: {}",
|
|
|
|
src_size, dst_end - dst);
|
|
|
|
|
|
|
|
memcpy(dst, src, src_size);
|
|
|
|
return dst + src_size;
|
2020-09-19 19:15:16 +00:00
|
|
|
}
|
|
|
|
|
2022-12-20 01:21:23 +00:00
|
|
|
void render(double width, char * dst, const char * dst_end)
|
2020-09-19 19:15:16 +00:00
|
|
|
{
|
2022-12-20 16:02:30 +00:00
|
|
|
Int64 int_width = static_cast<Int64>(width * GRADES_IN_FULL_BAR);
|
2022-12-20 01:21:23 +00:00
|
|
|
size_t floor_width = (int_width / GRADES_IN_FULL_BAR);
|
2020-09-19 19:15:16 +00:00
|
|
|
|
|
|
|
for (size_t i = 0; i < floor_width; ++i)
|
|
|
|
{
|
2022-12-20 01:21:23 +00:00
|
|
|
dst = checkedCopy(FULL_BAR, UNICODE_BAR_CHAR_SIZE, dst, dst_end);
|
2020-09-19 19:15:16 +00:00
|
|
|
}
|
|
|
|
|
2022-12-20 01:21:23 +00:00
|
|
|
size_t remainder = int_width % GRADES_IN_FULL_BAR;
|
2020-09-19 19:15:16 +00:00
|
|
|
|
|
|
|
if (remainder)
|
|
|
|
{
|
2022-12-20 01:21:23 +00:00
|
|
|
dst = checkedCopy(&FRACTIONAL_BARS[(remainder - 1) * UNICODE_BAR_CHAR_SIZE], UNICODE_BAR_CHAR_SIZE, dst, dst_end);
|
2020-09-19 19:15:16 +00:00
|
|
|
}
|
|
|
|
|
2022-12-21 09:55:20 +00:00
|
|
|
checkedCopy("\0", 1, dst, dst_end);
|
2020-09-19 19:15:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
std::string render(double width)
|
|
|
|
{
|
2022-12-20 01:21:23 +00:00
|
|
|
std::string res(getWidthInBytes(width) + 1, '\0');
|
|
|
|
render(width, res.data(), res.data() + res.size());
|
2020-09-19 19:15:16 +00:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
}
|