#define PCRE2_CODE_UNIT_WIDTH 8 #include #include #include #include #include "GLiNER/tokenizer_utils.hpp" namespace gliner { // RAII wrapper for PCRE2 resources class PCRE2Resource { private: pcre2_code *pattern_; pcre2_match_data *match_data_; public: PCRE2Resource() : pattern_(nullptr), match_data_(nullptr) {} ~PCRE2Resource() { if (match_data_) pcre2_match_data_free(match_data_); if (pattern_) pcre2_code_free(pattern_); } // Prevent copying PCRE2Resource(const PCRE2Resource &) = delete; PCRE2Resource &operator=(const PCRE2Resource &) = delete; void compilePattern(const char *pattern) { int errorcode; PCRE2_SIZE erroroffset; pattern_ = pcre2_compile( reinterpret_cast(pattern), PCRE2_ZERO_TERMINATED, PCRE2_UTF | PCRE2_UCP, &errorcode, &erroroffset, nullptr); if (!pattern_) { PCRE2_UCHAR buffer[256]; pcre2_get_error_message(errorcode, buffer, sizeof(buffer)); throw std::runtime_error("PCRE2 compilation failed at offset " + std::to_string(erroroffset) + ": " + reinterpret_cast(buffer)); } // Enable JIT compilation for better performance pcre2_jit_compile(pattern_, PCRE2_JIT_COMPLETE); match_data_ = pcre2_match_data_create_from_pattern(pattern_, nullptr); if (!match_data_) { throw std::runtime_error("Failed to create PCRE2 match data"); } } pcre2_code *pattern() const { return pattern_; } pcre2_match_data *match_data() const { return match_data_; } PCRE2_SIZE *getOvectorPointer() const { return pcre2_get_ovector_pointer(match_data_); } }; struct WhitespaceTokenSplitter::Implementation { PCRE2Resource pcre2; }; std::string LoadBytesFromFile(const std::string &path) { std::ifstream fs(path, std::ios::in | std::ios::binary); if (!fs) { throw std::runtime_error("Cannot open file: " + path); } // More efficient file reading using a single allocation fs.seekg(0, std::ios::end); std::string data; data.reserve(fs.tellg()); fs.seekg(0, std::ios::beg); data.assign( std::istreambuf_iterator(fs), std::istreambuf_iterator()); return data; } WhitespaceTokenSplitter::WhitespaceTokenSplitter() : pimpl(std::make_unique()) { pimpl->pcre2.compilePattern("\\w+(?:[-_]\\w+)*|\\S"); } WhitespaceTokenSplitter::~WhitespaceTokenSplitter() = default; std::vector WhitespaceTokenSplitter::call(const std::string &text) { std::vector tokens; tokens.reserve(text.length() / 4); // Estimate initial capacity PCRE2_SIZE *ovector = pimpl->pcre2.getOvectorPointer(); const size_t subject_length = text.length(); size_t start_offset = 0; while (true) { int rc = pcre2_match( pimpl->pcre2.pattern(), reinterpret_cast(text.c_str()), subject_length, start_offset, PCRE2_NO_UTF_CHECK, pimpl->pcre2.match_data(), nullptr); if (rc < 0) { if (rc != PCRE2_ERROR_NOMATCH) { throw std::runtime_error("PCRE2 matching error: " + std::to_string(rc)); } break; } const size_t start = ovector[0]; const size_t end = ovector[1]; tokens.push_back({start, end, text.substr(start, end - start)}); start_offset = end; } return tokens; } }