#include "utils.hpp"
#include <cstddef>
#include <string_view>
#if defined(__SSE2__) && defined(LIBDDWAF_VECTORIZED_TRANSFORMERS)
# include <immintrin.h>
#endif
#include "cow_string.hpp"
#include "transformer/lowercase.hpp"
namespace ddwaf::transformer {
#if !defined(__SSE2__) || !defined(LIBDDWAF_VECTORIZED_TRANSFORMERS)
bool lowercase::transform_impl(cow_string &str)
{
std::size_t pos = 0;
for (; pos < str.length() && (str.at(pos) < 'A' || str.at(pos) > 'Z'); ++pos) {}
if (pos == str.length()) {
return false;
}
for (; pos < str.length(); ++pos) { str[pos] = tolower(str.at(pos)); }
return true;
}
#else
bool lowercase::needs_transform(std::string_view str)
{
if (str.empty()) {
return false;
}
const char *input = str.data();
const __m128i sse_mask_lower_bound = _mm_set1_epi8('A' - 1);
const __m128i sse_mask_upper_bound = _mm_set1_epi8('Z' + 1);
const std::size_t aligned_size = str.size() & ~0xF;
bool has_uppercase = false;
for (std::size_t i = 0; i < aligned_size && !has_uppercase; i += 16) {
const __m128i input_data = _mm_loadu_si128((__m128i *)(input + i));
const __m128i cmp_upper =
_mm_cmpgt_epi8(input_data, sse_mask_lower_bound); const __m128i cmp_lower = _mm_cmpgt_epi8(sse_mask_upper_bound, input_data); const __m128i cmp_result =
_mm_and_si128(cmp_upper, cmp_lower); has_uppercase =
_mm_movemask_epi8(_mm_cmpeq_epi8(cmp_result, _mm_setzero_si128())) != 0xFFFF;
}
for (std::size_t i = aligned_size; i < str.size() && !has_uppercase; i++) {
has_uppercase = isupper(input[i]);
}
return has_uppercase;
}
bool lowercase::transform_impl(cow_string &str)
{
auto size = str.length();
char *input = str.modifiable_data();
const __m128i sse_mask_upper_bound = _mm_set1_epi8('Z' + 1);
const __m128i sse_mask_lower_bound = _mm_set1_epi8('A' - 1);
const __m128i sse_addition_value = _mm_set1_epi8(0x20);
const std::size_t aligned_size = size & ~0xF;
for (std::size_t i = 0; i < aligned_size; i += 16) {
const __m128i input_data = _mm_loadu_si128((__m128i *)(input + i));
const __m128i cmp_upper = _mm_cmpgt_epi8(input_data, sse_mask_lower_bound); const __m128i cmp_lower = _mm_cmpgt_epi8(sse_mask_upper_bound, input_data); const __m128i cmp_result = _mm_and_si128(cmp_upper, cmp_lower);
const __m128i result =
_mm_add_epi8(input_data, _mm_and_si128(cmp_result, sse_addition_value));
_mm_storeu_si128((__m128i *)(input + i), result);
}
for (std::size_t i = aligned_size; i < size; i++) {
const char c = input[i];
input[i] = tolower(c);
}
return true;
}
#endif
}