ArduinoJson is now a header-only library (issue #199)

This commit is contained in:
Benoit Blanchon
2016-06-22 21:41:19 +02:00
parent 0801e16327
commit 8c7edbd9c3
52 changed files with 819 additions and 958 deletions

View File

@ -1,4 +1,5 @@
# http://clang.llvm.org/docs/ClangFormatStyleOptions.html # http://clang.llvm.org/docs/ClangFormatStyleOptions.html
BasedOnStyle: Google BasedOnStyle: Google
Standard: Cpp03 Standard: Cpp03
AllowShortFunctionsOnASingleLine: Empty

View File

@ -5,10 +5,4 @@
// https://github.com/bblanchon/ArduinoJson // https://github.com/bblanchon/ArduinoJson
// If you like this project, please add a star! // If you like this project, please add a star!
// About this file
// ---------------
// This file is here for [PlatformIO](http://platformio.org/).
// It must be present in the root for the tool to find it.
// Feel free to ignore this file if your working in another environment.
#include "include/ArduinoJson.h" #include "include/ArduinoJson.h"

View File

@ -1,6 +1,11 @@
ArduinoJson: change log ArduinoJson: change log
======================= =======================
HEAD
----
* ArduinoJson is now a header-only library (issue #199)
v5.5.1 v5.5.1
------ ------

View File

@ -5,7 +5,7 @@
# https://github.com/bblanchon/ArduinoJson # https://github.com/bblanchon/ArduinoJson
# If you like this project, please add a star! # If you like this project, please add a star!
cmake_minimum_required(VERSION 2.8.12) cmake_minimum_required(VERSION 3.0)
project(ArduinoJson) project(ArduinoJson)
enable_testing() enable_testing()
@ -18,5 +18,4 @@ if(${COVERAGE})
set(CMAKE_CXX_FLAGS "-g -O0 -fprofile-arcs -ftest-coverage") set(CMAKE_CXX_FLAGS "-g -O0 -fprofile-arcs -ftest-coverage")
endif() endif()
add_subdirectory(src)
add_subdirectory(test) add_subdirectory(test)

View File

@ -5,9 +5,5 @@
// https://github.com/bblanchon/ArduinoJson // https://github.com/bblanchon/ArduinoJson
// If you like this project, please add a star! // If you like this project, please add a star!
#include "ArduinoJson/DynamicJsonBuffer.hpp" #include "ArduinoJson.hpp"
#include "ArduinoJson/JsonArray.hpp"
#include "ArduinoJson/JsonObject.hpp"
#include "ArduinoJson/StaticJsonBuffer.hpp"
using namespace ArduinoJson; using namespace ArduinoJson;

19
include/ArduinoJson.hpp Normal file
View File

@ -0,0 +1,19 @@
// Copyright Benoit Blanchon 2014-2016
// MIT License
//
// Arduino JSON library
// https://github.com/bblanchon/ArduinoJson
// If you like this project, please add a star!
#include "ArduinoJson/DynamicJsonBuffer.hpp"
#include "ArduinoJson/JsonArray.hpp"
#include "ArduinoJson/JsonObject.hpp"
#include "ArduinoJson/StaticJsonBuffer.hpp"
#include "ArduinoJson/Internals/JsonParser.ipp"
#include "ArduinoJson/JsonArray.ipp"
#include "ArduinoJson/JsonBuffer.ipp"
#include "ArduinoJson/JsonObject.ipp"
#include "ArduinoJson/JsonVariant.ipp"
using namespace ArduinoJson;

View File

@ -11,12 +11,26 @@
#include <stdlib.h> #include <stdlib.h>
#if defined(__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wnon-virtual-dtor"
#elif defined(__GNUC__)
#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
#pragma GCC diagnostic push
#endif
#pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
#endif
namespace ArduinoJson { namespace ArduinoJson {
namespace Internals { namespace Internals {
class DefaultAllocator { class DefaultAllocator {
public: public:
void* allocate(size_t size) { return malloc(size); } void* allocate(size_t size) {
void deallocate(void* pointer) { free(pointer); } return malloc(size);
}
void deallocate(void* pointer) {
free(pointer);
}
}; };
template <typename TAllocator> template <typename TAllocator>
@ -51,7 +65,6 @@ class BlockJsonBuffer : public JsonBuffer {
return total; return total;
} }
protected:
virtual void* alloc(size_t bytes) { virtual void* alloc(size_t bytes) {
return canAllocInHead(bytes) ? allocInHead(bytes) : allocInNewBlock(bytes); return canAllocInHead(bytes) ? allocInHead(bytes) : allocInNewBlock(bytes);
} }
@ -92,3 +105,11 @@ class BlockJsonBuffer : public JsonBuffer {
}; };
} }
} }
#if defined(__clang__)
#pragma clang diagnostic pop
#elif defined(__GNUC__)
#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
#pragma GCC diagnostic pop
#endif
#endif

View File

@ -9,6 +9,48 @@
namespace ArduinoJson { namespace ArduinoJson {
namespace Internals { namespace Internals {
const char *skipSpacesAndComments(const char *ptr); inline const char *skipCStyleComment(const char *ptr) {
ptr += 2;
for (;;) {
if (ptr[0] == '\0') return ptr;
if (ptr[0] == '*' && ptr[1] == '/') return ptr + 2;
ptr++;
}
}
inline const char *skipCppStyleComment(const char *ptr) {
ptr += 2;
for (;;) {
if (ptr[0] == '\0' || ptr[0] == '\n') return ptr;
ptr++;
}
}
inline const char *skipSpacesAndComments(const char *ptr) {
for (;;) {
switch (ptr[0]) {
case ' ':
case '\t':
case '\r':
case '\n':
ptr++;
continue;
case '/':
switch (ptr[1]) {
case '*':
ptr = skipCStyleComment(ptr);
break;
case '/':
ptr = skipCppStyleComment(ptr);
break;
default:
return ptr;
}
break;
default:
return ptr;
}
}
}
} }
} }

View File

@ -16,7 +16,7 @@ class Encoding {
public: public:
// Optimized for code size on a 8-bit AVR // Optimized for code size on a 8-bit AVR
static char escapeChar(char c) { static char escapeChar(char c) {
const char *p = _escapeTable; const char *p = escapeTable(false);
while (p[0] && p[1] != c) { while (p[0] && p[1] != c) {
p += 2; p += 2;
} }
@ -25,7 +25,7 @@ class Encoding {
// Optimized for code size on a 8-bit AVR // Optimized for code size on a 8-bit AVR
static char unescapeChar(char c) { static char unescapeChar(char c) {
const char *p = _escapeTable + 4; const char *p = escapeTable(true);
for (;;) { for (;;) {
if (p[0] == '\0') return c; if (p[0] == '\0') return c;
if (p[0] == c) return p[1]; if (p[0] == c) return p[1];
@ -34,7 +34,9 @@ class Encoding {
} }
private: private:
static const char _escapeTable[]; static const char *escapeTable(bool excludeIdenticals) {
return &"\"\"\\\\b\bf\fn\nr\rt\t"[excludeIdenticals ? 4 : 0];
}
}; };
} }
} }

View File

@ -23,7 +23,13 @@ class IndentedPrint : public Print {
isNewLine = true; isNewLine = true;
} }
virtual size_t write(uint8_t); virtual size_t write(uint8_t c) {
size_t n = 0;
if (isNewLine) n += writeTabs();
n += sink->write(c);
isNewLine = c == '\n';
return n;
}
// Adds one level of indentation // Adds one level of indentation
void indent() { void indent() {
@ -46,7 +52,11 @@ class IndentedPrint : public Print {
uint8_t tabSize : 3; uint8_t tabSize : 3;
bool isNewLine : 1; bool isNewLine : 1;
size_t writeTabs(); size_t writeTabs() {
size_t n = 0;
for (int i = 0; i < level * tabSize; i++) n += sink->write(' ');
return n;
}
static const int MAX_LEVEL = 15; // because it's only 4 bits static const int MAX_LEVEL = 15; // because it's only 4 bits
static const int MAX_TAB_SIZE = 7; // because it's only 3 bits static const int MAX_TAB_SIZE = 7; // because it's only 3 bits

View File

@ -44,6 +44,19 @@ class JsonParser {
inline bool parseObjectTo(JsonVariant *destination); inline bool parseObjectTo(JsonVariant *destination);
inline bool parseStringTo(JsonVariant *destination); inline bool parseStringTo(JsonVariant *destination);
static inline bool isInRange(char c, char min, char max) {
return min <= c && c <= max;
}
static inline bool isLetterOrNumber(char c) {
return isInRange(c, '0', '9') || isInRange(c, 'a', 'z') ||
isInRange(c, 'A', 'Z') || c == '-' || c == '.';
}
static inline bool isQuote(char c) {
return c == '\'' || c == '\"';
}
JsonBuffer *_buffer; JsonBuffer *_buffer;
const char *_readPtr; const char *_readPtr;
char *_writePtr; char *_writePtr;

View File

@ -5,18 +5,10 @@
// https://github.com/bblanchon/ArduinoJson // https://github.com/bblanchon/ArduinoJson
// If you like this project, please add a star! // If you like this project, please add a star!
#include "../../include/ArduinoJson/Internals/JsonParser.hpp" #include "JsonParser.hpp"
#include "Comments.hpp"
#include "../../include/ArduinoJson/Internals/Comments.hpp" inline bool ArduinoJson::Internals::JsonParser::skip(char charToSkip) {
#include "../../include/ArduinoJson/Internals/Encoding.hpp"
#include "../../include/ArduinoJson/JsonArray.hpp"
#include "../../include/ArduinoJson/JsonBuffer.hpp"
#include "../../include/ArduinoJson/JsonObject.hpp"
using namespace ArduinoJson;
using namespace ArduinoJson::Internals;
bool JsonParser::skip(char charToSkip) {
const char *ptr = skipSpacesAndComments(_readPtr); const char *ptr = skipSpacesAndComments(_readPtr);
if (*ptr != charToSkip) return false; if (*ptr != charToSkip) return false;
ptr++; ptr++;
@ -24,7 +16,8 @@ bool JsonParser::skip(char charToSkip) {
return true; return true;
} }
bool JsonParser::parseAnythingTo(JsonVariant *destination) { inline bool ArduinoJson::Internals::JsonParser::parseAnythingTo(
JsonVariant *destination) {
if (_nestingLimit == 0) return false; if (_nestingLimit == 0) return false;
_nestingLimit--; _nestingLimit--;
bool success = parseAnythingToUnsafe(destination); bool success = parseAnythingToUnsafe(destination);
@ -32,7 +25,8 @@ bool JsonParser::parseAnythingTo(JsonVariant *destination) {
return success; return success;
} }
inline bool JsonParser::parseAnythingToUnsafe(JsonVariant *destination) { inline bool ArduinoJson::Internals::JsonParser::parseAnythingToUnsafe(
JsonVariant *destination) {
_readPtr = skipSpacesAndComments(_readPtr); _readPtr = skipSpacesAndComments(_readPtr);
switch (*_readPtr) { switch (*_readPtr) {
@ -47,7 +41,8 @@ inline bool JsonParser::parseAnythingToUnsafe(JsonVariant *destination) {
} }
} }
JsonArray &JsonParser::parseArray() { inline ArduinoJson::JsonArray &
ArduinoJson::Internals::JsonParser::parseArray() {
// Create an empty array // Create an empty array
JsonArray &array = _buffer->createArray(); JsonArray &array = _buffer->createArray();
@ -78,7 +73,8 @@ ERROR_NO_MEMORY:
return JsonArray::invalid(); return JsonArray::invalid();
} }
bool JsonParser::parseArrayTo(JsonVariant *destination) { inline bool ArduinoJson::Internals::JsonParser::parseArrayTo(
JsonVariant *destination) {
JsonArray &array = parseArray(); JsonArray &array = parseArray();
if (!array.success()) return false; if (!array.success()) return false;
@ -86,7 +82,8 @@ bool JsonParser::parseArrayTo(JsonVariant *destination) {
return true; return true;
} }
JsonObject &JsonParser::parseObject() { inline ArduinoJson::JsonObject &
ArduinoJson::Internals::JsonParser::parseObject() {
// Create an empty object // Create an empty object
JsonObject &object = _buffer->createObject(); JsonObject &object = _buffer->createObject();
@ -124,7 +121,8 @@ ERROR_NO_MEMORY:
return JsonObject::invalid(); return JsonObject::invalid();
} }
bool JsonParser::parseObjectTo(JsonVariant *destination) { inline bool ArduinoJson::Internals::JsonParser::parseObjectTo(
JsonVariant *destination) {
JsonObject &object = parseObject(); JsonObject &object = parseObject();
if (!object.success()) return false; if (!object.success()) return false;
@ -132,18 +130,7 @@ bool JsonParser::parseObjectTo(JsonVariant *destination) {
return true; return true;
} }
static inline bool isInRange(char c, char min, char max) { inline const char *ArduinoJson::Internals::JsonParser::parseString() {
return min <= c && c <= max;
}
static inline bool isLetterOrNumber(char c) {
return isInRange(c, '0', '9') || isInRange(c, 'a', 'z') ||
isInRange(c, 'A', 'Z') || c == '-' || c == '.';
}
static inline bool isQuote(char c) { return c == '\'' || c == '\"'; }
const char *JsonParser::parseString() {
const char *readPtr = _readPtr; const char *readPtr = _readPtr;
char *writePtr = _writePtr; char *writePtr = _writePtr;
@ -188,7 +175,8 @@ const char *JsonParser::parseString() {
return startPtr; return startPtr;
} }
bool JsonParser::parseStringTo(JsonVariant *destination) { inline bool ArduinoJson::Internals::JsonParser::parseStringTo(
JsonVariant *destination) {
bool hasQuotes = isQuote(_readPtr[0]); bool hasQuotes = isQuote(_readPtr[0]);
const char *value = parseString(); const char *value = parseString();
if (value == NULL) return false; if (value == NULL) return false;

View File

@ -7,12 +7,12 @@
#pragma once #pragma once
#include "../Polyfills/attributes.hpp"
#include "../Polyfills/isInfinity.hpp" #include "../Polyfills/isInfinity.hpp"
#include "../Polyfills/isNaN.hpp" #include "../Polyfills/isNaN.hpp"
#include "../Polyfills/normalize.hpp" #include "../Polyfills/normalize.hpp"
#include "../Print.hpp" #include "../Print.hpp"
#include "Encoding.hpp" #include "Encoding.hpp"
#include "ForceInline.hpp"
#include "JsonFloat.hpp" #include "JsonFloat.hpp"
#include "JsonInteger.hpp" #include "JsonInteger.hpp"

View File

@ -36,21 +36,56 @@ class List {
// Would return false in the following situation: // Would return false in the following situation:
// - the memory allocation failed (StaticJsonBuffer was too small) // - the memory allocation failed (StaticJsonBuffer was too small)
// - the JSON parsing failed // - the JSON parsing failed
bool success() const { return _buffer != NULL; } bool success() const {
return _buffer != NULL;
}
// Returns the numbers of elements in the list. // Returns the numbers of elements in the list.
// For a JsonObject, it would return the number of key-value pairs // For a JsonObject, it would return the number of key-value pairs
size_t size() const; size_t size() const {
size_t nodeCount = 0;
for (node_type *node = _firstNode; node; node = node->next) nodeCount++;
return nodeCount;
}
iterator begin() { return iterator(_firstNode); } iterator begin() {
iterator end() { return iterator(NULL); } return iterator(_firstNode);
}
iterator end() {
return iterator(NULL);
}
const_iterator begin() const { return const_iterator(_firstNode); } const_iterator begin() const {
const_iterator end() const { return const_iterator(NULL); } return const_iterator(_firstNode);
}
const_iterator end() const {
return const_iterator(NULL);
}
protected: protected:
node_type *addNewNode(); node_type *addNewNode() {
void removeNode(node_type *nodeToRemove); node_type *newNode = new (_buffer) node_type();
if (_firstNode) {
node_type *lastNode = _firstNode;
while (lastNode->next) lastNode = lastNode->next;
lastNode->next = newNode;
} else {
_firstNode = newNode;
}
return newNode;
}
void removeNode(node_type *nodeToRemove) {
if (!nodeToRemove) return;
if (nodeToRemove == _firstNode) {
_firstNode = nodeToRemove->next;
} else {
for (node_type *node = _firstNode; node; node = node->next)
if (node->next == nodeToRemove) node->next = nodeToRemove->next;
}
}
JsonBuffer *_buffer; JsonBuffer *_buffer;
node_type *_firstNode; node_type *_firstNode;

View File

@ -20,24 +20,89 @@ class Prettyfier : public Print {
_inString = false; _inString = false;
} }
virtual size_t write(uint8_t); virtual size_t write(uint8_t c) {
size_t n = _inString ? handleStringChar(c) : handleMarkupChar(c);
_previousChar = c;
return n;
}
private: private:
Prettyfier& operator=(const Prettyfier&); // cannot be assigned Prettyfier& operator=(const Prettyfier&); // cannot be assigned
bool inEmptyBlock() { return _previousChar == '{' || _previousChar == '['; } bool inEmptyBlock() {
return _previousChar == '{' || _previousChar == '[';
}
size_t handleStringChar(uint8_t); size_t handleStringChar(uint8_t c) {
size_t handleMarkupChar(uint8_t); bool isQuote = c == '"' && _previousChar != '\\';
size_t handleBlockClose(uint8_t); if (isQuote) _inString = false;
size_t handleBlockOpen(uint8_t);
size_t handleColon(); return _sink.write(c);
size_t handleComma(); }
size_t handleQuoteOpen();
size_t handleNormalChar(uint8_t); size_t handleMarkupChar(uint8_t c) {
size_t indentIfNeeded(); switch (c) {
size_t unindentIfNeeded(); case '{':
case '[':
return writeBlockOpen(c);
case '}':
case ']':
return writeBlockClose(c);
case ':':
return writeColon();
case ',':
return writeComma();
case '"':
return writeQuoteOpen();
default:
return writeNormalChar(c);
}
}
size_t writeBlockClose(uint8_t c) {
return unindentIfNeeded() + _sink.write(c);
}
size_t writeBlockOpen(uint8_t c) {
return indentIfNeeded() + _sink.write(c);
}
size_t writeColon() {
return _sink.write(':') + _sink.write(' ');
}
size_t writeComma() {
return _sink.write(',') + _sink.println();
}
size_t writeQuoteOpen() {
_inString = true;
return indentIfNeeded() + _sink.write('"');
}
size_t writeNormalChar(uint8_t c) {
return indentIfNeeded() + _sink.write(c);
}
size_t indentIfNeeded() {
if (!inEmptyBlock()) return 0;
_sink.indent();
return _sink.println();
}
size_t unindentIfNeeded() {
if (inEmptyBlock()) return 0;
_sink.unindent();
return _sink.println();
}
uint8_t _previousChar; uint8_t _previousChar;
IndentedPrint& _sink; IndentedPrint& _sink;

View File

@ -20,7 +20,13 @@ class StaticStringBuilder : public Print {
buffer[0] = '\0'; buffer[0] = '\0';
} }
virtual size_t write(uint8_t c); virtual size_t write(uint8_t c) {
if (length >= capacity) return 0;
buffer[length++] = c;
buffer[length] = '\0';
return 1;
}
private: private:
char *buffer; char *buffer;

View File

@ -56,10 +56,12 @@ class JsonArray : public Internals::JsonPrintable<JsonArray>,
: Internals::List<JsonVariant>(buffer) {} : Internals::List<JsonVariant>(buffer) {}
// Gets the value at the specified index // Gets the value at the specified index
FORCE_INLINE JsonVariant operator[](size_t index) const; JsonVariant operator[](size_t index) const {
return get(index);
}
// Gets or sets the value at specified index // Gets or sets the value at specified index
FORCE_INLINE JsonArraySubscript operator[](size_t index); JsonArraySubscript operator[](size_t index);
// Adds the specified value at the end of the array. // Adds the specified value at the end of the array.
// //
@ -72,7 +74,7 @@ class JsonArray : public Internals::JsonPrintable<JsonArray>,
// bool add(double value); // bool add(double value);
// bool add(const char*); // bool add(const char*);
template <typename T> template <typename T>
FORCE_INLINE bool add( bool add(
T value, T value,
typename TypeTraits::EnableIf< typename TypeTraits::EnableIf<
CanSet<T>::value && !TypeTraits::IsReference<T>::value>::type * = 0) { CanSet<T>::value && !TypeTraits::IsReference<T>::value>::type * = 0) {
@ -83,18 +85,16 @@ class JsonArray : public Internals::JsonPrintable<JsonArray>,
// bool add(JsonArray&); // bool add(JsonArray&);
// bool add(JsonObject&); // bool add(JsonObject&);
template <typename T> template <typename T>
FORCE_INLINE bool add( bool add(const T &value,
const T &value, typename TypeTraits::EnableIf<CanSet<T &>::value>::type * = 0) {
typename TypeTraits::EnableIf<CanSet<T &>::value>::type * = 0) {
return addNode<T &>(const_cast<T &>(value)); return addNode<T &>(const_cast<T &>(value));
} }
// bool add(float value, uint8_t decimals); // bool add(float value, uint8_t decimals);
// bool add(double value, uint8_t decimals); // bool add(double value, uint8_t decimals);
template <typename T> template <typename T>
FORCE_INLINE bool add( bool add(T value, uint8_t decimals,
T value, uint8_t decimals, typename TypeTraits::EnableIf<
typename TypeTraits::EnableIf<TypeTraits::IsFloatingPoint<T>::value>::type TypeTraits::IsFloatingPoint<T>::value>::type * = 0) {
* = 0) {
return addNode<JsonVariant>(JsonVariant(value, decimals)); return addNode<JsonVariant>(JsonVariant(value, decimals));
} }
@ -105,7 +105,7 @@ class JsonArray : public Internals::JsonPrintable<JsonArray>,
// bool set(size_t index, int value); // bool set(size_t index, int value);
// bool set(size_t index, short value); // bool set(size_t index, short value);
template <typename T> template <typename T>
FORCE_INLINE bool set( bool set(
size_t index, T value, size_t index, T value,
typename TypeTraits::EnableIf< typename TypeTraits::EnableIf<
CanSet<T>::value && !TypeTraits::IsReference<T>::value>::type * = 0) { CanSet<T>::value && !TypeTraits::IsReference<T>::value>::type * = 0) {
@ -116,31 +116,38 @@ class JsonArray : public Internals::JsonPrintable<JsonArray>,
// bool set(size_t index, JsonArray&); // bool set(size_t index, JsonArray&);
// bool set(size_t index, JsonObject&); // bool set(size_t index, JsonObject&);
template <typename T> template <typename T>
FORCE_INLINE bool set( bool set(size_t index, const T &value,
size_t index, const T &value, typename TypeTraits::EnableIf<CanSet<T &>::value>::type * = 0) {
typename TypeTraits::EnableIf<CanSet<T &>::value>::type * = 0) {
return setNodeAt<T &>(index, const_cast<T &>(value)); return setNodeAt<T &>(index, const_cast<T &>(value));
} }
// bool set(size_t index, float value, uint8_t decimals = 2); // bool set(size_t index, float value, uint8_t decimals = 2);
// bool set(size_t index, double value, uint8_t decimals = 2); // bool set(size_t index, double value, uint8_t decimals = 2);
template <typename T> template <typename T>
FORCE_INLINE bool set( bool set(size_t index, T value, uint8_t decimals,
size_t index, T value, uint8_t decimals, typename TypeTraits::EnableIf<
typename TypeTraits::EnableIf<TypeTraits::IsFloatingPoint<T>::value>::type TypeTraits::IsFloatingPoint<T>::value>::type * = 0) {
* = 0) {
return setNodeAt<const JsonVariant &>(index, JsonVariant(value, decimals)); return setNodeAt<const JsonVariant &>(index, JsonVariant(value, decimals));
} }
// Gets the value at the specified index. // Gets the value at the specified index.
FORCE_INLINE JsonVariant get(size_t index) const; JsonVariant get(size_t index) const {
node_type *node = getNodeAt(index);
return node ? node->content : JsonVariant();
}
// Gets the value at the specified index. // Gets the value at the specified index.
template <typename T> template <typename T>
FORCE_INLINE T get(size_t index) const; T get(size_t index) const {
node_type *node = getNodeAt(index);
return node ? node->content.as<T>() : JsonVariant::defaultValue<T>();
}
// Check the type of the value at specified index. // Check the type of the value at specified index.
template <typename T> template <typename T>
FORCE_INLINE bool is(size_t index) const; bool is(size_t index) const {
node_type *node = getNodeAt(index);
return node ? node->content.is<T>() : false;
}
// Creates a JsonArray and adds a reference at the end of the array. // Creates a JsonArray and adds a reference at the end of the array.
// It's a shortcut for JsonBuffer::createArray() and JsonArray::add() // It's a shortcut for JsonBuffer::createArray() and JsonArray::add()
@ -151,15 +158,34 @@ class JsonArray : public Internals::JsonPrintable<JsonArray>,
JsonObject &createNestedObject(); JsonObject &createNestedObject();
// Removes element at specified index. // Removes element at specified index.
void removeAt(size_t index); void removeAt(size_t index) {
removeNode(getNodeAt(index));
}
// Returns a reference an invalid JsonArray. // Returns a reference an invalid JsonArray.
// This object is meant to replace a NULL pointer. // This object is meant to replace a NULL pointer.
// This is used when memory allocation or JSON parsing fail. // This is used when memory allocation or JSON parsing fail.
static JsonArray &invalid() { return _invalid; } static JsonArray &invalid() {
static JsonArray instance(NULL);
return instance;
}
// Serialize the array to the specified JsonWriter. // Serialize the array to the specified JsonWriter.
void writeTo(Internals::JsonWriter &writer) const; void writeTo(Internals::JsonWriter &writer) const {
writer.beginArray();
const node_type *child = _firstNode;
while (child) {
child->content.writeTo(writer);
child = child->next;
if (!child) break;
writer.writeComma();
}
writer.endArray();
}
// Imports a 1D array // Imports a 1D array
template <typename T, size_t N> template <typename T, size_t N>
@ -215,20 +241,28 @@ class JsonArray : public Internals::JsonPrintable<JsonArray>,
} }
private: private:
node_type *getNodeAt(size_t index) const; node_type *getNodeAt(size_t index) const {
node_type *node = _firstNode;
while (node && index--) node = node->next;
return node;
}
template <typename TValue> template <typename TValue>
bool setNodeAt(size_t index, TValue value); bool setNodeAt(size_t index, TValue value) {
node_type *node = getNodeAt(index);
return node != NULL && setNodeValue<TValue>(node, value);
}
template <typename TValue> template <typename TValue>
bool addNode(TValue); bool addNode(TValue value) {
node_type *node = addNewNode();
return node != NULL && setNodeValue<TValue>(node, value);
}
template <typename T> template <typename T>
FORCE_INLINE bool setNodeValue(node_type *, T value); bool setNodeValue(node_type *node, T value) {
node->content = value;
// The instance returned by JsonArray::invalid() return true;
static JsonArray _invalid; }
}; };
} }
#include "JsonArray.ipp"

View File

@ -13,32 +13,6 @@
namespace ArduinoJson { namespace ArduinoJson {
inline JsonArraySubscript JsonArray::operator[](size_t index) {
return JsonArraySubscript(*this, index);
}
inline JsonVariant JsonArray::operator[](size_t index) const {
return get(index);
}
template <typename TValue>
inline bool JsonArray::addNode(TValue value) {
node_type *node = addNewNode();
return node != NULL && setNodeValue<TValue>(node, value);
}
template <typename TValue>
inline bool JsonArray::setNodeAt(size_t index, TValue value) {
node_type *node = getNodeAt(index);
return node != NULL && setNodeValue<TValue>(node, value);
}
template <typename TValue>
inline bool JsonArray::setNodeValue(node_type *node, TValue value) {
node->content = value;
return true;
}
template <> template <>
inline bool JsonArray::setNodeValue(node_type *node, String &value) { inline bool JsonArray::setNodeValue(node_type *node, String &value) {
const char *copy = _buffer->strdup(value); const char *copy = _buffer->strdup(value);
@ -47,29 +21,6 @@ inline bool JsonArray::setNodeValue(node_type *node, String &value) {
return true; return true;
} }
inline JsonVariant JsonArray::get(size_t index) const {
node_type *node = getNodeAt(index);
return node ? node->content : JsonVariant();
}
template <typename T>
inline T JsonArray::get(size_t index) const {
node_type *node = getNodeAt(index);
return node ? node->content.as<T>() : JsonVariant::defaultValue<T>();
}
template <typename T>
inline bool JsonArray::is(size_t index) const {
node_type *node = getNodeAt(index);
return node ? node->content.is<T>() : false;
}
template <typename TImplem>
inline const JsonArraySubscript JsonVariantBase<TImplem>::operator[](
int index) const {
return asArray()[index];
}
template <> template <>
inline JsonArray &JsonVariant::defaultValue<JsonArray &>() { inline JsonArray &JsonVariant::defaultValue<JsonArray &>() {
return JsonArray::invalid(); return JsonArray::invalid();

View File

@ -77,6 +77,16 @@ inline std::ostream& operator<<(std::ostream& os,
} }
#endif #endif
inline JsonArraySubscript JsonArray::operator[](size_t index) {
return JsonArraySubscript(*this, index);
}
template <typename TImplem>
inline const JsonArraySubscript JsonVariantBase<TImplem>::operator[](
int index) const {
return asArray()[index];
}
} // namespace ArduinoJson } // namespace ArduinoJson
#ifdef _MSC_VER #ifdef _MSC_VER

View File

@ -0,0 +1,44 @@
// Copyright Benoit Blanchon 2014-2016
// MIT License
//
// Arduino JSON library
// https://github.com/bblanchon/ArduinoJson
// If you like this project, please add a star!
#include "Internals/JsonParser.hpp"
inline ArduinoJson::JsonArray &ArduinoJson::JsonBuffer::createArray() {
JsonArray *ptr = new (this) JsonArray(this);
return ptr ? *ptr : JsonArray::invalid();
}
inline ArduinoJson::JsonObject &ArduinoJson::JsonBuffer::createObject() {
JsonObject *ptr = new (this) JsonObject(this);
return ptr ? *ptr : JsonObject::invalid();
}
inline ArduinoJson::JsonArray &ArduinoJson::JsonBuffer::parseArray(
char *json, uint8_t nestingLimit) {
Internals::JsonParser parser(this, json, nestingLimit);
return parser.parseArray();
}
inline ArduinoJson::JsonObject &ArduinoJson::JsonBuffer::parseObject(
char *json, uint8_t nestingLimit) {
Internals::JsonParser parser(this, json, nestingLimit);
return parser.parseObject();
}
inline ArduinoJson::JsonVariant ArduinoJson::JsonBuffer::parse(
char *json, uint8_t nestingLimit) {
Internals::JsonParser parser(this, json, nestingLimit);
return parser.parseVariant();
}
inline char *ArduinoJson::JsonBuffer::strdup(const char *source,
size_t length) {
size_t size = length + 1;
char *dest = static_cast<char *>(alloc(size));
if (dest != NULL) memcpy(dest, source, size);
return dest;
}

View File

@ -52,15 +52,16 @@ class JsonObject : public Internals::JsonPrintable<JsonObject>,
// Create an empty JsonArray attached to the specified JsonBuffer. // Create an empty JsonArray attached to the specified JsonBuffer.
// You should not use this constructor directly. // You should not use this constructor directly.
// Instead, use JsonBuffer::createObject() or JsonBuffer.parseObject(). // Instead, use JsonBuffer::createObject() or JsonBuffer.parseObject().
FORCE_INLINE explicit JsonObject(JsonBuffer* buffer) explicit JsonObject(JsonBuffer* buffer) : Internals::List<JsonPair>(buffer) {}
: Internals::List<JsonPair>(buffer) {}
// Gets or sets the value associated with the specified key. // Gets or sets the value associated with the specified key.
FORCE_INLINE JsonObjectSubscript<const char*> operator[](const char* key); JsonObjectSubscript<const char*> operator[](const char* key);
FORCE_INLINE JsonObjectSubscript<const String&> operator[](const String& key); JsonObjectSubscript<const String&> operator[](const String& key);
// Gets the value associated with the specified key. // Gets the value associated with the specified key.
FORCE_INLINE JsonVariant operator[](JsonObjectKey key) const; JsonVariant operator[](JsonObjectKey key) const {
return get(key);
}
// Sets the specified key with the specified value. // Sets the specified key with the specified value.
// bool set(TKey key, bool value); // bool set(TKey key, bool value);
@ -73,7 +74,7 @@ class JsonObject : public Internals::JsonPrintable<JsonObject>,
// bool set(TKey key, const char* value); // bool set(TKey key, const char* value);
// bool set(TKey key, RawJson value); // bool set(TKey key, RawJson value);
template <typename T> template <typename T>
FORCE_INLINE bool set( bool set(
JsonObjectKey key, T value, JsonObjectKey key, T value,
typename TypeTraits::EnableIf< typename TypeTraits::EnableIf<
CanSet<T>::value && !TypeTraits::IsReference<T>::value>::type* = 0) { CanSet<T>::value && !TypeTraits::IsReference<T>::value>::type* = 0) {
@ -84,71 +85,117 @@ class JsonObject : public Internals::JsonPrintable<JsonObject>,
// bool set(Key, JsonObject&); // bool set(Key, JsonObject&);
// bool set(Key, JsonVariant&); // bool set(Key, JsonVariant&);
template <typename T> template <typename T>
FORCE_INLINE bool set( bool set(JsonObjectKey key, const T& value,
JsonObjectKey key, const T& value, typename TypeTraits::EnableIf<CanSet<T&>::value>::type* = 0) {
typename TypeTraits::EnableIf<CanSet<T&>::value>::type* = 0) {
return setNodeAt<T&>(key, const_cast<T&>(value)); return setNodeAt<T&>(key, const_cast<T&>(value));
} }
// bool set(Key, float value, uint8_t decimals); // bool set(Key, float value, uint8_t decimals);
// bool set(Key, double value, uint8_t decimals); // bool set(Key, double value, uint8_t decimals);
template <typename TValue> template <typename TValue>
FORCE_INLINE bool set( bool set(JsonObjectKey key, TValue value, uint8_t decimals,
JsonObjectKey key, TValue value, uint8_t decimals, typename TypeTraits::EnableIf<
typename TypeTraits::EnableIf< TypeTraits::IsFloatingPoint<TValue>::value>::type* = 0) {
TypeTraits::IsFloatingPoint<TValue>::value>::type* = 0) {
return setNodeAt<const JsonVariant&>(key, JsonVariant(value, decimals)); return setNodeAt<const JsonVariant&>(key, JsonVariant(value, decimals));
} }
// Gets the value associated with the specified key. // Gets the value associated with the specified key.
FORCE_INLINE JsonVariant get(JsonObjectKey) const; JsonVariant get(JsonObjectKey key) const {
node_type* node = getNodeAt(key.c_str());
return node ? node->content.value : JsonVariant();
}
// Gets the value associated with the specified key. // Gets the value associated with the specified key.
template <typename T> template <typename T>
FORCE_INLINE T get(JsonObjectKey) const; T get(JsonObjectKey key) const {
node_type* node = getNodeAt(key.c_str());
return node ? node->content.value.as<T>() : JsonVariant::defaultValue<T>();
}
// Checks the type of the value associated with the specified key. // Checks the type of the value associated with the specified key.
template <typename T> template <typename T>
FORCE_INLINE bool is(JsonObjectKey) const; bool is(JsonObjectKey key) const {
node_type* node = getNodeAt(key.c_str());
return node ? node->content.value.is<T>() : false;
}
// Creates and adds a JsonArray. // Creates and adds a JsonArray.
// This is a shortcut for JsonBuffer::createArray() and JsonObject::add(). // This is a shortcut for JsonBuffer::createArray() and JsonObject::add().
FORCE_INLINE JsonArray& createNestedArray(JsonObjectKey key); JsonArray& createNestedArray(JsonObjectKey key);
// Creates and adds a JsonObject. // Creates and adds a JsonObject.
// This is a shortcut for JsonBuffer::createObject() and JsonObject::add(). // This is a shortcut for JsonBuffer::createObject() and JsonObject::add().
FORCE_INLINE JsonObject& createNestedObject(JsonObjectKey key); JsonObject& createNestedObject(JsonObjectKey key);
// Tells weither the specified key is present and associated with a value. // Tells weither the specified key is present and associated with a value.
FORCE_INLINE bool containsKey(JsonObjectKey key) const; bool containsKey(JsonObjectKey key) const {
return getNodeAt(key.c_str()) != NULL;
}
// Removes the specified key and the associated value. // Removes the specified key and the associated value.
void remove(JsonObjectKey key); void remove(JsonObjectKey key) {
removeNode(getNodeAt(key.c_str()));
}
// Returns a reference an invalid JsonObject. // Returns a reference an invalid JsonObject.
// This object is meant to replace a NULL pointer. // This object is meant to replace a NULL pointer.
// This is used when memory allocation or JSON parsing fail. // This is used when memory allocation or JSON parsing fail.
static JsonObject& invalid() { return _invalid; } static JsonObject& invalid() {
static JsonObject instance(NULL);
return instance;
}
// Serialize the object to the specified JsonWriter // Serialize the object to the specified JsonWriter
void writeTo(Internals::JsonWriter& writer) const; void writeTo(Internals::JsonWriter& writer) const {
writer.beginObject();
const node_type* node = _firstNode;
while (node) {
writer.writeString(node->content.key);
writer.writeColon();
node->content.value.writeTo(writer);
node = node->next;
if (!node) break;
writer.writeComma();
}
writer.endObject();
}
private: private:
// Returns the list node that matches the specified key. // Returns the list node that matches the specified key.
node_type* getNodeAt(const char* key) const; node_type* getNodeAt(const char* key) const {
for (node_type* node = _firstNode; node; node = node->next) {
node_type* getOrCreateNodeAt(const char* key); if (!strcmp(node->content.key, key)) return node;
}
return NULL;
}
template <typename T> template <typename T>
FORCE_INLINE bool setNodeAt(JsonObjectKey key, T value); bool setNodeAt(JsonObjectKey key, T value) {
node_type* node = getNodeAt(key.c_str());
if (!node) {
node = addNewNode();
if (!node || !setNodeKey(node, key)) return false;
}
return setNodeValue<T>(node, value);
}
FORCE_INLINE bool setNodeKey(node_type*, JsonObjectKey key); bool setNodeKey(node_type* node, JsonObjectKey key) {
if (key.needs_copy()) {
node->content.key = _buffer->strdup(key.c_str());
if (node->content.key == NULL) return false;
} else {
node->content.key = key.c_str();
}
return true;
}
template <typename T> template <typename T>
FORCE_INLINE bool setNodeValue(node_type*, T value); bool setNodeValue(node_type* node, T value) {
node->content.value = value;
// The instance returned by JsonObject::invalid() return true;
static JsonObject _invalid; }
}; };
} }
#include "JsonObject.ipp"

View File

@ -13,71 +13,6 @@
namespace ArduinoJson { namespace ArduinoJson {
inline JsonVariant JsonObject::get(JsonObjectKey key) const {
node_type *node = getNodeAt(key.c_str());
return node ? node->content.value : JsonVariant();
}
template <typename T>
inline T JsonObject::get(JsonObjectKey key) const {
node_type *node = getNodeAt(key.c_str());
return node ? node->content.value.as<T>() : JsonVariant::defaultValue<T>();
}
template <typename T>
inline bool JsonObject::is(JsonObjectKey key) const {
node_type *node = getNodeAt(key.c_str());
return node ? node->content.value.is<T>() : false;
}
inline JsonObjectSubscript<const char *> JsonObject::operator[](
const char *key) {
return JsonObjectSubscript<const char *>(*this, key);
}
inline JsonObjectSubscript<const String &> JsonObject::operator[](
const String &key) {
return JsonObjectSubscript<const String &>(*this, key);
}
inline JsonVariant JsonObject::operator[](JsonObjectKey key) const {
return get(key);
}
inline bool JsonObject::containsKey(JsonObjectKey key) const {
return getNodeAt(key.c_str()) != NULL;
}
inline void JsonObject::remove(JsonObjectKey key) {
removeNode(getNodeAt(key.c_str()));
}
template <typename T>
inline bool JsonObject::setNodeAt(JsonObjectKey key, T value) {
node_type *node = getNodeAt(key.c_str());
if (!node) {
node = addNewNode();
if (!node || !setNodeKey(node, key)) return false;
}
return setNodeValue<T>(node, value);
}
inline bool JsonObject::setNodeKey(node_type *node, JsonObjectKey key) {
if (key.needs_copy()) {
node->content.key = _buffer->strdup(key.c_str());
if (node->content.key == NULL) return false;
} else {
node->content.key = key.c_str();
}
return true;
}
template <typename TValue>
inline bool JsonObject::setNodeValue(node_type *node, TValue value) {
node->content.value = value;
return true;
}
template <> template <>
inline bool JsonObject::setNodeValue(node_type *node, String &value) { inline bool JsonObject::setNodeValue(node_type *node, String &value) {
node->content.value = _buffer->strdup(value); node->content.value = _buffer->strdup(value);
@ -90,18 +25,6 @@ inline bool JsonObject::setNodeValue(node_type *node, const String &value) {
return node->content.value; return node->content.value;
} }
template <typename TImplem>
inline const JsonObjectSubscript<const char *> JsonVariantBase<TImplem>::
operator[](const char *key) const {
return asObject()[key];
}
template <typename TImplem>
inline const JsonObjectSubscript<const String &> JsonVariantBase<TImplem>::
operator[](const String &key) const {
return asObject()[key];
}
template <> template <>
inline JsonObject const &JsonVariant::defaultValue<JsonObject const &>() { inline JsonObject const &JsonVariant::defaultValue<JsonObject const &>() {
return JsonObject::invalid(); return JsonObject::invalid();

View File

@ -45,9 +45,13 @@ class JsonObjectSubscript : public JsonVariantBase<JsonObjectSubscript<TKey> > {
return *this; return *this;
} }
FORCE_INLINE bool success() const { return _object.containsKey(_key); } FORCE_INLINE bool success() const {
return _object.containsKey(_key);
}
FORCE_INLINE operator JsonVariant() const { return _object.get(_key); } FORCE_INLINE operator JsonVariant() const {
return _object.get(_key);
}
template <typename TValue> template <typename TValue>
FORCE_INLINE TValue as() const { FORCE_INLINE TValue as() const {
@ -69,7 +73,9 @@ class JsonObjectSubscript : public JsonVariantBase<JsonObjectSubscript<TKey> > {
return _object.set(_key, value, decimals); return _object.set(_key, value, decimals);
} }
FORCE_INLINE JsonVariant get() { return _object.get(_key); } FORCE_INLINE JsonVariant get() {
return _object.get(_key);
}
void writeTo(Internals::JsonWriter& writer) const { void writeTo(Internals::JsonWriter& writer) const {
_object.get(_key).writeTo(writer); _object.get(_key).writeTo(writer);
@ -92,6 +98,28 @@ inline std::ostream& operator<<(
} }
#endif #endif
inline JsonObjectSubscript<const char*> JsonObject::operator[](
const char* key) {
return JsonObjectSubscript<const char*>(*this, key);
}
inline JsonObjectSubscript<const String&> JsonObject::operator[](
const String& key) {
return JsonObjectSubscript<const String&>(*this, key);
}
template <typename TImplem>
inline const JsonObjectSubscript<const char*> JsonVariantBase<TImplem>::
operator[](const char* key) const {
return asObject()[key];
}
template <typename TImplem>
inline const JsonObjectSubscript<const String&> JsonVariantBase<TImplem>::
operator[](const String& key) const {
return asObject()[key];
}
} // namespace ArduinoJson } // namespace ArduinoJson
#ifdef _MSC_VER #ifdef _MSC_VER

View File

@ -41,11 +41,15 @@ class JsonVariant : public JsonVariantBase<JsonVariant> {
struct IsConstructibleFrom; struct IsConstructibleFrom;
// Creates an uninitialized JsonVariant // Creates an uninitialized JsonVariant
FORCE_INLINE JsonVariant() : _type(Internals::JSON_UNDEFINED) {} JsonVariant() : _type(Internals::JSON_UNDEFINED) {}
// Create a JsonVariant containing a boolean value. // Create a JsonVariant containing a boolean value.
// It will be serialized as "true" or "false" in JSON. // It will be serialized as "true" or "false" in JSON.
FORCE_INLINE JsonVariant(bool value); JsonVariant(bool value) {
using namespace Internals;
_type = JSON_BOOLEAN;
_content.asInteger = static_cast<JsonInteger>(value);
}
// Create a JsonVariant containing a floating point value. // Create a JsonVariant containing a floating point value.
// The second argument specifies the number of decimal digits to write in // The second argument specifies the number of decimal digits to write in
@ -53,10 +57,9 @@ class JsonVariant : public JsonVariantBase<JsonVariant> {
// JsonVariant(double value, uint8_t decimals); // JsonVariant(double value, uint8_t decimals);
// JsonVariant(float value, uint8_t decimals); // JsonVariant(float value, uint8_t decimals);
template <typename T> template <typename T>
FORCE_INLINE JsonVariant( JsonVariant(T value, uint8_t decimals = 2,
T value, uint8_t decimals = 2, typename TypeTraits::EnableIf<
typename TypeTraits::EnableIf<TypeTraits::IsFloatingPoint<T>::value>::type TypeTraits::IsFloatingPoint<T>::value>::type * = 0) {
* = 0) {
using namespace Internals; using namespace Internals;
_type = static_cast<JsonVariantType>(JSON_FLOAT_0_DECIMALS + decimals); _type = static_cast<JsonVariantType>(JSON_FLOAT_0_DECIMALS + decimals);
_content.asFloat = static_cast<JsonFloat>(value); _content.asFloat = static_cast<JsonFloat>(value);
@ -67,9 +70,9 @@ class JsonVariant : public JsonVariantBase<JsonVariant> {
// JsonVariant(signed int) // JsonVariant(signed int)
// JsonVariant(signed long) // JsonVariant(signed long)
template <typename T> template <typename T>
FORCE_INLINE JsonVariant( JsonVariant(T value,
T value, typename TypeTraits::EnableIf< typename TypeTraits::EnableIf<
TypeTraits::IsSignedIntegral<T>::value>::type * = 0) { TypeTraits::IsSignedIntegral<T>::value>::type * = 0) {
using namespace Internals; using namespace Internals;
if (value >= 0) { if (value >= 0) {
_type = JSON_POSITIVE_INTEGER; _type = JSON_POSITIVE_INTEGER;
@ -83,25 +86,37 @@ class JsonVariant : public JsonVariantBase<JsonVariant> {
// JsonVariant(unsigned int) // JsonVariant(unsigned int)
// JsonVariant(unsigned long) // JsonVariant(unsigned long)
template <typename T> template <typename T>
FORCE_INLINE JsonVariant( JsonVariant(T value,
T value, typename TypeTraits::EnableIf< typename TypeTraits::EnableIf<
TypeTraits::IsUnsignedIntegral<T>::value>::type * = 0) { TypeTraits::IsUnsignedIntegral<T>::value>::type * = 0) {
using namespace Internals; using namespace Internals;
_type = JSON_POSITIVE_INTEGER; _type = JSON_POSITIVE_INTEGER;
_content.asInteger = static_cast<JsonUInt>(value); _content.asInteger = static_cast<JsonUInt>(value);
} }
// Create a JsonVariant containing a string. // Create a JsonVariant containing a string.
FORCE_INLINE JsonVariant(const char *value); JsonVariant(const char *value) {
_type = Internals::JSON_STRING;
_content.asString = value;
}
// Create a JsonVariant containing an unparsed string // Create a JsonVariant containing an unparsed string
FORCE_INLINE JsonVariant(RawJson value); JsonVariant(RawJson value) {
_type = Internals::JSON_UNPARSED;
_content.asString = value;
}
// Create a JsonVariant containing a reference to an array. // Create a JsonVariant containing a reference to an array.
FORCE_INLINE JsonVariant(JsonArray &array); JsonVariant(JsonArray &array) {
_type = Internals::JSON_ARRAY;
_content.asArray = &array;
}
// Create a JsonVariant containing a reference to an object. // Create a JsonVariant containing a reference to an object.
FORCE_INLINE JsonVariant(JsonObject &object); JsonVariant(JsonObject &object) {
_type = Internals::JSON_OBJECT;
_content.asObject = &object;
}
// Get the variant as the specified type. // Get the variant as the specified type.
// //
@ -257,7 +272,9 @@ class JsonVariant : public JsonVariantBase<JsonVariant> {
} }
// Returns true if the variant has a value // Returns true if the variant has a value
bool success() const { return _type != Internals::JSON_UNDEFINED; } bool success() const {
return _type != Internals::JSON_UNDEFINED;
}
// Serialize the variant to a JsonWriter // Serialize the variant to a JsonWriter
void writeTo(Internals::JsonWriter &writer) const; void writeTo(Internals::JsonWriter &writer) const;
@ -275,9 +292,8 @@ class JsonVariant : public JsonVariantBase<JsonVariant> {
private: private:
// It's not allowed to store a char // It's not allowed to store a char
template <typename T> template <typename T>
FORCE_INLINE JsonVariant(T value, JsonVariant(T value, typename TypeTraits::EnableIf<
typename TypeTraits::EnableIf< TypeTraits::IsSame<T, char>::value>::type * = 0);
TypeTraits::IsSame<T, char>::value>::type * = 0);
String toString() const; String toString() const;
Internals::JsonFloat asFloat() const; Internals::JsonFloat asFloat() const;
@ -286,9 +302,15 @@ class JsonVariant : public JsonVariantBase<JsonVariant> {
bool isBoolean() const; bool isBoolean() const;
bool isFloat() const; bool isFloat() const;
bool isInteger() const; bool isInteger() const;
bool isArray() const { return _type == Internals::JSON_ARRAY; } bool isArray() const {
bool isObject() const { return _type == Internals::JSON_OBJECT; } return _type == Internals::JSON_ARRAY;
bool isString() const { return _type == Internals::JSON_STRING; } }
bool isObject() const {
return _type == Internals::JSON_OBJECT;
}
bool isString() const {
return _type == Internals::JSON_STRING;
}
// The current type of the variant // The current type of the variant
Internals::JsonVariantType _type; Internals::JsonVariantType _type;
@ -328,6 +350,3 @@ struct JsonVariant::IsConstructibleFrom {
TypeTraits::IsSame<T, const JsonVariant &>::value; TypeTraits::IsSame<T, const JsonVariant &>::value;
}; };
} }
// Include inline implementations
#include "JsonVariant.ipp"

View File

@ -10,37 +10,15 @@
#include "Configuration.hpp" #include "Configuration.hpp"
#include "JsonVariant.hpp" #include "JsonVariant.hpp"
#include "Internals/Parse.hpp" #include "Internals/Parse.hpp"
#include "JsonArray.hpp"
#include "JsonObject.hpp"
#include <string.h> #include <string.h> // for strcmp
#include <errno.h> // for errno
#include <stdlib.h> // for strtol, strtod
namespace ArduinoJson { namespace ArduinoJson {
inline JsonVariant::JsonVariant(bool value) {
using namespace Internals;
_type = JSON_BOOLEAN;
_content.asInteger = static_cast<JsonInteger>(value);
}
inline JsonVariant::JsonVariant(const char *value) {
_type = Internals::JSON_STRING;
_content.asString = value;
}
inline JsonVariant::JsonVariant(RawJson value) {
_type = Internals::JSON_UNPARSED;
_content.asString = value;
}
inline JsonVariant::JsonVariant(JsonArray &array) {
_type = Internals::JSON_ARRAY;
_content.asArray = &array;
}
inline JsonVariant::JsonVariant(JsonObject &object) {
_type = Internals::JSON_OBJECT;
_content.asObject = &object;
}
inline Internals::JsonInteger JsonVariant::asInteger() const { inline Internals::JsonInteger JsonVariant::asInteger() const {
using namespace Internals; using namespace Internals;
switch (_type) { switch (_type) {
@ -80,6 +58,119 @@ inline Internals::JsonUInt JsonVariant::asUnsignedInteger() const {
} }
} }
inline const char *JsonVariant::asString() const {
using namespace Internals;
if (_type == JSON_UNPARSED && _content.asString &&
!strcmp("null", _content.asString))
return NULL;
if (_type == JSON_STRING || _type == JSON_UNPARSED) return _content.asString;
return NULL;
}
inline Internals::JsonFloat JsonVariant::asFloat() const {
using namespace Internals;
switch (_type) {
case JSON_UNDEFINED:
return 0;
case JSON_POSITIVE_INTEGER:
case JSON_BOOLEAN:
return static_cast<JsonFloat>(_content.asInteger);
case JSON_NEGATIVE_INTEGER:
return -static_cast<JsonFloat>(_content.asInteger);
case JSON_STRING:
case JSON_UNPARSED:
return _content.asString ? parse<JsonFloat>(_content.asString) : 0;
default:
return _content.asFloat;
}
}
inline String JsonVariant::toString() const {
using namespace Internals;
String s;
if ((_type == JSON_STRING || _type == JSON_UNPARSED) &&
_content.asString != NULL)
s = _content.asString;
else
printTo(s);
return s;
}
inline bool JsonVariant::isBoolean() const {
using namespace Internals;
if (_type == JSON_BOOLEAN) return true;
if (_type != JSON_UNPARSED || _content.asString == NULL) return false;
return !strcmp(_content.asString, "true") ||
!strcmp(_content.asString, "false");
}
inline bool JsonVariant::isInteger() const {
using namespace Internals;
if (_type == JSON_POSITIVE_INTEGER || _type == JSON_NEGATIVE_INTEGER)
return true;
if (_type != JSON_UNPARSED || _content.asString == NULL) return false;
char *end;
errno = 0;
strtol(_content.asString, &end, 10);
return *end == '\0' && errno == 0;
}
inline bool JsonVariant::isFloat() const {
using namespace Internals;
if (_type >= JSON_FLOAT_0_DECIMALS) return true;
if (_type != JSON_UNPARSED || _content.asString == NULL) return false;
char *end;
errno = 0;
strtod(_content.asString, &end);
return *end == '\0' && errno == 0 && !is<long>();
}
inline void JsonVariant::writeTo(Internals::JsonWriter &writer) const {
using namespace Internals;
switch (_type) {
case JSON_UNDEFINED:
return;
case JSON_ARRAY:
_content.asArray->writeTo(writer);
return;
case JSON_OBJECT:
_content.asObject->writeTo(writer);
return;
case JSON_STRING:
writer.writeString(_content.asString);
return;
case JSON_UNPARSED:
writer.writeRaw(_content.asString);
return;
case JSON_NEGATIVE_INTEGER:
writer.writeRaw('-');
case JSON_POSITIVE_INTEGER:
writer.writeInteger(_content.asInteger);
return;
case JSON_BOOLEAN:
writer.writeBoolean(_content.asInteger != 0);
return;
default:
uint8_t decimals = static_cast<uint8_t>(_type - JSON_FLOAT_0_DECIMALS);
writer.writeFloat(_content.asFloat, decimals);
}
}
#if ARDUINOJSON_ENABLE_STD_STREAM #if ARDUINOJSON_ENABLE_STD_STREAM
inline std::ostream &operator<<(std::ostream &os, const JsonVariant &source) { inline std::ostream &operator<<(std::ostream &os, const JsonVariant &source) {
return source.printTo(os); return source.printTo(os);

View File

@ -7,7 +7,7 @@
#pragma once #pragma once
#include "Internals/ForceInline.hpp" #include "Polyfills/attributes.hpp"
#include "JsonObjectKey.hpp" #include "JsonObjectKey.hpp"
namespace ArduinoJson { namespace ArduinoJson {

View File

@ -9,6 +9,8 @@
#ifdef _MSC_VER #ifdef _MSC_VER
#define FORCE_INLINE __forceinline #define FORCE_INLINE __forceinline
#define NO_INLINE __declspec(noinline)
#else #else
#define FORCE_INLINE __attribute__((always_inline)) #define FORCE_INLINE __attribute__((always_inline))
#define NO_INLINE __attribute__((noinline))
#endif #endif

View File

@ -9,6 +9,16 @@
#include "JsonBuffer.hpp" #include "JsonBuffer.hpp"
#if defined(__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wnon-virtual-dtor"
#elif defined(__GNUC__)
#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
#pragma GCC diagnostic push
#endif
#pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
#endif
namespace ArduinoJson { namespace ArduinoJson {
// Implements a JsonBuffer with fixed memory allocation. // Implements a JsonBuffer with fixed memory allocation.
@ -19,8 +29,12 @@ class StaticJsonBuffer : public JsonBuffer {
public: public:
explicit StaticJsonBuffer() : _size(0) {} explicit StaticJsonBuffer() : _size(0) {}
size_t capacity() const { return CAPACITY; } size_t capacity() const {
size_t size() const { return _size; } return CAPACITY;
}
size_t size() const {
return _size;
}
virtual void* alloc(size_t bytes) { virtual void* alloc(size_t bytes) {
if (_size + bytes > CAPACITY) return NULL; if (_size + bytes > CAPACITY) return NULL;
@ -34,3 +48,11 @@ class StaticJsonBuffer : public JsonBuffer {
size_t _size; size_t _size;
}; };
} }
#if defined(__clang__)
#pragma clang diagnostic pop
#elif defined(__GNUC__)
#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
#pragma GCC diagnostic pop
#endif
#endif

View File

@ -1,14 +0,0 @@
// Copyright Benoit Blanchon 2014-2016
// MIT License
//
// Arduino JSON library
// https://github.com/bblanchon/ArduinoJson
// If you like this project, please add a star!
// About this file
// ---------------
// This file is here to please the Arduino IDE. It must be present in the src/
// for the IDE to find it. Feel free to ignore this file if your working in
// another environment
#include "../include/ArduinoJson.h"

View File

@ -1,71 +0,0 @@
# Copyright Benoit Blanchon 2014-2016
# MIT License
#
# Arduino JSON library
# https://github.com/bblanchon/ArduinoJson
# If you like this project, please add a star!
file(GLOB_RECURSE HPP_FILES ../include/*.hpp)
file(GLOB_RECURSE IPP_FILES ../include/*.ipp)
file(GLOB_RECURSE CPP_FILES *.cpp)
if(CMAKE_CXX_COMPILER_ID MATCHES "(GNU|Clang)")
add_compile_options(
-fno-exceptions
-fno-rtti
-pedantic
-Wall
-Wcast-align
-Wcast-qual
-Wconversion
-Wctor-dtor-privacy
-Wdisabled-optimization
-Werror
-Wextra
-Wformat=2
-Winit-self
-Wmissing-include-dirs
-Wno-parentheses
-Wno-sign-conversion
-Wno-unused
-Wno-variadic-macros
-Wnon-virtual-dtor
-Wold-style-cast
-Woverloaded-virtual
-Wredundant-decls
-Wshadow
-Wsign-promo
-Wstrict-overflow=5
-Wundef
)
endif()
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU")
add_compile_options(
-Wstrict-null-sentinel
)
if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 4.5)
add_compile_options(-Wlogical-op) # the flag exists in 4.4 but is buggy
endif()
if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 4.6)
add_compile_options(-Wnoexcept)
endif()
endif()
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
add_compile_options(
-Wc++11-compat
-Wdeprecated-register
)
endif()
if(MSVC)
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
add_compile_options(-W4)
endif()
add_library(ArduinoJson ${CPP_FILES} ${HPP_FILES} ${IPP_FILES})
target_include_directories(ArduinoJson INTERFACE ${CMAKE_CURRENT_LIST_DIR}/../include)

View File

@ -1,52 +0,0 @@
// Copyright Benoit Blanchon 2014-2016
// MIT License
//
// Arduino JSON library
// https://github.com/bblanchon/ArduinoJson
// If you like this project, please add a star!
#include "../../include/ArduinoJson/Internals/Comments.hpp"
inline static const char *skipCStyleComment(const char *ptr) {
ptr += 2;
for (;;) {
if (ptr[0] == '\0') return ptr;
if (ptr[0] == '*' && ptr[1] == '/') return ptr + 2;
ptr++;
}
}
inline static const char *skipCppStyleComment(const char *ptr) {
ptr += 2;
for (;;) {
if (ptr[0] == '\0' || ptr[0] == '\n') return ptr;
ptr++;
}
}
const char *ArduinoJson::Internals::skipSpacesAndComments(const char *ptr) {
for (;;) {
switch (ptr[0]) {
case ' ':
case '\t':
case '\r':
case '\n':
ptr++;
continue;
case '/':
switch (ptr[1]) {
case '*':
ptr = skipCStyleComment(ptr);
break;
case '/':
ptr = skipCppStyleComment(ptr);
break;
default:
return ptr;
}
break;
default:
return ptr;
}
}
}

View File

@ -1,14 +0,0 @@
// Copyright Benoit Blanchon 2014-2016
// MIT License
//
// Arduino JSON library
// https://github.com/bblanchon/ArduinoJson
// If you like this project, please add a star!
#include "../../include/ArduinoJson/Internals/Encoding.hpp"
// How to escape special chars:
// _escapeTable[2*i+1] => the special char
// _escapeTable[2*i] => the char to use instead
const char ArduinoJson::Internals::Encoding::_escapeTable[] =
"\"\"\\\\b\bf\fn\nr\rt\t";

View File

@ -1,30 +0,0 @@
// Copyright Benoit Blanchon 2014-2016
// MIT License
//
// Arduino JSON library
// https://github.com/bblanchon/ArduinoJson
// If you like this project, please add a star!
#include "../../include/ArduinoJson/Internals/IndentedPrint.hpp"
using namespace ArduinoJson::Internals;
size_t IndentedPrint::write(uint8_t c) {
size_t n = 0;
if (isNewLine) n += writeTabs();
n += sink->write(c);
isNewLine = c == '\n';
return n;
}
inline size_t IndentedPrint::writeTabs() {
size_t n = 0;
for (int i = 0; i < level * tabSize; i++) n += sink->write(' ');
return n;
}

View File

@ -1,50 +0,0 @@
// Copyright Benoit Blanchon 2014-2016
// MIT License
//
// Arduino JSON library
// https://github.com/bblanchon/ArduinoJson
// If you like this project, please add a star!
#include "../../include/ArduinoJson/Internals/List.hpp"
#include "../../include/ArduinoJson/JsonPair.hpp"
#include "../../include/ArduinoJson/JsonVariant.hpp"
using namespace ArduinoJson;
using namespace ArduinoJson::Internals;
template <typename T>
size_t List<T>::size() const {
size_t nodeCount = 0;
for (node_type *node = _firstNode; node; node = node->next) nodeCount++;
return nodeCount;
}
template <typename T>
typename List<T>::node_type *List<T>::addNewNode() {
node_type *newNode = new (_buffer) node_type();
if (_firstNode) {
node_type *lastNode = _firstNode;
while (lastNode->next) lastNode = lastNode->next;
lastNode->next = newNode;
} else {
_firstNode = newNode;
}
return newNode;
}
template <typename T>
void List<T>::removeNode(node_type *nodeToRemove) {
if (!nodeToRemove) return;
if (nodeToRemove == _firstNode) {
_firstNode = nodeToRemove->next;
} else {
for (node_type *node = _firstNode; node; node = node->next)
if (node->next == nodeToRemove) node->next = nodeToRemove->next;
}
}
template class ArduinoJson::Internals::List<JsonPair>;
template class ArduinoJson::Internals::List<JsonVariant>;

View File

@ -1,87 +0,0 @@
// Copyright Benoit Blanchon 2014-2016
// MIT License
//
// Arduino JSON library
// https://github.com/bblanchon/ArduinoJson
// If you like this project, please add a star!
#include "../../include/ArduinoJson/Internals/Prettyfier.hpp"
using namespace ArduinoJson::Internals;
size_t Prettyfier::write(uint8_t c) {
size_t n = _inString ? handleStringChar(c) : handleMarkupChar(c);
_previousChar = c;
return n;
}
inline size_t Prettyfier::handleStringChar(uint8_t c) {
bool isQuote = c == '"' && _previousChar != '\\';
if (isQuote) _inString = false;
return _sink.write(c);
}
inline size_t Prettyfier::handleMarkupChar(uint8_t c) {
switch (c) {
case '{':
case '[':
return handleBlockOpen(c);
case '}':
case ']':
return handleBlockClose(c);
case ':':
return handleColon();
case ',':
return handleComma();
case '"':
return handleQuoteOpen();
default:
return handleNormalChar(c);
}
}
inline size_t Prettyfier::handleBlockOpen(uint8_t c) {
return indentIfNeeded() + _sink.write(c);
}
inline size_t Prettyfier::handleBlockClose(uint8_t c) {
return unindentIfNeeded() + _sink.write(c);
}
inline size_t Prettyfier::handleColon() {
return _sink.write(':') + _sink.write(' ');
}
inline size_t Prettyfier::handleComma() {
return _sink.write(',') + _sink.println();
}
inline size_t Prettyfier::handleQuoteOpen() {
_inString = true;
return indentIfNeeded() + _sink.write('"');
}
inline size_t Prettyfier::handleNormalChar(uint8_t c) {
return indentIfNeeded() + _sink.write(c);
}
size_t Prettyfier::indentIfNeeded() {
if (!inEmptyBlock()) return 0;
_sink.indent();
return _sink.println();
}
size_t Prettyfier::unindentIfNeeded() {
if (inEmptyBlock()) return 0;
_sink.unindent();
return _sink.println();
}

View File

@ -1,18 +0,0 @@
// Copyright Benoit Blanchon 2014-2016
// MIT License
//
// Arduino JSON library
// https://github.com/bblanchon/ArduinoJson
// If you like this project, please add a star!
#include "../../include/ArduinoJson/Internals/StaticStringBuilder.hpp"
using namespace ArduinoJson::Internals;
size_t StaticStringBuilder::write(uint8_t c) {
if (length >= capacity) return 0;
buffer[length++] = c;
buffer[length] = '\0';
return 1;
}

View File

@ -1,40 +0,0 @@
// Copyright Benoit Blanchon 2014-2016
// MIT License
//
// Arduino JSON library
// https://github.com/bblanchon/ArduinoJson
// If you like this project, please add a star!
#include "../include/ArduinoJson/JsonArray.hpp"
#include "../include/ArduinoJson/JsonBuffer.hpp"
#include "../include/ArduinoJson/JsonObject.hpp"
using namespace ArduinoJson;
using namespace ArduinoJson::Internals;
JsonArray JsonArray::_invalid(NULL);
JsonArray::node_type *JsonArray::getNodeAt(size_t index) const {
node_type *node = _firstNode;
while (node && index--) node = node->next;
return node;
}
void JsonArray::removeAt(size_t index) { removeNode(getNodeAt(index)); }
void JsonArray::writeTo(JsonWriter &writer) const {
writer.beginArray();
const node_type *child = _firstNode;
while (child) {
child->content.writeTo(writer);
child = child->next;
if (!child) break;
writer.writeComma();
}
writer.endArray();
}

View File

@ -1,47 +0,0 @@
// Copyright Benoit Blanchon 2014-2016
// MIT License
//
// Arduino JSON library
// https://github.com/bblanchon/ArduinoJson
// If you like this project, please add a star!
#include "../include/ArduinoJson/JsonBuffer.hpp"
#include "../include/ArduinoJson/Internals/JsonParser.hpp"
#include "../include/ArduinoJson/JsonArray.hpp"
#include "../include/ArduinoJson/JsonObject.hpp"
using namespace ArduinoJson;
using namespace ArduinoJson::Internals;
JsonArray &JsonBuffer::createArray() {
JsonArray *ptr = new (this) JsonArray(this);
return ptr ? *ptr : JsonArray::invalid();
}
JsonObject &JsonBuffer::createObject() {
JsonObject *ptr = new (this) JsonObject(this);
return ptr ? *ptr : JsonObject::invalid();
}
JsonArray &JsonBuffer::parseArray(char *json, uint8_t nestingLimit) {
JsonParser parser(this, json, nestingLimit);
return parser.parseArray();
}
JsonObject &JsonBuffer::parseObject(char *json, uint8_t nestingLimit) {
JsonParser parser(this, json, nestingLimit);
return parser.parseObject();
}
JsonVariant JsonBuffer::parse(char *json, uint8_t nestingLimit) {
JsonParser parser(this, json, nestingLimit);
return parser.parseVariant();
}
char *JsonBuffer::strdup(const char *source, size_t length) {
size_t size = length + 1;
char *dest = static_cast<char *>(alloc(size));
if (dest != NULL) memcpy(dest, source, size);
return dest;
}

View File

@ -1,44 +0,0 @@
// Copyright Benoit Blanchon 2014-2016
// MIT License
//
// Arduino JSON library
// https://github.com/bblanchon/ArduinoJson
// If you like this project, please add a star!
#include "../include/ArduinoJson/JsonObject.hpp"
#include <string.h> // for strcmp
#include "../include/ArduinoJson/Internals/StaticStringBuilder.hpp"
#include "../include/ArduinoJson/JsonArray.hpp"
#include "../include/ArduinoJson/JsonBuffer.hpp"
using namespace ArduinoJson;
using namespace ArduinoJson::Internals;
JsonObject JsonObject::_invalid(NULL);
JsonObject::node_type *JsonObject::getNodeAt(const char *key) const {
for (node_type *node = _firstNode; node; node = node->next) {
if (!strcmp(node->content.key, key)) return node;
}
return NULL;
}
void JsonObject::writeTo(JsonWriter &writer) const {
writer.beginObject();
const node_type *node = _firstNode;
while (node) {
writer.writeString(node->content.key);
writer.writeColon();
node->content.value.writeTo(writer);
node = node->next;
if (!node) break;
writer.writeComma();
}
writer.endObject();
}

View File

@ -1,125 +0,0 @@
// Copyright Benoit Blanchon 2014-2016
// MIT License
//
// Arduino JSON library
// https://github.com/bblanchon/ArduinoJson
// If you like this project, please add a star!
#include "../include/ArduinoJson/JsonVariant.hpp"
#include "../include/ArduinoJson/JsonArray.hpp"
#include "../include/ArduinoJson/JsonObject.hpp"
#include <errno.h> // for errno
#include <stdlib.h> // for strtol, strtod
using namespace ArduinoJson::Internals;
namespace ArduinoJson {
const char *JsonVariant::asString() const {
if (_type == JSON_UNPARSED && _content.asString &&
!strcmp("null", _content.asString))
return NULL;
if (_type == JSON_STRING || _type == JSON_UNPARSED) return _content.asString;
return NULL;
}
JsonFloat JsonVariant::asFloat() const {
switch (_type) {
case JSON_UNDEFINED:
return 0;
case JSON_POSITIVE_INTEGER:
case JSON_BOOLEAN:
return static_cast<JsonFloat>(_content.asInteger);
case JSON_NEGATIVE_INTEGER:
return -static_cast<JsonFloat>(_content.asInteger);
case JSON_STRING:
case JSON_UNPARSED:
return _content.asString ? parse<JsonFloat>(_content.asString) : 0;
default:
return _content.asFloat;
}
}
String JsonVariant::toString() const {
String s;
if ((_type == JSON_STRING || _type == JSON_UNPARSED) &&
_content.asString != NULL)
s = _content.asString;
else
printTo(s);
return s;
}
bool JsonVariant::isBoolean() const {
if (_type == JSON_BOOLEAN) return true;
if (_type != JSON_UNPARSED || _content.asString == NULL) return false;
return !strcmp(_content.asString, "true") ||
!strcmp(_content.asString, "false");
}
bool JsonVariant::isInteger() const {
if (_type == JSON_POSITIVE_INTEGER || _type == JSON_NEGATIVE_INTEGER)
return true;
if (_type != JSON_UNPARSED || _content.asString == NULL) return false;
char *end;
errno = 0;
strtol(_content.asString, &end, 10);
return *end == '\0' && errno == 0;
}
bool JsonVariant::isFloat() const {
if (_type >= JSON_FLOAT_0_DECIMALS) return true;
if (_type != JSON_UNPARSED || _content.asString == NULL) return false;
char *end;
errno = 0;
strtod(_content.asString, &end);
return *end == '\0' && errno == 0 && !is<long>();
}
void JsonVariant::writeTo(JsonWriter &writer) const {
switch (_type) {
case JSON_UNDEFINED:
return;
case JSON_ARRAY:
_content.asArray->writeTo(writer);
return;
case JSON_OBJECT:
_content.asObject->writeTo(writer);
return;
case JSON_STRING:
writer.writeString(_content.asString);
return;
case JSON_UNPARSED:
writer.writeRaw(_content.asString);
return;
case JSON_NEGATIVE_INTEGER:
writer.writeRaw('-');
case JSON_POSITIVE_INTEGER:
writer.writeInteger(_content.asInteger);
return;
case JSON_BOOLEAN:
writer.writeBoolean(_content.asInteger != 0);
return;
default:
uint8_t decimals = static_cast<uint8_t>(_type - JSON_FLOAT_0_DECIMALS);
writer.writeFloat(_content.asFloat, decimals);
}
}
}

View File

@ -5,31 +5,69 @@
# https://github.com/bblanchon/ArduinoJson # https://github.com/bblanchon/ArduinoJson
# If you like this project, please add a star! # If you like this project, please add a star!
set(GTEST_DIR ../third-party/gtest-1.7.0) include(gtest.cmake)
file(GLOB TESTS_FILES *.hpp *.cpp) file(GLOB TESTS_FILES *.hpp *.cpp)
include_directories( if(CMAKE_CXX_COMPILER_ID MATCHES "(GNU|Clang)")
${GTEST_DIR} add_compile_options(
${GTEST_DIR}/include) -fno-exceptions
-fno-rtti
add_definitions(-DGTEST_HAS_PTHREAD=0) -pedantic
-Wall
# Workaround for Visual Studio 2012 -Wcast-align
if (MSVC AND MSVC_VERSION EQUAL 1700) -Wcast-qual
add_definitions(-D_VARIADIC_MAX=10) -Wconversion
-Wctor-dtor-privacy
-Wdisabled-optimization
-Werror
-Wextra
-Wformat=2
-Winit-self
-Wmissing-include-dirs
-Wno-parentheses
-Wno-sign-conversion
-Wno-unused
-Wno-variadic-macros
-Wnon-virtual-dtor
-Wold-style-cast
-Woverloaded-virtual
-Wredundant-decls
-Wshadow
-Wsign-promo
-Wstrict-overflow=5
-Wundef
)
endif() endif()
if (MSVC) if(CMAKE_CXX_COMPILER_ID MATCHES "GNU")
add_compile_options(
-Wstrict-null-sentinel
)
if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 4.5)
add_compile_options(-Wlogical-op) # the flag exists in 4.4 but is buggy
endif()
if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 4.6)
add_compile_options(-Wnoexcept)
endif()
endif()
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
add_compile_options(
-Wc++11-compat
-Wdeprecated-register
)
endif()
if(MSVC)
add_definitions(-D_CRT_SECURE_NO_WARNINGS) add_definitions(-D_CRT_SECURE_NO_WARNINGS)
add_compile_options(-W4)
endif() endif()
add_executable(ArduinoJsonTests add_executable(ArduinoJsonTests ${TESTS_FILES})
${TESTS_FILES} target_include_directories(ArduinoJsonTests PRIVATE ${CMAKE_CURRENT_LIST_DIR}/../include)
${GTEST_DIR}/src/gtest-all.cc target_link_libraries(ArduinoJsonTests gtest)
${GTEST_DIR}/src/gtest_main.cc)
target_link_libraries(ArduinoJsonTests ArduinoJson)
add_test(ArduinoJsonTests ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/ArduinoJsonTests) add_test(ArduinoJsonTests ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/ArduinoJsonTests)

View File

@ -6,11 +6,7 @@
// If you like this project, please add a star! // If you like this project, please add a star!
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <ArduinoJson.h>
#define protected public
#include <ArduinoJson/DynamicJsonBuffer.hpp>
using namespace ArduinoJson;
class DynamicJsonBuffer_Basic_Tests : public testing::Test { class DynamicJsonBuffer_Basic_Tests : public testing::Test {
protected: protected:

View File

@ -44,7 +44,7 @@ TEST(JsonArray_CopyTo_Tests, TwoOneDimensionIntegerArray) {
DynamicJsonBuffer jsonBuffer; DynamicJsonBuffer jsonBuffer;
JsonArray& array = jsonBuffer.parseArray(json); JsonArray& array = jsonBuffer.parseArray(json);
int destination[3][2] = {0}; int destination[3][2] = {{0}};
array.copyTo(destination); array.copyTo(destination);
ASSERT_EQ(1, destination[0][0]); ASSERT_EQ(1, destination[0][0]);

View File

@ -6,9 +6,7 @@
// If you like this project, please add a star! // If you like this project, please add a star!
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <ArduinoJson/JsonVariant.hpp> #include <ArduinoJson.h>
using namespace ArduinoJson;
class JsonVariant_Comparison_Tests : public ::testing::Test { class JsonVariant_Comparison_Tests : public ::testing::Test {
protected: protected:

View File

@ -6,11 +6,7 @@
// If you like this project, please add a star! // If you like this project, please add a star!
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <ArduinoJson.h>
#define protected public
#include <ArduinoJson/StaticJsonBuffer.hpp>
using namespace ArduinoJson;
class StaticJsonBuffer_Basic_Tests : public testing::Test { class StaticJsonBuffer_Basic_Tests : public testing::Test {
protected: protected:

View File

@ -10,9 +10,13 @@
class StaticJsonBuffer_ParseArray_Tests : public testing::Test { class StaticJsonBuffer_ParseArray_Tests : public testing::Test {
protected: protected:
void with(JsonBuffer& jsonBuffer) { _jsonBuffer = &jsonBuffer; } void with(JsonBuffer& jsonBuffer) {
_jsonBuffer = &jsonBuffer;
}
void whenInputIs(const char* json) { strcpy(_jsonString, json); } void whenInputIs(const char* json) {
strcpy(_jsonString, json);
}
void parseMustSucceed() { void parseMustSucceed() {
EXPECT_TRUE(_jsonBuffer->parseArray(_jsonString).success()); EXPECT_TRUE(_jsonBuffer->parseArray(_jsonString).success());
@ -73,9 +77,12 @@ TEST_F(StaticJsonBuffer_ParseArray_Tests,
} }
TEST_F(StaticJsonBuffer_ParseArray_Tests, CharPtrNull) { TEST_F(StaticJsonBuffer_ParseArray_Tests, CharPtrNull) {
ASSERT_FALSE(StaticJsonBuffer<100>().parseArray((char*)0).success()); ASSERT_FALSE(
StaticJsonBuffer<100>().parseArray(static_cast<char*>(0)).success());
} }
TEST_F(StaticJsonBuffer_ParseArray_Tests, ConstCharPtrNull) { TEST_F(StaticJsonBuffer_ParseArray_Tests, ConstCharPtrNull) {
ASSERT_FALSE(StaticJsonBuffer<100>().parseArray((const char*)0).success()); ASSERT_FALSE(StaticJsonBuffer<100>()
.parseArray(static_cast<const char*>(0))
.success());
} }

View File

@ -10,9 +10,13 @@
class StaticJsonBuffer_ParseObject_Tests : public testing::Test { class StaticJsonBuffer_ParseObject_Tests : public testing::Test {
protected: protected:
void with(JsonBuffer& jsonBuffer) { _jsonBuffer = &jsonBuffer; } void with(JsonBuffer& jsonBuffer) {
_jsonBuffer = &jsonBuffer;
}
void whenInputIs(const char* json) { strcpy(_jsonString, json); } void whenInputIs(const char* json) {
strcpy(_jsonString, json);
}
void parseMustSucceed() { void parseMustSucceed() {
EXPECT_TRUE(_jsonBuffer->parseObject(_jsonString).success()); EXPECT_TRUE(_jsonBuffer->parseObject(_jsonString).success());
@ -74,9 +78,12 @@ TEST_F(StaticJsonBuffer_ParseObject_Tests,
} }
TEST_F(StaticJsonBuffer_ParseObject_Tests, CharPtrNull) { TEST_F(StaticJsonBuffer_ParseObject_Tests, CharPtrNull) {
ASSERT_FALSE(StaticJsonBuffer<100>().parseObject((char*)0).success()); ASSERT_FALSE(
StaticJsonBuffer<100>().parseObject(static_cast<char*>(0)).success());
} }
TEST_F(StaticJsonBuffer_ParseObject_Tests, ConstCharPtrNull) { TEST_F(StaticJsonBuffer_ParseObject_Tests, ConstCharPtrNull) {
ASSERT_FALSE(StaticJsonBuffer<100>().parseObject((const char*)0).success()); ASSERT_FALSE(StaticJsonBuffer<100>()
.parseObject(static_cast<const char*>(0))
.success());
} }

24
test/gtest.cmake Normal file
View File

@ -0,0 +1,24 @@
set(GTEST_DIR ../third-party/gtest-1.7.0)
add_library(gtest
${GTEST_DIR}/src/gtest-all.cc
${GTEST_DIR}/src/gtest_main.cc
)
target_include_directories(gtest
PUBLIC
${GTEST_DIR}
${GTEST_DIR}/include
)
target_compile_definitions(gtest PUBLIC -DGTEST_HAS_PTHREAD=0)
if (MSVC)
if (MSVC_VERSION EQUAL 1700)
# Workaround for Visual Studio 2012
target_compile_definitions(gtest PUBLIC -D_VARIADIC_MAX=10)
endif()
target_compile_definitions(gtest PUBLIC -D_CRT_SECURE_NO_WARNINGS)
endif()

View File

@ -1,3 +1,8 @@
// clang-format off
#ifdef __GNUC__
#pragma GCC system_header
#endif
// This file was GENERATED by command: // This file was GENERATED by command:
// pump.py gtest-param-test.h.pump // pump.py gtest-param-test.h.pump
// DO NOT EDIT BY HAND!!! // DO NOT EDIT BY HAND!!!

View File

@ -1,3 +1,8 @@
// clang-format off
#ifdef __GNUC__
#pragma GCC system_header
#endif
// Copyright 2005, Google Inc. // Copyright 2005, Google Inc.
// All rights reserved. // All rights reserved.
// //

View File

@ -1,3 +1,8 @@
// clang-format off
#ifdef __GNUC__
#pragma GCC system_header
#endif
// Copyright 2005, Google Inc. // Copyright 2005, Google Inc.
// All rights reserved. // All rights reserved.
// //

View File

@ -1,3 +1,8 @@
// clang-format off
#ifdef __GNUC__
#pragma GCC system_header
#endif
// Copyright 2005, Google Inc. // Copyright 2005, Google Inc.
// All rights reserved. // All rights reserved.
// //