Skip to content

Commit 453f870

Browse files
authored
Use STL streams for buffer IO (#178)
This reduces the boost::iostreams footprint to only file IO.
1 parent 8ebade6 commit 453f870

File tree

6 files changed

+74
-88
lines changed

6 files changed

+74
-88
lines changed

core/include/core/dataio.h

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -50,17 +50,6 @@ off_t g3_istream_seek(g3_istream &stream, off_t offset);
5050
*/
5151
off_t g3_istream_tell(g3_istream &stream);
5252

53-
/**
54-
* Configure a filtering stream for G3Frame decompression from a memory buffer.
55-
*
56-
* @param stream A reference to the filtering istream that will be configured
57-
* by this function. Must be instantiated prior to this
58-
* function.
59-
* @param buffer A pointer to a char buffer in memory.
60-
* @param len Size of the buffer in bytes.
61-
*/
62-
void g3_istream_from_buffer(g3_istream &stream, const char *buf, size_t len);
63-
6453
/**
6554
* Configure a filtering stream for G3Frame compression to a local file.
6655
*
@@ -87,16 +76,6 @@ void g3_ostream_to_path(g3_ostream &stream, const std::string &path,
8776
*/
8877
size_t g3_ostream_count(g3_ostream &stream);
8978

90-
/**
91-
* Configure a filtering stream for G3Frame compression to a memory buffer.
92-
*
93-
* @param stream A reference to the filtering ostream that will be configured
94-
* by this function. Must be instantiated prior to this
95-
* function.
96-
* @param buffer A reference a char buffer in memory.
97-
*/
98-
void g3_ostream_to_buffer(g3_ostream &stream, std::vector<char> &buf);
99-
10079
/**
10180
* Check that the input filename is a valid filename on disk.
10281
*

core/include/core/serialization.h

Lines changed: 65 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#ifndef _G3_SERIALIZATION_H
22
#define _G3_SERIALIZATION_H
33

4-
#include <dataio.h>
4+
#include <sstream>
55

66
#include <cereal/archives/portable_binary.hpp>
77

@@ -22,15 +22,76 @@ template void x::serialize(cereal::PortableBinaryInputArchive &, unsigned); \
2222
template void x::save(cereal::PortableBinaryOutputArchive &, unsigned) const; \
2323
template void x::load(cereal::PortableBinaryInputArchive &, unsigned); \
2424

25+
// Work around crummy slow implementation of xsgetn() in libc++
26+
class G3InputStreamBuffer : public std::basic_streambuf<char>
27+
{
28+
public:
29+
G3InputStreamBuffer(std::vector<char> &vec) : basic_streambuf() {
30+
setg(&vec[0], &vec[0], &vec[0] + vec.size());
31+
}
32+
G3InputStreamBuffer(char *buf, size_t len) : basic_streambuf() {
33+
setg(buf, buf, buf + len);
34+
}
35+
protected:
36+
std::streamsize xsgetn(char_type *buf, std::streamsize n) {
37+
std::streamsize to_read = egptr() - gptr();
38+
if (to_read > n)
39+
to_read = n;
40+
memcpy(buf, gptr(), to_read);
41+
gbump(to_read);
42+
return to_read;
43+
}
44+
};
45+
46+
class G3BufferInputStream : public std::istream
47+
{
48+
public:
49+
G3BufferInputStream(std::vector<char> &vec) : std::istream(&sbuf_), sbuf_(vec) {}
50+
G3BufferInputStream(char *buf, size_t len) : std::istream(&sbuf_), sbuf_(buf, len) {}
51+
private:
52+
G3InputStreamBuffer sbuf_;
53+
};
54+
55+
class G3OutputStreamBuffer : public std::basic_streambuf<char>
56+
{
57+
public:
58+
G3OutputStreamBuffer(std::vector<char> &buffer) : buffer_(buffer) {
59+
setp(&buffer_[0], &buffer_[0] + buffer_.size());
60+
}
61+
protected:
62+
std::streamsize xsputn(const char* s, std::streamsize n) {
63+
buffer_.insert(buffer_.end(), s, s + n);
64+
pbump(n);
65+
return n;
66+
}
67+
68+
int overflow(int c = std::char_traits<char>::eof()) {
69+
if (c != std::char_traits<char>::eof()) {
70+
buffer_.push_back(static_cast<char>(c));
71+
pbump(1);
72+
}
73+
return c;
74+
}
75+
private:
76+
std::vector<char>& buffer_;
77+
};
78+
79+
class G3BufferOutputStream : public std::ostream
80+
{
81+
public:
82+
G3BufferOutputStream(std::vector<char> &vec) : std::ostream(&sbuf_), sbuf_(vec) {}
83+
private:
84+
G3OutputStreamBuffer sbuf_;
85+
};
86+
2587
template <class T>
2688
struct g3frameobject_picklesuite : boost::python::pickle_suite
2789
{
2890
static boost::python::tuple getstate(boost::python::object obj)
2991
{
3092
namespace bp = boost::python;
3193
std::vector<char> buffer;
32-
g3_ostream os;
33-
g3_ostream_to_buffer(os, buffer);
94+
G3BufferOutputStream os(buffer);
3495
{
3596
cereal::PortableBinaryOutputArchive ar(os);
3697
ar << bp::extract<const T &>(obj)();
@@ -50,8 +111,7 @@ struct g3frameobject_picklesuite : boost::python::pickle_suite
50111
PyObject_GetBuffer(bp::object(state[1]).ptr(), &view,
51112
PyBUF_SIMPLE);
52113

53-
g3_istream fis;
54-
g3_istream_from_buffer(fis, (char *)view.buf, view.len);
114+
G3BufferInputStream fis((char *)view.buf, view.len);
55115
cereal::PortableBinaryInputArchive ar(fis);
56116

57117
bp::extract<bp::dict>(obj.attr("__dict__"))().update(state[0]);

core/src/G3Frame.cxx

Lines changed: 5 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
#include <pybindings.h>
66
#include <dataio.h>
77

8-
#include <sstream>
98
#include <stdlib.h>
109
#include <cxxabi.h>
1110
#include <algorithm>
@@ -14,24 +13,6 @@ namespace bp = boost::python;
1413

1514
extern "C" unsigned long crc32c(unsigned long crc, const uint8_t *buf, unsigned int len);
1615

17-
// Work around crummy slow implementation of xsgetn() in libc++
18-
class fast_streambuf : public std::basic_streambuf<char>
19-
{
20-
public:
21-
fast_streambuf(std::vector<char> &vec) : basic_streambuf() {
22-
setg(&vec[0], &vec[0], &vec[0] + vec.size());
23-
}
24-
protected:
25-
std::streamsize xsgetn(char_type *buf, std::streamsize n) {
26-
std::streamsize to_read = egptr() - gptr();
27-
if (to_read > n)
28-
to_read = n;
29-
memcpy(buf, gptr(), to_read);
30-
gbump(to_read);
31-
return to_read;
32-
}
33-
};
34-
3516
template <typename T>
3617
static std::string cxx_demangle(const T& v)
3718
{
@@ -313,15 +294,6 @@ void G3Frame::load(T &is)
313294
testcrc, crc);
314295
}
315296

316-
template <>
317-
void G3Frame::load(std::vector<char> &data)
318-
{
319-
fast_streambuf sb(data);
320-
std::istream is(&sb);
321-
322-
load(is);
323-
}
324-
325297
void G3Frame::DropBlobs(bool decode_all) const
326298
{
327299
for (auto i = map_.begin(); i != map_.end(); i++) {
@@ -370,8 +342,7 @@ void G3Frame::blob_decode(struct blob_container &blob)
370342
if (blob.frameobject)
371343
return;
372344

373-
fast_streambuf sb(*blob.blob);
374-
std::istream is(&sb);
345+
G3BufferInputStream is(*blob.blob);
375346
cereal::PortableBinaryInputArchive item_ar(is);
376347
item_ar >> make_nvp("val", ptr);
377348
blob.frameobject = ptr;
@@ -391,8 +362,7 @@ void G3Frame::blob_encode(struct blob_container &blob)
391362

392363
// If no encoded frameobject, serialize it
393364
blob.blob = std::make_shared<std::vector<char> >();
394-
g3_ostream item_os;
395-
g3_ostream_to_buffer(item_os, *blob.blob);
365+
G3BufferOutputStream item_os(*blob.blob);
396366
cereal::PortableBinaryOutputArchive item_ar(item_os);
397367
item_ar << make_nvp("val", blob.frameobject);
398368
item_os.flush();
@@ -432,8 +402,7 @@ struct g3frame_picklesuite : boost::python::pickle_suite
432402
{
433403
namespace bp = boost::python;
434404
std::vector<char> buffer;
435-
g3_ostream os;
436-
g3_ostream_to_buffer(os, buffer);
405+
G3BufferOutputStream os(buffer);
437406
(bp::extract<const G3Frame &>(obj))().save(os);
438407
os.flush();
439408

@@ -450,9 +419,9 @@ struct g3frame_picklesuite : boost::python::pickle_suite
450419
PyObject_GetBuffer(bp::object(state[1]).ptr(), &view,
451420
PyBUF_SIMPLE);
452421

453-
std::vector<char> buf((char *)view.buf, (char *)view.buf + view.len);
454422
bp::extract<bp::dict>(obj.attr("__dict__"))().update(state[0]);
455-
(bp::extract<G3Frame &>(obj))().load(buf);
423+
G3BufferInputStream is((char *)view.buf, view.len);
424+
(bp::extract<G3Frame &>(obj))().load(is);
456425
PyBuffer_Release(&view);
457426
}
458427
};

core/src/G3Map.cxx

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
#include <pybindings.h>
44
#include <container_pybindings.h>
55
#include <serialization.h>
6-
#include <dataio.h>
76
#include "int_storage.h"
87

98
/* Special load/save for int64_t, using the same encoding at G3VectorInt */
@@ -159,12 +158,11 @@ template <class A> void G3MapFrameObject::save(A &ar, const unsigned v) const
159158
uint32_t len = size();
160159
ar << cereal::make_nvp("len", len);
161160

162-
g3_ostream os;
163161
for (auto i = begin(); i != end(); i++) {
164162
ar << cereal::make_nvp("key", i->first);
165163

166164
std::vector<char> buffer;
167-
g3_ostream_to_buffer(os, buffer);
165+
G3BufferOutputStream os(buffer);
168166
{
169167
A subar(os);
170168
subar << cereal::make_nvp("item",
@@ -184,16 +182,14 @@ template <class A> void G3MapFrameObject::load(A &ar, const unsigned v)
184182

185183
uint32_t len;
186184
ar >> cereal::make_nvp("len", len);
187-
g3_istream fis;
188185
for (uint32_t i = 0; i < len; i++) {
189186
std::pair<std::string, G3FrameObjectPtr> item;
190187
std::vector<char> buffer;
191188

192189
ar >> cereal::make_nvp("key", item.first);
193190
ar >> cereal::make_nvp("value", buffer);
194191

195-
g3_istream_from_buffer(fis, (char *)&buffer[0], buffer.size());
196-
192+
G3BufferInputStream fis(buffer);
197193
A subar(fis);
198194
subar >> cereal::make_nvp("item", item.second);
199195
this->insert(item);

core/src/G3NetworkSender.cxx

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#include <pybindings.h>
22
#include <G3NetworkSender.h>
33

4-
#include <dataio.h>
4+
#include <serialization.h>
55

66
#include <chrono>
77

@@ -173,8 +173,7 @@ void G3NetworkSender::SerializeFrame(serialization_task& task)
173173
{
174174
try{
175175
netbuf_type buf(new std::vector<char>);
176-
g3_ostream os;
177-
g3_ostream_to_buffer(os, *buf);
176+
G3BufferOutputStream os(*buf);
178177
task.input->save(os);
179178
os.flush();
180179
task.output.set_value(buf);

core/src/dataio.cxx

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,6 @@
1010
#endif
1111
#include <boost/iostreams/device/file.hpp>
1212
#include <boost/iostreams/device/file_descriptor.hpp>
13-
#include <boost/iostreams/device/array.hpp>
14-
#include <boost/iostreams/device/back_inserter.hpp>
1513
#include <filesystem>
1614

1715
#include <sys/types.h>
@@ -178,13 +176,6 @@ g3_istream_tell(g3_istream &stream)
178176
return boost::iostreams::seek(stream, 0, std::ios_base::cur);
179177
}
180178

181-
void
182-
g3_istream_from_buffer(g3_istream &stream, const char *buf, size_t len)
183-
{
184-
stream.reset();
185-
stream.push(boost::iostreams::array_source(buf, len));
186-
}
187-
188179
void
189180
g3_ostream_to_path(g3_ostream &stream, const std::string &path,
190181
bool append, bool counter)
@@ -227,14 +218,6 @@ g3_ostream_count(g3_ostream &stream)
227218
return counter->characters();
228219
}
229220

230-
void
231-
g3_ostream_to_buffer(g3_ostream &stream,
232-
std::vector<char> &buf)
233-
{
234-
stream.reset();
235-
stream.push(boost::iostreams::back_inserter(buf));
236-
}
237-
238221
void
239222
g3_check_input_path(const std::string &path)
240223
{

0 commit comments

Comments
 (0)