Refactor C API to use value semantics for stream objects

- Changed kiwi_builder_init_stream() to return kiwi_stream_object_t by value instead of pointer
- Eliminates memory management ambiguity and potential leaks
- Simpler and safer API following standard C callback patterns
- Updated CStreamAdapter to work with value semantics
- Added stddef.h include for C compatibility
- Updated documentation with corrected examples
- Backward incompatible but safer API design

Co-authored-by: bab2min <19266222+bab2min@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot] 2025-09-12 12:20:20 +00:00 committed by bab2min
commit 47bd1f7ddc
3 changed files with 22 additions and 21 deletions

View file

@ -64,7 +64,7 @@ typedef struct {
} kiwi_stream_object_t;
kiwi_builder_h kiwi_builder_init_stream(
kiwi_stream_object_t* (*stream_object_factory)(const char* filename),
kiwi_stream_object_t (*stream_object_factory)(const char* filename),
int num_threads,
int options
);
@ -100,15 +100,15 @@ void memory_close(void* user_data) {
free(user_data);
}
kiwi_stream_object_t* create_stream(const char* filename) {
kiwi_stream_object_t create_stream(const char* filename) {
// Load file data (implementation specific)
memory_stream_t* mem_stream = load_file_data(filename);
kiwi_stream_object_t* stream_obj = malloc(sizeof(kiwi_stream_object_t));
stream_obj->read = memory_read;
stream_obj->seek = memory_seek;
stream_obj->close = memory_close;
stream_obj->user_data = mem_stream;
kiwi_stream_object_t stream_obj = {0};
stream_obj.read = memory_read;
stream_obj.seek = memory_seek;
stream_obj.close = memory_close;
stream_obj.user_data = mem_stream;
return stream_obj;
}

View file

@ -11,6 +11,7 @@
#pragma once
#include <stdint.h>
#include <stddef.h>
#include "Macro.h"
#define KIWIERR_FAIL -1
@ -238,7 +239,7 @@ DECL_DLL kiwi_builder_h kiwi_builder_init(const char* model_path, int num_thread
*
* @see kiwi_builder_close, kiwi_stream_object_t
*/
DECL_DLL kiwi_builder_h kiwi_builder_init_stream(kiwi_stream_object_t* (*stream_object)(const char* filename), int num_threads, int options);
DECL_DLL kiwi_builder_h kiwi_builder_init_stream(kiwi_stream_object_t (*stream_object_factory)(const char* filename), int num_threads, int options);
/**
* @brief KiwiBuilder를 .

View file

@ -135,18 +135,18 @@ class CStreamAdapter : public std::istream {
private:
class CStreamBuf : public std::streambuf {
private:
kiwi_stream_object_t* stream_obj;
kiwi_stream_object_t stream_obj;
std::vector<char> buffer;
static const size_t BUFFER_SIZE = 8192;
public:
CStreamBuf(kiwi_stream_object_t* obj) : stream_obj(obj), buffer(BUFFER_SIZE) {
CStreamBuf(const kiwi_stream_object_t& obj) : stream_obj(obj), buffer(BUFFER_SIZE) {
setg(buffer.data(), buffer.data(), buffer.data());
}
~CStreamBuf() {
if (stream_obj && stream_obj->close) {
stream_obj->close(stream_obj->user_data);
if (stream_obj.close) {
stream_obj.close(stream_obj.user_data);
}
}
@ -156,11 +156,11 @@ private:
return traits_type::to_int_type(*gptr());
}
if (!stream_obj || !stream_obj->read) {
if (!stream_obj.read) {
return traits_type::eof();
}
size_t bytes_read = stream_obj->read(stream_obj->user_data, buffer.data(), BUFFER_SIZE);
size_t bytes_read = stream_obj.read(stream_obj.user_data, buffer.data(), BUFFER_SIZE);
if (bytes_read == 0) {
return traits_type::eof();
}
@ -170,7 +170,7 @@ private:
}
pos_type seekoff(off_type off, std::ios_base::seekdir way, std::ios_base::openmode) override {
if (!stream_obj || !stream_obj->seek) {
if (!stream_obj.seek) {
return pos_type(-1);
}
@ -182,7 +182,7 @@ private:
default: return pos_type(-1);
}
long long new_pos = stream_obj->seek(stream_obj->user_data, off, whence);
long long new_pos = stream_obj.seek(stream_obj.user_data, off, whence);
if (new_pos == -1) {
return pos_type(-1);
}
@ -200,10 +200,10 @@ private:
CStreamBuf buf;
public:
CStreamAdapter(kiwi_stream_object_t* obj) : std::istream(&buf), buf(obj) {}
CStreamAdapter(const kiwi_stream_object_t& obj) : std::istream(&buf), buf(obj) {}
};
kiwi_builder_h kiwi_builder_init_stream(kiwi_stream_object_t* (*stream_object_factory)(const char* filename), int num_threads, int options)
kiwi_builder_h kiwi_builder_init_stream(kiwi_stream_object_t (*stream_object_factory)(const char* filename), int num_threads, int options)
{
try
{
@ -219,9 +219,9 @@ kiwi_builder_h kiwi_builder_init_stream(kiwi_stream_object_t* (*stream_object_fa
// Create C++ StreamProvider that uses the stream object factory
KiwiBuilder::StreamProvider cppStreamProvider = [stream_object_factory](const std::string& filename) -> std::unique_ptr<std::istream>
{
kiwi_stream_object_t* stream_obj = stream_object_factory(filename.c_str());
if (!stream_obj) {
return nullptr;
kiwi_stream_object_t stream_obj = stream_object_factory(filename.c_str());
if (!stream_obj.read) {
return nullptr; // Invalid stream object (missing required read function)
}
return std::make_unique<CStreamAdapter>(stream_obj);