Browse Source

Moved parsing utilities to json_parser.cpp.
Moved json_parser.hpp parts to json/json_binder_parser.hpp.
Moved general json_parser.hpp parts to json_common.hpp

Samuel Jaffe 9 năm trước cách đây
mục cha
commit
3f4d671e87
11 tập tin đã thay đổi với 287 bổ sung179 xóa
  1. 19 65
      json.cpp
  2. 22 13
      json.h
  3. 32 12
      json.xcodeproj/project.pbxproj
  4. 0 19
      json_parser.hpp
  5. 2 10
      json/json_direct_scalar_binder.hpp
  6. 2 1
      json_binder.hpp
  7. 2 2
      json_common.cpp
  8. 0 56
      json_common.h
  9. 84 0
      json_common.hpp
  10. 124 0
      json_parser.cpp
  11. 0 1
      json_test.cpp

+ 19 - 65
json.cpp

@@ -6,74 +6,10 @@
 //  Copyright © 2016 Sam Jaffe. All rights reserved.
 //
 
-#include "json.h"
-#include "json_parser.hpp"
-#include "json_binder.hpp"
+#include "json.hpp"
 
 const json::value json::value::null_value{};
 
-namespace {
-  void parse_object(json::value& json, char const*& data);
-  void parse_array(json::value& json, char const*& data);
-  void parse_one_token(json::value& json, char const*& data);
-  
-  void parse_one_token(json::value& json, char const*& data) {
-    const char ch = json::helper::get_next_element(data);
-    if (ch == '{') {
-      parse_object(json, ++data);
-    } else if (ch == '[') {
-      parse_array(json, ++data);
-    } else if (ch == '"') {
-      json::helper::parse_string(json, ++data);
-    } else if (isnumber(ch)) {
-      json::helper::parse_numeric(json, data);
-    } else if (!strncmp(data, "true", 4)) {
-      json = true;
-    } else if (!strncmp(data, "false", 5)) {
-      json = false;
-    } else {
-      throw json::malformed_json_exception(std::string("Expected the start of a JSON element, found character '") + ch + "' instead");
-    }
-  }
-  
-  void parse_object(json::value& json, char const*& data) {
-    std::string key;
-    while (*data && *data != '}') {
-      json::helper::parse_string(key, data);
-      if (json::helper::get_next_element(data) != ':') {
-        throw json::malformed_json_exception(std::string("Expected key:value pair delimited by ':', got '") + *data + "' instead");
-      }
-      parse_one_token(json[key], ++data);
-      json::helper::advance_to_boundary<'}'>(data);
-    }
-    if (*data) ++data;
-    else throw json::malformed_json_exception("Reached end of parse string without finding object end");
-  }
-  
-  void parse_array(json::value& json, char const*& data) {
-    size_t current_idx = 0;
-    while (*data && *data != ']') {
-      parse_one_token(json[current_idx++], data);
-      json::helper::advance_to_boundary<']'>(data);
-    }
-    if (*data) ++data;
-    else throw json::malformed_json_exception("Reached end of parse string without finding array end");
-  }
-}
-
-namespace json {
-  namespace parser {
-    void parse(json::value& json, char const* data) {
-      parse_one_token(json, data);
-      if (*data) throw json::malformed_json_exception("Expected a single json token in top-level parse");
-    }
-  }
-}
-
-void json::value::parse(char const* data)  { parser::parse(*this, data); }
-void json::value::parse(std::string const& str) { parser::parse(*this, str); }
-void json::value::parse(std::istream & in)  { parser::parse(*this, in); }
-
 json::value& json::value::operator[](const size_t idx) {
   if (!is_array()) {
     data.set<array_jt>();
@@ -129,6 +65,22 @@ json::value::int_jt json::value::as_int() const {
     return static_cast<int_jt>(data.get<double_jt>());
   } else if (data.is<int_jt>()) {
     return data.get<int_jt>();
+  } else if (data.is<uint_jt>() && data.get<uint_jt>() <= uint_jt(INT_JT_MAX)) {
+    return static_cast<int_jt>(data.get<uint_jt>());
+  } else if (data.is<bool_jt>()) {
+    return data.get<bool_jt>() ? 1 : 0;
+  } else {
+    return 0;
+  }
+}
+
+json::value::uint_jt json::value::as_uint() const {
+  if (data.is<double_jt>()) {
+    return static_cast<int_jt>(data.get<double_jt>());
+  } else if (data.is<int_jt>() && data.get<int_jt>() >= 0) {
+    return data.get<int_jt>();
+  } else if (data.is<uint_jt>()) {
+    return data.get<uint_jt>();
   } else if (data.is<bool_jt>()) {
     return data.get<bool_jt>() ? 1 : 0;
   } else {
@@ -139,6 +91,8 @@ json::value::int_jt json::value::as_int() const {
 json::value::bool_jt json::value::as_bool() const {
   if (data.is<double_jt>()) {
     return data.get<double_jt>() != 0;
+  } else if (data.is<uint_jt>()) {
+    return data.get<uint_jt>() != 0;
   } else if (data.is<int_jt>()) {
     return data.get<int_jt>() != 0;
   } else if (data.is<bool_jt>()) {

+ 22 - 13
json.h

@@ -9,12 +9,10 @@
 #ifndef json_hpp
 #define json_hpp
 
-#include <map>
-#include <vector>
-#include <utility>
-
 #include "../variant/variant.hpp"
-#include "json_common.h"
+#include "json_common.hpp"
+
+#include <utility>
 
 #define JSON_TYPE_LIST \
   X(object) \
@@ -22,28 +20,37 @@
   X(string) \
   X(double) \
   X(int) \
+  X(uint) \
   X(bool)
 
 namespace json {
+  namespace {
+    const constexpr json::int_jt INT_JT_MAX_LAST_DIGIT = (0x7FFFFFFF % 10);
+    const constexpr json::int_jt INT_JT_MAX = json::uint_jt(-1) - 1;
+    const constexpr json::int_jt INT_JT_MIN = json::int_jt(~(json::uint_jt(-1) / 2));
+    const constexpr json::uint_jt INT_JT_OVER = json::uint_jt(INT_JT_MAX) + 1;
+    const constexpr json::uint_jt UINT_JT_MAX = json::uint_jt(0) - 1;
+    //  const constexpr json::uint_jt UINT_JT_MIN = 0;
+  }
+  
   class value;
   namespace parser {
-    template <typename T> void parse(T& json, char const* data);
-    template <typename T> void parse(T& json, std::string const& str);
-    template <typename T> void parse(T& json, std::istream & in);
+    void parse(value&, char const*);
   }
   
   class value {
   public:
     using object_jt = std::map<std::string, value>;
     using array_jt = std::vector<value>;
-    using string_jt = std::string;
-    using double_jt = double;
-    using int_jt = int32_t;
-    using bool_jt = bool;
+    using string_jt = json::string_jt;
+    using double_jt = json::double_jt;
+    using int_jt = json::int_jt;
+    using uint_jt = json::uint_jt;
+    using bool_jt = json::bool_jt;
   private:
     static const value null_value;
     
-    using data_t = variant<object_jt, array_jt, string_jt, double_jt, int_jt, bool_jt>;
+    using data_t = variant<object_jt, array_jt, string_jt, double_jt, int_jt, uint_jt, bool_jt>;
     data_t data;
   public:
 #define X(type) bool is_##type() const { return data.is<type##_jt>(); }
@@ -80,11 +87,13 @@ namespace json {
     string_jt const& as_string() const;
     double_jt as_double() const;
     int_jt as_int() const;
+    uint_jt as_uint() const;
     bool_jt as_bool() const;
     
     operator string_jt const&() const { return as_string(); }
     operator double_jt() const { return as_double(); }
     operator int_jt() const { return as_int(); }
+    operator uint_jt() const { return as_uint(); }
     operator bool_jt() const { return as_bool(); }
     
   };

+ 32 - 12
json.xcodeproj/project.pbxproj

@@ -10,8 +10,9 @@
 		CD217D911CCAD587007C50C6 /* json_test.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CD217D8F1CCAD587007C50C6 /* json_test.cpp */; };
 		CD472C761CCC1ABD0084C8D6 /* json_common.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CD472C751CCC1ABD0084C8D6 /* json_common.cpp */; };
 		CD472C771CCC1ABD0084C8D6 /* json_common.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CD472C751CCC1ABD0084C8D6 /* json_common.cpp */; };
+		CD472C801CCDA4B00084C8D6 /* json_parser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CD472C7F1CCDA4B00084C8D6 /* json_parser.cpp */; };
 		CDB2F7431C5D48090067C2EC /* json.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CDB2F7411C5D48090067C2EC /* json.cpp */; };
-		CDB2F7441C5D48090067C2EC /* json.h in Headers */ = {isa = PBXBuildFile; fileRef = CDB2F7421C5D48090067C2EC /* json.h */; };
+		CDB2F7441C5D48090067C2EC /* json.hpp in Headers */ = {isa = PBXBuildFile; fileRef = CDB2F7421C5D48090067C2EC /* json.hpp */; };
 /* End PBXBuildFile section */
 
 /* Begin PBXCopyFilesBuildPhase section */
@@ -28,7 +29,7 @@
 
 /* Begin PBXFileReference section */
 		CD217D8F1CCAD587007C50C6 /* json_test.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = json_test.cpp; sourceTree = "<group>"; };
-		CD217D921CCAD885007C50C6 /* json_common.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = json_common.h; sourceTree = "<group>"; };
+		CD217D921CCAD885007C50C6 /* json_common.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = json_common.hpp; sourceTree = "<group>"; };
 		CD472C751CCC1ABD0084C8D6 /* json_common.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = json_common.cpp; sourceTree = "<group>"; };
 		CD472C791CCC1CD80084C8D6 /* json_tuple_binder.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = json_tuple_binder.hpp; sourceTree = "<group>"; };
 		CD472C7A1CCC1D440084C8D6 /* json_object_binder.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = json_object_binder.hpp; sourceTree = "<group>"; };
@@ -36,11 +37,12 @@
 		CD472C7C1CCC1DDF0084C8D6 /* json_direct_vector_binder.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = json_direct_vector_binder.hpp; sourceTree = "<group>"; };
 		CD472C7D1CCC1E120084C8D6 /* json_direct_scalar_binder.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = json_direct_scalar_binder.hpp; sourceTree = "<group>"; };
 		CD472C7E1CCC498C0084C8D6 /* json_direct_binder.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = json_direct_binder.hpp; sourceTree = "<group>"; };
+		CD472C7F1CCDA4B00084C8D6 /* json_parser.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = json_parser.cpp; sourceTree = "<group>"; };
 		CDB2F7331C5D47F70067C2EC /* libjson.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libjson.dylib; sourceTree = BUILT_PRODUCTS_DIR; };
 		CDB2F7411C5D48090067C2EC /* json.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = json.cpp; sourceTree = "<group>"; tabWidth = 2; };
-		CDB2F7421C5D48090067C2EC /* json.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = json.h; sourceTree = "<group>"; tabWidth = 2; };
-		CDB2F7451C5E9BEB0067C2EC /* json_parser.hpp */ = {isa = PBXFileReference; indentWidth = 2; lastKnownFileType = sourcecode.cpp.h; path = json_parser.hpp; sourceTree = "<group>"; tabWidth = 2; };
-		CDB2F7461C5EA2E80067C2EC /* json_binder.hpp */ = {isa = PBXFileReference; indentWidth = 2; lastKnownFileType = sourcecode.cpp.h; path = json_binder.hpp; sourceTree = "<group>"; tabWidth = 2; };
+		CDB2F7421C5D48090067C2EC /* json.hpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.h; path = json.hpp; sourceTree = "<group>"; tabWidth = 2; };
+		CDB2F7451C5E9BEB0067C2EC /* json_binder_parser.hpp */ = {isa = PBXFileReference; indentWidth = 2; lastKnownFileType = sourcecode.cpp.h; path = json_binder_parser.hpp; sourceTree = "<group>"; tabWidth = 2; };
+		CDB2F7461C5EA2E80067C2EC /* json_binder.hpp */ = {isa = PBXFileReference; indentWidth = 2; lastKnownFileType = sourcecode.cpp.h; path = json_binder.hpp; sourceTree = SOURCE_ROOT; tabWidth = 2; };
 		CDF643321C6E9A8B0016A475 /* json-test */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "json-test"; sourceTree = BUILT_PRODUCTS_DIR; };
 /* End PBXFileReference section */
 
@@ -65,6 +67,7 @@
 		CD472C781CCC1CB00084C8D6 /* impl */ = {
 			isa = PBXGroup;
 			children = (
+				CDB2F7451C5E9BEB0067C2EC /* json_binder_parser.hpp */,
 				CD472C791CCC1CD80084C8D6 /* json_tuple_binder.hpp */,
 				CD472C7A1CCC1D440084C8D6 /* json_object_binder.hpp */,
 				CD472C7E1CCC498C0084C8D6 /* json_direct_binder.hpp */,
@@ -73,20 +76,36 @@
 				CD472C7C1CCC1DDF0084C8D6 /* json_direct_vector_binder.hpp */,
 			);
 			name = impl;
+			sourceTree = "<group>";
+		};
+		CD472C821CCDA5830084C8D6 /* binder */ = {
+			isa = PBXGroup;
+			children = (
+				CDB2F7461C5EA2E80067C2EC /* json_binder.hpp */,
+				CD472C781CCC1CB00084C8D6 /* impl */,
+			);
+			name = binder;
 			path = json;
 			sourceTree = "<group>";
 		};
+		CD472C831CCDA5990084C8D6 /* json */ = {
+			isa = PBXGroup;
+			children = (
+				CDB2F7411C5D48090067C2EC /* json.cpp */,
+				CDB2F7421C5D48090067C2EC /* json.hpp */,
+				CD472C7F1CCDA4B00084C8D6 /* json_parser.cpp */,
+			);
+			name = json;
+			sourceTree = "<group>";
+		};
 		CDB2F72A1C5D47F70067C2EC = {
 			isa = PBXGroup;
 			children = (
 				CD217D8F1CCAD587007C50C6 /* json_test.cpp */,
-				CDB2F7411C5D48090067C2EC /* json.cpp */,
-				CDB2F7421C5D48090067C2EC /* json.h */,
-				CD217D921CCAD885007C50C6 /* json_common.h */,
+				CD217D921CCAD885007C50C6 /* json_common.hpp */,
 				CD472C751CCC1ABD0084C8D6 /* json_common.cpp */,
-				CDB2F7451C5E9BEB0067C2EC /* json_parser.hpp */,
-				CDB2F7461C5EA2E80067C2EC /* json_binder.hpp */,
-				CD472C781CCC1CB00084C8D6 /* impl */,
+				CD472C831CCDA5990084C8D6 /* json */,
+				CD472C821CCDA5830084C8D6 /* binder */,
 				CDB2F7341C5D47F70067C2EC /* Products */,
 			);
 			sourceTree = "<group>";
@@ -107,7 +126,7 @@
 			isa = PBXHeadersBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
-				CDB2F7441C5D48090067C2EC /* json.h in Headers */,
+				CDB2F7441C5D48090067C2EC /* json.hpp in Headers */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -188,6 +207,7 @@
 			isa = PBXSourcesBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
+				CD472C801CCDA4B00084C8D6 /* json_parser.cpp in Sources */,
 				CDB2F7431C5D48090067C2EC /* json.cpp in Sources */,
 				CD472C761CCC1ABD0084C8D6 /* json_common.cpp in Sources */,
 			);

+ 0 - 19
json_parser.hpp

@@ -10,34 +10,15 @@
 #define json_parser_h
 #pragma once
 
-#include <iostream>
-
 namespace json {
   class value;
   
   namespace binder { template <typename, typename> class visitor; }
   
   namespace parser {
-    void parse(value& json, char const* data);
-    
     template <typename T, typename S>
     void parse(binder::visitor<T, S>&, char const*);
     
-    template <typename T>
-    void parse(T& json, std::string const& str) {
-      parse(json, str.c_str());
-    }
-    
-    template <typename T>
-    void parse(T& json, std::istream & in) {
-      in.seekg(0, std::ios_base::end);
-      size_t end = in.tellg();
-      char data[end];
-      in.seekg(0);
-      in.read(data, end);
-      parse(json, data);
-    }
-    
     template <typename T, typename S, typename V>
     void parse(binder::visitor<T, S>&& v, V& s) {
       parse(v, s);

+ 2 - 10
json/json_direct_scalar_binder.hpp

@@ -39,11 +39,7 @@ namespace json { namespace binder {
     virtual binder_impl<T>* clone() const override { return new direct_binder(*this); }
     
     virtual void parse(T& val, char const*& data) const override {
-      //        if (false) {
-      json::helper::parse_numeric(val.*ptr, data);
-      //        } else {
-      //          throw json::malformed_json_exception("Expected an integral type here");
-      //        }
+      json::helper::parse_integer(val.*ptr, data);
     }
     
     virtual void write(T const& val, std::string & data) const override {
@@ -62,11 +58,7 @@ namespace json { namespace binder {
     virtual binder_impl<T>* clone() const override { return new direct_binder(*this); }
     
     virtual void parse(T& val, char const*& data) const override {
-      //        if (false) {
-      json::helper::parse_numeric(val.*ptr, data);
-      //        } else {
-      //          throw json::malformed_json_exception("Expected a floating point type here");
-      //        }
+      json::helper::parse_double(val.*ptr, data);
     }
     
     virtual void write(T const& val, std::string & data) const override {

+ 2 - 1
json_binder.hpp

@@ -10,7 +10,7 @@
 #define json_binder_h
 #pragma once
 
-#include "json_common.h"
+#include "json_common.hpp"
 
 #include <map>
 #include <string>
@@ -103,6 +103,7 @@ namespace json {
   }
 }
 
+#include "json/json_binder_parser.hpp"
 #include "json/json_direct_binder.hpp"
 #include "json/json_tuple_binder.hpp"
 #include "json/json_object_binder.hpp"

+ 2 - 2
json_common.cpp

@@ -5,7 +5,7 @@
 //  Created by Sam Jaffe on 4/23/16.
 //
 
-#include "json_common.h"
+#include "json_common.hpp"
 
 namespace json {
   namespace helper {
@@ -41,6 +41,6 @@ namespace json {
         }
       }
       throw json::malformed_json_exception("Could not locate end of string");
-    }
+    }    
   }
 }

+ 0 - 56
json_common.h

@@ -1,56 +0,0 @@
-//
-//  json_common.h
-//  json
-//
-//  Created by Sam Jaffe on 4/22/16.
-//
-
-#pragma once
-
-#include <cstdlib>
-#include <stdexcept>
-#include <string>
-
-namespace json {
-  class malformed_json_exception : public std::domain_error {
-    using std::domain_error::domain_error;
-  };
-}
-
-namespace json {
-  namespace helper {
-    const char get_next_element(char const*& data);
-    
-    /**
-     * @throws json::malformed_json_exception
-     */
-    void advance_to_boundary(char const endtok, char const*& data);
-    
-    /**
-     * @throws json::malformed_json_exception
-     */
-    std::string parse_string(char const * & data);
-    
-    template <typename T>
-    void parse_string(T& json, char const*& data) {
-      json = parse_string(data);
-    }
-    
-    template <typename T>
-    void parse_numeric(T& json, char const*& data) {
-      // TODO: more sophisticated float detection?
-      char const* start = data;
-      while (*++data) {
-        if (*data == '.') {
-          while (isnumber(*++data));
-          json = atof(start);
-          break;
-        } else if (!isnumber(*data)) {
-          json = atoi(start);
-          break;
-        }
-      }
-    }
-    
-  }
-}

+ 84 - 0
json_common.hpp

@@ -0,0 +1,84 @@
+//
+//  json_common.h
+//  json
+//
+//  Created by Sam Jaffe on 4/22/16.
+//
+
+#pragma once
+
+#include "../variant/variant.hpp"
+
+#include <cstdlib>
+#include <iostream>
+#include <map>
+#include <stdexcept>
+#include <string>
+#include <vector>
+
+namespace json {
+  
+  using string_jt = std::string;
+  using double_jt = double;
+  using int_jt = int32_t;
+  using uint_jt = uint32_t;
+  using bool_jt = bool;
+  
+  using numeric_jt = variant<int_jt, uint_jt, double_jt>;
+  
+  class value;
+
+  class malformed_json_exception :
+  public std::domain_error {
+    using std::domain_error::domain_error;
+  };
+}
+
+namespace json {
+  namespace helper {
+    const char get_next_element(char const*& data);
+    
+    /**
+     * @throws json::malformed_json_exception
+     */
+    void advance_to_boundary(char const endtok, char const *& data);
+    
+    /**
+     * @throws json::malformed_json_exception
+     */
+    std::string parse_string(char const * & data);
+        
+    template <typename T>
+    void parse_string(T& json, char const * & data) {
+      json = parse_string(data);
+    }
+    
+    template <typename T>
+    void parse_double(T& json, char const * & data) {
+      json = atof(data);
+    }
+    
+    template <typename T>
+    void parse_integer(T& json, char const * & data) {
+      json = atoi(data);
+    }
+    
+  }
+  
+  namespace parser {
+    template <typename T>
+    void parse(T& json, std::string const& str) {
+      parse(json, str.c_str());
+    }
+    
+    template <typename T>
+    void parse(T& json, std::istream & in) {
+      in.seekg(0, std::ios_base::end);
+      size_t end = in.tellg();
+      char data[end];
+      in.seekg(0);
+      in.read(data, end);
+      parse(json, data);
+    }
+  }
+}

+ 124 - 0
json_parser.cpp

@@ -0,0 +1,124 @@
+//
+//  json_parser.cpp
+//  json
+//
+//  Created by Sam Jaffe on 4/24/16.
+//
+
+#include "json.hpp"
+
+namespace json { namespace {
+  char const * get_numeric_token_end(char const * start);
+  void parse_numeric(value& json, char const*& data);
+  void parse_object(value& json, char const*& data);
+  void parse_array(value& json, char const*& data);
+  void parse_one_token(value& json, char const*& data);
+  
+  void parse_one_token(value& json, char const*& data) {
+    const char ch = helper::get_next_element(data);
+    if (ch == '{') {
+      parse_object(json, ++data);
+    } else if (ch == '[') {
+      parse_array(json, ++data);
+    } else if (ch == '"') {
+      helper::parse_string(json, ++data);
+    } else if (!strncmp(data, "true", 4)) {
+      json = true;
+    } else if (!strncmp(data, "false", 5)) {
+      json = false;
+    } else {
+      parse_numeric(json, data);
+    }
+  }
+  
+  char const * get_numeric_token_end(char const * start) {
+    while (strchr(",]}", *start) == NULL &&
+           !isspace(*start)) {
+      ++start;
+    }
+    return start;
+  }
+  
+  void parse_numeric(value & json, char const * & data) {
+    char const * start = data;
+    char const * const end = get_numeric_token_end(start);
+    
+    if (end == start) {
+      throw malformed_json_exception("Expected any token, got nothing");
+    }
+    
+    bool const negative = *start == '-';
+    if (negative) ++start;
+    
+    uint_jt const threshold = (UINT_JT_MAX / 10);
+    uint_jt val = 0;
+    for (; start != end; ++start) {
+      if (!isdigit(*start)) {
+        helper::parse_double(json, start);
+        return;
+      }
+      int_jt digit = static_cast<int_jt>(*start - '\0');
+      if (val >= threshold) {
+        if (val > threshold || (start + 1) < end || digit > INT_JT_MAX_LAST_DIGIT) {
+          helper::parse_double(json, start);
+          return;
+        }
+      }
+      val = (10 * val) + digit;
+    }
+    if (negative && val == INT_JT_OVER) {
+      json = INT_JT_MIN;
+    } else if (negative) {
+      json = -int_jt(val);
+    } else if (val <= uint_jt(INT_JT_MAX)) {
+      json = int_jt(val);
+    } else {
+      json = val;
+    }
+  }
+  
+  void parse_object(value& json, char const*& data) {
+    std::string key;
+    while (*data && *data != '}') {
+      helper::parse_string(key, data);
+      if (helper::get_next_element(data) != ':') {
+        throw malformed_json_exception(std::string("Expected key:value pair delimited by ':', got '") + *data + "' instead");
+      }
+      parse_one_token(json[key], ++data);
+      helper::advance_to_boundary('}', data);
+    }
+    if (*data) ++data;
+    else throw malformed_json_exception("Reached end of parse string without finding object end");
+  }
+  
+  void parse_array(value& json, char const*& data) {
+    size_t current_idx = 0;
+    while (*data && *data != ']') {
+      parse_one_token(json[current_idx++], data);
+      helper::advance_to_boundary(']', data);
+    }
+    if (*data) ++data;
+    else throw malformed_json_exception("Reached end of parse string without finding array end");
+  }
+} }
+
+namespace json {
+  namespace parser {
+    void parse(value& json, char const* data) {
+      parse_one_token(json, data);
+      if (*data) throw malformed_json_exception("Expected a single json token in top-level parse");
+    }
+  }
+}
+
+void json::value::parse(char const* data) {
+  parser::parse(*this, data);
+}
+
+void json::value::parse(std::string const& str) {
+  parser::parse(*this, str);
+}
+
+void json::value::parse(std::istream & in) {
+  parser::parse(*this, in);
+}

+ 0 - 1
json_test.cpp

@@ -6,7 +6,6 @@
 //
 
 #include "json_binder.hpp"
-#include "json_parser.hpp"
 
 struct test_t {
   int a, b;