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

@ -29,27 +29,32 @@
#ifndef __cplusplus #ifndef __cplusplus
extern int posix_memalign(void **__memptr, size_t __alignment, size_t __size); extern int posix_memalign(void** __memptr, size_t __alignment, size_t __size);
#else #else
// Some systems (e.g. those with GNU libc) declare posix_memalign with an // Some systems (e.g. those with GNU libc) declare posix_memalign with an
// exception specifier. Via an "egregious workaround" in // exception specifier. Via an "egregious workaround" in
// Sema::CheckEquivalentExceptionSpec, Clang accepts the following as a valid // Sema::CheckEquivalentExceptionSpec, Clang accepts the following as a valid
// redeclaration of glibc's declaration. // redeclaration of glibc's declaration.
extern "C" int posix_memalign(void **__memptr, size_t __alignment, size_t __size); 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;
} }
@ -57,7 +62,7 @@ static __inline__ void *__attribute__((__always_inline__, __malloc__)) _mm_mallo
} }
static __inline__ void __attribute__((__always_inline__)) _mm_free(void *__p) static __inline__ void __attribute__((__always_inline__)) _mm_free(void* __p)
{ {
free(__p); free(__p);
} }

View file

@ -8,25 +8,25 @@
* IMPLIED ARE HEREBY DISCLAIMED. This includes but is not limited to * IMPLIED ARE HEREBY DISCLAIMED. This includes but is not limited to
* warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/ */
/* /*
* Copyright (c) 2002 Todd C. Miller <Todd.Miller@courtesan.com> * Copyright (c) 2002 Todd C. Miller <Todd.Miller@courtesan.com>
* *
* Permission to use, copy, modify, and distribute this software for any * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies. * copyright notice and this permission notice appear in all copies.
* *
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
* *
* Sponsored in part by the Defense Advanced Research Projects * Sponsored in part by the Defense Advanced Research Projects
* Agency (DARPA) and Air Force Research Laboratory, Air Force * Agency (DARPA) and Air Force Research Laboratory, Air Force
* Materiel Command, USAF, under agreement number F39502-99-1-0512. * Materiel Command, USAF, under agreement number F39502-99-1-0512.
*/ */
/*- /*-
* Copyright (c) 2000 The NetBSD Foundation, Inc. * Copyright (c) 2000 The NetBSD Foundation, Inc.
* All rights reserved. * All rights reserved.
@ -82,7 +82,7 @@ int optopt = '?'; /* character checked for validity */
#undef optreset /* see getopt.h */ #undef optreset /* see getopt.h */
#define optreset __mingw_optreset #define optreset __mingw_optreset
int optreset; /* reset getopt */ int optreset; /* reset getopt */
char *optarg; /* argument associated with option */ char* optarg; /* argument associated with option */
#endif #endif
//extern int optind; /* index of first non-option in argv */ //extern int optind; /* index of first non-option in argv */
@ -106,7 +106,7 @@ char *optarg; /* argument associated with option */
#ifndef __CYGWIN__ #ifndef __CYGWIN__
#define __progname __argv[0] #define __progname __argv[0]
#else #else
extern char __declspec(dllimport) *__progname; extern char __declspec(dllimport)* __progname;
#endif #endif
#ifdef __CYGWIN__ #ifdef __CYGWIN__
@ -115,14 +115,14 @@ static char EMSG[] = "";
#define EMSG "" #define EMSG ""
#endif #endif
static int getopt_internal(int, char * const *, const char *, static int getopt_internal(int, char* const*, const char*,
const struct option *, int *, int); const struct option*, int*, int);
static int parse_long_options(char * const *, const char *, static int parse_long_options(char* const*, const char*,
const struct option *, int *, int); const struct option*, int*, int);
static int gcd(int, int); static int gcd(int, int);
static void permute_args(int, int, int, char * const *); static void permute_args(int, int, int, char* const*);
static char *place = EMSG; /* option letter processing */ static char* place = EMSG; /* option letter processing */
/* XXX: set optreset to 1 rather than these two */ /* XXX: set optreset to 1 rather than these two */
static int nonopt_start = -1; /* first non option argument (for permute) */ static int nonopt_start = -1; /* first non option argument (for permute) */
@ -137,20 +137,22 @@ static const char illoptchar[] = "unknown option -- %c";
static const char illoptstring[] = "unknown option -- %s"; static const char illoptstring[] = "unknown option -- %s";
static void static void
_vwarnx(const char *fmt,va_list ap) _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)fprintf(stderr,"\n"); (void)vfprintf(stderr, fmt, ap);
}
(void)fprintf(stderr, "\n");
} }
static void static void
warnx(const char *fmt,...) warnx(const char* fmt, ...)
{ {
va_list ap; va_list ap;
va_start(ap,fmt); va_start(ap, fmt);
_vwarnx(fmt,ap); _vwarnx(fmt, ap);
va_end(ap); va_end(ap);
} }
@ -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;
@ -179,10 +182,10 @@ gcd(int a, int b)
*/ */
static void static void
permute_args(int panonopt_start, int panonopt_end, int opt_end, permute_args(int panonopt_start, int panonopt_end, int opt_end,
char * const *nargv) char* const* nargv)
{ {
int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos; int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos;
char *swap; char* swap;
/* /*
* compute lengths of blocks and number and size of cycles * compute lengths of blocks and number and size of cycles
@ -192,19 +195,25 @@ 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];
/* LINTED const cast */ /* LINTED const cast */
((char **)nargv)[cstart] = swap; ((char**)nargv)[cstart] = swap;
} }
} }
} }
@ -217,7 +226,7 @@ permute_args(int panonopt_start, int panonopt_end, int opt_end,
* [eventually this will replace the BSD getopt] * [eventually this will replace the BSD getopt]
*/ */
int int
getopt(int nargc, char * const *nargv, const char *options) getopt(int nargc, char* const* nargv, const char* options)
{ {
/* /*
@ -267,9 +276,9 @@ extern "C" {
struct option /* specification for a long form option... */ struct option /* specification for a long form option... */
{ {
const char *name; /* option name, without leading hyphens */ const char* name; /* option name, without leading hyphens */
int has_arg; /* does it take an argument? */ int has_arg; /* does it take an argument? */
int *flag; /* where to save its status, or NULL */ int* flag; /* where to save its status, or NULL */
int val; /* its associated status value */ int val; /* its associated status value */
}; };
@ -286,10 +295,10 @@ enum /* permitted values for its `has_arg' field... */
* Returns -1 if short_too is set and the option does not match long_options. * Returns -1 if short_too is set and the option does not match long_options.
*/ */
static int static int
parse_long_options(char * const *nargv, const char *options, parse_long_options(char* const* nargv, const char* options,
const struct option *long_options, int *idx, int short_too) const struct option* long_options, int* idx, int short_too)
{ {
char *current_argv, *has_equal; char* current_argv, *has_equal;
size_t current_argv_len; size_t current_argv_len;
int i, ambiguous, match; int i, ambiguous, match;
@ -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;
@ -327,85 +344,118 @@ parse_long_options(char * const *nargv, const char *options,
* If this is a known short option, don't allow * If this is a known short option, don't allow
* 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,
current_argv); current_argv);
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 {
&& has_equal) { if(long_options[match].has_arg == no_argument
if (PRINT_ERROR) && has_equal)
{
if(PRINT_ERROR)
warnx(noarg, (int)current_argv_len, warnx(noarg, (int)current_argv_len,
current_argv); current_argv);
/* /*
* 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 == }
required_argument) { else if(long_options[match].has_arg ==
required_argument)
{
/* /*
* optional argument doesn't use next nargv * optional argument doesn't use next nargv
*/ */
optarg = nargv[optind++]; optarg = nargv[optind++];
} }
} }
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.
*/ */
if (PRINT_ERROR) if(PRINT_ERROR)
warnx(recargstring, warnx(recargstring,
current_argv); current_argv);
/* /*
* 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
} }
@ -414,22 +464,26 @@ parse_long_options(char * const *nargv, const char *options,
* Parse argc/argv argument vector. Called by user level routines. * Parse argc/argv argument vector. Called by user level routines.
*/ */
static int static int
getopt_internal(int nargc, char * const *nargv, const char *options, getopt_internal(int nargc, char* const* nargv, const char* options,
const struct option *long_options, int *idx, int flags) const struct option* long_options, int* idx, int flags)
{ {
char *oli; /* option letter list index */ char* oli; /* option letter list index */
int optchar, short_too; int optchar, short_too;
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
@ -438,30 +492,44 @@ getopt_internal(int nargc, char * const *nargv, const char *options,
* CV, 2009-12-14: Check POSIXLY_CORRECT anew if optind == 0 or * CV, 2009-12-14: Check POSIXLY_CORRECT anew if optind == 0 or
* 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.
@ -471,10 +539,12 @@ start:
nonopt_start = nonopt_end = -1; nonopt_start = nonopt_end = -1;
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.
@ -490,9 +561,12 @@ start:
return (-1); return (-1);
} }
/* 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 -
@ -503,20 +577,24 @@ start:
/* process next argument */ /* process next argument */
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;
@ -532,73 +610,107 @@ start:
* 2) the arg is not just "-" * 2) the arg is not just "-"
* 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);
} }
} }
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;
} }
@ -611,8 +723,8 @@ start:
* Parse argc/argv argument vector. * Parse argc/argv argument vector.
*/ */
int int
getopt_long(int nargc, char * const *nargv, const char *options, getopt_long(int nargc, char* const* nargv, const char* options,
const struct option *long_options, int *idx) const struct option* long_options, int* idx)
{ {
return (getopt_internal(nargc, nargv, options, long_options, idx, return (getopt_internal(nargc, nargv, options, long_options, idx,
@ -624,12 +736,12 @@ getopt_long(int nargc, char * const *nargv, const char *options,
* Parse argc/argv argument vector. * Parse argc/argv argument vector.
*/ */
int int
getopt_long_only(int nargc, char * const *nargv, const char *options, getopt_long_only(int nargc, char* const* nargv, const char* options,
const struct option *long_options, int *idx) const struct option* long_options, int* idx)
{ {
return (getopt_internal(nargc, nargv, options, long_options, idx, return (getopt_internal(nargc, nargv, options, long_options, idx,
FLAG_PERMUTE|FLAG_LONGONLY)); FLAG_PERMUTE | FLAG_LONGONLY));
} }
//extern int getopt_long(int nargc, char * const *nargv, const char *options, //extern int getopt_long(int nargc, char * const *nargv, const char *options,

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,108 +151,147 @@ 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;
return buffer; return buffer;
} }
//! 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.
MemoryPoolAllocator(const MemoryPoolAllocator& rhs) /* = delete */; MemoryPoolAllocator(const MemoryPoolAllocator & rhs) /* = delete */;
//! Copy assignment operator is not permitted. //! Copy assignment operator is not permitted.
MemoryPoolAllocator& operator=(const MemoryPoolAllocator& rhs) /* = delete */; MemoryPoolAllocator & operator=(const MemoryPoolAllocator & rhs) /* = delete */;
//! Creates a new chunk. //! Creates a new chunk.
/*! \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,23 +299,26 @@ 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.
}; };
ChunkHeader *chunkHead_; //!< Head of the chunk linked-list. Only the head chunk serves allocation. ChunkHeader* chunkHead_; //!< Head of the chunk linked-list. Only the head chunk serves allocation.
size_t chunk_capacity_; //!< The minimum capacity of chunk when they are allocated. size_t chunk_capacity_; //!< The minimum capacity of chunk when they are allocated.
void *userBuffer_; //!< User supplied buffer. void* userBuffer_; //!< User supplied buffer.
BaseAllocator* baseAllocator_; //!< base allocator for allocating memory chunks. BaseAllocator* baseAllocator_; //!< base allocator for allocating memory chunks.
BaseAllocator* ownBaseAllocator_; //!< base allocator created by this object. BaseAllocator* ownBaseAllocator_; //!< base allocator created by this object.
}; };

File diff suppressed because it is too large Load diff

View file

@ -36,59 +36,112 @@ 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 &);
EncodedInputStream& operator=(const EncodedInputStream&); EncodedInputStream & operator=(const EncodedInputStream &);
InputByteStream& is_; InputByteStream & is_;
Ch current_; Ch current_;
}; };
//! 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_;
private: private:
EncodedInputStream(const EncodedInputStream&); EncodedInputStream(const EncodedInputStream &);
EncodedInputStream& operator=(const EncodedInputStream&); EncodedInputStream & operator=(const EncodedInputStream &);
}; };
//! Output byte stream wrapper with statically bound encoding. //! Output byte stream wrapper with statically bound encoding.
@ -97,31 +150,61 @@ 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 &);
EncodedOutputStream& operator=(const EncodedOutputStream&); EncodedOutputStream & operator=(const EncodedOutputStream &);
OutputByteStream& os_; OutputByteStream & os_;
}; };
#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
@ -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
@ -176,17 +293,54 @@ private:
// FF FE UTF-16LE // FF FE UTF-16LE
// EF BB BF UTF-8 // EF BB BF UTF-8
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,24 +353,43 @@ 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);
InputByteStream* is_; InputByteStream* is_;
UTFType type_; UTFType type_;
Ch current_; Ch current_;
@ -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,43 +415,82 @@ 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_);
} }
typedef void (*PutFunc)(OutputByteStream&, Ch); typedef void (*PutFunc)(OutputByteStream &, Ch);
OutputByteStream* os_; OutputByteStream* os_;
UTFType type_; UTFType type_;

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,70 +223,116 @@ 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
10,3,3,3,3,3,3,3,3,3,3,3,3,4,3,3, 11,6,6,6,5,8,8,8,8,8,8,8,8,8,8,8, 8, 8, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
10, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 3, 3, 11, 6, 6, 6, 5, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
}; };
return type[c]; return type[c];
} }
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,29 +764,33 @@ 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,54 +803,66 @@ 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.
} }
}; };
// Forward declaration. // Forward declaration.
template<typename Stream> template<typename Stream>
inline void PutUnsafe(Stream& stream, typename Stream::Ch c); 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

@ -19,51 +19,72 @@
#ifdef __clang__ #ifdef __clang__
RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(switch-enum) RAPIDJSON_DIAG_OFF(switch - enum)
RAPIDJSON_DIAG_OFF(covered-switch-default) RAPIDJSON_DIAG_OFF(covered - switch - default)
#endif #endif
RAPIDJSON_NAMESPACE_BEGIN RAPIDJSON_NAMESPACE_BEGIN
//! Maps error code of parsing into error message. //! Maps error code of parsing into error message.
/*! /*!
\ingroup RAPIDJSON_ERRORS \ingroup RAPIDJSON_ERRORS
\param parseErrorCode Error code obtained in parsing. \param parseErrorCode Error code obtained in parsing.
\return the error message. \return the error message.
\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.");
}
} }
}
RAPIDJSON_NAMESPACE_END RAPIDJSON_NAMESPACE_END

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

@ -21,8 +21,8 @@
#ifdef __clang__ #ifdef __clang__
RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(padded) RAPIDJSON_DIAG_OFF(padded)
RAPIDJSON_DIAG_OFF(unreachable-code) RAPIDJSON_DIAG_OFF(unreachable - code)
RAPIDJSON_DIAG_OFF(missing-noreturn) RAPIDJSON_DIAG_OFF(missing - noreturn)
#endif #endif
RAPIDJSON_NAMESPACE_BEGIN RAPIDJSON_NAMESPACE_BEGIN
@ -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;
@ -81,10 +115,10 @@ private:
} }
std::FILE* fp_; std::FILE* fp_;
Ch *buffer_; Ch* buffer_;
size_t bufferSize_; size_t bufferSize_;
Ch *bufferLast_; Ch* bufferLast_;
Ch *current_; Ch* current_;
size_t readCount_; size_t readCount_;
size_t count_; //!< Number of characters read size_t count_; //!< Number of characters read
bool eof_; bool eof_;

View file

@ -20,7 +20,7 @@
#ifdef __clang__ #ifdef __clang__
RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(unreachable-code) RAPIDJSON_DIAG_OFF(unreachable - code)
#endif #endif
RAPIDJSON_NAMESPACE_BEGIN RAPIDJSON_NAMESPACE_BEGIN
@ -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,26 +84,47 @@ 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.
FileWriteStream(const FileWriteStream&); FileWriteStream(const FileWriteStream &);
FileWriteStream& operator=(const FileWriteStream&); FileWriteStream & operator=(const FileWriteStream &);
std::FILE* fp_; std::FILE* fp_;
char *buffer_; char* buffer_;
char *bufferEnd_; char* bufferEnd_;
char *current_; char* current_;
}; };
//! 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

@ -46,12 +46,12 @@ class MemoryPoolAllocator;
template <typename Encoding> template <typename Encoding>
struct GenericStringStream; struct GenericStringStream;
typedef GenericStringStream<UTF8<char> > StringStream; typedef GenericStringStream<UTF8<char>> StringStream;
template <typename Encoding> template <typename Encoding>
struct GenericInsituStringStream; struct GenericInsituStringStream;
typedef GenericInsituStringStream<UTF8<char> > InsituStringStream; typedef GenericInsituStringStream<UTF8<char>> InsituStringStream;
// stringbuffer.h // stringbuffer.h
@ -113,7 +113,7 @@ struct GenericStringRef;
template <typename Encoding, typename Allocator> template <typename Encoding, typename Allocator>
class GenericValue; class GenericValue;
typedef GenericValue<UTF8<char>, MemoryPoolAllocator<CrtAllocator> > Value; typedef GenericValue<UTF8<char>, MemoryPoolAllocator<CrtAllocator>> Value;
template <typename Encoding, typename Allocator, typename StackAllocator> template <typename Encoding, typename Allocator, typename StackAllocator>
class GenericDocument; class GenericDocument;
@ -141,10 +141,11 @@ typedef IGenericRemoteSchemaDocumentProvider<SchemaDocument> IRemoteSchemaDocume
template < template <
typename SchemaDocumentType, typename SchemaDocumentType,
typename OutputHandler, typename OutputHandler,
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;
@ -119,48 +159,64 @@ public:
k = p1 >> 32; k = p1 >> 32;
} }
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;
@ -263,14 +372,18 @@ private:
uint64_t x0 = a0 * b0, x1 = a0 * b1, x2 = a1 * b0, x3 = a1 * b1; uint64_t x0 = a0 * b0, x1 = a0 * b1, x2 = a1 * b0, x3 = a1 * b1;
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
@ -282,7 +395,7 @@ private:
Type digits_[kCapacity]; Type digits_[kCapacity];
size_t count_; size_t count_;
}; };
} // namespace internal } // namespace internal
RAPIDJSON_NAMESPACE_END RAPIDJSON_NAMESPACE_END

View file

@ -28,59 +28,71 @@
#endif #endif
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++)
#endif #endif
#ifdef __clang__ #ifdef __clang__
RAPIDJSON_DIAG_PUSH 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;
uint128 p = static_cast<uint128>(f) * static_cast<uint128>(rhs.f); uint128 p = static_cast<uint128>(f) * static_cast<uint128>(rhs.f);
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,11 +153,13 @@ 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;
const uint64_t be = (e == kDpDenormalExponent && (f & kDpHiddenBit) == 0) ? 0 : const uint64_t be = (e == kDpDenormalExponent && (f & kDpHiddenBit) == 0) ? 0 :
static_cast<uint64_t>(e + kDpExponentBias); static_cast<uint64_t>(e + kDpExponentBias);
u.u64 = (f & kDpSignificandMask) | (be << kDpSignificandSize); u.u64 = (f & kDpSignificandMask) | (be << kDpSignificandSize);
@ -159,11 +178,13 @@ struct DiyFp {
uint64_t f; uint64_t f;
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,
@ -221,35 +243,39 @@ inline DiyFp GetCachedPowerByIndex(size_t index) {
907, 933, 960, 986, 1013, 1039, 1066 907, 933, 960, 986, 1013, 1039, 1066
}; };
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
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);
} }
#ifdef __GNUC__ #ifdef __GNUC__
RAPIDJSON_DIAG_POP RAPIDJSON_DIAG_POP
#endif #endif
#ifdef __clang__ #ifdef __clang__
RAPIDJSON_DIAG_POP RAPIDJSON_DIAG_POP
RAPIDJSON_DIAG_OFF(padded) RAPIDJSON_DIAG_OFF(padded)
#endif #endif
} // namespace internal } // namespace internal

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,
while (rest < wp_w && delta - rest >= ten_kappa && uint64_t wp_w)
{
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,24 +156,29 @@ 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));
return; return;
} }
} }
} }
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);
@ -121,111 +190,144 @@ inline void Grisu2(double value, char* buffer, int* length, int* K) {
Wm.f++; Wm.f++;
Wp.f--; Wp.f--;
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] = '.';
buffer[length + 1] = 'e'; buffer[length + 1] = 'e';
return WriteExponent(kk - 1, &buffer[0 + length + 2]); return WriteExponent(kk - 1, &buffer[0 + length + 2]);
} }
} }
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;
} }
@ -233,10 +335,10 @@ inline char* dtoa(double value, char* buffer, int maxDecimalPlaces = 324) {
Grisu2(value, buffer, &length, &K); Grisu2(value, buffer, &length, &K);
return Prettify(buffer, length, K, maxDecimalPlaces); return Prettify(buffer, length, K, maxDecimalPlaces);
} }
} }
#ifdef __GNUC__ #ifdef __GNUC__
RAPIDJSON_DIAG_POP RAPIDJSON_DIAG_POP
#endif #endif
} // namespace internal } // namespace internal

View file

@ -18,46 +18,95 @@
#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;
}
bool IsNan() const { return (u_ & kExponentMask) == kExponentMask && Significand() != 0; } uint64_t Significand() const
bool IsInf() const { return (u_ & kExponentMask) == kExponentMask && Significand() == 0; } {
bool IsNanOrInf() const { return (u_ & kExponentMask) == kExponentMask; } return u_ & kSignificandMask;
bool IsNormal() const { return (u_ & kExponentMask) != 0 || Significand() == 0; } }
bool IsZero() const { return (u_ & (kExponentMask | kSignificandMask)) == 0; } int Exponent() const
{
uint64_t IntegerSignificand() const { return IsNormal() ? Significand() | kHiddenBit : Significand(); } return static_cast<int>(((u_ & kExponentMask) >> kSignificandSize) - kExponentBias);
int IntegerExponent() const { return (IsNormal() ? Exponent() : kDenormalExponent) - kSignificandSize; }
uint64_t ToBias() const { return (u_ & kSignMask) ? ~u_ + 1 : u_ | kSignMask; }
static unsigned EffectiveSignificandSize(int order) {
if (order >= -1021)
return 53;
else if (order <= -1074)
return 0;
else
return static_cast<unsigned>(order) + 1074;
} }
private: bool IsNan() const
{
return (u_ & kExponentMask) == kExponentMask && Significand() != 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();
}
int IntegerExponent() const
{
return (IsNormal() ? Exponent() : kDenormalExponent) - kSignificandSize;
}
uint64_t ToBias() const
{
return (u_ & kSignMask) ? ~u_ + 1 : u_ | kSignMask;
}
static unsigned EffectiveSignificandSize(int order)
{
if(order >= -1021)
{
return 53;
}
else if(order <= -1074)
{
return 0;
}
else
{
return static_cast<unsigned>(order) + 1074;
}
}
private:
static const int kSignificandSize = 52; static const int kSignificandSize = 52;
static const int kExponentBias = 0x3FF; static const int kExponentBias = 0x3FF;
static const int kDenormalExponent = 1 - kExponentBias; static const int kDenormalExponent = 1 - kExponentBias;
@ -66,11 +115,12 @@ 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_;
}; };
}; };
} // namespace internal } // namespace internal
RAPIDJSON_NAMESPACE_END RAPIDJSON_NAMESPACE_END

View file

@ -18,40 +18,52 @@
#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] = { {
'0','0','0','1','0','2','0','3','0','4','0','5','0','6','0','7','0','8','0','9', static const char cDigitsLut[200] =
'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', '0', '0', '0', '1', '0', '2', '0', '3', '0', '4', '0', '5', '0', '6', '0', '7', '0', '8', '0', '9',
'3','0','3','1','3','2','3','3','3','4','3','5','3','6','3','7','3','8','3','9', '1', '0', '1', '1', '1', '2', '1', '3', '1', '4', '1', '5', '1', '6', '1', '7', '1', '8', '1', '9',
'4','0','4','1','4','2','4','3','4','4','4','5','4','6','4','7','4','8','4','9', '2', '0', '2', '1', '2', '2', '2', '3', '2', '4', '2', '5', '2', '6', '2', '7', '2', '8', '2', '9',
'5','0','5','1','5','2','5','3','5','4','5','5','5','6','5','7','5','8','5','9', '3', '0', '3', '1', '3', '2', '3', '3', '3', '4', '3', '5', '3', '6', '3', '7', '3', '8', '3', '9',
'6','0','6','1','6','2','6','3','6','4','6','5','6','6','6','7','6','8','6','9', '4', '0', '4', '1', '4', '2', '4', '3', '4', '4', '4', '5', '4', '6', '4', '7', '4', '8', '4', '9',
'7','0','7','1','7','2','7','3','7','4','7','5','7','6','7','7','7','8','7','9', '5', '0', '5', '1', '5', '2', '5', '3', '5', '4', '5', '5', '5', '6', '5', '7', '5', '8', '5', '9',
'8','0','8','1','8','2','8','3','8','4','8','5','8','6','8','7','8','8','8','9', '6', '0', '6', '1', '6', '2', '6', '3', '6', '4', '6', '5', '6', '6', '6', '7', '6', '8', '6', '9',
'9','0','9','1','9','2','9','3','9','4','9','5','9','6','9','7','9','8','9','9' '7', '0', '7', '1', '7', '2', '7', '3', '7', '4', '7', '5', '7', '6', '7', '7', '7', '8', '7', '9',
'8', '0', '8', '1', '8', '2', '8', '3', '8', '4', '8', '5', '8', '6', '8', '7', '8', '8', '8', '9',
'9', '0', '9', '1', '9', '2', '9', '3', '9', '4', '9', '5', '9', '6', '9', '7', '9', '8', '9', '9'
}; };
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;
@ -62,12 +74,18 @@ inline char* u32toa(uint32_t value, char* buffer) {
const uint32_t d3 = (c / 100) << 1; const uint32_t d3 = (c / 100) << 1;
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
@ -108,19 +130,22 @@ inline char* u32toa(uint32_t value, char* buffer) {
*buffer++ = cDigitsLut[d4 + 1]; *buffer++ = cDigitsLut[d4 + 1];
} }
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;
} }
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;
@ -157,12 +191,18 @@ inline char* u64toa(uint64_t value, char* buffer) {
const uint32_t d3 = (c / 100) << 1; const uint32_t d3 = (c / 100) << 1;
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);
@ -193,22 +234,38 @@ inline char* u64toa(uint64_t value, char* buffer) {
const uint32_t d7 = (c1 / 100) << 1; const uint32_t d7 = (c1 / 100) << 1;
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];
@ -286,17 +349,19 @@ 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;
} }
return u64toa(u, buffer); return u64toa(u, buffer);
} }
} // namespace internal } // namespace internal
RAPIDJSON_NAMESPACE_END RAPIDJSON_NAMESPACE_END

View file

@ -32,121 +32,164 @@ 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;
}; };
typedef BoolType<true> TrueType; typedef BoolType<true> TrueType;
typedef BoolType<false> FalseType; 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 <bool C, typename T1, typename T2> struct SelectIfCond : SelectIfImpl<C>::template Apply<T1,T2> {}; template <typename T1, typename T2> struct Apply
template <typename C, typename T1, typename T2> struct SelectIf : SelectIfCond<C::Value, T1, T2> {}; {
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 <typename C, typename T1, typename T2> struct SelectIf : SelectIfCond<C::Value, T1, T2> {};
template <bool Cond1, bool Cond2> struct AndExprCond : FalseType {}; template <bool Cond1, bool Cond2> struct AndExprCond : FalseType {};
template <> struct AndExprCond<true, true> : TrueType {}; template <> struct AndExprCond<true, true> : TrueType {};
template <bool Cond1, bool Cond2> struct OrExprCond : TrueType {}; template <bool Cond1, bool Cond2> struct OrExprCond : TrueType {};
template <> struct OrExprCond<false, false> : FalseType {}; template <> struct OrExprCond<false, false> : FalseType {};
template <typename C> struct BoolExpr : SelectIf<C,TrueType,FalseType>::Type {}; template <typename C> struct BoolExpr : SelectIf<C, TrueType, FalseType>::Type {};
template <typename C> struct NotExpr : SelectIf<C,FalseType,TrueType>::Type {}; template <typename C> struct NotExpr : SelectIf<C, FalseType, TrueType>::Type {};
template <typename C1, typename C2> struct AndExpr : AndExprCond<C1::Value, C2::Value>::Type {}; template <typename C1, typename C2> struct AndExpr : AndExprCond<C1::Value, C2::Value>::Type {};
template <typename C1, typename C2> struct OrExpr : OrExprCond<C1::Value, C2::Value>::Type {}; template <typename C1, typename C2> struct OrExpr : OrExprCond<C1::Value, C2::Value>::Type {};
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// AddConst, MaybeAddConst, RemoveConst // AddConst, MaybeAddConst, RemoveConst
template <typename T> struct AddConst { typedef const T Type; }; template <typename T> struct AddConst
template <bool Constify, typename T> struct MaybeAddConst : SelectIfCond<Constify, const T, T> {}; {
template <typename T> struct RemoveConst { typedef T Type; }; typedef const T Type;
template <typename T> struct RemoveConst<const T> { typedef T Type; }; };
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<const T>
{
typedef T Type;
};
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// IsSame, IsConst, IsMoreConst, IsPointer // IsSame, IsConst, IsMoreConst, IsPointer
// //
template <typename T, typename U> struct IsSame : FalseType {}; template <typename T, typename U> struct IsSame : FalseType {};
template <typename T> struct IsSame<T, T> : TrueType {}; template <typename T> struct IsSame<T, T> : TrueType {};
template <typename T> struct IsConst : FalseType {}; template <typename T> struct IsConst : FalseType {};
template <typename T> struct IsConst<const T> : TrueType {}; template <typename T> struct IsConst<const T> : TrueType {};
template <typename CT, typename T> template <typename CT, typename T>
struct IsMoreConst struct IsMoreConst
: AndExpr<IsSame<typename RemoveConst<CT>::Type, typename RemoveConst<T>::Type>, : AndExpr<IsSame<typename RemoveConst<CT>::Type, typename RemoveConst<T>::Type>,
BoolType<IsConst<CT>::Value >= IsConst<T>::Value> >::Type {}; BoolType<IsConst<CT>::Value >= IsConst<T>::Value> >::Type {};
template <typename T> struct IsPointer : FalseType {}; template <typename T> struct IsPointer : FalseType {};
template <typename T> struct IsPointer<T*> : TrueType {}; template <typename T> struct IsPointer<T*> : TrueType {};
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// IsBaseOf // IsBaseOf
// //
#if RAPIDJSON_HAS_CXX11_TYPETRAITS #if RAPIDJSON_HAS_CXX11_TYPETRAITS
template <typename B, typename D> struct IsBaseOf template <typename B, typename D> struct IsBaseOf
: BoolType< ::std::is_base_of<B,D>::value> {}; : BoolType<::std::is_base_of<B, D>::value> {};
#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);
typedef char (&Yes)[1]; typedef char(&Yes)[1];
typedef char (&No) [2]; typedef char(&No) [2];
template <typename T> template <typename T>
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 D*(); operator const B* () const;
operator const D* ();
}; };
enum { Value = (sizeof(Check(Host(), 0)) == sizeof(Yes)) }; enum { Value = (sizeof(Check(Host(), 0)) == sizeof(Yes)) };
}; };
template <typename B, typename D> struct IsBaseOf template <typename B, typename D> struct IsBaseOf
: OrExpr<IsSame<B, D>, BoolExpr<IsBaseOfImpl<B, D> > >::Type {}; : OrExpr<IsSame<B, D>, BoolExpr<IsBaseOfImpl<B, D>>>::Type {};
#endif // RAPIDJSON_HAS_CXX11_TYPETRAITS #endif // RAPIDJSON_HAS_CXX11_TYPETRAITS
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
// 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> {};
template <typename Condition, typename T = void> template <typename Condition, typename T = void>
struct DisableIf : DisableIfCond<Condition::Value, T> {}; 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,36 +18,39 @@
#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,
1e+41, 1e+42, 1e+43, 1e+44, 1e+45, 1e+46, 1e+47, 1e+48, 1e+49, 1e+50, 1e+51, 1e+52, 1e+53, 1e+54, 1e+55, 1e+56, 1e+57, 1e+58, 1e+59, 1e+60, 1e+41, 1e+42, 1e+43, 1e+44, 1e+45, 1e+46, 1e+47, 1e+48, 1e+49, 1e+50, 1e+51, 1e+52, 1e+53, 1e+54, 1e+55, 1e+56, 1e+57, 1e+58, 1e+59, 1e+60,
1e+61, 1e+62, 1e+63, 1e+64, 1e+65, 1e+66, 1e+67, 1e+68, 1e+69, 1e+70, 1e+71, 1e+72, 1e+73, 1e+74, 1e+75, 1e+76, 1e+77, 1e+78, 1e+79, 1e+80, 1e+61, 1e+62, 1e+63, 1e+64, 1e+65, 1e+66, 1e+67, 1e+68, 1e+69, 1e+70, 1e+71, 1e+72, 1e+73, 1e+74, 1e+75, 1e+76, 1e+77, 1e+78, 1e+79, 1e+80,
1e+81, 1e+82, 1e+83, 1e+84, 1e+85, 1e+86, 1e+87, 1e+88, 1e+89, 1e+90, 1e+91, 1e+92, 1e+93, 1e+94, 1e+95, 1e+96, 1e+97, 1e+98, 1e+99, 1e+100, 1e+81, 1e+82, 1e+83, 1e+84, 1e+85, 1e+86, 1e+87, 1e+88, 1e+89, 1e+90, 1e+91, 1e+92, 1e+93, 1e+94, 1e+95, 1e+96, 1e+97, 1e+98, 1e+99, 1e+100,
1e+101,1e+102,1e+103,1e+104,1e+105,1e+106,1e+107,1e+108,1e+109,1e+110,1e+111,1e+112,1e+113,1e+114,1e+115,1e+116,1e+117,1e+118,1e+119,1e+120, 1e+101, 1e+102, 1e+103, 1e+104, 1e+105, 1e+106, 1e+107, 1e+108, 1e+109, 1e+110, 1e+111, 1e+112, 1e+113, 1e+114, 1e+115, 1e+116, 1e+117, 1e+118, 1e+119, 1e+120,
1e+121,1e+122,1e+123,1e+124,1e+125,1e+126,1e+127,1e+128,1e+129,1e+130,1e+131,1e+132,1e+133,1e+134,1e+135,1e+136,1e+137,1e+138,1e+139,1e+140, 1e+121, 1e+122, 1e+123, 1e+124, 1e+125, 1e+126, 1e+127, 1e+128, 1e+129, 1e+130, 1e+131, 1e+132, 1e+133, 1e+134, 1e+135, 1e+136, 1e+137, 1e+138, 1e+139, 1e+140,
1e+141,1e+142,1e+143,1e+144,1e+145,1e+146,1e+147,1e+148,1e+149,1e+150,1e+151,1e+152,1e+153,1e+154,1e+155,1e+156,1e+157,1e+158,1e+159,1e+160, 1e+141, 1e+142, 1e+143, 1e+144, 1e+145, 1e+146, 1e+147, 1e+148, 1e+149, 1e+150, 1e+151, 1e+152, 1e+153, 1e+154, 1e+155, 1e+156, 1e+157, 1e+158, 1e+159, 1e+160,
1e+161,1e+162,1e+163,1e+164,1e+165,1e+166,1e+167,1e+168,1e+169,1e+170,1e+171,1e+172,1e+173,1e+174,1e+175,1e+176,1e+177,1e+178,1e+179,1e+180, 1e+161, 1e+162, 1e+163, 1e+164, 1e+165, 1e+166, 1e+167, 1e+168, 1e+169, 1e+170, 1e+171, 1e+172, 1e+173, 1e+174, 1e+175, 1e+176, 1e+177, 1e+178, 1e+179, 1e+180,
1e+181,1e+182,1e+183,1e+184,1e+185,1e+186,1e+187,1e+188,1e+189,1e+190,1e+191,1e+192,1e+193,1e+194,1e+195,1e+196,1e+197,1e+198,1e+199,1e+200, 1e+181, 1e+182, 1e+183, 1e+184, 1e+185, 1e+186, 1e+187, 1e+188, 1e+189, 1e+190, 1e+191, 1e+192, 1e+193, 1e+194, 1e+195, 1e+196, 1e+197, 1e+198, 1e+199, 1e+200,
1e+201,1e+202,1e+203,1e+204,1e+205,1e+206,1e+207,1e+208,1e+209,1e+210,1e+211,1e+212,1e+213,1e+214,1e+215,1e+216,1e+217,1e+218,1e+219,1e+220, 1e+201, 1e+202, 1e+203, 1e+204, 1e+205, 1e+206, 1e+207, 1e+208, 1e+209, 1e+210, 1e+211, 1e+212, 1e+213, 1e+214, 1e+215, 1e+216, 1e+217, 1e+218, 1e+219, 1e+220,
1e+221,1e+222,1e+223,1e+224,1e+225,1e+226,1e+227,1e+228,1e+229,1e+230,1e+231,1e+232,1e+233,1e+234,1e+235,1e+236,1e+237,1e+238,1e+239,1e+240, 1e+221, 1e+222, 1e+223, 1e+224, 1e+225, 1e+226, 1e+227, 1e+228, 1e+229, 1e+230, 1e+231, 1e+232, 1e+233, 1e+234, 1e+235, 1e+236, 1e+237, 1e+238, 1e+239, 1e+240,
1e+241,1e+242,1e+243,1e+244,1e+245,1e+246,1e+247,1e+248,1e+249,1e+250,1e+251,1e+252,1e+253,1e+254,1e+255,1e+256,1e+257,1e+258,1e+259,1e+260, 1e+241, 1e+242, 1e+243, 1e+244, 1e+245, 1e+246, 1e+247, 1e+248, 1e+249, 1e+250, 1e+251, 1e+252, 1e+253, 1e+254, 1e+255, 1e+256, 1e+257, 1e+258, 1e+259, 1e+260,
1e+261,1e+262,1e+263,1e+264,1e+265,1e+266,1e+267,1e+268,1e+269,1e+270,1e+271,1e+272,1e+273,1e+274,1e+275,1e+276,1e+277,1e+278,1e+279,1e+280, 1e+261, 1e+262, 1e+263, 1e+264, 1e+265, 1e+266, 1e+267, 1e+268, 1e+269, 1e+270, 1e+271, 1e+272, 1e+273, 1e+274, 1e+275, 1e+276, 1e+277, 1e+278, 1e+279, 1e+280,
1e+281,1e+282,1e+283,1e+284,1e+285,1e+286,1e+287,1e+288,1e+289,1e+290,1e+291,1e+292,1e+293,1e+294,1e+295,1e+296,1e+297,1e+298,1e+299,1e+300, 1e+281, 1e+282, 1e+283, 1e+284, 1e+285, 1e+286, 1e+287, 1e+288, 1e+289, 1e+290, 1e+291, 1e+292, 1e+293, 1e+294, 1e+295, 1e+296, 1e+297, 1e+298, 1e+299, 1e+300,
1e+301,1e+302,1e+303,1e+304,1e+305,1e+306,1e+307,1e+308 1e+301, 1e+302, 1e+303, 1e+304, 1e+305, 1e+306, 1e+307, 1e+308
}; };
RAPIDJSON_ASSERT(n >= 0 && n <= 308); RAPIDJSON_ASSERT(n >= 0 && n <= 308);
return e[n]; return e[n];
} }
} // namespace internal } // namespace internal
RAPIDJSON_NAMESPACE_END RAPIDJSON_NAMESPACE_END

View file

@ -22,35 +22,37 @@
#ifdef __clang__ #ifdef __clang__
RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(padded) RAPIDJSON_DIAG_OFF(padded)
RAPIDJSON_DIAG_OFF(switch-enum) RAPIDJSON_DIAG_OFF(switch - enum)
RAPIDJSON_DIAG_OFF(implicit-fallthrough) RAPIDJSON_DIAG_OFF(implicit - fallthrough)
#endif #endif
#ifdef __GNUC__ #ifdef __GNUC__
RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(effc++) RAPIDJSON_DIAG_OFF(effc++)
#endif #endif
#ifdef _MSC_VER #ifdef _MSC_VER
RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated
#endif #endif
#ifndef RAPIDJSON_REGEX_VERBOSE #ifndef RAPIDJSON_REGEX_VERBOSE
#define RAPIDJSON_REGEX_VERBOSE 0 #define RAPIDJSON_REGEX_VERBOSE 0
#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(
static const SizeType kRegexInvalidRange = ~SizeType(0); 0); //!< Represents an invalid index in GenericRegex::State::out, out1
static const SizeType kRegexInvalidRange = ~SizeType(0);
//! Regular expression engine with subset of ECMAscript grammar. //! Regular expression engine with subset of ECMAscript grammar.
/*! /*!
Supported regular expression syntax: Supported regular expression syntax:
- \c ab Concatenation - \c ab Concatenation
- \c a|b Alternation - \c a|b Alternation
@ -80,10 +82,11 @@ static const SizeType kRegexInvalidRange = ~SizeType(0);
\note This is a Thompson NFA engine, implemented with reference to \note This is a Thompson NFA engine, implemented with reference to
Cox, Russ. "Regular Expression Matching Can Be Simple And Fast (but is slow in Java, Perl, PHP, Python, Ruby,...).", Cox, Russ. "Regular Expression Matching Can Be Simple And Fast (but is slow in Java, Perl, PHP, Python, Ruby,...).",
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;
GenericRegex(const Ch* source, Allocator* allocator = 0) : GenericRegex(const Ch* source, Allocator* allocator = 0) :
@ -91,40 +94,47 @@ public:
stateSet_(), state0_(allocator, 0), state1_(allocator, 0), anchorBegin_(), anchorEnd_() stateSet_(), state0_(allocator, 0), state1_(allocator, 0), anchorBegin_(), anchorEnd_()
{ {
GenericStringStream<Encoding> ss(source); GenericStringStream<Encoding> ss(source);
DecodedStream<GenericStringStream<Encoding> > ds(ss); DecodedStream<GenericStringStream<Encoding>> ds(ss);
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() {
unsigned c = codepoint_;
if (c) // No further decoding when '\0'
Decode(); Decode();
}
unsigned Peek()
{
return codepoint_;
}
unsigned Take()
{
unsigned c = codepoint_;
if(c) // No further decoding when '\0'
{
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;
@ -220,9 +253,11 @@ private:
break; break;
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;
@ -233,49 +268,70 @@ private:
break; break;
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);
break; break;
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;
} }
else
m = n;
if (!EvalQuantifier(operandStack, n, m) || ds.Peek() != '}') if(ds.Peek() == ',')
{
ds.Take();
if(ds.Peek() == '}')
{
m = kInfinityQuantifier;
}
else if(!ParseUnsigned(ds, &m) || m < n)
{
return; return;
}
}
else
{
m = n;
}
if(!EvalQuantifier(operandStack, n, m) || ds.Peek() != '}')
{
return;
}
ds.Take(); ds.Take();
} }
break; break;
@ -288,8 +344,10 @@ private:
case '[': case '[':
{ {
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);
@ -298,8 +356,10 @@ private:
break; break;
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
@ -308,20 +368,24 @@ 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);
} }
printf("\n"); printf("\n");
@ -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) }
Eval(operandStack, kZeroOrMore); // a{0,} -> a* else if(m == kInfinityQuantifier)
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? {
for (unsigned i = 0; i < m - 1; i++) CloneTopOperand(operandStack);
Eval(operandStack, kConcatenation); // a{0,5} -> a?a?a?a?a? } // a{0,5} -> a? a? a? a? a?
for(unsigned i = 0; i < m - 1; i++)
{
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? {
for (unsigned i = n; i < m; i++) CloneTopOperand(operandStack);
Eval(operandStack, kConcatenation); // a{3,5} -> a a aa?a? } // a{3,5} -> a a a a? a?
for(unsigned i = n; i < m; i++)
{
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') { }
if (r >= 429496729 && ds.Peek() > '5') // 2^32 - 1 = 4294967295 while(ds.Peek() >= '0' && ds.Peek() <= '9')
{
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;
} }
@ -548,10 +682,14 @@ private:
case 0: case 0:
{ {
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,78 +733,105 @@ 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);
state0_.Clear(); state0_.Clear();
Stack<Allocator> *current = &state0_, *next = &state1_; Stack<Allocator>* current = &state0_, *next = &state1_;
const size_t stateSetSize = GetStateSetSize(); const size_t stateSetSize = GetStateSetSize();
std::memset(stateSet_, 0, stateSetSize); std::memset(stateSet_, 0, stateSetSize);
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); {
if (sr.codepoint == codepoint || const State & sr = GetState(*s);
if(sr.codepoint == codepoint ||
sr.codepoint == kAnyCharacterClass || sr.codepoint == kAnyCharacterClass ||
(sr.codepoint == kRangeCharacterClass && MatchRange(sr.rangeStart, codepoint))) (sr.codepoint == kRangeCharacterClass && MatchRange(sr.rangeStart, codepoint)))
{ {
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); {
if (codepoint >= (r.start & ~kRangeNegationFlag) && codepoint <= r.end) const Range & r = GetRange(rangeIndex);
if(codepoint >= (r.start & ~kRangeNegationFlag) && codepoint <= r.end)
{
return yes; return yes;
}
rangeIndex = r.next; rangeIndex = r.next;
} }
return !yes; return !yes;
@ -683,11 +851,11 @@ private:
mutable Stack<Allocator> state1_; mutable Stack<Allocator> state1_;
bool anchorBegin_; bool anchorBegin_;
bool anchorEnd_; bool anchorEnd_;
}; };
typedef GenericRegex<UTF8<> > Regex; typedef GenericRegex<UTF8<>> Regex;
} // namespace internal } // namespace internal
RAPIDJSON_NAMESPACE_END RAPIDJSON_NAMESPACE_END
#ifdef __clang__ #ifdef __clang__

View file

@ -20,28 +20,32 @@
#if defined(__clang__) #if defined(__clang__)
RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(c++98-compat) RAPIDJSON_DIAG_OFF(c++98 - compat)
#endif #endif
RAPIDJSON_NAMESPACE_BEGIN RAPIDJSON_NAMESPACE_BEGIN
namespace internal { namespace internal
{
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// Stack // Stack
//! A type-unsafe stack for storing different types of data. //! A type-unsafe stack for storing different types of data.
/*! \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
Stack(Stack&& rhs) Stack(Stack && rhs)
: allocator_(rhs.allocator_), : allocator_(rhs.allocator_),
ownAllocator_(rhs.ownAllocator_), ownAllocator_(rhs.ownAllocator_),
stack_(rhs.stack_), stack_(rhs.stack_),
@ -58,13 +62,15 @@ 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,92 +152,128 @@ 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
} }
// Prohibit copy constructor & assignment operator. // Prohibit copy constructor & assignment operator.
Stack(const Stack&); Stack(const Stack &);
Stack& operator=(const Stack&); Stack & operator=(const Stack &);
Allocator* allocator_; Allocator* allocator_;
Allocator* ownAllocator_; Allocator* ownAllocator_;
char *stack_; char* stack_;
char *stackTop_; char* stackTop_;
char *stackEnd_; char* stackEnd_;
size_t initialCapacity_; size_t initialCapacity_;
}; };
} // namespace internal } // namespace internal
RAPIDJSON_NAMESPACE_END RAPIDJSON_NAMESPACE_END

View file

@ -18,36 +18,45 @@
#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)
\param s Null-terminated input string. \param s Null-terminated input string.
\return Number of characters in the string. \return Number of characters in the string.
\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;
return true; return true;
} }
} // namespace internal } // namespace internal
RAPIDJSON_NAMESPACE_END RAPIDJSON_NAMESPACE_END

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;
@ -72,17 +94,23 @@ 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;
} }
@ -106,38 +134,49 @@ inline int CheckWithinHalfULP(double b, const BigInteger& d, int dExp) {
dS.Difference(bS, &delta); dS.Difference(bS, &delta);
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
@ -165,9 +206,11 @@ inline bool StrtodDiyFp(const char* decimals, size_t length, size_t decimalPosit
int adjustment = dExp - actualExp - 1; int adjustment = dExp - actualExp - 1;
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);
@ -253,15 +318,19 @@ 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);
} }
} // namespace internal } // namespace internal
RAPIDJSON_NAMESPACE_END RAPIDJSON_NAMESPACE_END

View file

@ -19,22 +19,24 @@
#if defined(__clang__) #if defined(__clang__)
RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(c++98-compat) 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;
} }
} // namespace internal } // namespace internal
RAPIDJSON_NAMESPACE_END RAPIDJSON_NAMESPACE_END

View file

@ -47,58 +47,86 @@ 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;
} }
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;
} }
private: private:
BasicIStreamWrapper(const BasicIStreamWrapper&); BasicIStreamWrapper(const BasicIStreamWrapper &);
BasicIStreamWrapper& operator=(const BasicIStreamWrapper&); BasicIStreamWrapper & operator=(const BasicIStreamWrapper &);
StreamType& stream_; StreamType & stream_;
size_t count_; //!< Number of characters read. Note: size_t count_; //!< Number of characters read. Note:
mutable Ch peekBuffer_[4]; mutable Ch peekBuffer_[4];
}; };

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

@ -19,8 +19,8 @@
#ifdef __clang__ #ifdef __clang__
RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(unreachable-code) RAPIDJSON_DIAG_OFF(unreachable - code)
RAPIDJSON_DIAG_OFF(missing-noreturn) RAPIDJSON_DIAG_OFF(missing - noreturn)
#endif #endif
RAPIDJSON_NAMESPACE_BEGIN RAPIDJSON_NAMESPACE_BEGIN
@ -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,31 +42,54 @@ 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 &);
BasicOStreamWrapper& operator=(const BasicOStreamWrapper&); BasicOStreamWrapper & operator=(const BasicOStreamWrapper &);
StreamType& stream_; StreamType & stream_;
}; };
typedef BasicOStreamWrapper<std::ostream> OStreamWrapper; typedef BasicOStreamWrapper<std::ostream> OStreamWrapper;

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,85 +87,130 @@ 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();
} }
bool ret = Base::WriteEndObject(); bool ret = Base::WriteEndObject();
(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();
} }
bool ret = Base::WriteEndArray(); bool ret = Base::WriteEndArray();
(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);
} }
@ -242,8 +321,8 @@ protected:
private: private:
// Prohibit copy constructor & assignment operator. // Prohibit copy constructor & assignment operator.
PrettyWriter(const PrettyWriter&); PrettyWriter(const PrettyWriter &);
PrettyWriter& operator=(const PrettyWriter&); PrettyWriter & operator=(const PrettyWriter &);
}; };
RAPIDJSON_NAMESPACE_END RAPIDJSON_NAMESPACE_END

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
@ -475,7 +478,7 @@ RAPIDJSON_NAMESPACE_END
#define RAPIDJSON_MULTILINEMACRO_BEGIN do { #define RAPIDJSON_MULTILINEMACRO_BEGIN do {
#define RAPIDJSON_MULTILINEMACRO_END \ #define RAPIDJSON_MULTILINEMACRO_END \
} while((void)0, 0) } while((void)0, 0)
// adopted from Boost // adopted from Boost
#define RAPIDJSON_VERSION_CODE(x,y,z) \ #define RAPIDJSON_VERSION_CODE(x,y,z) \
@ -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,23 +82,28 @@ 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);
}
} }
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
@ -107,31 +113,56 @@ 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 };
}; };
//! String stream with UTF8 encoding. //! String stream with UTF8 encoding.
typedef GenericStringStream<UTF8<> > StringStream; typedef GenericStringStream<UTF8<>> StringStream;
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// InsituStringStream // InsituStringStream
@ -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,12 +226,13 @@ struct GenericInsituStringStream {
}; };
template <typename Encoding> template <typename Encoding>
struct StreamTraits<GenericInsituStringStream<Encoding> > { struct StreamTraits<GenericInsituStringStream<Encoding>>
{
enum { copyOptimization = 1 }; enum { copyOptimization = 1 };
}; };
//! Insitu string stream with UTF8 encoding. //! Insitu string stream with UTF8 encoding.
typedef GenericInsituStringStream<UTF8<> > InsituStringStream; typedef GenericInsituStringStream<UTF8<>> InsituStringStream;
RAPIDJSON_NAMESPACE_END RAPIDJSON_NAMESPACE_END

View file

@ -26,7 +26,7 @@
#if defined(__clang__) #if defined(__clang__)
RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(c++98-compat) RAPIDJSON_DIAG_OFF(c++98 - compat)
#endif #endif
RAPIDJSON_NAMESPACE_BEGIN RAPIDJSON_NAMESPACE_BEGIN
@ -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,33 +106,39 @@ 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_;
private: private:
// Prohibit copy constructor & assignment operator. // Prohibit copy constructor & assignment operator.
GenericStringBuffer(const GenericStringBuffer&); GenericStringBuffer(const GenericStringBuffer &);
GenericStringBuffer& operator=(const GenericStringBuffer&); GenericStringBuffer & operator=(const GenericStringBuffer &);
}; };
//! String buffer with UTF8 encoding //! String buffer with UTF8 encoding
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

@ -41,7 +41,7 @@ RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant
#ifdef __clang__ #ifdef __clang__
RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(padded) RAPIDJSON_DIAG_OFF(padded)
RAPIDJSON_DIAG_OFF(unreachable-code) RAPIDJSON_DIAG_OFF(unreachable - code)
#endif #endif
RAPIDJSON_NAMESPACE_BEGIN RAPIDJSON_NAMESPACE_BEGIN
@ -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;
@ -96,12 +98,14 @@ public:
\param levelDepth Initial capacity of stack. \param levelDepth Initial capacity of stack.
*/ */
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,124 +318,181 @@ 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 (!(writeFlags & kWriteNanAndInfFlag)) if(internal::Double(d).IsNanOrInf())
{
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;
} }
char buffer[25]; char buffer[25];
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
'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', // 10 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', // 10
0, 0, '"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20 0, 0, '"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20
Z16, Z16, // 30~4F Z16, Z16, // 30~4F
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\\', 0, 0, 0, // 50 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '\\', 0, 0, 0, // 50
Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16 // 60~FF Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16 // 60~FF
#undef Z16 #undef Z16
}; };
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;
@ -387,77 +501,114 @@ protected:
PutUnsafe(*os_, hexDigits[(lead >> 12) & 15]); PutUnsafe(*os_, hexDigits[(lead >> 12) & 15]);
PutUnsafe(*os_, hexDigits[(lead >> 8) & 15]); PutUnsafe(*os_, hexDigits[(lead >> 8) & 15]);
PutUnsafe(*os_, hexDigits[(lead >> 4) & 15]); PutUnsafe(*os_, hexDigits[(lead >> 4) & 15]);
PutUnsafe(*os_, hexDigits[(lead ) & 15]); PutUnsafe(*os_, hexDigits[(lead) & 15]);
PutUnsafe(*os_, '\\'); PutUnsafe(*os_, '\\');
PutUnsafe(*os_, 'u'); PutUnsafe(*os_, 'u');
PutUnsafe(*os_, hexDigits[(trail >> 12) & 15]); PutUnsafe(*os_, hexDigits[(trail >> 12) & 15]);
PutUnsafe(*os_, hexDigits[(trail >> 8) & 15]); PutUnsafe(*os_, hexDigits[(trail >> 8) & 15]);
PutUnsafe(*os_, hexDigits[(trail >> 4) & 15]); PutUnsafe(*os_, hexDigits[(trail >> 4) & 15]);
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]);
PutUnsafe(*os_, hexDigits[static_cast<unsigned char>(c) & 0xF]); PutUnsafe(*os_, hexDigits[static_cast<unsigned char>(c) & 0xF]);
} }
} }
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;
} }
@ -468,67 +619,87 @@ protected:
private: private:
// Prohibit copy constructor & assignment operator. // Prohibit copy constructor & assignment operator.
Writer(const Writer&); Writer(const Writer &);
Writer& operator=(const Writer&); Writer & operator=(const Writer &);
}; };
// 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)));
return true; return true;
} }
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)));
return true; return true;
} }
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)));
return true; return true;
} }
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)));
return true; return true;
} }
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;
} }
char *buffer = os_->Push(25); char* buffer = os_->Push(25);
char* end = internal::dtoa(d, buffer, maxDecimalPlaces_); char* end = internal::dtoa(d, buffer, maxDecimalPlaces_);
os_->Pop(static_cast<size_t>(25 - (end - buffer))); os_->Pop(static_cast<size_t>(25 - (end - buffer)));
return true; return true;
@ -536,44 +707,58 @@ 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));
if (nextAligned > end) const char* endAligned = reinterpret_cast<const char*>(reinterpret_cast<size_t>(end) & static_cast<size_t>
(~15));
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] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' };
static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' }; static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' };
static const char space[16] = { 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19 }; static const char space[16] = { 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19 };
const __m128i dq = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&dquote[0])); const __m128i dq = _mm_loadu_si128(reinterpret_cast<const __m128i*>(&dquote[0]));
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;
@ -583,13 +768,15 @@ inline bool Writer<StringBuffer>::ScanWriteUnescapedString(StringStream& is, siz
len = static_cast<SizeType>(__builtin_ffs(r) - 1); len = static_cast<SizeType>(__builtin_ffs(r) - 1);
#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;
} }
_mm_storeu_si128(reinterpret_cast<__m128i *>(os_->PushUnsafe(16)), s); _mm_storeu_si128(reinterpret_cast<__m128i*>(os_->PushUnsafe(16)), s);
} }
is.src_ = p; is.src_ = p;

View file

@ -40,7 +40,7 @@ class Options;
class App : public IConsoleListener class App : public IConsoleListener
{ {
public: public:
App(int argc, char **argv); App(int argc, char** argv);
~App(); ~App();
int exec(); int exec();
@ -52,14 +52,14 @@ private:
void background(); void background();
void close(); void close();
static void onSignal(uv_signal_t *handle, int signum); static void onSignal(uv_signal_t* handle, int signum);
static App *m_self; static App* m_self;
Console *m_console; Console* m_console;
Httpd *m_httpd; Httpd* m_httpd;
Network *m_network; Network* m_network;
Options *m_options; Options* m_options;
uv_signal_t m_sigHUP; uv_signal_t m_sigHUP;
uv_signal_t m_sigINT; uv_signal_t m_sigINT;
uv_signal_t m_sigTERM; uv_signal_t m_sigTERM;

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

@ -26,13 +26,14 @@
#include "interfaces/IConsoleListener.h" #include "interfaces/IConsoleListener.h"
Console::Console(IConsoleListener *listener) Console::Console(IConsoleListener* listener)
: m_listener(listener) : m_listener(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;
} }
@ -41,7 +42,7 @@ Console::Console(IConsoleListener *listener)
} }
void Console::onAllocBuffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf) void Console::onAllocBuffer(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf)
{ {
auto console = static_cast<Console*>(handle->data); auto console = static_cast<Console*>(handle->data);
buf->len = 1; buf->len = 1;
@ -49,13 +50,15 @@ 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

@ -34,14 +34,14 @@ class IConsoleListener;
class Console class Console
{ {
public: public:
Console(IConsoleListener *listener); Console(IConsoleListener* listener);
private: private:
static void onAllocBuffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf); static void onAllocBuffer(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf);
static void onRead(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf); static void onRead(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf);
char m_buf[1]; char m_buf[1];
IConsoleListener *m_listener; IConsoleListener* m_listener;
uv_tty_t m_tty; uv_tty_t m_tty;
}; };

View file

@ -38,22 +38,38 @@ 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
}; };
static bool allocate(int algo, int threads, bool doubleHash, bool enabled); static bool allocate(int algo, int threads, bool doubleHash, bool enabled);
static cryptonight_ctx *create(int threadId); static cryptonight_ctx* create(int threadId);
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;
@ -61,10 +77,10 @@ private:
static int m_flags; static int m_flags;
static int m_threads; static int m_threads;
static size_t m_offset; static size_t m_offset;
VAR_ALIGN(16, static uint8_t *m_memory); VAR_ALIGN(16, static uint8_t* m_memory);
# ifndef XMRIG_NO_AEON # ifndef XMRIG_NO_AEON
static cryptonight_ctx *createLite(int threadId); static cryptonight_ctx* createLite(int threadId);
# endif # endif
}; };

View file

@ -41,7 +41,7 @@ void Handle::join()
} }
void Handle::start(void (*callback) (void *)) void Handle::start(void (*callback)(void*))
{ {
uv_thread_create(&m_thread, callback, this); uv_thread_create(&m_thread, callback, this);
} }

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();