Added a visitor version of unpack API,

The current unpacking APIs are constructed on the visitor mechanism.
(Fixed #418)

Updated test condition.
This commit is contained in:
Takatoshi Kondo 2016-04-14 00:20:00 +09:00
parent 07b5000824
commit d5b515899c
8 changed files with 1698 additions and 22 deletions

View File

@ -44,7 +44,7 @@ public:
m_pac.buffer_consumed(count);
msgpack::object_handle oh;
while (m_pac.next(&oh)) {
while (m_pac.next(oh)) {
msgpack::object msg = oh.get();
unique_zone& life = oh.zone();
process_message(msg, life);

File diff suppressed because it is too large Load Diff

View File

@ -76,17 +76,24 @@ using v1::detail::value;
using v1::detail::load;
using v1::detail::context;
} // detail
using v1::unpacked;
using v1::unpacker;
/// Unpacking class for a stream deserialization.
class unpacker;
using v1::unpack_return;
template <typename unpack_visitor, typename referenced_buffer_hook>
class basic_unpacker;
typedef enum unpack_return {
UNPACK_SUCCESS = v1::UNPACK_SUCCESS,
UNPACK_EXTRA_BYTES = v1::UNPACK_EXTRA_BYTES,
UNPACK_CONTINUE = v1::UNPACK_CONTINUE,
UNPACK_PARSE_ERROR = v1::UNPACK_PARSE_ERROR,
UNPACK_STOP_VISITOR = -2
} unpack_return;
/// Unpack msgpack::object from a buffer.
/**
@ -293,9 +300,40 @@ msgpack::object unpack(
const char* data, std::size_t len,
unpack_reference_func f = nullptr, void* user_data = nullptr, unpack_limit const& limit = unpack_limit());
/// Unpack msgpack formatted data via a visitor
/**
* @param data The pointer to the buffer.
* @param len The length of the buffer.
* @param off The offset position of the buffer. It is read and overwritten.
*
* @return if unpacking process finishs without error then return true, otherwise return false.
*
*/
template <typename UnpackVisitor>
bool unpack_visit(const char* data, size_t len, size_t& off, UnpackVisitor&);
/// Unpack msgpack formatted data via a visitor
/**
* @param data The pointer to the buffer.
* @param len The length of the buffer.
*
* @return if unpacking process finishs without error then return true, otherwise return false.
*
*/
template <typename UnpackVisitor>
bool unpack_visit(const char* data, size_t len, UnpackVisitor& v);
namespace detail {
using v1::detail::unpack_imp;
unpack_return
unpack_imp(const char* data, std::size_t len, std::size_t& off,
msgpack::zone& result_zone, msgpack::object& result, bool& referenced,
unpack_reference_func f, void* user_data,
unpack_limit const& limit);
template <typename UnpackVisitor>
unpack_return
unpack_visit_imp(const char* data, size_t len, size_t& off, UnpackVisitor& v);
} // detail

View File

@ -30,6 +30,7 @@ LIST (APPEND check_PROGRAMS
reference.cpp
streaming.cpp
streaming_c.cpp
unpack_visitor.cpp
user_class.cpp
version.cpp
zone.cpp

View File

@ -25,6 +25,7 @@ check_PROGRAMS = \
reference \
streaming \
streaming_c \
unpack_visitor \
user_class \
version \
zone
@ -70,6 +71,7 @@ raw_SOURCES = raw.cpp
reference_SOURCES = reference.cpp
streaming_SOURCES = streaming.cpp
streaming_c_SOURCES = streaming_c.cpp
unpack_visitor_SOURCES = unpack_visitor.cpp
user_class_SOURCES = user_class.cpp
version_SOURCES = version.cpp
zone_SOURCES = zone.cpp

View File

@ -27,11 +27,11 @@ TEST(cases, format)
feed_file(pac_compact, "cases_compact.mpac");
msgpack::object_handle oh;
while(pac.next(&oh)) {
while(pac.next(oh)) {
msgpack::object_handle oh_compact;
EXPECT_TRUE( pac_compact.next(&oh_compact) );
EXPECT_TRUE( pac_compact.next(oh_compact) );
EXPECT_EQ(oh_compact.get(), oh.get());
}
EXPECT_FALSE( pac_compact.next(&oh) );
EXPECT_FALSE( pac_compact.next(oh) );
}

View File

@ -48,6 +48,9 @@ TEST(streaming, basic)
}
}
// obsolete
#if MSGPACK_DEFAULT_API_VERSION == 1
TEST(streaming, basic_pointer)
{
msgpack::sbuffer buffer;
@ -94,6 +97,8 @@ TEST(streaming, basic_pointer)
}
}
#endif // MSGPACK_DEFAULT_API_VERSION == 1
#if !defined(MSGPACK_USE_CPP03)
TEST(streaming, move)
@ -207,6 +212,8 @@ TEST(streaming, event)
handler.on_read();
}
// obsolete
#if MSGPACK_DEFAULT_API_VERSION == 1
// backward compatibility
TEST(streaming, basic_compat)
@ -314,3 +321,5 @@ TEST(streaming, event_compat)
handler.expect = 3;
handler.on_read();
}
#endif // !defined(MSGPACK_USE_CPP03)

135
test/unpack_visitor.cpp Normal file
View File

@ -0,0 +1,135 @@
#include <msgpack.hpp>
#include <gtest/gtest.h>
#include <sstream>
// To avoid link error
TEST(unpack_visitor, dummy)
{
}
#if MSGPACK_DEFAULT_API_VERSION >= 2
struct json_visitor : msgpack::v2::null_visitor {
json_visitor(std::string& s):m_s(s) {}
bool visit_nil() {
m_s += "null";
return true;
}
bool visit_boolean(bool v) {
if (v) m_s += "true";
else m_s += "false";
return true;
}
bool visit_positive_integer(uint64_t v) {
std::stringstream ss;
ss << v;
m_s += ss.str();
return true;
}
bool visit_negative_integer(int64_t v) {
std::stringstream ss;
ss << v;
m_s += ss.str();
return true;
}
bool visit_str(const char* v, uint32_t size) {
m_s += '"' + std::string(v, size) + '"';
return true;
}
bool start_array(uint32_t /*num_elements*/) {
m_s += "[";
return true;
}
bool end_array_item() {
m_s += ",";
return true;
}
bool end_array() {
m_s.erase(m_s.size() - 1, 1); // remove the last ','
m_s += "]";
return true;
}
bool start_map(uint32_t /*num_kv_pairs*/) {
m_s += "{";
return true;
}
bool end_map_key() {
m_s += ":";
return true;
}
bool end_map() {
m_s += "}";
return true;
}
void parse_error(size_t /*parsed_offset*/, size_t /*error_offset*/) {
EXPECT_TRUE(false);
}
void insufficient_bytes(size_t /*parsed_offset*/, size_t /*error_offset*/) {
EXPECT_TRUE(false);
}
std::string& m_s;
};
TEST(unpack_visitor, json)
{
std::stringstream ss;
msgpack::packer<std::stringstream> p(ss);
p.pack_map(1);
p.pack("key");
p.pack_array(3);
p.pack(42);
p.pack_nil();
p.pack(true);
std::string json;
json_visitor v(json);
std::size_t off = 0;
bool ret = msgpack::v2::unpack_visit(ss.str().data(), ss.str().size(), off, v);
EXPECT_TRUE(ret);
EXPECT_EQ("{\"key\":[42,null,true]}", json);
}
struct parse_error_check_visitor : msgpack::v2::null_visitor {
parse_error_check_visitor(bool& called):m_called(called) {}
void parse_error(size_t parsed_offset, size_t error_offset) {
EXPECT_EQ(1, parsed_offset);
EXPECT_EQ(2, error_offset);
m_called = true;
}
bool& m_called;
};
TEST(unpack_visitor, parse_error)
{
bool called = false;
parse_error_check_visitor v(called);
std::size_t off = 0;
char const data[] = { static_cast<char>(0x93u), 0x01u, static_cast<char>(0xc1u), 0x03u };
bool ret = msgpack::v2::unpack_visit(data, sizeof(data), off, v);
EXPECT_FALSE(ret);
EXPECT_TRUE(called);
}
struct insuf_bytes_check_visitor : msgpack::v2::null_visitor {
insuf_bytes_check_visitor(bool& called):m_called(called) {}
void insufficient_bytes(size_t parsed_offset, size_t error_offset) {
EXPECT_EQ(2, parsed_offset);
EXPECT_EQ(3, error_offset);
m_called = true;
}
bool& m_called;
};
TEST(unpack_visitor, insuf_bytes)
{
bool called = false;
insuf_bytes_check_visitor v(called);
std::size_t off = 0;
char const data[] = { static_cast<char>(0x93u), 0x01u, 0x01u };
bool ret = msgpack::v2::unpack_visit(data, sizeof(data), off, v);
EXPECT_FALSE(ret);
EXPECT_TRUE(called);
}
#endif // MSGPACK_DEFAULT_API_VERSION >= 1