Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
J
json
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Libraries
json
Commits
9f5dccba
Unverified
Commit
9f5dccba
authored
Feb 11, 2017
by
Niels Lohmann
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
💄
cleanup
parent
926af6d5
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
128 additions
and
164 deletions
+128
-164
src/json.hpp
src/json.hpp
+64
-82
src/json.hpp.re2c
src/json.hpp.re2c
+64
-82
No files found.
src/json.hpp
View file @
9f5dccba
...
...
@@ -10840,13 +10840,13 @@ basic_json_parser_66:
/*!
@brief parse string into a built-in arithmetic type as if
the current
locale is POSIX.
@brief parse string into a built-in arithmetic type as if
the current
locale is POSIX.
note: in floating-point case strtod may parse
past the token's end - this is not an error.
@note in floating-point case strtod may parse past the token's end -
this is not an error
any leading blanks are not handled.
@note any leading blanks are not handled
*/
struct
strtonum
{
...
...
@@ -10855,36 +10855,37 @@ basic_json_parser_66:
:
m_start
(
start
),
m_end
(
end
)
{}
/// return true iff parsed successfully as
/// number of type T.
///
/// @val shall contain parsed value, or
/// undefined value if could not parse.
template
<
typename
T
,
typename
=
typename
std
::
enable_if
<
std
::
is_arithmetic
<
T
>
::
value
>::
type
>
/*!
@return true iff parsed successfully as number of type T
@param[in,out] val shall contain parsed value, or undefined value
if could not parse
*/
template
<
typename
T
,
typename
=
typename
std
::
enable_if
<
std
::
is_arithmetic
<
T
>
::
value
>::
type
>
bool
to
(
T
&
val
)
const
{
return
parse
(
val
,
std
::
is_integral
<
T
>
());
}
/// return true iff token matches ^[+-]\d+$
///
/// this is a helper to determine whether to
/// parse the token into floating-point or
/// integral type. We wouldn't need it if
/// we had separate token types for integral
/// and floating-point cases.
/*!
This is a helper to determine whether to parse the token into
floating-point or integral type.
@note We wouldn't need it if we had separate token types for
integral and floating-point cases.
@return true iff token matches `^[+-]\d+$`
*/
bool
is_integral
()
const
{
const
char
*
p
=
m_start
;
if
(
!
p
)
if
(
p
==
nullptr
)
{
return
false
;
// LCOV_EXCL_LINE
}
if
(
*
p
==
'-'
or
*
p
==
'+'
)
if
(
(
*
p
==
'-'
)
or
(
*
p
==
'+'
)
)
{
++
p
;
}
...
...
@@ -10894,39 +10895,31 @@ basic_json_parser_66:
return
false
;
// LCOV_EXCL_LINE
}
while
(
p
<
m_end
and
*
p
>=
'0'
and
*
p
<=
'9'
)
while
((
p
<
m_end
)
and
(
*
p
>=
'0'
)
and
(
*
p
<=
'9'
))
{
++
p
;
}
return
p
==
m_end
;
return
(
p
==
m_end
)
;
}
private:
const
char
*
const
m_start
=
nullptr
;
const
char
*
const
m_end
=
nullptr
;
const
char
*
const
m_end
=
nullptr
;
// overloaded wrappers for strtod/strtof/strtold
// that will be called from parse<floating_point_t>
static
void
strtof
(
float
&
f
,
const
char
*
str
,
char
**
endptr
)
static
void
strtof
(
float
&
f
,
const
char
*
str
,
char
**
endptr
)
{
f
=
std
::
strtof
(
str
,
endptr
);
}
static
void
strtof
(
double
&
f
,
const
char
*
str
,
char
**
endptr
)
static
void
strtof
(
double
&
f
,
const
char
*
str
,
char
**
endptr
)
{
f
=
std
::
strtod
(
str
,
endptr
);
}
static
void
strtof
(
long
double
&
f
,
const
char
*
str
,
char
**
endptr
)
static
void
strtof
(
long
double
&
f
,
const
char
*
str
,
char
**
endptr
)
{
f
=
std
::
strtold
(
str
,
endptr
);
}
...
...
@@ -10934,37 +10927,32 @@ basic_json_parser_66:
template
<
typename
T
>
bool
parse
(
T
&
value
,
/*is_integral=*/
std
::
false_type
)
const
{
// replace decimal separator with locale-specific
// version, when necessary; data will point to
// either the original string, or buf, or tempstr
// containing the fixed string.
// replace decimal separator with locale-specific version,
// when necessary; data will point to either the original
// string, or buf, or tempstr containing the fixed string.
std
::
string
tempstr
;
std
::
array
<
char
,
64
>
buf
;
const
size_t
len
=
static_cast
<
size_t
>
(
m_end
-
m_start
);
// Since dealing with strtod family of functions,
// we're getting the decimal point char from the
// C locale facilities instead of C++'s numpunct
// facet of the current std::locale;
// since dealing with strtod family of functions, we're
// getting the decimal point char from the C locale facilities
// instead of C++'s numpunct facet of the current std::locale
const
auto
loc
=
localeconv
();
assert
(
loc
!=
nullptr
);
const
char
decimal_point_char
=
!
loc
->
decimal_point
?
'.'
:
loc
->
decimal_point
[
0
];
const
char
decimal_point_char
=
(
loc
->
decimal_point
==
nullptr
)
?
'.'
:
loc
->
decimal_point
[
0
];
const
char
*
data
=
m_start
;
if
(
decimal_point_char
!=
'.'
)
{
const
size_t
ds_pos
=
static_cast
<
size_t
>
(
std
::
find
(
m_start
,
m_end
,
'.'
)
-
m_start
);
const
size_t
ds_pos
=
static_cast
<
size_t
>
(
std
::
find
(
m_start
,
m_end
,
'.'
)
-
m_start
);
if
(
ds_pos
!=
len
)
{
// copy the data into the local buffer or
// tempstr, if buffer is too small;
// replace decimal separator, and update
// data to point to the modified bytes
if
(
len
+
1
<
buf
.
size
())
// copy the data into the local buffer or tempstr, if
// buffer is too small; replace decimal separator, and
// update data to point to the modified bytes
if
((
len
+
1
)
<
buf
.
size
())
{
std
::
copy
(
m_start
,
m_end
,
buf
.
data
());
buf
[
len
]
=
0
;
...
...
@@ -10985,13 +10973,12 @@ basic_json_parser_66:
// this calls appropriate overload depending on T
strtof
(
value
,
data
,
&
endptr
);
// note that reading past the end is OK, the data may be,
// for example, "123.", where the parsed token only
// contains "123", but strtod will read the dot as well.
const
bool
ok
=
endptr
>=
data
+
len
and
len
>
0
;
// note that reading past the end is OK, the data may be, for
// example, "123.", where the parsed token only contains
// "123", but strtod will read the dot as well.
const
bool
ok
=
(
endptr
>=
(
data
+
len
))
and
(
len
>
0
);
if
(
ok
and
value
==
0.0
and
*
data
==
'-'
)
if
(
ok
and
(
value
==
0.0
)
and
(
*
data
==
'-'
)
)
{
// some implementations forget to negate the zero
value
=
-
0.0
;
...
...
@@ -11000,16 +10987,12 @@ basic_json_parser_66:
return
ok
;
}
signed
long
long
parse_integral
(
char
**
endptr
,
/*is_signed*/
std
::
true_type
)
const
signed
long
long
parse_integral
(
char
**
endptr
,
/*is_signed*/
std
::
true_type
)
const
{
return
std
::
strtoll
(
m_start
,
endptr
,
10
);
}
unsigned
long
long
parse_integral
(
char
**
endptr
,
/*is_signed*/
std
::
false_type
)
const
unsigned
long
long
parse_integral
(
char
**
endptr
,
/*is_signed*/
std
::
false_type
)
const
{
return
std
::
strtoull
(
m_start
,
endptr
,
10
);
}
...
...
@@ -11018,20 +11001,20 @@ basic_json_parser_66:
bool
parse
(
T
&
value
,
/*is_integral=*/
std
::
true_type
)
const
{
char
*
endptr
=
nullptr
;
errno
=
0
;
// these are thread-local
errno
=
0
;
// these are thread-local
const
auto
x
=
parse_integral
(
&
endptr
,
std
::
is_signed
<
T
>
());
static_assert
(
std
::
is_signed
<
T
>
()
// called right overload?
==
std
::
is_signed
<
decltype
(
x
)
>
(),
""
);
// called right overload?
static_assert
(
std
::
is_signed
<
T
>
()
==
std
::
is_signed
<
decltype
(
x
)
>
(),
""
);
value
=
static_cast
<
T
>
(
x
);
return
x
==
static_cast
<
decltype
(
x
)
>
(
value
)
// x fits into destination T
and
(
x
<
0
)
==
(
value
<
0
)
// preserved sign
and
(
x
!=
0
or
is_integral
())
// strto[u]ll did nto fail
and
errno
==
0
// strto[u]ll did not overflow
and
m_start
<
m_end
// token was not empty
and
endptr
==
m_end
;
// parsed entire token exactly
return
(
x
==
static_cast
<
decltype
(
x
)
>
(
value
)
)
// x fits into destination T
and
(
x
<
0
)
==
(
value
<
0
)
// preserved sign
and
(
(
x
!=
0
)
or
is_integral
())
// strto[u]ll did nto fail
and
(
errno
==
0
)
// strto[u]ll did not overflow
and
(
m_start
<
m_end
)
// token was not empty
and
(
endptr
==
m_end
);
// parsed entire token exactly
}
};
...
...
@@ -11061,20 +11044,20 @@ basic_json_parser_66:
strtonum
num
(
reinterpret_cast
<
const
char
*>
(
m_start
),
reinterpret_cast
<
const
char
*>
(
m_cursor
));
const
bool
is_negative
=
*
m_start
==
'-'
;
const
bool
is_negative
=
(
*
m_start
==
'-'
)
;
result
.
m_type
=
value_t
::
discarded
;
if
(
not
num
.
is_integral
())
{
;
// will parse as float below
// will parse as float below
}
else
if
(
is_negative
)
{
number_integer_t
val
{
0
};
if
(
num
.
to
(
val
))
{
result
.
m_type
=
value_t
::
number_integer
;
result
.
m_type
=
value_t
::
number_integer
;
result
.
m_value
=
val
;
}
}
...
...
@@ -11089,14 +11072,13 @@ basic_json_parser_66:
}
number_float_t
val
{
0
};
if
(
result
.
m_type
!=
value_t
::
discarded
or
!
num
.
to
(
val
))
if
(
result
.
m_type
!=
value_t
::
discarded
or
(
not
num
.
to
(
val
)))
{
return
;
// already have a value from above
// or couldn't parse as float_t
// already have a value from above or couldn't parse as float_t
return
;
}
result
.
m_type
=
value_t
::
number_float
;
result
.
m_type
=
value_t
::
number_float
;
result
.
m_value
=
val
;
// replace infinity and NAN by null
...
...
src/json.hpp.re2c
View file @
9f5dccba
...
...
@@ -9990,13 +9990,13 @@ class basic_json
/*!
@brief parse string into a built-in arithmetic type as if
the current
locale is POSIX.
@brief parse string into a built-in arithmetic type as if
the current
locale is POSIX.
note: in floating-point case strtod may parse
past the token's end - this is not an error.
@note in floating-point case strtod may parse past the token's end -
this is not an error
any leading blanks are not handled.
@note any leading blanks are not handled
*/
struct strtonum
{
...
...
@@ -10005,36 +10005,37 @@ class basic_json
: m_start(start), m_end(end)
{}
/// return true iff parsed successfully as
/// number of type T.
///
/// @val shall contain parsed value, or
/// undefined value if could not parse.
template<typename T,
typename = typename std::enable_if<
std::is_arithmetic<T>::value>::type >
/*!
@return true iff parsed successfully as number of type T
@param[in,out] val shall contain parsed value, or undefined value
if could not parse
*/
template<typename T, typename = typename std::enable_if<std::is_arithmetic<T>::value>::type>
bool to(T& val) const
{
return parse(val, std::is_integral<T>());
}
/// return true iff token matches ^[+-]\d+$
///
/// this is a helper to determine whether to
/// parse the token into floating-point or
/// integral type. We wouldn't need it if
/// we had separate token types for integral
/// and floating-point cases.
/*!
This is a helper to determine whether to parse the token into
floating-point or integral type.
@note We wouldn't need it if we had separate token types for
integral and floating-point cases.
@return true iff token matches `^[+-]\d+$`
*/
bool is_integral() const
{
const char* p = m_start;
if (
!p
)
if (
p == nullptr
)
{
return false; // LCOV_EXCL_LINE
}
if (
*p == '-' or * p == '+'
)
if (
(*p == '-') or (*p == '+')
)
{
++p;
}
...
...
@@ -10044,39 +10045,31 @@ class basic_json
return false; // LCOV_EXCL_LINE
}
while (p < m_end and* p >= '0'
and * p <= '9')
while ((p < m_end) and (*p >= '0') and (*p <= '9'))
{
++p;
}
return
p == m_end
;
return
(p == m_end)
;
}
private:
const char* const m_start = nullptr;
const char* const m_end
= nullptr;
const char* const m_end = nullptr;
// overloaded wrappers for strtod/strtof/strtold
// that will be called from parse<floating_point_t>
static void strtof(float& f,
const char* str,
char** endptr)
static void strtof(float& f, const char* str, char** endptr)
{
f = std::strtof(str, endptr);
}
static void strtof(double& f,
const char* str,
char** endptr)
static void strtof(double& f, const char* str, char** endptr)
{
f = std::strtod(str, endptr);
}
static void strtof(long double& f,
const char* str,
char** endptr)
static void strtof(long double& f, const char* str, char** endptr)
{
f = std::strtold(str, endptr);
}
...
...
@@ -10084,37 +10077,32 @@ class basic_json
template<typename T>
bool parse(T& value, /*is_integral=*/std::false_type) const
{
// replace decimal separator with locale-specific
// version, when necessary; data will point to
// either the original string, or buf, or tempstr
// containing the fixed string.
// replace decimal separator with locale-specific version,
// when necessary; data will point to either the original
// string, or buf, or tempstr containing the fixed string.
std::string tempstr;
std::array<char, 64> buf;
const size_t len = static_cast<size_t>(m_end - m_start);
// Since dealing with strtod family of functions,
// we're getting the decimal point char from the
// C locale facilities instead of C++'s numpunct
// facet of the current std::locale;
// since dealing with strtod family of functions, we're
// getting the decimal point char from the C locale facilities
// instead of C++'s numpunct facet of the current std::locale
const auto loc = localeconv();
assert(loc != nullptr);
const char decimal_point_char = !loc->decimal_point ? '.'
: loc->decimal_point[0];
const char decimal_point_char = (loc->decimal_point == nullptr) ? '.' : loc->decimal_point[0];
const char* data = m_start;
if (decimal_point_char != '.')
{
const size_t ds_pos = static_cast<size_t>(
std::find(m_start, m_end, '.') - m_start );
const size_t ds_pos = static_cast<size_t>(std::find(m_start, m_end, '.') - m_start);
if (ds_pos != len)
{
// copy the data into the local buffer or
// tempstr, if buffer is too small;
// replace decimal separator, and update
// data to point to the modified bytes
if (len + 1 < buf.size())
// copy the data into the local buffer or tempstr, if
// buffer is too small; replace decimal separator, and
// update data to point to the modified bytes
if ((len + 1) < buf.size())
{
std::copy(m_start, m_end, buf.data());
buf[len] = 0;
...
...
@@ -10135,13 +10123,12 @@ class basic_json
// this calls appropriate overload depending on T
strtof(value, data, &endptr);
// note that reading past the end is OK, the data may be,
// for example, "123.", where the parsed token only
// contains "123", but strtod will read the dot as well.
const bool ok = endptr >= data + len
and len > 0;
// note that reading past the end is OK, the data may be, for
// example, "123.", where the parsed token only contains
// "123", but strtod will read the dot as well.
const bool ok = (endptr >= (data + len)) and (len > 0);
if (ok and
value == 0.0 and * data == '-'
)
if (ok and
(value == 0.0) and (*data == '-')
)
{
// some implementations forget to negate the zero
value = -0.0;
...
...
@@ -10150,16 +10137,12 @@ class basic_json
return ok;
}
signed long long parse_integral(
char** endptr,
/*is_signed*/std::true_type) const
signed long long parse_integral(char** endptr, /*is_signed*/std::true_type) const
{
return std::strtoll(m_start, endptr, 10);
}
unsigned long long parse_integral(
char** endptr,
/*is_signed*/std::false_type) const
unsigned long long parse_integral(char** endptr, /*is_signed*/std::false_type) const
{
return std::strtoull(m_start, endptr, 10);
}
...
...
@@ -10168,20 +10151,20 @@ class basic_json
bool parse(T& value, /*is_integral=*/std::true_type) const
{
char* endptr = nullptr;
errno
= 0; // these are thread-local
errno = 0; // these are thread-local
const auto x = parse_integral(&endptr, std::is_signed<T>());
static_assert(std::is_signed<T>()
// called right overload?
== std::is_signed<decltype(x)>(), "");
// called right overload?
static_assert(std::is_signed<T>()
== std::is_signed<decltype(x)>(), "");
value = static_cast<T>(x);
return
x == static_cast<decltype(x)>(value
) // x fits into destination T
and (x < 0) == (value < 0)
// preserved sign
and (
x != 0 or is_integral())
// strto[u]ll did nto fail
and
errno == 0
// strto[u]ll did not overflow
and
m_start < m_end
// token was not empty
and
endptr == m_end;
// parsed entire token exactly
return
(x == static_cast<decltype(x)>(value)
) // x fits into destination T
and (x < 0) == (value < 0) // preserved sign
and (
(x != 0) or is_integral())
// strto[u]ll did nto fail
and
(errno == 0)
// strto[u]ll did not overflow
and
(m_start < m_end)
// token was not empty
and
(endptr == m_end);
// parsed entire token exactly
}
};
...
...
@@ -10211,20 +10194,20 @@ class basic_json
strtonum num(reinterpret_cast<const char*>(m_start),
reinterpret_cast<const char*>(m_cursor));
const bool is_negative =
*m_start == '-'
;
const bool is_negative =
(*m_start == '-')
;
result.m_type = value_t::discarded;
if (not num.is_integral())
{
;
// will parse as float below
// will parse as float below
}
else if (is_negative)
{
number_integer_t val{0};
if (num.to(val))
{
result.m_type
= value_t::number_integer;
result.m_type = value_t::number_integer;
result.m_value = val;
}
}
...
...
@@ -10239,14 +10222,13 @@ class basic_json
}
number_float_t val{0};
if (result.m_type != value_t::discarded
or !num.to(val))
if (result.m_type != value_t::discarded or (not num.to(val)))
{
return; // already have a value from above
// or couldn't parse as float_t
// already have a value from above or couldn't parse as float_t
return;
}
result.m_type
= value_t::number_float;
result.m_type = value_t::number_float;
result.m_value = val;
// replace infinity and NAN by null
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment