- initial commit
This commit is contained in:
commit
4502e7e51c
5 changed files with 1593 additions and 0 deletions
16
Makefile.am
Normal file
16
Makefile.am
Normal file
|
@ -0,0 +1,16 @@
|
|||
noinst_PROGRAMS = json json98
|
||||
TESTS = ./json ./json98
|
||||
|
||||
#CXXFLAGS = -O3 -flto
|
||||
|
||||
json_SOURCES = src/JSON.cc src/JSON.h test/JSON_test.cc
|
||||
json_CXXFLAGS = -std=c++11
|
||||
json_CPPFLAGS = -I$(top_srcdir)/src
|
||||
|
||||
json98_SOURCES = src/JSON.cc src/JSON.h test/JSON_test.cc
|
||||
json98_CXXFLAGS = -std=c++98
|
||||
json98_CPPFLAGS = -I$(top_srcdir)/src
|
||||
|
||||
svn-clean: maintainer-clean
|
||||
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
|
11
configure.ac
Normal file
11
configure.ac
Normal file
|
@ -0,0 +1,11 @@
|
|||
AC_PREREQ([2.69])
|
||||
AC_INIT([JSON], [1.0], [BUG-REPORT-ADDRESS])
|
||||
AC_CONFIG_SRCDIR([src/JSON.cc])
|
||||
|
||||
AM_INIT_AUTOMAKE([foreign])
|
||||
AM_SILENT_RULES([yes])
|
||||
|
||||
AC_PROG_CXX
|
||||
|
||||
AC_CONFIG_FILES(Makefile)
|
||||
AC_OUTPUT
|
1063
src/JSON.cc
Normal file
1063
src/JSON.cc
Normal file
File diff suppressed because it is too large
Load diff
267
src/JSON.h
Normal file
267
src/JSON.h
Normal file
|
@ -0,0 +1,267 @@
|
|||
#pragma once
|
||||
|
||||
// a helper macro to detect C++11 compliant compilers
|
||||
#if __cplusplus >= 201103L
|
||||
#define __cplusplus11
|
||||
#endif
|
||||
|
||||
// allow us to use "nullptr" everywhere
|
||||
#ifndef nullptr
|
||||
#define nullptr NULL
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
// additional C++11 header
|
||||
#ifdef __cplusplus11
|
||||
#include <mutex>
|
||||
#include <initializer_list>
|
||||
#endif
|
||||
|
||||
class JSON {
|
||||
private:
|
||||
#ifdef __cplusplus11
|
||||
/// mutex to guard payload
|
||||
static std::mutex _token;
|
||||
#endif
|
||||
|
||||
public:
|
||||
/// possible types of a JSON object
|
||||
typedef enum {
|
||||
array, object, null, string, boolean, number_int, number_float
|
||||
} json_t;
|
||||
|
||||
private:
|
||||
/// the type of this object
|
||||
json_t _type;
|
||||
|
||||
/// the payload
|
||||
void* _payload;
|
||||
|
||||
public:
|
||||
#ifdef __cplusplus11
|
||||
/// a type for objects
|
||||
typedef std::tuple<std::string, JSON> object_t;
|
||||
/// a type for arrays
|
||||
typedef std::initializer_list<JSON> array_t;
|
||||
#endif
|
||||
|
||||
public:
|
||||
/// create an empty (null) object
|
||||
JSON();
|
||||
/// create a string object from C++ string
|
||||
JSON(const std::string&);
|
||||
/// create a string object from C string
|
||||
JSON(char*);
|
||||
/// create a string object from C string
|
||||
JSON(const char*);
|
||||
/// create a Boolean object
|
||||
JSON(const bool);
|
||||
/// create a number object
|
||||
JSON(const int);
|
||||
/// create a number object
|
||||
JSON(const double);
|
||||
#ifdef __cplusplus11
|
||||
/// create from an initializer list (to an array)
|
||||
JSON(array_t);
|
||||
/// create from a mapping (to an object)
|
||||
JSON(object_t);
|
||||
#endif
|
||||
|
||||
/// copy constructor
|
||||
JSON(const JSON&);
|
||||
|
||||
#ifdef __cplusplus11
|
||||
/// move constructor
|
||||
JSON(JSON&&);
|
||||
#endif
|
||||
|
||||
/// copy assignment
|
||||
#ifdef __cplusplus11
|
||||
JSON& operator=(JSON);
|
||||
#else
|
||||
JSON& operator=(const JSON&);
|
||||
#endif
|
||||
|
||||
/// destructor
|
||||
~JSON();
|
||||
|
||||
/// implicit conversion to string representation
|
||||
operator const std::string() const;
|
||||
/// implicit conversion to integer (only for numbers)
|
||||
operator int() const;
|
||||
/// implicit conversion to double (only for numbers)
|
||||
operator double() const;
|
||||
/// implicit conversion to Boolean (only for Booleans)
|
||||
operator bool() const;
|
||||
|
||||
/// write to stream
|
||||
friend std::ostream& operator<<(std::ostream& o, const JSON& j) {
|
||||
o << j.toString();
|
||||
return o;
|
||||
}
|
||||
|
||||
/// write to stream
|
||||
friend std::ostream& operator>>(const JSON& j, std::ostream& o) {
|
||||
o << j.toString();
|
||||
return o;
|
||||
}
|
||||
|
||||
/// read from stream
|
||||
friend std::istream& operator>>(std::istream& i, JSON& j) {
|
||||
parser(i).parse(j);
|
||||
return i;
|
||||
}
|
||||
|
||||
/// read from stream
|
||||
friend std::istream& operator<<(JSON& j, std::istream& i) {
|
||||
parser(i).parse(j);
|
||||
return i;
|
||||
}
|
||||
|
||||
/// explicit conversion to string representation (C++ style)
|
||||
const std::string toString() const;
|
||||
|
||||
/// add an object/array to an array
|
||||
JSON& operator+=(const JSON&);
|
||||
/// add a string to an array
|
||||
JSON& operator+=(const std::string&);
|
||||
/// add a string to an array
|
||||
JSON& operator+=(const char*);
|
||||
/// add a Boolean to an array
|
||||
JSON& operator+=(bool);
|
||||
/// add a number to an array
|
||||
JSON& operator+=(int);
|
||||
/// add a number to an array
|
||||
JSON& operator+=(double);
|
||||
|
||||
/// operator to set an element in an array
|
||||
JSON& operator[](int);
|
||||
/// operator to get an element in an array
|
||||
const JSON& operator[](const int) const;
|
||||
|
||||
/// operator to set an element in an object
|
||||
JSON& operator[](const std::string&);
|
||||
/// operator to set an element in an object
|
||||
JSON& operator[](const char*);
|
||||
/// operator to get an element in an object
|
||||
const JSON& operator[](const std::string&) const;
|
||||
|
||||
/// return the number of stored values
|
||||
size_t size() const;
|
||||
/// checks whether object is empty
|
||||
bool empty() const;
|
||||
|
||||
/// return the type of the object
|
||||
json_t type() const;
|
||||
|
||||
/// direct access to the underlying payload
|
||||
void* data();
|
||||
/// direct access to the underlying payload
|
||||
const void* data() const;
|
||||
|
||||
/// lexicographically compares the values
|
||||
bool operator==(const JSON&) const;
|
||||
|
||||
private:
|
||||
/// return the type as string
|
||||
std::string _typename() const;
|
||||
|
||||
// forward declaration to friend this class
|
||||
public:
|
||||
class const_iterator;
|
||||
|
||||
public:
|
||||
/// an iterator
|
||||
class iterator {
|
||||
friend class JSON::const_iterator;
|
||||
public:
|
||||
iterator();
|
||||
iterator(JSON*);
|
||||
iterator(const iterator&);
|
||||
~iterator();
|
||||
|
||||
iterator& operator=(const iterator&);
|
||||
bool operator==(const iterator&) const;
|
||||
bool operator!=(const iterator&) const;
|
||||
iterator& operator++();
|
||||
JSON& operator*() const;
|
||||
JSON* operator->() const;
|
||||
|
||||
/// getter for the key (in case of objects)
|
||||
std::string key() const;
|
||||
/// getter for the value
|
||||
JSON& value() const;
|
||||
|
||||
private:
|
||||
/// a JSON value
|
||||
JSON* _object;
|
||||
/// an iterator for JSON arrays
|
||||
std::vector<JSON>::iterator* _vi;
|
||||
/// an iterator for JSON objects
|
||||
std::map<std::string, JSON>::iterator* _oi;
|
||||
};
|
||||
|
||||
/// a const iterator
|
||||
class const_iterator {
|
||||
public:
|
||||
const_iterator();
|
||||
const_iterator(const JSON*);
|
||||
const_iterator(const const_iterator&);
|
||||
const_iterator(const iterator&);
|
||||
~const_iterator();
|
||||
|
||||
const_iterator& operator=(const const_iterator&);
|
||||
bool operator==(const const_iterator&) const;
|
||||
bool operator!=(const const_iterator&) const;
|
||||
const_iterator& operator++();
|
||||
const JSON& operator*() const;
|
||||
const JSON* operator->() const;
|
||||
|
||||
/// getter for the key (in case of objects)
|
||||
std::string key() const;
|
||||
/// getter for the value
|
||||
const JSON& value() const;
|
||||
|
||||
private:
|
||||
/// a JSON value
|
||||
const JSON* _object;
|
||||
/// an iterator for JSON arrays
|
||||
std::vector<JSON>::const_iterator* _vi;
|
||||
/// an iterator for JSON objects
|
||||
std::map<std::string, JSON>::const_iterator* _oi;
|
||||
};
|
||||
|
||||
public:
|
||||
iterator begin();
|
||||
iterator end();
|
||||
const_iterator begin() const;
|
||||
const_iterator end() const;
|
||||
const_iterator cbegin() const;
|
||||
const_iterator cend() const;
|
||||
|
||||
private:
|
||||
class parser {
|
||||
public:
|
||||
parser(char*);
|
||||
parser(std::string&);
|
||||
parser(std::istream&);
|
||||
~parser();
|
||||
void parse(JSON&);
|
||||
|
||||
private:
|
||||
bool next();
|
||||
void error(std::string = "");
|
||||
std::string parseString();
|
||||
void parseTrue();
|
||||
void parseFalse();
|
||||
void parseNull();
|
||||
void expect(char);
|
||||
|
||||
char _current;
|
||||
char* _buffer;
|
||||
size_t _pos;
|
||||
};
|
||||
};
|
236
test/JSON_test.cc
Normal file
236
test/JSON_test.cc
Normal file
|
@ -0,0 +1,236 @@
|
|||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <cstdio>
|
||||
#include <cassert>
|
||||
#include <JSON.h>
|
||||
#include <sstream>
|
||||
|
||||
void test_null() {
|
||||
/* a null object */
|
||||
|
||||
// construct
|
||||
JSON a, b;
|
||||
|
||||
// copy assign
|
||||
b = JSON();
|
||||
|
||||
// copy construct
|
||||
JSON c(a);
|
||||
|
||||
// copy construct
|
||||
JSON d = a;
|
||||
|
||||
// assign operator
|
||||
JSON e = JSON();
|
||||
|
||||
// compare
|
||||
assert(a == b);
|
||||
|
||||
// type
|
||||
assert(a.type() == JSON::null);
|
||||
|
||||
// empty and size
|
||||
assert(a.size() == 0);
|
||||
assert(a.empty() == true);
|
||||
|
||||
// output
|
||||
std::cout << a << '\n';
|
||||
|
||||
// string represetations
|
||||
assert(a.toString() == std::string("null"));
|
||||
|
||||
// invalid conversion to int
|
||||
try {
|
||||
int i = 0;
|
||||
i = a;
|
||||
assert(false);
|
||||
} catch (const std::exception& ex) {
|
||||
assert(ex.what() == std::string("cannot cast null to JSON number"));
|
||||
}
|
||||
|
||||
// invalid conversion to double
|
||||
try {
|
||||
double f = 0;
|
||||
f = a;
|
||||
assert(false);
|
||||
} catch (const std::exception& ex) {
|
||||
assert(ex.what() == std::string("cannot cast null to JSON number"));
|
||||
}
|
||||
|
||||
// invalid conversion to bool
|
||||
try {
|
||||
bool b = a;
|
||||
assert(false);
|
||||
} catch (const std::exception& ex) {
|
||||
assert(ex.what() == std::string("cannot cast null to JSON Boolean"));
|
||||
}
|
||||
|
||||
// invalid conversion to string
|
||||
try {
|
||||
std::string s = a;
|
||||
assert(false);
|
||||
} catch (const std::exception& ex) {
|
||||
assert(ex.what() == std::string("cannot cast null to JSON string"));
|
||||
}
|
||||
}
|
||||
|
||||
void test_string() {
|
||||
/* a string object */
|
||||
|
||||
// construct
|
||||
JSON a = "object a";
|
||||
JSON b;
|
||||
|
||||
// copy assign
|
||||
b = JSON("object a");
|
||||
|
||||
// copy construct
|
||||
JSON c(a);
|
||||
|
||||
// copy construct
|
||||
JSON d = a;
|
||||
|
||||
// assign operator
|
||||
JSON e = JSON("");
|
||||
|
||||
// compare
|
||||
assert(a == b);
|
||||
|
||||
// type
|
||||
assert(a.type() == JSON::string);
|
||||
|
||||
// empty and size
|
||||
assert(a.size() == 1);
|
||||
assert(a.empty() == false);
|
||||
|
||||
// output
|
||||
std::cout << a << '\n';
|
||||
|
||||
// string represetations
|
||||
assert(a.toString() == std::string("\"object a\""));
|
||||
|
||||
// invalid conversion to int
|
||||
try {
|
||||
int i = 0;
|
||||
i = a;
|
||||
assert(false);
|
||||
} catch (const std::exception& ex) {
|
||||
assert(ex.what() == std::string("cannot cast string to JSON number"));
|
||||
}
|
||||
|
||||
// invalid conversion to double
|
||||
try {
|
||||
double f = 0;
|
||||
f = a;
|
||||
assert(false);
|
||||
} catch (const std::exception& ex) {
|
||||
assert(ex.what() == std::string("cannot cast string to JSON number"));
|
||||
}
|
||||
|
||||
// invalid conversion to bool
|
||||
try {
|
||||
bool b = false;
|
||||
b = a;
|
||||
assert(false);
|
||||
} catch (const std::exception& ex) {
|
||||
assert(ex.what() == std::string("cannot cast string to JSON Boolean"));
|
||||
}
|
||||
}
|
||||
|
||||
void test_array() {
|
||||
JSON a;
|
||||
a += JSON();
|
||||
a += 1;
|
||||
a += 1.0;
|
||||
a += true;
|
||||
a += "string";
|
||||
|
||||
// type
|
||||
assert(a.type() == JSON::array);
|
||||
|
||||
// empty and size
|
||||
assert(a.size() == 5);
|
||||
assert(a.empty() == false);
|
||||
|
||||
// output
|
||||
std::cout << a << '\n';
|
||||
|
||||
// check for elements
|
||||
assert(a[1] == JSON(1));
|
||||
assert(a[2] == JSON(1.0));
|
||||
assert(a[3] == JSON(true));
|
||||
assert(a[4] == JSON("string"));
|
||||
|
||||
// invalid access to element
|
||||
try {
|
||||
a[5] = 1;
|
||||
assert(false);
|
||||
} catch (const std::exception& ex) {
|
||||
assert(ex.what() == std::string("cannot access element at index 5"));
|
||||
}
|
||||
|
||||
// get elements
|
||||
{
|
||||
int i = a[1];
|
||||
double d = a[2];
|
||||
bool b = a[3];
|
||||
std::string s = a[4];
|
||||
}
|
||||
|
||||
// set elements
|
||||
a[1] = 2;
|
||||
|
||||
#ifdef __cplusplus11
|
||||
// construction from initializer list
|
||||
JSON b = {JSON(), 2, 1.0, true, "string"};
|
||||
assert(a == b);
|
||||
#endif
|
||||
|
||||
// iterators
|
||||
for (JSON::iterator i = a.begin(); i != a.end(); ++i) {
|
||||
std::cerr << *i << '\n';
|
||||
}
|
||||
|
||||
for (JSON::const_iterator i = a.cbegin(); i != a.cend(); ++i) {
|
||||
std::cerr << *i << '\n';
|
||||
}
|
||||
|
||||
#ifdef __cplusplus11
|
||||
for (auto element : a) {
|
||||
std::cerr << element << '\n';
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void test_streaming() {
|
||||
// stream text representation into stream
|
||||
std::stringstream i;
|
||||
i << "{ \"foo\": true, \"baz\": [1,2,3,4] }";
|
||||
|
||||
// create JSON from stream
|
||||
{
|
||||
JSON j, k;
|
||||
i >> j;
|
||||
k << i;
|
||||
assert(j.toString() == k.toString());
|
||||
}
|
||||
|
||||
// roundtrip
|
||||
{
|
||||
std::stringstream o;
|
||||
JSON j, k;
|
||||
i >> j;
|
||||
j >> o;
|
||||
o >> k;
|
||||
assert(j.toString() == k.toString());
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
test_null();
|
||||
test_string();
|
||||
test_array();
|
||||
test_streaming();
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in a new issue