C++ style

Apply c++ code format  to all files!
This commit is contained in:
enWILLYado 2018-02-17 20:15:48 +01:00
parent 7f31f70876
commit 4276afc4f4
43 changed files with 14589 additions and 10107 deletions

View file

@ -39,17 +39,22 @@ extern "C" int posix_memalign(void **__memptr, size_t __alignment, size_t __size
#endif #endif
static __inline__ void *__attribute__((__always_inline__, __malloc__)) _mm_malloc(size_t __size, size_t __align) static __inline__ void* __attribute__((__always_inline__, __malloc__)) _mm_malloc(size_t __size,
size_t __align)
{
if(__align == 1)
{ {
if (__align == 1) {
return malloc(__size); return malloc(__size);
} }
if(!(__align & (__align - 1)) && __align < sizeof(void*)) if(!(__align & (__align - 1)) && __align < sizeof(void*))
{
__align = sizeof(void*); __align = sizeof(void*);
}
void* __mallocedMemory; void* __mallocedMemory;
if (posix_memalign(&__mallocedMemory, __align, __size)) { if(posix_memalign(&__mallocedMemory, __align, __size))
{
return 0; return 0;
} }

View file

@ -141,7 +141,9 @@ _vwarnx(const char *fmt,va_list ap)
{ {
(void)fprintf(stderr, "%s: ", __progname); (void)fprintf(stderr, "%s: ", __progname);
if(fmt != NULL) if(fmt != NULL)
{
(void)vfprintf(stderr, fmt, ap); (void)vfprintf(stderr, fmt, ap);
}
(void)fprintf(stderr, "\n"); (void)fprintf(stderr, "\n");
} }
@ -163,7 +165,8 @@ gcd(int a, int b)
int c; int c;
c = a % b; c = a % b;
while (c != 0) { while(c != 0)
{
a = b; a = b;
b = c; b = c;
c = a % b; c = a % b;
@ -192,14 +195,20 @@ permute_args(int panonopt_start, int panonopt_end, int opt_end,
ncycle = gcd(nnonopts, nopts); ncycle = gcd(nnonopts, nopts);
cyclelen = (opt_end - panonopt_start) / ncycle; cyclelen = (opt_end - panonopt_start) / ncycle;
for (i = 0; i < ncycle; i++) { for(i = 0; i < ncycle; i++)
{
cstart = panonopt_end + i; cstart = panonopt_end + i;
pos = cstart; pos = cstart;
for (j = 0; j < cyclelen; j++) { for(j = 0; j < cyclelen; j++)
{
if(pos >= panonopt_end) if(pos >= panonopt_end)
{
pos -= nnonopts; pos -= nnonopts;
}
else else
{
pos += nopts; pos += nopts;
}
swap = nargv[pos]; swap = nargv[pos];
/* LINTED const cast */ /* LINTED const cast */
((char**) nargv)[pos] = nargv[cstart]; ((char**) nargv)[pos] = nargv[cstart];
@ -304,20 +313,28 @@ parse_long_options(char * const *nargv, const char *options,
optind++; optind++;
if ((has_equal = strchr(current_argv, '=')) != NULL) { if((has_equal = strchr(current_argv, '=')) != NULL)
{
/* argument found (--option=arg) */ /* argument found (--option=arg) */
current_argv_len = has_equal - current_argv; current_argv_len = has_equal - current_argv;
has_equal++; has_equal++;
} else }
else
{
current_argv_len = strlen(current_argv); current_argv_len = strlen(current_argv);
}
for (i = 0; long_options[i].name; i++) { for(i = 0; long_options[i].name; i++)
{
/* find matching long option */ /* find matching long option */
if(strncmp(current_argv, long_options[i].name, if(strncmp(current_argv, long_options[i].name,
current_argv_len)) current_argv_len))
{
continue; continue;
}
if (strlen(long_options[i].name) == current_argv_len) { if(strlen(long_options[i].name) == current_argv_len)
{
/* exact match */ /* exact match */
match = i; match = i;
ambiguous = 0; ambiguous = 0;
@ -328,14 +345,21 @@ parse_long_options(char * const *nargv, const char *options,
* a partial match of a single character. * a partial match of a single character.
*/ */
if(short_too && current_argv_len == 1) if(short_too && current_argv_len == 1)
{
continue; continue;
}
if(match == -1) /* partial match */ if(match == -1) /* partial match */
{
match = i; match = i;
}
else if(!IDENTICAL_INTERPRETATION(i, match)) else if(!IDENTICAL_INTERPRETATION(i, match))
{
ambiguous = 1; ambiguous = 1;
} }
if (ambiguous) { }
if(ambiguous)
{
/* ambiguous abbreviation */ /* ambiguous abbreviation */
if(PRINT_ERROR) if(PRINT_ERROR)
warnx(ambig, (int)current_argv_len, warnx(ambig, (int)current_argv_len,
@ -343,9 +367,11 @@ parse_long_options(char * const *nargv, const char *options,
optopt = 0; optopt = 0;
return (BADCH); return (BADCH);
} }
if (match != -1) { /* option found */ if(match != -1) /* option found */
{
if(long_options[match].has_arg == no_argument if(long_options[match].has_arg == no_argument
&& has_equal) { && has_equal)
{
if(PRINT_ERROR) if(PRINT_ERROR)
warnx(noarg, (int)current_argv_len, warnx(noarg, (int)current_argv_len,
current_argv); current_argv);
@ -353,17 +379,25 @@ parse_long_options(char * const *nargv, const char *options,
* XXX: GNU sets optopt to val regardless of flag * XXX: GNU sets optopt to val regardless of flag
*/ */
if(long_options[match].flag == NULL) if(long_options[match].flag == NULL)
{
optopt = long_options[match].val; optopt = long_options[match].val;
}
else else
{
optopt = 0; optopt = 0;
}
return (BADARG); return (BADARG);
} }
if(long_options[match].has_arg == required_argument || if(long_options[match].has_arg == required_argument ||
long_options[match].has_arg == optional_argument) { long_options[match].has_arg == optional_argument)
{
if(has_equal) if(has_equal)
{
optarg = has_equal; optarg = has_equal;
}
else if(long_options[match].has_arg == else if(long_options[match].has_arg ==
required_argument) { required_argument)
{
/* /*
* optional argument doesn't use next nargv * optional argument doesn't use next nargv
*/ */
@ -371,7 +405,8 @@ parse_long_options(char * const *nargv, const char *options,
} }
} }
if((long_options[match].has_arg == required_argument) if((long_options[match].has_arg == required_argument)
&& (optarg == NULL)) { && (optarg == NULL))
{
/* /*
* Missing argument; leading ':' indicates no error * Missing argument; leading ':' indicates no error
* should be generated. * should be generated.
@ -383,29 +418,44 @@ parse_long_options(char * const *nargv, const char *options,
* XXX: GNU sets optopt to val regardless of flag * XXX: GNU sets optopt to val regardless of flag
*/ */
if(long_options[match].flag == NULL) if(long_options[match].flag == NULL)
{
optopt = long_options[match].val; optopt = long_options[match].val;
}
else else
{
optopt = 0; optopt = 0;
}
--optind; --optind;
return (BADARG); return (BADARG);
} }
} else { /* unknown option */ }
if (short_too) { else /* unknown option */
{
if(short_too)
{
--optind; --optind;
return (-1); return (-1);
} }
if(PRINT_ERROR) if(PRINT_ERROR)
{
warnx(illoptstring, current_argv); warnx(illoptstring, current_argv);
}
optopt = 0; optopt = 0;
return (BADCH); return (BADCH);
} }
if(idx) if(idx)
{
*idx = match; *idx = match;
if (long_options[match].flag) { }
if(long_options[match].flag)
{
*long_options[match].flag = long_options[match].val; *long_options[match].flag = long_options[match].val;
return (0); return (0);
} else }
else
{
return (long_options[match].val); return (long_options[match].val);
}
#undef IDENTICAL_INTERPRETATION #undef IDENTICAL_INTERPRETATION
} }
@ -422,14 +472,18 @@ getopt_internal(int nargc, char * const *nargv, const char *options,
static int posixly_correct = -1; static int posixly_correct = -1;
if(options == NULL) if(options == NULL)
{
return (-1); return (-1);
}
/* /*
* XXX Some GNU programs (like cvs) set optind to 0 instead of * XXX Some GNU programs (like cvs) set optind to 0 instead of
* XXX using optreset. Work around this braindamage. * XXX using optreset. Work around this braindamage.
*/ */
if(optind == 0) if(optind == 0)
{
optind = optreset = 1; optind = optreset = 1;
}
/* /*
* Disable GNU extensions if POSIXLY_CORRECT is set or options * Disable GNU extensions if POSIXLY_CORRECT is set or options
@ -439,29 +493,43 @@ getopt_internal(int nargc, char * const *nargv, const char *options,
* optreset != 0 for GNU compatibility. * optreset != 0 for GNU compatibility.
*/ */
if(posixly_correct == -1 || optreset != 0) if(posixly_correct == -1 || optreset != 0)
{
posixly_correct = (getenv("POSIXLY_CORRECT") != NULL); posixly_correct = (getenv("POSIXLY_CORRECT") != NULL);
}
if(*options == '-') if(*options == '-')
{
flags |= FLAG_ALLARGS; flags |= FLAG_ALLARGS;
}
else if(posixly_correct || *options == '+') else if(posixly_correct || *options == '+')
{
flags &= ~FLAG_PERMUTE; flags &= ~FLAG_PERMUTE;
}
if(*options == '+' || *options == '-') if(*options == '+' || *options == '-')
{
options++; options++;
}
optarg = NULL; optarg = NULL;
if(optreset) if(optreset)
{
nonopt_start = nonopt_end = -1; nonopt_start = nonopt_end = -1;
}
start: start:
if (optreset || !*place) { /* update scanning pointer */ if(optreset || !*place) /* update scanning pointer */
{
optreset = 0; optreset = 0;
if (optind >= nargc) { /* end of argument vector */ if(optind >= nargc) /* end of argument vector */
{
place = EMSG; place = EMSG;
if (nonopt_end != -1) { if(nonopt_end != -1)
{
/* do permutation, if we have to */ /* do permutation, if we have to */
permute_args(nonopt_start, nonopt_end, permute_args(nonopt_start, nonopt_end,
optind, nargv); optind, nargv);
optind -= nonopt_end - nonopt_start; optind -= nonopt_end - nonopt_start;
} }
else if (nonopt_start != -1) { else if(nonopt_start != -1)
{
/* /*
* If we skipped non-options, set optind * If we skipped non-options, set optind
* to the first of them. * to the first of them.
@ -472,9 +540,11 @@ start:
return (-1); return (-1);
} }
if(*(place = nargv[optind]) != '-' || if(*(place = nargv[optind]) != '-' ||
(place[1] == '\0' && strchr(options, '-') == NULL)) { (place[1] == '\0' && strchr(options, '-') == NULL))
{
place = EMSG; /* found non-option */ place = EMSG; /* found non-option */
if (flags & FLAG_ALLARGS) { if(flags & FLAG_ALLARGS)
{
/* /*
* GNU extension: * GNU extension:
* return non-option as argument to option 1 * return non-option as argument to option 1
@ -482,7 +552,8 @@ start:
optarg = nargv[optind++]; optarg = nargv[optind++];
return (INORDER); return (INORDER);
} }
if (!(flags & FLAG_PERMUTE)) { if(!(flags & FLAG_PERMUTE))
{
/* /*
* If no permutation wanted, stop parsing * If no permutation wanted, stop parsing
* at first non-option. * at first non-option.
@ -491,8 +562,11 @@ start:
} }
/* do permutation */ /* do permutation */
if(nonopt_start == -1) if(nonopt_start == -1)
{
nonopt_start = optind; nonopt_start = optind;
else if (nonopt_end != -1) { }
else if(nonopt_end != -1)
{
permute_args(nonopt_start, nonopt_end, permute_args(nonopt_start, nonopt_end,
optind, nargv); optind, nargv);
nonopt_start = optind - nonopt_start = optind -
@ -504,19 +578,23 @@ start:
goto start; goto start;
} }
if(nonopt_start != -1 && nonopt_end == -1) if(nonopt_start != -1 && nonopt_end == -1)
{
nonopt_end = optind; nonopt_end = optind;
}
/* /*
* If we have "-" do nothing, if "--" we are done. * If we have "-" do nothing, if "--" we are done.
*/ */
if (place[1] != '\0' && *++place == '-' && place[1] == '\0') { if(place[1] != '\0' && *++place == '-' && place[1] == '\0')
{
optind++; optind++;
place = EMSG; place = EMSG;
/* /*
* We found an option (--), so if we skipped * We found an option (--), so if we skipped
* non-options, we have to permute. * non-options, we have to permute.
*/ */
if (nonopt_end != -1) { if(nonopt_end != -1)
{
permute_args(nonopt_start, nonopt_end, permute_args(nonopt_start, nonopt_end,
optind, nargv); optind, nargv);
optind -= nonopt_end - nonopt_start; optind -= nonopt_end - nonopt_start;
@ -533,16 +611,22 @@ start:
* 3) either the arg starts with -- we are getopt_long_only() * 3) either the arg starts with -- we are getopt_long_only()
*/ */
if(long_options != NULL && place != nargv[optind] && if(long_options != NULL && place != nargv[optind] &&
(*place == '-' || (flags & FLAG_LONGONLY))) { (*place == '-' || (flags & FLAG_LONGONLY)))
{
short_too = 0; short_too = 0;
if(*place == '-') if(*place == '-')
{
place++; /* --foo long option */ place++; /* --foo long option */
}
else if(*place != ':' && strchr(options, *place) != NULL) else if(*place != ':' && strchr(options, *place) != NULL)
{
short_too = 1; /* could be short option too */ short_too = 1; /* could be short option too */
}
optchar = parse_long_options(nargv, options, long_options, optchar = parse_long_options(nargv, options, long_options,
idx, short_too); idx, short_too);
if (optchar != -1) { if(optchar != -1)
{
place = EMSG; place = EMSG;
return (optchar); return (optchar);
} }
@ -550,55 +634,83 @@ start:
if((optchar = (int) * place++) == (int)':' || if((optchar = (int) * place++) == (int)':' ||
(optchar == (int)'-' && *place != '\0') || (optchar == (int)'-' && *place != '\0') ||
(oli = (char*)strchr(options, optchar)) == NULL) { (oli = (char*)strchr(options, optchar)) == NULL)
{
/* /*
* If the user specified "-" and '-' isn't listed in * If the user specified "-" and '-' isn't listed in
* options, return -1 (non-option) as per POSIX. * options, return -1 (non-option) as per POSIX.
* Otherwise, it is an unknown option character (or ':'). * Otherwise, it is an unknown option character (or ':').
*/ */
if(optchar == (int)'-' && *place == '\0') if(optchar == (int)'-' && *place == '\0')
{
return (-1); return (-1);
}
if(!*place) if(!*place)
{
++optind; ++optind;
}
if(PRINT_ERROR) if(PRINT_ERROR)
{
warnx(illoptchar, optchar); warnx(illoptchar, optchar);
}
optopt = optchar; optopt = optchar;
return (BADCH); return (BADCH);
} }
if (long_options != NULL && optchar == 'W' && oli[1] == ';') { if(long_options != NULL && optchar == 'W' && oli[1] == ';')
{
/* -W long-option */ /* -W long-option */
if(*place) /* no space */ if(*place) /* no space */
/* NOTHING */; /* NOTHING */;
else if (++optind >= nargc) { /* no arg */ else if(++optind >= nargc) /* no arg */
{
place = EMSG; place = EMSG;
if(PRINT_ERROR) if(PRINT_ERROR)
{
warnx(recargchar, optchar); warnx(recargchar, optchar);
}
optopt = optchar; optopt = optchar;
return (BADARG); return (BADARG);
} else /* white space */ }
else /* white space */
{
place = nargv[optind]; place = nargv[optind];
}
optchar = parse_long_options(nargv, options, long_options, optchar = parse_long_options(nargv, options, long_options,
idx, 0); idx, 0);
place = EMSG; place = EMSG;
return (optchar); return (optchar);
} }
if (*++oli != ':') { /* doesn't take argument */ if(*++oli != ':') /* doesn't take argument */
{
if(!*place) if(!*place)
{
++optind; ++optind;
} else { /* takes (optional) argument */ }
}
else /* takes (optional) argument */
{
optarg = NULL; optarg = NULL;
if(*place) /* no white space */ if(*place) /* no white space */
{
optarg = place; optarg = place;
else if (oli[1] != ':') { /* arg not optional */ }
if (++optind >= nargc) { /* no arg */ else if(oli[1] != ':') /* arg not optional */
{
if(++optind >= nargc) /* no arg */
{
place = EMSG; place = EMSG;
if(PRINT_ERROR) if(PRINT_ERROR)
{
warnx(recargchar, optchar); warnx(recargchar, optchar);
}
optopt = optchar; optopt = optchar;
return (BADARG); return (BADARG);
} else }
else
{
optarg = nargv[optind]; optarg = nargv[optind];
} }
}
place = EMSG; place = EMSG;
++optind; ++optind;
} }

View file

@ -59,24 +59,35 @@ concept Allocator {
/*! This class is just wrapper for standard C library memory routines. /*! This class is just wrapper for standard C library memory routines.
\note implements Allocator concept \note implements Allocator concept
*/ */
class CrtAllocator { class CrtAllocator
{
public: public:
static const bool kNeedFree = true; static const bool kNeedFree = true;
void* Malloc(size_t size) { void* Malloc(size_t size)
{
if(size) // behavior of malloc(0) is implementation defined. if(size) // behavior of malloc(0) is implementation defined.
{
return std::malloc(size); return std::malloc(size);
}
else else
{
return NULL; // standardize to returning NULL. return NULL; // standardize to returning NULL.
} }
void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) { }
void* Realloc(void* originalPtr, size_t originalSize, size_t newSize)
{
(void)originalSize; (void)originalSize;
if (newSize == 0) { if(newSize == 0)
{
std::free(originalPtr); std::free(originalPtr);
return NULL; return NULL;
} }
return std::realloc(originalPtr, newSize); return std::realloc(originalPtr, newSize);
} }
static void Free(void *ptr) { std::free(ptr); } static void Free(void* ptr)
{
std::free(ptr);
}
}; };
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
@ -99,9 +110,11 @@ public:
\note implements Allocator concept \note implements Allocator concept
*/ */
template <typename BaseAllocator = CrtAllocator> template <typename BaseAllocator = CrtAllocator>
class MemoryPoolAllocator { class MemoryPoolAllocator
{
public: public:
static const bool kNeedFree = false; //!< Tell users that no need to call Free() with this allocator. (concept Allocator) static const bool kNeedFree =
false; //!< Tell users that no need to call Free() with this allocator. (concept Allocator)
//! Constructor with chunkSize. //! Constructor with chunkSize.
/*! \param chunkSize The size of memory chunk. The default is kDefaultChunkSize. /*! \param chunkSize The size of memory chunk. The default is kDefaultChunkSize.
@ -122,8 +135,10 @@ public:
\param chunkSize The size of memory chunk. The default is kDefaultChunkSize. \param chunkSize The size of memory chunk. The default is kDefaultChunkSize.
\param baseAllocator The allocator for allocating memory chunks. \param baseAllocator The allocator for allocating memory chunks.
*/ */
MemoryPoolAllocator(void *buffer, size_t size, size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) : MemoryPoolAllocator(void* buffer, size_t size, size_t chunkSize = kDefaultChunkCapacity,
chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(buffer), baseAllocator_(baseAllocator), ownBaseAllocator_(0) BaseAllocator* baseAllocator = 0) :
chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(buffer), baseAllocator_(baseAllocator),
ownBaseAllocator_(0)
{ {
RAPIDJSON_ASSERT(buffer != 0); RAPIDJSON_ASSERT(buffer != 0);
RAPIDJSON_ASSERT(size > sizeof(ChunkHeader)); RAPIDJSON_ASSERT(size > sizeof(ChunkHeader));
@ -136,51 +151,67 @@ public:
//! Destructor. //! Destructor.
/*! This deallocates all memory chunks, excluding the user-supplied buffer. /*! This deallocates all memory chunks, excluding the user-supplied buffer.
*/ */
~MemoryPoolAllocator() { ~MemoryPoolAllocator()
{
Clear(); Clear();
RAPIDJSON_DELETE(ownBaseAllocator_); RAPIDJSON_DELETE(ownBaseAllocator_);
} }
//! Deallocates all memory chunks, excluding the user-supplied buffer. //! Deallocates all memory chunks, excluding the user-supplied buffer.
void Clear() { void Clear()
while (chunkHead_ && chunkHead_ != userBuffer_) { {
while(chunkHead_ && chunkHead_ != userBuffer_)
{
ChunkHeader* next = chunkHead_->next; ChunkHeader* next = chunkHead_->next;
baseAllocator_->Free(chunkHead_); baseAllocator_->Free(chunkHead_);
chunkHead_ = next; chunkHead_ = next;
} }
if(chunkHead_ && chunkHead_ == userBuffer_) if(chunkHead_ && chunkHead_ == userBuffer_)
{
chunkHead_->size = 0; // Clear user buffer chunkHead_->size = 0; // Clear user buffer
} }
}
//! Computes the total capacity of allocated memory chunks. //! Computes the total capacity of allocated memory chunks.
/*! \return total capacity in bytes. /*! \return total capacity in bytes.
*/ */
size_t Capacity() const { size_t Capacity() const
{
size_t capacity = 0; size_t capacity = 0;
for(ChunkHeader* c = chunkHead_; c != 0; c = c->next) for(ChunkHeader* c = chunkHead_; c != 0; c = c->next)
{
capacity += c->capacity; capacity += c->capacity;
}
return capacity; return capacity;
} }
//! Computes the memory blocks allocated. //! Computes the memory blocks allocated.
/*! \return total used bytes. /*! \return total used bytes.
*/ */
size_t Size() const { size_t Size() const
{
size_t size = 0; size_t size = 0;
for(ChunkHeader* c = chunkHead_; c != 0; c = c->next) for(ChunkHeader* c = chunkHead_; c != 0; c = c->next)
{
size += c->size; size += c->size;
}
return size; return size;
} }
//! Allocates a memory block. (concept Allocator) //! Allocates a memory block. (concept Allocator)
void* Malloc(size_t size) { void* Malloc(size_t size)
{
if(!size) if(!size)
{
return NULL; return NULL;
}
size = RAPIDJSON_ALIGN(size); size = RAPIDJSON_ALIGN(size);
if(chunkHead_ == 0 || chunkHead_->size + size > chunkHead_->capacity) if(chunkHead_ == 0 || chunkHead_->size + size > chunkHead_->capacity)
if(!AddChunk(chunk_capacity_ > size ? chunk_capacity_ : size)) if(!AddChunk(chunk_capacity_ > size ? chunk_capacity_ : size))
{
return NULL; return NULL;
}
void* buffer = reinterpret_cast<char*>(chunkHead_) + RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size; void* buffer = reinterpret_cast<char*>(chunkHead_) + RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size;
chunkHead_->size += size; chunkHead_->size += size;
@ -188,41 +219,59 @@ public:
} }
//! Resizes a memory block (concept Allocator) //! Resizes a memory block (concept Allocator)
void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) { void* Realloc(void* originalPtr, size_t originalSize, size_t newSize)
{
if(originalPtr == 0) if(originalPtr == 0)
{
return Malloc(newSize); return Malloc(newSize);
}
if(newSize == 0) if(newSize == 0)
{
return NULL; return NULL;
}
originalSize = RAPIDJSON_ALIGN(originalSize); originalSize = RAPIDJSON_ALIGN(originalSize);
newSize = RAPIDJSON_ALIGN(newSize); newSize = RAPIDJSON_ALIGN(newSize);
// Do not shrink if new size is smaller than original // Do not shrink if new size is smaller than original
if(originalSize >= newSize) if(originalSize >= newSize)
{
return originalPtr; return originalPtr;
}
// Simply expand it if it is the last allocation and there is sufficient space // Simply expand it if it is the last allocation and there is sufficient space
if (originalPtr == reinterpret_cast<char *>(chunkHead_) + RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size - originalSize) { if(originalPtr == reinterpret_cast<char*>(chunkHead_) + RAPIDJSON_ALIGN(sizeof(
ChunkHeader)) + chunkHead_->size - originalSize)
{
size_t increment = static_cast<size_t>(newSize - originalSize); size_t increment = static_cast<size_t>(newSize - originalSize);
if (chunkHead_->size + increment <= chunkHead_->capacity) { if(chunkHead_->size + increment <= chunkHead_->capacity)
{
chunkHead_->size += increment; chunkHead_->size += increment;
return originalPtr; return originalPtr;
} }
} }
// Realloc process: allocate and copy memory, do not free original buffer. // Realloc process: allocate and copy memory, do not free original buffer.
if (void* newBuffer = Malloc(newSize)) { if(void* newBuffer = Malloc(newSize))
{
if(originalSize) if(originalSize)
{
std::memcpy(newBuffer, originalPtr, originalSize); std::memcpy(newBuffer, originalPtr, originalSize);
}
return newBuffer; return newBuffer;
} }
else else
{
return NULL; return NULL;
} }
}
//! Frees a memory block (concept Allocator) //! Frees a memory block (concept Allocator)
static void Free(void *ptr) { (void)ptr; } // Do nothing static void Free(void* ptr)
{
(void)ptr; // Do nothing
}
private: private:
//! Copy constructor is not permitted. //! Copy constructor is not permitted.
@ -234,10 +283,15 @@ private:
/*! \param capacity Capacity of the chunk in bytes. /*! \param capacity Capacity of the chunk in bytes.
\return true if success. \return true if success.
*/ */
bool AddChunk(size_t capacity) { bool AddChunk(size_t capacity)
{
if(!baseAllocator_) if(!baseAllocator_)
{
ownBaseAllocator_ = baseAllocator_ = RAPIDJSON_NEW(BaseAllocator()); ownBaseAllocator_ = baseAllocator_ = RAPIDJSON_NEW(BaseAllocator());
if (ChunkHeader* chunk = reinterpret_cast<ChunkHeader*>(baseAllocator_->Malloc(RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + capacity))) { }
if(ChunkHeader* chunk = reinterpret_cast<ChunkHeader*>(baseAllocator_->Malloc(RAPIDJSON_ALIGN(sizeof(
ChunkHeader)) + capacity)))
{
chunk->capacity = capacity; chunk->capacity = capacity;
chunk->size = 0; chunk->size = 0;
chunk->next = chunkHead_; chunk->next = chunkHead_;
@ -245,15 +299,18 @@ private:
return true; return true;
} }
else else
{
return false; return false;
} }
}
static const int kDefaultChunkCapacity = 64 * 1024; //!< Default chunk capacity. static const int kDefaultChunkCapacity = 64 * 1024; //!< Default chunk capacity.
//! Chunk header for perpending to each chunk. //! Chunk header for perpending to each chunk.
/*! Chunks are stored as a singly linked list. /*! Chunks are stored as a singly linked list.
*/ */
struct ChunkHeader { struct ChunkHeader
{
size_t capacity; //!< Capacity of the chunk in bytes (excluding the header itself). size_t capacity; //!< Capacity of the chunk in bytes (excluding the header itself).
size_t size; //!< Current size of allocated memory in bytes. size_t size; //!< Current size of allocated memory in bytes.
ChunkHeader* next; //!< Next chunk in the linked list. ChunkHeader* next; //!< Next chunk in the linked list.

File diff suppressed because it is too large Load diff

View file

@ -36,24 +36,51 @@ RAPIDJSON_NAMESPACE_BEGIN
\tparam InputByteStream Type of input byte stream. For example, FileReadStream. \tparam InputByteStream Type of input byte stream. For example, FileReadStream.
*/ */
template <typename Encoding, typename InputByteStream> template <typename Encoding, typename InputByteStream>
class EncodedInputStream { class EncodedInputStream
{
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
public: public:
typedef typename Encoding::Ch Ch; typedef typename Encoding::Ch Ch;
EncodedInputStream(InputByteStream& is) : is_(is) { EncodedInputStream(InputByteStream & is) : is_(is)
{
current_ = Encoding::TakeBOM(is_); current_ = Encoding::TakeBOM(is_);
} }
Ch Peek() const { return current_; } Ch Peek() const
Ch Take() { Ch c = current_; current_ = Encoding::Take(is_); return c; } {
size_t Tell() const { return is_.Tell(); } return current_;
}
Ch Take()
{
Ch c = current_;
current_ = Encoding::Take(is_);
return c;
}
size_t Tell() const
{
return is_.Tell();
}
// Not implemented // Not implemented
void Put(Ch) { RAPIDJSON_ASSERT(false); } void Put(Ch)
void Flush() { RAPIDJSON_ASSERT(false); } {
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } RAPIDJSON_ASSERT(false);
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } }
void Flush()
{
RAPIDJSON_ASSERT(false);
}
Ch* PutBegin()
{
RAPIDJSON_ASSERT(false);
return 0;
}
size_t PutEnd(Ch*)
{
RAPIDJSON_ASSERT(false);
return 0;
}
private: private:
EncodedInputStream(const EncodedInputStream &); EncodedInputStream(const EncodedInputStream &);
@ -65,24 +92,50 @@ private:
//! Specialized for UTF8 MemoryStream. //! Specialized for UTF8 MemoryStream.
template <> template <>
class EncodedInputStream<UTF8<>, MemoryStream> { class EncodedInputStream<UTF8<>, MemoryStream>
{
public: public:
typedef UTF8<>::Ch Ch; typedef UTF8<>::Ch Ch;
EncodedInputStream(MemoryStream& is) : is_(is) { EncodedInputStream(MemoryStream & is) : is_(is)
if (static_cast<unsigned char>(is_.Peek()) == 0xEFu) is_.Take(); {
if (static_cast<unsigned char>(is_.Peek()) == 0xBBu) is_.Take(); if(static_cast<unsigned char>(is_.Peek()) == 0xEFu)
if (static_cast<unsigned char>(is_.Peek()) == 0xBFu) is_.Take(); {
is_.Take();
}
if(static_cast<unsigned char>(is_.Peek()) == 0xBBu)
{
is_.Take();
}
if(static_cast<unsigned char>(is_.Peek()) == 0xBFu)
{
is_.Take();
}
}
Ch Peek() const
{
return is_.Peek();
}
Ch Take()
{
return is_.Take();
}
size_t Tell() const
{
return is_.Tell();
} }
Ch Peek() const { return is_.Peek(); }
Ch Take() { return is_.Take(); }
size_t Tell() const { return is_.Tell(); }
// Not implemented // Not implemented
void Put(Ch) {} void Put(Ch) {}
void Flush() {} void Flush() {}
Ch* PutBegin() { return 0; } Ch* PutBegin()
size_t PutEnd(Ch*) { return 0; } {
return 0;
}
size_t PutEnd(Ch*)
{
return 0;
}
MemoryStream & is_; MemoryStream & is_;
@ -97,25 +150,55 @@ private:
\tparam OutputByteStream Type of input byte stream. For example, FileWriteStream. \tparam OutputByteStream Type of input byte stream. For example, FileWriteStream.
*/ */
template <typename Encoding, typename OutputByteStream> template <typename Encoding, typename OutputByteStream>
class EncodedOutputStream { class EncodedOutputStream
{
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
public: public:
typedef typename Encoding::Ch Ch; typedef typename Encoding::Ch Ch;
EncodedOutputStream(OutputByteStream& os, bool putBOM = true) : os_(os) { EncodedOutputStream(OutputByteStream & os, bool putBOM = true) : os_(os)
{
if(putBOM) if(putBOM)
{
Encoding::PutBOM(os_); Encoding::PutBOM(os_);
} }
}
void Put(Ch c) { Encoding::Put(os_, c); } void Put(Ch c)
void Flush() { os_.Flush(); } {
Encoding::Put(os_, c);
}
void Flush()
{
os_.Flush();
}
// Not implemented // Not implemented
Ch Peek() const { RAPIDJSON_ASSERT(false); return 0;} Ch Peek() const
Ch Take() { RAPIDJSON_ASSERT(false); return 0;} {
size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; } RAPIDJSON_ASSERT(false);
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } return 0;
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } }
Ch Take()
{
RAPIDJSON_ASSERT(false);
return 0;
}
size_t Tell() const
{
RAPIDJSON_ASSERT(false);
return 0;
}
Ch* PutBegin()
{
RAPIDJSON_ASSERT(false);
return 0;
}
size_t PutEnd(Ch*)
{
RAPIDJSON_ASSERT(false);
return 0;
}
private: private:
EncodedOutputStream(const EncodedOutputStream &); EncodedOutputStream(const EncodedOutputStream &);
@ -132,7 +215,8 @@ private:
\tparam InputByteStream type of input byte stream to be wrapped. \tparam InputByteStream type of input byte stream to be wrapped.
*/ */
template <typename CharType, typename InputByteStream> template <typename CharType, typename InputByteStream>
class AutoUTFInputStream { class AutoUTFInputStream
{
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
public: public:
typedef CharType Ch; typedef CharType Ch;
@ -142,7 +226,8 @@ public:
\param is input stream to be wrapped. \param is input stream to be wrapped.
\param type UTF encoding type if it is not detected from the stream. \param type UTF encoding type if it is not detected from the stream.
*/ */
AutoUTFInputStream(InputByteStream& is, UTFType type = kUTF8) : is_(&is), type_(type), hasBOM_(false) { AutoUTFInputStream(InputByteStream & is, UTFType type = kUTF8) : is_(&is), type_(type), hasBOM_(false)
{
RAPIDJSON_ASSERT(type >= kUTF8 && type <= kUTF32BE); RAPIDJSON_ASSERT(type >= kUTF8 && type <= kUTF32BE);
DetectType(); DetectType();
static const TakeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Take) }; static const TakeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Take) };
@ -150,25 +235,57 @@ public:
current_ = takeFunc_(*is_); current_ = takeFunc_(*is_);
} }
UTFType GetType() const { return type_; } UTFType GetType() const
bool HasBOM() const { return hasBOM_; } {
return type_;
}
bool HasBOM() const
{
return hasBOM_;
}
Ch Peek() const { return current_; } Ch Peek() const
Ch Take() { Ch c = current_; current_ = takeFunc_(*is_); return c; } {
size_t Tell() const { return is_->Tell(); } return current_;
}
Ch Take()
{
Ch c = current_;
current_ = takeFunc_(*is_);
return c;
}
size_t Tell() const
{
return is_->Tell();
}
// Not implemented // Not implemented
void Put(Ch) { RAPIDJSON_ASSERT(false); } void Put(Ch)
void Flush() { RAPIDJSON_ASSERT(false); } {
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } RAPIDJSON_ASSERT(false);
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } }
void Flush()
{
RAPIDJSON_ASSERT(false);
}
Ch* PutBegin()
{
RAPIDJSON_ASSERT(false);
return 0;
}
size_t PutEnd(Ch*)
{
RAPIDJSON_ASSERT(false);
return 0;
}
private: private:
AutoUTFInputStream(const AutoUTFInputStream &); AutoUTFInputStream(const AutoUTFInputStream &);
AutoUTFInputStream & operator=(const AutoUTFInputStream &); AutoUTFInputStream & operator=(const AutoUTFInputStream &);
// Detect encoding type with BOM or RFC 4627 // Detect encoding type with BOM or RFC 4627
void DetectType() { void DetectType()
{
// BOM (Byte Order Mark): // BOM (Byte Order Mark):
// 00 00 FE FF UTF-32BE // 00 00 FE FF UTF-32BE
// FF FE 00 00 UTF-32LE // FF FE 00 00 UTF-32LE
@ -178,15 +295,52 @@ private:
const unsigned char* c = reinterpret_cast<const unsigned char*>(is_->Peek4()); const unsigned char* c = reinterpret_cast<const unsigned char*>(is_->Peek4());
if(!c) if(!c)
{
return; return;
}
unsigned bom = static_cast<unsigned>(c[0] | (c[1] << 8) | (c[2] << 16) | (c[3] << 24)); unsigned bom = static_cast<unsigned>(c[0] | (c[1] << 8) | (c[2] << 16) | (c[3] << 24));
hasBOM_ = false; hasBOM_ = false;
if (bom == 0xFFFE0000) { type_ = kUTF32BE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); } if(bom == 0xFFFE0000)
else if (bom == 0x0000FEFF) { type_ = kUTF32LE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); } {
else if ((bom & 0xFFFF) == 0xFFFE) { type_ = kUTF16BE; hasBOM_ = true; is_->Take(); is_->Take(); } type_ = kUTF32BE;
else if ((bom & 0xFFFF) == 0xFEFF) { type_ = kUTF16LE; hasBOM_ = true; is_->Take(); is_->Take(); } hasBOM_ = true;
else if ((bom & 0xFFFFFF) == 0xBFBBEF) { type_ = kUTF8; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); } is_->Take();
is_->Take();
is_->Take();
is_->Take();
}
else if(bom == 0x0000FEFF)
{
type_ = kUTF32LE;
hasBOM_ = true;
is_->Take();
is_->Take();
is_->Take();
is_->Take();
}
else if((bom & 0xFFFF) == 0xFFFE)
{
type_ = kUTF16BE;
hasBOM_ = true;
is_->Take();
is_->Take();
}
else if((bom & 0xFFFF) == 0xFEFF)
{
type_ = kUTF16LE;
hasBOM_ = true;
is_->Take();
is_->Take();
}
else if((bom & 0xFFFFFF) == 0xBFBBEF)
{
type_ = kUTF8;
hasBOM_ = true;
is_->Take();
is_->Take();
is_->Take();
}
// RFC 4627: Section 3 // RFC 4627: Section 3
// "Since the first two characters of a JSON text will always be ASCII // "Since the first two characters of a JSON text will always be ASCII
@ -199,21 +353,40 @@ private:
// xx 00 xx 00 UTF-16LE // xx 00 xx 00 UTF-16LE
// xx xx xx xx UTF-8 // xx xx xx xx UTF-8
if (!hasBOM_) { if(!hasBOM_)
{
unsigned pattern = (c[0] ? 1 : 0) | (c[1] ? 2 : 0) | (c[2] ? 4 : 0) | (c[3] ? 8 : 0); unsigned pattern = (c[0] ? 1 : 0) | (c[1] ? 2 : 0) | (c[2] ? 4 : 0) | (c[3] ? 8 : 0);
switch (pattern) { switch(pattern)
case 0x08: type_ = kUTF32BE; break; {
case 0x0A: type_ = kUTF16BE; break; case 0x08:
case 0x01: type_ = kUTF32LE; break; type_ = kUTF32BE;
case 0x05: type_ = kUTF16LE; break; break;
case 0x0F: type_ = kUTF8; break; case 0x0A:
default: break; // Use type defined by user. type_ = kUTF16BE;
break;
case 0x01:
type_ = kUTF32LE;
break;
case 0x05:
type_ = kUTF16LE;
break;
case 0x0F:
type_ = kUTF8;
break;
default:
break; // Use type defined by user.
} }
} }
// Runtime check whether the size of character type is sufficient. It only perform checks with assertion. // Runtime check whether the size of character type is sufficient. It only perform checks with assertion.
if (type_ == kUTF16LE || type_ == kUTF16BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 2); if(type_ == kUTF16LE || type_ == kUTF16BE)
if (type_ == kUTF32LE || type_ == kUTF32BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 4); {
RAPIDJSON_ASSERT(sizeof(Ch) >= 2);
}
if(type_ == kUTF32LE || type_ == kUTF32BE)
{
RAPIDJSON_ASSERT(sizeof(Ch) >= 4);
}
} }
typedef Ch(*TakeFunc)(InputByteStream & is); typedef Ch(*TakeFunc)(InputByteStream & is);
@ -230,7 +403,8 @@ private:
\tparam OutputByteStream type of output byte stream to be wrapped. \tparam OutputByteStream type of output byte stream to be wrapped.
*/ */
template <typename CharType, typename OutputByteStream> template <typename CharType, typename OutputByteStream>
class AutoUTFOutputStream { class AutoUTFOutputStream
{
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
public: public:
typedef CharType Ch; typedef CharType Ch;
@ -241,37 +415,76 @@ public:
\param type UTF encoding type. \param type UTF encoding type.
\param putBOM Whether to write BOM at the beginning of the stream. \param putBOM Whether to write BOM at the beginning of the stream.
*/ */
AutoUTFOutputStream(OutputByteStream& os, UTFType type, bool putBOM) : os_(&os), type_(type) { AutoUTFOutputStream(OutputByteStream & os, UTFType type, bool putBOM) : os_(&os), type_(type)
{
RAPIDJSON_ASSERT(type >= kUTF8 && type <= kUTF32BE); RAPIDJSON_ASSERT(type >= kUTF8 && type <= kUTF32BE);
// Runtime check whether the size of character type is sufficient. It only perform checks with assertion. // Runtime check whether the size of character type is sufficient. It only perform checks with assertion.
if (type_ == kUTF16LE || type_ == kUTF16BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 2); if(type_ == kUTF16LE || type_ == kUTF16BE)
if (type_ == kUTF32LE || type_ == kUTF32BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 4); {
RAPIDJSON_ASSERT(sizeof(Ch) >= 2);
}
if(type_ == kUTF32LE || type_ == kUTF32BE)
{
RAPIDJSON_ASSERT(sizeof(Ch) >= 4);
}
static const PutFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Put) }; static const PutFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Put) };
putFunc_ = f[type_]; putFunc_ = f[type_];
if(putBOM) if(putBOM)
{
PutBOM(); PutBOM();
} }
}
UTFType GetType() const { return type_; } UTFType GetType() const
{
return type_;
}
void Put(Ch c) { putFunc_(*os_, c); } void Put(Ch c)
void Flush() { os_->Flush(); } {
putFunc_(*os_, c);
}
void Flush()
{
os_->Flush();
}
// Not implemented // Not implemented
Ch Peek() const { RAPIDJSON_ASSERT(false); return 0;} Ch Peek() const
Ch Take() { RAPIDJSON_ASSERT(false); return 0;} {
size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; } RAPIDJSON_ASSERT(false);
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } return 0;
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } }
Ch Take()
{
RAPIDJSON_ASSERT(false);
return 0;
}
size_t Tell() const
{
RAPIDJSON_ASSERT(false);
return 0;
}
Ch* PutBegin()
{
RAPIDJSON_ASSERT(false);
return 0;
}
size_t PutEnd(Ch*)
{
RAPIDJSON_ASSERT(false);
return 0;
}
private: private:
AutoUTFOutputStream(const AutoUTFOutputStream &); AutoUTFOutputStream(const AutoUTFOutputStream &);
AutoUTFOutputStream & operator=(const AutoUTFOutputStream &); AutoUTFOutputStream & operator=(const AutoUTFOutputStream &);
void PutBOM() { void PutBOM()
{
typedef void (*PutBOMFunc)(OutputByteStream &); typedef void (*PutBOMFunc)(OutputByteStream &);
static const PutBOMFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(PutBOM) }; static const PutBOMFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(PutBOM) };
f[type_](*os_); f[type_](*os_);

View file

@ -93,25 +93,32 @@ concept Encoding {
\note implements Encoding concept \note implements Encoding concept
*/ */
template<typename CharType = char> template<typename CharType = char>
struct UTF8 { struct UTF8
{
typedef CharType Ch; typedef CharType Ch;
enum { supportUnicode = 1 }; enum { supportUnicode = 1 };
template<typename OutputStream> template<typename OutputStream>
static void Encode(OutputStream& os, unsigned codepoint) { static void Encode(OutputStream & os, unsigned codepoint)
{
if(codepoint <= 0x7F) if(codepoint <= 0x7F)
{
os.Put(static_cast<Ch>(codepoint & 0xFF)); os.Put(static_cast<Ch>(codepoint & 0xFF));
else if (codepoint <= 0x7FF) { }
else if(codepoint <= 0x7FF)
{
os.Put(static_cast<Ch>(0xC0 | ((codepoint >> 6) & 0xFF))); os.Put(static_cast<Ch>(0xC0 | ((codepoint >> 6) & 0xFF)));
os.Put(static_cast<Ch>(0x80 | ((codepoint & 0x3F)))); os.Put(static_cast<Ch>(0x80 | ((codepoint & 0x3F))));
} }
else if (codepoint <= 0xFFFF) { else if(codepoint <= 0xFFFF)
{
os.Put(static_cast<Ch>(0xE0 | ((codepoint >> 12) & 0xFF))); os.Put(static_cast<Ch>(0xE0 | ((codepoint >> 12) & 0xFF)));
os.Put(static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F))); os.Put(static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F)));
os.Put(static_cast<Ch>(0x80 | (codepoint & 0x3F))); os.Put(static_cast<Ch>(0x80 | (codepoint & 0x3F)));
} }
else { else
{
RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
os.Put(static_cast<Ch>(0xF0 | ((codepoint >> 18) & 0xFF))); os.Put(static_cast<Ch>(0xF0 | ((codepoint >> 18) & 0xFF)));
os.Put(static_cast<Ch>(0x80 | ((codepoint >> 12) & 0x3F))); os.Put(static_cast<Ch>(0x80 | ((codepoint >> 12) & 0x3F)));
@ -121,19 +128,25 @@ struct UTF8 {
} }
template<typename OutputStream> template<typename OutputStream>
static void EncodeUnsafe(OutputStream& os, unsigned codepoint) { static void EncodeUnsafe(OutputStream & os, unsigned codepoint)
{
if(codepoint <= 0x7F) if(codepoint <= 0x7F)
{
PutUnsafe(os, static_cast<Ch>(codepoint & 0xFF)); PutUnsafe(os, static_cast<Ch>(codepoint & 0xFF));
else if (codepoint <= 0x7FF) { }
else if(codepoint <= 0x7FF)
{
PutUnsafe(os, static_cast<Ch>(0xC0 | ((codepoint >> 6) & 0xFF))); PutUnsafe(os, static_cast<Ch>(0xC0 | ((codepoint >> 6) & 0xFF)));
PutUnsafe(os, static_cast<Ch>(0x80 | ((codepoint & 0x3F)))); PutUnsafe(os, static_cast<Ch>(0x80 | ((codepoint & 0x3F))));
} }
else if (codepoint <= 0xFFFF) { else if(codepoint <= 0xFFFF)
{
PutUnsafe(os, static_cast<Ch>(0xE0 | ((codepoint >> 12) & 0xFF))); PutUnsafe(os, static_cast<Ch>(0xE0 | ((codepoint >> 12) & 0xFF)));
PutUnsafe(os, static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F))); PutUnsafe(os, static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F)));
PutUnsafe(os, static_cast<Ch>(0x80 | (codepoint & 0x3F))); PutUnsafe(os, static_cast<Ch>(0x80 | (codepoint & 0x3F)));
} }
else { else
{
RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
PutUnsafe(os, static_cast<Ch>(0xF0 | ((codepoint >> 18) & 0xFF))); PutUnsafe(os, static_cast<Ch>(0xF0 | ((codepoint >> 18) & 0xFF)));
PutUnsafe(os, static_cast<Ch>(0x80 | ((codepoint >> 12) & 0x3F))); PutUnsafe(os, static_cast<Ch>(0x80 | ((codepoint >> 12) & 0x3F)));
@ -143,32 +156,66 @@ struct UTF8 {
} }
template <typename InputStream> template <typename InputStream>
static bool Decode(InputStream& is, unsigned* codepoint) { static bool Decode(InputStream & is, unsigned* codepoint)
{
#define COPY() c = is.Take(); *codepoint = (*codepoint << 6) | (static_cast<unsigned char>(c) & 0x3Fu) #define COPY() c = is.Take(); *codepoint = (*codepoint << 6) | (static_cast<unsigned char>(c) & 0x3Fu)
#define TRANS(mask) result &= ((GetRange(static_cast<unsigned char>(c)) & mask) != 0) #define TRANS(mask) result &= ((GetRange(static_cast<unsigned char>(c)) & mask) != 0)
#define TAIL() COPY(); TRANS(0x70) #define TAIL() COPY(); TRANS(0x70)
typename InputStream::Ch c = is.Take(); typename InputStream::Ch c = is.Take();
if (!(c & 0x80)) { if(!(c & 0x80))
{
*codepoint = static_cast<unsigned char>(c); *codepoint = static_cast<unsigned char>(c);
return true; return true;
} }
unsigned char type = GetRange(static_cast<unsigned char>(c)); unsigned char type = GetRange(static_cast<unsigned char>(c));
if (type >= 32) { if(type >= 32)
{
*codepoint = 0; *codepoint = 0;
} else { }
else
{
*codepoint = (0xFF >> type) & static_cast<unsigned char>(c); *codepoint = (0xFF >> type) & static_cast<unsigned char>(c);
} }
bool result = true; bool result = true;
switch (type) { switch(type)
case 2: TAIL(); return result; {
case 3: TAIL(); TAIL(); return result; case 2:
case 4: COPY(); TRANS(0x50); TAIL(); return result; TAIL();
case 5: COPY(); TRANS(0x10); TAIL(); TAIL(); return result; return result;
case 6: TAIL(); TAIL(); TAIL(); return result; case 3:
case 10: COPY(); TRANS(0x20); TAIL(); return result; TAIL();
case 11: COPY(); TRANS(0x60); TAIL(); TAIL(); return result; TAIL();
default: return false; return result;
case 4:
COPY();
TRANS(0x50);
TAIL();
return result;
case 5:
COPY();
TRANS(0x10);
TAIL();
TAIL();
return result;
case 6:
TAIL();
TAIL();
TAIL();
return result;
case 10:
COPY();
TRANS(0x20);
TAIL();
return result;
case 11:
COPY();
TRANS(0x60);
TAIL();
TAIL();
return result;
default:
return false;
} }
#undef COPY #undef COPY
#undef TRANS #undef TRANS
@ -176,35 +223,69 @@ struct UTF8 {
} }
template <typename InputStream, typename OutputStream> template <typename InputStream, typename OutputStream>
static bool Validate(InputStream& is, OutputStream& os) { static bool Validate(InputStream & is, OutputStream & os)
{
#define COPY() os.Put(c = is.Take()) #define COPY() os.Put(c = is.Take())
#define TRANS(mask) result &= ((GetRange(static_cast<unsigned char>(c)) & mask) != 0) #define TRANS(mask) result &= ((GetRange(static_cast<unsigned char>(c)) & mask) != 0)
#define TAIL() COPY(); TRANS(0x70) #define TAIL() COPY(); TRANS(0x70)
Ch c; Ch c;
COPY(); COPY();
if(!(c & 0x80)) if(!(c & 0x80))
{
return true; return true;
}
bool result = true; bool result = true;
switch (GetRange(static_cast<unsigned char>(c))) { switch(GetRange(static_cast<unsigned char>(c)))
case 2: TAIL(); return result; {
case 3: TAIL(); TAIL(); return result; case 2:
case 4: COPY(); TRANS(0x50); TAIL(); return result; TAIL();
case 5: COPY(); TRANS(0x10); TAIL(); TAIL(); return result; return result;
case 6: TAIL(); TAIL(); TAIL(); return result; case 3:
case 10: COPY(); TRANS(0x20); TAIL(); return result; TAIL();
case 11: COPY(); TRANS(0x60); TAIL(); TAIL(); return result; TAIL();
default: return false; return result;
case 4:
COPY();
TRANS(0x50);
TAIL();
return result;
case 5:
COPY();
TRANS(0x10);
TAIL();
TAIL();
return result;
case 6:
TAIL();
TAIL();
TAIL();
return result;
case 10:
COPY();
TRANS(0x20);
TAIL();
return result;
case 11:
COPY();
TRANS(0x60);
TAIL();
TAIL();
return result;
default:
return false;
} }
#undef COPY #undef COPY
#undef TRANS #undef TRANS
#undef TAIL #undef TAIL
} }
static unsigned char GetRange(unsigned char c) { static unsigned char GetRange(unsigned char c)
{
// Referring to DFA of http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ // Referring to DFA of http://bjoern.hoehrmann.de/utf-8/decoder/dfa/
// With new mapping 1 -> 0x10, 7 -> 0x20, 9 -> 0x40, such that AND operation can test multiple types. // With new mapping 1 -> 0x10, 7 -> 0x20, 9 -> 0x40, such that AND operation can test multiple types.
static const unsigned char type[] = { static const unsigned char type[] =
{
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,
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,
@ -220,26 +301,38 @@ struct UTF8 {
} }
template <typename InputByteStream> template <typename InputByteStream>
static CharType TakeBOM(InputByteStream& is) { static CharType TakeBOM(InputByteStream & is)
{
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
typename InputByteStream::Ch c = Take(is); typename InputByteStream::Ch c = Take(is);
if (static_cast<unsigned char>(c) != 0xEFu) return c; if(static_cast<unsigned char>(c) != 0xEFu)
{
return c;
}
c = is.Take(); c = is.Take();
if (static_cast<unsigned char>(c) != 0xBBu) return c; if(static_cast<unsigned char>(c) != 0xBBu)
{
return c;
}
c = is.Take(); c = is.Take();
if (static_cast<unsigned char>(c) != 0xBFu) return c; if(static_cast<unsigned char>(c) != 0xBFu)
{
return c;
}
c = is.Take(); c = is.Take();
return c; return c;
} }
template <typename InputByteStream> template <typename InputByteStream>
static Ch Take(InputByteStream& is) { static Ch Take(InputByteStream & is)
{
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
return static_cast<Ch>(is.Take()); return static_cast<Ch>(is.Take());
} }
template <typename OutputByteStream> template <typename OutputByteStream>
static void PutBOM(OutputByteStream& os) { static void PutBOM(OutputByteStream & os)
{
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
os.Put(static_cast<typename OutputByteStream::Ch>(0xEFu)); os.Put(static_cast<typename OutputByteStream::Ch>(0xEFu));
os.Put(static_cast<typename OutputByteStream::Ch>(0xBBu)); os.Put(static_cast<typename OutputByteStream::Ch>(0xBBu));
@ -247,7 +340,8 @@ struct UTF8 {
} }
template <typename OutputByteStream> template <typename OutputByteStream>
static void Put(OutputByteStream& os, Ch c) { static void Put(OutputByteStream & os, Ch c)
{
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
os.Put(static_cast<typename OutputByteStream::Ch>(c)); os.Put(static_cast<typename OutputByteStream::Ch>(c));
} }
@ -266,20 +360,24 @@ struct UTF8 {
For streaming, use UTF16LE and UTF16BE, which handle endianness. For streaming, use UTF16LE and UTF16BE, which handle endianness.
*/ */
template<typename CharType = wchar_t> template<typename CharType = wchar_t>
struct UTF16 { struct UTF16
{
typedef CharType Ch; typedef CharType Ch;
RAPIDJSON_STATIC_ASSERT(sizeof(Ch) >= 2); RAPIDJSON_STATIC_ASSERT(sizeof(Ch) >= 2);
enum { supportUnicode = 1 }; enum { supportUnicode = 1 };
template<typename OutputStream> template<typename OutputStream>
static void Encode(OutputStream& os, unsigned codepoint) { static void Encode(OutputStream & os, unsigned codepoint)
{
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2); RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2);
if (codepoint <= 0xFFFF) { if(codepoint <= 0xFFFF)
{
RAPIDJSON_ASSERT(codepoint < 0xD800 || codepoint > 0xDFFF); // Code point itself cannot be surrogate pair RAPIDJSON_ASSERT(codepoint < 0xD800 || codepoint > 0xDFFF); // Code point itself cannot be surrogate pair
os.Put(static_cast<typename OutputStream::Ch>(codepoint)); os.Put(static_cast<typename OutputStream::Ch>(codepoint));
} }
else { else
{
RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
unsigned v = codepoint - 0x10000; unsigned v = codepoint - 0x10000;
os.Put(static_cast<typename OutputStream::Ch>((v >> 10) | 0xD800)); os.Put(static_cast<typename OutputStream::Ch>((v >> 10) | 0xD800));
@ -289,13 +387,16 @@ struct UTF16 {
template<typename OutputStream> template<typename OutputStream>
static void EncodeUnsafe(OutputStream& os, unsigned codepoint) { static void EncodeUnsafe(OutputStream & os, unsigned codepoint)
{
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2); RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2);
if (codepoint <= 0xFFFF) { if(codepoint <= 0xFFFF)
{
RAPIDJSON_ASSERT(codepoint < 0xD800 || codepoint > 0xDFFF); // Code point itself cannot be surrogate pair RAPIDJSON_ASSERT(codepoint < 0xD800 || codepoint > 0xDFFF); // Code point itself cannot be surrogate pair
PutUnsafe(os, static_cast<typename OutputStream::Ch>(codepoint)); PutUnsafe(os, static_cast<typename OutputStream::Ch>(codepoint));
} }
else { else
{
RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
unsigned v = codepoint - 0x10000; unsigned v = codepoint - 0x10000;
PutUnsafe(os, static_cast<typename OutputStream::Ch>((v >> 10) | 0xD800)); PutUnsafe(os, static_cast<typename OutputStream::Ch>((v >> 10) | 0xD800));
@ -304,14 +405,17 @@ struct UTF16 {
} }
template <typename InputStream> template <typename InputStream>
static bool Decode(InputStream& is, unsigned* codepoint) { static bool Decode(InputStream & is, unsigned* codepoint)
{
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2); RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2);
typename InputStream::Ch c = is.Take(); typename InputStream::Ch c = is.Take();
if (c < 0xD800 || c > 0xDFFF) { if(c < 0xD800 || c > 0xDFFF)
{
*codepoint = static_cast<unsigned>(c); *codepoint = static_cast<unsigned>(c);
return true; return true;
} }
else if (c <= 0xDBFF) { else if(c <= 0xDBFF)
{
*codepoint = (static_cast<unsigned>(c) & 0x3FF) << 10; *codepoint = (static_cast<unsigned>(c) & 0x3FF) << 10;
c = is.Take(); c = is.Take();
*codepoint |= (static_cast<unsigned>(c) & 0x3FF); *codepoint |= (static_cast<unsigned>(c) & 0x3FF);
@ -322,14 +426,18 @@ struct UTF16 {
} }
template <typename InputStream, typename OutputStream> template <typename InputStream, typename OutputStream>
static bool Validate(InputStream& is, OutputStream& os) { static bool Validate(InputStream & is, OutputStream & os)
{
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2); RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2);
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2); RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2);
typename InputStream::Ch c; typename InputStream::Ch c;
os.Put(static_cast<typename OutputStream::Ch>(c = is.Take())); os.Put(static_cast<typename OutputStream::Ch>(c = is.Take()));
if(c < 0xD800 || c > 0xDFFF) if(c < 0xD800 || c > 0xDFFF)
{
return true; return true;
else if (c <= 0xDBFF) { }
else if(c <= 0xDBFF)
{
os.Put(c = is.Take()); os.Put(c = is.Take());
return c >= 0xDC00 && c <= 0xDFFF; return c >= 0xDC00 && c <= 0xDFFF;
} }
@ -339,16 +447,19 @@ struct UTF16 {
//! UTF-16 little endian encoding. //! UTF-16 little endian encoding.
template<typename CharType = wchar_t> template<typename CharType = wchar_t>
struct UTF16LE : UTF16<CharType> { struct UTF16LE : UTF16<CharType>
{
template <typename InputByteStream> template <typename InputByteStream>
static CharType TakeBOM(InputByteStream& is) { static CharType TakeBOM(InputByteStream & is)
{
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
CharType c = Take(is); CharType c = Take(is);
return static_cast<uint16_t>(c) == 0xFEFFu ? Take(is) : c; return static_cast<uint16_t>(c) == 0xFEFFu ? Take(is) : c;
} }
template <typename InputByteStream> template <typename InputByteStream>
static CharType Take(InputByteStream& is) { static CharType Take(InputByteStream & is)
{
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
unsigned c = static_cast<uint8_t>(is.Take()); unsigned c = static_cast<uint8_t>(is.Take());
c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 8; c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 8;
@ -356,14 +467,16 @@ struct UTF16LE : UTF16<CharType> {
} }
template <typename OutputByteStream> template <typename OutputByteStream>
static void PutBOM(OutputByteStream& os) { static void PutBOM(OutputByteStream & os)
{
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
os.Put(static_cast<typename OutputByteStream::Ch>(0xFFu)); os.Put(static_cast<typename OutputByteStream::Ch>(0xFFu));
os.Put(static_cast<typename OutputByteStream::Ch>(0xFEu)); os.Put(static_cast<typename OutputByteStream::Ch>(0xFEu));
} }
template <typename OutputByteStream> template <typename OutputByteStream>
static void Put(OutputByteStream& os, CharType c) { static void Put(OutputByteStream & os, CharType c)
{
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
os.Put(static_cast<typename OutputByteStream::Ch>(static_cast<unsigned>(c) & 0xFFu)); os.Put(static_cast<typename OutputByteStream::Ch>(static_cast<unsigned>(c) & 0xFFu));
os.Put(static_cast<typename OutputByteStream::Ch>((static_cast<unsigned>(c) >> 8) & 0xFFu)); os.Put(static_cast<typename OutputByteStream::Ch>((static_cast<unsigned>(c) >> 8) & 0xFFu));
@ -372,16 +485,19 @@ struct UTF16LE : UTF16<CharType> {
//! UTF-16 big endian encoding. //! UTF-16 big endian encoding.
template<typename CharType = wchar_t> template<typename CharType = wchar_t>
struct UTF16BE : UTF16<CharType> { struct UTF16BE : UTF16<CharType>
{
template <typename InputByteStream> template <typename InputByteStream>
static CharType TakeBOM(InputByteStream& is) { static CharType TakeBOM(InputByteStream & is)
{
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
CharType c = Take(is); CharType c = Take(is);
return static_cast<uint16_t>(c) == 0xFEFFu ? Take(is) : c; return static_cast<uint16_t>(c) == 0xFEFFu ? Take(is) : c;
} }
template <typename InputByteStream> template <typename InputByteStream>
static CharType Take(InputByteStream& is) { static CharType Take(InputByteStream & is)
{
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
unsigned c = static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 8; unsigned c = static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 8;
c |= static_cast<uint8_t>(is.Take()); c |= static_cast<uint8_t>(is.Take());
@ -389,14 +505,16 @@ struct UTF16BE : UTF16<CharType> {
} }
template <typename OutputByteStream> template <typename OutputByteStream>
static void PutBOM(OutputByteStream& os) { static void PutBOM(OutputByteStream & os)
{
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
os.Put(static_cast<typename OutputByteStream::Ch>(0xFEu)); os.Put(static_cast<typename OutputByteStream::Ch>(0xFEu));
os.Put(static_cast<typename OutputByteStream::Ch>(0xFFu)); os.Put(static_cast<typename OutputByteStream::Ch>(0xFFu));
} }
template <typename OutputByteStream> template <typename OutputByteStream>
static void Put(OutputByteStream& os, CharType c) { static void Put(OutputByteStream & os, CharType c)
{
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
os.Put(static_cast<typename OutputByteStream::Ch>((static_cast<unsigned>(c) >> 8) & 0xFFu)); os.Put(static_cast<typename OutputByteStream::Ch>((static_cast<unsigned>(c) >> 8) & 0xFFu));
os.Put(static_cast<typename OutputByteStream::Ch>(static_cast<unsigned>(c) & 0xFFu)); os.Put(static_cast<typename OutputByteStream::Ch>(static_cast<unsigned>(c) & 0xFFu));
@ -415,28 +533,32 @@ struct UTF16BE : UTF16<CharType> {
For streaming, use UTF32LE and UTF32BE, which handle endianness. For streaming, use UTF32LE and UTF32BE, which handle endianness.
*/ */
template<typename CharType = unsigned> template<typename CharType = unsigned>
struct UTF32 { struct UTF32
{
typedef CharType Ch; typedef CharType Ch;
RAPIDJSON_STATIC_ASSERT(sizeof(Ch) >= 4); RAPIDJSON_STATIC_ASSERT(sizeof(Ch) >= 4);
enum { supportUnicode = 1 }; enum { supportUnicode = 1 };
template<typename OutputStream> template<typename OutputStream>
static void Encode(OutputStream& os, unsigned codepoint) { static void Encode(OutputStream & os, unsigned codepoint)
{
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 4); RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 4);
RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
os.Put(codepoint); os.Put(codepoint);
} }
template<typename OutputStream> template<typename OutputStream>
static void EncodeUnsafe(OutputStream& os, unsigned codepoint) { static void EncodeUnsafe(OutputStream & os, unsigned codepoint)
{
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 4); RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 4);
RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
PutUnsafe(os, codepoint); PutUnsafe(os, codepoint);
} }
template <typename InputStream> template <typename InputStream>
static bool Decode(InputStream& is, unsigned* codepoint) { static bool Decode(InputStream & is, unsigned* codepoint)
{
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 4); RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 4);
Ch c = is.Take(); Ch c = is.Take();
*codepoint = c; *codepoint = c;
@ -444,7 +566,8 @@ struct UTF32 {
} }
template <typename InputStream, typename OutputStream> template <typename InputStream, typename OutputStream>
static bool Validate(InputStream& is, OutputStream& os) { static bool Validate(InputStream & is, OutputStream & os)
{
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 4); RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 4);
Ch c; Ch c;
os.Put(c = is.Take()); os.Put(c = is.Take());
@ -454,16 +577,19 @@ struct UTF32 {
//! UTF-32 little endian enocoding. //! UTF-32 little endian enocoding.
template<typename CharType = unsigned> template<typename CharType = unsigned>
struct UTF32LE : UTF32<CharType> { struct UTF32LE : UTF32<CharType>
{
template <typename InputByteStream> template <typename InputByteStream>
static CharType TakeBOM(InputByteStream& is) { static CharType TakeBOM(InputByteStream & is)
{
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
CharType c = Take(is); CharType c = Take(is);
return static_cast<uint32_t>(c) == 0x0000FEFFu ? Take(is) : c; return static_cast<uint32_t>(c) == 0x0000FEFFu ? Take(is) : c;
} }
template <typename InputByteStream> template <typename InputByteStream>
static CharType Take(InputByteStream& is) { static CharType Take(InputByteStream & is)
{
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
unsigned c = static_cast<uint8_t>(is.Take()); unsigned c = static_cast<uint8_t>(is.Take());
c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 8; c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 8;
@ -473,7 +599,8 @@ struct UTF32LE : UTF32<CharType> {
} }
template <typename OutputByteStream> template <typename OutputByteStream>
static void PutBOM(OutputByteStream& os) { static void PutBOM(OutputByteStream & os)
{
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
os.Put(static_cast<typename OutputByteStream::Ch>(0xFFu)); os.Put(static_cast<typename OutputByteStream::Ch>(0xFFu));
os.Put(static_cast<typename OutputByteStream::Ch>(0xFEu)); os.Put(static_cast<typename OutputByteStream::Ch>(0xFEu));
@ -482,7 +609,8 @@ struct UTF32LE : UTF32<CharType> {
} }
template <typename OutputByteStream> template <typename OutputByteStream>
static void Put(OutputByteStream& os, CharType c) { static void Put(OutputByteStream & os, CharType c)
{
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
os.Put(static_cast<typename OutputByteStream::Ch>(c & 0xFFu)); os.Put(static_cast<typename OutputByteStream::Ch>(c & 0xFFu));
os.Put(static_cast<typename OutputByteStream::Ch>((c >> 8) & 0xFFu)); os.Put(static_cast<typename OutputByteStream::Ch>((c >> 8) & 0xFFu));
@ -493,16 +621,19 @@ struct UTF32LE : UTF32<CharType> {
//! UTF-32 big endian encoding. //! UTF-32 big endian encoding.
template<typename CharType = unsigned> template<typename CharType = unsigned>
struct UTF32BE : UTF32<CharType> { struct UTF32BE : UTF32<CharType>
{
template <typename InputByteStream> template <typename InputByteStream>
static CharType TakeBOM(InputByteStream& is) { static CharType TakeBOM(InputByteStream & is)
{
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
CharType c = Take(is); CharType c = Take(is);
return static_cast<uint32_t>(c) == 0x0000FEFFu ? Take(is) : c; return static_cast<uint32_t>(c) == 0x0000FEFFu ? Take(is) : c;
} }
template <typename InputByteStream> template <typename InputByteStream>
static CharType Take(InputByteStream& is) { static CharType Take(InputByteStream & is)
{
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
unsigned c = static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 24; unsigned c = static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 24;
c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 16; c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 16;
@ -512,7 +643,8 @@ struct UTF32BE : UTF32<CharType> {
} }
template <typename OutputByteStream> template <typename OutputByteStream>
static void PutBOM(OutputByteStream& os) { static void PutBOM(OutputByteStream & os)
{
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
os.Put(static_cast<typename OutputByteStream::Ch>(0x00u)); os.Put(static_cast<typename OutputByteStream::Ch>(0x00u));
os.Put(static_cast<typename OutputByteStream::Ch>(0x00u)); os.Put(static_cast<typename OutputByteStream::Ch>(0x00u));
@ -521,7 +653,8 @@ struct UTF32BE : UTF32<CharType> {
} }
template <typename OutputByteStream> template <typename OutputByteStream>
static void Put(OutputByteStream& os, CharType c) { static void Put(OutputByteStream & os, CharType c)
{
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
os.Put(static_cast<typename OutputByteStream::Ch>((c >> 24) & 0xFFu)); os.Put(static_cast<typename OutputByteStream::Ch>((c >> 24) & 0xFFu));
os.Put(static_cast<typename OutputByteStream::Ch>((c >> 16) & 0xFFu)); os.Put(static_cast<typename OutputByteStream::Ch>((c >> 16) & 0xFFu));
@ -539,58 +672,67 @@ struct UTF32BE : UTF32<CharType> {
\note implements Encoding concept \note implements Encoding concept
*/ */
template<typename CharType = char> template<typename CharType = char>
struct ASCII { struct ASCII
{
typedef CharType Ch; typedef CharType Ch;
enum { supportUnicode = 0 }; enum { supportUnicode = 0 };
template<typename OutputStream> template<typename OutputStream>
static void Encode(OutputStream& os, unsigned codepoint) { static void Encode(OutputStream & os, unsigned codepoint)
{
RAPIDJSON_ASSERT(codepoint <= 0x7F); RAPIDJSON_ASSERT(codepoint <= 0x7F);
os.Put(static_cast<Ch>(codepoint & 0xFF)); os.Put(static_cast<Ch>(codepoint & 0xFF));
} }
template<typename OutputStream> template<typename OutputStream>
static void EncodeUnsafe(OutputStream& os, unsigned codepoint) { static void EncodeUnsafe(OutputStream & os, unsigned codepoint)
{
RAPIDJSON_ASSERT(codepoint <= 0x7F); RAPIDJSON_ASSERT(codepoint <= 0x7F);
PutUnsafe(os, static_cast<Ch>(codepoint & 0xFF)); PutUnsafe(os, static_cast<Ch>(codepoint & 0xFF));
} }
template <typename InputStream> template <typename InputStream>
static bool Decode(InputStream& is, unsigned* codepoint) { static bool Decode(InputStream & is, unsigned* codepoint)
{
uint8_t c = static_cast<uint8_t>(is.Take()); uint8_t c = static_cast<uint8_t>(is.Take());
*codepoint = c; *codepoint = c;
return c <= 0X7F; return c <= 0X7F;
} }
template <typename InputStream, typename OutputStream> template <typename InputStream, typename OutputStream>
static bool Validate(InputStream& is, OutputStream& os) { static bool Validate(InputStream & is, OutputStream & os)
{
uint8_t c = static_cast<uint8_t>(is.Take()); uint8_t c = static_cast<uint8_t>(is.Take());
os.Put(static_cast<typename OutputStream::Ch>(c)); os.Put(static_cast<typename OutputStream::Ch>(c));
return c <= 0x7F; return c <= 0x7F;
} }
template <typename InputByteStream> template <typename InputByteStream>
static CharType TakeBOM(InputByteStream& is) { static CharType TakeBOM(InputByteStream & is)
{
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
uint8_t c = static_cast<uint8_t>(Take(is)); uint8_t c = static_cast<uint8_t>(Take(is));
return static_cast<Ch>(c); return static_cast<Ch>(c);
} }
template <typename InputByteStream> template <typename InputByteStream>
static Ch Take(InputByteStream& is) { static Ch Take(InputByteStream & is)
{
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
return static_cast<Ch>(is.Take()); return static_cast<Ch>(is.Take());
} }
template <typename OutputByteStream> template <typename OutputByteStream>
static void PutBOM(OutputByteStream& os) { static void PutBOM(OutputByteStream & os)
{
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
(void)os; (void)os;
} }
template <typename OutputByteStream> template <typename OutputByteStream>
static void Put(OutputByteStream& os, Ch c) { static void Put(OutputByteStream & os, Ch c)
{
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
os.Put(static_cast<typename OutputByteStream::Ch>(c)); os.Put(static_cast<typename OutputByteStream::Ch>(c));
} }
@ -600,7 +742,8 @@ struct ASCII {
// AutoUTF // AutoUTF
//! Runtime-specified UTF encoding type of a stream. //! Runtime-specified UTF encoding type of a stream.
enum UTFType { enum UTFType
{
kUTF8 = 0, //!< UTF-8. kUTF8 = 0, //!< UTF-8.
kUTF16LE = 1, //!< UTF-16 little endian. kUTF16LE = 1, //!< UTF-16 little endian.
kUTF16BE = 2, //!< UTF-16 big endian. kUTF16BE = 2, //!< UTF-16 big endian.
@ -612,7 +755,8 @@ enum UTFType {
/*! \note This class can be used with AutoUTFInputtStream and AutoUTFOutputStream, which provides GetType(). /*! \note This class can be used with AutoUTFInputtStream and AutoUTFOutputStream, which provides GetType().
*/ */
template<typename CharType> template<typename CharType>
struct AutoUTF { struct AutoUTF
{
typedef CharType Ch; typedef CharType Ch;
enum { supportUnicode = 1 }; enum { supportUnicode = 1 };
@ -620,28 +764,32 @@ struct AutoUTF {
#define RAPIDJSON_ENCODINGS_FUNC(x) UTF8<Ch>::x, UTF16LE<Ch>::x, UTF16BE<Ch>::x, UTF32LE<Ch>::x, UTF32BE<Ch>::x #define RAPIDJSON_ENCODINGS_FUNC(x) UTF8<Ch>::x, UTF16LE<Ch>::x, UTF16BE<Ch>::x, UTF32LE<Ch>::x, UTF32BE<Ch>::x
template<typename OutputStream> template<typename OutputStream>
RAPIDJSON_FORCEINLINE static void Encode(OutputStream& os, unsigned codepoint) { RAPIDJSON_FORCEINLINE static void Encode(OutputStream & os, unsigned codepoint)
{
typedef void (*EncodeFunc)(OutputStream &, unsigned); typedef void (*EncodeFunc)(OutputStream &, unsigned);
static const EncodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Encode) }; static const EncodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Encode) };
(*f[os.GetType()])(os, codepoint); (*f[os.GetType()])(os, codepoint);
} }
template<typename OutputStream> template<typename OutputStream>
RAPIDJSON_FORCEINLINE static void EncodeUnsafe(OutputStream& os, unsigned codepoint) { RAPIDJSON_FORCEINLINE static void EncodeUnsafe(OutputStream & os, unsigned codepoint)
{
typedef void (*EncodeFunc)(OutputStream &, unsigned); typedef void (*EncodeFunc)(OutputStream &, unsigned);
static const EncodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(EncodeUnsafe) }; static const EncodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(EncodeUnsafe) };
(*f[os.GetType()])(os, codepoint); (*f[os.GetType()])(os, codepoint);
} }
template <typename InputStream> template <typename InputStream>
RAPIDJSON_FORCEINLINE static bool Decode(InputStream& is, unsigned* codepoint) { RAPIDJSON_FORCEINLINE static bool Decode(InputStream & is, unsigned* codepoint)
{
typedef bool (*DecodeFunc)(InputStream &, unsigned*); typedef bool (*DecodeFunc)(InputStream &, unsigned*);
static const DecodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Decode) }; static const DecodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Decode) };
return (*f[is.GetType()])(is, codepoint); return (*f[is.GetType()])(is, codepoint);
} }
template <typename InputStream, typename OutputStream> template <typename InputStream, typename OutputStream>
RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) { RAPIDJSON_FORCEINLINE static bool Validate(InputStream & is, OutputStream & os)
{
typedef bool (*ValidateFunc)(InputStream &, OutputStream &); typedef bool (*ValidateFunc)(InputStream &, OutputStream &);
static const ValidateFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Validate) }; static const ValidateFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Validate) };
return (*f[is.GetType()])(is, os); return (*f[is.GetType()])(is, os);
@ -655,29 +803,37 @@ struct AutoUTF {
//! Encoding conversion. //! Encoding conversion.
template<typename SourceEncoding, typename TargetEncoding> template<typename SourceEncoding, typename TargetEncoding>
struct Transcoder { struct Transcoder
{
//! Take one Unicode codepoint from source encoding, convert it to target encoding and put it to the output stream. //! Take one Unicode codepoint from source encoding, convert it to target encoding and put it to the output stream.
template<typename InputStream, typename OutputStream> template<typename InputStream, typename OutputStream>
RAPIDJSON_FORCEINLINE static bool Transcode(InputStream& is, OutputStream& os) { RAPIDJSON_FORCEINLINE static bool Transcode(InputStream & is, OutputStream & os)
{
unsigned codepoint; unsigned codepoint;
if(!SourceEncoding::Decode(is, &codepoint)) if(!SourceEncoding::Decode(is, &codepoint))
{
return false; return false;
}
TargetEncoding::Encode(os, codepoint); TargetEncoding::Encode(os, codepoint);
return true; return true;
} }
template<typename InputStream, typename OutputStream> template<typename InputStream, typename OutputStream>
RAPIDJSON_FORCEINLINE static bool TranscodeUnsafe(InputStream& is, OutputStream& os) { RAPIDJSON_FORCEINLINE static bool TranscodeUnsafe(InputStream & is, OutputStream & os)
{
unsigned codepoint; unsigned codepoint;
if(!SourceEncoding::Decode(is, &codepoint)) if(!SourceEncoding::Decode(is, &codepoint))
{
return false; return false;
}
TargetEncoding::EncodeUnsafe(os, codepoint); TargetEncoding::EncodeUnsafe(os, codepoint);
return true; return true;
} }
//! Validate one Unicode codepoint from an encoded stream. //! Validate one Unicode codepoint from an encoded stream.
template<typename InputStream, typename OutputStream> template<typename InputStream, typename OutputStream>
RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) { RAPIDJSON_FORCEINLINE static bool Validate(InputStream & is, OutputStream & os)
{
return Transcode(is, os); // Since source/target encoding is different, must transcode. return Transcode(is, os); // Since source/target encoding is different, must transcode.
} }
}; };
@ -688,21 +844,25 @@ inline void PutUnsafe(Stream& stream, typename Stream::Ch c);
//! Specialization of Transcoder with same source and target encoding. //! Specialization of Transcoder with same source and target encoding.
template<typename Encoding> template<typename Encoding>
struct Transcoder<Encoding, Encoding> { struct Transcoder<Encoding, Encoding>
{
template<typename InputStream, typename OutputStream> template<typename InputStream, typename OutputStream>
RAPIDJSON_FORCEINLINE static bool Transcode(InputStream& is, OutputStream& os) { RAPIDJSON_FORCEINLINE static bool Transcode(InputStream & is, OutputStream & os)
{
os.Put(is.Take()); // Just copy one code unit. This semantic is different from primary template class. os.Put(is.Take()); // Just copy one code unit. This semantic is different from primary template class.
return true; return true;
} }
template<typename InputStream, typename OutputStream> template<typename InputStream, typename OutputStream>
RAPIDJSON_FORCEINLINE static bool TranscodeUnsafe(InputStream& is, OutputStream& os) { RAPIDJSON_FORCEINLINE static bool TranscodeUnsafe(InputStream & is, OutputStream & os)
{
PutUnsafe(os, is.Take()); // Just copy one code unit. This semantic is different from primary template class. PutUnsafe(os, is.Take()); // Just copy one code unit. This semantic is different from primary template class.
return true; return true;
} }
template<typename InputStream, typename OutputStream> template<typename InputStream, typename OutputStream>
RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) { RAPIDJSON_FORCEINLINE static bool Validate(InputStream & is, OutputStream & os)
{
return Encoding::Validate(is, os); // source/target encoding are the same return Encoding::Validate(is, os); // source/target encoding are the same
} }
}; };

View file

@ -33,35 +33,56 @@ RAPIDJSON_NAMESPACE_BEGIN
\note User can make a copy of this function for localization. \note User can make a copy of this function for localization.
Using switch-case is safer for future modification of error codes. Using switch-case is safer for future modification of error codes.
*/ */
inline const RAPIDJSON_ERROR_CHARTYPE* GetParseError_En(ParseErrorCode parseErrorCode) { inline const RAPIDJSON_ERROR_CHARTYPE* GetParseError_En(ParseErrorCode parseErrorCode)
switch (parseErrorCode) { {
case kParseErrorNone: return RAPIDJSON_ERROR_STRING("No error."); switch(parseErrorCode)
{
case kParseErrorNone:
return RAPIDJSON_ERROR_STRING("No error.");
case kParseErrorDocumentEmpty: return RAPIDJSON_ERROR_STRING("The document is empty."); case kParseErrorDocumentEmpty:
case kParseErrorDocumentRootNotSingular: return RAPIDJSON_ERROR_STRING("The document root must not be followed by other values."); return RAPIDJSON_ERROR_STRING("The document is empty.");
case kParseErrorDocumentRootNotSingular:
return RAPIDJSON_ERROR_STRING("The document root must not be followed by other values.");
case kParseErrorValueInvalid: return RAPIDJSON_ERROR_STRING("Invalid value."); case kParseErrorValueInvalid:
return RAPIDJSON_ERROR_STRING("Invalid value.");
case kParseErrorObjectMissName: return RAPIDJSON_ERROR_STRING("Missing a name for object member."); case kParseErrorObjectMissName:
case kParseErrorObjectMissColon: return RAPIDJSON_ERROR_STRING("Missing a colon after a name of object member."); return RAPIDJSON_ERROR_STRING("Missing a name for object member.");
case kParseErrorObjectMissCommaOrCurlyBracket: return RAPIDJSON_ERROR_STRING("Missing a comma or '}' after an object member."); case kParseErrorObjectMissColon:
return RAPIDJSON_ERROR_STRING("Missing a colon after a name of object member.");
case kParseErrorObjectMissCommaOrCurlyBracket:
return RAPIDJSON_ERROR_STRING("Missing a comma or '}' after an object member.");
case kParseErrorArrayMissCommaOrSquareBracket: return RAPIDJSON_ERROR_STRING("Missing a comma or ']' after an array element."); case kParseErrorArrayMissCommaOrSquareBracket:
return RAPIDJSON_ERROR_STRING("Missing a comma or ']' after an array element.");
case kParseErrorStringUnicodeEscapeInvalidHex: return RAPIDJSON_ERROR_STRING("Incorrect hex digit after \\u escape in string."); case kParseErrorStringUnicodeEscapeInvalidHex:
case kParseErrorStringUnicodeSurrogateInvalid: return RAPIDJSON_ERROR_STRING("The surrogate pair in string is invalid."); return RAPIDJSON_ERROR_STRING("Incorrect hex digit after \\u escape in string.");
case kParseErrorStringEscapeInvalid: return RAPIDJSON_ERROR_STRING("Invalid escape character in string."); case kParseErrorStringUnicodeSurrogateInvalid:
case kParseErrorStringMissQuotationMark: return RAPIDJSON_ERROR_STRING("Missing a closing quotation mark in string."); return RAPIDJSON_ERROR_STRING("The surrogate pair in string is invalid.");
case kParseErrorStringInvalidEncoding: return RAPIDJSON_ERROR_STRING("Invalid encoding in string."); case kParseErrorStringEscapeInvalid:
return RAPIDJSON_ERROR_STRING("Invalid escape character in string.");
case kParseErrorStringMissQuotationMark:
return RAPIDJSON_ERROR_STRING("Missing a closing quotation mark in string.");
case kParseErrorStringInvalidEncoding:
return RAPIDJSON_ERROR_STRING("Invalid encoding in string.");
case kParseErrorNumberTooBig: return RAPIDJSON_ERROR_STRING("Number too big to be stored in double."); case kParseErrorNumberTooBig:
case kParseErrorNumberMissFraction: return RAPIDJSON_ERROR_STRING("Miss fraction part in number."); return RAPIDJSON_ERROR_STRING("Number too big to be stored in double.");
case kParseErrorNumberMissExponent: return RAPIDJSON_ERROR_STRING("Miss exponent in number."); case kParseErrorNumberMissFraction:
return RAPIDJSON_ERROR_STRING("Miss fraction part in number.");
case kParseErrorNumberMissExponent:
return RAPIDJSON_ERROR_STRING("Miss exponent in number.");
case kParseErrorTermination: return RAPIDJSON_ERROR_STRING("Terminate parsing due to Handler error."); case kParseErrorTermination:
case kParseErrorUnspecificSyntaxError: return RAPIDJSON_ERROR_STRING("Unspecific syntax error."); return RAPIDJSON_ERROR_STRING("Terminate parsing due to Handler error.");
case kParseErrorUnspecificSyntaxError:
return RAPIDJSON_ERROR_STRING("Unspecific syntax error.");
default: return RAPIDJSON_ERROR_STRING("Unknown error."); default:
return RAPIDJSON_ERROR_STRING("Unknown error.");
} }
} }

View file

@ -61,7 +61,8 @@ RAPIDJSON_NAMESPACE_BEGIN
/*! \ingroup RAPIDJSON_ERRORS /*! \ingroup RAPIDJSON_ERRORS
\see GenericReader::Parse, GenericReader::GetParseErrorCode \see GenericReader::Parse, GenericReader::GetParseErrorCode
*/ */
enum ParseErrorCode { enum ParseErrorCode
{
kParseErrorNone = 0, //!< No error. kParseErrorNone = 0, //!< No error.
kParseErrorDocumentEmpty, //!< The document is empty. kParseErrorDocumentEmpty, //!< The document is empty.
@ -103,7 +104,8 @@ enum ParseErrorCode {
\endcode \endcode
\see GenericReader::Parse, GenericDocument::Parse \see GenericReader::Parse, GenericDocument::Parse
*/ */
struct ParseResult { struct ParseResult
{
public: public:
//! Default constructor, no error. //! Default constructor, no error.
ParseResult() : code_(kParseErrorNone), offset_(0) {} ParseResult() : code_(kParseErrorNone), offset_(0) {}
@ -111,23 +113,51 @@ public:
ParseResult(ParseErrorCode code, size_t offset) : code_(code), offset_(offset) {} ParseResult(ParseErrorCode code, size_t offset) : code_(code), offset_(offset) {}
//! Get the error code. //! Get the error code.
ParseErrorCode Code() const { return code_; } ParseErrorCode Code() const
{
return code_;
}
//! Get the error offset, if \ref IsError(), 0 otherwise. //! Get the error offset, if \ref IsError(), 0 otherwise.
size_t Offset() const { return offset_; } size_t Offset() const
{
return offset_;
}
//! Conversion to \c bool, returns \c true, iff !\ref IsError(). //! Conversion to \c bool, returns \c true, iff !\ref IsError().
operator bool() const { return !IsError(); } operator bool() const
{
return !IsError();
}
//! Whether the result is an error. //! Whether the result is an error.
bool IsError() const { return code_ != kParseErrorNone; } bool IsError() const
{
return code_ != kParseErrorNone;
}
bool operator==(const ParseResult& that) const { return code_ == that.code_; } bool operator==(const ParseResult & that) const
bool operator==(ParseErrorCode code) const { return code_ == code; } {
friend bool operator==(ParseErrorCode code, const ParseResult & err) { return code == err.code_; } return code_ == that.code_;
}
bool operator==(ParseErrorCode code) const
{
return code_ == code;
}
friend bool operator==(ParseErrorCode code, const ParseResult & err)
{
return code == err.code_;
}
//! Reset error code. //! Reset error code.
void Clear() { Set(kParseErrorNone); } void Clear()
{
Set(kParseErrorNone);
}
//! Update error code and offset. //! Update error code and offset.
void Set(ParseErrorCode code, size_t offset = 0) { code_ = code; offset_ = offset; } void Set(ParseErrorCode code, size_t offset = 0)
{
code_ = code;
offset_ = offset;
}
private: private:
ParseErrorCode code_; ParseErrorCode code_;

View file

@ -31,7 +31,8 @@ RAPIDJSON_NAMESPACE_BEGIN
/*! /*!
\note implements Stream concept \note implements Stream concept
*/ */
class FileReadStream { class FileReadStream
{
public: public:
typedef char Ch; //!< Character type (byte). typedef char Ch; //!< Character type (byte).
@ -41,38 +42,71 @@ public:
\param buffer user-supplied buffer. \param buffer user-supplied buffer.
\param bufferSize size of buffer in bytes. Must >=4 bytes. \param bufferSize size of buffer in bytes. Must >=4 bytes.
*/ */
FileReadStream(std::FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferSize_(bufferSize), bufferLast_(0), current_(buffer_), readCount_(0), count_(0), eof_(false) { FileReadStream(std::FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer),
bufferSize_(bufferSize), bufferLast_(0), current_(buffer_), readCount_(0), count_(0), eof_(false)
{
RAPIDJSON_ASSERT(fp_ != 0); RAPIDJSON_ASSERT(fp_ != 0);
RAPIDJSON_ASSERT(bufferSize >= 4); RAPIDJSON_ASSERT(bufferSize >= 4);
Read(); Read();
} }
Ch Peek() const { return *current_; } Ch Peek() const
Ch Take() { Ch c = *current_; Read(); return c; } {
size_t Tell() const { return count_ + static_cast<size_t>(current_ - buffer_); } return *current_;
}
Ch Take()
{
Ch c = *current_;
Read();
return c;
}
size_t Tell() const
{
return count_ + static_cast<size_t>(current_ - buffer_);
}
// Not implemented // Not implemented
void Put(Ch) { RAPIDJSON_ASSERT(false); } void Put(Ch)
void Flush() { RAPIDJSON_ASSERT(false); } {
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } RAPIDJSON_ASSERT(false);
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } }
void Flush()
{
RAPIDJSON_ASSERT(false);
}
Ch* PutBegin()
{
RAPIDJSON_ASSERT(false);
return 0;
}
size_t PutEnd(Ch*)
{
RAPIDJSON_ASSERT(false);
return 0;
}
// For encoding detection only. // For encoding detection only.
const Ch* Peek4() const { const Ch* Peek4() const
{
return (current_ + 4 <= bufferLast_) ? current_ : 0; return (current_ + 4 <= bufferLast_) ? current_ : 0;
} }
private: private:
void Read() { void Read()
{
if(current_ < bufferLast_) if(current_ < bufferLast_)
{
++current_; ++current_;
else if (!eof_) { }
else if(!eof_)
{
count_ += readCount_; count_ += readCount_;
readCount_ = fread(buffer_, 1, bufferSize_, fp_); readCount_ = fread(buffer_, 1, bufferSize_, fp_);
bufferLast_ = buffer_ + readCount_ - 1; bufferLast_ = buffer_ + readCount_ - 1;
current_ = buffer_; current_ = buffer_;
if (readCount_ < bufferSize_) { if(readCount_ < bufferSize_)
{
buffer_[readCount_] = '\0'; buffer_[readCount_] = '\0';
++bufferLast_; ++bufferLast_;
eof_ = true; eof_ = true;

View file

@ -29,24 +29,32 @@ RAPIDJSON_NAMESPACE_BEGIN
/*! /*!
\note implements Stream concept \note implements Stream concept
*/ */
class FileWriteStream { class FileWriteStream
{
public: public:
typedef char Ch; //!< Character type. Only support char. typedef char Ch; //!< Character type. Only support char.
FileWriteStream(std::FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferEnd_(buffer + bufferSize), current_(buffer_) { FileWriteStream(std::FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer),
bufferEnd_(buffer + bufferSize), current_(buffer_)
{
RAPIDJSON_ASSERT(fp_ != 0); RAPIDJSON_ASSERT(fp_ != 0);
} }
void Put(char c) { void Put(char c)
{
if(current_ >= bufferEnd_) if(current_ >= bufferEnd_)
{
Flush(); Flush();
}
*current_++ = c; *current_++ = c;
} }
void PutN(char c, size_t n) { void PutN(char c, size_t n)
{
size_t avail = static_cast<size_t>(bufferEnd_ - current_); size_t avail = static_cast<size_t>(bufferEnd_ - current_);
while (n > avail) { while(n > avail)
{
std::memset(current_, c, avail); std::memset(current_, c, avail);
current_ += avail; current_ += avail;
Flush(); Flush();
@ -54,16 +62,20 @@ public:
avail = static_cast<size_t>(bufferEnd_ - current_); avail = static_cast<size_t>(bufferEnd_ - current_);
} }
if (n > 0) { if(n > 0)
{
std::memset(current_, c, n); std::memset(current_, c, n);
current_ += n; current_ += n;
} }
} }
void Flush() { void Flush()
if (current_ != buffer_) { {
if(current_ != buffer_)
{
size_t result = fwrite(buffer_, 1, static_cast<size_t>(current_ - buffer_), fp_); size_t result = fwrite(buffer_, 1, static_cast<size_t>(current_ - buffer_), fp_);
if (result < static_cast<size_t>(current_ - buffer_)) { if(result < static_cast<size_t>(current_ - buffer_))
{
// failure deliberately ignored at this time // failure deliberately ignored at this time
// added to avoid warn_unused_result build errors // added to avoid warn_unused_result build errors
} }
@ -72,11 +84,31 @@ public:
} }
// Not implemented // Not implemented
char Peek() const { RAPIDJSON_ASSERT(false); return 0; } char Peek() const
char Take() { RAPIDJSON_ASSERT(false); return 0; } {
size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; } RAPIDJSON_ASSERT(false);
char* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } return 0;
size_t PutEnd(char*) { RAPIDJSON_ASSERT(false); return 0; } }
char Take()
{
RAPIDJSON_ASSERT(false);
return 0;
}
size_t Tell() const
{
RAPIDJSON_ASSERT(false);
return 0;
}
char* PutBegin()
{
RAPIDJSON_ASSERT(false);
return 0;
}
size_t PutEnd(char*)
{
RAPIDJSON_ASSERT(false);
return 0;
}
private: private:
// Prohibit copy constructor & assignment operator. // Prohibit copy constructor & assignment operator.
@ -91,7 +123,8 @@ private:
//! Implement specialized version of PutN() with memset() for better performance. //! Implement specialized version of PutN() with memset() for better performance.
template<> template<>
inline void PutN(FileWriteStream& stream, char c, size_t n) { inline void PutN(FileWriteStream & stream, char c, size_t n)
{
stream.PutN(c, n); stream.PutN(c, n);
} }

View file

@ -144,7 +144,8 @@ template <
typename StateAllocator > typename StateAllocator >
class GenericSchemaValidator; class GenericSchemaValidator;
typedef GenericSchemaValidator<SchemaDocument, BaseReaderHandler<UTF8<char>, void>, CrtAllocator> SchemaValidator; typedef GenericSchemaValidator<SchemaDocument, BaseReaderHandler<UTF8<char>, void>, CrtAllocator>
SchemaValidator;
RAPIDJSON_NAMESPACE_END RAPIDJSON_NAMESPACE_END

View file

@ -23,92 +23,132 @@
#endif #endif
RAPIDJSON_NAMESPACE_BEGIN RAPIDJSON_NAMESPACE_BEGIN
namespace internal { namespace internal
{
class BigInteger { class BigInteger
{
public: public:
typedef uint64_t Type; typedef uint64_t Type;
BigInteger(const BigInteger& rhs) : count_(rhs.count_) { BigInteger(const BigInteger & rhs) : count_(rhs.count_)
{
std::memcpy(digits_, rhs.digits_, count_ * sizeof(Type)); std::memcpy(digits_, rhs.digits_, count_ * sizeof(Type));
} }
explicit BigInteger(uint64_t u) : count_(1) { explicit BigInteger(uint64_t u) : count_(1)
{
digits_[0] = u; digits_[0] = u;
} }
BigInteger(const char* decimals, size_t length) : count_(1) { BigInteger(const char* decimals, size_t length) : count_(1)
{
RAPIDJSON_ASSERT(length > 0); RAPIDJSON_ASSERT(length > 0);
digits_[0] = 0; digits_[0] = 0;
size_t i = 0; size_t i = 0;
const size_t kMaxDigitPerIteration = 19; // 2^64 = 18446744073709551616 > 10^19 const size_t kMaxDigitPerIteration = 19; // 2^64 = 18446744073709551616 > 10^19
while (length >= kMaxDigitPerIteration) { while(length >= kMaxDigitPerIteration)
{
AppendDecimal64(decimals + i, decimals + i + kMaxDigitPerIteration); AppendDecimal64(decimals + i, decimals + i + kMaxDigitPerIteration);
length -= kMaxDigitPerIteration; length -= kMaxDigitPerIteration;
i += kMaxDigitPerIteration; i += kMaxDigitPerIteration;
} }
if(length > 0) if(length > 0)
{
AppendDecimal64(decimals + i, decimals + i + length); AppendDecimal64(decimals + i, decimals + i + length);
} }
}
BigInteger & operator=(const BigInteger & rhs) BigInteger & operator=(const BigInteger & rhs)
{ {
if (this != &rhs) { if(this != &rhs)
{
count_ = rhs.count_; count_ = rhs.count_;
std::memcpy(digits_, rhs.digits_, count_ * sizeof(Type)); std::memcpy(digits_, rhs.digits_, count_ * sizeof(Type));
} }
return *this; return *this;
} }
BigInteger& operator=(uint64_t u) { BigInteger & operator=(uint64_t u)
{
digits_[0] = u; digits_[0] = u;
count_ = 1; count_ = 1;
return *this; return *this;
} }
BigInteger& operator+=(uint64_t u) { BigInteger & operator+=(uint64_t u)
{
Type backup = digits_[0]; Type backup = digits_[0];
digits_[0] += u; digits_[0] += u;
for (size_t i = 0; i < count_ - 1; i++) { for(size_t i = 0; i < count_ - 1; i++)
{
if(digits_[i] >= backup) if(digits_[i] >= backup)
{
return *this; // no carry return *this; // no carry
}
backup = digits_[i + 1]; backup = digits_[i + 1];
digits_[i + 1] += 1; digits_[i + 1] += 1;
} }
// Last carry // Last carry
if(digits_[count_ - 1] < backup) if(digits_[count_ - 1] < backup)
{
PushBack(1); PushBack(1);
}
return *this; return *this;
} }
BigInteger& operator*=(uint64_t u) { BigInteger & operator*=(uint64_t u)
if (u == 0) return *this = 0; {
if (u == 1) return *this; if(u == 0)
if (*this == 1) return *this = u; {
return *this = 0;
}
if(u == 1)
{
return *this;
}
if(*this == 1)
{
return *this = u;
}
uint64_t k = 0; uint64_t k = 0;
for (size_t i = 0; i < count_; i++) { for(size_t i = 0; i < count_; i++)
{
uint64_t hi; uint64_t hi;
digits_[i] = MulAdd64(digits_[i], u, k, &hi); digits_[i] = MulAdd64(digits_[i], u, k, &hi);
k = hi; k = hi;
} }
if(k > 0) if(k > 0)
{
PushBack(k); PushBack(k);
}
return *this; return *this;
} }
BigInteger& operator*=(uint32_t u) { BigInteger & operator*=(uint32_t u)
if (u == 0) return *this = 0; {
if (u == 1) return *this; if(u == 0)
if (*this == 1) return *this = u; {
return *this = 0;
}
if(u == 1)
{
return *this;
}
if(*this == 1)
{
return *this = u;
}
uint64_t k = 0; uint64_t k = 0;
for (size_t i = 0; i < count_; i++) { for(size_t i = 0; i < count_; i++)
{
const uint64_t c = digits_[i] >> 32; const uint64_t c = digits_[i] >> 32;
const uint64_t d = digits_[i] & 0xFFFFFFFF; const uint64_t d = digits_[i] & 0xFFFFFFFF;
const uint64_t uc = u * c; const uint64_t uc = u * c;
@ -120,47 +160,63 @@ public:
} }
if(k > 0) if(k > 0)
{
PushBack(k); PushBack(k);
}
return *this; return *this;
} }
BigInteger& operator<<=(size_t shift) { BigInteger & operator<<=(size_t shift)
if (IsZero() || shift == 0) return *this; {
if(IsZero() || shift == 0)
{
return *this;
}
size_t offset = shift / kTypeBit; size_t offset = shift / kTypeBit;
size_t interShift = shift % kTypeBit; size_t interShift = shift % kTypeBit;
RAPIDJSON_ASSERT(count_ + offset <= kCapacity); RAPIDJSON_ASSERT(count_ + offset <= kCapacity);
if (interShift == 0) { if(interShift == 0)
{
std::memmove(&digits_[count_ - 1 + offset], &digits_[count_ - 1], count_ * sizeof(Type)); std::memmove(&digits_[count_ - 1 + offset], &digits_[count_ - 1], count_ * sizeof(Type));
count_ += offset; count_ += offset;
} }
else { else
{
digits_[count_] = 0; digits_[count_] = 0;
for(size_t i = count_; i > 0; i--) for(size_t i = count_; i > 0; i--)
{
digits_[i + offset] = (digits_[i] << interShift) | (digits_[i - 1] >> (kTypeBit - interShift)); digits_[i + offset] = (digits_[i] << interShift) | (digits_[i - 1] >> (kTypeBit - interShift));
}
digits_[offset] = digits_[0] << interShift; digits_[offset] = digits_[0] << interShift;
count_ += offset; count_ += offset;
if(digits_[count_]) if(digits_[count_])
{
count_++; count_++;
} }
}
std::memset(digits_, 0, offset * sizeof(Type)); std::memset(digits_, 0, offset * sizeof(Type));
return *this; return *this;
} }
bool operator==(const BigInteger& rhs) const { bool operator==(const BigInteger & rhs) const
{
return count_ == rhs.count_ && std::memcmp(digits_, rhs.digits_, count_ * sizeof(Type)) == 0; return count_ == rhs.count_ && std::memcmp(digits_, rhs.digits_, count_ * sizeof(Type)) == 0;
} }
bool operator==(const Type rhs) const { bool operator==(const Type rhs) const
{
return count_ == 1 && digits_[0] == rhs; return count_ == 1 && digits_[0] == rhs;
} }
BigInteger& MultiplyPow5(unsigned exp) { BigInteger & MultiplyPow5(unsigned exp)
static const uint32_t kPow5[12] = { {
static const uint32_t kPow5[12] =
{
5, 5,
5 * 5, 5 * 5,
5 * 5 * 5, 5 * 5 * 5,
@ -174,71 +230,121 @@ public:
5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5
}; };
if (exp == 0) return *this; if(exp == 0)
for (; exp >= 27; exp -= 27) *this *= RAPIDJSON_UINT64_C2(0X6765C793, 0XFA10079D); // 5^27 {
for (; exp >= 13; exp -= 13) *this *= static_cast<uint32_t>(1220703125u); // 5^13 return *this;
if (exp > 0) *this *= kPow5[exp - 1]; }
for(; exp >= 27; exp -= 27)
{
*this *= RAPIDJSON_UINT64_C2(0X6765C793, 0XFA10079D); // 5^27
}
for(; exp >= 13; exp -= 13)
{
*this *= static_cast<uint32_t>(1220703125u); // 5^13
}
if(exp > 0)
{
*this *= kPow5[exp - 1];
}
return *this; return *this;
} }
// Compute absolute difference of this and rhs. // Compute absolute difference of this and rhs.
// Assume this != rhs // Assume this != rhs
bool Difference(const BigInteger& rhs, BigInteger* out) const { bool Difference(const BigInteger & rhs, BigInteger* out) const
{
int cmp = Compare(rhs); int cmp = Compare(rhs);
RAPIDJSON_ASSERT(cmp != 0); RAPIDJSON_ASSERT(cmp != 0);
const BigInteger* a, *b; // Makes a > b const BigInteger* a, *b; // Makes a > b
bool ret; bool ret;
if (cmp < 0) { a = &rhs; b = this; ret = true; } if(cmp < 0)
else { a = this; b = &rhs; ret = false; } {
a = &rhs;
b = this;
ret = true;
}
else
{
a = this;
b = &rhs;
ret = false;
}
Type borrow = 0; Type borrow = 0;
for (size_t i = 0; i < a->count_; i++) { for(size_t i = 0; i < a->count_; i++)
{
Type d = a->digits_[i] - borrow; Type d = a->digits_[i] - borrow;
if(i < b->count_) if(i < b->count_)
{
d -= b->digits_[i]; d -= b->digits_[i];
}
borrow = (d > a->digits_[i]) ? 1 : 0; borrow = (d > a->digits_[i]) ? 1 : 0;
out->digits_[i] = d; out->digits_[i] = d;
if(d != 0) if(d != 0)
{
out->count_ = i + 1; out->count_ = i + 1;
} }
}
return ret; return ret;
} }
int Compare(const BigInteger& rhs) const { int Compare(const BigInteger & rhs) const
{
if(count_ != rhs.count_) if(count_ != rhs.count_)
{
return count_ < rhs.count_ ? -1 : 1; return count_ < rhs.count_ ? -1 : 1;
}
for(size_t i = count_; i-- > 0;) for(size_t i = count_; i-- > 0;)
if(digits_[i] != rhs.digits_[i]) if(digits_[i] != rhs.digits_[i])
{
return digits_[i] < rhs.digits_[i] ? -1 : 1; return digits_[i] < rhs.digits_[i] ? -1 : 1;
}
return 0; return 0;
} }
size_t GetCount() const { return count_; } size_t GetCount() const
Type GetDigit(size_t index) const { RAPIDJSON_ASSERT(index < count_); return digits_[index]; } {
bool IsZero() const { return count_ == 1 && digits_[0] == 0; } return count_;
}
Type GetDigit(size_t index) const
{
RAPIDJSON_ASSERT(index < count_);
return digits_[index];
}
bool IsZero() const
{
return count_ == 1 && digits_[0] == 0;
}
private: private:
void AppendDecimal64(const char* begin, const char* end) { void AppendDecimal64(const char* begin, const char* end)
{
uint64_t u = ParseUint64(begin, end); uint64_t u = ParseUint64(begin, end);
if(IsZero()) if(IsZero())
{
*this = u; *this = u;
else { }
else
{
unsigned exp = static_cast<unsigned>(end - begin); unsigned exp = static_cast<unsigned>(end - begin);
(MultiplyPow5(exp) <<= exp) += u; // *this = *this * 10^exp + u (MultiplyPow5(exp) <<= exp) += u; // *this = *this * 10^exp + u
} }
} }
void PushBack(Type digit) { void PushBack(Type digit)
{
RAPIDJSON_ASSERT(count_ < kCapacity); RAPIDJSON_ASSERT(count_ < kCapacity);
digits_[count_++] = digit; digits_[count_++] = digit;
} }
static uint64_t ParseUint64(const char* begin, const char* end) { static uint64_t ParseUint64(const char* begin, const char* end)
{
uint64_t r = 0; uint64_t r = 0;
for (const char* p = begin; p != end; ++p) { for(const char* p = begin; p != end; ++p)
{
RAPIDJSON_ASSERT(*p >= '0' && *p <= '9'); RAPIDJSON_ASSERT(*p >= '0' && *p <= '9');
r = r * 10u + static_cast<unsigned>(*p - '0'); r = r * 10u + static_cast<unsigned>(*p - '0');
} }
@ -246,11 +352,14 @@ private:
} }
// Assume a * b + k < 2^128 // Assume a * b + k < 2^128
static uint64_t MulAdd64(uint64_t a, uint64_t b, uint64_t k, uint64_t* outHigh) { static uint64_t MulAdd64(uint64_t a, uint64_t b, uint64_t k, uint64_t* outHigh)
{
#if defined(_MSC_VER) && defined(_M_AMD64) #if defined(_MSC_VER) && defined(_M_AMD64)
uint64_t low = _umul128(a, b, outHigh) + k; uint64_t low = _umul128(a, b, outHigh) + k;
if(low < k) if(low < k)
{
(*outHigh)++; (*outHigh)++;
}
return low; return low;
#elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && defined(__x86_64__) #elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && defined(__x86_64__)
__extension__ typedef unsigned __int128 uint128; __extension__ typedef unsigned __int128 uint128;
@ -264,13 +373,17 @@ private:
x1 += (x0 >> 32); // can't give carry x1 += (x0 >> 32); // can't give carry
x1 += x2; x1 += x2;
if(x1 < x2) if(x1 < x2)
{
x3 += (static_cast<uint64_t>(1) << 32); x3 += (static_cast<uint64_t>(1) << 32);
}
uint64_t lo = (x1 << 32) + (x0 & 0xFFFFFFFF); uint64_t lo = (x1 << 32) + (x0 & 0xFFFFFFFF);
uint64_t hi = x3 + (x1 >> 32); uint64_t hi = x3 + (x1 >> 32);
lo += k; lo += k;
if(lo < k) if(lo < k)
{
hi++; hi++;
}
*outHigh = hi; *outHigh = hi;
return lo; return lo;
#endif #endif

View file

@ -28,7 +28,8 @@
#endif #endif
RAPIDJSON_NAMESPACE_BEGIN RAPIDJSON_NAMESPACE_BEGIN
namespace internal { namespace internal
{
#ifdef __GNUC__ #ifdef __GNUC__
RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PUSH
@ -40,39 +41,48 @@ RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(padded) RAPIDJSON_DIAG_OFF(padded)
#endif #endif
struct DiyFp { struct DiyFp
{
DiyFp() : f(), e() {} DiyFp() : f(), e() {}
DiyFp(uint64_t fp, int exp) : f(fp), e(exp) {} DiyFp(uint64_t fp, int exp) : f(fp), e(exp) {}
explicit DiyFp(double d) { explicit DiyFp(double d)
union { {
union
{
double d; double d;
uint64_t u64; uint64_t u64;
} u = { d }; } u = { d };
int biased_e = static_cast<int>((u.u64 & kDpExponentMask) >> kDpSignificandSize); int biased_e = static_cast<int>((u.u64 & kDpExponentMask) >> kDpSignificandSize);
uint64_t significand = (u.u64 & kDpSignificandMask); uint64_t significand = (u.u64 & kDpSignificandMask);
if (biased_e != 0) { if(biased_e != 0)
{
f = significand + kDpHiddenBit; f = significand + kDpHiddenBit;
e = biased_e - kDpExponentBias; e = biased_e - kDpExponentBias;
} }
else { else
{
f = significand; f = significand;
e = kDpMinExponent + 1; e = kDpMinExponent + 1;
} }
} }
DiyFp operator-(const DiyFp& rhs) const { DiyFp operator-(const DiyFp & rhs) const
{
return DiyFp(f - rhs.f, e); return DiyFp(f - rhs.f, e);
} }
DiyFp operator*(const DiyFp& rhs) const { DiyFp operator*(const DiyFp & rhs) const
{
#if defined(_MSC_VER) && defined(_M_AMD64) #if defined(_MSC_VER) && defined(_M_AMD64)
uint64_t h; uint64_t h;
uint64_t l = _umul128(f, rhs.f, &h); uint64_t l = _umul128(f, rhs.f, &h);
if(l & (uint64_t(1) << 63)) // rounding if(l & (uint64_t(1) << 63)) // rounding
{
h++; h++;
}
return DiyFp(h, e + rhs.e + 64); return DiyFp(h, e + rhs.e + 64);
#elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && defined(__x86_64__) #elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && defined(__x86_64__)
__extension__ typedef unsigned __int128 uint128; __extension__ typedef unsigned __int128 uint128;
@ -80,7 +90,9 @@ struct DiyFp {
uint64_t h = static_cast<uint64_t>(p >> 64); uint64_t h = static_cast<uint64_t>(p >> 64);
uint64_t l = static_cast<uint64_t>(p); uint64_t l = static_cast<uint64_t>(p);
if(l & (uint64_t(1) << 63)) // rounding if(l & (uint64_t(1) << 63)) // rounding
{
h++; h++;
}
return DiyFp(h, e + rhs.e + 64); return DiyFp(h, e + rhs.e + 64);
#else #else
const uint64_t M32 = 0xFFFFFFFF; const uint64_t M32 = 0xFFFFFFFF;
@ -98,7 +110,8 @@ struct DiyFp {
#endif #endif
} }
DiyFp Normalize() const { DiyFp Normalize() const
{
#if defined(_MSC_VER) && defined(_M_AMD64) #if defined(_MSC_VER) && defined(_M_AMD64)
unsigned long index; unsigned long index;
_BitScanReverse64(&index, f); _BitScanReverse64(&index, f);
@ -108,7 +121,8 @@ struct DiyFp {
return DiyFp(f << s, e - s); return DiyFp(f << s, e - s);
#else #else
DiyFp res = *this; DiyFp res = *this;
while (!(res.f & (static_cast<uint64_t>(1) << 63))) { while(!(res.f & (static_cast<uint64_t>(1) << 63)))
{
res.f <<= 1; res.f <<= 1;
res.e--; res.e--;
} }
@ -116,9 +130,11 @@ struct DiyFp {
#endif #endif
} }
DiyFp NormalizeBoundary() const { DiyFp NormalizeBoundary() const
{
DiyFp res = *this; DiyFp res = *this;
while (!(res.f & (kDpHiddenBit << 1))) { while(!(res.f & (kDpHiddenBit << 1)))
{
res.f <<= 1; res.f <<= 1;
res.e--; res.e--;
} }
@ -127,7 +143,8 @@ struct DiyFp {
return res; return res;
} }
void NormalizedBoundaries(DiyFp* minus, DiyFp* plus) const { void NormalizedBoundaries(DiyFp* minus, DiyFp* plus) const
{
DiyFp pl = DiyFp((f << 1) + 1, e - 1).NormalizeBoundary(); DiyFp pl = DiyFp((f << 1) + 1, e - 1).NormalizeBoundary();
DiyFp mi = (f == kDpHiddenBit) ? DiyFp((f << 2) - 1, e - 2) : DiyFp((f << 1) - 1, e - 1); DiyFp mi = (f == kDpHiddenBit) ? DiyFp((f << 2) - 1, e - 2) : DiyFp((f << 1) - 1, e - 1);
mi.f <<= mi.e - pl.e; mi.f <<= mi.e - pl.e;
@ -136,8 +153,10 @@ struct DiyFp {
*minus = mi; *minus = mi;
} }
double ToDouble() const { double ToDouble() const
union { {
union
{
double d; double d;
uint64_t u64; uint64_t u64;
} u; } u;
@ -161,9 +180,11 @@ struct DiyFp {
int e; int e;
}; };
inline DiyFp GetCachedPowerByIndex(size_t index) { inline DiyFp GetCachedPowerByIndex(size_t index)
{
// 10^-348, 10^-340, ..., 10^340 // 10^-348, 10^-340, ..., 10^340
static const uint64_t kCachedPowers_F[] = { static const uint64_t kCachedPowers_F[] =
{
RAPIDJSON_UINT64_C2(0xfa8fd5a0, 0x081c0288), RAPIDJSON_UINT64_C2(0xbaaee17f, 0xa23ebf76), RAPIDJSON_UINT64_C2(0xfa8fd5a0, 0x081c0288), RAPIDJSON_UINT64_C2(0xbaaee17f, 0xa23ebf76),
RAPIDJSON_UINT64_C2(0x8b16fb20, 0x3055ac76), RAPIDJSON_UINT64_C2(0xcf42894a, 0x5dce35ea), RAPIDJSON_UINT64_C2(0x8b16fb20, 0x3055ac76), RAPIDJSON_UINT64_C2(0xcf42894a, 0x5dce35ea),
RAPIDJSON_UINT64_C2(0x9a6bb0aa, 0x55653b2d), RAPIDJSON_UINT64_C2(0xe61acf03, 0x3d1a45df), RAPIDJSON_UINT64_C2(0x9a6bb0aa, 0x55653b2d), RAPIDJSON_UINT64_C2(0xe61acf03, 0x3d1a45df),
@ -209,7 +230,8 @@ inline DiyFp GetCachedPowerByIndex(size_t index) {
RAPIDJSON_UINT64_C2(0x9e19db92, 0xb4e31ba9), RAPIDJSON_UINT64_C2(0xeb96bf6e, 0xbadf77d9), RAPIDJSON_UINT64_C2(0x9e19db92, 0xb4e31ba9), RAPIDJSON_UINT64_C2(0xeb96bf6e, 0xbadf77d9),
RAPIDJSON_UINT64_C2(0xaf87023b, 0x9bf0ee6b) RAPIDJSON_UINT64_C2(0xaf87023b, 0x9bf0ee6b)
}; };
static const int16_t kCachedPowers_E[] = { static const int16_t kCachedPowers_E[] =
{
-1220, -1193, -1166, -1140, -1113, -1087, -1060, -1034, -1007, -980, -1220, -1193, -1166, -1140, -1113, -1087, -1060, -1034, -1007, -980,
-954, -927, -901, -874, -847, -821, -794, -768, -741, -715, -954, -927, -901, -874, -847, -821, -794, -768, -741, -715,
-688, -661, -635, -608, -582, -555, -529, -502, -475, -449, -688, -661, -635, -608, -582, -555, -529, -502, -475, -449,
@ -223,13 +245,16 @@ inline DiyFp GetCachedPowerByIndex(size_t index) {
return DiyFp(kCachedPowers_F[index], kCachedPowers_E[index]); return DiyFp(kCachedPowers_F[index], kCachedPowers_E[index]);
} }
inline DiyFp GetCachedPower(int e, int* K) { inline DiyFp GetCachedPower(int e, int* K)
{
//int k = static_cast<int>(ceil((-61 - e) * 0.30102999566398114)) + 374; //int k = static_cast<int>(ceil((-61 - e) * 0.30102999566398114)) + 374;
double dk = (-61 - e) * 0.30102999566398114 + 347; // dk must be positive, so can do ceiling in positive double dk = (-61 - e) * 0.30102999566398114 + 347; // dk must be positive, so can do ceiling in positive
int k = static_cast<int>(dk); int k = static_cast<int>(dk);
if(dk - k > 0.0) if(dk - k > 0.0)
{
k++; k++;
}
unsigned index = static_cast<unsigned>((k >> 3) + 1); unsigned index = static_cast<unsigned>((k >> 3) + 1);
*K = -(-348 + static_cast<int>(index << 3)); // decimal exponent no need lookup table *K = -(-348 + static_cast<int>(index << 3)); // decimal exponent no need lookup table
@ -237,7 +262,8 @@ inline DiyFp GetCachedPower(int e, int* K) {
return GetCachedPowerByIndex(index); return GetCachedPowerByIndex(index);
} }
inline DiyFp GetCachedPower10(int exp, int *outExp) { inline DiyFp GetCachedPower10(int exp, int* outExp)
{
unsigned index = (static_cast<unsigned>(exp) + 348u) / 8u; unsigned index = (static_cast<unsigned>(exp) + 348u) / 8u;
*outExp = -348 + static_cast<int>(index) * 8; *outExp = -348 + static_cast<int>(index) * 8;
return GetCachedPowerByIndex(index); return GetCachedPowerByIndex(index);

View file

@ -24,40 +24,71 @@
#include "ieee754.h" #include "ieee754.h"
RAPIDJSON_NAMESPACE_BEGIN RAPIDJSON_NAMESPACE_BEGIN
namespace internal { namespace internal
{
#ifdef __GNUC__ #ifdef __GNUC__
RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(effc++) RAPIDJSON_DIAG_OFF(effc++)
RAPIDJSON_DIAG_OFF(array-bounds) // some gcc versions generate wrong warnings https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59124 RAPIDJSON_DIAG_OFF(array -
bounds) // some gcc versions generate wrong warnings https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59124
#endif #endif
inline void GrisuRound(char* buffer, int len, uint64_t delta, uint64_t rest, uint64_t ten_kappa, uint64_t wp_w) { inline void GrisuRound(char* buffer, int len, uint64_t delta, uint64_t rest, uint64_t ten_kappa,
uint64_t wp_w)
{
while(rest < wp_w && delta - rest >= ten_kappa && while(rest < wp_w && delta - rest >= ten_kappa &&
(rest + ten_kappa < wp_w || /// closer (rest + ten_kappa < wp_w || /// closer
wp_w - rest > rest + ten_kappa - wp_w)) { wp_w - rest > rest + ten_kappa - wp_w))
{
buffer[len - 1]--; buffer[len - 1]--;
rest += ten_kappa; rest += ten_kappa;
} }
} }
inline unsigned CountDecimalDigit32(uint32_t n) { inline unsigned CountDecimalDigit32(uint32_t n)
{
// Simple pure C++ implementation was faster than __builtin_clz version in this situation. // Simple pure C++ implementation was faster than __builtin_clz version in this situation.
if (n < 10) return 1; if(n < 10)
if (n < 100) return 2; {
if (n < 1000) return 3; return 1;
if (n < 10000) return 4; }
if (n < 100000) return 5; if(n < 100)
if (n < 1000000) return 6; {
if (n < 10000000) return 7; return 2;
if (n < 100000000) return 8; }
if(n < 1000)
{
return 3;
}
if(n < 10000)
{
return 4;
}
if(n < 100000)
{
return 5;
}
if(n < 1000000)
{
return 6;
}
if(n < 10000000)
{
return 7;
}
if(n < 100000000)
{
return 8;
}
// Will not reach 10 digits in DigitGen() // Will not reach 10 digits in DigitGen()
//if (n < 1000000000) return 9; //if (n < 1000000000) return 9;
//return 10; //return 10;
return 9; return 9;
} }
inline void DigitGen(const DiyFp& W, const DiyFp& Mp, uint64_t delta, char* buffer, int* len, int* K) { inline void DigitGen(const DiyFp & W, const DiyFp & Mp, uint64_t delta, char* buffer, int* len, int* K)
{
static const uint32_t kPow10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 }; static const uint32_t kPow10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 };
const DiyFp one(uint64_t(1) << -Mp.e, Mp.e); const DiyFp one(uint64_t(1) << -Mp.e, Mp.e);
const DiyFp wp_w = Mp - W; const DiyFp wp_w = Mp - W;
@ -66,25 +97,58 @@ inline void DigitGen(const DiyFp& W, const DiyFp& Mp, uint64_t delta, char* buff
unsigned kappa = CountDecimalDigit32(p1); // kappa in [0, 9] unsigned kappa = CountDecimalDigit32(p1); // kappa in [0, 9]
*len = 0; *len = 0;
while (kappa > 0) { while(kappa > 0)
{
uint32_t d = 0; uint32_t d = 0;
switch (kappa) { switch(kappa)
case 9: d = p1 / 100000000; p1 %= 100000000; break; {
case 8: d = p1 / 10000000; p1 %= 10000000; break; case 9:
case 7: d = p1 / 1000000; p1 %= 1000000; break; d = p1 / 100000000;
case 6: d = p1 / 100000; p1 %= 100000; break; p1 %= 100000000;
case 5: d = p1 / 10000; p1 %= 10000; break; break;
case 4: d = p1 / 1000; p1 %= 1000; break; case 8:
case 3: d = p1 / 100; p1 %= 100; break; d = p1 / 10000000;
case 2: d = p1 / 10; p1 %= 10; break; p1 %= 10000000;
case 1: d = p1; p1 = 0; break; break;
default:; case 7:
d = p1 / 1000000;
p1 %= 1000000;
break;
case 6:
d = p1 / 100000;
p1 %= 100000;
break;
case 5:
d = p1 / 10000;
p1 %= 10000;
break;
case 4:
d = p1 / 1000;
p1 %= 1000;
break;
case 3:
d = p1 / 100;
p1 %= 100;
break;
case 2:
d = p1 / 10;
p1 %= 10;
break;
case 1:
d = p1;
p1 = 0;
break;
default:
;
} }
if(d || *len) if(d || *len)
{
buffer[(*len)++] = static_cast<char>('0' + static_cast<char>(d)); buffer[(*len)++] = static_cast<char>('0' + static_cast<char>(d));
}
kappa--; kappa--;
uint64_t tmp = (static_cast<uint64_t>(p1) << -one.e) + p2; uint64_t tmp = (static_cast<uint64_t>(p1) << -one.e) + p2;
if (tmp <= delta) { if(tmp <= delta)
{
*K += kappa; *K += kappa;
GrisuRound(buffer, *len, delta, tmp, static_cast<uint64_t>(kPow10[kappa]) << -one.e, wp_w.f); GrisuRound(buffer, *len, delta, tmp, static_cast<uint64_t>(kPow10[kappa]) << -one.e, wp_w.f);
return; return;
@ -92,15 +156,19 @@ inline void DigitGen(const DiyFp& W, const DiyFp& Mp, uint64_t delta, char* buff
} }
// kappa = 0 // kappa = 0
for (;;) { for(;;)
{
p2 *= 10; p2 *= 10;
delta *= 10; delta *= 10;
char d = static_cast<char>(p2 >> -one.e); char d = static_cast<char>(p2 >> -one.e);
if(d || *len) if(d || *len)
{
buffer[(*len)++] = static_cast<char>('0' + d); buffer[(*len)++] = static_cast<char>('0' + d);
}
p2 &= one.f - 1; p2 &= one.f - 1;
kappa--; kappa--;
if (p2 < delta) { if(p2 < delta)
{
*K += kappa; *K += kappa;
int index = -static_cast<int>(kappa); int index = -static_cast<int>(kappa);
GrisuRound(buffer, *len, delta, p2, one.f, wp_w.f * (index < 9 ? kPow10[-static_cast<int>(kappa)] : 0)); GrisuRound(buffer, *len, delta, p2, one.f, wp_w.f * (index < 9 ? kPow10[-static_cast<int>(kappa)] : 0));
@ -109,7 +177,8 @@ inline void DigitGen(const DiyFp& W, const DiyFp& Mp, uint64_t delta, char* buff
} }
} }
inline void Grisu2(double value, char* buffer, int* length, int* K) { inline void Grisu2(double value, char* buffer, int* length, int* K)
{
const DiyFp v(value); const DiyFp v(value);
DiyFp w_m, w_p; DiyFp w_m, w_p;
v.NormalizedBoundaries(&w_m, &w_p); v.NormalizedBoundaries(&w_m, &w_p);
@ -123,88 +192,115 @@ inline void Grisu2(double value, char* buffer, int* length, int* K) {
DigitGen(W, Wp, Wp.f - Wm.f, buffer, length, K); DigitGen(W, Wp, Wp.f - Wm.f, buffer, length, K);
} }
inline char* WriteExponent(int K, char* buffer) { inline char* WriteExponent(int K, char* buffer)
if (K < 0) { {
if(K < 0)
{
*buffer++ = '-'; *buffer++ = '-';
K = -K; K = -K;
} }
if (K >= 100) { if(K >= 100)
{
*buffer++ = static_cast<char>('0' + static_cast<char>(K / 100)); *buffer++ = static_cast<char>('0' + static_cast<char>(K / 100));
K %= 100; K %= 100;
const char* d = GetDigitsLut() + K * 2; const char* d = GetDigitsLut() + K * 2;
*buffer++ = d[0]; *buffer++ = d[0];
*buffer++ = d[1]; *buffer++ = d[1];
} }
else if (K >= 10) { else if(K >= 10)
{
const char* d = GetDigitsLut() + K * 2; const char* d = GetDigitsLut() + K * 2;
*buffer++ = d[0]; *buffer++ = d[0];
*buffer++ = d[1]; *buffer++ = d[1];
} }
else else
{
*buffer++ = static_cast<char>('0' + static_cast<char>(K)); *buffer++ = static_cast<char>('0' + static_cast<char>(K));
}
return buffer; return buffer;
} }
inline char* Prettify(char* buffer, int length, int k, int maxDecimalPlaces) { inline char* Prettify(char* buffer, int length, int k, int maxDecimalPlaces)
{
const int kk = length + k; // 10^(kk-1) <= v < 10^kk const int kk = length + k; // 10^(kk-1) <= v < 10^kk
if (0 <= k && kk <= 21) { if(0 <= k && kk <= 21)
{
// 1234e7 -> 12340000000 // 1234e7 -> 12340000000
for(int i = length; i < kk; i++) for(int i = length; i < kk; i++)
{
buffer[i] = '0'; buffer[i] = '0';
}
buffer[kk] = '.'; buffer[kk] = '.';
buffer[kk + 1] = '0'; buffer[kk + 1] = '0';
return &buffer[kk + 2]; return &buffer[kk + 2];
} }
else if (0 < kk && kk <= 21) { else if(0 < kk && kk <= 21)
{
// 1234e-2 -> 12.34 // 1234e-2 -> 12.34
std::memmove(&buffer[kk + 1], &buffer[kk], static_cast<size_t>(length - kk)); std::memmove(&buffer[kk + 1], &buffer[kk], static_cast<size_t>(length - kk));
buffer[kk] = '.'; buffer[kk] = '.';
if (0 > k + maxDecimalPlaces) { if(0 > k + maxDecimalPlaces)
{
// When maxDecimalPlaces = 2, 1.2345 -> 1.23, 1.102 -> 1.1 // When maxDecimalPlaces = 2, 1.2345 -> 1.23, 1.102 -> 1.1
// Remove extra trailing zeros (at least one) after truncation. // Remove extra trailing zeros (at least one) after truncation.
for(int i = kk + maxDecimalPlaces; i > kk + 1; i--) for(int i = kk + maxDecimalPlaces; i > kk + 1; i--)
if(buffer[i] != '0') if(buffer[i] != '0')
{
return &buffer[i + 1]; return &buffer[i + 1];
}
return &buffer[kk + 2]; // Reserve one zero return &buffer[kk + 2]; // Reserve one zero
} }
else else
{
return &buffer[length + 1]; return &buffer[length + 1];
} }
else if (-6 < kk && kk <= 0) { }
else if(-6 < kk && kk <= 0)
{
// 1234e-6 -> 0.001234 // 1234e-6 -> 0.001234
const int offset = 2 - kk; const int offset = 2 - kk;
std::memmove(&buffer[offset], &buffer[0], static_cast<size_t>(length)); std::memmove(&buffer[offset], &buffer[0], static_cast<size_t>(length));
buffer[0] = '0'; buffer[0] = '0';
buffer[1] = '.'; buffer[1] = '.';
for(int i = 2; i < offset; i++) for(int i = 2; i < offset; i++)
{
buffer[i] = '0'; buffer[i] = '0';
if (length - kk > maxDecimalPlaces) { }
if(length - kk > maxDecimalPlaces)
{
// When maxDecimalPlaces = 2, 0.123 -> 0.12, 0.102 -> 0.1 // When maxDecimalPlaces = 2, 0.123 -> 0.12, 0.102 -> 0.1
// Remove extra trailing zeros (at least one) after truncation. // Remove extra trailing zeros (at least one) after truncation.
for(int i = maxDecimalPlaces + 1; i > 2; i--) for(int i = maxDecimalPlaces + 1; i > 2; i--)
if(buffer[i] != '0') if(buffer[i] != '0')
{
return &buffer[i + 1]; return &buffer[i + 1];
}
return &buffer[3]; // Reserve one zero return &buffer[3]; // Reserve one zero
} }
else else
{
return &buffer[length + offset]; return &buffer[length + offset];
} }
else if (kk < -maxDecimalPlaces) { }
else if(kk < -maxDecimalPlaces)
{
// Truncate to zero // Truncate to zero
buffer[0] = '0'; buffer[0] = '0';
buffer[1] = '.'; buffer[1] = '.';
buffer[2] = '0'; buffer[2] = '0';
return &buffer[3]; return &buffer[3];
} }
else if (length == 1) { else if(length == 1)
{
// 1e30 // 1e30
buffer[1] = 'e'; buffer[1] = 'e';
return WriteExponent(kk - 1, &buffer[2]); return WriteExponent(kk - 1, &buffer[2]);
} }
else { else
{
// 1234e30 -> 1.234e33 // 1234e30 -> 1.234e33
std::memmove(&buffer[2], &buffer[1], static_cast<size_t>(length - 1)); std::memmove(&buffer[2], &buffer[1], static_cast<size_t>(length - 1));
buffer[1] = '.'; buffer[1] = '.';
@ -213,19 +309,25 @@ inline char* Prettify(char* buffer, int length, int k, int maxDecimalPlaces) {
} }
} }
inline char* dtoa(double value, char* buffer, int maxDecimalPlaces = 324) { inline char* dtoa(double value, char* buffer, int maxDecimalPlaces = 324)
{
RAPIDJSON_ASSERT(maxDecimalPlaces >= 1); RAPIDJSON_ASSERT(maxDecimalPlaces >= 1);
Double d(value); Double d(value);
if (d.IsZero()) { if(d.IsZero())
{
if(d.Sign()) if(d.Sign())
{
*buffer++ = '-'; // -0.0, Issue #289 *buffer++ = '-'; // -0.0, Issue #289
}
buffer[0] = '0'; buffer[0] = '0';
buffer[1] = '.'; buffer[1] = '.';
buffer[2] = '0'; buffer[2] = '0';
return &buffer[3]; return &buffer[3];
} }
else { else
if (value < 0) { {
if(value < 0)
{
*buffer++ = '-'; *buffer++ = '-';
value = -value; value = -value;
} }

View file

@ -18,44 +18,93 @@
#include "../rapidjson.h" #include "../rapidjson.h"
RAPIDJSON_NAMESPACE_BEGIN RAPIDJSON_NAMESPACE_BEGIN
namespace internal { namespace internal
{
class Double { class Double
{
public: public:
Double() {} Double() {}
Double(double d) : d_(d) {} Double(double d) : d_(d) {}
Double(uint64_t u) : u_(u) {} Double(uint64_t u) : u_(u) {}
double Value() const { return d_; } double Value() const
uint64_t Uint64Value() const { return u_; } {
return d_;
}
uint64_t Uint64Value() const
{
return u_;
}
double NextPositiveDouble() const { double NextPositiveDouble() const
{
RAPIDJSON_ASSERT(!Sign()); RAPIDJSON_ASSERT(!Sign());
return Double(u_ + 1).Value(); return Double(u_ + 1).Value();
} }
bool Sign() const { return (u_ & kSignMask) != 0; } bool Sign() const
uint64_t Significand() const { return u_ & kSignificandMask; } {
int Exponent() const { return static_cast<int>(((u_ & kExponentMask) >> kSignificandSize) - kExponentBias); } return (u_ & kSignMask) != 0;
}
uint64_t Significand() const
{
return u_ & kSignificandMask;
}
int Exponent() const
{
return static_cast<int>(((u_ & kExponentMask) >> kSignificandSize) - kExponentBias);
}
bool IsNan() const { return (u_ & kExponentMask) == kExponentMask && Significand() != 0; } bool IsNan() const
bool IsInf() const { return (u_ & kExponentMask) == kExponentMask && Significand() == 0; } {
bool IsNanOrInf() const { return (u_ & kExponentMask) == kExponentMask; } return (u_ & kExponentMask) == kExponentMask && Significand() != 0;
bool IsNormal() const { return (u_ & kExponentMask) != 0 || Significand() == 0; } }
bool IsZero() const { return (u_ & (kExponentMask | kSignificandMask)) == 0; } bool IsInf() const
{
return (u_ & kExponentMask) == kExponentMask && Significand() == 0;
}
bool IsNanOrInf() const
{
return (u_ & kExponentMask) == kExponentMask;
}
bool IsNormal() const
{
return (u_ & kExponentMask) != 0 || Significand() == 0;
}
bool IsZero() const
{
return (u_ & (kExponentMask | kSignificandMask)) == 0;
}
uint64_t IntegerSignificand() const { return IsNormal() ? Significand() | kHiddenBit : Significand(); } uint64_t IntegerSignificand() const
int IntegerExponent() const { return (IsNormal() ? Exponent() : kDenormalExponent) - kSignificandSize; } {
uint64_t ToBias() const { return (u_ & kSignMask) ? ~u_ + 1 : u_ | kSignMask; } return IsNormal() ? Significand() | kHiddenBit : Significand();
}
int IntegerExponent() const
{
return (IsNormal() ? Exponent() : kDenormalExponent) - kSignificandSize;
}
uint64_t ToBias() const
{
return (u_ & kSignMask) ? ~u_ + 1 : u_ | kSignMask;
}
static unsigned EffectiveSignificandSize(int order) { static unsigned EffectiveSignificandSize(int order)
{
if(order >= -1021) if(order >= -1021)
{
return 53; return 53;
}
else if(order <= -1074) else if(order <= -1074)
{
return 0; return 0;
}
else else
{
return static_cast<unsigned>(order) + 1074; return static_cast<unsigned>(order) + 1074;
} }
}
private: private:
static const int kSignificandSize = 52; static const int kSignificandSize = 52;
@ -66,7 +115,8 @@ private:
static const uint64_t kSignificandMask = RAPIDJSON_UINT64_C2(0x000FFFFF, 0xFFFFFFFF); static const uint64_t kSignificandMask = RAPIDJSON_UINT64_C2(0x000FFFFF, 0xFFFFFFFF);
static const uint64_t kHiddenBit = RAPIDJSON_UINT64_C2(0x00100000, 0x00000000); static const uint64_t kHiddenBit = RAPIDJSON_UINT64_C2(0x00100000, 0x00000000);
union { union
{
double d_; double d_;
uint64_t u_; uint64_t u_;
}; };

View file

@ -18,10 +18,13 @@
#include "../rapidjson.h" #include "../rapidjson.h"
RAPIDJSON_NAMESPACE_BEGIN RAPIDJSON_NAMESPACE_BEGIN
namespace internal { namespace internal
{
inline const char* GetDigitsLut() { inline const char* GetDigitsLut()
static const char cDigitsLut[200] = { {
static const char cDigitsLut[200] =
{
'0', '0', '0', '1', '0', '2', '0', '3', '0', '4', '0', '5', '0', '6', '0', '7', '0', '8', '0', '9', '0', '0', '0', '1', '0', '2', '0', '3', '0', '4', '0', '5', '0', '6', '0', '7', '0', '8', '0', '9',
'1', '0', '1', '1', '1', '2', '1', '3', '1', '4', '1', '5', '1', '6', '1', '7', '1', '8', '1', '9', '1', '0', '1', '1', '1', '2', '1', '3', '1', '4', '1', '5', '1', '6', '1', '7', '1', '8', '1', '9',
'2', '0', '2', '1', '2', '2', '2', '3', '2', '4', '2', '5', '2', '6', '2', '7', '2', '8', '2', '9', '2', '0', '2', '1', '2', '2', '2', '3', '2', '4', '2', '5', '2', '6', '2', '7', '2', '8', '2', '9',
@ -36,22 +39,31 @@ inline const char* GetDigitsLut() {
return cDigitsLut; return cDigitsLut;
} }
inline char* u32toa(uint32_t value, char* buffer) { inline char* u32toa(uint32_t value, char* buffer)
{
const char* cDigitsLut = GetDigitsLut(); const char* cDigitsLut = GetDigitsLut();
if (value < 10000) { if(value < 10000)
{
const uint32_t d1 = (value / 100) << 1; const uint32_t d1 = (value / 100) << 1;
const uint32_t d2 = (value % 100) << 1; const uint32_t d2 = (value % 100) << 1;
if(value >= 1000) if(value >= 1000)
{
*buffer++ = cDigitsLut[d1]; *buffer++ = cDigitsLut[d1];
}
if(value >= 100) if(value >= 100)
{
*buffer++ = cDigitsLut[d1 + 1]; *buffer++ = cDigitsLut[d1 + 1];
}
if(value >= 10) if(value >= 10)
{
*buffer++ = cDigitsLut[d2]; *buffer++ = cDigitsLut[d2];
}
*buffer++ = cDigitsLut[d2 + 1]; *buffer++ = cDigitsLut[d2 + 1];
} }
else if (value < 100000000) { else if(value < 100000000)
{
// value = bbbbcccc // value = bbbbcccc
const uint32_t b = value / 10000; const uint32_t b = value / 10000;
const uint32_t c = value % 10000; const uint32_t c = value % 10000;
@ -63,11 +75,17 @@ inline char* u32toa(uint32_t value, char* buffer) {
const uint32_t d4 = (c % 100) << 1; const uint32_t d4 = (c % 100) << 1;
if(value >= 10000000) if(value >= 10000000)
{
*buffer++ = cDigitsLut[d1]; *buffer++ = cDigitsLut[d1];
}
if(value >= 1000000) if(value >= 1000000)
{
*buffer++ = cDigitsLut[d1 + 1]; *buffer++ = cDigitsLut[d1 + 1];
}
if(value >= 100000) if(value >= 100000)
{
*buffer++ = cDigitsLut[d2]; *buffer++ = cDigitsLut[d2];
}
*buffer++ = cDigitsLut[d2 + 1]; *buffer++ = cDigitsLut[d2 + 1];
*buffer++ = cDigitsLut[d3]; *buffer++ = cDigitsLut[d3];
@ -75,19 +93,23 @@ inline char* u32toa(uint32_t value, char* buffer) {
*buffer++ = cDigitsLut[d4]; *buffer++ = cDigitsLut[d4];
*buffer++ = cDigitsLut[d4 + 1]; *buffer++ = cDigitsLut[d4 + 1];
} }
else { else
{
// value = aabbbbcccc in decimal // value = aabbbbcccc in decimal
const uint32_t a = value / 100000000; // 1 to 42 const uint32_t a = value / 100000000; // 1 to 42
value %= 100000000; value %= 100000000;
if (a >= 10) { if(a >= 10)
{
const unsigned i = a << 1; const unsigned i = a << 1;
*buffer++ = cDigitsLut[i]; *buffer++ = cDigitsLut[i];
*buffer++ = cDigitsLut[i + 1]; *buffer++ = cDigitsLut[i + 1];
} }
else else
{
*buffer++ = static_cast<char>('0' + static_cast<char>(a)); *buffer++ = static_cast<char>('0' + static_cast<char>(a));
}
const uint32_t b = value / 10000; // 0 to 9999 const uint32_t b = value / 10000; // 0 to 9999
const uint32_t c = value % 10000; // 0 to 9999 const uint32_t c = value % 10000; // 0 to 9999
@ -110,9 +132,11 @@ inline char* u32toa(uint32_t value, char* buffer) {
return buffer; return buffer;
} }
inline char* i32toa(int32_t value, char* buffer) { inline char* i32toa(int32_t value, char* buffer)
{
uint32_t u = static_cast<uint32_t>(value); uint32_t u = static_cast<uint32_t>(value);
if (value < 0) { if(value < 0)
{
*buffer++ = '-'; *buffer++ = '-';
u = ~u + 1; u = ~u + 1;
} }
@ -120,7 +144,8 @@ inline char* i32toa(int32_t value, char* buffer) {
return u32toa(u, buffer); return u32toa(u, buffer);
} }
inline char* u64toa(uint64_t value, char* buffer) { inline char* u64toa(uint64_t value, char* buffer)
{
const char* cDigitsLut = GetDigitsLut(); const char* cDigitsLut = GetDigitsLut();
const uint64_t kTen8 = 100000000; const uint64_t kTen8 = 100000000;
const uint64_t kTen9 = kTen8 * 10; const uint64_t kTen9 = kTen8 * 10;
@ -132,21 +157,30 @@ inline char* u64toa(uint64_t value, char* buffer) {
const uint64_t kTen15 = kTen8 * 10000000; const uint64_t kTen15 = kTen8 * 10000000;
const uint64_t kTen16 = kTen8 * kTen8; const uint64_t kTen16 = kTen8 * kTen8;
if (value < kTen8) { if(value < kTen8)
{
uint32_t v = static_cast<uint32_t>(value); uint32_t v = static_cast<uint32_t>(value);
if (v < 10000) { if(v < 10000)
{
const uint32_t d1 = (v / 100) << 1; const uint32_t d1 = (v / 100) << 1;
const uint32_t d2 = (v % 100) << 1; const uint32_t d2 = (v % 100) << 1;
if(v >= 1000) if(v >= 1000)
{
*buffer++ = cDigitsLut[d1]; *buffer++ = cDigitsLut[d1];
}
if(v >= 100) if(v >= 100)
{
*buffer++ = cDigitsLut[d1 + 1]; *buffer++ = cDigitsLut[d1 + 1];
}
if(v >= 10) if(v >= 10)
{
*buffer++ = cDigitsLut[d2]; *buffer++ = cDigitsLut[d2];
}
*buffer++ = cDigitsLut[d2 + 1]; *buffer++ = cDigitsLut[d2 + 1];
} }
else { else
{
// value = bbbbcccc // value = bbbbcccc
const uint32_t b = v / 10000; const uint32_t b = v / 10000;
const uint32_t c = v % 10000; const uint32_t c = v % 10000;
@ -158,11 +192,17 @@ inline char* u64toa(uint64_t value, char* buffer) {
const uint32_t d4 = (c % 100) << 1; const uint32_t d4 = (c % 100) << 1;
if(value >= 10000000) if(value >= 10000000)
{
*buffer++ = cDigitsLut[d1]; *buffer++ = cDigitsLut[d1];
}
if(value >= 1000000) if(value >= 1000000)
{
*buffer++ = cDigitsLut[d1 + 1]; *buffer++ = cDigitsLut[d1 + 1];
}
if(value >= 100000) if(value >= 100000)
{
*buffer++ = cDigitsLut[d2]; *buffer++ = cDigitsLut[d2];
}
*buffer++ = cDigitsLut[d2 + 1]; *buffer++ = cDigitsLut[d2 + 1];
*buffer++ = cDigitsLut[d3]; *buffer++ = cDigitsLut[d3];
@ -171,7 +211,8 @@ inline char* u64toa(uint64_t value, char* buffer) {
*buffer++ = cDigitsLut[d4 + 1]; *buffer++ = cDigitsLut[d4 + 1];
} }
} }
else if (value < kTen16) { else if(value < kTen16)
{
const uint32_t v0 = static_cast<uint32_t>(value / kTen8); const uint32_t v0 = static_cast<uint32_t>(value / kTen8);
const uint32_t v1 = static_cast<uint32_t>(value % kTen8); const uint32_t v1 = static_cast<uint32_t>(value % kTen8);
@ -194,21 +235,37 @@ inline char* u64toa(uint64_t value, char* buffer) {
const uint32_t d8 = (c1 % 100) << 1; const uint32_t d8 = (c1 % 100) << 1;
if(value >= kTen15) if(value >= kTen15)
{
*buffer++ = cDigitsLut[d1]; *buffer++ = cDigitsLut[d1];
}
if(value >= kTen14) if(value >= kTen14)
{
*buffer++ = cDigitsLut[d1 + 1]; *buffer++ = cDigitsLut[d1 + 1];
}
if(value >= kTen13) if(value >= kTen13)
{
*buffer++ = cDigitsLut[d2]; *buffer++ = cDigitsLut[d2];
}
if(value >= kTen12) if(value >= kTen12)
{
*buffer++ = cDigitsLut[d2 + 1]; *buffer++ = cDigitsLut[d2 + 1];
}
if(value >= kTen11) if(value >= kTen11)
{
*buffer++ = cDigitsLut[d3]; *buffer++ = cDigitsLut[d3];
}
if(value >= kTen10) if(value >= kTen10)
{
*buffer++ = cDigitsLut[d3 + 1]; *buffer++ = cDigitsLut[d3 + 1];
}
if(value >= kTen9) if(value >= kTen9)
{
*buffer++ = cDigitsLut[d4]; *buffer++ = cDigitsLut[d4];
}
if(value >= kTen8) if(value >= kTen8)
{
*buffer++ = cDigitsLut[d4 + 1]; *buffer++ = cDigitsLut[d4 + 1];
}
*buffer++ = cDigitsLut[d5]; *buffer++ = cDigitsLut[d5];
*buffer++ = cDigitsLut[d5 + 1]; *buffer++ = cDigitsLut[d5 + 1];
@ -219,25 +276,31 @@ inline char* u64toa(uint64_t value, char* buffer) {
*buffer++ = cDigitsLut[d8]; *buffer++ = cDigitsLut[d8];
*buffer++ = cDigitsLut[d8 + 1]; *buffer++ = cDigitsLut[d8 + 1];
} }
else { else
{
const uint32_t a = static_cast<uint32_t>(value / kTen16); // 1 to 1844 const uint32_t a = static_cast<uint32_t>(value / kTen16); // 1 to 1844
value %= kTen16; value %= kTen16;
if(a < 10) if(a < 10)
{
*buffer++ = static_cast<char>('0' + static_cast<char>(a)); *buffer++ = static_cast<char>('0' + static_cast<char>(a));
else if (a < 100) { }
else if(a < 100)
{
const uint32_t i = a << 1; const uint32_t i = a << 1;
*buffer++ = cDigitsLut[i]; *buffer++ = cDigitsLut[i];
*buffer++ = cDigitsLut[i + 1]; *buffer++ = cDigitsLut[i + 1];
} }
else if (a < 1000) { else if(a < 1000)
{
*buffer++ = static_cast<char>('0' + static_cast<char>(a / 100)); *buffer++ = static_cast<char>('0' + static_cast<char>(a / 100));
const uint32_t i = (a % 100) << 1; const uint32_t i = (a % 100) << 1;
*buffer++ = cDigitsLut[i]; *buffer++ = cDigitsLut[i];
*buffer++ = cDigitsLut[i + 1]; *buffer++ = cDigitsLut[i + 1];
} }
else { else
{
const uint32_t i = (a / 100) << 1; const uint32_t i = (a / 100) << 1;
const uint32_t j = (a % 100) << 1; const uint32_t j = (a % 100) << 1;
*buffer++ = cDigitsLut[i]; *buffer++ = cDigitsLut[i];
@ -288,9 +351,11 @@ inline char* u64toa(uint64_t value, char* buffer) {
return buffer; return buffer;
} }
inline char* i64toa(int64_t value, char* buffer) { inline char* i64toa(int64_t value, char* buffer)
{
uint64_t u = static_cast<uint64_t>(value); uint64_t u = static_cast<uint64_t>(value);
if (value < 0) { if(value < 0)
{
*buffer++ = '-'; *buffer++ = '-';
u = ~u + 1; u = ~u + 1;
} }

View file

@ -32,15 +32,20 @@ RAPIDJSON_DIAG_OFF(6334)
//@cond RAPIDJSON_INTERNAL //@cond RAPIDJSON_INTERNAL
RAPIDJSON_NAMESPACE_BEGIN RAPIDJSON_NAMESPACE_BEGIN
namespace internal { namespace internal
{
// Helper to wrap/convert arbitrary types to void, useful for arbitrary type matching // Helper to wrap/convert arbitrary types to void, useful for arbitrary type matching
template <typename T> struct Void { typedef void Type; }; template <typename T> struct Void
{
typedef void Type;
};
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// BoolType, TrueType, FalseType // BoolType, TrueType, FalseType
// //
template <bool Cond> struct BoolType { template <bool Cond> struct BoolType
{
static const bool Value = Cond; static const bool Value = Cond;
typedef BoolType Type; typedef BoolType Type;
}; };
@ -52,8 +57,20 @@ typedef BoolType<false> FalseType;
// SelectIf, BoolExpr, NotExpr, AndExpr, OrExpr // SelectIf, BoolExpr, NotExpr, AndExpr, OrExpr
// //
template <bool C> struct SelectIfImpl { template <typename T1, typename T2> struct Apply { typedef T1 Type; }; }; template <bool C> struct SelectIfImpl
template <> struct SelectIfImpl<false> { template <typename T1, typename T2> struct Apply { typedef T2 Type; }; }; {
template <typename T1, typename T2> struct Apply
{
typedef T1 Type;
};
};
template <> struct SelectIfImpl<false>
{
template <typename T1, typename T2> struct Apply
{
typedef T2 Type;
};
};
template <bool C, typename T1, typename T2> struct SelectIfCond : SelectIfImpl<C>::template Apply<T1, T2> {}; template <bool C, typename T1, typename T2> struct SelectIfCond : SelectIfImpl<C>::template Apply<T1, T2> {};
template <typename C, typename T1, typename T2> struct SelectIf : SelectIfCond<C::Value, T1, T2> {}; template <typename C, typename T1, typename T2> struct SelectIf : SelectIfCond<C::Value, T1, T2> {};
@ -70,10 +87,19 @@ template <typename C1, typename C2> struct OrExpr : OrExprCond<C1::Value, C2::V
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// AddConst, MaybeAddConst, RemoveConst // AddConst, MaybeAddConst, RemoveConst
template <typename T> struct AddConst { typedef const T Type; }; template <typename T> struct AddConst
{
typedef const T Type;
};
template <bool Constify, typename T> struct MaybeAddConst : SelectIfCond<Constify, const T, T> {}; template <bool Constify, typename T> struct MaybeAddConst : SelectIfCond<Constify, const T, T> {};
template <typename T> struct RemoveConst { typedef T Type; }; template <typename T> struct RemoveConst
template <typename T> struct RemoveConst<const T> { typedef T Type; }; {
typedef T Type;
};
template <typename T> struct RemoveConst<const T>
{
typedef T Type;
};
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
@ -103,7 +129,8 @@ template <typename B, typename D> struct IsBaseOf
#else // simplified version adopted from Boost #else // simplified version adopted from Boost
template<typename B, typename D> struct IsBaseOfImpl { template<typename B, typename D> struct IsBaseOfImpl
{
RAPIDJSON_STATIC_ASSERT(sizeof(B) != 0); RAPIDJSON_STATIC_ASSERT(sizeof(B) != 0);
RAPIDJSON_STATIC_ASSERT(sizeof(D) != 0); RAPIDJSON_STATIC_ASSERT(sizeof(D) != 0);
@ -114,7 +141,8 @@ template<typename B, typename D> struct IsBaseOfImpl {
static Yes Check(const D*, T); static Yes Check(const D*, T);
static No Check(const B*, int); static No Check(const B*, int);
struct Host { struct Host
{
operator const B* () const; operator const B* () const;
operator const D* (); operator const D* ();
}; };
@ -131,11 +159,23 @@ template <typename B, typename D> struct IsBaseOf
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
// EnableIf / DisableIf // EnableIf / DisableIf
// //
template <bool Condition, typename T = void> struct EnableIfCond { typedef T Type; }; template <bool Condition, typename T = void> struct EnableIfCond
template <typename T> struct EnableIfCond<false, T> { /* empty */ }; {
typedef T Type;
};
template <typename T> struct EnableIfCond<false, T>
{
/* empty */
};
template <bool Condition, typename T = void> struct DisableIfCond { typedef T Type; }; template <bool Condition, typename T = void> struct DisableIfCond
template <typename T> struct DisableIfCond<true, T> { /* empty */ }; {
typedef T Type;
};
template <typename T> struct DisableIfCond<true, T>
{
/* empty */
};
template <typename Condition, typename T = void> template <typename Condition, typename T = void>
struct EnableIf : EnableIfCond<Condition::Value, T> {}; struct EnableIf : EnableIfCond<Condition::Value, T> {};
@ -146,7 +186,10 @@ struct DisableIf : DisableIfCond<Condition::Value, T> {};
// SFINAE helpers // SFINAE helpers
struct SfinaeTag {}; struct SfinaeTag {};
template <typename T> struct RemoveSfinaeTag; template <typename T> struct RemoveSfinaeTag;
template <typename T> struct RemoveSfinaeTag<SfinaeTag&(*)(T)> { typedef T Type; }; template <typename T> struct RemoveSfinaeTag<SfinaeTag&(*)(T)>
{
typedef T Type;
};
#define RAPIDJSON_REMOVEFPTR_(type) \ #define RAPIDJSON_REMOVEFPTR_(type) \
typename ::RAPIDJSON_NAMESPACE::internal::RemoveSfinaeTag \ typename ::RAPIDJSON_NAMESPACE::internal::RemoveSfinaeTag \

View file

@ -18,15 +18,18 @@
#include "../rapidjson.h" #include "../rapidjson.h"
RAPIDJSON_NAMESPACE_BEGIN RAPIDJSON_NAMESPACE_BEGIN
namespace internal { namespace internal
{
//! Computes integer powers of 10 in double (10.0^n). //! Computes integer powers of 10 in double (10.0^n).
/*! This function uses lookup table for fast and accurate results. /*! This function uses lookup table for fast and accurate results.
\param n non-negative exponent. Must <= 308. \param n non-negative exponent. Must <= 308.
\return 10.0^n \return 10.0^n
*/ */
inline double Pow10(int n) { inline double Pow10(int n)
static const double e[] = { // 1e-0...1e308: 309 * 8 bytes = 2472 bytes {
static const double e[] = // 1e-0...1e308: 309 * 8 bytes = 2472 bytes
{
1e+0, 1e+0,
1e+1, 1e+2, 1e+3, 1e+4, 1e+5, 1e+6, 1e+7, 1e+8, 1e+9, 1e+10, 1e+11, 1e+12, 1e+13, 1e+14, 1e+15, 1e+16, 1e+17, 1e+18, 1e+19, 1e+20, 1e+1, 1e+2, 1e+3, 1e+4, 1e+5, 1e+6, 1e+7, 1e+8, 1e+9, 1e+10, 1e+11, 1e+12, 1e+13, 1e+14, 1e+15, 1e+16, 1e+17, 1e+18, 1e+19, 1e+20,
1e+21, 1e+22, 1e+23, 1e+24, 1e+25, 1e+26, 1e+27, 1e+28, 1e+29, 1e+30, 1e+31, 1e+32, 1e+33, 1e+34, 1e+35, 1e+36, 1e+37, 1e+38, 1e+39, 1e+40, 1e+21, 1e+22, 1e+23, 1e+24, 1e+25, 1e+26, 1e+27, 1e+28, 1e+29, 1e+30, 1e+31, 1e+32, 1e+33, 1e+34, 1e+35, 1e+36, 1e+37, 1e+38, 1e+39, 1e+40,

View file

@ -41,12 +41,14 @@ RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated
#endif #endif
RAPIDJSON_NAMESPACE_BEGIN RAPIDJSON_NAMESPACE_BEGIN
namespace internal { namespace internal
{
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// GenericRegex // GenericRegex
static const SizeType kRegexInvalidState = ~SizeType(0); //!< Represents an invalid index in GenericRegex::State::out, out1 static const SizeType kRegexInvalidState = ~SizeType(
0); //!< Represents an invalid index in GenericRegex::State::out, out1
static const SizeType kRegexInvalidRange = ~SizeType(0); static const SizeType kRegexInvalidRange = ~SizeType(0);
//! Regular expression engine with subset of ECMAscript grammar. //! Regular expression engine with subset of ECMAscript grammar.
@ -82,7 +84,8 @@ static const SizeType kRegexInvalidRange = ~SizeType(0);
https://swtch.com/~rsc/regexp/regexp1.html https://swtch.com/~rsc/regexp/regexp1.html
*/ */
template <typename Encoding, typename Allocator = CrtAllocator> template <typename Encoding, typename Allocator = CrtAllocator>
class GenericRegex { class GenericRegex
{
public: public:
typedef typename Encoding::Ch Ch; typedef typename Encoding::Ch Ch;
@ -95,36 +98,43 @@ public:
Parse(ds); Parse(ds);
} }
~GenericRegex() { ~GenericRegex()
{
Allocator::Free(stateSet_); Allocator::Free(stateSet_);
} }
bool IsValid() const { bool IsValid() const
{
return root_ != kRegexInvalidState; return root_ != kRegexInvalidState;
} }
template <typename InputStream> template <typename InputStream>
bool Match(InputStream& is) const { bool Match(InputStream & is) const
{
return SearchWithAnchoring(is, true, true); return SearchWithAnchoring(is, true, true);
} }
bool Match(const Ch* s) const { bool Match(const Ch* s) const
{
GenericStringStream<Encoding> is(s); GenericStringStream<Encoding> is(s);
return Match(is); return Match(is);
} }
template <typename InputStream> template <typename InputStream>
bool Search(InputStream& is) const { bool Search(InputStream & is) const
{
return SearchWithAnchoring(is, anchorBegin_, anchorEnd_); return SearchWithAnchoring(is, anchorBegin_, anchorEnd_);
} }
bool Search(const Ch* s) const { bool Search(const Ch* s) const
{
GenericStringStream<Encoding> is(s); GenericStringStream<Encoding> is(s);
return Search(is); return Search(is);
} }
private: private:
enum Operator { enum Operator
{
kZeroOrOne, kZeroOrOne,
kZeroOrMore, kZeroOrMore,
kOneOrMore, kOneOrMore,
@ -137,20 +147,23 @@ private:
static const unsigned kRangeCharacterClass = 0xFFFFFFFE; static const unsigned kRangeCharacterClass = 0xFFFFFFFE;
static const unsigned kRangeNegationFlag = 0x80000000; static const unsigned kRangeNegationFlag = 0x80000000;
struct Range { struct Range
{
unsigned start; // unsigned start; //
unsigned end; unsigned end;
SizeType next; SizeType next;
}; };
struct State { struct State
{
SizeType out; //!< Equals to kInvalid for matching state SizeType out; //!< Equals to kInvalid for matching state
SizeType out1; //!< Equals to non-kInvalid for split SizeType out1; //!< Equals to non-kInvalid for split
SizeType rangeStart; SizeType rangeStart;
unsigned codepoint; unsigned codepoint;
}; };
struct Frag { struct Frag
{
Frag(SizeType s, SizeType o, SizeType m) : start(s), out(o), minIndex(m) {} Frag(SizeType s, SizeType o, SizeType m) : start(s), out(o), minIndex(m) {}
SizeType start; SizeType start;
SizeType out; //!< link-list of all output states SizeType out; //!< link-list of all output states
@ -158,49 +171,67 @@ private:
}; };
template <typename SourceStream> template <typename SourceStream>
class DecodedStream { class DecodedStream
{
public: public:
DecodedStream(SourceStream& ss) : ss_(ss), codepoint_() { Decode(); } DecodedStream(SourceStream & ss) : ss_(ss), codepoint_()
unsigned Peek() { return codepoint_; } {
unsigned Take() { Decode();
}
unsigned Peek()
{
return codepoint_;
}
unsigned Take()
{
unsigned c = codepoint_; unsigned c = codepoint_;
if(c) // No further decoding when '\0' if(c) // No further decoding when '\0'
{
Decode(); Decode();
}
return c; return c;
} }
private: private:
void Decode() { void Decode()
{
if(!Encoding::Decode(ss_, &codepoint_)) if(!Encoding::Decode(ss_, &codepoint_))
{
codepoint_ = 0; codepoint_ = 0;
} }
}
SourceStream & ss_; SourceStream & ss_;
unsigned codepoint_; unsigned codepoint_;
}; };
State& GetState(SizeType index) { State & GetState(SizeType index)
{
RAPIDJSON_ASSERT(index < stateCount_); RAPIDJSON_ASSERT(index < stateCount_);
return states_.template Bottom<State>()[index]; return states_.template Bottom<State>()[index];
} }
const State& GetState(SizeType index) const { const State & GetState(SizeType index) const
{
RAPIDJSON_ASSERT(index < stateCount_); RAPIDJSON_ASSERT(index < stateCount_);
return states_.template Bottom<State>()[index]; return states_.template Bottom<State>()[index];
} }
Range& GetRange(SizeType index) { Range & GetRange(SizeType index)
{
RAPIDJSON_ASSERT(index < rangeCount_); RAPIDJSON_ASSERT(index < rangeCount_);
return ranges_.template Bottom<Range>()[index]; return ranges_.template Bottom<Range>()[index];
} }
const Range& GetRange(SizeType index) const { const Range & GetRange(SizeType index) const
{
RAPIDJSON_ASSERT(index < rangeCount_); RAPIDJSON_ASSERT(index < rangeCount_);
return ranges_.template Bottom<Range>()[index]; return ranges_.template Bottom<Range>()[index];
} }
template <typename InputStream> template <typename InputStream>
void Parse(DecodedStream<InputStream>& ds) { void Parse(DecodedStream<InputStream> & ds)
{
Allocator allocator; Allocator allocator;
Stack<Allocator> operandStack(&allocator, 256); // Frag Stack<Allocator> operandStack(&allocator, 256); // Frag
Stack<Allocator> operatorStack(&allocator, 256); // Operator Stack<Allocator> operatorStack(&allocator, 256); // Operator
@ -209,8 +240,10 @@ private:
*atomCountStack.template Push<unsigned>() = 0; *atomCountStack.template Push<unsigned>() = 0;
unsigned codepoint; unsigned codepoint;
while (ds.Peek() != 0) { while(ds.Peek() != 0)
switch (codepoint = ds.Take()) { {
switch(codepoint = ds.Take())
{
case '^': case '^':
anchorBegin_ = true; anchorBegin_ = true;
break; break;
@ -222,7 +255,9 @@ private:
case '|': case '|':
while(!operatorStack.Empty() && *operatorStack.template Top<Operator>() < kAlternation) while(!operatorStack.Empty() && *operatorStack.template Top<Operator>() < kAlternation)
if(!Eval(operandStack, *operatorStack.template Pop<Operator>(1))) if(!Eval(operandStack, *operatorStack.template Pop<Operator>(1)))
{
return; return;
}
*operatorStack.template Push<Operator>() = kAlternation; *operatorStack.template Push<Operator>() = kAlternation;
*atomCountStack.template Top<unsigned>() = 0; *atomCountStack.template Top<unsigned>() = 0;
break; break;
@ -235,9 +270,13 @@ private:
case ')': case ')':
while(!operatorStack.Empty() && *operatorStack.template Top<Operator>() != kLeftParenthesis) while(!operatorStack.Empty() && *operatorStack.template Top<Operator>() != kLeftParenthesis)
if(!Eval(operandStack, *operatorStack.template Pop<Operator>(1))) if(!Eval(operandStack, *operatorStack.template Pop<Operator>(1)))
{
return; return;
}
if(operatorStack.Empty()) if(operatorStack.Empty())
{
return; return;
}
operatorStack.template Pop<Operator>(1); operatorStack.template Pop<Operator>(1);
atomCountStack.template Pop<unsigned>(1); atomCountStack.template Pop<unsigned>(1);
ImplicitConcatenation(atomCountStack, operatorStack); ImplicitConcatenation(atomCountStack, operatorStack);
@ -245,37 +284,54 @@ private:
case '?': case '?':
if(!Eval(operandStack, kZeroOrOne)) if(!Eval(operandStack, kZeroOrOne))
{
return; return;
}
break; break;
case '*': case '*':
if(!Eval(operandStack, kZeroOrMore)) if(!Eval(operandStack, kZeroOrMore))
{
return; return;
}
break; break;
case '+': case '+':
if(!Eval(operandStack, kOneOrMore)) if(!Eval(operandStack, kOneOrMore))
{
return; return;
}
break; break;
case '{': case '{':
{ {
unsigned n, m; unsigned n, m;
if(!ParseUnsigned(ds, &n)) if(!ParseUnsigned(ds, &n))
return; {
if (ds.Peek() == ',') {
ds.Take();
if (ds.Peek() == '}')
m = kInfinityQuantifier;
else if (!ParseUnsigned(ds, &m) || m < n)
return; return;
} }
if(ds.Peek() == ',')
{
ds.Take();
if(ds.Peek() == '}')
{
m = kInfinityQuantifier;
}
else if(!ParseUnsigned(ds, &m) || m < n)
{
return;
}
}
else else
{
m = n; m = n;
}
if(!EvalQuantifier(operandStack, n, m) || ds.Peek() != '}') if(!EvalQuantifier(operandStack, n, m) || ds.Peek() != '}')
{
return; return;
}
ds.Take(); ds.Take();
} }
break; break;
@ -289,7 +345,9 @@ private:
{ {
SizeType range; SizeType range;
if(!ParseRange(ds, &range)) if(!ParseRange(ds, &range))
{
return; return;
}
SizeType s = NewState(kRegexInvalidState, kRegexInvalidState, kRangeCharacterClass); SizeType s = NewState(kRegexInvalidState, kRegexInvalidState, kRangeCharacterClass);
GetState(s).rangeStart = range; GetState(s).rangeStart = range;
*operandStack.template Push<Frag>() = Frag(s, s, s); *operandStack.template Push<Frag>() = Frag(s, s, s);
@ -299,7 +357,9 @@ private:
case '\\': // Escape character case '\\': // Escape character
if(!CharacterEscape(ds, &codepoint)) if(!CharacterEscape(ds, &codepoint))
{
return; // Unsupported escape character return; // Unsupported escape character
}
// fall through to default // fall through to default
default: // Pattern character default: // Pattern character
@ -310,17 +370,21 @@ private:
while(!operatorStack.Empty()) while(!operatorStack.Empty())
if(!Eval(operandStack, *operatorStack.template Pop<Operator>(1))) if(!Eval(operandStack, *operatorStack.template Pop<Operator>(1)))
{
return; return;
}
// Link the operand to matching state. // Link the operand to matching state.
if (operandStack.GetSize() == sizeof(Frag)) { if(operandStack.GetSize() == sizeof(Frag))
{
Frag* e = operandStack.template Pop<Frag>(1); Frag* e = operandStack.template Pop<Frag>(1);
Patch(e->out, NewState(kRegexInvalidState, kRegexInvalidState, 0)); Patch(e->out, NewState(kRegexInvalidState, kRegexInvalidState, 0));
root_ = e->start; root_ = e->start;
#if RAPIDJSON_REGEX_VERBOSE #if RAPIDJSON_REGEX_VERBOSE
printf("root: %d\n", root_); printf("root: %d\n", root_);
for (SizeType i = 0; i < stateCount_ ; i++) { for(SizeType i = 0; i < stateCount_ ; i++)
{
State & s = GetState(i); State & s = GetState(i);
printf("[%2d] out: %2d out1: %2d c: '%c'\n", i, s.out, s.out1, (char)s.codepoint); printf("[%2d] out: %2d out1: %2d c: '%c'\n", i, s.out, s.out1, (char)s.codepoint);
} }
@ -330,14 +394,16 @@ private:
// Preallocate buffer for SearchWithAnchoring() // Preallocate buffer for SearchWithAnchoring()
RAPIDJSON_ASSERT(stateSet_ == 0); RAPIDJSON_ASSERT(stateSet_ == 0);
if (stateCount_ > 0) { if(stateCount_ > 0)
{
stateSet_ = static_cast<unsigned*>(states_.GetAllocator().Malloc(GetStateSetSize())); stateSet_ = static_cast<unsigned*>(states_.GetAllocator().Malloc(GetStateSetSize()));
state0_.template Reserve<SizeType>(stateCount_); state0_.template Reserve<SizeType>(stateCount_);
state1_.template Reserve<SizeType>(stateCount_); state1_.template Reserve<SizeType>(stateCount_);
} }
} }
SizeType NewState(SizeType out, SizeType out1, unsigned codepoint) { SizeType NewState(SizeType out, SizeType out1, unsigned codepoint)
{
State* s = states_.template Push<State>(); State* s = states_.template Push<State>();
s->out = out; s->out = out;
s->out1 = out1; s->out1 = out1;
@ -346,34 +412,45 @@ private:
return stateCount_++; return stateCount_++;
} }
void PushOperand(Stack<Allocator>& operandStack, unsigned codepoint) { void PushOperand(Stack<Allocator> & operandStack, unsigned codepoint)
{
SizeType s = NewState(kRegexInvalidState, kRegexInvalidState, codepoint); SizeType s = NewState(kRegexInvalidState, kRegexInvalidState, codepoint);
*operandStack.template Push<Frag>() = Frag(s, s, s); *operandStack.template Push<Frag>() = Frag(s, s, s);
} }
void ImplicitConcatenation(Stack<Allocator>& atomCountStack, Stack<Allocator>& operatorStack) { void ImplicitConcatenation(Stack<Allocator> & atomCountStack, Stack<Allocator> & operatorStack)
{
if(*atomCountStack.template Top<unsigned>()) if(*atomCountStack.template Top<unsigned>())
{
*operatorStack.template Push<Operator>() = kConcatenation; *operatorStack.template Push<Operator>() = kConcatenation;
}
(*atomCountStack.template Top<unsigned>())++; (*atomCountStack.template Top<unsigned>())++;
} }
SizeType Append(SizeType l1, SizeType l2) { SizeType Append(SizeType l1, SizeType l2)
{
SizeType old = l1; SizeType old = l1;
while(GetState(l1).out != kRegexInvalidState) while(GetState(l1).out != kRegexInvalidState)
{
l1 = GetState(l1).out; l1 = GetState(l1).out;
}
GetState(l1).out = l2; GetState(l1).out = l2;
return old; return old;
} }
void Patch(SizeType l, SizeType s) { void Patch(SizeType l, SizeType s)
for (SizeType next; l != kRegexInvalidState; l = next) { {
for(SizeType next; l != kRegexInvalidState; l = next)
{
next = GetState(l).out; next = GetState(l).out;
GetState(l).out = s; GetState(l).out = s;
} }
} }
bool Eval(Stack<Allocator>& operandStack, Operator op) { bool Eval(Stack<Allocator> & operandStack, Operator op)
switch (op) { {
switch(op)
{
case kConcatenation: case kConcatenation:
RAPIDJSON_ASSERT(operandStack.GetSize() >= sizeof(Frag) * 2); RAPIDJSON_ASSERT(operandStack.GetSize() >= sizeof(Frag) * 2);
{ {
@ -385,7 +462,8 @@ private:
return true; return true;
case kAlternation: case kAlternation:
if (operandStack.GetSize() >= sizeof(Frag) * 2) { if(operandStack.GetSize() >= sizeof(Frag) * 2)
{
Frag e2 = *operandStack.template Pop<Frag>(1); Frag e2 = *operandStack.template Pop<Frag>(1);
Frag e1 = *operandStack.template Pop<Frag>(1); Frag e1 = *operandStack.template Pop<Frag>(1);
SizeType s = NewState(e1.start, e2.start, 0); SizeType s = NewState(e1.start, e2.start, 0);
@ -395,7 +473,8 @@ private:
return false; return false;
case kZeroOrOne: case kZeroOrOne:
if (operandStack.GetSize() >= sizeof(Frag)) { if(operandStack.GetSize() >= sizeof(Frag))
{
Frag e = *operandStack.template Pop<Frag>(1); Frag e = *operandStack.template Pop<Frag>(1);
SizeType s = NewState(kRegexInvalidState, e.start, 0); SizeType s = NewState(kRegexInvalidState, e.start, 0);
*operandStack.template Push<Frag>() = Frag(s, Append(e.out, s), e.minIndex); *operandStack.template Push<Frag>() = Frag(s, Append(e.out, s), e.minIndex);
@ -404,7 +483,8 @@ private:
return false; return false;
case kZeroOrMore: case kZeroOrMore:
if (operandStack.GetSize() >= sizeof(Frag)) { if(operandStack.GetSize() >= sizeof(Frag))
{
Frag e = *operandStack.template Pop<Frag>(1); Frag e = *operandStack.template Pop<Frag>(1);
SizeType s = NewState(kRegexInvalidState, e.start, 0); SizeType s = NewState(kRegexInvalidState, e.start, 0);
Patch(e.out, s); Patch(e.out, s);
@ -415,7 +495,8 @@ private:
default: default:
RAPIDJSON_ASSERT(op == kOneOrMore); RAPIDJSON_ASSERT(op == kOneOrMore);
if (operandStack.GetSize() >= sizeof(Frag)) { if(operandStack.GetSize() >= sizeof(Frag))
{
Frag e = *operandStack.template Pop<Frag>(1); Frag e = *operandStack.template Pop<Frag>(1);
SizeType s = NewState(kRegexInvalidState, e.start, 0); SizeType s = NewState(kRegexInvalidState, e.start, 0);
Patch(e.out, s); Patch(e.out, s);
@ -426,70 +507,108 @@ private:
} }
} }
bool EvalQuantifier(Stack<Allocator>& operandStack, unsigned n, unsigned m) { bool EvalQuantifier(Stack<Allocator> & operandStack, unsigned n, unsigned m)
{
RAPIDJSON_ASSERT(n <= m); RAPIDJSON_ASSERT(n <= m);
RAPIDJSON_ASSERT(operandStack.GetSize() >= sizeof(Frag)); RAPIDJSON_ASSERT(operandStack.GetSize() >= sizeof(Frag));
if (n == 0) { if(n == 0)
{
if(m == 0) // a{0} not support if(m == 0) // a{0} not support
{
return false; return false;
}
else if(m == kInfinityQuantifier) else if(m == kInfinityQuantifier)
Eval(operandStack, kZeroOrMore); // a{0,} -> a* {
else { Eval(operandStack, kZeroOrMore);
} // a{0,} -> a*
else
{
Eval(operandStack, kZeroOrOne); // a{0,5} -> a? Eval(operandStack, kZeroOrOne); // a{0,5} -> a?
for(unsigned i = 0; i < m - 1; i++) for(unsigned i = 0; i < m - 1; i++)
CloneTopOperand(operandStack); // a{0,5} -> a? a? a? a? a? {
CloneTopOperand(operandStack);
} // a{0,5} -> a? a? a? a? a?
for(unsigned i = 0; i < m - 1; i++) for(unsigned i = 0; i < m - 1; i++)
Eval(operandStack, kConcatenation); // a{0,5} -> a?a?a?a?a? {
Eval(operandStack, kConcatenation);
} // a{0,5} -> a?a?a?a?a?
} }
return true; return true;
} }
for(unsigned i = 0; i < n - 1; i++) // a{3} -> a a a for(unsigned i = 0; i < n - 1; i++) // a{3} -> a a a
{
CloneTopOperand(operandStack); CloneTopOperand(operandStack);
}
if(m == kInfinityQuantifier) if(m == kInfinityQuantifier)
Eval(operandStack, kOneOrMore); // a{3,} -> a a a+ {
else if (m > n) { Eval(operandStack, kOneOrMore);
} // a{3,} -> a a a+
else if(m > n)
{
CloneTopOperand(operandStack); // a{3,5} -> a a a a CloneTopOperand(operandStack); // a{3,5} -> a a a a
Eval(operandStack, kZeroOrOne); // a{3,5} -> a a a a? Eval(operandStack, kZeroOrOne); // a{3,5} -> a a a a?
for(unsigned i = n; i < m - 1; i++) for(unsigned i = n; i < m - 1; i++)
CloneTopOperand(operandStack); // a{3,5} -> a a a a? a? {
CloneTopOperand(operandStack);
} // a{3,5} -> a a a a? a?
for(unsigned i = n; i < m; i++) for(unsigned i = n; i < m; i++)
Eval(operandStack, kConcatenation); // a{3,5} -> a a aa?a? {
Eval(operandStack, kConcatenation);
} // a{3,5} -> a a aa?a?
} }
for(unsigned i = 0; i < n - 1; i++) for(unsigned i = 0; i < n - 1; i++)
Eval(operandStack, kConcatenation); // a{3} -> aaa, a{3,} -> aaa+, a{3.5} -> aaaa?a? {
Eval(operandStack, kConcatenation);
} // a{3} -> aaa, a{3,} -> aaa+, a{3.5} -> aaaa?a?
return true; return true;
} }
static SizeType Min(SizeType a, SizeType b) { return a < b ? a : b; } static SizeType Min(SizeType a, SizeType b)
{
return a < b ? a : b;
}
void CloneTopOperand(Stack<Allocator>& operandStack) { void CloneTopOperand(Stack<Allocator> & operandStack)
{
const Frag src = *operandStack.template Top<Frag>(); // Copy constructor to prevent invalidation const Frag src = *operandStack.template Top<Frag>(); // Copy constructor to prevent invalidation
SizeType count = stateCount_ - src.minIndex; // Assumes top operand contains states in [src->minIndex, stateCount_) SizeType count = stateCount_ -
src.minIndex; // Assumes top operand contains states in [src->minIndex, stateCount_)
State* s = states_.template Push<State>(count); State* s = states_.template Push<State>(count);
memcpy(s, &GetState(src.minIndex), count * sizeof(State)); memcpy(s, &GetState(src.minIndex), count * sizeof(State));
for (SizeType j = 0; j < count; j++) { for(SizeType j = 0; j < count; j++)
{
if(s[j].out != kRegexInvalidState) if(s[j].out != kRegexInvalidState)
{
s[j].out += count; s[j].out += count;
}
if(s[j].out1 != kRegexInvalidState) if(s[j].out1 != kRegexInvalidState)
{
s[j].out1 += count; s[j].out1 += count;
} }
}
*operandStack.template Push<Frag>() = Frag(src.start + count, src.out + count, src.minIndex + count); *operandStack.template Push<Frag>() = Frag(src.start + count, src.out + count, src.minIndex + count);
stateCount_ += count; stateCount_ += count;
} }
template <typename InputStream> template <typename InputStream>
bool ParseUnsigned(DecodedStream<InputStream>& ds, unsigned* u) { bool ParseUnsigned(DecodedStream<InputStream> & ds, unsigned* u)
{
unsigned r = 0; unsigned r = 0;
if(ds.Peek() < '0' || ds.Peek() > '9') if(ds.Peek() < '0' || ds.Peek() > '9')
{
return false; return false;
while (ds.Peek() >= '0' && ds.Peek() <= '9') { }
while(ds.Peek() >= '0' && ds.Peek() <= '9')
{
if(r >= 429496729 && ds.Peek() > '5') // 2^32 - 1 = 4294967295 if(r >= 429496729 && ds.Peek() > '5') // 2^32 - 1 = 4294967295
{
return false; // overflow return false; // overflow
}
r = r * 10 + (ds.Take() - '0'); r = r * 10 + (ds.Take() - '0');
} }
*u = r; *u = r;
@ -497,49 +616,64 @@ private:
} }
template <typename InputStream> template <typename InputStream>
bool ParseRange(DecodedStream<InputStream>& ds, SizeType* range) { bool ParseRange(DecodedStream<InputStream> & ds, SizeType* range)
{
bool isBegin = true; bool isBegin = true;
bool negate = false; bool negate = false;
int step = 0; int step = 0;
SizeType start = kRegexInvalidRange; SizeType start = kRegexInvalidRange;
SizeType current = kRegexInvalidRange; SizeType current = kRegexInvalidRange;
unsigned codepoint; unsigned codepoint;
while ((codepoint = ds.Take()) != 0) { while((codepoint = ds.Take()) != 0)
if (isBegin) { {
if(isBegin)
{
isBegin = false; isBegin = false;
if (codepoint == '^') { if(codepoint == '^')
{
negate = true; negate = true;
continue; continue;
} }
} }
switch (codepoint) { switch(codepoint)
{
case ']': case ']':
if(start == kRegexInvalidRange) if(start == kRegexInvalidRange)
{
return false; // Error: nothing inside [] return false; // Error: nothing inside []
if (step == 2) { // Add trailing '-' }
if(step == 2) // Add trailing '-'
{
SizeType r = NewRange('-'); SizeType r = NewRange('-');
RAPIDJSON_ASSERT(current != kRegexInvalidRange); RAPIDJSON_ASSERT(current != kRegexInvalidRange);
GetRange(current).next = r; GetRange(current).next = r;
} }
if(negate) if(negate)
{
GetRange(start).start |= kRangeNegationFlag; GetRange(start).start |= kRangeNegationFlag;
}
*range = start; *range = start;
return true; return true;
case '\\': case '\\':
if (ds.Peek() == 'b') { if(ds.Peek() == 'b')
{
ds.Take(); ds.Take();
codepoint = 0x0008; // Escape backspace character codepoint = 0x0008; // Escape backspace character
} }
else if(!CharacterEscape(ds, &codepoint)) else if(!CharacterEscape(ds, &codepoint))
{
return false; return false;
}
// fall through to default // fall through to default
default: default:
switch (step) { switch(step)
{
case 1: case 1:
if (codepoint == '-') { if(codepoint == '-')
{
step++; step++;
break; break;
} }
@ -549,9 +683,13 @@ private:
{ {
SizeType r = NewRange(codepoint); SizeType r = NewRange(codepoint);
if(current != kRegexInvalidRange) if(current != kRegexInvalidRange)
{
GetRange(current).next = r; GetRange(current).next = r;
}
if(start == kRegexInvalidRange) if(start == kRegexInvalidRange)
{
start = r; start = r;
}
current = r; current = r;
} }
step = 1; step = 1;
@ -567,7 +705,8 @@ private:
return false; return false;
} }
SizeType NewRange(unsigned codepoint) { SizeType NewRange(unsigned codepoint)
{
Range* r = ranges_.template Push<Range>(); Range* r = ranges_.template Push<Range>();
r->start = r->end = codepoint; r->start = r->end = codepoint;
r->next = kRegexInvalidRange; r->next = kRegexInvalidRange;
@ -575,9 +714,11 @@ private:
} }
template <typename InputStream> template <typename InputStream>
bool CharacterEscape(DecodedStream<InputStream>& ds, unsigned* escapedCodepoint) { bool CharacterEscape(DecodedStream<InputStream> & ds, unsigned* escapedCodepoint)
{
unsigned codepoint; unsigned codepoint;
switch (codepoint = ds.Take()) { switch(codepoint = ds.Take())
{
case '^': case '^':
case '$': case '$':
case '|': case '|':
@ -592,19 +733,31 @@ private:
case '{': case '{':
case '}': case '}':
case '\\': case '\\':
*escapedCodepoint = codepoint; return true; *escapedCodepoint = codepoint;
case 'f': *escapedCodepoint = 0x000C; return true; return true;
case 'n': *escapedCodepoint = 0x000A; return true; case 'f':
case 'r': *escapedCodepoint = 0x000D; return true; *escapedCodepoint = 0x000C;
case 't': *escapedCodepoint = 0x0009; return true; return true;
case 'v': *escapedCodepoint = 0x000B; return true; case 'n':
*escapedCodepoint = 0x000A;
return true;
case 'r':
*escapedCodepoint = 0x000D;
return true;
case 't':
*escapedCodepoint = 0x0009;
return true;
case 'v':
*escapedCodepoint = 0x000B;
return true;
default: default:
return false; // Unsupported escape character return false; // Unsupported escape character
} }
} }
template <typename InputStream> template <typename InputStream>
bool SearchWithAnchoring(InputStream& is, bool anchorBegin, bool anchorEnd) const { bool SearchWithAnchoring(InputStream & is, bool anchorBegin, bool anchorEnd) const
{
RAPIDJSON_ASSERT(IsValid()); RAPIDJSON_ASSERT(IsValid());
DecodedStream<InputStream> ds(is); DecodedStream<InputStream> ds(is);
@ -615,11 +768,13 @@ private:
bool matched = AddState(*current, root_); bool matched = AddState(*current, root_);
unsigned codepoint; unsigned codepoint;
while (!current->Empty() && (codepoint = ds.Take()) != 0) { while(!current->Empty() && (codepoint = ds.Take()) != 0)
{
std::memset(stateSet_, 0, stateSetSize); std::memset(stateSet_, 0, stateSetSize);
next->Clear(); next->Clear();
matched = false; matched = false;
for (const SizeType* s = current->template Bottom<SizeType>(); s != current->template End<SizeType>(); ++s) { for(const SizeType* s = current->template Bottom<SizeType>(); s != current->template End<SizeType>(); ++s)
{
const State & sr = GetState(*s); const State & sr = GetState(*s);
if(sr.codepoint == codepoint || if(sr.codepoint == codepoint ||
sr.codepoint == kAnyCharacterClass || sr.codepoint == kAnyCharacterClass ||
@ -627,43 +782,56 @@ private:
{ {
matched = AddState(*next, sr.out) || matched; matched = AddState(*next, sr.out) || matched;
if(!anchorEnd && matched) if(!anchorEnd && matched)
{
return true; return true;
} }
}
if(!anchorBegin) if(!anchorBegin)
{
AddState(*next, root_); AddState(*next, root_);
} }
}
internal::Swap(current, next); internal::Swap(current, next);
} }
return matched; return matched;
} }
size_t GetStateSetSize() const { size_t GetStateSetSize() const
{
return (stateCount_ + 31) / 32 * 4; return (stateCount_ + 31) / 32 * 4;
} }
// Return whether the added states is a match state // Return whether the added states is a match state
bool AddState(Stack<Allocator>& l, SizeType index) const { bool AddState(Stack<Allocator> & l, SizeType index) const
{
RAPIDJSON_ASSERT(index != kRegexInvalidState); RAPIDJSON_ASSERT(index != kRegexInvalidState);
const State & s = GetState(index); const State & s = GetState(index);
if (s.out1 != kRegexInvalidState) { // Split if(s.out1 != kRegexInvalidState) // Split
{
bool matched = AddState(l, s.out); bool matched = AddState(l, s.out);
return AddState(l, s.out1) || matched; return AddState(l, s.out1) || matched;
} }
else if (!(stateSet_[index >> 5] & (1 << (index & 31)))) { else if(!(stateSet_[index >> 5] & (1 << (index & 31))))
{
stateSet_[index >> 5] |= (1 << (index & 31)); stateSet_[index >> 5] |= (1 << (index & 31));
*l.template PushUnsafe<SizeType>() = index; *l.template PushUnsafe<SizeType>() = index;
} }
return s.out == kRegexInvalidState; // by using PushUnsafe() above, we can ensure s is not validated due to reallocation. return s.out ==
kRegexInvalidState; // by using PushUnsafe() above, we can ensure s is not validated due to reallocation.
} }
bool MatchRange(SizeType rangeIndex, unsigned codepoint) const { bool MatchRange(SizeType rangeIndex, unsigned codepoint) const
{
bool yes = (GetRange(rangeIndex).start & kRangeNegationFlag) == 0; bool yes = (GetRange(rangeIndex).start & kRangeNegationFlag) == 0;
while (rangeIndex != kRegexInvalidRange) { while(rangeIndex != kRegexInvalidRange)
{
const Range & r = GetRange(rangeIndex); const Range & r = GetRange(rangeIndex);
if(codepoint >= (r.start & ~kRangeNegationFlag) && codepoint <= r.end) if(codepoint >= (r.start & ~kRangeNegationFlag) && codepoint <= r.end)
{
return yes; return yes;
}
rangeIndex = r.next; rangeIndex = r.next;
} }
return !yes; return !yes;

View file

@ -24,7 +24,8 @@ RAPIDJSON_DIAG_OFF(c++98-compat)
#endif #endif
RAPIDJSON_NAMESPACE_BEGIN RAPIDJSON_NAMESPACE_BEGIN
namespace internal { namespace internal
{
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// Stack // Stack
@ -33,11 +34,14 @@ namespace internal {
/*! \tparam Allocator Allocator for allocating stack memory. /*! \tparam Allocator Allocator for allocating stack memory.
*/ */
template <typename Allocator> template <typename Allocator>
class Stack { class Stack
{
public: public:
// Optimization note: Do not allocate memory for stack_ in constructor. // Optimization note: Do not allocate memory for stack_ in constructor.
// Do it lazily when first Push() -> Expand() -> Resize(). // Do it lazily when first Push() -> Expand() -> Resize().
Stack(Allocator* allocator, size_t stackCapacity) : allocator_(allocator), ownAllocator_(0), stack_(0), stackTop_(0), stackEnd_(0), initialCapacity_(stackCapacity) { Stack(Allocator* allocator, size_t stackCapacity) : allocator_(allocator), ownAllocator_(0), stack_(0),
stackTop_(0), stackEnd_(0), initialCapacity_(stackCapacity)
{
} }
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS #if RAPIDJSON_HAS_CXX11_RVALUE_REFS
@ -58,12 +62,14 @@ public:
} }
#endif #endif
~Stack() { ~Stack()
{
Destroy(); Destroy();
} }
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS #if RAPIDJSON_HAS_CXX11_RVALUE_REFS
Stack& operator=(Stack&& rhs) { Stack & operator=(Stack && rhs)
{
if(&rhs != this) if(&rhs != this)
{ {
Destroy(); Destroy();
@ -86,7 +92,8 @@ public:
} }
#endif #endif
void Swap(Stack& rhs) RAPIDJSON_NOEXCEPT { void Swap(Stack & rhs) RAPIDJSON_NOEXCEPT
{
internal::Swap(allocator_, rhs.allocator_); internal::Swap(allocator_, rhs.allocator_);
internal::Swap(ownAllocator_, rhs.ownAllocator_); internal::Swap(ownAllocator_, rhs.ownAllocator_);
internal::Swap(stack_, rhs.stack_); internal::Swap(stack_, rhs.stack_);
@ -95,10 +102,15 @@ public:
internal::Swap(initialCapacity_, rhs.initialCapacity_); internal::Swap(initialCapacity_, rhs.initialCapacity_);
} }
void Clear() { stackTop_ = stack_; } void Clear()
{
stackTop_ = stack_;
}
void ShrinkToFit() { void ShrinkToFit()
if (Empty()) { {
if(Empty())
{
// If the stack is empty, completely deallocate the memory. // If the stack is empty, completely deallocate the memory.
Allocator::Free(stack_); Allocator::Free(stack_);
stack_ = 0; stack_ = 0;
@ -106,26 +118,33 @@ public:
stackEnd_ = 0; stackEnd_ = 0;
} }
else else
{
Resize(GetSize()); Resize(GetSize());
} }
}
// Optimization note: try to minimize the size of this function for force inline. // Optimization note: try to minimize the size of this function for force inline.
// Expansion is run very infrequently, so it is moved to another (probably non-inline) function. // Expansion is run very infrequently, so it is moved to another (probably non-inline) function.
template<typename T> template<typename T>
RAPIDJSON_FORCEINLINE void Reserve(size_t count = 1) { RAPIDJSON_FORCEINLINE void Reserve(size_t count = 1)
{
// Expand the stack if needed // Expand the stack if needed
if(RAPIDJSON_UNLIKELY(stackTop_ + sizeof(T) * count > stackEnd_)) if(RAPIDJSON_UNLIKELY(stackTop_ + sizeof(T) * count > stackEnd_))
{
Expand<T>(count); Expand<T>(count);
} }
}
template<typename T> template<typename T>
RAPIDJSON_FORCEINLINE T* Push(size_t count = 1) { RAPIDJSON_FORCEINLINE T* Push(size_t count = 1)
{
Reserve<T>(count); Reserve<T>(count);
return PushUnsafe<T>(count); return PushUnsafe<T>(count);
} }
template<typename T> template<typename T>
RAPIDJSON_FORCEINLINE T* PushUnsafe(size_t count = 1) { RAPIDJSON_FORCEINLINE T* PushUnsafe(size_t count = 1)
{
RAPIDJSON_ASSERT(stackTop_ + sizeof(T) * count <= stackEnd_); RAPIDJSON_ASSERT(stackTop_ + sizeof(T) * count <= stackEnd_);
T* ret = reinterpret_cast<T*>(stackTop_); T* ret = reinterpret_cast<T*>(stackTop_);
stackTop_ += sizeof(T) * count; stackTop_ += sizeof(T) * count;
@ -133,77 +152,113 @@ public:
} }
template<typename T> template<typename T>
T* Pop(size_t count) { T* Pop(size_t count)
{
RAPIDJSON_ASSERT(GetSize() >= count * sizeof(T)); RAPIDJSON_ASSERT(GetSize() >= count * sizeof(T));
stackTop_ -= count * sizeof(T); stackTop_ -= count * sizeof(T);
return reinterpret_cast<T*>(stackTop_); return reinterpret_cast<T*>(stackTop_);
} }
template<typename T> template<typename T>
T* Top() { T* Top()
{
RAPIDJSON_ASSERT(GetSize() >= sizeof(T)); RAPIDJSON_ASSERT(GetSize() >= sizeof(T));
return reinterpret_cast<T*>(stackTop_ - sizeof(T)); return reinterpret_cast<T*>(stackTop_ - sizeof(T));
} }
template<typename T> template<typename T>
const T* Top() const { const T* Top() const
{
RAPIDJSON_ASSERT(GetSize() >= sizeof(T)); RAPIDJSON_ASSERT(GetSize() >= sizeof(T));
return reinterpret_cast<T*>(stackTop_ - sizeof(T)); return reinterpret_cast<T*>(stackTop_ - sizeof(T));
} }
template<typename T> template<typename T>
T* End() { return reinterpret_cast<T*>(stackTop_); } T* End()
{
return reinterpret_cast<T*>(stackTop_);
}
template<typename T> template<typename T>
const T* End() const { return reinterpret_cast<T*>(stackTop_); } const T* End() const
{
return reinterpret_cast<T*>(stackTop_);
}
template<typename T> template<typename T>
T* Bottom() { return reinterpret_cast<T*>(stack_); } T* Bottom()
{
return reinterpret_cast<T*>(stack_);
}
template<typename T> template<typename T>
const T* Bottom() const { return reinterpret_cast<T*>(stack_); } const T* Bottom() const
{
return reinterpret_cast<T*>(stack_);
}
bool HasAllocator() const { bool HasAllocator() const
{
return allocator_ != 0; return allocator_ != 0;
} }
Allocator& GetAllocator() { Allocator & GetAllocator()
{
RAPIDJSON_ASSERT(allocator_); RAPIDJSON_ASSERT(allocator_);
return *allocator_; return *allocator_;
} }
bool Empty() const { return stackTop_ == stack_; } bool Empty() const
size_t GetSize() const { return static_cast<size_t>(stackTop_ - stack_); } {
size_t GetCapacity() const { return static_cast<size_t>(stackEnd_ - stack_); } return stackTop_ == stack_;
}
size_t GetSize() const
{
return static_cast<size_t>(stackTop_ - stack_);
}
size_t GetCapacity() const
{
return static_cast<size_t>(stackEnd_ - stack_);
}
private: private:
template<typename T> template<typename T>
void Expand(size_t count) { void Expand(size_t count)
{
// Only expand the capacity if the current stack exists. Otherwise just create a stack with initial capacity. // Only expand the capacity if the current stack exists. Otherwise just create a stack with initial capacity.
size_t newCapacity; size_t newCapacity;
if (stack_ == 0) { if(stack_ == 0)
{
if(!allocator_) if(!allocator_)
{
ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator()); ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator());
}
newCapacity = initialCapacity_; newCapacity = initialCapacity_;
} else { }
else
{
newCapacity = GetCapacity(); newCapacity = GetCapacity();
newCapacity += (newCapacity + 1) / 2; newCapacity += (newCapacity + 1) / 2;
} }
size_t newSize = GetSize() + sizeof(T) * count; size_t newSize = GetSize() + sizeof(T) * count;
if(newCapacity < newSize) if(newCapacity < newSize)
{
newCapacity = newSize; newCapacity = newSize;
}
Resize(newCapacity); Resize(newCapacity);
} }
void Resize(size_t newCapacity) { void Resize(size_t newCapacity)
{
const size_t size = GetSize(); // Backup the current size const size_t size = GetSize(); // Backup the current size
stack_ = static_cast<char*>(allocator_->Realloc(stack_, GetCapacity(), newCapacity)); stack_ = static_cast<char*>(allocator_->Realloc(stack_, GetCapacity(), newCapacity));
stackTop_ = stack_ + size; stackTop_ = stack_ + size;
stackEnd_ = stack_ + newCapacity; stackEnd_ = stack_ + newCapacity;
} }
void Destroy() { void Destroy()
{
Allocator::Free(stack_); Allocator::Free(stack_);
RAPIDJSON_DELETE(ownAllocator_); // Only delete if it is owned by the stack RAPIDJSON_DELETE(ownAllocator_); // Only delete if it is owned by the stack
} }

View file

@ -18,7 +18,8 @@
#include "../stream.h" #include "../stream.h"
RAPIDJSON_NAMESPACE_BEGIN RAPIDJSON_NAMESPACE_BEGIN
namespace internal { namespace internal
{
//! Custom strlen() which works on different character types. //! Custom strlen() which works on different character types.
/*! \tparam Ch Character type (e.g. char, wchar_t, short) /*! \tparam Ch Character type (e.g. char, wchar_t, short)
@ -27,22 +28,30 @@ namespace internal {
\note This has the same semantics as strlen(), the return value is not number of Unicode codepoints. \note This has the same semantics as strlen(), the return value is not number of Unicode codepoints.
*/ */
template <typename Ch> template <typename Ch>
inline SizeType StrLen(const Ch* s) { inline SizeType StrLen(const Ch* s)
{
const Ch* p = s; const Ch* p = s;
while (*p) ++p; while(*p)
{
++p;
}
return SizeType(p - s); return SizeType(p - s);
} }
//! Returns number of code points in a encoded string. //! Returns number of code points in a encoded string.
template<typename Encoding> template<typename Encoding>
bool CountStringCodePoint(const typename Encoding::Ch* s, SizeType length, SizeType* outCount) { bool CountStringCodePoint(const typename Encoding::Ch* s, SizeType length, SizeType* outCount)
{
GenericStringStream<Encoding> is(s); GenericStringStream<Encoding> is(s);
const typename Encoding::Ch* end = s + length; const typename Encoding::Ch* end = s + length;
SizeType count = 0; SizeType count = 0;
while (is.src_ < end) { while(is.src_ < end)
{
unsigned codepoint; unsigned codepoint;
if(!Encoding::Decode(is, &codepoint)) if(!Encoding::Decode(is, &codepoint))
{
return false; return false;
}
count++; count++;
} }
*outCount = count; *outCount = count;

View file

@ -21,37 +21,57 @@
#include "pow10.h" #include "pow10.h"
RAPIDJSON_NAMESPACE_BEGIN RAPIDJSON_NAMESPACE_BEGIN
namespace internal { namespace internal
{
inline double FastPath(double significand, int exp) { inline double FastPath(double significand, int exp)
{
if(exp < -308) if(exp < -308)
{
return 0.0; return 0.0;
}
else if(exp >= 0) else if(exp >= 0)
{
return significand * internal::Pow10(exp); return significand * internal::Pow10(exp);
}
else else
{
return significand / internal::Pow10(-exp); return significand / internal::Pow10(-exp);
} }
}
inline double StrtodNormalPrecision(double d, int p) { inline double StrtodNormalPrecision(double d, int p)
if (p < -308) { {
if(p < -308)
{
// Prevent expSum < -308, making Pow10(p) = 0 // Prevent expSum < -308, making Pow10(p) = 0
d = FastPath(d, -308); d = FastPath(d, -308);
d = FastPath(d, p + 308); d = FastPath(d, p + 308);
} }
else else
{
d = FastPath(d, p); d = FastPath(d, p);
}
return d; return d;
} }
template <typename T> template <typename T>
inline T Min3(T a, T b, T c) { inline T Min3(T a, T b, T c)
{
T m = a; T m = a;
if (m > b) m = b; if(m > b)
if (m > c) m = c; {
m = b;
}
if(m > c)
{
m = c;
}
return m; return m;
} }
inline int CheckWithinHalfULP(double b, const BigInteger& d, int dExp) { inline int CheckWithinHalfULP(double b, const BigInteger & d, int dExp)
{
const Double db(b); const Double db(b);
const uint64_t bInt = db.IntegerSignificand(); const uint64_t bInt = db.IntegerSignificand();
const int bExp = db.IntegerExponent(); const int bExp = db.IntegerExponent();
@ -60,11 +80,13 @@ inline int CheckWithinHalfULP(double b, const BigInteger& d, int dExp) {
int dS_Exp2 = 0, dS_Exp5 = 0, bS_Exp2 = 0, bS_Exp5 = 0, hS_Exp2 = 0, hS_Exp5 = 0; int dS_Exp2 = 0, dS_Exp5 = 0, bS_Exp2 = 0, bS_Exp5 = 0, hS_Exp2 = 0, hS_Exp5 = 0;
// Adjust for decimal exponent // Adjust for decimal exponent
if (dExp >= 0) { if(dExp >= 0)
{
dS_Exp2 += dExp; dS_Exp2 += dExp;
dS_Exp5 += dExp; dS_Exp5 += dExp;
} }
else { else
{
bS_Exp2 -= dExp; bS_Exp2 -= dExp;
bS_Exp5 -= dExp; bS_Exp5 -= dExp;
hS_Exp2 -= dExp; hS_Exp2 -= dExp;
@ -73,16 +95,22 @@ inline int CheckWithinHalfULP(double b, const BigInteger& d, int dExp) {
// Adjust for binary exponent // Adjust for binary exponent
if(bExp >= 0) if(bExp >= 0)
{
bS_Exp2 += bExp; bS_Exp2 += bExp;
else { }
else
{
dS_Exp2 -= bExp; dS_Exp2 -= bExp;
hS_Exp2 -= bExp; hS_Exp2 -= bExp;
} }
// Adjust for half ulp exponent // Adjust for half ulp exponent
if(hExp >= 0) if(hExp >= 0)
{
hS_Exp2 += hExp; hS_Exp2 += hExp;
else { }
else
{
dS_Exp2 -= hExp; dS_Exp2 -= hExp;
bS_Exp2 -= hExp; bS_Exp2 -= hExp;
} }
@ -108,36 +136,47 @@ inline int CheckWithinHalfULP(double b, const BigInteger& d, int dExp) {
return delta.Compare(hS); return delta.Compare(hS);
} }
inline bool StrtodFast(double d, int p, double* result) { inline bool StrtodFast(double d, int p, double* result)
{
// Use fast path for string-to-double conversion if possible // Use fast path for string-to-double conversion if possible
// see http://www.exploringbinary.com/fast-path-decimal-to-floating-point-conversion/ // see http://www.exploringbinary.com/fast-path-decimal-to-floating-point-conversion/
if (p > 22 && p < 22 + 16) { if(p > 22 && p < 22 + 16)
{
// Fast Path Cases In Disguise // Fast Path Cases In Disguise
d *= internal::Pow10(p - 22); d *= internal::Pow10(p - 22);
p = 22; p = 22;
} }
if (p >= -22 && p <= 22 && d <= 9007199254740991.0) { // 2^53 - 1 if(p >= -22 && p <= 22 && d <= 9007199254740991.0) // 2^53 - 1
{
*result = FastPath(d, p); *result = FastPath(d, p);
return true; return true;
} }
else else
{
return false; return false;
} }
}
// Compute an approximation and see if it is within 1/2 ULP // Compute an approximation and see if it is within 1/2 ULP
inline bool StrtodDiyFp(const char* decimals, size_t length, size_t decimalPosition, int exp, double* result) { inline bool StrtodDiyFp(const char* decimals, size_t length, size_t decimalPosition, int exp, double* result)
{
uint64_t significand = 0; uint64_t significand = 0;
size_t i = 0; // 2^64 - 1 = 18446744073709551615, 1844674407370955161 = 0x1999999999999999 size_t i = 0; // 2^64 - 1 = 18446744073709551615, 1844674407370955161 = 0x1999999999999999
for (; i < length; i++) { for(; i < length; i++)
{
if(significand > RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) || if(significand > RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) ||
(significand == RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) && decimals[i] > '5')) (significand == RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) && decimals[i] > '5'))
{
break; break;
}
significand = significand * 10u + static_cast<unsigned>(decimals[i] - '0'); significand = significand * 10u + static_cast<unsigned>(decimals[i] - '0');
} }
if(i < length && decimals[i] >= '5') // Rounding if(i < length && decimals[i] >= '5') // Rounding
{
significand++; significand++;
}
size_t remaining = length - i; size_t remaining = length - i;
const unsigned kUlpShift = 3; const unsigned kUlpShift = 3;
@ -152,8 +191,10 @@ inline bool StrtodDiyFp(const char* decimals, size_t length, size_t decimalPosit
int actualExp; int actualExp;
DiyFp cachedPower = GetCachedPower10(dExp, &actualExp); DiyFp cachedPower = GetCachedPower10(dExp, &actualExp);
if (actualExp != dExp) { if(actualExp != dExp)
static const DiyFp kPow10[] = { {
static const DiyFp kPow10[] =
{
DiyFp(RAPIDJSON_UINT64_C2(0xa0000000, 00000000), -60), // 10^1 DiyFp(RAPIDJSON_UINT64_C2(0xa0000000, 00000000), -60), // 10^1
DiyFp(RAPIDJSON_UINT64_C2(0xc8000000, 00000000), -57), // 10^2 DiyFp(RAPIDJSON_UINT64_C2(0xc8000000, 00000000), -57), // 10^2
DiyFp(RAPIDJSON_UINT64_C2(0xfa000000, 00000000), -54), // 10^3 DiyFp(RAPIDJSON_UINT64_C2(0xfa000000, 00000000), -54), // 10^3
@ -166,8 +207,10 @@ inline bool StrtodDiyFp(const char* decimals, size_t length, size_t decimalPosit
RAPIDJSON_ASSERT(adjustment >= 0 && adjustment < 7); RAPIDJSON_ASSERT(adjustment >= 0 && adjustment < 7);
v = v * kPow10[adjustment]; v = v * kPow10[adjustment];
if(length + static_cast<unsigned>(adjustment) > 19u) // has more digits than decimal digits in 64-bit if(length + static_cast<unsigned>(adjustment) > 19u) // has more digits than decimal digits in 64-bit
{
error += kUlp / 2; error += kUlp / 2;
} }
}
v = v * cachedPower; v = v * cachedPower;
@ -179,7 +222,8 @@ inline bool StrtodDiyFp(const char* decimals, size_t length, size_t decimalPosit
const unsigned effectiveSignificandSize = Double::EffectiveSignificandSize(64 + v.e); const unsigned effectiveSignificandSize = Double::EffectiveSignificandSize(64 + v.e);
unsigned precisionSize = 64 - effectiveSignificandSize; unsigned precisionSize = 64 - effectiveSignificandSize;
if (precisionSize + kUlpShift >= 64) { if(precisionSize + kUlpShift >= 64)
{
unsigned scaleExp = (precisionSize + kUlpShift) - 63; unsigned scaleExp = (precisionSize + kUlpShift) - 63;
v.f >>= scaleExp; v.f >>= scaleExp;
v.e += scaleExp; v.e += scaleExp;
@ -190,9 +234,11 @@ inline bool StrtodDiyFp(const char* decimals, size_t length, size_t decimalPosit
DiyFp rounded(v.f >> precisionSize, v.e + static_cast<int>(precisionSize)); DiyFp rounded(v.f >> precisionSize, v.e + static_cast<int>(precisionSize));
const uint64_t precisionBits = (v.f & ((uint64_t(1) << precisionSize) - 1)) * kUlp; const uint64_t precisionBits = (v.f & ((uint64_t(1) << precisionSize) - 1)) * kUlp;
const uint64_t halfWay = (uint64_t(1) << (precisionSize - 1)) * kUlp; const uint64_t halfWay = (uint64_t(1) << (precisionSize - 1)) * kUlp;
if (precisionBits >= halfWay + static_cast<unsigned>(error)) { if(precisionBits >= halfWay + static_cast<unsigned>(error))
{
rounded.f++; rounded.f++;
if (rounded.f & (DiyFp::kDpHiddenBit << 1)) { // rounding overflows mantissa (issue #340) if(rounded.f & (DiyFp::kDpHiddenBit << 1)) // rounding overflows mantissa (issue #340)
{
rounded.f >>= 1; rounded.f >>= 1;
rounded.e++; rounded.e++;
} }
@ -200,44 +246,62 @@ inline bool StrtodDiyFp(const char* decimals, size_t length, size_t decimalPosit
*result = rounded.ToDouble(); *result = rounded.ToDouble();
return halfWay - static_cast<unsigned>(error) >= precisionBits || precisionBits >= halfWay + static_cast<unsigned>(error); return halfWay - static_cast<unsigned>(error) >= precisionBits ||
precisionBits >= halfWay + static_cast<unsigned>(error);
} }
inline double StrtodBigInteger(double approx, const char* decimals, size_t length, size_t decimalPosition, int exp) { inline double StrtodBigInteger(double approx, const char* decimals, size_t length, size_t decimalPosition,
int exp)
{
const BigInteger dInt(decimals, length); const BigInteger dInt(decimals, length);
const int dExp = static_cast<int>(decimalPosition) - static_cast<int>(length) + exp; const int dExp = static_cast<int>(decimalPosition) - static_cast<int>(length) + exp;
Double a(approx); Double a(approx);
int cmp = CheckWithinHalfULP(a.Value(), dInt, dExp); int cmp = CheckWithinHalfULP(a.Value(), dInt, dExp);
if(cmp < 0) if(cmp < 0)
{
return a.Value(); // within half ULP return a.Value(); // within half ULP
else if (cmp == 0) { }
else if(cmp == 0)
{
// Round towards even // Round towards even
if(a.Significand() & 1) if(a.Significand() & 1)
{
return a.NextPositiveDouble(); return a.NextPositiveDouble();
}
else else
{
return a.Value(); return a.Value();
} }
}
else // adjustment else // adjustment
{
return a.NextPositiveDouble(); return a.NextPositiveDouble();
} }
}
inline double StrtodFullPrecision(double d, int p, const char* decimals, size_t length, size_t decimalPosition, int exp) { inline double StrtodFullPrecision(double d, int p, const char* decimals, size_t length, size_t decimalPosition,
int exp)
{
RAPIDJSON_ASSERT(d >= 0.0); RAPIDJSON_ASSERT(d >= 0.0);
RAPIDJSON_ASSERT(length >= 1); RAPIDJSON_ASSERT(length >= 1);
double result; double result;
if(StrtodFast(d, p, &result)) if(StrtodFast(d, p, &result))
{
return result; return result;
}
// Trim leading zeros // Trim leading zeros
while (*decimals == '0' && length > 1) { while(*decimals == '0' && length > 1)
{
length--; length--;
decimals++; decimals++;
decimalPosition--; decimalPosition--;
} }
// Trim trailing zeros // Trim trailing zeros
while (decimals[length - 1] == '0' && length > 1) { while(decimals[length - 1] == '0' && length > 1)
{
length--; length--;
decimalPosition--; decimalPosition--;
exp++; exp++;
@ -245,7 +309,8 @@ inline double StrtodFullPrecision(double d, int p, const char* decimals, size_t
// Trim right-most digits // Trim right-most digits
const int kMaxDecimalDigit = 780; const int kMaxDecimalDigit = 780;
if (static_cast<int>(length) > kMaxDecimalDigit) { if(static_cast<int>(length) > kMaxDecimalDigit)
{
int delta = (static_cast<int>(length) - kMaxDecimalDigit); int delta = (static_cast<int>(length) - kMaxDecimalDigit);
exp += delta; exp += delta;
decimalPosition -= static_cast<unsigned>(delta); decimalPosition -= static_cast<unsigned>(delta);
@ -254,10 +319,14 @@ inline double StrtodFullPrecision(double d, int p, const char* decimals, size_t
// If too small, underflow to zero // If too small, underflow to zero
if(int(length) + exp < -324) if(int(length) + exp < -324)
{
return 0.0; return 0.0;
}
if(StrtodDiyFp(decimals, length, decimalPosition, exp, &result)) if(StrtodDiyFp(decimals, length, decimalPosition, exp, &result))
{
return result; return result;
}
// Use approximation from StrtodDiyFp and make adjustment with BigInteger comparison // Use approximation from StrtodDiyFp and make adjustment with BigInteger comparison
return StrtodBigInteger(result, decimals, length, decimalPosition, exp); return StrtodBigInteger(result, decimals, length, decimalPosition, exp);

View file

@ -23,14 +23,16 @@ RAPIDJSON_DIAG_OFF(c++98-compat)
#endif #endif
RAPIDJSON_NAMESPACE_BEGIN RAPIDJSON_NAMESPACE_BEGIN
namespace internal { namespace internal
{
//! Custom swap() to avoid dependency on C++ <algorithm> header //! Custom swap() to avoid dependency on C++ <algorithm> header
/*! \tparam T Type of the arguments to swap, should be instantiated with primitive C++ types only. /*! \tparam T Type of the arguments to swap, should be instantiated with primitive C++ types only.
\note This has the same semantics as std::swap(). \note This has the same semantics as std::swap().
*/ */
template <typename T> template <typename T>
inline void Swap(T& a, T& b) RAPIDJSON_NOEXCEPT { inline void Swap(T & a, T & b) RAPIDJSON_NOEXCEPT
{
T tmp = a; T tmp = a;
a = b; a = b;
b = tmp; b = tmp;

View file

@ -47,42 +47,68 @@ RAPIDJSON_NAMESPACE_BEGIN
*/ */
template <typename StreamType> template <typename StreamType>
class BasicIStreamWrapper { class BasicIStreamWrapper
{
public: public:
typedef typename StreamType::char_type Ch; typedef typename StreamType::char_type Ch;
BasicIStreamWrapper(StreamType & stream) : stream_(stream), count_(), peekBuffer_() {} BasicIStreamWrapper(StreamType & stream) : stream_(stream), count_(), peekBuffer_() {}
Ch Peek() const { Ch Peek() const
{
typename StreamType::int_type c = stream_.peek(); typename StreamType::int_type c = stream_.peek();
return RAPIDJSON_LIKELY(c != StreamType::traits_type::eof()) ? static_cast<Ch>(c) : '\0'; return RAPIDJSON_LIKELY(c != StreamType::traits_type::eof()) ? static_cast<Ch>(c) : '\0';
} }
Ch Take() { Ch Take()
{
typename StreamType::int_type c = stream_.get(); typename StreamType::int_type c = stream_.get();
if (RAPIDJSON_LIKELY(c != StreamType::traits_type::eof())) { if(RAPIDJSON_LIKELY(c != StreamType::traits_type::eof()))
{
count_++; count_++;
return static_cast<Ch>(c); return static_cast<Ch>(c);
} }
else else
{
return '\0'; return '\0';
} }
}
// tellg() may return -1 when failed. So we count by ourself. // tellg() may return -1 when failed. So we count by ourself.
size_t Tell() const { return count_; } size_t Tell() const
{
return count_;
}
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } Ch* PutBegin()
void Put(Ch) { RAPIDJSON_ASSERT(false); } {
void Flush() { RAPIDJSON_ASSERT(false); } RAPIDJSON_ASSERT(false);
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } return 0;
}
void Put(Ch)
{
RAPIDJSON_ASSERT(false);
}
void Flush()
{
RAPIDJSON_ASSERT(false);
}
size_t PutEnd(Ch*)
{
RAPIDJSON_ASSERT(false);
return 0;
}
// For encoding detection only. // For encoding detection only.
const Ch* Peek4() const { const Ch* Peek4() const
{
RAPIDJSON_ASSERT(sizeof(Ch) == 1); // Only usable for byte stream. RAPIDJSON_ASSERT(sizeof(Ch) == 1); // Only usable for byte stream.
int i; int i;
bool hasError = false; bool hasError = false;
for (i = 0; i < 4; ++i) { for(i = 0; i < 4; ++i)
{
typename StreamType::int_type c = stream_.get(); typename StreamType::int_type c = stream_.get();
if (c == StreamType::traits_type::eof()) { if(c == StreamType::traits_type::eof())
{
hasError = true; hasError = true;
stream_.clear(); stream_.clear();
break; break;
@ -90,7 +116,9 @@ public:
peekBuffer_[i] = static_cast<Ch>(c); peekBuffer_[i] = static_cast<Ch>(c);
} }
for(--i; i >= 0; --i) for(--i; i >= 0; --i)
{
stream_.putback(peekBuffer_[i]); stream_.putback(peekBuffer_[i]);
}
return !hasError ? peekBuffer_ : 0; return !hasError ? peekBuffer_ : 0;
} }

View file

@ -34,24 +34,45 @@ RAPIDJSON_NAMESPACE_BEGIN
\note implements Stream concept \note implements Stream concept
*/ */
template <typename Allocator = CrtAllocator> template <typename Allocator = CrtAllocator>
struct GenericMemoryBuffer { struct GenericMemoryBuffer
{
typedef char Ch; // byte typedef char Ch; // byte
GenericMemoryBuffer(Allocator* allocator = 0, size_t capacity = kDefaultCapacity) : stack_(allocator, capacity) {} GenericMemoryBuffer(Allocator* allocator = 0, size_t capacity = kDefaultCapacity) : stack_(allocator,
capacity) {}
void Put(Ch c) { *stack_.template Push<Ch>() = c; } void Put(Ch c)
{
*stack_.template Push<Ch>() = c;
}
void Flush() {} void Flush() {}
void Clear() { stack_.Clear(); } void Clear()
void ShrinkToFit() { stack_.ShrinkToFit(); } {
Ch* Push(size_t count) { return stack_.template Push<Ch>(count); } stack_.Clear();
void Pop(size_t count) { stack_.template Pop<Ch>(count); } }
void ShrinkToFit()
{
stack_.ShrinkToFit();
}
Ch* Push(size_t count)
{
return stack_.template Push<Ch>(count);
}
void Pop(size_t count)
{
stack_.template Pop<Ch>(count);
}
const Ch* GetBuffer() const { const Ch* GetBuffer() const
{
return stack_.template Bottom<Ch>(); return stack_.template Bottom<Ch>();
} }
size_t GetSize() const { return stack_.GetSize(); } size_t GetSize() const
{
return stack_.GetSize();
}
static const size_t kDefaultCapacity = 256; static const size_t kDefaultCapacity = 256;
mutable internal::Stack<Allocator> stack_; mutable internal::Stack<Allocator> stack_;
@ -61,7 +82,8 @@ typedef GenericMemoryBuffer<> MemoryBuffer;
//! Implement specialized version of PutN() with memset() for better performance. //! Implement specialized version of PutN() with memset() for better performance.
template<> template<>
inline void PutN(MemoryBuffer& memoryBuffer, char c, size_t n) { inline void PutN(MemoryBuffer & memoryBuffer, char c, size_t n)
{
std::memset(memoryBuffer.stack_.Push<char>(n), c, n * sizeof(c)); std::memset(memoryBuffer.stack_.Push<char>(n), c, n * sizeof(c));
} }

View file

@ -37,22 +37,47 @@ RAPIDJSON_NAMESPACE_BEGIN
3. MemoryStream supports Peek4() for encoding detection. StringStream is specified with an encoding so it should not have Peek4(). 3. MemoryStream supports Peek4() for encoding detection. StringStream is specified with an encoding so it should not have Peek4().
\note implements Stream concept \note implements Stream concept
*/ */
struct MemoryStream { struct MemoryStream
{
typedef char Ch; // byte typedef char Ch; // byte
MemoryStream(const Ch* src, size_t size) : src_(src), begin_(src), end_(src + size), size_(size) {} MemoryStream(const Ch* src, size_t size) : src_(src), begin_(src), end_(src + size), size_(size) {}
Ch Peek() const { return RAPIDJSON_UNLIKELY(src_ == end_) ? '\0' : *src_; } Ch Peek() const
Ch Take() { return RAPIDJSON_UNLIKELY(src_ == end_) ? '\0' : *src_++; } {
size_t Tell() const { return static_cast<size_t>(src_ - begin_); } return RAPIDJSON_UNLIKELY(src_ == end_) ? '\0' : *src_;
}
Ch Take()
{
return RAPIDJSON_UNLIKELY(src_ == end_) ? '\0' : *src_++;
}
size_t Tell() const
{
return static_cast<size_t>(src_ - begin_);
}
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } Ch* PutBegin()
void Put(Ch) { RAPIDJSON_ASSERT(false); } {
void Flush() { RAPIDJSON_ASSERT(false); } RAPIDJSON_ASSERT(false);
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } return 0;
}
void Put(Ch)
{
RAPIDJSON_ASSERT(false);
}
void Flush()
{
RAPIDJSON_ASSERT(false);
}
size_t PutEnd(Ch*)
{
RAPIDJSON_ASSERT(false);
return 0;
}
// For encoding detection only. // For encoding detection only.
const Ch* Peek4() const { const Ch* Peek4() const
{
return Tell() + 4 <= size_ ? src_ : 0; return Tell() + 4 <= size_ ? src_ : 0;
} }

View file

@ -42,25 +42,48 @@ RAPIDJSON_NAMESPACE_BEGIN
*/ */
template <typename StreamType> template <typename StreamType>
class BasicOStreamWrapper { class BasicOStreamWrapper
{
public: public:
typedef typename StreamType::char_type Ch; typedef typename StreamType::char_type Ch;
BasicOStreamWrapper(StreamType & stream) : stream_(stream) {} BasicOStreamWrapper(StreamType & stream) : stream_(stream) {}
void Put(Ch c) { void Put(Ch c)
{
stream_.put(c); stream_.put(c);
} }
void Flush() { void Flush()
{
stream_.flush(); stream_.flush();
} }
// Not implemented // Not implemented
char Peek() const { RAPIDJSON_ASSERT(false); return 0; } char Peek() const
char Take() { RAPIDJSON_ASSERT(false); return 0; } {
size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; } RAPIDJSON_ASSERT(false);
char* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } return 0;
size_t PutEnd(char*) { RAPIDJSON_ASSERT(false); return 0; } }
char Take()
{
RAPIDJSON_ASSERT(false);
return 0;
}
size_t Tell() const
{
RAPIDJSON_ASSERT(false);
return 0;
}
char* PutBegin()
{
RAPIDJSON_ASSERT(false);
return 0;
}
size_t PutEnd(char*)
{
RAPIDJSON_ASSERT(false);
return 0;
}
private: private:
BasicOStreamWrapper(const BasicOStreamWrapper &); BasicOStreamWrapper(const BasicOStreamWrapper &);

File diff suppressed because it is too large Load diff

View file

@ -27,7 +27,8 @@ RAPIDJSON_NAMESPACE_BEGIN
//! Combination of PrettyWriter format flags. //! Combination of PrettyWriter format flags.
/*! \see PrettyWriter::SetFormatOptions /*! \see PrettyWriter::SetFormatOptions
*/ */
enum PrettyFormatOptions { enum PrettyFormatOptions
{
kFormatDefault = 0, //!< Default pretty formatting. kFormatDefault = 0, //!< Default pretty formatting.
kFormatSingleLineArray = 1 //!< Format arrays on a single line. kFormatSingleLineArray = 1 //!< Format arrays on a single line.
}; };
@ -40,7 +41,8 @@ enum PrettyFormatOptions {
\tparam StackAllocator Type of allocator for allocating memory of stack. \tparam StackAllocator Type of allocator for allocating memory of stack.
*/ */
template<typename OutputStream, typename SourceEncoding = UTF8<>, typename TargetEncoding = UTF8<>, typename StackAllocator = CrtAllocator, unsigned writeFlags = kWriteDefaultFlags> template<typename OutputStream, typename SourceEncoding = UTF8<>, typename TargetEncoding = UTF8<>, typename StackAllocator = CrtAllocator, unsigned writeFlags = kWriteDefaultFlags>
class PrettyWriter : public Writer<OutputStream, SourceEncoding, TargetEncoding, StackAllocator, writeFlags> { class PrettyWriter : public Writer<OutputStream, SourceEncoding, TargetEncoding, StackAllocator, writeFlags>
{
public: public:
typedef Writer<OutputStream, SourceEncoding, TargetEncoding, StackAllocator> Base; typedef Writer<OutputStream, SourceEncoding, TargetEncoding, StackAllocator> Base;
typedef typename Base::Ch Ch; typedef typename Base::Ch Ch;
@ -50,7 +52,8 @@ public:
\param allocator User supplied allocator. If it is null, it will create a private one. \param allocator User supplied allocator. If it is null, it will create a private one.
\param levelDepth Initial capacity of stack. \param levelDepth Initial capacity of stack.
*/ */
explicit PrettyWriter(OutputStream& os, StackAllocator* allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) : explicit PrettyWriter(OutputStream & os, StackAllocator* allocator = 0,
size_t levelDepth = Base::kDefaultLevelDepth) :
Base(os, allocator, levelDepth), indentChar_(' '), indentCharCount_(4), formatOptions_(kFormatDefault) {} Base(os, allocator, levelDepth), indentChar_(' '), indentCharCount_(4), formatOptions_(kFormatDefault) {}
@ -62,7 +65,8 @@ public:
\param indentCharCount Number of indent characters for each indentation level. \param indentCharCount Number of indent characters for each indentation level.
\note The default indentation is 4 spaces. \note The default indentation is 4 spaces.
*/ */
PrettyWriter& SetIndent(Ch indentChar, unsigned indentCharCount) { PrettyWriter & SetIndent(Ch indentChar, unsigned indentCharCount)
{
RAPIDJSON_ASSERT(indentChar == ' ' || indentChar == '\t' || indentChar == '\n' || indentChar == '\r'); RAPIDJSON_ASSERT(indentChar == ' ' || indentChar == '\t' || indentChar == '\n' || indentChar == '\r');
indentChar_ = indentChar; indentChar_ = indentChar;
indentCharCount_ = indentCharCount; indentCharCount_ = indentCharCount;
@ -72,7 +76,8 @@ public:
//! Set pretty writer formatting options. //! Set pretty writer formatting options.
/*! \param options Formatting options. /*! \param options Formatting options.
*/ */
PrettyWriter& SetFormatOptions(PrettyFormatOptions options) { PrettyWriter & SetFormatOptions(PrettyFormatOptions options)
{
formatOptions_ = options; formatOptions_ = options;
return *this; return *this;
} }
@ -82,53 +87,91 @@ public:
*/ */
//@{ //@{
bool Null() { PrettyPrefix(kNullType); return Base::WriteNull(); } bool Null()
bool Bool(bool b) { PrettyPrefix(b ? kTrueType : kFalseType); return Base::WriteBool(b); } {
bool Int(int i) { PrettyPrefix(kNumberType); return Base::WriteInt(i); } PrettyPrefix(kNullType);
bool Uint(unsigned u) { PrettyPrefix(kNumberType); return Base::WriteUint(u); } return Base::WriteNull();
bool Int64(int64_t i64) { PrettyPrefix(kNumberType); return Base::WriteInt64(i64); } }
bool Uint64(uint64_t u64) { PrettyPrefix(kNumberType); return Base::WriteUint64(u64); } bool Bool(bool b)
bool Double(double d) { PrettyPrefix(kNumberType); return Base::WriteDouble(d); } {
PrettyPrefix(b ? kTrueType : kFalseType);
return Base::WriteBool(b);
}
bool Int(int i)
{
PrettyPrefix(kNumberType);
return Base::WriteInt(i);
}
bool Uint(unsigned u)
{
PrettyPrefix(kNumberType);
return Base::WriteUint(u);
}
bool Int64(int64_t i64)
{
PrettyPrefix(kNumberType);
return Base::WriteInt64(i64);
}
bool Uint64(uint64_t u64)
{
PrettyPrefix(kNumberType);
return Base::WriteUint64(u64);
}
bool Double(double d)
{
PrettyPrefix(kNumberType);
return Base::WriteDouble(d);
}
bool RawNumber(const Ch* str, SizeType length, bool copy = false) { bool RawNumber(const Ch* str, SizeType length, bool copy = false)
{
(void)copy; (void)copy;
PrettyPrefix(kNumberType); PrettyPrefix(kNumberType);
return Base::WriteString(str, length); return Base::WriteString(str, length);
} }
bool String(const Ch* str, SizeType length, bool copy = false) { bool String(const Ch* str, SizeType length, bool copy = false)
{
(void)copy; (void)copy;
PrettyPrefix(kStringType); PrettyPrefix(kStringType);
return Base::WriteString(str, length); return Base::WriteString(str, length);
} }
#if RAPIDJSON_HAS_STDSTRING #if RAPIDJSON_HAS_STDSTRING
bool String(const std::basic_string<Ch>& str) { bool String(const std::basic_string<Ch> & str)
{
return String(str.data(), SizeType(str.size())); return String(str.data(), SizeType(str.size()));
} }
#endif #endif
bool StartObject() { bool StartObject()
{
PrettyPrefix(kObjectType); PrettyPrefix(kObjectType);
new(Base::level_stack_.template Push<typename Base::Level>()) typename Base::Level(false); new(Base::level_stack_.template Push<typename Base::Level>()) typename Base::Level(false);
return Base::WriteStartObject(); return Base::WriteStartObject();
} }
bool Key(const Ch* str, SizeType length, bool copy = false) { return String(str, length, copy); } bool Key(const Ch* str, SizeType length, bool copy = false)
{
return String(str, length, copy);
}
#if RAPIDJSON_HAS_STDSTRING #if RAPIDJSON_HAS_STDSTRING
bool Key(const std::basic_string<Ch>& str) { bool Key(const std::basic_string<Ch> & str)
{
return Key(str.data(), SizeType(str.size())); return Key(str.data(), SizeType(str.size()));
} }
#endif #endif
bool EndObject(SizeType memberCount = 0) { bool EndObject(SizeType memberCount = 0)
{
(void)memberCount; (void)memberCount;
RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level)); RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level));
RAPIDJSON_ASSERT(!Base::level_stack_.template Top<typename Base::Level>()->inArray); RAPIDJSON_ASSERT(!Base::level_stack_.template Top<typename Base::Level>()->inArray);
bool empty = Base::level_stack_.template Pop<typename Base::Level>(1)->valueCount == 0; bool empty = Base::level_stack_.template Pop<typename Base::Level>(1)->valueCount == 0;
if (!empty) { if(!empty)
{
Base::os_->Put('\n'); Base::os_->Put('\n');
WriteIndent(); WriteIndent();
} }
@ -136,23 +179,28 @@ public:
(void)ret; (void)ret;
RAPIDJSON_ASSERT(ret == true); RAPIDJSON_ASSERT(ret == true);
if(Base::level_stack_.Empty()) // end of json text if(Base::level_stack_.Empty()) // end of json text
{
Base::os_->Flush(); Base::os_->Flush();
}
return true; return true;
} }
bool StartArray() { bool StartArray()
{
PrettyPrefix(kArrayType); PrettyPrefix(kArrayType);
new(Base::level_stack_.template Push<typename Base::Level>()) typename Base::Level(true); new(Base::level_stack_.template Push<typename Base::Level>()) typename Base::Level(true);
return Base::WriteStartArray(); return Base::WriteStartArray();
} }
bool EndArray(SizeType memberCount = 0) { bool EndArray(SizeType memberCount = 0)
{
(void)memberCount; (void)memberCount;
RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level)); RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level));
RAPIDJSON_ASSERT(Base::level_stack_.template Top<typename Base::Level>()->inArray); RAPIDJSON_ASSERT(Base::level_stack_.template Top<typename Base::Level>()->inArray);
bool empty = Base::level_stack_.template Pop<typename Base::Level>(1)->valueCount == 0; bool empty = Base::level_stack_.template Pop<typename Base::Level>(1)->valueCount == 0;
if (!empty && !(formatOptions_ & kFormatSingleLineArray)) { if(!empty && !(formatOptions_ & kFormatSingleLineArray))
{
Base::os_->Put('\n'); Base::os_->Put('\n');
WriteIndent(); WriteIndent();
} }
@ -160,7 +208,9 @@ public:
(void)ret; (void)ret;
RAPIDJSON_ASSERT(ret == true); RAPIDJSON_ASSERT(ret == true);
if(Base::level_stack_.Empty()) // end of json text if(Base::level_stack_.Empty()) // end of json text
{
Base::os_->Flush(); Base::os_->Flush();
}
return true; return true;
} }
@ -170,8 +220,14 @@ public:
//@{ //@{
//! Simpler but slower overload. //! Simpler but slower overload.
bool String(const Ch* str) { return String(str, internal::StrLen(str)); } bool String(const Ch* str)
bool Key(const Ch* str) { return Key(str, internal::StrLen(str)); } {
return String(str, internal::StrLen(str));
}
bool Key(const Ch* str)
{
return Key(str, internal::StrLen(str));
}
//@} //@}
@ -184,54 +240,77 @@ public:
\param type Type of the root of json. \param type Type of the root of json.
\note When using PrettyWriter::RawValue(), the result json may not be indented correctly. \note When using PrettyWriter::RawValue(), the result json may not be indented correctly.
*/ */
bool RawValue(const Ch* json, size_t length, Type type) { PrettyPrefix(type); return Base::WriteRawValue(json, length); } bool RawValue(const Ch* json, size_t length, Type type)
{
protected: PrettyPrefix(type);
void PrettyPrefix(Type type) { return Base::WriteRawValue(json, length);
(void)type;
if (Base::level_stack_.GetSize() != 0) { // this value is not at root
typename Base::Level* level = Base::level_stack_.template Top<typename Base::Level>();
if (level->inArray) {
if (level->valueCount > 0) {
Base::os_->Put(','); // add comma if it is not the first element in array
if (formatOptions_ & kFormatSingleLineArray)
Base::os_->Put(' ');
} }
if (!(formatOptions_ & kFormatSingleLineArray)) { protected:
void PrettyPrefix(Type type)
{
(void)type;
if(Base::level_stack_.GetSize() != 0) // this value is not at root
{
typename Base::Level* level = Base::level_stack_.template Top<typename Base::Level>();
if(level->inArray)
{
if(level->valueCount > 0)
{
Base::os_->Put(','); // add comma if it is not the first element in array
if(formatOptions_ & kFormatSingleLineArray)
{
Base::os_->Put(' ');
}
}
if(!(formatOptions_ & kFormatSingleLineArray))
{
Base::os_->Put('\n'); Base::os_->Put('\n');
WriteIndent(); WriteIndent();
} }
} }
else { // in object else // in object
if (level->valueCount > 0) { {
if (level->valueCount % 2 == 0) { if(level->valueCount > 0)
{
if(level->valueCount % 2 == 0)
{
Base::os_->Put(','); Base::os_->Put(',');
Base::os_->Put('\n'); Base::os_->Put('\n');
} }
else { else
{
Base::os_->Put(':'); Base::os_->Put(':');
Base::os_->Put(' '); Base::os_->Put(' ');
} }
} }
else else
{
Base::os_->Put('\n'); Base::os_->Put('\n');
}
if(level->valueCount % 2 == 0) if(level->valueCount % 2 == 0)
{
WriteIndent(); WriteIndent();
} }
}
if(!level->inArray && level->valueCount % 2 == 0) if(!level->inArray && level->valueCount % 2 == 0)
{
RAPIDJSON_ASSERT(type == kStringType); // if it's in object, then even number should be a name RAPIDJSON_ASSERT(type == kStringType); // if it's in object, then even number should be a name
}
level->valueCount++; level->valueCount++;
} }
else { else
{
RAPIDJSON_ASSERT(!Base::hasRoot_); // Should only has one and only one root. RAPIDJSON_ASSERT(!Base::hasRoot_); // Should only has one and only one root.
Base::hasRoot_ = true; Base::hasRoot_ = true;
} }
} }
void WriteIndent() { void WriteIndent()
{
size_t count = (Base::level_stack_.GetSize() / sizeof(typename Base::Level)) * indentCharCount_; size_t count = (Base::level_stack_.GetSize() / sizeof(typename Base::Level)) * indentCharCount_;
PutN(*Base::os_, static_cast<typename TargetEncoding::Ch>(indentChar_), count); PutN(*Base::os_, static_cast<typename TargetEncoding::Ch>(indentChar_), count);
} }

View file

@ -411,7 +411,10 @@ RAPIDJSON_NAMESPACE_END
#endif #endif
RAPIDJSON_NAMESPACE_BEGIN RAPIDJSON_NAMESPACE_BEGIN
template <bool x> struct STATIC_ASSERTION_FAILURE; template <bool x> struct STATIC_ASSERTION_FAILURE;
template <> struct STATIC_ASSERTION_FAILURE<true> { enum { value = 1 }; }; template <> struct STATIC_ASSERTION_FAILURE<true>
{
enum { value = 1 };
};
template<int x> struct StaticAssertTest {}; template<int x> struct StaticAssertTest {};
RAPIDJSON_NAMESPACE_END RAPIDJSON_NAMESPACE_END
@ -599,7 +602,8 @@ RAPIDJSON_NAMESPACE_END
RAPIDJSON_NAMESPACE_BEGIN RAPIDJSON_NAMESPACE_BEGIN
//! Type of JSON value //! Type of JSON value
enum Type { enum Type
{
kNullType = 0, //!< null kNullType = 0, //!< null
kFalseType = 1, //!< false kFalseType = 1, //!< false
kTrueType = 2, //!< true kTrueType = 2, //!< true

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -70,7 +70,8 @@ concept Stream {
See TEST(Reader, CustomStringStream) in readertest.cpp for example. See TEST(Reader, CustomStringStream) in readertest.cpp for example.
*/ */
template<typename Stream> template<typename Stream>
struct StreamTraits { struct StreamTraits
{
//! Whether to make local copy of stream for optimization during parsing. //! Whether to make local copy of stream for optimization during parsing.
/*! /*!
By default, for safety, streams do not use local copy optimization. By default, for safety, streams do not use local copy optimization.
@ -81,24 +82,29 @@ struct StreamTraits {
//! Reserve n characters for writing to a stream. //! Reserve n characters for writing to a stream.
template<typename Stream> template<typename Stream>
inline void PutReserve(Stream& stream, size_t count) { inline void PutReserve(Stream & stream, size_t count)
{
(void)stream; (void)stream;
(void)count; (void)count;
} }
//! Write character to a stream, presuming buffer is reserved. //! Write character to a stream, presuming buffer is reserved.
template<typename Stream> template<typename Stream>
inline void PutUnsafe(Stream& stream, typename Stream::Ch c) { inline void PutUnsafe(Stream & stream, typename Stream::Ch c)
{
stream.Put(c); stream.Put(c);
} }
//! Put N copies of a character to a stream. //! Put N copies of a character to a stream.
template<typename Stream, typename Ch> template<typename Stream, typename Ch>
inline void PutN(Stream& stream, Ch c, size_t n) { inline void PutN(Stream & stream, Ch c, size_t n)
{
PutReserve(stream, n); PutReserve(stream, n);
for(size_t i = 0; i < n; i++) for(size_t i = 0; i < n; i++)
{
PutUnsafe(stream, c); PutUnsafe(stream, c);
} }
}
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// StringStream // StringStream
@ -107,26 +113,51 @@ inline void PutN(Stream& stream, Ch c, size_t n) {
/*! \note implements Stream concept /*! \note implements Stream concept
*/ */
template <typename Encoding> template <typename Encoding>
struct GenericStringStream { struct GenericStringStream
{
typedef typename Encoding::Ch Ch; typedef typename Encoding::Ch Ch;
GenericStringStream(const Ch* src) : src_(src), head_(src) {} GenericStringStream(const Ch* src) : src_(src), head_(src) {}
Ch Peek() const { return *src_; } Ch Peek() const
Ch Take() { return *src_++; } {
size_t Tell() const { return static_cast<size_t>(src_ - head_); } return *src_;
}
Ch Take()
{
return *src_++;
}
size_t Tell() const
{
return static_cast<size_t>(src_ - head_);
}
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } Ch* PutBegin()
void Put(Ch) { RAPIDJSON_ASSERT(false); } {
void Flush() { RAPIDJSON_ASSERT(false); } RAPIDJSON_ASSERT(false);
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } return 0;
}
void Put(Ch)
{
RAPIDJSON_ASSERT(false);
}
void Flush()
{
RAPIDJSON_ASSERT(false);
}
size_t PutEnd(Ch*)
{
RAPIDJSON_ASSERT(false);
return 0;
}
const Ch* src_; //!< Current read position. const Ch* src_; //!< Current read position.
const Ch* head_; //!< Original head of the string. const Ch* head_; //!< Original head of the string.
}; };
template <typename Encoding> template <typename Encoding>
struct StreamTraits<GenericStringStream<Encoding> > { struct StreamTraits<GenericStringStream<Encoding>>
{
enum { copyOptimization = 1 }; enum { copyOptimization = 1 };
}; };
@ -141,25 +172,53 @@ typedef GenericStringStream<UTF8<> > StringStream;
\note implements Stream concept \note implements Stream concept
*/ */
template <typename Encoding> template <typename Encoding>
struct GenericInsituStringStream { struct GenericInsituStringStream
{
typedef typename Encoding::Ch Ch; typedef typename Encoding::Ch Ch;
GenericInsituStringStream(Ch* src) : src_(src), dst_(0), head_(src) {} GenericInsituStringStream(Ch* src) : src_(src), dst_(0), head_(src) {}
// Read // Read
Ch Peek() { return *src_; } Ch Peek()
Ch Take() { return *src_++; } {
size_t Tell() { return static_cast<size_t>(src_ - head_); } return *src_;
}
Ch Take()
{
return *src_++;
}
size_t Tell()
{
return static_cast<size_t>(src_ - head_);
}
// Write // Write
void Put(Ch c) { RAPIDJSON_ASSERT(dst_ != 0); *dst_++ = c; } void Put(Ch c)
{
RAPIDJSON_ASSERT(dst_ != 0);
*dst_++ = c;
}
Ch* PutBegin() { return dst_ = src_; } Ch* PutBegin()
size_t PutEnd(Ch* begin) { return static_cast<size_t>(dst_ - begin); } {
return dst_ = src_;
}
size_t PutEnd(Ch* begin)
{
return static_cast<size_t>(dst_ - begin);
}
void Flush() {} void Flush() {}
Ch* Push(size_t count) { Ch* begin = dst_; dst_ += count; return begin; } Ch* Push(size_t count)
void Pop(size_t count) { dst_ -= count; } {
Ch* begin = dst_;
dst_ += count;
return begin;
}
void Pop(size_t count)
{
dst_ -= count;
}
Ch* src_; Ch* src_;
Ch* dst_; Ch* dst_;
@ -167,7 +226,8 @@ struct GenericInsituStringStream {
}; };
template <typename Encoding> template <typename Encoding>
struct StreamTraits<GenericInsituStringStream<Encoding> > { struct StreamTraits<GenericInsituStringStream<Encoding>>
{
enum { copyOptimization = 1 }; enum { copyOptimization = 1 };
}; };

View file

@ -38,39 +38,67 @@ RAPIDJSON_NAMESPACE_BEGIN
\note implements Stream concept \note implements Stream concept
*/ */
template <typename Encoding, typename Allocator = CrtAllocator> template <typename Encoding, typename Allocator = CrtAllocator>
class GenericStringBuffer { class GenericStringBuffer
{
public: public:
typedef typename Encoding::Ch Ch; typedef typename Encoding::Ch Ch;
GenericStringBuffer(Allocator* allocator = 0, size_t capacity = kDefaultCapacity) : stack_(allocator, capacity) {} GenericStringBuffer(Allocator* allocator = 0, size_t capacity = kDefaultCapacity) : stack_(allocator,
capacity) {}
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS #if RAPIDJSON_HAS_CXX11_RVALUE_REFS
GenericStringBuffer(GenericStringBuffer && rhs) : stack_(std::move(rhs.stack_)) {} GenericStringBuffer(GenericStringBuffer && rhs) : stack_(std::move(rhs.stack_)) {}
GenericStringBuffer& operator=(GenericStringBuffer&& rhs) { GenericStringBuffer & operator=(GenericStringBuffer && rhs)
{
if(&rhs != this) if(&rhs != this)
{
stack_ = std::move(rhs.stack_); stack_ = std::move(rhs.stack_);
}
return *this; return *this;
} }
#endif #endif
void Put(Ch c) { *stack_.template Push<Ch>() = c; } void Put(Ch c)
void PutUnsafe(Ch c) { *stack_.template PushUnsafe<Ch>() = c; } {
*stack_.template Push<Ch>() = c;
}
void PutUnsafe(Ch c)
{
*stack_.template PushUnsafe<Ch>() = c;
}
void Flush() {} void Flush() {}
void Clear() { stack_.Clear(); } void Clear()
void ShrinkToFit() { {
stack_.Clear();
}
void ShrinkToFit()
{
// Push and pop a null terminator. This is safe. // Push and pop a null terminator. This is safe.
*stack_.template Push<Ch>() = '\0'; *stack_.template Push<Ch>() = '\0';
stack_.ShrinkToFit(); stack_.ShrinkToFit();
stack_.template Pop<Ch>(1); stack_.template Pop<Ch>(1);
} }
void Reserve(size_t count) { stack_.template Reserve<Ch>(count); } void Reserve(size_t count)
Ch* Push(size_t count) { return stack_.template Push<Ch>(count); } {
Ch* PushUnsafe(size_t count) { return stack_.template PushUnsafe<Ch>(count); } stack_.template Reserve<Ch>(count);
void Pop(size_t count) { stack_.template Pop<Ch>(count); } }
Ch* Push(size_t count)
{
return stack_.template Push<Ch>(count);
}
Ch* PushUnsafe(size_t count)
{
return stack_.template PushUnsafe<Ch>(count);
}
void Pop(size_t count)
{
stack_.template Pop<Ch>(count);
}
const Ch* GetString() const { const Ch* GetString() const
{
// Push and pop a null terminator. This is safe. // Push and pop a null terminator. This is safe.
*stack_.template Push<Ch>() = '\0'; *stack_.template Push<Ch>() = '\0';
stack_.template Pop<Ch>(1); stack_.template Pop<Ch>(1);
@ -78,7 +106,10 @@ public:
return stack_.template Bottom<Ch>(); return stack_.template Bottom<Ch>();
} }
size_t GetSize() const { return stack_.GetSize(); } size_t GetSize() const
{
return stack_.GetSize();
}
static const size_t kDefaultCapacity = 256; static const size_t kDefaultCapacity = 256;
mutable internal::Stack<Allocator> stack_; mutable internal::Stack<Allocator> stack_;
@ -93,18 +124,21 @@ private:
typedef GenericStringBuffer<UTF8<>> StringBuffer; typedef GenericStringBuffer<UTF8<>> StringBuffer;
template<typename Encoding, typename Allocator> template<typename Encoding, typename Allocator>
inline void PutReserve(GenericStringBuffer<Encoding, Allocator>& stream, size_t count) { inline void PutReserve(GenericStringBuffer<Encoding, Allocator> & stream, size_t count)
{
stream.Reserve(count); stream.Reserve(count);
} }
template<typename Encoding, typename Allocator> template<typename Encoding, typename Allocator>
inline void PutUnsafe(GenericStringBuffer<Encoding, Allocator>& stream, typename Encoding::Ch c) { inline void PutUnsafe(GenericStringBuffer<Encoding, Allocator> & stream, typename Encoding::Ch c)
{
stream.PutUnsafe(c); stream.PutUnsafe(c);
} }
//! Implement specialized version of PutN() with memset() for better performance. //! Implement specialized version of PutN() with memset() for better performance.
template<> template<>
inline void PutN(GenericStringBuffer<UTF8<> >& stream, char c, size_t n) { inline void PutN(GenericStringBuffer<UTF8<>> & stream, char c, size_t n)
{
std::memset(stream.stack_.Push<char>(n), c, n * sizeof(c)); std::memset(stream.stack_.Push<char>(n), c, n * sizeof(c));
} }

View file

@ -60,7 +60,8 @@ RAPIDJSON_NAMESPACE_BEGIN
#endif #endif
//! Combination of writeFlags //! Combination of writeFlags
enum WriteFlag { enum WriteFlag
{
kWriteNoFlags = 0, //!< No flags are set. kWriteNoFlags = 0, //!< No flags are set.
kWriteValidateEncodingFlag = 1, //!< Validate encoding of JSON strings. kWriteValidateEncodingFlag = 1, //!< Validate encoding of JSON strings.
kWriteNanAndInfFlag = 2, //!< Allow writing of Infinity, -Infinity and NaN. kWriteNanAndInfFlag = 2, //!< Allow writing of Infinity, -Infinity and NaN.
@ -84,7 +85,8 @@ enum WriteFlag {
\note implements Handler concept \note implements Handler concept
*/ */
template<typename OutputStream, typename SourceEncoding = UTF8<>, typename TargetEncoding = UTF8<>, typename StackAllocator = CrtAllocator, unsigned writeFlags = kWriteDefaultFlags> template<typename OutputStream, typename SourceEncoding = UTF8<>, typename TargetEncoding = UTF8<>, typename StackAllocator = CrtAllocator, unsigned writeFlags = kWriteDefaultFlags>
class Writer { class Writer
{
public: public:
typedef typename SourceEncoding::Ch Ch; typedef typename SourceEncoding::Ch Ch;
@ -97,11 +99,13 @@ public:
*/ */
explicit explicit
Writer(OutputStream & os, StackAllocator* stackAllocator = 0, size_t levelDepth = kDefaultLevelDepth) : Writer(OutputStream & os, StackAllocator* stackAllocator = 0, size_t levelDepth = kDefaultLevelDepth) :
os_(&os), level_stack_(stackAllocator, levelDepth * sizeof(Level)), maxDecimalPlaces_(kDefaultMaxDecimalPlaces), hasRoot_(false) {} os_(&os), level_stack_(stackAllocator, levelDepth* sizeof(Level)), maxDecimalPlaces_(kDefaultMaxDecimalPlaces),
hasRoot_(false) {}
explicit explicit
Writer(StackAllocator* allocator = 0, size_t levelDepth = kDefaultLevelDepth) : Writer(StackAllocator* allocator = 0, size_t levelDepth = kDefaultLevelDepth) :
os_(0), level_stack_(allocator, levelDepth * sizeof(Level)), maxDecimalPlaces_(kDefaultMaxDecimalPlaces), hasRoot_(false) {} os_(0), level_stack_(allocator, levelDepth* sizeof(Level)), maxDecimalPlaces_(kDefaultMaxDecimalPlaces),
hasRoot_(false) {}
//! Reset the writer with a new stream. //! Reset the writer with a new stream.
/*! /*!
@ -121,7 +125,8 @@ public:
writer.EndObject(); writer.EndObject();
\endcode \endcode
*/ */
void Reset(OutputStream& os) { void Reset(OutputStream & os)
{
os_ = &os; os_ = &os;
hasRoot_ = false; hasRoot_ = false;
level_stack_.Clear(); level_stack_.Clear();
@ -131,11 +136,13 @@ public:
/*! /*!
A complete JSON has a complete root object or array. A complete JSON has a complete root object or array.
*/ */
bool IsComplete() const { bool IsComplete() const
{
return hasRoot_ && level_stack_.Empty(); return hasRoot_ && level_stack_.Empty();
} }
int GetMaxDecimalPlaces() const { int GetMaxDecimalPlaces() const
{
return maxDecimalPlaces_; return maxDecimalPlaces_;
} }
@ -160,7 +167,8 @@ public:
writer.SetMaxDecimalPlaces(Writer::kDefaultMaxDecimalPlaces); writer.SetMaxDecimalPlaces(Writer::kDefaultMaxDecimalPlaces);
\endcode \endcode
*/ */
void SetMaxDecimalPlaces(int maxDecimalPlaces) { void SetMaxDecimalPlaces(int maxDecimalPlaces)
{
maxDecimalPlaces_ = maxDecimalPlaces; maxDecimalPlaces_ = maxDecimalPlaces;
} }
@ -169,47 +177,83 @@ public:
*/ */
//@{ //@{
bool Null() { Prefix(kNullType); return EndValue(WriteNull()); } bool Null()
bool Bool(bool b) { Prefix(b ? kTrueType : kFalseType); return EndValue(WriteBool(b)); } {
bool Int(int i) { Prefix(kNumberType); return EndValue(WriteInt(i)); } Prefix(kNullType);
bool Uint(unsigned u) { Prefix(kNumberType); return EndValue(WriteUint(u)); } return EndValue(WriteNull());
bool Int64(int64_t i64) { Prefix(kNumberType); return EndValue(WriteInt64(i64)); } }
bool Uint64(uint64_t u64) { Prefix(kNumberType); return EndValue(WriteUint64(u64)); } bool Bool(bool b)
{
Prefix(b ? kTrueType : kFalseType);
return EndValue(WriteBool(b));
}
bool Int(int i)
{
Prefix(kNumberType);
return EndValue(WriteInt(i));
}
bool Uint(unsigned u)
{
Prefix(kNumberType);
return EndValue(WriteUint(u));
}
bool Int64(int64_t i64)
{
Prefix(kNumberType);
return EndValue(WriteInt64(i64));
}
bool Uint64(uint64_t u64)
{
Prefix(kNumberType);
return EndValue(WriteUint64(u64));
}
//! Writes the given \c double value to the stream //! Writes the given \c double value to the stream
/*! /*!
\param d The value to be written. \param d The value to be written.
\return Whether it is succeed. \return Whether it is succeed.
*/ */
bool Double(double d) { Prefix(kNumberType); return EndValue(WriteDouble(d)); } bool Double(double d)
{
Prefix(kNumberType);
return EndValue(WriteDouble(d));
}
bool RawNumber(const Ch* str, SizeType length, bool copy = false) { bool RawNumber(const Ch* str, SizeType length, bool copy = false)
{
(void)copy; (void)copy;
Prefix(kNumberType); Prefix(kNumberType);
return EndValue(WriteString(str, length)); return EndValue(WriteString(str, length));
} }
bool String(const Ch* str, SizeType length, bool copy = false) { bool String(const Ch* str, SizeType length, bool copy = false)
{
(void)copy; (void)copy;
Prefix(kStringType); Prefix(kStringType);
return EndValue(WriteString(str, length)); return EndValue(WriteString(str, length));
} }
#if RAPIDJSON_HAS_STDSTRING #if RAPIDJSON_HAS_STDSTRING
bool String(const std::basic_string<Ch>& str) { bool String(const std::basic_string<Ch> & str)
{
return String(str.data(), SizeType(str.size())); return String(str.data(), SizeType(str.size()));
} }
#endif #endif
bool StartObject() { bool StartObject()
{
Prefix(kObjectType); Prefix(kObjectType);
new(level_stack_.template Push<Level>()) Level(false); new(level_stack_.template Push<Level>()) Level(false);
return WriteStartObject(); return WriteStartObject();
} }
bool Key(const Ch* str, SizeType length, bool copy = false) { return String(str, length, copy); } bool Key(const Ch* str, SizeType length, bool copy = false)
{
return String(str, length, copy);
}
bool EndObject(SizeType memberCount = 0) { bool EndObject(SizeType memberCount = 0)
{
(void)memberCount; (void)memberCount;
RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level)); RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level));
RAPIDJSON_ASSERT(!level_stack_.template Top<Level>()->inArray); RAPIDJSON_ASSERT(!level_stack_.template Top<Level>()->inArray);
@ -217,13 +261,15 @@ public:
return EndValue(WriteEndObject()); return EndValue(WriteEndObject());
} }
bool StartArray() { bool StartArray()
{
Prefix(kArrayType); Prefix(kArrayType);
new(level_stack_.template Push<Level>()) Level(true); new(level_stack_.template Push<Level>()) Level(true);
return WriteStartArray(); return WriteStartArray();
} }
bool EndArray(SizeType elementCount = 0) { bool EndArray(SizeType elementCount = 0)
{
(void)elementCount; (void)elementCount;
RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level)); RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level));
RAPIDJSON_ASSERT(level_stack_.template Top<Level>()->inArray); RAPIDJSON_ASSERT(level_stack_.template Top<Level>()->inArray);
@ -236,8 +282,14 @@ public:
//@{ //@{
//! Simpler but slower overload. //! Simpler but slower overload.
bool String(const Ch* str) { return String(str, internal::StrLen(str)); } bool String(const Ch* str)
bool Key(const Ch* str) { return Key(str, internal::StrLen(str)); } {
return String(str, internal::StrLen(str));
}
bool Key(const Ch* str)
{
return Key(str, internal::StrLen(str));
}
//@} //@}
@ -249,11 +301,16 @@ public:
\param length Length of the json. \param length Length of the json.
\param type Type of the root of json. \param type Type of the root of json.
*/ */
bool RawValue(const Ch* json, size_t length, Type type) { Prefix(type); return EndValue(WriteRawValue(json, length)); } bool RawValue(const Ch* json, size_t length, Type type)
{
Prefix(type);
return EndValue(WriteRawValue(json, length));
}
protected: protected:
//! Information for each nested level //! Information for each nested level
struct Level { struct Level
{
Level(bool inArray_) : valueCount(0), inArray(inArray_) {} Level(bool inArray_) : valueCount(0), inArray(inArray_) {}
size_t valueCount; //!< number of values in this level size_t valueCount; //!< number of values in this level
bool inArray; //!< true if in array, otherwise in object bool inArray; //!< true if in array, otherwise in object
@ -261,76 +318,119 @@ protected:
static const size_t kDefaultLevelDepth = 32; static const size_t kDefaultLevelDepth = 32;
bool WriteNull() { bool WriteNull()
{
PutReserve(*os_, 4); PutReserve(*os_, 4);
PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'u'); PutUnsafe(*os_, 'l'); PutUnsafe(*os_, 'l'); return true; PutUnsafe(*os_, 'n');
PutUnsafe(*os_, 'u');
PutUnsafe(*os_, 'l');
PutUnsafe(*os_, 'l');
return true;
} }
bool WriteBool(bool b) { bool WriteBool(bool b)
if (b) { {
if(b)
{
PutReserve(*os_, 4); PutReserve(*os_, 4);
PutUnsafe(*os_, 't'); PutUnsafe(*os_, 'r'); PutUnsafe(*os_, 'u'); PutUnsafe(*os_, 'e'); PutUnsafe(*os_, 't');
PutUnsafe(*os_, 'r');
PutUnsafe(*os_, 'u');
PutUnsafe(*os_, 'e');
} }
else { else
{
PutReserve(*os_, 5); PutReserve(*os_, 5);
PutUnsafe(*os_, 'f'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'l'); PutUnsafe(*os_, 's'); PutUnsafe(*os_, 'e'); PutUnsafe(*os_, 'f');
PutUnsafe(*os_, 'a');
PutUnsafe(*os_, 'l');
PutUnsafe(*os_, 's');
PutUnsafe(*os_, 'e');
} }
return true; return true;
} }
bool WriteInt(int i) { bool WriteInt(int i)
{
char buffer[11]; char buffer[11];
const char* end = internal::i32toa(i, buffer); const char* end = internal::i32toa(i, buffer);
PutReserve(*os_, static_cast<size_t>(end - buffer)); PutReserve(*os_, static_cast<size_t>(end - buffer));
for(const char* p = buffer; p != end; ++p) for(const char* p = buffer; p != end; ++p)
{
PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(*p)); PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(*p));
}
return true; return true;
} }
bool WriteUint(unsigned u) { bool WriteUint(unsigned u)
{
char buffer[10]; char buffer[10];
const char* end = internal::u32toa(u, buffer); const char* end = internal::u32toa(u, buffer);
PutReserve(*os_, static_cast<size_t>(end - buffer)); PutReserve(*os_, static_cast<size_t>(end - buffer));
for(const char* p = buffer; p != end; ++p) for(const char* p = buffer; p != end; ++p)
{
PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(*p)); PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(*p));
}
return true; return true;
} }
bool WriteInt64(int64_t i64) { bool WriteInt64(int64_t i64)
{
char buffer[21]; char buffer[21];
const char* end = internal::i64toa(i64, buffer); const char* end = internal::i64toa(i64, buffer);
PutReserve(*os_, static_cast<size_t>(end - buffer)); PutReserve(*os_, static_cast<size_t>(end - buffer));
for(const char* p = buffer; p != end; ++p) for(const char* p = buffer; p != end; ++p)
{
PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(*p)); PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(*p));
}
return true; return true;
} }
bool WriteUint64(uint64_t u64) { bool WriteUint64(uint64_t u64)
{
char buffer[20]; char buffer[20];
char* end = internal::u64toa(u64, buffer); char* end = internal::u64toa(u64, buffer);
PutReserve(*os_, static_cast<size_t>(end - buffer)); PutReserve(*os_, static_cast<size_t>(end - buffer));
for(char* p = buffer; p != end; ++p) for(char* p = buffer; p != end; ++p)
{
PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(*p)); PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(*p));
}
return true; return true;
} }
bool WriteDouble(double d) { bool WriteDouble(double d)
if (internal::Double(d).IsNanOrInf()) { {
if(internal::Double(d).IsNanOrInf())
{
if(!(writeFlags & kWriteNanAndInfFlag)) if(!(writeFlags & kWriteNanAndInfFlag))
{
return false; return false;
if (internal::Double(d).IsNan()) { }
if(internal::Double(d).IsNan())
{
PutReserve(*os_, 3); PutReserve(*os_, 3);
PutUnsafe(*os_, 'N'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'N'); PutUnsafe(*os_, 'N');
PutUnsafe(*os_, 'a');
PutUnsafe(*os_, 'N');
return true; return true;
} }
if (internal::Double(d).Sign()) { if(internal::Double(d).Sign())
{
PutReserve(*os_, 9); PutReserve(*os_, 9);
PutUnsafe(*os_, '-'); PutUnsafe(*os_, '-');
} }
else else
{
PutReserve(*os_, 8); PutReserve(*os_, 8);
PutUnsafe(*os_, 'I'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'f'); }
PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 't'); PutUnsafe(*os_, 'y'); PutUnsafe(*os_, 'I');
PutUnsafe(*os_, 'n');
PutUnsafe(*os_, 'f');
PutUnsafe(*os_, 'i');
PutUnsafe(*os_, 'n');
PutUnsafe(*os_, 'i');
PutUnsafe(*os_, 't');
PutUnsafe(*os_, 'y');
return true; return true;
} }
@ -338,13 +438,17 @@ protected:
char* end = internal::dtoa(d, buffer, maxDecimalPlaces_); char* end = internal::dtoa(d, buffer, maxDecimalPlaces_);
PutReserve(*os_, static_cast<size_t>(end - buffer)); PutReserve(*os_, static_cast<size_t>(end - buffer));
for(char* p = buffer; p != end; ++p) for(char* p = buffer; p != end; ++p)
{
PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(*p)); PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(*p));
}
return true; return true;
} }
bool WriteString(const Ch* str, SizeType length) { bool WriteString(const Ch* str, SizeType length)
{
static const typename TargetEncoding::Ch hexDigits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; static const typename TargetEncoding::Ch hexDigits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
static const char escape[256] = { static const char escape[256] =
{
#define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 #define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
//0 1 2 3 4 5 6 7 8 9 A B C D E F //0 1 2 3 4 5 6 7 8 9 A B C D E F
'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'b', 't', 'n', 'u', 'f', 'r', 'u', 'u', // 00 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'b', 't', 'n', 'u', 'f', 'r', 'u', 'u', // 00
@ -357,28 +461,38 @@ protected:
}; };
if(TargetEncoding::supportUnicode) if(TargetEncoding::supportUnicode)
{
PutReserve(*os_, 2 + length * 6); // "\uxxxx..." PutReserve(*os_, 2 + length * 6); // "\uxxxx..."
}
else else
{
PutReserve(*os_, 2 + length * 12); // "\uxxxx\uyyyy..." PutReserve(*os_, 2 + length * 12); // "\uxxxx\uyyyy..."
}
PutUnsafe(*os_, '\"'); PutUnsafe(*os_, '\"');
GenericStringStream<SourceEncoding> is(str); GenericStringStream<SourceEncoding> is(str);
while (ScanWriteUnescapedString(is, length)) { while(ScanWriteUnescapedString(is, length))
{
const Ch c = is.Peek(); const Ch c = is.Peek();
if (!TargetEncoding::supportUnicode && static_cast<unsigned>(c) >= 0x80) { if(!TargetEncoding::supportUnicode && static_cast<unsigned>(c) >= 0x80)
{
// Unicode escaping // Unicode escaping
unsigned codepoint; unsigned codepoint;
if(RAPIDJSON_UNLIKELY(!SourceEncoding::Decode(is, &codepoint))) if(RAPIDJSON_UNLIKELY(!SourceEncoding::Decode(is, &codepoint)))
{
return false; return false;
}
PutUnsafe(*os_, '\\'); PutUnsafe(*os_, '\\');
PutUnsafe(*os_, 'u'); PutUnsafe(*os_, 'u');
if (codepoint <= 0xD7FF || (codepoint >= 0xE000 && codepoint <= 0xFFFF)) { if(codepoint <= 0xD7FF || (codepoint >= 0xE000 && codepoint <= 0xFFFF))
{
PutUnsafe(*os_, hexDigits[(codepoint >> 12) & 15]); PutUnsafe(*os_, hexDigits[(codepoint >> 12) & 15]);
PutUnsafe(*os_, hexDigits[(codepoint >> 8) & 15]); PutUnsafe(*os_, hexDigits[(codepoint >> 8) & 15]);
PutUnsafe(*os_, hexDigits[(codepoint >> 4) & 15]); PutUnsafe(*os_, hexDigits[(codepoint >> 4) & 15]);
PutUnsafe(*os_, hexDigits[(codepoint) & 15]); PutUnsafe(*os_, hexDigits[(codepoint) & 15]);
} }
else { else
{
RAPIDJSON_ASSERT(codepoint >= 0x010000 && codepoint <= 0x10FFFF); RAPIDJSON_ASSERT(codepoint >= 0x010000 && codepoint <= 0x10FFFF);
// Surrogate pair // Surrogate pair
unsigned s = codepoint - 0x010000; unsigned s = codepoint - 0x010000;
@ -396,11 +510,14 @@ protected:
PutUnsafe(*os_, hexDigits[(trail) & 15]); PutUnsafe(*os_, hexDigits[(trail) & 15]);
} }
} }
else if ((sizeof(Ch) == 1 || static_cast<unsigned>(c) < 256) && RAPIDJSON_UNLIKELY(escape[static_cast<unsigned char>(c)])) { else if((sizeof(Ch) == 1 || static_cast<unsigned>(c) < 256) &&
RAPIDJSON_UNLIKELY(escape[static_cast<unsigned char>(c)]))
{
is.Take(); is.Take();
PutUnsafe(*os_, '\\'); PutUnsafe(*os_, '\\');
PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(escape[static_cast<unsigned char>(c)])); PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(escape[static_cast<unsigned char>(c)]));
if (escape[static_cast<unsigned char>(c)] == 'u') { if(escape[static_cast<unsigned char>(c)] == 'u')
{
PutUnsafe(*os_, '0'); PutUnsafe(*os_, '0');
PutUnsafe(*os_, '0'); PutUnsafe(*os_, '0');
PutUnsafe(*os_, hexDigits[static_cast<unsigned char>(c) >> 4]); PutUnsafe(*os_, hexDigits[static_cast<unsigned char>(c) >> 4]);
@ -410,54 +527,88 @@ protected:
else if(RAPIDJSON_UNLIKELY(!(writeFlags & kWriteValidateEncodingFlag ? else if(RAPIDJSON_UNLIKELY(!(writeFlags & kWriteValidateEncodingFlag ?
Transcoder<SourceEncoding, TargetEncoding>::Validate(is, *os_) : Transcoder<SourceEncoding, TargetEncoding>::Validate(is, *os_) :
Transcoder<SourceEncoding, TargetEncoding>::TranscodeUnsafe(is, *os_)))) Transcoder<SourceEncoding, TargetEncoding>::TranscodeUnsafe(is, *os_))))
{
return false; return false;
} }
}
PutUnsafe(*os_, '\"'); PutUnsafe(*os_, '\"');
return true; return true;
} }
bool ScanWriteUnescapedString(GenericStringStream<SourceEncoding>& is, size_t length) { bool ScanWriteUnescapedString(GenericStringStream<SourceEncoding> & is, size_t length)
{
return RAPIDJSON_LIKELY(is.Tell() < length); return RAPIDJSON_LIKELY(is.Tell() < length);
} }
bool WriteStartObject() { os_->Put('{'); return true; } bool WriteStartObject()
bool WriteEndObject() { os_->Put('}'); return true; } {
bool WriteStartArray() { os_->Put('['); return true; } os_->Put('{');
bool WriteEndArray() { os_->Put(']'); return true; } return true;
}
bool WriteEndObject()
{
os_->Put('}');
return true;
}
bool WriteStartArray()
{
os_->Put('[');
return true;
}
bool WriteEndArray()
{
os_->Put(']');
return true;
}
bool WriteRawValue(const Ch* json, size_t length) { bool WriteRawValue(const Ch* json, size_t length)
{
PutReserve(*os_, length); PutReserve(*os_, length);
for (size_t i = 0; i < length; i++) { for(size_t i = 0; i < length; i++)
{
RAPIDJSON_ASSERT(json[i] != '\0'); RAPIDJSON_ASSERT(json[i] != '\0');
PutUnsafe(*os_, json[i]); PutUnsafe(*os_, json[i]);
} }
return true; return true;
} }
void Prefix(Type type) { void Prefix(Type type)
{
(void)type; (void)type;
if (RAPIDJSON_LIKELY(level_stack_.GetSize() != 0)) { // this value is not at root if(RAPIDJSON_LIKELY(level_stack_.GetSize() != 0)) // this value is not at root
{
Level* level = level_stack_.template Top<Level>(); Level* level = level_stack_.template Top<Level>();
if (level->valueCount > 0) { if(level->valueCount > 0)
{
if(level->inArray) if(level->inArray)
{
os_->Put(','); // add comma if it is not the first element in array os_->Put(','); // add comma if it is not the first element in array
}
else // in object else // in object
{
os_->Put((level->valueCount % 2 == 0) ? ',' : ':'); os_->Put((level->valueCount % 2 == 0) ? ',' : ':');
} }
}
if(!level->inArray && level->valueCount % 2 == 0) if(!level->inArray && level->valueCount % 2 == 0)
{
RAPIDJSON_ASSERT(type == kStringType); // if it's in object, then even number should be a name RAPIDJSON_ASSERT(type == kStringType); // if it's in object, then even number should be a name
}
level->valueCount++; level->valueCount++;
} }
else { else
{
RAPIDJSON_ASSERT(!hasRoot_); // Should only has one and only one root. RAPIDJSON_ASSERT(!hasRoot_); // Should only has one and only one root.
hasRoot_ = true; hasRoot_ = true;
} }
} }
// Flush the value if it is the top level one. // Flush the value if it is the top level one.
bool EndValue(bool ret) { bool EndValue(bool ret)
{
if(RAPIDJSON_UNLIKELY(level_stack_.Empty())) // end of json text if(RAPIDJSON_UNLIKELY(level_stack_.Empty())) // end of json text
{
os_->Flush(); os_->Flush();
}
return ret; return ret;
} }
@ -475,7 +626,8 @@ private:
// Full specialization for StringStream to prevent memory copying // Full specialization for StringStream to prevent memory copying
template<> template<>
inline bool Writer<StringBuffer>::WriteInt(int i) { inline bool Writer<StringBuffer>::WriteInt(int i)
{
char* buffer = os_->Push(11); char* buffer = os_->Push(11);
const char* end = internal::i32toa(i, buffer); const char* end = internal::i32toa(i, buffer);
os_->Pop(static_cast<size_t>(11 - (end - buffer))); os_->Pop(static_cast<size_t>(11 - (end - buffer)));
@ -483,7 +635,8 @@ inline bool Writer<StringBuffer>::WriteInt(int i) {
} }
template<> template<>
inline bool Writer<StringBuffer>::WriteUint(unsigned u) { inline bool Writer<StringBuffer>::WriteUint(unsigned u)
{
char* buffer = os_->Push(10); char* buffer = os_->Push(10);
const char* end = internal::u32toa(u, buffer); const char* end = internal::u32toa(u, buffer);
os_->Pop(static_cast<size_t>(10 - (end - buffer))); os_->Pop(static_cast<size_t>(10 - (end - buffer)));
@ -491,7 +644,8 @@ inline bool Writer<StringBuffer>::WriteUint(unsigned u) {
} }
template<> template<>
inline bool Writer<StringBuffer>::WriteInt64(int64_t i64) { inline bool Writer<StringBuffer>::WriteInt64(int64_t i64)
{
char* buffer = os_->Push(21); char* buffer = os_->Push(21);
const char* end = internal::i64toa(i64, buffer); const char* end = internal::i64toa(i64, buffer);
os_->Pop(static_cast<size_t>(21 - (end - buffer))); os_->Pop(static_cast<size_t>(21 - (end - buffer)));
@ -499,7 +653,8 @@ inline bool Writer<StringBuffer>::WriteInt64(int64_t i64) {
} }
template<> template<>
inline bool Writer<StringBuffer>::WriteUint64(uint64_t u) { inline bool Writer<StringBuffer>::WriteUint64(uint64_t u)
{
char* buffer = os_->Push(20); char* buffer = os_->Push(20);
const char* end = internal::u64toa(u, buffer); const char* end = internal::u64toa(u, buffer);
os_->Pop(static_cast<size_t>(20 - (end - buffer))); os_->Pop(static_cast<size_t>(20 - (end - buffer)));
@ -507,24 +662,40 @@ inline bool Writer<StringBuffer>::WriteUint64(uint64_t u) {
} }
template<> template<>
inline bool Writer<StringBuffer>::WriteDouble(double d) { inline bool Writer<StringBuffer>::WriteDouble(double d)
if (internal::Double(d).IsNanOrInf()) { {
if(internal::Double(d).IsNanOrInf())
{
// Note: This code path can only be reached if (RAPIDJSON_WRITE_DEFAULT_FLAGS & kWriteNanAndInfFlag). // Note: This code path can only be reached if (RAPIDJSON_WRITE_DEFAULT_FLAGS & kWriteNanAndInfFlag).
if(!(kWriteDefaultFlags & kWriteNanAndInfFlag)) if(!(kWriteDefaultFlags & kWriteNanAndInfFlag))
{
return false; return false;
if (internal::Double(d).IsNan()) { }
if(internal::Double(d).IsNan())
{
PutReserve(*os_, 3); PutReserve(*os_, 3);
PutUnsafe(*os_, 'N'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'N'); PutUnsafe(*os_, 'N');
PutUnsafe(*os_, 'a');
PutUnsafe(*os_, 'N');
return true; return true;
} }
if (internal::Double(d).Sign()) { if(internal::Double(d).Sign())
{
PutReserve(*os_, 9); PutReserve(*os_, 9);
PutUnsafe(*os_, '-'); PutUnsafe(*os_, '-');
} }
else else
{
PutReserve(*os_, 8); PutReserve(*os_, 8);
PutUnsafe(*os_, 'I'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'f'); }
PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 't'); PutUnsafe(*os_, 'y'); PutUnsafe(*os_, 'I');
PutUnsafe(*os_, 'n');
PutUnsafe(*os_, 'f');
PutUnsafe(*os_, 'i');
PutUnsafe(*os_, 'n');
PutUnsafe(*os_, 'i');
PutUnsafe(*os_, 't');
PutUnsafe(*os_, 'y');
return true; return true;
} }
@ -536,27 +707,39 @@ inline bool Writer<StringBuffer>::WriteDouble(double d) {
#if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42) #if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42)
template<> template<>
inline bool Writer<StringBuffer>::ScanWriteUnescapedString(StringStream& is, size_t length) { inline bool Writer<StringBuffer>::ScanWriteUnescapedString(StringStream & is, size_t length)
{
if(length < 16) if(length < 16)
{
return RAPIDJSON_LIKELY(is.Tell() < length); return RAPIDJSON_LIKELY(is.Tell() < length);
}
if(!RAPIDJSON_LIKELY(is.Tell() < length)) if(!RAPIDJSON_LIKELY(is.Tell() < length))
{
return false; return false;
}
const char* p = is.src_; const char* p = is.src_;
const char* end = is.head_ + length; const char* end = is.head_ + length;
const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15)); const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>
const char* endAligned = reinterpret_cast<const char*>(reinterpret_cast<size_t>(end) & static_cast<size_t>(~15)); (p) + 15) & static_cast<size_t>(~15));
const char* endAligned = reinterpret_cast<const char*>(reinterpret_cast<size_t>(end) & static_cast<size_t>
(~15));
if(nextAligned > end) if(nextAligned > end)
{
return true; return true;
}
while(p != nextAligned) while(p != nextAligned)
if (*p < 0x20 || *p == '\"' || *p == '\\') { if(*p < 0x20 || *p == '\"' || *p == '\\')
{
is.src_ = p; is.src_ = p;
return RAPIDJSON_LIKELY(is.Tell() < length); return RAPIDJSON_LIKELY(is.Tell() < length);
} }
else else
{
os_->PutUnsafe(*p++); os_->PutUnsafe(*p++);
}
// The rest of string using SIMD // The rest of string using SIMD
static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' }; static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' };
@ -566,14 +749,16 @@ inline bool Writer<StringBuffer>::ScanWriteUnescapedString(StringStream& is, siz
const __m128i bs = _mm_loadu_si128(reinterpret_cast<const __m128i*>(&bslash[0])); const __m128i bs = _mm_loadu_si128(reinterpret_cast<const __m128i*>(&bslash[0]));
const __m128i sp = _mm_loadu_si128(reinterpret_cast<const __m128i*>(&space[0])); const __m128i sp = _mm_loadu_si128(reinterpret_cast<const __m128i*>(&space[0]));
for (; p != endAligned; p += 16) { for(; p != endAligned; p += 16)
{
const __m128i s = _mm_load_si128(reinterpret_cast<const __m128i*>(p)); const __m128i s = _mm_load_si128(reinterpret_cast<const __m128i*>(p));
const __m128i t1 = _mm_cmpeq_epi8(s, dq); const __m128i t1 = _mm_cmpeq_epi8(s, dq);
const __m128i t2 = _mm_cmpeq_epi8(s, bs); const __m128i t2 = _mm_cmpeq_epi8(s, bs);
const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x19) == 0x19 const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x19) == 0x19
const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3); const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3);
unsigned short r = static_cast<unsigned short>(_mm_movemask_epi8(x)); unsigned short r = static_cast<unsigned short>(_mm_movemask_epi8(x));
if (RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped if(RAPIDJSON_UNLIKELY(r != 0)) // some of characters is escaped
{
SizeType len; SizeType len;
#ifdef _MSC_VER // Find the index of first escaped #ifdef _MSC_VER // Find the index of first escaped
unsigned long offset; unsigned long offset;
@ -584,7 +769,9 @@ inline bool Writer<StringBuffer>::ScanWriteUnescapedString(StringStream& is, siz
#endif #endif
char* q = reinterpret_cast<char*>(os_->PushUnsafe(len)); char* q = reinterpret_cast<char*>(os_->PushUnsafe(len));
for(size_t i = 0; i < len; i++) for(size_t i = 0; i < len; i++)
{
q[i] = p[i]; q[i] = p[i];
}
p += len; p += len;
break; break;

View file

@ -33,18 +33,23 @@
void App::background() void App::background()
{ {
if (m_options->affinity() != -1L) { if(m_options->affinity() != -1L)
{
Cpu::setAffinity(-1, m_options->affinity()); Cpu::setAffinity(-1, m_options->affinity());
} }
if (!m_options->background()) { if(!m_options->background())
{
return; return;
} }
HWND hcon = GetConsoleWindow(); HWND hcon = GetConsoleWindow();
if (hcon) { if(hcon)
{
ShowWindow(hcon, SW_HIDE); ShowWindow(hcon, SW_HIDE);
} else { }
else
{
HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE); HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE);
CloseHandle(h); CloseHandle(h);
FreeConsole(); FreeConsole();

View file

@ -32,7 +32,8 @@ Console::Console(IConsoleListener *listener)
m_tty.data = this; m_tty.data = this;
uv_tty_init(uv_default_loop(), &m_tty, 0, 1); uv_tty_init(uv_default_loop(), &m_tty, 0, 1);
if (!uv_is_readable(reinterpret_cast<uv_stream_t*>(&m_tty))) { if(!uv_is_readable(reinterpret_cast<uv_stream_t*>(&m_tty)))
{
return; return;
} }
@ -51,11 +52,13 @@ void Console::onAllocBuffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t
void Console::onRead(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) void Console::onRead(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf)
{ {
if (nread < 0) { if(nread < 0)
{
return uv_close(reinterpret_cast<uv_handle_t*>(stream), nullptr); return uv_close(reinterpret_cast<uv_handle_t*>(stream), nullptr);
} }
if (nread == 1) { if(nread == 1)
{
static_cast<Console*>(stream->data)->m_listener->onConsoleCommand(buf->base[0]); static_cast<Console*>(stream->data)->m_listener->onConsoleCommand(buf->base[0]);
} }
} }

View file

@ -38,7 +38,8 @@ struct cryptonight_ctx;
class Mem class Mem
{ {
public: public:
enum Flags { enum Flags
{
HugepagesAvailable = 1, HugepagesAvailable = 1,
HugepagesEnabled = 2, HugepagesEnabled = 2,
Lock = 4 Lock = 4
@ -49,11 +50,26 @@ public:
static void* calloc(size_t num, size_t size); static void* calloc(size_t num, size_t size);
static void release(); static void release();
static inline bool isDoubleHash() { return m_doubleHash; } static inline bool isDoubleHash()
static inline bool isHugepagesAvailable() { return (m_flags & HugepagesAvailable) != 0; } {
static inline bool isHugepagesEnabled() { return (m_flags & HugepagesEnabled) != 0; } return m_doubleHash;
static inline int flags() { return m_flags; } }
static inline int threads() { return m_threads; } static inline bool isHugepagesAvailable()
{
return (m_flags & HugepagesAvailable) != 0;
}
static inline bool isHugepagesEnabled()
{
return (m_flags & HugepagesEnabled) != 0;
}
static inline int flags()
{
return m_flags;
}
static inline int threads()
{
return m_threads;
}
private: private:
static bool m_doubleHash; static bool m_doubleHash;

View file

@ -24,7 +24,8 @@
#include "App.h" #include "App.h"
int main(int argc, char **argv) { int main(int argc, char** argv)
{
App app(argc, argv); App app(argc, argv);
return app.exec(); return app.exec();