[Arduino] JSON library 5.1

I recently released a new version of ArduinoJson, my JSON library for embedded platforms.

ArduinoJson is built around two concepts: fixed memory allocation and zero copy. I originally wrote this library two years ago to run on an Arduino Duemilanove with only 2KB of RAM. As far as I know, there is no other library that can do that properly.

What’s new?

  • Support for long long

Yep. That’s it.

This is a very small improvement, but required a lot of effort in refactoring. I know very few people will be interested in this, but I needed it for a project and I knew it would force me to make the code more generic.

Template meta-programming

Up to now, I’ve been restraining myself from using template meta-programming techniques (TMP) in ArduinoJson because I wanted the code to be easy to understand, even for a novice in C++.

But that was mainly because, at that time, the documentation of ArduinoJson was very poor. Now it’s far for being complete, but it improved a lot. In particular, the API reference was missing and is now almost complete.

So why using TMP now? Simply because I allows me to remove a lot of duplication. Here is a simple example:

In ArduinoJson 5.0:

bool add(bool value);
bool add(signed char value);
bool add(signed long value);
bool add(signed int value);
bool add(signed short value);
bool add(unsigned char value);
bool add(unsigned long value);
bool add(unsigned int value);
bool add(unsigned short value);
bool add(float value);
bool add(double value);
bool add(const char* value);

now becomes, in ArduinoJson 5.1:

template <typename T>
bool add(T value,
    typename EnableIf<CanSet<T>::value>::type* = 0);

If it’s the first time that you’re in contact with TMP, this code snippet is probably hurting you badly. It uses a C++ rule called SFINAE, which says that the compiler will not issue an error if the template argument substitution fails. In this case EnableIf<>::type will be void if CanSet<T>::value is true, otherwise it will be undefined, leading to a substitution failure which is not an error. In the end, this declaration allows me to declare a template method that will be available only on certain types, those allowed by CanSet.

So it should be clear now why I waited to have a comprehensive documentation before using TMP in ArduinoJson. Also you should see why I needed TMP to add yet another integral type: adding long long and unsigned long long would have forced me to add more overloads, but thanks to TMP, I just needed to change the result of the meta function CanSet<>.

Don’t worry, this doesn’t affect the user code.

Configuration of the library

Of course, not everybody is going to use long long in their program. First it’s a C++11 feature, and second it takes 64 bits which is not an option on 8-bit MCU.

So there are a bunch of preprocessor symbols that can be used to enable and disable features of the library. They are all defined in the ArduinoJson/Configuration.hpp, but here is a summary:

  • ARDUINOJSON_USE_DOUBLE determines if the storage of floating point values is double (the default in non-Arduino platforms) or float (the default on Arduino platforms).
  • ARDUINOJSON_USE_LONG_LONG determines if the storage of integral values is long long (the default in non-Arduino platforms) or long (the default on Arduino platforms).
  • ARDUINOJSON_ENABLE_STD_STREAM allows to print JsonArrays and JsonObjects to std::cout
  • ARDUINOJSON_ENABLE_ALIGNMENT forces StaticJsonBuffer and DynamicJsonBuffer to return pointers aligned on CPU words (this is the default for most platforms).

Code size

As with previous versions, a crazy level of attention has been taken to keep the code small. I’m glad to announce that the example JsonParserExample.ino lost 40 bytes! This is mostly due to a better inlining from the compiler, as I moved more code in the headers.

Here is an updated chart of the code size of ArduinoJson:

Evolution of the size of samples programs

The orange line and blue lines are the size of the JSON generator and parser. See this previous article for details on this chart.

Next evolutions

The next big change will be to make ArduinoJson a header only library. This will make the library easier to include in all projects (ie not just Arduino and CMake) and will stop the proliferation of the ArduinoJson.h files in the source tree. This is planned for version 6.0.

But before that, I need to fix issue #170: currently ArduinoJson stores all integral values into long (or long long, as we saw above), therefore when you set a JsonVariant to an big unsigned long value, it will be printed as a negative value. This is planned for version 5.2 and will sadly make the code a little bigger.

See also