yams/plugins/zyp/zpdf_wrapper.h
Trevon 6d8877a6d4
feat(search): add Simeon bandit tuning (#33)
* feat(search): per-profile simeon bandit with training-free self-tuning

* fix(zyp): free parallel buffers correctly

* fix: code cleanup and simeon version bump

* fix(search): guard Simeon bandit state
2026-05-17 04:08:50 -04:00

135 lines
3.9 KiB
C++

/**
* @file zpdf_wrapper.h
* @brief C++ RAII wrapper for zpdf library
*/
#pragma once
#include <cstddef>
#include <cstdint>
#include <memory>
#include <optional>
#include <span>
#include <string>
#include <string_view>
#include <vector>
namespace yams::zyp {
/**
* RAII wrapper for zpdf text buffer.
* Automatically frees the buffer on destruction.
*/
class TextBuffer {
public:
TextBuffer() = default;
TextBuffer(uint8_t* data, size_t len);
static TextBuffer fromMalloc(uint8_t* data, size_t len);
~TextBuffer();
// Move-only
TextBuffer(TextBuffer&& other) noexcept;
TextBuffer& operator=(TextBuffer&& other) noexcept;
TextBuffer(const TextBuffer&) = delete;
TextBuffer& operator=(const TextBuffer&) = delete;
/** Get text as string_view */
[[nodiscard]] std::string_view text() const;
/** Check if buffer is empty */
[[nodiscard]] bool empty() const;
/** Check if buffer is valid */
[[nodiscard]] explicit operator bool() const;
/** Get raw data pointer */
[[nodiscard]] const uint8_t* data() const { return data_; }
/** Get buffer length */
[[nodiscard]] size_t size() const { return len_; }
private:
enum class Deallocator { Zpdf, Malloc };
TextBuffer(uint8_t* data, size_t len, Deallocator deallocator);
void release() noexcept;
uint8_t* data_ = nullptr;
size_t len_ = 0;
Deallocator deallocator_ = Deallocator::Zpdf;
};
/**
* Page information structure.
*/
struct PageInfo {
double width; /**< Page width in points */
double height; /**< Page height in points */
int rotation; /**< Rotation in degrees (0, 90, 180, 270) */
};
/**
* RAII wrapper for zpdf document handle.
*/
class Document {
public:
/**
* Open a PDF document from a file path.
* @param path File path
* @return Document if successful, nullopt on error
*/
[[nodiscard]] static std::optional<Document> open(std::string_view path);
/**
* Open a PDF document from a memory buffer.
* @param data PDF data
* @return Document if successful, nullopt on error
*/
[[nodiscard]] static std::optional<Document> openMemory(std::span<const uint8_t> data);
~Document();
// Move-only
Document(Document&& other) noexcept;
Document& operator=(Document&& other) noexcept;
Document(const Document&) = delete;
Document& operator=(const Document&) = delete;
/** Get page count */
[[nodiscard]] int pageCount() const;
/** Get page information */
[[nodiscard]] std::optional<PageInfo> pageInfo(int pageNum) const;
/** Extract text from a single page */
[[nodiscard]] TextBuffer extractPage(int pageNum) const;
/** Extract text from all pages (sequential, reading-order) */
[[nodiscard]] TextBuffer extractAll() const;
/** Extract text from all pages using multiple threads.
* Opens per-thread Document instances from the same buffer and
* distributes pages across threads for true parallelism.
* @param data Raw PDF buffer (must remain valid for the duration of the call)
* @param numThreads Number of threads (0 = hardware concurrency)
* @return Combined text buffer, or empty TextBuffer on failure */
[[nodiscard]] static TextBuffer extractAllParallelized(std::span<const uint8_t> data,
int numThreads = 0);
/** Alias for extractAll(); named for backward compatibility.
* Note: despite the name this is sequential, not parallel;
* use extractAllParallelized() for true parallelism. */
[[nodiscard]] TextBuffer extractAllParallel() const;
/** Extract text in visual reading order (experimental) */
[[nodiscard]] TextBuffer extractAllReadingOrder() const;
/** Check if document handle is valid */
[[nodiscard]] bool valid() const;
private:
explicit Document(void* handle);
void* handle_ = nullptr;
};
} // namespace yams::zyp