summaryrefslogtreecommitdiff
path: root/cpp/unpack.cpp
diff options
context:
space:
mode:
authorfrsyuki <frsyuki@5a5092ae-2292-43ba-b2d5-dcab9c1a2731>2009-02-15 09:09:56 +0000
committerfrsyuki <frsyuki@5a5092ae-2292-43ba-b2d5-dcab9c1a2731>2009-02-15 09:09:56 +0000
commit990ac38ccdb51acc520fa43c99115cb216ec95e6 (patch)
tree47e1cac5605c2839fd7ae5af4ae30ed34060e2f3 /cpp/unpack.cpp
parent249d3e9c908ea4a3fd2012a753ca7f0cea0b4ee5 (diff)
downloadmsgpack-python-990ac38ccdb51acc520fa43c99115cb216ec95e6.tar.gz
lang/c/msgpack: C++ binding: implemented built-in buffer.
git-svn-id: file:///Users/frsyuki/project/msgpack-git/svn/x@55 5a5092ae-2292-43ba-b2d5-dcab9c1a2731
Diffstat (limited to 'cpp/unpack.cpp')
-rw-r--r--cpp/unpack.cpp107
1 files changed, 91 insertions, 16 deletions
diff --git a/cpp/unpack.cpp b/cpp/unpack.cpp
index 0f02d3c..5055008 100644
--- a/cpp/unpack.cpp
+++ b/cpp/unpack.cpp
@@ -5,10 +5,10 @@
namespace msgpack {
struct unpacker::context {
- context(zone& z)
+ context(zone* z)
{
msgpack_unpacker_init(&m_ctx);
- m_ctx.user = &z;
+ m_ctx.user = z;
}
~context() { }
@@ -30,6 +30,22 @@ struct unpacker::context {
m_ctx.user = z;
}
+ void reset(zone* z)
+ {
+ msgpack_unpacker_init(&m_ctx);
+ m_ctx.user = z;
+ }
+
+ zone* user()
+ {
+ return m_ctx.user;
+ }
+
+ void user(zone* z)
+ {
+ m_ctx.user = z;
+ }
+
private:
msgpack_unpacker m_ctx;
@@ -39,46 +55,105 @@ private:
};
-unpacker::unpacker(zone& z) :
- m_ctx(new context(z)),
- m_zone(z),
- m_finished(false)
+unpacker::unpacker() :
+ m_zone(new zone()),
+ m_ctx(new context(m_zone)),
+ m_buffer(NULL),
+ m_used(0),
+ m_free(0),
+ m_off(0)
{ }
-unpacker::~unpacker() { delete m_ctx; }
+unpacker::~unpacker()
+{
+ free(m_buffer);
+ delete m_ctx;
+ delete m_zone;
+}
-size_t unpacker::execute(const void* data, size_t len, size_t off)
+void unpacker::expand_buffer(size_t len)
{
- int ret = m_ctx->execute(data, len, &off);
+ if(m_off == 0) {
+ size_t next_size;
+ if(m_free != 0) { next_size = m_free * 2; }
+ else { next_size = MSGPACK_UNPACKER_INITIAL_BUFFER_SIZE; }
+ while(next_size < len + m_used) { next_size *= 2; }
+
+ // FIXME realloc?
+
+ void* tmp = malloc(next_size);
+ if(!tmp) { throw std::bad_alloc(); }
+ memcpy(tmp, m_buffer, m_used);
+
+ free(m_buffer);
+ m_buffer = tmp;
+ m_free = next_size - m_used;
+
+ } else {
+ size_t next_size = MSGPACK_UNPACKER_INITIAL_BUFFER_SIZE;
+ while(next_size < len + m_used - m_off) { next_size *= 2; }
+
+ void* tmp = malloc(next_size);
+ if(!tmp) { throw std::bad_alloc(); }
+ memcpy(tmp, ((char*)m_buffer)+m_off, m_used-m_off);
+
+ try {
+ m_zone->push_finalizer<void>(&zone::finalize_free, NULL, m_buffer);
+ } catch (...) {
+ free(tmp);
+ throw;
+ }
+
+ m_buffer = tmp;
+ m_used = m_used - m_off;
+ m_free = next_size - m_used;
+ m_off = 0;
+ }
+}
+
+bool unpacker::execute()
+{
+ int ret = m_ctx->execute(m_buffer, m_used, &m_off);
if(ret < 0) {
throw unpack_error("parse error");
- } else if(ret > 0) {
- m_finished = true;
- return off;
+ } else if(ret == 0) {
+ return false;
} else {
- m_finished = false;
- return off;
+ return true;
}
}
+zone* unpacker::release_zone()
+{
+ zone* z = m_zone;
+ m_zone = NULL;
+ m_zone = new zone();
+ m_ctx->user(m_zone);
+ return z;
+}
object unpacker::data()
{
return object(m_ctx->data());
}
-
void unpacker::reset()
{
+ if(!m_zone->empty()) {
+ delete m_zone;
+ m_zone = NULL;
+ m_zone = new zone();
+ }
+ expand_buffer(0);
m_ctx->reset();
}
object unpacker::unpack(const void* data, size_t len, zone& z)
{
- context ctx(z);
+ context ctx(&z);
size_t off = 0;
int ret = ctx.execute(data, len, &off);
if(ret < 0) {