You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@avro.apache.org by th...@apache.org on 2021/03/31 03:20:14 UTC

[avro] branch master updated: AVRO-3051: Modernized JSON module (#1164)

This is an automated email from the ASF dual-hosted git repository.

thiru pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/avro.git


The following commit(s) were added to refs/heads/master by this push:
     new 95876f2  AVRO-3051: Modernized JSON module (#1164)
95876f2 is described below

commit 95876f284d59acb3d7993918bda9747a68f68b99
Author: Thiruvalluvan M G <th...@apache.org>
AuthorDate: Wed Mar 31 08:50:01 2021 +0530

    AVRO-3051: Modernized JSON module (#1164)
    
    * Modernized JSON module
    
    * Fixed a spelling issue
    
    * Fixed an issue with enum value, casuing cppcheck to fail
    
    Co-authored-by: Thiruvalluvan M G <th...@startsmartlabs.com>
---
 lang/c++/impl/Compiler.cc          | 38 +++++++--------
 lang/c++/impl/json/JsonDom.cc      | 65 +++++++++++++------------
 lang/c++/impl/json/JsonDom.hh      | 70 ++++++++++++++++-----------
 lang/c++/impl/json/JsonIO.cc       | 39 ++++++++-------
 lang/c++/impl/json/JsonIO.hh       | 33 ++++++-------
 lang/c++/impl/parsing/JsonCodec.cc | 58 +++++++++++-----------
 lang/c++/test/JsonTests.cc         | 98 +++++++++++++++++++-------------------
 7 files changed, 209 insertions(+), 192 deletions(-)

diff --git a/lang/c++/impl/Compiler.cc b/lang/c++/impl/Compiler.cc
index 5427636..d76546f 100644
--- a/lang/c++/impl/Compiler.cc
+++ b/lang/c++/impl/Compiler.cc
@@ -176,37 +176,37 @@ static GenericDatum makeGenericDatum(NodePtr n,
     }
     switch (t) {
         case AVRO_STRING:
-            assertType(e, json::etString);
+            assertType(e, json::EntityType::String);
             return GenericDatum(e.stringValue());
         case AVRO_BYTES:
-            assertType(e, json::etString);
+            assertType(e, json::EntityType::String);
             return GenericDatum(toBin(e.bytesValue()));
         case AVRO_INT:
-            assertType(e, json::etLong);
+            assertType(e, json::EntityType::Long);
             return GenericDatum(static_cast<int32_t>(e.longValue()));
         case AVRO_LONG:
-            assertType(e, json::etLong);
+            assertType(e, json::EntityType::Long);
             return GenericDatum(e.longValue());
         case AVRO_FLOAT:
-            if (dt == json::etLong) {
+            if (dt == json::EntityType::Long) {
                 return GenericDatum(static_cast<float>(e.longValue()));
             }
-            assertType(e, json::etDouble);
+            assertType(e, json::EntityType::Double);
             return GenericDatum(static_cast<float>(e.doubleValue()));
         case AVRO_DOUBLE:
-            if (dt == json::etLong) {
+            if (dt == json::EntityType::Long) {
                 return GenericDatum(static_cast<double>(e.longValue()));
             }
-            assertType(e, json::etDouble);
+            assertType(e, json::EntityType::Double);
             return GenericDatum(e.doubleValue());
         case AVRO_BOOL:
-            assertType(e, json::etBool);
+            assertType(e, json::EntityType::Bool);
             return GenericDatum(e.boolValue());
         case AVRO_NULL:
-            assertType(e, json::etNull);
+            assertType(e, json::EntityType::Null);
             return GenericDatum();
         case AVRO_RECORD: {
-            assertType(e, json::etObject);
+            assertType(e, json::EntityType::Obj);
             GenericRecord result(n);
             const map<string, Entity> &v = e.objectValue();
             for (size_t i = 0; i < n->leaves(); ++i) {
@@ -222,10 +222,10 @@ static GenericDatum makeGenericDatum(NodePtr n,
             return GenericDatum(n, result);
         }
         case AVRO_ENUM:
-            assertType(e, json::etString);
+            assertType(e, json::EntityType::String);
             return GenericDatum(n, GenericEnum(n, e.stringValue()));
         case AVRO_ARRAY: {
-            assertType(e, json::etArray);
+            assertType(e, json::EntityType::Arr);
             GenericArray result(n);
             const vector<Entity> &elements = e.arrayValue();
             for (const auto &element : elements) {
@@ -234,7 +234,7 @@ static GenericDatum makeGenericDatum(NodePtr n,
             return GenericDatum(n, result);
         }
         case AVRO_MAP: {
-            assertType(e, json::etObject);
+            assertType(e, json::EntityType::Obj);
             GenericMap result(n);
             const map<string, Entity> &v = e.objectValue();
             for (const auto &it : v) {
@@ -250,7 +250,7 @@ static GenericDatum makeGenericDatum(NodePtr n,
             return GenericDatum(n, result);
         }
         case AVRO_FIXED:
-            assertType(e, json::etString);
+            assertType(e, json::EntityType::String);
             return GenericDatum(n, GenericFixed(n, toBin(e.bytesValue())));
         default: throw Exception(boost::format("Unknown type: %1%") % t);
     }
@@ -340,7 +340,7 @@ static NodePtr makeEnumNode(const Entity &e,
     const Array &v = getArrayField(e, m, "symbols");
     concepts::MultiAttribute<string> symbols;
     for (const auto &it : v) {
-        if (it.type() != json::etString) {
+        if (it.type() != json::EntityType::String) {
             throw Exception(boost::format("Enum symbol not a string: %1%") % it.toString());
         }
         symbols.add(it.stringValue());
@@ -467,9 +467,9 @@ static NodePtr makeNode(const Entity &e, const Array &m,
 
 static NodePtr makeNode(const json::Entity &e, SymbolTable &st, const string &ns) {
     switch (e.type()) {
-        case json::etString: return makeNode(e.stringValue(), st, ns);
-        case json::etObject: return makeNode(e, e.objectValue(), st, ns);
-        case json::etArray: return makeNode(e, e.arrayValue(), st, ns);
+        case json::EntityType::String: return makeNode(e.stringValue(), st, ns);
+        case json::EntityType::Obj: return makeNode(e, e.objectValue(), st, ns);
+        case json::EntityType::Arr: return makeNode(e, e.arrayValue(), st, ns);
         default: throw Exception(boost::format("Invalid Avro type: %1%") % e.toString());
     }
 }
diff --git a/lang/c++/impl/json/JsonDom.cc b/lang/c++/impl/json/JsonDom.cc
index fdf46e9..5bffda2 100644
--- a/lang/c++/impl/json/JsonDom.cc
+++ b/lang/c++/impl/json/JsonDom.cc
@@ -20,7 +20,7 @@
 
 #include <stdexcept>
 
-#include <string.h>
+#include <cstring>
 
 #include "JsonIO.hh"
 #include "Stream.hh"
@@ -32,49 +32,49 @@ namespace avro {
 namespace json {
 const char *typeToString(EntityType t) {
     switch (t) {
-        case etNull: return "null";
-        case etBool: return "bool";
-        case etLong: return "long";
-        case etDouble: return "double";
-        case etString: return "string";
-        case etArray: return "array";
-        case etObject: return "object";
+        case EntityType::Null: return "null";
+        case EntityType::Bool: return "bool";
+        case EntityType::Long: return "long";
+        case EntityType::Double: return "double";
+        case EntityType::String: return "string";
+        case EntityType::Arr: return "array";
+        case EntityType::Obj: return "object";
         default: return "unknown";
     }
 }
 
 Entity readEntity(JsonParser &p) {
     switch (p.peek()) {
-        case JsonParser::tkNull:
+        case JsonParser::Token::Null:
             p.advance();
             return Entity(p.line());
-        case JsonParser::tkBool:
+        case JsonParser::Token::Bool:
             p.advance();
             return Entity(p.boolValue(), p.line());
-        case JsonParser::tkLong:
+        case JsonParser::Token::Long:
             p.advance();
             return Entity(p.longValue(), p.line());
-        case JsonParser::tkDouble:
+        case JsonParser::Token::Double:
             p.advance();
             return Entity(p.doubleValue(), p.line());
-        case JsonParser::tkString:
+        case JsonParser::Token::String:
             p.advance();
             return Entity(std::make_shared<String>(p.rawString()), p.line());
-        case JsonParser::tkArrayStart: {
+        case JsonParser::Token::ArrayStart: {
             size_t l = p.line();
             p.advance();
             std::shared_ptr<Array> v = std::make_shared<Array>();
-            while (p.peek() != JsonParser::tkArrayEnd) {
+            while (p.peek() != JsonParser::Token::ArrayEnd) {
                 v->push_back(readEntity(p));
             }
             p.advance();
             return Entity(v, l);
         }
-        case JsonParser::tkObjectStart: {
+        case JsonParser::Token::ObjectStart: {
             size_t l = p.line();
             p.advance();
             std::shared_ptr<Object> v = std::make_shared<Object>();
-            while (p.peek() != JsonParser::tkObjectEnd) {
+            while (p.peek() != JsonParser::Token::ObjectEnd) {
                 p.advance();
                 std::string k = p.stringValue();
                 Entity n = readEntity(p);
@@ -105,36 +105,35 @@ Entity loadEntity(const uint8_t *text, size_t len) {
 
 void writeEntity(JsonGenerator<JsonNullFormatter> &g, const Entity &n) {
     switch (n.type()) {
-        case etNull:
+        case EntityType::Null:
             g.encodeNull();
             break;
-        case etBool:
+        case EntityType::Bool:
             g.encodeBool(n.boolValue());
             break;
-        case etLong:
+        case EntityType::Long:
             g.encodeNumber(n.longValue());
             break;
-        case etDouble:
+        case EntityType::Double:
             g.encodeNumber(n.doubleValue());
             break;
-        case etString:
+        case EntityType::String:
             g.encodeString(n.stringValue());
             break;
-        case etArray: {
+        case EntityType::Arr: {
             g.arrayStart();
             const Array &v = n.arrayValue();
-            for (Array::const_iterator it = v.begin();
-                 it != v.end(); ++it) {
-                writeEntity(g, *it);
+            for (const auto &it : v) {
+                writeEntity(g, it);
             }
             g.arrayEnd();
         } break;
-        case etObject: {
+        case EntityType::Obj: {
             g.objectStart();
             const Object &v = n.objectValue();
-            for (Object::const_iterator it = v.begin(); it != v.end(); ++it) {
-                g.encodeString(it->first);
-                writeEntity(g, it->second);
+            for (const auto &it : v) {
+                g.encodeString(it.first);
+                writeEntity(g, it.second);
             }
             g.objectEnd();
         } break;
@@ -149,12 +148,12 @@ void Entity::ensureType(EntityType type) const {
 }
 
 String Entity::stringValue() const {
-    ensureType(etString);
+    ensureType(EntityType::String);
     return JsonParser::toStringValue(**boost::any_cast<std::shared_ptr<String>>(&value_));
 }
 
 String Entity::bytesValue() const {
-    ensureType(etString);
+    ensureType(EntityType::String);
     return JsonParser::toBytesValue(**boost::any_cast<std::shared_ptr<String>>(&value_));
 }
 
@@ -165,7 +164,7 @@ std::string Entity::toString() const {
     writeEntity(g, *this);
     g.flush();
     std::unique_ptr<InputStream> in = memoryInputStream(*out);
-    const uint8_t *p = 0;
+    const uint8_t *p = nullptr;
     size_t n = 0;
     size_t c = 0;
     while (in->next(&p, &n)) {
diff --git a/lang/c++/impl/json/JsonDom.hh b/lang/c++/impl/json/JsonDom.hh
index cc17a86..3fb5670 100644
--- a/lang/c++/impl/json/JsonDom.hh
+++ b/lang/c++/impl/json/JsonDom.hh
@@ -19,10 +19,10 @@
 #ifndef avro_json_JsonDom_hh__
 #define avro_json_JsonDom_hh__
 
+#include <cstdint>
 #include <iostream>
 #include <map>
 #include <memory>
-#include <stdint.h>
 #include <string>
 #include <vector>
 
@@ -49,18 +49,22 @@ class JsonNullFormatter;
 template<typename F = JsonNullFormatter>
 class AVRO_DECL JsonGenerator;
 
-enum EntityType {
-    etNull,
-    etBool,
-    etLong,
-    etDouble,
-    etString,
-    etArray,
-    etObject
+enum class EntityType {
+    Null,
+    Bool,
+    Long,
+    Double,
+    String,
+    Arr,
+    Obj
 };
 
 const char *typeToString(EntityType t);
 
+inline std::ostream &operator<<(std::ostream &os, EntityType et) {
+    return os << typeToString(et);
+}
+
 class AVRO_DECL Entity {
     EntityType type_;
     boost::any value_;
@@ -69,30 +73,42 @@ class AVRO_DECL Entity {
     void ensureType(EntityType) const;
 
 public:
-    Entity(size_t line = 0) : type_(etNull), line_(line) {}
-    Entity(Bool v, size_t line = 0) : type_(etBool), value_(v), line_(line) {}
-    Entity(Long v, size_t line = 0) : type_(etLong), value_(v), line_(line) {}
-    Entity(Double v, size_t line = 0) : type_(etDouble), value_(v), line_(line) {}
-    Entity(const std::shared_ptr<String> &v, size_t line = 0) : type_(etString), value_(v), line_(line) {}
-    Entity(const std::shared_ptr<Array> &v, size_t line = 0) : type_(etArray), value_(v), line_(line) {}
-    Entity(const std::shared_ptr<Object> &v, size_t line = 0) : type_(etObject), value_(v), line_(line) {}
+    explicit Entity(size_t line = 0) : type_(EntityType::Null), line_(line) {}
+    // Not explicit because do want implicit conversion
+    // NOLINTNEXTLINE(google-explicit-constructor)
+    Entity(Bool v, size_t line = 0) : type_(EntityType::Bool), value_(v), line_(line) {}
+    // Not explicit because do want implicit conversion
+    // NOLINTNEXTLINE(google-explicit-constructor)
+    Entity(Long v, size_t line = 0) : type_(EntityType::Long), value_(v), line_(line) {}
+    // Not explicit because do want implicit conversion
+    // NOLINTNEXTLINE(google-explicit-constructor)
+    Entity(Double v, size_t line = 0) : type_(EntityType::Double), value_(v), line_(line) {}
+    // Not explicit because do want implicit conversion
+    // NOLINTNEXTLINE(google-explicit-constructor)
+    Entity(const std::shared_ptr<String> &v, size_t line = 0) : type_(EntityType::String), value_(v), line_(line) {}
+    // Not explicit because do want implicit conversion
+    // NOLINTNEXTLINE(google-explicit-constructor)
+    Entity(const std::shared_ptr<Array> &v, size_t line = 0) : type_(EntityType::Arr), value_(v), line_(line) {}
+    // Not explicit because do want implicit conversion
+    // NOLINTNEXTLINE(google-explicit-constructor)
+    Entity(const std::shared_ptr<Object> &v, size_t line = 0) : type_(EntityType::Obj), value_(v), line_(line) {}
 
     EntityType type() const { return type_; }
 
     size_t line() const { return line_; }
 
     Bool boolValue() const {
-        ensureType(etBool);
+        ensureType(EntityType::Bool);
         return boost::any_cast<Bool>(value_);
     }
 
     Long longValue() const {
-        ensureType(etLong);
+        ensureType(EntityType::Long);
         return boost::any_cast<Long>(value_);
     }
 
     Double doubleValue() const {
-        ensureType(etDouble);
+        ensureType(EntityType::Double);
         return boost::any_cast<Double>(value_);
     }
 
@@ -101,12 +117,12 @@ public:
     String bytesValue() const;
 
     const Array &arrayValue() const {
-        ensureType(etArray);
+        ensureType(EntityType::Arr);
         return **boost::any_cast<std::shared_ptr<Array>>(&value_);
     }
 
     const Object &objectValue() const {
-        ensureType(etObject);
+        ensureType(EntityType::Obj);
         return **boost::any_cast<std::shared_ptr<Object>>(&value_);
     }
 
@@ -119,37 +135,37 @@ struct type_traits {
 
 template<>
 struct type_traits<bool> {
-    static EntityType type() { return etBool; }
+    static EntityType type() { return EntityType::Bool; }
     static const char *name() { return "bool"; }
 };
 
 template<>
 struct type_traits<int64_t> {
-    static EntityType type() { return etLong; }
+    static EntityType type() { return EntityType::Long; }
     static const char *name() { return "long"; }
 };
 
 template<>
 struct type_traits<double> {
-    static EntityType type() { return etDouble; }
+    static EntityType type() { return EntityType::Double; }
     static const char *name() { return "double"; }
 };
 
 template<>
 struct type_traits<std::string> {
-    static EntityType type() { return etString; }
+    static EntityType type() { return EntityType::String; }
     static const char *name() { return "string"; }
 };
 
 template<>
 struct type_traits<std::vector<Entity>> {
-    static EntityType type() { return etArray; }
+    static EntityType type() { return EntityType::Arr; }
     static const char *name() { return "array"; }
 };
 
 template<>
 struct type_traits<std::map<std::string, Entity>> {
-    static EntityType type() { return etObject; }
+    static EntityType type() { return EntityType::Obj; }
     static const char *name() { return "object"; }
 };
 
diff --git a/lang/c++/impl/json/JsonIO.cc b/lang/c++/impl/json/JsonIO.cc
index ba930e6..6254948 100644
--- a/lang/c++/impl/json/JsonIO.cc
+++ b/lang/c++/impl/json/JsonIO.cc
@@ -51,13 +51,13 @@ char JsonParser::next() {
 
 void JsonParser::expectToken(Token tk) {
     if (advance() != tk) {
-        if (tk == tkDouble) {
-            if (cur() == tkString
+        if (tk == Token::Double) {
+            if (cur() == Token::String
                 && (sv == "Infinity" || sv == "-Infinity" || sv == "NaN")) {
-                curToken = tkDouble;
+                curToken = Token::Double;
                 dv = sv == "Infinity" ? std::numeric_limits<double>::infinity() : sv == "-Infinity" ? -std::numeric_limits<double>::infinity() : std::numeric_limits<double>::quiet_NaN();
                 return;
-            } else if (cur() == tkLong) {
+            } else if (cur() == Token::Long) {
                 dv = double(lv);
                 return;
             }
@@ -76,7 +76,7 @@ JsonParser::Token JsonParser::doAdvance() {
         if (curState == stArray0 || curState == stArrayN) {
             curState = stateStack.top();
             stateStack.pop();
-            return tkArrayEnd;
+            return Token::ArrayEnd;
         } else {
             throw unexpected(ch);
         }
@@ -84,7 +84,7 @@ JsonParser::Token JsonParser::doAdvance() {
         if (curState == stObject0 || curState == stObjectN) {
             curState = stateStack.top();
             stateStack.pop();
-            return tkObjectEnd;
+            return Token::ObjectEnd;
         } else {
             throw unexpected(ch);
         }
@@ -117,21 +117,21 @@ JsonParser::Token JsonParser::doAdvance() {
         case '[':
             stateStack.push(curState);
             curState = stArray0;
-            return tkArrayStart;
+            return Token::ArrayStart;
         case '{':
             stateStack.push(curState);
             curState = stObject0;
-            return tkObjectStart;
+            return Token::ObjectStart;
         case '"':
             return tryString();
         case 't':
             bv = true;
-            return tryLiteral("rue", 3, tkBool);
+            return tryLiteral("rue", 3, Token::Bool);
         case 'f':
             bv = false;
-            return tryLiteral("alse", 4, tkBool);
+            return tryLiteral("alse", 4, Token::Bool);
         case 'n':
-            return tryLiteral("ull", 3, tkNull);
+            return tryLiteral("ull", 3, Token::Null);
         default:
             if (isdigit(ch) || ch == '-') {
                 return tryNumber(ch);
@@ -244,6 +244,8 @@ JsonParser::Token JsonParser::tryNumber(char ch) {
                     hasNext = true;
                 }
                 break;
+            default:
+                throw Exception("Unexpected JSON parse state");
         }
         if (state == 1 || state == 2 || state == 4 || state == 7) {
             if (hasNext) {
@@ -252,10 +254,10 @@ JsonParser::Token JsonParser::tryNumber(char ch) {
             std::istringstream iss(sv);
             if (state == 1 || state == 2) {
                 iss >> lv;
-                return tkLong;
+                return Token::Long;
             } else {
                 iss >> dv;
-                return tkDouble;
+                return Token::Double;
             }
         } else {
             if (hasNext) {
@@ -272,7 +274,7 @@ JsonParser::Token JsonParser::tryString() {
     for (;;) {
         char ch = in_.read();
         if (ch == '"') {
-            return tkString;
+            return Token::String;
         } else if (ch == '\\') {
             ch = in_.read();
             switch (ch) {
@@ -294,9 +296,8 @@ JsonParser::Token JsonParser::tryString() {
                     in_.readBytes(reinterpret_cast<uint8_t *>(e), 4);
                     sv.push_back('\\');
                     sv.push_back(ch);
-                    for (int i = 0; i < 4; i++) {
+                    for (char c : e) {
                         n *= 16;
-                        char c = e[i];
                         if (isdigit(c) || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')) {
                             sv.push_back(c);
                         } else {
@@ -344,10 +345,10 @@ string JsonParser::decodeString(const string &s, bool binary) {
                 case 'U': {
                     uint32_t n = 0;
                     char e[4];
-                    for (int i = 0; i < 4; i++) {
+                    for (char &i : e) {
                         n *= 16;
                         char c = *++it;
-                        e[i] = c;
+                        i = c;
                         if (isdigit(c)) {
                             n += c - '0';
                         } else if (c >= 'a' && c <= 'f') {
@@ -387,6 +388,8 @@ string JsonParser::decodeString(const string &s, bool binary) {
                     }
                 }
                     continue;
+                default:
+                    throw Exception("Unexpected JSON parse state");
             }
         } else {
             result.push_back(ch);
diff --git a/lang/c++/impl/json/JsonIO.hh b/lang/c++/impl/json/JsonIO.hh
index 466e5b7..94889e5 100644
--- a/lang/c++/impl/json/JsonIO.hh
+++ b/lang/c++/impl/json/JsonIO.hh
@@ -39,16 +39,16 @@ inline char toHex(unsigned int n) {
 
 class AVRO_DECL JsonParser : boost::noncopyable {
 public:
-    enum Token {
-        tkNull,
-        tkBool,
-        tkLong,
-        tkDouble,
-        tkString,
-        tkArrayStart,
-        tkArrayEnd,
-        tkObjectStart,
-        tkObjectEnd
+    enum class Token {
+        Null,
+        Bool,
+        Long,
+        Double,
+        String,
+        ArrayStart,
+        ArrayEnd,
+        ObjectStart,
+        ObjectEnd
     };
 
     size_t line() const { return line_; }
@@ -80,13 +80,14 @@ private:
     Token tryLiteral(const char exp[], size_t n, Token tk);
     Token tryNumber(char ch);
     Token tryString();
-    Exception unexpected(unsigned char ch);
+    static Exception unexpected(unsigned char ch);
     char next();
 
     static std::string decodeString(const std::string &s, bool binary);
 
 public:
-    JsonParser() : curState(stValue), hasNext(false), peeked(false), line_(1) {}
+    JsonParser() : curState(stValue), hasNext(false), nextChar(0), peeked(false),
+                   curToken(Token::Null), bv(false), lv(0), dv(0), line_(1) {}
 
     void init(InputStream &is) {
         // Clear by swapping with an empty stack
@@ -171,13 +172,13 @@ public:
     static const char *const tokenNames[];
 
     static const char *toString(Token tk) {
-        return tokenNames[tk];
+        return tokenNames[static_cast<size_t>(tk)];
     }
 };
 
 class AVRO_DECL JsonNullFormatter {
 public:
-    JsonNullFormatter(StreamWriter &) {}
+    explicit JsonNullFormatter(StreamWriter &) {}
 
     void handleObjectStart() {}
     void handleObjectEnd() {}
@@ -201,7 +202,7 @@ class AVRO_DECL JsonPrettyFormatter {
     }
 
 public:
-    JsonPrettyFormatter(StreamWriter &out) : out_(out), level_(0), indent_(10, ' ') {}
+    explicit JsonPrettyFormatter(StreamWriter &out) : out_(out), level_(0), indent_(10, ' ') {}
 
     void handleObjectStart() {
         out_.write('\n');
@@ -280,7 +281,7 @@ class AVRO_DECL JsonGenerator {
                     throw Exception("Invalid UTF-8 sequence");
                 } else {
                     int more = 1;
-                    uint32_t value = 0;
+                    uint32_t value;
                     if ((*p & 0x20) != 0) {
                         more++;
                         if ((*p & 0x10) != 0) {
diff --git a/lang/c++/impl/parsing/JsonCodec.cc b/lang/c++/impl/parsing/JsonCodec.cc
index 9416ff6..c207ed8 100644
--- a/lang/c++/impl/parsing/JsonCodec.cc
+++ b/lang/c++/impl/parsing/JsonCodec.cc
@@ -158,13 +158,13 @@ public:
     size_t handle(const Symbol &s) {
         switch (s.kind()) {
             case Symbol::sRecordStart:
-                expectToken(in_, JsonParser::tkObjectStart);
+                expectToken(in_, JsonParser::Token::ObjectStart);
                 break;
             case Symbol::sRecordEnd:
-                expectToken(in_, JsonParser::tkObjectEnd);
+                expectToken(in_, JsonParser::Token::ObjectEnd);
                 break;
             case Symbol::sField:
-                expectToken(in_, JsonParser::tkString);
+                expectToken(in_, JsonParser::Token::String);
                 if (s.extra<string>() != in_.stringValue()) {
                     throw Exception("Incorrect field");
                 }
@@ -227,13 +227,13 @@ void JsonDecoder<P>::expect(JsonParser::Token tk) {
 template<typename P>
 void JsonDecoder<P>::decodeNull() {
     parser_.advance(Symbol::sNull);
-    expect(JsonParser::tkNull);
+    expect(JsonParser::Token::Null);
 }
 
 template<typename P>
 bool JsonDecoder<P>::decodeBool() {
     parser_.advance(Symbol::sBool);
-    expect(JsonParser::tkBool);
+    expect(JsonParser::Token::Bool);
     bool result = in_.boolValue();
     return result;
 }
@@ -241,7 +241,7 @@ bool JsonDecoder<P>::decodeBool() {
 template<typename P>
 int32_t JsonDecoder<P>::decodeInt() {
     parser_.advance(Symbol::sInt);
-    expect(JsonParser::tkLong);
+    expect(JsonParser::Token::Long);
     int64_t result = in_.longValue();
     if (result < INT32_MIN || result > INT32_MAX) {
         throw Exception(boost::format("Value out of range for Avro int: %1%")
@@ -253,7 +253,7 @@ int32_t JsonDecoder<P>::decodeInt() {
 template<typename P>
 int64_t JsonDecoder<P>::decodeLong() {
     parser_.advance(Symbol::sLong);
-    expect(JsonParser::tkLong);
+    expect(JsonParser::Token::Long);
     int64_t result = in_.longValue();
     return result;
 }
@@ -261,7 +261,7 @@ int64_t JsonDecoder<P>::decodeLong() {
 template<typename P>
 float JsonDecoder<P>::decodeFloat() {
     parser_.advance(Symbol::sFloat);
-    expect(JsonParser::tkDouble);
+    expect(JsonParser::Token::Double);
     double result = in_.doubleValue();
     return static_cast<float>(result);
 }
@@ -269,7 +269,7 @@ float JsonDecoder<P>::decodeFloat() {
 template<typename P>
 double JsonDecoder<P>::decodeDouble() {
     parser_.advance(Symbol::sDouble);
-    expect(JsonParser::tkDouble);
+    expect(JsonParser::Token::Double);
     double result = in_.doubleValue();
     return result;
 }
@@ -277,14 +277,14 @@ double JsonDecoder<P>::decodeDouble() {
 template<typename P>
 void JsonDecoder<P>::decodeString(string &value) {
     parser_.advance(Symbol::sString);
-    expect(JsonParser::tkString);
+    expect(JsonParser::Token::String);
     value = in_.stringValue();
 }
 
 template<typename P>
 void JsonDecoder<P>::skipString() {
     parser_.advance(Symbol::sString);
-    expect(JsonParser::tkString);
+    expect(JsonParser::Token::String);
 }
 
 static vector<uint8_t> toBytes(const string &s) {
@@ -294,21 +294,21 @@ static vector<uint8_t> toBytes(const string &s) {
 template<typename P>
 void JsonDecoder<P>::decodeBytes(vector<uint8_t> &value) {
     parser_.advance(Symbol::sBytes);
-    expect(JsonParser::tkString);
+    expect(JsonParser::Token::String);
     value = toBytes(in_.bytesValue());
 }
 
 template<typename P>
 void JsonDecoder<P>::skipBytes() {
     parser_.advance(Symbol::sBytes);
-    expect(JsonParser::tkString);
+    expect(JsonParser::Token::String);
 }
 
 template<typename P>
 void JsonDecoder<P>::decodeFixed(size_t n, vector<uint8_t> &value) {
     parser_.advance(Symbol::sFixed);
     parser_.assertSize(n);
-    expect(JsonParser::tkString);
+    expect(JsonParser::Token::String);
     value = toBytes(in_.bytesValue());
     if (value.size() != n) {
         throw Exception("Incorrect value for fixed");
@@ -319,7 +319,7 @@ template<typename P>
 void JsonDecoder<P>::skipFixed(size_t n) {
     parser_.advance(Symbol::sFixed);
     parser_.assertSize(n);
-    expect(JsonParser::tkString);
+    expect(JsonParser::Token::String);
     vector<uint8_t> result = toBytes(in_.bytesValue());
     if (result.size() != n) {
         throw Exception("Incorrect value for fixed");
@@ -329,7 +329,7 @@ void JsonDecoder<P>::skipFixed(size_t n) {
 template<typename P>
 size_t JsonDecoder<P>::decodeEnum() {
     parser_.advance(Symbol::sEnum);
-    expect(JsonParser::tkString);
+    expect(JsonParser::Token::String);
     size_t result = parser_.indexForName(in_.stringValue());
     return result;
 }
@@ -338,14 +338,14 @@ template<typename P>
 size_t JsonDecoder<P>::arrayStart() {
     parser_.advance(Symbol::sArrayStart);
     parser_.pushRepeatCount(0);
-    expect(JsonParser::tkArrayStart);
+    expect(JsonParser::Token::ArrayStart);
     return arrayNext();
 }
 
 template<typename P>
 size_t JsonDecoder<P>::arrayNext() {
     parser_.processImplicitActions();
-    if (in_.peek() == JsonParser::tkArrayEnd) {
+    if (in_.peek() == JsonParser::Token::ArrayEnd) {
         in_.advance();
         parser_.popRepeater();
         parser_.advance(Symbol::sArrayEnd);
@@ -360,12 +360,12 @@ void JsonDecoder<P>::skipComposite() {
     size_t level = 0;
     for (;;) {
         switch (in_.advance()) {
-            case JsonParser::tkArrayStart:
-            case JsonParser::tkObjectStart:
+            case JsonParser::Token::ArrayStart:
+            case JsonParser::Token::ObjectStart:
                 ++level;
                 continue;
-            case JsonParser::tkArrayEnd:
-            case JsonParser::tkObjectEnd:
+            case JsonParser::Token::ArrayEnd:
+            case JsonParser::Token::ObjectEnd:
                 if (level == 0) {
                     return;
                 }
@@ -388,7 +388,7 @@ size_t JsonDecoder<P>::skipArray() {
     parser_.advance(Symbol::sArrayStart);
     parser_.pop();
     parser_.advance(Symbol::sArrayEnd);
-    expect(JsonParser::tkArrayStart);
+    expect(JsonParser::Token::ArrayStart);
     skipComposite();
     return 0;
 }
@@ -397,14 +397,14 @@ template<typename P>
 size_t JsonDecoder<P>::mapStart() {
     parser_.advance(Symbol::sMapStart);
     parser_.pushRepeatCount(0);
-    expect(JsonParser::tkObjectStart);
+    expect(JsonParser::Token::ObjectStart);
     return mapNext();
 }
 
 template<typename P>
 size_t JsonDecoder<P>::mapNext() {
     parser_.processImplicitActions();
-    if (in_.peek() == JsonParser::tkObjectEnd) {
+    if (in_.peek() == JsonParser::Token::ObjectEnd) {
         in_.advance();
         parser_.popRepeater();
         parser_.advance(Symbol::sMapEnd);
@@ -419,7 +419,7 @@ size_t JsonDecoder<P>::skipMap() {
     parser_.advance(Symbol::sMapStart);
     parser_.pop();
     parser_.advance(Symbol::sMapEnd);
-    expect(JsonParser::tkObjectStart);
+    expect(JsonParser::Token::ObjectStart);
     skipComposite();
     return 0;
 }
@@ -429,11 +429,11 @@ size_t JsonDecoder<P>::decodeUnionIndex() {
     parser_.advance(Symbol::sUnion);
 
     size_t result;
-    if (in_.peek() == JsonParser::tkNull) {
+    if (in_.peek() == JsonParser::Token::Null) {
         result = parser_.indexForName("null");
     } else {
-        expect(JsonParser::tkObjectStart);
-        expect(JsonParser::tkString);
+        expect(JsonParser::Token::ObjectStart);
+        expect(JsonParser::Token::String);
         result = parser_.indexForName(in_.stringValue());
     }
     parser_.selectBranch(result);
diff --git a/lang/c++/test/JsonTests.cc b/lang/c++/test/JsonTests.cc
index 6b5ec60..3832e69 100644
--- a/lang/c++/test/JsonTests.cc
+++ b/lang/c++/test/JsonTests.cc
@@ -24,8 +24,6 @@
 
 #include "../impl/json/JsonDom.hh"
 
-#define S(x) #x
-
 namespace avro {
 namespace json {
 
@@ -38,38 +36,38 @@ struct TestData {
 };
 
 TestData<bool> boolData[] = {
-    {"true", etBool, true, "true"},
-    {"false", etBool, false, "false"},
+    {"true", EntityType::Bool, true, "true"},
+    {"false", EntityType::Bool, false, "false"},
 };
 
 TestData<int64_t> longData[] = {
-    {"0", etLong, 0, "0"},
-    {"-1", etLong, -1, "-1"},
-    {"1", etLong, 1, "1"},
-    {"9223372036854775807", etLong, 9223372036854775807LL, "9223372036854775807"},
-    {"-9223372036854775807", etLong, -9223372036854775807LL, "-9223372036854775807"},
+    {"0", EntityType::Long, 0, "0"},
+    {"-1", EntityType::Long, -1, "-1"},
+    {"1", EntityType::Long, 1, "1"},
+    {"9223372036854775807", EntityType::Long, 9223372036854775807LL, "9223372036854775807"},
+    {"-9223372036854775807", EntityType::Long, -9223372036854775807LL, "-9223372036854775807"},
 };
 
 TestData<double> doubleData[] = {
-    {"0.0", etDouble, 0.0, "0"},
-    {"-1.0", etDouble, -1.0, "-1"},
-    {"1.0", etDouble, 1.0, "1"},
-    {"4.7e3", etDouble, 4700.0, "4700"},
-    {"-7.2e-4", etDouble, -0.00072, NULL},
-    {"1e4", etDouble, 10000, "10000"},
-    {"-1e-4", etDouble, -0.0001, "-0.0001"},
-    {"-0e0", etDouble, 0.0, "-0"},
+    {"0.0", EntityType::Double, 0.0, "0"},
+    {"-1.0", EntityType::Double, -1.0, "-1"},
+    {"1.0", EntityType::Double, 1.0, "1"},
+    {"4.7e3", EntityType::Double, 4700.0, "4700"},
+    {"-7.2e-4", EntityType::Double, -0.00072, nullptr},
+    {"1e4", EntityType::Double, 10000, "10000"},
+    {"-1e-4", EntityType::Double, -0.0001, "-0.0001"},
+    {"-0e0", EntityType::Double, 0.0, "-0"},
 };
 
 TestData<const char *> stringData[] = {
-    {"\"\"", etString, "", "\"\""},
-    {"\"a\"", etString, "a", "\"a\""},
-    {"\"\\U000a\"", etString, "\n", "\"\\n\""},
-    {"\"\\u000a\"", etString, "\n", "\"\\n\""},
-    {"\"\\\"\"", etString, "\"", "\"\\\"\""},
-    {"\"\\/\"", etString, "/", "\"\\/\""},
-    {"\"\\u20ac\"", etString, "\xe2\x82\xac", "\"\\u20ac\""},
-    {"\"\\u03c0\"", etString, "\xcf\x80", "\"\\u03c0\""},
+    {"\"\"", EntityType::String, "", "\"\""},
+    {"\"a\"", EntityType::String, "a", "\"a\""},
+    {R"("\U000a")", EntityType::String, "\n", R"("\n")"},
+    {R"("\u000a")", EntityType::String, "\n", R"("\n")"},
+    {R"("\"")", EntityType::String, "\"", R"("\"")"},
+    {R"("\/")", EntityType::String, "/", R"("\/")"},
+    {R"("\u20ac")", EntityType::String, "\xe2\x82\xac", R"("\u20ac")"},
+    {R"("\u03c0")", EntityType::String, "\xcf\x80", R"("\u03c0")"},
 };
 
 void testBool(const TestData<bool> &d) {
@@ -90,7 +88,7 @@ void testDouble(const TestData<double> &d) {
     Entity n = loadEntity(d.input);
     BOOST_CHECK_EQUAL(n.type(), d.type);
     BOOST_CHECK_CLOSE(n.doubleValue(), d.value, 1e-10);
-    if (d.output != NULL) {
+    if (d.output != nullptr) {
         BOOST_CHECK_EQUAL(n.toString(), d.output);
     }
 }
@@ -104,99 +102,99 @@ void testString(const TestData<const char *> &d) {
 
 static void testNull() {
     Entity n = loadEntity("null");
-    BOOST_CHECK_EQUAL(n.type(), etNull);
+    BOOST_CHECK_EQUAL(n.type(), EntityType::Null);
 }
 
 static void testArray0() {
     Entity n = loadEntity("[]");
-    BOOST_CHECK_EQUAL(n.type(), etArray);
+    BOOST_CHECK_EQUAL(n.type(), EntityType::Arr);
     const Array &a = n.arrayValue();
     BOOST_CHECK_EQUAL(a.size(), 0);
 }
 
 static void testArray1() {
     Entity n = loadEntity("[200]");
-    BOOST_CHECK_EQUAL(n.type(), etArray);
+    BOOST_CHECK_EQUAL(n.type(), EntityType::Arr);
     const Array &a = n.arrayValue();
     BOOST_CHECK_EQUAL(a.size(), 1);
-    BOOST_CHECK_EQUAL(a[0].type(), etLong);
+    BOOST_CHECK_EQUAL(a[0].type(), EntityType::Long);
     BOOST_CHECK_EQUAL(a[0].longValue(), 200ll);
 }
 
 static void testArray2() {
     Entity n = loadEntity("[200, \"v100\"]");
-    BOOST_CHECK_EQUAL(n.type(), etArray);
+    BOOST_CHECK_EQUAL(n.type(), EntityType::Arr);
     const Array &a = n.arrayValue();
     BOOST_CHECK_EQUAL(a.size(), 2);
-    BOOST_CHECK_EQUAL(a[0].type(), etLong);
+    BOOST_CHECK_EQUAL(a[0].type(), EntityType::Long);
     BOOST_CHECK_EQUAL(a[0].longValue(), 200ll);
-    BOOST_CHECK_EQUAL(a[1].type(), etString);
+    BOOST_CHECK_EQUAL(a[1].type(), EntityType::String);
     BOOST_CHECK_EQUAL(a[1].stringValue(), "v100");
 }
 
 static void testObject0() {
     Entity n = loadEntity("{}");
-    BOOST_CHECK_EQUAL(n.type(), etObject);
+    BOOST_CHECK_EQUAL(n.type(), EntityType::Obj);
     const Object &m = n.objectValue();
     BOOST_CHECK_EQUAL(m.size(), 0);
 }
 
 static void testObject1() {
     Entity n = loadEntity("{\"k1\": 100}");
-    BOOST_CHECK_EQUAL(n.type(), etObject);
+    BOOST_CHECK_EQUAL(n.type(), EntityType::Obj);
     const Object &m = n.objectValue();
     BOOST_CHECK_EQUAL(m.size(), 1);
     BOOST_CHECK_EQUAL(m.begin()->first, "k1");
-    BOOST_CHECK_EQUAL(m.begin()->second.type(), etLong);
+    BOOST_CHECK_EQUAL(m.begin()->second.type(), EntityType::Long);
     BOOST_CHECK_EQUAL(m.begin()->second.longValue(), 100ll);
 }
 
 static void testObject2() {
-    Entity n = loadEntity("{\"k1\": 100, \"k2\": [400, \"v0\"]}");
-    BOOST_CHECK_EQUAL(n.type(), etObject);
+    Entity n = loadEntity(R"({"k1": 100, "k2": [400, "v0"]})");
+    BOOST_CHECK_EQUAL(n.type(), EntityType::Obj);
     const Object &m = n.objectValue();
     BOOST_CHECK_EQUAL(m.size(), 2);
 
-    Object::const_iterator it = m.find("k1");
+    auto it = m.find("k1");
     BOOST_CHECK(it != m.end());
-    BOOST_CHECK_EQUAL(it->second.type(), etLong);
+    BOOST_CHECK_EQUAL(it->second.type(), EntityType::Long);
     BOOST_CHECK_EQUAL(m.begin()->second.longValue(), 100ll);
 
     it = m.find("k2");
     BOOST_CHECK(it != m.end());
-    BOOST_CHECK_EQUAL(it->second.type(), etArray);
+    BOOST_CHECK_EQUAL(it->second.type(), EntityType::Arr);
     const Array &a = it->second.arrayValue();
     BOOST_CHECK_EQUAL(a.size(), 2);
-    BOOST_CHECK_EQUAL(a[0].type(), etLong);
+    BOOST_CHECK_EQUAL(a[0].type(), EntityType::Long);
     BOOST_CHECK_EQUAL(a[0].longValue(), 400ll);
-    BOOST_CHECK_EQUAL(a[1].type(), etString);
+    BOOST_CHECK_EQUAL(a[1].type(), EntityType::String);
     BOOST_CHECK_EQUAL(a[1].stringValue(), "v0");
 }
 
 } // namespace json
 } // namespace avro
 
-#define COUNTOF(x) (sizeof(x) / sizeof(x[0]))
+#define COUNT_OF(x) (sizeof(x) / sizeof(x[0]))
 
 boost::unit_test::test_suite *
-init_unit_test_suite(int argc, char *argv[]) {
+init_unit_test_suite(int /* argc */, char * /* argv */[]) {
     using namespace boost::unit_test;
 
-    test_suite *ts = BOOST_TEST_SUITE("Avro C++ unit tests for json routines");
+    auto *ts = BOOST_TEST_SUITE("Avro C++ unit tests for json routines");
 
     ts->add(BOOST_TEST_CASE(&avro::json::testNull));
     ts->add(BOOST_PARAM_TEST_CASE(&avro::json::testBool,
                                   avro::json::boolData,
-                                  avro::json::boolData + COUNTOF(avro::json::boolData)));
+                                  avro::json::boolData + COUNT_OF(avro::json::boolData)));
     ts->add(BOOST_PARAM_TEST_CASE(&avro::json::testLong,
                                   avro::json::longData,
-                                  avro::json::longData + COUNTOF(avro::json::longData)));
+                                  avro::json::longData + COUNT_OF(avro::json::longData)));
     ts->add(BOOST_PARAM_TEST_CASE(&avro::json::testDouble,
                                   avro::json::doubleData,
-                                  avro::json::doubleData + COUNTOF(avro::json::doubleData)));
+                                  avro::json::doubleData + COUNT_OF(avro::json::doubleData)));
     ts->add(BOOST_PARAM_TEST_CASE(&avro::json::testString,
                                   avro::json::stringData,
-                                  avro::json::stringData + COUNTOF(avro::json::stringData)));
+                                  avro::json::stringData + COUNT_OF(avro::json::stringData)));
 
     ts->add(BOOST_TEST_CASE(&avro::json::testArray0));
     ts->add(BOOST_TEST_CASE(&avro::json::testArray1));