Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // File: pjson.h - written by Rich Geldreich 2012 - License: Unlicense http://unlicense.org/
- #ifndef PURPLE_JSON_H
- #define PURPLE_JSON_H
- #ifdef WIN32
- #pragma once
- #endif
- #include <string>
- #include <vector>
- #include <limits>
- #include <assert.h>
- // ---- Macros
- #define PJSON_ASSERT assert
- #define PJSON_FORCEINLINE __forceinline
- #define PJSON_PARSE_STATS 0
- #define PJSON_DEFAULT_MIN_CHUNK_SIZE 4096
- #define PJSON_MAX_CHUNK_GROW_SIZE 8*1024*1024
- #define PJSON_DEFAULT_MAX_BYTES_TO_PRESERVE_ACROSS_RESETS 16*1024*1024
- #define PJSON_MIN(a, b) (((a) < (b)) ? (a) : (b))
- #define PJSON_MAX(a, b) (((a) < (b)) ? (b) : (a))
- namespace pjson
- {
- // ---- Types
- typedef unsigned char uint8;
- typedef unsigned int uint;
- typedef signed int int32;
- typedef unsigned int uint32;
- typedef signed __int64 int64;
- typedef unsigned __int64 uint64;
- class document;
- class value_variant;
- struct value_variant_data;
- struct key_value_t;
- typedef std::vector<char> char_vec_t;
- typedef std::string string_t;
- // Memory allocation
- inline void* pjson_malloc(size_t size) { return malloc(size); }
- inline void* pjson_realloc(void* p, size_t size) { return realloc(p, size); }
- inline void pjson_free(void* p) { free(p); }
- // Misc. Helpers
- template<typename T> inline void swap(T& l, T& r) { T temp(l); l = r; r = temp; }
- inline bool is_power_of_2(uint32 x) { return x && ((x & (x - 1U)) == 0U); }
- inline uint32 next_pow2(uint32 val) { val--; val |= val >> 16; val |= val >> 8; val |= val >> 4; val |= val >> 2; val |= val >> 1; return val + 1; }
- inline int pjson_stricmp(const char* p, const char* q) { return _stricmp(p, q); }
- // ---- Global Arrays
- // This template utilizes the One Definition Rule to create global arrays in a header.
- template<typename unused=void>
- struct globals_struct
- {
- static const uint8 s_str_serialize_flags[256];
- static const double s_pow10_table[63];
- static const uint8 s_parse_flags[256];
- };
- typedef globals_struct<> globals;
- template<typename unused>
- const uint8 globals_struct<unused>::s_str_serialize_flags[256] =
- {
- // 0 1 2 3 4 5 6 7 8 9 A B C D E F
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1
- 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, // 5
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 6
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 7
- // 128-255
- 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0
- };
- template<typename unused>
- const double globals_struct<unused>::s_pow10_table[63] =
- {
- 1.e-031,1.e-030,1.e-029,1.e-028,1.e-027,1.e-026,1.e-025,1.e-024,1.e-023,1.e-022,1.e-021,1.e-020,1.e-019,1.e-018,1.e-017,1.e-016,
- 1.e-015,1.e-014,1.e-013,1.e-012,1.e-011,1.e-010,1.e-009,1.e-008,1.e-007,1.e-006,1.e-005,1.e-004,1.e-003,1.e-002,1.e-001,1.e+000,
- 1.e+001,1.e+002,1.e+003,1.e+004,1.e+005,1.e+006,1.e+007,1.e+008,1.e+009,1.e+010,1.e+011,1.e+012,1.e+013,1.e+014,1.e+015,1.e+016,
- 1.e+017,1.e+018,1.e+019,1.e+020,1.e+021,1.e+022,1.e+023,1.e+024,1.e+025,1.e+026,1.e+027,1.e+028,1.e+029,1.e+030,1.e+031
- };
- // bit 0 (1) - set if: \0 cr lf " \
- // bit 1 (2) - set if: \0 cr lf
- // bit 2 (4) - set if: whitespace
- // bit 3 (8) - set if: 0-9
- // bit 4 (0x10) - set if: 0-9 e E .
- template<typename unused>
- const uint8 globals_struct<unused>::s_parse_flags[256] =
- {
- // 0 1 2 3 4 5 6 7 8 9 A B C D E F
- 7, 4, 4, 4, 4, 4, 4, 4, 4, 4, 7, 4, 4, 7, 4, 4, // 0
- 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, // 1
- 4, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10,0, // 2
- 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, 0x18,0x18,0, 0, 0, 0, 0, 0, // 3
- 0, 0, 0, 0, 0, 0x10,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, // 5
- 0, 0, 0, 0, 0, 0x10,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 6
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 7
- // 128-255
- 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0
- };
- // ---- Pool Allocator
- struct pool_allocator
- {
- inline pool_allocator(uint initial_size = 0, uint min_chunk_size = PJSON_DEFAULT_MIN_CHUNK_SIZE, size_t max_bytes_to_preserve_across_resets = PJSON_DEFAULT_MAX_BYTES_TO_PRESERVE_ACROSS_RESETS) :
- m_pActive_chunks(NULL),
- m_pFree_chunks(NULL),
- m_total_free_bytes(0),
- m_initial_size(initial_size),
- m_min_chunk_size(min_chunk_size),
- m_cur_grow_size(min_chunk_size),
- m_max_to_preserve_across_resets(max_bytes_to_preserve_across_resets)
- {
- if (initial_size)
- {
- m_pActive_chunks = static_cast<chunk*>(pjson_malloc(sizeof(chunk) + initial_size));
- m_pActive_chunks->m_pNext = NULL;
- m_pActive_chunks->m_ofs = 0;
- m_pActive_chunks->m_size = initial_size;
- }
- }
- inline ~pool_allocator()
- {
- clear();
- }
- // Release all active/free chunks
- void clear()
- {
- free_chunk_chain(m_pActive_chunks);
- m_pActive_chunks = NULL;
- free_chunk_chain(m_pFree_chunks);
- m_pFree_chunks = NULL;
- m_total_free_bytes = 0;
- m_cur_grow_size = m_min_chunk_size;
- }
- inline size_t get_total_free_bytes() const { return m_total_free_bytes; }
- inline uint get_min_chunk_size() const { return m_min_chunk_size; }
- inline size_t get_max_bytes_to_preserve_across_resets() const { return m_max_to_preserve_across_resets; }
- inline void set_min_chunk_size(uint s) { m_min_chunk_size = m_cur_grow_size = s; }
- inline void set_max_bytes_to_preserve_across_resets(size_t s) { m_max_to_preserve_across_resets = s; }
- inline uint get_cur_grow_size() const { return m_cur_grow_size; }
- inline void* Alloc(size_t size)
- {
- size = (size + 3) & ~3;
- if ((!m_pActive_chunks) || ((m_pActive_chunks->m_size - m_pActive_chunks->m_ofs) < size))
- {
- chunk* pNew_chunk = m_pFree_chunks;
- if ((pNew_chunk) && (pNew_chunk->m_size >= size))
- {
- PJSON_ASSERT(m_total_free_bytes >= pNew_chunk->m_size);
- m_total_free_bytes -= pNew_chunk->m_size;
- m_pFree_chunks = pNew_chunk->m_pNext;
- PJSON_ASSERT(!pNew_chunk->m_ofs);
- }
- else
- {
- size_t alloc_size = PJSON_MAX(size, m_cur_grow_size);
- m_cur_grow_size = PJSON_MIN(m_cur_grow_size * 2, PJSON_MAX_CHUNK_GROW_SIZE);
- pNew_chunk = static_cast<chunk*>(pjson_malloc(sizeof(chunk) + alloc_size));
- pNew_chunk->m_size = alloc_size;
- pNew_chunk->m_ofs = 0;
- }
- pNew_chunk->m_pNext = m_pActive_chunks;
- m_pActive_chunks = pNew_chunk;
- }
- void* pRet = (uint8*)m_pActive_chunks + sizeof(chunk) + m_pActive_chunks->m_ofs;
- m_pActive_chunks->m_ofs += size;
- PJSON_ASSERT(m_pActive_chunks->m_ofs <= m_pActive_chunks->m_size);
- return pRet;
- }
- inline void* Realloc(void* p, size_t new_size, size_t cur_size)
- {
- if (!p)
- return Alloc(new_size);
- new_size = (new_size + 3) & ~3;
- cur_size = (cur_size + 3) & ~3;
- if (new_size == cur_size)
- return p;
- uint8* pTop = (uint8*)m_pActive_chunks + sizeof(chunk) + m_pActive_chunks->m_ofs;
- if ((static_cast<uint8*>(p) + cur_size) == pTop)
- {
- if (new_size > cur_size)
- {
- size_t bytes_needed = new_size - cur_size;
- if ((m_pActive_chunks->m_size - m_pActive_chunks->m_ofs) >= bytes_needed)
- {
- m_pActive_chunks->m_ofs += bytes_needed;
- PJSON_ASSERT(m_pActive_chunks->m_ofs <= m_pActive_chunks->m_size);
- return p;
- }
- }
- else
- {
- PJSON_ASSERT(m_pActive_chunks->m_ofs >= (cur_size - new_size));
- m_pActive_chunks->m_ofs -= (cur_size - new_size);
- return new_size ? p : NULL;
- }
- }
- if (!new_size)
- return NULL;
- void* pNew_block = Alloc(new_size);
- memcpy(pNew_block, p, cur_size);
- return pNew_block;
- }
- // Move all active chunks to the free chunk list, then free any chunks if we're over the preserve limit.
- inline void reset()
- {
- if (!m_pActive_chunks)
- return;
- chunk* pCur_active_tail = m_pActive_chunks;
- size_t total_allocated_bytes = 0;
- for ( ; ; )
- {
- total_allocated_bytes += pCur_active_tail->m_size;
- pCur_active_tail->m_ofs = 0;
- if (!pCur_active_tail->m_pNext)
- break;
- pCur_active_tail = pCur_active_tail->m_pNext;
- }
- pCur_active_tail->m_pNext = m_pFree_chunks;
- m_pFree_chunks = m_pActive_chunks;
- m_pActive_chunks = NULL;
- m_total_free_bytes += total_allocated_bytes;
- while (m_total_free_bytes > m_max_to_preserve_across_resets)
- {
- PJSON_ASSERT(m_pFree_chunks);
- chunk* pNext_free = m_pFree_chunks->m_pNext;
- PJSON_ASSERT(m_total_free_bytes >= m_pFree_chunks->m_size);
- m_total_free_bytes -= m_pFree_chunks->m_size;
- pjson_free(m_pFree_chunks);
- m_pFree_chunks = pNext_free;
- }
- m_cur_grow_size = m_min_chunk_size;
- }
- struct stats_t
- {
- size_t m_total_allocated;
- uint m_num_active_chunks;
- size_t m_num_active_bytes_allocated;
- size_t m_num_active_bytes_avail;
- size_t m_max_active_chunk_size;
- uint m_num_free_chunks;
- size_t m_num_free_chunk_bytes_avail;
- size_t m_max_free_chunk_size;
- };
- inline void get_stats(stats_t& s) const
- {
- memset(&s, 0, sizeof(s));
- chunk* pChunk = m_pActive_chunks;
- while (pChunk)
- {
- s.m_num_active_chunks++;
- s.m_total_allocated += pChunk->m_size;
- s.m_num_active_bytes_allocated += pChunk->m_ofs;
- s.m_num_active_bytes_avail += (pChunk->m_size - pChunk->m_ofs);
- s.m_max_active_chunk_size = PJSON_MAX(s.m_max_active_chunk_size, pChunk->m_size);
- pChunk = pChunk->m_pNext;
- }
- pChunk = m_pFree_chunks;
- while (pChunk)
- {
- s.m_num_free_chunks++;
- s.m_total_allocated += pChunk->m_size;
- PJSON_ASSERT(!pChunk->m_ofs);
- s.m_num_free_chunk_bytes_avail += pChunk->m_size;
- s.m_max_free_chunk_size = PJSON_MAX(s.m_max_free_chunk_size, pChunk->m_size);
- pChunk = pChunk->m_pNext;
- }
- PJSON_ASSERT(s.m_num_free_chunk_bytes_avail == m_total_free_bytes);
- }
- private:
- pool_allocator(const pool_allocator&);
- pool_allocator& operator= (const pool_allocator&);
- struct chunk
- {
- chunk* m_pNext;
- size_t m_size;
- size_t m_ofs;
- };
- chunk* m_pActive_chunks;
- chunk* m_pFree_chunks;
- size_t m_total_free_bytes;
- uint m_initial_size;
- uint m_min_chunk_size;
- size_t m_max_to_preserve_across_resets;
- uint m_cur_grow_size;
- inline void free_chunk_chain(chunk* pChunk)
- {
- while (pChunk)
- {
- chunk* pNext_chunk = pChunk->m_pNext;
- pjson_free(pChunk);
- pChunk = pNext_chunk;
- }
- }
- };
- // ---- Simple vector (growable array)
- template<typename T>
- struct simple_vector_default_copy_construction_policy
- {
- inline static void copy_construct(void *pDst, const T& init, pool_allocator& alloc) { alloc; new (pDst) T(init); }
- inline static void assign(void *pDst, const T& src, pool_allocator& alloc) { alloc; *static_cast<T*>(pDst) = src; }
- };
- template<typename T>
- struct simple_vector_allocator_copy_construction_policy
- {
- inline static void copy_construct(void *pDst, const T& init, pool_allocator& alloc) { alloc; new (pDst) T(init, alloc); }
- inline static void assign(void *pDst, const T& src, pool_allocator& alloc) { static_cast<T*>(pDst)->assign(src, alloc); }
- };
- template <typename T> inline T* construct(T* p) { return new (static_cast<void*>(p)) T; }
- template <typename T> inline void construct_array(T* p, uint n) { T* q = p + n; for ( ; p != q; ++p) new (static_cast<void*>(p)) T; }
- template<typename T>
- struct elemental_vector
- {
- typedef T value_type;
- typedef T& reference;
- typedef const T& const_reference;
- typedef T* pointer;
- typedef const T* const_pointer;
- T* m_p;
- uint32 m_size;
- };
- template<typename T, bool UseConstructor, typename ConstructionPolicy = simple_vector_default_copy_construction_policy<T> >
- struct simple_vector : elemental_vector<T>
- {
- inline simple_vector() { construct(); }
- inline simple_vector(const simple_vector& other, pool_allocator& alloc) { construct(other, alloc); }
- // Manual constructor methods
- inline void construct() { m_p = NULL; m_size = 0; }
- inline void construct(uint size, pool_allocator& alloc) { construct(); enlarge(size, alloc, false); }
- inline void construct(const T* p, uint size, pool_allocator& alloc)
- {
- m_size = size;
- m_p = NULL;
- if (size)
- {
- uint num_bytes = sizeof(T) * size;
- m_p = static_cast<T*>(alloc.Alloc(num_bytes));
- if (UseConstructor)
- {
- T* pDst = m_p;
- T* pDst_end = pDst + size;
- const T* pSrc = p;
- while (pDst != pDst_end)
- ConstructionPolicy::copy_construct(pDst++, *pSrc++, alloc);
- }
- else
- memcpy(m_p, p, num_bytes);
- }
- }
- inline void construct(const simple_vector& other, pool_allocator& alloc)
- {
- construct(other.m_p, other.m_size, alloc);
- }
- inline uint size() const { return m_size; }
- inline uint size_in_bytes() const { return m_size * sizeof(T); }
- inline const T& operator[] (uint i) const { PJSON_ASSERT(i < m_size); return m_p[i]; }
- inline T& operator[] (uint i) { PJSON_ASSERT(i < m_size); return m_p[i]; }
- inline const T* get_ptr() const { return m_p; }
- inline T* get_ptr() { return m_p; }
- inline const T* get_ptr(const T* pDef) const { return m_p ? m_p : pDef; }
- inline T* get_ptr(T* pDef) { return m_p ? m_p : pDef; }
- inline void clear() { m_p = NULL; m_size = 0; }
- inline void resize(uint new_size, pool_allocator& alloc)
- {
- if (new_size > m_size)
- {
- grow(new_size, alloc);
- if (UseConstructor)
- construct_array(m_p + m_size, new_size - m_size);
- }
- m_size = new_size;
- }
- inline void shrink(uint new_size)
- {
- m_size = new_size;
- }
- inline T* enlarge_no_construct(uint n, pool_allocator& alloc)
- {
- PJSON_ASSERT(n);
- uint cur_size = m_size, new_size = m_size + n;
- grow(new_size, alloc);
- m_size = new_size;
- return m_p + cur_size;
- }
- inline T* enlarge(uint n, pool_allocator& alloc)
- {
- T* p = enlarge_no_construct(n, alloc);
- if (UseConstructor)
- construct_array(p, n);
- return p;
- }
- inline void push_back(const T& obj, pool_allocator& alloc)
- {
- PJSON_ASSERT(!m_p || (&obj < m_p) || (&obj >= (m_p + m_size)));
- grow(m_size + 1, alloc);
- if (UseConstructor)
- ConstructionPolicy::copy_construct(m_p + m_size, obj, alloc);
- else
- memcpy(m_p + m_size, &obj, sizeof(T));
- m_size++;
- }
- inline void push_back(const T* p, uint n, pool_allocator& alloc)
- {
- PJSON_ASSERT(!m_p || ((p + n) <= m_p) || (p >= (m_p + m_size)));
- T* pDst = enlarge_no_construct(n, alloc);
- if (UseConstructor)
- {
- T* pDst_end = pDst + n;
- const T* pSrc = p;
- while (pDst != pDst_end)
- ConstructionPolicy::copy_construct(pDst, *pSrc++, alloc);
- }
- else
- memcpy(pDst, p, sizeof(T) * n);
- }
- inline void assign(const T* p, uint n, pool_allocator& alloc)
- {
- PJSON_ASSERT(!m_p || ((p + n) <= m_p) || (p >= (m_p + m_size)));
- const uint num_to_assign = PJSON_MIN(m_size, n);
- if (num_to_assign)
- {
- if (UseConstructor)
- {
- for (uint i = 0; i < num_to_assign; ++i)
- ConstructionPolicy::assign(&m_p[i], p[i], alloc);
- }
- else
- memcpy(m_p, p, sizeof(T) * num_to_assign);
- }
- if (n > m_size)
- push_back(p + num_to_assign, n - num_to_assign, alloc);
- else
- shrink(n);
- }
- inline void assign(const simple_vector& other, pool_allocator& alloc)
- {
- assign(other.m_p, other.m_size, alloc);
- }
- inline void erase(uint start, uint n)
- {
- PJSON_ASSERT((start + n) <= m_size);
- if ((!n) || ((start + n) > m_size))
- return;
- const uint num_to_move = m_size - (start + n);
- T* pDst = m_p + start;
- memmove(pDst, m_p + start + n, num_to_move * sizeof(T));
- m_size -= n;
- }
- inline void swap(simple_vector& other)
- {
- pjson::swap(m_p, other.m_p);
- pjson::swap(m_size, other.m_size);
- }
- inline void grow(uint new_size, pool_allocator& alloc)
- {
- if (new_size > m_size)
- m_p = static_cast<T*>(alloc.Realloc(m_p, sizeof(T) * new_size, m_size * sizeof(T)));
- }
- };
- enum json_value_type_t
- {
- cJSONValueTypeNull = 0,
- cJSONValueTypeBool,
- cJSONValueTypeInt,
- cJSONValueTypeDouble,
- // All types that follow require storage. Do not change the relative order of these types.
- cJSONValueTypeString,
- cJSONValueTypeArray,
- cJSONValueTypeObject,
- };
- // ---- struct value_variant_data
- typedef simple_vector<char, false> string_vec_t;
- typedef simple_vector<key_value_t, true, simple_vector_allocator_copy_construction_policy<key_value_t> > key_value_vec_t;
- typedef simple_vector<value_variant, true, simple_vector_allocator_copy_construction_policy<value_variant> > value_variant_vec_t;
- #pragma pack(push, 4)
- struct value_variant_data
- {
- union json_value_data_t
- {
- elemental_vector<key_value_vec_t::value_type> m_object;
- elemental_vector<value_variant_vec_t::value_type> m_array;
- elemental_vector<string_vec_t::value_type> m_string;
- int64 m_nVal;
- double m_flVal;
- };
- json_value_data_t m_data;
- json_value_type_t m_type;
- inline const string_vec_t& get_string() const { return (const string_vec_t&)m_data.m_string; }
- inline string_vec_t& get_string() { return (string_vec_t&)m_data.m_string; }
- inline const char* get_string_ptr() const { return get_string().get_ptr(""); }
- inline const value_variant_vec_t& get_array() const { return (const value_variant_vec_t&)m_data.m_array; }
- inline value_variant_vec_t& get_array() { return (value_variant_vec_t&)m_data.m_array; }
- inline const key_value_vec_t& get_object() const { return (const key_value_vec_t&)m_data.m_object; }
- inline key_value_vec_t& get_object() { return (key_value_vec_t&)m_data.m_object; }
- };
- // ---- struct key_value_t
- struct key_value_t
- {
- inline key_value_t() { }
- inline key_value_t(const key_value_t& other, pool_allocator& alloc);
- inline void assign(const key_value_t& src, pool_allocator& alloc);
- inline const string_vec_t& get_key() const { return m_key; }
- inline string_vec_t& get_key() { return m_key; }
- inline const value_variant& get_value() const { return (const value_variant&)m_value_data; }
- inline value_variant& get_value() { return (value_variant&)m_value_data; }
- string_vec_t m_key;
- value_variant_data m_value_data;
- };
- #pragma pack(pop)
- // ---- class char_vector_print_helper
- class char_vector_print_helper
- {
- char_vector_print_helper(const char_vector_print_helper&);
- char_vector_print_helper& operator= (const char_vector_print_helper&);
- public:
- inline char_vector_print_helper(char_vec_t& buf) : m_buf(buf) { }
- inline void resize(size_t new_size) { m_buf.resize(new_size); }
- inline size_t size() const { return m_buf.size(); }
- inline char* get_ptr() const { return &m_buf[0]; }
- inline const char_vec_t& get_buf() const { return m_buf; }
- inline char_vec_t& get_buf() { return m_buf; }
- inline void puts(const char* pStr, size_t l) { m_buf.insert(m_buf.end(), pStr, pStr + l); }
- inline void print_tabs(size_t n) { m_buf.insert(m_buf.end(), n, '\t'); }
- inline void print_char(char c) { m_buf.push_back(c); }
- void print_escaped(const string_vec_t& str)
- {
- const char* pStr = str.m_p;
- uint len = str.m_size; len;
- static const char* s_to_hex = "0123456789abcdef";
- print_char('\"');
- while (*pStr)
- {
- uint8 c = *pStr++;
- if ((c >= ' ') && (c != '\"') && (c != '\\'))
- print_char(c);
- else
- {
- print_char('\\');
- switch (c)
- {
- case '\b': print_char('b'); break;
- case '\r': print_char('r'); break;
- case '\t': print_char('t'); break;
- case '\f': print_char('f'); break;
- case '\n': print_char('n'); break;
- case '\\': print_char('\\'); break;
- case '\"': print_char('\"'); break;
- default: puts("u00", 3); print_char(s_to_hex[c >> 4]); print_char(s_to_hex[c & 0xF]); break;
- }
- }
- }
- print_char('\"');
- }
- private:
- char_vec_t& m_buf;
- };
- // ---- class char_buf_print_helper
- class char_buf_print_helper
- {
- char_buf_print_helper(const char_buf_print_helper&);
- char_buf_print_helper& operator= (const char_buf_print_helper&);
- public:
- inline char_buf_print_helper(char* pBuf, size_t buf_size) : m_pDst(pBuf), m_pStart(pBuf), m_pEnd(pBuf + buf_size) { }
- inline void resize(size_t new_size) { PJSON_ASSERT(new_size <= (size_t)(m_pEnd - m_pStart)); m_pDst = m_pStart + new_size; }
- inline size_t size() const { return m_pDst - m_pStart; }
- inline char* get_ptr() const { return m_pStart; }
- inline void puts(const char* pStr, size_t l) { memcpy(m_pDst, pStr, l = PJSON_MIN(l, (size_t)(m_pEnd - m_pDst))); m_pDst += l; }
- inline void print_tabs(size_t n) { n = PJSON_MIN(n, (size_t)(m_pEnd - m_pDst)); memset(m_pDst, '\t', n); m_pDst += n; }
- inline void print_char(char c) { if (m_pDst < m_pEnd) *m_pDst++ = c; }
- void print_escaped(const string_vec_t& str)
- {
- static const char* s_to_hex = "0123456789abcdef";
- const char* pStr = str.m_p;
- char* pDst = m_pDst;
- char* pEnd = m_pEnd;
- uint len = str.m_size;
- // If len!=0, it includes the terminating null, so this expression is conservative.
- if (static_cast<size_t>(pEnd - pDst) < (len + 2)) { m_pDst = pEnd; return; }
- *pDst++ = '\"';
- uint8 c = 0; if (pStr) c = pStr[0];
- while (!globals::s_str_serialize_flags[c])
- {
- pDst[0] = c; c = pStr[1]; if (globals::s_str_serialize_flags[c]) { ++pStr, ++pDst; break; }
- pDst[1] = c; c = pStr[2]; if (globals::s_str_serialize_flags[c]) { pStr += 2, pDst += 2; break; }
- pDst[2] = c; c = pStr[3]; if (globals::s_str_serialize_flags[c]) { pStr += 3, pDst += 3; break; }
- pDst[3] = c; c = pStr[4]; pStr += 4, pDst += 4;
- }
- while (c)
- {
- if ((pEnd - pDst) < 7)
- {
- m_pDst = pEnd;
- return;
- }
- if (!globals::s_str_serialize_flags[c])
- *pDst++ = c;
- else
- {
- pDst[0] = '\\';
- switch (c)
- {
- case '\b': pDst[1] = 'b'; break;
- case '\r': pDst[1] = 'r'; break;
- case '\t': pDst[1] = 't'; break;
- case '\f': pDst[1] = 'f'; break;
- case '\n': pDst[1] = 'n'; break;
- case '\\': pDst[1] = '\\'; break;
- case '\"': pDst[1] = '\"'; break;
- default: pDst[1] = 'u', pDst[2] = '0', pDst[3] = '0', pDst[4] = s_to_hex[c >> 4], pDst[5] = s_to_hex[c & 0xF]; pDst += 3; break;
- }
- pDst += 2;
- }
- c = *pStr++;
- }
- *pDst++ = '\"';
- PJSON_ASSERT(pDst <= pEnd);
- m_pDst = pDst;
- }
- private:
- char* m_pDst, *m_pStart, *m_pEnd;
- };
- // ---- class serialize_helper
- template<typename T>
- class serialize_helper : public T
- {
- public:
- typedef T base;
- template<typename I> inline serialize_helper(I& init) : T(init) { }
- template<typename I, typename J> inline serialize_helper(I& init1, J& init2) : T(init1, init2) { }
- inline void puts(const char* pStr) { T::puts(pStr, strlen(pStr)); }
- inline void puts(const char* pStr, size_t l) { T::puts(pStr, l); }
- };
- // ---- class value_variant
- #pragma pack(push, 4)
- class value_variant : public value_variant_data
- {
- friend document;
- friend key_value_t;
- value_variant(const value_variant&);
- value_variant& operator= (const value_variant&);
- public:
- inline value_variant() { m_type = cJSONValueTypeNull; m_data.m_nVal = 0; }
- inline value_variant(bool val) { m_type = cJSONValueTypeBool; m_data.m_nVal = val; }
- inline value_variant(int32 nVal) { m_type = cJSONValueTypeInt; m_data.m_nVal = nVal; }
- inline value_variant(uint32 nVal) { m_type = cJSONValueTypeInt; m_data.m_nVal = nVal; }
- inline value_variant(int64 nVal) { m_type = cJSONValueTypeInt; m_data.m_nVal = nVal; }
- inline value_variant(double flVal) { m_type = cJSONValueTypeDouble; m_data.m_flVal = flVal; }
- inline value_variant(const char* pStr, pool_allocator& alloc)
- {
- m_type = cJSONValueTypeString;
- if (!pStr) pStr = "";
- get_string().construct(pStr, static_cast<uint>(strlen(pStr)) + 1, alloc);
- }
- inline value_variant(json_value_type_t type)
- {
- construct(type);
- }
- inline value_variant(const value_variant& other, pool_allocator& alloc)
- {
- construct(other, alloc);
- }
- inline value_variant &assign(const value_variant& rhs, pool_allocator& alloc)
- {
- if (this == &rhs)
- return *this;
- if ((m_type >= cJSONValueTypeString) && (m_type == rhs.m_type))
- {
- if (is_string())
- get_string().assign(rhs.get_string(), alloc);
- else if (is_object())
- get_object().assign(rhs.get_object(), alloc);
- else
- get_array().assign(rhs.get_array(), alloc);
- }
- else
- {
- construct(rhs, alloc);
- }
- return *this;
- }
- inline json_value_type_t get_type() const { return m_type; }
- inline bool is_null() const { return m_type == cJSONValueTypeNull; }
- inline bool is_valid() const { return m_type != cJSONValueTypeNull; }
- inline bool is_bool() const { return m_type == cJSONValueTypeBool; }
- inline bool is_int() const { return m_type == cJSONValueTypeInt; }
- inline bool is_double() const { return m_type == cJSONValueTypeDouble; }
- inline bool is_numeric() const { return (m_type == cJSONValueTypeInt) || (m_type == cJSONValueTypeDouble); }
- inline bool is_string() const { return m_type == cJSONValueTypeString; }
- inline bool is_object_or_array() const { return m_type >= cJSONValueTypeArray; }
- inline bool is_object() const { return m_type == cJSONValueTypeObject; }
- inline bool is_array() const { return m_type == cJSONValueTypeArray; }
- inline void clear() { set_to_null(); }
- inline void assume_ownership(value_variant& src_val) { set_to_null(); swap(src_val); }
- inline void release_ownership(value_variant& dst_value) { dst_value.set_to_null(); dst_value.swap(*this); }
- inline value_variant& set_to_object() { construct(cJSONValueTypeObject); return *this; }
- inline value_variant& set_to_array() { construct(cJSONValueTypeArray); return *this; }
- inline value_variant& set_to_node(bool is_object) { construct(is_object ? cJSONValueTypeObject : cJSONValueTypeArray); return *this; }
- inline value_variant& set_to_null() { m_data.m_nVal = 0; m_type = cJSONValueTypeNull; return *this; }
- inline value_variant& set(bool val) { m_data.m_nVal = val; m_type = cJSONValueTypeBool; return *this; }
- inline value_variant& set(int32 nVal) { m_data.m_nVal = nVal; m_type = cJSONValueTypeInt; return *this; }
- inline value_variant& set(int64 nVal) { m_data.m_nVal = nVal; m_type = cJSONValueTypeInt; return *this; }
- inline value_variant& set(uint32 nVal) { set(static_cast<int64>(nVal)); return *this; }
- inline value_variant& set(double flVal) { m_data.m_flVal = flVal; m_type = cJSONValueTypeDouble; return *this; }
- inline value_variant& set(const char* pStr, pool_allocator& alloc)
- {
- if (!pStr) pStr = "";
- uint l = static_cast<uint>(strlen(pStr)) + 1;
- if (!is_string())
- {
- m_type = cJSONValueTypeString;
- get_string().construct(pStr, l, alloc);
- }
- else
- get_string().assign(pStr, l, alloc);
- return *this;
- }
- inline value_variant& set_assume_ownership(char* pStr, uint len)
- {
- m_type = cJSONValueTypeString;
- string_vec_t& str = get_string();
- str.m_p = pStr;
- str.m_size = len;
- return *this;
- }
- inline value_variant& set(const value_variant* pVals, uint n, pool_allocator& alloc)
- {
- if (!is_array())
- {
- m_type = cJSONValueTypeArray;
- get_array().construct(pVals, n, alloc);
- }
- else
- get_array().assign(pVals, n, alloc);
- return *this;
- }
- inline value_variant& set_assume_ownership(value_variant* pVals, uint n)
- {
- m_type = cJSONValueTypeArray;
- value_variant_vec_t& arr = get_array();
- arr.m_p = pVals;
- arr.m_size = n;
- return *this;
- }
- inline value_variant& set(const key_value_t* pKey_values, uint n, pool_allocator& alloc)
- {
- if (!is_object())
- {
- m_type = cJSONValueTypeObject;
- get_object().construct(pKey_values, n, alloc);
- }
- else
- get_object().assign(pKey_values, n, alloc);
- return *this;
- }
- inline value_variant& set_assume_ownership(key_value_t* pKey_values, uint n)
- {
- m_type = cJSONValueTypeObject;
- key_value_vec_t& obj = get_object();
- obj.m_p = pKey_values;
- obj.m_size = n;
- return *this;
- }
- inline value_variant &operator=(bool val) { set(val); return *this; }
- inline value_variant &operator=(int32 nVal) { set(nVal); return *this; }
- inline value_variant &operator=(uint32 nVal) { set(nVal); return *this; }
- inline value_variant &operator=(int64 nVal) { set(nVal); return *this; }
- inline value_variant &operator=(double flVal) { set(flVal); return *this; }
- inline bool get_bool_value(bool& val, bool def = false) const { if (is_bool()) { val = (m_data.m_nVal != 0); return true; } else return convert_to_bool(val, def); }
- inline bool get_numeric_value(int32& val, int32 def = 0) const { if ((is_int()) && (m_data.m_nVal == static_cast<int32>(m_data.m_nVal))) { val = static_cast<int32>(m_data.m_nVal); return true; } else return convert_to_int32(val, def); }
- inline bool get_numeric_value(int64& val, int64 def = 0) const { if (is_int()) { val = m_data.m_nVal; return true; } else return convert_to_int64(val, def); }
- inline bool get_numeric_value(float& val, float def = 0.0f) const { if (is_double()) { val = static_cast<float>(m_data.m_flVal); return true; } else return convert_to_float(val, def); }
- inline bool get_numeric_value(double& val, double def = 0.0f) const { if (is_double()) { val = m_data.m_flVal; return true; } else return convert_to_double(val, def); }
- inline bool get_string_value(string_t& val, const char* pDef = "") const { if (is_string()) { val = get_string_ptr(); return true; } else return convert_to_string(val, pDef); }
- inline bool as_bool(bool def = false) const { bool result; get_bool_value(result, def); return result; }
- inline int as_int32(int32 def = 0) const { int32 result; get_numeric_value(result, def); return result; }
- inline int64 as_int64(int64 def = 0) const { int64 result; get_numeric_value(result, def); return result; }
- inline float as_float(float def = 0.0f) const { float result; get_numeric_value(result, def); return result; }
- inline double as_double(double def = 0.0f) const { double result; get_numeric_value(result, def); return result; }
- // Returns value as a string, or the default string if the value cannot be converted.
- inline string_t as_string(const char* pDef = "") const { string_t result; get_string_value(result, pDef); return result; }
- // Returns pointer to null terminated string or NULL if the value is not a string.
- inline const char* as_string_ptr() const { return is_string() ? get_string_ptr() : NULL; }
- inline void swap(value_variant& other)
- {
- pjson::swap(m_type, other.m_type);
- get_object().swap(other.get_object());
- }
- inline uint size() const { PJSON_ASSERT(is_object_or_array()); return is_object_or_array() ? get_array().size() : 0; }
- inline const char *get_key_name_at_index(uint index) const { PJSON_ASSERT(is_object()); return get_object()[index].get_key().get_ptr(""); }
- inline const value_variant *find_child_array(const char *pName) const
- {
- int index = find_key(pName);
- if ((index >= 0) && (get_object()[index].get_value().is_array()))
- return &get_object()[index].get_value();
- return NULL;
- }
- inline const value_variant *find_child_object(const char *pName) const
- {
- int index = find_key(pName);
- if ((index >= 0) && (get_object()[index].get_value().is_object()))
- return &get_object()[index].get_value();
- return NULL;
- }
- inline const value_variant *find_value_variant(const char *pName) const
- {
- int index = find_key(pName);
- return (index < 0) ? NULL : &get_object()[index].get_value();
- }
- inline int find_key(const char *pName) const
- {
- if (!is_object())
- {
- PJSON_ASSERT(0);
- return -1;
- }
- const uint n = get_array().size();
- const key_value_vec_t &obj = get_object();
- for (uint i = 0; i < n; i++)
- if (strcmp(pName, obj[i].get_key().get_ptr("")) == 0)
- return i;
- return -1;
- }
- inline bool has_key(const char *pName) const
- {
- return find_key(pName) >= 0;
- }
- inline bool as_bool(const char *pName, bool def = false) const
- {
- int index = find_key(pName);
- return (index < 0) ? def : get_object()[index].get_value().as_bool(def);
- }
- inline int as_int32(const char *pName, int32 def = 0) const
- {
- int index = find_key(pName);
- return (index < 0) ? def : get_object()[index].get_value().as_int32(def);
- }
- inline int64 as_int64(const char *pName, int64 def = 0) const
- {
- int index = find_key(pName);
- return (index < 0) ? def : get_object()[index].get_value().as_int64(def);
- }
- inline float as_float(const char *pName, float def = 0.0f) const
- {
- int index = find_key(pName);
- return (index < 0) ? def : get_object()[index].get_value().as_float(def);
- }
- inline double as_double(const char *pName, double def = 0.0f) const
- {
- int index = find_key(pName);
- return (index < 0) ? def : get_object()[index].get_value().as_double(def);
- }
- inline const char* as_string_ptr(const char *pName, const char *pDef = "") const
- {
- int index = find_key(pName);
- if (index < 0)
- return pDef;
- const char *p = get_object()[index].get_value().as_string_ptr();
- return p ? p : pDef;
- }
- inline value_variant& get_value_at_index(uint index) { PJSON_ASSERT(is_object_or_array()); return is_object() ? get_object()[index].get_value() : get_array()[index]; }
- inline const value_variant& get_value_at_index(uint index) const { PJSON_ASSERT(is_object_or_array()); return is_object() ? get_object()[index].get_value() : get_array()[index]; }
- inline value_variant& operator[](uint index) { PJSON_ASSERT(is_object_or_array()); return is_object() ? get_object()[index].get_value() : get_array()[index]; }
- inline const value_variant& operator[](uint index) const { PJSON_ASSERT(is_object_or_array()); return is_object() ? get_object()[index].get_value() : get_array()[index]; }
- inline json_value_type_t get_value_type_at_index(uint index) const { return get_value_at_index(index).get_type(); }
- inline bool is_child_at_index(uint index) const { return get_value_type_at_index(index) >= cJSONValueTypeArray; }
- inline bool has_children() const
- {
- if (is_object())
- {
- const key_value_vec_t& obj = get_object();
- const uint s = obj.size();
- for (uint i = 0; i < s; ++i)
- if (obj[i].get_value().is_object_or_array())
- return true;
- }
- else if (is_array())
- {
- const value_variant_vec_t& arr = get_array();
- const uint s = arr.size();
- for (uint i = 0; i < s; ++i)
- if (arr[i].is_object_or_array())
- return true;
- }
- return false;
- }
- inline void clear_object_or_array()
- {
- PJSON_ASSERT(is_object_or_array());
- if (is_object())
- get_object().clear();
- else if (is_array())
- get_array().clear();
- }
- inline void resize(uint n, pool_allocator& alloc)
- {
- PJSON_ASSERT(is_object_or_array());
- if (is_object())
- get_object().resize(n, alloc);
- else if (is_array())
- get_array().resize(n, alloc);
- }
- inline void set_key_name_at_index(uint index, const char *pKey, uint key_len, pool_allocator& alloc)
- {
- PJSON_ASSERT(is_object());
- string_vec_t& str = get_object()[index].get_key();
- str.assign(pKey, key_len + 1, alloc);
- }
- inline void set_key_name_at_index(uint index, const char *pKey, pool_allocator& alloc)
- {
- set_key_name_at_index(index, pKey, static_cast<uint>(strlen(pKey)) + 1, alloc);
- }
- inline value_variant& add_key_value(const char* pKey, uint key_len, const value_variant& val, pool_allocator& alloc)
- {
- PJSON_ASSERT(is_object());
- key_value_vec_t& obj = get_object();
- key_value_t* pKey_value = obj.enlarge_no_construct(1, alloc);
- pKey_value->get_key().construct(pKey, key_len + 1, alloc);
- pKey_value->get_value().construct(val, alloc);
- return *this;
- }
- inline value_variant& add_key_value(const char* pKey, const value_variant& val, pool_allocator& alloc)
- {
- return add_key_value(pKey, static_cast<uint>(strlen(pKey)), val, alloc);
- }
- inline value_variant& add_value(const value_variant& val, pool_allocator& alloc)
- {
- PJSON_ASSERT(is_array());
- get_array().enlarge_no_construct(1, alloc)->construct(val, alloc);
- return *this;
- }
- bool serialize(char* pBuf, size_t buf_size, size_t* pSize = NULL, bool formatted = true, bool null_terminate = true) const
- {
- serialize_helper<char_buf_print_helper> helper(pBuf, buf_size);
- serialize_internal(helper, formatted, null_terminate, 0);
- if (pSize)
- *pSize = helper.size();
- return (helper.size() < buf_size);
- }
- bool serialize(char_vec_t& buf, bool formatted = true, bool null_terminate = true) const
- {
- serialize_helper<char_vector_print_helper> helper(buf);
- serialize_internal(helper, formatted, null_terminate, 0);
- return true;
- }
- protected:
- // Manual constructor
- inline void construct(json_value_type_t type)
- {
- m_type = type;
- memset(&m_data, 0, sizeof(m_data));
- }
- // Assumes variant has NOT been constructed yet.
- inline void construct(const value_variant& other, pool_allocator& alloc)
- {
- m_type = other.m_type;
- m_data.m_nVal = other.m_data.m_nVal;
- if (m_type >= cJSONValueTypeString)
- {
- if (m_type == cJSONValueTypeObject)
- get_object().construct(other.get_object(), alloc);
- else if (m_type == cJSONValueTypeArray)
- get_array().construct(other.get_array(), alloc);
- else
- get_string().construct(other.get_string(), alloc);
- }
- }
- inline bool convert_to_bool(bool& val, bool def) const
- {
- switch (m_type)
- {
- case cJSONValueTypeBool:
- case cJSONValueTypeInt:
- {
- val = (m_data.m_nVal != 0);
- return true;
- }
- case cJSONValueTypeDouble:
- {
- val = (m_data.m_flVal != 0);
- return true;
- }
- case cJSONValueTypeString:
- {
- if (!pjson_stricmp(get_string_ptr(), "false"))
- {
- val = false;
- return true;
- }
- else if (!pjson_stricmp(get_string_ptr(), "true"))
- {
- val = true;
- return true;
- }
- val = (atof(get_string_ptr()) != 0.0f);
- return true;
- }
- }
- val = def;
- return false;
- }
- inline bool convert_to_int32(int32& val, int32 def) const
- {
- val = def;
- int64 val64;
- if (!convert_to_int64(val64, def))
- return false;
- if ((val64 < std::numeric_limits<int32>::min()) || (val64 > std::numeric_limits<int32>::max()))
- return false;
- val = static_cast<int32>(val64);
- return true;
- }
- inline bool convert_to_int64(int64& val, int64 def) const
- {
- switch (m_type)
- {
- case cJSONValueTypeBool:
- case cJSONValueTypeInt:
- {
- val = m_data.m_nVal;
- return true;
- }
- case cJSONValueTypeDouble:
- {
- val = static_cast<int64>(m_data.m_flVal);
- return true;
- }
- case cJSONValueTypeString:
- {
- if (!pjson_stricmp(get_string_ptr(), "false"))
- {
- val = 0;
- return true;
- }
- else if (!pjson_stricmp(get_string_ptr(), "true"))
- {
- val = 1;
- return true;
- }
- double flVal = floor(atof(get_string_ptr()));
- if ((flVal >= std::numeric_limits<int64>::min()) && (flVal <= std::numeric_limits<int64>::max()))
- {
- val = static_cast<int64>(flVal);
- return true;
- }
- break;
- }
- }
- val = def;
- return false;
- }
- inline bool convert_to_float(float& val, float def) const
- {
- switch (m_type)
- {
- case cJSONValueTypeBool:
- case cJSONValueTypeInt:
- {
- val = static_cast<float>(m_data.m_nVal);
- return true;
- }
- case cJSONValueTypeDouble:
- {
- val = static_cast<float>(m_data.m_flVal);
- return true;
- }
- case cJSONValueTypeString:
- {
- if (!pjson_stricmp(get_string_ptr(), "false"))
- {
- val = 0;
- return true;
- }
- else if (!pjson_stricmp(get_string_ptr(), "true"))
- {
- val = 1;
- return true;
- }
- val = static_cast<float>(atof(get_string_ptr()));
- return true;
- }
- }
- val = def;
- return false;
- }
- inline bool convert_to_double(double& val, double def) const
- {
- switch (m_type)
- {
- case cJSONValueTypeBool:
- case cJSONValueTypeInt:
- {
- val = static_cast<double>(m_data.m_nVal);
- return true;
- }
- case cJSONValueTypeDouble:
- {
- val = m_data.m_flVal;
- return true;
- }
- case cJSONValueTypeString:
- {
- if (!pjson_stricmp(get_string_ptr(), "false"))
- {
- val = 0;
- return true;
- }
- else if (!pjson_stricmp(get_string_ptr(), "true"))
- {
- val = 1;
- return true;
- }
- val = atof(get_string_ptr());
- return true;
- }
- }
- val = def;
- return false;
- }
- inline bool convert_to_string(char* pBuf, size_t buf_size) const
- {
- switch (m_type)
- {
- case cJSONValueTypeNull:
- {
- pBuf[0] = 'n', pBuf[1] = 'u', pBuf[2] = 'l', pBuf[3] = 'l', pBuf[4] = '\0';
- return true;
- }
- case cJSONValueTypeBool:
- {
- if (m_data.m_nVal)
- pBuf[0] = 't', pBuf[1] = 'r', pBuf[2] = 'u', pBuf[3] = 'e', pBuf[4] = '\0';
- else
- pBuf[0] = 'f', pBuf[1] = 'a', pBuf[2] = 'l', pBuf[3] = 's', pBuf[4] = 'e', pBuf[5] = '\0';
- return true;
- }
- case cJSONValueTypeInt:
- {
- char* pDst = pBuf;
- int64 n = m_data.m_nVal;
- uint64 s = static_cast<uint64>(n >> 63);
- *pDst = '-';
- pDst -= s;
- n = (n ^ s) - s;
- char* pLeft = pDst;
- do
- {
- *pDst++ = '0' + (n % 10);
- n /= 10;
- } while (n);
- *pDst = '\0';
- do
- {
- char c = *--pDst;
- *pDst = *pLeft;
- *pLeft++ = c;
- } while (pDst > pLeft);
- return true;
- }
- case cJSONValueTypeDouble:
- {
- return 0 == _gcvt_s(pBuf, buf_size, m_data.m_flVal, 15);
- }
- }
- return false;
- }
- inline bool convert_to_string(string_t& val, const char* pDef) const
- {
- char buf[64];
- if (m_type == cJSONValueTypeString)
- val = get_string_ptr();
- else
- {
- if (!convert_to_string(buf, sizeof(buf)))
- {
- val.assign(pDef);
- return false;
- }
- val.assign(buf);
- }
- return true;
- }
- inline uint8 get_end_char() const { return (m_type == cJSONValueTypeArray) ? ']' : '}'; }
- template<typename serializer>
- void serialize_node(serializer& out, bool formatted, uint cur_indent) const
- {
- char buf[64];
- const uint size = get_array().size();
- if (!size)
- {
- static const char* g_empty_object_strs[4] = { "[]", "[ ]", "{}", "{ }" };
- out.puts(g_empty_object_strs[is_object() * 2 + formatted], 2 + formatted);
- return;
- }
- if (formatted && is_array() && !has_children())
- {
- size_t start_of_line_ofs = out.size();
- out.puts("[ ", 2);
- const uint cMaxLineLen = 100;
- for (uint i = 0; i < size; i++)
- {
- const value_variant& child_val = get_value_at_index(i);
- if (child_val.is_string())
- out.print_escaped(child_val.get_string());
- else
- {
- child_val.convert_to_string(buf, sizeof(buf));
- out.puts(buf);
- }
- if (i != size - 1)
- out.puts(", ", 2);
- if (((out.size() - start_of_line_ofs) > cMaxLineLen) && (i != size - 1))
- {
- out.print_char('\n');
- out.print_tabs(cur_indent + 1);
- start_of_line_ofs = out.size();
- }
- }
- out.puts(" ]", 2);
- return;
- }
- out.print_char(is_object() ? '{' : '[');
- if (formatted)
- out.print_char('\n');
- cur_indent++;
- for (uint i = 0; i < size; i++)
- {
- const value_variant& child_val = get_value_at_index(i);
- if (formatted)
- out.print_tabs(cur_indent);
- if (is_object())
- {
- out.print_escaped(get_object()[i].get_key());
- if (formatted)
- out.puts(" : ", 3);
- else
- out.print_char(':');
- }
- json_value_type_t val_type = child_val.get_type();
- if (val_type >= cJSONValueTypeArray)
- child_val.serialize_node(out, formatted, cur_indent);
- else if (val_type == cJSONValueTypeString)
- out.print_escaped(child_val.get_string());
- else
- {
- child_val.convert_to_string(buf, sizeof(buf));
- out.puts(buf);
- }
- if (i != size - 1)
- out.print_char(',');
- if (formatted)
- out.print_char('\n');
- }
- cur_indent--;
- if (formatted)
- out.print_tabs(cur_indent);
- out.print_char(is_object() ? '}' : ']');
- }
- template<typename serializer>
- void serialize_internal(serializer& out, bool formatted, bool null_terminate, uint cur_indent) const
- {
- if (formatted)
- out.print_tabs(cur_indent);
- if (is_object_or_array())
- {
- serialize_node(out, formatted, cur_indent);
- if (formatted)
- out.print_char('\n');
- }
- else
- {
- if (is_string())
- out.print_escaped(get_string());
- else
- {
- string_t str;
- if (get_string_value(str))
- out.puts(str.c_str(), str.length());
- }
- }
- if (null_terminate)
- out.print_char('\0');
- }
- template<typename T> value_variant(T*);
- template<typename T> value_variant(const T*);
- template<typename T> value_variant& operator= (T*);
- template<typename T> value_variant& operator= (const T*);
- };
- #pragma pack(pop)
- inline key_value_t::key_value_t(const key_value_t& other, pool_allocator& alloc) :
- m_key(other.get_key(), alloc)
- {
- get_value().construct(other.get_value(), alloc);
- }
- inline void key_value_t::assign(const key_value_t& src, pool_allocator& alloc)
- {
- get_key().assign(src.get_key(), alloc);
- get_value().assign(src.get_value(), alloc);
- }
- // ---- class error_info
- class error_info
- {
- public:
- inline error_info() : m_ofs(0), m_pError_message(NULL) { }
- inline void set(size_t ofs, const char* pMsg) { m_ofs = ofs; m_pError_message = pMsg; }
- size_t m_ofs;
- const char* m_pError_message;
- };
- // ---- class growable_stack
- class growable_stack
- {
- public:
- inline growable_stack(uint initial_size) :
- m_pBuf(NULL),
- m_size(initial_size),
- m_ofs(0)
- {
- if (initial_size)
- m_pBuf = static_cast<uint8*>(pjson_malloc(initial_size));
- }
- inline ~growable_stack()
- {
- pjson_free(m_pBuf);
- }
- inline void clear()
- {
- pjson_free(m_pBuf);
- m_pBuf = NULL;
- m_size = 0;
- m_ofs = 0;
- }
- inline uint8* get_top_ptr() { return reinterpret_cast<uint8*>(m_pBuf) + m_ofs; }
- template<typename T> inline T* get_top_obj() { return reinterpret_cast<T*>(m_pBuf + m_ofs - sizeof(T)); }
- inline void reset() { m_ofs = 0; }
- inline size_t get_ofs() { return m_ofs; }
- template<typename T>
- PJSON_FORCEINLINE T* push(uint num)
- {
- const size_t bytes_needed = sizeof(T) * num;
- T* pResult = reinterpret_cast<T*>(m_pBuf + m_ofs);
- m_ofs += bytes_needed;
- if (m_ofs > m_size)
- {
- m_ofs -= bytes_needed;
- m_size = PJSON_MAX(1, m_size * 2);
- while(m_size <= (m_ofs + bytes_needed))
- m_size *= 2;
- m_pBuf = static_cast<uint8*>(pjson_realloc(m_pBuf, m_size));
- pResult = reinterpret_cast<T*>(m_pBuf + m_ofs);
- m_ofs += bytes_needed;
- }
- PJSON_ASSERT(m_ofs <= m_size);
- return pResult;
- }
- template<typename T>
- inline T* pop(uint num)
- {
- size_t bytes_needed = sizeof(T) * num;
- PJSON_ASSERT(bytes_needed <= m_ofs);
- m_ofs -= bytes_needed;
- return reinterpret_cast<T*>(m_pBuf + m_ofs);
- }
- private:
- uint8* m_pBuf;
- size_t m_size;
- size_t m_ofs;
- };
- // ---- class document
- class document : public value_variant
- {
- document(const document&);
- document& operator= (const document&);
- public:
- inline document(uint initial_pool_size = 0, uint min_pool_chunk_size = PJSON_DEFAULT_MIN_CHUNK_SIZE, uint initial_stack_size = 0) :
- m_allocator(initial_pool_size, min_pool_chunk_size),
- m_initial_stack_size(initial_stack_size),
- m_stack(initial_stack_size)
- {
- #if PJSON_PARSE_STATS
- m_parse_stats.clear();
- #endif
- }
- inline ~document()
- {
- }
- const pool_allocator& get_allocator() const { return m_allocator; }
- pool_allocator& get_allocator() { return m_allocator; }
- void clear()
- {
- set_to_null();
- m_allocator.clear();
- m_stack.clear();
- #if PJSON_PARSE_STATS
- m_parse_stats.clear();
- #endif
- }
- bool deserialize_in_place(char* pStr)
- {
- return deserialize_start((uint8*)pStr);
- }
- #if PJSON_PARSE_STATS
- struct parse_stats_t
- {
- size_t m_num_string, m_num_string_chars;
- size_t m_num_numeric, m_num_numeric_chars;
- size_t m_num_whitespace_blocks, m_num_whitespace_chars;
- size_t m_num_control;
- size_t m_num_comment, m_num_comment_chars;
- size_t m_num_value_pop, m_value_pop_bytes;
- size_t m_num_bool_chars;
- size_t m_num_escape_breaks;
- size_t m_num_unicode_escapes;
- void clear() { memset(this, 0, sizeof(*this)); }
- };
- const parse_stats_t& get_parse_stats() const { return m_parse_stats; }
- parse_stats_t& get_parse_stats() { return m_parse_stats; }
- #endif
- private:
- pool_allocator m_allocator;
- uint m_initial_stack_size;
- growable_stack m_stack;
- error_info m_error_info;
- const uint8* m_pStart;
- const uint8* m_pStr;
- inline bool set_error(const uint8* pStr, const char* pMsg)
- {
- m_pStr = pStr;
- m_error_info.set(m_pStr - m_pStart, pMsg);
- return false;
- }
- #if PJSON_PARSE_STATS
- parse_stats_t m_parse_stats;
- #endif
- #if PJSON_PARSE_STATS
- #define PJSON_INCREMENT_STAT(x) do { ++m_parse_stats.x; } while(0)
- #define PJSON_UPDATE_STAT(x, n) do { m_parse_stats.x += n; } while(0)
- #else
- #define PJSON_INCREMENT_STAT(x) do { } while(0)
- #define PJSON_UPDATE_STAT(x, n) do { } while(0)
- #endif
- #define PJSON_SKIP_WHITESPACE \
- while (globals::s_parse_flags[*pStr] & 4) \
- { \
- PJSON_INCREMENT_STAT(m_num_whitespace_blocks); \
- do { \
- if (!(globals::s_parse_flags[pStr[1]] & 4)) { ++pStr; PJSON_INCREMENT_STAT(m_num_whitespace_chars); break; } \
- if (!(globals::s_parse_flags[pStr[2]] & 4)) { pStr += 2; PJSON_UPDATE_STAT(m_num_whitespace_chars, 2); break; } \
- if (!(globals::s_parse_flags[pStr[3]] & 4)) { pStr += 3; PJSON_UPDATE_STAT(m_num_whitespace_chars, 3); break; } \
- pStr += 4; PJSON_UPDATE_STAT(m_num_whitespace_chars, 4); \
- } while (globals::s_parse_flags[*pStr] & 4); \
- if ((*pStr != '/') || (pStr[1] != '/')) break; \
- pStr += 2; PJSON_INCREMENT_STAT(m_num_comment); PJSON_UPDATE_STAT(m_num_comment_chars, 2); \
- while ((*pStr) && (*pStr != '\n') && (*pStr != '\r')) { PJSON_INCREMENT_STAT(m_num_comment_chars); ++pStr; } \
- }
- inline const uint8* skip_whitespace(const uint8* p)
- {
- uint8 c;
- while ((c = *p) != '\0')
- {
- if ((c == ' ') || (c == '\t'))
- {
- do
- {
- PJSON_INCREMENT_STAT(m_num_whitespace_chars);
- } while (*++p == c);
- continue;
- }
- if ((c == '/') && (p[1] == '/'))
- {
- p += 2; PJSON_INCREMENT_STAT(m_num_comment); PJSON_UPDATE_STAT(m_num_comment_chars, 2);
- while ((*p) && (*p != '\n') && (*p != '\r'))
- {
- PJSON_UPDATE_STAT(m_num_comment_chars, 2);
- ++p;
- }
- continue;
- }
- else if (c > ' ')
- break;
- PJSON_INCREMENT_STAT(m_num_whitespace_chars);
- ++p;
- }
- return p;
- }
- bool deserialize_internal()
- {
- static const uint8 g_utf8_first_byte[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
- m_stack.reset();
- memcpy(m_stack.push<value_variant>(1), static_cast<value_variant*>(this), sizeof(value_variant));
- const uint8* pStr = ++m_pStr;
- PJSON_UPDATE_STAT(m_num_control, 1);
- bool cur_is_object = is_object();
- uint8 cur_end_char = get_end_char();
- uint cur_num_elements = 0;
- for ( ; ; )
- {
- PJSON_SKIP_WHITESPACE;
- uint8 c = *pStr;
- if (c == ',')
- {
- if (!cur_num_elements)
- return set_error(pStr, "Unexpected comma");
- ++pStr;
- PJSON_UPDATE_STAT(m_num_control, 1);
- PJSON_SKIP_WHITESPACE;
- c = *pStr;
- }
- else if ((cur_num_elements) && (c != cur_end_char))
- return set_error(pStr, "Expected comma or object/array end character");
- while (c == cur_end_char)
- {
- PJSON_UPDATE_STAT(m_num_control, 1);
- ++pStr;
- for ( ; ; )
- {
- uint n = cur_num_elements, num_bytes = cur_num_elements * (cur_is_object ? sizeof(key_value_t) : sizeof(value_variant));
- void* pSrc = m_stack.pop<uint8>(num_bytes);
- PJSON_INCREMENT_STAT(m_num_value_pop);
- PJSON_UPDATE_STAT(m_value_pop_bytes, num_bytes);
- // The top of the stack (after popping the current array/object) could contain either a value_variant (if cur_is_object is set),
- // or a key_value_t, which ends in a value_variant. So all we need to do is look at the very end, which always has a value_variant.
- value_variant* pCur_variant = m_stack.get_top_obj<value_variant>();
- value_variant_vec_t& arr = pCur_variant->get_array();
- cur_is_object = (arr.m_p != NULL);
- cur_end_char = cur_is_object ? '}' : ']';
- cur_num_elements = arr.m_size;
- arr.m_size = n;
- arr.m_p = NULL;
- if (num_bytes)
- memcpy(arr.m_p = static_cast<value_variant*>(m_allocator.Alloc(num_bytes)), pSrc, num_bytes);
- if (m_stack.get_ofs() <= sizeof(value_variant))
- {
- PJSON_ASSERT(m_stack.get_ofs() == sizeof(value_variant));
- memcpy(static_cast<value_variant*>(this), m_stack.pop<value_variant>(1), sizeof(value_variant));
- m_pStr = pStr;
- return true;
- }
- PJSON_SKIP_WHITESPACE;
- if (*pStr == ',')
- {
- PJSON_UPDATE_STAT(m_num_control, 1);
- ++pStr;
- PJSON_SKIP_WHITESPACE;
- c = *pStr;
- break;
- }
- if (*pStr++ != cur_end_char)
- return set_error(pStr, "Unexpected character within object or array");
- PJSON_UPDATE_STAT(m_num_control, 1);
- }
- }
- ++cur_num_elements;
- value_variant* pChild_variant;
- if (!cur_is_object)
- pChild_variant = m_stack.push<value_variant>(1);
- else
- {
- if (c != '\"')
- return set_error(pStr, "Expected quoted key string");
- ++pStr; PJSON_INCREMENT_STAT(m_num_string); PJSON_INCREMENT_STAT(m_num_string_chars);
- uint8* pBuf = (uint8*)pStr;
- c = *pStr++; PJSON_INCREMENT_STAT(m_num_string_chars);
- if (!(globals::s_parse_flags[c] & 1))
- {
- do
- {
- c = pStr[0]; if (globals::s_parse_flags[c] & 1) { ++pStr; PJSON_UPDATE_STAT(m_num_string_chars, 1); break; }
- c = pStr[1]; if (globals::s_parse_flags[c] & 1) { pStr += 2; PJSON_UPDATE_STAT(m_num_string_chars, 2); break; }
- c = pStr[2]; if (globals::s_parse_flags[c] & 1) { pStr += 3; PJSON_UPDATE_STAT(m_num_string_chars, 3); break; }
- c = pStr[3];
- pStr += 4; PJSON_UPDATE_STAT(m_num_string_chars, 4);
- } while (!(globals::s_parse_flags[c] & 1));
- }
- uint8* pDst = (uint8*)pStr - 1;
- if (c != '\"') PJSON_INCREMENT_STAT(m_num_escape_breaks);
- while (c != '\"')
- {
- if (globals::s_parse_flags[c] & 2)
- return set_error(pStr, "Missing end quote");
- c = *pStr++; PJSON_INCREMENT_STAT(m_num_string_chars);
- if (c == 'u')
- {
- PJSON_INCREMENT_STAT(m_num_unicode_escapes);
- uint u = 0;
- for (uint i = 0; i < 4; i++)
- {
- u <<= 4;
- int cc = *pStr++; PJSON_INCREMENT_STAT(m_num_string_chars);
- if ((cc >= 'A') && (cc <= 'F'))
- u += cc - 'A' + 10;
- else if ((cc >= 'a') && (cc <= 'f'))
- u += cc - 'a' + 10;
- else if ((cc >= '0') && (cc <= '9'))
- u += cc - '0';
- else
- return set_error(pStr, "Invalid Unicode escape");
- }
- uint len = 3; if ((u) && (u < 0x80)) len = 1; else if (u < 0x800) len = 2;
- pDst += len;
- uint8* q = pDst;
- switch (len)
- {
- case 3: *--q = static_cast<uint8>((u | 0x80) & 0xBF); u >>= 6; // falls through
- case 2: *--q = static_cast<uint8>((u | 0x80) & 0xBF); u >>= 6; // falls through
- case 1: *--q = static_cast<uint8>(u | g_utf8_first_byte[len]);
- }
- }
- else
- {
- switch (c)
- {
- case 'b': c = '\b'; break;
- case 'f': c = '\f'; break;
- case 'n': c = '\n'; break;
- case 'r': c = '\r'; break;
- case 't': c = '\t'; break;
- case '\\': case '\"': case '/': break;
- case '\0': return set_error(pStr, "Incomplete string escape");
- default: { *pDst++ = '\\'; break; } // unrecognized escape, so forcefully escape the backslash (not standard)
- }
- *pDst++ = c;
- }
- c = *pStr++; PJSON_INCREMENT_STAT(m_num_string_chars);
- while (!(globals::s_parse_flags[c] & 1))
- {
- pDst[0] = c;
- c = pStr[0]; if (globals::s_parse_flags[c] & 1) { ++pDst; ++pStr; PJSON_INCREMENT_STAT(m_num_string_chars); break; }
- pDst[1] = c;
- c = pStr[1]; if (globals::s_parse_flags[c] & 1) { pDst += 2; pStr += 2; PJSON_UPDATE_STAT(m_num_string_chars, 2); break; }
- pDst[2] = c;
- c = pStr[2]; if (globals::s_parse_flags[c] & 1) { pDst += 3; pStr += 3; PJSON_UPDATE_STAT(m_num_string_chars, 3); break; }
- pDst[3] = c;
- pDst += 4;
- c = pStr[3];
- pStr += 4; PJSON_UPDATE_STAT(m_num_string_chars, 4);
- }
- }
- *pDst++ = '\0';
- key_value_t* pKey_value = m_stack.push<key_value_t>(1);
- pChild_variant = &pKey_value->get_value();
- pKey_value->get_key().m_p = (char*)pBuf;
- pKey_value->get_key().m_size = static_cast<uint>(pDst - pBuf);
- PJSON_SKIP_WHITESPACE;
- if (*pStr != ':')
- return set_error(pStr, "Missing colon after key");
- ++pStr; PJSON_INCREMENT_STAT(m_num_control);
- PJSON_SKIP_WHITESPACE;
- c = *pStr;
- }
- switch (c)
- {
- case '{':
- case '[':
- {
- ++pStr; PJSON_INCREMENT_STAT(m_num_control);
- pChild_variant->m_type = (c == '{') ? cJSONValueTypeObject : cJSONValueTypeArray;
- pChild_variant->m_data.m_object.m_size = cur_num_elements;
- pChild_variant->m_data.m_object.m_p = (key_value_t*)cur_is_object;
- cur_is_object = (c == '{');
- cur_num_elements = 0;
- cur_end_char = c + 2;
- break;
- }
- case '\"':
- {
- ++pStr; PJSON_INCREMENT_STAT(m_num_string); PJSON_INCREMENT_STAT(m_num_string_chars);
- uint8* pBuf = (uint8*)pStr;
- c = *pStr++; PJSON_INCREMENT_STAT(m_num_string_chars);
- if (!(globals::s_parse_flags[c] & 1))
- {
- do
- {
- c = pStr[0]; if (globals::s_parse_flags[c] & 1) { ++pStr; PJSON_INCREMENT_STAT(m_num_string_chars); break; }
- c = pStr[1]; if (globals::s_parse_flags[c] & 1) { pStr += 2; PJSON_UPDATE_STAT(m_num_string_chars, 2); break; }
- c = pStr[2]; if (globals::s_parse_flags[c] & 1) { pStr += 3; PJSON_UPDATE_STAT(m_num_string_chars, 3); break; }
- c = pStr[3];
- pStr += 4; PJSON_UPDATE_STAT(m_num_string_chars, 4);
- } while (!(globals::s_parse_flags[c] & 1));
- }
- uint8* pDst = (uint8*)pStr - 1;
- if (c != '\"') PJSON_INCREMENT_STAT(m_num_escape_breaks);
- while (c != '\"')
- {
- if (globals::s_parse_flags[c] & 2)
- return set_error(pStr, "Missing end quote");
- c = *pStr++; PJSON_INCREMENT_STAT(m_num_string_chars);
- if (c == 'u')
- {
- PJSON_INCREMENT_STAT(m_num_unicode_escapes);
- uint u = 0;
- for (uint i = 0; i < 4; i++)
- {
- u <<= 4;
- int cc = *pStr++; PJSON_INCREMENT_STAT(m_num_string_chars);
- if ((cc >= 'A') && (cc <= 'F'))
- u += cc - 'A' + 10;
- else if ((cc >= 'a') && (cc <= 'f'))
- u += cc - 'a' + 10;
- else if ((cc >= '0') && (cc <= '9'))
- u += cc - '0';
- else
- return set_error(pStr, "Invalid Unicode escape");
- }
- uint len = 3; if ((u) && (u < 0x80)) len = 1; else if (u < 0x800) len = 2;
- pDst += len;
- uint8* q = pDst;
- switch (len)
- {
- case 3: *--q = static_cast<uint8>((u | 0x80) & 0xBF); u >>= 6; // falls through
- case 2: *--q = static_cast<uint8>((u | 0x80) & 0xBF); u >>= 6; // falls through
- case 1: *--q = static_cast<uint8>(u | g_utf8_first_byte[len]);
- }
- }
- else
- {
- switch (c)
- {
- case 'b': c = '\b'; break;
- case 'f': c = '\f'; break;
- case 'n': c = '\n'; break;
- case 'r': c = '\r'; break;
- case 't': c = '\t'; break;
- case '\\': case '\"': case '/': break;
- case '\0': return set_error(pStr, "Incomplete string escape");
- default: { *pDst++ = '\\'; break; } // unrecognized escape, so forcefully escape the backslash (not standard)
- }
- *pDst++ = c;
- }
- c = *pStr++; PJSON_INCREMENT_STAT(m_num_string_chars);
- while (!(globals::s_parse_flags[c] & 1))
- {
- pDst[0] = c;
- c = pStr[0]; if (globals::s_parse_flags[c] & 1) { ++pDst; ++pStr; PJSON_INCREMENT_STAT(m_num_string_chars); break; }
- pDst[1] = c;
- c = pStr[1]; if (globals::s_parse_flags[c] & 1) { pDst += 2; pStr += 2; PJSON_UPDATE_STAT(m_num_string_chars, 2); break; }
- pDst[2] = c;
- c = pStr[2]; if (globals::s_parse_flags[c] & 1) { pDst += 3; pStr += 3; PJSON_UPDATE_STAT(m_num_string_chars, 3); break; }
- pDst[3] = c;
- pDst += 4;
- c = pStr[3];
- pStr += 4; PJSON_UPDATE_STAT(m_num_string_chars, 4);
- }
- }
- *pDst++ = '\0';
- pChild_variant->m_type = cJSONValueTypeString;
- string_vec_t& str = pChild_variant->get_string();
- str.m_p = (char*)pBuf;
- str.m_size = static_cast<uint>(pDst - pBuf);
- break;
- }
- case 'n':
- {
- if ((pStr[1] == 'u') && (pStr[2] == 'l') && (pStr[3] == 'l'))
- {
- pStr += 4; PJSON_UPDATE_STAT(m_num_bool_chars, 4);
- pChild_variant->construct(cJSONValueTypeNull);
- }
- else
- return set_error(pStr, "Unrecognized character");
- break;
- }
- case 't':
- {
- if ((pStr[1] == 'r') && (pStr[2] == 'u') && (pStr[3] == 'e'))
- {
- pStr += 4; PJSON_UPDATE_STAT(m_num_bool_chars, 4);
- pChild_variant->construct(cJSONValueTypeBool);
- pChild_variant->m_data.m_nVal = 1;
- }
- else
- return set_error(pStr, "Unrecognized character");
- break;
- }
- case 'f':
- {
- if ((pStr[1] == 'a') && (pStr[2] == 'l') && (pStr[3] == 's') && (pStr[4] == 'e'))
- {
- pStr += 5; PJSON_UPDATE_STAT(m_num_bool_chars, 5);
- pChild_variant->construct(cJSONValueTypeBool);
- }
- else
- return set_error(pStr, "Unrecognized character");
- break;
- }
- case '0': case '1': case '2': case '3': case '4': case '5':
- case '6': case '7': case '8': case '9': case '-': case '.':
- {
- PJSON_INCREMENT_STAT(m_num_numeric);
- if (c == '-') PJSON_INCREMENT_STAT(m_num_numeric_chars);
- uint32 n32 = 0;
- int is_neg = (c == '-');
- c = *(pStr += is_neg);
- if (globals::s_parse_flags[c] & 8)
- {
- n32 = c - '0'; c = *++pStr; PJSON_UPDATE_STAT(m_num_numeric_chars, 1);
- if (globals::s_parse_flags[c] & 8)
- {
- n32 = (n32 * 10U) + (c - '0'); c = *++pStr; PJSON_UPDATE_STAT(m_num_numeric_chars, 1);
- if (globals::s_parse_flags[c] & 8)
- {
- n32 = (n32 * 10U) + (c - '0'); c = *++pStr; PJSON_UPDATE_STAT(m_num_numeric_chars, 1);
- if (globals::s_parse_flags[c] & 8)
- {
- n32 = (n32 * 10U) + (c - '0'); c = *++pStr; PJSON_UPDATE_STAT(m_num_numeric_chars, 1);
- if (globals::s_parse_flags[c] & 8)
- {
- n32 = (n32 * 10U) + (c - '0'); c = *++pStr; PJSON_UPDATE_STAT(m_num_numeric_chars, 1);
- if (globals::s_parse_flags[c] & 8)
- {
- n32 = (n32 * 10U) + (c - '0'); c = *++pStr; PJSON_UPDATE_STAT(m_num_numeric_chars, 1);
- if (globals::s_parse_flags[c] & 8)
- {
- n32 = (n32 * 10U) + (c - '0'); c = *++pStr; PJSON_UPDATE_STAT(m_num_numeric_chars, 1);
- if (globals::s_parse_flags[c] & 8)
- {
- n32 = (n32 * 10U) + (c - '0'); c = *++pStr; PJSON_UPDATE_STAT(m_num_numeric_chars, 1);
- }
- }
- }
- }
- }
- }
- }
- }
- if (!(globals::s_parse_flags[c] & 0x10))
- {
- pChild_variant->m_type = cJSONValueTypeInt;
- pChild_variant->m_data.m_nVal = is_neg + (static_cast<int32>(n32) ^ (-is_neg));
- }
- else
- {
- uint64 n64 = n32;
- while (globals::s_parse_flags[c] & 8)
- {
- n64 = n64 * 10U + (c - '0'); PJSON_INCREMENT_STAT(m_num_numeric_chars); c = *++pStr;
- if ((!(globals::s_parse_flags[c] & 8)) || (n64 > 0xCCCCCCCCCCCCCCBULL))
- break;
- n64 = n64 * 10U + (c - '0'); PJSON_INCREMENT_STAT(m_num_numeric_chars); c = *++pStr;
- if (n64 > 0xCCCCCCCCCCCCCCBULL)
- break;
- }
- if (!(globals::s_parse_flags[c] & 0x10))
- {
- pChild_variant->m_type = cJSONValueTypeInt;
- pChild_variant->m_data.m_nVal = is_neg + (static_cast<int64>(n64) ^ (-is_neg));
- }
- else
- {
- double f = static_cast<double>(n64);
- int scale = 0, escalesign = 1, escale = 0;
- while (globals::s_parse_flags[c] & 8)
- {
- f = f * 10.0f + (c - '0'); PJSON_INCREMENT_STAT(m_num_numeric_chars); c = *++pStr;
- if (!(globals::s_parse_flags[c] & 8))
- break;
- f = f * 10.0f + (c - '0'); PJSON_INCREMENT_STAT(m_num_numeric_chars); c = *++pStr;
- }
- if (c == '.')
- {
- PJSON_INCREMENT_STAT(m_num_numeric_chars); c = *++pStr;
- while (globals::s_parse_flags[c] & 8)
- {
- scale--; f = f * 10.0f + (c - '0'); PJSON_INCREMENT_STAT(m_num_numeric_chars); c = *++pStr;
- if (!(globals::s_parse_flags[c] & 8))
- break;
- scale--; f = f * 10.0f + (c - '0'); PJSON_INCREMENT_STAT(m_num_numeric_chars); c = *++pStr;
- }
- }
- if ((c == 'e') || (c == 'E'))
- {
- PJSON_INCREMENT_STAT(m_num_numeric_chars);
- c = *++pStr;
- if (c == '-')
- {
- escalesign = -1;
- PJSON_INCREMENT_STAT(m_num_numeric_chars); c = *++pStr;
- }
- else if (c == '+')
- {
- PJSON_INCREMENT_STAT(m_num_numeric_chars); c = *++pStr;
- }
- while (globals::s_parse_flags[c] & 8)
- {
- if (escale > 0xCCCCCCB)
- return set_error(pStr, "Failed parsing numeric value");
- escale = escale * 10 + (c - '0');
- PJSON_INCREMENT_STAT(m_num_numeric_chars); c = *++pStr;
- }
- }
- static const float s_neg[2] = { 1.0f, -1.0f };
- double v = f * s_neg[is_neg];
- int64 final_scale = scale + escale * escalesign;
- if (static_cast<uint64>(final_scale + 31) <= 62)
- v *= globals::s_pow10_table[static_cast<int>(final_scale) + 31];
- else
- {
- if ((final_scale < INT32_MIN) || (final_scale > INT32_MAX))
- return set_error(pStr, "Failed parsing numeric value");
- v *= pow(10.0, static_cast<int>(final_scale));
- }
- pChild_variant->m_type = cJSONValueTypeDouble;
- pChild_variant->m_data.m_flVal = v;
- }
- }
- break;
- }
- case '\0':
- return set_error(pStr, "Premature end of string (expected name or value)");
- default:
- return set_error(pStr, "Unrecognized character");
- }
- }
- }
- bool deserialize_start(uint8* pStr)
- {
- set_to_null();
- #if PJSON_PARSE_STATS
- m_parse_stats.clear();
- #endif
- m_allocator.reset();
- m_pStart = pStr;
- m_pStr = skip_whitespace(pStr);
- if (!*m_pStr)
- return set_error(m_pStr, "Nothing to deserialize");
- bool success = false;
- uint8 c = *m_pStr;
- if ((c == '{') || (c == '['))
- {
- set_to_node(c == '{'); PJSON_INCREMENT_STAT(m_num_control);
- success = deserialize_internal();
- }
- else
- return set_error(m_pStr, "Root value must be an object or array");
- if (success)
- {
- m_pStr = skip_whitespace(m_pStr);
- success = !*m_pStr;
- if (!success)
- set_error(m_pStr, "Unknown data at end of document");
- }
- return success;
- }
- };
- } // namespace pjson
- #endif // PJSON_H
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement