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,37 +29,42 @@
#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;
}
return __mallocedMemory; return __mallocedMemory;
} }
static __inline__ void __attribute__((__always_inline__)) _mm_free(void *__p) static __inline__ void __attribute__((__always_inline__)) _mm_free(void* __p)
{ {
free(__p); free(__p);
} }
#endif /* __ALIGNED_MALLOC_H__ */ #endif /* __ALIGNED_MALLOC_H__ */

View file

@ -3,30 +3,30 @@
* DISCLAIMER * DISCLAIMER
* This file is part of the mingw-w64 runtime package. * This file is part of the mingw-w64 runtime package.
* *
* The mingw-w64 runtime package and its code is distributed in the hope that it * The mingw-w64 runtime package and its code is distributed in the hope that it
* will be useful but WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESSED OR * will be useful but WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESSED OR
* 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,21 +137,23 @@ 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,17 +276,17 @@ 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 */
}; };
enum /* permitted values for its `has_arg' field... */ enum /* permitted values for its `has_arg' field... */
{ {
no_argument = 0, /* option never takes an argument */ no_argument = 0, /* option never takes an argument */
required_argument, /* option always requires an argument */ required_argument, /* option always requires an argument */
optional_argument /* option may take an argument */ optional_argument /* option may take an argument */
}; };
/* /*
@ -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,35 +561,42 @@ 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 -
(nonopt_end - nonopt_start); (nonopt_end - nonopt_start);
nonopt_end = -1; nonopt_end = -1;
} }
optind++; optind++;
/* 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;
} }
nonopt_start = nonopt_end = -1; nonopt_start = nonopt_end = -1;
@ -532,72 +610,106 @@ 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 */ {
else if (*place != ':' && strchr(options, *place) != NULL) place++; /* --foo long option */
short_too = 1; /* could be short option too */ }
else if(*place != ':' && strchr(options, *place) != NULL)
{
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,12 +723,12 @@ 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,
FLAG_PERMUTE)); FLAG_PERMUTE));
} }
/* /*
@ -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

@ -1,5 +1,5 @@
// Tencent is pleased to support the open source community by making RapidJSON available. // Tencent is pleased to support the open source community by making RapidJSON available.
// //
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// //
// Licensed under the MIT License (the "License"); you may not use this file except // Licensed under the MIT License (the "License"); you may not use this file except
@ -7,9 +7,9 @@
// //
// http://opensource.org/licenses/MIT // http://opensource.org/licenses/MIT
// //
// Unless required by applicable law or agreed to in writing, software distributed // Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License. // specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_ALLOCATORS_H_ #ifndef RAPIDJSON_ALLOCATORS_H_
@ -24,10 +24,10 @@ RAPIDJSON_NAMESPACE_BEGIN
/*! \class rapidjson::Allocator /*! \class rapidjson::Allocator
\brief Concept for allocating, resizing and freeing memory block. \brief Concept for allocating, resizing and freeing memory block.
Note that Malloc() and Realloc() are non-static but Free() is static. Note that Malloc() and Realloc() are non-static but Free() is static.
So if an allocator need to support Free(), it needs to put its pointer in So if an allocator need to support Free(), it needs to put its pointer in
the header of memory block. the header of memory block.
\code \code
@ -59,31 +59,42 @@ 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. {
return std::malloc(size); if(size) // behavior of malloc(0) is implementation defined.
else {
return NULL; // standardize to returning NULL. return std::malloc(size);
} }
void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) { else
(void)originalSize; {
if (newSize == 0) { return NULL; // standardize to returning NULL.
std::free(originalPtr); }
return NULL; }
} void* Realloc(void* originalPtr, size_t originalSize, size_t newSize)
return std::realloc(originalPtr, newSize); {
} (void)originalSize;
static void Free(void *ptr) { std::free(ptr); } if(newSize == 0)
{
std::free(originalPtr);
return NULL;
}
return std::realloc(originalPtr, newSize);
}
static void Free(void* ptr)
{
std::free(ptr);
}
}; };
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// MemoryPoolAllocator // MemoryPoolAllocator
//! Default memory allocator used by the parser and DOM. //! Default memory allocator used by the parser and DOM.
/*! This allocator allocate memory blocks from pre-allocated memory chunks. /*! This allocator allocate memory blocks from pre-allocated memory chunks.
It does not free memory blocks. And Realloc() only allocate new memory. It does not free memory blocks. And Realloc() only allocate new memory.
@ -99,171 +110,217 @@ 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.
\param baseAllocator The allocator for allocating memory chunks. \param baseAllocator The allocator for allocating memory chunks.
*/ */
MemoryPoolAllocator(size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) : MemoryPoolAllocator(size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) :
chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(0), baseAllocator_(baseAllocator), ownBaseAllocator_(0) chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(0), baseAllocator_(baseAllocator), ownBaseAllocator_(0)
{ {
} }
//! Constructor with user-supplied buffer. //! Constructor with user-supplied buffer.
/*! The user buffer will be used firstly. When it is full, memory pool allocates new chunk with chunk size. /*! The user buffer will be used firstly. When it is full, memory pool allocates new chunk with chunk size.
The user buffer will not be deallocated when this allocator is destructed. The user buffer will not be deallocated when this allocator is destructed.
\param buffer User supplied buffer. \param buffer User supplied buffer.
\param size Size of the buffer in bytes. It must at least larger than sizeof(ChunkHeader). \param size Size of the buffer in bytes. It must at least larger than sizeof(ChunkHeader).
\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),
RAPIDJSON_ASSERT(buffer != 0); ownBaseAllocator_(0)
RAPIDJSON_ASSERT(size > sizeof(ChunkHeader)); {
chunkHead_ = reinterpret_cast<ChunkHeader*>(buffer); RAPIDJSON_ASSERT(buffer != 0);
chunkHead_->capacity = size - sizeof(ChunkHeader); RAPIDJSON_ASSERT(size > sizeof(ChunkHeader));
chunkHead_->size = 0; chunkHead_ = reinterpret_cast<ChunkHeader*>(buffer);
chunkHead_->next = 0; chunkHead_->capacity = size - sizeof(ChunkHeader);
} chunkHead_->size = 0;
chunkHead_->next = 0;
}
//! 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(); {
RAPIDJSON_DELETE(ownBaseAllocator_); Clear();
} 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_) { {
ChunkHeader* next = chunkHead_->next; while(chunkHead_ && chunkHead_ != userBuffer_)
baseAllocator_->Free(chunkHead_); {
chunkHead_ = next; ChunkHeader* next = chunkHead_->next;
} baseAllocator_->Free(chunkHead_);
if (chunkHead_ && chunkHead_ == userBuffer_) chunkHead_ = next;
chunkHead_->size = 0; // Clear user buffer }
} if(chunkHead_ && chunkHead_ == userBuffer_)
{
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; {
for (ChunkHeader* c = chunkHead_; c != 0; c = c->next) size_t capacity = 0;
capacity += c->capacity; for(ChunkHeader* c = chunkHead_; c != 0; c = c->next)
return capacity; {
} capacity += c->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; {
for (ChunkHeader* c = chunkHead_; c != 0; c = c->next) size_t size = 0;
size += c->size; for(ChunkHeader* c = chunkHead_; c != 0; c = c->next)
return size; {
} size += c->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) {
return NULL; if(!size)
{
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) {
return Malloc(newSize); if(originalPtr == 0)
{
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(
size_t increment = static_cast<size_t>(newSize - originalSize); ChunkHeader)) + chunkHead_->size - originalSize)
if (chunkHead_->size + increment <= chunkHead_->capacity) { {
chunkHead_->size += increment; size_t increment = static_cast<size_t>(newSize - originalSize);
return originalPtr; if(chunkHead_->size + increment <= chunkHead_->capacity)
} {
} chunkHead_->size += increment;
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) {
std::memcpy(newBuffer, originalPtr, originalSize); if(originalSize)
return newBuffer; {
} std::memcpy(newBuffer, originalPtr, originalSize);
else }
return NULL; return newBuffer;
} }
else
{
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_) {
ownBaseAllocator_ = baseAllocator_ = RAPIDJSON_NEW(BaseAllocator()); if(!baseAllocator_)
if (ChunkHeader* chunk = reinterpret_cast<ChunkHeader*>(baseAllocator_->Malloc(RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + capacity))) { {
chunk->capacity = capacity; ownBaseAllocator_ = baseAllocator_ = RAPIDJSON_NEW(BaseAllocator());
chunk->size = 0; }
chunk->next = chunkHead_; if(ChunkHeader* chunk = reinterpret_cast<ChunkHeader*>(baseAllocator_->Malloc(RAPIDJSON_ALIGN(sizeof(
chunkHead_ = chunk; ChunkHeader)) + capacity)))
return true; {
} chunk->capacity = capacity;
else chunk->size = 0;
return false; chunk->next = chunkHead_;
} chunkHead_ = chunk;
return true;
}
else
{
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 size; //!< Current size of allocated memory in bytes. size_t capacity; //!< Capacity of the chunk in bytes (excluding the header itself).
ChunkHeader *next; //!< Next chunk in the linked list. size_t size; //!< Current size of allocated memory in bytes.
}; 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.
}; };
RAPIDJSON_NAMESPACE_END RAPIDJSON_NAMESPACE_END

File diff suppressed because it is too large Load diff

View file

@ -1,5 +1,5 @@
// Tencent is pleased to support the open source community by making RapidJSON available. // Tencent is pleased to support the open source community by making RapidJSON available.
// //
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// //
// Licensed under the MIT License (the "License"); you may not use this file except // Licensed under the MIT License (the "License"); you may not use this file except
@ -7,9 +7,9 @@
// //
// http://opensource.org/licenses/MIT // http://opensource.org/licenses/MIT
// //
// Unless required by applicable law or agreed to in writing, software distributed // Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License. // specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_ENCODEDSTREAM_H_ #ifndef RAPIDJSON_ENCODEDSTREAM_H_
@ -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();
Ch Peek() const { return is_.Peek(); } }
Ch Take() { return is_.Take(); } if(static_cast<unsigned char>(is_.Peek()) == 0xBBu)
size_t Tell() const { return is_.Tell(); } {
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();
}
// 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) {
Encoding::PutBOM(os_); if(putBOM)
} {
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,96 +215,186 @@ 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;
//! Constructor. //! Constructor.
/*! /*!
\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); {
DetectType(); RAPIDJSON_ASSERT(type >= kUTF8 && type <= kUTF32BE);
static const TakeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Take) }; DetectType();
takeFunc_ = f[type_]; static const TakeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Take) };
current_ = takeFunc_(*is_); takeFunc_ = f[type_];
} 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): {
// 00 00 FE FF UTF-32BE // BOM (Byte Order Mark):
// FF FE 00 00 UTF-32LE // 00 00 FE FF UTF-32BE
// FE FF UTF-16BE // FF FE 00 00 UTF-32LE
// FF FE UTF-16LE // FE FF UTF-16BE
// EF BB BF UTF-8 // FF FE UTF-16LE
// 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
// characters [RFC0020], it is possible to determine whether an octet // characters [RFC0020], it is possible to determine whether an octet
// stream is UTF-8, UTF-16 (BE or LE), or UTF-32 (BE or LE) by looking // stream is UTF-8, UTF-16 (BE or LE), or UTF-32 (BE or LE) by looking
// at the pattern of nulls in the first four octets." // at the pattern of nulls in the first four octets."
// 00 00 00 xx UTF-32BE // 00 00 00 xx UTF-32BE
// 00 xx 00 xx UTF-16BE // 00 xx 00 xx UTF-16BE
// xx 00 00 00 UTF-32LE // xx 00 00 00 UTF-32LE
// 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); {
switch (pattern) { unsigned pattern = (c[0] ? 1 : 0) | (c[1] ? 2 : 0) | (c[2] ? 4 : 0) | (c[3] ? 8 : 0);
case 0x08: type_ = kUTF32BE; break; switch(pattern)
case 0x0A: type_ = kUTF16BE; break; {
case 0x01: type_ = kUTF32LE; break; case 0x08:
case 0x05: type_ = kUTF16LE; break; type_ = kUTF32BE;
case 0x0F: type_ = kUTF8; break; break;
default: break; // Use type defined by user. case 0x0A:
} 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_;
TakeFunc takeFunc_; TakeFunc takeFunc_;
bool hasBOM_; bool hasBOM_;
}; };
//! Output stream wrapper with dynamically bound encoding and automatic encoding detection. //! Output stream wrapper with dynamically bound encoding and automatic encoding detection.
@ -230,58 +403,98 @@ 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;
//! Constructor. //! Constructor.
/*! /*!
\param os output stream to be wrapped. \param os output stream to be wrapped.
\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&); {
static const PutBOMFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(PutBOM) }; typedef void (*PutBOMFunc)(OutputByteStream &);
f[type_](*os_); static const PutBOMFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(PutBOM) };
} f[type_](*os_);
}
typedef void (*PutFunc)(OutputByteStream&, Ch); typedef void (*PutFunc)(OutputByteStream &, Ch);
OutputByteStream* os_; OutputByteStream* os_;
UTFType type_; UTFType type_;
PutFunc putFunc_; PutFunc putFunc_;
}; };
#undef RAPIDJSON_ENCODINGS_FUNC #undef RAPIDJSON_ENCODINGS_FUNC

File diff suppressed because it is too large Load diff

View file

@ -1,5 +1,5 @@
// Tencent is pleased to support the open source community by making RapidJSON available. // Tencent is pleased to support the open source community by making RapidJSON available.
// //
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// //
// Licensed under the MIT License (the "License"); you may not use this file except // Licensed under the MIT License (the "License"); you may not use this file except
@ -7,9 +7,9 @@
// //
// http://opensource.org/licenses/MIT // http://opensource.org/licenses/MIT
// //
// Unless required by applicable law or agreed to in writing, software distributed // Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License. // specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_ERROR_EN_H_ #ifndef RAPIDJSON_ERROR_EN_H_
@ -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:
case kParseErrorValueInvalid: return RAPIDJSON_ERROR_STRING("Invalid value."); return RAPIDJSON_ERROR_STRING("The document root must not be followed by other values.");
case kParseErrorObjectMissName: return RAPIDJSON_ERROR_STRING("Missing a name for 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 kParseErrorStringUnicodeEscapeInvalidHex: return RAPIDJSON_ERROR_STRING("Incorrect hex digit after \\u escape in string."); case kParseErrorValueInvalid:
case kParseErrorStringUnicodeSurrogateInvalid: return RAPIDJSON_ERROR_STRING("The surrogate pair in string is invalid."); return RAPIDJSON_ERROR_STRING("Invalid value.");
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 kParseErrorObjectMissName:
case kParseErrorNumberMissFraction: return RAPIDJSON_ERROR_STRING("Miss fraction part in number."); return RAPIDJSON_ERROR_STRING("Missing a name for object member.");
case kParseErrorNumberMissExponent: return RAPIDJSON_ERROR_STRING("Miss exponent in number."); 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 kParseErrorTermination: return RAPIDJSON_ERROR_STRING("Terminate parsing due to Handler error."); case kParseErrorArrayMissCommaOrSquareBracket:
case kParseErrorUnspecificSyntaxError: return RAPIDJSON_ERROR_STRING("Unspecific syntax error."); return RAPIDJSON_ERROR_STRING("Missing a comma or ']' after an array element.");
default: return RAPIDJSON_ERROR_STRING("Unknown error."); case kParseErrorStringUnicodeEscapeInvalidHex:
} return RAPIDJSON_ERROR_STRING("Incorrect hex digit after \\u escape in string.");
} case kParseErrorStringUnicodeSurrogateInvalid:
return RAPIDJSON_ERROR_STRING("The surrogate pair in string is invalid.");
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 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 kParseErrorUnspecificSyntaxError:
return RAPIDJSON_ERROR_STRING("Unspecific syntax error.");
default:
return RAPIDJSON_ERROR_STRING("Unknown error.");
}
}
RAPIDJSON_NAMESPACE_END RAPIDJSON_NAMESPACE_END

View file

@ -1,5 +1,5 @@
// Tencent is pleased to support the open source community by making RapidJSON available. // Tencent is pleased to support the open source community by making RapidJSON available.
// //
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// //
// Licensed under the MIT License (the "License"); you may not use this file except // Licensed under the MIT License (the "License"); you may not use this file except
@ -7,9 +7,9 @@
// //
// http://opensource.org/licenses/MIT // http://opensource.org/licenses/MIT
// //
// Unless required by applicable law or agreed to in writing, software distributed // Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License. // specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_ERROR_ERROR_H_ #ifndef RAPIDJSON_ERROR_ERROR_H_
@ -61,32 +61,33 @@ 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.
kParseErrorDocumentRootNotSingular, //!< The document root must not follow by other values. kParseErrorDocumentRootNotSingular, //!< The document root must not follow by other values.
kParseErrorValueInvalid, //!< Invalid value. kParseErrorValueInvalid, //!< Invalid value.
kParseErrorObjectMissName, //!< Missing a name for object member. kParseErrorObjectMissName, //!< Missing a name for object member.
kParseErrorObjectMissColon, //!< Missing a colon after a name of object member. kParseErrorObjectMissColon, //!< Missing a colon after a name of object member.
kParseErrorObjectMissCommaOrCurlyBracket, //!< Missing a comma or '}' after an object member. kParseErrorObjectMissCommaOrCurlyBracket, //!< Missing a comma or '}' after an object member.
kParseErrorArrayMissCommaOrSquareBracket, //!< Missing a comma or ']' after an array element. kParseErrorArrayMissCommaOrSquareBracket, //!< Missing a comma or ']' after an array element.
kParseErrorStringUnicodeEscapeInvalidHex, //!< Incorrect hex digit after \\u escape in string. kParseErrorStringUnicodeEscapeInvalidHex, //!< Incorrect hex digit after \\u escape in string.
kParseErrorStringUnicodeSurrogateInvalid, //!< The surrogate pair in string is invalid. kParseErrorStringUnicodeSurrogateInvalid, //!< The surrogate pair in string is invalid.
kParseErrorStringEscapeInvalid, //!< Invalid escape character in string. kParseErrorStringEscapeInvalid, //!< Invalid escape character in string.
kParseErrorStringMissQuotationMark, //!< Missing a closing quotation mark in string. kParseErrorStringMissQuotationMark, //!< Missing a closing quotation mark in string.
kParseErrorStringInvalidEncoding, //!< Invalid encoding in string. kParseErrorStringInvalidEncoding, //!< Invalid encoding in string.
kParseErrorNumberTooBig, //!< Number too big to be stored in double. kParseErrorNumberTooBig, //!< Number too big to be stored in double.
kParseErrorNumberMissFraction, //!< Miss fraction part in number. kParseErrorNumberMissFraction, //!< Miss fraction part in number.
kParseErrorNumberMissExponent, //!< Miss exponent in number. kParseErrorNumberMissExponent, //!< Miss exponent in number.
kParseErrorTermination, //!< Parsing was terminated. kParseErrorTermination, //!< Parsing was terminated.
kParseErrorUnspecificSyntaxError //!< Unspecific syntax error. kParseErrorUnspecificSyntaxError //!< Unspecific syntax error.
}; };
//! Result of parsing (wraps ParseErrorCode) //! Result of parsing (wraps ParseErrorCode)
@ -103,35 +104,64 @@ 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) {}
//! Constructor to set an error. //! Constructor to set an error.
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
//! Get the error offset, if \ref IsError(), 0 otherwise. {
size_t Offset() const { return offset_; } return code_;
}
//! Get the error offset, if \ref IsError(), 0 otherwise.
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
//! Whether the result is an error. {
bool IsError() const { return code_ != kParseErrorNone; } return !IsError();
}
//! Whether the result is an error.
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()
//! Update error code and offset. {
void Set(ParseErrorCode code, size_t offset = 0) { code_ = code; offset_ = offset; } Set(kParseErrorNone);
}
//! Update error code and offset.
void Set(ParseErrorCode code, size_t offset = 0)
{
code_ = code;
offset_ = offset;
}
private: private:
ParseErrorCode code_; ParseErrorCode code_;
size_t offset_; size_t offset_;
}; };
//! Function pointer type of GetParseError(). //! Function pointer type of GetParseError().

View file

@ -1,5 +1,5 @@
// Tencent is pleased to support the open source community by making RapidJSON available. // Tencent is pleased to support the open source community by making RapidJSON available.
// //
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// //
// Licensed under the MIT License (the "License"); you may not use this file except // Licensed under the MIT License (the "License"); you may not use this file except
@ -7,9 +7,9 @@
// //
// http://opensource.org/licenses/MIT // http://opensource.org/licenses/MIT
// //
// Unless required by applicable law or agreed to in writing, software distributed // Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License. // specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_FILEREADSTREAM_H_ #ifndef RAPIDJSON_FILEREADSTREAM_H_
@ -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,63 +31,97 @@ 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).
//! Constructor. //! Constructor.
/*! /*!
\param fp File pointer opened for read. \param fp File pointer opened for read.
\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),
RAPIDJSON_ASSERT(fp_ != 0); bufferSize_(bufferSize), bufferLast_(0), current_(buffer_), readCount_(0), count_(0), eof_(false)
RAPIDJSON_ASSERT(bufferSize >= 4); {
Read(); RAPIDJSON_ASSERT(fp_ != 0);
} RAPIDJSON_ASSERT(bufferSize >= 4);
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_) {
++current_; if(current_ < bufferLast_)
else if (!eof_) { {
count_ += readCount_; ++current_;
readCount_ = fread(buffer_, 1, bufferSize_, fp_); }
bufferLast_ = buffer_ + readCount_ - 1; else if(!eof_)
current_ = buffer_; {
count_ += readCount_;
readCount_ = fread(buffer_, 1, bufferSize_, fp_);
bufferLast_ = buffer_ + readCount_ - 1;
current_ = buffer_;
if (readCount_ < bufferSize_) { if(readCount_ < bufferSize_)
buffer_[readCount_] = '\0'; {
++bufferLast_; buffer_[readCount_] = '\0';
eof_ = true; ++bufferLast_;
} eof_ = true;
} }
} }
}
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_;
}; };
RAPIDJSON_NAMESPACE_END RAPIDJSON_NAMESPACE_END

View file

@ -1,5 +1,5 @@
// Tencent is pleased to support the open source community by making RapidJSON available. // Tencent is pleased to support the open source community by making RapidJSON available.
// //
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// //
// Licensed under the MIT License (the "License"); you may not use this file except // Licensed under the MIT License (the "License"); you may not use this file except
@ -7,9 +7,9 @@
// //
// http://opensource.org/licenses/MIT // http://opensource.org/licenses/MIT
// //
// Unless required by applicable law or agreed to in writing, software distributed // Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License. // specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_FILEWRITESTREAM_H_ #ifndef RAPIDJSON_FILEWRITESTREAM_H_
@ -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,70 +29,103 @@ 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),
RAPIDJSON_ASSERT(fp_ != 0); bufferEnd_(buffer + bufferSize), current_(buffer_)
} {
RAPIDJSON_ASSERT(fp_ != 0);
}
void Put(char c) { void Put(char c)
if (current_ >= bufferEnd_) {
Flush(); if(current_ >= bufferEnd_)
{
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_); {
while (n > avail) { size_t avail = static_cast<size_t>(bufferEnd_ - current_);
std::memset(current_, c, avail); while(n > avail)
current_ += avail; {
Flush(); std::memset(current_, c, avail);
n -= avail; current_ += avail;
avail = static_cast<size_t>(bufferEnd_ - current_); Flush();
} n -= avail;
avail = static_cast<size_t>(bufferEnd_ - current_);
}
if (n > 0) { if(n > 0)
std::memset(current_, c, n); {
current_ += n; std::memset(current_, c, n);
} current_ += n;
} }
}
void Flush() { void Flush()
if (current_ != buffer_) { {
size_t result = fwrite(buffer_, 1, static_cast<size_t>(current_ - buffer_), fp_); if(current_ != buffer_)
if (result < static_cast<size_t>(current_ - buffer_)) { {
// failure deliberately ignored at this time size_t result = fwrite(buffer_, 1, static_cast<size_t>(current_ - buffer_), fp_);
// added to avoid warn_unused_result build errors if(result < static_cast<size_t>(current_ - buffer_))
} {
current_ = buffer_; // failure deliberately ignored at this time
} // added to avoid warn_unused_result build errors
} }
current_ = buffer_;
}
}
// 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);
} }
RAPIDJSON_NAMESPACE_END RAPIDJSON_NAMESPACE_END

View file

@ -1,5 +1,5 @@
// Tencent is pleased to support the open source community by making RapidJSON available. // Tencent is pleased to support the open source community by making RapidJSON available.
// //
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// //
// Licensed under the MIT License (the "License"); you may not use this file except // Licensed under the MIT License (the "License"); you may not use this file except
@ -7,9 +7,9 @@
// //
// http://opensource.org/licenses/MIT // http://opensource.org/licenses/MIT
// //
// Unless required by applicable law or agreed to in writing, software distributed // Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License. // specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_FWD_H_ #ifndef RAPIDJSON_FWD_H_
@ -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
@ -101,7 +101,7 @@ class PrettyWriter;
// document.h // document.h
template <typename Encoding, typename Allocator> template <typename Encoding, typename Allocator>
struct GenericMember; struct GenericMember;
template <bool Const, typename Encoding, typename Allocator> template <bool Const, typename Encoding, typename Allocator>
@ -110,10 +110,10 @@ class GenericMemberIterator;
template<typename CharType> template<typename CharType>
struct GenericStringRef; 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

@ -1,5 +1,5 @@
// Tencent is pleased to support the open source community by making RapidJSON available. // Tencent is pleased to support the open source community by making RapidJSON available.
// //
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// //
// Licensed under the MIT License (the "License"); you may not use this file except // Licensed under the MIT License (the "License"); you may not use this file except
@ -7,9 +7,9 @@
// //
// http://opensource.org/licenses/MIT // http://opensource.org/licenses/MIT
// //
// Unless required by applicable law or agreed to in writing, software distributed // Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License. // specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_BIGINTEGER_H_ #ifndef RAPIDJSON_BIGINTEGER_H_
@ -23,266 +23,379 @@
#endif #endif
RAPIDJSON_NAMESPACE_BEGIN RAPIDJSON_NAMESPACE_BEGIN
namespace internal { namespace internal
{
class BigInteger { class BigInteger
public: {
typedef uint64_t Type; public:
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); {
digits_[0] = 0; RAPIDJSON_ASSERT(length > 0);
size_t i = 0; digits_[0] = 0;
const size_t kMaxDigitPerIteration = 19; // 2^64 = 18446744073709551616 > 10^19 size_t i = 0;
while (length >= kMaxDigitPerIteration) { const size_t kMaxDigitPerIteration = 19; // 2^64 = 18446744073709551616 > 10^19
AppendDecimal64(decimals + i, decimals + i + kMaxDigitPerIteration); while(length >= kMaxDigitPerIteration)
length -= kMaxDigitPerIteration; {
i += kMaxDigitPerIteration; AppendDecimal64(decimals + i, decimals + i + kMaxDigitPerIteration);
} length -= 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) }
{
if (this != &rhs) {
count_ = rhs.count_;
std::memcpy(digits_, rhs.digits_, count_ * sizeof(Type));
}
return *this;
}
BigInteger& operator=(uint64_t u) {
digits_[0] = u;
count_ = 1;
return *this;
}
BigInteger& operator+=(uint64_t u) { BigInteger & operator=(const BigInteger & rhs)
Type backup = digits_[0]; {
digits_[0] += u; if(this != &rhs)
for (size_t i = 0; i < count_ - 1; i++) { {
if (digits_[i] >= backup) count_ = rhs.count_;
return *this; // no carry std::memcpy(digits_, rhs.digits_, count_ * sizeof(Type));
backup = digits_[i + 1]; }
digits_[i + 1] += 1; return *this;
} }
// Last carry BigInteger & operator=(uint64_t u)
if (digits_[count_ - 1] < backup) {
PushBack(1); digits_[0] = u;
count_ = 1;
return *this;
}
return *this; BigInteger & operator+=(uint64_t u)
} {
Type backup = digits_[0];
digits_[0] += u;
for(size_t i = 0; i < count_ - 1; i++)
{
if(digits_[i] >= backup)
{
return *this; // no carry
}
backup = digits_[i + 1];
digits_[i + 1] += 1;
}
BigInteger& operator*=(uint64_t u) { // Last carry
if (u == 0) return *this = 0; if(digits_[count_ - 1] < backup)
if (u == 1) return *this; {
if (*this == 1) return *this = u; PushBack(1);
}
uint64_t k = 0; return *this;
for (size_t i = 0; i < count_; i++) { }
uint64_t hi;
digits_[i] = MulAdd64(digits_[i], u, k, &hi);
k = hi;
}
if (k > 0)
PushBack(k);
return *this; BigInteger & operator*=(uint64_t u)
} {
if(u == 0)
{
return *this = 0;
}
if(u == 1)
{
return *this;
}
if(*this == 1)
{
return *this = u;
}
BigInteger& operator*=(uint32_t u) { uint64_t k = 0;
if (u == 0) return *this = 0; for(size_t i = 0; i < count_; i++)
if (u == 1) return *this; {
if (*this == 1) return *this = u; uint64_t hi;
digits_[i] = MulAdd64(digits_[i], u, k, &hi);
k = hi;
}
uint64_t k = 0; if(k > 0)
for (size_t i = 0; i < count_; i++) { {
const uint64_t c = digits_[i] >> 32; PushBack(k);
const uint64_t d = digits_[i] & 0xFFFFFFFF; }
const uint64_t uc = u * c;
const uint64_t ud = u * d;
const uint64_t p0 = ud + k;
const uint64_t p1 = uc + (p0 >> 32);
digits_[i] = (p0 & 0xFFFFFFFF) | (p1 << 32);
k = p1 >> 32;
}
if (k > 0)
PushBack(k);
return *this; return *this;
} }
BigInteger& operator<<=(size_t shift) { BigInteger & operator*=(uint32_t u)
if (IsZero() || shift == 0) return *this; {
if(u == 0)
{
return *this = 0;
}
if(u == 1)
{
return *this;
}
if(*this == 1)
{
return *this = u;
}
size_t offset = shift / kTypeBit; uint64_t k = 0;
size_t interShift = shift % kTypeBit; for(size_t i = 0; i < count_; i++)
RAPIDJSON_ASSERT(count_ + offset <= kCapacity); {
const uint64_t c = digits_[i] >> 32;
const uint64_t d = digits_[i] & 0xFFFFFFFF;
const uint64_t uc = u * c;
const uint64_t ud = u * d;
const uint64_t p0 = ud + k;
const uint64_t p1 = uc + (p0 >> 32);
digits_[i] = (p0 & 0xFFFFFFFF) | (p1 << 32);
k = p1 >> 32;
}
if (interShift == 0) { if(k > 0)
std::memmove(&digits_[count_ - 1 + offset], &digits_[count_ - 1], count_ * sizeof(Type)); {
count_ += offset; PushBack(k);
} }
else {
digits_[count_] = 0;
for (size_t i = count_; i > 0; i--)
digits_[i + offset] = (digits_[i] << interShift) | (digits_[i - 1] >> (kTypeBit - interShift));
digits_[offset] = digits_[0] << interShift;
count_ += offset;
if (digits_[count_])
count_++;
}
std::memset(digits_, 0, offset * sizeof(Type)); return *this;
}
return *this; BigInteger & operator<<=(size_t shift)
} {
if(IsZero() || shift == 0)
{
return *this;
}
bool operator==(const BigInteger& rhs) const { size_t offset = shift / kTypeBit;
return count_ == rhs.count_ && std::memcmp(digits_, rhs.digits_, count_ * sizeof(Type)) == 0; size_t interShift = shift % kTypeBit;
} RAPIDJSON_ASSERT(count_ + offset <= kCapacity);
bool operator==(const Type rhs) const { if(interShift == 0)
return count_ == 1 && digits_[0] == rhs; {
} std::memmove(&digits_[count_ - 1 + offset], &digits_[count_ - 1], count_ * sizeof(Type));
count_ += offset;
}
else
{
digits_[count_] = 0;
for(size_t i = count_; i > 0; i--)
{
digits_[i + offset] = (digits_[i] << interShift) | (digits_[i - 1] >> (kTypeBit - interShift));
}
digits_[offset] = digits_[0] << interShift;
count_ += offset;
if(digits_[count_])
{
count_++;
}
}
BigInteger& MultiplyPow5(unsigned exp) { std::memset(digits_, 0, offset * sizeof(Type));
static const uint32_t kPow5[12] = {
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 * 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;
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;
}
// Compute absolute difference of this and rhs. return *this;
// Assume this != rhs }
bool Difference(const BigInteger& rhs, BigInteger* out) const {
int cmp = Compare(rhs);
RAPIDJSON_ASSERT(cmp != 0);
const BigInteger *a, *b; // Makes a > b
bool ret;
if (cmp < 0) { a = &rhs; b = this; ret = true; }
else { a = this; b = &rhs; ret = false; }
Type borrow = 0; bool operator==(const BigInteger & rhs) const
for (size_t i = 0; i < a->count_; i++) { {
Type d = a->digits_[i] - borrow; return count_ == rhs.count_ && std::memcmp(digits_, rhs.digits_, count_ * sizeof(Type)) == 0;
if (i < b->count_) }
d -= b->digits_[i];
borrow = (d > a->digits_[i]) ? 1 : 0;
out->digits_[i] = d;
if (d != 0)
out->count_ = i + 1;
}
return ret; bool operator==(const Type rhs) const
} {
return count_ == 1 && digits_[0] == rhs;
}
int Compare(const BigInteger& rhs) const { BigInteger & MultiplyPow5(unsigned exp)
if (count_ != rhs.count_) {
return count_ < rhs.count_ ? -1 : 1; static const uint32_t kPow5[12] =
{
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 * 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;
}
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;
}
for (size_t i = count_; i-- > 0;) // Compute absolute difference of this and rhs.
if (digits_[i] != rhs.digits_[i]) // Assume this != rhs
return digits_[i] < rhs.digits_[i] ? -1 : 1; bool Difference(const BigInteger & rhs, BigInteger* out) const
{
int cmp = Compare(rhs);
RAPIDJSON_ASSERT(cmp != 0);
const BigInteger* a, *b; // Makes a > b
bool ret;
if(cmp < 0)
{
a = &rhs;
b = this;
ret = true;
}
else
{
a = this;
b = &rhs;
ret = false;
}
return 0; Type borrow = 0;
} for(size_t i = 0; i < a->count_; i++)
{
Type d = a->digits_[i] - borrow;
if(i < b->count_)
{
d -= b->digits_[i];
}
borrow = (d > a->digits_[i]) ? 1 : 0;
out->digits_[i] = d;
if(d != 0)
{
out->count_ = i + 1;
}
}
size_t GetCount() const { return count_; } return ret;
Type GetDigit(size_t index) const { RAPIDJSON_ASSERT(index < count_); return digits_[index]; } }
bool IsZero() const { return count_ == 1 && digits_[0] == 0; }
private: int Compare(const BigInteger & rhs) const
void AppendDecimal64(const char* begin, const char* end) { {
uint64_t u = ParseUint64(begin, end); if(count_ != rhs.count_)
if (IsZero()) {
*this = u; return count_ < rhs.count_ ? -1 : 1;
else { }
unsigned exp = static_cast<unsigned>(end - begin);
(MultiplyPow5(exp) <<= exp) += u; // *this = *this * 10^exp + u
}
}
void PushBack(Type digit) { for(size_t i = count_; i-- > 0;)
RAPIDJSON_ASSERT(count_ < kCapacity); if(digits_[i] != rhs.digits_[i])
digits_[count_++] = digit; {
} return digits_[i] < rhs.digits_[i] ? -1 : 1;
}
static uint64_t ParseUint64(const char* begin, const char* end) { return 0;
uint64_t r = 0; }
for (const char* p = begin; p != end; ++p) {
RAPIDJSON_ASSERT(*p >= '0' && *p <= '9');
r = r * 10u + static_cast<unsigned>(*p - '0');
}
return r;
}
// Assume a * b + k < 2^128 size_t GetCount() const
static uint64_t MulAdd64(uint64_t a, uint64_t b, uint64_t k, uint64_t* outHigh) { {
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:
void AppendDecimal64(const char* begin, const char* end)
{
uint64_t u = ParseUint64(begin, end);
if(IsZero())
{
*this = u;
}
else
{
unsigned exp = static_cast<unsigned>(end - begin);
(MultiplyPow5(exp) <<= exp) += u; // *this = *this * 10^exp + u
}
}
void PushBack(Type digit)
{
RAPIDJSON_ASSERT(count_ < kCapacity);
digits_[count_++] = digit;
}
static uint64_t ParseUint64(const char* begin, const char* end)
{
uint64_t r = 0;
for(const char* p = begin; p != end; ++p)
{
RAPIDJSON_ASSERT(*p >= '0' && *p <= '9');
r = r * 10u + static_cast<unsigned>(*p - '0');
}
return r;
}
// Assume a * b + k < 2^128
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)++; {
return low; (*outHigh)++;
}
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;
uint128 p = static_cast<uint128>(a) * static_cast<uint128>(b); uint128 p = static_cast<uint128>(a) * static_cast<uint128>(b);
p += k; p += k;
*outHigh = static_cast<uint64_t>(p >> 64); *outHigh = static_cast<uint64_t>(p >> 64);
return static_cast<uint64_t>(p); return static_cast<uint64_t>(p);
#else #else
const uint64_t a0 = a & 0xFFFFFFFF, a1 = a >> 32, b0 = b & 0xFFFFFFFF, b1 = b >> 32; const uint64_t a0 = a & 0xFFFFFFFF, a1 = a >> 32, b0 = b & 0xFFFFFFFF, b1 = b >> 32;
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); {
uint64_t lo = (x1 << 32) + (x0 & 0xFFFFFFFF); x3 += (static_cast<uint64_t>(1) << 32);
uint64_t hi = x3 + (x1 >> 32); }
uint64_t lo = (x1 << 32) + (x0 & 0xFFFFFFFF);
uint64_t hi = x3 + (x1 >> 32);
lo += k; lo += k;
if (lo < k) if(lo < k)
hi++; {
*outHigh = hi; hi++;
return lo; }
*outHigh = hi;
return lo;
#endif #endif
} }
static const size_t kBitCount = 3328; // 64bit * 54 > 10^1000 static const size_t kBitCount = 3328; // 64bit * 54 > 10^1000
static const size_t kCapacity = kBitCount / sizeof(Type); static const size_t kCapacity = kBitCount / sizeof(Type);
static const size_t kTypeBit = sizeof(Type) * 8; static const size_t kTypeBit = sizeof(Type) * 8;
Type digits_[kCapacity]; Type digits_[kCapacity];
size_t count_; size_t count_;
}; };
} // namespace internal } // namespace internal
RAPIDJSON_NAMESPACE_END RAPIDJSON_NAMESPACE_END

View file

@ -1,5 +1,5 @@
// Tencent is pleased to support the open source community by making RapidJSON available. // Tencent is pleased to support the open source community by making RapidJSON available.
// //
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// //
// Licensed under the MIT License (the "License"); you may not use this file except // Licensed under the MIT License (the "License"); you may not use this file except
@ -7,9 +7,9 @@
// //
// http://opensource.org/licenses/MIT // http://opensource.org/licenses/MIT
// //
// Unless required by applicable law or agreed to in writing, software distributed // Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License. // specific language governing permissions and limitations under the License.
// This is a C++ header-only implementation of Grisu2 algorithm from the publication: // This is a C++ header-only implementation of Grisu2 algorithm from the publication:
@ -28,228 +28,254 @@
#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 { {
double d; union
uint64_t u64; {
} u = { d }; double d;
uint64_t u64;
} 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; {
e = biased_e - kDpExponentBias; f = significand + kDpHiddenBit;
} e = biased_e - kDpExponentBias;
else { }
f = significand; else
e = kDpMinExponent + 1; {
} f = significand;
} 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++; {
return DiyFp(h, e + rhs.e + 64); h++;
}
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++; {
return DiyFp(h, e + rhs.e + 64); h++;
}
return DiyFp(h, e + rhs.e + 64);
#else #else
const uint64_t M32 = 0xFFFFFFFF; const uint64_t M32 = 0xFFFFFFFF;
const uint64_t a = f >> 32; const uint64_t a = f >> 32;
const uint64_t b = f & M32; const uint64_t b = f & M32;
const uint64_t c = rhs.f >> 32; const uint64_t c = rhs.f >> 32;
const uint64_t d = rhs.f & M32; const uint64_t d = rhs.f & M32;
const uint64_t ac = a * c; const uint64_t ac = a * c;
const uint64_t bc = b * c; const uint64_t bc = b * c;
const uint64_t ad = a * d; const uint64_t ad = a * d;
const uint64_t bd = b * d; const uint64_t bd = b * d;
uint64_t tmp = (bd >> 32) + (ad & M32) + (bc & M32); uint64_t tmp = (bd >> 32) + (ad & M32) + (bc & M32);
tmp += 1U << 31; /// mult_round tmp += 1U << 31; /// mult_round
return DiyFp(ac + (ad >> 32) + (bc >> 32) + (tmp >> 32), e + rhs.e + 64); return DiyFp(ac + (ad >> 32) + (bc >> 32) + (tmp >> 32), e + rhs.e + 64);
#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);
return DiyFp(f << (63 - index), e - (63 - index)); return DiyFp(f << (63 - index), e - (63 - index));
#elif defined(__GNUC__) && __GNUC__ >= 4 #elif defined(__GNUC__) && __GNUC__ >= 4
int s = __builtin_clzll(f); int s = __builtin_clzll(f);
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.e--; res.f <<= 1;
} res.e--;
return res; }
return res;
#endif #endif
} }
DiyFp NormalizeBoundary() const { DiyFp NormalizeBoundary() const
DiyFp res = *this; {
while (!(res.f & (kDpHiddenBit << 1))) { DiyFp res = *this;
res.f <<= 1; while(!(res.f & (kDpHiddenBit << 1)))
res.e--; {
} res.f <<= 1;
res.f <<= (kDiySignificandSize - kDpSignificandSize - 2); res.e--;
res.e = res.e - (kDiySignificandSize - kDpSignificandSize - 2); }
return res; res.f <<= (kDiySignificandSize - kDpSignificandSize - 2);
} res.e = res.e - (kDiySignificandSize - kDpSignificandSize - 2);
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 mi = (f == kDpHiddenBit) ? DiyFp((f << 2) - 1, e - 2) : DiyFp((f << 1) - 1, e - 1); DiyFp pl = DiyFp((f << 1) + 1, e - 1).NormalizeBoundary();
mi.f <<= mi.e - pl.e; DiyFp mi = (f == kDpHiddenBit) ? DiyFp((f << 2) - 1, e - 2) : DiyFp((f << 1) - 1, e - 1);
mi.e = pl.e; mi.f <<= mi.e - pl.e;
*plus = pl; mi.e = pl.e;
*minus = mi; *plus = pl;
} *minus = mi;
}
double ToDouble() const { double ToDouble() const
union { {
double d; union
uint64_t u64; {
}u; double d;
const uint64_t be = (e == kDpDenormalExponent && (f & kDpHiddenBit) == 0) ? 0 : uint64_t u64;
static_cast<uint64_t>(e + kDpExponentBias); } u;
u.u64 = (f & kDpSignificandMask) | (be << kDpSignificandSize); const uint64_t be = (e == kDpDenormalExponent && (f & kDpHiddenBit) == 0) ? 0 :
return u.d; static_cast<uint64_t>(e + kDpExponentBias);
} u.u64 = (f & kDpSignificandMask) | (be << kDpSignificandSize);
return u.d;
}
static const int kDiySignificandSize = 64; static const int kDiySignificandSize = 64;
static const int kDpSignificandSize = 52; static const int kDpSignificandSize = 52;
static const int kDpExponentBias = 0x3FF + kDpSignificandSize; static const int kDpExponentBias = 0x3FF + kDpSignificandSize;
static const int kDpMaxExponent = 0x7FF - kDpExponentBias; static const int kDpMaxExponent = 0x7FF - kDpExponentBias;
static const int kDpMinExponent = -kDpExponentBias; static const int kDpMinExponent = -kDpExponentBias;
static const int kDpDenormalExponent = -kDpExponentBias + 1; static const int kDpDenormalExponent = -kDpExponentBias + 1;
static const uint64_t kDpExponentMask = RAPIDJSON_UINT64_C2(0x7FF00000, 0x00000000); static const uint64_t kDpExponentMask = RAPIDJSON_UINT64_C2(0x7FF00000, 0x00000000);
static const uint64_t kDpSignificandMask = RAPIDJSON_UINT64_C2(0x000FFFFF, 0xFFFFFFFF); static const uint64_t kDpSignificandMask = RAPIDJSON_UINT64_C2(0x000FFFFF, 0xFFFFFFFF);
static const uint64_t kDpHiddenBit = RAPIDJSON_UINT64_C2(0x00100000, 0x00000000); static const uint64_t kDpHiddenBit = RAPIDJSON_UINT64_C2(0x00100000, 0x00000000);
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 {
static const uint64_t kCachedPowers_F[] = { // 10^-348, 10^-340, ..., 10^340
RAPIDJSON_UINT64_C2(0xfa8fd5a0, 0x081c0288), RAPIDJSON_UINT64_C2(0xbaaee17f, 0xa23ebf76), static const uint64_t kCachedPowers_F[] =
RAPIDJSON_UINT64_C2(0x8b16fb20, 0x3055ac76), RAPIDJSON_UINT64_C2(0xcf42894a, 0x5dce35ea), {
RAPIDJSON_UINT64_C2(0x9a6bb0aa, 0x55653b2d), RAPIDJSON_UINT64_C2(0xe61acf03, 0x3d1a45df), RAPIDJSON_UINT64_C2(0xfa8fd5a0, 0x081c0288), RAPIDJSON_UINT64_C2(0xbaaee17f, 0xa23ebf76),
RAPIDJSON_UINT64_C2(0xab70fe17, 0xc79ac6ca), RAPIDJSON_UINT64_C2(0xff77b1fc, 0xbebcdc4f), RAPIDJSON_UINT64_C2(0x8b16fb20, 0x3055ac76), RAPIDJSON_UINT64_C2(0xcf42894a, 0x5dce35ea),
RAPIDJSON_UINT64_C2(0xbe5691ef, 0x416bd60c), RAPIDJSON_UINT64_C2(0x8dd01fad, 0x907ffc3c), RAPIDJSON_UINT64_C2(0x9a6bb0aa, 0x55653b2d), RAPIDJSON_UINT64_C2(0xe61acf03, 0x3d1a45df),
RAPIDJSON_UINT64_C2(0xd3515c28, 0x31559a83), RAPIDJSON_UINT64_C2(0x9d71ac8f, 0xada6c9b5), RAPIDJSON_UINT64_C2(0xab70fe17, 0xc79ac6ca), RAPIDJSON_UINT64_C2(0xff77b1fc, 0xbebcdc4f),
RAPIDJSON_UINT64_C2(0xea9c2277, 0x23ee8bcb), RAPIDJSON_UINT64_C2(0xaecc4991, 0x4078536d), RAPIDJSON_UINT64_C2(0xbe5691ef, 0x416bd60c), RAPIDJSON_UINT64_C2(0x8dd01fad, 0x907ffc3c),
RAPIDJSON_UINT64_C2(0x823c1279, 0x5db6ce57), RAPIDJSON_UINT64_C2(0xc2109436, 0x4dfb5637), RAPIDJSON_UINT64_C2(0xd3515c28, 0x31559a83), RAPIDJSON_UINT64_C2(0x9d71ac8f, 0xada6c9b5),
RAPIDJSON_UINT64_C2(0x9096ea6f, 0x3848984f), RAPIDJSON_UINT64_C2(0xd77485cb, 0x25823ac7), RAPIDJSON_UINT64_C2(0xea9c2277, 0x23ee8bcb), RAPIDJSON_UINT64_C2(0xaecc4991, 0x4078536d),
RAPIDJSON_UINT64_C2(0xa086cfcd, 0x97bf97f4), RAPIDJSON_UINT64_C2(0xef340a98, 0x172aace5), RAPIDJSON_UINT64_C2(0x823c1279, 0x5db6ce57), RAPIDJSON_UINT64_C2(0xc2109436, 0x4dfb5637),
RAPIDJSON_UINT64_C2(0xb23867fb, 0x2a35b28e), RAPIDJSON_UINT64_C2(0x84c8d4df, 0xd2c63f3b), RAPIDJSON_UINT64_C2(0x9096ea6f, 0x3848984f), RAPIDJSON_UINT64_C2(0xd77485cb, 0x25823ac7),
RAPIDJSON_UINT64_C2(0xc5dd4427, 0x1ad3cdba), RAPIDJSON_UINT64_C2(0x936b9fce, 0xbb25c996), RAPIDJSON_UINT64_C2(0xa086cfcd, 0x97bf97f4), RAPIDJSON_UINT64_C2(0xef340a98, 0x172aace5),
RAPIDJSON_UINT64_C2(0xdbac6c24, 0x7d62a584), RAPIDJSON_UINT64_C2(0xa3ab6658, 0x0d5fdaf6), RAPIDJSON_UINT64_C2(0xb23867fb, 0x2a35b28e), RAPIDJSON_UINT64_C2(0x84c8d4df, 0xd2c63f3b),
RAPIDJSON_UINT64_C2(0xf3e2f893, 0xdec3f126), RAPIDJSON_UINT64_C2(0xb5b5ada8, 0xaaff80b8), RAPIDJSON_UINT64_C2(0xc5dd4427, 0x1ad3cdba), RAPIDJSON_UINT64_C2(0x936b9fce, 0xbb25c996),
RAPIDJSON_UINT64_C2(0x87625f05, 0x6c7c4a8b), RAPIDJSON_UINT64_C2(0xc9bcff60, 0x34c13053), RAPIDJSON_UINT64_C2(0xdbac6c24, 0x7d62a584), RAPIDJSON_UINT64_C2(0xa3ab6658, 0x0d5fdaf6),
RAPIDJSON_UINT64_C2(0x964e858c, 0x91ba2655), RAPIDJSON_UINT64_C2(0xdff97724, 0x70297ebd), RAPIDJSON_UINT64_C2(0xf3e2f893, 0xdec3f126), RAPIDJSON_UINT64_C2(0xb5b5ada8, 0xaaff80b8),
RAPIDJSON_UINT64_C2(0xa6dfbd9f, 0xb8e5b88f), RAPIDJSON_UINT64_C2(0xf8a95fcf, 0x88747d94), RAPIDJSON_UINT64_C2(0x87625f05, 0x6c7c4a8b), RAPIDJSON_UINT64_C2(0xc9bcff60, 0x34c13053),
RAPIDJSON_UINT64_C2(0xb9447093, 0x8fa89bcf), RAPIDJSON_UINT64_C2(0x8a08f0f8, 0xbf0f156b), RAPIDJSON_UINT64_C2(0x964e858c, 0x91ba2655), RAPIDJSON_UINT64_C2(0xdff97724, 0x70297ebd),
RAPIDJSON_UINT64_C2(0xcdb02555, 0x653131b6), RAPIDJSON_UINT64_C2(0x993fe2c6, 0xd07b7fac), RAPIDJSON_UINT64_C2(0xa6dfbd9f, 0xb8e5b88f), RAPIDJSON_UINT64_C2(0xf8a95fcf, 0x88747d94),
RAPIDJSON_UINT64_C2(0xe45c10c4, 0x2a2b3b06), RAPIDJSON_UINT64_C2(0xaa242499, 0x697392d3), RAPIDJSON_UINT64_C2(0xb9447093, 0x8fa89bcf), RAPIDJSON_UINT64_C2(0x8a08f0f8, 0xbf0f156b),
RAPIDJSON_UINT64_C2(0xfd87b5f2, 0x8300ca0e), RAPIDJSON_UINT64_C2(0xbce50864, 0x92111aeb), RAPIDJSON_UINT64_C2(0xcdb02555, 0x653131b6), RAPIDJSON_UINT64_C2(0x993fe2c6, 0xd07b7fac),
RAPIDJSON_UINT64_C2(0x8cbccc09, 0x6f5088cc), RAPIDJSON_UINT64_C2(0xd1b71758, 0xe219652c), RAPIDJSON_UINT64_C2(0xe45c10c4, 0x2a2b3b06), RAPIDJSON_UINT64_C2(0xaa242499, 0x697392d3),
RAPIDJSON_UINT64_C2(0x9c400000, 0x00000000), RAPIDJSON_UINT64_C2(0xe8d4a510, 0x00000000), RAPIDJSON_UINT64_C2(0xfd87b5f2, 0x8300ca0e), RAPIDJSON_UINT64_C2(0xbce50864, 0x92111aeb),
RAPIDJSON_UINT64_C2(0xad78ebc5, 0xac620000), RAPIDJSON_UINT64_C2(0x813f3978, 0xf8940984), RAPIDJSON_UINT64_C2(0x8cbccc09, 0x6f5088cc), RAPIDJSON_UINT64_C2(0xd1b71758, 0xe219652c),
RAPIDJSON_UINT64_C2(0xc097ce7b, 0xc90715b3), RAPIDJSON_UINT64_C2(0x8f7e32ce, 0x7bea5c70), RAPIDJSON_UINT64_C2(0x9c400000, 0x00000000), RAPIDJSON_UINT64_C2(0xe8d4a510, 0x00000000),
RAPIDJSON_UINT64_C2(0xd5d238a4, 0xabe98068), RAPIDJSON_UINT64_C2(0x9f4f2726, 0x179a2245), RAPIDJSON_UINT64_C2(0xad78ebc5, 0xac620000), RAPIDJSON_UINT64_C2(0x813f3978, 0xf8940984),
RAPIDJSON_UINT64_C2(0xed63a231, 0xd4c4fb27), RAPIDJSON_UINT64_C2(0xb0de6538, 0x8cc8ada8), RAPIDJSON_UINT64_C2(0xc097ce7b, 0xc90715b3), RAPIDJSON_UINT64_C2(0x8f7e32ce, 0x7bea5c70),
RAPIDJSON_UINT64_C2(0x83c7088e, 0x1aab65db), RAPIDJSON_UINT64_C2(0xc45d1df9, 0x42711d9a), RAPIDJSON_UINT64_C2(0xd5d238a4, 0xabe98068), RAPIDJSON_UINT64_C2(0x9f4f2726, 0x179a2245),
RAPIDJSON_UINT64_C2(0x924d692c, 0xa61be758), RAPIDJSON_UINT64_C2(0xda01ee64, 0x1a708dea), RAPIDJSON_UINT64_C2(0xed63a231, 0xd4c4fb27), RAPIDJSON_UINT64_C2(0xb0de6538, 0x8cc8ada8),
RAPIDJSON_UINT64_C2(0xa26da399, 0x9aef774a), RAPIDJSON_UINT64_C2(0xf209787b, 0xb47d6b85), RAPIDJSON_UINT64_C2(0x83c7088e, 0x1aab65db), RAPIDJSON_UINT64_C2(0xc45d1df9, 0x42711d9a),
RAPIDJSON_UINT64_C2(0xb454e4a1, 0x79dd1877), RAPIDJSON_UINT64_C2(0x865b8692, 0x5b9bc5c2), RAPIDJSON_UINT64_C2(0x924d692c, 0xa61be758), RAPIDJSON_UINT64_C2(0xda01ee64, 0x1a708dea),
RAPIDJSON_UINT64_C2(0xc83553c5, 0xc8965d3d), RAPIDJSON_UINT64_C2(0x952ab45c, 0xfa97a0b3), RAPIDJSON_UINT64_C2(0xa26da399, 0x9aef774a), RAPIDJSON_UINT64_C2(0xf209787b, 0xb47d6b85),
RAPIDJSON_UINT64_C2(0xde469fbd, 0x99a05fe3), RAPIDJSON_UINT64_C2(0xa59bc234, 0xdb398c25), RAPIDJSON_UINT64_C2(0xb454e4a1, 0x79dd1877), RAPIDJSON_UINT64_C2(0x865b8692, 0x5b9bc5c2),
RAPIDJSON_UINT64_C2(0xf6c69a72, 0xa3989f5c), RAPIDJSON_UINT64_C2(0xb7dcbf53, 0x54e9bece), RAPIDJSON_UINT64_C2(0xc83553c5, 0xc8965d3d), RAPIDJSON_UINT64_C2(0x952ab45c, 0xfa97a0b3),
RAPIDJSON_UINT64_C2(0x88fcf317, 0xf22241e2), RAPIDJSON_UINT64_C2(0xcc20ce9b, 0xd35c78a5), RAPIDJSON_UINT64_C2(0xde469fbd, 0x99a05fe3), RAPIDJSON_UINT64_C2(0xa59bc234, 0xdb398c25),
RAPIDJSON_UINT64_C2(0x98165af3, 0x7b2153df), RAPIDJSON_UINT64_C2(0xe2a0b5dc, 0x971f303a), RAPIDJSON_UINT64_C2(0xf6c69a72, 0xa3989f5c), RAPIDJSON_UINT64_C2(0xb7dcbf53, 0x54e9bece),
RAPIDJSON_UINT64_C2(0xa8d9d153, 0x5ce3b396), RAPIDJSON_UINT64_C2(0xfb9b7cd9, 0xa4a7443c), RAPIDJSON_UINT64_C2(0x88fcf317, 0xf22241e2), RAPIDJSON_UINT64_C2(0xcc20ce9b, 0xd35c78a5),
RAPIDJSON_UINT64_C2(0xbb764c4c, 0xa7a44410), RAPIDJSON_UINT64_C2(0x8bab8eef, 0xb6409c1a), RAPIDJSON_UINT64_C2(0x98165af3, 0x7b2153df), RAPIDJSON_UINT64_C2(0xe2a0b5dc, 0x971f303a),
RAPIDJSON_UINT64_C2(0xd01fef10, 0xa657842c), RAPIDJSON_UINT64_C2(0x9b10a4e5, 0xe9913129), RAPIDJSON_UINT64_C2(0xa8d9d153, 0x5ce3b396), RAPIDJSON_UINT64_C2(0xfb9b7cd9, 0xa4a7443c),
RAPIDJSON_UINT64_C2(0xe7109bfb, 0xa19c0c9d), RAPIDJSON_UINT64_C2(0xac2820d9, 0x623bf429), RAPIDJSON_UINT64_C2(0xbb764c4c, 0xa7a44410), RAPIDJSON_UINT64_C2(0x8bab8eef, 0xb6409c1a),
RAPIDJSON_UINT64_C2(0x80444b5e, 0x7aa7cf85), RAPIDJSON_UINT64_C2(0xbf21e440, 0x03acdd2d), RAPIDJSON_UINT64_C2(0xd01fef10, 0xa657842c), RAPIDJSON_UINT64_C2(0x9b10a4e5, 0xe9913129),
RAPIDJSON_UINT64_C2(0x8e679c2f, 0x5e44ff8f), RAPIDJSON_UINT64_C2(0xd433179d, 0x9c8cb841), RAPIDJSON_UINT64_C2(0xe7109bfb, 0xa19c0c9d), RAPIDJSON_UINT64_C2(0xac2820d9, 0x623bf429),
RAPIDJSON_UINT64_C2(0x9e19db92, 0xb4e31ba9), RAPIDJSON_UINT64_C2(0xeb96bf6e, 0xbadf77d9), RAPIDJSON_UINT64_C2(0x80444b5e, 0x7aa7cf85), RAPIDJSON_UINT64_C2(0xbf21e440, 0x03acdd2d),
RAPIDJSON_UINT64_C2(0xaf87023b, 0x9bf0ee6b) RAPIDJSON_UINT64_C2(0x8e679c2f, 0x5e44ff8f), RAPIDJSON_UINT64_C2(0xd433179d, 0x9c8cb841),
}; RAPIDJSON_UINT64_C2(0x9e19db92, 0xb4e31ba9), RAPIDJSON_UINT64_C2(0xeb96bf6e, 0xbadf77d9),
static const int16_t kCachedPowers_E[] = { RAPIDJSON_UINT64_C2(0xaf87023b, 0x9bf0ee6b)
-1220, -1193, -1166, -1140, -1113, -1087, -1060, -1034, -1007, -980, };
-954, -927, -901, -874, -847, -821, -794, -768, -741, -715, static const int16_t kCachedPowers_E[] =
-688, -661, -635, -608, -582, -555, -529, -502, -475, -449, {
-422, -396, -369, -343, -316, -289, -263, -236, -210, -183, -1220, -1193, -1166, -1140, -1113, -1087, -1060, -1034, -1007, -980,
-157, -130, -103, -77, -50, -24, 3, 30, 56, 83, -954, -927, -901, -874, -847, -821, -794, -768, -741, -715,
109, 136, 162, 189, 216, 242, 269, 295, 322, 348, -688, -661, -635, -608, -582, -555, -529, -502, -475, -449,
375, 402, 428, 455, 481, 508, 534, 561, 588, 614, -422, -396, -369, -343, -316, -289, -263, -236, -210, -183,
641, 667, 694, 720, 747, 774, 800, 827, 853, 880, -157, -130, -103, -77, -50, -24, 3, 30, 56, 83,
907, 933, 960, 986, 1013, 1039, 1066 109, 136, 162, 189, 216, 242, 269, 295, 322, 348,
}; 375, 402, 428, 455, 481, 508, 534, 561, 588, 614,
return DiyFp(kCachedPowers_F[index], kCachedPowers_E[index]); 641, 667, 694, 720, 747, 774, 800, 827, 853, 880,
} 907, 933, 960, 986, 1013, 1039, 1066
};
inline DiyFp GetCachedPower(int e, int* K) { return DiyFp(kCachedPowers_F[index], kCachedPowers_E[index]);
}
//int k = static_cast<int>(ceil((-61 - e) * 0.30102999566398114)) + 374; inline DiyFp GetCachedPower(int e, int* K)
double dk = (-61 - e) * 0.30102999566398114 + 347; // dk must be positive, so can do ceiling in positive {
int k = static_cast<int>(dk);
if (dk - k > 0.0)
k++;
unsigned index = static_cast<unsigned>((k >> 3) + 1); //int k = static_cast<int>(ceil((-61 - e) * 0.30102999566398114)) + 374;
*K = -(-348 + static_cast<int>(index << 3)); // decimal exponent no need lookup table double dk = (-61 - e) * 0.30102999566398114 + 347; // dk must be positive, so can do ceiling in positive
int k = static_cast<int>(dk);
if(dk - k > 0.0)
{
k++;
}
return GetCachedPowerByIndex(index); unsigned index = static_cast<unsigned>((k >> 3) + 1);
} *K = -(-348 + static_cast<int>(index << 3)); // decimal exponent no need lookup table
inline DiyFp GetCachedPower10(int exp, int *outExp) { return GetCachedPowerByIndex(index);
unsigned index = (static_cast<unsigned>(exp) + 348u) / 8u; }
*outExp = -348 + static_cast<int>(index) * 8;
return GetCachedPowerByIndex(index); inline DiyFp GetCachedPower10(int exp, int* outExp)
} {
unsigned index = (static_cast<unsigned>(exp) + 348u) / 8u;
*outExp = -348 + static_cast<int>(index) * 8;
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

@ -1,5 +1,5 @@
// Tencent is pleased to support the open source community by making RapidJSON available. // Tencent is pleased to support the open source community by making RapidJSON available.
// //
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// //
// Licensed under the MIT License (the "License"); you may not use this file except // Licensed under the MIT License (the "License"); you may not use this file except
@ -7,9 +7,9 @@
// //
// http://opensource.org/licenses/MIT // http://opensource.org/licenses/MIT
// //
// Unless required by applicable law or agreed to in writing, software distributed // Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License. // specific language governing permissions and limitations under the License.
// This is a C++ header-only implementation of Grisu2 algorithm from the publication: // This is a C++ header-only implementation of Grisu2 algorithm from the publication:
@ -24,219 +24,321 @@
#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)
(rest + ten_kappa < wp_w || /// closer {
wp_w - rest > rest + ten_kappa - wp_w)) { while(rest < wp_w && delta - rest >= ten_kappa &&
buffer[len - 1]--; (rest + ten_kappa < wp_w || /// closer
rest += ten_kappa; wp_w - rest > rest + ten_kappa - wp_w))
} {
} buffer[len - 1]--;
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. {
if (n < 10) return 1; // Simple pure C++ implementation was faster than __builtin_clz version in this situation.
if (n < 100) return 2; if(n < 10)
if (n < 1000) return 3; {
if (n < 10000) return 4; return 1;
if (n < 100000) return 5; }
if (n < 1000000) return 6; if(n < 100)
if (n < 10000000) return 7; {
if (n < 100000000) return 8; return 2;
// Will not reach 10 digits in DigitGen() }
//if (n < 1000000000) return 9; if(n < 1000)
//return 10; {
return 9; 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()
//if (n < 1000000000) return 9;
//return 10;
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 }; {
const DiyFp one(uint64_t(1) << -Mp.e, Mp.e); static const uint32_t kPow10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 };
const DiyFp wp_w = Mp - W; const DiyFp one(uint64_t(1) << -Mp.e, Mp.e);
uint32_t p1 = static_cast<uint32_t>(Mp.f >> -one.e); const DiyFp wp_w = Mp - W;
uint64_t p2 = Mp.f & (one.f - 1); uint32_t p1 = static_cast<uint32_t>(Mp.f >> -one.e);
unsigned kappa = CountDecimalDigit32(p1); // kappa in [0, 9] uint64_t p2 = Mp.f & (one.f - 1);
*len = 0; unsigned kappa = CountDecimalDigit32(p1); // kappa in [0, 9]
*len = 0;
while (kappa > 0) { while(kappa > 0)
uint32_t d = 0; {
switch (kappa) { uint32_t d = 0;
case 9: d = p1 / 100000000; p1 %= 100000000; break; switch(kappa)
case 8: d = p1 / 10000000; p1 %= 10000000; break; {
case 7: d = p1 / 1000000; p1 %= 1000000; break; case 9:
case 6: d = p1 / 100000; p1 %= 100000; break; d = p1 / 100000000;
case 5: d = p1 / 10000; p1 %= 10000; break; p1 %= 100000000;
case 4: d = p1 / 1000; p1 %= 1000; break; break;
case 3: d = p1 / 100; p1 %= 100; break; case 8:
case 2: d = p1 / 10; p1 %= 10; break; d = p1 / 10000000;
case 1: d = p1; p1 = 0; break; p1 %= 10000000;
default:; break;
} case 7:
if (d || *len) d = p1 / 1000000;
buffer[(*len)++] = static_cast<char>('0' + static_cast<char>(d)); p1 %= 1000000;
kappa--; break;
uint64_t tmp = (static_cast<uint64_t>(p1) << -one.e) + p2; case 6:
if (tmp <= delta) { d = p1 / 100000;
*K += kappa; p1 %= 100000;
GrisuRound(buffer, *len, delta, tmp, static_cast<uint64_t>(kPow10[kappa]) << -one.e, wp_w.f); break;
return; 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)
{
buffer[(*len)++] = static_cast<char>('0' + static_cast<char>(d));
}
kappa--;
uint64_t tmp = (static_cast<uint64_t>(p1) << -one.e) + p2;
if(tmp <= delta)
{
*K += kappa;
GrisuRound(buffer, *len, delta, tmp, static_cast<uint64_t>(kPow10[kappa]) << -one.e, wp_w.f);
return;
}
}
// kappa = 0 // kappa = 0
for (;;) { for(;;)
p2 *= 10; {
delta *= 10; p2 *= 10;
char d = static_cast<char>(p2 >> -one.e); delta *= 10;
if (d || *len) char d = static_cast<char>(p2 >> -one.e);
buffer[(*len)++] = static_cast<char>('0' + d); if(d || *len)
p2 &= one.f - 1; {
kappa--; buffer[(*len)++] = static_cast<char>('0' + d);
if (p2 < delta) { }
*K += kappa; p2 &= one.f - 1;
int index = -static_cast<int>(kappa); kappa--;
GrisuRound(buffer, *len, delta, p2, one.f, wp_w.f * (index < 9 ? kPow10[-static_cast<int>(kappa)] : 0)); if(p2 < delta)
return; {
} *K += 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));
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); {
DiyFp w_m, w_p; const DiyFp v(value);
v.NormalizedBoundaries(&w_m, &w_p); DiyFp w_m, w_p;
v.NormalizedBoundaries(&w_m, &w_p);
const DiyFp c_mk = GetCachedPower(w_p.e, K); const DiyFp c_mk = GetCachedPower(w_p.e, K);
const DiyFp W = v.Normalize() * c_mk; const DiyFp W = v.Normalize() * c_mk;
DiyFp Wp = w_p * c_mk; DiyFp Wp = w_p * c_mk;
DiyFp Wm = w_m * c_mk; DiyFp Wm = w_m * c_mk;
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) { {
*buffer++ = '-'; if(K < 0)
K = -K; {
} *buffer++ = '-';
K = -K;
}
if (K >= 100) { if(K >= 100)
*buffer++ = static_cast<char>('0' + static_cast<char>(K / 100)); {
K %= 100; *buffer++ = static_cast<char>('0' + static_cast<char>(K / 100));
const char* d = GetDigitsLut() + K * 2; K %= 100;
*buffer++ = d[0]; const char* d = GetDigitsLut() + K * 2;
*buffer++ = d[1]; *buffer++ = d[0];
} *buffer++ = d[1];
else if (K >= 10) { }
const char* d = GetDigitsLut() + K * 2; else if(K >= 10)
*buffer++ = d[0]; {
*buffer++ = d[1]; const char* d = GetDigitsLut() + K * 2;
} *buffer++ = d[0];
else *buffer++ = d[1];
*buffer++ = static_cast<char>('0' + static_cast<char>(K)); }
else
{
*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 {
for (int i = length; i < kk; i++) // 1234e7 -> 12340000000
buffer[i] = '0'; for(int i = length; i < kk; i++)
buffer[kk] = '.'; {
buffer[kk + 1] = '0'; buffer[i] = '0';
return &buffer[kk + 2]; }
} buffer[kk] = '.';
else if (0 < kk && kk <= 21) { buffer[kk + 1] = '0';
// 1234e-2 -> 12.34 return &buffer[kk + 2];
std::memmove(&buffer[kk + 1], &buffer[kk], static_cast<size_t>(length - kk)); }
buffer[kk] = '.'; else if(0 < kk && kk <= 21)
if (0 > k + maxDecimalPlaces) { {
// When maxDecimalPlaces = 2, 1.2345 -> 1.23, 1.102 -> 1.1 // 1234e-2 -> 12.34
// Remove extra trailing zeros (at least one) after truncation. std::memmove(&buffer[kk + 1], &buffer[kk], static_cast<size_t>(length - kk));
for (int i = kk + maxDecimalPlaces; i > kk + 1; i--) buffer[kk] = '.';
if (buffer[i] != '0') if(0 > k + maxDecimalPlaces)
return &buffer[i + 1]; {
return &buffer[kk + 2]; // Reserve one zero // When maxDecimalPlaces = 2, 1.2345 -> 1.23, 1.102 -> 1.1
} // Remove extra trailing zeros (at least one) after truncation.
else for(int i = kk + maxDecimalPlaces; i > kk + 1; i--)
return &buffer[length + 1]; if(buffer[i] != '0')
} {
else if (-6 < kk && kk <= 0) { return &buffer[i + 1];
// 1234e-6 -> 0.001234 }
const int offset = 2 - kk; return &buffer[kk + 2]; // Reserve one zero
std::memmove(&buffer[offset], &buffer[0], static_cast<size_t>(length)); }
buffer[0] = '0'; else
buffer[1] = '.'; {
for (int i = 2; i < offset; i++) return &buffer[length + 1];
buffer[i] = '0'; }
if (length - kk > maxDecimalPlaces) { }
// When maxDecimalPlaces = 2, 0.123 -> 0.12, 0.102 -> 0.1 else if(-6 < kk && kk <= 0)
// Remove extra trailing zeros (at least one) after truncation. {
for (int i = maxDecimalPlaces + 1; i > 2; i--) // 1234e-6 -> 0.001234
if (buffer[i] != '0') const int offset = 2 - kk;
return &buffer[i + 1]; std::memmove(&buffer[offset], &buffer[0], static_cast<size_t>(length));
return &buffer[3]; // Reserve one zero buffer[0] = '0';
} buffer[1] = '.';
else for(int i = 2; i < offset; i++)
return &buffer[length + offset]; {
} buffer[i] = '0';
else if (kk < -maxDecimalPlaces) { }
// Truncate to zero if(length - kk > maxDecimalPlaces)
buffer[0] = '0'; {
buffer[1] = '.'; // When maxDecimalPlaces = 2, 0.123 -> 0.12, 0.102 -> 0.1
buffer[2] = '0'; // Remove extra trailing zeros (at least one) after truncation.
return &buffer[3]; for(int i = maxDecimalPlaces + 1; i > 2; i--)
} if(buffer[i] != '0')
else if (length == 1) { {
// 1e30 return &buffer[i + 1];
buffer[1] = 'e'; }
return WriteExponent(kk - 1, &buffer[2]); return &buffer[3]; // Reserve one zero
} }
else { else
// 1234e30 -> 1.234e33 {
std::memmove(&buffer[2], &buffer[1], static_cast<size_t>(length - 1)); return &buffer[length + offset];
buffer[1] = '.'; }
buffer[length + 1] = 'e'; }
return WriteExponent(kk - 1, &buffer[0 + length + 2]); else if(kk < -maxDecimalPlaces)
} {
} // Truncate to zero
buffer[0] = '0';
buffer[1] = '.';
buffer[2] = '0';
return &buffer[3];
}
else if(length == 1)
{
// 1e30
buffer[1] = 'e';
return WriteExponent(kk - 1, &buffer[2]);
}
else
{
// 1234e30 -> 1.234e33
std::memmove(&buffer[2], &buffer[1], static_cast<size_t>(length - 1));
buffer[1] = '.';
buffer[length + 1] = 'e';
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); {
Double d(value); RAPIDJSON_ASSERT(maxDecimalPlaces >= 1);
if (d.IsZero()) { Double d(value);
if (d.Sign()) if(d.IsZero())
*buffer++ = '-'; // -0.0, Issue #289 {
buffer[0] = '0'; if(d.Sign())
buffer[1] = '.'; {
buffer[2] = '0'; *buffer++ = '-'; // -0.0, Issue #289
return &buffer[3]; }
} buffer[0] = '0';
else { buffer[1] = '.';
if (value < 0) { buffer[2] = '0';
*buffer++ = '-'; return &buffer[3];
value = -value; }
} else
int length, K; {
Grisu2(value, buffer, &length, &K); if(value < 0)
return Prettify(buffer, length, K, maxDecimalPlaces); {
} *buffer++ = '-';
} value = -value;
}
int length, K;
Grisu2(value, buffer, &length, &K);
return Prettify(buffer, length, K, maxDecimalPlaces);
}
}
#ifdef __GNUC__ #ifdef __GNUC__
RAPIDJSON_DIAG_POP RAPIDJSON_DIAG_POP
#endif #endif
} // namespace internal } // namespace internal

View file

@ -1,5 +1,5 @@
// Tencent is pleased to support the open source community by making RapidJSON available. // Tencent is pleased to support the open source community by making RapidJSON available.
// //
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// //
// Licensed under the MIT License (the "License"); you may not use this file except // Licensed under the MIT License (the "License"); you may not use this file except
@ -7,9 +7,9 @@
// //
// http://opensource.org/licenses/MIT // http://opensource.org/licenses/MIT
// //
// Unless required by applicable law or agreed to in writing, software distributed // Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License. // specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_IEEE754_ #ifndef RAPIDJSON_IEEE754_
@ -18,59 +18,109 @@
#include "../rapidjson.h" #include "../rapidjson.h"
RAPIDJSON_NAMESPACE_BEGIN RAPIDJSON_NAMESPACE_BEGIN
namespace internal { namespace internal
{
class Double { class Double
public: {
Double() {} public:
Double(double d) : d_(d) {} Double() {}
Double(uint64_t u) : u_(u) {} Double(double d) : d_(d) {}
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()); {
return Double(u_ + 1).Value(); RAPIDJSON_ASSERT(!Sign());
} return Double(u_ + 1).Value();
}
bool Sign() const { return (u_ & kSignMask) != 0; } bool Sign() const
uint64_t Significand() const { return u_ & kSignificandMask; } {
int Exponent() const { return static_cast<int>(((u_ & kExponentMask) >> kSignificandSize) - kExponentBias); } return (u_ & kSignMask) != 0;
}
uint64_t Significand() const
{
return u_ & kSignificandMask;
}
int Exponent() const
{
return static_cast<int>(((u_ & kExponentMask) >> kSignificandSize) - kExponentBias);
}
bool IsNan() const { return (u_ & kExponentMask) == kExponentMask && Significand() != 0; } bool IsNan() const
bool IsInf() const { return (u_ & kExponentMask) == kExponentMask && Significand() == 0; } {
bool IsNanOrInf() const { return (u_ & kExponentMask) == kExponentMask; } return (u_ & kExponentMask) == kExponentMask && Significand() != 0;
bool IsNormal() const { return (u_ & kExponentMask) != 0 || Significand() == 0; } }
bool IsZero() const { return (u_ & (kExponentMask | kSignificandMask)) == 0; } bool IsInf() const
{
return (u_ & kExponentMask) == kExponentMask && Significand() == 0;
}
bool IsNanOrInf() const
{
return (u_ & kExponentMask) == kExponentMask;
}
bool IsNormal() const
{
return (u_ & kExponentMask) != 0 || Significand() == 0;
}
bool IsZero() const
{
return (u_ & (kExponentMask | kSignificandMask)) == 0;
}
uint64_t IntegerSignificand() const { return IsNormal() ? Significand() | kHiddenBit : Significand(); } uint64_t IntegerSignificand() const
int IntegerExponent() const { return (IsNormal() ? Exponent() : kDenormalExponent) - kSignificandSize; } {
uint64_t ToBias() const { return (u_ & kSignMask) ? ~u_ + 1 : u_ | kSignMask; } return IsNormal() ? Significand() | kHiddenBit : Significand();
}
int IntegerExponent() const
{
return (IsNormal() ? Exponent() : kDenormalExponent) - kSignificandSize;
}
uint64_t ToBias() const
{
return (u_ & kSignMask) ? ~u_ + 1 : u_ | kSignMask;
}
static unsigned EffectiveSignificandSize(int order) { static unsigned EffectiveSignificandSize(int order)
if (order >= -1021) {
return 53; if(order >= -1021)
else if (order <= -1074) {
return 0; return 53;
else }
return static_cast<unsigned>(order) + 1074; else if(order <= -1074)
} {
return 0;
}
else
{
return static_cast<unsigned>(order) + 1074;
}
}
private: 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;
static const uint64_t kSignMask = RAPIDJSON_UINT64_C2(0x80000000, 0x00000000); static const uint64_t kSignMask = RAPIDJSON_UINT64_C2(0x80000000, 0x00000000);
static const uint64_t kExponentMask = RAPIDJSON_UINT64_C2(0x7FF00000, 0x00000000); static const uint64_t kExponentMask = RAPIDJSON_UINT64_C2(0x7FF00000, 0x00000000);
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_; {
uint64_t u_; double d_;
}; uint64_t u_;
}; };
};
} // namespace internal } // namespace internal
RAPIDJSON_NAMESPACE_END RAPIDJSON_NAMESPACE_END

View file

@ -1,5 +1,5 @@
// Tencent is pleased to support the open source community by making RapidJSON available. // Tencent is pleased to support the open source community by making RapidJSON available.
// //
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// //
// Licensed under the MIT License (the "License"); you may not use this file except // Licensed under the MIT License (the "License"); you may not use this file except
@ -7,9 +7,9 @@
// //
// http://opensource.org/licenses/MIT // http://opensource.org/licenses/MIT
// //
// Unless required by applicable law or agreed to in writing, software distributed // Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License. // specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_ITOA_ #ifndef RAPIDJSON_ITOA_
@ -18,285 +18,350 @@
#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',
return cDigitsLut; '9', '0', '9', '1', '9', '2', '9', '3', '9', '4', '9', '5', '9', '6', '9', '7', '9', '8', '9', '9'
} };
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 d2 = (value % 100) << 1; const uint32_t d1 = (value / 100) << 1;
const uint32_t d2 = (value % 100) << 1;
if (value >= 1000)
*buffer++ = cDigitsLut[d1];
if (value >= 100)
*buffer++ = cDigitsLut[d1 + 1];
if (value >= 10)
*buffer++ = cDigitsLut[d2];
*buffer++ = cDigitsLut[d2 + 1];
}
else if (value < 100000000) {
// value = bbbbcccc
const uint32_t b = value / 10000;
const uint32_t c = value % 10000;
const uint32_t d1 = (b / 100) << 1;
const uint32_t d2 = (b % 100) << 1;
const uint32_t d3 = (c / 100) << 1;
const uint32_t d4 = (c % 100) << 1;
if (value >= 10000000)
*buffer++ = cDigitsLut[d1];
if (value >= 1000000)
*buffer++ = cDigitsLut[d1 + 1];
if (value >= 100000)
*buffer++ = cDigitsLut[d2];
*buffer++ = cDigitsLut[d2 + 1];
*buffer++ = cDigitsLut[d3];
*buffer++ = cDigitsLut[d3 + 1];
*buffer++ = cDigitsLut[d4];
*buffer++ = cDigitsLut[d4 + 1];
}
else {
// value = aabbbbcccc in decimal
const uint32_t a = value / 100000000; // 1 to 42
value %= 100000000;
if (a >= 10) {
const unsigned i = a << 1;
*buffer++ = cDigitsLut[i];
*buffer++ = cDigitsLut[i + 1];
}
else
*buffer++ = static_cast<char>('0' + static_cast<char>(a));
const uint32_t b = value / 10000; // 0 to 9999 if(value >= 1000)
const uint32_t c = value % 10000; // 0 to 9999 {
*buffer++ = cDigitsLut[d1];
const uint32_t d1 = (b / 100) << 1; }
const uint32_t d2 = (b % 100) << 1; if(value >= 100)
{
const uint32_t d3 = (c / 100) << 1; *buffer++ = cDigitsLut[d1 + 1];
const uint32_t d4 = (c % 100) << 1; }
if(value >= 10)
*buffer++ = cDigitsLut[d1]; {
*buffer++ = cDigitsLut[d1 + 1]; *buffer++ = cDigitsLut[d2];
*buffer++ = cDigitsLut[d2]; }
*buffer++ = cDigitsLut[d2 + 1]; *buffer++ = cDigitsLut[d2 + 1];
*buffer++ = cDigitsLut[d3]; }
*buffer++ = cDigitsLut[d3 + 1]; else if(value < 100000000)
*buffer++ = cDigitsLut[d4]; {
*buffer++ = cDigitsLut[d4 + 1]; // value = bbbbcccc
} const uint32_t b = value / 10000;
return buffer; const uint32_t c = value % 10000;
}
inline char* i32toa(int32_t value, char* buffer) { const uint32_t d1 = (b / 100) << 1;
uint32_t u = static_cast<uint32_t>(value); const uint32_t d2 = (b % 100) << 1;
if (value < 0) {
*buffer++ = '-';
u = ~u + 1;
}
return u32toa(u, buffer); const uint32_t d3 = (c / 100) << 1;
} const uint32_t d4 = (c % 100) << 1;
inline char* u64toa(uint64_t value, char* buffer) { if(value >= 10000000)
const char* cDigitsLut = GetDigitsLut(); {
const uint64_t kTen8 = 100000000; *buffer++ = cDigitsLut[d1];
const uint64_t kTen9 = kTen8 * 10; }
const uint64_t kTen10 = kTen8 * 100; if(value >= 1000000)
const uint64_t kTen11 = kTen8 * 1000; {
const uint64_t kTen12 = kTen8 * 10000; *buffer++ = cDigitsLut[d1 + 1];
const uint64_t kTen13 = kTen8 * 100000; }
const uint64_t kTen14 = kTen8 * 1000000; if(value >= 100000)
const uint64_t kTen15 = kTen8 * 10000000; {
const uint64_t kTen16 = kTen8 * kTen8; *buffer++ = cDigitsLut[d2];
}
if (value < kTen8) { *buffer++ = cDigitsLut[d2 + 1];
uint32_t v = static_cast<uint32_t>(value);
if (v < 10000) {
const uint32_t d1 = (v / 100) << 1;
const uint32_t d2 = (v % 100) << 1;
if (v >= 1000)
*buffer++ = cDigitsLut[d1];
if (v >= 100)
*buffer++ = cDigitsLut[d1 + 1];
if (v >= 10)
*buffer++ = cDigitsLut[d2];
*buffer++ = cDigitsLut[d2 + 1];
}
else {
// value = bbbbcccc
const uint32_t b = v / 10000;
const uint32_t c = v % 10000;
const uint32_t d1 = (b / 100) << 1;
const uint32_t d2 = (b % 100) << 1;
const uint32_t d3 = (c / 100) << 1;
const uint32_t d4 = (c % 100) << 1;
if (value >= 10000000)
*buffer++ = cDigitsLut[d1];
if (value >= 1000000)
*buffer++ = cDigitsLut[d1 + 1];
if (value >= 100000)
*buffer++ = cDigitsLut[d2];
*buffer++ = cDigitsLut[d2 + 1];
*buffer++ = cDigitsLut[d3];
*buffer++ = cDigitsLut[d3 + 1];
*buffer++ = cDigitsLut[d4];
*buffer++ = cDigitsLut[d4 + 1];
}
}
else if (value < kTen16) {
const uint32_t v0 = static_cast<uint32_t>(value / kTen8);
const uint32_t v1 = static_cast<uint32_t>(value % kTen8);
const uint32_t b0 = v0 / 10000;
const uint32_t c0 = v0 % 10000;
const uint32_t d1 = (b0 / 100) << 1;
const uint32_t d2 = (b0 % 100) << 1;
const uint32_t d3 = (c0 / 100) << 1;
const uint32_t d4 = (c0 % 100) << 1;
const uint32_t b1 = v1 / 10000; *buffer++ = cDigitsLut[d3];
const uint32_t c1 = v1 % 10000; *buffer++ = cDigitsLut[d3 + 1];
*buffer++ = cDigitsLut[d4];
const uint32_t d5 = (b1 / 100) << 1; *buffer++ = cDigitsLut[d4 + 1];
const uint32_t d6 = (b1 % 100) << 1; }
else
const uint32_t d7 = (c1 / 100) << 1; {
const uint32_t d8 = (c1 % 100) << 1; // value = aabbbbcccc in decimal
if (value >= kTen15) const uint32_t a = value / 100000000; // 1 to 42
*buffer++ = cDigitsLut[d1]; value %= 100000000;
if (value >= kTen14)
*buffer++ = cDigitsLut[d1 + 1];
if (value >= kTen13)
*buffer++ = cDigitsLut[d2];
if (value >= kTen12)
*buffer++ = cDigitsLut[d2 + 1];
if (value >= kTen11)
*buffer++ = cDigitsLut[d3];
if (value >= kTen10)
*buffer++ = cDigitsLut[d3 + 1];
if (value >= kTen9)
*buffer++ = cDigitsLut[d4];
if (value >= kTen8)
*buffer++ = cDigitsLut[d4 + 1];
*buffer++ = cDigitsLut[d5];
*buffer++ = cDigitsLut[d5 + 1];
*buffer++ = cDigitsLut[d6];
*buffer++ = cDigitsLut[d6 + 1];
*buffer++ = cDigitsLut[d7];
*buffer++ = cDigitsLut[d7 + 1];
*buffer++ = cDigitsLut[d8];
*buffer++ = cDigitsLut[d8 + 1];
}
else {
const uint32_t a = static_cast<uint32_t>(value / kTen16); // 1 to 1844
value %= kTen16;
if (a < 10)
*buffer++ = static_cast<char>('0' + static_cast<char>(a));
else if (a < 100) {
const uint32_t i = a << 1;
*buffer++ = cDigitsLut[i];
*buffer++ = cDigitsLut[i + 1];
}
else if (a < 1000) {
*buffer++ = static_cast<char>('0' + static_cast<char>(a / 100));
const uint32_t i = (a % 100) << 1;
*buffer++ = cDigitsLut[i];
*buffer++ = cDigitsLut[i + 1];
}
else {
const uint32_t i = (a / 100) << 1;
const uint32_t j = (a % 100) << 1;
*buffer++ = cDigitsLut[i];
*buffer++ = cDigitsLut[i + 1];
*buffer++ = cDigitsLut[j];
*buffer++ = cDigitsLut[j + 1];
}
const uint32_t v0 = static_cast<uint32_t>(value / kTen8);
const uint32_t v1 = static_cast<uint32_t>(value % kTen8);
const uint32_t b0 = v0 / 10000;
const uint32_t c0 = v0 % 10000;
const uint32_t d1 = (b0 / 100) << 1;
const uint32_t d2 = (b0 % 100) << 1;
const uint32_t d3 = (c0 / 100) << 1;
const uint32_t d4 = (c0 % 100) << 1;
const uint32_t b1 = v1 / 10000;
const uint32_t c1 = v1 % 10000;
const uint32_t d5 = (b1 / 100) << 1;
const uint32_t d6 = (b1 % 100) << 1;
const uint32_t d7 = (c1 / 100) << 1;
const uint32_t d8 = (c1 % 100) << 1;
*buffer++ = cDigitsLut[d1];
*buffer++ = cDigitsLut[d1 + 1];
*buffer++ = cDigitsLut[d2];
*buffer++ = cDigitsLut[d2 + 1];
*buffer++ = cDigitsLut[d3];
*buffer++ = cDigitsLut[d3 + 1];
*buffer++ = cDigitsLut[d4];
*buffer++ = cDigitsLut[d4 + 1];
*buffer++ = cDigitsLut[d5];
*buffer++ = cDigitsLut[d5 + 1];
*buffer++ = cDigitsLut[d6];
*buffer++ = cDigitsLut[d6 + 1];
*buffer++ = cDigitsLut[d7];
*buffer++ = cDigitsLut[d7 + 1];
*buffer++ = cDigitsLut[d8];
*buffer++ = cDigitsLut[d8 + 1];
}
return buffer;
}
inline char* i64toa(int64_t value, char* buffer) { if(a >= 10)
uint64_t u = static_cast<uint64_t>(value); {
if (value < 0) { const unsigned i = a << 1;
*buffer++ = '-'; *buffer++ = cDigitsLut[i];
u = ~u + 1; *buffer++ = cDigitsLut[i + 1];
} }
else
{
*buffer++ = static_cast<char>('0' + static_cast<char>(a));
}
return u64toa(u, buffer); const uint32_t b = value / 10000; // 0 to 9999
} const uint32_t c = value % 10000; // 0 to 9999
const uint32_t d1 = (b / 100) << 1;
const uint32_t d2 = (b % 100) << 1;
const uint32_t d3 = (c / 100) << 1;
const uint32_t d4 = (c % 100) << 1;
*buffer++ = cDigitsLut[d1];
*buffer++ = cDigitsLut[d1 + 1];
*buffer++ = cDigitsLut[d2];
*buffer++ = cDigitsLut[d2 + 1];
*buffer++ = cDigitsLut[d3];
*buffer++ = cDigitsLut[d3 + 1];
*buffer++ = cDigitsLut[d4];
*buffer++ = cDigitsLut[d4 + 1];
}
return buffer;
}
inline char* i32toa(int32_t value, char* buffer)
{
uint32_t u = static_cast<uint32_t>(value);
if(value < 0)
{
*buffer++ = '-';
u = ~u + 1;
}
return u32toa(u, buffer);
}
inline char* u64toa(uint64_t value, char* buffer)
{
const char* cDigitsLut = GetDigitsLut();
const uint64_t kTen8 = 100000000;
const uint64_t kTen9 = kTen8 * 10;
const uint64_t kTen10 = kTen8 * 100;
const uint64_t kTen11 = kTen8 * 1000;
const uint64_t kTen12 = kTen8 * 10000;
const uint64_t kTen13 = kTen8 * 100000;
const uint64_t kTen14 = kTen8 * 1000000;
const uint64_t kTen15 = kTen8 * 10000000;
const uint64_t kTen16 = kTen8 * kTen8;
if(value < kTen8)
{
uint32_t v = static_cast<uint32_t>(value);
if(v < 10000)
{
const uint32_t d1 = (v / 100) << 1;
const uint32_t d2 = (v % 100) << 1;
if(v >= 1000)
{
*buffer++ = cDigitsLut[d1];
}
if(v >= 100)
{
*buffer++ = cDigitsLut[d1 + 1];
}
if(v >= 10)
{
*buffer++ = cDigitsLut[d2];
}
*buffer++ = cDigitsLut[d2 + 1];
}
else
{
// value = bbbbcccc
const uint32_t b = v / 10000;
const uint32_t c = v % 10000;
const uint32_t d1 = (b / 100) << 1;
const uint32_t d2 = (b % 100) << 1;
const uint32_t d3 = (c / 100) << 1;
const uint32_t d4 = (c % 100) << 1;
if(value >= 10000000)
{
*buffer++ = cDigitsLut[d1];
}
if(value >= 1000000)
{
*buffer++ = cDigitsLut[d1 + 1];
}
if(value >= 100000)
{
*buffer++ = cDigitsLut[d2];
}
*buffer++ = cDigitsLut[d2 + 1];
*buffer++ = cDigitsLut[d3];
*buffer++ = cDigitsLut[d3 + 1];
*buffer++ = cDigitsLut[d4];
*buffer++ = cDigitsLut[d4 + 1];
}
}
else if(value < kTen16)
{
const uint32_t v0 = static_cast<uint32_t>(value / kTen8);
const uint32_t v1 = static_cast<uint32_t>(value % kTen8);
const uint32_t b0 = v0 / 10000;
const uint32_t c0 = v0 % 10000;
const uint32_t d1 = (b0 / 100) << 1;
const uint32_t d2 = (b0 % 100) << 1;
const uint32_t d3 = (c0 / 100) << 1;
const uint32_t d4 = (c0 % 100) << 1;
const uint32_t b1 = v1 / 10000;
const uint32_t c1 = v1 % 10000;
const uint32_t d5 = (b1 / 100) << 1;
const uint32_t d6 = (b1 % 100) << 1;
const uint32_t d7 = (c1 / 100) << 1;
const uint32_t d8 = (c1 % 100) << 1;
if(value >= kTen15)
{
*buffer++ = cDigitsLut[d1];
}
if(value >= kTen14)
{
*buffer++ = cDigitsLut[d1 + 1];
}
if(value >= kTen13)
{
*buffer++ = cDigitsLut[d2];
}
if(value >= kTen12)
{
*buffer++ = cDigitsLut[d2 + 1];
}
if(value >= kTen11)
{
*buffer++ = cDigitsLut[d3];
}
if(value >= kTen10)
{
*buffer++ = cDigitsLut[d3 + 1];
}
if(value >= kTen9)
{
*buffer++ = cDigitsLut[d4];
}
if(value >= kTen8)
{
*buffer++ = cDigitsLut[d4 + 1];
}
*buffer++ = cDigitsLut[d5];
*buffer++ = cDigitsLut[d5 + 1];
*buffer++ = cDigitsLut[d6];
*buffer++ = cDigitsLut[d6 + 1];
*buffer++ = cDigitsLut[d7];
*buffer++ = cDigitsLut[d7 + 1];
*buffer++ = cDigitsLut[d8];
*buffer++ = cDigitsLut[d8 + 1];
}
else
{
const uint32_t a = static_cast<uint32_t>(value / kTen16); // 1 to 1844
value %= kTen16;
if(a < 10)
{
*buffer++ = static_cast<char>('0' + static_cast<char>(a));
}
else if(a < 100)
{
const uint32_t i = a << 1;
*buffer++ = cDigitsLut[i];
*buffer++ = cDigitsLut[i + 1];
}
else if(a < 1000)
{
*buffer++ = static_cast<char>('0' + static_cast<char>(a / 100));
const uint32_t i = (a % 100) << 1;
*buffer++ = cDigitsLut[i];
*buffer++ = cDigitsLut[i + 1];
}
else
{
const uint32_t i = (a / 100) << 1;
const uint32_t j = (a % 100) << 1;
*buffer++ = cDigitsLut[i];
*buffer++ = cDigitsLut[i + 1];
*buffer++ = cDigitsLut[j];
*buffer++ = cDigitsLut[j + 1];
}
const uint32_t v0 = static_cast<uint32_t>(value / kTen8);
const uint32_t v1 = static_cast<uint32_t>(value % kTen8);
const uint32_t b0 = v0 / 10000;
const uint32_t c0 = v0 % 10000;
const uint32_t d1 = (b0 / 100) << 1;
const uint32_t d2 = (b0 % 100) << 1;
const uint32_t d3 = (c0 / 100) << 1;
const uint32_t d4 = (c0 % 100) << 1;
const uint32_t b1 = v1 / 10000;
const uint32_t c1 = v1 % 10000;
const uint32_t d5 = (b1 / 100) << 1;
const uint32_t d6 = (b1 % 100) << 1;
const uint32_t d7 = (c1 / 100) << 1;
const uint32_t d8 = (c1 % 100) << 1;
*buffer++ = cDigitsLut[d1];
*buffer++ = cDigitsLut[d1 + 1];
*buffer++ = cDigitsLut[d2];
*buffer++ = cDigitsLut[d2 + 1];
*buffer++ = cDigitsLut[d3];
*buffer++ = cDigitsLut[d3 + 1];
*buffer++ = cDigitsLut[d4];
*buffer++ = cDigitsLut[d4 + 1];
*buffer++ = cDigitsLut[d5];
*buffer++ = cDigitsLut[d5 + 1];
*buffer++ = cDigitsLut[d6];
*buffer++ = cDigitsLut[d6 + 1];
*buffer++ = cDigitsLut[d7];
*buffer++ = cDigitsLut[d7 + 1];
*buffer++ = cDigitsLut[d8];
*buffer++ = cDigitsLut[d8 + 1];
}
return buffer;
}
inline char* i64toa(int64_t value, char* buffer)
{
uint64_t u = static_cast<uint64_t>(value);
if(value < 0)
{
*buffer++ = '-';
u = ~u + 1;
}
return u64toa(u, buffer);
}
} // namespace internal } // namespace internal
RAPIDJSON_NAMESPACE_END RAPIDJSON_NAMESPACE_END

View file

@ -1,5 +1,5 @@
// Tencent is pleased to support the open source community by making RapidJSON available. // Tencent is pleased to support the open source community by making RapidJSON available.
// //
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// //
// Licensed under the MIT License (the "License"); you may not use this file except // Licensed under the MIT License (the "License"); you may not use this file except
@ -7,9 +7,9 @@
// //
// http://opensource.org/licenses/MIT // http://opensource.org/licenses/MIT
// //
// Unless required by applicable law or agreed to in writing, software distributed // Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License. // specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_INTERNAL_META_H_ #ifndef RAPIDJSON_INTERNAL_META_H_
@ -32,143 +32,186 @@ 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; {
typedef BoolType Type; static const bool Value = Cond;
}; typedef BoolType Type;
typedef BoolType<true> TrueType; };
typedef BoolType<false> FalseType; typedef BoolType<true> TrueType;
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(D) != 0); RAPIDJSON_STATIC_ASSERT(sizeof(B) != 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 \
< ::RAPIDJSON_NAMESPACE::internal::SfinaeTag&(*) type>::Type < ::RAPIDJSON_NAMESPACE::internal::SfinaeTag&(*) type>::Type
#define RAPIDJSON_ENABLEIF(cond) \ #define RAPIDJSON_ENABLEIF(cond) \
typename ::RAPIDJSON_NAMESPACE::internal::EnableIf \ typename ::RAPIDJSON_NAMESPACE::internal::EnableIf \
<RAPIDJSON_REMOVEFPTR_(cond)>::Type * = NULL <RAPIDJSON_REMOVEFPTR_(cond)>::Type * = NULL
#define RAPIDJSON_DISABLEIF(cond) \ #define RAPIDJSON_DISABLEIF(cond) \
typename ::RAPIDJSON_NAMESPACE::internal::DisableIf \ typename ::RAPIDJSON_NAMESPACE::internal::DisableIf \
<RAPIDJSON_REMOVEFPTR_(cond)>::Type * = NULL <RAPIDJSON_REMOVEFPTR_(cond)>::Type * = NULL
#define RAPIDJSON_ENABLEIF_RETURN(cond,returntype) \ #define RAPIDJSON_ENABLEIF_RETURN(cond,returntype) \
typename ::RAPIDJSON_NAMESPACE::internal::EnableIf \ typename ::RAPIDJSON_NAMESPACE::internal::EnableIf \
<RAPIDJSON_REMOVEFPTR_(cond), \ <RAPIDJSON_REMOVEFPTR_(cond), \
RAPIDJSON_REMOVEFPTR_(returntype)>::Type RAPIDJSON_REMOVEFPTR_(returntype)>::Type
#define RAPIDJSON_DISABLEIF_RETURN(cond,returntype) \ #define RAPIDJSON_DISABLEIF_RETURN(cond,returntype) \
typename ::RAPIDJSON_NAMESPACE::internal::DisableIf \ typename ::RAPIDJSON_NAMESPACE::internal::DisableIf \
<RAPIDJSON_REMOVEFPTR_(cond), \ <RAPIDJSON_REMOVEFPTR_(cond), \
RAPIDJSON_REMOVEFPTR_(returntype)>::Type RAPIDJSON_REMOVEFPTR_(returntype)>::Type
} // namespace internal } // namespace internal
RAPIDJSON_NAMESPACE_END RAPIDJSON_NAMESPACE_END

View file

@ -1,5 +1,5 @@
// Tencent is pleased to support the open source community by making RapidJSON available. // Tencent is pleased to support the open source community by making RapidJSON available.
// //
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// //
// Licensed under the MIT License (the "License"); you may not use this file except // Licensed under the MIT License (the "License"); you may not use this file except
@ -7,9 +7,9 @@
// //
// http://opensource.org/licenses/MIT // http://opensource.org/licenses/MIT
// //
// Unless required by applicable law or agreed to in writing, software distributed // Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License. // specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_POW10_ #ifndef RAPIDJSON_POW10_
@ -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 {
1e+0, static const double e[] = // 1e-0...1e308: 309 * 8 bytes = 2472 bytes
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+0,
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+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+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+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+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+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+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+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+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+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+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+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+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+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+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+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+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+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+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+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+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+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+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+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+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+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+301,1e+302,1e+303,1e+304,1e+305,1e+306,1e+307,1e+308 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,
RAPIDJSON_ASSERT(n >= 0 && n <= 308); 1e+301, 1e+302, 1e+303, 1e+304, 1e+305, 1e+306, 1e+307, 1e+308
return e[n]; };
} RAPIDJSON_ASSERT(n >= 0 && n <= 308);
return e[n];
}
} // namespace internal } // namespace internal
RAPIDJSON_NAMESPACE_END RAPIDJSON_NAMESPACE_END

File diff suppressed because it is too large Load diff

View file

@ -1,5 +1,5 @@
// Tencent is pleased to support the open source community by making RapidJSON available. // Tencent is pleased to support the open source community by making RapidJSON available.
// //
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// //
// Licensed under the MIT License (the "License"); you may not use this file except // Licensed under the MIT License (the "License"); you may not use this file except
@ -7,9 +7,9 @@
// //
// http://opensource.org/licenses/MIT // http://opensource.org/licenses/MIT
// //
// Unless required by applicable law or agreed to in writing, software distributed // Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License. // specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_INTERNAL_STACK_H_ #ifndef RAPIDJSON_INTERNAL_STACK_H_
@ -20,205 +20,260 @@
#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: {
// Optimization note: Do not allocate memory for stack_ in constructor. public:
// Do it lazily when first Push() -> Expand() -> Resize(). // Optimization note: Do not allocate memory for stack_ in constructor.
Stack(Allocator* allocator, size_t stackCapacity) : allocator_(allocator), ownAllocator_(0), stack_(0), stackTop_(0), stackEnd_(0), initialCapacity_(stackCapacity) { // 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)
{
}
#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_),
stackTop_(rhs.stackTop_), stackTop_(rhs.stackTop_),
stackEnd_(rhs.stackEnd_), stackEnd_(rhs.stackEnd_),
initialCapacity_(rhs.initialCapacity_) initialCapacity_(rhs.initialCapacity_)
{ {
rhs.allocator_ = 0; rhs.allocator_ = 0;
rhs.ownAllocator_ = 0; rhs.ownAllocator_ = 0;
rhs.stack_ = 0; rhs.stack_ = 0;
rhs.stackTop_ = 0; rhs.stackTop_ = 0;
rhs.stackEnd_ = 0; rhs.stackEnd_ = 0;
rhs.initialCapacity_ = 0; rhs.initialCapacity_ = 0;
} }
#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();
allocator_ = rhs.allocator_; allocator_ = rhs.allocator_;
ownAllocator_ = rhs.ownAllocator_; ownAllocator_ = rhs.ownAllocator_;
stack_ = rhs.stack_; stack_ = rhs.stack_;
stackTop_ = rhs.stackTop_; stackTop_ = rhs.stackTop_;
stackEnd_ = rhs.stackEnd_; stackEnd_ = rhs.stackEnd_;
initialCapacity_ = rhs.initialCapacity_; initialCapacity_ = rhs.initialCapacity_;
rhs.allocator_ = 0; rhs.allocator_ = 0;
rhs.ownAllocator_ = 0; rhs.ownAllocator_ = 0;
rhs.stack_ = 0; rhs.stack_ = 0;
rhs.stackTop_ = 0; rhs.stackTop_ = 0;
rhs.stackEnd_ = 0; rhs.stackEnd_ = 0;
rhs.initialCapacity_ = 0; rhs.initialCapacity_ = 0;
} }
return *this; return *this;
} }
#endif #endif
void Swap(Stack& rhs) RAPIDJSON_NOEXCEPT { void Swap(Stack & rhs) RAPIDJSON_NOEXCEPT
internal::Swap(allocator_, rhs.allocator_); {
internal::Swap(ownAllocator_, rhs.ownAllocator_); internal::Swap(allocator_, rhs.allocator_);
internal::Swap(stack_, rhs.stack_); internal::Swap(ownAllocator_, rhs.ownAllocator_);
internal::Swap(stackTop_, rhs.stackTop_); internal::Swap(stack_, rhs.stack_);
internal::Swap(stackEnd_, rhs.stackEnd_); internal::Swap(stackTop_, rhs.stackTop_);
internal::Swap(initialCapacity_, rhs.initialCapacity_); internal::Swap(stackEnd_, rhs.stackEnd_);
} internal::Swap(initialCapacity_, rhs.initialCapacity_);
}
void Clear() { stackTop_ = stack_; } void Clear()
{
stackTop_ = stack_;
}
void ShrinkToFit() { void ShrinkToFit()
if (Empty()) { {
// If the stack is empty, completely deallocate the memory. if(Empty())
Allocator::Free(stack_); {
stack_ = 0; // If the stack is empty, completely deallocate the memory.
stackTop_ = 0; Allocator::Free(stack_);
stackEnd_ = 0; stack_ = 0;
} stackTop_ = 0;
else stackEnd_ = 0;
Resize(GetSize()); }
} else
{
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 {
if (RAPIDJSON_UNLIKELY(stackTop_ + sizeof(T) * count > stackEnd_)) // Expand the stack if needed
Expand<T>(count); if(RAPIDJSON_UNLIKELY(stackTop_ + sizeof(T) * count > stackEnd_))
} {
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); {
return PushUnsafe<T>(count); Reserve<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_); {
T* ret = reinterpret_cast<T*>(stackTop_); RAPIDJSON_ASSERT(stackTop_ + sizeof(T) * count <= stackEnd_);
stackTop_ += sizeof(T) * count; T* ret = reinterpret_cast<T*>(stackTop_);
return ret; stackTop_ += sizeof(T) * count;
} return ret;
}
template<typename T> template<typename T>
T* Pop(size_t count) { T* Pop(size_t count)
RAPIDJSON_ASSERT(GetSize() >= count * sizeof(T)); {
stackTop_ -= count * sizeof(T); RAPIDJSON_ASSERT(GetSize() >= count * sizeof(T));
return reinterpret_cast<T*>(stackTop_); stackTop_ -= count * sizeof(T);
} return reinterpret_cast<T*>(stackTop_);
}
template<typename T> template<typename T>
T* Top() { T* Top()
RAPIDJSON_ASSERT(GetSize() >= sizeof(T)); {
return reinterpret_cast<T*>(stackTop_ - sizeof(T)); RAPIDJSON_ASSERT(GetSize() >= 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)); {
return reinterpret_cast<T*>(stackTop_ - sizeof(T)); RAPIDJSON_ASSERT(GetSize() >= 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_); {
return *allocator_; RAPIDJSON_ASSERT(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. {
size_t newCapacity; // Only expand the capacity if the current stack exists. Otherwise just create a stack with initial capacity.
if (stack_ == 0) { size_t newCapacity;
if (!allocator_) if(stack_ == 0)
ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator()); {
newCapacity = initialCapacity_; if(!allocator_)
} else { {
newCapacity = GetCapacity(); ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator());
newCapacity += (newCapacity + 1) / 2; }
} newCapacity = initialCapacity_;
size_t newSize = GetSize() + sizeof(T) * count; }
if (newCapacity < newSize) else
newCapacity = newSize; {
newCapacity = GetCapacity();
newCapacity += (newCapacity + 1) / 2;
}
size_t newSize = GetSize() + sizeof(T) * count;
if(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 {
stack_ = static_cast<char*>(allocator_->Realloc(stack_, GetCapacity(), newCapacity)); const size_t size = GetSize(); // Backup the current size
stackTop_ = stack_ + size; stack_ = static_cast<char*>(allocator_->Realloc(stack_, GetCapacity(), newCapacity));
stackEnd_ = stack_ + newCapacity; stackTop_ = stack_ + size;
} stackEnd_ = stack_ + newCapacity;
}
void Destroy() { void Destroy()
Allocator::Free(stack_); {
RAPIDJSON_DELETE(ownAllocator_); // Only delete if it is owned by the stack Allocator::Free(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

@ -1,5 +1,5 @@
// Tencent is pleased to support the open source community by making RapidJSON available. // Tencent is pleased to support the open source community by making RapidJSON available.
// //
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// //
// Licensed under the MIT License (the "License"); you may not use this file except // Licensed under the MIT License (the "License"); you may not use this file except
@ -7,9 +7,9 @@
// //
// http://opensource.org/licenses/MIT // http://opensource.org/licenses/MIT
// //
// Unless required by applicable law or agreed to in writing, software distributed // Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License. // specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_INTERNAL_STRFUNC_H_ #ifndef RAPIDJSON_INTERNAL_STRFUNC_H_
@ -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; {
while (*p) ++p; const Ch* p = s;
return SizeType(p - s); while(*p)
} {
++p;
}
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); {
const typename Encoding::Ch* end = s + length; GenericStringStream<Encoding> is(s);
SizeType count = 0; const typename Encoding::Ch* end = s + length;
while (is.src_ < end) { SizeType count = 0;
unsigned codepoint; while(is.src_ < end)
if (!Encoding::Decode(is, &codepoint)) {
return false; unsigned codepoint;
count++; if(!Encoding::Decode(is, &codepoint))
} {
*outCount = count; return false;
return true; }
} count++;
}
*outCount = count;
return true;
}
} // namespace internal } // namespace internal
RAPIDJSON_NAMESPACE_END RAPIDJSON_NAMESPACE_END

View file

@ -1,5 +1,5 @@
// Tencent is pleased to support the open source community by making RapidJSON available. // Tencent is pleased to support the open source community by making RapidJSON available.
// //
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// //
// Licensed under the MIT License (the "License"); you may not use this file except // Licensed under the MIT License (the "License"); you may not use this file except
@ -7,9 +7,9 @@
// //
// http://opensource.org/licenses/MIT // http://opensource.org/licenses/MIT
// //
// Unless required by applicable law or agreed to in writing, software distributed // Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License. // specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_STRTOD_ #ifndef RAPIDJSON_STRTOD_
@ -21,247 +21,316 @@
#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) {
return 0.0; if(exp < -308)
else if (exp >= 0) {
return significand * internal::Pow10(exp); return 0.0;
else }
return significand / internal::Pow10(-exp); else if(exp >= 0)
} {
return significand * internal::Pow10(exp);
}
else
{
return significand / internal::Pow10(-exp);
}
}
inline double StrtodNormalPrecision(double d, int p) { inline double StrtodNormalPrecision(double d, int p)
if (p < -308) { {
// Prevent expSum < -308, making Pow10(p) = 0 if(p < -308)
d = FastPath(d, -308); {
d = FastPath(d, p + 308); // Prevent expSum < -308, making Pow10(p) = 0
} d = FastPath(d, -308);
else d = FastPath(d, p + 308);
d = FastPath(d, p); }
return d; else
} {
d = FastPath(d, p);
}
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; {
if (m > b) m = b; T m = a;
if (m > c) m = c; if(m > b)
return m; {
} m = b;
}
if(m > c)
{
m = c;
}
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 uint64_t bInt = db.IntegerSignificand(); const Double db(b);
const int bExp = db.IntegerExponent(); const uint64_t bInt = db.IntegerSignificand();
const int hExp = bExp - 1; const int bExp = db.IntegerExponent();
const int hExp = bExp - 1;
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_Exp5 += dExp; dS_Exp2 += dExp;
} dS_Exp5 += dExp;
else { }
bS_Exp2 -= dExp; else
bS_Exp5 -= dExp; {
hS_Exp2 -= dExp; bS_Exp2 -= dExp;
hS_Exp5 -= dExp; bS_Exp5 -= dExp;
} hS_Exp2 -= dExp;
hS_Exp5 -= dExp;
}
// Adjust for binary exponent // Adjust for binary exponent
if (bExp >= 0) if(bExp >= 0)
bS_Exp2 += bExp; {
else { bS_Exp2 += bExp;
dS_Exp2 -= bExp; }
hS_Exp2 -= bExp; else
} {
dS_Exp2 -= bExp;
hS_Exp2 -= bExp;
}
// Adjust for half ulp exponent // Adjust for half ulp exponent
if (hExp >= 0) if(hExp >= 0)
hS_Exp2 += hExp; {
else { hS_Exp2 += hExp;
dS_Exp2 -= hExp; }
bS_Exp2 -= hExp; else
} {
dS_Exp2 -= hExp;
bS_Exp2 -= hExp;
}
// Remove common power of two factor from all three scaled values // Remove common power of two factor from all three scaled values
int common_Exp2 = Min3(dS_Exp2, bS_Exp2, hS_Exp2); int common_Exp2 = Min3(dS_Exp2, bS_Exp2, hS_Exp2);
dS_Exp2 -= common_Exp2; dS_Exp2 -= common_Exp2;
bS_Exp2 -= common_Exp2; bS_Exp2 -= common_Exp2;
hS_Exp2 -= common_Exp2; hS_Exp2 -= common_Exp2;
BigInteger dS = d; BigInteger dS = d;
dS.MultiplyPow5(static_cast<unsigned>(dS_Exp5)) <<= static_cast<unsigned>(dS_Exp2); dS.MultiplyPow5(static_cast<unsigned>(dS_Exp5)) <<= static_cast<unsigned>(dS_Exp2);
BigInteger bS(bInt); BigInteger bS(bInt);
bS.MultiplyPow5(static_cast<unsigned>(bS_Exp5)) <<= static_cast<unsigned>(bS_Exp2); bS.MultiplyPow5(static_cast<unsigned>(bS_Exp5)) <<= static_cast<unsigned>(bS_Exp2);
BigInteger hS(1); BigInteger hS(1);
hS.MultiplyPow5(static_cast<unsigned>(hS_Exp5)) <<= static_cast<unsigned>(hS_Exp2); hS.MultiplyPow5(static_cast<unsigned>(hS_Exp5)) <<= static_cast<unsigned>(hS_Exp2);
BigInteger delta(0); BigInteger delta(0);
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 {
// see http://www.exploringbinary.com/fast-path-decimal-to-floating-point-conversion/ // Use fast path for string-to-double conversion if possible
if (p > 22 && p < 22 + 16) { // see http://www.exploringbinary.com/fast-path-decimal-to-floating-point-conversion/
// Fast Path Cases In Disguise if(p > 22 && p < 22 + 16)
d *= internal::Pow10(p - 22); {
p = 22; // Fast Path Cases In Disguise
} d *= internal::Pow10(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); {
return true; *result = FastPath(d, p);
} return true;
else }
return false; else
} {
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; {
size_t i = 0; // 2^64 - 1 = 18446744073709551615, 1844674407370955161 = 0x1999999999999999 uint64_t significand = 0;
for (; i < length; i++) { size_t i = 0; // 2^64 - 1 = 18446744073709551615, 1844674407370955161 = 0x1999999999999999
if (significand > RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) || for(; i < length; i++)
(significand == RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) && decimals[i] > '5')) {
break; if(significand > RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) ||
significand = significand * 10u + static_cast<unsigned>(decimals[i] - '0'); (significand == RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) && decimals[i] > '5'))
} {
break;
if (i < length && decimals[i] >= '5') // Rounding }
significand++; significand = significand * 10u + static_cast<unsigned>(decimals[i] - '0');
}
size_t remaining = length - i; if(i < length && decimals[i] >= '5') // Rounding
const unsigned kUlpShift = 3; {
const unsigned kUlp = 1 << kUlpShift; significand++;
int64_t error = (remaining == 0) ? 0 : kUlp / 2; }
DiyFp v(significand, 0); size_t remaining = length - i;
v = v.Normalize(); const unsigned kUlpShift = 3;
error <<= -v.e; const unsigned kUlp = 1 << kUlpShift;
int64_t error = (remaining == 0) ? 0 : kUlp / 2;
const int dExp = static_cast<int>(decimalPosition) - static_cast<int>(i) + exp; DiyFp v(significand, 0);
v = v.Normalize();
error <<= -v.e;
int actualExp; const int dExp = static_cast<int>(decimalPosition) - static_cast<int>(i) + exp;
DiyFp cachedPower = GetCachedPower10(dExp, &actualExp);
if (actualExp != dExp) {
static const DiyFp kPow10[] = {
DiyFp(RAPIDJSON_UINT64_C2(0xa0000000, 00000000), -60), // 10^1
DiyFp(RAPIDJSON_UINT64_C2(0xc8000000, 00000000), -57), // 10^2
DiyFp(RAPIDJSON_UINT64_C2(0xfa000000, 00000000), -54), // 10^3
DiyFp(RAPIDJSON_UINT64_C2(0x9c400000, 00000000), -50), // 10^4
DiyFp(RAPIDJSON_UINT64_C2(0xc3500000, 00000000), -47), // 10^5
DiyFp(RAPIDJSON_UINT64_C2(0xf4240000, 00000000), -44), // 10^6
DiyFp(RAPIDJSON_UINT64_C2(0x98968000, 00000000), -40) // 10^7
};
int adjustment = dExp - actualExp - 1;
RAPIDJSON_ASSERT(adjustment >= 0 && adjustment < 7);
v = v * kPow10[adjustment];
if (length + static_cast<unsigned>(adjustment)> 19u) // has more digits than decimal digits in 64-bit
error += kUlp / 2;
}
v = v * cachedPower; int actualExp;
DiyFp cachedPower = GetCachedPower10(dExp, &actualExp);
if(actualExp != dExp)
{
static const DiyFp kPow10[] =
{
DiyFp(RAPIDJSON_UINT64_C2(0xa0000000, 00000000), -60), // 10^1
DiyFp(RAPIDJSON_UINT64_C2(0xc8000000, 00000000), -57), // 10^2
DiyFp(RAPIDJSON_UINT64_C2(0xfa000000, 00000000), -54), // 10^3
DiyFp(RAPIDJSON_UINT64_C2(0x9c400000, 00000000), -50), // 10^4
DiyFp(RAPIDJSON_UINT64_C2(0xc3500000, 00000000), -47), // 10^5
DiyFp(RAPIDJSON_UINT64_C2(0xf4240000, 00000000), -44), // 10^6
DiyFp(RAPIDJSON_UINT64_C2(0x98968000, 00000000), -40) // 10^7
};
int adjustment = dExp - actualExp - 1;
RAPIDJSON_ASSERT(adjustment >= 0 && adjustment < 7);
v = v * kPow10[adjustment];
if(length + static_cast<unsigned>(adjustment) > 19u) // has more digits than decimal digits in 64-bit
{
error += kUlp / 2;
}
}
error += kUlp + (error == 0 ? 0 : 1); v = v * cachedPower;
const int oldExp = v.e; error += kUlp + (error == 0 ? 0 : 1);
v = v.Normalize();
error <<= oldExp - v.e;
const unsigned effectiveSignificandSize = Double::EffectiveSignificandSize(64 + v.e); const int oldExp = v.e;
unsigned precisionSize = 64 - effectiveSignificandSize; v = v.Normalize();
if (precisionSize + kUlpShift >= 64) { error <<= oldExp - v.e;
unsigned scaleExp = (precisionSize + kUlpShift) - 63;
v.f >>= scaleExp;
v.e += scaleExp;
error = (error >> scaleExp) + 1 + static_cast<int>(kUlp);
precisionSize -= scaleExp;
}
DiyFp rounded(v.f >> precisionSize, v.e + static_cast<int>(precisionSize)); const unsigned effectiveSignificandSize = Double::EffectiveSignificandSize(64 + v.e);
const uint64_t precisionBits = (v.f & ((uint64_t(1) << precisionSize) - 1)) * kUlp; unsigned precisionSize = 64 - effectiveSignificandSize;
const uint64_t halfWay = (uint64_t(1) << (precisionSize - 1)) * kUlp; if(precisionSize + kUlpShift >= 64)
if (precisionBits >= halfWay + static_cast<unsigned>(error)) { {
rounded.f++; unsigned scaleExp = (precisionSize + kUlpShift) - 63;
if (rounded.f & (DiyFp::kDpHiddenBit << 1)) { // rounding overflows mantissa (issue #340) v.f >>= scaleExp;
rounded.f >>= 1; v.e += scaleExp;
rounded.e++; error = (error >> scaleExp) + 1 + static_cast<int>(kUlp);
} precisionSize -= scaleExp;
} }
*result = rounded.ToDouble(); 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 halfWay = (uint64_t(1) << (precisionSize - 1)) * kUlp;
if(precisionBits >= halfWay + static_cast<unsigned>(error))
{
rounded.f++;
if(rounded.f & (DiyFp::kDpHiddenBit << 1)) // rounding overflows mantissa (issue #340)
{
rounded.f >>= 1;
rounded.e++;
}
}
return halfWay - static_cast<unsigned>(error) >= precisionBits || precisionBits >= halfWay + static_cast<unsigned>(error); *result = rounded.ToDouble();
}
inline double StrtodBigInteger(double approx, const char* decimals, size_t length, size_t decimalPosition, int exp) { return halfWay - static_cast<unsigned>(error) >= precisionBits ||
const BigInteger dInt(decimals, length); precisionBits >= halfWay + static_cast<unsigned>(error);
const int dExp = static_cast<int>(decimalPosition) - static_cast<int>(length) + exp; }
Double a(approx);
int cmp = CheckWithinHalfULP(a.Value(), dInt, dExp);
if (cmp < 0)
return a.Value(); // within half ULP
else if (cmp == 0) {
// Round towards even
if (a.Significand() & 1)
return a.NextPositiveDouble();
else
return a.Value();
}
else // adjustment
return a.NextPositiveDouble();
}
inline double StrtodFullPrecision(double d, int p, 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,
RAPIDJSON_ASSERT(d >= 0.0); int exp)
RAPIDJSON_ASSERT(length >= 1); {
const BigInteger dInt(decimals, length);
const int dExp = static_cast<int>(decimalPosition) - static_cast<int>(length) + exp;
Double a(approx);
int cmp = CheckWithinHalfULP(a.Value(), dInt, dExp);
if(cmp < 0)
{
return a.Value(); // within half ULP
}
else if(cmp == 0)
{
// Round towards even
if(a.Significand() & 1)
{
return a.NextPositiveDouble();
}
else
{
return a.Value();
}
}
else // adjustment
{
return a.NextPositiveDouble();
}
}
double result; inline double StrtodFullPrecision(double d, int p, const char* decimals, size_t length, size_t decimalPosition,
if (StrtodFast(d, p, &result)) int exp)
return result; {
RAPIDJSON_ASSERT(d >= 0.0);
RAPIDJSON_ASSERT(length >= 1);
// Trim leading zeros double result;
while (*decimals == '0' && length > 1) { if(StrtodFast(d, p, &result))
length--; {
decimals++; return result;
decimalPosition--; }
}
// Trim trailing zeros // Trim leading zeros
while (decimals[length - 1] == '0' && length > 1) { while(*decimals == '0' && length > 1)
length--; {
decimalPosition--; length--;
exp++; decimals++;
} decimalPosition--;
}
// Trim right-most digits // Trim trailing zeros
const int kMaxDecimalDigit = 780; while(decimals[length - 1] == '0' && length > 1)
if (static_cast<int>(length) > kMaxDecimalDigit) { {
int delta = (static_cast<int>(length) - kMaxDecimalDigit); length--;
exp += delta; decimalPosition--;
decimalPosition -= static_cast<unsigned>(delta); exp++;
length = kMaxDecimalDigit; }
}
// If too small, underflow to zero // Trim right-most digits
if (int(length) + exp < -324) const int kMaxDecimalDigit = 780;
return 0.0; if(static_cast<int>(length) > kMaxDecimalDigit)
{
int delta = (static_cast<int>(length) - kMaxDecimalDigit);
exp += delta;
decimalPosition -= static_cast<unsigned>(delta);
length = kMaxDecimalDigit;
}
if (StrtodDiyFp(decimals, length, decimalPosition, exp, &result)) // If too small, underflow to zero
return result; if(int(length) + exp < -324)
{
return 0.0;
}
// Use approximation from StrtodDiyFp and make adjustment with BigInteger comparison if(StrtodDiyFp(decimals, length, decimalPosition, exp, &result))
return StrtodBigInteger(result, decimals, length, decimalPosition, exp); {
} return result;
}
// Use approximation from StrtodDiyFp and make adjustment with BigInteger comparison
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; {
a = b; T tmp = a;
b = tmp; a = b;
} b = tmp;
}
} // namespace internal } // namespace internal
RAPIDJSON_NAMESPACE_END RAPIDJSON_NAMESPACE_END

View file

@ -1,5 +1,5 @@
// Tencent is pleased to support the open source community by making RapidJSON available. // Tencent is pleased to support the open source community by making RapidJSON available.
// //
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// //
// Licensed under the MIT License (the "License"); you may not use this file except // Licensed under the MIT License (the "License"); you may not use this file except
@ -7,9 +7,9 @@
// //
// http://opensource.org/licenses/MIT // http://opensource.org/licenses/MIT
// //
// Unless required by applicable law or agreed to in writing, software distributed // Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License. // specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_ISTREAMWRAPPER_H_ #ifndef RAPIDJSON_ISTREAMWRAPPER_H_
@ -45,62 +45,90 @@ RAPIDJSON_NAMESPACE_BEGIN
\tparam StreamType Class derived from \c std::basic_istream. \tparam StreamType Class derived from \c std::basic_istream.
*/ */
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(); {
return RAPIDJSON_LIKELY(c != StreamType::traits_type::eof()) ? static_cast<Ch>(c) : '\0'; typename StreamType::int_type c = stream_.peek();
} return RAPIDJSON_LIKELY(c != StreamType::traits_type::eof()) ? static_cast<Ch>(c) : '\0';
}
Ch Take() { Ch Take()
typename StreamType::int_type c = stream_.get(); {
if (RAPIDJSON_LIKELY(c != StreamType::traits_type::eof())) { typename StreamType::int_type c = stream_.get();
count_++; if(RAPIDJSON_LIKELY(c != StreamType::traits_type::eof()))
return static_cast<Ch>(c); {
} count_++;
else return static_cast<Ch>(c);
return '\0'; }
} else
{
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. {
int i; RAPIDJSON_ASSERT(sizeof(Ch) == 1); // Only usable for byte stream.
bool hasError = false; int i;
for (i = 0; i < 4; ++i) { bool hasError = false;
typename StreamType::int_type c = stream_.get(); for(i = 0; i < 4; ++i)
if (c == StreamType::traits_type::eof()) { {
hasError = true; typename StreamType::int_type c = stream_.get();
stream_.clear(); if(c == StreamType::traits_type::eof())
break; {
} hasError = true;
peekBuffer_[i] = static_cast<Ch>(c); stream_.clear();
} break;
for (--i; i >= 0; --i) }
stream_.putback(peekBuffer_[i]); peekBuffer_[i] = static_cast<Ch>(c);
return !hasError ? peekBuffer_ : 0; }
} for(--i; i >= 0; --i)
{
stream_.putback(peekBuffer_[i]);
}
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];
}; };
typedef BasicIStreamWrapper<std::istream> IStreamWrapper; typedef BasicIStreamWrapper<std::istream> IStreamWrapper;

View file

@ -1,5 +1,5 @@
// Tencent is pleased to support the open source community by making RapidJSON available. // Tencent is pleased to support the open source community by making RapidJSON available.
// //
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// //
// Licensed under the MIT License (the "License"); you may not use this file except // Licensed under the MIT License (the "License"); you may not use this file except
@ -7,9 +7,9 @@
// //
// http://opensource.org/licenses/MIT // http://opensource.org/licenses/MIT
// //
// Unless required by applicable law or agreed to in writing, software distributed // Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License. // specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_MEMORYBUFFER_H_ #ifndef RAPIDJSON_MEMORYBUFFER_H_
@ -27,42 +27,64 @@ RAPIDJSON_NAMESPACE_BEGIN
It is similar to FileWriteBuffer but the destination is an in-memory buffer instead of a file. It is similar to FileWriteBuffer but the destination is an in-memory buffer instead of a file.
Differences between MemoryBuffer and StringBuffer: Differences between MemoryBuffer and StringBuffer:
1. StringBuffer has Encoding but MemoryBuffer is only a byte buffer. 1. StringBuffer has Encoding but MemoryBuffer is only a byte buffer.
2. StringBuffer::GetString() returns a null-terminated string. MemoryBuffer::GetBuffer() returns a buffer without terminator. 2. StringBuffer::GetString() returns a null-terminated string. MemoryBuffer::GetBuffer() returns a buffer without terminator.
\tparam Allocator type for allocating memory buffer. \tparam Allocator type for allocating memory buffer.
\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)
void Flush() {} {
*stack_.template Push<Ch>() = c;
}
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_;
}; };
typedef GenericMemoryBuffer<> MemoryBuffer; 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));
} }
RAPIDJSON_NAMESPACE_END RAPIDJSON_NAMESPACE_END

View file

@ -1,5 +1,5 @@
// Tencent is pleased to support the open source community by making RapidJSON available. // Tencent is pleased to support the open source community by making RapidJSON available.
// //
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// //
// Licensed under the MIT License (the "License"); you may not use this file except // Licensed under the MIT License (the "License"); you may not use this file except
@ -7,9 +7,9 @@
// //
// http://opensource.org/licenses/MIT // http://opensource.org/licenses/MIT
// //
// Unless required by applicable law or agreed to in writing, software distributed // Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License. // specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_MEMORYSTREAM_H_ #ifndef RAPIDJSON_MEMORYSTREAM_H_
@ -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,29 +37,54 @@ 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;
}
const Ch* src_; //!< Current read position. const Ch* src_; //!< Current read position.
const Ch* begin_; //!< Original head of the string. const Ch* begin_; //!< Original head of the string.
const Ch* end_; //!< End of stream. const Ch* end_; //!< End of stream.
size_t size_; //!< Size of the stream. size_t size_; //!< Size of the stream.
}; };
RAPIDJSON_NAMESPACE_END RAPIDJSON_NAMESPACE_END

View file

@ -1,5 +1,5 @@
// Tencent is pleased to support the open source community by making RapidJSON available. // Tencent is pleased to support the open source community by making RapidJSON available.
// //
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// //
// Licensed under the MIT License (the "License"); you may not use this file except // Licensed under the MIT License (the "License"); you may not use this file except
@ -7,9 +7,9 @@
// //
// http://opensource.org/licenses/MIT // http://opensource.org/licenses/MIT
// //
// Unless required by applicable law or agreed to in writing, software distributed // Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License. // specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_OSTREAMWRAPPER_H_ #ifndef RAPIDJSON_OSTREAMWRAPPER_H_
@ -40,33 +40,56 @@ RAPIDJSON_NAMESPACE_BEGIN
\tparam StreamType Class derived from \c std::basic_ostream. \tparam StreamType Class derived from \c std::basic_ostream.
*/ */
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

@ -1,5 +1,5 @@
// Tencent is pleased to support the open source community by making RapidJSON available. // Tencent is pleased to support the open source community by making RapidJSON available.
// //
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// //
// Licensed under the MIT License (the "License"); you may not use this file except // Licensed under the MIT License (the "License"); you may not use this file except
@ -7,9 +7,9 @@
// //
// http://opensource.org/licenses/MIT // http://opensource.org/licenses/MIT
// //
// Unless required by applicable law or agreed to in writing, software distributed // Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License. // specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_PRETTYWRITER_H_ #ifndef RAPIDJSON_PRETTYWRITER_H_
@ -27,9 +27,10 @@ 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. {
kFormatSingleLineArray = 1 //!< Format arrays on a single line. kFormatDefault = 0, //!< Default pretty formatting.
kFormatSingleLineArray = 1 //!< Format arrays on a single line.
}; };
//! Writer with indentation and spacing. //! Writer with indentation and spacing.
@ -40,210 +41,288 @@ 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;
//! Constructor //! Constructor
/*! \param os Output stream. /*! \param os Output stream.
\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,
Base(os, allocator, levelDepth), indentChar_(' '), indentCharCount_(4), formatOptions_(kFormatDefault) {} size_t levelDepth = Base::kDefaultLevelDepth) :
Base(os, allocator, levelDepth), indentChar_(' '), indentCharCount_(4), formatOptions_(kFormatDefault) {}
explicit PrettyWriter(StackAllocator* allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) : explicit PrettyWriter(StackAllocator* allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) :
Base(allocator, levelDepth), indentChar_(' '), indentCharCount_(4) {} Base(allocator, levelDepth), indentChar_(' '), indentCharCount_(4) {}
//! Set custom indentation. //! Set custom indentation.
/*! \param indentChar Character for indentation. Must be whitespace character (' ', '\\t', '\\n', '\\r'). /*! \param indentChar Character for indentation. Must be whitespace character (' ', '\\t', '\\n', '\\r').
\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'); {
indentChar_ = indentChar; RAPIDJSON_ASSERT(indentChar == ' ' || indentChar == '\t' || indentChar == '\n' || indentChar == '\r');
indentCharCount_ = indentCharCount; indentChar_ = indentChar;
return *this; indentCharCount_ = indentCharCount;
} return *this;
}
//! 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; {
return *this; formatOptions_ = options;
} return *this;
}
/*! @name Implementation of Handler /*! @name Implementation of Handler
\see Handler \see Handler
*/ */
//@{ //@{
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; {
PrettyPrefix(kNumberType); (void)copy;
return Base::WriteString(str, length); PrettyPrefix(kNumberType);
} 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; {
PrettyPrefix(kStringType); (void)copy;
return Base::WriteString(str, length); PrettyPrefix(kStringType);
} 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); {
new (Base::level_stack_.template Push<typename Base::Level>()) typename Base::Level(false); PrettyPrefix(kObjectType);
return Base::WriteStartObject(); new(Base::level_stack_.template Push<typename Base::Level>()) typename Base::Level(false);
} 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) {
(void)memberCount;
RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level));
RAPIDJSON_ASSERT(!Base::level_stack_.template Top<typename Base::Level>()->inArray);
bool empty = Base::level_stack_.template Pop<typename Base::Level>(1)->valueCount == 0;
if (!empty) { bool EndObject(SizeType memberCount = 0)
Base::os_->Put('\n'); {
WriteIndent(); (void)memberCount;
} RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level));
bool ret = Base::WriteEndObject(); RAPIDJSON_ASSERT(!Base::level_stack_.template Top<typename Base::Level>()->inArray);
(void)ret; bool empty = Base::level_stack_.template Pop<typename Base::Level>(1)->valueCount == 0;
RAPIDJSON_ASSERT(ret == true);
if (Base::level_stack_.Empty()) // end of json text
Base::os_->Flush();
return true;
}
bool StartArray() { if(!empty)
PrettyPrefix(kArrayType); {
new (Base::level_stack_.template Push<typename Base::Level>()) typename Base::Level(true); Base::os_->Put('\n');
return Base::WriteStartArray(); WriteIndent();
} }
bool ret = Base::WriteEndObject();
(void)ret;
RAPIDJSON_ASSERT(ret == true);
if(Base::level_stack_.Empty()) // end of json text
{
Base::os_->Flush();
}
return true;
}
bool EndArray(SizeType memberCount = 0) { bool StartArray()
(void)memberCount; {
RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level)); PrettyPrefix(kArrayType);
RAPIDJSON_ASSERT(Base::level_stack_.template Top<typename Base::Level>()->inArray); new(Base::level_stack_.template Push<typename Base::Level>()) typename Base::Level(true);
bool empty = Base::level_stack_.template Pop<typename Base::Level>(1)->valueCount == 0; return Base::WriteStartArray();
}
if (!empty && !(formatOptions_ & kFormatSingleLineArray)) { bool EndArray(SizeType memberCount = 0)
Base::os_->Put('\n'); {
WriteIndent(); (void)memberCount;
} RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level));
bool ret = Base::WriteEndArray(); RAPIDJSON_ASSERT(Base::level_stack_.template Top<typename Base::Level>()->inArray);
(void)ret; bool empty = Base::level_stack_.template Pop<typename Base::Level>(1)->valueCount == 0;
RAPIDJSON_ASSERT(ret == true);
if (Base::level_stack_.Empty()) // end of json text
Base::os_->Flush();
return true;
}
//@} if(!empty && !(formatOptions_ & kFormatSingleLineArray))
{
Base::os_->Put('\n');
WriteIndent();
}
bool ret = Base::WriteEndArray();
(void)ret;
RAPIDJSON_ASSERT(ret == true);
if(Base::level_stack_.Empty()) // end of json text
{
Base::os_->Flush();
}
return true;
}
/*! @name Convenience extensions */ //@}
//@{
//! Simpler but slower overload. /*! @name Convenience extensions */
bool String(const Ch* str) { return String(str, internal::StrLen(str)); } //@{
bool Key(const Ch* str) { return Key(str, internal::StrLen(str)); }
//@} //! Simpler but slower overload.
bool String(const Ch* str)
{
return String(str, internal::StrLen(str));
}
bool Key(const Ch* str)
{
return Key(str, internal::StrLen(str));
}
//! Write a raw JSON value. //@}
/*!
For user to write a stringified JSON as a value.
\param json A well-formed JSON value. It should not contain null character within [0, length - 1] range. //! Write a raw JSON value.
\param length Length of the json. /*!
\param type Type of the root of json. For user to write a stringified JSON as a value.
\note When using PrettyWriter::RawValue(), the result json may not be indented correctly.
*/ \param json A well-formed JSON value. It should not contain null character within [0, length - 1] range.
bool RawValue(const Ch* json, size_t length, Type type) { PrettyPrefix(type); return Base::WriteRawValue(json, length); } \param length Length of the json.
\param type Type of the root of json.
\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);
}
protected: protected:
void PrettyPrefix(Type type) { void PrettyPrefix(Type type)
(void)type; {
if (Base::level_stack_.GetSize() != 0) { // this value is not at root (void)type;
typename Base::Level* level = Base::level_stack_.template Top<typename Base::Level>(); 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->inArray)
if (level->valueCount > 0) { {
Base::os_->Put(','); // add comma if it is not the first element in array if(level->valueCount > 0)
if (formatOptions_ & kFormatSingleLineArray) {
Base::os_->Put(' '); Base::os_->Put(','); // add comma if it is not the first element in array
} if(formatOptions_ & kFormatSingleLineArray)
{
Base::os_->Put(' ');
}
}
if (!(formatOptions_ & kFormatSingleLineArray)) { if(!(formatOptions_ & kFormatSingleLineArray))
Base::os_->Put('\n'); {
WriteIndent(); Base::os_->Put('\n');
} WriteIndent();
} }
else { // in object }
if (level->valueCount > 0) { else // in object
if (level->valueCount % 2 == 0) { {
Base::os_->Put(','); if(level->valueCount > 0)
Base::os_->Put('\n'); {
} if(level->valueCount % 2 == 0)
else { {
Base::os_->Put(':'); Base::os_->Put(',');
Base::os_->Put(' '); Base::os_->Put('\n');
} }
} else
else {
Base::os_->Put('\n'); Base::os_->Put(':');
Base::os_->Put(' ');
}
}
else
{
Base::os_->Put('\n');
}
if (level->valueCount % 2 == 0) if(level->valueCount % 2 == 0)
WriteIndent(); {
} WriteIndent();
if (!level->inArray && level->valueCount % 2 == 0) }
RAPIDJSON_ASSERT(type == kStringType); // if it's in object, then even number should be a name }
level->valueCount++; if(!level->inArray && level->valueCount % 2 == 0)
} {
else { RAPIDJSON_ASSERT(type == kStringType); // if it's in object, then even number should be a name
RAPIDJSON_ASSERT(!Base::hasRoot_); // Should only has one and only one root. }
Base::hasRoot_ = true; level->valueCount++;
} }
} else
{
RAPIDJSON_ASSERT(!Base::hasRoot_); // Should only has one and only one root.
Base::hasRoot_ = true;
}
}
void WriteIndent() { void WriteIndent()
size_t count = (Base::level_stack_.GetSize() / sizeof(typename Base::Level)) * indentCharCount_; {
PutN(*Base::os_, static_cast<typename TargetEncoding::Ch>(indentChar_), count); size_t count = (Base::level_stack_.GetSize() / sizeof(typename Base::Level)) * indentCharCount_;
} PutN(*Base::os_, static_cast<typename TargetEncoding::Ch>(indentChar_), count);
}
Ch indentChar_; Ch indentChar_;
unsigned indentCharCount_; unsigned indentCharCount_;
PrettyFormatOptions formatOptions_; PrettyFormatOptions formatOptions_;
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

@ -1,5 +1,5 @@
// Tencent is pleased to support the open source community by making RapidJSON available. // Tencent is pleased to support the open source community by making RapidJSON available.
// //
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// //
// Licensed under the MIT License (the "License"); you may not use this file except // Licensed under the MIT License (the "License"); you may not use this file except
@ -7,9 +7,9 @@
// //
// http://opensource.org/licenses/MIT // http://opensource.org/licenses/MIT
// //
// Unless required by applicable law or agreed to in writing, software distributed // Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License. // specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_RAPIDJSON_H_ #ifndef RAPIDJSON_RAPIDJSON_H_
@ -17,7 +17,7 @@
/*!\file rapidjson.h /*!\file rapidjson.h
\brief common definitions and configuration \brief common definitions and configuration
\see RAPIDJSON_CONFIG \see RAPIDJSON_CONFIG
*/ */
@ -71,7 +71,7 @@
#define RAPIDJSON_MINOR_VERSION 1 #define RAPIDJSON_MINOR_VERSION 1
#define RAPIDJSON_PATCH_VERSION 0 #define RAPIDJSON_PATCH_VERSION 0
#define RAPIDJSON_VERSION_STRING \ #define RAPIDJSON_VERSION_STRING \
RAPIDJSON_STRINGIFY(RAPIDJSON_MAJOR_VERSION.RAPIDJSON_MINOR_VERSION.RAPIDJSON_PATCH_VERSION) RAPIDJSON_STRINGIFY(RAPIDJSON_MAJOR_VERSION.RAPIDJSON_MINOR_VERSION.RAPIDJSON_PATCH_VERSION)
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// RAPIDJSON_NAMESPACE_(BEGIN|END) // RAPIDJSON_NAMESPACE_(BEGIN|END)
@ -241,7 +241,7 @@
# elif defined(RAPIDJSON_DOXYGEN_RUNNING) # elif defined(RAPIDJSON_DOXYGEN_RUNNING)
# define RAPIDJSON_ENDIAN # define RAPIDJSON_ENDIAN
# else # else
# error Unknown machine endianess detected. User needs to define RAPIDJSON_ENDIAN. # error Unknown machine endianess detected. User needs to define RAPIDJSON_ENDIAN.
# endif # endif
#endif // RAPIDJSON_ENDIAN #endif // RAPIDJSON_ENDIAN
@ -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
@ -422,7 +425,7 @@ RAPIDJSON_NAMESPACE_END
#if defined(__GNUC__) #if defined(__GNUC__)
#define RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE __attribute__((unused)) #define RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE __attribute__((unused))
#else #else
#define RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE #define RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE
#endif #endif
#ifndef __clang__ #ifndef __clang__
//!@endcond //!@endcond
@ -434,9 +437,9 @@ RAPIDJSON_NAMESPACE_END
\hideinitializer \hideinitializer
*/ */
#define RAPIDJSON_STATIC_ASSERT(x) \ #define RAPIDJSON_STATIC_ASSERT(x) \
typedef ::RAPIDJSON_NAMESPACE::StaticAssertTest< \ typedef ::RAPIDJSON_NAMESPACE::StaticAssertTest< \
sizeof(::RAPIDJSON_NAMESPACE::STATIC_ASSERTION_FAILURE<bool(x) >)> \ sizeof(::RAPIDJSON_NAMESPACE::STATIC_ASSERTION_FAILURE<bool(x) >)> \
RAPIDJSON_JOIN(StaticAssertTypedef, __LINE__) RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE RAPIDJSON_JOIN(StaticAssertTypedef, __LINE__) RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE
#endif #endif
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
@ -473,20 +476,20 @@ RAPIDJSON_NAMESPACE_END
//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN //!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
#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) \
(((x)*100000) + ((y)*100) + (z)) (((x)*100000) + ((y)*100) + (z))
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// RAPIDJSON_DIAG_PUSH/POP, RAPIDJSON_DIAG_OFF // RAPIDJSON_DIAG_PUSH/POP, RAPIDJSON_DIAG_OFF
#if defined(__GNUC__) #if defined(__GNUC__)
#define RAPIDJSON_GNUC \ #define RAPIDJSON_GNUC \
RAPIDJSON_VERSION_CODE(__GNUC__,__GNUC_MINOR__,__GNUC_PATCHLEVEL__) RAPIDJSON_VERSION_CODE(__GNUC__,__GNUC_MINOR__,__GNUC_PATCHLEVEL__)
#endif #endif
#if defined(__clang__) || (defined(RAPIDJSON_GNUC) && RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,2,0)) #if defined(__clang__) || (defined(RAPIDJSON_GNUC) && RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,2,0))
@ -494,7 +497,7 @@ RAPIDJSON_NAMESPACE_END
#define RAPIDJSON_PRAGMA(x) _Pragma(RAPIDJSON_STRINGIFY(x)) #define RAPIDJSON_PRAGMA(x) _Pragma(RAPIDJSON_STRINGIFY(x))
#define RAPIDJSON_DIAG_PRAGMA(x) RAPIDJSON_PRAGMA(GCC diagnostic x) #define RAPIDJSON_DIAG_PRAGMA(x) RAPIDJSON_PRAGMA(GCC diagnostic x)
#define RAPIDJSON_DIAG_OFF(x) \ #define RAPIDJSON_DIAG_OFF(x) \
RAPIDJSON_DIAG_PRAGMA(ignored RAPIDJSON_STRINGIFY(RAPIDJSON_JOIN(-W,x))) RAPIDJSON_DIAG_PRAGMA(ignored RAPIDJSON_STRINGIFY(RAPIDJSON_JOIN(-W,x)))
// push/pop support in Clang and GCC>=4.6 // push/pop support in Clang and GCC>=4.6
#if defined(__clang__) || (defined(RAPIDJSON_GNUC) && RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,6,0)) #if defined(__clang__) || (defined(RAPIDJSON_GNUC) && RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,6,0))
@ -599,14 +602,15 @@ RAPIDJSON_NAMESPACE_END
RAPIDJSON_NAMESPACE_BEGIN RAPIDJSON_NAMESPACE_BEGIN
//! Type of JSON value //! Type of JSON value
enum Type { enum Type
kNullType = 0, //!< null {
kFalseType = 1, //!< false kNullType = 0, //!< null
kTrueType = 2, //!< true kFalseType = 1, //!< false
kObjectType = 3, //!< object kTrueType = 2, //!< true
kArrayType = 4, //!< array kObjectType = 3, //!< object
kStringType = 5, //!< string kArrayType = 4, //!< array
kNumberType = 6 //!< number kStringType = 5, //!< string
kNumberType = 6 //!< number
}; };
RAPIDJSON_NAMESPACE_END RAPIDJSON_NAMESPACE_END

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,5 +1,5 @@
// Tencent is pleased to support the open source community by making RapidJSON available. // Tencent is pleased to support the open source community by making RapidJSON available.
// //
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// //
// Licensed under the MIT License (the "License"); you may not use this file except // Licensed under the MIT License (the "License"); you may not use this file except
@ -7,9 +7,9 @@
// //
// http://opensource.org/licenses/MIT // http://opensource.org/licenses/MIT
// //
// Unless required by applicable law or agreed to in writing, software distributed // Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License. // specific language governing permissions and limitations under the License.
#include "rapidjson.h" #include "rapidjson.h"
@ -70,34 +70,40 @@ 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. /*!
Stream that can be copied fast should specialize this, like StreamTraits<StringStream>. By default, for safety, streams do not use local copy optimization.
*/ Stream that can be copied fast should specialize this, like StreamTraits<StringStream>.
enum { copyOptimization = 0 }; */
enum { copyOptimization = 0 };
}; };
//! 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)count; (void)stream;
(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); {
for (size_t i = 0; i < n; i++) PutReserve(stream, n);
PutUnsafe(stream, c); for(size_t i = 0; i < n; i++)
{
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,38 +172,67 @@ 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); } {
void Flush() {} return dst_ = src_;
}
size_t PutEnd(Ch* begin)
{
return static_cast<size_t>(dst_ - begin);
}
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_;
Ch* head_; Ch* head_;
}; };
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

@ -1,5 +1,5 @@
// Tencent is pleased to support the open source community by making RapidJSON available. // Tencent is pleased to support the open source community by making RapidJSON available.
// //
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// //
// Licensed under the MIT License (the "License"); you may not use this file except // Licensed under the MIT License (the "License"); you may not use this file except
@ -7,9 +7,9 @@
// //
// http://opensource.org/licenses/MIT // http://opensource.org/licenses/MIT
// //
// Unless required by applicable law or agreed to in writing, software distributed // Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License. // specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_STRINGBUFFER_H_ #ifndef RAPIDJSON_STRINGBUFFER_H_
@ -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,74 +38,108 @@ 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) {
stack_ = std::move(rhs.stack_); if(&rhs != this)
return *this; {
} stack_ = std::move(rhs.stack_);
}
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; } {
void Flush() {} *stack_.template Push<Ch>() = c;
}
void PutUnsafe(Ch c)
{
*stack_.template PushUnsafe<Ch>() = c;
}
void Flush() {}
void Clear() { stack_.Clear(); } void Clear()
void ShrinkToFit() { {
// Push and pop a null terminator. This is safe. stack_.Clear();
*stack_.template Push<Ch>() = '\0'; }
stack_.ShrinkToFit(); void ShrinkToFit()
stack_.template Pop<Ch>(1); {
} // Push and pop a null terminator. This is safe.
*stack_.template Push<Ch>() = '\0';
stack_.ShrinkToFit();
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. {
*stack_.template Push<Ch>() = '\0'; // Push and pop a null terminator. This is safe.
stack_.template Pop<Ch>(1); *stack_.template Push<Ch>() = '\0';
stack_.template Pop<Ch>(1);
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));
} }
RAPIDJSON_NAMESPACE_END RAPIDJSON_NAMESPACE_END

File diff suppressed because it is too large Load diff

View file

@ -40,29 +40,29 @@ 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();
protected: protected:
void onConsoleCommand(char command) override; void onConsoleCommand(char command) override;
private: 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,20 +33,25 @@
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); {
} else { ShowWindow(hcon, SW_HIDE);
HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE); }
CloseHandle(h); else
FreeConsole(); {
} HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE);
CloseHandle(h);
FreeConsole();
}
} }

View file

@ -26,36 +26,39 @@
#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;
}
uv_tty_set_mode(&m_tty, UV_TTY_MODE_RAW); uv_tty_set_mode(&m_tty, UV_TTY_MODE_RAW);
uv_read_start(reinterpret_cast<uv_stream_t*>(&m_tty), Console::onAllocBuffer, Console::onRead); uv_read_start(reinterpret_cast<uv_stream_t*>(&m_tty), Console::onAllocBuffer, Console::onRead);
} }
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;
buf->base = console->m_buf; buf->base = console->m_buf;
} }
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,15 +34,15 @@ 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,33 +38,49 @@ struct cryptonight_ctx;
class Mem class Mem
{ {
public: public:
enum Flags { enum Flags
HugepagesAvailable = 1, {
HugepagesEnabled = 2, HugepagesAvailable = 1,
Lock = 4 HugepagesEnabled = 2,
}; 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;
static int m_algo; static int m_algo;
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

@ -29,16 +29,16 @@
SubmitResult::SubmitResult(int64_t seq, uint32_t diff, uint64_t actualDiff) : SubmitResult::SubmitResult(int64_t seq, uint32_t diff, uint64_t actualDiff) :
seq(seq), seq(seq),
diff(diff), diff(diff),
actualDiff(actualDiff), actualDiff(actualDiff),
elapsed(0) elapsed(0)
{ {
start = uv_hrtime(); start = uv_hrtime();
} }
void SubmitResult::done() void SubmitResult::done()
{ {
elapsed = (uv_hrtime() - start) / 1000000; elapsed = (uv_hrtime() - start) / 1000000;
} }

View file

@ -26,22 +26,22 @@
Handle::Handle(int threadId, int threads, int64_t affinity, int priority) : Handle::Handle(int threadId, int threads, int64_t affinity, int priority) :
m_priority(priority), m_priority(priority),
m_threadId(threadId), m_threadId(threadId),
m_threads(threads), m_threads(threads),
m_affinity(affinity), m_affinity(affinity),
m_worker(nullptr) m_worker(nullptr)
{ {
} }
void Handle::join() void Handle::join()
{ {
uv_thread_join(&m_thread); uv_thread_join(&m_thread);
} }
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,8 +24,9 @@
#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();
} }