diff --git a/platformio.ini b/platformio.ini index bc25fa70ce..dc6528b5f3 100644 --- a/platformio.ini +++ b/platformio.ini @@ -234,7 +234,7 @@ monitor_speed = 115200 upload_speed = 115200 # fast upload speed (remove ';' when building for development use) ; upload_speed = 921600 - +lib_ldf_mode = chain+ # ------------------------------------------------------------------------------ # LIBRARIES: required dependencies # Please note that we don't always use the latest version of a library. @@ -252,6 +252,7 @@ lib_deps = ;;https://github.com/Aircoookie/ESPAsyncWebServer.git @ ~2.0.7 ;; https://github.com/lost-hope/ESPAsyncWebServer.git#master ;; WLEDMM to display .log and .wled files in /edit https://github.com/Aircoookie/ESPAsyncWebServer.git#v2.2.1 ;; newer with bugfixes and stability improvements + https://github.com/bblanchon/ArduinoJson.git#v6.21.4 #For use of the TTGO T-Display ESP32 Module with integrated TFT display uncomment the following line #TFT_eSPI #For compatible OLED display uncomment following @@ -1081,6 +1082,10 @@ HUB75_build_flags = HUB75_lib_deps = https://github.com/softhack007/ESP32-HUB75-MatrixPanel-DMA_sh7.git#fix_dangling_pointer ;; S3 bugfix for crash in ~MatrixPanel_I2S_DMA() HUB75_lib_ignore = ESP32 HUB75 LED MATRIX PANEL DMA Display ;; to remove the HUB75 lib dependancy (saves a few bytes) +Spotify_lib_deps = + https://github.com/witnessmenow/spotify-api-arduino.git#872e5c3 +Spotify_build_flags = -D USERMOD_SPOTIFY + NetDebug_build_flags = ;; WLEDMM: only setting WLED_DEBUG_HOST is enough, ip and port can be defined in sync settings as well -D WLED_DEBUG_HOST='"192.168.x.x"' ;; to send debug messages over network to host 192.168.x.y - FQDN is also possible @@ -1099,10 +1104,12 @@ build_flags_S = ; -D USERMOD_ARTIFX ;; WLEDMM usermod - temporarily moved into "_M", due to problems in "_S" when compiling with -O2 -D WLEDMM_FASTPATH ;; WLEDMM experimental option. Reduces audio lag (latency), and allows for faster LED framerates. May break compatibility with previous versions. ; -D WLED_DEBUG_HEAP ;; WLEDMM enable heap debugging + ${common_mm.Spotify_build_flags} lib_deps_S = ;; https://github.com/kosme/arduinoFFT#develop @ 1.9.2+sha.419d7b0 ;; used for USERMOD_AUDIOREACTIVE - using "known working" hash ${common_mm.AR_lib_deps} ;; used for USERMOD_AUDIOREACTIVE - optimized version, 10% faster on -S2/-C3 + ${common_mm.Spotify_lib_deps} build_flags_M = -D USERMOD_ARTIFX ; WLEDMM usermod - temporarily moved into "_M", due to problems in "_S" when compiling with -O2 diff --git a/usermods/Spotify/usermod_spotify.h b/usermods/Spotify/usermod_spotify.h new file mode 100644 index 0000000000..24b684e2c0 --- /dev/null +++ b/usermods/Spotify/usermod_spotify.h @@ -0,0 +1,391 @@ +#pragma once + +#include "wled.h" + +#include +#include + +#include + + +/* +Fetch now playing data from Spotify +*/ +WiFiClientSecure client; +SpotifyArduino spotify(client, "", "", ""); + +void printCurrentlyPlayingToSerial(CurrentlyPlaying currentlyPlaying) +{ + // Use the details in this method or if you want to store them + // make sure you copy them (using something like strncpy) + // const char* artist = + + USER_PRINTLN("--------- Currently Playing ---------"); + + USER_PRINT("Is Playing: "); + if (currentlyPlaying.isPlaying) + { + USER_PRINTLN("Yes"); + } + else + { + USER_PRINTLN("No"); + } + + USER_PRINT("Track: "); + USER_PRINTLN(currentlyPlaying.trackName); + USER_PRINT("Track URI: "); + USER_PRINTLN(currentlyPlaying.trackUri); + USER_PRINTLN(); + + USER_PRINTLN("Artists: "); + for (int i = 0; i < currentlyPlaying.numArtists; i++) + { + USER_PRINT("Name: "); + USER_PRINTLN(currentlyPlaying.artists[i].artistName); + USER_PRINT("Artist URI: "); + USER_PRINTLN(currentlyPlaying.artists[i].artistUri); + USER_PRINTLN(); + } + + USER_PRINT("Album: "); + USER_PRINTLN(currentlyPlaying.albumName); + USER_PRINT("Album URI: "); + USER_PRINTLN(currentlyPlaying.albumUri); + USER_PRINTLN(); + + if (currentlyPlaying.contextUri != NULL) + { + USER_PRINT("Context URI: "); + USER_PRINTLN(currentlyPlaying.contextUri); + USER_PRINTLN(); + } + + long progress = currentlyPlaying.progressMs; // duration passed in the song + long duration = currentlyPlaying.durationMs; // Length of Song + USER_PRINT("Elapsed time of song (ms): "); + USER_PRINT(progress); + USER_PRINT(" of "); + USER_PRINTLN(duration); + USER_PRINTLN(); + + float percentage = ((float)progress / (float)duration) * 100; + int clampedPercentage = (int)percentage; + USER_PRINT("<"); + for (int j = 0; j < 50; j++) + { + if (clampedPercentage >= (j * 2)) + { + USER_PRINT("="); + } + else + { + USER_PRINT("-"); + } + } + USER_PRINTLN(">"); + USER_PRINTLN(); + + // will be in order of widest to narrowest + // currentlyPlaying.numImages is the number of images that + // are stored + for (int i = 0; i < currentlyPlaying.numImages; i++) + { + USER_PRINTLN("------------------------"); + USER_PRINT("Album Image: "); + USER_PRINTLN(currentlyPlaying.albumImages[i].url); + USER_PRINT("Dimensions: "); + USER_PRINT(currentlyPlaying.albumImages[i].width); + USER_PRINT(" x "); + USER_PRINT(currentlyPlaying.albumImages[i].height); + USER_PRINTLN(); + } + USER_PRINTLN("------------------------"); +} + +class SpotifyUsermod : public Usermod { + + private: + + // Private class members. You can declare variables and functions only accessible to your usermod here + + String clientId = ""; + String clientSecret = ""; + String refreshToken = ""; + + + // any private methods should go here (non-inline method should be defined out of class) + void publishMqtt(const char* state, bool retain = false); // example for publishing MQTT message + + const char *loginLinkTemplate = "Login"; + const char *scope = "user-read-playback-state"; + + + unsigned long delayBetweenRequests = 10000; // Time between requests (1 minute) + unsigned long requestDueTime = 0; //time when request due + + + public: + + SpotifyUsermod(bool enabled):Usermod("Spotify", enabled) {} //WLEDMM + + + // methods called by WLED (can be inlined as they are called only once but if you call them explicitly define them out of class) + + /* + * setup() is called once at boot. WiFi is not yet connected at this point. + * readFromConfig() is called prior to setup() + * You can use it to initialize variables, sensors or similar. + */ + void setup() { + spotify.setRefreshToken(refreshToken.c_str()); + initDone = true; + } + + + /* + * connected() is called every time the WiFi is (re)connected + * Use it to initialize network interfaces + */ + void connected() { + if (!enabled) return; + USER_PRINTLN("Connected to WiFi!"); + client.setCACert(spotify_server_cert); + initDone = true; + const char *refreshToken = NULL; + String callbackURI = "http://" + WiFi.localIP().toString() + "/settings/um?um=Spotify"; + if(false) { + // if(strcmp(refreshToken.c_str(), "") == 0) { + USER_PRINTLN("Fetch refresh token"); + refreshToken = spotify.requestAccessTokens("AQBhcQ4OCmawSPENF8ZWizBRjE9vawQvrOnpsZzzOy3NdsK37WrqyZSSBRK2toNCABH1AIPcXZSVK3H-ya77wS_bEcd85nX1XDYPFVKEEzIzy4klRqfg8RtCyR14a2xTY1ya7I_mmpJBvOb9ZEL0tfT97QNQu3_K8-XaBAPMxEfkAMyJYE_HTVn37I6Q5FIFDL5MmHHZvj3nV7C_u9aqd9dWASGLyv3tWhwi", callbackURI.c_str()); + spotify.setRefreshToken(refreshToken); + } + + USER_PRINTLN("Refreshing Access Tokens"); + if (!spotify.refreshAccessToken()) { + USER_PRINTLN("Failed to get access tokens"); + } + USER_PRINTLN("SpotifyUsermod::connected completed"); + } + + + /* + * loop() is called continuously. Here you can check for events, read sensors, etc. + */ + void loop() { + // if usermod is disabled or called during strip updating just exit + // NOTE: on very long strips strip.isUpdating() may always return true so update accordingly + if (!enabled || strip.isUpdating()) return; + + // do your magic here + if (millis() - lastTime > 1000) { + // USER_PRINTLN("I'm alive!"); + lastTime = millis(); + if (millis() > requestDueTime) + { + USER_PRINT("Free Heap: "); + USER_PRINTLN(ESP.getFreeHeap()); + + USER_PRINTLN("getting currently playing song:"); + // Market can be excluded if you want e.g. spotify.getCurrentlyPlaying() + int status = spotify.getCurrentlyPlaying(printCurrentlyPlayingToSerial, "GB"); + if (status == 200){ + USER_PRINTLN("Successfully got currently playing"); + } + else if (status == 204) { + USER_PRINTLN("Doesn't seem to be anything playing"); + } + else { + USER_PRINT("Error: "); + USER_PRINTLN(status); + } + requestDueTime = millis() + delayBetweenRequests; + } + } + } + + + /* + * addToJsonInfo() can be used to add custom entries to the /json/info part of the JSON API. + * Creating an "u" object allows you to add custom key/value pairs to the Info section of the WLED web UI. + * Below it is shown how this could be used for e.g. a light sensor + */ + void addToJsonInfo(JsonObject& root) + { + // if "u" object does not exist yet wee need to create it + JsonObject user = root["u"]; + if (user.isNull()) user = root.createNestedObject("u"); + + //this code adds "u":{"ExampleUsermod":[20," lux"]} to the info object + //int reading = 20; + //JsonArray lightArr = user.createNestedArray(FPSTR(_name))); //name + //lightArr.add(reading); //value + //lightArr.add(F(" lux")); //unit + + // if you are implementing a sensor usermod, you may publish sensor data + //JsonObject sensor = root[F("sensor")]; + //if (sensor.isNull()) sensor = root.createNestedObject(F("sensor")); + //temp = sensor.createNestedArray(F("light")); + //temp.add(reading); + //temp.add(F("lux")); + } + + + /* + * addToJsonState() can be used to add custom entries to the /json/state part of the JSON API (state object). + * Values in the state object may be modified by connected clients + */ + void addToJsonState(JsonObject& root) + { + if (!initDone || !enabled) return; // prevent crash on boot applyPreset() + + JsonObject usermod = root[FPSTR(_name)]; + if (usermod.isNull()) usermod = root.createNestedObject(FPSTR(_name)); + + usermod["refreshToken"] = refreshToken; + } + + + /* + * readFromJsonState() can be used to receive data clients send to the /json/state part of the JSON API (state object). + * Values in the state object may be modified by connected clients + */ + void readFromJsonState(JsonObject& root) + { + if (!initDone) return; // prevent crash on boot applyPreset() + + JsonObject usermod = root[FPSTR(_name)]; + if (!usermod.isNull()) { + // expect JSON usermod data in usermod name object: {"ExampleUsermod:{"user0":10}"} + refreshToken = usermod["refreshToken"] | refreshToken; //if "refreshToken" key exists in JSON, update, else keep old value + } + // you can as well check WLED state JSON keys + //if (root["bri"] == 255) Serial.println(F("Don't burn down your garage!")); + } + + + /* + * addToConfig() can be used to add custom persistent settings to the cfg.json file in the "um" (usermod) object. + * It will be called by WLED when settings are actually saved (for example, LED settings are saved) + * If you want to force saving the current state, use serializeConfig() in your loop(). + * + * CAUTION: serializeConfig() will initiate a filesystem write operation. + * It might cause the LEDs to stutter and will cause flash wear if called too often. + * Use it sparingly and always in the loop, never in network callbacks! + * + * addToConfig() will make your settings editable through the Usermod Settings page automatically. + * + */ + void addToConfig(JsonObject& root) + { + Usermod::addToConfig(root); JsonObject top = root[FPSTR(_name)]; //WLEDMM + top["refreshToken"] = refreshToken; + top["code"] = "example3"; + } + + + /* + * readFromConfig() can be used to read back the custom settings you added with addToConfig(). + * This is called by WLED when settings are loaded (currently this only happens immediately after boot, or after saving on the Usermod Settings page) + * + * readFromConfig() is called BEFORE setup(). This means you can use your persistent values in setup() (e.g. pin assignments, buffer sizes), + * but also that if you want to write persistent values to a dynamic buffer, you'd need to allocate it here instead of in setup. + * If you don't know what that is, don't fret. It most likely doesn't affect your use case :) + * + * Return true in case the config values returned from Usermod Settings were complete, or false if you'd like WLED to save your defaults to disk (so any missing values are editable in Usermod Settings) + * + * getJsonValue() returns false if the value is missing, or copies the value into the variable provided and returns true if the value is present + * The configComplete variable is true only if the "exampleUsermod" object and all values are present. If any values are missing, WLED will know to call addToConfig() to save them + * + * This function is guaranteed to be called on boot, but could also be called every time settings are updated + */ + bool readFromConfig(JsonObject& root) + { + // default settings values could be set here (or below using the 3-argument getJsonValue()) instead of in the class definition or constructor + // setting them inside readFromConfig() is slightly more robust, handling the rare but plausible use case of single value being missing after boot (e.g. if the cfg.json was manually edited and a value was removed) + + bool configComplete = Usermod::readFromConfig(root);JsonObject top = root[FPSTR(_name)]; //WLEDMM + + configComplete &= getJsonValue(top["refreshToken"], refreshToken); + + return configComplete; + } + + + /* + * appendConfigData() is called when user enters usermod settings page + * it may add additional metadata for certain entry fields (adding drop down is possible) + * be careful not to add too much as oappend() buffer is limited to 3k + */ + void appendConfigData() + { + char populatedLoginLink[800]; + String callbackURI = "http://" + WiFi.localIP().toString() + "/settings/um?um=Spotify"; + sprintf(populatedLoginLink, loginLinkTemplate, clientId.c_str(), callbackURI.c_str(), scope); + oappend(SET_F("addInfo('")); oappend(String(FPSTR(_name)).c_str()); oappend(SET_F(":refreshToken")); oappend(SET_F("',1,'")); oappend(populatedLoginLink);oappend("');"); + } + + +#ifndef WLED_DISABLE_MQTT + /** + * handling of MQTT message + * topic only contains stripped topic (part after /wled/MAC) + */ + bool onMqttMessage(char* topic, char* payload) { + // check if we received a command + //if (strlen(topic) == 8 && strncmp_P(topic, PSTR("/command"), 8) == 0) { + // String action = payload; + // if (action == "on") { + // enabled = true; + // return true; + // } else if (action == "off") { + // enabled = false; + // return true; + // } else if (action == "toggle") { + // enabled = !enabled; + // return true; + // } + //} + return false; + } + + /** + * onMqttConnect() is called when MQTT connection is established + */ + void onMqttConnect(bool sessionPresent) { + // do any MQTT related initialisation here + //publishMqtt("I am alive!"); + } +#endif + + /* + * getId() allows you to optionally give your V2 usermod an unique ID (please define it in const.h!). + * This could be used in the future for the system to determine whether your usermod is installed. + */ + uint16_t getId() + { + return USERMOD_ID_SPOTIFY; + } + + //More methods can be added in the future, this example will then be extended. + //Your usermod will remain compatible as it does not need to implement all methods from the Usermod base class! +}; + + +// add more strings here to reduce flash memory usage + + +// implementation of non-inline member methods + +void SpotifyUsermod::publishMqtt(const char* state, bool retain) +{ +#ifndef WLED_DISABLE_MQTT + //Check if MQTT Connected, otherwise it will crash the 8266 + if (WLED_MQTT_CONNECTED) { + char subuf[64]; + strcpy(subuf, mqttDeviceTopic); + strcat_P(subuf, PSTR("/example")); + mqtt->publish(subuf, 0, retain, state); + } +#endif +} diff --git a/wled00/const.h b/wled00/const.h index 4cf783044b..89889d7362 100644 --- a/wled00/const.h +++ b/wled00/const.h @@ -143,6 +143,7 @@ #define USERMOD_ID_GAMES 92 //Usermod "usermod_v2_games.h" #define USERMOD_ID_ANIMARTRIX 93 //Usermod "usermod_v2_animartrix.h" #define USERMOD_ID_AUTOPLAYLIST 94 // Usermod usermod_v2_auto_playlist.h +#define USERMOD_ID_SPOTIFY 95 // Usermod usermod_spotify.h #define USERMOD_ID_241RINGS 101 //Usermod "usermod_v2_241_rings.h" diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index a2f1bf29a3..b478f161d8 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -140,7 +140,7 @@ void handleIR(); //json.cpp #include "ESPAsyncWebServer.h" -#include "src/dependencies/json/ArduinoJson-v6.h" +#include #include "src/dependencies/json/AsyncJson-v6.h" #include "FX.h" diff --git a/wled00/src/dependencies/json/ArduinoJson-v6.h b/wled00/src/dependencies/json/ArduinoJson-v6.h deleted file mode 100644 index 6b79d7a2aa..0000000000 --- a/wled00/src/dependencies/json/ArduinoJson-v6.h +++ /dev/null @@ -1,7339 +0,0 @@ -// ArduinoJson - https://arduinojson.org -// Copyright Benoit Blanchon 2014-2021 -// MIT License - -#pragma once - -#ifdef __cplusplus - -#if __cplusplus >= 201103L -# define ARDUINOJSON_HAS_LONG_LONG 1 -# define ARDUINOJSON_HAS_RVALUE_REFERENCES 1 -#else -# define ARDUINOJSON_HAS_LONG_LONG 0 -# define ARDUINOJSON_HAS_RVALUE_REFERENCES 0 -#endif -#ifndef ARDUINOJSON_HAS_NULLPTR -# if __cplusplus >= 201103L -# define ARDUINOJSON_HAS_NULLPTR 1 -# else -# define ARDUINOJSON_HAS_NULLPTR 0 -# endif -#endif -#if defined(_MSC_VER) && !ARDUINOJSON_HAS_LONG_LONG -# define ARDUINOJSON_HAS_INT64 1 -#else -# define ARDUINOJSON_HAS_INT64 0 -#endif -#ifndef ARDUINOJSON_EMBEDDED_MODE -# if defined(ARDUINO) /* Arduino*/ \ - || defined(__IAR_SYSTEMS_ICC__) /* IAR Embedded Workbench */ \ - || defined(__XC) /* MPLAB XC compiler */ \ - || defined(__ARMCC_VERSION) /* Keil ARM Compiler */ \ - || defined(__AVR) /* Atmel AVR8/GNU C Compiler */ -# define ARDUINOJSON_EMBEDDED_MODE 1 -# else -# define ARDUINOJSON_EMBEDDED_MODE 0 -# endif -#endif -#if !defined(ARDUINOJSON_ENABLE_STD_STREAM) && defined(__has_include) -# if __has_include() && \ - __has_include() && \ - !defined(min) && \ - !defined(max) -# define ARDUINOJSON_ENABLE_STD_STREAM 1 -# else -# define ARDUINOJSON_ENABLE_STD_STREAM 0 -# endif -#endif -#if !defined(ARDUINOJSON_ENABLE_STD_STRING) && defined(__has_include) -# if __has_include() && !defined(min) && !defined(max) -# define ARDUINOJSON_ENABLE_STD_STRING 1 -# else -# define ARDUINOJSON_ENABLE_STD_STRING 0 -# endif -#endif -#ifndef ARDUINOJSON_ENABLE_STRING_VIEW -# ifdef __has_include -# if __has_include() && __cplusplus >= 201703L -# define ARDUINOJSON_ENABLE_STRING_VIEW 1 -# endif -# endif -#endif -#ifndef ARDUINOJSON_ENABLE_STRING_VIEW -# define ARDUINOJSON_ENABLE_STRING_VIEW 0 -#endif -#if ARDUINOJSON_EMBEDDED_MODE -# ifndef ARDUINOJSON_USE_DOUBLE -# define ARDUINOJSON_USE_DOUBLE 0 -# endif -# ifndef ARDUINOJSON_USE_LONG_LONG -# define ARDUINOJSON_USE_LONG_LONG 0 -# endif -# ifndef ARDUINOJSON_ENABLE_STD_STRING -# define ARDUINOJSON_ENABLE_STD_STRING 0 -# endif -# ifndef ARDUINOJSON_ENABLE_STD_STREAM -# define ARDUINOJSON_ENABLE_STD_STREAM 0 -# endif -# ifndef ARDUINOJSON_DEFAULT_NESTING_LIMIT -# define ARDUINOJSON_DEFAULT_NESTING_LIMIT 10 -# endif -# ifndef ARDUINOJSON_SLOT_OFFSET_SIZE -# if defined(__SIZEOF_POINTER__) && __SIZEOF_POINTER__ == 2 -# define ARDUINOJSON_SLOT_OFFSET_SIZE 1 -# else -# define ARDUINOJSON_SLOT_OFFSET_SIZE 2 -# endif -# endif -#else // ARDUINOJSON_EMBEDDED_MODE -# ifndef ARDUINOJSON_USE_DOUBLE -# define ARDUINOJSON_USE_DOUBLE 1 -# endif -# ifndef ARDUINOJSON_USE_LONG_LONG -# if ARDUINOJSON_HAS_LONG_LONG || ARDUINOJSON_HAS_INT64 -# define ARDUINOJSON_USE_LONG_LONG 1 -# else -# define ARDUINOJSON_USE_LONG_LONG 0 -# endif -# endif -# ifndef ARDUINOJSON_ENABLE_STD_STRING -# define ARDUINOJSON_ENABLE_STD_STRING 1 -# endif -# ifndef ARDUINOJSON_ENABLE_STD_STREAM -# define ARDUINOJSON_ENABLE_STD_STREAM 1 -# endif -# ifndef ARDUINOJSON_DEFAULT_NESTING_LIMIT -# define ARDUINOJSON_DEFAULT_NESTING_LIMIT 50 -# endif -# ifndef ARDUINOJSON_SLOT_OFFSET_SIZE -# define ARDUINOJSON_SLOT_OFFSET_SIZE 4 -# endif -#endif // ARDUINOJSON_EMBEDDED_MODE -#ifdef ARDUINO -#include -# ifndef ARDUINOJSON_ENABLE_ARDUINO_STRING -# define ARDUINOJSON_ENABLE_ARDUINO_STRING 1 -# endif -# ifndef ARDUINOJSON_ENABLE_ARDUINO_STREAM -# define ARDUINOJSON_ENABLE_ARDUINO_STREAM 1 -# endif -# ifndef ARDUINOJSON_ENABLE_ARDUINO_PRINT -# define ARDUINOJSON_ENABLE_ARDUINO_PRINT 1 -# endif -#else // ARDUINO -# ifndef ARDUINOJSON_ENABLE_ARDUINO_STRING -# define ARDUINOJSON_ENABLE_ARDUINO_STRING 0 -# endif -# ifndef ARDUINOJSON_ENABLE_ARDUINO_STREAM -# define ARDUINOJSON_ENABLE_ARDUINO_STREAM 0 -# endif -# ifndef ARDUINOJSON_ENABLE_ARDUINO_PRINT -# define ARDUINOJSON_ENABLE_ARDUINO_PRINT 0 -# endif -#endif // ARDUINO -#ifndef ARDUINOJSON_ENABLE_PROGMEM -# if defined(PROGMEM) && defined(pgm_read_byte) && defined(pgm_read_dword) && \ - defined(pgm_read_ptr) && defined(pgm_read_float) -# define ARDUINOJSON_ENABLE_PROGMEM 1 -# else -# define ARDUINOJSON_ENABLE_PROGMEM 0 -# endif -#endif -#ifndef ARDUINOJSON_DECODE_UNICODE -# define ARDUINOJSON_DECODE_UNICODE 1 -#endif -#ifndef ARDUINOJSON_ENABLE_COMMENTS -# define ARDUINOJSON_ENABLE_COMMENTS 0 -#endif -#ifndef ARDUINOJSON_ENABLE_NAN -# define ARDUINOJSON_ENABLE_NAN 0 -#endif -#ifndef ARDUINOJSON_ENABLE_INFINITY -# define ARDUINOJSON_ENABLE_INFINITY 0 -#endif -#ifndef ARDUINOJSON_POSITIVE_EXPONENTIATION_THRESHOLD -# define ARDUINOJSON_POSITIVE_EXPONENTIATION_THRESHOLD 1e7 -#endif -#ifndef ARDUINOJSON_NEGATIVE_EXPONENTIATION_THRESHOLD -# define ARDUINOJSON_NEGATIVE_EXPONENTIATION_THRESHOLD 1e-5 -#endif -#ifndef ARDUINOJSON_LITTLE_ENDIAN -# if defined(_MSC_VER) || \ - (defined(__BYTE_ORDER__) && \ - __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) || \ - defined(__LITTLE_ENDIAN__) || defined(__i386) || defined(__x86_64) -# define ARDUINOJSON_LITTLE_ENDIAN 1 -# else -# define ARDUINOJSON_LITTLE_ENDIAN 0 -# endif -#endif -#ifndef ARDUINOJSON_ENABLE_ALIGNMENT -# if defined(__AVR) -# define ARDUINOJSON_ENABLE_ALIGNMENT 0 -# else -# define ARDUINOJSON_ENABLE_ALIGNMENT 1 -# endif -#endif -#ifndef ARDUINOJSON_TAB -# define ARDUINOJSON_TAB " " -#endif -#ifndef ARDUINOJSON_ENABLE_STRING_DEDUPLICATION -# define ARDUINOJSON_ENABLE_STRING_DEDUPLICATION 1 -#endif -#ifndef ARDUINOJSON_STRING_BUFFER_SIZE -# define ARDUINOJSON_STRING_BUFFER_SIZE 32 -#endif -#ifndef ARDUINOJSON_DEBUG -# ifdef __PLATFORMIO_BUILD_DEBUG__ -# define ARDUINOJSON_DEBUG 1 -# else -# define ARDUINOJSON_DEBUG 0 -# endif -#endif -#if ARDUINOJSON_HAS_NULLPTR && defined(nullptr) -# error nullptr is defined as a macro. Remove the faulty #define or #undef nullptr -#endif -#if !ARDUINOJSON_DEBUG -# ifdef __clang__ -# pragma clang system_header -# elif defined __GNUC__ -# pragma GCC system_header -# endif -#endif -#define ARDUINOJSON_EXPAND6(a, b, c, d, e, f) a, b, c, d, e, f -#define ARDUINOJSON_EXPAND9(a, b, c, d, e, f, g, h, i) a, b, c, d, e, f, g, h, i -#define ARDUINOJSON_EXPAND18(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, \ - q, r) \ - a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r -#define ARDUINOJSON_CONCAT_(A, B) A##B -#define ARDUINOJSON_CONCAT2(A, B) ARDUINOJSON_CONCAT_(A, B) -#define ARDUINOJSON_CONCAT4(A, B, C, D) \ - ARDUINOJSON_CONCAT2(ARDUINOJSON_CONCAT2(A, B), ARDUINOJSON_CONCAT2(C, D)) -#define ARDUINOJSON_HEX_DIGIT_0000() 0 -#define ARDUINOJSON_HEX_DIGIT_0001() 1 -#define ARDUINOJSON_HEX_DIGIT_0010() 2 -#define ARDUINOJSON_HEX_DIGIT_0011() 3 -#define ARDUINOJSON_HEX_DIGIT_0100() 4 -#define ARDUINOJSON_HEX_DIGIT_0101() 5 -#define ARDUINOJSON_HEX_DIGIT_0110() 6 -#define ARDUINOJSON_HEX_DIGIT_0111() 7 -#define ARDUINOJSON_HEX_DIGIT_1000() 8 -#define ARDUINOJSON_HEX_DIGIT_1001() 9 -#define ARDUINOJSON_HEX_DIGIT_1010() A -#define ARDUINOJSON_HEX_DIGIT_1011() B -#define ARDUINOJSON_HEX_DIGIT_1100() C -#define ARDUINOJSON_HEX_DIGIT_1101() D -#define ARDUINOJSON_HEX_DIGIT_1110() E -#define ARDUINOJSON_HEX_DIGIT_1111() F -#define ARDUINOJSON_HEX_DIGIT_(A, B, C, D) ARDUINOJSON_HEX_DIGIT_##A##B##C##D() -#define ARDUINOJSON_HEX_DIGIT(A, B, C, D) ARDUINOJSON_HEX_DIGIT_(A, B, C, D) -#define ARDUINOJSON_VERSION "6.18.1" -#define ARDUINOJSON_VERSION_MAJOR 6 -#define ARDUINOJSON_VERSION_MINOR 18 -#define ARDUINOJSON_VERSION_REVISION 1 -#ifndef ARDUINOJSON_NAMESPACE -# define ARDUINOJSON_NAMESPACE \ - ARDUINOJSON_CONCAT4( \ - ARDUINOJSON_CONCAT4(ArduinoJson, ARDUINOJSON_VERSION_MAJOR, \ - ARDUINOJSON_VERSION_MINOR, \ - ARDUINOJSON_VERSION_REVISION), \ - _, \ - ARDUINOJSON_HEX_DIGIT( \ - ARDUINOJSON_ENABLE_PROGMEM, ARDUINOJSON_USE_LONG_LONG, \ - ARDUINOJSON_USE_DOUBLE, ARDUINOJSON_ENABLE_STRING_DEDUPLICATION), \ - ARDUINOJSON_HEX_DIGIT( \ - ARDUINOJSON_ENABLE_NAN, ARDUINOJSON_ENABLE_INFINITY, \ - ARDUINOJSON_ENABLE_COMMENTS, ARDUINOJSON_DECODE_UNICODE)) -#endif -#if ARDUINOJSON_DEBUG -#include -# define ARDUINOJSON_ASSERT(X) assert(X) -#else -# define ARDUINOJSON_ASSERT(X) ((void)0) -#endif -#include -namespace ARDUINOJSON_NAMESPACE { -class MemoryPool; -class VariantData; -class VariantSlot; -class CollectionData { - VariantSlot *_head; - VariantSlot *_tail; - public: - VariantData *addElement(MemoryPool *pool); - VariantData *getElement(size_t index) const; - VariantData *getOrAddElement(size_t index, MemoryPool *pool); - void removeElement(size_t index); - bool equalsArray(const CollectionData &other) const; - template - VariantData *addMember(TAdaptedString key, MemoryPool *pool); - template - VariantData *getMember(TAdaptedString key) const; - template - VariantData *getOrAddMember(TAdaptedString key, MemoryPool *pool); - template - void removeMember(TAdaptedString key) { - removeSlot(getSlot(key)); - } - template - bool containsKey(const TAdaptedString &key) const; - bool equalsObject(const CollectionData &other) const; - void clear(); - size_t memoryUsage() const; - size_t nesting() const; - size_t size() const; - VariantSlot *addSlot(MemoryPool *); - void removeSlot(VariantSlot *slot); - bool copyFrom(const CollectionData &src, MemoryPool *pool); - VariantSlot *head() const { - return _head; - } - void movePointers(ptrdiff_t stringDistance, ptrdiff_t variantDistance); - private: - VariantSlot *getSlot(size_t index) const; - template - VariantSlot *getSlot(TAdaptedString key) const; - VariantSlot *getPreviousSlot(VariantSlot *) const; -}; -inline VariantData *arrayAdd(CollectionData *arr, MemoryPool *pool) { - return arr ? arr->addElement(pool) : 0; -} -template -inline typename TVisitor::result_type arrayAccept(const CollectionData *arr, - TVisitor &visitor) { - if (arr) - return visitor.visitArray(*arr); - else - return visitor.visitNull(); -} -inline bool arrayEquals(const CollectionData *lhs, const CollectionData *rhs) { - if (lhs == rhs) - return true; - if (!lhs || !rhs) - return false; - return lhs->equalsArray(*rhs); -} -#if ARDUINOJSON_ENABLE_ALIGNMENT -inline bool isAligned(size_t value) { - const size_t mask = sizeof(void *) - 1; - size_t addr = value; - return (addr & mask) == 0; -} -inline size_t addPadding(size_t bytes) { - const size_t mask = sizeof(void *) - 1; - return (bytes + mask) & ~mask; -} -template -struct AddPadding { - static const size_t mask = sizeof(void *) - 1; - static const size_t value = (bytes + mask) & ~mask; -}; -#else -inline bool isAligned(size_t) { - return true; -} -inline size_t addPadding(size_t bytes) { - return bytes; -} -template -struct AddPadding { - static const size_t value = bytes; -}; -#endif -template -inline bool isAligned(T *ptr) { - return isAligned(reinterpret_cast(ptr)); -} -template -inline T *addPadding(T *p) { - size_t address = addPadding(reinterpret_cast(p)); - return reinterpret_cast(address); -} -template Y)> -struct Max {}; -template -struct Max { - static const size_t value = X; -}; -template -struct Max { - static const size_t value = Y; -}; -} // namespace ARDUINOJSON_NAMESPACE -#include -#include -namespace ARDUINOJSON_NAMESPACE { -inline int safe_strcmp(const char* a, const char* b) { - if (a == b) - return 0; - if (!a) - return -1; - if (!b) - return 1; - return strcmp(a, b); -} -inline int safe_strncmp(const char* a, const char* b, size_t n) { - if (a == b) - return 0; - if (!a) - return -1; - if (!b) - return 1; - return strncmp(a, b, n); -} -template -struct conditional { - typedef TrueType type; -}; -template -struct conditional { - typedef FalseType type; -}; -template -struct enable_if {}; -template -struct enable_if { - typedef T type; -}; -template -struct integral_constant { - static const T value = v; -}; -typedef integral_constant true_type; -typedef integral_constant false_type; -template -struct is_array : false_type {}; -template -struct is_array : true_type {}; -template -struct is_array : true_type {}; -template -class is_base_of { - protected: // <- to avoid GCC's "all member functions in class are private" - typedef char Yes[1]; - typedef char No[2]; - static Yes &probe(const TBase *); - static No &probe(...); - public: - static const bool value = - sizeof(probe(reinterpret_cast(0))) == sizeof(Yes); -}; -template -T declval(); -template -struct is_class { - protected: // <- to avoid GCC's "all member functions in class are private" - typedef char Yes[1]; - typedef char No[2]; - template - static Yes &probe(void (U::*)(void)); - template - static No &probe(...); - public: - static const bool value = sizeof(probe(0)) == sizeof(Yes); -}; -template -struct is_const : false_type {}; -template -struct is_const : true_type {}; -} // namespace ARDUINOJSON_NAMESPACE -#ifdef _MSC_VER -# pragma warning(push) -# pragma warning(disable : 4244) -#endif -#ifdef __ICCARM__ -#pragma diag_suppress=Pa093 -#endif -namespace ARDUINOJSON_NAMESPACE { -template -struct is_convertible { - protected: // <- to avoid GCC's "all member functions in class are private" - typedef char Yes[1]; - typedef char No[2]; - static Yes &probe(To); - static No &probe(...); - public: - static const bool value = sizeof(probe(declval())) == sizeof(Yes); -}; -} // namespace ARDUINOJSON_NAMESPACE -#ifdef _MSC_VER -# pragma warning(pop) -#endif -#ifdef __ICCARM__ -#pragma diag_default=Pa093 -#endif -namespace ARDUINOJSON_NAMESPACE { -template -struct is_same : false_type {}; -template -struct is_same : true_type {}; -template -struct remove_cv { - typedef T type; -}; -template -struct remove_cv { - typedef T type; -}; -template -struct remove_cv { - typedef T type; -}; -template -struct remove_cv { - typedef T type; -}; -template -struct is_floating_point - : integral_constant< - bool, // - is_same::type>::value || - is_same::type>::value> {}; -template -struct is_integral : integral_constant::type, signed char>::value || - is_same::type, unsigned char>::value || - is_same::type, signed short>::value || - is_same::type, unsigned short>::value || - is_same::type, signed int>::value || - is_same::type, unsigned int>::value || - is_same::type, signed long>::value || - is_same::type, unsigned long>::value || -#if ARDUINOJSON_HAS_LONG_LONG - is_same::type, signed long long>::value || - is_same::type, unsigned long long>::value || -#endif -#if ARDUINOJSON_HAS_INT64 - is_same::type, signed __int64>::value || - is_same::type, unsigned __int64>::value || -#endif - is_same::type, char>::value || - is_same::type, bool>::value> {}; -template -struct is_enum { - static const bool value = is_convertible::value && - !is_class::value && !is_integral::value && - !is_floating_point::value; -}; -template -struct is_pointer : false_type {}; -template -struct is_pointer : true_type {}; -template -struct is_signed : integral_constant::type, char>::value || - is_same::type, signed char>::value || - is_same::type, signed short>::value || - is_same::type, signed int>::value || - is_same::type, signed long>::value || -#if ARDUINOJSON_HAS_LONG_LONG - is_same::type, signed long long>::value || -#endif -#if ARDUINOJSON_HAS_INT64 - is_same::type, signed __int64>::value || -#endif - is_same::type, float>::value || - is_same::type, double>::value> {}; -template -struct is_unsigned : integral_constant::type, unsigned char>::value || - is_same::type, unsigned short>::value || - is_same::type, unsigned int>::value || - is_same::type, unsigned long>::value || -#if ARDUINOJSON_HAS_INT64 - is_same::type, unsigned __int64>::value || -#endif -#if ARDUINOJSON_HAS_LONG_LONG - is_same::type, unsigned long long>::value || -#endif - is_same::type, bool>::value> {}; -template -struct type_identity { - typedef T type; -}; -template -struct make_unsigned; -template <> -struct make_unsigned : type_identity {}; -template <> -struct make_unsigned : type_identity {}; -template <> -struct make_unsigned : type_identity {}; -template <> -struct make_unsigned : type_identity {}; -template <> -struct make_unsigned : type_identity {}; -template <> -struct make_unsigned : type_identity {}; -template <> -struct make_unsigned : type_identity {}; -template <> -struct make_unsigned : type_identity {}; -template <> -struct make_unsigned : type_identity {}; -#if ARDUINOJSON_HAS_LONG_LONG -template <> -struct make_unsigned : type_identity {}; -template <> -struct make_unsigned : type_identity {}; -#endif -#if ARDUINOJSON_HAS_INT64 -template <> -struct make_unsigned : type_identity {}; -template <> -struct make_unsigned : type_identity {}; -#endif -template -struct remove_const { - typedef T type; -}; -template -struct remove_const { - typedef T type; -}; -template -struct remove_reference { - typedef T type; -}; -template -struct remove_reference { - typedef T type; -}; -template -struct IsString : false_type {}; -template -struct IsString : IsString {}; -template -struct IsString : IsString {}; -namespace storage_policies { -struct store_by_address {}; -struct store_by_copy {}; -struct decide_at_runtime {}; -} // namespace storage_policies -class ConstRamStringAdapter { - public: - ConstRamStringAdapter(const char* str = 0) : _str(str) {} - int compare(const char* other) const { - return safe_strcmp(_str, other); - } - bool equals(const char* expected) const { - return compare(expected) == 0; - } - bool isNull() const { - return !_str; - } - size_t size() const { - if (!_str) - return 0; - return strlen(_str); - } - const char* data() const { - return _str; - } - typedef storage_policies::store_by_address storage_policy; - protected: - const char* _str; -}; -template <> -struct IsString : true_type {}; -template -struct IsString : true_type {}; -inline ConstRamStringAdapter adaptString(const char* str) { - return ConstRamStringAdapter(str); -} -class RamStringAdapter : public ConstRamStringAdapter { - public: - RamStringAdapter(const char* str) : ConstRamStringAdapter(str) {} - void copyTo(char* p, size_t n) const { - memcpy(p, _str, n); - } - typedef ARDUINOJSON_NAMESPACE::storage_policies::store_by_copy storage_policy; -}; -template -inline RamStringAdapter adaptString(const TChar* str) { - return RamStringAdapter(reinterpret_cast(str)); -} -inline RamStringAdapter adaptString(char* str) { - return RamStringAdapter(str); -} -template -struct IsString { - static const bool value = sizeof(TChar) == 1; -}; -template <> -struct IsString { - static const bool value = false; -}; -class SizedRamStringAdapter { - public: - SizedRamStringAdapter(const char* str, size_t n) : _str(str), _size(n) {} - int compare(const char* other) const { - return safe_strncmp(_str, other, _size); - } - bool equals(const char* expected) const { - return compare(expected) == 0; - } - bool isNull() const { - return !_str; - } - void copyTo(char* p, size_t n) const { - memcpy(p, _str, n); - } - size_t size() const { - return _size; - } - typedef storage_policies::store_by_copy storage_policy; - private: - const char* _str; - size_t _size; -}; -template -inline SizedRamStringAdapter adaptString(const TChar* str, size_t size) { - return SizedRamStringAdapter(reinterpret_cast(str), size); -} -} // namespace ARDUINOJSON_NAMESPACE -#if ARDUINOJSON_ENABLE_STD_STRING -#include -namespace ARDUINOJSON_NAMESPACE { -template -class StdStringAdapter { - public: - StdStringAdapter(const TString& str) : _str(&str) {} - void copyTo(char* p, size_t n) const { - memcpy(p, _str->c_str(), n); - } - bool isNull() const { - return false; - } - int compare(const char* other) const { - if (!other) - return 1; - return _str->compare(other); - } - bool equals(const char* expected) const { - if (!expected) - return false; - return *_str == expected; - } - size_t size() const { - return _str->size(); - } - typedef storage_policies::store_by_copy storage_policy; - private: - const TString* _str; -}; -template -struct IsString > : true_type { -}; -template -inline StdStringAdapter > -adaptString(const std::basic_string& str) { - return StdStringAdapter >( - str); -} -} // namespace ARDUINOJSON_NAMESPACE -#endif -#if ARDUINOJSON_ENABLE_STRING_VIEW -#include -namespace ARDUINOJSON_NAMESPACE { -class StringViewAdapter { - public: - StringViewAdapter(std::string_view str) : _str(str) {} - void copyTo(char* p, size_t n) const { - memcpy(p, _str.data(), n); - } - bool isNull() const { - return false; - } - int compare(const char* other) const { - if (!other) - return 1; - return _str.compare(other); - } - bool equals(const char* expected) const { - if (!expected) - return false; - return _str == expected; - } - size_t size() const { - return _str.size(); - } - typedef storage_policies::store_by_copy storage_policy; - private: - std::string_view _str; -}; -template <> -struct IsString : true_type {}; -inline StringViewAdapter adaptString(const std::string_view& str) { - return StringViewAdapter(str); -} -} // namespace ARDUINOJSON_NAMESPACE -#endif -#if ARDUINOJSON_ENABLE_ARDUINO_STRING -namespace ARDUINOJSON_NAMESPACE { -class ArduinoStringAdapter { - public: - ArduinoStringAdapter(const ::String& str) : _str(&str) {} - void copyTo(char* p, size_t n) const { - memcpy(p, _str->c_str(), n); - } - bool isNull() const { - return !_str->c_str(); - } - int compare(const char* other) const { - const char* me = _str->c_str(); - return safe_strcmp(me, other); - } - bool equals(const char* expected) const { - return compare(expected) == 0; - } - size_t size() const { - return _str->length(); - } - typedef storage_policies::store_by_copy storage_policy; - private: - const ::String* _str; -}; -template <> -struct IsString< ::String> : true_type {}; -template <> -struct IsString< ::StringSumHelper> : true_type {}; -inline ArduinoStringAdapter adaptString(const ::String& str) { - return ArduinoStringAdapter(str); -} -} // namespace ARDUINOJSON_NAMESPACE -#endif -#if ARDUINOJSON_ENABLE_PROGMEM -namespace ARDUINOJSON_NAMESPACE { -struct pgm_p { - pgm_p(const char* p) : address(p) {} - const char* address; -}; -} // namespace ARDUINOJSON_NAMESPACE -#ifndef strlen_P -inline size_t strlen_P(ARDUINOJSON_NAMESPACE::pgm_p s) { - const char* p = s.address; - ARDUINOJSON_ASSERT(p != NULL); - while (pgm_read_byte(p)) p++; - return size_t(p - s.address); -} -#endif -#ifndef strncmp_P -inline int strncmp_P(const char* a, ARDUINOJSON_NAMESPACE::pgm_p b, size_t n) { - const char* s1 = a; - const char* s2 = b.address; - ARDUINOJSON_ASSERT(s1 != NULL); - ARDUINOJSON_ASSERT(s2 != NULL); - while (n-- > 0) { - char c1 = *s1++; - char c2 = static_cast(pgm_read_byte(s2++)); - if (c1 < c2) - return -1; - if (c1 > c2) - return 1; - if (c1 == 0 /* and c2 as well */) - return 0; - } - return 0; -} -#endif -#ifndef strcmp_P -inline int strcmp_P(const char* a, ARDUINOJSON_NAMESPACE::pgm_p b) { - const char* s1 = a; - const char* s2 = b.address; - ARDUINOJSON_ASSERT(s1 != NULL); - ARDUINOJSON_ASSERT(s2 != NULL); - for (;;) { - char c1 = *s1++; - char c2 = static_cast(pgm_read_byte(s2++)); - if (c1 < c2) - return -1; - if (c1 > c2) - return 1; - if (c1 == 0 /* and c2 as well */) - return 0; - } -} -#endif -#ifndef memcpy_P -inline void* memcpy_P(void* dst, ARDUINOJSON_NAMESPACE::pgm_p src, size_t n) { - uint8_t* d = reinterpret_cast(dst); - const char* s = src.address; - ARDUINOJSON_ASSERT(d != NULL); - ARDUINOJSON_ASSERT(s != NULL); - while (n-- > 0) { - *d++ = pgm_read_byte(s++); - } - return dst; -} -#endif -namespace ARDUINOJSON_NAMESPACE { -class FlashStringAdapter { - public: - FlashStringAdapter(const __FlashStringHelper* str) : _str(str) {} - int compare(const char* other) const { - if (!other && !_str) - return 0; - if (!_str) - return -1; - if (!other) - return 1; - return -strcmp_P(other, reinterpret_cast(_str)); - } - bool equals(const char* expected) const { - return compare(expected) == 0; - } - bool isNull() const { - return !_str; - } - void copyTo(char* p, size_t n) const { - memcpy_P(p, reinterpret_cast(_str), n); - } - size_t size() const { - if (!_str) - return 0; - return strlen_P(reinterpret_cast(_str)); - } - typedef storage_policies::store_by_copy storage_policy; - private: - const __FlashStringHelper* _str; -}; -inline FlashStringAdapter adaptString(const __FlashStringHelper* str) { - return FlashStringAdapter(str); -} -template <> -struct IsString : true_type {}; -class SizedFlashStringAdapter { - public: - SizedFlashStringAdapter(const __FlashStringHelper* str, size_t sz) - : _str(str), _size(sz) {} - int compare(const char* other) const { - if (!other && !_str) - return 0; - if (!_str) - return -1; - if (!other) - return 1; - return -strncmp_P(other, reinterpret_cast(_str), _size); - } - bool equals(const char* expected) const { - return compare(expected) == 0; - } - bool isNull() const { - return !_str; - } - void copyTo(char* p, size_t n) const { - memcpy_P(p, reinterpret_cast(_str), n); - } - size_t size() const { - return _size; - } - typedef storage_policies::store_by_copy storage_policy; - private: - const __FlashStringHelper* _str; - size_t _size; -}; -inline SizedFlashStringAdapter adaptString(const __FlashStringHelper* str, - size_t sz) { - return SizedFlashStringAdapter(str, sz); -} -} // namespace ARDUINOJSON_NAMESPACE -#endif -namespace ARDUINOJSON_NAMESPACE { -template -struct int_t; -template <> -struct int_t<8> { - typedef int8_t type; -}; -template <> -struct int_t<16> { - typedef int16_t type; -}; -template <> -struct int_t<32> { - typedef int32_t type; -}; -} // namespace ARDUINOJSON_NAMESPACE -#ifdef _MSC_VER -# pragma warning(push) -# pragma warning(disable : 4310) -#endif -namespace ARDUINOJSON_NAMESPACE { -template -struct numeric_limits; -template -struct numeric_limits::value>::type> { - static T lowest() { - return 0; - } - static T highest() { - return T(-1); - } -}; -template -struct numeric_limits< - T, typename enable_if::value && is_signed::value>::type> { - static T lowest() { - return T(T(1) << (sizeof(T) * 8 - 1)); - } - static T highest() { - return T(~lowest()); - } -}; -} // namespace ARDUINOJSON_NAMESPACE -#ifdef _MSC_VER -# pragma warning(pop) -#endif -namespace ARDUINOJSON_NAMESPACE { -#if ARDUINOJSON_USE_DOUBLE -typedef double Float; -#else -typedef float Float; -#endif -#if ARDUINOJSON_USE_LONG_LONG -typedef int64_t Integer; -typedef uint64_t UInt; -#else -typedef long Integer; -typedef unsigned long UInt; -#endif -} // namespace ARDUINOJSON_NAMESPACE -#if ARDUINOJSON_HAS_LONG_LONG && !ARDUINOJSON_USE_LONG_LONG -# define ARDUINOJSON_ASSERT_INTEGER_TYPE_IS_SUPPORTED(T) \ - static_assert(sizeof(T) <= sizeof(ARDUINOJSON_NAMESPACE::Integer), \ - "To use 64-bit integers with ArduinoJson, you must set " \ - "ARDUINOJSON_USE_LONG_LONG to 1. See " \ - "https://arduinojson.org/v6/api/config/use_long_long/"); -#else -# define ARDUINOJSON_ASSERT_INTEGER_TYPE_IS_SUPPORTED(T) -#endif -namespace ARDUINOJSON_NAMESPACE { -enum { - VALUE_MASK = 0x7F, - OWNED_VALUE_BIT = 0x01, - VALUE_IS_NULL = 0, - VALUE_IS_LINKED_RAW = 0x02, - VALUE_IS_OWNED_RAW = 0x03, - VALUE_IS_LINKED_STRING = 0x04, - VALUE_IS_OWNED_STRING = 0x05, - VALUE_IS_BOOLEAN = 0x06, - NUMBER_BIT = 0x08, - VALUE_IS_UNSIGNED_INTEGER = 0x08, - VALUE_IS_SIGNED_INTEGER = 0x0A, - VALUE_IS_FLOAT = 0x0C, - COLLECTION_MASK = 0x60, - VALUE_IS_OBJECT = 0x20, - VALUE_IS_ARRAY = 0x40, - OWNED_KEY_BIT = 0x80 -}; -struct RawData { - const char *data; - size_t size; -}; -union VariantContent { - Float asFloat; - bool asBoolean; - UInt asUnsignedInteger; - Integer asSignedInteger; - CollectionData asCollection; - const char *asString; - struct { - const char *data; - size_t size; - } asRaw; -}; -typedef int_t::type VariantSlotDiff; -class VariantSlot { - VariantContent _content; - uint8_t _flags; - VariantSlotDiff _next; - const char* _key; - public: - VariantData* data() { - return reinterpret_cast(&_content); - } - const VariantData* data() const { - return reinterpret_cast(&_content); - } - VariantSlot* next() { - return _next ? this + _next : 0; - } - const VariantSlot* next() const { - return const_cast(this)->next(); - } - VariantSlot* next(size_t distance) { - VariantSlot* slot = this; - while (distance--) { - if (!slot->_next) - return 0; - slot += slot->_next; - } - return slot; - } - const VariantSlot* next(size_t distance) const { - return const_cast(this)->next(distance); - } - void setNext(VariantSlot* slot) { - ARDUINOJSON_ASSERT(!slot || slot - this >= - numeric_limits::lowest()); - ARDUINOJSON_ASSERT(!slot || slot - this <= - numeric_limits::highest()); - _next = VariantSlotDiff(slot ? slot - this : 0); - } - void setNextNotNull(VariantSlot* slot) { - ARDUINOJSON_ASSERT(slot != 0); - ARDUINOJSON_ASSERT(slot - this >= - numeric_limits::lowest()); - ARDUINOJSON_ASSERT(slot - this <= - numeric_limits::highest()); - _next = VariantSlotDiff(slot - this); - } - void setKey(const char* k, storage_policies::store_by_copy) { - ARDUINOJSON_ASSERT(k != NULL); - _flags |= OWNED_KEY_BIT; - _key = k; - } - void setKey(const char* k, storage_policies::store_by_address) { - ARDUINOJSON_ASSERT(k != NULL); - _flags &= VALUE_MASK; - _key = k; - } - const char* key() const { - return _key; - } - bool ownsKey() const { - return (_flags & OWNED_KEY_BIT) != 0; - } - void clear() { - _next = 0; - _flags = 0; - _key = 0; - } - void movePointers(ptrdiff_t stringDistance, ptrdiff_t variantDistance) { - if (_flags & OWNED_KEY_BIT) - _key += stringDistance; - if (_flags & OWNED_VALUE_BIT) - _content.asString += stringDistance; - if (_flags & COLLECTION_MASK) - _content.asCollection.movePointers(stringDistance, variantDistance); - } -}; -} // namespace ARDUINOJSON_NAMESPACE -#define JSON_STRING_SIZE(SIZE) (SIZE + 1) -namespace ARDUINOJSON_NAMESPACE { -class MemoryPool { - public: - MemoryPool(char* buf, size_t capa) - : _begin(buf), - _left(buf), - _right(buf ? buf + capa : 0), - _end(buf ? buf + capa : 0), - _overflowed(false) { - ARDUINOJSON_ASSERT(isAligned(_begin)); - ARDUINOJSON_ASSERT(isAligned(_right)); - ARDUINOJSON_ASSERT(isAligned(_end)); - } - void* buffer() { - return _begin; // NOLINT(clang-analyzer-unix.Malloc) - } - size_t capacity() const { - return size_t(_end - _begin); - } - size_t size() const { - return size_t(_left - _begin + _end - _right); - } - bool overflowed() const { - return _overflowed; - } - VariantSlot* allocVariant() { - return allocRight(); - } - template - const char* saveString(const TAdaptedString& str) { - if (str.isNull()) - return 0; -#if ARDUINOJSON_ENABLE_STRING_DEDUPLICATION - const char* existingCopy = findString(str); - if (existingCopy) - return existingCopy; -#endif - size_t n = str.size(); - char* newCopy = allocString(n + 1); - if (newCopy) { - str.copyTo(newCopy, n); - newCopy[n] = 0; // force null-terminator - } - return newCopy; - } - void getFreeZone(char** zoneStart, size_t* zoneSize) const { - *zoneStart = _left; - *zoneSize = size_t(_right - _left); - } - const char* saveStringFromFreeZone(size_t len) { -#if ARDUINOJSON_ENABLE_STRING_DEDUPLICATION - const char* dup = findString(adaptString(_left)); - if (dup) - return dup; -#endif - const char* str = _left; - _left += len; - checkInvariants(); - return str; - } - void markAsOverflowed() { - _overflowed = true; - } - void clear() { - _left = _begin; - _right = _end; - _overflowed = false; - } - bool canAlloc(size_t bytes) const { - return _left + bytes <= _right; - } - bool owns(void* p) const { - return _begin <= p && p < _end; - } - void* operator new(size_t, void* p) { - return p; - } - ptrdiff_t squash() { - char* new_right = addPadding(_left); - if (new_right >= _right) - return 0; - size_t right_size = static_cast(_end - _right); - memmove(new_right, _right, right_size); - ptrdiff_t bytes_reclaimed = _right - new_right; - _right = new_right; - _end = new_right + right_size; - return bytes_reclaimed; - } - void movePointers(ptrdiff_t offset) { - _begin += offset; - _left += offset; - _right += offset; - _end += offset; - } - private: - void checkInvariants() { - ARDUINOJSON_ASSERT(_begin <= _left); - ARDUINOJSON_ASSERT(_left <= _right); - ARDUINOJSON_ASSERT(_right <= _end); - ARDUINOJSON_ASSERT(isAligned(_right)); - } -#if ARDUINOJSON_ENABLE_STRING_DEDUPLICATION - template - const char* findString(const TAdaptedString& str) { - for (char* next = _begin; next < _left; ++next) { - if (str.equals(next)) - return next; - while (*next) ++next; - } - return 0; - } -#endif - char* allocString(size_t n) { - if (!canAlloc(n)) { - _overflowed = true; - return 0; - } - char* s = _left; - _left += n; - checkInvariants(); - return s; - } - template - T* allocRight() { - return reinterpret_cast(allocRight(sizeof(T))); - } - void* allocRight(size_t bytes) { - if (!canAlloc(bytes)) { - _overflowed = true; - return 0; - } - _right -= bytes; - return _right; - } - char *_begin, *_left, *_right, *_end; - bool _overflowed; -}; -template -class SerializedValue { - public: - explicit SerializedValue(T str) : _str(str) {} - operator T() const { - return _str; - } - const char* data() const { - return _str.c_str(); - } - size_t size() const { - return _str.length(); - } - private: - T _str; -}; -template -class SerializedValue { - public: - explicit SerializedValue(TChar* p, size_t n) : _data(p), _size(n) {} - operator TChar*() const { - return _data; - } - TChar* data() const { - return _data; - } - size_t size() const { - return _size; - } - private: - TChar* _data; - size_t _size; -}; -template -inline SerializedValue serialized(T str) { - return SerializedValue(str); -} -template -inline SerializedValue serialized(TChar* p) { - return SerializedValue(p, adaptString(p).size()); -} -template -inline SerializedValue serialized(TChar* p, size_t n) { - return SerializedValue(p, n); -} -} // namespace ARDUINOJSON_NAMESPACE -#if defined(__clang__) -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wconversion" -#elif defined(__GNUC__) -# if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) -# pragma GCC diagnostic push -# endif -# pragma GCC diagnostic ignored "-Wconversion" -#endif -namespace ARDUINOJSON_NAMESPACE { -template -typename enable_if::value && is_unsigned::value && - is_integral::value && sizeof(TOut) <= sizeof(TIn), - bool>::type -canConvertNumber(TIn value) { - return value <= TIn(numeric_limits::highest()); -} -template -typename enable_if::value && is_unsigned::value && - is_integral::value && sizeof(TIn) < sizeof(TOut), - bool>::type -canConvertNumber(TIn) { - return true; -} -template -typename enable_if::value && is_floating_point::value, - bool>::type -canConvertNumber(TIn) { - return true; -} -template -typename enable_if::value && is_signed::value && - is_integral::value && is_signed::value && - sizeof(TOut) < sizeof(TIn), - bool>::type -canConvertNumber(TIn value) { - return value >= TIn(numeric_limits::lowest()) && - value <= TIn(numeric_limits::highest()); -} -template -typename enable_if::value && is_signed::value && - is_integral::value && is_signed::value && - sizeof(TIn) <= sizeof(TOut), - bool>::type -canConvertNumber(TIn) { - return true; -} -template -typename enable_if::value && is_signed::value && - is_integral::value && is_unsigned::value && - sizeof(TOut) >= sizeof(TIn), - bool>::type -canConvertNumber(TIn value) { - if (value < 0) - return false; - return TOut(value) <= numeric_limits::highest(); -} -template -typename enable_if::value && is_signed::value && - is_integral::value && is_unsigned::value && - sizeof(TOut) < sizeof(TIn), - bool>::type -canConvertNumber(TIn value) { - if (value < 0) - return false; - return value <= TIn(numeric_limits::highest()); -} -template -typename enable_if::value && - !is_floating_point::value, - bool>::type -canConvertNumber(TIn value) { - return value >= numeric_limits::lowest() && - value <= numeric_limits::highest(); -} -template -TOut convertNumber(TIn value) { - return canConvertNumber(value) ? TOut(value) : 0; -} -} // namespace ARDUINOJSON_NAMESPACE -#if defined(__clang__) -# pragma clang diagnostic pop -#elif defined(__GNUC__) -# if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) -# pragma GCC diagnostic pop -# endif -#endif -#if defined(__GNUC__) -# if __GNUC__ >= 7 -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wmaybe-uninitialized" -# pragma GCC diagnostic ignored "-Wuninitialized" -# endif -#endif -namespace ARDUINOJSON_NAMESPACE { -class VariantData { - VariantContent _content; // must be first to allow cast from array to variant - uint8_t _flags; - public: - void init() { - _flags = VALUE_IS_NULL; - } - template - typename TVisitor::result_type accept(TVisitor &visitor) const { - switch (type()) { - case VALUE_IS_FLOAT: - return visitor.visitFloat(_content.asFloat); - case VALUE_IS_ARRAY: - return visitor.visitArray(_content.asCollection); - case VALUE_IS_OBJECT: - return visitor.visitObject(_content.asCollection); - case VALUE_IS_LINKED_STRING: - case VALUE_IS_OWNED_STRING: - return visitor.visitString(_content.asString); - case VALUE_IS_OWNED_RAW: - case VALUE_IS_LINKED_RAW: - return visitor.visitRawJson(_content.asRaw.data, _content.asRaw.size); - case VALUE_IS_SIGNED_INTEGER: - return visitor.visitSignedInteger(_content.asSignedInteger); - case VALUE_IS_UNSIGNED_INTEGER: - return visitor.visitUnsignedInteger(_content.asUnsignedInteger); - case VALUE_IS_BOOLEAN: - return visitor.visitBoolean(_content.asBoolean != 0); - default: - return visitor.visitNull(); - } - } - template - T asIntegral() const; - template - T asFloat() const; - const char *asString() const; - bool asBoolean() const; - CollectionData *asArray() { - return isArray() ? &_content.asCollection : 0; - } - const CollectionData *asArray() const { - return const_cast(this)->asArray(); - } - CollectionData *asObject() { - return isObject() ? &_content.asCollection : 0; - } - const CollectionData *asObject() const { - return const_cast(this)->asObject(); - } - bool copyFrom(const VariantData &src, MemoryPool *pool) { - switch (src.type()) { - case VALUE_IS_ARRAY: - return toArray().copyFrom(src._content.asCollection, pool); - case VALUE_IS_OBJECT: - return toObject().copyFrom(src._content.asCollection, pool); - case VALUE_IS_OWNED_STRING: - return setString(RamStringAdapter(src._content.asString), pool); - case VALUE_IS_OWNED_RAW: - return setOwnedRaw( - serialized(src._content.asRaw.data, src._content.asRaw.size), pool); - default: - setType(src.type()); - _content = src._content; - return true; - } - } - bool isArray() const { - return (_flags & VALUE_IS_ARRAY) != 0; - } - bool isBoolean() const { - return type() == VALUE_IS_BOOLEAN; - } - bool isCollection() const { - return (_flags & COLLECTION_MASK) != 0; - } - template - bool isInteger() const { - switch (type()) { - case VALUE_IS_UNSIGNED_INTEGER: - return canConvertNumber(_content.asUnsignedInteger); - case VALUE_IS_SIGNED_INTEGER: - return canConvertNumber(_content.asSignedInteger); - default: - return false; - } - } - bool isFloat() const { - return (_flags & NUMBER_BIT) != 0; - } - bool isString() const { - return type() == VALUE_IS_LINKED_STRING || type() == VALUE_IS_OWNED_STRING; - } - bool isObject() const { - return (_flags & VALUE_IS_OBJECT) != 0; - } - bool isNull() const { - return type() == VALUE_IS_NULL; - } - bool isEnclosed() const { - return !isFloat(); - } - void remove(size_t index) { - if (isArray()) - _content.asCollection.removeElement(index); - } - template - void remove(TAdaptedString key) { - if (isObject()) - _content.asCollection.removeMember(key); - } - void setBoolean(bool value) { - setType(VALUE_IS_BOOLEAN); - _content.asBoolean = value; - } - void setFloat(Float value) { - setType(VALUE_IS_FLOAT); - _content.asFloat = value; - } - void setLinkedRaw(SerializedValue value) { - if (value.data()) { - setType(VALUE_IS_LINKED_RAW); - _content.asRaw.data = value.data(); - _content.asRaw.size = value.size(); - } else { - setType(VALUE_IS_NULL); - } - } - template - bool setOwnedRaw(SerializedValue value, MemoryPool *pool) { - const char *dup = pool->saveString(adaptString(value.data(), value.size())); - if (dup) { - setType(VALUE_IS_OWNED_RAW); - _content.asRaw.data = dup; - _content.asRaw.size = value.size(); - return true; - } else { - setType(VALUE_IS_NULL); - return false; - } - } - template - typename enable_if::value>::type setInteger(T value) { - setType(VALUE_IS_UNSIGNED_INTEGER); - _content.asUnsignedInteger = static_cast(value); - } - template - typename enable_if::value>::type setInteger(T value) { - setType(VALUE_IS_SIGNED_INTEGER); - _content.asSignedInteger = value; - } - void setNull() { - setType(VALUE_IS_NULL); - } - void setStringPointer(const char *s, storage_policies::store_by_copy) { - ARDUINOJSON_ASSERT(s != 0); - setType(VALUE_IS_OWNED_STRING); - _content.asString = s; - } - void setStringPointer(const char *s, storage_policies::store_by_address) { - ARDUINOJSON_ASSERT(s != 0); - setType(VALUE_IS_LINKED_STRING); - _content.asString = s; - } - template - bool setString(TAdaptedString value, MemoryPool *pool) { - return storeString(value, pool, typename TAdaptedString::storage_policy()); - } - CollectionData &toArray() { - setType(VALUE_IS_ARRAY); - _content.asCollection.clear(); - return _content.asCollection; - } - CollectionData &toObject() { - setType(VALUE_IS_OBJECT); - _content.asCollection.clear(); - return _content.asCollection; - } - size_t memoryUsage() const { - switch (type()) { - case VALUE_IS_OWNED_STRING: - return strlen(_content.asString) + 1; - case VALUE_IS_OWNED_RAW: - return _content.asRaw.size; - case VALUE_IS_OBJECT: - case VALUE_IS_ARRAY: - return _content.asCollection.memoryUsage(); - default: - return 0; - } - } - size_t nesting() const { - return isCollection() ? _content.asCollection.nesting() : 0; - } - size_t size() const { - return isCollection() ? _content.asCollection.size() : 0; - } - VariantData *addElement(MemoryPool *pool) { - if (isNull()) - toArray(); - if (!isArray()) - return 0; - return _content.asCollection.addElement(pool); - } - VariantData *getElement(size_t index) const { - return isArray() ? _content.asCollection.getElement(index) : 0; - } - VariantData *getOrAddElement(size_t index, MemoryPool *pool) { - if (isNull()) - toArray(); - if (!isArray()) - return 0; - return _content.asCollection.getOrAddElement(index, pool); - } - template - VariantData *getMember(TAdaptedString key) const { - return isObject() ? _content.asCollection.getMember(key) : 0; - } - template - VariantData *getOrAddMember(TAdaptedString key, MemoryPool *pool) { - if (isNull()) - toObject(); - if (!isObject()) - return 0; - return _content.asCollection.getOrAddMember(key, pool); - } - void movePointers(ptrdiff_t stringDistance, ptrdiff_t variantDistance) { - if (_flags & OWNED_VALUE_BIT) - _content.asString += stringDistance; - if (_flags & COLLECTION_MASK) - _content.asCollection.movePointers(stringDistance, variantDistance); - } - uint8_t type() const { - return _flags & VALUE_MASK; - } - private: - void setType(uint8_t t) { - _flags &= OWNED_KEY_BIT; - _flags |= t; - } - template - inline bool storeString(TAdaptedString value, MemoryPool *pool, - storage_policies::decide_at_runtime) { - if (value.isStatic()) - return storeString(value, pool, storage_policies::store_by_address()); - else - return storeString(value, pool, storage_policies::store_by_copy()); - } - template - inline bool storeString(TAdaptedString value, MemoryPool *, - storage_policies::store_by_address) { - if (value.isNull()) - setNull(); - else - setStringPointer(value.data(), storage_policies::store_by_address()); - return true; - } - template - inline bool storeString(TAdaptedString value, MemoryPool *pool, - storage_policies::store_by_copy) { - if (value.isNull()) { - setNull(); - return true; - } - const char *copy = pool->saveString(value); - if (!copy) { - setNull(); - return false; - } - setStringPointer(copy, storage_policies::store_by_copy()); - return true; - } -}; -} // namespace ARDUINOJSON_NAMESPACE -#if defined(__GNUC__) -# if __GNUC__ >= 8 -# pragma GCC diagnostic pop -# endif -#endif -namespace ARDUINOJSON_NAMESPACE { -template -inline bool slotSetKey(VariantSlot* var, TAdaptedString key, MemoryPool* pool) { - if (!var) - return false; - return slotSetKey(var, key, pool, typename TAdaptedString::storage_policy()); -} -template -inline bool slotSetKey(VariantSlot* var, TAdaptedString key, MemoryPool* pool, - storage_policies::decide_at_runtime) { - if (key.isStatic()) { - return slotSetKey(var, key, pool, storage_policies::store_by_address()); - } else { - return slotSetKey(var, key, pool, storage_policies::store_by_copy()); - } -} -template -inline bool slotSetKey(VariantSlot* var, TAdaptedString key, MemoryPool*, - storage_policies::store_by_address) { - ARDUINOJSON_ASSERT(var); - var->setKey(key.data(), storage_policies::store_by_address()); - return true; -} -template -inline bool slotSetKey(VariantSlot* var, TAdaptedString key, MemoryPool* pool, - storage_policies::store_by_copy) { - const char* dup = pool->saveString(key); - if (!dup) - return false; - ARDUINOJSON_ASSERT(var); - var->setKey(dup, storage_policies::store_by_copy()); - return true; -} -inline size_t slotSize(const VariantSlot* var) { - size_t n = 0; - while (var) { - n++; - var = var->next(); - } - return n; -} -inline VariantData* slotData(VariantSlot* slot) { - return reinterpret_cast(slot); -} -struct Visitable { -}; -template -struct IsVisitable : is_base_of {}; -template -struct IsVisitable : IsVisitable {}; -template -struct Converter; -template -class InvalidConversion; // Error here? See https://arduinojson.org/v6/invalid-conversion/ -} // namespace ARDUINOJSON_NAMESPACE -#ifdef _MSC_VER // Visual Studio -# define FORCE_INLINE // __forceinline causes C4714 when returning std::string -# define NO_INLINE __declspec(noinline) -# ifndef ARDUINOJSON_DEPRECATED -# define ARDUINOJSON_DEPRECATED(msg) __declspec(deprecated(msg)) -# endif -#elif defined(__GNUC__) // GCC or Clang -# define FORCE_INLINE __attribute__((always_inline)) -# define NO_INLINE __attribute__((noinline)) -# ifndef ARDUINOJSON_DEPRECATED -# if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5) -# define ARDUINOJSON_DEPRECATED(msg) __attribute__((deprecated(msg))) -# else -# define ARDUINOJSON_DEPRECATED(msg) __attribute__((deprecated)) -# endif -# endif -#else // Other compilers -# define FORCE_INLINE -# define NO_INLINE -# ifndef ARDUINOJSON_DEPRECATED -# define ARDUINOJSON_DEPRECATED(msg) -# endif -#endif -#if __cplusplus >= 201103L -# define NOEXCEPT noexcept -#else -# define NOEXCEPT throw() -#endif -#if defined(__has_attribute) -# if __has_attribute(no_sanitize) -# define ARDUINOJSON_NO_SANITIZE(check) __attribute__((no_sanitize(check))) -# else -# define ARDUINOJSON_NO_SANITIZE(check) -# endif -#else -# define ARDUINOJSON_NO_SANITIZE(check) -#endif -namespace ARDUINOJSON_NAMESPACE { -template -inline typename TVisitor::result_type variantAccept(const VariantData *var, - TVisitor &visitor) { - if (var != 0) - return var->accept(visitor); - else - return visitor.visitNull(); -} -inline const CollectionData *variantAsArray(const VariantData *var) { - return var != 0 ? var->asArray() : 0; -} -inline const CollectionData *variantAsObject(const VariantData *var) { - return var != 0 ? var->asObject() : 0; -} -inline CollectionData *variantAsObject(VariantData *var) { - return var != 0 ? var->asObject() : 0; -} -inline bool variantCopyFrom(VariantData *dst, const VariantData *src, - MemoryPool *pool) { - if (!dst) - return false; - if (!src) { - dst->setNull(); - return true; - } - return dst->copyFrom(*src, pool); -} -inline int variantCompare(const VariantData *a, const VariantData *b); -inline void variantSetNull(VariantData *var) { - if (!var) - return; - var->setNull(); -} -template -inline bool variantSetString(VariantData *var, TAdaptedString value, - MemoryPool *pool) { - if (!var) - return false; - return var->setString(value, pool); -} -inline size_t variantSize(const VariantData *var) { - return var != 0 ? var->size() : 0; -} -inline CollectionData *variantToArray(VariantData *var) { - if (!var) - return 0; - return &var->toArray(); -} -inline CollectionData *variantToObject(VariantData *var) { - if (!var) - return 0; - return &var->toObject(); -} -inline NO_INLINE VariantData *variantAddElement(VariantData *var, - MemoryPool *pool) { - return var != 0 ? var->addElement(pool) : 0; -} -inline NO_INLINE VariantData *variantGetOrAddElement(VariantData *var, - size_t index, - MemoryPool *pool) { - return var != 0 ? var->getOrAddElement(index, pool) : 0; -} -template -NO_INLINE VariantData *variantGetOrAddMember(VariantData *var, TChar *key, - MemoryPool *pool) { - return var != 0 ? var->getOrAddMember(adaptString(key), pool) : 0; -} -template -NO_INLINE VariantData *variantGetOrAddMember(VariantData *var, - const TString &key, - MemoryPool *pool) { - return var != 0 ? var->getOrAddMember(adaptString(key), pool) : 0; -} -inline bool variantIsNull(const VariantData *var) { - return var == 0 || var->isNull(); -} -enum CompareResult { - COMPARE_RESULT_DIFFER = 0, - COMPARE_RESULT_EQUAL = 1, - COMPARE_RESULT_GREATER = 2, - COMPARE_RESULT_LESS = 4, - COMPARE_RESULT_GREATER_OR_EQUAL = 3, - COMPARE_RESULT_LESS_OR_EQUAL = 5 -}; -template -CompareResult arithmeticCompare(const T &lhs, const T &rhs) { - if (lhs < rhs) - return COMPARE_RESULT_LESS; - else if (lhs > rhs) - return COMPARE_RESULT_GREATER; - else - return COMPARE_RESULT_EQUAL; -} -template -CompareResult arithmeticCompare( - const T1 &lhs, const T2 &rhs, - typename enable_if::value && is_integral::value && - sizeof(T1) < sizeof(T2), - int // Using int instead of void to avoid C2572 on - >::type * = 0) { - return arithmeticCompare(static_cast(lhs), rhs); -} -template -CompareResult arithmeticCompare( - const T1 &lhs, const T2 &rhs, - typename enable_if::value && is_integral::value && - sizeof(T2) < sizeof(T1)>::type * = 0) { - return arithmeticCompare(lhs, static_cast(rhs)); -} -template -CompareResult arithmeticCompare( - const T1 &lhs, const T2 &rhs, - typename enable_if::value && is_integral::value && - is_signed::value == is_signed::value && - sizeof(T2) == sizeof(T1)>::type * = 0) { - return arithmeticCompare(lhs, static_cast(rhs)); -} -template -CompareResult arithmeticCompare( - const T1 &lhs, const T2 &rhs, - typename enable_if::value && is_integral::value && - is_unsigned::value && is_signed::value && - sizeof(T2) == sizeof(T1)>::type * = 0) { - if (rhs < 0) - return COMPARE_RESULT_GREATER; - return arithmeticCompare(lhs, static_cast(rhs)); -} -template -CompareResult arithmeticCompare( - const T1 &lhs, const T2 &rhs, - typename enable_if::value && is_integral::value && - is_signed::value && is_unsigned::value && - sizeof(T2) == sizeof(T1)>::type * = 0) { - if (lhs < 0) - return COMPARE_RESULT_LESS; - return arithmeticCompare(static_cast(lhs), rhs); -} -template -CompareResult arithmeticCompare( - const T1 &lhs, const T2 &rhs, - typename enable_if::value || - is_floating_point::value>::type * = 0) { - return arithmeticCompare(static_cast(lhs), - static_cast(rhs)); -} -template -CompareResult arithmeticCompareNegateLeft( - UInt, const T2 &, typename enable_if::value>::type * = 0) { - return COMPARE_RESULT_LESS; -} -template -CompareResult arithmeticCompareNegateLeft( - UInt lhs, const T2 &rhs, - typename enable_if::value>::type * = 0) { - if (rhs > 0) - return COMPARE_RESULT_LESS; - return arithmeticCompare(-rhs, static_cast(lhs)); -} -template -CompareResult arithmeticCompareNegateRight( - const T1 &, UInt, typename enable_if::value>::type * = 0) { - return COMPARE_RESULT_GREATER; -} -template -CompareResult arithmeticCompareNegateRight( - const T1 &lhs, UInt rhs, - typename enable_if::value>::type * = 0) { - if (lhs > 0) - return COMPARE_RESULT_GREATER; - return arithmeticCompare(static_cast(rhs), -lhs); -} -struct VariantTag {}; -template -struct IsVariant : is_base_of {}; -template -CompareResult compare(const T1 &lhs, const T2 &rhs); // VariantCompare.cpp -template -struct VariantOperators { - template - friend - typename enable_if::value && !is_array::value, T>::type - operator|(const TVariant &variant, const T &defaultValue) { - if (variant.template is()) - return variant.template as(); - else - return defaultValue; - } - friend const char *operator|(const TVariant &variant, - const char *defaultValue) { - if (variant.template is()) - return variant.template as(); - else - return defaultValue; - } - template - friend typename enable_if::value, typename T::variant_type>::type - operator|(const TVariant &variant, T defaultValue) { - if (variant) - return variant; - else - return defaultValue; - } - template - friend bool operator==(T *lhs, TVariant rhs) { - return compare(rhs, lhs) == COMPARE_RESULT_EQUAL; - } - template - friend bool operator==(const T &lhs, TVariant rhs) { - return compare(rhs, lhs) == COMPARE_RESULT_EQUAL; - } - template - friend bool operator==(TVariant lhs, T *rhs) { - return compare(lhs, rhs) == COMPARE_RESULT_EQUAL; - } - template - friend typename enable_if::value, bool>::type operator==( - TVariant lhs, const T &rhs) { - return compare(lhs, rhs) == COMPARE_RESULT_EQUAL; - } - template - friend bool operator!=(T *lhs, TVariant rhs) { - return compare(rhs, lhs) != COMPARE_RESULT_EQUAL; - } - template - friend bool operator!=(const T &lhs, TVariant rhs) { - return compare(rhs, lhs) != COMPARE_RESULT_EQUAL; - } - template - friend bool operator!=(TVariant lhs, T *rhs) { - return compare(lhs, rhs) != COMPARE_RESULT_EQUAL; - } - template - friend typename enable_if::value, bool>::type operator!=( - TVariant lhs, const T &rhs) { - return compare(lhs, rhs) != COMPARE_RESULT_EQUAL; - } - template - friend bool operator<(T *lhs, TVariant rhs) { - return compare(rhs, lhs) == COMPARE_RESULT_GREATER; - } - template - friend bool operator<(const T &lhs, TVariant rhs) { - return compare(rhs, lhs) == COMPARE_RESULT_GREATER; - } - template - friend bool operator<(TVariant lhs, T *rhs) { - return compare(lhs, rhs) == COMPARE_RESULT_LESS; - } - template - friend typename enable_if::value, bool>::type operator<( - TVariant lhs, const T &rhs) { - return compare(lhs, rhs) == COMPARE_RESULT_LESS; - } - template - friend bool operator<=(T *lhs, TVariant rhs) { - return (compare(rhs, lhs) & COMPARE_RESULT_GREATER_OR_EQUAL) != 0; - } - template - friend bool operator<=(const T &lhs, TVariant rhs) { - return (compare(rhs, lhs) & COMPARE_RESULT_GREATER_OR_EQUAL) != 0; - } - template - friend bool operator<=(TVariant lhs, T *rhs) { - return (compare(lhs, rhs) & COMPARE_RESULT_LESS_OR_EQUAL) != 0; - } - template - friend typename enable_if::value, bool>::type operator<=( - TVariant lhs, const T &rhs) { - return (compare(lhs, rhs) & COMPARE_RESULT_LESS_OR_EQUAL) != 0; - } - template - friend bool operator>(T *lhs, TVariant rhs) { - return compare(rhs, lhs) == COMPARE_RESULT_LESS; - } - template - friend bool operator>(const T &lhs, TVariant rhs) { - return compare(rhs, lhs) == COMPARE_RESULT_LESS; - } - template - friend bool operator>(TVariant lhs, T *rhs) { - return compare(lhs, rhs) == COMPARE_RESULT_GREATER; - } - template - friend typename enable_if::value, bool>::type operator>( - TVariant lhs, const T &rhs) { - return compare(lhs, rhs) == COMPARE_RESULT_GREATER; - } - template - friend bool operator>=(T *lhs, TVariant rhs) { - return (compare(rhs, lhs) & COMPARE_RESULT_LESS_OR_EQUAL) != 0; - } - template - friend bool operator>=(const T &lhs, TVariant rhs) { - return (compare(rhs, lhs) & COMPARE_RESULT_LESS_OR_EQUAL) != 0; - } - template - friend bool operator>=(TVariant lhs, T *rhs) { - return (compare(lhs, rhs) & COMPARE_RESULT_GREATER_OR_EQUAL) != 0; - } - template - friend typename enable_if::value, bool>::type operator>=( - TVariant lhs, const T &rhs) { - return (compare(lhs, rhs) & COMPARE_RESULT_GREATER_OR_EQUAL) != 0; - } -}; -class ArrayRef; -class ObjectRef; -template -class ElementProxy; -template -class ArrayShortcuts { - public: - FORCE_INLINE ElementProxy operator[](size_t index) const; - FORCE_INLINE ObjectRef createNestedObject() const; - FORCE_INLINE ArrayRef createNestedArray() const; - template - FORCE_INLINE bool add(const T &value) const { - return impl()->addElement().set(value); - } - template - FORCE_INLINE bool add(T *value) const { - return impl()->addElement().set(value); - } - private: - const TArray *impl() const { - return static_cast(this); - } -}; -template -class MemberProxy; -template -class ObjectShortcuts { - public: - template - FORCE_INLINE typename enable_if::value, bool>::type - containsKey(const TString &key) const; - template - FORCE_INLINE typename enable_if::value, bool>::type - containsKey(TChar *key) const; - template - FORCE_INLINE typename enable_if::value, - MemberProxy >::type - operator[](const TString &key) const; - template - FORCE_INLINE typename enable_if::value, - MemberProxy >::type - operator[](TChar *key) const; - template - FORCE_INLINE ArrayRef createNestedArray(const TString &key) const; - template - FORCE_INLINE ArrayRef createNestedArray(TChar *key) const; - template - ObjectRef createNestedObject(const TString &key) const; - template - ObjectRef createNestedObject(TChar *key) const; - private: - const TObject *impl() const { - return static_cast(this); - } -}; -template -class VariantShortcuts : public ObjectShortcuts, - public ArrayShortcuts { - public: - using ArrayShortcuts::createNestedArray; - using ArrayShortcuts::createNestedObject; - using ArrayShortcuts::operator[]; - using ObjectShortcuts::createNestedArray; - using ObjectShortcuts::createNestedObject; - using ObjectShortcuts::operator[]; -}; -class ArrayRef; -class ObjectRef; -template -class VariantRefBase : public VariantTag { - public: - FORCE_INLINE bool isNull() const { - return variantIsNull(_data); - } - FORCE_INLINE bool isUndefined() const { - return !_data; - } - FORCE_INLINE size_t memoryUsage() const { - return _data ? _data->memoryUsage() : 0; - } - FORCE_INLINE size_t nesting() const { - return _data ? _data->nesting() : 0; - } - size_t size() const { - return variantSize(_data); - } - protected: - VariantRefBase(TData *data) : _data(data) {} - TData *_data; - friend TData *getData(const VariantRefBase &variant) { - return variant._data; - } -}; -class VariantRef : public VariantRefBase, - public VariantOperators, - public VariantShortcuts, - public Visitable { - typedef VariantRefBase base_type; - friend class VariantConstRef; - public: - FORCE_INLINE VariantRef(MemoryPool *pool, VariantData *data) - : base_type(data), _pool(pool) {} - FORCE_INLINE VariantRef() : base_type(0), _pool(0) {} - FORCE_INLINE void clear() const { - return variantSetNull(_data); - } - template - FORCE_INLINE bool set(const T &value) const { - return Converter::toJson(value, *this); - } - bool ARDUINOJSON_DEPRECATED( - "Support for char is deprecated, use int8_t or uint8_t instead") - set(char value) const; - template - FORCE_INLINE bool set(T *value) const { - return Converter::toJson(value, *this); - } - template - FORCE_INLINE - typename enable_if::value && !is_same::value, - T>::type - as() const { - return Converter::fromJson(*this); - } - template - FORCE_INLINE typename enable_if::value, const char *>::type - ARDUINOJSON_DEPRECATED("Replace as() with as()") - as() const { - return as(); - } - template - FORCE_INLINE typename enable_if::value, char>::type - ARDUINOJSON_DEPRECATED( - "Support for char is deprecated, use int8_t or uint8_t instead") - as() const { - return as(); - } - template - FORCE_INLINE - typename enable_if::value && !is_same::value, - bool>::type - is() const { - return Converter::checkJson(*this); - } - template - FORCE_INLINE typename enable_if::value, bool>::type - ARDUINOJSON_DEPRECATED("Replace is() with is()") - is() const { - return is(); - } - template - FORCE_INLINE typename enable_if::value, bool>::type - ARDUINOJSON_DEPRECATED( - "Support for char is deprecated, use int8_t or uint8_t instead") - is() const { - return is(); - } - template - FORCE_INLINE operator T() const { - return as(); - } - template - typename TVisitor::result_type accept(TVisitor &visitor) const { - return variantAccept(_data, visitor); - } - template - typename enable_if::value, ArrayRef>::type to() const; - template - typename enable_if::value, ObjectRef>::type to() const; - template - typename enable_if::value, VariantRef>::type to() - const; - VariantRef addElement() const; - FORCE_INLINE VariantRef getElement(size_t) const; - FORCE_INLINE VariantRef getOrAddElement(size_t) const; - template - FORCE_INLINE VariantRef getMember(TChar *) const; - template - FORCE_INLINE typename enable_if::value, VariantRef>::type - getMember(const TString &) const; - template - FORCE_INLINE VariantRef getOrAddMember(TChar *) const; - template - FORCE_INLINE VariantRef getOrAddMember(const TString &) const; - FORCE_INLINE void remove(size_t index) const { - if (_data) - _data->remove(index); - } - template - FORCE_INLINE typename enable_if::value>::type remove( - TChar *key) const { - if (_data) - _data->remove(adaptString(key)); - } - template - FORCE_INLINE typename enable_if::value>::type remove( - const TString &key) const { - if (_data) - _data->remove(adaptString(key)); - } - private: - MemoryPool *_pool; - friend MemoryPool *getPool(const VariantRef &variant) { - return variant._pool; - } -}; -class VariantConstRef : public VariantRefBase, - public VariantOperators, - public VariantShortcuts, - public Visitable { - typedef VariantRefBase base_type; - friend class VariantRef; - public: - VariantConstRef() : base_type(0) {} - VariantConstRef(const VariantData *data) : base_type(data) {} - VariantConstRef(VariantRef var) : base_type(var._data) {} - template - typename TVisitor::result_type accept(TVisitor &visitor) const { - return variantAccept(_data, visitor); - } - template - FORCE_INLINE - typename enable_if::value && !is_same::value, - T>::type - as() const { - return Converter::fromJson(*this); - } - template - FORCE_INLINE typename enable_if::value, const char *>::type - ARDUINOJSON_DEPRECATED("Replace as() with as()") - as() const { - return as(); - } - template - FORCE_INLINE typename enable_if::value, char>::type - ARDUINOJSON_DEPRECATED( - "Support for char is deprecated, use int8_t or uint8_t instead") - as() const { - return as(); - } - template - FORCE_INLINE - typename enable_if::value && !is_same::value, - bool>::type - is() const { - return Converter::checkJson(*this); - } - template - FORCE_INLINE typename enable_if::value, bool>::type - ARDUINOJSON_DEPRECATED("Replace is() with is()") - is() const { - return is(); - } - template - FORCE_INLINE typename enable_if::value, bool>::type - ARDUINOJSON_DEPRECATED( - "Support for char is deprecated, use int8_t or uint8_t instead") - is() const { - return is(); - } - template - FORCE_INLINE operator T() const { - return as(); - } - FORCE_INLINE VariantConstRef getElement(size_t) const; - FORCE_INLINE VariantConstRef operator[](size_t index) const { - return getElement(index); - } - template - FORCE_INLINE VariantConstRef getMember(const TString &key) const { - return VariantConstRef( - objectGetMember(variantAsObject(_data), adaptString(key))); - } - template - FORCE_INLINE VariantConstRef getMember(TChar *key) const { - const CollectionData *obj = variantAsObject(_data); - return VariantConstRef(obj ? obj->getMember(adaptString(key)) : 0); - } - template - FORCE_INLINE - typename enable_if::value, VariantConstRef>::type - operator[](const TString &key) const { - return getMember(key); - } - template - FORCE_INLINE - typename enable_if::value, VariantConstRef>::type - operator[](TChar *key) const { - return getMember(key); - } -}; -template <> -struct Converter { - static bool toJson(VariantRef src, VariantRef dst) { - return variantCopyFrom(getData(dst), getData(src), getPool(dst)); - } - static VariantRef fromJson(VariantRef src) { - return src; - } - static InvalidConversion fromJson( - VariantConstRef); - static bool checkJson(VariantRef src) { - VariantData *data = getData(src); - return !!data; - } - static bool checkJson(VariantConstRef) { - return false; - } -}; -template <> -struct Converter { - static bool toJson(VariantConstRef src, VariantRef dst) { - return variantCopyFrom(getData(dst), getData(src), getPool(dst)); - } - static VariantConstRef fromJson(VariantConstRef src) { - return VariantConstRef(getData(src)); - } - static bool checkJson(VariantConstRef src) { - const VariantData *data = getData(src); - return !!data; - } -}; -class VariantPtr { - public: - VariantPtr(MemoryPool *pool, VariantData *data) : _variant(pool, data) {} - VariantRef *operator->() { - return &_variant; - } - VariantRef &operator*() { - return _variant; - } - private: - VariantRef _variant; -}; -class ArrayIterator { - public: - ArrayIterator() : _slot(0) {} - explicit ArrayIterator(MemoryPool *pool, VariantSlot *slot) - : _pool(pool), _slot(slot) {} - VariantRef operator*() const { - return VariantRef(_pool, _slot->data()); - } - VariantPtr operator->() { - return VariantPtr(_pool, _slot->data()); - } - bool operator==(const ArrayIterator &other) const { - return _slot == other._slot; - } - bool operator!=(const ArrayIterator &other) const { - return _slot != other._slot; - } - ArrayIterator &operator++() { - _slot = _slot->next(); - return *this; - } - ArrayIterator &operator+=(size_t distance) { - _slot = _slot->next(distance); - return *this; - } - VariantSlot *internal() { - return _slot; - } - private: - MemoryPool *_pool; - VariantSlot *_slot; -}; -class VariantConstPtr { - public: - VariantConstPtr(const VariantData *data) : _variant(data) {} - VariantConstRef *operator->() { - return &_variant; - } - VariantConstRef &operator*() { - return _variant; - } - private: - VariantConstRef _variant; -}; -class ArrayConstRefIterator { - public: - ArrayConstRefIterator() : _slot(0) {} - explicit ArrayConstRefIterator(const VariantSlot *slot) : _slot(slot) {} - VariantConstRef operator*() const { - return VariantConstRef(_slot->data()); - } - VariantConstPtr operator->() { - return VariantConstPtr(_slot->data()); - } - bool operator==(const ArrayConstRefIterator &other) const { - return _slot == other._slot; - } - bool operator!=(const ArrayConstRefIterator &other) const { - return _slot != other._slot; - } - ArrayConstRefIterator &operator++() { - _slot = _slot->next(); - return *this; - } - ArrayConstRefIterator &operator+=(size_t distance) { - _slot = _slot->next(distance); - return *this; - } - const VariantSlot *internal() { - return _slot; - } - private: - const VariantSlot *_slot; -}; -} // namespace ARDUINOJSON_NAMESPACE -#define JSON_ARRAY_SIZE(NUMBER_OF_ELEMENTS) \ - ((NUMBER_OF_ELEMENTS) * sizeof(ARDUINOJSON_NAMESPACE::VariantSlot)) -namespace ARDUINOJSON_NAMESPACE { -class ObjectRef; -template -class ElementProxy; -template -class ArrayRefBase { - public: - operator VariantConstRef() const { - const void* data = _data; // prevent warning cast-align - return VariantConstRef(reinterpret_cast(data)); - } - template - FORCE_INLINE typename TVisitor::result_type accept(TVisitor& visitor) const { - return arrayAccept(_data, visitor); - } - FORCE_INLINE bool isNull() const { - return _data == 0; - } - FORCE_INLINE operator bool() const { - return _data != 0; - } - FORCE_INLINE size_t memoryUsage() const { - return _data ? _data->memoryUsage() : 0; - } - FORCE_INLINE size_t nesting() const { - return _data ? _data->nesting() : 0; - } - FORCE_INLINE size_t size() const { - return _data ? _data->size() : 0; - } - protected: - ArrayRefBase(TData* data) : _data(data) {} - TData* _data; -}; -class ArrayConstRef : public ArrayRefBase, - public Visitable { - friend class ArrayRef; - typedef ArrayRefBase base_type; - public: - typedef ArrayConstRefIterator iterator; - FORCE_INLINE iterator begin() const { - if (!_data) - return iterator(); - return iterator(_data->head()); - } - FORCE_INLINE iterator end() const { - return iterator(); - } - FORCE_INLINE ArrayConstRef() : base_type(0) {} - FORCE_INLINE ArrayConstRef(const CollectionData* data) : base_type(data) {} - FORCE_INLINE bool operator==(ArrayConstRef rhs) const { - return arrayEquals(_data, rhs._data); - } - FORCE_INLINE VariantConstRef operator[](size_t index) const { - return getElement(index); - } - FORCE_INLINE VariantConstRef getElement(size_t index) const { - return VariantConstRef(_data ? _data->getElement(index) : 0); - } -}; -class ArrayRef : public ArrayRefBase, - public ArrayShortcuts, - public Visitable { - typedef ArrayRefBase base_type; - public: - typedef ArrayIterator iterator; - FORCE_INLINE ArrayRef() : base_type(0), _pool(0) {} - FORCE_INLINE ArrayRef(MemoryPool* pool, CollectionData* data) - : base_type(data), _pool(pool) {} - operator VariantRef() { - void* data = _data; // prevent warning cast-align - return VariantRef(_pool, reinterpret_cast(data)); - } - operator ArrayConstRef() const { - return ArrayConstRef(_data); - } - VariantRef addElement() const { - return VariantRef(_pool, arrayAdd(_data, _pool)); - } - FORCE_INLINE iterator begin() const { - if (!_data) - return iterator(); - return iterator(_pool, _data->head()); - } - FORCE_INLINE iterator end() const { - return iterator(); - } - FORCE_INLINE bool set(ArrayConstRef src) const { - if (!_data || !src._data) - return false; - return _data->copyFrom(*src._data, _pool); - } - FORCE_INLINE bool operator==(ArrayRef rhs) const { - return arrayEquals(_data, rhs._data); - } - FORCE_INLINE VariantRef getOrAddElement(size_t index) const { - return VariantRef(_pool, _data ? _data->getOrAddElement(index, _pool) : 0); - } - FORCE_INLINE VariantRef getElement(size_t index) const { - return VariantRef(_pool, _data ? _data->getElement(index) : 0); - } - FORCE_INLINE void remove(iterator it) const { - if (!_data) - return; - _data->removeSlot(it.internal()); - } - FORCE_INLINE void remove(size_t index) const { - if (!_data) - return; - _data->removeElement(index); - } - void clear() const { - if (!_data) - return; - _data->clear(); - } - private: - MemoryPool* _pool; -}; -template <> -struct Converter { - static bool toJson(VariantConstRef src, VariantRef dst) { - return variantCopyFrom(getData(dst), getData(src), getPool(dst)); - } - static ArrayConstRef fromJson(VariantConstRef src) { - return ArrayConstRef(variantAsArray(getData(src))); - } - static bool checkJson(VariantConstRef src) { - const VariantData* data = getData(src); - return data && data->isArray(); - } -}; -template <> -struct Converter { - static bool toJson(VariantConstRef src, VariantRef dst) { - return variantCopyFrom(getData(dst), getData(src), getPool(dst)); - } - static ArrayRef fromJson(VariantRef src) { - VariantData* data = getData(src); - MemoryPool* pool = getPool(src); - return ArrayRef(pool, data != 0 ? data->asArray() : 0); - } - static InvalidConversion fromJson(VariantConstRef); - static bool checkJson(VariantConstRef) { - return false; - } - static bool checkJson(VariantRef src) { - VariantData* data = getData(src); - return data && data->isArray(); - } -}; -template -typename TVisitor::result_type objectAccept(const CollectionData *obj, - TVisitor &visitor) { - if (obj) - return visitor.visitObject(*obj); - else - return visitor.visitNull(); -} -inline bool objectEquals(const CollectionData *lhs, const CollectionData *rhs) { - if (lhs == rhs) - return true; - if (!lhs || !rhs) - return false; - return lhs->equalsObject(*rhs); -} -template -inline VariantData *objectGetMember(const CollectionData *obj, - TAdaptedString key) { - if (!obj) - return 0; - return obj->getMember(key); -} -template -void objectRemove(CollectionData *obj, TAdaptedString key) { - if (!obj) - return; - obj->removeMember(key); -} -template -inline VariantData *objectGetOrAddMember(CollectionData *obj, - TAdaptedString key, MemoryPool *pool) { - if (!obj) - return 0; - return obj->getOrAddMember(key, pool); -} -class String { - public: - String() : _data(0), _isStatic(true) {} - String(const char* data, bool isStaticData = true) - : _data(data), _isStatic(isStaticData) {} - const char* c_str() const { - return _data; - } - bool isNull() const { - return !_data; - } - bool isStatic() const { - return _isStatic; - } - friend bool operator==(String lhs, String rhs) { - if (lhs._data == rhs._data) - return true; - if (!lhs._data) - return false; - if (!rhs._data) - return false; - return strcmp(lhs._data, rhs._data) == 0; - } - friend bool operator!=(String lhs, String rhs) { - if (lhs._data == rhs._data) - return false; - if (!lhs._data) - return true; - if (!rhs._data) - return true; - return strcmp(lhs._data, rhs._data) != 0; - } - private: - const char* _data; - bool _isStatic; -}; -class StringAdapter : public RamStringAdapter { - public: - StringAdapter(const String& str) - : RamStringAdapter(str.c_str()), _isStatic(str.isStatic()) {} - bool isStatic() const { - return _isStatic; - } - typedef storage_policies::decide_at_runtime storage_policy; - private: - bool _isStatic; -}; -template <> -struct IsString : true_type {}; -inline StringAdapter adaptString(const String& str) { - return StringAdapter(str); -} -class Pair { - public: - Pair(MemoryPool* pool, VariantSlot* slot) { - if (slot) { - _key = String(slot->key(), !slot->ownsKey()); - _value = VariantRef(pool, slot->data()); - } - } - String key() const { - return _key; - } - VariantRef value() const { - return _value; - } - private: - String _key; - VariantRef _value; -}; -class PairConst { - public: - PairConst(const VariantSlot* slot) { - if (slot) { - _key = String(slot->key(), !slot->ownsKey()); - _value = VariantConstRef(slot->data()); - } - } - String key() const { - return _key; - } - VariantConstRef value() const { - return _value; - } - private: - String _key; - VariantConstRef _value; -}; -class PairPtr { - public: - PairPtr(MemoryPool *pool, VariantSlot *slot) : _pair(pool, slot) {} - const Pair *operator->() const { - return &_pair; - } - const Pair &operator*() const { - return _pair; - } - private: - Pair _pair; -}; -class ObjectIterator { - public: - ObjectIterator() : _slot(0) {} - explicit ObjectIterator(MemoryPool *pool, VariantSlot *slot) - : _pool(pool), _slot(slot) {} - Pair operator*() const { - return Pair(_pool, _slot); - } - PairPtr operator->() { - return PairPtr(_pool, _slot); - } - bool operator==(const ObjectIterator &other) const { - return _slot == other._slot; - } - bool operator!=(const ObjectIterator &other) const { - return _slot != other._slot; - } - ObjectIterator &operator++() { - _slot = _slot->next(); - return *this; - } - ObjectIterator &operator+=(size_t distance) { - _slot = _slot->next(distance); - return *this; - } - VariantSlot *internal() { - return _slot; - } - private: - MemoryPool *_pool; - VariantSlot *_slot; -}; -class PairConstPtr { - public: - PairConstPtr(const VariantSlot *slot) : _pair(slot) {} - const PairConst *operator->() const { - return &_pair; - } - const PairConst &operator*() const { - return _pair; - } - private: - PairConst _pair; -}; -class ObjectConstIterator { - public: - ObjectConstIterator() : _slot(0) {} - explicit ObjectConstIterator(const VariantSlot *slot) : _slot(slot) {} - PairConst operator*() const { - return PairConst(_slot); - } - PairConstPtr operator->() { - return PairConstPtr(_slot); - } - bool operator==(const ObjectConstIterator &other) const { - return _slot == other._slot; - } - bool operator!=(const ObjectConstIterator &other) const { - return _slot != other._slot; - } - ObjectConstIterator &operator++() { - _slot = _slot->next(); - return *this; - } - ObjectConstIterator &operator+=(size_t distance) { - _slot = _slot->next(distance); - return *this; - } - const VariantSlot *internal() { - return _slot; - } - private: - const VariantSlot *_slot; -}; -} // namespace ARDUINOJSON_NAMESPACE -#define JSON_OBJECT_SIZE(NUMBER_OF_ELEMENTS) \ - ((NUMBER_OF_ELEMENTS) * sizeof(ARDUINOJSON_NAMESPACE::VariantSlot)) -namespace ARDUINOJSON_NAMESPACE { -template -class ObjectRefBase { - public: - operator VariantConstRef() const { - const void* data = _data; // prevent warning cast-align - return VariantConstRef(reinterpret_cast(data)); - } - template - typename TVisitor::result_type accept(TVisitor& visitor) const { - return objectAccept(_data, visitor); - } - FORCE_INLINE bool isNull() const { - return _data == 0; - } - FORCE_INLINE operator bool() const { - return _data != 0; - } - FORCE_INLINE size_t memoryUsage() const { - return _data ? _data->memoryUsage() : 0; - } - FORCE_INLINE size_t nesting() const { - return _data ? _data->nesting() : 0; - } - FORCE_INLINE size_t size() const { - return _data ? _data->size() : 0; - } - protected: - ObjectRefBase(TData* data) : _data(data) {} - TData* _data; -}; -class ObjectConstRef : public ObjectRefBase, - public Visitable { - friend class ObjectRef; - typedef ObjectRefBase base_type; - public: - typedef ObjectConstIterator iterator; - ObjectConstRef() : base_type(0) {} - ObjectConstRef(const CollectionData* data) : base_type(data) {} - FORCE_INLINE iterator begin() const { - if (!_data) - return iterator(); - return iterator(_data->head()); - } - FORCE_INLINE iterator end() const { - return iterator(); - } - template - FORCE_INLINE bool containsKey(const TString& key) const { - return !getMember(key).isUndefined(); - } - template - FORCE_INLINE bool containsKey(TChar* key) const { - return !getMember(key).isUndefined(); - } - template - FORCE_INLINE VariantConstRef getMember(const TString& key) const { - return get_impl(adaptString(key)); - } - template - FORCE_INLINE VariantConstRef getMember(TChar* key) const { - return get_impl(adaptString(key)); - } - template - FORCE_INLINE - typename enable_if::value, VariantConstRef>::type - operator[](const TString& key) const { - return get_impl(adaptString(key)); - } - template - FORCE_INLINE - typename enable_if::value, VariantConstRef>::type - operator[](TChar* key) const { - return get_impl(adaptString(key)); - } - FORCE_INLINE bool operator==(ObjectConstRef rhs) const { - return objectEquals(_data, rhs._data); - } - private: - template - FORCE_INLINE VariantConstRef get_impl(TAdaptedString key) const { - return VariantConstRef(objectGetMember(_data, key)); - } -}; -class ObjectRef : public ObjectRefBase, - public ObjectShortcuts, - public Visitable { - typedef ObjectRefBase base_type; - public: - typedef ObjectIterator iterator; - FORCE_INLINE ObjectRef() : base_type(0), _pool(0) {} - FORCE_INLINE ObjectRef(MemoryPool* buf, CollectionData* data) - : base_type(data), _pool(buf) {} - operator VariantRef() const { - void* data = _data; // prevent warning cast-align - return VariantRef(_pool, reinterpret_cast(data)); - } - operator ObjectConstRef() const { - return ObjectConstRef(_data); - } - FORCE_INLINE iterator begin() const { - if (!_data) - return iterator(); - return iterator(_pool, _data->head()); - } - FORCE_INLINE iterator end() const { - return iterator(); - } - void clear() const { - if (!_data) - return; - _data->clear(); - } - FORCE_INLINE bool set(ObjectConstRef src) { - if (!_data || !src._data) - return false; - return _data->copyFrom(*src._data, _pool); - } - template - FORCE_INLINE VariantRef getMember(const TString& key) const { - return VariantRef(_pool, objectGetMember(_data, adaptString(key))); - } - template - FORCE_INLINE VariantRef getMember(TChar* key) const { - return VariantRef(_pool, objectGetMember(_data, adaptString(key))); - } - template - FORCE_INLINE VariantRef getOrAddMember(const TString& key) const { - return VariantRef(_pool, - objectGetOrAddMember(_data, adaptString(key), _pool)); - } - template - FORCE_INLINE VariantRef getOrAddMember(TChar* key) const { - return VariantRef(_pool, - objectGetOrAddMember(_data, adaptString(key), _pool)); - } - FORCE_INLINE bool operator==(ObjectRef rhs) const { - return objectEquals(_data, rhs._data); - } - FORCE_INLINE void remove(iterator it) const { - if (!_data) - return; - _data->removeSlot(it.internal()); - } - template - FORCE_INLINE void remove(const TString& key) const { - objectRemove(_data, adaptString(key)); - } - template - FORCE_INLINE void remove(TChar* key) const { - objectRemove(_data, adaptString(key)); - } - private: - MemoryPool* _pool; -}; -template <> -struct Converter { - static bool toJson(VariantConstRef src, VariantRef dst) { - return variantCopyFrom(getData(dst), getData(src), getPool(dst)); - } - static ObjectConstRef fromJson(VariantConstRef src) { - return ObjectConstRef(variantAsObject(getData(src))); - } - static bool checkJson(VariantConstRef src) { - const VariantData* data = getData(src); - return data && data->isObject(); - } -}; -template <> -struct Converter { - static bool toJson(VariantConstRef src, VariantRef dst) { - return variantCopyFrom(getData(dst), getData(src), getPool(dst)); - } - static ObjectRef fromJson(VariantRef src) { - VariantData* data = getData(src); - MemoryPool* pool = getPool(src); - return ObjectRef(pool, data != 0 ? data->asObject() : 0); - } - static InvalidConversion fromJson( - VariantConstRef); - static bool checkJson(VariantConstRef) { - return false; - } - static bool checkJson(VariantRef src) { - VariantData* data = getData(src); - return data && data->isObject(); - } -}; -class ArrayRef; -class ObjectRef; -class VariantRef; -template -struct VariantTo {}; -template <> -struct VariantTo { - typedef ArrayRef type; -}; -template <> -struct VariantTo { - typedef ObjectRef type; -}; -template <> -struct VariantTo { - typedef VariantRef type; -}; -} // namespace ARDUINOJSON_NAMESPACE -#ifdef _MSC_VER -# pragma warning(push) -# pragma warning(disable : 4522) -#endif -namespace ARDUINOJSON_NAMESPACE { -template -class ElementProxy : public VariantOperators >, - public VariantShortcuts >, - public Visitable, - public VariantTag { - typedef ElementProxy this_type; - public: - typedef VariantRef variant_type; - FORCE_INLINE ElementProxy(TArray array, size_t index) - : _array(array), _index(index) {} - FORCE_INLINE ElementProxy(const ElementProxy& src) - : _array(src._array), _index(src._index) {} - FORCE_INLINE this_type& operator=(const this_type& src) { - getOrAddUpstreamElement().set(src.as()); - return *this; - } - template - FORCE_INLINE this_type& operator=(const T& src) { - getOrAddUpstreamElement().set(src); - return *this; - } - template - FORCE_INLINE this_type& operator=(T* src) { - getOrAddUpstreamElement().set(src); - return *this; - } - FORCE_INLINE void clear() const { - getUpstreamElement().clear(); - } - FORCE_INLINE bool isNull() const { - return getUpstreamElement().isNull(); - } - template - FORCE_INLINE typename enable_if::value, T>::type as() - const { - return getUpstreamElement().template as(); - } - template - FORCE_INLINE typename enable_if::value, const char*>::type - ARDUINOJSON_DEPRECATED("Replace as() with as()") - as() const { - return as(); - } - template - FORCE_INLINE operator T() const { - return getUpstreamElement(); - } - template - FORCE_INLINE bool is() const { - return getUpstreamElement().template is(); - } - template - FORCE_INLINE typename VariantTo::type to() const { - return getOrAddUpstreamElement().template to(); - } - template - FORCE_INLINE bool set(const TValue& value) const { - return getOrAddUpstreamElement().set(value); - } - template - FORCE_INLINE bool set(TValue* value) const { - return getOrAddUpstreamElement().set(value); - } - template - typename TVisitor::result_type accept(TVisitor& visitor) const { - return getUpstreamElement().accept(visitor); - } - FORCE_INLINE size_t size() const { - return getUpstreamElement().size(); - } - template - VariantRef getMember(TNestedKey* key) const { - return getUpstreamElement().getMember(key); - } - template - VariantRef getMember(const TNestedKey& key) const { - return getUpstreamElement().getMember(key); - } - template - VariantRef getOrAddMember(TNestedKey* key) const { - return getOrAddUpstreamElement().getOrAddMember(key); - } - template - VariantRef getOrAddMember(const TNestedKey& key) const { - return getOrAddUpstreamElement().getOrAddMember(key); - } - VariantRef addElement() const { - return getOrAddUpstreamElement().addElement(); - } - VariantRef getElement(size_t index) const { - return getOrAddUpstreamElement().getElement(index); - } - VariantRef getOrAddElement(size_t index) const { - return getOrAddUpstreamElement().getOrAddElement(index); - } - FORCE_INLINE void remove(size_t index) const { - getUpstreamElement().remove(index); - } - template - FORCE_INLINE typename enable_if::value>::type remove( - TChar* key) const { - getUpstreamElement().remove(key); - } - template - FORCE_INLINE typename enable_if::value>::type remove( - const TString& key) const { - getUpstreamElement().remove(key); - } - private: - FORCE_INLINE VariantRef getUpstreamElement() const { - return _array.getElement(_index); - } - FORCE_INLINE VariantRef getOrAddUpstreamElement() const { - return _array.getOrAddElement(_index); - } - friend bool convertToJson(const this_type& src, VariantRef dst) { - return dst.set(src.getUpstreamElement()); - } - TArray _array; - const size_t _index; -}; -} // namespace ARDUINOJSON_NAMESPACE -#ifdef _MSC_VER -# pragma warning(pop) -#endif -#ifdef _MSC_VER -# pragma warning(push) -# pragma warning(disable : 4522) -#endif -namespace ARDUINOJSON_NAMESPACE { -template -class MemberProxy : public VariantOperators >, - public VariantShortcuts >, - public Visitable, - public VariantTag { - typedef MemberProxy this_type; - public: - typedef VariantRef variant_type; - FORCE_INLINE MemberProxy(TObject variant, TStringRef key) - : _object(variant), _key(key) {} - FORCE_INLINE MemberProxy(const MemberProxy &src) - : _object(src._object), _key(src._key) {} - FORCE_INLINE operator VariantConstRef() const { - return getUpstreamMember(); - } - FORCE_INLINE this_type &operator=(const this_type &src) { - getOrAddUpstreamMember().set(src); - return *this; - } - template - FORCE_INLINE typename enable_if::value, this_type &>::type - operator=(const TValue &src) { - getOrAddUpstreamMember().set(src); - return *this; - } - template - FORCE_INLINE this_type &operator=(TChar *src) { - getOrAddUpstreamMember().set(src); - return *this; - } - FORCE_INLINE void clear() const { - getUpstreamMember().clear(); - } - FORCE_INLINE bool isNull() const { - return getUpstreamMember().isNull(); - } - template - FORCE_INLINE typename enable_if::value, T>::type as() - const { - return getUpstreamMember().template as(); - } - template - FORCE_INLINE typename enable_if::value, const char *>::type - ARDUINOJSON_DEPRECATED("Replace as() with as()") - as() const { - return as(); - } - template - FORCE_INLINE operator T() const { - return getUpstreamMember(); - } - template - FORCE_INLINE bool is() const { - return getUpstreamMember().template is(); - } - FORCE_INLINE size_t size() const { - return getUpstreamMember().size(); - } - FORCE_INLINE void remove(size_t index) const { - getUpstreamMember().remove(index); - } - template - FORCE_INLINE typename enable_if::value>::type remove( - TChar *key) const { - getUpstreamMember().remove(key); - } - template - FORCE_INLINE typename enable_if::value>::type remove( - const TString &key) const { - getUpstreamMember().remove(key); - } - template - FORCE_INLINE typename VariantTo::type to() { - return getOrAddUpstreamMember().template to(); - } - template - FORCE_INLINE bool set(const TValue &value) { - return getOrAddUpstreamMember().set(value); - } - template - FORCE_INLINE bool set(TChar *value) { - return getOrAddUpstreamMember().set(value); - } - template - typename TVisitor::result_type accept(TVisitor &visitor) const { - return getUpstreamMember().accept(visitor); - } - FORCE_INLINE VariantRef addElement() const { - return getOrAddUpstreamMember().addElement(); - } - FORCE_INLINE VariantRef getElement(size_t index) const { - return getUpstreamMember().getElement(index); - } - FORCE_INLINE VariantRef getOrAddElement(size_t index) const { - return getOrAddUpstreamMember().getOrAddElement(index); - } - template - FORCE_INLINE VariantRef getMember(TChar *key) const { - return getUpstreamMember().getMember(key); - } - template - FORCE_INLINE VariantRef getMember(const TString &key) const { - return getUpstreamMember().getMember(key); - } - template - FORCE_INLINE VariantRef getOrAddMember(TChar *key) const { - return getOrAddUpstreamMember().getOrAddMember(key); - } - template - FORCE_INLINE VariantRef getOrAddMember(const TString &key) const { - return getOrAddUpstreamMember().getOrAddMember(key); - } - private: - FORCE_INLINE VariantRef getUpstreamMember() const { - return _object.getMember(_key); - } - FORCE_INLINE VariantRef getOrAddUpstreamMember() const { - return _object.getOrAddMember(_key); - } - friend bool convertToJson(const this_type &src, VariantRef dst) { - return dst.set(src.getUpstreamMember()); - } - TObject _object; - TStringRef _key; -}; -} // namespace ARDUINOJSON_NAMESPACE -#ifdef _MSC_VER -# pragma warning(pop) -#endif -namespace ARDUINOJSON_NAMESPACE { -class JsonDocument : public Visitable { - public: - template - typename TVisitor::result_type accept(TVisitor& visitor) const { - return getVariant().accept(visitor); - } - template - T as() { - return getVariant().template as(); - } - template - T as() const { - return getVariant().template as(); - } - void clear() { - _pool.clear(); - _data.init(); - } - template - bool is() { - return getVariant().template is(); - } - template - bool is() const { - return getVariant().template is(); - } - bool isNull() const { - return getVariant().isNull(); - } - size_t memoryUsage() const { - return _pool.size(); - } - bool overflowed() const { - return _pool.overflowed(); - } - size_t nesting() const { - return _data.nesting(); - } - size_t capacity() const { - return _pool.capacity(); - } - size_t size() const { - return _data.size(); - } - bool set(const JsonDocument& src) { - return to().set(src.as()); - } - template - typename enable_if::value, bool>::type set( - const T& src) { - return to().set(src); - } - template - typename VariantTo::type to() { - clear(); - return getVariant().template to(); - } - MemoryPool& memoryPool() { - return _pool; - } - VariantData& data() { - return _data; - } - ArrayRef createNestedArray() { - return addElement().to(); - } - template - ArrayRef createNestedArray(TChar* key) { - return getOrAddMember(key).template to(); - } - template - ArrayRef createNestedArray(const TString& key) { - return getOrAddMember(key).template to(); - } - ObjectRef createNestedObject() { - return addElement().to(); - } - template - ObjectRef createNestedObject(TChar* key) { - return getOrAddMember(key).template to(); - } - template - ObjectRef createNestedObject(const TString& key) { - return getOrAddMember(key).template to(); - } - template - bool containsKey(TChar* key) const { - return !getMember(key).isUndefined(); - } - template - bool containsKey(const TString& key) const { - return !getMember(key).isUndefined(); - } - template - FORCE_INLINE typename enable_if::value, - MemberProxy >::type - operator[](const TString& key) { - return MemberProxy(*this, key); - } - template - FORCE_INLINE typename enable_if::value, - MemberProxy >::type - operator[](TChar* key) { - return MemberProxy(*this, key); - } - template - FORCE_INLINE - typename enable_if::value, VariantConstRef>::type - operator[](const TString& key) const { - return getMember(key); - } - template - FORCE_INLINE - typename enable_if::value, VariantConstRef>::type - operator[](TChar* key) const { - return getMember(key); - } - FORCE_INLINE ElementProxy operator[](size_t index) { - return ElementProxy(*this, index); - } - FORCE_INLINE VariantConstRef operator[](size_t index) const { - return getElement(index); - } - FORCE_INLINE VariantRef getElement(size_t index) { - return VariantRef(&_pool, _data.getElement(index)); - } - FORCE_INLINE VariantConstRef getElement(size_t index) const { - return VariantConstRef(_data.getElement(index)); - } - FORCE_INLINE VariantRef getOrAddElement(size_t index) { - return VariantRef(&_pool, _data.getOrAddElement(index, &_pool)); - } - template - FORCE_INLINE VariantConstRef getMember(TChar* key) const { - return VariantConstRef(_data.getMember(adaptString(key))); - } - template - FORCE_INLINE - typename enable_if::value, VariantConstRef>::type - getMember(const TString& key) const { - return VariantConstRef(_data.getMember(adaptString(key))); - } - template - FORCE_INLINE VariantRef getMember(TChar* key) { - return VariantRef(&_pool, _data.getMember(adaptString(key))); - } - template - FORCE_INLINE typename enable_if::value, VariantRef>::type - getMember(const TString& key) { - return VariantRef(&_pool, _data.getMember(adaptString(key))); - } - template - FORCE_INLINE VariantRef getOrAddMember(TChar* key) { - return VariantRef(&_pool, _data.getOrAddMember(adaptString(key), &_pool)); - } - template - FORCE_INLINE VariantRef getOrAddMember(const TString& key) { - return VariantRef(&_pool, _data.getOrAddMember(adaptString(key), &_pool)); - } - FORCE_INLINE VariantRef addElement() { - return VariantRef(&_pool, _data.addElement(&_pool)); - } - template - FORCE_INLINE bool add(const TValue& value) { - return addElement().set(value); - } - template - FORCE_INLINE bool add(TChar* value) { - return addElement().set(value); - } - FORCE_INLINE void remove(size_t index) { - _data.remove(index); - } - template - FORCE_INLINE typename enable_if::value>::type remove( - TChar* key) { - _data.remove(adaptString(key)); - } - template - FORCE_INLINE typename enable_if::value>::type remove( - const TString& key) { - _data.remove(adaptString(key)); - } - FORCE_INLINE operator VariantConstRef() const { - return VariantConstRef(&_data); - } - bool operator==(VariantConstRef rhs) const { - return getVariant() == rhs; - } - bool operator!=(VariantConstRef rhs) const { - return getVariant() != rhs; - } - protected: - JsonDocument() : _pool(0, 0) { - _data.init(); - } - JsonDocument(MemoryPool pool) : _pool(pool) { - _data.init(); - } - JsonDocument(char* buf, size_t capa) : _pool(buf, capa) { - _data.init(); - } - ~JsonDocument() {} - void replacePool(MemoryPool pool) { - _pool = pool; - } - VariantRef getVariant() { - return VariantRef(&_pool, &_data); - } - VariantConstRef getVariant() const { - return VariantConstRef(&_data); - } - MemoryPool _pool; - VariantData _data; - private: - JsonDocument(const JsonDocument&); - JsonDocument& operator=(const JsonDocument&); -}; -inline bool convertToJson(const JsonDocument& src, VariantRef dst) { - return dst.set(src.as()); -} -template -class AllocatorOwner { - public: - AllocatorOwner() {} - AllocatorOwner(const AllocatorOwner& src) : _allocator(src._allocator) {} - AllocatorOwner(TAllocator a) : _allocator(a) {} - void* allocate(size_t size) { - return _allocator.allocate(size); - } - void deallocate(void* ptr) { - if (ptr) - _allocator.deallocate(ptr); - } - void* reallocate(void* ptr, size_t new_size) { - return _allocator.reallocate(ptr, new_size); - } - TAllocator& allocator() { - return _allocator; - } - private: - TAllocator _allocator; -}; -template -class BasicJsonDocument : AllocatorOwner, public JsonDocument { - public: - explicit BasicJsonDocument(size_t capa, TAllocator alloc = TAllocator()) - : AllocatorOwner(alloc), JsonDocument(allocPool(capa)) {} - BasicJsonDocument(const BasicJsonDocument& src) - : AllocatorOwner(src), JsonDocument() { - copyAssignFrom(src); - } -#if ARDUINOJSON_HAS_RVALUE_REFERENCES - BasicJsonDocument(BasicJsonDocument&& src) : AllocatorOwner(src) { - moveAssignFrom(src); - } -#endif - BasicJsonDocument(const JsonDocument& src) { - copyAssignFrom(src); - } - template - BasicJsonDocument( - const T& src, - typename enable_if< - is_same::value || is_same::value || - is_same::value || is_same::value || - is_same::value || - is_same::value>::type* = 0) - : JsonDocument(allocPool(src.memoryUsage())) { - set(src); - } - BasicJsonDocument(VariantRef src) - : JsonDocument(allocPool(src.memoryUsage())) { - set(src); - } - ~BasicJsonDocument() { - freePool(); - } - BasicJsonDocument& operator=(const BasicJsonDocument& src) { - copyAssignFrom(src); - return *this; - } -#if ARDUINOJSON_HAS_RVALUE_REFERENCES - BasicJsonDocument& operator=(BasicJsonDocument&& src) { - moveAssignFrom(src); - return *this; - } -#endif - template - BasicJsonDocument& operator=(const T& src) { - reallocPoolIfTooSmall(src.memoryUsage()); - set(src); - return *this; - } - void shrinkToFit() { - ptrdiff_t bytes_reclaimed = _pool.squash(); - if (bytes_reclaimed == 0) - return; - void* old_ptr = _pool.buffer(); - void* new_ptr = this->reallocate(old_ptr, _pool.capacity()); - ptrdiff_t ptr_offset = - static_cast(new_ptr) - static_cast(old_ptr); - _pool.movePointers(ptr_offset); - _data.movePointers(ptr_offset, ptr_offset - bytes_reclaimed); - } - bool garbageCollect() { - BasicJsonDocument tmp(*this); - if (!tmp.capacity()) - return false; - tmp.set(*this); - moveAssignFrom(tmp); - return true; - } - using AllocatorOwner::allocator; - private: - MemoryPool allocPool(size_t requiredSize) { - size_t capa = addPadding(requiredSize); - return MemoryPool(reinterpret_cast(this->allocate(capa)), capa); - } - void reallocPoolIfTooSmall(size_t requiredSize) { - if (requiredSize <= capacity()) - return; - freePool(); - replacePool(allocPool(addPadding(requiredSize))); - } - void freePool() { - this->deallocate(memoryPool().buffer()); - } - void copyAssignFrom(const JsonDocument& src) { - reallocPoolIfTooSmall(src.capacity()); - set(src); - } - void moveAssignFrom(BasicJsonDocument& src) { - freePool(); - _data = src._data; - _pool = src._pool; - src._data.setNull(); - src._pool = MemoryPool(0, 0); - } -}; -} // namespace ARDUINOJSON_NAMESPACE -#include -namespace ARDUINOJSON_NAMESPACE { -struct DefaultAllocator { - void* allocate(size_t size) { - return malloc(size); - } - void deallocate(void* ptr) { - free(ptr); - } - void* reallocate(void* ptr, size_t new_size) { - return realloc(ptr, new_size); - } -}; -typedef BasicJsonDocument DynamicJsonDocument; -template -class StaticJsonDocument : public JsonDocument { - static const size_t _capacity = - AddPadding::value>::value; - public: - StaticJsonDocument() : JsonDocument(_buffer, _capacity) {} - StaticJsonDocument(const StaticJsonDocument& src) - : JsonDocument(_buffer, _capacity) { - set(src); - } - template - StaticJsonDocument(const T& src, - typename enable_if::value>::type* = 0) - : JsonDocument(_buffer, _capacity) { - set(src); - } - StaticJsonDocument(VariantRef src) : JsonDocument(_buffer, _capacity) { - set(src); - } - StaticJsonDocument operator=(const StaticJsonDocument& src) { - set(src); - return *this; - } - template - StaticJsonDocument operator=(const T& src) { - set(src); - return *this; - } - void garbageCollect() { - StaticJsonDocument tmp(*this); - set(tmp); - } - private: - char _buffer[_capacity]; -}; -template -inline ArrayRef ArrayShortcuts::createNestedArray() const { - return impl()->addElement().template to(); -} -template -inline ObjectRef ArrayShortcuts::createNestedObject() const { - return impl()->addElement().template to(); -} -template -inline ElementProxy ArrayShortcuts::operator[]( - size_t index) const { - return ElementProxy(*impl(), index); -} -template -struct Visitor { - typedef TResult result_type; - TResult visitArray(const CollectionData &) { - return TResult(); - } - TResult visitBoolean(bool) { - return TResult(); - } - TResult visitFloat(Float) { - return TResult(); - } - TResult visitSignedInteger(Integer) { - return TResult(); - } - TResult visitNull() { - return TResult(); - } - TResult visitObject(const CollectionData &) { - return TResult(); - } - TResult visitUnsignedInteger(UInt) { - return TResult(); - } - TResult visitRawJson(const char *, size_t) { - return TResult(); - } - TResult visitString(const char *) { - return TResult(); - } -}; -template -inline typename enable_if::value && - !is_base_of::value, - bool>::type -copyArray(T (&src)[N], const TDestination& dst) { - return copyArray(src, N, dst); -} -template -inline bool copyArray(T (&src)[N], JsonDocument& dst) { - return copyArray(src, dst.to()); -} -template -inline typename enable_if::value && - !is_base_of::value, - bool>::type -copyArray(T* src, size_t len, const TDestination& dst) { - bool ok = true; - for (size_t i = 0; i < len; i++) { - ok &= dst.add(src[i]); - } - return ok; -} -template -inline bool copyArray(T* src, size_t len, JsonDocument& dst) { - return copyArray(src, len, dst.to()); -} -template -inline typename enable_if::value, - bool>::type -copyArray(T (&src)[N1][N2], const TDestination& dst) { - bool ok = true; - for (size_t i = 0; i < N1; i++) { - ArrayRef nestedArray = dst.createNestedArray(); - for (size_t j = 0; j < N2; j++) { - ok &= nestedArray.add(src[i][j]); - } - } - return ok; -} -template -inline bool copyArray(T (&src)[N1][N2], JsonDocument& dst) { - return copyArray(src, dst.to()); -} -template -class ArrayCopier1D : public Visitor { - public: - ArrayCopier1D(T* destination, size_t capacity) - : _destination(destination), _capacity(capacity) {} - size_t visitArray(const CollectionData& array) { - size_t size = 0; - VariantSlot* slot = array.head(); - while (slot != 0 && size < _capacity) { - _destination[size++] = - Converter::fromJson(VariantConstRef(slot->data())); - slot = slot->next(); - } - return size; - } - private: - T* _destination; - size_t _capacity; -}; -template -class ArrayCopier2D : public Visitor { - public: - ArrayCopier2D(T (*destination)[N1][N2]) : _destination(destination) {} - void visitArray(const CollectionData& array) { - VariantSlot* slot = array.head(); - size_t n = 0; - while (slot != 0 && n < N1) { - ArrayCopier1D copier((*_destination)[n++], N2); - variantAccept(slot->data(), copier); - slot = slot->next(); - } - } - private: - T (*_destination)[N1][N2]; - size_t _capacity1, _capacity2; -}; -template -inline typename enable_if::value, size_t>::type copyArray( - const TSource& src, T (&dst)[N]) { - return copyArray(src, dst, N); -} -template -inline size_t copyArray(const TSource& src, T* dst, size_t len) { - ArrayCopier1D copier(dst, len); - return src.accept(copier); -} -template -inline void copyArray(const TSource& src, T (&dst)[N1][N2]) { - ArrayCopier2D copier(&dst); - src.accept(copier); -} -inline bool variantEquals(const VariantData* a, const VariantData* b) { - return variantCompare(a, b) == COMPARE_RESULT_EQUAL; -} -inline VariantSlot* CollectionData::addSlot(MemoryPool* pool) { - VariantSlot* slot = pool->allocVariant(); - if (!slot) - return 0; - if (_tail) { - _tail->setNextNotNull(slot); - _tail = slot; - } else { - _head = slot; - _tail = slot; - } - slot->clear(); - return slot; -} -inline VariantData* CollectionData::addElement(MemoryPool* pool) { - return slotData(addSlot(pool)); -} -template -inline VariantData* CollectionData::addMember(TAdaptedString key, - MemoryPool* pool) { - VariantSlot* slot = addSlot(pool); - if (!slotSetKey(slot, key, pool)) { - removeSlot(slot); - return 0; - } - return slot->data(); -} -inline void CollectionData::clear() { - _head = 0; - _tail = 0; -} -template -inline bool CollectionData::containsKey(const TAdaptedString& key) const { - return getSlot(key) != 0; -} -inline bool CollectionData::copyFrom(const CollectionData& src, - MemoryPool* pool) { - clear(); - for (VariantSlot* s = src._head; s; s = s->next()) { - VariantData* var; - if (s->key() != 0) { - if (s->ownsKey()) - var = addMember(RamStringAdapter(s->key()), pool); - else - var = addMember(ConstRamStringAdapter(s->key()), pool); - } else { - var = addElement(pool); - } - if (!var) - return false; - if (!var->copyFrom(*s->data(), pool)) - return false; - } - return true; -} -inline bool CollectionData::equalsObject(const CollectionData& other) const { - size_t count = 0; - for (VariantSlot* slot = _head; slot; slot = slot->next()) { - VariantData* v1 = slot->data(); - VariantData* v2 = other.getMember(adaptString(slot->key())); - if (!variantEquals(v1, v2)) - return false; - count++; - } - return count == other.size(); -} -inline bool CollectionData::equalsArray(const CollectionData& other) const { - VariantSlot* s1 = _head; - VariantSlot* s2 = other._head; - for (;;) { - if (s1 == s2) - return true; - if (!s1 || !s2) - return false; - if (!variantEquals(s1->data(), s2->data())) - return false; - s1 = s1->next(); - s2 = s2->next(); - } -} -template -inline VariantSlot* CollectionData::getSlot(TAdaptedString key) const { - VariantSlot* slot = _head; - while (slot) { - if (key.equals(slot->key())) - break; - slot = slot->next(); - } - return slot; -} -inline VariantSlot* CollectionData::getSlot(size_t index) const { - if (!_head) - return 0; - return _head->next(index); -} -inline VariantSlot* CollectionData::getPreviousSlot(VariantSlot* target) const { - VariantSlot* current = _head; - while (current) { - VariantSlot* next = current->next(); - if (next == target) - return current; - current = next; - } - return 0; -} -template -inline VariantData* CollectionData::getMember(TAdaptedString key) const { - VariantSlot* slot = getSlot(key); - return slot ? slot->data() : 0; -} -template -inline VariantData* CollectionData::getOrAddMember(TAdaptedString key, - MemoryPool* pool) { - if (key.isNull()) - return 0; - VariantSlot* slot = getSlot(key); - if (slot) - return slot->data(); - return addMember(key, pool); -} -inline VariantData* CollectionData::getElement(size_t index) const { - VariantSlot* slot = getSlot(index); - return slot ? slot->data() : 0; -} -inline VariantData* CollectionData::getOrAddElement(size_t index, - MemoryPool* pool) { - VariantSlot* slot = _head; - while (slot && index > 0) { - slot = slot->next(); - index--; - } - if (!slot) - index++; - while (index > 0) { - slot = addSlot(pool); - index--; - } - return slotData(slot); -} -inline void CollectionData::removeSlot(VariantSlot* slot) { - if (!slot) - return; - VariantSlot* prev = getPreviousSlot(slot); - VariantSlot* next = slot->next(); - if (prev) - prev->setNext(next); - else - _head = next; - if (!next) - _tail = prev; -} -inline void CollectionData::removeElement(size_t index) { - removeSlot(getSlot(index)); -} -inline size_t CollectionData::memoryUsage() const { - size_t total = 0; - for (VariantSlot* s = _head; s; s = s->next()) { - total += sizeof(VariantSlot) + s->data()->memoryUsage(); - if (s->ownsKey()) - total += strlen(s->key()) + 1; - } - return total; -} -inline size_t CollectionData::nesting() const { - size_t maxChildNesting = 0; - for (VariantSlot* s = _head; s; s = s->next()) { - size_t childNesting = s->data()->nesting(); - if (childNesting > maxChildNesting) - maxChildNesting = childNesting; - } - return maxChildNesting + 1; -} -inline size_t CollectionData::size() const { - return slotSize(_head); -} -template -inline void movePointer(T*& p, ptrdiff_t offset) { - if (!p) - return; - p = reinterpret_cast( - reinterpret_cast(reinterpret_cast(p) + offset)); - ARDUINOJSON_ASSERT(isAligned(p)); -} -inline void CollectionData::movePointers(ptrdiff_t stringDistance, - ptrdiff_t variantDistance) { - movePointer(_head, variantDistance); - movePointer(_tail, variantDistance); - for (VariantSlot* slot = _head; slot; slot = slot->next()) - slot->movePointers(stringDistance, variantDistance); -} -template -template -inline ArrayRef ObjectShortcuts::createNestedArray( - const TString& key) const { - return impl()->getOrAddMember(key).template to(); -} -template -template -inline ArrayRef ObjectShortcuts::createNestedArray(TChar* key) const { - return impl()->getOrAddMember(key).template to(); -} -template -template -inline ObjectRef ObjectShortcuts::createNestedObject( - const TString& key) const { - return impl()->getOrAddMember(key).template to(); -} -template -template -inline ObjectRef ObjectShortcuts::createNestedObject( - TChar* key) const { - return impl()->getOrAddMember(key).template to(); -} -template -template -inline typename enable_if::value, bool>::type -ObjectShortcuts::containsKey(const TString& key) const { - return !impl()->getMember(key).isUndefined(); -} -template -template -inline typename enable_if::value, bool>::type -ObjectShortcuts::containsKey(TChar* key) const { - return !impl()->getMember(key).isUndefined(); -} -template -template -inline typename enable_if::value, - MemberProxy >::type -ObjectShortcuts::operator[](TString* key) const { - return MemberProxy(*impl(), key); -} -template -template -inline typename enable_if::value, - MemberProxy >::type -ObjectShortcuts::operator[](const TString& key) const { - return MemberProxy(*impl(), key); -} -} // namespace ARDUINOJSON_NAMESPACE -#if ARDUINOJSON_ENABLE_ARDUINO_STRING -#endif -#if ARDUINOJSON_ENABLE_STD_STRING -#endif -namespace ARDUINOJSON_NAMESPACE { -template -struct IsWriteableString : false_type {}; -#if ARDUINOJSON_ENABLE_ARDUINO_STRING -template <> -struct IsWriteableString< ::String> : true_type {}; -#endif -#if ARDUINOJSON_ENABLE_STD_STRING -template -struct IsWriteableString > - : true_type {}; -#endif -template -struct Converter { - static bool toJson(const T& src, VariantRef dst) { - return convertToJson(src, dst); // Error here? See https://arduinojson.org/v6/unsupported-set/ - } - static T fromJson(VariantConstRef src) { - T result; // Error here? See https://arduinojson.org/v6/non-default-constructible/ - convertFromJson(src, result); // Error here? See https://arduinojson.org/v6/unsupported-as/ - return result; - } - static bool checkJson(VariantConstRef src) { - T dummy; - return canConvertFromJson(src, dummy); // Error here? See https://arduinojson.org/v6/unsupported-is/ - } -}; -template -struct Converter< - T, typename enable_if::value && !is_same::value && - !is_same::value>::type> { - static bool toJson(T src, VariantRef dst) { - VariantData* data = getData(dst); - ARDUINOJSON_ASSERT_INTEGER_TYPE_IS_SUPPORTED(T); - if (!data) - return false; - data->setInteger(src); - return true; - } - static T fromJson(VariantConstRef src) { - ARDUINOJSON_ASSERT_INTEGER_TYPE_IS_SUPPORTED(T); - const VariantData* data = getData(src); - return data ? data->asIntegral() : T(); - } - static bool checkJson(VariantConstRef src) { - const VariantData* data = getData(src); - return data && data->isInteger(); - } -}; -template -struct Converter::value>::type> { - static bool toJson(T src, VariantRef dst) { - return dst.set(static_cast(src)); - } - static T fromJson(VariantConstRef src) { - const VariantData* data = getData(src); - return data ? static_cast(data->asIntegral()) : T(); - } - static bool checkJson(VariantConstRef src) { - const VariantData* data = getData(src); - return data && data->isInteger(); - } -}; -template <> -struct Converter { - static bool toJson(bool src, VariantRef dst) { - VariantData* data = getData(dst); - if (!data) - return false; - data->setBoolean(src); - return true; - } - static bool fromJson(VariantConstRef src) { - const VariantData* data = getData(src); - return data ? data->asBoolean() : false; - } - static bool checkJson(VariantConstRef src) { - const VariantData* data = getData(src); - return data && data->isBoolean(); - } -}; -template -struct Converter::value>::type> { - static bool toJson(T src, VariantRef dst) { - VariantData* data = getData(dst); - if (!data) - return false; - data->setFloat(static_cast(src)); - return true; - } - static T fromJson(VariantConstRef src) { - const VariantData* data = getData(src); - return data ? data->asFloat() : false; - } - static bool checkJson(VariantConstRef src) { - const VariantData* data = getData(src); - return data && data->isFloat(); - } -}; -template <> -struct Converter { - static bool toJson(const char* src, VariantRef dst) { - return variantSetString(getData(dst), adaptString(src), getPool(dst)); - } - static const char* fromJson(VariantConstRef src) { - const VariantData* data = getData(src); - return data ? data->asString() : 0; - } - static bool checkJson(VariantConstRef src) { - const VariantData* data = getData(src); - return data && data->isString(); - } -}; -template -inline typename enable_if::value, bool>::type convertToJson( - const T& src, VariantRef dst) { - VariantData* data = getData(dst); - MemoryPool* pool = getPool(dst); - return variantSetString(data, adaptString(src), pool); -} -template -inline typename enable_if::value>::type convertFromJson( - VariantConstRef src, T& dst) { - const VariantData* data = getData(src); - const char* cstr = data != 0 ? data->asString() : 0; - if (cstr) - dst = cstr; - else - serializeJson(src, dst); -} -template -inline typename enable_if::value, bool>::type -canConvertFromJson(VariantConstRef src, const T&) { - const VariantData* data = getData(src); - return data && data->isString(); -} -template <> -struct Converter > { - static bool toJson(SerializedValue src, VariantRef dst) { - VariantData* data = getData(dst); - if (!data) - return false; - data->setLinkedRaw(src); - return true; - } -}; -template -struct Converter, - typename enable_if::value>::type> { - static bool toJson(SerializedValue src, VariantRef dst) { - VariantData* data = getData(dst); - MemoryPool* pool = getPool(dst); - return data != 0 && data->setOwnedRaw(src, pool); - } -}; -#if ARDUINOJSON_HAS_NULLPTR -template <> -struct Converter { - static bool toJson(decltype(nullptr), VariantRef dst) { - variantSetNull(getData(dst)); - return true; - } - static decltype(nullptr) fromJson(VariantConstRef) { - return nullptr; - } - static bool checkJson(VariantConstRef src) { - const VariantData* data = getData(src); - return data == 0 || data->isNull(); - } -}; -#endif -#if ARDUINOJSON_ENABLE_ARDUINO_STREAM -class MemoryPoolPrint : public Print { - public: - MemoryPoolPrint(MemoryPool* pool) : _pool(pool), _size(0) { - pool->getFreeZone(&_string, &_capacity); - } - const char* c_str() { - _string[_size++] = 0; - ARDUINOJSON_ASSERT(_size <= _capacity); - return _pool->saveStringFromFreeZone(_size); - } - size_t write(uint8_t c) { - if (_size >= _capacity) - return 0; - _string[_size++] = char(c); - return 1; - } - size_t write(const uint8_t* buffer, size_t size) { - if (_size + size >= _capacity) { - _size = _capacity; // mark as overflowed - return 0; - } - memcpy(&_string[_size], buffer, size); - _size += size; - return size; - } - bool overflowed() const { - return _size >= _capacity; - } - private: - MemoryPool* _pool; - size_t _size; - char* _string; - size_t _capacity; -}; -inline bool convertToJson(const ::Printable& src, VariantRef dst) { - MemoryPool* pool = getPool(dst); - VariantData* data = getData(dst); - if (!pool || !data) - return false; - MemoryPoolPrint print(pool); - src.printTo(print); - if (print.overflowed()) { - pool->markAsOverflowed(); - data->setNull(); - return false; - } - data->setStringPointer(print.c_str(), storage_policies::store_by_copy()); - return true; -} -#endif -class CollectionData; -struct ComparerBase : Visitor {}; -template -struct Comparer; -template -struct Comparer::value>::type> - : ComparerBase { - T rhs; - explicit Comparer(T value) : rhs(value) {} - CompareResult visitString(const char *lhs) { - int i = adaptString(rhs).compare(lhs); - if (i < 0) - return COMPARE_RESULT_GREATER; - else if (i > 0) - return COMPARE_RESULT_LESS; - else - return COMPARE_RESULT_EQUAL; - } - CompareResult visitNull() { - if (adaptString(rhs).isNull()) - return COMPARE_RESULT_EQUAL; - else - return COMPARE_RESULT_DIFFER; - } -}; -template -struct Comparer::value || - is_floating_point::value>::type> - : ComparerBase { - T rhs; - explicit Comparer(T value) : rhs(value) {} - CompareResult visitFloat(Float lhs) { - return arithmeticCompare(lhs, rhs); - } - CompareResult visitSignedInteger(Integer lhs) { - return arithmeticCompare(lhs, rhs); - } - CompareResult visitUnsignedInteger(UInt lhs) { - return arithmeticCompare(lhs, rhs); - } - CompareResult visitBoolean(bool lhs) { - return visitUnsignedInteger(static_cast(lhs)); - } -}; -struct NullComparer : ComparerBase { - CompareResult visitNull() { - return COMPARE_RESULT_EQUAL; - } -}; -#if ARDUINOJSON_HAS_NULLPTR -template <> -struct Comparer : NullComparer { - explicit Comparer(decltype(nullptr)) : NullComparer() {} -}; -#endif -struct ArrayComparer : ComparerBase { - const CollectionData *_rhs; - explicit ArrayComparer(const CollectionData &rhs) : _rhs(&rhs) {} - CompareResult visitArray(const CollectionData &lhs) { - if (lhs.equalsArray(*_rhs)) - return COMPARE_RESULT_EQUAL; - else - return COMPARE_RESULT_DIFFER; - } -}; -struct ObjectComparer : ComparerBase { - const CollectionData *_rhs; - explicit ObjectComparer(const CollectionData &rhs) : _rhs(&rhs) {} - CompareResult visitObject(const CollectionData &lhs) { - if (lhs.equalsObject(*_rhs)) - return COMPARE_RESULT_EQUAL; - else - return COMPARE_RESULT_DIFFER; - } -}; -struct RawComparer : ComparerBase { - const char *_rhsData; - size_t _rhsSize; - explicit RawComparer(const char *rhsData, size_t rhsSize) - : _rhsData(rhsData), _rhsSize(rhsSize) {} - CompareResult visitRawJson(const char *lhsData, size_t lhsSize) { - size_t size = _rhsSize < lhsSize ? _rhsSize : lhsSize; - int n = memcmp(lhsData, _rhsData, size); - if (n < 0) - return COMPARE_RESULT_LESS; - else if (n > 0) - return COMPARE_RESULT_GREATER; - else - return COMPARE_RESULT_EQUAL; - } -}; -template -struct Comparer::value>::type> - : ComparerBase { - T rhs; - explicit Comparer(T value) : rhs(value) {} - CompareResult visitArray(const CollectionData &lhs) { - ArrayComparer comparer(lhs); - return accept(comparer); - } - CompareResult visitObject(const CollectionData &lhs) { - ObjectComparer comparer(lhs); - return accept(comparer); - } - CompareResult visitFloat(Float lhs) { - Comparer comparer(lhs); - return accept(comparer); - } - CompareResult visitString(const char *lhs) { - Comparer comparer(lhs); - return accept(comparer); - } - CompareResult visitRawJson(const char *lhsData, size_t lhsSize) { - RawComparer comparer(lhsData, lhsSize); - return accept(comparer); - } - CompareResult visitSignedInteger(Integer lhs) { - Comparer comparer(lhs); - return accept(comparer); - } - CompareResult visitUnsignedInteger(UInt lhs) { - Comparer comparer(lhs); - return accept(comparer); - } - CompareResult visitBoolean(bool lhs) { - Comparer comparer(lhs); - return accept(comparer); - } - CompareResult visitNull() { - NullComparer comparer; - return accept(comparer); - } - private: - template - CompareResult accept(TComparer &comparer) { - CompareResult reversedResult = rhs.accept(comparer); - switch (reversedResult) { - case COMPARE_RESULT_GREATER: - return COMPARE_RESULT_LESS; - case COMPARE_RESULT_LESS: - return COMPARE_RESULT_GREATER; - default: - return reversedResult; - } - } -}; -template -CompareResult compare(const T1 &lhs, const T2 &rhs) { - Comparer comparer(rhs); - return lhs.accept(comparer); -} -inline int variantCompare(const VariantData *a, const VariantData *b) { - return compare(VariantConstRef(a), VariantConstRef(b)); -} -#ifndef isnan -template -bool isnan(T x) { - return x != x; -} -#endif -#ifndef isinf -template -bool isinf(T x) { - return x != 0.0 && x * 2 == x; -} -#endif -template -struct alias_cast_t { - union { - F raw; - T data; - }; -}; -template -T alias_cast(F raw_data) { - alias_cast_t ac; - ac.raw = raw_data; - return ac.data; -} -} // namespace ARDUINOJSON_NAMESPACE -#if ARDUINOJSON_ENABLE_PROGMEM -namespace ARDUINOJSON_NAMESPACE { -template -typename enable_if::value, T>::type pgm_read(const void* p) { - return reinterpret_cast(pgm_read_ptr(p)); -} -template -typename enable_if::value && - sizeof(T) == sizeof(float), // on AVR sizeof(double) == - T>::type -pgm_read(const void* p) { - return pgm_read_float(p); -} -template -typename enable_if::value, T>::type pgm_read( - const void* p) { - return pgm_read_dword(p); -} -} // namespace ARDUINOJSON_NAMESPACE -# ifndef ARDUINOJSON_DEFINE_STATIC_ARRAY -# define ARDUINOJSON_DEFINE_STATIC_ARRAY(type, name, value) \ - static type const name[] PROGMEM = value; -# endif -# ifndef ARDUINOJSON_READ_STATIC_ARRAY -# define ARDUINOJSON_READ_STATIC_ARRAY(type, name, index) \ - pgm_read(name + index) -# endif -#else // i.e. ARDUINOJSON_ENABLE_PROGMEM == 0 -# ifndef ARDUINOJSON_DEFINE_STATIC_ARRAY -# define ARDUINOJSON_DEFINE_STATIC_ARRAY(type, name, value) \ - static type const name[] = value; -# endif -# ifndef ARDUINOJSON_READ_STATIC_ARRAY -# define ARDUINOJSON_READ_STATIC_ARRAY(type, name, index) name[index] -# endif -#endif -namespace ARDUINOJSON_NAMESPACE { -template -struct FloatTraits {}; -template -struct FloatTraits { - typedef uint64_t mantissa_type; - static const short mantissa_bits = 52; - static const mantissa_type mantissa_max = - (mantissa_type(1) << mantissa_bits) - 1; - typedef int16_t exponent_type; - static const exponent_type exponent_max = 308; - template - static T make_float(T m, TExponent e) { - if (e > 0) { - for (uint8_t index = 0; e != 0; index++) { - if (e & 1) - m *= positiveBinaryPowerOfTen(index); - e >>= 1; - } - } else { - e = TExponent(-e); - for (uint8_t index = 0; e != 0; index++) { - if (e & 1) - m *= negativeBinaryPowerOfTen(index); - e >>= 1; - } - } - return m; - } - static T positiveBinaryPowerOfTen(int index) { - ARDUINOJSON_DEFINE_STATIC_ARRAY( // - uint32_t, factors, - ARDUINOJSON_EXPAND18({ - 0x40240000, 0x00000000, // 1e1 - 0x40590000, 0x00000000, // 1e2 - 0x40C38800, 0x00000000, // 1e4 - 0x4197D784, 0x00000000, // 1e8 - 0x4341C379, 0x37E08000, // 1e16 - 0x4693B8B5, 0xB5056E17, // 1e32 - 0x4D384F03, 0xE93FF9F5, // 1e64 - 0x5A827748, 0xF9301D32, // 1e128 - 0x75154FDD, 0x7F73BF3C // 1e256 - })); - return forge( - ARDUINOJSON_READ_STATIC_ARRAY(uint32_t, factors, 2 * index), - ARDUINOJSON_READ_STATIC_ARRAY(uint32_t, factors, 2 * index + 1)); - } - static T negativeBinaryPowerOfTen(int index) { - ARDUINOJSON_DEFINE_STATIC_ARRAY( // - uint32_t, factors, - ARDUINOJSON_EXPAND18({ - 0x3FB99999, 0x9999999A, // 1e-1 - 0x3F847AE1, 0x47AE147B, // 1e-2 - 0x3F1A36E2, 0xEB1C432D, // 1e-4 - 0x3E45798E, 0xE2308C3A, // 1e-8 - 0x3C9CD2B2, 0x97D889BC, // 1e-16 - 0x3949F623, 0xD5A8A733, // 1e-32 - 0x32A50FFD, 0x44F4A73D, // 1e-64 - 0x255BBA08, 0xCF8C979D, // 1e-128 - 0x0AC80628, 0x64AC6F43 // 1e-256 - })); - return forge( - ARDUINOJSON_READ_STATIC_ARRAY(uint32_t, factors, 2 * index), - ARDUINOJSON_READ_STATIC_ARRAY(uint32_t, factors, 2 * index + 1)); - } - static T negativeBinaryPowerOfTenPlusOne(int index) { - ARDUINOJSON_DEFINE_STATIC_ARRAY( // - uint32_t, factors, - ARDUINOJSON_EXPAND18({ - 0x3FF00000, 0x00000000, // 1e0 - 0x3FB99999, 0x9999999A, // 1e-1 - 0x3F50624D, 0xD2F1A9FC, // 1e-3 - 0x3E7AD7F2, 0x9ABCAF48, // 1e-7 - 0x3CD203AF, 0x9EE75616, // 1e-15 - 0x398039D6, 0x65896880, // 1e-31 - 0x32DA53FC, 0x9631D10D, // 1e-63 - 0x25915445, 0x81B7DEC2, // 1e-127 - 0x0AFE07B2, 0x7DD78B14 // 1e-255 - })); - return forge( - ARDUINOJSON_READ_STATIC_ARRAY(uint32_t, factors, 2 * index), - ARDUINOJSON_READ_STATIC_ARRAY(uint32_t, factors, 2 * index + 1)); - } - static T nan() { - return forge(0x7ff80000, 0x00000000); - } - static T inf() { - return forge(0x7ff00000, 0x00000000); - } - static T highest() { - return forge(0x7FEFFFFF, 0xFFFFFFFF); - } - static T lowest() { - return forge(0xFFEFFFFF, 0xFFFFFFFF); - } - static T forge(uint32_t msb, uint32_t lsb) { - return alias_cast((uint64_t(msb) << 32) | lsb); - } -}; -template -struct FloatTraits { - typedef uint32_t mantissa_type; - static const short mantissa_bits = 23; - static const mantissa_type mantissa_max = - (mantissa_type(1) << mantissa_bits) - 1; - typedef int8_t exponent_type; - static const exponent_type exponent_max = 38; - template - static T make_float(T m, TExponent e) { - if (e > 0) { - for (uint8_t index = 0; e != 0; index++) { - if (e & 1) - m *= positiveBinaryPowerOfTen(index); - e >>= 1; - } - } else { - e = -e; - for (uint8_t index = 0; e != 0; index++) { - if (e & 1) - m *= negativeBinaryPowerOfTen(index); - e >>= 1; - } - } - return m; - } - static T positiveBinaryPowerOfTen(int index) { - ARDUINOJSON_DEFINE_STATIC_ARRAY( - T, factors, - ARDUINOJSON_EXPAND6({1e1f, 1e2f, 1e4f, 1e8f, 1e16f, 1e32f})); - return ARDUINOJSON_READ_STATIC_ARRAY(T, factors, index); - } - static T negativeBinaryPowerOfTen(int index) { - ARDUINOJSON_DEFINE_STATIC_ARRAY( - T, factors, - ARDUINOJSON_EXPAND6({1e-1f, 1e-2f, 1e-4f, 1e-8f, 1e-16f, 1e-32f})); - return ARDUINOJSON_READ_STATIC_ARRAY(T, factors, index); - } - static T negativeBinaryPowerOfTenPlusOne(int index) { - ARDUINOJSON_DEFINE_STATIC_ARRAY( - T, factors, - ARDUINOJSON_EXPAND6({1e0f, 1e-1f, 1e-3f, 1e-7f, 1e-15f, 1e-31f})); - return ARDUINOJSON_READ_STATIC_ARRAY(T, factors, index); - } - static T forge(uint32_t bits) { - return alias_cast(bits); - } - static T nan() { - return forge(0x7fc00000); - } - static T inf() { - return forge(0x7f800000); - } - static T highest() { - return forge(0x7f7fffff); - } - static T lowest() { - return forge(0xFf7fffff); - } -}; -#ifndef isdigit -inline bool isdigit(char c) { - return '0' <= c && c <= '9'; -} -#endif -inline bool issign(char c) { - return '-' == c || c == '+'; -} -template -struct choose_largest : conditional<(sizeof(A) > sizeof(B)), A, B> {}; -inline bool parseNumber(const char* s, VariantData& result) { - typedef FloatTraits traits; - typedef choose_largest::type mantissa_t; - typedef traits::exponent_type exponent_t; - ARDUINOJSON_ASSERT(s != 0); - bool is_negative = false; - switch (*s) { - case '-': - is_negative = true; - s++; - break; - case '+': - s++; - break; - } -#if ARDUINOJSON_ENABLE_NAN - if (*s == 'n' || *s == 'N') { - result.setFloat(traits::nan()); - return true; - } -#endif -#if ARDUINOJSON_ENABLE_INFINITY - if (*s == 'i' || *s == 'I') { - result.setFloat(is_negative ? -traits::inf() : traits::inf()); - return true; - } -#endif - if (!isdigit(*s) && *s != '.') - return false; - mantissa_t mantissa = 0; - exponent_t exponent_offset = 0; - const mantissa_t maxUint = UInt(-1); - while (isdigit(*s)) { - uint8_t digit = uint8_t(*s - '0'); - if (mantissa > maxUint / 10) - break; - mantissa *= 10; - if (mantissa > maxUint - digit) - break; - mantissa += digit; - s++; - } - if (*s == '\0') { - if (is_negative) { - const mantissa_t sintMantissaMax = mantissa_t(1) - << (sizeof(Integer) * 8 - 1); - if (mantissa <= sintMantissaMax) { - result.setInteger(Integer(~mantissa + 1)); - return true; - } - } else { - result.setInteger(UInt(mantissa)); - return true; - } - } - while (mantissa > traits::mantissa_max) { - mantissa /= 10; - exponent_offset++; - } - while (isdigit(*s)) { - exponent_offset++; - s++; - } - if (*s == '.') { - s++; - while (isdigit(*s)) { - if (mantissa < traits::mantissa_max / 10) { - mantissa = mantissa * 10 + uint8_t(*s - '0'); - exponent_offset--; - } - s++; - } - } - int exponent = 0; - if (*s == 'e' || *s == 'E') { - s++; - bool negative_exponent = false; - if (*s == '-') { - negative_exponent = true; - s++; - } else if (*s == '+') { - s++; - } - while (isdigit(*s)) { - exponent = exponent * 10 + (*s - '0'); - if (exponent + exponent_offset > traits::exponent_max) { - if (negative_exponent) - result.setFloat(is_negative ? -0.0f : 0.0f); - else - result.setFloat(is_negative ? -traits::inf() : traits::inf()); - return true; - } - s++; - } - if (negative_exponent) - exponent = -exponent; - } - exponent += exponent_offset; - if (*s != '\0') - return false; - Float final_result = - traits::make_float(static_cast(mantissa), exponent); - result.setFloat(is_negative ? -final_result : final_result); - return true; -} -template -inline T parseNumber(const char* s) { - VariantData value; - value.init(); // VariantData is a POD, so it has no constructor - parseNumber(s, value); - return Converter::fromJson(VariantConstRef(&value)); -} -template -inline T VariantData::asIntegral() const { - switch (type()) { - case VALUE_IS_BOOLEAN: - return _content.asBoolean; - case VALUE_IS_UNSIGNED_INTEGER: - return convertNumber(_content.asUnsignedInteger); - case VALUE_IS_SIGNED_INTEGER: - return convertNumber(_content.asSignedInteger); - case VALUE_IS_LINKED_STRING: - case VALUE_IS_OWNED_STRING: - return parseNumber(_content.asString); - case VALUE_IS_FLOAT: - return convertNumber(_content.asFloat); - default: - return 0; - } -} -inline bool VariantData::asBoolean() const { - switch (type()) { - case VALUE_IS_BOOLEAN: - return _content.asBoolean; - case VALUE_IS_SIGNED_INTEGER: - case VALUE_IS_UNSIGNED_INTEGER: - return _content.asUnsignedInteger != 0; - case VALUE_IS_FLOAT: - return _content.asFloat != 0; - case VALUE_IS_NULL: - return false; - default: - return true; - } -} -template -inline T VariantData::asFloat() const { - switch (type()) { - case VALUE_IS_BOOLEAN: - return static_cast(_content.asBoolean); - case VALUE_IS_UNSIGNED_INTEGER: - return static_cast(_content.asUnsignedInteger); - case VALUE_IS_SIGNED_INTEGER: - return static_cast(_content.asSignedInteger); - case VALUE_IS_LINKED_STRING: - case VALUE_IS_OWNED_STRING: - return parseNumber(_content.asString); - case VALUE_IS_FLOAT: - return static_cast(_content.asFloat); - default: - return 0; - } -} -inline const char *VariantData::asString() const { - switch (type()) { - case VALUE_IS_LINKED_STRING: - case VALUE_IS_OWNED_STRING: - return _content.asString; - default: - return 0; - } -} -template -inline typename enable_if::value, ArrayRef>::type -VariantRef::to() const { - return ArrayRef(_pool, variantToArray(_data)); -} -template -typename enable_if::value, ObjectRef>::type -VariantRef::to() const { - return ObjectRef(_pool, variantToObject(_data)); -} -template -typename enable_if::value, VariantRef>::type -VariantRef::to() const { - variantSetNull(_data); - return *this; -} -inline VariantConstRef VariantConstRef::getElement(size_t index) const { - return ArrayConstRef(_data != 0 ? _data->asArray() : 0)[index]; -} -inline VariantRef VariantRef::addElement() const { - return VariantRef(_pool, variantAddElement(_data, _pool)); -} -inline VariantRef VariantRef::getElement(size_t index) const { - return VariantRef(_pool, _data != 0 ? _data->getElement(index) : 0); -} -inline VariantRef VariantRef::getOrAddElement(size_t index) const { - return VariantRef(_pool, variantGetOrAddElement(_data, index, _pool)); -} -template -inline VariantRef VariantRef::getMember(TChar *key) const { - return VariantRef(_pool, _data != 0 ? _data->getMember(adaptString(key)) : 0); -} -template -inline typename enable_if::value, VariantRef>::type -VariantRef::getMember(const TString &key) const { - return VariantRef(_pool, _data != 0 ? _data->getMember(adaptString(key)) : 0); -} -template -inline VariantRef VariantRef::getOrAddMember(TChar *key) const { - return VariantRef(_pool, variantGetOrAddMember(_data, key, _pool)); -} -template -inline VariantRef VariantRef::getOrAddMember(const TString &key) const { - return VariantRef(_pool, variantGetOrAddMember(_data, key, _pool)); -} -inline VariantConstRef operator|(VariantConstRef preferedValue, - VariantConstRef defaultValue) { - return preferedValue ? preferedValue : defaultValue; -} -inline bool VariantRef::set(char value) const { - return set(value); -} -} // namespace ARDUINOJSON_NAMESPACE -#if ARDUINOJSON_ENABLE_STD_STREAM -#include -#endif -namespace ARDUINOJSON_NAMESPACE { -class DeserializationError { - typedef void (DeserializationError::*bool_type)() const; - void safeBoolHelper() const {} - public: - enum Code { - Ok, - EmptyInput, - IncompleteInput, - InvalidInput, - NoMemory, - TooDeep - }; - DeserializationError() {} - DeserializationError(Code c) : _code(c) {} - friend bool operator==(const DeserializationError& lhs, - const DeserializationError& rhs) { - return lhs._code == rhs._code; - } - friend bool operator!=(const DeserializationError& lhs, - const DeserializationError& rhs) { - return lhs._code != rhs._code; - } - friend bool operator==(const DeserializationError& lhs, Code rhs) { - return lhs._code == rhs; - } - friend bool operator==(Code lhs, const DeserializationError& rhs) { - return lhs == rhs._code; - } - friend bool operator!=(const DeserializationError& lhs, Code rhs) { - return lhs._code != rhs; - } - friend bool operator!=(Code lhs, const DeserializationError& rhs) { - return lhs != rhs._code; - } - operator bool_type() const { - return _code != Ok ? &DeserializationError::safeBoolHelper : 0; - } - friend bool operator==(bool value, const DeserializationError& err) { - return static_cast(err) == value; - } - friend bool operator==(const DeserializationError& err, bool value) { - return static_cast(err) == value; - } - friend bool operator!=(bool value, const DeserializationError& err) { - return static_cast(err) != value; - } - friend bool operator!=(const DeserializationError& err, bool value) { - return static_cast(err) != value; - } - Code code() const { - return _code; - } - const char* c_str() const { - static const char* messages[] = { - "Ok", "EmptyInput", "IncompleteInput", - "InvalidInput", "NoMemory", "TooDeep"}; - ARDUINOJSON_ASSERT(static_cast(_code) < - sizeof(messages) / sizeof(messages[0])); - return messages[_code]; - } -#if ARDUINOJSON_ENABLE_PROGMEM - const __FlashStringHelper* f_str() const { - ARDUINOJSON_DEFINE_STATIC_ARRAY(char, s0, "Ok"); - ARDUINOJSON_DEFINE_STATIC_ARRAY(char, s1, "EmptyInput"); - ARDUINOJSON_DEFINE_STATIC_ARRAY(char, s2, "IncompleteInput"); - ARDUINOJSON_DEFINE_STATIC_ARRAY(char, s3, "InvalidInput"); - ARDUINOJSON_DEFINE_STATIC_ARRAY(char, s4, "NoMemory"); - ARDUINOJSON_DEFINE_STATIC_ARRAY(char, s5, "TooDeep"); - ARDUINOJSON_DEFINE_STATIC_ARRAY( - const char*, messages, ARDUINOJSON_EXPAND6({s0, s1, s2, s3, s4, s5})); - return ARDUINOJSON_READ_STATIC_ARRAY(const __FlashStringHelper*, messages, - _code); - } -#endif - private: - Code _code; -}; -#if ARDUINOJSON_ENABLE_STD_STREAM -inline std::ostream& operator<<(std::ostream& s, - const DeserializationError& e) { - s << e.c_str(); - return s; -} -inline std::ostream& operator<<(std::ostream& s, DeserializationError::Code c) { - s << DeserializationError(c).c_str(); - return s; -} -#endif -class Filter { - public: - explicit Filter(VariantConstRef v) : _variant(v) {} - bool allow() const { - return _variant; - } - bool allowArray() const { - return _variant == true || _variant.is(); - } - bool allowObject() const { - return _variant == true || _variant.is(); - } - bool allowValue() const { - return _variant == true; - } - template - Filter operator[](const TKey& key) const { - if (_variant == true) // "true" means "allow recursively" - return *this; - else - return Filter(_variant[key] | _variant["*"]); - } - private: - VariantConstRef _variant; -}; -struct AllowAllFilter { - bool allow() const { - return true; - } - bool allowArray() const { - return true; - } - bool allowObject() const { - return true; - } - bool allowValue() const { - return true; - } - template - AllowAllFilter operator[](const TKey&) const { - return AllowAllFilter(); - } -}; -class NestingLimit { - public: - NestingLimit() : _value(ARDUINOJSON_DEFAULT_NESTING_LIMIT) {} - explicit NestingLimit(uint8_t n) : _value(n) {} - NestingLimit decrement() const { - ARDUINOJSON_ASSERT(_value > 0); - return NestingLimit(static_cast(_value - 1)); - } - bool reached() const { - return _value == 0; - } - private: - uint8_t _value; -}; -template -struct Reader { - public: - Reader(TSource& source) : _source(&source) {} - int read() { - return _source->read(); - } - size_t readBytes(char* buffer, size_t length) { - return _source->readBytes(buffer, length); - } - private: - TSource* _source; -}; -template -struct BoundedReader { -}; -template -class IteratorReader { - TIterator _ptr, _end; - public: - explicit IteratorReader(TIterator begin, TIterator end) - : _ptr(begin), _end(end) {} - int read() { - if (_ptr < _end) - return static_cast(*_ptr++); - else - return -1; - } - size_t readBytes(char* buffer, size_t length) { - size_t i = 0; - while (i < length && _ptr < _end) buffer[i++] = *_ptr++; - return i; - } -}; -template -struct void_ { - typedef void type; -}; -template -struct Reader::type> - : IteratorReader { - explicit Reader(const TSource& source) - : IteratorReader(source.begin(), - source.end()) {} -}; -template -struct IsCharOrVoid { - static const bool value = - is_same::value || is_same::value || - is_same::value || is_same::value; -}; -template -struct IsCharOrVoid : IsCharOrVoid {}; -template -struct Reader::value>::type> { - const char* _ptr; - public: - explicit Reader(const void* ptr) - : _ptr(ptr ? reinterpret_cast(ptr) : "") {} - int read() { - return static_cast(*_ptr++); - } - size_t readBytes(char* buffer, size_t length) { - for (size_t i = 0; i < length; i++) buffer[i] = *_ptr++; - return length; - } -}; -template -struct BoundedReader::value>::type> - : public IteratorReader { - public: - explicit BoundedReader(const void* ptr, size_t len) - : IteratorReader(reinterpret_cast(ptr), - reinterpret_cast(ptr) + len) {} -}; -template -struct Reader, void> : Reader { - explicit Reader(const ElementProxy& x) - : Reader(x.template as()) {} -}; -template -struct Reader, void> : Reader { - explicit Reader(const MemberProxy& x) - : Reader(x.template as()) {} -}; -template <> -struct Reader : Reader { - explicit Reader(VariantRef x) : Reader(x.as()) {} -}; -template <> -struct Reader : Reader { - explicit Reader(VariantConstRef x) - : Reader(x.as()) {} -}; -} // namespace ARDUINOJSON_NAMESPACE -#if ARDUINOJSON_ENABLE_ARDUINO_STREAM -namespace ARDUINOJSON_NAMESPACE { -template -struct Reader::value>::type> { - public: - explicit Reader(Stream& stream) : _stream(&stream) {} - int read() { - char c; - return _stream->readBytes(&c, 1) ? static_cast(c) : -1; - } - size_t readBytes(char* buffer, size_t length) { - return _stream->readBytes(buffer, length); - } - private: - Stream* _stream; -}; -} // namespace ARDUINOJSON_NAMESPACE -#endif -#if ARDUINOJSON_ENABLE_ARDUINO_STRING -namespace ARDUINOJSON_NAMESPACE { -template -struct Reader::value>::type> - : BoundedReader { - explicit Reader(const ::String& s) - : BoundedReader(s.c_str(), s.length()) {} -}; -} // namespace ARDUINOJSON_NAMESPACE -#endif -#if ARDUINOJSON_ENABLE_PROGMEM -namespace ARDUINOJSON_NAMESPACE { -template <> -struct Reader { - const char* _ptr; - public: - explicit Reader(const __FlashStringHelper* ptr) - : _ptr(reinterpret_cast(ptr)) {} - int read() { - return pgm_read_byte(_ptr++); - } - size_t readBytes(char* buffer, size_t length) { - memcpy_P(buffer, _ptr, length); - _ptr += length; - return length; - } -}; -template <> -struct BoundedReader { - const char* _ptr; - const char* _end; - public: - explicit BoundedReader(const __FlashStringHelper* ptr, size_t size) - : _ptr(reinterpret_cast(ptr)), _end(_ptr + size) {} - int read() { - if (_ptr < _end) - return pgm_read_byte(_ptr++); - else - return -1; - } - size_t readBytes(char* buffer, size_t length) { - size_t available = static_cast(_end - _ptr); - if (available < length) - length = available; - memcpy_P(buffer, _ptr, length); - _ptr += length; - return length; - } -}; -} // namespace ARDUINOJSON_NAMESPACE -#endif -#if ARDUINOJSON_ENABLE_STD_STREAM -#include -namespace ARDUINOJSON_NAMESPACE { -template -struct Reader::value>::type> { - public: - explicit Reader(std::istream& stream) : _stream(&stream) {} - int read() { - return _stream->get(); - } - size_t readBytes(char* buffer, size_t length) { - _stream->read(buffer, static_cast(length)); - return static_cast(_stream->gcount()); - } - private: - std::istream* _stream; -}; -} // namespace ARDUINOJSON_NAMESPACE -#endif -namespace ARDUINOJSON_NAMESPACE { -class StringCopier { - public: - StringCopier(MemoryPool& pool) : _pool(&pool) {} - void startString() { - _pool->getFreeZone(&_ptr, &_capacity); - _size = 0; - } - const char* save() { - ARDUINOJSON_ASSERT(_ptr); - return _pool->saveStringFromFreeZone(_size); - } - void append(const char* s) { - while (*s) append(*s++); - } - void append(const char* s, size_t n) { - while (n-- > 0) append(*s++); - } - void append(char c) { - if (!_ptr) - return; - if (_size >= _capacity) { - _ptr = 0; - _pool->markAsOverflowed(); - return; - } - _ptr[_size++] = c; - } - bool isValid() { - return _ptr != 0; - } - const char* c_str() { - return _ptr; - } - typedef storage_policies::store_by_copy storage_policy; - private: - MemoryPool* _pool; - char* _ptr; - size_t _size, _capacity; -}; -class StringMover { - public: - StringMover(char* ptr) : _writePtr(ptr) {} - void startString() { - _startPtr = _writePtr; - } - const char* save() const { - return _startPtr; - } - void append(char c) { - *_writePtr++ = c; - } - bool isValid() const { - return true; - } - const char* c_str() const { - return _startPtr; - } - typedef storage_policies::store_by_address storage_policy; - private: - char* _writePtr; - char* _startPtr; -}; -template -StringCopier makeStringStorage(TInput&, MemoryPool& pool) { - return StringCopier(pool); -} -template -StringMover makeStringStorage( - TChar* input, MemoryPool&, - typename enable_if::value>::type* = 0) { - return StringMover(reinterpret_cast(input)); -} -template