From f2957dc3bfc0cb8b481ee8e95efc38cfca149542 Mon Sep 17 00:00:00 2001
From: Niels <niels.lohmann@gmail.com>
Date: Sun, 22 Mar 2015 19:07:43 +0100
Subject: [PATCH] fixed #45 (added count function for keys in objects)

---
 Makefile          |  2 +-
 src/json.hpp      |  8 ++++-
 src/json.hpp.re2c |  8 ++++-
 test/unit.cpp     | 79 +++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 94 insertions(+), 3 deletions(-)

diff --git a/Makefile b/Makefile
index 4353eb30..105f4369 100644
--- a/Makefile
+++ b/Makefile
@@ -3,7 +3,7 @@ RE2C = re2c
 SED = gsed
 
 # additional flags
-FLAGS = -Wall -Wextra -pedantic -Weffc++ -Wcast-align -Wcast-qual -Wctor-dtor-privacy -Wdisabled-optimization -Wformat=2 -Winit-self -Wmissing-declarations -Wmissing-include-dirs -Wold-style-cast -Woverloaded-virtual -Wredundant-decls -Wshadow -Wsign-conversion -Wsign-promo -Wstrict-overflow=5 -Wswitch -Wundef -Wno-unused -Wnon-virtual-dtor -Wreorder
+FLAGS = -Wall -Wextra -pedantic -Weffc++ -Wcast-align -Wcast-qual -Wctor-dtor-privacy -Wdisabled-optimization -Wformat=2 -Winit-self -Wmissing-declarations -Wmissing-include-dirs -Wold-style-cast -Woverloaded-virtual -Wredundant-decls -Wshadow -Wsign-conversion -Wsign-promo -Wstrict-overflow=5 -Wswitch -Wundef -Wno-unused -Wnon-virtual-dtor -Wreorder -Wdeprecated
 
 all: json_unit
 
diff --git a/src/json.hpp b/src/json.hpp
index 89269ea3..09880b9e 100644
--- a/src/json.hpp
+++ b/src/json.hpp
@@ -1049,7 +1049,6 @@ class basic_json
         return m_value.object->operator[](key);
     }
 
-
     /// find an element in an object
     inline iterator find(typename object_t::key_type key)
     {
@@ -1076,6 +1075,13 @@ class basic_json
         return result;
     }
 
+    /// returns the number of occurrences of a key in an object
+    inline size_type count(typename object_t::key_type key) const
+    {
+        // return 0 for all nonobject types
+        return (m_type == value_t::object) ? m_value.object->count(key) : 0;
+    }
+
 
     ///////////////
     // iterators //
diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c
index 5ebda5a7..36bb0e00 100644
--- a/src/json.hpp.re2c
+++ b/src/json.hpp.re2c
@@ -1049,7 +1049,6 @@ class basic_json
         return m_value.object->operator[](key);
     }
 
-
     /// find an element in an object
     inline iterator find(typename object_t::key_type key)
     {
@@ -1076,6 +1075,13 @@ class basic_json
         return result;
     }
 
+    /// returns the number of occurrences of a key in an object
+    inline size_type count(typename object_t::key_type key) const
+    {
+        // return 0 for all nonobject types
+        return (m_type == value_t::object) ? m_value.object->count(key) : 0;
+    }
+
 
     ///////////////
     // iterators //
diff --git a/test/unit.cpp b/test/unit.cpp
index 81bfa977..fb73205a 100644
--- a/test/unit.cpp
+++ b/test/unit.cpp
@@ -2441,6 +2441,85 @@ TEST_CASE("element access")
                 }
             }
         }
+
+        SECTION("count keys in an object")
+        {
+            SECTION("existing element")
+            {
+                for (auto key :
+                        {"integer", "floating", "null", "string", "boolean", "object", "array"
+                        })
+                {
+                    CHECK(j.count(key) == 1);
+                    CHECK(j_const.count(key) == 1);
+                }
+            }
+
+            SECTION("nonexisting element")
+            {
+                CHECK(j.count("foo") == 0);
+                CHECK(j_const.count("foo") == 0);
+            }
+
+            SECTION("all types")
+            {
+                SECTION("null")
+                {
+                    json j_nonobject(json::value_t::null);
+                    const json j_nonobject_const(j_nonobject);
+                    CHECK(j_nonobject.count("foo") == 0);
+                    CHECK(j_nonobject_const.count("foo") == 0);
+                }
+
+                SECTION("string")
+                {
+                    json j_nonobject(json::value_t::string);
+                    const json j_nonobject_const(j_nonobject);
+                    CHECK(j_nonobject.count("foo") == 0);
+                    CHECK(j_nonobject_const.count("foo") == 0);
+                }
+
+                SECTION("object")
+                {
+                    json j_nonobject(json::value_t::object);
+                    const json j_nonobject_const(j_nonobject);
+                    CHECK(j_nonobject.count("foo") == 0);
+                    CHECK(j_nonobject_const.count("foo") == 0);
+                }
+
+                SECTION("array")
+                {
+                    json j_nonobject(json::value_t::array);
+                    const json j_nonobject_const(j_nonobject);
+                    CHECK(j_nonobject.count("foo") == 0);
+                    CHECK(j_nonobject_const.count("foo") == 0);
+                }
+
+                SECTION("boolean")
+                {
+                    json j_nonobject(json::value_t::boolean);
+                    const json j_nonobject_const(j_nonobject);
+                    CHECK(j_nonobject.count("foo") == 0);
+                    CHECK(j_nonobject_const.count("foo") == 0);
+                }
+
+                SECTION("number (integer)")
+                {
+                    json j_nonobject(json::value_t::number_integer);
+                    const json j_nonobject_const(j_nonobject);
+                    CHECK(j_nonobject.count("foo") == 0);
+                    CHECK(j_nonobject_const.count("foo") == 0);
+                }
+
+                SECTION("number (floating-point)")
+                {
+                    json j_nonobject(json::value_t::number_float);
+                    const json j_nonobject_const(j_nonobject);
+                    CHECK(j_nonobject.count("foo") == 0);
+                    CHECK(j_nonobject_const.count("foo") == 0);
+                }
+            }
+        }
     }
 }