[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 isdouble
(the default in non-Arduino platforms) orfloat
(the default on Arduino platforms).ARDUINOJSON_USE_LONG_LONG
determines if the storage of integral values islong long
(the default in non-Arduino platforms) orlong
(the default on Arduino platforms).ARDUINOJSON_ENABLE_STD_STREAM
allows to printJsonArray
s andJsonObject
s tostd::cout
ARDUINOJSON_ENABLE_ALIGNMENT
forcesStaticJsonBuffer
andDynamicJsonBuffer
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:
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
- ArduinoJson on GitHub
- ArduinoJson documentation
- Announcement of v5.0, in September 2015
- Announcement of ArduinoJson 4.0, in November 2014
- Announcement of ArduinoJson 3.0, in July 2014
- Announcement of ArduinoJson 2.0, in July 2014
- Announcement of ArduinoJson 1.0, in January 2014
- Wikipedia: Substitution failure is not an error (SFINAE)
- “Metaprogramming in C++”, by Johannes Koskinen