2018-09-09 23:36:06 +00:00
|
|
|
#include <Columns/ColumnString.h>
|
|
|
|
|
|
|
|
|
|
|
|
namespace DB
|
|
|
|
{
|
|
|
|
|
|
|
|
template <char not_case_lower_bound, char not_case_upper_bound>
|
|
|
|
struct LowerUpperImpl
|
|
|
|
{
|
2018-11-25 00:08:50 +00:00
|
|
|
static void vector(const ColumnString::Chars & data,
|
2018-09-09 23:36:06 +00:00
|
|
|
const ColumnString::Offsets & offsets,
|
2018-11-25 00:08:50 +00:00
|
|
|
ColumnString::Chars & res_data,
|
2018-09-09 23:36:06 +00:00
|
|
|
ColumnString::Offsets & res_offsets)
|
|
|
|
{
|
|
|
|
res_data.resize(data.size());
|
|
|
|
res_offsets.assign(offsets);
|
|
|
|
array(data.data(), data.data() + data.size(), res_data.data());
|
|
|
|
}
|
|
|
|
|
2020-03-23 02:12:31 +00:00
|
|
|
static void vectorFixed(const ColumnString::Chars & data, size_t /*n*/, ColumnString::Chars & res_data)
|
2018-09-09 23:36:06 +00:00
|
|
|
{
|
|
|
|
res_data.resize(data.size());
|
|
|
|
array(data.data(), data.data() + data.size(), res_data.data());
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
static void array(const UInt8 * src, const UInt8 * src_end, UInt8 * dst)
|
|
|
|
{
|
|
|
|
const auto flip_case_mask = 'A' ^ 'a';
|
|
|
|
|
2019-01-04 12:10:00 +00:00
|
|
|
#ifdef __SSE2__
|
2018-09-09 23:36:06 +00:00
|
|
|
const auto bytes_sse = sizeof(__m128i);
|
|
|
|
const auto src_end_sse = src_end - (src_end - src) % bytes_sse;
|
|
|
|
|
|
|
|
const auto v_not_case_lower_bound = _mm_set1_epi8(not_case_lower_bound - 1);
|
|
|
|
const auto v_not_case_upper_bound = _mm_set1_epi8(not_case_upper_bound + 1);
|
|
|
|
const auto v_flip_case_mask = _mm_set1_epi8(flip_case_mask);
|
|
|
|
|
|
|
|
for (; src < src_end_sse; src += bytes_sse, dst += bytes_sse)
|
|
|
|
{
|
|
|
|
/// load 16 sequential 8-bit characters
|
|
|
|
const auto chars = _mm_loadu_si128(reinterpret_cast<const __m128i *>(src));
|
|
|
|
|
|
|
|
/// find which 8-bit sequences belong to range [case_lower_bound, case_upper_bound]
|
|
|
|
const auto is_not_case
|
|
|
|
= _mm_and_si128(_mm_cmpgt_epi8(chars, v_not_case_lower_bound), _mm_cmplt_epi8(chars, v_not_case_upper_bound));
|
|
|
|
|
|
|
|
/// keep `flip_case_mask` only where necessary, zero out elsewhere
|
|
|
|
const auto xor_mask = _mm_and_si128(v_flip_case_mask, is_not_case);
|
|
|
|
|
|
|
|
/// flip case by applying calculated mask
|
|
|
|
const auto cased_chars = _mm_xor_si128(chars, xor_mask);
|
|
|
|
|
|
|
|
/// store result back to destination
|
|
|
|
_mm_storeu_si128(reinterpret_cast<__m128i *>(dst), cased_chars);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
for (; src < src_end; ++src, ++dst)
|
|
|
|
if (*src >= not_case_lower_bound && *src <= not_case_upper_bound)
|
|
|
|
*dst = *src ^ flip_case_mask;
|
|
|
|
else
|
|
|
|
*dst = *src;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
}
|