1#include <Functions/IFunctionImpl.h>
2#include <Functions/FunctionFactory.h>
3#include <DataTypes/DataTypesNumber.h>
4#include <Formats/FormatSettings.h>
5#include <Columns/ColumnsNumber.h>
6#include <IO/WriteBufferFromString.h>
7#include <Common/UTF8Helpers.h>
8#include <Common/assert_cast.h>
9
10
11namespace DB
12{
13
14/** visibleWidth(x) - calculates the approximate width when outputting the value in a text form to the console.
15 * In fact it calculate the number of Unicode code points.
16 * It does not support zero width and full width characters, combining characters, etc.
17 */
18class FunctionVisibleWidth : public IFunction
19{
20public:
21 static constexpr auto name = "visibleWidth";
22 static FunctionPtr create(const Context &)
23 {
24 return std::make_shared<FunctionVisibleWidth>();
25 }
26
27 bool useDefaultImplementationForNulls() const override { return false; }
28 ColumnNumbers getArgumentsThatDontImplyNullableReturnType(size_t /*number_of_arguments*/) const override { return {0}; }
29
30 /// Get the name of the function.
31 String getName() const override
32 {
33 return name;
34 }
35
36 size_t getNumberOfArguments() const override
37 {
38 return 1;
39 }
40
41 DataTypePtr getReturnTypeImpl(const DataTypes & /*arguments*/) const override
42 {
43 return std::make_shared<DataTypeUInt64>();
44 }
45
46 bool useDefaultImplementationForConstants() const override { return true; }
47
48 /// Execute the function on the block.
49 void executeImpl(Block & block, const ColumnNumbers & arguments, size_t result, size_t input_rows_count) override
50 {
51 auto & src = block.getByPosition(arguments[0]);
52 size_t size = input_rows_count;
53
54 auto res_col = ColumnUInt64::create(size);
55 auto & res_data = assert_cast<ColumnUInt64 &>(*res_col).getData();
56
57 /// For simplicity reasons, function is implemented by serializing into temporary buffer.
58
59 String tmp;
60 FormatSettings format_settings;
61 for (size_t i = 0; i < size; ++i)
62 {
63 {
64 WriteBufferFromString out(tmp);
65 src.type->serializeAsText(*src.column, i, out, format_settings);
66 }
67
68 res_data[i] = UTF8::countCodePoints(reinterpret_cast<const UInt8 *>(tmp.data()), tmp.size());
69 }
70
71 block.getByPosition(result).column = std::move(res_col);
72 }
73};
74
75
76void registerFunctionVisibleWidth(FunctionFactory & factory)
77{
78 factory.registerFunction<FunctionVisibleWidth>();
79}
80
81}
82