1 | #include <Columns/ColumnString.h> |
2 | #include <Functions/FunctionFactory.h> |
3 | #include <Functions/FunctionStringToString.h> |
4 | #include <common/find_symbols.h> |
5 | |
6 | |
7 | namespace DB |
8 | { |
9 | |
10 | namespace ErrorCodes |
11 | { |
12 | extern const int ILLEGAL_TYPE_OF_ARGUMENT; |
13 | } |
14 | |
15 | struct TrimModeLeft |
16 | { |
17 | static constexpr auto name = "trimLeft" ; |
18 | static constexpr bool trim_left = true; |
19 | static constexpr bool trim_right = false; |
20 | }; |
21 | |
22 | struct TrimModeRight |
23 | { |
24 | static constexpr auto name = "trimRight" ; |
25 | static constexpr bool trim_left = false; |
26 | static constexpr bool trim_right = true; |
27 | }; |
28 | |
29 | struct TrimModeBoth |
30 | { |
31 | static constexpr auto name = "trimBoth" ; |
32 | static constexpr bool trim_left = true; |
33 | static constexpr bool trim_right = true; |
34 | }; |
35 | |
36 | template <typename mode> |
37 | class FunctionTrimImpl |
38 | { |
39 | public: |
40 | static void vector( |
41 | const ColumnString::Chars & data, |
42 | const ColumnString::Offsets & offsets, |
43 | ColumnString::Chars & res_data, |
44 | ColumnString::Offsets & res_offsets) |
45 | { |
46 | size_t size = offsets.size(); |
47 | res_offsets.resize(size); |
48 | res_data.reserve(data.size()); |
49 | |
50 | size_t prev_offset = 0; |
51 | size_t res_offset = 0; |
52 | |
53 | const UInt8 * start; |
54 | size_t length; |
55 | |
56 | for (size_t i = 0; i < size; ++i) |
57 | { |
58 | execute(reinterpret_cast<const UInt8 *>(&data[prev_offset]), offsets[i] - prev_offset - 1, start, length); |
59 | |
60 | res_data.resize(res_data.size() + length + 1); |
61 | memcpySmallAllowReadWriteOverflow15(&res_data[res_offset], start, length); |
62 | res_offset += length + 1; |
63 | res_data[res_offset - 1] = '\0'; |
64 | |
65 | res_offsets[i] = res_offset; |
66 | prev_offset = offsets[i]; |
67 | } |
68 | } |
69 | |
70 | static void vector_fixed(const ColumnString::Chars &, size_t, ColumnString::Chars &) |
71 | { |
72 | throw Exception("Functions trimLeft, trimRight and trimBoth cannot work with FixedString argument" , ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); |
73 | } |
74 | |
75 | private: |
76 | static void execute(const UInt8 * data, size_t size, const UInt8 *& res_data, size_t & res_size) |
77 | { |
78 | const char * char_data = reinterpret_cast<const char *>(data); |
79 | const char * char_end = char_data + size; |
80 | |
81 | if constexpr (mode::trim_left) |
82 | { |
83 | const char * found = find_first_not_symbols<' '>(char_data, char_end); |
84 | size_t num_chars = found - char_data; |
85 | char_data += num_chars; |
86 | } |
87 | |
88 | if constexpr (mode::trim_right) |
89 | { |
90 | const char * found = find_last_not_symbols_or_null<' '>(char_data, char_end); |
91 | if (found) |
92 | char_end = found + 1; |
93 | else |
94 | char_end = char_data; |
95 | } |
96 | |
97 | res_data = reinterpret_cast<const UInt8 *>(char_data); |
98 | res_size = char_end - char_data; |
99 | } |
100 | }; |
101 | |
102 | using FunctionTrimLeft = FunctionStringToString<FunctionTrimImpl<TrimModeLeft>, TrimModeLeft>; |
103 | using FunctionTrimRight = FunctionStringToString<FunctionTrimImpl<TrimModeRight>, TrimModeRight>; |
104 | using FunctionTrimBoth = FunctionStringToString<FunctionTrimImpl<TrimModeBoth>, TrimModeBoth>; |
105 | |
106 | void registerFunctionTrim(FunctionFactory & factory) |
107 | { |
108 | factory.registerFunction<FunctionTrimLeft>(); |
109 | factory.registerFunction<FunctionTrimRight>(); |
110 | factory.registerFunction<FunctionTrimBoth>(); |
111 | } |
112 | } |
113 | |