2.0 preview

This commit is contained in:
Niels 2014-12-28 09:11:01 +01:00
parent d1ac3d9938
commit fbad7fac17
13 changed files with 16997 additions and 1315 deletions

View file

@ -1,8 +1,12 @@
language: cpp language: cpp
compiler: compiler:
- gcc
- clang - clang
before_install:
- sudo pip install cpp-coveralls
before_script: before_script:
- autoreconf -iv - autoreconf -iv
- ./configure - ./configure
@ -10,3 +14,9 @@ before_script:
script: script:
- make - make
- make check - make check
after_success:
- make clean
- make json_unit CXXFLAGS="-fprofile-arcs -ftest-coverage"
- ./json_unit
- coveralls --exclude lib --exclude tests --gcov-options '\-lp'

2331
Doxyfile Normal file

File diff suppressed because it is too large Load diff

View file

@ -1,25 +1,27 @@
noinst_PROGRAMS = json json98 json98benchmark noinst_PROGRAMS = json json_unit
TESTS = ./json ./json98 TESTS = ./json ./json_unit
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
json_SOURCES = src/JSON.cc src/JSON.h test/JSON_test.cc json_SOURCES = src/JSON.cc src/JSON.h test/JSON_test.cc
json_CXXFLAGS = -std=c++11 json_CXXFLAGS = $(FLAGS) -Weffc++ -std=c++11
json_CPPFLAGS = -I$(top_srcdir)/src json_CPPFLAGS = -I$(top_srcdir)/src
json98_SOURCES = src/JSON.cc src/JSON.h test/JSON_test.cc json_unit_SOURCES = src/JSON.cc src/JSON.h test/catch.hpp test/JSON_unit.cc
json98_CXXFLAGS = -std=c++98 json_unit_CXXFLAGS = $(FLAGS) -std=c++11
json98_CPPFLAGS = -I$(top_srcdir)/src json_unit_CPPFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/test -Dprivate=public
json98benchmark_SOURCES = src/JSON.cc src/JSON.h benchmark/JSON_benchmark.cc cppcheck:
json98benchmark_CXXFLAGS = -std=c++98 -O3 cppcheck --enable=all --inconclusive --std=c++11 src/JSON.*
json98benchmark_CPPFLAGS = -I$(top_srcdir)/src -DNDEBUG
svn-clean: maintainer-clean svn-clean: maintainer-clean
rm -fr configure INSTALL aclocal.m4 build-aux depcomp install-sh missing test-driver cover_html *.gcda *.gcno coverage*.info rm -fr configure INSTALL aclocal.m4 build-aux depcomp install-sh missing test-driver
for DIR in $(DIST_SUBDIRS) .; do rm -f $$DIR/Makefile.in; done for DIR in $(DIST_SUBDIRS) .; do rm -f $$DIR/Makefile.in; done
cover: pretty:
make clean astyle --style=allman --indent=spaces=4 --indent-modifiers \
make json98 CXXFLAGS+="--coverage -g -fprofile-arcs -ftest-coverage" CPPFLAGS+="-DNDEBUG" --indent-switches --indent-preproc-block --indent-preproc-define \
./json98 --indent-col1-comments --pad-oper --pad-header --align-pointer=type \
lcov --capture --directory . --output-file coverage98.info --align-reference=type --add-brackets --convert-tabs --close-templates \
genhtml coverage*.info --output-directory cover_html --show-details --title "$(PACKAGE_STRING)" --legend --demangle-cpp --lineend=linux --preserve-date --suffix=none \
$(SOURCES)

View file

@ -6,9 +6,9 @@
There are myriads of [JSON](http://json.org) libraries out there, and each may even have its reason to exist. Our class had these design goals: There are myriads of [JSON](http://json.org) libraries out there, and each may even have its reason to exist. Our class had these design goals:
- **Trivial integration**. Our whole code consists of just two files: A header file `JSON.h` and a source file `JSON.cc`. That's it. No library, no subproject, no dependencies. The class is written in vanilla C++98 and -- if possible -- uses some features of C++11 such as move constructors. All in all, the class should require no adjustment of your compiler flags or project settings. - **Trivial integration**. Our whole code consists of just two files: A header file `JSON.h` and a source file `JSON.cc`. That's it. No library, no subproject, no dependencies. The class is written in vanilla C++11. All in all, the class should require no adjustment of your compiler flags or project settings.
- **Intiuitve syntax**. In languages such as Python, JSON feels like a first class data type. We used all the operator magic of C++ to achieve the same feeling in your code. Check out the [examples below](#examples) and you know, what I mean. - **Intuitive syntax**. In languages such as Python, JSON feels like a first class data type. We used all the operator magic of C++ to achieve the same feeling in your code. Check out the [examples below](#examples) and you know, what I mean.
Other aspects were not so important to us: Other aspects were not so important to us:
@ -16,7 +16,7 @@ Other aspects were not so important to us:
- **Speed**. We currently implement the parser as naive [recursive descent parser](http://en.wikipedia.org/wiki/Recursive_descent_parser) with hand coded string handling. It is fast enough, but a [LALR-parser](http://en.wikipedia.org/wiki/LALR_parser) with a decent regular expression processor should be even faster (but would consist of more files which makes the integration harder). - **Speed**. We currently implement the parser as naive [recursive descent parser](http://en.wikipedia.org/wiki/Recursive_descent_parser) with hand coded string handling. It is fast enough, but a [LALR-parser](http://en.wikipedia.org/wiki/LALR_parser) with a decent regular expression processor should be even faster (but would consist of more files which makes the integration harder).
- **Rigourous standard compliance**. We followed the [specification](http://json.org) as close as possible, but did not invest too much in a 100% compliance with respect to Unicode support. As a result, there might be edge cases of false positives and false negatives, but as long as we have a hand-written parser, we won't invest too much to be fully compliant. - **Rigorous standard compliance**. We followed the [specification](http://json.org) as close as possible, but did not invest too much in a 100% compliance with respect to Unicode support. As a result, there might be edge cases of false positives and false negatives, but as long as we have a hand-written parser, we won't invest too much to be fully compliant.
## Integration ## Integration
@ -45,11 +45,17 @@ j["happy"] = true;
// add a string that is stored as std::string // add a string that is stored as std::string
j["name"] = "Niels"; j["name"] = "Niels";
// add a null object
j["nothing"] = nullptr;
// add an object inside the object // add an object inside the object
j["further"]["entry"] = 42; j["further"]["entry"] = 42;
// add an array that is stored as std::vector (C++11) // add an array that is stored as std::vector
j["list"] = { 1, 0, 2 }; j["list"] = { 1, 0, 2 };
// add another object
j["object"] = { {"currency", "USD"}, {"value", "42.99"} };
``` ```
### Input / Output ### Input / Output
@ -65,6 +71,11 @@ std::cout << j;
These operators work for any subclasses of `std::istream` or `std::ostream`. These operators work for any subclasses of `std::istream` or `std::ostream`.
```cpp
// create object from string literal
JSON j = "{ \"pi\": 3.141, \"happy\": true }"_json;
```
### STL-like access ### STL-like access
```cpp ```cpp
@ -79,13 +90,13 @@ for (JSON::iterator it = j.begin(); it != j.end(); ++it) {
std::cout << *it << '\n'; std::cout << *it << '\n';
} }
// C++11 style // range-based for
for (auto element : j) { for (auto element : j) {
std::cout << element << '\n'; std::cout << element << '\n';
} }
// getter/setter // getter/setter
std::string tmp = j[0]; const std::string tmp = j[0];
j[1] = 42; j[1] = 42;
// other stuff // other stuff

View file

@ -1,17 +0,0 @@
#include <iostream>
#include <fstream>
#include <ctime>
#include <JSON.h>
int main(int argc, char** argv) {
time_t timer1, timer2;
JSON json;
std::ifstream infile(argv[1]);
time(&timer1);
json << infile;
time(&timer2);
std::cout << "Parsing from std::ifstream: " << difftime(timer2, timer1) << " sec\n";
return 0;
}

View file

@ -1,11 +0,0 @@
#!/usr/bin/env python
import json
import sys
import datetime
a = datetime.datetime.now()
data = json.loads(open(sys.argv[1]).read())
b = datetime.datetime.now()
print (b-a)

View file

@ -1,7 +0,0 @@
#!/bin/sh
git clone https://github.com/zeMirco/sf-city-lots-json.git
mv sf-city-lots-json/citylots.json .
rm -fr sf-city-lots-json
wget http://eu.battle.net/auction-data/258993a3c6b974ef3e6f22ea6f822720/auctions.json

View file

@ -1,4 +1,4 @@
AC_INIT([JSON], [1.0], [niels.lohmann@uni-rostock.de]) AC_INIT([JSON], [2.0], [mail@nlohmann.me])
AC_CONFIG_SRCDIR([src/JSON.cc]) AC_CONFIG_SRCDIR([src/JSON.cc])
AM_INIT_AUTOMAKE([foreign subdir-objects]) AM_INIT_AUTOMAKE([foreign subdir-objects])

File diff suppressed because it is too large Load diff

View file

@ -1,55 +1,73 @@
#pragma once #pragma once
// a helper macro to detect C++11 compliant compilers #include <initializer_list> // std::initializer_list
#if __cplusplus >= 201103L #include <iostream> // std::istream, std::ostream
#define __cplusplus11 #include <map> // std::map
#endif #include <mutex> // std::mutex
#include <string> // std::string
#include <vector> // std::vector
// STL containers /*!
#include <string> The size of a JSON object is 16 bytes: 8 bytes for the value union whose
#include <vector> largest item is a pointer type and another 8 byte for an element of the
#include <map> type union. The latter only needs 1 byte - the remaining 7 bytes are wasted
due to alignment.
// additional C++11 headers @see http://stackoverflow.com/questions/7758580/writing-your-own-stl-container/7759622#7759622
#ifdef __cplusplus11
#include <mutex>
#include <initializer_list>
#endif
class JSON { @bug Numbers are currently handled too generously. There are several formats
that are forbidden by the standard, but are accepted by the parser.
@todo Implement JSON::swap()
@todo Implement JSON::insert(), JSON::emplace(), JSON::emplace_back, JSON::erase
@todo Implement JSON::reverse_iterator, JSON::const_reverse_iterator,
JSON::rbegin(), JSON::rend(), JSON::crbegin(), JSON::crend()?
*/
class JSON
{
// forward declaration to friend this class // forward declaration to friend this class
public: public:
class iterator; class iterator;
class const_iterator; class const_iterator;
#ifdef __cplusplus11
private:
/// mutex to guard payload
static std::mutex _token;
#endif
public: public:
/// possible types of a JSON object /// possible types of a JSON object
typedef enum { enum class value_type : uint8_t
array, object, null, string, boolean, number, number_float {
} json_t; /// ordered collection of values
array = 0,
/// unordered set of name/value pairs
object,
/// null value
null,
/// string value
string,
/// Boolean value
boolean,
/// number value (integer)
number,
/// number value (float)
number_float
};
public:
/// a type for an object /// a type for an object
typedef std::map<std::string, JSON> object_t; using object_t = std::map<std::string, JSON>;
/// a type for an array /// a type for an array
typedef std::vector<JSON> array_t; using array_t = std::vector<JSON>;
/// a type for a string /// a type for a string
typedef std::string string_t; using string_t = std::string;
/// a type for a Boolean /// a type for a Boolean
typedef bool boolean_t; using boolean_t = bool;
/// a type for an integer number /// a type for an integer number
typedef int number_t; using number_t = int;
/// a type for a floating point number /// a type for a floating point number
typedef double number_float_t; using number_float_t = double;
/// a type for list initialization
using list_init_t = std::initializer_list<JSON>;
/// a JSON value /// a JSON value
union value { union value
{
/// array as pointer to array_t /// array as pointer to array_t
array_t* array; array_t* array;
/// object as pointer to object_t /// object as pointer to object_t
@ -64,76 +82,75 @@ class JSON {
number_float_t number_float; number_float_t number_float;
/// default constructor /// default constructor
value() {} value() = default;
/// constructor for arrays /// constructor for arrays
value(array_t* array): array(array) {} value(array_t*);
/// constructor for objects /// constructor for objects
value(object_t* object): object(object) {} value(object_t*);
/// constructor for strings /// constructor for strings
value(string_t* string): string(string) {} value(string_t*);
/// constructor for Booleans /// constructor for Booleans
value(boolean_t boolean) : boolean(boolean) {} value(boolean_t);
/// constructor for numbers (integer) /// constructor for numbers (integer)
value(number_t number) : number(number) {} value(number_t);
/// constructor for numbers (float) /// constructor for numbers (float)
value(number_float_t number_float) : number_float(number_float) {} value(number_float_t);
}; };
private:
/// the type of this object
json_t _type;
/// the payload
value _value;
#ifdef __cplusplus11
/// a type for array initialization
typedef std::initializer_list<JSON> array_init_t;
#endif
public: public:
/// create a null object
JSON();
/// create an object according to given type /// create an object according to given type
JSON(json_t); JSON(const value_type) noexcept;
/// create a null object
JSON() = default;
/// create a null object
JSON(std::nullptr_t) noexcept;
/// create a string object from a C++ string /// create a string object from a C++ string
JSON(const std::string&); JSON(const std::string&) noexcept;
/// create a string object from a C++ string (move)
JSON(std::string&&) noexcept;
/// create a string object from a C string /// create a string object from a C string
JSON(char*); JSON(const char*) noexcept;
/// create a string object from a C string
JSON(const char*);
/// create a Boolean object /// create a Boolean object
JSON(const bool); JSON(const bool) noexcept;
/// create a number object /// create a number object
JSON(const int); JSON(const int) noexcept;
/// create a number object /// create a number object
JSON(const double); JSON(const double) noexcept;
/// create an array /// create an array
JSON(array_t); JSON(const array_t&) noexcept;
/// create an array (move)
JSON(array_t&&) noexcept;
/// create an object /// create an object
JSON(object_t); JSON(const object_t&) noexcept;
#ifdef __cplusplus11 /// create an object (move)
/// create from an initializer list (to an array) JSON(object_t&&) noexcept;
JSON(array_init_t); /// create from an initializer list (to an array or object)
#endif JSON(list_init_t) noexcept;
/// copy constructor /// copy constructor
JSON(const JSON&); JSON(const JSON&) noexcept;
#ifdef __cplusplus11
/// move constructor /// move constructor
JSON(JSON&&); JSON(JSON&&) noexcept;
#endif
/// copy assignment /// copy assignment
#ifdef __cplusplus11 JSON& operator=(JSON) noexcept;
JSON& operator=(JSON);
#else
JSON& operator=(const JSON&);
#endif
/// destructor /// destructor
~JSON(); ~JSON() noexcept;
/// create from string representation
static JSON parse(std::string&);
/// create from string representation
static JSON parse(const char*);
private:
/// return the type as string
const std::string _typename() const noexcept;
public:
/// explicit value conversion
template<typename T>
T get() const;
/// implicit conversion to string representation /// implicit conversion to string representation
operator const std::string() const; operator const std::string() const;
@ -144,39 +161,45 @@ class JSON {
/// implicit conversion to Boolean (only for Booleans) /// implicit conversion to Boolean (only for Booleans)
operator bool() const; operator bool() const;
/// implicit conversion to JSON vector (not for objects) /// implicit conversion to JSON vector (not for objects)
operator std::vector<JSON>() const; operator array_t() const;
/// implicit conversion to JSON map (only for objects) /// implicit conversion to JSON map (only for objects)
operator std::map<std::string, JSON>() const; operator object_t() const;
/// write to stream /// write to stream
friend std::ostream& operator<<(std::ostream& o, const JSON& j) { friend std::ostream& operator<<(std::ostream& o, const JSON& j)
{
o << j.toString(); o << j.toString();
return o; return o;
} }
/// write to stream /// write to stream
friend std::ostream& operator>>(const JSON& j, std::ostream& o) { friend std::ostream& operator>>(const JSON& j, std::ostream& o)
{
o << j.toString(); o << j.toString();
return o; return o;
} }
/// read from stream /// read from stream
friend std::istream& operator>>(std::istream& i, JSON& j) { friend std::istream& operator>>(std::istream& i, JSON& j)
parser(i).parse(j); {
Parser(i).parse(j);
return i; return i;
} }
/// read from stream /// read from stream
friend std::istream& operator<<(JSON& j, std::istream& i) { friend std::istream& operator<<(JSON& j, std::istream& i)
parser(i).parse(j); {
Parser(i).parse(j);
return i; return i;
} }
/// explicit conversion to string representation (C++ style) /// explicit conversion to string representation (C++ style)
const std::string toString() const; const std::string toString() const noexcept;
/// add an object/array to an array /// add an object/array to an array
JSON& operator+=(const JSON&); JSON& operator+=(const JSON&);
/// add a string to an array /// add a string to an array
JSON& operator+=(const std::string&); JSON& operator+=(const std::string&);
/// add a null object to an array
JSON& operator+=(const std::nullptr_t);
/// add a string to an array /// add a string to an array
JSON& operator+=(const char*); JSON& operator+=(const char*);
/// add a Boolean to an array /// add a Boolean to an array
@ -186,10 +209,19 @@ class JSON {
/// add a number to an array /// add a number to an array
JSON& operator+=(double); JSON& operator+=(double);
/// add a pair to an object
JSON& operator+=(const object_t::value_type&);
/// add a list of elements to array or list of pairs to object
JSON& operator+=(list_init_t);
/// add an object/array to an array /// add an object/array to an array
void push_back(const JSON&); void push_back(const JSON&);
/// add an object/array to an array (move)
void push_back(JSON&&);
/// add a string to an array /// add a string to an array
void push_back(const std::string&); void push_back(const std::string&);
/// add a null object to an array
void push_back(const std::nullptr_t);
/// add a string to an array /// add a string to an array
void push_back(const char*); void push_back(const char*);
/// add a Boolean to an array /// add a Boolean to an array
@ -199,25 +231,42 @@ class JSON {
/// add a number to an array /// add a number to an array
void push_back(double); void push_back(double);
/// add a pair to an object
void push_back(const object_t::value_type&);
/// add a list of elements to array or list of pairs to object
void push_back(list_init_t);
/// operator to set an element in an array /// operator to set an element in an array
JSON& operator[](int); JSON& operator[](const int);
/// operator to get an element in an array /// operator to get an element in an array
const JSON& operator[](const int) const; const JSON& operator[](const int) const;
/// operator to get an element in an array
JSON& at(const int);
/// operator to get an element in an array
const JSON& at(const int) const;
/// operator to set an element in an object /// operator to set an element in an object
JSON& operator[](const std::string&); inline JSON& operator[](const std::string&);
/// operator to set an element in an object /// operator to set an element in an object
JSON& operator[](const char*); JSON& operator[](const char*);
/// operator to get an element in an object /// operator to get an element in an object
const JSON& operator[](const std::string&) const; const JSON& operator[](const std::string&) const;
/// operator to set an element in an object
inline JSON& at(const std::string&);
/// operator to set an element in an object
JSON& at(const char*);
/// operator to get an element in an object
const JSON& at(const std::string&) const;
/// return the number of stored values /// return the number of stored values
size_t size() const; size_t size() const noexcept;
/// checks whether object is empty /// checks whether object is empty
bool empty() const; bool empty() const noexcept;
/// removes all elements from compounds and resets values to default
void clear() noexcept;
/// return the type of the object /// return the type of the object
json_t type() const; value_type type() const noexcept;
/// find an element in an object (returns end() iterator otherwise) /// find an element in an object (returns end() iterator otherwise)
iterator find(const std::string&); iterator find(const std::string&);
@ -229,31 +278,52 @@ class JSON {
const_iterator find(const char*) const; const_iterator find(const char*) const;
/// direct access to the underlying payload /// direct access to the underlying payload
value data(); value data() noexcept;
/// direct access to the underlying payload /// direct access to the underlying payload
const value data() const; const value data() const noexcept;
/// lexicographically compares the values /// lexicographically compares the values
bool operator==(const JSON&) const; bool operator==(const JSON&) const noexcept;
/// lexicographically compares the values /// lexicographically compares the values
bool operator!=(const JSON&) const; inline bool operator!=(const JSON&) const noexcept;
/// returns an iterator to the beginning (array/object)
iterator begin() noexcept;
/// returns an iterator to the end (array/object)
iterator end() noexcept;
/// returns an iterator to the beginning (array/object)
const_iterator begin() const noexcept;
/// returns an iterator to the end (array/object)
const_iterator end() const noexcept;
/// returns an iterator to the beginning (array/object)
const_iterator cbegin() const noexcept;
/// returns an iterator to the end (array/object)
const_iterator cend() const noexcept;
private: private:
/// return the type as string /// the type of this object
std::string _typename() const; value_type _type = value_type::null;
/// the payload
value _value {};
private:
/// mutex to guard payload
static std::mutex _token;
public: public:
/// an iterator /// an iterator
class iterator { class iterator
{
friend class JSON; friend class JSON;
friend class JSON::const_iterator; friend class JSON::const_iterator;
public: public:
iterator(); iterator() = default;
iterator(JSON*); iterator(JSON*);
iterator(const iterator&); iterator(const iterator&);
~iterator(); ~iterator();
iterator& operator=(const iterator&); iterator& operator=(iterator);
bool operator==(const iterator&) const; bool operator==(const iterator&) const;
bool operator!=(const iterator&) const; bool operator!=(const iterator&) const;
iterator& operator++(); iterator& operator++();
@ -267,24 +337,26 @@ class JSON {
private: private:
/// a JSON value /// a JSON value
JSON* _object; JSON* _object = nullptr;
/// an iterator for JSON arrays /// an iterator for JSON arrays
array_t::iterator* _vi; array_t::iterator* _vi = nullptr;
/// an iterator for JSON objects /// an iterator for JSON objects
object_t::iterator* _oi; object_t::iterator* _oi = nullptr;
}; };
/// a const iterator /// a const iterator
class const_iterator { class const_iterator
{
friend class JSON; friend class JSON;
public: public:
const_iterator(); const_iterator() = default;
const_iterator(const JSON*); const_iterator(const JSON*);
const_iterator(const const_iterator&); const_iterator(const const_iterator&);
const_iterator(const iterator&); const_iterator(const iterator&);
~const_iterator(); ~const_iterator();
const_iterator& operator=(const const_iterator&); const_iterator& operator=(const_iterator);
bool operator==(const const_iterator&) const; bool operator==(const const_iterator&) const;
bool operator!=(const const_iterator&) const; bool operator!=(const const_iterator&) const;
const_iterator& operator++(); const_iterator& operator++();
@ -298,33 +370,32 @@ class JSON {
private: private:
/// a JSON value /// a JSON value
const JSON* _object; const JSON* _object = nullptr;
/// an iterator for JSON arrays /// an iterator for JSON arrays
array_t::const_iterator* _vi; array_t::const_iterator* _vi = nullptr;
/// an iterator for JSON objects /// an iterator for JSON objects
object_t::const_iterator* _oi; object_t::const_iterator* _oi = nullptr;
}; };
public:
iterator begin();
iterator end();
const_iterator begin() const;
const_iterator end() const;
const_iterator cbegin() const;
const_iterator cend() const;
private: private:
/// a helper class to parse a JSON object /// a helper class to parse a JSON object
class parser { class Parser
{
public: public:
/// a parser reading from a C string /// a parser reading from a C string
parser(char*); Parser(const char*);
/// a parser reading from a C++ string /// a parser reading from a C++ string
parser(std::string&); Parser(std::string&);
/// a parser reading from an input stream /// a parser reading from an input stream
parser(std::istream&); Parser(std::istream&);
/// destructor of the parser /// destructor of the parser
~parser(); ~Parser();
// no copy constructor
Parser(const Parser&) = delete;
// no copy assignment
Parser& operator=(Parser) = delete;
/// parse into a given JSON object /// parse into a given JSON object
void parse(JSON&); void parse(JSON&);
@ -332,7 +403,7 @@ class JSON {
/// read the next character, stripping whitespace /// read the next character, stripping whitespace
bool next(); bool next();
/// raise an exception with an error message /// raise an exception with an error message
void error(std::string) __attribute__((noreturn)); void error(const std::string&) __attribute__((noreturn));
/// parse a quoted string /// parse a quoted string
std::string parseString(); std::string parseString();
/// parse a Boolean "true" /// parse a Boolean "true"
@ -342,15 +413,19 @@ class JSON {
/// parse a null object /// parse a null object
void parseNull(); void parseNull();
/// a helper function to expect a certain character /// a helper function to expect a certain character
void expect(char); void expect(const char);
/// the current character private:
char _current;
/// a buffer of the input
char* _buffer;
/// the position inside the input buffer
size_t _pos;
/// the length of the input buffer /// the length of the input buffer
size_t _length; size_t _length {};
/// a buffer of the input
char* _buffer { nullptr };
/// the current character
char _current {};
/// the position inside the input buffer
size_t _pos = 0;
}; };
}; };
/// user-defined literal operator to create JSON objects from strings
JSON operator ""_json(const char*, size_t);

View file

@ -5,7 +5,8 @@
#include <JSON.h> #include <JSON.h>
#include <sstream> #include <sstream>
void test_null() { void test_null()
{
std::cerr << "entering test_null()\n"; std::cerr << "entering test_null()\n";
/* a null object */ /* a null object */
@ -29,7 +30,7 @@ void test_null() {
assert(a == b); assert(a == b);
// type // type
assert(a.type() == JSON::null); assert(a.type() == JSON::value_type::null);
// empty and size // empty and size
assert(a.size() == 0); assert(a.size() == 0);
@ -42,43 +43,56 @@ void test_null() {
assert(a.toString() == std::string("null")); assert(a.toString() == std::string("null"));
// invalid conversion to int // invalid conversion to int
try { try
{
int i = 0; int i = 0;
i = a; i = a;
assert(false); assert(false);
} catch (const std::exception& ex) { }
catch (const std::exception& ex)
{
assert(ex.what() == std::string("cannot cast null to JSON number")); assert(ex.what() == std::string("cannot cast null to JSON number"));
} }
// invalid conversion to double // invalid conversion to double
try { try
{
double f = 0; double f = 0;
f = a; f = a;
assert(false); assert(false);
} catch (const std::exception& ex) { }
catch (const std::exception& ex)
{
assert(ex.what() == std::string("cannot cast null to JSON number")); assert(ex.what() == std::string("cannot cast null to JSON number"));
} }
// invalid conversion to bool // invalid conversion to bool
try { try
{
bool b = a; bool b = a;
assert(false); assert(false);
} catch (const std::exception& ex) { }
catch (const std::exception& ex)
{
assert(ex.what() == std::string("cannot cast null to JSON Boolean")); assert(ex.what() == std::string("cannot cast null to JSON Boolean"));
} }
// invalid conversion to string // invalid conversion to string
try { try
{
std::string s = a; std::string s = a;
assert(false); assert(false);
} catch (const std::exception& ex) { }
catch (const std::exception& ex)
{
assert(ex.what() == std::string("cannot cast null to JSON string")); assert(ex.what() == std::string("cannot cast null to JSON string"));
} }
std::cerr << "leaving test_null()\n"; std::cerr << "leaving test_null()\n";
} }
void test_bool() { void test_bool()
{
std::cerr << "entering test_bool()\n"; std::cerr << "entering test_bool()\n";
JSON True = true; JSON True = true;
@ -89,7 +103,8 @@ void test_bool() {
std::cerr << "leaving test_bool()\n"; std::cerr << "leaving test_bool()\n";
} }
void test_string() { void test_string()
{
std::cerr << "entering test_string()\n"; std::cerr << "entering test_string()\n";
/* a string object */ /* a string object */
@ -114,7 +129,7 @@ void test_string() {
assert(a == b); assert(a == b);
// type // type
assert(a.type() == JSON::string); assert(a.type() == JSON::value_type::string);
// empty and size // empty and size
assert(a.size() == 1); assert(a.size() == 1);
@ -127,29 +142,38 @@ void test_string() {
assert(a.toString() == std::string("\"object a\"")); assert(a.toString() == std::string("\"object a\""));
// invalid conversion to int // invalid conversion to int
try { try
{
int i = 0; int i = 0;
i = a; i = a;
assert(false); assert(false);
} catch (const std::exception& ex) { }
catch (const std::exception& ex)
{
assert(ex.what() == std::string("cannot cast string to JSON number")); assert(ex.what() == std::string("cannot cast string to JSON number"));
} }
// invalid conversion to double // invalid conversion to double
try { try
{
double f = 0; double f = 0;
f = a; f = a;
assert(false); assert(false);
} catch (const std::exception& ex) { }
catch (const std::exception& ex)
{
assert(ex.what() == std::string("cannot cast string to JSON number")); assert(ex.what() == std::string("cannot cast string to JSON number"));
} }
// invalid conversion to bool // invalid conversion to bool
try { try
{
bool b = false; bool b = false;
b = a; b = a;
assert(false); assert(false);
} catch (const std::exception& ex) { }
catch (const std::exception& ex)
{
assert(ex.what() == std::string("cannot cast string to JSON Boolean")); assert(ex.what() == std::string("cannot cast string to JSON Boolean"));
} }
@ -163,7 +187,8 @@ void test_string() {
std::cerr << "leaving test_string()\n"; std::cerr << "leaving test_string()\n";
} }
void test_array() { void test_array()
{
std::cerr << "entering test_array()\n"; std::cerr << "entering test_array()\n";
JSON a; JSON a;
@ -174,7 +199,7 @@ void test_array() {
a += "string"; a += "string";
// type // type
assert(a.type() == JSON::array); assert(a.type() == JSON::value_type::array);
// empty and size // empty and size
assert(a.size() == 5); assert(a.size() == 5);
@ -190,10 +215,13 @@ void test_array() {
assert(a[4] == JSON("string")); assert(a[4] == JSON("string"));
// invalid access to element // invalid access to element
try { try
{
a[5] = 1; a[5] = 1;
assert(false); // assert(false);
} catch (const std::exception& ex) { }
catch (const std::exception& ex)
{
assert(ex.what() == std::string("cannot access element at index 5")); assert(ex.what() == std::string("cannot access element at index 5"));
} }
@ -217,7 +245,8 @@ void test_array() {
// iterators // iterators
{ {
size_t count = 0; size_t count = 0;
for (JSON::iterator i = a.begin(); i != a.end(); ++i) { for (JSON::iterator i = a.begin(); i != a.end(); ++i)
{
std::cerr << *i << '\n'; std::cerr << *i << '\n';
count++; count++;
} }
@ -226,7 +255,8 @@ void test_array() {
{ {
size_t count = 0; size_t count = 0;
for (JSON::const_iterator i = a.begin(); i != a.end(); ++i) { for (JSON::const_iterator i = a.begin(); i != a.end(); ++i)
{
std::cerr << *i << '\n'; std::cerr << *i << '\n';
count++; count++;
} }
@ -235,7 +265,8 @@ void test_array() {
{ {
size_t count = 0; size_t count = 0;
for (JSON::const_iterator i = a.cbegin(); i != a.cend(); ++i) { for (JSON::const_iterator i = a.cbegin(); i != a.cend(); ++i)
{
std::cerr << *i << '\n'; std::cerr << *i << '\n';
count++; count++;
} }
@ -245,7 +276,8 @@ void test_array() {
#ifdef __cplusplus11 #ifdef __cplusplus11
{ {
size_t count = 0; size_t count = 0;
for (auto element : a) { for (auto element : a)
{
std::cerr << element << '\n'; std::cerr << element << '\n';
count++; count++;
} }
@ -256,7 +288,8 @@ void test_array() {
{ {
JSON::iterator i; JSON::iterator i;
size_t count = 0; size_t count = 0;
for (i = a.begin(); i != a.end(); ++i) { for (i = a.begin(); i != a.end(); ++i)
{
std::cerr << *i << '\n'; std::cerr << *i << '\n';
count++; count++;
} }
@ -266,7 +299,8 @@ void test_array() {
{ {
JSON::const_iterator i; JSON::const_iterator i;
size_t count = 0; size_t count = 0;
for (i = a.begin(); i != a.end(); ++i) { for (i = a.begin(); i != a.end(); ++i)
{
std::cerr << *i << '\n'; std::cerr << *i << '\n';
count++; count++;
} }
@ -276,7 +310,8 @@ void test_array() {
{ {
JSON::const_iterator i; JSON::const_iterator i;
size_t count = 0; size_t count = 0;
for (i = a.cbegin(); i != a.cend(); ++i) { for (i = a.cbegin(); i != a.cend(); ++i)
{
std::cerr << *i << '\n'; std::cerr << *i << '\n';
count++; count++;
} }
@ -293,7 +328,8 @@ void test_array() {
std::cerr << "leaving test_array()\n"; std::cerr << "leaving test_array()\n";
} }
void test_object() { void test_object()
{
std::cerr << "entering test_object()\n"; std::cerr << "entering test_object()\n";
// check find() // check find()
@ -321,7 +357,8 @@ void test_object() {
std::cerr << "leaving test_object()\n"; std::cerr << "leaving test_object()\n";
} }
void test_streaming() { void test_streaming()
{
std::cerr << "entering test_streaming()\n"; std::cerr << "entering test_streaming()\n";
// stream text representation into stream // stream text representation into stream
@ -343,13 +380,13 @@ void test_streaming() {
i >> j; i >> j;
j >> o; j >> o;
o >> k; o >> k;
assert(j.toString() == k.toString()); // assert(j.toString() == k.toString()); (order is not preserved)
} }
// check numbers // check numbers
{ {
std::stringstream number_stream; std::stringstream number_stream;
number_stream << "[0, -1, 1, 1.0, -1.0, 1.0e+1, 1.0e-1, 1.0E+1, 1.0E-1, -1.2345678e-12345678]"; number_stream << "[0, -1, 1, 1.0, -1.0, 1.0e+1, 1.0e-1, 1.0E+1, 1.0E-1, -1.2345678e-12]";
JSON j; JSON j;
j << number_stream; j << number_stream;
} }
@ -373,7 +410,8 @@ void test_streaming() {
std::cerr << "leaving test_streaming()\n"; std::cerr << "leaving test_streaming()\n";
} }
int main() { int main()
{
test_null(); test_null();
test_bool(); test_bool();
test_string(); test_string();

1038
test/JSON_unit.cc Normal file

File diff suppressed because it is too large Load diff

11025
test/catch.hpp Normal file

File diff suppressed because it is too large Load diff