namespace simdutf { namespace SIMDUTF_IMPLEMENTATION { namespace { // Walks through a buffer in block-sized increments, loading the last part with // spaces template struct buf_block_reader { public: simdutf_really_inline buf_block_reader(const uint8_t *_buf, size_t _len); simdutf_really_inline size_t block_index(); simdutf_really_inline bool has_full_block() const; simdutf_really_inline const uint8_t *full_block() const; /** * Get the last block, padded with spaces. * * There will always be a last block, with at least 1 byte, unless len == 0 * (in which case this function fills the buffer with spaces and returns 0. In * particular, if len == STEP_SIZE there will be 0 full_blocks and 1 remainder * block with STEP_SIZE bytes and no spaces for padding. * * @return the number of effective characters in the last block. */ simdutf_really_inline size_t get_remainder(uint8_t *dst) const; simdutf_really_inline void advance(); private: const uint8_t *buf; const size_t len; const size_t lenminusstep; size_t idx; }; // Routines to print masks and text for debugging bitmask operations simdutf_unused static char *format_input_text_64(const uint8_t *text) { static char *buf = reinterpret_cast(malloc(sizeof(simd8x64) + 1)); for (size_t i = 0; i < sizeof(simd8x64); i++) { buf[i] = int8_t(text[i]) < ' ' ? '_' : int8_t(text[i]); } buf[sizeof(simd8x64)] = '\0'; return buf; } // Routines to print masks and text for debugging bitmask operations simdutf_unused static char *format_input_text(const simd8x64 &in) { static char *buf = reinterpret_cast(malloc(sizeof(simd8x64) + 1)); in.store(reinterpret_cast(buf)); for (size_t i = 0; i < sizeof(simd8x64); i++) { if (buf[i] < ' ') { buf[i] = '_'; } } buf[sizeof(simd8x64)] = '\0'; return buf; } simdutf_unused static char *format_mask(uint64_t mask) { static char *buf = reinterpret_cast(malloc(64 + 1)); for (size_t i = 0; i < 64; i++) { buf[i] = (mask & (size_t(1) << i)) ? 'X' : ' '; } buf[64] = '\0'; return buf; } template simdutf_really_inline buf_block_reader::buf_block_reader(const uint8_t *_buf, size_t _len) : buf{_buf}, len{_len}, lenminusstep{len < STEP_SIZE ? 0 : len - STEP_SIZE}, idx{0} {} template simdutf_really_inline size_t buf_block_reader::block_index() { return idx; } template simdutf_really_inline bool buf_block_reader::has_full_block() const { return idx < lenminusstep; } template simdutf_really_inline const uint8_t * buf_block_reader::full_block() const { return &buf[idx]; } template simdutf_really_inline size_t buf_block_reader::get_remainder(uint8_t *dst) const { if (len == idx) { return 0; } // memcpy(dst, null, 0) will trigger an error with some sanitizers std::memset(dst, 0x20, STEP_SIZE); // std::memset STEP_SIZE because it is more efficient // to write out 8 or 16 bytes at once. std::memcpy(dst, buf + idx, len - idx); return len - idx; } template simdutf_really_inline void buf_block_reader::advance() { idx += STEP_SIZE; } } // unnamed namespace } // namespace SIMDUTF_IMPLEMENTATION } // namespace simdutf