You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by ac...@apache.org on 2015/11/10 23:43:51 UTC
[1/3] qpid-proton git commit: NO-JIRA: c++: Speed up recurring_timer
example.
Repository: qpid-proton
Updated Branches:
refs/heads/master 1b1b2e596 -> 01e136cc6
NO-JIRA: c++: Speed up recurring_timer example.
Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/b131dc19
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/b131dc19
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/b131dc19
Branch: refs/heads/master
Commit: b131dc199f7f2c69a14587e45b6feaf741b53610
Parents: 1b1b2e5
Author: Alan Conway <ac...@redhat.com>
Authored: Thu Nov 5 10:22:49 2015 -0500
Committer: Alan Conway <ac...@redhat.com>
Committed: Tue Nov 10 17:06:27 2015 -0500
----------------------------------------------------------------------
examples/cpp/CMakeLists.txt | 2 +-
examples/cpp/example_test.py | 17 ++++++++++++++---
examples/cpp/recurring_timer.cpp | 29 ++++++++++++++---------------
3 files changed, 29 insertions(+), 19 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/b131dc19/examples/cpp/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/examples/cpp/CMakeLists.txt b/examples/cpp/CMakeLists.txt
index 3e5dafe..8916963 100644
--- a/examples/cpp/CMakeLists.txt
+++ b/examples/cpp/CMakeLists.txt
@@ -60,7 +60,7 @@ else(WIN32)
endif(WIN32)
add_test(NAME cpp_example_test
- COMMAND ${PYTHON_EXECUTABLE} ${env_py} -- "PATH=${test_path}" "PYTHONPATH=${CMAKE_CURRENT_SOURCE_DIR}" ${VALGRIND_ENV} ${PYTHON_EXECUTABLE} -m unittest -v example_test)
+ COMMAND ${PYTHON_EXECUTABLE} ${env_py} -- "PATH=${test_path}" ${VALGRIND_ENV} ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/example_test.py -v)
set(broker_tests example_test.ExampleTest.test_request_response example_test.ExampleTest.test_simple_send_recv)
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/b131dc19/examples/cpp/example_test.py
----------------------------------------------------------------------
diff --git a/examples/cpp/example_test.py b/examples/cpp/example_test.py
index 3ed8b9c..f51cf57 100644
--- a/examples/cpp/example_test.py
+++ b/examples/cpp/example_test.py
@@ -23,6 +23,7 @@ import unittest
import os, sys, socket, time
from random import randrange
from subprocess import Popen, PIPE, STDOUT
+from copy import copy
import platform
def cmdline(*args):
@@ -215,14 +216,24 @@ Values: map{string(k1):int(42), symbol(k2):boolean(false)}
self.assertEqual(expect, execute("encode_decode"))
def test_recurring_timer(self):
- expect="""Tick...
+ # Disable valgrind, this test is time-sensitive.
+ env = {k: v for k,v in os.environ.iteritems() if k != "VALGRIND"}
+ env, os.environ = os.environ, env
+ try:
+ expect="""Tick...
+Tick...
+Tock...
+Tick...
+Tock...
Tick...
Tock...
Tick...
Tock...
"""
- self.maxDiff = None
- self.assertEqual(expect, execute("recurring_timer", "-t", "3"))
+ self.maxDiff = None
+ self.assertEqual(expect, execute("recurring_timer", "-t", ".01", "-k", ".001"))
+ finally:
+ os.environ = env # Restore environment
if __name__ == "__main__":
unittest.main()
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/b131dc19/examples/cpp/recurring_timer.cpp
----------------------------------------------------------------------
diff --git a/examples/cpp/recurring_timer.cpp b/examples/cpp/recurring_timer.cpp
index b6141fd..37cbfed 100644
--- a/examples/cpp/recurring_timer.cpp
+++ b/examples/cpp/recurring_timer.cpp
@@ -43,53 +43,52 @@ class tocker : public proton::messaging_handler {
class recurring : public proton::messaging_handler {
private:
- int remaining_secs;
+ int remaining_msecs, tick_ms;
ticker tick_handler;
tocker tock_handler;
proton::task *cancel_task;
public:
- recurring(int secs) : remaining_secs(secs), cancel_task(0) {}
+ recurring(int msecs, int tickms) : remaining_msecs(msecs), tick_ms(tickms), cancel_task(0) {}
proton::task& ticktock(proton::event &e) {
// Show timer events in separate handlers.
- e.container().schedule(250, &tick_handler);
- return e.container().schedule(750, &tock_handler);
+ e.container().schedule(tick_ms, &tick_handler);
+ return e.container().schedule(tick_ms * 3, &tock_handler);
}
void on_start(proton::event &e) {
- if (remaining_secs <= 0)
+ if (remaining_msecs <= 0)
return;
proton::task& first_tock = ticktock(e);
- e.container().schedule(1000);
- remaining_secs--;
// Show a cancel operation.
cancel_task = &first_tock;
- e.container().schedule(500);
+ e.container().schedule(tick_ms);
}
void on_timer_task(proton::event &e) {
if (cancel_task) {
cancel_task->cancel();
cancel_task = 0;
- return;
}
- if (remaining_secs) {
+ remaining_msecs -= tick_ms * 2;
+ if (remaining_msecs > 0) {
ticktock(e);
- e.container().schedule(1000);
- remaining_secs--;
+ e.container().schedule(tick_ms * 4);
}
}
};
int main(int argc, char **argv) {
// Command line options
- int running_time_in_secs = 5;
+ double running_time = 5;
+ double tick = 0.25;
options opts(argc, argv);
- opts.add_value(running_time_in_secs, 't', "running time", "running time in seconds", "RUNTIME");
+ opts.add_value(running_time, 't', "running time", "running time in seconds", "RUNTIME");
+ opts.add_value(tick, 'k', "tick time", "tick time as fraction of second", "TICK");
try {
opts.parse();
- recurring recurring_handler(running_time_in_secs);
+ recurring recurring_handler(running_time * 1000, tick * 1000);
proton::container(recurring_handler).run();
return 0;
} catch (const bad_option& e) {
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org
[2/3] qpid-proton git commit: NO-JIRA: Removed dead code container.h
Posted by ac...@apache.org.
NO-JIRA: Removed dead code container.h
Contained only a typedef which is not referred to anywhere, no functions, and
was missing the close brace on 'extern "C" {' which implies it has never
actually been included anywhere or the windows C++ build would have failed.
Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/ecbe90a2
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/ecbe90a2
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/ecbe90a2
Branch: refs/heads/master
Commit: ecbe90a2fe28adec97093037df7da27cc9e519d8
Parents: b131dc1
Author: Alan Conway <ac...@redhat.com>
Authored: Wed Nov 4 15:41:46 2015 -0500
Committer: Alan Conway <ac...@redhat.com>
Committed: Tue Nov 10 17:07:24 2015 -0500
----------------------------------------------------------------------
proton-c/CMakeLists.txt | 1 -
proton-c/include/proton/container.h | 50 --------------------------------
2 files changed, 51 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/ecbe90a2/proton-c/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/proton-c/CMakeLists.txt b/proton-c/CMakeLists.txt
index 6a35170..d80d60a 100644
--- a/proton-c/CMakeLists.txt
+++ b/proton-c/CMakeLists.txt
@@ -344,7 +344,6 @@ set (qpid-proton-include
include/proton/codec.h
include/proton/condition.h
include/proton/connection.h
- include/proton/container.h
include/proton/delivery.h
include/proton/disposition.h
include/proton/engine.h
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/ecbe90a2/proton-c/include/proton/container.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/container.h b/proton-c/include/proton/container.h
deleted file mode 100644
index a1de525..0000000
--- a/proton-c/include/proton/container.h
+++ /dev/null
@@ -1,50 +0,0 @@
-#ifndef PROTON_CONTAINER_H
-#define PROTON_CONTAINER_H 1
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include <proton/import_export.h>
-#include <proton/type_compat.h>
-#include <stddef.h>
-#include <sys/types.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/** @file
- * Container API for the proton Engine.
- *
- * @defgroup container Container
- * @ingroup engine
- * @{
- */
-
-/**
- * Encapsulates the endpoint state associated with an AMQP Container.
- */
-typedef struct pn_container_t pn_container_t;
-
-/** @}
- */
-
-#endif /* container.h */
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org
Re: [1/3] qpid-proton git commit: NO-JIRA: c++: Speed up
recurring_timer example.
Posted by Chuck Rolke <cr...@redhat.com>.
This commit seems a bit heavy to be NO-JIRA as it breaks my windows builds several ways.
Compile error:
=============
fixed
Syntax error:
============
Python 2.6.1 complains about:
13: File "C:/Jenkins/workspace/proton-c-master-windows/examples/cpp/example_test.py", line 228
13: env = {k: v for k,v in os.environ.iteritems() if k != "VALGRIND"}
13: ^
Python 2.7.1 is fine with this. 2.6 works with simpler iteration constructs.
Self test fail:
==============
The test_recurring_time (on my single try) fails with an extra "Tock..." after the first "Tick...".
-Chuck
----- Original Message -----
> From: aconway@apache.org
> To: commits@qpid.apache.org
> Sent: Tuesday, November 10, 2015 5:43:51 PM
> Subject: [1/3] qpid-proton git commit: NO-JIRA: c++: Speed up recurring_timer example.
>
> Repository: qpid-proton
> Updated Branches:
> refs/heads/master 1b1b2e596 -> 01e136cc6
>
>
> NO-JIRA: c++: Speed up recurring_timer example.
>
>
> Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
> Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/b131dc19
> Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/b131dc19
> Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/b131dc19
>
> Branch: refs/heads/master
> Commit: b131dc199f7f2c69a14587e45b6feaf741b53610
> Parents: 1b1b2e5
> Author: Alan Conway <ac...@redhat.com>
> Authored: Thu Nov 5 10:22:49 2015 -0500
> Committer: Alan Conway <ac...@redhat.com>
> Committed: Tue Nov 10 17:06:27 2015 -0500
>
> ----------------------------------------------------------------------
> examples/cpp/CMakeLists.txt | 2 +-
> examples/cpp/example_test.py | 17 ++++++++++++++---
> examples/cpp/recurring_timer.cpp | 29 ++++++++++++++---------------
> 3 files changed, 29 insertions(+), 19 deletions(-)
> ----------------------------------------------------------------------
>
>
> http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/b131dc19/examples/cpp/CMakeLists.txt
> ----------------------------------------------------------------------
> diff --git a/examples/cpp/CMakeLists.txt b/examples/cpp/CMakeLists.txt
> index 3e5dafe..8916963 100644
> --- a/examples/cpp/CMakeLists.txt
> +++ b/examples/cpp/CMakeLists.txt
> @@ -60,7 +60,7 @@ else(WIN32)
> endif(WIN32)
>
> add_test(NAME cpp_example_test
> - COMMAND ${PYTHON_EXECUTABLE} ${env_py} -- "PATH=${test_path}"
> "PYTHONPATH=${CMAKE_CURRENT_SOURCE_DIR}" ${VALGRIND_ENV}
> ${PYTHON_EXECUTABLE} -m unittest -v example_test)
> + COMMAND ${PYTHON_EXECUTABLE} ${env_py} -- "PATH=${test_path}"
> ${VALGRIND_ENV} ${PYTHON_EXECUTABLE}
> ${CMAKE_CURRENT_SOURCE_DIR}/example_test.py -v)
>
> set(broker_tests example_test.ExampleTest.test_request_response
> example_test.ExampleTest.test_simple_send_recv)
>
>
> http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/b131dc19/examples/cpp/example_test.py
> ----------------------------------------------------------------------
> diff --git a/examples/cpp/example_test.py b/examples/cpp/example_test.py
> index 3ed8b9c..f51cf57 100644
> --- a/examples/cpp/example_test.py
> +++ b/examples/cpp/example_test.py
> @@ -23,6 +23,7 @@ import unittest
> import os, sys, socket, time
> from random import randrange
> from subprocess import Popen, PIPE, STDOUT
> +from copy import copy
> import platform
>
> def cmdline(*args):
> @@ -215,14 +216,24 @@ Values: map{string(k1):int(42),
> symbol(k2):boolean(false)}
> self.assertEqual(expect, execute("encode_decode"))
>
> def test_recurring_timer(self):
> - expect="""Tick...
> + # Disable valgrind, this test is time-sensitive.
> + env = {k: v for k,v in os.environ.iteritems() if k != "VALGRIND"}
> + env, os.environ = os.environ, env
> + try:
> + expect="""Tick...
> +Tick...
> +Tock...
> +Tick...
> +Tock...
> Tick...
> Tock...
> Tick...
> Tock...
> """
> - self.maxDiff = None
> - self.assertEqual(expect, execute("recurring_timer", "-t", "3"))
> + self.maxDiff = None
> + self.assertEqual(expect, execute("recurring_timer", "-t", ".01",
> "-k", ".001"))
> + finally:
> + os.environ = env # Restore environment
>
> if __name__ == "__main__":
> unittest.main()
>
> http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/b131dc19/examples/cpp/recurring_timer.cpp
> ----------------------------------------------------------------------
> diff --git a/examples/cpp/recurring_timer.cpp
> b/examples/cpp/recurring_timer.cpp
> index b6141fd..37cbfed 100644
> --- a/examples/cpp/recurring_timer.cpp
> +++ b/examples/cpp/recurring_timer.cpp
> @@ -43,53 +43,52 @@ class tocker : public proton::messaging_handler {
>
> class recurring : public proton::messaging_handler {
> private:
> - int remaining_secs;
> + int remaining_msecs, tick_ms;
> ticker tick_handler;
> tocker tock_handler;
> proton::task *cancel_task;
> public:
>
> - recurring(int secs) : remaining_secs(secs), cancel_task(0) {}
> + recurring(int msecs, int tickms) : remaining_msecs(msecs),
> tick_ms(tickms), cancel_task(0) {}
>
> proton::task& ticktock(proton::event &e) {
> // Show timer events in separate handlers.
> - e.container().schedule(250, &tick_handler);
> - return e.container().schedule(750, &tock_handler);
> + e.container().schedule(tick_ms, &tick_handler);
> + return e.container().schedule(tick_ms * 3, &tock_handler);
> }
>
> void on_start(proton::event &e) {
> - if (remaining_secs <= 0)
> + if (remaining_msecs <= 0)
> return;
> proton::task& first_tock = ticktock(e);
> - e.container().schedule(1000);
> - remaining_secs--;
> // Show a cancel operation.
> cancel_task = &first_tock;
> - e.container().schedule(500);
> + e.container().schedule(tick_ms);
> }
>
> void on_timer_task(proton::event &e) {
> if (cancel_task) {
> cancel_task->cancel();
> cancel_task = 0;
> - return;
> }
> - if (remaining_secs) {
> + remaining_msecs -= tick_ms * 2;
> + if (remaining_msecs > 0) {
> ticktock(e);
> - e.container().schedule(1000);
> - remaining_secs--;
> + e.container().schedule(tick_ms * 4);
> }
> }
> };
>
> int main(int argc, char **argv) {
> // Command line options
> - int running_time_in_secs = 5;
> + double running_time = 5;
> + double tick = 0.25;
> options opts(argc, argv);
> - opts.add_value(running_time_in_secs, 't', "running time", "running time
> in seconds", "RUNTIME");
> + opts.add_value(running_time, 't', "running time", "running time in
> seconds", "RUNTIME");
> + opts.add_value(tick, 'k', "tick time", "tick time as fraction of
> second", "TICK");
> try {
> opts.parse();
> - recurring recurring_handler(running_time_in_secs);
> + recurring recurring_handler(running_time * 1000, tick * 1000);
> proton::container(recurring_handler).run();
> return 0;
> } catch (const bad_option& e) {
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
> For additional commands, e-mail: commits-help@qpid.apache.org
>
>
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@qpid.apache.org
For additional commands, e-mail: dev-help@qpid.apache.org
[3/3] qpid-proton git commit: NO-JIRA: C++: Conversions for complex
types
Posted by ac...@apache.org.
NO-JIRA: C++: Conversions for complex types
Intuitive automatic conversions between standard C++ containers and AMQP types.
User can override for non-standard containers or non-default use of standard containers.
Examples in encode_decode.cpp.
Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/01e136cc
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/01e136cc
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/01e136cc
Branch: refs/heads/master
Commit: 01e136cc660a721da9178a98ff43bac143a4c8ce
Parents: ecbe90a
Author: Alan Conway <ac...@redhat.com>
Authored: Thu Nov 5 09:43:45 2015 -0500
Committer: Alan Conway <ac...@redhat.com>
Committed: Tue Nov 10 17:32:40 2015 -0500
----------------------------------------------------------------------
examples/cpp/direct_send.cpp | 2 +-
examples/cpp/encode_decode.cpp | 159 +++++-----
examples/cpp/example_test.py | 24 +-
examples/cpp/simple_send.cpp | 2 +-
.../bindings/cpp/include/proton/decoder.hpp | 287 +++++++++++++++----
.../bindings/cpp/include/proton/encoder.hpp | 103 +++++--
proton-c/bindings/cpp/include/proton/engine.hpp | 2 +-
.../bindings/cpp/include/proton/message.hpp | 18 +-
.../bindings/cpp/include/proton/message_id.hpp | 3 +-
.../cpp/include/proton/request_response.hpp | 3 -
.../bindings/cpp/include/proton/type_traits.hpp | 19 +-
proton-c/bindings/cpp/include/proton/types.hpp | 43 +--
proton-c/bindings/cpp/include/proton/value.hpp | 32 ++-
proton-c/bindings/cpp/src/decoder.cpp | 23 +-
proton-c/bindings/cpp/src/encoder.cpp | 8 +-
proton-c/bindings/cpp/src/interop_test.cpp | 6 +-
proton-c/bindings/cpp/src/message.cpp | 2 +-
proton-c/bindings/cpp/src/value.cpp | 16 +-
18 files changed, 501 insertions(+), 251 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/01e136cc/examples/cpp/direct_send.cpp
----------------------------------------------------------------------
diff --git a/examples/cpp/direct_send.cpp b/examples/cpp/direct_send.cpp
index 62e6ab9..13ca510 100644
--- a/examples/cpp/direct_send.cpp
+++ b/examples/cpp/direct_send.cpp
@@ -53,7 +53,7 @@ class simple_send : public proton::messaging_handler {
msg.id(sent + 1);
std::map<std::string, int> m;
m["sequence"] = sent+1;
- msg.body(proton::as<proton::MAP>(m));
+ msg.body(m);
sender.send(msg);
sent++;
}
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/01e136cc/examples/cpp/encode_decode.cpp
----------------------------------------------------------------------
diff --git a/examples/cpp/encode_decode.cpp b/examples/cpp/encode_decode.cpp
index 4f88c93..3d6fe48 100644
--- a/examples/cpp/encode_decode.cpp
+++ b/examples/cpp/encode_decode.cpp
@@ -24,8 +24,8 @@
#include <map>
#include <sstream>
#include <vector>
+#include <list>
-using namespace std;
// Examples of how to use the encoder and decoder to create and examine AMQP values.
//
@@ -34,12 +34,18 @@ using namespace std;
// values from a decoder in terms of their simple components.
void print(proton::value&);
-// Some helper templates to print map and vector results.
+// Some helper templates to print map and std::vector results.
namespace std {
-template<class T, class U> ostream& operator<<(ostream& o, const pair<T,U>& p) {
+template<class T, class U> ostream& operator<<(ostream& o, const std::pair<T,U>& p) {
return o << p.first << ":" << p.second;
}
-template<class T> ostream& operator<<(ostream& o, const vector<T>& v) {
+template<class T> ostream& operator<<(ostream& o, const std::vector<T>& v) {
+ o << "[ ";
+ ostream_iterator<T> oi(o, " ");
+ copy(v.begin(), v.end(), oi);
+ return o << "]";
+}
+template<class T> ostream& operator<<(ostream& o, const std::list<T>& v) {
o << "[ ";
ostream_iterator<T> oi(o, " ");
copy(v.begin(), v.end(), oi);
@@ -47,85 +53,109 @@ template<class T> ostream& operator<<(ostream& o, const vector<T>& v) {
}
template<class K, class T> ostream& operator<<(ostream& o, const map<K, T>& m) {
o << "{ ";
- ostream_iterator<pair<K,T> > oi(o, " ");
+ ostream_iterator<std::pair<K,T> > oi(o, " ");
copy(m.begin(), m.end(), oi);
return o << "}";
}
}
-// Insert/extract C++ containers.
-void insert_extract_containers() {
- cout << endl << "== Array, list and map." << endl;
+// Insert/extract native C++ containers with uniform type values.
+void uniform_containers() {
+ std::cout << std::endl << "== Array, list and map of uniform type." << std::endl;
+ proton::value v;
- vector<int> a;
+ std::vector<int> a;
a.push_back(1);
a.push_back(2);
a.push_back(3);
- vector<int> l;
- l.push_back(4);
- l.push_back(5);
- map<string, int> m;
- m["one"] = 1;
- m["two"] = 2;
+ // By default a C++ container is encoded as an AMQP array.
+ v = a;
+ print(v);
+ std::list<int> a1 = v; // Decode as a C++ std::list instead
+ std::cout << a1 << std::endl;
- proton::value v;
- v.encoder() << proton::as<proton::ARRAY>(a) << proton::as<proton::LIST>(l) << proton::as<proton::MAP>(m);
+ // You can specify that a container should be encoded as an AMQP list instead.
+ v = proton::as<proton::LIST>(a1);
print(v);
+ std::cout << v.get<std::vector<int> >() << std::endl;
- vector<int> a1, l1;
- map<string, int> m1;
- v.decoder().rewind();
- v.decoder() >> proton::as<proton::ARRAY>(a1) >> proton::as<proton::LIST>(l1) >> proton::as<proton::MAP>(m1);
- cout << "Extracted: " << a1 << ", " << l1 << ", " << m1 << endl;
+ // C++ map types (types with key_type, mapped_type) convert to an AMQP map by default.
+ std::map<std::string, int> m;
+ m["one"] = 1;
+ m["two"] = 2;
+ v = m;
+ print(v);
+ std::cout << v.get<std::map<std::string, int> >() << std::endl;
+
+ // You can convert a sequence of pairs to an AMQP map if you need to control the
+ // encoded ordering.
+ std::vector<std::pair<std::string, int> > pairs;
+ pairs.push_back(std::make_pair("z", 3));
+ pairs.push_back(std::make_pair("a", 4));
+ v = proton::as<proton::MAP>(pairs);
+ print(v);
+ // You can also decode an AMQP map as a sequence of pairs using decoder() and proton::to_pairs
+ std::vector<std::pair<std::string, int> > pairs2;
+ v.decoder() >> proton::to_pairs(pairs2);
+ std::cout << pairs2 << std::endl;
}
-// Containers with mixed types, use value to represent arbitrary AMQP types.
+// Containers with mixed types use value to represent arbitrary AMQP types.
void mixed_containers() {
- cout << endl << "== List and map of mixed type values." << endl;
- vector<proton::value> l;
+ std::cout << std::endl << "== List and map of mixed type values." << std::endl;
+ proton::value v;
+
+ std::vector<proton::value> l;
l.push_back(proton::value(42));
l.push_back(proton::value(proton::amqp_string("foo")));
- map<proton::value, proton::value> m;
+ // By default, a sequence of proton::value is treated as an AMQP list.
+ v = l;
+ print(v);
+ std::vector<proton::value> l2 = v;
+ std::cout << l2 << std::endl;
+
+ std::map<proton::value, proton::value> m;
m[proton::value("five")] = proton::value(5);
m[proton::value(4)] = proton::value("four");
- proton::value v;
- v.encoder() << proton::as<proton::LIST>(l) << proton::as<proton::MAP>(m);
+ v = m;
print(v);
-
- vector<proton::value> l1;
- map<proton::value, proton::value> m1;
- v.decoder().rewind();
- v.decoder() >> proton::as<proton::LIST>(l1) >> proton::as<proton::MAP>(m1);
- cout << "Extracted: " << l1 << ", " << m1 << endl;
+ std::map<proton::value, proton::value> m2 = v;
+ std::cout << m2 << std::endl;
}
// Insert using stream operators (see print_next for example of extracting with stream ops.)
-void insert_extract_stream_operators() {
- cout << endl << "== Insert with stream operators." << endl;
+void insert_stream_operators() {
+ std::cout << std::endl << "== Insert with stream operators." << std::endl;
proton::value v;
- // Note: array elements must be encoded with the exact type, they are not
- // automaticlly converted. Mismatched types for array elements will not
- // be detected until v.encode() is called.
- v.encoder() << proton::start::array(proton::INT) << proton::amqp_int(1) << proton::amqp_int(2) << proton::amqp_int(3) << proton::finish();
+
+ // Create an array of INT with values [1, 2, 3]
+ v.encoder() << proton::start::array(proton::INT)
+ << proton::amqp_int(1) << proton::amqp_int(2) << proton::amqp_int(3)
+ << proton::finish();
print(v);
- v.clear();
- v.encoder() << proton::start::list() << proton::amqp_int(42) << false << proton::amqp_symbol("x") << proton::finish();
+ // Create a mixed-type list of the values [42, false, "x"].
+ v.encoder() << proton::start::list()
+ << proton::amqp_int(42) << false << proton::amqp_symbol("x")
+ << proton::finish();
print(v);
- v.clear();
- v.encoder() << proton::start::map() << "k1" << proton::amqp_int(42) << proton::amqp_symbol("k2") << false << proton::finish();
+ // Create a map { "k1":42, "k2": false }
+ v.encoder() << proton::start::map()
+ << "k1" << proton::amqp_int(42)
+ << proton::amqp_symbol("k2") << false
+ << proton::finish();
print(v);
}
int main(int, char**) {
try {
- insert_extract_containers();
+ uniform_containers();
mixed_containers();
- insert_extract_stream_operators();
+ insert_stream_operators();
return 0;
- } catch (const exception& e) {
- cerr << endl << "error: " << e.what() << endl;
+ } catch (const std::exception& e) {
+ std::cerr << std::endl << "error: " << e.what() << std::endl;
}
return 1;
}
@@ -141,47 +171,47 @@ void print_next(proton::decoder& d) {
switch (type) {
case proton::ARRAY: {
d >> s;
- cout << "array<" << s.element;
+ std::cout << "array<" << s.element;
if (s.is_described) {
- cout << ", descriptor=";
+ std::cout << ", descriptor=";
print_next(d);
}
- cout << ">[";
+ std::cout << ">[";
for (size_t i = 0; i < s.size; ++i) {
- if (i) cout << ", ";
+ if (i) std::cout << ", ";
print_next(d);
}
- cout << "]";
+ std::cout << "]";
d >> proton::finish();
break;
}
case proton::LIST: {
d >> s;
- cout << "list[";
+ std::cout << "list[";
for (size_t i = 0; i < s.size; ++i) {
- if (i) cout << ", ";
+ if (i) std::cout << ", ";
print_next(d);
}
- cout << "]";
+ std::cout << "]";
d >> proton::finish();
break;
}
case proton::MAP: {
d >> s;
- cout << "map{";
+ std::cout << "map{";
for (size_t i = 0; i < s.size/2; ++i) {
- if (i) cout << ", ";
+ if (i) std::cout << ", ";
print_next(d);
- cout << ":"; // key:value
+ std::cout << ":"; // key:value
print_next(d);
}
- cout << "}";
+ std::cout << "}";
d >> proton::finish();
break;
}
case proton::DESCRIBED: {
d >> s;
- cout << "described(";
+ std::cout << "described(";
print_next(d); // Descriptor
print_next(d); // value
d >> proton::finish();
@@ -192,7 +222,7 @@ void print_next(proton::decoder& d) {
// we will take a short cut and extract to another value and print that.
proton::value v2;
d >> v2;
- cout << type << "(" << v2 << ")";
+ std::cout << type << "(" << v2 << ")";
}
}
@@ -200,10 +230,9 @@ void print_next(proton::decoder& d) {
void print(proton::value& v) {
proton::decoder& d = v.decoder();
d.rewind();
- cout << "Values: ";
while (d.more()) {
print_next(d);
- if (d.more()) cout << ", ";
+ if (d.more()) std::cout << ", ";
}
- cout << endl;
+ std::cout << std::endl;
}
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/01e136cc/examples/cpp/example_test.py
----------------------------------------------------------------------
diff --git a/examples/cpp/example_test.py b/examples/cpp/example_test.py
index f51cf57..bc552ab 100644
--- a/examples/cpp/example_test.py
+++ b/examples/cpp/example_test.py
@@ -199,18 +199,26 @@ class ExampleTest(unittest.TestCase):
def test_encode_decode(self):
expect="""
-== Array, list and map.
-Values: array<int>[int(1), int(2), int(3)], list[int(4), int(5)], map{string(one):int(1), string(two):int(2)}
-Extracted: [ 1 2 3 ], [ 4 5 ], { one:1 two:2 }
+== Array, list and map of uniform type.
+array<int>[int(1), int(2), int(3)]
+[ 1 2 3 ]
+list[int(1), int(2), int(3)]
+[ 1 2 3 ]
+map{string(one):int(1), string(two):int(2)}
+{ one:1 two:2 }
+map{string(z):int(3), string(a):int(4)}
+[ z:3 a:4 ]
== List and map of mixed type values.
-Values: list[int(42), string(foo)], map{int(4):string(four), string(five):int(5)}
-Extracted: [ 42 foo ], { 4:four five:5 }
+list[int(42), string(foo)]
+[ 42 foo ]
+map{int(4):string(four), string(five):int(5)}
+{ 4:four five:5 }
== Insert with stream operators.
-Values: array<int>[int(1), int(2), int(3)]
-Values: list[int(42), boolean(false), symbol(x)]
-Values: map{string(k1):int(42), symbol(k2):boolean(false)}
+array<int>[int(1), int(2), int(3)]
+list[int(42), boolean(false), symbol(x)]
+map{string(k1):int(42), symbol(k2):boolean(false)}
"""
self.maxDiff = None
self.assertEqual(expect, execute("encode_decode"))
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/01e136cc/examples/cpp/simple_send.cpp
----------------------------------------------------------------------
diff --git a/examples/cpp/simple_send.cpp b/examples/cpp/simple_send.cpp
index cb33207..31e2c73 100644
--- a/examples/cpp/simple_send.cpp
+++ b/examples/cpp/simple_send.cpp
@@ -51,7 +51,7 @@ class simple_send : public proton::messaging_handler {
msg.id(sent + 1);
std::map<std::string, int> m;
m["sequence"] = sent+1;
- msg.body(proton::as<proton::MAP>(m));
+ msg.body(m);
sender.send(msg);
sent++;
}
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/01e136cc/proton-c/bindings/cpp/include/proton/decoder.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/decoder.hpp b/proton-c/bindings/cpp/include/proton/decoder.hpp
index 33ddb4f..1d105e9 100644
--- a/proton-c/bindings/cpp/include/proton/decoder.hpp
+++ b/proton-c/bindings/cpp/include/proton/decoder.hpp
@@ -23,51 +23,130 @@
#include "proton/type_traits.hpp"
#include "proton/types.hpp"
#include "proton/facade.hpp"
+
#include <iosfwd>
+#ifndef PN_NO_CONTAINER_CONVERT
+
+#include <vector>
+#include <deque>
+#include <list>
+#include <map>
+
+#if PN_HAS_CPP11
+#include <array>
+#include <forward_list>
+#include <unordered_map>
+#endif // PN_HAS_CPP11
+
+#endif // PN_NO_CONTAINER_CONVERT
+
struct pn_data_t;
namespace proton {
-class data;
class message_id;
/** Raised by decoder operations on error.*/
struct decode_error : public error { PN_CPP_EXTERN explicit decode_error(const std::string&) throw(); };
-/** Skips a value with `decoder >> skip()`. */
+/** Skips a value with `dec >> skip()`. */
struct skip{};
-/** Rewind the decoder with `decoder >> rewind()`. */
+/** Assert the next type of value in the decoder: `dec >> assert_type(t)`
+ * throws if decoder.type() != t
+ */
+struct assert_type {
+ type_id type;
+ assert_type(type_id t) : type(t) {}
+};
+
+/** Rewind the decoder with `dec >> rewind()`. */
struct rewind{};
/**
- * Stream-like decoder from AMQP bytes to a stream of C++ values.
- *
- * types.h defines C++ types corresponding to AMQP types.
- *
- * decoder operator>> will extract AMQP types into corresponding C++ types, and
- * do simple conversions, e.g. from AMQP integer types to corresponding or
- * larger C++ integer types.
- *
- * You can require an exact AMQP type using the `as<type>(value)` helper. E.g.
- *
- * amqp_int i;
- * decoder >> as<INT>(i): // Will throw if decoder does not contain an INT
- *
- * You can also use the `as` helper to extract an AMQP list, array or map into C++ containers.
- *
- *
- * std::vector<amqp_int> v;
- * decoder >> as<LIST>(v); // Extract a list of INT.
- *
- * AMQP maps can be inserted/extracted to any container with pair<X,Y> as
- * value_type, which includes std::map and std::unordered_map but also for
- * example std::vector<std::pair<X,Y> >. This allows you to preserve order when
- * extracting AMQP maps.
- *
- * You can also extract container values element-by-element, see decoder::operator>>(decoder&, start&)
- *
+Stream-like decoder from AMQP bytes to C++ values.
+
+@see types.hpp defines C++ types corresponding to AMQP types.
+
+The decoder operator>> will extract AMQP types into any compatible C++
+type or throw an exception if the types are not compatible.
+
++-------------------------+-------------------------------+
+|AMQP type |Compatible C++ types |
++=========================+===============================+
+|BOOLEAN |amqp_boolean, bool |
++-------------------------+-------------------------------+
+|signed integer type I |C++ signed integer type T where|
+| |sizeof(T) >= sizeof(I) |
++-------------------------+-------------------------------+
+|unsigned integer type U |C++ unsigned integer type T |
+| |where sizeof(T) >= sizeof(U) |
++-------------------------+-------------------------------+
+|CHAR |amqp_char, wchar_t |
++-------------------------+-------------------------------+
+|FLOAT |amqp_float, float |
++-------------------------+-------------------------------+
+|DOUBLE |amqp_double, double |
++-------------------------+-------------------------------+
+|STRING |amqp_string, std::string |
++-------------------------+-------------------------------+
+|SYMBOL |amqp_symbol, std::string |
++-------------------------+-------------------------------+
+|BINARY |amqp_binary, std::string |
++-------------------------+-------------------------------+
+|DECIMAL<n> |amqp_decimal<n> |
++-------------------------+-------------------------------+
+|TIMESTAMP |amqp_timestamp |
++-------------------------+-------------------------------+
+|UUID |amqp_uuid |
++-------------------------+-------------------------------+
+
+The special proton::value type can hold any AMQP type, simple or compound.
+
+By default operator >> will do any conversion that does not lose data. For example
+any AMQP signed integer type can be extracted as follows:
+
+ int64_t i;
+ dec >> i;
+
+You can assert the exact AMQP type with proton::assert_type, for example
+the following will throw if the AMQP type is not an AMQP INT (32 bits)
+
+ amqp_int i;
+ dec >> assert_type(INT) >> i; // Will throw if decoder does not contain an INT
+
+You can extract AMQP ARRAY, LIST or MAP into standard C++ containers of compatible types, for example:
+
+ std::vector<int32_t> v;
+ dec >> v;
+
+This will work if the decoder contains an AMQP ARRAY or LIST of SHORT or INT values. It won't work
+for LONG or other types. It will also work for a MAP with keys and values that are SHORT OR INT,
+the map will be "flattened" into a sequence [ key1, value1, key2, value2 ] This will work with
+std::dequeue, std::array, std::list or std::forward_list.
+
+You can extract a MAP into a std::map or std::unordered_map
+
+ std::map<std::string, std::string> v;
+ dec >> v;
+
+This will work for any AMQP map with keys and values that are STRING, SYMBOL or BINARY.
+
+If you have non-standard container types that meet the most basic requirements for
+the container or associative-container concepts, you can use them via helper functions:
+
+ my_sequence_type<int64_t> s;
+ dec >> proton::to_sequence(s); // Decode sequence of integers
+ my_map_type<amqp_string, bool> s;
+ dec >> proton::to_map(s); // Decode map of string: bool.
+
+Finally you can extract an AMQP LIST with mixed type elements into a container of proton::value, e.g.
+
+ std::vector<proton::value> v;
+ dec >> v;
+
+You can also extract container values element-by-element, see decoder::operator>>(decoder&, start&)
*/
class decoder : public facade<pn_data_t, decoder> {
public:
@@ -124,14 +203,11 @@ class decoder : public facade<pn_data_t, decoder> {
PN_CPP_EXTERN friend decoder& operator>>(decoder&, amqp_uuid&);
PN_CPP_EXTERN friend decoder& operator>>(decoder&, std::string&);
PN_CPP_EXTERN friend decoder& operator>>(decoder&, message_id&);
- PN_CPP_EXTERN friend decoder& operator>>(decoder&, class data&);
+ PN_CPP_EXTERN friend decoder& operator>>(decoder&, value&);
///@}
/** Extract and return a value of type T. */
- template <class T> T get() { T value; *this >> value; return value; }
-
- /** Extract and return a value of type T, as AMQP type. */
- template <class T, type_id A> T get_as() { T value; *this >> as<A>(value); return value; }
+ template <class T> T extract() { T value; *this >> value; return value; }
/** Call decoder::start() in constructor, decoder::finish in destructor().
*
@@ -142,21 +218,15 @@ class decoder : public facade<pn_data_t, decoder> {
~scope() { decoder_ >> finish(); }
};
- template <type_id A, class T> friend decoder& operator>>(decoder& d, ref<T, A> ref) {
- d.check_type(A);
- d >> ref.value;
- return d;
- }
-
/** start extracting a container value, one of array, list, map, described.
* The basic pattern is:
*
* start s;
- * decoder >> s;
+ * dec >> s;
* // check s.type() to see if this is an ARRAY, LIST, MAP or DESCRIBED type.
* if (s.described) extract the descriptor...
* for (size_t i = 0; i < s.size(); ++i) Extract each element...
- * decoder >> finish();
+ * dec >> finish();
*
* The first value of an ARRAY is a descriptor if start::descriptor is true,
* followed by start.size elements of type start::element.
@@ -182,6 +252,9 @@ class decoder : public facade<pn_data_t, decoder> {
/** Skip a value */
PN_CPP_EXTERN friend decoder& operator>>(decoder&, skip);
+ /** Throw an exception if decoder.type() != assert_type.type */
+ PN_CPP_EXTERN friend decoder& operator>>(decoder&, assert_type);
+
/** Rewind to the beginning */
PN_CPP_EXTERN friend decoder& operator>>(decoder&, struct rewind);
@@ -191,46 +264,138 @@ class decoder : public facade<pn_data_t, decoder> {
friend class encoder;
};
+
// operator >> for integer types that are not covered by the standard overrides.
template <class T>
-typename enable_if<is_unknown_integer<T>::value, decoder&>::type operator>>(decoder& d, T& i) {
+typename enable_if<is_unknown_integer<T>::value, decoder&>::type
+operator>>(decoder& d, T& i) {
typename integer_type<sizeof(T), is_signed<T>::value>::type v;
d >> v; // Extract as a known integer type
i = v;
return d;
}
-template <class T> decoder& operator>>(decoder& d, ref<T, ARRAY> ref) {
+///@cond INTERNAL
+template <class T> struct sequence_ref {
+ sequence_ref(T& v) : value(v) {}
+ T& value;
+};
+
+template <class T> struct map_ref {
+ map_ref(T& v) : value(v) {}
+ T& value;
+};
+
+template <class T> struct pairs_ref {
+ pairs_ref(T& v) : value(v) {}
+ T& value;
+};
+///@endcond
+
+/**
+ * Return a wrapper for a C++ container to be decoded as a sequence. The AMQP
+ * ARRAY, LIST, and MAP types can all be decoded as a sequence, a map will be
+ * decoded as alternating key and value (provided they can both be converted to
+ * the container's value_type)
+ *
+ * The following expressions must be valid for T t;
+ * T::iterator
+ * t.clear()
+ * t.resize()
+ * t.begin()
+ * t.end()
+ */
+template <class T> sequence_ref<T> to_sequence(T& v) { return sequence_ref<T>(v); }
+
+/** Return a wrapper for a C++ map container to be decoded from an AMQP MAP.
+ * The following expressions must be valid for T t;
+ * T::key_type
+ * T::mapped_type
+ * t.clear()
+ * T::key_type k; T::mapped_type v; t[k] = v;
+ */
+template <class T> map_ref<T> to_map(T& v) { return map_ref<T>(v); }
+
+/** Return a wrapper for a C++ container of std::pair that can be decoded from AMQP maps,
+ * preserving the encoded map order.
+ *
+ * The following expressions must be valid for T t;
+ * T::iterator
+ * t.clear()
+ * t.resize()
+ * t.begin()
+ * t.end()
+ * T::iterator i; i->first; i->second
+ */
+template <class T> pairs_ref<T> to_pairs(T& v) { return pairs_ref<T>(v); }
+
+/** Extract any AMQP sequence (ARRAY, LIST or MAP) to a C++ container of T if
+ * the elements types are convertible to T. A MAP is extracted as [key1, value1,
+ * key2, value2...]
+ */
+template <class T> decoder& operator>>(decoder& d, sequence_ref<T> ref) {
decoder::scope s(d);
if (s.is_described) d >> skip();
- ref.value.clear();
- ref.value.resize(s.size);
- for (typename T::iterator i = ref.value.begin(); i != ref.value.end(); ++i) {
+ T& v = ref.value;
+ v.clear();
+ v.resize(s.size);
+ for (typename T::iterator i = v.begin(); i != v.end(); ++i)
d >> *i;
- }
return d;
}
-template <class T> decoder& operator>>(decoder& d, ref<T, LIST> ref) {
+void assert_map_scope(const decoder::scope& s);
+
+/** Extract an AMQP MAP to a C++ map */
+template <class T> decoder& operator>>(decoder& d, map_ref<T> ref) {
decoder::scope s(d);
- ref.value.clear();
- ref.value.resize(s.size);
- for (typename T::iterator i = ref.value.begin(); i != ref.value.end(); ++i)
- d >> *i;
+ assert_map_scope(s);
+ T& m = ref.value;
+ m.clear();
+ for (size_t i = 0; i < s.size/2; ++i) {
+ typename remove_const<typename T::key_type>::type k;
+ typename remove_const<typename T::mapped_type>::type v;
+ d >> k >> v;
+ m[k] = v;
+ }
return d;
}
-template <class T> decoder& operator>>(decoder& d, ref<T, MAP> ref) {
- decoder::scope m(d);
- ref.value.clear();
- for (size_t i = 0; i < m.size/2; ++i) {
- typename T::key_type k;
- typename T::mapped_type v;
- d >> k >> v;
- ref.value[k] = v;
+/** Extract an AMQP MAP to a C++ container of std::pair, preserving order. */
+template <class T> decoder& operator>>(decoder& d, pairs_ref<T> ref) {
+ decoder::scope s(d);
+ assert_map_scope(s);
+ T& m = ref.value;
+ m.clear();
+ m.resize(s.size/2);
+ for (typename T::iterator i = m.begin(); i != m.end(); ++i) {
+ d >> i->first >> i->second;
}
return d;
}
+#ifndef PN_NO_CONTAINER_CONVERT
+
+// Decode to sequence.
+template <class T, class A> decoder& operator>>(decoder &d, std::vector<T, A>& v) { return d >> to_sequence(v); }
+template <class T, class A> decoder& operator>>(decoder &d, std::deque<T, A>& v) { return d >> to_sequence(v); }
+template <class T, class A> decoder& operator>>(decoder &d, std::list<T, A>& v) { return d >> to_sequence(v); }
+
+// Decode to map.
+template <class K, class T, class C, class A> decoder& operator>>(decoder &d, std::map<K, T, C, A>& v) { return d >> to_map(v); }
+
+#if PN_HAS_CPP11
+
+// Decode to sequence.
+template <class T, class A> decoder& operator>>(decoder &d, std::forward_list<T, A>& v) { return d >> to_sequence(v); }
+template <class T, std::size_t N> decoder& operator>>(decoder &d, std::array<T, N>& v) { return d >> to_sequence(v); }
+
+// Decode to map.
+template <class K, class T, class C, class A> decoder& operator>>(decoder &d, std::unordered_map<K, T, C, A>& v) { return d >> to_map(v); }
+
+#endif // PN_HAS_CPP11
+#endif // PN_NO_CONTAINER_CONVERT
+
}
+
#endif // DECODER_H
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/01e136cc/proton-c/bindings/cpp/include/proton/encoder.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/encoder.hpp b/proton-c/bindings/cpp/include/proton/encoder.hpp
index 24684c1..7dd7ddb 100644
--- a/proton-c/bindings/cpp/include/proton/encoder.hpp
+++ b/proton-c/bindings/cpp/include/proton/encoder.hpp
@@ -25,39 +25,68 @@
#include "proton/facade.hpp"
#include <iosfwd>
+#ifndef PN_NO_CONTAINER_CONVERT
+
+#include <vector>
+#include <deque>
+#include <list>
+#include <map>
+
+#if PN_HAS_CPP11
+#include <array>
+#include <forward_list>
+#include <unordered_map>
+#endif // PN_HAS_CPP11
+
+#endif // PN_NO_CONTAINER_CONVERT
+
struct pn_data_t;
namespace proton {
-class data;
class message_id;
/** Raised by encoder operations on error */
struct encode_error : public error { PN_CPP_EXTERN explicit encode_error(const std::string&) throw(); };
/**
- * Stream C++ data values into an AMQP encoder using operator<<.
+ * Stream-like encoder from C++ values to AMQP values.
*
- * types.h defines C++ typedefs and types for AMQP each type. These types insert
- * as the corresponding AMQP type. Conversion rules apply to other types:
+ * types.hpp defines a C++ type for each AMQP type. For simple types they are
+ * just typedefs for corresponding native C++ types. These types encode as the
+ * corresponding AMQP type.
*
- * - Integer types insert as the AMQP integer of matching size and signedness.
- * - std::string or char* insert as AMQP strings.
+ * There are some special case conversions:
*
- * C++ containers can be inserted as AMQP containers with the as() helper
- * functions. For example:
+ * - Integer types other than those mentioned in types.hpp encode as the AMQP
+ * integer type of matching size and signedness.
+ * - std::string or char* insert as AMQP STRING.
*
- * std::vector<amqp_symbol> v;
- * encoder << as<amqp_list>(v);
+ * For example to encode an AMQP INT, BOOLEAN and STRING these are equivalent:
*
- * AMQP maps can be inserted from any container with std::pair<X,Y> as the
- * value_type. That includes std::map and std::unordered_map but also for
- * example std::vector<std::pair<X,Y> >. This allows you to control the order
- * of elements when inserting AMQP maps.
+ * enc << proton::amqp_int(1) << proton::amqp_boolean(true) << proton::amqp_string("foo");
+ * enc << int32_t(1) << true << "foo";
*
- * You can also insert containers element-by-element, see operator<<(encoder&, const start&)
+ * You can force the encoding using the `proton::as` template function, for example:
+ *
+ * uint64_t i = 100;
+ * enc << as<proton::SHORT>(i);
+ *
+ * C++ standard containers can be inserted. By default:
+ *
+ * - std::map and std::unordered_map encode as AMQP MAP
+ * - std::vector, std::deque, std::list, std::array or std::forward_list encode as an AMQP ARRAY.
+ * - std::vector<proton::value> etc. encode as AMQP LIST
+ *
+ * Again you can force the encoding using proton::as<LIST>() or proton::as<ARRAY>()
+ *
+ * Note that you can encode a sequence of pairs as a map, which allows you to control the
+ * encoded order if that is important:
+ *
+ * std::vector<std::pair<T1, T2> > v;
+ * enc << proton::as<MAP>(v);
*
- *@throw decoder::error if the curent value is not a container type.
+ * You can also insert containers element-by-element, see operator<<(encoder&, const start&)
*/
class encoder : public facade<pn_data_t, encoder> {
public:
@@ -107,7 +136,7 @@ class encoder : public facade<pn_data_t, encoder> {
friend PN_CPP_EXTERN encoder& operator<<(encoder&, amqp_symbol);
friend PN_CPP_EXTERN encoder& operator<<(encoder&, amqp_binary);
friend PN_CPP_EXTERN encoder& operator<<(encoder&, const message_id&);
- friend PN_CPP_EXTERN encoder& operator<<(encoder&, const class data&);
+ friend PN_CPP_EXTERN encoder& operator<<(encoder&, const value&);
///@}
/**
@@ -118,7 +147,7 @@ class encoder : public facade<pn_data_t, encoder> {
* and insert it into the encoder, followed by the contained elements. For
* example:
*
- * encoder << start::list() << amqp_int(1) << amqp_symbol("two") << 3.0 << finish();
+ * enc << start::list() << amqp_int(1) << amqp_symbol("two") << 3.0 << finish();
*/
friend PN_CPP_EXTERN encoder& operator<<(encoder&, const start&);
@@ -135,9 +164,6 @@ class encoder : public facade<pn_data_t, encoder> {
template <class T> friend encoder& operator<<(encoder&, cref<T, MAP>);
// TODO aconway 2015-06-16: described values.
///@}
-
- /** Copy data from a raw pn_data_t */
- friend PN_CPP_EXTERN encoder& operator<<(encoder&, pn_data_t*);
};
// Need to disambiguate char* conversion to bool and std::string as amqp_string.
@@ -179,11 +205,36 @@ template <class T> encoder& operator<<(encoder& e, cref<T, MAP> m){
e << finish();
return e;
}
-///@cond INTERNAL Convert a ref to a cref.
-template <class T, type_id A> encoder& operator<<(encoder& e, ref<T, A> ref) {
- return e << cref<T,A>(ref);
-}
-///@endcond
+#ifndef PN_NO_CONTAINER_CONVERT
+// Encode as ARRAY
+template <class T, class A> encoder& operator<<(encoder &e, const std::vector<T, A>& v) { return e << as<ARRAY>(v); }
+template <class T, class A> encoder& operator<<(encoder &e, const std::deque<T, A>& v) { return e << as<ARRAY>(v); }
+template <class T, class A> encoder& operator<<(encoder &e, const std::list<T, A>& v) { return e << as<ARRAY>(v); }
+
+// Encode as LIST
+template <class A> encoder& operator<<(encoder &e, const std::vector<value, A>& v) { return e << as<LIST>(v); }
+template <class A> encoder& operator<<(encoder &e, const std::deque<value, A>& v) { return e << as<LIST>(v); }
+template <class A> encoder& operator<<(encoder &e, const std::list<value, A>& v) { return e << as<LIST>(v); }
+
+// Encode as MAP
+template <class K, class T, class C, class A> encoder& operator<<(encoder &e, const std::map<K, T, C, A>& v) { return e << as<MAP>(v); }
+
+#if PN_HAS_CPP11
+
+// Encode as ARRAY.
+template <class T, class A> encoder& operator<<(encoder &e, const std::forward_list<T, A>& v) { return e << as<ARRAY>(v); }
+template <class T, std::size_t N> encoder& operator<<(encoder &e, const std::array<T, N>& v) { return e << as<ARRAY>(v); }n
+
+// Encode as LIST.
+template <class value, class A> encoder& operator<<(encoder &e, const std::forward_list<value, A>& v) { return e << as<LIST>(v); }
+template <class value, std::size_t N> encoder& operator<<(encoder &e, const std::array<value, N>& v) { return e << as<LIST>(v); }
+
+// Encode as map.
+template <class K, class T, class C, class A> encoder& operator<<(encoder &e, const std::unordered_map<K, T, C, A>& v) { return e << as<MAP>(v); }
+
+#endif // PN_HAS_CPP11
+
+#endif // PN_NO_CONTAINER_CONVERT
}
#endif // ENCODER_H
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/01e136cc/proton-c/bindings/cpp/include/proton/engine.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/engine.hpp b/proton-c/bindings/cpp/include/proton/engine.hpp
index 672e911..f27033d 100644
--- a/proton-c/bindings/cpp/include/proton/engine.hpp
+++ b/proton-c/bindings/cpp/include/proton/engine.hpp
@@ -31,7 +31,7 @@ namespace proton {
class handler;
class connection;
-/// Pointers to a data buffer.
+/// Pointers to a byte range to use as a buffer.
template <class T> class buffer {
public:
explicit buffer(T* begin__=0, T* end__=0) : begin_(begin__), end_(end__) {}
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/01e136cc/proton-c/bindings/cpp/include/proton/message.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/message.hpp b/proton-c/bindings/cpp/include/proton/message.hpp
index e9862c6..d996f85 100644
--- a/proton-c/bindings/cpp/include/proton/message.hpp
+++ b/proton-c/bindings/cpp/include/proton/message.hpp
@@ -26,6 +26,7 @@
#include "proton/message_id.hpp"
#include "proton/data.hpp"
#include "proton/pn_unique_ptr.hpp"
+#include "proton/value.hpp"
#include <string>
#include <utility>
@@ -95,32 +96,31 @@ class message
PN_CPP_EXTERN std::string reply_to_group_id() const;
///@}
- /** Set the body. If data has more than one value, each is encoded as an AMQP section. */
- PN_CPP_EXTERN void body(const data&);
+ /** Set the body. */
+ PN_CPP_EXTERN void body(const value&);
- /** Set the body to any type T that can be converted to proton::data */
- template <class T> void body(const T& v) { body().clear(); body().encoder() << v; }
-
- /** Get the body values. */
+ /** Get the body. Note data can be copied to a proton::value */
PN_CPP_EXTERN const data& body() const;
/** Get a reference to the body data, can be modified in-place. */
PN_CPP_EXTERN data& body();
- /** Encode into memory starting at buffer.first and ending before buffer.second */
+ // FIXME aconway 2015-11-10: use buffer
+ /** Encode message into memory starting at buffer.first and ending before buffer.second */
PN_CPP_EXTERN void encode(std::pair<char*, char*> buffer);
/** Encode into a string, growing the string if necessary. */
- PN_CPP_EXTERN void encode(std::string &data) const;
+ PN_CPP_EXTERN void encode(std::string &bytes) const;
/** Return encoded message as a string */
PN_CPP_EXTERN std::string encode() const;
+ // FIXME aconway 2015-11-10: use buffer
/** Decode from memory starting at buffer.first and ending before buffer.second */
PN_CPP_EXTERN void decode(std::pair<const char*, const char*> buffer);
/** Decode from string data into the message. */
- PN_CPP_EXTERN void decode(const std::string &data);
+ PN_CPP_EXTERN void decode(const std::string &bytes);
/// Decode the message from link corresponding to delivery.
PN_CPP_EXTERN void decode(proton::link&, proton::delivery&);
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/01e136cc/proton-c/bindings/cpp/include/proton/message_id.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/message_id.hpp b/proton-c/bindings/cpp/include/proton/message_id.hpp
index a472afd..4ff8b52 100644
--- a/proton-c/bindings/cpp/include/proton/message_id.hpp
+++ b/proton-c/bindings/cpp/include/proton/message_id.hpp
@@ -29,6 +29,8 @@ namespace proton {
class message_id : public comparable<message_id> {
public:
message_id() {}
+ message_id(const value& x) : value_(x) {}
+ message_id(const data& x) : value_(x) {}
message_id(const uint64_t& x) : value_(x) {}
message_id(const amqp_uuid& x) : value_(x) {}
message_id(const amqp_binary& x) : value_(x) {}
@@ -71,7 +73,6 @@ class message_id : public comparable<message_id> {
friend PN_CPP_EXTERN decoder& operator>>(decoder&, message_id&);
private:
- message_id(const value& v) : value_(v) {}
value value_;
friend class message;
};
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/01e136cc/proton-c/bindings/cpp/include/proton/request_response.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/request_response.hpp b/proton-c/bindings/cpp/include/proton/request_response.hpp
index 957c91a..58b8156 100644
--- a/proton-c/bindings/cpp/include/proton/request_response.hpp
+++ b/proton-c/bindings/cpp/include/proton/request_response.hpp
@@ -29,9 +29,6 @@
#include <string>
-struct pn_message_t;
-struct pn_data_t;
-
namespace proton {
/**
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/01e136cc/proton-c/bindings/cpp/include/proton/type_traits.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/type_traits.hpp b/proton-c/bindings/cpp/include/proton/type_traits.hpp
index bebf0b1..d12e0ed 100644
--- a/proton-c/bindings/cpp/include/proton/type_traits.hpp
+++ b/proton-c/bindings/cpp/include/proton/type_traits.hpp
@@ -30,7 +30,9 @@
#include "proton/types.hpp"
namespace proton {
-template <bool, class T=void> struct enable_if;
+class value;
+
+template <bool, class T=void> struct enable_if {};
template <class T> struct enable_if<true, T> { typedef T type; };
struct true_type { static const bool value = true; };
@@ -67,8 +69,15 @@ template <> struct is_signed<unsigned long long> : public false_type {};
template <> struct is_signed<signed long long> : public true_type {};
#endif
-// Metafunction returning exact AMQP type associated with a C++ type
-template <class T> struct type_id_of;
+template <class T, class U> struct is_same { static const bool value=false; };
+template <class T> struct is_same<T,T> { static const bool value=true; };
+
+
+template< class T > struct remove_const { typedef T type; };
+template< class T > struct remove_const<const T> { typedef T type; };
+
+// Metafunction returning AMQP type for basic C++ types
+template <class T, class Enable=void> struct type_id_of;
template<> struct type_id_of<amqp_null> { static const type_id value=NULL_; };
template<> struct type_id_of<amqp_boolean> { static const type_id value=BOOLEAN; };
template<> struct type_id_of<amqp_ubyte> { static const type_id value=UBYTE; };
@@ -91,12 +100,12 @@ template<> struct type_id_of<amqp_binary> { static const type_id value=BINARY; }
template<> struct type_id_of<amqp_string> { static const type_id value=STRING; };
template<> struct type_id_of<amqp_symbol> { static const type_id value=SYMBOL; };
-template <class T, class Enable=void> struct has_type_id { static const bool value = false; };
+template <class T, class Enable=void> struct has_type_id : public false_type {};
template <class T> struct has_type_id<T, typename enable_if<!!type_id_of<T>::value>::type> {
static const bool value = true;
};
-// amqp_map to known integer types by sizeof and signedness.
+// Map arbitrary integral types to know AMQP integral types.
template<size_t N, bool S> struct integer_type;
template<> struct integer_type<1, true> { typedef amqp_byte type; };
template<> struct integer_type<2, true> { typedef amqp_short type; };
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/01e136cc/proton-c/bindings/cpp/include/proton/types.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/types.hpp b/proton-c/bindings/cpp/include/proton/types.hpp
index 0f82ae3..b9fedd1 100644
--- a/proton-c/bindings/cpp/include/proton/types.hpp
+++ b/proton-c/bindings/cpp/include/proton/types.hpp
@@ -159,51 +159,22 @@ struct amqp_timestamp : public comparable<amqp_timestamp> {
};
///@cond INTERNAL
-template<class T, type_id A> struct type_pair {
+template<class T, type_id A> struct cref {
typedef T cpp_type;
- type_id type;
-};
-
-template<class T, type_id A> struct ref : public type_pair<T, A> {
- ref(T& v) : value(v) {}
- T& value;
-};
+ static const type_id type;
-template<class T, type_id A> struct cref : public type_pair<T, A> {
cref(const T& v) : value(v) {}
- cref(const ref<T,A>& ref) : value(ref.value) {}
const T& value;
};
+template <class T, type_id A> const type_id cref<T, A>::type = A;
///@endcond INTERNAL
-/** A holder for AMQP values. A holder is always encoded/decoded as its amqp_value, no need
- * for the as<TYPE>() helper functions.
- *
- * For example to encode an array of arrays using std::vector:
- *
- * typedef holder<std::vector<amqp_string>, ARRAY> Inner;
- * typedef holder<std::vector<Inner>, ARRAY> Outer;
- * Outer o ...
- * encoder << o;
- *
- */
-template<class T, type_id A> struct holder : public type_pair<T, A> {
- T value;
-};
-
-/** Create a reference to value as AMQP type A for decoding.
- * For example to decode an array of amqp_int:
- *
- * std::vector<amqp_int> v;
- * decoder >> as<ARRAY>(v);
- */
-template <type_id A, class T> ref<T, A> as(T& value) { return ref<T, A>(value); }
-
-/** Create a const reference to value as AMQP type A for encoding.
- * For example to encode an array of amqp_int:
+/**
+ * Indicate the desired AMQP type to use when encoding T.
+ * For example to encode a vector as a list:
*
* std::vector<amqp_int> v;
- * encoder << as<ARRAY>(v);
+ * encoder << as<LIST>(v);
*/
template <type_id A, class T> cref<T, A> as(const T& value) { return cref<T, A>(value); }
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/01e136cc/proton-c/bindings/cpp/include/proton/value.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/value.hpp b/proton-c/bindings/cpp/include/proton/value.hpp
index 8816064..ddc5501 100644
--- a/proton-c/bindings/cpp/include/proton/value.hpp
+++ b/proton-c/bindings/cpp/include/proton/value.hpp
@@ -30,11 +30,23 @@ class data;
class encoder;
class decoder;
-/** AMQP data with normal value semantics: copy, assign etc. */
+/**
+ * Holder for an AMQP value.
+ *
+ * proton::value can hold any AMQP data value, simple or compound. It has
+ * assignment and conversion operators to convert its contents easily to and
+ * from native C++ types.
+ *
+ * See proton::encoder and proton::decoder for details of the conversion rules.
+ * Assigning to a proton::value follows the encoder rules, converting from a
+ * proton::value (or calling proton::value::get) follows the decoder rules.
+ */
class value : public comparable<value> {
public:
PN_CPP_EXTERN value();
PN_CPP_EXTERN value(const value& x);
+ PN_CPP_EXTERN value(const data&);
+
template <class T> value(const T& x) : data_(data::create()) { *data_ = x; }
PN_CPP_EXTERN value& operator=(const value& x);
@@ -44,23 +56,26 @@ class value : public comparable<value> {
PN_CPP_EXTERN void clear();
PN_CPP_EXTERN bool empty() const;
- /** Encoder to encode complex data into this value.
- * Note if you enocde more than one value, all but the first will be ignored.
- */
+ // FIXME aconway 2015-11-06: rename encode/decode
+
+ /** Encoder to encode complex data into this value. Note this clears the value. */
PN_CPP_EXTERN class encoder& encoder();
- /** Decoder to decode complex data from this value */
- PN_CPP_EXTERN class decoder& decoder();
+ /** Decoder to decode complex data from this value. Note this rewinds the decoder. */
+ PN_CPP_EXTERN class decoder& decoder() const;
/** Type of the current value*/
PN_CPP_EXTERN type_id type() const;
/** Get the value. */
- template<class T> void get(T &t) const { rewind() >> t; }
+ template<class T> void get(T &t) const { decoder() >> t; }
/** Get the value. */
template<class T> T get() const { T t; get(t); return t; }
+ /** Automatic conversion */
+ template<class T> operator T() const { return get<T>(); }
+
PN_CPP_EXTERN bool operator==(const value& x) const;
PN_CPP_EXTERN bool operator<(const value& x) const;
@@ -69,9 +84,6 @@ class value : public comparable<value> {
friend PN_CPP_EXTERN std::ostream& operator<<(std::ostream& o, const value& dv);
private:
- value(const data&);
- class decoder& rewind() const { data_->decoder().rewind(); return data_->decoder(); }
-
pn_unique_ptr<data> data_;
friend class message;
};
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/01e136cc/proton-c/bindings/cpp/src/decoder.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/decoder.cpp b/proton-c/bindings/cpp/src/decoder.cpp
index d148b12..1fe13a2 100644
--- a/proton-c/bindings/cpp/src/decoder.cpp
+++ b/proton-c/bindings/cpp/src/decoder.cpp
@@ -147,16 +147,19 @@ decoder& operator>>(decoder& d, finish) { pn_data_exit(pn_cast(&d)); return d; }
decoder& operator>>(decoder& d, skip) { pn_data_next(pn_cast(&d)); return d; }
+decoder& operator>>(decoder& d, assert_type a) { bad_type(a.type, d.type()); return d; }
+
decoder& operator>>(decoder& d, rewind) { d.rewind(); return d; }
-decoder& operator>>(decoder& d, data& v) {
- if (pn_cast(&d) == pn_cast(&v)) throw decode_error("extract into self");
- v.clear();
+decoder& operator>>(decoder& d, value& v) {
+ pn_data_t *ddata = pn_cast(&d);
+ pn_data_t *vdata = pn_cast(&v.encoder());
+ if (ddata == vdata) throw decode_error("extract into self");
{
- narrow n(pn_cast(&d));
- check(pn_data_appendn(pn_cast(&v), pn_cast(&d), 1));
+ narrow n(ddata);
+ check(pn_data_appendn(vdata, ddata, 1));
}
- if (!pn_data_next(pn_cast(&d))) throw decode_error("no more data");
+ if (!pn_data_next(ddata)) throw decode_error("no more data");
return d;
}
@@ -340,4 +343,12 @@ decoder& operator>>(decoder& d, std::string& value) {
return d;
}
+void assert_map_scope(const decoder::scope& s) {
+ if (s.type != MAP)
+ throw decode_error("cannot decode "+type_name(s.type)+" as map");
+ if (s.size % 2 != 0)
+ throw decode_error("odd number of elements in map");
+}
+
+
}
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/01e136cc/proton-c/bindings/cpp/src/encoder.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/encoder.cpp b/proton-c/bindings/cpp/src/encoder.cpp
index 0230e88..c8e6928 100644
--- a/proton-c/bindings/cpp/src/encoder.cpp
+++ b/proton-c/bindings/cpp/src/encoder.cpp
@@ -130,9 +130,11 @@ encoder& operator<<(encoder& e, amqp_string value) { return insert(e, pn_cast(&e
encoder& operator<<(encoder& e, amqp_symbol value) { return insert(e, pn_cast(&e), value, pn_data_put_symbol); }
encoder& operator<<(encoder& e, amqp_binary value) { return insert(e, pn_cast(&e), value, pn_data_put_binary); }
-encoder& operator<<(encoder& e, const data& v) {
- if (pn_cast(&e) == pn_cast(&v)) throw encode_error("cannot insert into self");
- check(pn_data_append(pn_cast(&e), pn_cast(&v)), pn_cast(&e));
+encoder& operator<<(encoder& e, const value& v) {
+ pn_data_t *edata = pn_cast(&e);
+ pn_data_t *vdata = pn_cast(&v.decoder());
+ if (edata == vdata) throw encode_error("cannot insert into self");
+ check(pn_data_append(edata, vdata), edata);
return e;
}
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/01e136cc/proton-c/bindings/cpp/src/interop_test.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/interop_test.cpp b/proton-c/bindings/cpp/src/interop_test.cpp
index ac2701f..0bac03c 100644
--- a/proton-c/bindings/cpp/src/interop_test.cpp
+++ b/proton-c/bindings/cpp/src/interop_test.cpp
@@ -39,7 +39,11 @@ string read(string filename) {
return string(istreambuf_iterator<char>(ifs), istreambuf_iterator<char>());
}
-template <class T> T get(decoder& d) { return d.get_as<T, type_id_of<T>::value>(); }
+template <class T> T get(decoder& d) {
+ T v;
+ d >> assert_type(type_id_of<T>::value) >> v;
+ return v;
+}
template <class T> std::string str(const T& value) {
ostringstream oss;
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/01e136cc/proton-c/bindings/cpp/src/message.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/message.cpp b/proton-c/bindings/cpp/src/message.cpp
index 63f6520..7ebb821 100644
--- a/proton-c/bindings/cpp/src/message.cpp
+++ b/proton-c/bindings/cpp/src/message.cpp
@@ -161,7 +161,7 @@ std::string message::reply_to_group_id() const {
return s ? std::string(s) : std::string();
}
-void message::body(const data& v) { body() = v; }
+void message::body(const value& v) { body() = v; }
const data& message::body() const {
return *data::cast(pn_message_body(message_));
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/01e136cc/proton-c/bindings/cpp/src/value.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/value.cpp b/proton-c/bindings/cpp/src/value.cpp
index 6b4c402..7059d69 100644
--- a/proton-c/bindings/cpp/src/value.cpp
+++ b/proton-c/bindings/cpp/src/value.cpp
@@ -40,18 +40,16 @@ void value::clear() { data_->clear(); }
bool value::empty() const { return data_->empty(); }
-class encoder& value::encoder() { return data_->encoder(); }
+class encoder& value::encoder() { clear(); return data_->encoder(); }
-class decoder& value::decoder() { return data_->decoder(); }
+class decoder& value::decoder() const { data_->decoder().rewind(); return data_->decoder(); }
-type_id value::type() const { return rewind().type(); }
+type_id value::type() const { return decoder().type(); }
bool value::operator==(const value& x) const { return *data_ == *x.data_; }
bool value::operator<(const value& x) const { return *data_ < *x.data_; }
-
-
std::ostream& operator<<(std::ostream& o, const value& v) {
// pn_inspect prints strings with quotes which is not normal in C++.
switch (v.type()) {
@@ -63,12 +61,4 @@ std::ostream& operator<<(std::ostream& o, const value& v) {
}
}
-class encoder& operator<<(class encoder& e, const value& v) {
- return e << *v.data_;
-}
-
-class decoder& operator>>(class decoder& d, value& v) {
- return d >> *v.data_;
-}
-
}
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org