From a536a271ab98ffe2e66a6c412a71072808649e79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Du=C5=A1an=20Poizl?= Date: Sun, 21 May 2023 19:33:36 +0200 Subject: [PATCH] Add StreamBuffer to optimize save/load from memory --- CMakeLists.txt | 2 + libxisf.cpp | 13 +++-- streambuffer.cpp | 144 +++++++++++++++++++++++++++++++++++++++++++++++ streambuffer.h | 33 +++++++++++ 4 files changed, 187 insertions(+), 5 deletions(-) create mode 100644 streambuffer.cpp create mode 100644 streambuffer.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 715ff45..be70469 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -66,6 +66,8 @@ add_library(XISF libXISF_global.h libxisf.cpp libxisf.h + streambuffer.cpp + streambuffer.h utils.cpp variant.cpp ${THIRD_PARTY_SRC} diff --git a/libxisf.cpp b/libxisf.cpp index b6b7310..c25293f 100644 --- a/libxisf.cpp +++ b/libxisf.cpp @@ -27,6 +27,7 @@ #include #include #include +#include "streambuffer.h" namespace LibXISF { @@ -532,6 +533,7 @@ private: Image parseImage(const pugi::xml_node &node); std::unique_ptr _io; + std::unique_ptr _buffer; std::vector _images; Image _thumbnail; std::vector _properties; @@ -548,8 +550,8 @@ void XISFReaderPrivate::open(const String &name) void XISFReaderPrivate::open(const ByteArray &data) { close(); - std::string str((char*)data.data(), data.size()); - _io = std::make_unique(str, std::ios_base::in | std::ios_base::binary); + _buffer = std::make_unique(data); + _io = std::make_unique(_buffer.get()); readSignature(); readXISFHeader(); } @@ -565,6 +567,7 @@ void XISFReaderPrivate::open(std::istream *io) void XISFReaderPrivate::close() { _io.reset(); + _buffer.reset(); _images.clear(); _properties.clear(); } @@ -839,10 +842,10 @@ void XISFWriterPrivate::save(const String &name) void XISFWriterPrivate::save(ByteArray &data) { - std::ostringstream oss; + StreamBuffer buffer; + std::ostream oss(&buffer); save(oss); - std::string str = oss.str(); - data = ByteArray(str.data(), str.size()); + data = buffer.byteArray(); } void XISFWriterPrivate::save(std::ostream &io) diff --git a/streambuffer.cpp b/streambuffer.cpp new file mode 100644 index 0000000..dcebdf8 --- /dev/null +++ b/streambuffer.cpp @@ -0,0 +1,144 @@ +#include "streambuffer.h" + +namespace LibXISF +{ + +StreamBuffer::StreamBuffer() +{ + setg(nullptr, nullptr, nullptr); + setp(nullptr, nullptr); +} + +StreamBuffer::StreamBuffer(const ByteArray &byteArray) : + _size(byteArray.size()), + _byteArray(byteArray) +{ + if(_byteArray.size()) + { + char *ptr = _byteArray.data(); + setg(ptr, ptr, ptr + _size); + setp(ptr, ptr + _size); + } + else + { + setg(nullptr, nullptr, nullptr); + setp(nullptr, nullptr); + } +} + +ByteArray StreamBuffer::byteArray() +{ + return _byteArray; +} + +StreamBuffer::pos_type StreamBuffer::seekoff(off_type off, std::ios_base::seekdir dir, std::ios_base::openmode mode) +{ + pos_type ret = pos_type(off_type(-1)); + off_type newoffi = off; + off_type newoffo = off; + if(dir == std::ios_base::cur) + { + newoffi += gptr() - eback(); + newoffo += pptr() - pbase(); + } + else if(dir == std::ios_base::end) + newoffo = newoffi = _byteArray.size() - off; + + char *ptr = _byteArray.data(); + if(mode & std::ios_base::in && newoffi >= 0 && newoffi <= _size) + { + setg(ptr, ptr + newoffi, ptr + _size); + ret = pos_type(newoffi); + } + + if(mode & std::ios_base::out && newoffo >= 0 && newoffo <= _size) + { + setp(ptr, ptr + _size); + pbump(newoffo); + ret = pos_type(newoffo); + } + + return ret; +} + +StreamBuffer::pos_type StreamBuffer::seekpos(pos_type pos, std::ios_base::openmode mode) +{ + pos_type ret = pos_type(off_type(-1)); + off_type off = pos; + + if(off >= 0 && off <= (off_type)_byteArray.size()) + { + char *ptr = _byteArray.data(); + if(mode & std::ios_base::in) + setg(ptr, ptr + pos, ptr + _size); + + if(mode & std::ios_base::out) + { + setp(ptr, ptr + _size); + pbump(pos); + } + + ret = pos; + } + return ret; +} + +std::streamsize StreamBuffer::xsgetn(char_type *s, std::streamsize n) +{ + std::streamsize ret = 0; + std::streamsize len = egptr() - gptr(); + if(len > 0) + { + std::streamsize c = std::min(n, len); + std::memcpy(s, gptr(), c); + gbump(c); + ret = c; + } + return ret; +} + +StreamBuffer::int_type StreamBuffer::underflow() +{ + if(gptr() < egptr()) + return traits_type::to_int_type(*gptr()); + else + return traits_type::eof(); +} + +std::streamsize StreamBuffer::xsputn(const char_type *s, std::streamsize n) +{ + off_type len = epptr() - pptr(); + if(len < n) + { + _size += n - len; + _byteArray.resize(_size); + update_ptrs(); + } + std::memcpy(pptr(), s, n); + pbump(n); + return n; +} + +StreamBuffer::int_type StreamBuffer::overflow(int_type c) +{ + if(traits_type::eq_int_type(traits_type::eof(), c)) + return traits_type::eof(); + + _byteArray.append(c); + _size++; + pbump(1); + update_ptrs(); + return c; +} + +void StreamBuffer::update_ptrs() +{ + off_type ipos = gptr() - eback(); + off_type opos = pptr() - pbase(); + char *ptr = _byteArray.data(); + setg(ptr, ptr + ipos, ptr + _size); + setp(ptr, ptr + _size); + pbump(opos); +} + +} diff --git a/streambuffer.h b/streambuffer.h new file mode 100644 index 0000000..aff3920 --- /dev/null +++ b/streambuffer.h @@ -0,0 +1,33 @@ +#ifndef STREAMBUFFER_H +#define STREAMBUFFER_H + +#include +#include "libxisf.h" + +namespace LibXISF +{ + +class StreamBuffer : public std::streambuf +{ +public: + StreamBuffer(); + StreamBuffer(const ByteArray &byteArray); + ByteArray byteArray(); +protected: + pos_type seekoff(off_type off, std::ios_base::seekdir dir, std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out) override; + pos_type seekpos(pos_type pos, std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out) override; + + std::streamsize xsgetn(char_type *s, std::streamsize n) override; + int_type underflow() override; + + std::streamsize xsputn(const char_type *s, std::streamsize n) override; + int_type overflow(int_type c = traits_type::eof()) override; +private: + void update_ptrs(); + off_type _size = 0; + ByteArray _byteArray; +}; + +} + +#endif // STREAMBUFFER_H