CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
Path: blob/master/ext/gason/gason.cpp
Views: 1401
#include "gason.h"1#include <stdlib.h>23#define JSON_ZONE_SIZE 40964#define JSON_STACK_SIZE 3256const char *jsonStrError(int err) {7switch (err) {8#define XX(no, str) \9case JSON_##no: \10return str;11JSON_ERRNO_MAP(XX)12#undef XX13default:14return "unknown";15}16}1718void *JsonAllocator::allocate(size_t size) {19size = (size + 7) & ~7;2021if (head && head->used + size <= JSON_ZONE_SIZE) {22char *p = (char *)head + head->used;23head->used += size;24return p;25}2627size_t allocSize = sizeof(Zone) + size;28Zone *zone = (Zone *)malloc(allocSize <= JSON_ZONE_SIZE ? JSON_ZONE_SIZE : allocSize);29if (zone == nullptr)30return nullptr;31zone->used = allocSize;32if (allocSize <= JSON_ZONE_SIZE || head == nullptr) {33zone->next = head;34head = zone;35} else {36zone->next = head->next;37head->next = zone;38}39return (char *)zone + sizeof(Zone);40}4142void JsonAllocator::deallocate() {43while (head) {44Zone *next = head->next;45free(head);46head = next;47}48}4950static inline bool isspace(char c) {51return c == ' ' || (c >= '\t' && c <= '\r');52}5354static inline bool isdelim(char c) {55return c == ',' || c == ':' || c == ']' || c == '}' || isspace(c) || !c;56}5758static inline bool isdigit(char c) {59return c >= '0' && c <= '9';60}6162static inline bool isxdigit(char c) {63return (c >= '0' && c <= '9') || ((c & ~' ') >= 'A' && (c & ~' ') <= 'F');64}6566static inline int char2int(char c) {67if (c <= '9')68return c - '0';69return (c & ~' ') - 'A' + 10;70}7172static double string2double(char *s, char **endptr) {73char ch = *s;74if (ch == '-')75++s;7677double result = 0;78while (isdigit(*s))79result = (result * 10) + (*s++ - '0');8081if (*s == '.') {82++s;8384double fraction = 1;85while (isdigit(*s)) {86fraction *= 0.1;87result += (*s++ - '0') * fraction;88}89}9091if (*s == 'e' || *s == 'E') {92++s;9394double base = 10;95if (*s == '+')96++s;97else if (*s == '-') {98++s;99base = 0.1;100}101102unsigned int exponent = 0;103while (isdigit(*s))104exponent = (exponent * 10) + (*s++ - '0');105106double power = 1;107for (; exponent; exponent >>= 1, base *= base)108if (exponent & 1)109power *= base;110111result *= power;112}113114*endptr = s;115return ch == '-' ? -result : result;116}117118static inline JsonNode *insertAfter(JsonNode *tail, JsonNode *node) {119if (!tail)120return node->next = node;121node->next = tail->next;122tail->next = node;123return node;124}125126static inline JsonValue listToValue(JsonTag tag, JsonNode *tail) {127if (tail) {128auto head = tail->next;129tail->next = nullptr;130return JsonValue(tag, head);131}132return JsonValue(tag, nullptr);133}134135int jsonParse(char *s, char **endptr, JsonValue *value, JsonAllocator &allocator) {136JsonNode *tails[JSON_STACK_SIZE];137JsonTag tags[JSON_STACK_SIZE];138char *keys[JSON_STACK_SIZE];139JsonValue o;140int pos = -1;141bool separator = true;142JsonNode *node;143*endptr = s;144145while (*s) {146while (isspace(*s)) {147++s;148if (!*s) break;149}150*endptr = s++;151switch (**endptr) {152case '-':153if (!isdigit(*s) && *s != '.') {154*endptr = s;155return JSON_BAD_NUMBER;156}157case '0':158case '1':159case '2':160case '3':161case '4':162case '5':163case '6':164case '7':165case '8':166case '9':167o = JsonValue(string2double(*endptr, &s));168if (!isdelim(*s)) {169*endptr = s;170return JSON_BAD_NUMBER;171}172break;173case '"':174o = JsonValue(JSON_STRING, s);175for (char *it = s; *s; ++it, ++s) {176int c = *it = *s;177if (c == '\\') {178c = *++s;179switch (c) {180case '\\':181case '"':182case '/':183*it = c;184break;185case 'b':186*it = '\b';187break;188case 'f':189*it = '\f';190break;191case 'n':192*it = '\n';193break;194case 'r':195*it = '\r';196break;197case 't':198*it = '\t';199break;200case 'u':201c = 0;202for (int i = 0; i < 4; ++i) {203if (isxdigit(*++s)) {204c = c * 16 + char2int(*s);205} else {206*endptr = s;207return JSON_BAD_STRING;208}209}210if (c < 0x80) {211*it = c;212} else if (c < 0x800) {213*it++ = 0xC0 | (c >> 6);214*it = 0x80 | (c & 0x3F);215} else {216*it++ = 0xE0 | (c >> 12);217*it++ = 0x80 | ((c >> 6) & 0x3F);218*it = 0x80 | (c & 0x3F);219}220break;221default:222*endptr = s;223return JSON_BAD_STRING;224}225} else if ((unsigned int)c < ' ' || c == '\x7F') {226*endptr = s;227return JSON_BAD_STRING;228} else if (c == '"') {229*it = 0;230++s;231break;232}233}234if (!isdelim(*s)) {235*endptr = s;236return JSON_BAD_STRING;237}238break;239case 't':240if (!(s[0] == 'r' && s[1] == 'u' && s[2] == 'e' && isdelim(s[3])))241return JSON_BAD_IDENTIFIER;242o = JsonValue(JSON_TRUE);243s += 3;244break;245case 'f':246if (!(s[0] == 'a' && s[1] == 'l' && s[2] == 's' && s[3] == 'e' && isdelim(s[4])))247return JSON_BAD_IDENTIFIER;248o = JsonValue(JSON_FALSE);249s += 4;250break;251case 'n':252if (!(s[0] == 'u' && s[1] == 'l' && s[2] == 'l' && isdelim(s[3])))253return JSON_BAD_IDENTIFIER;254o = JsonValue(JSON_NULL);255s += 3;256break;257case ']':258if (pos == -1)259return JSON_STACK_UNDERFLOW;260if (tags[pos] != JSON_ARRAY)261return JSON_MISMATCH_BRACKET;262o = listToValue(JSON_ARRAY, tails[pos--]);263break;264case '}':265if (pos == -1)266return JSON_STACK_UNDERFLOW;267if (tags[pos] != JSON_OBJECT)268return JSON_MISMATCH_BRACKET;269if (keys[pos] != nullptr)270return JSON_UNEXPECTED_CHARACTER;271o = listToValue(JSON_OBJECT, tails[pos--]);272break;273case '[':274if (++pos == JSON_STACK_SIZE)275return JSON_STACK_OVERFLOW;276tails[pos] = nullptr;277tags[pos] = JSON_ARRAY;278keys[pos] = nullptr;279separator = true;280continue;281case '{':282if (++pos == JSON_STACK_SIZE)283return JSON_STACK_OVERFLOW;284tails[pos] = nullptr;285tags[pos] = JSON_OBJECT;286keys[pos] = nullptr;287separator = true;288continue;289case ':':290if (separator || keys[pos] == nullptr)291return JSON_UNEXPECTED_CHARACTER;292separator = true;293continue;294case ',':295if (separator || keys[pos] != nullptr)296return JSON_UNEXPECTED_CHARACTER;297separator = true;298continue;299case '\0':300continue;301default:302return JSON_UNEXPECTED_CHARACTER;303}304305separator = false;306307if (pos == -1) {308*endptr = s;309*value = o;310return JSON_OK;311}312313if (tags[pos] == JSON_OBJECT) {314if (!keys[pos]) {315if (o.getTag() != JSON_STRING)316return JSON_UNQUOTED_KEY;317keys[pos] = o.toString();318continue;319}320if ((node = (JsonNode *) allocator.allocate(sizeof(JsonNode))) == nullptr)321return JSON_ALLOCATION_FAILURE;322tails[pos] = insertAfter(tails[pos], node);323tails[pos]->key = keys[pos];324keys[pos] = nullptr;325} else {326if ((node = (JsonNode *) allocator.allocate(sizeof(JsonNode) - sizeof(char *))) == nullptr)327return JSON_ALLOCATION_FAILURE;328tails[pos] = insertAfter(tails[pos], node);329}330tails[pos]->value = o;331}332return JSON_BREAKING_BAD;333}334335336