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/06/18 23:58:25 UTC
[47/50] [abbrv] qpid-proton git commit: PROTON-865: cpp encode/decode
support for complex types.
PROTON-865: cpp encode/decode support for complex types.
Support for streaming complex AMQP types element by element and for
inserting/extracting C++ containers as AMQP containers.
See examples/cpp/encode_decode.cpp for examples of use.
Described types are not yet fully supported.
Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/693752d3
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/693752d3
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/693752d3
Branch: refs/heads/cjansen-cpp-client
Commit: 693752d37c918aed97f4b5bde25716f00ff27a8d
Parents: c99be7a
Author: Alan Conway <ac...@redhat.com>
Authored: Fri Jun 12 13:47:48 2015 -0400
Committer: Alan Conway <ac...@redhat.com>
Committed: Thu Jun 18 17:28:44 2015 -0400
----------------------------------------------------------------------
examples/cpp/CMakeLists.txt | 12 +-
examples/cpp/encode_decode.cpp | 257 ++++++++++++++++
examples/cpp/example_test.py | 41 ++-
examples/cpp/simple_recv.cpp | 2 +-
proton-c/CMakeLists.txt | 5 +-
proton-c/bindings/cpp/CMakeLists.txt | 8 +-
proton-c/bindings/cpp/include/proton/cpp/Data.h | 4 +
.../bindings/cpp/include/proton/cpp/Decoder.h | 172 +++++++----
.../bindings/cpp/include/proton/cpp/Duration.h | 2 +-
.../bindings/cpp/include/proton/cpp/Encoder.h | 84 ++++-
.../bindings/cpp/include/proton/cpp/Exception.h | 49 ---
.../cpp/include/proton/cpp/MessagingHandler.h | 2 +-
.../bindings/cpp/include/proton/cpp/Value.h | 63 ++--
.../bindings/cpp/include/proton/cpp/Values.h | 56 ++++
.../bindings/cpp/include/proton/cpp/types.h | 246 ++++++++++-----
proton-c/bindings/cpp/src/ConnectionImpl.h | 2 +-
proton-c/bindings/cpp/src/ContainerImpl.cpp | 8 -
proton-c/bindings/cpp/src/Data.cpp | 4 +-
proton-c/bindings/cpp/src/Decoder.cpp | 83 ++++-
proton-c/bindings/cpp/src/Encoder.cpp | 74 ++++-
proton-c/bindings/cpp/src/Handler.cpp | 6 +-
proton-c/bindings/cpp/src/MessagingAdapter.cpp | 10 +-
proton-c/bindings/cpp/src/MessagingHandler.cpp | 2 +-
proton-c/bindings/cpp/src/Msg.h | 22 +-
proton-c/bindings/cpp/src/ProtonEvent.cpp | 3 +-
proton-c/bindings/cpp/src/ProtonHandler.cpp | 2 +-
proton-c/bindings/cpp/src/Transport.cpp | 2 +-
proton-c/bindings/cpp/src/Value.cpp | 111 +++++--
proton-c/bindings/cpp/src/Values.cpp | 39 +++
proton-c/bindings/cpp/src/interop_test.cpp | 8 +-
proton-c/bindings/cpp/src/proton_bits.cpp | 8 +
proton-c/bindings/cpp/src/proton_bits.h | 5 +
proton-c/bindings/cpp/src/types.cpp | 47 ++-
proton-c/bindings/go/README.md | 5 -
.../proton/go/amqp/interop_test.go | 308 -------------------
proton-c/docs/api/index.md | 6 +-
proton-c/docs/api/user.doxygen.in | 2 +-
proton-c/include/proton/codec.h | 9 +-
proton-c/src/codec/codec.c | 10 +-
proton-c/src/codec/encoder.c | 10 +-
40 files changed, 1106 insertions(+), 683 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/693752d3/examples/cpp/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/examples/cpp/CMakeLists.txt b/examples/cpp/CMakeLists.txt
index b1e4a1f..bafcd38 100644
--- a/examples/cpp/CMakeLists.txt
+++ b/examples/cpp/CMakeLists.txt
@@ -17,11 +17,19 @@
# under the License.
#
-include_directories ("${CMAKE_SOURCE_DIR}/proton-c/bindings/cpp/include")
+include_directories("${CMAKE_SOURCE_DIR}/proton-c/bindings/cpp/include")
-foreach(example broker helloworld helloworld_blocking helloworld_direct simple_recv simple_send)
+foreach(example
+ broker
+ helloworld
+ helloworld_blocking
+ helloworld_direct
+ simple_recv
+ simple_send
+ encode_decode)
add_executable(${example} ${example}.cpp)
target_link_libraries(${example} qpid-proton-cpp)
+ set_source_files_properties(${example}.cpp PROPERTIES COMPILE_FLAGS "${CXX_WARNING_FLAGS}")
endforeach()
add_test(
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/693752d3/examples/cpp/encode_decode.cpp
----------------------------------------------------------------------
diff --git a/examples/cpp/encode_decode.cpp b/examples/cpp/encode_decode.cpp
new file mode 100644
index 0000000..5096c40
--- /dev/null
+++ b/examples/cpp/encode_decode.cpp
@@ -0,0 +1,257 @@
+/*
+ * 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/cpp/Values.h>
+#include <proton/cpp/Value.h>
+#include <algorithm>
+#include <iostream>
+#include <iterator>
+#include <map>
+#include <sstream>
+#include <stdexcept>
+#include <vector>
+
+using namespace std;
+using namespace proton::reactor;
+
+// Examples of how to use the Encoder and Decoder to create and examine AMQP values.
+//
+
+// Print is defined at the end as an example of how to query and extract complex
+// values in terms of their simple components.
+void print(Values& values);
+
+// Inserting and extracting simple C++ values.
+void simple_insert_extract() {
+ Values values;
+ cout << endl << "== Simple values: int, string, bool" << endl;
+ values << 42 << "foo" << true;
+ print(values);
+ int i;
+ std::string s;
+ bool b;
+ values.rewind();
+ values >> i >> s >> b;
+ cout << "Extracted: " << i << ", " << s << ", " << b << endl;
+ cout << "Encoded as AMQP in " << values.encode().size() << " bytes" << endl;
+}
+
+// Inserting values as a specific AMQP type
+void simple_insert_extract_exact_type() {
+ Values values;
+ cout << endl << "== Specific AMQP types: byte, long, symbol" << endl;
+ values << Byte('x') << Long(123456789123456789) << Symbol("bar");
+ print(values);
+ values.rewind();
+ // Check that we encoded the correct types, but note that decoding will
+ // still convert to standard C++ types, in particular any AMQP integer type
+ // can be converted to a long-enough C++ integer type..
+ int64_t i1, i2;
+ std::string s;
+ values >> i1 >> i2 >> s;
+ cout << "Extracted (with conversion) " << i1 << ", " << i2 << ", " << s << endl;
+
+ // Now use the as() function to fail unless we extract the exact AMQP type expected.
+ values.rewind(); // Byte(1) << Long(2) << Symbol("bar");
+ Long l;
+ // Fails, extracting Byte as Long
+ try { values >> as<LONG>(l); throw logic_error("expected error"); } catch (Decoder::Error) {}
+ Byte b;
+ values >> as<BYTE>(b) >> as<LONG>(l); // OK, extract Byte as Byte, Long as Long.
+ std::string str;
+ // Fails, extracting Symbol as String.
+ try { values >> as<STRING>(str); throw logic_error("expected error"); } catch (Decoder::Error) {}
+ values >> as<SYMBOL>(str); // OK, extract Symbol as Symbol
+ cout << "Extracted (exact) " << b << ", " << l << ", " << str << endl;
+}
+
+// Some helper templates to print map and vector results.
+namespace std {
+template<class T, class U> ostream& operator<<(ostream& o, const pair<T,U>& p) {
+ return o << p.first << ":" << p.second;
+}
+template<class T> ostream& operator<<(ostream& o, const vector<T>& v) {
+ o << "[ ";
+ ostream_iterator<T> oi(o, " ");
+ copy(v.begin(), v.end(), oi);
+ return o << "]";
+}
+template<class K, class T> ostream& operator<<(ostream& o, const map<K, T>& m) {
+ o << "{ ";
+ ostream_iterator<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;
+
+ 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;
+
+ Values values;
+ values << as<ARRAY>(a) << as<LIST>(l) << as<MAP>(m);
+ print(values);
+
+ vector<int> a1, l1;
+ map<string, int> m1;
+ values.rewind();
+ values >> as<ARRAY>(a1) >> as<LIST>(l1) >> as<MAP>(m1);
+ cout << "Extracted: " << a1 << ", " << l1 << ", " << m1 << endl;
+}
+
+// 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<Value> l;
+ l.push_back(Value(42));
+ l.push_back(Value(String("foo")));
+ map<Value, Value> m;
+ m[Value("five")] = Value(5);
+ m[Value(4)] = Value("four");
+ Values values;
+ values << as<LIST>(l) << as<MAP>(m);
+ print(values);
+
+ vector<Value> l1;
+ map<Value, Value> m1;
+ values.rewind();
+ values >> as<LIST>(l1) >> as<MAP>(m1);
+ cout << "Extracted: " << l1 << ", " << m1 << endl;
+}
+
+// Insert using stream operators (see printNext for example of extracting with stream ops.)
+void insert_extract_stream_operators() {
+ cout << endl << "== Insert with stream operators." << endl;
+ Values values;
+ // 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 values.encode() is called.
+ values << Start::array(INT) << Int(1) << Int(2) << Int(3) << finish();
+ print(values);
+
+ values.clear();
+ values << Start::list() << Int(42) << false << Symbol("x") << finish();
+ print(values);
+
+ values.clear();
+ values << Start::map() << "k1" << Int(42) << Symbol("k2") << false << finish();
+ print(values);
+}
+
+int main(int, char**) {
+ try {
+ simple_insert_extract();
+ simple_insert_extract_exact_type();
+ insert_extract_containers();
+ mixed_containers();
+ insert_extract_stream_operators();
+ } catch (const exception& e) {
+ cerr << endl << "error: " << e.what() << endl;
+ return 1;
+ }
+}
+
+// printNext prints the next value from Values by recursively descending into complex values.
+//
+// NOTE this is for example puroses only: There is a built in ostream operator<< for Values.
+//
+//
+void printNext(Values& values) {
+ TypeId type = values.type();
+ Start start;
+ switch (type) {
+ case ARRAY: {
+ values >> start;
+ cout << "array<" << start.element;
+ if (start.isDescribed) {
+ cout << ", descriptor=";
+ printNext(values);
+ }
+ cout << ">[";
+ for (size_t i = 0; i < start.size; ++i) {
+ if (i) cout << ", ";
+ printNext(values);
+ }
+ cout << "]";
+ values >> finish();
+ break;
+ }
+ case LIST: {
+ values >> start;
+ cout << "list[";
+ for (size_t i = 0; i < start.size; ++i) {
+ if (i) cout << ", ";
+ printNext(values);
+ }
+ cout << "]";
+ values >> finish();
+ break;
+ }
+ case MAP: {
+ values >> start;
+ cout << "map{";
+ for (size_t i = 0; i < start.size/2; ++i) {
+ if (i) cout << ", ";
+ printNext(values);
+ cout << ":"; // key:value
+ printNext(values);
+ }
+ cout << "}";
+ values >> finish();
+ break;
+ }
+ case DESCRIBED: {
+ values >> start;
+ cout << "described(";
+ printNext(values); // Descriptor
+ printNext(values); // Value
+ values >> finish();
+ break;
+ }
+ default:
+ // A simple type. We could continue the switch for all AMQP types but
+ // instead we us the `Value` type which can hold and print any AMQP
+ // value.
+ Value v;
+ values >> v;
+ cout << type << "(" << v << ")";
+ }
+}
+
+// Print all the values with printNext
+void print(Values& values) {
+ values.rewind();
+ cout << "Values: ";
+ while (values.more()) {
+ printNext(values);
+ if (values.more()) cout << ", ";
+ }
+ cout << endl;
+}
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/693752d3/examples/cpp/example_test.py
----------------------------------------------------------------------
diff --git a/examples/cpp/example_test.py b/examples/cpp/example_test.py
index 9a8ac67..3da1ddb 100644
--- a/examples/cpp/example_test.py
+++ b/examples/cpp/example_test.py
@@ -20,7 +20,7 @@
import unittest
import os, sys, socket, time
from random import randrange
-from subprocess import Popen, check_output, PIPE
+from subprocess import Popen, check_output, PIPE, STDOUT
NULL = open(os.devnull, 'w')
@@ -58,7 +58,7 @@ class Broker(object):
class ExampleTest(unittest.TestCase):
- """Test examples"""
+ """Run the examples, verify they behave as expected."""
@classmethod
def tearDownClass(self):
@@ -89,6 +89,8 @@ class ExampleTest(unittest.TestCase):
recv_expect += "".join(['[%d]: b"some arbitrary binary data"\n' % (i+1) for i in range(n)])
self.assertEqual(recv_expect, recv)
+ # FIXME aconway 2015-06-16: bug when receiver is started before sender, messages
+ # are not delivered to receiver.
def FIXME_test_simple_recv_send(self):
"""Start receiver first, then run sender"""
b = Broker.get()
@@ -101,5 +103,40 @@ class ExampleTest(unittest.TestCase):
out, err = recv.communicate()
self.assertEqual(recv_expect, out)
+ def call(self, *cmd):
+ p = Popen(cmd, stdout=PIPE, stderr=STDOUT)
+ out, err = p.communicate()
+ self.assertEqual(0, p.returncode,
+ "%s exit code %s, output:\n%s\n---- end of %s exit code %s" % (
+ cmd, p.returncode, out, cmd, p.returncode))
+ return out
+
+ def test_encode_decode(self):
+ expect="""
+== Simple values: int, string, bool
+Values: int(42), string("foo"), bool(true)
+Extracted: 42, foo, 1
+Encoded as AMQP in 8 bytes
+
+== Specific AMQP types: byte, long, symbol
+Values: byte(120), long(123456789123456789), symbol(:bar)
+Extracted (with conversion) 120, 123456789123456789, bar
+Extracted (exact) x, 123456789123456789, bar
+
+== 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 }
+
+== 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 }
+
+== Insert with stream operators.
+Values: array<int>[int(1), int(2), int(3)]
+Values: list[int(42), bool(false), symbol(:x)]
+Values: map{string("k1"):int(42), symbol(:"k2"):bool(false)}
+"""
+ self.maxDiff = None
+ self.assertMultiLineEqual(expect, self.call("./encode_decode"))
if __name__ == "__main__":
unittest.main()
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/693752d3/examples/cpp/simple_recv.cpp
----------------------------------------------------------------------
diff --git a/examples/cpp/simple_recv.cpp b/examples/cpp/simple_recv.cpp
index 42c561b..6612b16 100644
--- a/examples/cpp/simple_recv.cpp
+++ b/examples/cpp/simple_recv.cpp
@@ -46,7 +46,7 @@ class Recv : public MessagingHandler {
}
void onMessage(Event &e) {
- uint64_t id = 0;
+ int64_t id = 0;
Message msg = e.getMessage();
if (msg.getIdType() == PN_ULONG) {
id = msg.getId();
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/693752d3/proton-c/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/proton-c/CMakeLists.txt b/proton-c/CMakeLists.txt
index 049755e..9276a74 100644
--- a/proton-c/CMakeLists.txt
+++ b/proton-c/CMakeLists.txt
@@ -213,6 +213,8 @@ if (CMAKE_COMPILER_IS_GNUCC)
set (WERROR "-Werror")
endif (ENABLE_WARNING_ERROR)
set (COMPILE_WARNING_FLAGS "${WERROR} -Wall -pedantic-errors")
+ # C++ allow "%z" format specifier and variadic macros
+ set (CXX_WARNING_FLAGS "${COMPILE_WARNING_FLAGS} -Wno-format -Wno-variadic-macros" CACHE STRING "C++ warning flags")
if (NOT BUILD_WITH_CXX)
set (COMPILE_WARNING_FLAGS "${COMPILE_WARNING_FLAGS} -Wstrict-prototypes")
set (COMPILE_LANGUAGE_FLAGS "-std=c99")
@@ -227,8 +229,7 @@ if (CMAKE_COMPILER_IS_GNUCC)
set (COMPILE_WARNING_FLAGS "${COMPILE_WARNING_FLAGS} -Wc++-compat -Wvla -Wsign-compare -Wwrite-strings")
endif (${GCC_VERSION} VERSION_LESS "4.3.0")
else (NOT BUILD_WITH_CXX)
- # allow "%z" format specifier and variadic macros
- set (COMPILE_WARNING_FLAGS "${COMPILE_WARNING_FLAGS} -Wno-format -Wno-variadic-macros")
+ set (COMPILE_WARNING_FLAGS "${CXX_WARNING_FLAGS}")
endif (NOT BUILD_WITH_CXX)
if (ENABLE_UNDEFINED_ERROR)
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/693752d3/proton-c/bindings/cpp/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/CMakeLists.txt b/proton-c/bindings/cpp/CMakeLists.txt
index cc1c74a..18533ec 100644
--- a/proton-c/bindings/cpp/CMakeLists.txt
+++ b/proton-c/bindings/cpp/CMakeLists.txt
@@ -22,8 +22,7 @@
include_directories ("${CMAKE_CURRENT_SOURCE_DIR}/src")
include_directories ("${CMAKE_CURRENT_SOURCE_DIR}/include")
-add_library (
- qpid-proton-cpp SHARED
+set(qpid-proton-cpp-source
src/Acceptor.cpp
src/Acking.cpp
src/Connection.cpp
@@ -54,6 +53,7 @@ add_library (
src/Transport.cpp
src/Url.cpp
src/Value.cpp
+ src/Values.cpp
src/proton_bits.cpp
src/blocking/BlockingConnection.cpp
src/blocking/BlockingConnectionImpl.cpp
@@ -63,6 +63,10 @@ add_library (
src/types.cpp
)
+set_source_files_properties(${qpid-proton-cpp-source} PROPERTIES COMPILE_FLAGS "${CXX_WARNING_FLAGS}")
+
+add_library(qpid-proton-cpp SHARED ${qpid-proton-cpp-source})
+
target_link_libraries (qpid-proton-cpp ${PLATFORM_LIBS} qpid-proton)
set_target_properties (
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/693752d3/proton-c/bindings/cpp/include/proton/cpp/Data.h
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/cpp/Data.h b/proton-c/bindings/cpp/include/proton/cpp/Data.h
index 2204e8f..ef78a13 100644
--- a/proton-c/bindings/cpp/include/proton/cpp/Data.h
+++ b/proton-c/bindings/cpp/include/proton/cpp/Data.h
@@ -22,6 +22,10 @@
#include "proton/cpp/ImportExport.h"
#include <iosfwd>
+/**@file
+ * Base for classes that hold AMQP data.
+ * @internal
+ */
struct pn_data_t;
namespace proton {
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/693752d3/proton-c/bindings/cpp/include/proton/cpp/Decoder.h
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/cpp/Decoder.h b/proton-c/bindings/cpp/include/proton/cpp/Decoder.h
index 542315e..9b6df6e 100644
--- a/proton-c/bindings/cpp/include/proton/cpp/Decoder.h
+++ b/proton-c/bindings/cpp/include/proton/cpp/Decoder.h
@@ -29,43 +29,40 @@ namespace reactor {
class Value;
+/**@file
+ * Stream-like decoder from AMQP bytes to C++ values.
+ * @ingroup cpp
+ */
+
/**
+@ingroup cpp
+
Stream-like decoder from AMQP bytes to a stream of C++ values.
-@see types.h defines C++ typedefs and types for AMQP each type. These types can
-all be extracted from the corresponding AMQP type. In additon operator>> will do
-the following conversions from AMQP to C++ types:
-
-+-----------------------------------------+--------------------------------------------------+
-|Target C++ type |Allowed AMQP types |
-+=========================================+==================================================+
-|bool |Bool |
-|-----------------------------------------+--------------------------------------------------|
-|signed integer type |Byte,Short,Int,Long [1] |
-+-----------------------------------------+--------------------------------------------------+
-|unsigned integer type |UByte,UShort,UInt,ULong [1] |
-+-----------------------------------------+--------------------------------------------------+
-|float or double |Float or Double |
-+-----------------------------------------+--------------------------------------------------+
-|Value |Any type |
-+-----------------------------------------+--------------------------------------------------+
-|std::string |String, Binary, Symbol |
-+-----------------------------------------+--------------------------------------------------+
-|wchar_t |Char |
-+-----------------------------------------+--------------------------------------------------+
-|std::map<K, T> |Map with keys that convert to K and data that |
-| |converts to T |
-+-----------------------------------------+--------------------------------------------------+
-|Map |Map may have mixed keys and data types |
-+-----------------------------------------+--------------------------------------------------+
-|std::vector<T> |List or Array if data converts to T |
-+-----------------------------------------+--------------------------------------------------+
-|List |List, may have mixed types and datas |
-+-----------------------------------------+--------------------------------------------------+
-
-You can disable conversions and force an exact type match using @see exact()
+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.
+
+ 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<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 perserve order when
+extracting AMQP maps.
+
+You can also extract container values element-by-element, see the Start class.
*/
-class Decoder : public virtual Data {
+PN_CPP_EXTERN class Decoder : public virtual Data {
public:
/** Raised if a Decoder operation fails */
struct Error : public ProtonException {
@@ -95,10 +92,12 @@ class Decoder : public virtual Data {
*/
PN_CPP_EXTERN TypeId type() const;
- /** @defgroup decoder_simple_types Extract simple types, @see Decoder for details.
- *@throw Error if the Decoder is empty or the current value has an incompatible type.
- *@{
+ /** @name Extract simple types
+ * Overloads to extract simple types.
+ * @throw Error if the Decoder is empty or the current value has an incompatible type.
+ * @{
*/
+ PN_CPP_EXTERN friend Decoder& operator>>(Decoder&, Null);
PN_CPP_EXTERN friend Decoder& operator>>(Decoder&, Bool&);
PN_CPP_EXTERN friend Decoder& operator>>(Decoder&, Ubyte&);
PN_CPP_EXTERN friend Decoder& operator>>(Decoder&, Byte&);
@@ -120,14 +119,59 @@ class Decoder : public virtual Data {
PN_CPP_EXTERN friend Decoder& operator>>(Decoder&, Value&);
///@}
- ///@internal
- template <class T> struct ExactRef { T& value; ExactRef(T& ref) : value(ref) {} };
+ /** 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, TypeId A> T getAs() { T value; *this >> as<A>(value); return value; }
- /** @see exact() */
- template <class T> friend Decoder& operator>>(Decoder&, ExactRef<T>);
+ /** Call Decoder::start() in constructor, Decoder::finish in destructor() */
+ struct Scope : public Start {
+ Decoder& decoder;
+ Scope(Decoder& d) : decoder(d) { d >> *this; }
+ ~Scope() { decoder >> finish(); }
+ };
+
+ template <TypeId A, class T> friend Decoder& operator>>(Decoder& d, Ref<T, A> ref) {
+ d.checkType(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;
+ * // 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();
+ *
+ * The first value of an ARRAY is a descriptor if Start::descriptor is true,
+ * followed by Start::size elemets of type Start::element.
+ *
+ * A LIST has Start::size elements which may be of mixed type.
+ *
+ * A MAP has Start::size elements which alternate key, value, key, value...
+ * and may be of mixed type.
+ *
+ * A DESCRIBED contains a descriptor and a single element, so it always has
+ * Start::described=true and Start::size=1.
+ *
+ * Note Scope automatically calls finish() in its destructor.
+ *
+ *@throw decoder::error if the curent value is not a container type.
+ */
+ PN_CPP_EXTERN friend Decoder& operator>>(Decoder&, Start&);
+
+ /** Finish extracting a container value. */
+ PN_CPP_EXTERN friend Decoder& operator>>(Decoder&, Finish);
+
+ /** Skip a value */
+ PN_CPP_EXTERN friend Decoder& operator>>(Decoder&, Skip);
private:
- PN_CPP_EXTERN Decoder(pn_data_t*);
template <class T> Decoder& extract(T& value);
void checkType(TypeId);
@@ -139,26 +183,36 @@ class Decoder : public virtual Data {
friend class Encoder;
};
-/**
- * exact() disables the conversions allowed by Decoder operator>> and requires exact type match.
- *
- * For example the following will throw Decode::Error unless decoder conntains
- * an AMQP bool and an AMQP ULong.
- *
- * @code
- * Bool b;
- * ULong ul;
- * decoder >> exact(b) >> exact(ul)
- * @code
- */
-template <class T> Decoder::ExactRef<T> exact(T& value) {
- return Decoder::ExactRef<T>(value);
+template <class T> Decoder& operator>>(Decoder& d, Ref<T, ARRAY> ref) {
+ Decoder::Scope s(d);
+ if (s.isDescribed) d >> skip();
+ ref.value.clear();
+ ref.value.resize(s.size);
+ for (typename T::iterator i = ref.value.begin(); i != ref.value.end(); ++i) {
+ d >> *i;
+ }
+ return d;
+}
+
+template <class T> Decoder& operator>>(Decoder& d, Ref<T, LIST> 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;
+ return d;
}
-///@see exact()
-template <class T> Decoder& operator>>(Decoder& d, Decoder::ExactRef<T> ref) {
- d.checkType(TypeIdOf<T>::value);
- d >> ref.value;
+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;
+ }
+ return d;
}
}} // namespace proton::reactor
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/693752d3/proton-c/bindings/cpp/include/proton/cpp/Duration.h
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/cpp/Duration.h b/proton-c/bindings/cpp/include/proton/cpp/Duration.h
index 08aaf3f..bb2a063 100644
--- a/proton-c/bindings/cpp/include/proton/cpp/Duration.h
+++ b/proton-c/bindings/cpp/include/proton/cpp/Duration.h
@@ -28,7 +28,7 @@
namespace proton {
namespace reactor {
-/** \ingroup C++
+/** @ingroup cpp
* A duration is a time in milliseconds.
*/
class Duration
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/693752d3/proton-c/bindings/cpp/include/proton/cpp/Encoder.h
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/cpp/Encoder.h b/proton-c/bindings/cpp/include/proton/cpp/Encoder.h
index 460bea4..8e92881 100644
--- a/proton-c/bindings/cpp/include/proton/cpp/Encoder.h
+++ b/proton-c/bindings/cpp/include/proton/cpp/Encoder.h
@@ -31,13 +31,28 @@ namespace reactor {
class Value;
+/**@file
+ * Stream-like encoder from C++ values to AMQP bytes.
+ * @ingroup cpp
+*/
+
/**
-Stream-like encoder from C++ values to AMQP bytes.
+@ingroup cpp
-@see types.h defines C++ typedefs and types for AMQP each type. These types
+types.h defines C++ typedefs and types for AMQP each type. These types
insert as the corresponding AMQP type. Normal C++ conversion rules apply if you
insert any other type.
+C++ containers can be inserted as AMQP containers with the as() helper functions. E.g.
+
+ std::vector<Symbol> v; encoder << as<List>(v);
+
+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 perserve order when
+extracting AMQP maps.
+
+You can also insert containers element-by-element, see the Start class.
*/
class Encoder : public virtual Data {
public:
@@ -68,9 +83,10 @@ class Encoder : public virtual Data {
/** Encode the current values into a std::string. Clears the encoder. */
PN_CPP_EXTERN std::string encode();
- /** @defgroup encoder_simple_types Insert simple types.
+ /** @name Insert simple types.
*@{
*/
+ PN_CPP_EXTERN friend Encoder& operator<<(Encoder&, Null);
PN_CPP_EXTERN friend Encoder& operator<<(Encoder&, Bool);
PN_CPP_EXTERN friend Encoder& operator<<(Encoder&, Ubyte);
PN_CPP_EXTERN friend Encoder& operator<<(Encoder&, Byte);
@@ -94,8 +110,25 @@ class Encoder : public virtual Data {
PN_CPP_EXTERN friend Encoder& operator<<(Encoder&, const Value&);
///@}
+ /** Start a container type. See the Start class. */
+ PN_CPP_EXTERN friend Encoder& operator<<(Encoder&, const Start&);
+
+ /** Finish a container type. */
+ PN_CPP_EXTERN friend Encoder& operator<<(Encoder& e, Finish);
+
+
+ /**@name Insert values returned by the as<TypeId> helper.
+ *@{
+ */
+ template <class T, TypeId A> friend Encoder& operator<<(Encoder&, CRef<T, A>);
+ template <class T> friend Encoder& operator<<(Encoder&, CRef<T, ARRAY>);
+ template <class T> friend Encoder& operator<<(Encoder&, CRef<T, LIST>);
+ template <class T> friend Encoder& operator<<(Encoder&, CRef<T, MAP>);
+ // TODO aconway 2015-06-16: DESCRIBED.
+ ///@}
+
private:
- PN_CPP_EXTERN Encoder(pn_data_t* pd); // Does not own.
+ PN_CPP_EXTERN Encoder(pn_data_t* pd);
// Not implemented
Encoder(const Encoder&);
@@ -104,5 +137,48 @@ class Encoder : public virtual Data {
friend class Value;
};
+/** Encode const char* as string */
+inline Encoder& operator<<(Encoder& e, const char* s) { return e << String(s); }
+
+/** Encode char* as string */
+inline Encoder& operator<<(Encoder& e, char* s) { return e << String(s); }
+
+/** Encode std::string as string */
+inline Encoder& operator<<(Encoder& e, const std::string& s) { return e << String(s); }
+
+//@internal Convert a Ref to a CRef.
+template <class T, TypeId A> Encoder& operator<<(Encoder& e, Ref<T, A> ref) {
+ return e << CRef<T,A>(ref);
+}
+
+// TODO aconway 2015-06-16: described array insertion.
+
+template <class T> Encoder& operator<<(Encoder& e, CRef<T, ARRAY> a) {
+ e << Start::array(TypeIdOf<typename T::value_type>::value);
+ for (typename T::const_iterator i = a.value.begin(); i != a.value.end(); ++i)
+ e << *i;
+ e << finish();
+ return e;
+}
+
+template <class T> Encoder& operator<<(Encoder& e, CRef<T, LIST> l) {
+ e << Start::list();
+ for (typename T::const_iterator i = l.value.begin(); i != l.value.end(); ++i)
+ e << *i;
+ e << finish();
+ return e;
+}
+
+template <class T> Encoder& operator<<(Encoder& e, CRef<T, MAP> m){
+ e << Start::map();
+ for (typename T::const_iterator i = m.value.begin(); i != m.value.end(); ++i) {
+ e << i->first;
+ e << i->second;
+ }
+ e << finish();
+ return e;
+}
+
+
}}
#endif // ENCODER_H
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/693752d3/proton-c/bindings/cpp/include/proton/cpp/Exception.h
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/cpp/Exception.h b/proton-c/bindings/cpp/include/proton/cpp/Exception.h
deleted file mode 100644
index d24c8ef..0000000
--- a/proton-c/bindings/cpp/include/proton/cpp/Exception.h
+++ /dev/null
@@ -1,49 +0,0 @@
-#ifndef PROTON_CPP_EXCEPTIONS_H
-#define PROTON_CPP_EXCEPTIONS_H
-
-/*
- *
- * 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 <stdexcept>
-
-namespace proton {
-namespace reactor {
-
-class Exception : public std::runtime_error
-{
- public:
- explicit Exception(const std::string& msg) throw() : std::runtime_error(msg) {}
-};
-
-class MessageReject : public Exception
-{
- public:
- explicit MessageReject(const std::string& msg) throw() : Exception(msg) {}
-};
-
-class MessageRelease : public Exception
-{
- public:
- explicit MessageRelease(const std::string& msg) throw() : Exception(msg) {}
-};
-
-}} // namespace proton::reactor
-
-#endif /*!PROTON_CPP_EXCEPTIONS_H*/
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/693752d3/proton-c/bindings/cpp/include/proton/cpp/MessagingHandler.h
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/cpp/MessagingHandler.h b/proton-c/bindings/cpp/include/proton/cpp/MessagingHandler.h
index e6c0341..07b0dde 100644
--- a/proton-c/bindings/cpp/include/proton/cpp/MessagingHandler.h
+++ b/proton-c/bindings/cpp/include/proton/cpp/MessagingHandler.h
@@ -78,8 +78,8 @@ class PN_CPP_EXTERN MessagingHandler : public ProtonHandler , public Acking
virtual void onTransportClosed(Event &e);
protected:
int prefetch;
- bool autoSettle;
bool autoAccept;
+ bool autoSettle;
bool peerCloseIsError;
MessagingAdapter *messagingAdapter;
Handler *flowController;
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/693752d3/proton-c/bindings/cpp/include/proton/cpp/Value.h
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/cpp/Value.h b/proton-c/bindings/cpp/include/proton/cpp/Value.h
index 65ca7ec..9555f29 100644
--- a/proton-c/bindings/cpp/include/proton/cpp/Value.h
+++ b/proton-c/bindings/cpp/include/proton/cpp/Value.h
@@ -19,66 +19,61 @@
* under the License.
*/
-#include "proton/cpp/Encoder.h"
-#include "proton/cpp/Decoder.h"
-#include <iosfwd>
+#include "proton/cpp/Values.h"
+/**@file
+ * Holder for an AMQP value.
+ * @ingroup cpp
+ */
namespace proton {
namespace reactor {
-/** Holds a sequence of AMQP values, allows inserting and extracting.
- *
- * After inserting values, call rewind() to extract them.
- */
-class Values : public Encoder, public Decoder {
- public:
- Values();
- Values(const Values&);
- ~Values();
-
- /** Copy data from another Values */
- Values& operator=(const Values&);
-
- PN_CPP_EXTERN void rewind();
-
- private:
- friend class Value;
-};
-
/** Holds a single AMQP value. */
-class Value {
+PN_CPP_EXTERN class Value {
public:
PN_CPP_EXTERN Value();
PN_CPP_EXTERN Value(const Value&);
+ /** Converting constructor from any settable value */
+ template <class T> explicit Value(const T& v);
PN_CPP_EXTERN ~Value();
-
PN_CPP_EXTERN Value& operator=(const Value&);
+
TypeId type() const;
- /** Set the value */
+ /** Set the value. */
template<class T> void set(const T& value);
- /** Get the value */
+ /** Get the value. */
template<class T> void get(T& value) const;
/** Get the value */
template<class T> T get() const;
/** Assignment sets the value */
template<class T> Value& operator=(const T& value);
+
/** Conversion operator gets the value */
template<class T> operator T() const;
- /** Insert a value into an Encoder. */
+ /** insert a value into an Encoder. */
PN_CPP_EXTERN friend Encoder& operator<<(Encoder&, const Value&);
/** Extract a value from a decoder. */
- PN_CPP_EXTERN friend Decoder& operator>>(Decoder&, const Value&);
+ PN_CPP_EXTERN friend Decoder& operator>>(Decoder&, Value&);
+
+ /** Human readable format */
+ PN_CPP_EXTERN friend std::ostream& operator<<(std::ostream&, const Value&);
- friend Decoder& operator>>(Decoder&, Value&);
- friend Encoder& operator<<(Encoder&, const Value&);
+ bool operator==(const Value&) const;
+ bool operator !=(const Value& v) const{ return !(*this == v); }
- private:
- Values values;
+ /** operator < makes Value valid for use as a std::map key. */
+ bool operator<(const Value&) const;
+ bool operator>(const Value& v) const { return v < *this; }
+ bool operator<=(const Value& v) const { return !(*this > v); }
+ bool operator>=(const Value& v) const { return !(*this < v); }
+
+ private:
+ mutable Values values;
};
template<class T> void Value::set(const T& value) {
@@ -88,8 +83,7 @@ template<class T> void Value::set(const T& value) {
template<class T> void Value::get(T& value) const {
Values& v = const_cast<Values&>(values);
- v.rewind();
- v >> value;
+ v.rewind() >> value;
}
template<class T> T Value::get() const { T value; get(value); return value; }
@@ -98,6 +92,7 @@ template<class T> Value& Value::operator=(const T& value) { set(value); return *
template<class T> Value::operator T() const { return get<T>(); }
+template<class T> Value::Value(const T& value) { set(value); }
}}
#endif // VALUE_H
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/693752d3/proton-c/bindings/cpp/include/proton/cpp/Values.h
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/cpp/Values.h b/proton-c/bindings/cpp/include/proton/cpp/Values.h
new file mode 100644
index 0000000..5f62dd9
--- /dev/null
+++ b/proton-c/bindings/cpp/include/proton/cpp/Values.h
@@ -0,0 +1,56 @@
+#ifndef VALUES_H
+#define VALUES_H
+/*
+ * 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/cpp/Encoder.h>
+#include <proton/cpp/Decoder.h>
+
+/**@file
+ * Holder for a sequence of AMQP values.
+ * @ingroup cpp
+ */
+
+namespace proton {
+namespace reactor {
+
+/** Holds a sequence of AMQP values, allows inserting and extracting.
+ *
+ * After inserting values, call rewind() to extract them.
+ */
+PN_CPP_EXTERN class Values : public Encoder, public Decoder {
+ public:
+ Values();
+ Values(const Values&);
+ ~Values();
+
+ /** Copy data from another Values */
+ Values& operator=(const Values&);
+
+ PN_CPP_EXTERN Values& rewind();
+
+ private:
+ friend class Value;
+};
+
+PN_CPP_EXTERN std::ostream& operator<<(std::ostream&, const Values&);
+
+}}
+
+#endif // VALUES_H
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/693752d3/proton-c/bindings/cpp/include/proton/cpp/types.h
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/cpp/types.h b/proton-c/bindings/cpp/include/proton/cpp/types.h
index 963a330..edd95b9 100644
--- a/proton-c/bindings/cpp/include/proton/cpp/types.h
+++ b/proton-c/bindings/cpp/include/proton/cpp/types.h
@@ -19,61 +19,68 @@
* under the License.
*/
+#include <proton/codec.h>
+#include "proton/cpp/ImportExport.h"
+#include <algorithm>
+#include <bitset>
#include <string>
#include <stdint.h>
-#include <proton/codec.h>
-
-namespace proton {
-namespace reactor {
+#include <memory.h>
/**@file
- *
- * C++ types representing simple AMQP types.
- *
+ * C++ types representing AMQP types.
+ * @ingroup cpp
*/
+namespace proton {
+namespace reactor {
-/** Convert pn_bytes_t to string */
-std::string str(const pn_bytes_t&);
-
-/** Convert string to pn_bytes_t */
-pn_bytes_t bytes(const std::string&);
-
-/** Identifies an AMQP type */
+/** TypeId identifies an AMQP type */
enum TypeId {
- NULL_=PN_NULL,
- BOOL=PN_BOOL,
- UBYTE=PN_UBYTE,
- BYTE=PN_BYTE,
- USHORT=PN_USHORT,
- SHORT=PN_SHORT,
- UINT=PN_UINT,
- INT=PN_INT,
- CHAR=PN_CHAR,
- ULONG=PN_ULONG,
- LONG=PN_LONG,
- TIMESTAMP=PN_TIMESTAMP,
- FLOAT=PN_FLOAT,
- DOUBLE=PN_DOUBLE,
- DECIMAL32=PN_DECIMAL32,
- DECIMAL64=PN_DECIMAL64,
- DECIMAL128=PN_DECIMAL128,
- UUID=PN_UUID,
- BINARY=PN_BINARY,
- STRING=PN_STRING,
- SYMBOL=PN_SYMBOL,
- DESCRIBED=PN_DESCRIBED,
- ARRAY=PN_ARRAY,
- LIST=PN_LIST,
- MAP=PN_MAP
+ NULL_=PN_NULL, ///< The null type, contains no data.
+ BOOL=PN_BOOL, ///< Boolean true or false.
+ UBYTE=PN_UBYTE, ///< Unsigned 8 bit integer.
+ BYTE=PN_BYTE, ///< Signed 8 bit integer.
+ USHORT=PN_USHORT, ///< Unsigned 16 bit integer.
+ SHORT=PN_SHORT, ///< Signed 16 bit integer.
+ UINT=PN_UINT, ///< Unsigned 32 bit integer.
+ INT=PN_INT, ///< Signed 32 bit integer.
+ CHAR=PN_CHAR, ///< 32 bit unicode character.
+ ULONG=PN_ULONG, ///< Unsigned 64 bit integer.
+ LONG=PN_LONG, ///< Signed 64 bit integer.
+ TIMESTAMP=PN_TIMESTAMP, ///< Signed 64 bit milliseconds since the epoch.
+ FLOAT=PN_FLOAT, ///< 32 bit binary floating point.
+ DOUBLE=PN_DOUBLE, ///< 64 bit binary floating point.
+ DECIMAL32=PN_DECIMAL32, ///< 32 bit decimal floating point.
+ DECIMAL64=PN_DECIMAL64, ///< 64 bit decimal floating point.
+ DECIMAL128=PN_DECIMAL128, ///< 128 bit decimal floating point.
+ UUID=PN_UUID, ///< 16 byte UUID.
+ BINARY=PN_BINARY, ///< Variable length sequence of bytes.
+ STRING=PN_STRING, ///< Variable length utf8-encoded string.
+ SYMBOL=PN_SYMBOL, ///< Variable length encoded string.
+ DESCRIBED=PN_DESCRIBED, ///< A descriptor and a value.
+ ARRAY=PN_ARRAY, ///< A sequence of values of the same type.
+ LIST=PN_LIST, ///< A sequence of values, may be of mixed types.
+ MAP=PN_MAP ///< A sequence of key:value pairs, may be of mixed types.
};
-/** @defgroup types C++ type definitions for AMQP types.
- *
+///@internal
+template <class T> struct Comparable {};
+template<class T> bool operator<(const Comparable<T>& a, const Comparable<T>& b) {
+ return static_cast<const T&>(a) < static_cast<const T&>(b); // operator < provided by type T
+}
+template<class T> bool operator>(const Comparable<T>& a, const Comparable<T>& b) { return b < a; }
+template<class T> bool operator<=(const Comparable<T>& a, const Comparable<T>& b) { return !(a > b); }
+template<class T> bool operator>=(const Comparable<T>& a, const Comparable<T>& b) { return !(a < b); }
+template<class T> bool operator==(const Comparable<T>& a, const Comparable<T>& b) { return a <= b && b <= a; }
+template<class T> bool operator!=(const Comparable<T>& a, const Comparable<T>& b) { return !(a == b); }
+
+/**
+ * @name C++ types representing AMQP types.
+ * @{
+ * @ingroup cpp
* These types are all distinct for overloading purposes and will insert as the
* corresponding AMQP type with Encoder operator<<.
- *
- * @{
*/
struct Null {};
typedef bool Bool;
@@ -90,11 +97,14 @@ typedef float Float;
typedef double Double;
///@internal
+pn_bytes_t pn_bytes(const std::string&);
+
+///@internal
#define STRING_LIKE(NAME) \
- struct NAME : public std::string{ \
+ PN_CPP_EXTERN struct NAME : public std::string{ \
NAME(const std::string& s=std::string()) : std::string(s) {} \
- NAME(const pn_bytes_t& b) : std::string(str(b)) {} \
- operator pn_bytes_t() const { return bytes(*this); } \
+ NAME(const pn_bytes_t& b) : std::string(b.start, b.size) {} \
+ operator pn_bytes_t() const { return pn_bytes(*this); } \
}
/** UTF-8 encoded string */
@@ -104,58 +114,136 @@ STRING_LIKE(Symbol);
/** Binary data */
STRING_LIKE(Binary);
+///@internal
+pn_uuid_t pn_uuid(const std::string&);
+
+/** UUID is represented as a string but treated as if it always has 16 bytes. */
+PN_CPP_EXTERN struct Uuid : public std::string{
+ Uuid(const std::string& s=std::string()) : std::string(s) {}
+ Uuid(const pn_uuid_t& u) : std::string(&u.bytes[0], sizeof(pn_uuid_t::bytes)) {}
+ operator pn_uuid_t() const { return pn_uuid(*this); }
+};
+
// TODO aconway 2015-06-11: alternative representation of variable-length data
// as pointer to existing buffers.
-template <class T> struct Decimal {
- T value;
- Decimal(T v) : value(v) {}
- Decimal& operator=(T v) { value = v; }
- operator T() const { return value; }
+// TODO aconway 2015-06-16: usable representation of decimal types.
+template <class T> struct Decimal : public Comparable<Decimal<T> > {
+ char value[sizeof(T)];
+ Decimal() { ::memset(value, 0, sizeof(T)); }
+ Decimal(const T& v) { ::memcpy(value, &v, sizeof(T)); }
+ operator T() const { return *reinterpret_cast<const T*>(value); }
+ bool operator<(const Decimal<T>& x) {
+ return std::lexicographical_compare(value, value+sizeof(T), x.value, x.value+sizeof(T));
+ }
};
typedef Decimal<pn_decimal32_t> Decimal32;
typedef Decimal<pn_decimal64_t> Decimal64;
typedef Decimal<pn_decimal128_t> Decimal128;
-struct Timestamp {
+PN_CPP_EXTERN struct Timestamp {
pn_timestamp_t milliseconds; ///< Since the epoch 00:00:00 (UTC), 1 January 1970.
- Timestamp(int64_t ms) : milliseconds(ms) {}
+ Timestamp(int64_t ms=0) : milliseconds(ms) {}
operator pn_timestamp_t() const { return milliseconds; }
+ bool operator<(const Timestamp& x) { return milliseconds < x.milliseconds; }
};
-typedef pn_uuid_t Uuid;
-
///@}
-/** Meta-function to get the type-id from a class */
template <class T> struct TypeIdOf {};
-template<> struct TypeIdOf<Null> { static const TypeId value; };
-template<> struct TypeIdOf<Bool> { static const TypeId value; };
-template<> struct TypeIdOf<Ubyte> { static const TypeId value; };
-template<> struct TypeIdOf<Byte> { static const TypeId value; };
-template<> struct TypeIdOf<Ushort> { static const TypeId value; };
-template<> struct TypeIdOf<Short> { static const TypeId value; };
-template<> struct TypeIdOf<Uint> { static const TypeId value; };
-template<> struct TypeIdOf<Int> { static const TypeId value; };
-template<> struct TypeIdOf<Char> { static const TypeId value; };
-template<> struct TypeIdOf<Ulong> { static const TypeId value; };
-template<> struct TypeIdOf<Long> { static const TypeId value; };
-template<> struct TypeIdOf<Timestamp> { static const TypeId value; };
-template<> struct TypeIdOf<Float> { static const TypeId value; };
-template<> struct TypeIdOf<Double> { static const TypeId value; };
-template<> struct TypeIdOf<Decimal32> { static const TypeId value; };
-template<> struct TypeIdOf<Decimal64> { static const TypeId value; };
-template<> struct TypeIdOf<Decimal128> { static const TypeId value; };
-template<> struct TypeIdOf<Uuid> { static const TypeId value; };
-template<> struct TypeIdOf<Binary> { static const TypeId value; };
-template<> struct TypeIdOf<String> { static const TypeId value; };
-template<> struct TypeIdOf<Symbol> { static const TypeId value; };
+template<> struct TypeIdOf<Null> { static const TypeId value=NULL_; };
+template<> struct TypeIdOf<Bool> { static const TypeId value=BOOL; };
+template<> struct TypeIdOf<Ubyte> { static const TypeId value=UBYTE; };
+template<> struct TypeIdOf<Byte> { static const TypeId value=BYTE; };
+template<> struct TypeIdOf<Ushort> { static const TypeId value=USHORT; };
+template<> struct TypeIdOf<Short> { static const TypeId value=SHORT; };
+template<> struct TypeIdOf<Uint> { static const TypeId value=UINT; };
+template<> struct TypeIdOf<Int> { static const TypeId value=INT; };
+template<> struct TypeIdOf<Char> { static const TypeId value=CHAR; };
+template<> struct TypeIdOf<Ulong> { static const TypeId value=ULONG; };
+template<> struct TypeIdOf<Long> { static const TypeId value=LONG; };
+template<> struct TypeIdOf<Timestamp> { static const TypeId value=TIMESTAMP; };
+template<> struct TypeIdOf<Float> { static const TypeId value=FLOAT; };
+template<> struct TypeIdOf<Double> { static const TypeId value=DOUBLE; };
+template<> struct TypeIdOf<Decimal32> { static const TypeId value=DECIMAL32; };
+template<> struct TypeIdOf<Decimal64> { static const TypeId value=DECIMAL64; };
+template<> struct TypeIdOf<Decimal128> { static const TypeId value=DECIMAL128; };
+template<> struct TypeIdOf<Uuid> { static const TypeId value=UUID; };
+template<> struct TypeIdOf<Binary> { static const TypeId value=BINARY; };
+template<> struct TypeIdOf<String> { static const TypeId value=STRING; };
+template<> struct TypeIdOf<Symbol> { static const TypeId value=SYMBOL; };
+
+template<class T, TypeId A> struct TypePair {
+ typedef T CppType;
+ TypeId type;
+};
+
+template<class T, TypeId A> struct Ref : public TypePair<T, A> {
+ Ref(T& v) : value(v) {}
+ T& value;
+};
+
+template<class T, TypeId A> struct CRef : public TypePair<T, A> {
+ CRef(const T& v) : value(v) {}
+ CRef(const Ref<T,A>& ref) : value(ref.value) {}
+ const T& value;
+};
+
+/** Create a reference to value as AMQP type A for decoding. For example to decode an array of Int:
+ *
+ * std::vector<Int> v;
+ * decoder >> as<ARRAY>(v);
+ */
+template <TypeId 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. */
+template <TypeId A, class T> CRef<T, A> as(const T& value) { return CRef<T, A>(value); }
+
+///@}
+
+// TODO aconway 2015-06-16: described types.
/** Return the name of a type. */
-std::string typeName(TypeId);
+PN_CPP_EXTERN std::string typeName(TypeId);
+
+/** Print the name of a type */
+PN_CPP_EXTERN std::ostream& operator<<(std::ostream&, TypeId);
/** Return the name of a type from a class. */
-template<class T> std::string typeName() { return typeName(TypeIdOf<T>::value); }
+PN_CPP_EXTERN template<class T> std::string typeName() { return typeName(TypeIdOf<T>::value); }
+
+/** Information needed to start extracting or inserting a container type.
+ *
+ * With a decoder you can use `Start s = decoder.start()` or `Start s; decoder > s`
+ * to get the Start for the current container.
+ *
+ * With an encoder use one of the member functions startArray, startList, startMap or startDescribed
+ * to create an appropriate Start value, e.g. `encoder << startList() << ...`
+ */
+PN_CPP_EXTERN struct Start {
+ Start(TypeId type=NULL_, TypeId element=NULL_, bool described=false, size_t size=0);
+ TypeId type; ///< The container type: ARRAY, LIST, MAP or DESCRIBED.
+ TypeId element; ///< the element type for array only.
+ bool isDescribed; ///< true if first value is a descriptor.
+ size_t size; ///< the element count excluding the descriptor (if any)
+
+ /** Return a Start for an array */
+ static Start array(TypeId element, bool described=false);
+ /** Return a Start for a list */
+ static Start list();
+ /** Return a Start for a map */
+ static Start map();
+ /** Return a Start for a described type */
+ static Start described();
+};
+
+/** Finish insterting or extracting a container value. */
+PN_CPP_EXTERN struct Finish {};
+inline Finish finish() { return Finish(); }
+
+/** Skip a value */
+PN_CPP_EXTERN struct Skip{};
+inline Skip skip() { return Skip(); }
}}
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/693752d3/proton-c/bindings/cpp/src/ConnectionImpl.h
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/ConnectionImpl.h b/proton-c/bindings/cpp/src/ConnectionImpl.h
index 7add9a0..f16c862 100644
--- a/proton-c/bindings/cpp/src/ConnectionImpl.h
+++ b/proton-c/bindings/cpp/src/ConnectionImpl.h
@@ -41,7 +41,7 @@ class ConnectionImpl : public Endpoint
public:
PN_CPP_EXTERN ConnectionImpl(Container &c, pn_connection_t &pnConn);
PN_CPP_EXTERN ConnectionImpl(Container &c, Handler *h = 0);
- PN_CPP_EXTERN ~ConnectionImpl();
+ PN_CPP_EXTERN virtual ~ConnectionImpl();
PN_CPP_EXTERN Transport &getTransport();
PN_CPP_EXTERN Handler *getOverride();
PN_CPP_EXTERN void setOverride(Handler *h);
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/693752d3/proton-c/bindings/cpp/src/ContainerImpl.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/ContainerImpl.cpp b/proton-c/bindings/cpp/src/ContainerImpl.cpp
index 61fc860..989bd00 100644
--- a/proton-c/bindings/cpp/src/ContainerImpl.cpp
+++ b/proton-c/bindings/cpp/src/ContainerImpl.cpp
@@ -47,10 +47,6 @@ ConnectionImpl *getImpl(const Connection &c) {
return PrivateImplRef<Connection>::get(c);
}
-ContainerImpl *getImpl(const Container &c) {
- return PrivateImplRef<Container>::get(c);
-}
-
} // namespace
@@ -253,8 +249,6 @@ Sender ContainerImpl::createSender(Connection &connection, std::string &addr, Ha
pn_record_set_handler(record, wrapHandler(h));
}
snd.open();
-
- ConnectionImpl *connImpl = getImpl(connection);
return snd;
}
@@ -266,8 +260,6 @@ Sender ContainerImpl::createSender(std::string &urlString) {
Sender snd = session.createSender(containerId + '-' + path);
pn_terminus_set_address(pn_link_target(snd.getPnLink()), path.c_str());
snd.open();
-
- ConnectionImpl *connImpl = getImpl(conn);
return snd;
}
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/693752d3/proton-c/bindings/cpp/src/Data.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/Data.cpp b/proton-c/bindings/cpp/src/Data.cpp
index 6cfc09b..790cecb 100644
--- a/proton-c/bindings/cpp/src/Data.cpp
+++ b/proton-c/bindings/cpp/src/Data.cpp
@@ -41,8 +41,6 @@ void Data::clear() { pn_data_clear(data); }
bool Data::empty() const { return pn_data_size(data) == 0; }
-std::ostream& operator<<(std::ostream& o, const Data& d) {
- o << Object(d.data);
-}
+std::ostream& operator<<(std::ostream& o, const Data& d) { return o << Object(d.data); }
}} // namespace proton::reactor
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/693752d3/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 4170378..503db81 100644
--- a/proton-c/bindings/cpp/src/Decoder.cpp
+++ b/proton-c/bindings/cpp/src/Decoder.cpp
@@ -18,8 +18,10 @@
*/
#include "proton/cpp/Decoder.h"
+#include "proton/cpp/Value.h"
#include <proton/codec.h>
#include "proton_bits.h"
+#include "Msg.h"
namespace proton {
namespace reactor {
@@ -44,15 +46,28 @@ struct SaveState {
~SaveState() { if (data) pn_data_restore(data, handle); }
void cancel() { data = 0; }
};
+
+struct Narrow {
+ pn_data_t* data;
+ Narrow(pn_data_t* d) : data(d) { pn_data_narrow(d); }
+ ~Narrow() { pn_data_widen(data); }
+};
+
+template <class T> T check(T result) {
+ if (result < 0)
+ throw Decoder::Error("decode: " + errorStr(result));
+ return result;
+}
+
+std::string str(const pn_bytes_t& b) { return std::string(b.start, b.size); }
+
}
void Decoder::decode(const char* i, size_t size) {
SaveState ss(data);
const char* end = i + size;
while (i < end) {
- int result = pn_data_decode(data, i, end - i);
- if (result < 0) throw Decoder::Error("decode: " + errorStr(result));
- i += result;
+ i += check(pn_data_decode(data, i, end - i));
}
}
@@ -89,11 +104,65 @@ template <class T, class U> void extract(pn_data_t* data, T& value, U (*get)(pn_
}
+void Decoder::checkType(TypeId want) {
+ TypeId got = type();
+ if (want != got) badType(want, got);
+}
+
TypeId Decoder::type() const {
SaveState ss(data);
return preGet(data);
}
+Decoder& operator>>(Decoder& d, Start& s) {
+ SaveState ss(d.data);
+ s.type = preGet(d.data);
+ switch (s.type) {
+ case ARRAY:
+ s.size = pn_data_get_array(d.data);
+ s.element = TypeId(pn_data_get_array_type(d.data));
+ s.isDescribed = pn_data_is_array_described(d.data);
+ break;
+ case LIST:
+ s.size = pn_data_get_list(d.data);
+ break;
+ case MAP:
+ s.size = pn_data_get_map(d.data);
+ break;
+ case DESCRIBED:
+ s.isDescribed = true;
+ s.size = 1;
+ break;
+ default:
+ throw Decoder::Error(MSG("decode: " << s.type << " is not a container type"));
+ }
+ pn_data_enter(d.data);
+ ss.cancel();
+ return d;
+}
+
+Decoder& operator>>(Decoder& d, Finish) { pn_data_exit(d.data); return d; }
+
+Decoder& operator>>(Decoder& d, Skip) { pn_data_next(d.data); return d; }
+
+Decoder& operator>>(Decoder& d, Value& v) {
+ if (d.data == v.values.data) throw Decoder::Error("decode: extract into self");
+ pn_data_clear(v.values.data);
+ {
+ Narrow n(d.data);
+ check(pn_data_appendn(v.values.data, d.data, 1));
+ }
+ if (!pn_data_next(d.data)) throw Decoder::Error("decode: no more data");
+ return d;
+}
+
+
+Decoder& operator>>(Decoder& d, Null) {
+ SaveState ss(d.data);
+ badType(NULL_, preGet(d.data));
+ return d;
+}
+
Decoder& operator>>(Decoder& d, Bool& value) {
extract(d.data, value, pn_data_get_bool);
return d;
@@ -112,7 +181,7 @@ Decoder& operator>>(Decoder& d, Ubyte& value) {
Decoder& operator>>(Decoder& d, Byte& value) {
SaveState ss(d.data);
switch (preGet(d.data)) {
- case BYTE: value = pn_data_get_ubyte(d.data); break;
+ case BYTE: value = pn_data_get_byte(d.data); break;
default: badType(BYTE, TypeId(TypeId(pn_data_type(d.data))));
}
ss.cancel();
@@ -256,10 +325,4 @@ Decoder& operator>>(Decoder& d, std::string& value) {
return d;
}
-void Decoder::checkType(TypeId want) {
- TypeId got = type();
- if (want != got) badType(want, got);
-}
-
-
}} // namespace proton::reactor
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/693752d3/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 81fa365..9182400 100644
--- a/proton-c/bindings/cpp/src/Encoder.cpp
+++ b/proton-c/bindings/cpp/src/Encoder.cpp
@@ -18,8 +18,10 @@
*/
#include "proton/cpp/Encoder.h"
+#include "proton/cpp/Value.h"
#include <proton/codec.h>
#include "proton_bits.h"
+#include "Msg.h"
namespace proton {
namespace reactor {
@@ -33,27 +35,30 @@ struct SaveState {
pn_handle_t handle;
SaveState(pn_data_t* d) : data(d), handle(pn_data_point(d)) {}
~SaveState() { if (data) pn_data_restore(data, handle); }
+ void cancel() { data = 0; }
};
-template <class T> T check(T result) {
+void check(int result, pn_data_t* data) {
if (result < 0)
- throw Encoder::Error("encode: " + errorStr(result));
- return result;
+ throw Encoder::Error("encode: " + errorStr(pn_data_error(data), result));
}
}
bool Encoder::encode(char* buffer, size_t& size) {
SaveState ss(data); // In case of error
- pn_data_rewind(data);
ssize_t result = pn_data_encode(data, buffer, size);
if (result == PN_OVERFLOW) {
- size = pn_data_encoded_size(data);
- return false;
+ result = pn_data_encoded_size(data);
+ if (result >= 0) {
+ size = result;
+ return false;
+ }
}
- check(result);
+ check(result, data);
size = result;
- ss.data = 0; // Don't restore state, all is well.
+ ss.cancel(); // Don't restore state, all is well.
pn_data_clear(data);
+ return true;
}
void Encoder::encode(std::string& s) {
@@ -70,16 +75,35 @@ std::string Encoder::encode() {
return s;
}
+Encoder& operator<<(Encoder& e, const Start& s) {
+ switch (s.type) {
+ case ARRAY: pn_data_put_array(e.data, s.isDescribed, pn_type_t(s.element)); break;
+ case MAP: pn_data_put_map(e.data); break;
+ case LIST: pn_data_put_list(e.data); break;
+ case DESCRIBED: pn_data_put_described(e.data); break;
+ default:
+ throw Encoder::Error(MSG("encode: " << s.type << " is not a container type"));
+ }
+ pn_data_enter(e.data);
+ return e;
+}
+
+Encoder& operator<<(Encoder& e, Finish) {
+ pn_data_exit(e.data);
+ return e;
+}
+
namespace {
template <class T, class U>
Encoder& insert(Encoder& e, pn_data_t* data, T& value, int (*put)(pn_data_t*, U)) {
SaveState ss(data); // Save state in case of error.
- check(put(data, value));
- ss.data = 0; // Don't restore state, all is good.
+ check(put(data, value), data);
+ ss.cancel(); // Don't restore state, all is good.
return e;
}
}
+Encoder& operator<<(Encoder& e, Null) { pn_data_put_null(e.data); return e; }
Encoder& operator<<(Encoder& e, Bool value) { return insert(e, e.data, value, pn_data_put_bool); }
Encoder& operator<<(Encoder& e, Ubyte value) { return insert(e, e.data, value, pn_data_put_ubyte); }
Encoder& operator<<(Encoder& e, Byte value) { return insert(e, e.data, value, pn_data_put_byte); }
@@ -101,4 +125,34 @@ Encoder& operator<<(Encoder& e, String value) { return insert(e, e.data, value,
Encoder& operator<<(Encoder& e, Symbol value) { return insert(e, e.data, value, pn_data_put_symbol); }
Encoder& operator<<(Encoder& e, Binary value) { return insert(e, e.data, value, pn_data_put_binary); }
+// Meta-function to get the class from the type ID.
+template <TypeId A> struct ClassOf {};
+template<> struct ClassOf<NULL_> { typedef Null ValueType; };
+template<> struct ClassOf<BOOL> { typedef Bool ValueType; };
+template<> struct ClassOf<UBYTE> { typedef Ubyte ValueType; };
+template<> struct ClassOf<BYTE> { typedef Byte ValueType; };
+template<> struct ClassOf<USHORT> { typedef Ushort ValueType; };
+template<> struct ClassOf<SHORT> { typedef Short ValueType; };
+template<> struct ClassOf<UINT> { typedef Uint ValueType; };
+template<> struct ClassOf<INT> { typedef Int ValueType; };
+template<> struct ClassOf<CHAR> { typedef Char ValueType; };
+template<> struct ClassOf<ULONG> { typedef Ulong ValueType; };
+template<> struct ClassOf<LONG> { typedef Long ValueType; };
+template<> struct ClassOf<TIMESTAMP> { typedef Timestamp ValueType; };
+template<> struct ClassOf<FLOAT> { typedef Float ValueType; };
+template<> struct ClassOf<DOUBLE> { typedef Double ValueType; };
+template<> struct ClassOf<DECIMAL32> { typedef Decimal32 ValueType; };
+template<> struct ClassOf<DECIMAL64> { typedef Decimal64 ValueType; };
+template<> struct ClassOf<DECIMAL128> { typedef Decimal128 ValueType; };
+template<> struct ClassOf<UUID> { typedef Uuid ValueType; };
+template<> struct ClassOf<BINARY> { typedef Binary ValueType; };
+template<> struct ClassOf<STRING> { typedef String ValueType; };
+template<> struct ClassOf<SYMBOL> { typedef Symbol ValueType; };
+
+Encoder& operator<<(Encoder& e, const Value& v) {
+ if (e.data == v.values.data) throw Encoder::Error("encode: cannot insert into self");
+ check(pn_data_appendn(e.data, v.values.data, 1), e.data);
+ return e;
+}
+
}} // namespace proton::reactor
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/693752d3/proton-c/bindings/cpp/src/Handler.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/Handler.cpp b/proton-c/bindings/cpp/src/Handler.cpp
index 4d1b581..5c37c8d 100644
--- a/proton-c/bindings/cpp/src/Handler.cpp
+++ b/proton-c/bindings/cpp/src/Handler.cpp
@@ -24,10 +24,10 @@
namespace proton {
namespace reactor {
-Handler::Handler(){};
-Handler::~Handler(){};
+Handler::Handler() {}
+Handler::~Handler() {}
-void Handler::onUnhandled(Event &e){};
+void Handler::onUnhandled(Event &e) {}
void Handler::addChildHandler(Handler &e) {
childHandlers.push_back(&e);
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/693752d3/proton-c/bindings/cpp/src/MessagingAdapter.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/MessagingAdapter.cpp b/proton-c/bindings/cpp/src/MessagingAdapter.cpp
index 625485e..f137397 100644
--- a/proton-c/bindings/cpp/src/MessagingAdapter.cpp
+++ b/proton-c/bindings/cpp/src/MessagingAdapter.cpp
@@ -35,10 +35,10 @@ namespace reactor {
MessagingAdapter::MessagingAdapter(MessagingHandler &delegate_) :
MessagingHandler(true, delegate_.prefetch, delegate_.autoSettle, delegate_.autoAccept, delegate_.peerCloseIsError),
delegate(delegate_)
-{};
+{}
-MessagingAdapter::~MessagingAdapter(){};
+MessagingAdapter::~MessagingAdapter(){}
void MessagingAdapter::onReactorInit(Event &e) {
@@ -126,7 +126,7 @@ void MessagingAdapter::onDelivery(Event &e) {
MessagingEvent mevent(PN_MESSAGING_ACCEPTED, *pe);
delegate.onAccepted(mevent);
}
- else if (rstate = PN_REJECTED) {
+ else if (rstate == PN_REJECTED) {
MessagingEvent mevent(PN_MESSAGING_REJECTED, *pe);
delegate.onRejected(mevent);
}
@@ -164,10 +164,6 @@ bool isRemoteOpen(pn_state_t state) {
return state & PN_REMOTE_ACTIVE;
}
-bool isRemoteClosed(pn_state_t state) {
- return state & PN_REMOTE_CLOSED;
-}
-
} // namespace
void MessagingAdapter::onLinkRemoteClose(Event &e) {
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/693752d3/proton-c/bindings/cpp/src/MessagingHandler.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/MessagingHandler.cpp b/proton-c/bindings/cpp/src/MessagingHandler.cpp
index 925186a..6e3d2bd 100644
--- a/proton-c/bindings/cpp/src/MessagingHandler.cpp
+++ b/proton-c/bindings/cpp/src/MessagingHandler.cpp
@@ -83,7 +83,7 @@ void MessagingHandler::createHelpers() {
MessagingHandler::~MessagingHandler(){
delete flowController;
delete messagingAdapter;
-};
+}
void MessagingHandler::onAbort(Event &e) { onUnhandled(e); }
void MessagingHandler::onAccepted(Event &e) { onUnhandled(e); }
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/693752d3/proton-c/bindings/cpp/src/Msg.h
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/Msg.h b/proton-c/bindings/cpp/src/Msg.h
index cd8f9e8..2b4c6da 100644
--- a/proton-c/bindings/cpp/src/Msg.h
+++ b/proton-c/bindings/cpp/src/Msg.h
@@ -44,30 +44,10 @@ struct Msg {
Msg(const Msg& m) : os(m.str()) {}
std::string str() const { return os.str(); }
operator std::string() const { return str(); }
-
- Msg& operator<<(long n) { os << n; return *this; }
- Msg& operator<<(unsigned long n) { os << n; return *this; }
- Msg& operator<<(bool n) { os << n; return *this; }
- Msg& operator<<(short n) { os << n; return *this; }
- Msg& operator<<(unsigned short n) { os << n; return *this; }
- Msg& operator<<(int n) { os << n; return *this; }
- Msg& operator<<(unsigned int n) { os << n; return *this; }
-#ifdef _GLIBCXX_USE_LONG_LONG
- Msg& operator<<(long long n) { os << n; return *this; }
- Msg& operator<<(unsigned long long n) { os << n; return *this; }
-#endif
- Msg& operator<<(double n) { os << n; return *this; }
- Msg& operator<<(float n) { os << n; return *this; }
- Msg& operator<<(long double n) { os << n; return *this; }
-
template <class T> Msg& operator<<(const T& t) { os <<t; return *this; }
};
-
-
-inline std::ostream& operator<<(std::ostream& o, const Msg& m) {
- return o << m.str();
-}
+inline std::ostream& operator<<(std::ostream& o, const Msg& m) { return o << m.str(); }
/** Construct a message using operator << and append (file:line) */
#define QUOTE_(x) #x
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/693752d3/proton-c/bindings/cpp/src/ProtonEvent.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/ProtonEvent.cpp b/proton-c/bindings/cpp/src/ProtonEvent.cpp
index 16b92b6..0b0f1d0 100644
--- a/proton-c/bindings/cpp/src/ProtonEvent.cpp
+++ b/proton-c/bindings/cpp/src/ProtonEvent.cpp
@@ -70,11 +70,12 @@ Receiver ProtonEvent::getReceiver() {
Link ProtonEvent::getLink() {
pn_link_t *lnk = pn_event_link(getPnEvent());
- if (lnk)
+ if (lnk) {
if (pn_link_is_sender(lnk))
return Sender(lnk);
else
return Receiver(lnk);
+ }
throw ProtonException(MSG("No link context for this event"));
}
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/693752d3/proton-c/bindings/cpp/src/ProtonHandler.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/ProtonHandler.cpp b/proton-c/bindings/cpp/src/ProtonHandler.cpp
index 83d9087..f96f5a6 100644
--- a/proton-c/bindings/cpp/src/ProtonHandler.cpp
+++ b/proton-c/bindings/cpp/src/ProtonHandler.cpp
@@ -24,7 +24,7 @@
namespace proton {
namespace reactor {
-ProtonHandler::ProtonHandler(){};
+ProtonHandler::ProtonHandler(){}
// Everything goes to onUnhandled() unless overriden by subclass
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/693752d3/proton-c/bindings/cpp/src/Transport.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/Transport.cpp b/proton-c/bindings/cpp/src/Transport.cpp
index 7f22b84..91eb8d9 100644
--- a/proton-c/bindings/cpp/src/Transport.cpp
+++ b/proton-c/bindings/cpp/src/Transport.cpp
@@ -27,7 +27,7 @@ namespace proton {
namespace reactor {
-Transport::Transport() : connection(0), pnTransport(pn_transport()) {} ;
+Transport::Transport() : connection(0), pnTransport(pn_transport()) {}
Transport::~Transport() { pn_decref(pnTransport); }
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/693752d3/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 8e1e38c..b488481 100644
--- a/proton-c/bindings/cpp/src/Value.cpp
+++ b/proton-c/bindings/cpp/src/Value.cpp
@@ -21,21 +21,15 @@
#include "proton_bits.h"
#include <proton/codec.h>
#include <ostream>
+#include <algorithm>
namespace proton {
namespace reactor {
-Values::Values() {}
-Values::Values(const Values& v) { *this = v; }
-Values::~Values() {}
-Values& Values::operator=(const Values& v) { Data::operator=(v); }
-
-void Values::rewind() { pn_data_rewind(data); }
-
-Value::Value() {}
+Value::Value() { *this = Null(); }
Value::Value(const Value& v) { *this = v; }
Value::~Value() {}
-Value& Value::operator=(const Value& v) { values = v.values; }
+Value& Value::operator=(const Value& v) { values = v.values; return *this; }
TypeId Value::type() const {
const_cast<Values&>(values).rewind();
@@ -50,22 +44,93 @@ template <class T> T check(T result) {
}
}
-Encoder& operator<<(Encoder& e, const Value& v) {
- if (e.data == v.values.data) throw Encoder::Error("Values inserted into self");
- pn_data_narrow(e.data);
- int result = pn_data_appendn(e.data, v.values.data, 1);
- pn_data_widen(e.data);
- check(result);
- return e;
+std::ostream& operator<<(std::ostream& o, const Value& v) {
+ return o << v.values;
+}
+
+namespace {
+
+// Compare nodes, return -1 if a<b, 0 if a==b, +1 if a>b
+// Forward-declare so we can use it recursively.
+int compareNext(Values& a, Values& b);
+
+template <class T> int compare(const T& a, const T& b) {
+ if (a < b) return -1;
+ else if (a > b) return +1;
+ else return 0;
+}
+
+int compareContainer(Values& a, Values& b) {
+ Decoder::Scope sa(a), sb(b);
+ // Compare described vs. not-described.
+ int cmp = compare(sa.isDescribed, sb.isDescribed);
+ if (cmp) return cmp;
+ // Lexical sort (including descriptor if there is one)
+ size_t minSize = std::min(sa.size, sb.size) + int(sa.isDescribed);
+ for (size_t i = 0; i < minSize; ++i) {
+ cmp = compareNext(a, b);
+ if (cmp) return cmp;
+ }
+ return compare(sa.size, sb.size);
+}
+
+template <class T> int compareSimple(Values& a, Values& b) {
+ T va, vb;
+ a >> va;
+ b >> vb;
+ return compare(va, vb);
+}
+
+int compareNext(Values& a, Values& b) {
+ // Sort by TypeId first.
+ TypeId ta = a.type(), tb = b.type();
+ int cmp = compare(ta, tb);
+ if (cmp) return cmp;
+
+ switch (ta) {
+ case NULL_: return 0;
+ case ARRAY:
+ case LIST:
+ case MAP:
+ case DESCRIBED:
+ return compareContainer(a, b);
+ case BOOL: return compareSimple<Bool>(a, b);
+ case UBYTE: return compareSimple<Ubyte>(a, b);
+ case BYTE: return compareSimple<Byte>(a, b);
+ case USHORT: return compareSimple<Ushort>(a, b);
+ case SHORT: return compareSimple<Short>(a, b);
+ case UINT: return compareSimple<Uint>(a, b);
+ case INT: return compareSimple<Int>(a, b);
+ case CHAR: return compareSimple<Char>(a, b);
+ case ULONG: return compareSimple<Ulong>(a, b);
+ case LONG: return compareSimple<Long>(a, b);
+ case TIMESTAMP: return compareSimple<Timestamp>(a, b);
+ case FLOAT: return compareSimple<Float>(a, b);
+ case DOUBLE: return compareSimple<Double>(a, b);
+ case DECIMAL32: return compareSimple<Decimal32>(a, b);
+ case DECIMAL64: return compareSimple<Decimal64>(a, b);
+ case DECIMAL128: return compareSimple<Decimal128>(a, b);
+ case UUID: return compareSimple<Uuid>(a, b);
+ case BINARY: return compareSimple<Binary>(a, b);
+ case STRING: return compareSimple<String>(a, b);
+ case SYMBOL: return compareSimple<Symbol>(a, b);
+ }
+ // Invalid but equal TypeId, treat as equal.
+ return 0;
+}
+
+} // namespace
+
+bool Value::operator==(const Value& v) const {
+ values.rewind();
+ v.values.rewind();
+ return compareNext(values, v.values) == 0;
}
-Decoder& operator>>(Decoder& e, Value& v) {
- if (e.data == v.values.data) throw Decoder::Error("Values extracted from self");
- pn_data_narrow(e.data);
- int result = pn_data_appendn(e.data, v.values.data, 1);
- pn_data_widen(e.data);
- check(result);
- return e;
+bool Value::operator<(const Value& v) const {
+ values.rewind();
+ v.values.rewind();
+ return compareNext(values, v.values) < 0;
}
}}
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/693752d3/proton-c/bindings/cpp/src/Values.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/Values.cpp b/proton-c/bindings/cpp/src/Values.cpp
new file mode 100644
index 0000000..20fb9f1
--- /dev/null
+++ b/proton-c/bindings/cpp/src/Values.cpp
@@ -0,0 +1,39 @@
+/*
+ * 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/cpp/Value.h"
+#include "proton_bits.h"
+#include <proton/codec.h>
+#include <ostream>
+
+namespace proton {
+namespace reactor {
+
+Values::Values() {}
+Values::Values(const Values& v) { *this = v; }
+Values::~Values() {}
+Values& Values::operator=(const Values& v) { Data::operator=(v); return *this; }
+
+Values& Values::rewind() { pn_data_rewind(data); return *this; }
+
+std::ostream& operator<<(std::ostream& o, const Values& v) {
+ return o << static_cast<const Encoder&>(v);
+}
+
+}}
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/693752d3/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 b344553..d7bef51 100644
--- a/proton-c/bindings/cpp/src/interop_test.cpp
+++ b/proton-c/bindings/cpp/src/interop_test.cpp
@@ -48,11 +48,7 @@ string read(string filename) {
return string(istreambuf_iterator<char>(ifs), istreambuf_iterator<char>());
}
-template <class T> T get(Decoder& d) {
- T value;
- d >> exact(value);
- return value;
-}
+template <class T> T get(Decoder& d) { return d.getAs<T, TypeIdOf<T>::value>(); }
template <class T> std::string str(const T& value) {
ostringstream oss;
@@ -129,7 +125,7 @@ int run_test(void (*testfn)(), const char* name) {
return 1;
}
-// FIXME aconway 2015-06-11: not testing all types.
+// TODO aconway 2015-06-11: interop test is not complete.
#define RUN_TEST(T) run_test(&T, #T)
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/693752d3/proton-c/bindings/cpp/src/proton_bits.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/proton_bits.cpp b/proton-c/bindings/cpp/src/proton_bits.cpp
index 2e96430..10f7c59 100644
--- a/proton-c/bindings/cpp/src/proton_bits.cpp
+++ b/proton-c/bindings/cpp/src/proton_bits.cpp
@@ -39,6 +39,14 @@ std::string errorStr(int code) {
}
}
+std::string errorStr(pn_error_t* err, int code) {
+ if (err && pn_error_code(err)) {
+ const char* text = pn_error_text(err);
+ return text ? std::string(text) : errorStr(pn_error_code(err));
+ }
+ return errorStr(code);
+}
+
std::ostream& operator<<(std::ostream& o, const Object& object) {
pn_string_t* str = pn_string("");
pn_inspect(object.value, str);
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/693752d3/proton-c/bindings/cpp/src/proton_bits.h
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/proton_bits.h b/proton-c/bindings/cpp/src/proton_bits.h
index a905172..e57f188 100644
--- a/proton-c/bindings/cpp/src/proton_bits.h
+++ b/proton-c/bindings/cpp/src/proton_bits.h
@@ -20,13 +20,18 @@
*/
#include <iosfwd>
+#include <proton/error.h>
/**@file
*
* Assorted internal proton utilities.
*/
+
std::string errorStr(int code);
+/** Print the error string from pn_error_t, or from code if pn_error_t has no error. */
+std::string errorStr(pn_error_t*, int code=0);
+
/** Wrapper for a proton object pointer. */
struct Object { void* value; Object(void* o) : value(o) {} };
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/693752d3/proton-c/bindings/cpp/src/types.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/types.cpp b/proton-c/bindings/cpp/src/types.cpp
index 127ee7d..4f2c6ac 100644
--- a/proton-c/bindings/cpp/src/types.cpp
+++ b/proton-c/bindings/cpp/src/types.cpp
@@ -19,32 +19,11 @@
#include "proton/cpp/types.h"
#include <proton/codec.h>
+#include <ostream>
namespace proton {
namespace reactor {
-const TypeId TypeIdOf<Null>::value = NULL_;
-const TypeId TypeIdOf<Bool>::value = BOOL;
-const TypeId TypeIdOf<Ubyte>::value = UBYTE;
-const TypeId TypeIdOf<Byte>::value = BYTE;
-const TypeId TypeIdOf<Ushort>::value = USHORT;
-const TypeId TypeIdOf<Short>::value = SHORT;
-const TypeId TypeIdOf<Uint>::value = UINT;
-const TypeId TypeIdOf<Int>::value = INT;
-const TypeId TypeIdOf<Char>::value = CHAR;
-const TypeId TypeIdOf<Ulong>::value = ULONG;
-const TypeId TypeIdOf<Long>::value = LONG;
-const TypeId TypeIdOf<Timestamp>::value = TIMESTAMP;
-const TypeId TypeIdOf<Float>::value = FLOAT;
-const TypeId TypeIdOf<Double>::value = DOUBLE;
-const TypeId TypeIdOf<Decimal32>::value = DECIMAL32;
-const TypeId TypeIdOf<Decimal64>::value = DECIMAL64;
-const TypeId TypeIdOf<Decimal128>::value = DECIMAL128;
-const TypeId TypeIdOf<Uuid>::value = UUID;
-const TypeId TypeIdOf<Binary>::value = BINARY;
-const TypeId TypeIdOf<String>::value = STRING;
-const TypeId TypeIdOf<Symbol>::value = SYMBOL;
-
std::string typeName(TypeId t) {
switch (t) {
case NULL_: return "null";
@@ -76,7 +55,27 @@ std::string typeName(TypeId t) {
}
}
-std::string str(const pn_bytes_t& b) { return std::string(b.start, b.size); }
-pn_bytes_t bytes(const std::string& s) { pn_bytes_t b; b.start = &s[0]; b.size = s.size(); return b; }
+std::ostream& operator<<(std::ostream& o,TypeId t) { return o << typeName(t); }
+
+PN_CPP_EXTERN bool isContainer(TypeId t) {
+ return (t == LIST || t == MAP || t == ARRAY || t == DESCRIBED);
+}
+
+pn_bytes_t pn_bytes(const std::string& s) {
+ pn_bytes_t b = { s.size(), const_cast<char*>(&s[0]) };
+ return b;
+}
+
+pn_uuid_t pn_uuid(const std::string& s) {
+ pn_uuid_t u = {0}; // Zero initialized.
+ std::copy(s.begin(), s.begin() + std::max(s.size(), sizeof(pn_uuid_t::bytes)), &u.bytes[0]);
+ return u;
+}
+
+Start::Start(TypeId t, TypeId e, bool d, size_t s) : type(t), element(e), isDescribed(d), size(s) {}
+Start Start::array(TypeId element, bool described) { return Start(ARRAY, element, described); }
+Start Start::list() { return Start(LIST); }
+Start Start::map() { return Start(MAP); }
+Start Start::described() { return Start(DESCRIBED, NULL_, true); }
}}
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/693752d3/proton-c/bindings/go/README.md
----------------------------------------------------------------------
diff --git a/proton-c/bindings/go/README.md b/proton-c/bindings/go/README.md
deleted file mode 100644
index 0d3a74e..0000000
--- a/proton-c/bindings/go/README.md
+++ /dev/null
@@ -1,5 +0,0 @@
-# *EXPERIMENTAL* Go binding for proton
-
-Experimental work on the Go language binding has been moved to the `go1` branch
-until it is ready for use. You can `git checkout go1` on your git clone, or
-browse at https://github.com/apache/qpid-proton/blob/go1/proton-c/bindings/go/README.md
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org