@@ -23,19 +23,15 @@ extern "C" {
2323#include " base/flags.h"
2424#include " base/logging.h"
2525#include " base/pod_array.h"
26+ #include " core/detail/bitpacking.h"
2627#include " core/string_set.h"
2728
28- #if defined(__aarch64__)
29- #include " base/sse2neon.h"
30- #else
31- #include < emmintrin.h>
32- #endif
33-
3429ABSL_FLAG (bool , use_set2, true , " If true use DenseSet for an optimized set data structure" );
3530
3631namespace dfly {
3732using namespace std ;
3833using absl::GetFlag;
34+ using detail::binpacked_len;
3935
4036namespace {
4137
@@ -154,35 +150,6 @@ inline void FreeObjStream(void* ptr) {
154150 freeStream ((stream*)ptr);
155151}
156152
157- // Daniel Lemire's function validate_ascii_fast() - under Apache/MIT license.
158- // See https://github.com/lemire/fastvalidate-utf-8/
159- // The function returns true (1) if all chars passed in src are
160- // 7-bit values (0x00..0x7F). Otherwise, it returns false (0).
161- bool validate_ascii_fast (const char * src, size_t len) {
162- size_t i = 0 ;
163- __m128i has_error = _mm_setzero_si128 ();
164- if (len >= 16 ) {
165- for (; i <= len - 16 ; i += 16 ) {
166- __m128i current_bytes = _mm_loadu_si128 ((const __m128i*)(src + i));
167- has_error = _mm_or_si128 (has_error, current_bytes);
168- }
169- }
170- int error_mask = _mm_movemask_epi8 (has_error);
171-
172- char tail_has_error = 0 ;
173- for (; i < len; i++) {
174- tail_has_error |= src[i];
175- }
176- error_mask |= (tail_has_error & 0x80 );
177-
178- return !error_mask;
179- }
180-
181- // maps ascii len to 7-bit packed length. Each 8 bytes are converted to 7 bytes.
182- inline constexpr size_t binpacked_len (size_t ascii_len) {
183- return (ascii_len * 7 + 7 ) / 8 ; /* rounded up */
184- }
185-
186153// converts 7-bit packed length back to ascii length. Note that this conversion
187154// is not accurate since it maps 7 bytes to 8 bytes (rounds up), while we may have
188155// 7 byte strings converted to 7 byte as well.
@@ -428,91 +395,6 @@ void RobjWrapper::MakeInnerRoom(size_t current_cap, size_t desired, pmr::memory_
428395 inner_obj_ = newp;
429396}
430397
431- #if defined(__GNUC__) && !defined(__clang__)
432- #pragma GCC push_options
433- #pragma GCC optimize("Ofast")
434- #endif
435-
436- // len must be at least 16
437- void ascii_pack (const char * ascii, size_t len, uint8_t * bin) {
438- const char * end = ascii + len;
439-
440- unsigned i = 0 ;
441- while (ascii + 8 <= end) {
442- for (i = 0 ; i < 7 ; ++i) {
443- *bin++ = (ascii[0 ] >> i) | (ascii[1 ] << (7 - i));
444- ++ascii;
445- }
446- ++ascii;
447- }
448-
449- // epilog - we do not pack since we have less than 8 bytes.
450- while (ascii < end) {
451- *bin++ = *ascii++;
452- }
453- }
454-
455- // unpacks 8->7 encoded blob back to ascii.
456- // generally, we can not unpack inplace because ascii (dest) buffer is 8/7 bigger than
457- // the source buffer.
458- // however, if binary data is positioned on the right of the ascii buffer with empty space on the
459- // left than we can unpack inplace.
460- void ascii_unpack (const uint8_t * bin, size_t ascii_len, char * ascii) {
461- constexpr uint8_t kM = 0x7F ;
462- uint8_t p = 0 ;
463- unsigned i = 0 ;
464-
465- while (ascii_len >= 8 ) {
466- for (i = 0 ; i < 7 ; ++i) {
467- uint8_t src = *bin; // keep on stack in case we unpack inplace.
468- *ascii++ = (p >> (8 - i)) | ((src << i) & kM );
469- p = src;
470- ++bin;
471- }
472-
473- ascii_len -= 8 ;
474- *ascii++ = p >> 1 ;
475- }
476-
477- DCHECK_LT (ascii_len, 8u );
478- for (i = 0 ; i < ascii_len; ++i) {
479- *ascii++ = *bin++;
480- }
481- }
482-
483- // compares packed and unpacked strings. packed must be of length = binpacked_len(ascii_len).
484- bool compare_packed (const uint8_t * packed, const char * ascii, size_t ascii_len) {
485- unsigned i = 0 ;
486- bool res = true ;
487- const char * end = ascii + ascii_len;
488-
489- while (ascii + 8 <= end) {
490- for (i = 0 ; i < 7 ; ++i) {
491- uint8_t conv = (ascii[0 ] >> i) | (ascii[1 ] << (7 - i));
492- res &= (conv == *packed);
493- ++ascii;
494- ++packed;
495- }
496-
497- if (!res)
498- return false ;
499-
500- ++ascii;
501- }
502-
503- while (ascii < end) {
504- if (*ascii++ != *packed++) {
505- return false ;
506- }
507- }
508-
509- return true ;
510- }
511-
512- #if defined(__GNUC__) && !defined(__clang__)
513- #pragma GCC pop_options
514- #endif
515-
516398} // namespace detail
517399
518400using namespace std ;
@@ -777,7 +659,7 @@ void CompactObj::SetString(std::string_view str) {
777659 DCHECK_GT (str.size (), kInlineLen );
778660
779661 string_view encoded = str;
780- bool is_ascii = kUseAsciiEncoding && validate_ascii_fast (str.data (), str.size ());
662+ bool is_ascii = kUseAsciiEncoding && detail:: validate_ascii_fast (str.data (), str.size ());
781663
782664 if (is_ascii) {
783665 size_t encode_len = binpacked_len (str.size ());
@@ -792,7 +674,7 @@ void CompactObj::SetString(std::string_view str) {
792674 }
793675
794676 tl.tmp_buf .resize (encode_len);
795- detail::ascii_pack (str.data (), str.size (), tl.tmp_buf .data ());
677+ detail::ascii_pack_simd (str.data (), str.size (), tl.tmp_buf .data ());
796678 encoded = string_view{reinterpret_cast <char *>(tl.tmp_buf .data ()), encode_len};
797679
798680 if (encoded.size () <= kInlineLen ) {
@@ -1125,7 +1007,7 @@ bool CompactObj::CmpEncoded(string_view sv) const {
11251007 if (u_.r_obj .Size () != encode_len)
11261008 return false ;
11271009
1128- if (!validate_ascii_fast (sv.data (), sv.size ()))
1010+ if (!detail:: validate_ascii_fast (sv.data (), sv.size ()))
11291011 return false ;
11301012
11311013 return detail::compare_packed (to_byte (u_.r_obj .inner_obj ()), sv.data (), sv.size ());
@@ -1139,7 +1021,7 @@ bool CompactObj::CmpEncoded(string_view sv) const {
11391021 if (u_.small_str .size () != encode_len)
11401022 return false ;
11411023
1142- if (!validate_ascii_fast (sv.data (), sv.size ()))
1024+ if (!detail:: validate_ascii_fast (sv.data (), sv.size ()))
11431025 return false ;
11441026
11451027 // We need to compare an unpacked sv with 2 packed parts.
0 commit comments