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/12/29 22:00:52 UTC

[1/4] qpid-proton git commit: PROTON-1085: c++: Rename "atom" type to "scalar".

Repository: qpid-proton
Updated Branches:
  refs/heads/master fd52a332f -> 117bb7cb0


PROTON-1085: c++: Rename "atom" type to "scalar".

Scalar is the term used in the AMQP standard.


Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/d2c5a5f2
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/d2c5a5f2
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/d2c5a5f2

Branch: refs/heads/master
Commit: d2c5a5f2017ed95102b03b173ad050e616fab30b
Parents: fd52a33
Author: Alan Conway <ac...@redhat.com>
Authored: Mon Dec 28 15:37:23 2015 -0500
Committer: Alan Conway <ac...@redhat.com>
Committed: Tue Dec 29 15:55:38 2015 -0500

----------------------------------------------------------------------
 proton-c/bindings/cpp/CMakeLists.txt            |   4 +-
 proton-c/bindings/cpp/include/proton/atom.hpp   | 122 ------------
 proton-c/bindings/cpp/include/proton/scalar.hpp | 122 ++++++++++++
 proton-c/bindings/cpp/include/proton/types.hpp  |  14 +-
 proton-c/bindings/cpp/src/atom.cpp              | 185 -------------------
 proton-c/bindings/cpp/src/atom_test.cpp         | 105 -----------
 proton-c/bindings/cpp/src/scalar.cpp            | 185 +++++++++++++++++++
 proton-c/bindings/cpp/src/scalar_test.cpp       | 105 +++++++++++
 proton-c/bindings/cpp/src/types.cpp             |  18 +-
 9 files changed, 430 insertions(+), 430 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d2c5a5f2/proton-c/bindings/cpp/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/CMakeLists.txt b/proton-c/bindings/cpp/CMakeLists.txt
index 78df0b5..10d40f8 100644
--- a/proton-c/bindings/cpp/CMakeLists.txt
+++ b/proton-c/bindings/cpp/CMakeLists.txt
@@ -26,7 +26,7 @@ include_directories(
 
 set(qpid-proton-cpp-source
   src/acceptor.cpp
-  src/atom.cpp
+  src/scalar.cpp
   src/blocking_connection.cpp
   src/blocking_connection_impl.cpp
   src/blocking_fetcher.cpp
@@ -170,4 +170,4 @@ endmacro(add_cpp_test)
 add_cpp_test(interop_test ${CMAKE_SOURCE_DIR}/tests)
 add_cpp_test(message_test)
 add_cpp_test(encode_decode_test)
-add_cpp_test(atom_test)
+add_cpp_test(scalar_test)

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d2c5a5f2/proton-c/bindings/cpp/include/proton/atom.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/atom.hpp b/proton-c/bindings/cpp/include/proton/atom.hpp
deleted file mode 100644
index ce2a385..0000000
--- a/proton-c/bindings/cpp/include/proton/atom.hpp
+++ /dev/null
@@ -1,122 +0,0 @@
-#ifndef ATOM_HPP
-#define ATOM_HPP
-/*
- * 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/types.hpp"
-#include <iosfwd>
-
-namespace proton {
-
-class atom;
-
-/** atom holds an instance of an atomic proton type. */
-class atom : public comparable<atom> {
-  public:
-    PN_CPP_EXTERN atom();
-    // Use default assign and copy.
-
-    /// Type for the value in the atom, NULL_TYPE if empty()
-    PN_CPP_EXTERN type_id type() const;
-    /// True if the atom is empty.
-    PN_CPP_EXTERN bool empty() const;
-
-    ///@name Create an atom, type() is deduced from the C++ type of the value.
-    ///@{
-    PN_CPP_EXTERN explicit atom(bool);
-    PN_CPP_EXTERN explicit atom(uint8_t);
-    PN_CPP_EXTERN explicit atom(int8_t);
-    PN_CPP_EXTERN explicit atom(uint16_t);
-    PN_CPP_EXTERN explicit atom(int16_t);
-    PN_CPP_EXTERN explicit atom(uint32_t);
-    PN_CPP_EXTERN explicit atom(int32_t);
-    PN_CPP_EXTERN explicit atom(uint64_t);
-    PN_CPP_EXTERN explicit atom(int64_t);
-    PN_CPP_EXTERN explicit atom(wchar_t);
-    PN_CPP_EXTERN explicit atom(float);
-    PN_CPP_EXTERN explicit atom(double);
-    PN_CPP_EXTERN explicit atom(amqp_timestamp);
-    PN_CPP_EXTERN explicit atom(const amqp_decimal32&);
-    PN_CPP_EXTERN explicit atom(const amqp_decimal64&);
-    PN_CPP_EXTERN explicit atom(const amqp_decimal128&);
-    PN_CPP_EXTERN explicit atom(const amqp_uuid&);
-    PN_CPP_EXTERN explicit atom(const amqp_string&);
-    PN_CPP_EXTERN explicit atom(const amqp_symbol&);
-    PN_CPP_EXTERN explicit atom(const amqp_binary&);
-    PN_CPP_EXTERN explicit atom(const std::string& s); ///< Treated as an AMQP string
-    PN_CPP_EXTERN explicit atom(const char* s);        ///< Treated as an AMQP string
-    ///@}
-
-    /// Assign to an atom using the same rules as construction.
-    template <class T> atom& operator=(T x) { return *this = atom(x); }
-
-    ///@name get(T&) extracts the value if the types match exactly,
-    ///i.e. if `type() == type_id_of<T>::value`
-    /// throws type_mismatch otherwise.
-    ///@{
-    PN_CPP_EXTERN void get(bool&) const;
-    PN_CPP_EXTERN void get(uint8_t&) const;
-    PN_CPP_EXTERN void get(int8_t&) const;
-    PN_CPP_EXTERN void get(uint16_t&) const;
-    PN_CPP_EXTERN void get(int16_t&) const;
-    PN_CPP_EXTERN void get(uint32_t&) const;
-    PN_CPP_EXTERN void get(int32_t&) const;
-    PN_CPP_EXTERN void get(uint64_t&) const;
-    PN_CPP_EXTERN void get(int64_t&) const;
-    PN_CPP_EXTERN void get(wchar_t&) const;
-    PN_CPP_EXTERN void get(float&) const;
-    PN_CPP_EXTERN void get(double&) const;
-    PN_CPP_EXTERN void get(amqp_timestamp&) const;
-    PN_CPP_EXTERN void get(amqp_decimal32&) const;
-    PN_CPP_EXTERN void get(amqp_decimal64&) const;
-    PN_CPP_EXTERN void get(amqp_decimal128&) const;
-    PN_CPP_EXTERN void get(amqp_uuid&) const;
-    PN_CPP_EXTERN void get(amqp_string&) const;
-    PN_CPP_EXTERN void get(amqp_symbol&) const;
-    PN_CPP_EXTERN void get(amqp_binary&) const;
-    PN_CPP_EXTERN void get(std::string&) const; ///< Treated as an AMQP string
-    ///@}
-
-    ///@ get<T>() is like get(T&) but returns the value..
-    template<class T> T get() const { T x; get(x); return x; }
-
-    ///@name as_ methods do "loose" conversion, they will convert the atom's
-    ///value to the requested type if possible, else throw type_mismatch
-    ///@{
-    PN_CPP_EXTERN int64_t as_int() const;     ///< Allowed if type_id_integral(type())
-    PN_CPP_EXTERN uint64_t as_uint() const;   ///< Allowed if type_id_integral(type())
-    PN_CPP_EXTERN double as_double() const;    ///< Allowed if type_id_floating_point(type())
-    PN_CPP_EXTERN std::string as_string() const; ///< Allowed if type_id_string_like(type())
-    ///@}
-
-    PN_CPP_EXTERN bool operator==(const atom& x) const;
-    /// Note if the values are of different type(), operator< will compare the type()
-    PN_CPP_EXTERN bool operator<(const atom& x) const;
-
-  PN_CPP_EXTERN friend std::ostream& operator<<(std::ostream&, const atom&);
-
-  private:
-    void ok(pn_type_t) const;
-    void set(const std::string&);
-    pn_atom_t atom_;
-    std::string str_;           // Owner of string-like data.
-};
-
-}
-#endif // ATOM_HPP

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d2c5a5f2/proton-c/bindings/cpp/include/proton/scalar.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/scalar.hpp b/proton-c/bindings/cpp/include/proton/scalar.hpp
new file mode 100644
index 0000000..0745281
--- /dev/null
+++ b/proton-c/bindings/cpp/include/proton/scalar.hpp
@@ -0,0 +1,122 @@
+#ifndef SCALAR_HPP
+#define SCALAR_HPP
+/*
+ * 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/types.hpp"
+#include <iosfwd>
+
+namespace proton {
+
+class scalar;
+
+/** scalar holds an instance of an atomic proton type. */
+class scalar : public comparable<scalar> {
+  public:
+    PN_CPP_EXTERN scalar();
+    // Use default assign and copy.
+
+    /// Type for the value in the scalar, NULL_TYPE if empty()
+    PN_CPP_EXTERN type_id type() const;
+    /// True if the scalar is empty.
+    PN_CPP_EXTERN bool empty() const;
+
+    ///@name Create an scalar, type() is deduced from the C++ type of the value.
+    ///@{
+    PN_CPP_EXTERN explicit scalar(bool);
+    PN_CPP_EXTERN explicit scalar(uint8_t);
+    PN_CPP_EXTERN explicit scalar(int8_t);
+    PN_CPP_EXTERN explicit scalar(uint16_t);
+    PN_CPP_EXTERN explicit scalar(int16_t);
+    PN_CPP_EXTERN explicit scalar(uint32_t);
+    PN_CPP_EXTERN explicit scalar(int32_t);
+    PN_CPP_EXTERN explicit scalar(uint64_t);
+    PN_CPP_EXTERN explicit scalar(int64_t);
+    PN_CPP_EXTERN explicit scalar(wchar_t);
+    PN_CPP_EXTERN explicit scalar(float);
+    PN_CPP_EXTERN explicit scalar(double);
+    PN_CPP_EXTERN explicit scalar(amqp_timestamp);
+    PN_CPP_EXTERN explicit scalar(const amqp_decimal32&);
+    PN_CPP_EXTERN explicit scalar(const amqp_decimal64&);
+    PN_CPP_EXTERN explicit scalar(const amqp_decimal128&);
+    PN_CPP_EXTERN explicit scalar(const amqp_uuid&);
+    PN_CPP_EXTERN explicit scalar(const amqp_string&);
+    PN_CPP_EXTERN explicit scalar(const amqp_symbol&);
+    PN_CPP_EXTERN explicit scalar(const amqp_binary&);
+    PN_CPP_EXTERN explicit scalar(const std::string& s); ///< Treated as an AMQP string
+    PN_CPP_EXTERN explicit scalar(const char* s);        ///< Treated as an AMQP string
+    ///@}
+
+    /// Assign to an scalar using the same rules as construction.
+    template <class T> scalar& operator=(T x) { return *this = scalar(x); }
+
+    ///@name get(T&) extracts the value if the types match exactly,
+    ///i.e. if `type() == type_id_of<T>::value`
+    /// throws type_mismatch otherwise.
+    ///@{
+    PN_CPP_EXTERN void get(bool&) const;
+    PN_CPP_EXTERN void get(uint8_t&) const;
+    PN_CPP_EXTERN void get(int8_t&) const;
+    PN_CPP_EXTERN void get(uint16_t&) const;
+    PN_CPP_EXTERN void get(int16_t&) const;
+    PN_CPP_EXTERN void get(uint32_t&) const;
+    PN_CPP_EXTERN void get(int32_t&) const;
+    PN_CPP_EXTERN void get(uint64_t&) const;
+    PN_CPP_EXTERN void get(int64_t&) const;
+    PN_CPP_EXTERN void get(wchar_t&) const;
+    PN_CPP_EXTERN void get(float&) const;
+    PN_CPP_EXTERN void get(double&) const;
+    PN_CPP_EXTERN void get(amqp_timestamp&) const;
+    PN_CPP_EXTERN void get(amqp_decimal32&) const;
+    PN_CPP_EXTERN void get(amqp_decimal64&) const;
+    PN_CPP_EXTERN void get(amqp_decimal128&) const;
+    PN_CPP_EXTERN void get(amqp_uuid&) const;
+    PN_CPP_EXTERN void get(amqp_string&) const;
+    PN_CPP_EXTERN void get(amqp_symbol&) const;
+    PN_CPP_EXTERN void get(amqp_binary&) const;
+    PN_CPP_EXTERN void get(std::string&) const; ///< Treated as an AMQP string
+    ///@}
+
+    ///@ get<T>() is like get(T&) but returns the value..
+    template<class T> T get() const { T x; get(x); return x; }
+
+    ///@name as_ methods do "loose" conversion, they will convert the scalar's
+    ///value to the requested type if possible, else throw type_mismatch
+    ///@{
+    PN_CPP_EXTERN int64_t as_int() const;     ///< Allowed if type_id_integral(type())
+    PN_CPP_EXTERN uint64_t as_uint() const;   ///< Allowed if type_id_integral(type())
+    PN_CPP_EXTERN double as_double() const;    ///< Allowed if type_id_floating_point(type())
+    PN_CPP_EXTERN std::string as_string() const; ///< Allowed if type_id_string_like(type())
+    ///@}
+
+    PN_CPP_EXTERN bool operator==(const scalar& x) const;
+    /// Note if the values are of different type(), operator< will compare the type()
+    PN_CPP_EXTERN bool operator<(const scalar& x) const;
+
+  PN_CPP_EXTERN friend std::ostream& operator<<(std::ostream&, const scalar&);
+
+  private:
+    void ok(pn_type_t) const;
+    void set(const std::string&);
+    pn_atom_t atom_;
+    std::string str_;           // Owner of string-like data.
+};
+
+}
+#endif // SCALAR_HPP

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d2c5a5f2/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 75bb226..645d9da 100644
--- a/proton-c/bindings/cpp/include/proton/types.hpp
+++ b/proton-c/bindings/cpp/include/proton/types.hpp
@@ -198,13 +198,13 @@ PN_CPP_EXTERN std::string type_name(type_id);
 ///@name Attributes of a type_id value, returns same result as the
 /// corresponding std::type_traits tests for the corresponding C++ types.
 ///@{
-PN_CPP_EXTERN bool type_id_atom(type_id);
-PN_CPP_EXTERN bool type_id_integral(type_id);
-PN_CPP_EXTERN bool type_id_signed(type_id); ///< CHAR and BOOL are not signed.
-PN_CPP_EXTERN bool type_id_floating_point(type_id);
-PN_CPP_EXTERN bool type_id_decimal(type_id);
-PN_CPP_EXTERN bool type_id_string_like(type_id);   ///< STRING, SYMBOL, BINARY
-PN_CPP_EXTERN bool type_id_container(type_id);
+PN_CPP_EXTERN bool type_id_is_scalar(type_id);
+PN_CPP_EXTERN bool type_id_is_integral(type_id);
+PN_CPP_EXTERN bool type_id_is_signed(type_id); ///< CHAR and BOOL are not signed.
+PN_CPP_EXTERN bool type_id_is_floating_point(type_id);
+PN_CPP_EXTERN bool type_id_is_decimal(type_id);
+PN_CPP_EXTERN bool type_id_is_string_like(type_id);   ///< STRING, SYMBOL, BINARY
+PN_CPP_EXTERN bool type_id_is_container(type_id);
 ///@}
 
 /** Print the name of a type. */

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d2c5a5f2/proton-c/bindings/cpp/src/atom.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/atom.cpp b/proton-c/bindings/cpp/src/atom.cpp
deleted file mode 100644
index 034b22c..0000000
--- a/proton-c/bindings/cpp/src/atom.cpp
+++ /dev/null
@@ -1,185 +0,0 @@
-/*
- * 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/atom.hpp"
-#include "proton/type_traits.hpp"
-
-#include <ostream>
-
-namespace proton {
-
-atom::atom() { atom_.type = PN_NULL; }
-
-type_id atom::type() const { return type_id(atom_.type); }
-bool atom::empty() const { return type() == NULL_TYPE; }
-
-atom::atom(bool x) { atom_.u.as_bool = x; atom_.type = PN_BOOL; }
-atom::atom(uint8_t x) { atom_.u.as_ubyte = x; atom_.type = PN_UBYTE; }
-atom::atom(int8_t x) { atom_.u.as_byte = x; atom_.type = PN_BYTE; }
-atom::atom(uint16_t x) { atom_.u.as_ushort = x; atom_.type = PN_USHORT; }
-atom::atom(int16_t x) { atom_.u.as_short = x; atom_.type = PN_SHORT; }
-atom::atom(uint32_t x) { atom_.u.as_uint = x; atom_.type = PN_UINT; }
-atom::atom(int32_t x) { atom_.u.as_int = x; atom_.type = PN_INT; }
-atom::atom(uint64_t x) { atom_.u.as_ulong = x; atom_.type = PN_ULONG; }
-atom::atom(int64_t x) { atom_.u.as_long = x; atom_.type = PN_LONG; }
-atom::atom(wchar_t x) { atom_.u.as_char = pn_char_t(x); atom_.type = PN_CHAR; }
-atom::atom(float x) { atom_.u.as_float = x; atom_.type = PN_FLOAT; }
-atom::atom(double x) { atom_.u.as_double = x; atom_.type = PN_DOUBLE; }
-atom::atom(amqp_timestamp x) { atom_.u.as_timestamp = x; atom_.type = PN_TIMESTAMP; }
-atom::atom(const amqp_decimal32& x) { atom_.u.as_decimal32 = x; atom_.type = PN_DECIMAL32; }
-atom::atom(const amqp_decimal64& x) { atom_.u.as_decimal64 = x; atom_.type = PN_DECIMAL64; }
-atom::atom(const amqp_decimal128& x) { atom_.u.as_decimal128 = x; atom_.type = PN_DECIMAL128; }
-atom::atom(const amqp_uuid& x) { atom_.u.as_uuid = x; atom_.type = PN_UUID; }
-
-void atom::set(const std::string& x) { str_ = x; atom_.u.as_bytes = pn_bytes(str_); }
-atom::atom(const amqp_string& x) { set(x); atom_.type = PN_STRING; }
-atom::atom(const amqp_symbol& x) { set(x); atom_.type = PN_SYMBOL; }
-atom::atom(const amqp_binary& x) { set(x); atom_.type = PN_BINARY; }
-atom::atom(const std::string& x) { *this = amqp_string(x); }
-atom::atom(const char* x) { *this = amqp_string(x); }
-
-void atom::ok(pn_type_t t) const {
-    if (atom_.type != t) throw type_mismatch(type_id(t), type());
-}
-
-void atom::get(bool& x) const { ok(PN_BOOL); x = atom_.u.as_bool; }
-void atom::get(uint8_t& x) const { ok(PN_UBYTE); x = atom_.u.as_ubyte; }
-void atom::get(int8_t& x) const { ok(PN_BYTE); x = atom_.u.as_byte; }
-void atom::get(uint16_t& x) const { ok(PN_USHORT); x = atom_.u.as_ushort; }
-void atom::get(int16_t& x) const { ok(PN_SHORT); x = atom_.u.as_short; }
-void atom::get(uint32_t& x) const { ok(PN_UINT); x = atom_.u.as_uint; }
-void atom::get(int32_t& x) const { ok(PN_INT); x = atom_.u.as_int; }
-void atom::get(wchar_t& x) const { ok(PN_CHAR); x = wchar_t(atom_.u.as_char); }
-void atom::get(uint64_t& x) const { ok(PN_ULONG); x = atom_.u.as_ulong; }
-void atom::get(int64_t& x) const { ok(PN_LONG); x = atom_.u.as_long; }
-void atom::get(amqp_timestamp& x) const { ok(PN_TIMESTAMP); x = atom_.u.as_timestamp; }
-void atom::get(float& x) const { ok(PN_FLOAT); x = atom_.u.as_float; }
-void atom::get(double& x) const { ok(PN_DOUBLE); x = atom_.u.as_double; }
-void atom::get(amqp_decimal32& x) const { ok(PN_DECIMAL32); x = atom_.u.as_decimal32; }
-void atom::get(amqp_decimal64& x) const { ok(PN_DECIMAL64); x = atom_.u.as_decimal64; }
-void atom::get(amqp_decimal128& x) const { ok(PN_DECIMAL128); x = atom_.u.as_decimal128; }
-void atom::get(amqp_uuid& x) const { ok(PN_UUID); x = atom_.u.as_uuid; }
-void atom::get(amqp_string& x) const { ok(PN_STRING); x = str_; }
-void atom::get(amqp_symbol& x) const { ok(PN_SYMBOL); x = str_; }
-void atom::get(amqp_binary& x) const { ok(PN_BINARY); x = str_; }
-void atom::get(std::string& x) const { x = get<amqp_string>(); }
-
-int64_t atom::as_int() const {
-    if (type_id_floating_point(type()))
-        return int64_t(as_double());
-    switch (atom_.type) {
-      case PN_BOOL: return atom_.u.as_bool;
-      case PN_UBYTE: return atom_.u.as_ubyte;
-      case PN_BYTE: return atom_.u.as_byte;
-      case PN_USHORT: return atom_.u.as_ushort;
-      case PN_SHORT: return atom_.u.as_short;
-      case PN_UINT: return atom_.u.as_uint;
-      case PN_INT: return atom_.u.as_int;
-      case PN_CHAR: return atom_.u.as_char;
-      case PN_ULONG: return int64_t(atom_.u.as_ulong);
-      case PN_LONG: return atom_.u.as_long;
-      default: throw type_mismatch(LONG, type(), "cannot convert");
-    }
-}
-
-uint64_t atom::as_uint() const {
-    if  (!type_id_integral(type()))
-        throw type_mismatch(ULONG, type(), "cannot convert");
-    return uint64_t(as_int());
-}
-
-double atom::as_double() const {
-    if (type_id_integral(type())) {
-        return type_id_signed(type()) ? double(as_int()) : double(as_uint());
-    }
-    switch (atom_.type) {
-      case PN_DOUBLE: return atom_.u.as_double;
-      case PN_FLOAT: return atom_.u.as_float;
-      default: throw type_mismatch(DOUBLE, type(), "cannot convert");
-    }
-}
-
-std::string atom::as_string() const {
-    if (type_id_string_like(type()))
-        return str_;
-    throw type_mismatch(DOUBLE, type(), "cannot convert");
-}
-
-
-namespace {
-template <class T, class F> T type_switch(const atom& a, F f) {
-    switch(a.type()) {
-      case BOOLEAN: return f(a.get<bool>());
-      case UBYTE: return f(a.get<uint8_t>());
-      case BYTE: return f(a.get<int8_t>());
-      case USHORT: return f(a.get<uint16_t>());
-      case SHORT: return f(a.get<int16_t>());
-      case UINT: return f(a.get<uint32_t>());
-      case INT: return f(a.get<int32_t>());
-      case CHAR: return f(a.get<wchar_t>());
-      case ULONG: return f(a.get<uint64_t>());
-      case LONG: return f(a.get<int64_t>());
-      case TIMESTAMP: return f(a.get<amqp_timestamp>());
-      case FLOAT: return f(a.get<float>());
-      case DOUBLE: return f(a.get<double>());
-      case DECIMAL32: return f(a.get<amqp_decimal32>());
-      case DECIMAL64: return f(a.get<amqp_decimal64>());
-      case DECIMAL128: return f(a.get<amqp_decimal128>());
-      case UUID: return f(a.get<amqp_uuid>());
-      case BINARY: return f(a.get<amqp_binary>());
-      case STRING: return f(a.get<amqp_string>());
-      case SYMBOL: return f(a.get<amqp_symbol>());
-      default:
-        throw error("bad atom type");
-    }
-}
-
-struct equal_op {
-    const atom& a;
-    equal_op(const atom& a_) : a(a_) {}
-    template<class T> bool operator()(T x) { return x == a.get<T>(); }
-};
-
-struct less_op {
-    const atom& a;
-    less_op(const atom& a_) : a(a_) {}
-    template<class T> bool operator()(T x) { return x < a.get<T>(); }
-};
-
-struct ostream_op {
-    std::ostream& o;
-    ostream_op(std::ostream& o_) : o(o_) {}
-    template<class T> std::ostream& operator()(T x) { return o << x; }
-};
-
-} // namespace
-
-bool atom::operator==(const atom& x) const {
-    return type_switch<bool>(*this, equal_op(x));
-}
-
-bool atom::operator<(const atom& x) const {
-    return type_switch<bool>(*this, less_op(x));
-}
-
-std::ostream& operator<<(std::ostream& o, const atom& a) {
-    return type_switch<std::ostream&>(a, ostream_op(o));
-}
-
-}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d2c5a5f2/proton-c/bindings/cpp/src/atom_test.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/atom_test.cpp b/proton-c/bindings/cpp/src/atom_test.cpp
deleted file mode 100644
index 0d85a36..0000000
--- a/proton-c/bindings/cpp/src/atom_test.cpp
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * 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 "test_bits.hpp"
-#include "proton/type_traits.hpp"
-
-#include <proton/atom.hpp>
-
-using namespace std;
-using namespace proton;
-
-// Inserting and extracting simple C++ values.
-template <class T> void type_test(T x, type_id tid, T y) {
-    atom v(x);
-    ASSERT_EQUAL(tid, v.type());
-    ASSERT(!v.empty());
-    ASSERT_EQUAL(x, v.get<T>());
-
-    atom v2;
-    ASSERT(v2.type() == NULL_TYPE);
-    v2 = x;
-    ASSERT_EQUAL(tid, v2.type());
-    ASSERT_EQUAL(x, v2.get<T>());
-    ASSERT_EQUAL(v, v2);
-    ASSERT_EQUAL(str(x), str(v));
-
-    v2 = y;
-    ASSERT(v != v2);
-    ASSERT(v < v2);
-    ASSERT(v2 > v);
-}
-
-#define ASSERT_MISMATCH(EXPR) \
-    try { (void)(EXPR); FAIL("expected type_mismatch: " #EXPR); } catch (type_mismatch) {}
-
-void convert_test() {
-    atom a;
-    ASSERT_EQUAL(NULL_TYPE, a.type());
-    ASSERT(a.empty());
-    ASSERT_MISMATCH(a.get<float>());
-
-    a = amqp_binary("foo");
-    ASSERT_MISMATCH(a.get<int16_t>());
-    ASSERT_MISMATCH(a.as_int());
-    ASSERT_MISMATCH(a.as_double());
-    ASSERT_MISMATCH(a.get<amqp_string>());           // No strict conversion
-    ASSERT_EQUAL(a.as_string(), std::string("foo")); // OK string-like conversion
-
-    a = int16_t(42);
-    ASSERT_MISMATCH(a.get<std::string>());
-    ASSERT_MISMATCH(a.get<amqp_timestamp>());
-    ASSERT_MISMATCH(a.as_string());
-    ASSERT_EQUAL(a.as_int(), 42);
-    ASSERT_EQUAL(a.as_uint(), 42);
-    ASSERT_EQUAL(a.as_double(), 42);
-
-    a = int16_t(-42);
-    ASSERT_EQUAL(a.as_int(), -42);
-    ASSERT_EQUAL(a.as_uint(), uint64_t(-42));
-    ASSERT_EQUAL(a.as_double(), -42);
-}
-
-int main(int, char**) {
-    int failed = 0;
-    RUN_TEST(failed, type_test(false, BOOLEAN, true));
-    RUN_TEST(failed, type_test(amqp_ubyte(42), UBYTE, amqp_ubyte(50)));
-    RUN_TEST(failed, type_test(amqp_byte('x'), BYTE, amqp_byte('y')));
-    RUN_TEST(failed, type_test(amqp_ushort(4242), USHORT, amqp_ushort(5252)));
-    RUN_TEST(failed, type_test(amqp_short(-4242), SHORT, amqp_short(3)));
-    RUN_TEST(failed, type_test(amqp_uint(4242), UINT, amqp_uint(5252)));
-    RUN_TEST(failed, type_test(amqp_int(-4242), INT, amqp_int(3)));
-    RUN_TEST(failed, type_test(amqp_ulong(4242), ULONG, amqp_ulong(5252)));
-    RUN_TEST(failed, type_test(amqp_long(-4242), LONG, amqp_long(3)));
-    RUN_TEST(failed, type_test(wchar_t(23), CHAR, wchar_t(24)));
-    RUN_TEST(failed, type_test(amqp_float(1.234), FLOAT, amqp_float(2.345)));
-    RUN_TEST(failed, type_test(amqp_double(11.2233), DOUBLE, amqp_double(12)));
-    RUN_TEST(failed, type_test(amqp_timestamp(0), TIMESTAMP, amqp_timestamp(1)));
-    RUN_TEST(failed, type_test(amqp_decimal32(0), DECIMAL32, amqp_decimal32(1)));
-    RUN_TEST(failed, type_test(amqp_decimal64(0), DECIMAL64, amqp_decimal64(1)));
-    pn_decimal128_t da = {0}, db = {1};
-    RUN_TEST(failed, type_test(amqp_decimal128(da), DECIMAL128, amqp_decimal128(db)));
-    pn_uuid_t ua = {0}, ub = {1};
-    RUN_TEST(failed, type_test(amqp_uuid(ua), UUID, amqp_uuid(ub)));
-    RUN_TEST(failed, type_test(amqp_string("aaa"), STRING, amqp_string("aaaa")));
-    RUN_TEST(failed, type_test(amqp_symbol("aaa"), SYMBOL, amqp_symbol("aaaa")));
-    RUN_TEST(failed, type_test(amqp_binary("aaa"), BINARY, amqp_binary("aaaa")));
-    RUN_TEST(failed, type_test(std::string("xxx"), STRING, std::string("yyy")));
-    return failed;
-}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d2c5a5f2/proton-c/bindings/cpp/src/scalar.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/scalar.cpp b/proton-c/bindings/cpp/src/scalar.cpp
new file mode 100644
index 0000000..13daf32
--- /dev/null
+++ b/proton-c/bindings/cpp/src/scalar.cpp
@@ -0,0 +1,185 @@
+/*
+ * 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/scalar.hpp"
+#include "proton/type_traits.hpp"
+
+#include <ostream>
+
+namespace proton {
+
+scalar::scalar() { atom_.type = PN_NULL; }
+
+type_id scalar::type() const { return type_id(atom_.type); }
+bool scalar::empty() const { return type() == NULL_TYPE; }
+
+scalar::scalar(bool x) { atom_.u.as_bool = x; atom_.type = PN_BOOL; }
+scalar::scalar(uint8_t x) { atom_.u.as_ubyte = x; atom_.type = PN_UBYTE; }
+scalar::scalar(int8_t x) { atom_.u.as_byte = x; atom_.type = PN_BYTE; }
+scalar::scalar(uint16_t x) { atom_.u.as_ushort = x; atom_.type = PN_USHORT; }
+scalar::scalar(int16_t x) { atom_.u.as_short = x; atom_.type = PN_SHORT; }
+scalar::scalar(uint32_t x) { atom_.u.as_uint = x; atom_.type = PN_UINT; }
+scalar::scalar(int32_t x) { atom_.u.as_int = x; atom_.type = PN_INT; }
+scalar::scalar(uint64_t x) { atom_.u.as_ulong = x; atom_.type = PN_ULONG; }
+scalar::scalar(int64_t x) { atom_.u.as_long = x; atom_.type = PN_LONG; }
+scalar::scalar(wchar_t x) { atom_.u.as_char = pn_char_t(x); atom_.type = PN_CHAR; }
+scalar::scalar(float x) { atom_.u.as_float = x; atom_.type = PN_FLOAT; }
+scalar::scalar(double x) { atom_.u.as_double = x; atom_.type = PN_DOUBLE; }
+scalar::scalar(amqp_timestamp x) { atom_.u.as_timestamp = x; atom_.type = PN_TIMESTAMP; }
+scalar::scalar(const amqp_decimal32& x) { atom_.u.as_decimal32 = x; atom_.type = PN_DECIMAL32; }
+scalar::scalar(const amqp_decimal64& x) { atom_.u.as_decimal64 = x; atom_.type = PN_DECIMAL64; }
+scalar::scalar(const amqp_decimal128& x) { atom_.u.as_decimal128 = x; atom_.type = PN_DECIMAL128; }
+scalar::scalar(const amqp_uuid& x) { atom_.u.as_uuid = x; atom_.type = PN_UUID; }
+
+void scalar::set(const std::string& x) { str_ = x; atom_.u.as_bytes = pn_bytes(str_); }
+scalar::scalar(const amqp_string& x) { set(x); atom_.type = PN_STRING; }
+scalar::scalar(const amqp_symbol& x) { set(x); atom_.type = PN_SYMBOL; }
+scalar::scalar(const amqp_binary& x) { set(x); atom_.type = PN_BINARY; }
+scalar::scalar(const std::string& x) { *this = amqp_string(x); }
+scalar::scalar(const char* x) { *this = amqp_string(x); }
+
+void scalar::ok(pn_type_t t) const {
+    if (atom_.type != t) throw type_mismatch(type_id(t), type());
+}
+
+void scalar::get(bool& x) const { ok(PN_BOOL); x = atom_.u.as_bool; }
+void scalar::get(uint8_t& x) const { ok(PN_UBYTE); x = atom_.u.as_ubyte; }
+void scalar::get(int8_t& x) const { ok(PN_BYTE); x = atom_.u.as_byte; }
+void scalar::get(uint16_t& x) const { ok(PN_USHORT); x = atom_.u.as_ushort; }
+void scalar::get(int16_t& x) const { ok(PN_SHORT); x = atom_.u.as_short; }
+void scalar::get(uint32_t& x) const { ok(PN_UINT); x = atom_.u.as_uint; }
+void scalar::get(int32_t& x) const { ok(PN_INT); x = atom_.u.as_int; }
+void scalar::get(wchar_t& x) const { ok(PN_CHAR); x = wchar_t(atom_.u.as_char); }
+void scalar::get(uint64_t& x) const { ok(PN_ULONG); x = atom_.u.as_ulong; }
+void scalar::get(int64_t& x) const { ok(PN_LONG); x = atom_.u.as_long; }
+void scalar::get(amqp_timestamp& x) const { ok(PN_TIMESTAMP); x = atom_.u.as_timestamp; }
+void scalar::get(float& x) const { ok(PN_FLOAT); x = atom_.u.as_float; }
+void scalar::get(double& x) const { ok(PN_DOUBLE); x = atom_.u.as_double; }
+void scalar::get(amqp_decimal32& x) const { ok(PN_DECIMAL32); x = atom_.u.as_decimal32; }
+void scalar::get(amqp_decimal64& x) const { ok(PN_DECIMAL64); x = atom_.u.as_decimal64; }
+void scalar::get(amqp_decimal128& x) const { ok(PN_DECIMAL128); x = atom_.u.as_decimal128; }
+void scalar::get(amqp_uuid& x) const { ok(PN_UUID); x = atom_.u.as_uuid; }
+void scalar::get(amqp_string& x) const { ok(PN_STRING); x = str_; }
+void scalar::get(amqp_symbol& x) const { ok(PN_SYMBOL); x = str_; }
+void scalar::get(amqp_binary& x) const { ok(PN_BINARY); x = str_; }
+void scalar::get(std::string& x) const { x = get<amqp_string>(); }
+
+int64_t scalar::as_int() const {
+    if (type_id_is_floating_point(type()))
+        return int64_t(as_double());
+    switch (atom_.type) {
+      case PN_BOOL: return atom_.u.as_bool;
+      case PN_UBYTE: return atom_.u.as_ubyte;
+      case PN_BYTE: return atom_.u.as_byte;
+      case PN_USHORT: return atom_.u.as_ushort;
+      case PN_SHORT: return atom_.u.as_short;
+      case PN_UINT: return atom_.u.as_uint;
+      case PN_INT: return atom_.u.as_int;
+      case PN_CHAR: return atom_.u.as_char;
+      case PN_ULONG: return int64_t(atom_.u.as_ulong);
+      case PN_LONG: return atom_.u.as_long;
+      default: throw type_mismatch(LONG, type(), "cannot convert");
+    }
+}
+
+uint64_t scalar::as_uint() const {
+    if  (!type_id_is_integral(type()))
+        throw type_mismatch(ULONG, type(), "cannot convert");
+    return uint64_t(as_int());
+}
+
+double scalar::as_double() const {
+    if (type_id_is_integral(type())) {
+        return type_id_is_signed(type()) ? double(as_int()) : double(as_uint());
+    }
+    switch (atom_.type) {
+      case PN_DOUBLE: return atom_.u.as_double;
+      case PN_FLOAT: return atom_.u.as_float;
+      default: throw type_mismatch(DOUBLE, type(), "cannot convert");
+    }
+}
+
+std::string scalar::as_string() const {
+    if (type_id_is_string_like(type()))
+        return str_;
+    throw type_mismatch(DOUBLE, type(), "cannot convert");
+}
+
+
+namespace {
+template <class T, class F> T type_switch(const scalar& a, F f) {
+    switch(a.type()) {
+      case BOOLEAN: return f(a.get<bool>());
+      case UBYTE: return f(a.get<uint8_t>());
+      case BYTE: return f(a.get<int8_t>());
+      case USHORT: return f(a.get<uint16_t>());
+      case SHORT: return f(a.get<int16_t>());
+      case UINT: return f(a.get<uint32_t>());
+      case INT: return f(a.get<int32_t>());
+      case CHAR: return f(a.get<wchar_t>());
+      case ULONG: return f(a.get<uint64_t>());
+      case LONG: return f(a.get<int64_t>());
+      case TIMESTAMP: return f(a.get<amqp_timestamp>());
+      case FLOAT: return f(a.get<float>());
+      case DOUBLE: return f(a.get<double>());
+      case DECIMAL32: return f(a.get<amqp_decimal32>());
+      case DECIMAL64: return f(a.get<amqp_decimal64>());
+      case DECIMAL128: return f(a.get<amqp_decimal128>());
+      case UUID: return f(a.get<amqp_uuid>());
+      case BINARY: return f(a.get<amqp_binary>());
+      case STRING: return f(a.get<amqp_string>());
+      case SYMBOL: return f(a.get<amqp_symbol>());
+      default:
+        throw error("bad scalar type");
+    }
+}
+
+struct equal_op {
+    const scalar& a;
+    equal_op(const scalar& a_) : a(a_) {}
+    template<class T> bool operator()(T x) { return x == a.get<T>(); }
+};
+
+struct less_op {
+    const scalar& a;
+    less_op(const scalar& a_) : a(a_) {}
+    template<class T> bool operator()(T x) { return x < a.get<T>(); }
+};
+
+struct ostream_op {
+    std::ostream& o;
+    ostream_op(std::ostream& o_) : o(o_) {}
+    template<class T> std::ostream& operator()(T x) { return o << x; }
+};
+
+} // namespace
+
+bool scalar::operator==(const scalar& x) const {
+    return type_switch<bool>(*this, equal_op(x));
+}
+
+bool scalar::operator<(const scalar& x) const {
+    return type_switch<bool>(*this, less_op(x));
+}
+
+std::ostream& operator<<(std::ostream& o, const scalar& a) {
+    return type_switch<std::ostream&>(a, ostream_op(o));
+}
+
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d2c5a5f2/proton-c/bindings/cpp/src/scalar_test.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/scalar_test.cpp b/proton-c/bindings/cpp/src/scalar_test.cpp
new file mode 100644
index 0000000..c7de785
--- /dev/null
+++ b/proton-c/bindings/cpp/src/scalar_test.cpp
@@ -0,0 +1,105 @@
+/*
+ * 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 "test_bits.hpp"
+#include "proton/type_traits.hpp"
+
+#include <proton/scalar.hpp>
+
+using namespace std;
+using namespace proton;
+
+// Inserting and extracting simple C++ values.
+template <class T> void type_test(T x, type_id tid, T y) {
+    scalar v(x);
+    ASSERT_EQUAL(tid, v.type());
+    ASSERT(!v.empty());
+    ASSERT_EQUAL(x, v.get<T>());
+
+    scalar v2;
+    ASSERT(v2.type() == NULL_TYPE);
+    v2 = x;
+    ASSERT_EQUAL(tid, v2.type());
+    ASSERT_EQUAL(x, v2.get<T>());
+    ASSERT_EQUAL(v, v2);
+    ASSERT_EQUAL(str(x), str(v));
+
+    v2 = y;
+    ASSERT(v != v2);
+    ASSERT(v < v2);
+    ASSERT(v2 > v);
+}
+
+#define ASSERT_MISMATCH(EXPR) \
+    try { (void)(EXPR); FAIL("expected type_mismatch: " #EXPR); } catch (type_mismatch) {}
+
+void convert_test() {
+    scalar a;
+    ASSERT_EQUAL(NULL_TYPE, a.type());
+    ASSERT(a.empty());
+    ASSERT_MISMATCH(a.get<float>());
+
+    a = amqp_binary("foo");
+    ASSERT_MISMATCH(a.get<int16_t>());
+    ASSERT_MISMATCH(a.as_int());
+    ASSERT_MISMATCH(a.as_double());
+    ASSERT_MISMATCH(a.get<amqp_string>());           // No strict conversion
+    ASSERT_EQUAL(a.as_string(), std::string("foo")); // OK string-like conversion
+
+    a = int16_t(42);
+    ASSERT_MISMATCH(a.get<std::string>());
+    ASSERT_MISMATCH(a.get<amqp_timestamp>());
+    ASSERT_MISMATCH(a.as_string());
+    ASSERT_EQUAL(a.as_int(), 42);
+    ASSERT_EQUAL(a.as_uint(), 42);
+    ASSERT_EQUAL(a.as_double(), 42);
+
+    a = int16_t(-42);
+    ASSERT_EQUAL(a.as_int(), -42);
+    ASSERT_EQUAL(a.as_uint(), uint64_t(-42));
+    ASSERT_EQUAL(a.as_double(), -42);
+}
+
+int main(int, char**) {
+    int failed = 0;
+    RUN_TEST(failed, type_test(false, BOOLEAN, true));
+    RUN_TEST(failed, type_test(amqp_ubyte(42), UBYTE, amqp_ubyte(50)));
+    RUN_TEST(failed, type_test(amqp_byte('x'), BYTE, amqp_byte('y')));
+    RUN_TEST(failed, type_test(amqp_ushort(4242), USHORT, amqp_ushort(5252)));
+    RUN_TEST(failed, type_test(amqp_short(-4242), SHORT, amqp_short(3)));
+    RUN_TEST(failed, type_test(amqp_uint(4242), UINT, amqp_uint(5252)));
+    RUN_TEST(failed, type_test(amqp_int(-4242), INT, amqp_int(3)));
+    RUN_TEST(failed, type_test(amqp_ulong(4242), ULONG, amqp_ulong(5252)));
+    RUN_TEST(failed, type_test(amqp_long(-4242), LONG, amqp_long(3)));
+    RUN_TEST(failed, type_test(wchar_t(23), CHAR, wchar_t(24)));
+    RUN_TEST(failed, type_test(amqp_float(1.234), FLOAT, amqp_float(2.345)));
+    RUN_TEST(failed, type_test(amqp_double(11.2233), DOUBLE, amqp_double(12)));
+    RUN_TEST(failed, type_test(amqp_timestamp(0), TIMESTAMP, amqp_timestamp(1)));
+    RUN_TEST(failed, type_test(amqp_decimal32(0), DECIMAL32, amqp_decimal32(1)));
+    RUN_TEST(failed, type_test(amqp_decimal64(0), DECIMAL64, amqp_decimal64(1)));
+    pn_decimal128_t da = {0}, db = {1};
+    RUN_TEST(failed, type_test(amqp_decimal128(da), DECIMAL128, amqp_decimal128(db)));
+    pn_uuid_t ua = {0}, ub = {1};
+    RUN_TEST(failed, type_test(amqp_uuid(ua), UUID, amqp_uuid(ub)));
+    RUN_TEST(failed, type_test(amqp_string("aaa"), STRING, amqp_string("aaaa")));
+    RUN_TEST(failed, type_test(amqp_symbol("aaa"), SYMBOL, amqp_symbol("aaaa")));
+    RUN_TEST(failed, type_test(amqp_binary("aaa"), BINARY, amqp_binary("aaaa")));
+    RUN_TEST(failed, type_test(std::string("xxx"), STRING, std::string("yyy")));
+    return failed;
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d2c5a5f2/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 d8e40ce..fa7b0bd 100644
--- a/proton-c/bindings/cpp/src/types.cpp
+++ b/proton-c/bindings/cpp/src/types.cpp
@@ -95,15 +95,15 @@ std::string type_name(type_id t) {
     return "unknown";
 }
 
-static bool type_id_signed_int(type_id t) { return t == BYTE || t == SHORT || t == INT || t == LONG; }
-static bool type_id_unsigned_int(type_id t) { return t == UBYTE || t == USHORT || t == UINT || t == ULONG; }
-bool type_id_integral(type_id t) { return t == BOOLEAN || t == CHAR || type_id_unsigned_int(t) || type_id_signed_int(t); }
-bool type_id_floating_point(type_id t) { return t == FLOAT || t == DOUBLE; }
-bool type_id_decimal(type_id t) { return t == DECIMAL32 || t == DECIMAL64 || t == DECIMAL128; }
-bool type_id_signed(type_id t) { return type_id_signed_int(t) || type_id_floating_point(t) || type_id_decimal(t); }
-bool type_id_string_like(type_id t) { return t == BINARY || t == STRING || t == SYMBOL; }
-bool type_id_container(type_id t) { return t == LIST || t == MAP || t == ARRAY || t == DESCRIBED; }
-bool type_id_atom(type_id t) { return type_id_integral(t) || type_id_floating_point(t) || type_id_decimal(t) || type_id_string_like(t) || t == TIMESTAMP || t == UUID; }
+static bool type_id_is_signed_int(type_id t) { return t == BYTE || t == SHORT || t == INT || t == LONG; }
+static bool type_id_is_unsigned_int(type_id t) { return t == UBYTE || t == USHORT || t == UINT || t == ULONG; }
+bool type_id_is_integral(type_id t) { return t == BOOLEAN || t == CHAR || type_id_is_unsigned_int(t) || type_id_is_signed_int(t); }
+bool type_id_is_floating_point(type_id t) { return t == FLOAT || t == DOUBLE; }
+bool type_id_is_decimal(type_id t) { return t == DECIMAL32 || t == DECIMAL64 || t == DECIMAL128; }
+bool type_id_is_signed(type_id t) { return type_id_is_signed_int(t) || type_id_is_floating_point(t) || type_id_is_decimal(t); }
+bool type_id_is_string_like(type_id t) { return t == BINARY || t == STRING || t == SYMBOL; }
+bool type_id_is_container(type_id t) { return t == LIST || t == MAP || t == ARRAY || t == DESCRIBED; }
+bool type_id_is_scalar(type_id t) { return type_id_is_integral(t) || type_id_is_floating_point(t) || type_id_is_decimal(t) || type_id_is_string_like(t) || t == TIMESTAMP || t == UUID; }
 
 
 std::ostream& operator<<(std::ostream& o,type_id t) { return o << type_name(t); }


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org


[2/4] qpid-proton git commit: PROTON-1085: c++: clean up access to message properties, instructions and annotations.

Posted by ac...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1622d0e6/proton-c/bindings/cpp/src/scalar.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/scalar.cpp b/proton-c/bindings/cpp/src/scalar.cpp
index 13daf32..9e8d124 100644
--- a/proton-c/bindings/cpp/src/scalar.cpp
+++ b/proton-c/bindings/cpp/src/scalar.cpp
@@ -17,6 +17,7 @@
  * under the License.
  */
 
+#include "msg.hpp"
 #include "proton/scalar.hpp"
 #include "proton/type_traits.hpp"
 
@@ -25,37 +26,50 @@
 namespace proton {
 
 scalar::scalar() { atom_.type = PN_NULL; }
+scalar::scalar(const scalar& x) { set(x.atom_); }
+scalar& scalar::operator=(const scalar& x) { set(x.atom_); return *this; }
 
 type_id scalar::type() const { return type_id(atom_.type); }
 bool scalar::empty() const { return type() == NULL_TYPE; }
 
-scalar::scalar(bool x) { atom_.u.as_bool = x; atom_.type = PN_BOOL; }
-scalar::scalar(uint8_t x) { atom_.u.as_ubyte = x; atom_.type = PN_UBYTE; }
-scalar::scalar(int8_t x) { atom_.u.as_byte = x; atom_.type = PN_BYTE; }
-scalar::scalar(uint16_t x) { atom_.u.as_ushort = x; atom_.type = PN_USHORT; }
-scalar::scalar(int16_t x) { atom_.u.as_short = x; atom_.type = PN_SHORT; }
-scalar::scalar(uint32_t x) { atom_.u.as_uint = x; atom_.type = PN_UINT; }
-scalar::scalar(int32_t x) { atom_.u.as_int = x; atom_.type = PN_INT; }
-scalar::scalar(uint64_t x) { atom_.u.as_ulong = x; atom_.type = PN_ULONG; }
-scalar::scalar(int64_t x) { atom_.u.as_long = x; atom_.type = PN_LONG; }
-scalar::scalar(wchar_t x) { atom_.u.as_char = pn_char_t(x); atom_.type = PN_CHAR; }
-scalar::scalar(float x) { atom_.u.as_float = x; atom_.type = PN_FLOAT; }
-scalar::scalar(double x) { atom_.u.as_double = x; atom_.type = PN_DOUBLE; }
-scalar::scalar(amqp_timestamp x) { atom_.u.as_timestamp = x; atom_.type = PN_TIMESTAMP; }
-scalar::scalar(const amqp_decimal32& x) { atom_.u.as_decimal32 = x; atom_.type = PN_DECIMAL32; }
-scalar::scalar(const amqp_decimal64& x) { atom_.u.as_decimal64 = x; atom_.type = PN_DECIMAL64; }
-scalar::scalar(const amqp_decimal128& x) { atom_.u.as_decimal128 = x; atom_.type = PN_DECIMAL128; }
-scalar::scalar(const amqp_uuid& x) { atom_.u.as_uuid = x; atom_.type = PN_UUID; }
-
-void scalar::set(const std::string& x) { str_ = x; atom_.u.as_bytes = pn_bytes(str_); }
-scalar::scalar(const amqp_string& x) { set(x); atom_.type = PN_STRING; }
-scalar::scalar(const amqp_symbol& x) { set(x); atom_.type = PN_SYMBOL; }
-scalar::scalar(const amqp_binary& x) { set(x); atom_.type = PN_BINARY; }
-scalar::scalar(const std::string& x) { *this = amqp_string(x); }
-scalar::scalar(const char* x) { *this = amqp_string(x); }
+void scalar::set(const std::string& x, pn_type_t t) {
+    atom_.type = t;
+    str_ = x;
+    atom_.u.as_bytes = pn_bytes(str_);
+}
+
+void scalar::set(const pn_atom_t& atom) {
+    if (type_id_is_string_like(type_id(atom.type)))
+        set(str(atom.u.as_bytes), atom.type);
+    else
+        atom_ = atom;
+}
+
+scalar& scalar::operator=(bool x) { atom_.u.as_bool = x; atom_.type = PN_BOOL; return *this; }
+scalar& scalar::operator=(uint8_t x) { atom_.u.as_ubyte = x; atom_.type = PN_UBYTE; return *this; }
+scalar& scalar::operator=(int8_t x) { atom_.u.as_byte = x; atom_.type = PN_BYTE; return *this; }
+scalar& scalar::operator=(uint16_t x) { atom_.u.as_ushort = x; atom_.type = PN_USHORT; return *this; }
+scalar& scalar::operator=(int16_t x) { atom_.u.as_short = x; atom_.type = PN_SHORT; return *this; }
+scalar& scalar::operator=(uint32_t x) { atom_.u.as_uint = x; atom_.type = PN_UINT; return *this; }
+scalar& scalar::operator=(int32_t x) { atom_.u.as_int = x; atom_.type = PN_INT; return *this; }
+scalar& scalar::operator=(uint64_t x) { atom_.u.as_ulong = x; atom_.type = PN_ULONG; return *this; }
+scalar& scalar::operator=(int64_t x) { atom_.u.as_long = x; atom_.type = PN_LONG; return *this; }
+scalar& scalar::operator=(wchar_t x) { atom_.u.as_char = x; atom_.type = PN_CHAR; return *this; }
+scalar& scalar::operator=(float x) { atom_.u.as_float = x; atom_.type = PN_FLOAT; return *this; }
+scalar& scalar::operator=(double x) { atom_.u.as_double = x; atom_.type = PN_DOUBLE; return *this; }
+scalar& scalar::operator=(amqp_timestamp x) { atom_.u.as_timestamp = x; atom_.type = PN_TIMESTAMP; return *this; }
+scalar& scalar::operator=(const amqp_decimal32& x) { atom_.u.as_decimal32 = x; atom_.type = PN_DECIMAL32; return *this; }
+scalar& scalar::operator=(const amqp_decimal64& x) { atom_.u.as_decimal64 = x; atom_.type = PN_DECIMAL64; return *this; }
+scalar& scalar::operator=(const amqp_decimal128& x) { atom_.u.as_decimal128 = x; atom_.type = PN_DECIMAL128; return *this; }
+scalar& scalar::operator=(const amqp_uuid& x) { atom_.u.as_uuid = x; atom_.type = PN_UUID; return *this; }
+scalar& scalar::operator=(const amqp_string& x) { set(x, PN_STRING); return *this; }
+scalar& scalar::operator=(const amqp_symbol& x) { set(x, PN_SYMBOL); return *this; }
+scalar& scalar::operator=(const amqp_binary& x) { set(x, PN_BINARY); return *this; }
+scalar& scalar::operator=(const std::string& x) { set(x, PN_STRING); return *this; }
+scalar& scalar::operator=(const char* x) { set(x, PN_STRING); return *this; }
 
 void scalar::ok(pn_type_t t) const {
-    if (atom_.type != t) throw type_mismatch(type_id(t), type());
+    if (atom_.type != t) throw type_error(type_id(t), type());
 }
 
 void scalar::get(bool& x) const { ok(PN_BOOL); x = atom_.u.as_bool; }
@@ -75,9 +89,9 @@ void scalar::get(amqp_decimal32& x) const { ok(PN_DECIMAL32); x = atom_.u.as_dec
 void scalar::get(amqp_decimal64& x) const { ok(PN_DECIMAL64); x = atom_.u.as_decimal64; }
 void scalar::get(amqp_decimal128& x) const { ok(PN_DECIMAL128); x = atom_.u.as_decimal128; }
 void scalar::get(amqp_uuid& x) const { ok(PN_UUID); x = atom_.u.as_uuid; }
-void scalar::get(amqp_string& x) const { ok(PN_STRING); x = str_; }
-void scalar::get(amqp_symbol& x) const { ok(PN_SYMBOL); x = str_; }
-void scalar::get(amqp_binary& x) const { ok(PN_BINARY); x = str_; }
+void scalar::get(amqp_string& x) const { ok(PN_STRING); x = amqp_string(str_); }
+void scalar::get(amqp_symbol& x) const { ok(PN_SYMBOL); x = amqp_symbol(str_); }
+void scalar::get(amqp_binary& x) const { ok(PN_BINARY); x = amqp_binary(str_); }
 void scalar::get(std::string& x) const { x = get<amqp_string>(); }
 
 int64_t scalar::as_int() const {
@@ -94,13 +108,14 @@ int64_t scalar::as_int() const {
       case PN_CHAR: return atom_.u.as_char;
       case PN_ULONG: return int64_t(atom_.u.as_ulong);
       case PN_LONG: return atom_.u.as_long;
-      default: throw type_mismatch(LONG, type(), "cannot convert");
+      case PN_TIMESTAMP: return atom_.u.as_timestamp;
+      default: throw type_error(LONG, type(), "cannot convert");
     }
 }
 
 uint64_t scalar::as_uint() const {
     if  (!type_id_is_integral(type()))
-        throw type_mismatch(ULONG, type(), "cannot convert");
+        throw type_error(ULONG, type(), "cannot convert");
     return uint64_t(as_int());
 }
 
@@ -111,18 +126,19 @@ double scalar::as_double() const {
     switch (atom_.type) {
       case PN_DOUBLE: return atom_.u.as_double;
       case PN_FLOAT: return atom_.u.as_float;
-      default: throw type_mismatch(DOUBLE, type(), "cannot convert");
+      default: throw type_error(DOUBLE, type(), "cannot convert");
     }
 }
 
 std::string scalar::as_string() const {
     if (type_id_is_string_like(type()))
         return str_;
-    throw type_mismatch(DOUBLE, type(), "cannot convert");
+    throw type_error(STRING, type(), "cannot convert");
 }
 
-
 namespace {
+template<class T> int opaque_cmp(const T& x, const T& y) { return memcmp(&x, &y, sizeof(T)); }
+
 template <class T, class F> T type_switch(const scalar& a, F f) {
     switch(a.type()) {
       case BOOLEAN: return f(a.get<bool>());
@@ -170,16 +186,21 @@ struct ostream_op {
 
 } // namespace
 
-bool scalar::operator==(const scalar& x) const {
-    return type_switch<bool>(*this, equal_op(x));
+bool operator==(const scalar& x, const scalar& y) {
+    if (x.type() != y.type()) return false;
+    if (x.empty()) return true;
+    return type_switch<bool>(x, equal_op(y));
 }
 
-bool scalar::operator<(const scalar& x) const {
-    return type_switch<bool>(*this, less_op(x));
+bool operator<(const scalar& x, const scalar& y) {
+    if (x.type() != y.type()) return x.type() < y.type();
+    if (x.empty()) return false;
+    return type_switch<bool>(x, less_op(y));
 }
 
 std::ostream& operator<<(std::ostream& o, const scalar& a) {
+    if (a.empty()) return o << "<null>";
     return type_switch<std::ostream&>(a, ostream_op(o));
 }
 
-}
+} // namespace proton

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1622d0e6/proton-c/bindings/cpp/src/scalar_test.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/scalar_test.cpp b/proton-c/bindings/cpp/src/scalar_test.cpp
index c7de785..cb66e41 100644
--- a/proton-c/bindings/cpp/src/scalar_test.cpp
+++ b/proton-c/bindings/cpp/src/scalar_test.cpp
@@ -21,51 +21,62 @@
 #include "proton/type_traits.hpp"
 
 #include <proton/scalar.hpp>
+#include <proton/value.hpp>
+#include <proton/message_id.hpp>
+#include <proton/annotation_key.hpp>
+
+#include <sstream>
 
 using namespace std;
 using namespace proton;
 
 // Inserting and extracting simple C++ values.
 template <class T> void type_test(T x, type_id tid, T y) {
-    scalar v(x);
-    ASSERT_EQUAL(tid, v.type());
-    ASSERT(!v.empty());
-    ASSERT_EQUAL(x, v.get<T>());
+    scalar s(x);
+    ASSERT_EQUAL(tid, s.type());
+    ASSERT(!s.empty());
+    ASSERT_EQUAL(x, s.get<T>());
 
     scalar v2;
     ASSERT(v2.type() == NULL_TYPE);
     v2 = x;
     ASSERT_EQUAL(tid, v2.type());
     ASSERT_EQUAL(x, v2.get<T>());
-    ASSERT_EQUAL(v, v2);
-    ASSERT_EQUAL(str(x), str(v));
+    ASSERT_EQUAL(s, v2);
+    ASSERT_EQUAL(str(x), str(s));
 
     v2 = y;
-    ASSERT(v != v2);
-    ASSERT(v < v2);
-    ASSERT(v2 > v);
+    ASSERT(s != v2);
+    ASSERT(s < v2);
+    ASSERT(v2 > s);
 }
 
-#define ASSERT_MISMATCH(EXPR) \
-    try { (void)(EXPR); FAIL("expected type_mismatch: " #EXPR); } catch (type_mismatch) {}
+#define ASSERT_MISMATCH(EXPR, WANT, GOT)                        \
+    try {                                                       \
+        (void)(EXPR);                                           \
+        FAIL("expected type_error: " #EXPR);                    \
+    } catch (const type_error& e) {                             \
+        ASSERT_EQUAL(WANT, e.want);                             \
+        ASSERT_EQUAL(GOT, e.got);                               \
+    }
 
 void convert_test() {
     scalar a;
     ASSERT_EQUAL(NULL_TYPE, a.type());
     ASSERT(a.empty());
-    ASSERT_MISMATCH(a.get<float>());
+    ASSERT_MISMATCH(a.get<float>(), FLOAT, NULL_TYPE);
 
     a = amqp_binary("foo");
-    ASSERT_MISMATCH(a.get<int16_t>());
-    ASSERT_MISMATCH(a.as_int());
-    ASSERT_MISMATCH(a.as_double());
-    ASSERT_MISMATCH(a.get<amqp_string>());           // No strict conversion
+    ASSERT_MISMATCH(a.get<int16_t>(), SHORT, BINARY);
+    ASSERT_MISMATCH(a.as_int(), LONG, BINARY);
+    ASSERT_MISMATCH(a.as_double(), DOUBLE, BINARY);
+    ASSERT_MISMATCH(a.get<amqp_string>(), STRING, BINARY); // No strict conversion
     ASSERT_EQUAL(a.as_string(), std::string("foo")); // OK string-like conversion
 
     a = int16_t(42);
-    ASSERT_MISMATCH(a.get<std::string>());
-    ASSERT_MISMATCH(a.get<amqp_timestamp>());
-    ASSERT_MISMATCH(a.as_string());
+    ASSERT_MISMATCH(a.get<std::string>(), STRING, SHORT);
+    ASSERT_MISMATCH(a.get<amqp_timestamp>(), TIMESTAMP, SHORT);
+    ASSERT_MISMATCH(a.as_string(), STRING, SHORT);
     ASSERT_EQUAL(a.as_int(), 42);
     ASSERT_EQUAL(a.as_uint(), 42);
     ASSERT_EQUAL(a.as_double(), 42);
@@ -76,6 +87,33 @@ void convert_test() {
     ASSERT_EQUAL(a.as_double(), -42);
 }
 
+void encode_decode_test() {
+    value v;
+    scalar a("foo");
+    v = a;                      // Assignment to value does encode, get<> does decode.
+    ASSERT_EQUAL(v, a);
+    ASSERT_EQUAL(std::string("foo"), v.get<std::string>());
+    scalar a2 = v.get<scalar>();
+    ASSERT_EQUAL(std::string("foo"), a2.get<std::string>());
+}
+
+void message_id_test() {
+    ASSERT_EQUAL(23, message_id(23).as_int());
+    ASSERT_EQUAL(23, message_id(23).get<uint64_t>());
+    ASSERT(message_id("foo") != message_id(amqp_binary("foo")));
+    ASSERT_EQUAL(scalar("foo"), message_id("foo"));
+    ASSERT_EQUAL("foo", message_id("foo").as_string());
+    ASSERT(message_id("a") < message_id("z"));
+    ASSERT_EQUAL(amqp_uuid(), message_id(amqp_uuid()).get<amqp_uuid>());
+}
+
+void annotation_key_test() {
+    ASSERT_EQUAL(23, annotation_key(23).as_int());
+    ASSERT_EQUAL(23, annotation_key(23).get<uint64_t>());
+    ASSERT_EQUAL("foo", annotation_key("foo").as_string());
+    ASSERT_EQUAL(scalar(amqp_symbol("foo")), annotation_key("foo"));
+}
+
 int main(int, char**) {
     int failed = 0;
     RUN_TEST(failed, type_test(false, BOOLEAN, true));
@@ -101,5 +139,9 @@ int main(int, char**) {
     RUN_TEST(failed, type_test(amqp_symbol("aaa"), SYMBOL, amqp_symbol("aaaa")));
     RUN_TEST(failed, type_test(amqp_binary("aaa"), BINARY, amqp_binary("aaaa")));
     RUN_TEST(failed, type_test(std::string("xxx"), STRING, std::string("yyy")));
+    RUN_TEST(failed, encode_decode_test());
+    RUN_TEST(failed, message_id_test());
+    RUN_TEST(failed, annotation_key_test());
+    RUN_TEST(failed, convert_test());
     return failed;
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1622d0e6/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 fa7b0bd..7a38f12 100644
--- a/proton-c/bindings/cpp/src/types.cpp
+++ b/proton-c/bindings/cpp/src/types.cpp
@@ -33,20 +33,18 @@ inline std::ostream& print_segment(std::ostream& o, const amqp_uuid& u, size_t b
     return o << sep;
 }
 
-std::string mismatch_message(type_id want, type_id got, const std::string& msg=std::string())
-{
+std::string mismatch_message(type_id want, type_id got, const std::string& msg=std::string()) {
     std::ostringstream s;
-    s << "type mismatch: want " << type_name(want) << " got " << type_name(got);
+    s << "want " << want << " got " << got;
     if (!msg.empty()) s << ": " << msg;
     return s.str();
 }
-}
+} // namespace
 
-type_mismatch::type_mismatch(type_id want_, type_id got_, const std::string &msg)
-    : error(mismatch_message(want_, got_, msg)), want(want_), got(got_)
+type_error::type_error(type_id want_, type_id got_, const std::string &msg)
+    : decode_error(mismatch_message(want_, got_, msg)), want(want_), got(got_)
 {}
 
-
 std::ostream& operator<<(std::ostream& o, const amqp_decimal32&) { return o << "<decimal32>"; }
 std::ostream& operator<<(std::ostream& o, const amqp_decimal64&) { return o << "<decimal64>"; }
 std::ostream& operator<<(std::ostream& o, const amqp_decimal128&) { return o << "<decimal128>"; }
@@ -95,9 +93,9 @@ std::string type_name(type_id t) {
     return "unknown";
 }
 
-static bool type_id_is_signed_int(type_id t) { return t == BYTE || t == SHORT || t == INT || t == LONG; }
-static bool type_id_is_unsigned_int(type_id t) { return t == UBYTE || t == USHORT || t == UINT || t == ULONG; }
-bool type_id_is_integral(type_id t) { return t == BOOLEAN || t == CHAR || type_id_is_unsigned_int(t) || type_id_is_signed_int(t); }
+bool type_id_is_signed_int(type_id t) { return t == BYTE || t == SHORT || t == INT || t == LONG; }
+bool type_id_is_unsigned_int(type_id t) { return t == UBYTE || t == USHORT || t == UINT || t == ULONG; }
+bool type_id_is_integral(type_id t) { return t == BOOLEAN || t == CHAR || t == TIMESTAMP || type_id_is_unsigned_int(t) || type_id_is_signed_int(t); }
 bool type_id_is_floating_point(type_id t) { return t == FLOAT || t == DOUBLE; }
 bool type_id_is_decimal(type_id t) { return t == DECIMAL32 || t == DECIMAL64 || t == DECIMAL128; }
 bool type_id_is_signed(type_id t) { return type_id_is_signed_int(t) || type_id_is_floating_point(t) || type_id_is_decimal(t); }
@@ -106,7 +104,7 @@ bool type_id_is_container(type_id t) { return t == LIST || t == MAP || t == ARRA
 bool type_id_is_scalar(type_id t) { return type_id_is_integral(t) || type_id_is_floating_point(t) || type_id_is_decimal(t) || type_id_is_string_like(t) || t == TIMESTAMP || t == UUID; }
 
 
-std::ostream& operator<<(std::ostream& o,type_id t) { return o << type_name(t); }
+std::ostream& operator<<(std::ostream& o, type_id t) { return o << type_name(t); }
 
 
 pn_bytes_t pn_bytes(const std::string& s) {

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1622d0e6/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 b603bf9..bf652c5 100644
--- a/proton-c/bindings/cpp/src/value.cpp
+++ b/proton-c/bindings/cpp/src/value.cpp
@@ -30,8 +30,20 @@ value::value() : data_(data::create()) {}
 
 value::value(const value& x) : data_(data::create()) { data_.copy(x.data_); }
 
+#if PN_HAS_CPP11
+value::value(value&& x) : data_(0) { swap(x); }
+#endif
+
+// Referencing an external value
+value::value(data d) : data_(d) {}
+
+// Referencing an external value
+value& value::ref(data d) { data_ = d; return *this; }
+
 value& value::operator=(const value& x) { data_.copy(x.data_); return *this; }
 
+void value::swap(value& x) { std::swap(data_, x.data_); }
+
 void value::clear() { data_.clear(); }
 
 bool value::empty() const { return data_.empty(); }
@@ -48,6 +60,8 @@ bool value::operator<(const value& x) const { return data_.less(x.data_); }
 
 std::ostream& operator<<(std::ostream& o, const value& v) {
     // pn_inspect prints strings with quotes which is not normal in C++.
+    if (v.empty())
+        return o << "<empty>";
     switch (v.type()) {
       case STRING:
       case SYMBOL:


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org


[4/4] qpid-proton git commit: PROTON-1085: c++: Replace all operator== and < members with free functions, drop comparable template.

Posted by ac...@apache.org.
PROTON-1085: c++: Replace all operator== and < members with free functions, drop comparable template.


Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/117bb7cb
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/117bb7cb
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/117bb7cb

Branch: refs/heads/master
Commit: 117bb7cb0bcb588f91c8a2a6a45b0cb9d211d7d6
Parents: 1622d0e
Author: Alan Conway <ac...@redhat.com>
Authored: Tue Dec 29 13:54:02 2015 -0500
Committer: Alan Conway <ac...@redhat.com>
Committed: Tue Dec 29 15:56:44 2015 -0500

----------------------------------------------------------------------
 .../bindings/cpp/include/proton/comparable.hpp  | 38 --------------------
 .../bindings/cpp/include/proton/duration.hpp    |  8 ++---
 proton-c/bindings/cpp/include/proton/object.hpp |  5 ++-
 proton-c/bindings/cpp/include/proton/scalar.hpp |  6 ++--
 proton-c/bindings/cpp/include/proton/types.hpp  | 15 ++++----
 proton-c/bindings/cpp/include/proton/value.hpp  |  8 ++---
 proton-c/bindings/cpp/src/scalar.cpp            |  1 -
 proton-c/bindings/cpp/src/value.cpp             |  4 +--
 8 files changed, 21 insertions(+), 64 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/117bb7cb/proton-c/bindings/cpp/include/proton/comparable.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/comparable.hpp b/proton-c/bindings/cpp/include/proton/comparable.hpp
deleted file mode 100644
index 2649a8d..0000000
--- a/proton-c/bindings/cpp/include/proton/comparable.hpp
+++ /dev/null
@@ -1,38 +0,0 @@
-#ifndef COMPARABLE_HPP
-#define COMPARABLE_HPP
-/*
- * 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.
- */
-
-namespace proton {
-
-///@cond INTERNAL
-
-/// Internal base class to provide comparison operators. T must provide < and ==.
-template <class T> struct comparable {
-  friend bool operator>(const T &a, const T &b) { return b < a; }
-  friend bool operator<=(const T &a, const T &b) { return !(a > b); }
-  friend bool operator>=(const T &a, const T &b) { return !(a < b); }
-  friend bool operator!=(const T &a, const T &b) { return !(a == b); }
-};
-
-///@endcond
-
-}
-
-#endif // COMPARABLE_HPP

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/117bb7cb/proton-c/bindings/cpp/include/proton/duration.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/duration.hpp b/proton-c/bindings/cpp/include/proton/duration.hpp
index e562c47..cea785f 100644
--- a/proton-c/bindings/cpp/include/proton/duration.hpp
+++ b/proton-c/bindings/cpp/include/proton/duration.hpp
@@ -28,21 +28,21 @@
 namespace proton {
 
 /** Duration in milliseconds. */
-class duration : public comparable<duration>
+class duration
 {
   public:
     amqp_ulong milliseconds;
     explicit duration(amqp_ulong ms = 0) : milliseconds(ms) {}
 
-    bool operator<(duration d) { return milliseconds < d.milliseconds; }
-    bool operator==(duration d) { return milliseconds == d.milliseconds; }
-
     PN_CPP_EXTERN static const duration FOREVER; ///< Wait for ever
     PN_CPP_EXTERN static const duration IMMEDIATE; ///< Don't wait at all
     PN_CPP_EXTERN static const duration SECOND; ///< One second
     PN_CPP_EXTERN static const duration MINUTE; ///< One minute
 };
 
+inline bool operator<(duration x, duration y) { return x.milliseconds < y.milliseconds; }
+inline bool operator==(duration x, duration y) { return x.milliseconds == y.milliseconds; }
+
 inline duration operator*(duration d, amqp_ulong n) { return duration(d.milliseconds*n); }
 inline duration operator*(amqp_ulong n, duration d) { return d * n; }
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/117bb7cb/proton-c/bindings/cpp/include/proton/object.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/object.hpp b/proton-c/bindings/cpp/include/proton/object.hpp
index e98a956..32bc086 100644
--- a/proton-c/bindings/cpp/include/proton/object.hpp
+++ b/proton-c/bindings/cpp/include/proton/object.hpp
@@ -21,7 +21,6 @@
 
 #include "proton/config.hpp"
 #include "proton/export.hpp"
-#include "proton/comparable.hpp"
 
 #include <memory>
 
@@ -34,7 +33,7 @@ class pn_ptr_base {
     PN_CPP_EXTERN static void decref(void* p);
 };
 
-template <class T> class pn_ptr : public comparable<pn_ptr<T> >, private pn_ptr_base {
+template <class T> class pn_ptr : private pn_ptr_base {
   public:
     pn_ptr() : ptr_(0) {}
     pn_ptr(T* p) : ptr_(p) { incref(ptr_); }
@@ -71,7 +70,7 @@ template <class T> pn_ptr<T> take_ownership(T* p) { return pn_ptr<T>::take_owner
 /**
  * Base class for proton object types
  */
-template <class T> class object : public comparable<object<T> > {
+template <class T> class object {
   public:
     bool operator!() const { return !object_; }
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/117bb7cb/proton-c/bindings/cpp/include/proton/scalar.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/scalar.hpp b/proton-c/bindings/cpp/include/proton/scalar.hpp
index 6fe29fa..d135ab6 100644
--- a/proton-c/bindings/cpp/include/proton/scalar.hpp
+++ b/proton-c/bindings/cpp/include/proton/scalar.hpp
@@ -29,7 +29,7 @@ class encoder;
 class decoder;
 
 /** scalar holds an instance of any scalar AMQP type. */
-class scalar : public comparable<scalar> {
+class scalar {
   public:
     PN_CPP_EXTERN scalar();
     PN_CPP_EXTERN scalar(const scalar&);
@@ -130,9 +130,9 @@ class scalar : public comparable<scalar> {
 };
 
 ///@internal base for restricted scalar types
-class restricted_scalar : public comparable<restricted_scalar> {
+class restricted_scalar {
   public:
-    operator scalar() const { return scalar_; }
+    operator const scalar&() const { return scalar_; }
     type_id type() const { return scalar_.type(); }
 
     ///@name as_ methods do "loose" conversion, they will convert the scalar's

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/117bb7cb/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 db5989b..062566a 100644
--- a/proton-c/bindings/cpp/include/proton/types.hpp
+++ b/proton-c/bindings/cpp/include/proton/types.hpp
@@ -25,7 +25,6 @@
 
 #include "proton/export.hpp"
 #include "proton/error.hpp"
-#include "proton/comparable.hpp"
 
 #include <proton/codec.h>
 #include <proton/type_compat.h>
@@ -141,7 +140,7 @@ struct amqp_binary : public std::string {
 };
 
 /// Template for opaque proton proton types that can be treated as byte arrays.
-template <class P> struct opaque: public comparable<opaque<P> > {
+template <class P> struct opaque {
     P value;
     opaque(const P& p=P()) : value(p) {}
     operator P() const { return value; }
@@ -153,11 +152,11 @@ template <class P> struct opaque: public comparable<opaque<P> > {
     const char* end() const { return reinterpret_cast<const char*>(&value)+size(); }
     char& operator[](size_t i) { return *(begin()+i); }
     const char& operator[](size_t i) const { return *(begin()+i); }
-
-    bool operator==(const opaque& x) const { return std::equal(begin(), end(), x.begin()); }
-    bool operator<(const opaque& x) const { return std::lexicographical_compare(begin(), end(), x.begin(), x.end()); }
 };
 
+template <class T> bool operator==(const opaque<T>& x, const opaque<T>& y) { return std::equal(x.begin(), x.end(), y.begin()); }
+template <class T> bool operator<(const opaque<T>& x, const opaque<T>& y) { return std::lexicographical_compare(x.begin(), x.end(), y.begin(), y.end()); }
+
 /// AMQP 16-byte UUID.
 typedef opaque<pn_uuid_t> amqp_uuid;
 PN_CPP_EXTERN std::ostream& operator<<(std::ostream&, const amqp_uuid&);
@@ -172,13 +171,13 @@ typedef opaque<pn_decimal128_t> amqp_decimal128;
 PN_CPP_EXTERN std::ostream& operator<<(std::ostream&, const amqp_decimal128&);
 
 /// AMQP timestamp, milliseconds since the epoch 00:00:00 (UTC), 1 January 1970.
-struct amqp_timestamp : public comparable<amqp_timestamp> {
+struct amqp_timestamp {
     pn_timestamp_t milliseconds;
     amqp_timestamp(::int64_t ms=0) : milliseconds(ms) {}
     operator pn_timestamp_t() const { return milliseconds; }
-    bool operator==(const amqp_timestamp& x) { return milliseconds == x.milliseconds; }
-    bool operator<(const amqp_timestamp& x) { return milliseconds < x.milliseconds; }
 };
+inline bool operator==(amqp_timestamp x, amqp_timestamp y) { return x.milliseconds == y.milliseconds; }
+inline bool operator<(amqp_timestamp x, amqp_timestamp y) { return x.milliseconds < y.milliseconds; }
 PN_CPP_EXTERN std::ostream& operator<<(std::ostream&, const amqp_timestamp&);
 
 // TODO aconway 2015-06-16: described types.

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/117bb7cb/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 dedcadd..1ecaaa5 100644
--- a/proton-c/bindings/cpp/include/proton/value.hpp
+++ b/proton-c/bindings/cpp/include/proton/value.hpp
@@ -40,7 +40,7 @@ class decoder;
  * 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> {
+class value {
   public:
     PN_CPP_EXTERN value();
     PN_CPP_EXTERN value(const value&);
@@ -73,12 +73,10 @@ class value : public comparable<value> {
     /** Get the value. */
     template<class T> T get() const { T t; get(t); return t; }
 
-    // FIXME aconway 2015-12-28: friend ops.
-    PN_CPP_EXTERN bool operator==(const value& x) const;
-    PN_CPP_EXTERN bool operator<(const value& x) const;
-
     PN_CPP_EXTERN void swap(value& v);
 
+  friend PN_CPP_EXTERN bool operator==(const value& x, const value& y);
+  friend PN_CPP_EXTERN bool operator<(const value& x, const value& y);
   friend PN_CPP_EXTERN class encoder operator<<(class encoder e, const value& dv);
   friend PN_CPP_EXTERN class decoder operator>>(class decoder d, value& dv);
   friend PN_CPP_EXTERN std::ostream& operator<<(std::ostream& o, const value& dv);

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/117bb7cb/proton-c/bindings/cpp/src/scalar.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/scalar.cpp b/proton-c/bindings/cpp/src/scalar.cpp
index 9e8d124..d52c8eb 100644
--- a/proton-c/bindings/cpp/src/scalar.cpp
+++ b/proton-c/bindings/cpp/src/scalar.cpp
@@ -137,7 +137,6 @@ std::string scalar::as_string() const {
 }
 
 namespace {
-template<class T> int opaque_cmp(const T& x, const T& y) { return memcmp(&x, &y, sizeof(T)); }
 
 template <class T, class F> T type_switch(const scalar& a, F f) {
     switch(a.type()) {

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/117bb7cb/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 bf652c5..9e8448c 100644
--- a/proton-c/bindings/cpp/src/value.cpp
+++ b/proton-c/bindings/cpp/src/value.cpp
@@ -54,9 +54,9 @@ class decoder value::decoder() const { data_.decoder().rewind(); return data_.de
 
 type_id value::type() const { return decoder().type(); }
 
-bool value::operator==(const value& x) const { return data_.equal(x.data_); }
+bool operator==(const value& x, const value& y) { return x.data_.equal(y.data_); }
 
-bool value::operator<(const value& x) const { return data_.less(x.data_); }
+bool operator<(const value& x, const value& y) { return x.data_.less(y.data_); }
 
 std::ostream& operator<<(std::ostream& o, const value& v) {
     // pn_inspect prints strings with quotes which is not normal in C++.


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org


[3/4] qpid-proton git commit: PROTON-1085: c++: clean up access to message properties, instructions and annotations.

Posted by ac...@apache.org.
PROTON-1085: c++: clean up access to message properties, instructions and annotations.

- Use proton::value& as message::body() type.
- Create pn_message on demand for empty message.
- Use proton::scalar as basis for messsage_id and annotation_key
  - message_id restricted to be one of: uint64_t, amqp_uuid, amqp_binary or amqp_string.
  - annotation_key restricted to be on of: uint64_t or amqp_symbol.
- Decode and cache application properties, annotations and instructions on demand as std::map.
  - message::properties() returns std::map<std::string, scalar>&
  - message::instructions()/annotations() returns std::map<annotation_key, value>&


Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/1622d0e6
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/1622d0e6
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/1622d0e6

Branch: refs/heads/master
Commit: 1622d0e608738da7b603b7e497bc3a8166325865
Parents: d2c5a5f
Author: Alan Conway <ac...@redhat.com>
Authored: Fri Dec 18 09:33:58 2015 -0500
Committer: Alan Conway <ac...@redhat.com>
Committed: Tue Dec 29 15:56:44 2015 -0500

----------------------------------------------------------------------
 examples/cpp/client.cpp                         |   2 +-
 examples/cpp/example_test.py                    |  18 +-
 proton-c/CMakeLists.txt                         |   2 +-
 .../cpp/include/proton/annotation_key.hpp       |  58 +++++
 proton-c/bindings/cpp/include/proton/data.hpp   |   2 -
 .../bindings/cpp/include/proton/decoder.hpp     |  27 +--
 .../bindings/cpp/include/proton/encoder.hpp     |  26 +-
 proton-c/bindings/cpp/include/proton/error.hpp  |   6 +
 .../bindings/cpp/include/proton/message.hpp     |  81 +++----
 .../bindings/cpp/include/proton/message_id.hpp  |  67 ++---
 proton-c/bindings/cpp/include/proton/scalar.hpp | 117 +++++----
 proton-c/bindings/cpp/include/proton/ssl.hpp    |   2 +-
 .../bindings/cpp/include/proton/type_traits.hpp |   2 +-
 proton-c/bindings/cpp/include/proton/types.hpp  |  77 +++---
 proton-c/bindings/cpp/include/proton/value.hpp  |  16 +-
 proton-c/bindings/cpp/src/decoder.cpp           | 138 ++++++-----
 .../bindings/cpp/src/encode_decode_test.cpp     |  39 ++-
 proton-c/bindings/cpp/src/encoder.cpp           |  56 +++--
 proton-c/bindings/cpp/src/error.cpp             |   2 +
 proton-c/bindings/cpp/src/event.cpp             |   2 +-
 proton-c/bindings/cpp/src/message.cpp           | 242 ++++++++-----------
 proton-c/bindings/cpp/src/message_test.cpp      | 102 +++++---
 proton-c/bindings/cpp/src/scalar.cpp            |  97 +++++---
 proton-c/bindings/cpp/src/scalar_test.cpp       |  80 ++++--
 proton-c/bindings/cpp/src/types.cpp             |  20 +-
 proton-c/bindings/cpp/src/value.cpp             |  14 ++
 26 files changed, 751 insertions(+), 544 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1622d0e6/examples/cpp/client.cpp
----------------------------------------------------------------------
diff --git a/examples/cpp/client.cpp b/examples/cpp/client.cpp
index 4dee119..3f5c4ab 100644
--- a/examples/cpp/client.cpp
+++ b/examples/cpp/client.cpp
@@ -58,7 +58,7 @@ class client : public proton::messaging_handler {
     void on_message(proton::event &e) {
         if (requests.empty()) return; // Spurious extra message!
         proton::message& response = e.message();
-        std::cout << '"' << requests.front() << '"' << " => " << response.body() << std::endl;
+        std::cout << requests.front() << " => " << response.body() << std::endl;
         requests.erase(requests.begin());
         if (!requests.empty()) {
             send_request();

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1622d0e6/examples/cpp/example_test.py
----------------------------------------------------------------------
diff --git a/examples/cpp/example_test.py b/examples/cpp/example_test.py
index 1f800c0..c1e7ac5 100644
--- a/examples/cpp/example_test.py
+++ b/examples/cpp/example_test.py
@@ -125,17 +125,17 @@ class ExampleTest(unittest.TestCase):
     def test_helloworld(self):
         b = Broker.get()
         hw = execute("helloworld", b.addr)
-        self.assertEqual('"Hello World!"\n', hw)
+        self.assertEqual('Hello World!\n', hw)
 
     def test_helloworld_blocking(self):
         b = Broker.get()
         hw = execute("helloworld_blocking", b.addr)
-        self.assertEqual('"Hello World!"\n', hw)
+        self.assertEqual('Hello World!\n', hw)
 
     def test_helloworld_direct(self):
         addr = pick_addr()
         hw = execute("helloworld_direct", addr)
-        self.assertEqual('"Hello World!"\n', hw)
+        self.assertEqual('Hello World!\n', hw)
 
     def test_simple_send_recv(self):
         b = Broker.get()
@@ -165,10 +165,10 @@ class ExampleTest(unittest.TestCase):
         send_expect = "direct_send listening on amqp://%s\nall messages confirmed\n" % (addr)
         self.assertEqual(send_expect, verify(send))
 
-    CLIENT_EXPECT=""""Twas brillig, and the slithy toves" => "TWAS BRILLIG, AND THE SLITHY TOVES"
-"Did gire and gymble in the wabe." => "DID GIRE AND GYMBLE IN THE WABE."
-"All mimsy were the borogroves," => "ALL MIMSY WERE THE BOROGROVES,"
-"And the mome raths outgrabe." => "AND THE MOME RATHS OUTGRABE."
+    CLIENT_EXPECT="""Twas brillig, and the slithy toves => TWAS BRILLIG, AND THE SLITHY TOVES
+Did gire and gymble in the wabe. => DID GIRE AND GYMBLE IN THE WABE.
+All mimsy were the borogroves, => ALL MIMSY WERE THE BOROGROVES,
+And the mome raths outgrabe. => AND THE MOME RATHS OUTGRABE.
 """
     def test_simple_recv_send(self):
         # Start receiver first, then run sender"""
@@ -247,7 +247,7 @@ Tock...
     def test_ssl(self):
         # SSL without SASL
         expect="""Outgoing client connection connected via SSL.  Server certificate identity CN=test_server
-"Hello World!"
+Hello World!
 """
         addr = "amqps://" + pick_addr() + "/examples"
         ignore_first_line, ignore_nl, ssl_hw = execute("ssl", addr, ssl_certs_dir()).partition('\n')
@@ -257,7 +257,7 @@ Tock...
         # SSL with SASL EXTERNAL
         expect="""Inbound client certificate identity CN=test_client
 Outgoing client connection connected via SSL.  Server certificate identity CN=test_server
-"Hello World!"
+Hello World!
 """
         addr = "amqps://" + pick_addr() + "/examples"
         ignore_first_line, ignore_nl, ssl_hw = execute("ssl_client_cert", addr, ssl_certs_dir()).partition('\n')

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1622d0e6/proton-c/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/proton-c/CMakeLists.txt b/proton-c/CMakeLists.txt
index 3d2f457..b645563 100644
--- a/proton-c/CMakeLists.txt
+++ b/proton-c/CMakeLists.txt
@@ -246,7 +246,7 @@ if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
   if (ENABLE_WARNING_ERROR)
     set (WERROR "-Werror")
   endif (ENABLE_WARNING_ERROR)
-  set (CXX_WARNING_FLAGS "${WERROR} -pedantic -Weverything -Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-float-equal -Wno-padded -Wno-sign-conversion -Wno-switch-enum -Wno-weak-vtables -Wno-exit-time-destructors -Wno-global-constructors -Wno-shorten-64-to-32")
+  set (CXX_WARNING_FLAGS "${WERROR} -pedantic -Weverything -Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-float-equal -Wno-padded -Wno-sign-conversion -Wno-switch-enum -Wno-weak-vtables -Wno-exit-time-destructors -Wno-global-constructors -Wno-shorten-64-to-32 -Wno-documentation -Wno-documentation-unknown-command")
 endif()
 
 if (MSVC)

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1622d0e6/proton-c/bindings/cpp/include/proton/annotation_key.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/annotation_key.hpp b/proton-c/bindings/cpp/include/proton/annotation_key.hpp
new file mode 100644
index 0000000..edd63b1
--- /dev/null
+++ b/proton-c/bindings/cpp/include/proton/annotation_key.hpp
@@ -0,0 +1,58 @@
+#ifndef ANNOTATION_KEY_HPP
+#define ANNOTATION_KEY_HPP
+/*
+ * 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/types.hpp"
+#include "proton/scalar.hpp"
+
+namespace proton {
+class encoder;
+class decoder;
+
+/** An annotation_key can contain one of the following types: uint64_t or amqp_symbol. */
+class annotation_key : public restricted_scalar {
+  public:
+    annotation_key() { scalar_ = uint64_t(0); }
+
+    ///@name Assign a C++ value, deduce the AMQP type()
+    ///@{
+    annotation_key& operator=(uint64_t x) { scalar_ = x; return *this; }
+    annotation_key& operator=(const amqp_symbol& x) { scalar_ = x; return *this; }
+    /// std::string is encoded as amqp_symbol
+    annotation_key& operator=(const std::string& x) { scalar_ = amqp_symbol(x); return *this; }
+    /// char* is encoded as amqp_symbol
+    annotation_key& operator=(const char *x) { scalar_ = amqp_symbol(x); return *this; }
+    ///@}
+
+    /// Converting constructor from any type that we can assign from.
+    template <class T> annotation_key(T x) { *this = x; }
+
+    void get(uint64_t& x) const { scalar_.get(x); }
+    void get(amqp_symbol& x) const { scalar_.get(x); }
+
+    template<class T> T get() const { T x; get(x); return x; }
+
+  friend PN_CPP_EXTERN encoder operator<<(encoder, const annotation_key&);
+  friend PN_CPP_EXTERN decoder operator>>(decoder, annotation_key&);
+  friend class message;
+};
+
+}
+#endif // ANNOTATION_KEY_HPP

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1622d0e6/proton-c/bindings/cpp/include/proton/data.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/data.hpp b/proton-c/bindings/cpp/include/proton/data.hpp
index 37e1a61..7581ac7 100644
--- a/proton-c/bindings/cpp/include/proton/data.hpp
+++ b/proton-c/bindings/cpp/include/proton/data.hpp
@@ -39,8 +39,6 @@ class data;
 class data : public object<pn_data_t> {
   public:
     data(pn_data_t* d) : object<pn_data_t>(d) {}
-    data(const data& d) : object<pn_data_t>(d) {}
-    data& operator=(const data&);
 
     PN_CPP_EXTERN static data create();
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1622d0e6/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 3073989..5dae3c3 100644
--- a/proton-c/bindings/cpp/include/proton/decoder.hpp
+++ b/proton-c/bindings/cpp/include/proton/decoder.hpp
@@ -44,11 +44,11 @@ struct pn_data_t;
 
 namespace proton {
 
+class scalar;
 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&); };
+class annotation_key;
+class value;
 
 /** Skips a value with `dec >> skip()`. */
 struct skip{};
@@ -208,7 +208,9 @@ class decoder : public object<pn_data_t> {
     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, annotation_key&);
     PN_CPP_EXTERN friend decoder operator>>(decoder, value&);
+    PN_CPP_EXTERN friend decoder operator>>(decoder, scalar&);
     ///@}
 
     /** Extract and return a value of type T. */
@@ -256,8 +258,6 @@ class decoder : public object<pn_data_t> {
 
   private:
     PN_CPP_EXTERN void check_type(type_id);
-
-  friend class encoder;
 };
 
 /** Call decoder::start() in constructor, decoder::finish in destructor().
@@ -280,20 +280,13 @@ operator>>(decoder d, T& i)  {
 }
 
 ///@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) {}
+template <class T> struct ref {
+    ref(T& v) : value(v) {}
     T& value;
 };
+template <class T> struct sequence_ref : public ref<T> { sequence_ref(T& v) : ref<T>(v) {} };
+template <class T> struct map_ref : public ref<T> { map_ref(T& v) : ref<T>(v) {} };
+template <class T> struct pairs_ref : public ref<T> { pairs_ref(T& v) : ref<T>(v) {} };
 ///@endcond
 
 /**

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1622d0e6/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 940064d..e521922 100644
--- a/proton-c/bindings/cpp/include/proton/encoder.hpp
+++ b/proton-c/bindings/cpp/include/proton/encoder.hpp
@@ -44,11 +44,31 @@ struct pn_data_t;
 
 namespace proton {
 
+class scalar;
 class data;
 class message_id;
+class annotation_key;
+class value;
 
-/** Raised by encoder operations on error */
-struct encode_error : public error { PN_CPP_EXTERN explicit encode_error(const std::string&); };
+///@cond INTERNAL
+template<class T, type_id A> struct cref {
+    typedef T cpp_type;
+    static const type_id type;
+
+    cref(const T& v) : value(v) {}
+    const T& value;
+};
+template <class T, type_id A> const type_id cref<T, A>::type = A;
+///@endcond INTERNAL
+
+/**
+ * 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<LIST>(v);
+ */
+template <type_id A, class T> cref<T, A> as(const T& value) { return cref<T, A>(value); }
 
 /**
  * Stream-like encoder from C++ values to AMQP values.
@@ -139,7 +159,9 @@ class encoder : public object<pn_data_t> {
   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 annotation_key&);
   friend PN_CPP_EXTERN encoder operator<<(encoder, const value&);
+  friend PN_CPP_EXTERN encoder operator<<(encoder, const scalar&);
     ///@}
 
     /**

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1622d0e6/proton-c/bindings/cpp/include/proton/error.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/error.hpp b/proton-c/bindings/cpp/include/proton/error.hpp
index d2f57c6..f3475cf 100644
--- a/proton-c/bindings/cpp/include/proton/error.hpp
+++ b/proton-c/bindings/cpp/include/proton/error.hpp
@@ -34,6 +34,12 @@ struct error : public std::runtime_error { PN_CPP_EXTERN explicit error(const st
 /** Raised if timeout expires */
 struct timeout_error : public error { PN_CPP_EXTERN explicit timeout_error(const std::string&); };
 
+/** Raised if there is an error decoding AMQP data as a C++ value. */
+struct decode_error : public error { PN_CPP_EXTERN explicit decode_error(const std::string&); };
+
+/** Raised if there is an error encoding a C++ value as AMQP data. */
+struct encode_error : public error { PN_CPP_EXTERN explicit encode_error(const std::string&); };
+
 }
 
 #endif  /*!PROTON_CPP_EXCEPTIONS_H*/

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1622d0e6/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 52195aa..8bd1f85 100644
--- a/proton-c/bindings/cpp/include/proton/message.hpp
+++ b/proton-c/bindings/cpp/include/proton/message.hpp
@@ -22,9 +22,10 @@
  *
  */
 
-#include "proton/data.hpp"
 #include "proton/export.hpp"
 #include "proton/message_id.hpp"
+#include "proton/annotation_key.hpp"
+#include "proton/pn_unique_ptr.hpp"
 #include "proton/value.hpp"
 #include "proton/duration.hpp"
 
@@ -38,22 +39,28 @@ namespace proton {
 class link;
 class delivery;
 class message_id;
+class annotation_key;
 
 /** An AMQP message. Value semantics, can be copied or assigned to make a new message. */
 class message
 {
   public:
+    typedef std::map<std::string, scalar> property_map;
+    typedef std::map<annotation_key, value> annotation_map;
+
     PN_CPP_EXTERN message();
     PN_CPP_EXTERN message(const message&);
-    PN_CPP_EXTERN message(const value&);
-
 #if PN_HAS_CPP11
     PN_CPP_EXTERN message(message&&);
 #endif
+    /// Constructor that sets the body from any type that can be assigned to a value.
+    template <class T> explicit message(const T& body_) { body() = body_; }
+
     PN_CPP_EXTERN ~message();
+
     PN_CPP_EXTERN message& operator=(const message&);
 
-    void swap(message& x);
+    PN_CPP_EXTERN void swap(message& x);
 
     /** Clear the message content and properties. */
     PN_CPP_EXTERN void clear();
@@ -99,47 +106,28 @@ class message
 
     ///@}
 
-    /** Set the body. */
-    PN_CPP_EXTERN void body(const value&);
+    /** Set the body, equivalent to body() = v */
+    template<class T> void body(const T& v) { body() = v; }
 
-    /** Get the body. Note data can be copied to a proton::value */
-    PN_CPP_EXTERN const data body() const;
+    /** Get the body. */
+    PN_CPP_EXTERN const value& body() const;
 
-    /** Get a reference to the body data, can be modified in-place. */
-    PN_CPP_EXTERN data body();
+    /** Get a reference to the body that can be modified in-place. */
+    PN_CPP_EXTERN value& body();
 
-    /** Set the application properties. Must be a map with string keys or an
-     * empty value. You can assign to a proton::value from a standard C++ map
-     * of std::string to proton::value.
-     */
-    PN_CPP_EXTERN void properties(const value&);
+    /** Application properties map, can be modified in place. */
+    PN_CPP_EXTERN property_map& properties();
+    PN_CPP_EXTERN const property_map& properties() const;
 
-    /** Get the application properties, which will be a map with string keys or
-     * an empty value. You can assign proton::value containing a map to a
-     * standard C++ map of std::string to proton::value.
-     */
-    PN_CPP_EXTERN const data properties() const;
+    /** Message annotations map, can be modified in place. */
+    PN_CPP_EXTERN annotation_map& annotations();
+    PN_CPP_EXTERN const annotation_map& annotations() const;
 
-    /** Get a reference to the application properties, can be modified in-place.*/
-    PN_CPP_EXTERN data properties();
+    /** Delivery instructions map, can be modified in place. */
+    PN_CPP_EXTERN annotation_map& instructions();
+    PN_CPP_EXTERN const annotation_map& instructions() const;
 
-    /** Set an individual application property. */
-    PN_CPP_EXTERN void property(const std::string &name, const value &);
-
-    /** Get an individual application property. Returns an empty value if not found. */
-    PN_CPP_EXTERN value property(const std::string &name) const;
-
-    /** Erase an application property. Returns false if there was no such property. */
-    PN_CPP_EXTERN bool erase_property(const std::string &name);
-
-    PN_CPP_EXTERN void annotations(const value&);
-    PN_CPP_EXTERN const data annotations() const;
-    PN_CPP_EXTERN data annotations();
-    PN_CPP_EXTERN void annotation(const proton::amqp_symbol &key, const value &val);
-    PN_CPP_EXTERN value annotation(const proton::amqp_symbol &key) const;
-    PN_CPP_EXTERN bool erase_annotation(const proton::amqp_symbol &key);
-
-    /** Encode into a string, growing the string if necessary. */
+    /** Encode entire message into a string, growing the string if necessary. */
     PN_CPP_EXTERN void encode(std::string &bytes) const;
 
     /** Return encoded message as a string */
@@ -148,7 +136,7 @@ class message
     /** Decode from string data into the message. */
     PN_CPP_EXTERN void decode(const std::string &bytes);
 
-    /// Decode the message from link corresponding to delivery.
+    /** Decode the message corresponding to a delivery from a link. */
     PN_CPP_EXTERN void decode(proton::link, proton::delivery);
 
     /**
@@ -160,8 +148,6 @@ class message
      * and AMQP SEQUENCE sections, respectively. If inferred is false,
      * then all values in the body of the message will be encoded as AMQP
      * VALUE sections regardless of their type.
-     *
-     * @return the value of the inferred flag for the message
      */
     PN_CPP_EXTERN bool inferred() const;
     /** Get the inferred flag for a message. */
@@ -247,7 +233,16 @@ class message
     PN_CPP_EXTERN void sequence(int32_t);
 
   private:
-    pn_message_t *message_;
+    pn_message_t *pn_msg() const;
+    struct impl {
+        PN_CPP_EXTERN impl();
+        PN_CPP_EXTERN ~impl();
+        mutable pn_message_t *msg;
+        mutable value body;
+    } impl_;
+    mutable property_map properties_;
+    mutable annotation_map annotations_;
+    mutable annotation_map instructions_;
 };
 
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1622d0e6/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 4734dff..b08482f 100644
--- a/proton-c/bindings/cpp/include/proton/message_id.hpp
+++ b/proton-c/bindings/cpp/include/proton/message_id.hpp
@@ -20,63 +20,44 @@
  */
 
 #include "proton/types.hpp"
-#include "proton/value.hpp"
+#include "proton/scalar.hpp"
 
 namespace proton {
+class encoder;
+class decoder;
+
 /** A message_id can contain one of the following types:
- * uint64_t (aka amqp_ulong), amqp_uuid, amqp_binary or amqp_string.
+ * uint64_t, amqp_uuid, amqp_binary or amqp_string.
  */
-class message_id : public comparable<message_id> {
+class message_id : public restricted_scalar {
   public:
-    message_id() {}
-    message_id(const message_id& x) : value_(x.value_) {}
-    message_id(const uint64_t& x) : value_(x) {}
-    message_id(const amqp_uuid& x) : value_(x) {}
-    message_id(const amqp_binary& x) : value_(x) {}
-    message_id(const amqp_string& x) : value_(x) {}
-    /// string is encoded as amqp_string
-    message_id(const std::string& x) : value_(x) {}
-    message_id(const char *x) : value_(x) {}
+    message_id() { scalar_ = uint64_t(0); }
 
-    message_id& operator=(const message_id& x) { value_ = x.value_; return *this; }
-    message_id& operator=(const uint64_t& x) { value_ = x; return *this; }
-    message_id& operator=(const amqp_uuid& x) { value_ = x; return *this; }
-    message_id& operator=(const amqp_binary& x) { value_ = x; return *this; }
-    message_id& operator=(const amqp_string& x) { value_ = x; return *this; }
-    /// string is encoded as amqp_string
-    message_id& operator=(const std::string& x) { value_ = x; return *this; }
-    message_id& operator=(const char *x) { value_ = x; return *this; }
+    ///@name Assign a C++ value, deduce the AMQP type()
+    ///@{
+    message_id& operator=(uint64_t x) { scalar_ = x; return *this; }
+    message_id& operator=(const amqp_uuid& x) { scalar_ = x; return *this; }
+    message_id& operator=(const amqp_binary& x) { scalar_ = x; return *this; }
+    message_id& operator=(const amqp_string& x) { scalar_ = x; return *this; }
+    /// std::string is encoded as amqp_string
+    message_id& operator=(const std::string& x) { scalar_ = amqp_string(x); return *this; }
+    /// char* is encoded as amqp_string
+    message_id& operator=(const char *x) { scalar_ = amqp_string(x); return *this; }
+    ///@}
 
-    void clear() { value_.clear(); }
-    bool empty() const { return value_.empty(); }
-    type_id type() { return value_.type(); }
+    /// Converting constructor from any type that we can assign from.
+    template <class T> message_id(T x) { *this = x; }
 
-    void get(uint64_t& x) const { value_.get(x); }
-    void get(amqp_uuid& x) const { value_.get(x); }
-    void get(amqp_binary& x) const { value_.get(x); }
-    void get(amqp_string& x) const { value_.get(x); }
-    /// Both amqp_binary and amqp_string can be converted to std::string
-    void get(std::string& x) const { value_.get(x); }
+    void get(uint64_t& x) const { scalar_.get(x); }
+    void get(amqp_uuid& x) const { scalar_.get(x); }
+    void get(amqp_binary& x) const { scalar_.get(x); }
+    void get(amqp_string& x) const { scalar_.get(x); }
 
     template<class T> T get() const { T x; get(x); return x; }
 
-    // String representation: decimal representation of uint64_t, standard text
-    // representation of UUID, amqp_string or amqp_binary are returned without
-    // modification.
-    std::string& str() const;
-
-    bool operator==(const message_id& x) const { return value_ == x.value_; }
-    bool operator<(const message_id& x) const { return value_ < x.value_; }
-
-  friend std::ostream& operator<<(std::ostream&, const message_id&);
   friend PN_CPP_EXTERN encoder operator<<(encoder, const message_id&);
   friend PN_CPP_EXTERN decoder operator>>(decoder, message_id&);
-
-  private:
-    //message_id(const data d) : value_(d) {}
-    value value_;
   friend class message;
-  friend class data;
 };
 
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1622d0e6/proton-c/bindings/cpp/include/proton/scalar.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/scalar.hpp b/proton-c/bindings/cpp/include/proton/scalar.hpp
index 0745281..6fe29fa 100644
--- a/proton-c/bindings/cpp/include/proton/scalar.hpp
+++ b/proton-c/bindings/cpp/include/proton/scalar.hpp
@@ -21,54 +21,56 @@
 
 #include "proton/types.hpp"
 #include <iosfwd>
+#include <string>
 
 namespace proton {
 
-class scalar;
+class encoder;
+class decoder;
 
-/** scalar holds an instance of an atomic proton type. */
+/** scalar holds an instance of any scalar AMQP type. */
 class scalar : public comparable<scalar> {
   public:
     PN_CPP_EXTERN scalar();
-    // Use default assign and copy.
+    PN_CPP_EXTERN scalar(const scalar&);
+    PN_CPP_EXTERN scalar& operator=(const scalar&);
 
     /// Type for the value in the scalar, NULL_TYPE if empty()
     PN_CPP_EXTERN type_id type() const;
+
     /// True if the scalar is empty.
     PN_CPP_EXTERN bool empty() const;
 
-    ///@name Create an scalar, type() is deduced from the C++ type of the value.
+    ///@name Assign a C++ value, deduce the AMQP type()
     ///@{
-    PN_CPP_EXTERN explicit scalar(bool);
-    PN_CPP_EXTERN explicit scalar(uint8_t);
-    PN_CPP_EXTERN explicit scalar(int8_t);
-    PN_CPP_EXTERN explicit scalar(uint16_t);
-    PN_CPP_EXTERN explicit scalar(int16_t);
-    PN_CPP_EXTERN explicit scalar(uint32_t);
-    PN_CPP_EXTERN explicit scalar(int32_t);
-    PN_CPP_EXTERN explicit scalar(uint64_t);
-    PN_CPP_EXTERN explicit scalar(int64_t);
-    PN_CPP_EXTERN explicit scalar(wchar_t);
-    PN_CPP_EXTERN explicit scalar(float);
-    PN_CPP_EXTERN explicit scalar(double);
-    PN_CPP_EXTERN explicit scalar(amqp_timestamp);
-    PN_CPP_EXTERN explicit scalar(const amqp_decimal32&);
-    PN_CPP_EXTERN explicit scalar(const amqp_decimal64&);
-    PN_CPP_EXTERN explicit scalar(const amqp_decimal128&);
-    PN_CPP_EXTERN explicit scalar(const amqp_uuid&);
-    PN_CPP_EXTERN explicit scalar(const amqp_string&);
-    PN_CPP_EXTERN explicit scalar(const amqp_symbol&);
-    PN_CPP_EXTERN explicit scalar(const amqp_binary&);
-    PN_CPP_EXTERN explicit scalar(const std::string& s); ///< Treated as an AMQP string
-    PN_CPP_EXTERN explicit scalar(const char* s);        ///< Treated as an AMQP string
+    PN_CPP_EXTERN scalar& operator=(bool);
+    PN_CPP_EXTERN scalar& operator=(uint8_t);
+    PN_CPP_EXTERN scalar& operator=(int8_t);
+    PN_CPP_EXTERN scalar& operator=(uint16_t);
+    PN_CPP_EXTERN scalar& operator=(int16_t);
+    PN_CPP_EXTERN scalar& operator=(uint32_t);
+    PN_CPP_EXTERN scalar& operator=(int32_t);
+    PN_CPP_EXTERN scalar& operator=(uint64_t);
+    PN_CPP_EXTERN scalar& operator=(int64_t);
+    PN_CPP_EXTERN scalar& operator=(wchar_t);
+    PN_CPP_EXTERN scalar& operator=(float);
+    PN_CPP_EXTERN scalar& operator=(double);
+    PN_CPP_EXTERN scalar& operator=(amqp_timestamp);
+    PN_CPP_EXTERN scalar& operator=(const amqp_decimal32&);
+    PN_CPP_EXTERN scalar& operator=(const amqp_decimal64&);
+    PN_CPP_EXTERN scalar& operator=(const amqp_decimal128&);
+    PN_CPP_EXTERN scalar& operator=(const amqp_uuid&);
+    PN_CPP_EXTERN scalar& operator=(const amqp_string&);
+    PN_CPP_EXTERN scalar& operator=(const amqp_symbol&);
+    PN_CPP_EXTERN scalar& operator=(const amqp_binary&);
+    PN_CPP_EXTERN scalar& operator=(const std::string& s); ///< Treated as an AMQP string
+    PN_CPP_EXTERN scalar& operator=(const char* s);        ///< Treated as an AMQP string
     ///@}
 
-    /// Assign to an scalar using the same rules as construction.
-    template <class T> scalar& operator=(T x) { return *this = scalar(x); }
+    /// Construct from any type that we can assign from.
+    template <class T> explicit scalar(T x) { *this = x; }
 
-    ///@name get(T&) extracts the value if the types match exactly,
-    ///i.e. if `type() == type_id_of<T>::value`
-    /// throws type_mismatch otherwise.
+    ///@name get(T&) extracts the value if the types match exactly, throws type_error otherwise.
     ///@{
     PN_CPP_EXTERN void get(bool&) const;
     PN_CPP_EXTERN void get(uint8_t&) const;
@@ -97,25 +99,58 @@ class scalar : public comparable<scalar> {
     template<class T> T get() const { T x; get(x); return x; }
 
     ///@name as_ methods do "loose" conversion, they will convert the scalar's
-    ///value to the requested type if possible, else throw type_mismatch
+    ///value to the requested type if possible, else throw type_error
     ///@{
-    PN_CPP_EXTERN int64_t as_int() const;     ///< Allowed if type_id_integral(type())
-    PN_CPP_EXTERN uint64_t as_uint() const;   ///< Allowed if type_id_integral(type())
-    PN_CPP_EXTERN double as_double() const;    ///< Allowed if type_id_floating_point(type())
-    PN_CPP_EXTERN std::string as_string() const; ///< Allowed if type_id_string_like(type())
+    PN_CPP_EXTERN int64_t as_int() const;     ///< Allowed if type_id_is_integral(type())
+    PN_CPP_EXTERN uint64_t as_uint() const;   ///< Allowed if type_id_is_integral(type())
+    PN_CPP_EXTERN double as_double() const;    ///< Allowed if type_id_is_floating_point(type())
+    PN_CPP_EXTERN std::string as_string() const; ///< Allowed if type_id_is_string_like(type())
     ///@}
 
-    PN_CPP_EXTERN bool operator==(const scalar& x) const;
-    /// Note if the values are of different type(), operator< will compare the type()
-    PN_CPP_EXTERN bool operator<(const scalar& x) const;
+  friend PN_CPP_EXTERN std::ostream& operator<<(std::ostream&, const scalar&);
+  friend PN_CPP_EXTERN encoder operator<<(encoder, const scalar&);
+  friend PN_CPP_EXTERN decoder operator>>(decoder, scalar&);
+
 
-  PN_CPP_EXTERN friend std::ostream& operator<<(std::ostream&, const scalar&);
+    /// Scalars with different type() are considered unequal even if the values
+    /// are equal as numbers or strings.
+  friend PN_CPP_EXTERN bool operator==(const scalar& x, const scalar& y);
+
+    /// For scalars of different type(), operator< sorts by order of type().
+  friend PN_CPP_EXTERN bool operator<(const scalar& x, const scalar& y);
 
   private:
     void ok(pn_type_t) const;
-    void set(const std::string&);
+    void set(const std::string&, pn_type_t);
+    void set(const pn_atom_t&);
     pn_atom_t atom_;
     std::string str_;           // Owner of string-like data.
+
+  friend class message;
+};
+
+///@internal base for restricted scalar types
+class restricted_scalar : public comparable<restricted_scalar> {
+  public:
+    operator scalar() const { return scalar_; }
+    type_id type() const { return scalar_.type(); }
+
+    ///@name as_ methods do "loose" conversion, they will convert the scalar's
+    ///value to the requested type if possible, else throw type_error
+    ///@{
+    int64_t as_int() const { return scalar_.as_int(); }
+    uint64_t as_uint() const { return scalar_.as_uint(); }
+    double as_double() const { return scalar_.as_double();  }
+    std::string as_string() const { return scalar_.as_string(); }
+    ///@}
+
+  friend std::ostream& operator<<(std::ostream& o, const restricted_scalar& x)  { return o << x.scalar_; }
+  friend bool operator<(const restricted_scalar& x, const restricted_scalar& y)  { return x.scalar_ < y.scalar_; }
+  friend bool operator==(const restricted_scalar& x, const restricted_scalar& y)  { return x.scalar_ == y.scalar_; }
+
+  protected:
+    restricted_scalar() {}
+    scalar scalar_;
 };
 
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1622d0e6/proton-c/bindings/cpp/include/proton/ssl.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/ssl.hpp b/proton-c/bindings/cpp/include/proton/ssl.hpp
index b3757dc..0518dc6 100644
--- a/proton-c/bindings/cpp/include/proton/ssl.hpp
+++ b/proton-c/bindings/cpp/include/proton/ssl.hpp
@@ -79,7 +79,7 @@ class ssl_domain {
   public:
     PN_CPP_EXTERN ssl_domain(const ssl_domain&);
     PN_CPP_EXTERN ssl_domain& operator=(const ssl_domain&);
-    ~ssl_domain();
+    PN_CPP_EXTERN ~ssl_domain();
 
   protected:
     ssl_domain(bool is_server);

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1622d0e6/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 494f7db..8f502a3 100644
--- a/proton-c/bindings/cpp/include/proton/type_traits.hpp
+++ b/proton-c/bindings/cpp/include/proton/type_traits.hpp
@@ -76,7 +76,7 @@ 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 atomic C++ types
+// Metafunction returning AMQP type for scalar 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_TYPE; };
 template<> struct type_id_of<amqp_boolean> { static const type_id value=BOOLEAN; };

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1622d0e6/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 645d9da..db5989b 100644
--- a/proton-c/bindings/cpp/include/proton/types.hpp
+++ b/proton-c/bindings/cpp/include/proton/types.hpp
@@ -67,12 +67,26 @@ enum type_id {
     MAP=PN_MAP                  ///< A sequence of key:value pairs, may be of mixed types.
 };
 
+/// Name of the AMQP type
+PN_CPP_EXTERN std::string type_name(type_id);
+
+/// Print the type_name
+PN_CPP_EXTERN std::ostream& operator<<(std::ostream&, type_id);
+
 /// Raised when there is a type mismatch, with the expected and actual type ID.
-struct type_mismatch : public error {
-    PN_CPP_EXTERN explicit type_mismatch(type_id want, type_id got, const std::string& =std::string());
+struct type_error : public decode_error {
+    PN_CPP_EXTERN explicit type_error(type_id want, type_id got, const std::string& =std::string());
     type_id want; ///< Expected type_id
     type_id got;  ///< Actual type_id
 };
+ 
+
+///@cond INTERNAL
+/// Provide a full set of comparison operators for proton:: types that have < and ==.
+template <class T> bool operator>(const T &a, const T &b) { return b < a; }
+template <class T> bool operator<=(const T &a, const T &b) { return !(a > b); }
+template <class T> bool operator>=(const T &a, const T &b) { return !(a < b); }
+template <class T> bool operator!=(const T &a, const T &b) { return !(a == b); }
 
 PN_CPP_EXTERN pn_bytes_t pn_bytes(const std::string&);
 PN_CPP_EXTERN std::string str(const pn_bytes_t& b);
@@ -107,26 +121,23 @@ typedef double amqp_double;
 
 /// AMQP UTF-8 encoded string.
 struct amqp_string : public std::string {
-    amqp_string(const std::string& s=std::string()) : std::string(s) {}
-    amqp_string(const char* s) : std::string(s) {}
-    amqp_string(const pn_bytes_t& b) : std::string(b.start, b.size) {}
-    operator pn_bytes_t() const { return pn_bytes(*this); }
+    explicit amqp_string(const std::string& s=std::string()) : std::string(s) {}
+    explicit amqp_string(const char* s) : std::string(s) {}
+    explicit amqp_string(const pn_bytes_t& b) : std::string(b.start, b.size) {}
 };
 
 /// AMQP ASCII encoded symbolic name.
 struct amqp_symbol : public std::string {
-    amqp_symbol(const std::string& s=std::string()) : std::string(s) {}
-    amqp_symbol(const char* s) : std::string(s) {}
-    amqp_symbol(const pn_bytes_t& b) : std::string(b.start, b.size) {}
-    operator pn_bytes_t() const { return pn_bytes(*this); }
+    explicit amqp_symbol(const std::string& s=std::string()) : std::string(s) {}
+    explicit amqp_symbol(const char* s) : std::string(s) {}
+    explicit amqp_symbol(const pn_bytes_t& b) : std::string(b.start, b.size) {}
 };
 
 /// AMQP variable-length binary data.
 struct amqp_binary : public std::string {
-    amqp_binary(const std::string& s=std::string()) : std::string(s) {}
-    amqp_binary(const char* s) : std::string(s) {}
-    amqp_binary(const pn_bytes_t& b) : std::string(b.start, b.size) {}
-    operator pn_bytes_t() const { return pn_bytes(*this); }
+    explicit amqp_binary(const std::string& s=std::string()) : std::string(s) {}
+    explicit amqp_binary(const char* s) : std::string(s) {}
+    explicit amqp_binary(const pn_bytes_t& b) : std::string(b.start, b.size) {}
 };
 
 /// Template for opaque proton proton types that can be treated as byte arrays.
@@ -170,40 +181,28 @@ struct amqp_timestamp : public comparable<amqp_timestamp> {
 };
 PN_CPP_EXTERN std::ostream& operator<<(std::ostream&, const amqp_timestamp&);
 
-///@cond INTERNAL
-template<class T, type_id A> struct cref {
-    typedef T cpp_type;
-    static const type_id type;
-
-    cref(const T& v) : value(v) {}
-    const T& value;
-};
-template <class T, type_id A> const type_id cref<T, A>::type = A;
-///@endcond INTERNAL
-
-/**
- * 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<LIST>(v);
- */
-template <type_id A, class T> cref<T, A> as(const T& value) { return cref<T, A>(value); }
-
 // TODO aconway 2015-06-16: described types.
 
-/// Name of the AMQP type
-PN_CPP_EXTERN std::string type_name(type_id);
-
 ///@name Attributes of a type_id value, returns same result as the
 /// corresponding std::type_traits tests for the corresponding C++ types.
 ///@{
+/// Any scalar type
 PN_CPP_EXTERN bool type_id_is_scalar(type_id);
+/// One of the signed integer types: BYTE, SHORT, INT or LONG
+PN_CPP_EXTERN bool type_id_is_signed_int(type_id);
+/// One of the unsigned integer types: UBYTE, USHORT, UINT or ULONG
+PN_CPP_EXTERN bool type_id_is_unsigned_int(type_id);
+/// Any of the signed or unsigned integers, BOOL, CHAR or TIMESTAMP.
 PN_CPP_EXTERN bool type_id_is_integral(type_id);
-PN_CPP_EXTERN bool type_id_is_signed(type_id); ///< CHAR and BOOL are not signed.
+/// A floating point type, float or double
 PN_CPP_EXTERN bool type_id_is_floating_point(type_id);
+/// Any signed integer, float or double. BOOL, CHAR and TIMESTAMP are not signed.
+PN_CPP_EXTERN bool type_id_is_signed(type_id);
+/// Any DECIMAL type.
 PN_CPP_EXTERN bool type_id_is_decimal(type_id);
-PN_CPP_EXTERN bool type_id_is_string_like(type_id);   ///< STRING, SYMBOL, BINARY
+/// STRING, SYMBOL or BINARY
+PN_CPP_EXTERN bool type_id_is_string_like(type_id);
+/// Container types: MAP, LIST, ARRAY or DESCRIBED.
 PN_CPP_EXTERN bool type_id_is_container(type_id);
 ///@}
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1622d0e6/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 c33eea1..dedcadd 100644
--- a/proton-c/bindings/cpp/include/proton/value.hpp
+++ b/proton-c/bindings/cpp/include/proton/value.hpp
@@ -43,9 +43,10 @@ class decoder;
 class value : public comparable<value> {
   public:
     PN_CPP_EXTERN value();
-    PN_CPP_EXTERN value(const value& x);
-    // TODO: Should enumerate specifically all the pointer types that can convert to value
-    // to avoid accidental conversions to bool this will require enable_if<> or the like
+    PN_CPP_EXTERN value(const value&);
+#if PN_HAS_CPP11
+    PN_CPP_EXTERN value(value&&);
+#endif
     template <class T> value(const T& x) : data_(data::create()) { data_.copy(x); }
 
     PN_CPP_EXTERN value& operator=(const value& x);
@@ -65,18 +66,27 @@ class value : public comparable<value> {
 
     /** Get the value. */
     template<class T> void get(T &t) const { decoder() >> t; }
+    template<class T> void get(map_ref<T> t) const { decoder() >> t; }
+    template<class T> void get(pairs_ref<T> t) const { decoder() >> t; }
+    template<class T> void get(sequence_ref<T> t) const { decoder() >> t; }
 
     /** Get the value. */
     template<class T> T get() const { T t; get(t); return t; }
 
+    // FIXME aconway 2015-12-28: friend ops.
     PN_CPP_EXTERN bool operator==(const value& x) const;
     PN_CPP_EXTERN bool operator<(const value& x) const;
 
+    PN_CPP_EXTERN void swap(value& v);
+
   friend PN_CPP_EXTERN class encoder operator<<(class encoder e, const value& dv);
   friend PN_CPP_EXTERN class decoder operator>>(class decoder d, value& dv);
   friend PN_CPP_EXTERN std::ostream& operator<<(std::ostream& o, const value& dv);
 
   private:
+    value(data d);
+    value& ref(data d);
+
     data data_;
   friend class message;
 };

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1622d0e6/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 20d0461..4639683 100644
--- a/proton-c/bindings/cpp/src/decoder.cpp
+++ b/proton-c/bindings/cpp/src/decoder.cpp
@@ -21,6 +21,7 @@
 #include "proton/decoder.hpp"
 #include "proton/value.hpp"
 #include "proton/message_id.hpp"
+#include "proton/annotation_key.hpp"
 #include "proton_bits.hpp"
 #include "msg.hpp"
 
@@ -34,8 +35,6 @@ namespace proton {
  * to be returned by the decoder.
  *
  */
-decode_error::decode_error(const std::string& msg) : error("decode: "+msg) {}
-
 namespace {
 struct save_state {
     pn_data_t* data;
@@ -87,8 +86,7 @@ data decoder::data() { return proton::data(pn_object()); }
 namespace {
 
 void bad_type(type_id want, type_id got) {
-    if (want != got)
-        throw decode_error("expected "+type_name(want)+" found "+type_name(got));
+    if (want != got) throw type_error(want, got);
 }
 
 type_id pre_get(pn_data_t* data) {
@@ -99,10 +97,10 @@ type_id pre_get(pn_data_t* data) {
 }
 
 // Simple extract with no type conversion.
-template <class T, class U> void extract(pn_data_t* data, T& value, U (*get)(pn_data_t*)) {
+template <class T, class U> void extract(pn_data_t* data, T& x, U (*get)(pn_data_t*)) {
     save_state ss(data);
     bad_type(type_id_of<T>::value, pre_get(data));
-    value = T(get(data));
+    x = T(get(data));
     ss.cancel();                // No error, no rewind
 }
 
@@ -165,191 +163,211 @@ decoder operator>>(decoder d, value& v) {
     return d;
 }
 
-decoder operator>>(decoder d, message_id& id) {
+decoder operator>>(decoder d, message_id& x) {
     switch (d.type()) {
       case ULONG:
       case UUID:
       case BINARY:
       case STRING:
-        return d >> id.value_;
+        return d >> x.scalar_;
       default:
         throw decode_error("expected one of ulong, uuid, binary or string but found " +
                            type_name(d.type()));
     };
 }
 
+decoder operator>>(decoder d, annotation_key& x) {
+    switch (d.type()) {
+      case ULONG:
+      case SYMBOL:
+        return d >> x.scalar_;
+      default:
+        throw decode_error("expected one of ulong or symbol but found " + type_name(d.type()));
+    };
+}
+
 decoder operator>>(decoder d, amqp_null) {
     save_state ss(d.pn_object());
     bad_type(NULL_TYPE, pre_get(d.pn_object()));
     return d;
 }
 
-decoder operator>>(decoder d, amqp_boolean& value) {
-    extract(d.pn_object(), value, pn_data_get_bool);
+decoder operator>>(decoder d, scalar& x) {
+    save_state ss(d.pn_object());
+    type_id got = pre_get(d.pn_object());
+    if (!type_id_is_scalar(got))
+        throw decode_error("expected scalar, found "+type_name(got));
+    x.set(pn_data_get_atom(d.pn_object()));
+    ss.cancel();                // No error, no rewind
+    return d;
+}
+
+decoder operator>>(decoder d, amqp_boolean &x) {
+    extract(d.pn_object(), x, pn_data_get_bool);
     return d;
 }
 
-decoder operator>>(decoder d0, amqp_ubyte& value) {
+decoder operator>>(decoder d0, amqp_ubyte &x) {
     pn_data_t* d = d0.pn_object();
     save_state ss(d);
     switch (pre_get(d)) {
-      case UBYTE: value = pn_data_get_ubyte(d); break;
+      case UBYTE: x = pn_data_get_ubyte(d); break;
       default: bad_type(UBYTE, type_id(type_id(pn_data_type(d))));
     }
     ss.cancel();
     return d0;
 }
 
-decoder operator>>(decoder d0, amqp_byte& value) {
+decoder operator>>(decoder d0, amqp_byte &x) {
     pn_data_t* d = d0.pn_object();
     save_state ss(d);
     switch (pre_get(d)) {
-      case BYTE: value = pn_data_get_byte(d); break;
+      case BYTE: x = pn_data_get_byte(d); break;
       default: bad_type(BYTE, type_id(type_id(pn_data_type(d))));
     }
     ss.cancel();
     return d0;
 }
 
-decoder operator>>(decoder d0, amqp_ushort& value) {
+decoder operator>>(decoder d0, amqp_ushort &x) {
     pn_data_t* d = d0.pn_object();
     save_state ss(d);
     switch (pre_get(d)) {
-      case UBYTE: value = pn_data_get_ubyte(d); break;
-      case USHORT: value = pn_data_get_ushort(d); break;
+      case UBYTE: x = pn_data_get_ubyte(d); break;
+      case USHORT: x = pn_data_get_ushort(d); break;
       default: bad_type(USHORT, type_id(type_id(pn_data_type(d))));
     }
     ss.cancel();
     return d0;
 }
 
-decoder operator>>(decoder d0, amqp_short& value) {
+decoder operator>>(decoder d0, amqp_short &x) {
     pn_data_t* d = d0.pn_object();
     save_state ss(d);
     switch (pre_get(d)) {
-      case BYTE: value = pn_data_get_byte(d); break;
-      case SHORT: value = pn_data_get_short(d); break;
+      case BYTE: x = pn_data_get_byte(d); break;
+      case SHORT: x = pn_data_get_short(d); break;
       default: bad_type(SHORT, type_id(pn_data_type(d)));
     }
     ss.cancel();
     return d0;
 }
 
-decoder operator>>(decoder d0, amqp_uint& value) {
+decoder operator>>(decoder d0, amqp_uint &x) {
     pn_data_t* d = d0.pn_object();
     save_state ss(d);
     switch (pre_get(d)) {
-      case UBYTE: value = pn_data_get_ubyte(d); break;
-      case USHORT: value = pn_data_get_ushort(d); break;
-      case UINT: value = pn_data_get_uint(d); break;
+      case UBYTE: x = pn_data_get_ubyte(d); break;
+      case USHORT: x = pn_data_get_ushort(d); break;
+      case UINT: x = pn_data_get_uint(d); break;
       default: bad_type(UINT, type_id(pn_data_type(d)));
     }
     ss.cancel();
     return d0;
 }
 
-decoder operator>>(decoder d0, amqp_int& value) {
+decoder operator>>(decoder d0, amqp_int &x) {
     pn_data_t* d = d0.pn_object();
     save_state ss(d);
     switch (pre_get(d)) {
-      case BYTE: value = pn_data_get_byte(d); break;
-      case SHORT: value = pn_data_get_short(d); break;
-      case INT: value = pn_data_get_int(d); break;
+      case BYTE: x = pn_data_get_byte(d); break;
+      case SHORT: x = pn_data_get_short(d); break;
+      case INT: x = pn_data_get_int(d); break;
       default: bad_type(INT, type_id(pn_data_type(d)));
     }
     ss.cancel();
     return d0;
 }
 
-decoder operator>>(decoder d0, amqp_ulong& value) {
+decoder operator>>(decoder d0, amqp_ulong &x) {
     pn_data_t* d = d0.pn_object();
     save_state ss(d);
     switch (pre_get(d)) {
-      case UBYTE: value = pn_data_get_ubyte(d); break;
-      case USHORT: value = pn_data_get_ushort(d); break;
-      case UINT: value = pn_data_get_uint(d); break;
-      case ULONG: value = pn_data_get_ulong(d); break;
+      case UBYTE: x = pn_data_get_ubyte(d); break;
+      case USHORT: x = pn_data_get_ushort(d); break;
+      case UINT: x = pn_data_get_uint(d); break;
+      case ULONG: x = pn_data_get_ulong(d); break;
       default: bad_type(ULONG, type_id(pn_data_type(d)));
     }
     ss.cancel();
     return d0;
 }
 
-decoder operator>>(decoder d0, amqp_long& value) {
+decoder operator>>(decoder d0, amqp_long &x) {
     pn_data_t* d = d0.pn_object();
     save_state ss(d);
     switch (pre_get(d)) {
-      case BYTE: value = pn_data_get_byte(d); break;
-      case SHORT: value = pn_data_get_short(d); break;
-      case INT: value = pn_data_get_int(d); break;
-      case LONG: value = pn_data_get_long(d); break;
+      case BYTE: x = pn_data_get_byte(d); break;
+      case SHORT: x = pn_data_get_short(d); break;
+      case INT: x = pn_data_get_int(d); break;
+      case LONG: x = pn_data_get_long(d); break;
       default: bad_type(LONG, type_id(pn_data_type(d)));
     }
     ss.cancel();
     return d0;
 }
 
-decoder operator>>(decoder d, amqp_char& value) {
-    extract(d.pn_object(), value, pn_data_get_char);
+decoder operator>>(decoder d, amqp_char &x) {
+    extract(d.pn_object(), x, pn_data_get_char);
     return d;
 }
 
-decoder operator>>(decoder d, amqp_timestamp& value) {
-    extract(d.pn_object(), value, pn_data_get_timestamp);
+decoder operator>>(decoder d, amqp_timestamp &x) {
+    extract(d.pn_object(), x, pn_data_get_timestamp);
     return d;
 }
 
-decoder operator>>(decoder d0, amqp_float& value) {
+decoder operator>>(decoder d0, amqp_float &x) {
     pn_data_t* d = d0.pn_object();
     save_state ss(d);
     switch (pre_get(d)) {
-      case FLOAT: value = pn_data_get_float(d); break;
-      case DOUBLE: value = float(pn_data_get_double(d)); break;
+      case FLOAT: x = pn_data_get_float(d); break;
+      case DOUBLE: x = float(pn_data_get_double(d)); break;
       default: bad_type(FLOAT, type_id(pn_data_type(d)));
     }
     ss.cancel();
     return d0;
 }
 
-decoder operator>>(decoder d0, amqp_double& value) {
+decoder operator>>(decoder d0, amqp_double &x) {
     pn_data_t* d = d0.pn_object();
     save_state ss(d);
     switch (pre_get(d)) {
-      case FLOAT: value = pn_data_get_float(d); break;
-      case DOUBLE: value = pn_data_get_double(d); break;
+      case FLOAT: x = pn_data_get_float(d); break;
+      case DOUBLE: x = pn_data_get_double(d); break;
       default: bad_type(DOUBLE, type_id(pn_data_type(d)));
     }
     ss.cancel();
     return d0;
 }
 
-decoder operator>>(decoder d, amqp_decimal32& value) {
-    extract(d.pn_object(), value, pn_data_get_decimal32);
+decoder operator>>(decoder d, amqp_decimal32 &x) {
+    extract(d.pn_object(), x, pn_data_get_decimal32);
     return d;
 }
 
-decoder operator>>(decoder d, amqp_decimal64& value) {
-    extract(d.pn_object(), value, pn_data_get_decimal64);
+decoder operator>>(decoder d, amqp_decimal64 &x) {
+    extract(d.pn_object(), x, pn_data_get_decimal64);
     return d;
 }
 
-decoder operator>>(decoder d, amqp_decimal128& value)  {
-    extract(d.pn_object(), value, pn_data_get_decimal128);
+decoder operator>>(decoder d, amqp_decimal128 &x)  {
+    extract(d.pn_object(), x, pn_data_get_decimal128);
     return d;
 }
 
-decoder operator>>(decoder d, amqp_uuid& value)  {
-    extract(d.pn_object(), value, pn_data_get_uuid);
+decoder operator>>(decoder d, amqp_uuid &x)  {
+    extract(d.pn_object(), x, pn_data_get_uuid);
     return d;
 }
 
-decoder operator>>(decoder d0, std::string& value) {
+decoder operator>>(decoder d0, std::string &x) {
     pn_data_t* d = d0.pn_object();
     save_state ss(d);
     switch (pre_get(d)) {
-      case STRING: value = str(pn_data_get_string(d)); break;
-      case BINARY: value = str(pn_data_get_binary(d)); break;
-      case SYMBOL: value = str(pn_data_get_symbol(d)); break;
+      case STRING: x = str(pn_data_get_string(d)); break;
+      case BINARY: x = str(pn_data_get_binary(d)); break;
+      case SYMBOL: x = str(pn_data_get_symbol(d)); break;
       default: bad_type(STRING, type_id(pn_data_type(d)));
     }
     ss.cancel();

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1622d0e6/proton-c/bindings/cpp/src/encode_decode_test.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/encode_decode_test.cpp b/proton-c/bindings/cpp/src/encode_decode_test.cpp
index 3e15a58..8c285ac 100644
--- a/proton-c/bindings/cpp/src/encode_decode_test.cpp
+++ b/proton-c/bindings/cpp/src/encode_decode_test.cpp
@@ -48,31 +48,13 @@ template <class T> void value_test(T x, type_id tid, const std::string& s, T y)
     ASSERT(y > x);
 }
 
-void value_tests() {
-    value_test(false, BOOLEAN, "false", true);
-    value_test(amqp_ubyte(42), UBYTE, "42", amqp_ubyte(50));
-    value_test(amqp_byte(-42), BYTE, "-42", amqp_byte(-40));
-    value_test(amqp_ushort(4242), USHORT, "4242", amqp_ushort(5252));
-    value_test(amqp_short(-4242), SHORT, "-4242", amqp_short(3));
-    value_test(amqp_uint(4242), UINT, "4242", amqp_uint(5252));
-    value_test(amqp_int(-4242), INT, "-4242", amqp_int(3));
-    value_test(amqp_ulong(4242), ULONG, "4242", amqp_ulong(5252));
-    value_test(amqp_long(-4242), LONG, "-4242", amqp_long(3));
-    value_test(amqp_float(1.234), FLOAT, "1.234", amqp_float(2.345));
-    value_test(amqp_double(11.2233), DOUBLE, "11.2233", amqp_double(12));
-    value_test(amqp_string("aaa"), STRING, "aaa", amqp_string("aaaa"));
-    value_test(std::string("xxx"), STRING, "xxx", std::string("yyy"));
-    value_test(amqp_symbol("aaa"), SYMBOL, "aaa", amqp_symbol("aaaa"));
-    value_test(amqp_binary("aaa"), BINARY, "b\"aaa\"", amqp_binary("aaaa"));
-}
-
 // Map values
 void map_test() {
     std::map<string, int> m;
     m["a"] = 1;
     m["b"] = 2;
     m["c"] = 3;
-    proton::value v = m;
+    value v = m;
     ASSERT_EQUAL("{\"a\"=1, \"b\"=2, \"c\"=3}",  str(v));
     std::map<value, value> mv;
     v.get(mv);
@@ -81,8 +63,9 @@ void map_test() {
     mv.erase("c");
     v = value(mv);
     ASSERT_EQUAL("{\"a\"=1, \"b\"=b\"xyz\"}",  str(v));
+
     std::vector<std::pair<string, value> > vec;
-    v.decoder() >> to_pairs(vec);       // FIXME aconway 2015-11-17: get doesn't work with pairs.
+    v.get(to_pairs(vec));
     ASSERT_EQUAL(2, vec.size());
     ASSERT_EQUAL(std::make_pair(std::string("a"), value(1)), vec[0]);
     ASSERT_EQUAL(std::make_pair(std::string("b"), value(amqp_binary("xyz"))), vec[1]);
@@ -90,7 +73,21 @@ void map_test() {
 
 int main(int, char**) {
     int failed = 0;
+    RUN_TEST(failed, value_test(false, BOOLEAN, "false", true));
+    RUN_TEST(failed, value_test(amqp_ubyte(42), UBYTE, "42", amqp_ubyte(50)));
+    RUN_TEST(failed, value_test(amqp_byte(-42), BYTE, "-42", amqp_byte(-40)));
+    RUN_TEST(failed, value_test(amqp_ushort(4242), USHORT, "4242", amqp_ushort(5252)));
+    RUN_TEST(failed, value_test(amqp_short(-4242), SHORT, "-4242", amqp_short(3)));
+    RUN_TEST(failed, value_test(amqp_uint(4242), UINT, "4242", amqp_uint(5252)));
+    RUN_TEST(failed, value_test(amqp_int(-4242), INT, "-4242", amqp_int(3)));
+    RUN_TEST(failed, value_test(amqp_ulong(4242), ULONG, "4242", amqp_ulong(5252)));
+    RUN_TEST(failed, value_test(amqp_long(-4242), LONG, "-4242", amqp_long(3)));
+    RUN_TEST(failed, value_test(amqp_float(1.234), FLOAT, "1.234", amqp_float(2.345)));
+    RUN_TEST(failed, value_test(amqp_double(11.2233), DOUBLE, "11.2233", amqp_double(12)));
+    RUN_TEST(failed, value_test(amqp_string("aaa"), STRING, "aaa", amqp_string("aaaa")));
+    RUN_TEST(failed, value_test(std::string("xxx"), STRING, "xxx", std::string("yyy")));
+    RUN_TEST(failed, value_test(amqp_symbol("aaa"), SYMBOL, "aaa", amqp_symbol("aaaa")));
+    RUN_TEST(failed, value_test(amqp_binary("aaa"), BINARY, "b\"aaa\"", amqp_binary("aaaa")));
     RUN_TEST(failed, map_test());
-    RUN_TEST(failed, value_tests());
     return failed;
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1622d0e6/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 327426a..109b290 100644
--- a/proton-c/bindings/cpp/src/encoder.cpp
+++ b/proton-c/bindings/cpp/src/encoder.cpp
@@ -20,6 +20,7 @@
 #include "proton/data.hpp"
 #include "proton/encoder.hpp"
 #include "proton/message_id.hpp"
+#include "proton/annotation_key.hpp"
 #include "proton/value.hpp"
 
 #include "proton_bits.hpp"
@@ -100,35 +101,39 @@ encoder operator<<(encoder e, finish) {
 
 namespace {
 template <class T, class U>
-encoder insert(encoder e, pn_data_t* data, T& value, int (*put)(pn_data_t*, U)) {
+encoder insert(encoder e, pn_data_t* data, T& x, int (*put)(pn_data_t*, U)) {
     save_state ss(data);         // Save state in case of error.
-    check(put(data, value), data);
+    check(put(data, x), data);
     ss.cancel();                // Don't restore state, all is good.
     return e;
 }
+
+int pn_data_put_amqp_string(pn_data_t *d, const amqp_string& x) { return pn_data_put_string(d, pn_bytes(x)); }
+int pn_data_put_amqp_binary(pn_data_t *d, const amqp_binary& x) { return pn_data_put_binary(d, pn_bytes(x)); }
+int pn_data_put_amqp_symbol(pn_data_t *d, const amqp_symbol& x) { return pn_data_put_symbol(d, pn_bytes(x)); }
 }
 
 encoder operator<<(encoder e, amqp_null) { pn_data_put_null(e.pn_object()); return e; }
-encoder operator<<(encoder e, amqp_boolean value) { return insert(e, e.pn_object(), value, pn_data_put_bool); }
-encoder operator<<(encoder e, amqp_ubyte value) { return insert(e, e.pn_object(), value, pn_data_put_ubyte); }
-encoder operator<<(encoder e, amqp_byte value) { return insert(e, e.pn_object(), value, pn_data_put_byte); }
-encoder operator<<(encoder e, amqp_ushort value) { return insert(e, e.pn_object(), value, pn_data_put_ushort); }
-encoder operator<<(encoder e, amqp_short value) { return insert(e, e.pn_object(), value, pn_data_put_short); }
-encoder operator<<(encoder e, amqp_uint value) { return insert(e, e.pn_object(), value, pn_data_put_uint); }
-encoder operator<<(encoder e, amqp_int value) { return insert(e, e.pn_object(), value, pn_data_put_int); }
-encoder operator<<(encoder e, amqp_char value) { return insert(e, e.pn_object(), value, pn_data_put_char); }
-encoder operator<<(encoder e, amqp_ulong value) { return insert(e, e.pn_object(), value, pn_data_put_ulong); }
-encoder operator<<(encoder e, amqp_long value) { return insert(e, e.pn_object(), value, pn_data_put_long); }
-encoder operator<<(encoder e, amqp_timestamp value) { return insert(e, e.pn_object(), value, pn_data_put_timestamp); }
-encoder operator<<(encoder e, amqp_float value) { return insert(e, e.pn_object(), value, pn_data_put_float); }
-encoder operator<<(encoder e, amqp_double value) { return insert(e, e.pn_object(), value, pn_data_put_double); }
-encoder operator<<(encoder e, amqp_decimal32 value) { return insert(e, e.pn_object(), value, pn_data_put_decimal32); }
-encoder operator<<(encoder e, amqp_decimal64 value) { return insert(e, e.pn_object(), value, pn_data_put_decimal64); }
-encoder operator<<(encoder e, amqp_decimal128 value) { return insert(e, e.pn_object(), value, pn_data_put_decimal128); }
-encoder operator<<(encoder e, amqp_uuid value) { return insert(e, e.pn_object(), value, pn_data_put_uuid); }
-encoder operator<<(encoder e, amqp_string value) { return insert(e, e.pn_object(), value, pn_data_put_string); }
-encoder operator<<(encoder e, amqp_symbol value) { return insert(e, e.pn_object(), value, pn_data_put_symbol); }
-encoder operator<<(encoder e, amqp_binary value) { return insert(e, e.pn_object(), value, pn_data_put_binary); }
+encoder operator<<(encoder e, amqp_boolean x) { return insert(e, e.pn_object(), x, pn_data_put_bool); }
+encoder operator<<(encoder e, amqp_ubyte x) { return insert(e, e.pn_object(), x, pn_data_put_ubyte); }
+encoder operator<<(encoder e, amqp_byte x) { return insert(e, e.pn_object(), x, pn_data_put_byte); }
+encoder operator<<(encoder e, amqp_ushort x) { return insert(e, e.pn_object(), x, pn_data_put_ushort); }
+encoder operator<<(encoder e, amqp_short x) { return insert(e, e.pn_object(), x, pn_data_put_short); }
+encoder operator<<(encoder e, amqp_uint x) { return insert(e, e.pn_object(), x, pn_data_put_uint); }
+encoder operator<<(encoder e, amqp_int x) { return insert(e, e.pn_object(), x, pn_data_put_int); }
+encoder operator<<(encoder e, amqp_char x) { return insert(e, e.pn_object(), x, pn_data_put_char); }
+encoder operator<<(encoder e, amqp_ulong x) { return insert(e, e.pn_object(), x, pn_data_put_ulong); }
+encoder operator<<(encoder e, amqp_long x) { return insert(e, e.pn_object(), x, pn_data_put_long); }
+encoder operator<<(encoder e, amqp_timestamp x) { return insert(e, e.pn_object(), x, pn_data_put_timestamp); }
+encoder operator<<(encoder e, amqp_float x) { return insert(e, e.pn_object(), x, pn_data_put_float); }
+encoder operator<<(encoder e, amqp_double x) { return insert(e, e.pn_object(), x, pn_data_put_double); }
+encoder operator<<(encoder e, amqp_decimal32 x) { return insert(e, e.pn_object(), x, pn_data_put_decimal32); }
+encoder operator<<(encoder e, amqp_decimal64 x) { return insert(e, e.pn_object(), x, pn_data_put_decimal64); }
+encoder operator<<(encoder e, amqp_decimal128 x) { return insert(e, e.pn_object(), x, pn_data_put_decimal128); }
+encoder operator<<(encoder e, amqp_uuid x) { return insert(e, e.pn_object(), x, pn_data_put_uuid); }
+encoder operator<<(encoder e, amqp_string x) { return insert(e, e.pn_object(), x, pn_data_put_amqp_string); }
+encoder operator<<(encoder e, amqp_symbol x) { return insert(e, e.pn_object(), x, pn_data_put_amqp_symbol); }
+encoder operator<<(encoder e, amqp_binary x) { return insert(e, e.pn_object(), x, pn_data_put_amqp_binary); }
 
 encoder operator<<(encoder e, const value& v) {
     data edata = e.data();
@@ -138,6 +143,11 @@ encoder operator<<(encoder e, const value& v) {
     return e;
 }
 
-encoder operator<<(encoder e, const message_id& v) { return e << v.value_; }
+encoder operator<<(encoder e, const scalar& x) {
+    return insert(e, e.pn_object(), x.atom_, pn_data_put_atom);
+}
+
+encoder operator<<(encoder e, const message_id& x) { return e << x.scalar_; }
+encoder operator<<(encoder e, const annotation_key& x) { return e << x.scalar_; }
 
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1622d0e6/proton-c/bindings/cpp/src/error.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/error.cpp b/proton-c/bindings/cpp/src/error.cpp
index 980d6c0..8382a70 100644
--- a/proton-c/bindings/cpp/src/error.cpp
+++ b/proton-c/bindings/cpp/src/error.cpp
@@ -27,4 +27,6 @@ error::error(const std::string& msg) : std::runtime_error(prefix+msg) {}
 
 timeout_error::timeout_error(const std::string& msg) : error(msg) {}
 
+decode_error::decode_error(const std::string& msg) : error("decode: "+msg) {}
+
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1622d0e6/proton-c/bindings/cpp/src/event.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/event.cpp b/proton-c/bindings/cpp/src/event.cpp
index 2a35ee8..b3e93d8 100644
--- a/proton-c/bindings/cpp/src/event.cpp
+++ b/proton-c/bindings/cpp/src/event.cpp
@@ -77,5 +77,5 @@ class message &event::message() const {
     throw error(MSG("No message associated with event"));
 }
 
-event_loop::~event_loop() {}    // FIXME aconway 2015-12-28: move
+event_loop::~event_loop() {}
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1622d0e6/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 c2fcd00..c7ee1f6 100644
--- a/proton-c/bindings/cpp/src/message.cpp
+++ b/proton-c/bindings/cpp/src/message.cpp
@@ -19,6 +19,7 @@
  *
  */
 
+#include "proton/data.hpp"
 #include "proton/message.hpp"
 #include "proton/error.hpp"
 #include "proton/link.hpp"
@@ -31,24 +32,39 @@
 #include "msg.hpp"
 #include "proton_bits.hpp"
 
-#include <cstring>
+#include <string>
 #include <assert.h>
 
 namespace proton {
 
-message::message() : message_(::pn_message()) {}
+// impl exists so body is pre-constructed in reference mode (prevent it creating its own data)
+// for all message ctors.
+message::impl::impl() : msg(0), body(0) {}
 
-message::message(const message &m) : message_(::pn_message()) { *this = m; }
+message::impl::~impl() {
+    if (msg) {
+        body.ref(0);            // Clear the reference.
+        pn_message_free(msg);
+    }
+}
 
-#if defined(PN_HAS_CPP11) && PN_HAS_CPP11
-message::message(message &&m) : message_(::pn_message()) { swap(m); }
-#endif
+// Lazy construct the message.
+pn_message_t* message::pn_msg() const {
+    if (!impl_.msg) impl_.msg = pn_message();
+    return impl_.msg;
+}
+
+message::message() {}
+
+message::message(const message &m) { *this = m; }
 
-message::message(const value& v) : message_(::pn_message()) { body(v); }
+#if PN_HAS_CPP11
+message::message(message &&m) { swap(m); }
+#endif
 
-message::~message() { ::pn_message_free(message_); }
+message::~message() {}
 
-void message::swap(message& m) { std::swap(message_, m.message_); }
+void message::swap(message& m) { std::swap(impl_.msg, m.impl_.msg); }
 
 message& message::operator=(const message& m) {
     // TODO aconway 2015-08-10: more efficient pn_message_copy function
@@ -58,7 +74,7 @@ message& message::operator=(const message& m) {
     return *this;
 }
 
-void message::clear() { pn_message_clear(message_); }
+void message::clear() { if (impl_.msg) pn_message_clear(impl_.msg); }
 
 namespace {
 void check(int err) {
@@ -66,7 +82,7 @@ void check(int err) {
 }
 } // namespace
 
-void message::id(const message_id& id) { data(pn_message_id(message_)).copy(id.value_); }
+void message::id(const message_id& id) { pn_message_set_id(pn_msg(), id.scalar_.atom_); }
 
 namespace {
 inline message_id from_pn_atom(const pn_atom_t& v) {
@@ -86,222 +102,169 @@ inline message_id from_pn_atom(const pn_atom_t& v) {
 }
 
 message_id message::id() const {
-    return from_pn_atom(pn_message_get_id(message_));
+    return from_pn_atom(pn_message_get_id(pn_msg()));
 }
 
 void message::user_id(const std::string &id) {
-    check(pn_message_set_user_id(message_, pn_bytes(id)));
+    check(pn_message_set_user_id(pn_msg(), pn_bytes(id)));
 }
 
 std::string message::user_id() const {
-    return str(pn_message_get_user_id(message_));
+    return str(pn_message_get_user_id(pn_msg()));
 }
 
 void message::address(const std::string &addr) {
-    check(pn_message_set_address(message_, addr.c_str()));
+    check(pn_message_set_address(pn_msg(), addr.c_str()));
 }
 
 std::string message::address() const {
-    const char* addr = pn_message_get_address(message_);
+    const char* addr = pn_message_get_address(pn_msg());
     return addr ? std::string(addr) : std::string();
 }
 
 void message::subject(const std::string &s) {
-    check(pn_message_set_subject(message_, s.c_str()));
+    check(pn_message_set_subject(pn_msg(), s.c_str()));
 }
 
 std::string message::subject() const {
-    const char* s = pn_message_get_subject(message_);
+    const char* s = pn_message_get_subject(pn_msg());
     return s ? std::string(s) : std::string();
 }
 
 void message::reply_to(const std::string &s) {
-    check(pn_message_set_reply_to(message_, s.c_str()));
+    check(pn_message_set_reply_to(pn_msg(), s.c_str()));
 }
 
 std::string message::reply_to() const {
-    const char* s = pn_message_get_reply_to(message_);
+    const char* s = pn_message_get_reply_to(pn_msg());
     return s ? std::string(s) : std::string();
 }
 
 void message::correlation_id(const message_id& id) {
-    data(pn_message_correlation_id(message_)).copy(id.value_);
+    data(pn_message_correlation_id(pn_msg())).copy(id.scalar_);
 }
 
 message_id message::correlation_id() const {
-    return from_pn_atom(pn_message_get_correlation_id(message_));
+    return from_pn_atom(pn_message_get_correlation_id(pn_msg()));
 }
 
 void message::content_type(const std::string &s) {
-    check(pn_message_set_content_type(message_, s.c_str()));
+    check(pn_message_set_content_type(pn_msg(), s.c_str()));
 }
 
 std::string message::content_type() const {
-    const char* s = pn_message_get_content_type(message_);
+    const char* s = pn_message_get_content_type(pn_msg());
     return s ? std::string(s) : std::string();
 }
 
 void message::content_encoding(const std::string &s) {
-    check(pn_message_set_content_encoding(message_, s.c_str()));
+    check(pn_message_set_content_encoding(pn_msg(), s.c_str()));
 }
 
 std::string message::content_encoding() const {
-    const char* s = pn_message_get_content_encoding(message_);
+    const char* s = pn_message_get_content_encoding(pn_msg());
     return s ? std::string(s) : std::string();
 }
 
 void message::expiry_time(amqp_timestamp t) {
-    pn_message_set_expiry_time(message_, t.milliseconds);
+    pn_message_set_expiry_time(pn_msg(), t.milliseconds);
 }
 amqp_timestamp message::expiry_time() const {
-    return amqp_timestamp(pn_message_get_expiry_time(message_));
+    return amqp_timestamp(pn_message_get_expiry_time(pn_msg()));
 }
 
 void message::creation_time(amqp_timestamp t) {
-    pn_message_set_creation_time(message_, t);
+    pn_message_set_creation_time(pn_msg(), t);
 }
 amqp_timestamp message::creation_time() const {
-    return pn_message_get_creation_time(message_);
+    return pn_message_get_creation_time(pn_msg());
 }
 
 void message::group_id(const std::string &s) {
-    check(pn_message_set_group_id(message_, s.c_str()));
+    check(pn_message_set_group_id(pn_msg(), s.c_str()));
 }
 
 std::string message::group_id() const {
-    const char* s = pn_message_get_group_id(message_);
+    const char* s = pn_message_get_group_id(pn_msg());
     return s ? std::string(s) : std::string();
 }
 
 void message::reply_to_group_id(const std::string &s) {
-    check(pn_message_set_reply_to_group_id(message_, s.c_str()));
+    check(pn_message_set_reply_to_group_id(pn_msg(), s.c_str()));
 }
 
 std::string message::reply_to_group_id() const {
-    const char* s = pn_message_get_reply_to_group_id(message_);
+    const char* s = pn_message_get_reply_to_group_id(pn_msg());
     return s ? std::string(s) : std::string();
 }
 
-bool message::inferred() const { return pn_message_is_inferred(message_); }
-
-void message::inferred(bool b) { pn_message_set_inferred(message_, b); }
-
-void message::body(const value& v) { body().copy(v); }
+bool message::inferred() const { return pn_message_is_inferred(pn_msg()); }
 
-const data message::body() const {
-    return pn_message_body(message_);
-}
+void message::inferred(bool b) { pn_message_set_inferred(pn_msg(), b); }
 
-data message::body() {
-    return pn_message_body(message_);
-}
+const value& message::body() const { return impl_.body.ref(pn_message_body(pn_msg())); }
+value& message::body() { return impl_.body.ref(pn_message_body(pn_msg())); }
 
-void message::properties(const value& v) {
-    properties().copy(v);
-}
+// MAP CACHING: the properties, annotations and instructions maps can either be
+// encoded in the pn_message pn_data_t structures OR decoded as C++ map members
+// of the message but not both. At least one of the pn_data_t or the map member
+// is always empty, the non-empty one is the authority.
 
-const data message::properties() const {
-    return pn_message_properties(message_);
-}
-
-data message::properties() {
-    return pn_message_properties(message_);
-}
-
-namespace {
-typedef std::map<std::string, value> props_map;
-}
-
-void message::property(const std::string& name, const value &v) {
-    // TODO aconway 2015-11-17: not efficient but avoids cache consistency problems.
-    // Could avoid full encode/decode with linear scan of names. Need
-    // better codec suport for in-place modification of data.
-    props_map m;
-    if (!properties().empty())
-        properties().get(m);
-    m[name] = v;
-    properties(m);
-}
-
-value message::property(const std::string& name) const {
-    // TODO aconway 2015-11-17: not efficient but avoids cache consistency problems.
-    if (!properties().empty()) {
-        props_map m;
-        properties().get(m);
-        props_map::const_iterator i = m.find(name);
-        if (i != m.end())
-            return i->second;
+// Decode a map on demand
+template<class M> M& get_map(pn_message_t* msg, pn_data_t* (*get)(pn_message_t*), M& map) {
+    data d(get(msg));
+    if (map.empty() && !d.empty()) {
+        d.decoder() >> rewind() >> map;
+        d.clear();              // The map member is now the authority.
     }
-    return value();
+    return map;
 }
 
-bool message::erase_property(const std::string& name) {
-    // TODO aconway 2015-11-17: not efficient but avoids cache consistency problems.
-    if (!properties().empty()) {
-        props_map m;
-        properties().get(m);
-        if (m.erase(name)) {
-            properties(m);
-            return true;
-        }
+// Encode a map if necessary.
+template<class M> M& put_map(pn_message_t* msg, pn_data_t* (*get)(pn_message_t*), M& map) {
+    data d(get(msg));
+    if (d.empty() && !map.empty()) {
+        d.encoder() << map;
+        map.clear();        // The encoded pn_data_t  is now the authority.
     }
-    return false;
+    return map;
 }
 
-void message::annotations(const value& v) {
-    annotations().copy(v);
+message::property_map& message::properties() {
+    return get_map(pn_msg(), pn_message_properties, properties_);
 }
 
-const data message::annotations() const {
-    return pn_message_annotations(message_);
+const message::property_map& message::properties() const {
+    return get_map(pn_msg(), pn_message_properties, properties_);
 }
 
-data message::annotations() {
-    return pn_message_annotations(message_);
-}
 
-namespace {
-typedef std::map<proton::amqp_symbol, value> annotation_map;
+message::annotation_map& message::annotations() {
+    return get_map(pn_msg(), pn_message_annotations, annotations_);
 }
 
-void message::annotation(const proton::amqp_symbol &k, const value &v) {
-    annotation_map m;
-    if (!annotations().empty())
-        annotations().get(m);
-    m[k] = v;
-    annotations(m);
+const message::annotation_map& message::annotations() const {
+    return get_map(pn_msg(), pn_message_annotations, annotations_);
 }
 
-value message::annotation(const proton::amqp_symbol &k) const {
-    if (!annotations().empty()) {
-        annotation_map m;
-        annotations().get(m);
-        annotation_map::const_iterator i = m.find(k);
-        if (i != m.end())
-            return i->second;
-    }
-    return value();
 
+message::annotation_map& message::instructions() {
+    return get_map(pn_msg(), pn_message_instructions, instructions_);
 }
 
-bool message::erase_annotation(const proton::amqp_symbol &k) {
-    if (!annotations().empty()) {
-        annotation_map m;
-        annotations().get(m);
-        if (m.erase(k)) {
-            annotations(m);
-            return true;
-        }
-    }
-    return false;
+const message::annotation_map& message::instructions() const {
+    return get_map(pn_msg(), pn_message_instructions, instructions_);
 }
 
 void message::encode(std::string &s) const {
+    put_map(pn_msg(), pn_message_properties, properties_);
+    put_map(pn_msg(), pn_message_annotations, annotations_);
+    put_map(pn_msg(), pn_message_instructions, instructions_);
     size_t sz = s.capacity();
     if (sz < 512) sz = 512;
     while (true) {
         s.resize(sz);
-        int err = pn_message_encode(message_, const_cast<char*>(s.data()), &sz);
+        int err = pn_message_encode(pn_msg(), const_cast<char*>(s.data()), &sz);
         if (err) {
             if (err != PN_OVERFLOW)
                 check(err);
@@ -320,7 +283,10 @@ std::string message::encode() const {
 }
 
 void message::decode(const std::string &s) {
-    check(pn_message_decode(message_, s.data(), s.size()));
+    properties_.clear();
+    annotations_.clear();
+    instructions_.clear();
+    check(pn_message_decode(pn_msg(), s.data(), s.size()));
 }
 
 void message::decode(proton::link link, proton::delivery delivery) {
@@ -333,22 +299,22 @@ void message::decode(proton::link link, proton::delivery delivery) {
     link.advance();
 }
 
-bool message::durable() const { return pn_message_is_durable(message_); }
-void message::durable(bool b) { pn_message_set_durable(message_, b); }
+bool message::durable() const { return pn_message_is_durable(pn_msg()); }
+void message::durable(bool b) { pn_message_set_durable(pn_msg(), b); }
 
-duration message::ttl() const { return duration(pn_message_get_ttl(message_)); }
-void message::ttl(duration d) { pn_message_set_ttl(message_, d.milliseconds); }
+duration message::ttl() const { return duration(pn_message_get_ttl(pn_msg())); }
+void message::ttl(duration d) { pn_message_set_ttl(pn_msg(), d.milliseconds); }
 
-uint8_t message::priority() const { return pn_message_get_priority(message_); }
-void message::priority(uint8_t d) { pn_message_set_priority(message_, d); }
+uint8_t message::priority() const { return pn_message_get_priority(pn_msg()); }
+void message::priority(uint8_t d) { pn_message_set_priority(pn_msg(), d); }
 
-bool message::first_acquirer() const { return pn_message_is_first_acquirer(message_); }
-void message::first_acquirer(bool b) { pn_message_set_first_acquirer(message_, b); }
+bool message::first_acquirer() const { return pn_message_is_first_acquirer(pn_msg()); }
+void message::first_acquirer(bool b) { pn_message_set_first_acquirer(pn_msg(), b); }
 
-uint32_t message::delivery_count() const { return pn_message_get_delivery_count(message_); }
-void message::delivery_count(uint32_t d) { pn_message_set_delivery_count(message_, d); }
+uint32_t message::delivery_count() const { return pn_message_get_delivery_count(pn_msg()); }
+void message::delivery_count(uint32_t d) { pn_message_set_delivery_count(pn_msg(), d); }
 
-int32_t message::sequence() const { return pn_message_get_group_sequence(message_); }
-void message::sequence(int32_t d) { pn_message_set_group_sequence(message_, d); }
+int32_t message::sequence() const { return pn_message_get_group_sequence(pn_msg()); }
+void message::sequence(int32_t d) { pn_message_set_group_sequence(pn_msg(), d); }
 
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1622d0e6/proton-c/bindings/cpp/src/message_test.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/message_test.cpp b/proton-c/bindings/cpp/src/message_test.cpp
index 54995c0..9f05d1c 100644
--- a/proton-c/bindings/cpp/src/message_test.cpp
+++ b/proton-c/bindings/cpp/src/message_test.cpp
@@ -18,6 +18,7 @@
  */
 
 #include "proton/message.hpp"
+#include "proton/scalar.hpp"
 #include "test_bits.hpp"
 #include <string>
 #include <fstream>
@@ -32,58 +33,99 @@ using namespace proton;
     m.ATTR(#ATTR); \
     ASSERT_EQUAL(std::string(#ATTR), m.ATTR())
 
-#define CHECK_STR_VALUE(ATTR) \
+#define CHECK_MESSAGE_ID(ATTR) \
     m.ATTR(#ATTR); \
-    ASSERT_EQUAL(std::string(#ATTR), m.ATTR().get<std::string>())
+    ASSERT_EQUAL(scalar(#ATTR), m.ATTR())
 
-void test_message() {
+void test_message_properties() {
     message m("hello");
     std::string s = m.body().get<std::string>();
     ASSERT_EQUAL("hello", s);
 
-    CHECK_STR_VALUE(id);
+    CHECK_MESSAGE_ID(id);
     CHECK_STR(user_id);
     CHECK_STR(address);
     CHECK_STR(subject);
     CHECK_STR(reply_to);
-    CHECK_STR_VALUE(correlation_id);
+    CHECK_MESSAGE_ID(correlation_id);
     CHECK_STR(content_type);
     CHECK_STR(content_encoding);
     CHECK_STR(group_id);
     CHECK_STR(reply_to_group_id);
-
     m.expiry_time(42);
     ASSERT_EQUAL(m.expiry_time().milliseconds, 42);
     m.creation_time(4242);
     ASSERT_EQUAL(m.creation_time().milliseconds, 4242);
 
-    m.property("foo", 12);
-    ASSERT_EQUAL(m.property("foo"), value(12));
-    m.property("xxx", false);
-    ASSERT_EQUAL(m.property("xxx"), value(false));
-    ASSERT(m.erase_property("xxx"));
-    ASSERT(m.property("xxx").empty());
-    ASSERT(!m.erase_property("yyy"));
-
-    std::map<std::string, proton::value> props;
-    m.properties().get(props);
-    ASSERT_EQUAL(props.size(), 1);
-    ASSERT_EQUAL(props["foo"], value(12));
-    props["bar"] = amqp_symbol("xyz");
-    props["foo"] = true;
-    m.properties(props);
-    ASSERT_EQUAL(m.property("foo"), value(true));
-    ASSERT_EQUAL(m.property("bar"), value(amqp_symbol("xyz")));
-    m.property("bar", amqp_binary("bar"));
-    std::map<std::string, proton::value> props2;
-    m.properties().get(props2);
-    ASSERT_EQUAL(2, props2.size());
-    ASSERT_EQUAL(props2["foo"], value(true));
-    ASSERT_EQUAL(props2["bar"], value(amqp_binary("bar")));
+    message m2(m);
+    ASSERT_EQUAL("hello", m2.body().get<std::string>());
+    ASSERT_EQUAL(message_id("id"), m2.id());
+    ASSERT_EQUAL("user_id", m2.user_id());
+    ASSERT_EQUAL("address", m2.address());
+    ASSERT_EQUAL("subject", m2.subject());
+    ASSERT_EQUAL("reply_to", m2.reply_to());
+    ASSERT_EQUAL(message_id("correlation_id"), m2.correlation_id());
+    ASSERT_EQUAL("content_type", m2.content_type());
+    ASSERT_EQUAL("content_encoding", m2.content_encoding());
+    ASSERT_EQUAL("group_id", m2.group_id());
+    ASSERT_EQUAL("reply_to_group_id", m2.reply_to_group_id());
+    ASSERT_EQUAL(42, m2.expiry_time().milliseconds);
+    ASSERT_EQUAL(4242, m.creation_time().milliseconds);
+
+    m2 = m;
+    ASSERT_EQUAL("hello", m2.body().get<std::string>());
+    ASSERT_EQUAL(message_id("id"), m2.id());
+    ASSERT_EQUAL("user_id", m2.user_id());
+    ASSERT_EQUAL("address", m2.address());
+    ASSERT_EQUAL("subject", m2.subject());
+    ASSERT_EQUAL("reply_to", m2.reply_to());
+    ASSERT_EQUAL(message_id("correlation_id"), m2.correlation_id());
+    ASSERT_EQUAL("content_type", m2.content_type());
+    ASSERT_EQUAL("content_encoding", m2.content_encoding());
+    ASSERT_EQUAL("group_id", m2.group_id());
+    ASSERT_EQUAL("reply_to_group_id", m2.reply_to_group_id());
+    ASSERT_EQUAL(42, m2.expiry_time().milliseconds);
+    ASSERT_EQUAL(4242, m.creation_time().milliseconds);
+}
+
+void test_message_maps() {
+    message m;
+
+    ASSERT(m.properties().empty());
+    ASSERT(m.annotations().empty());
+    ASSERT(m.instructions().empty());
+
+    m.properties()["foo"] = 12;
+    m.instructions()["bar"] = "xyz";
+    m.annotations()[23] = "23";
+
+    ASSERT_EQUAL(m.properties()["foo"], scalar(12));
+    ASSERT_EQUAL(m.instructions()["bar"], scalar("xyz"));
+    ASSERT_EQUAL(m.annotations()[23], scalar("23"));
+
+    message m2(m);
+    message::annotation_map& amap = m2.instructions();
+
+    ASSERT_EQUAL(m2.properties()["foo"], scalar(12));
+    ASSERT_EQUAL(m2.instructions()["bar"], scalar("xyz"));
+    ASSERT_EQUAL(m2.annotations()[23], scalar("23"));
+
+    m.properties()["foo"] = "newfoo";
+    m.instructions()[24] = 1000;
+    m.annotations().erase(23);
+
+    m2 = m;
+    ASSERT_EQUAL(1, m2.properties().size());
+    ASSERT_EQUAL(m2.properties()["foo"], scalar("newfoo"));
+    ASSERT_EQUAL(2, m2.instructions().size());
+    ASSERT_EQUAL(m2.instructions()["bar"], scalar("xyz"));
+    ASSERT_EQUAL(m2.instructions()[24], scalar(1000));
+    ASSERT(m2.annotations().empty());
 }
 
 int main(int argc, char** argv) {
     int failed = 0;
-    RUN_TEST(failed, test_message());
+    RUN_TEST(failed, test_message_properties());
+    RUN_TEST(failed, test_message_maps());
     return failed;
 }


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org