ClickHouse/src/Common/UnicodeBar.cpp

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

94 lines
2.7 KiB
C++
Raw Normal View History

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
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
}
/// 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
2020-09-19 19:15:16 +00:00
size_t getWidthInBytes(double width)
{
Int64 int_width = Int64(width * GRADES_IN_FULL_BAR);
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
}
void render(double width, char * dst, const char * dst_end)
2020-09-19 19:15:16 +00:00
{
Int64 int_width = Int64(width * GRADES_IN_FULL_BAR);
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)
{
dst = checkedCopy(FULL_BAR, UNICODE_BAR_CHAR_SIZE, dst, dst_end);
2020-09-19 19:15:16 +00:00
}
size_t remainder = int_width % GRADES_IN_FULL_BAR;
2020-09-19 19:15:16 +00:00
if (remainder)
{
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
}
dst = checkedCopy("\0", 1, dst, dst_end);
2020-09-19 19:15:16 +00:00
}
std::string render(double width)
{
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;
}
}