|
|
|
#pragma once |
|
|
|
#include <stdint.h> |
|
#include <stddef.h> |
|
#include <assert.h> |
|
|
|
enum JsonTag { |
|
JSON_NUMBER = 0, |
|
JSON_STRING, |
|
JSON_ARRAY, |
|
JSON_OBJECT, |
|
JSON_TRUE, |
|
JSON_FALSE, |
|
JSON_NULL = 0xF |
|
}; |
|
|
|
struct JsonNode; |
|
|
|
#define JSON_VALUE_PAYLOAD_MASK 0x00007FFFFFFFFFFFULL |
|
#define JSON_VALUE_NAN_MASK 0x7FF8000000000000ULL |
|
#define JSON_VALUE_TAG_MASK 0xF |
|
#define JSON_VALUE_TAG_SHIFT 47 |
|
|
|
union JsonValue { |
|
uint64_t ival; |
|
double fval; |
|
|
|
JsonValue(double x) |
|
: fval(x) { |
|
} |
|
JsonValue(JsonTag tag = JSON_NULL, void *payload = nullptr) { |
|
assert((uintptr_t)payload <= JSON_VALUE_PAYLOAD_MASK); |
|
ival = JSON_VALUE_NAN_MASK | ((uint64_t)tag << JSON_VALUE_TAG_SHIFT) | (uintptr_t)payload; |
|
} |
|
bool isDouble() const { |
|
return (int64_t)ival <= (int64_t)JSON_VALUE_NAN_MASK; |
|
} |
|
JsonTag getTag() const { |
|
return isDouble() ? JSON_NUMBER : JsonTag((ival >> JSON_VALUE_TAG_SHIFT) & JSON_VALUE_TAG_MASK); |
|
} |
|
uint64_t getPayload() const { |
|
assert(!isDouble()); |
|
return ival & JSON_VALUE_PAYLOAD_MASK; |
|
} |
|
double toNumber() const { |
|
assert(getTag() == JSON_NUMBER); |
|
return fval; |
|
} |
|
char *toString() const { |
|
assert(getTag() == JSON_STRING); |
|
return (char *)getPayload(); |
|
} |
|
JsonNode *toNode() const { |
|
assert(getTag() == JSON_ARRAY || getTag() == JSON_OBJECT); |
|
return (JsonNode *)getPayload(); |
|
} |
|
}; |
|
|
|
struct JsonNode { |
|
JsonValue value; |
|
JsonNode *next; |
|
char *key; |
|
}; |
|
|
|
struct JsonIterator { |
|
JsonNode *p; |
|
|
|
void operator++() { |
|
p = p->next; |
|
} |
|
bool operator!=(const JsonIterator &x) const { |
|
return p != x.p; |
|
} |
|
JsonNode *operator*() const { |
|
return p; |
|
} |
|
JsonNode *operator->() const { |
|
return p; |
|
} |
|
}; |
|
|
|
inline JsonIterator begin(JsonValue o) { |
|
return JsonIterator{o.toNode()}; |
|
} |
|
inline JsonIterator end(JsonValue) { |
|
return JsonIterator{nullptr}; |
|
} |
|
|
|
#define JSON_ERRNO_MAP(XX) \ |
|
XX(OK, "ok") \ |
|
XX(BAD_NUMBER, "bad number") \ |
|
XX(BAD_STRING, "bad string") \ |
|
XX(BAD_IDENTIFIER, "bad identifier") \ |
|
XX(STACK_OVERFLOW, "stack overflow") \ |
|
XX(STACK_UNDERFLOW, "stack underflow") \ |
|
XX(MISMATCH_BRACKET, "mismatch bracket") \ |
|
XX(UNEXPECTED_CHARACTER, "unexpected character") \ |
|
XX(UNQUOTED_KEY, "unquoted key") \ |
|
XX(BREAKING_BAD, "breaking bad") \ |
|
XX(ALLOCATION_FAILURE, "allocation failure") |
|
|
|
enum JsonErrno { |
|
#define XX(no, str) JSON_##no, |
|
JSON_ERRNO_MAP(XX) |
|
#undef XX |
|
}; |
|
|
|
const char *jsonStrError(int err); |
|
|
|
class JsonAllocator { |
|
struct Zone { |
|
Zone *next; |
|
size_t used; |
|
} *head = nullptr; |
|
|
|
public: |
|
JsonAllocator() = default; |
|
JsonAllocator(const JsonAllocator &) = delete; |
|
JsonAllocator &operator=(const JsonAllocator &) = delete; |
|
JsonAllocator(JsonAllocator &&x) : head(x.head) { |
|
x.head = nullptr; |
|
} |
|
JsonAllocator &operator=(JsonAllocator &&x) { |
|
head = x.head; |
|
x.head = nullptr; |
|
return *this; |
|
} |
|
~JsonAllocator() { |
|
deallocate(); |
|
} |
|
void *allocate(size_t size); |
|
void deallocate(); |
|
}; |
|
|
|
int jsonParse(char *str, char **endptr, JsonValue *value, JsonAllocator &allocator); |
|
|