Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
J
json
Project
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Chen Yisong
json
Commits
fe628b58
Commit
fe628b58
authored
Oct 17, 2016
by
Théo DELRIEU
Committed by
Théo DELRIEU
Jan 21, 2017
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
anonymous namespace renamed to detail
parent
b443edf4
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
292 additions
and
19 deletions
+292
-19
json.hpp
src/json.hpp
+85
-8
unit-constructor3.cpp
test/src/unit-constructor3.cpp
+207
-11
No files found.
src/json.hpp
View file @
fe628b58
...
@@ -106,6 +106,14 @@ SOFTWARE.
...
@@ -106,6 +106,14 @@ SOFTWARE.
*/
*/
namespace
nlohmann
namespace
nlohmann
{
{
// TODO add real documentation before PR
// Traits structure declaration, users can specialize it for their own types
//
// constructing a json object from a user-defined type will call the
// 'json to_json(T)' function
//
// whereas calling json::get<T> will call 'T from_json(json const&)'
template
<
typename
T
,
typename
=
void
>
template
<
typename
T
,
typename
=
void
>
struct
json_traits
;
struct
json_traits
;
...
@@ -113,8 +121,8 @@ struct json_traits;
...
@@ -113,8 +121,8 @@ struct json_traits;
@brief unnamed namespace with internal helper functions
@brief unnamed namespace with internal helper functions
@since version 1.0.0
@since version 1.0.0
*/
*/
// TODO transform this anon ns to detail?
namespace
namespace
detail
{
{
/*!
/*!
@brief Helper to determine whether there's a key_type for T.
@brief Helper to determine whether there's a key_type for T.
...
@@ -140,6 +148,7 @@ struct has_mapped_type
...
@@ -140,6 +148,7 @@ struct has_mapped_type
};
};
// taken from http://stackoverflow.com/questions/10711952/how-to-detect-existence-of-a-class-using-sfinae
// taken from http://stackoverflow.com/questions/10711952/how-to-detect-existence-of-a-class-using-sfinae
// used to determine if json_traits is defined for a given type T
template
<
typename
T
>
template
<
typename
T
>
struct
has_destructor
struct
has_destructor
{
{
...
@@ -158,7 +167,23 @@ struct has_json_traits
...
@@ -158,7 +167,23 @@ struct has_json_traits
static
constexpr
bool
value
=
has_destructor
<
json_traits
<
T
>>::
value
;
static
constexpr
bool
value
=
has_destructor
<
json_traits
<
T
>>::
value
;
};
};
template
<>
struct
has_json_traits
<
void
>
:
std
::
false_type
{};
struct
to_json_fn
{
template
<
typename
T
>
constexpr
auto
operator
()(
T
&&
val
)
const
->
decltype
(
to_json
(
std
::
forward
<
T
>
(
val
)))
{
return
to_json
(
std
::
forward
<
T
>
(
val
));
}
};
struct
from_json_fn
{
template
<
typename
Json
,
typename
T
>
constexpr
auto
operator
()(
Json
const
&
from
,
T
&
to
)
const
->
decltype
(
from_json
(
from
,
to
))
{
return
from_json
(
from
,
to
);
}
};
/*!
/*!
@brief helper class to create locales with decimal point
@brief helper class to create locales with decimal point
...
@@ -181,6 +206,23 @@ struct DecimalSeparator : std::numpunct<char>
...
@@ -181,6 +206,23 @@ struct DecimalSeparator : std::numpunct<char>
};
};
// taken from ranges-v3
// TODO add doc
template
<
typename
T
>
struct
__static_const
{
static
constexpr
T
value
{};
};
template
<
typename
T
>
constexpr
T
__static_const
<
T
>::
value
;
inline
namespace
{
constexpr
auto
const
&
to_json
=
__static_const
<
detail
::
to_json_fn
>::
value
;
constexpr
auto
const
&
from_json
=
__static_const
<
detail
::
from_json_fn
>::
value
;
}
/*!
/*!
@brief a class to store JSON values
@brief a class to store JSON values
...
@@ -1337,10 +1379,24 @@ class basic_json
...
@@ -1337,10 +1379,24 @@ class basic_json
assert_invariant
();
assert_invariant
();
}
}
// constructor chosen if json_traits is specialized for type T
// note: constructor is marked explicit to avoid the following issue:
//
// struct not_equality_comparable{};
//
// not_equality_comparable{} == not_equality_comparable{};
//
// this will construct implicitely 2 json objects and call operator== on them
// which can cause nasty bugs on the user's in json-unrelated code
//
// the trade-off is expressivety in initializer-lists
// auto j = json{{"a", json(not_equality_comparable{})}};
//
// we can remove this constraint though, since lots of ctor are not explicit already
template
<
template
<
typename
T
,
typename
T
,
typename
=
typename
=
typename
std
::
enable_if
<
has_json_traits
<
typename
std
::
remove_cv
<
typename
std
::
enable_if
<
detail
::
has_json_traits
<
typename
std
::
remove_cv
<
typename
std
::
remove_reference
<
T
>::
type
>::
type
>::
value
>::
type
>
typename
std
::
remove_reference
<
T
>::
type
>::
type
>::
value
>::
type
>
explicit
basic_json
(
T
&&
val
)
explicit
basic_json
(
T
&&
val
)
:
basic_json
(
json_traits
<
typename
std
::
remove_cv
<
:
basic_json
(
json_traits
<
typename
std
::
remove_cv
<
...
@@ -2705,10 +2761,13 @@ class basic_json
...
@@ -2705,10 +2761,13 @@ class basic_json
// value access //
// value access //
//////////////////
//////////////////
// get_impl overload chosen if json_traits struct is specialized for type T
// simply returns json_traits<T>::from_json(*this);
// TODO add alias templates (enable_if_t etc)
template
<
template
<
typename
T
,
typename
T
,
typename
=
typename
=
typename
std
::
enable_if
<
typename
std
::
enable_if
<
has_json_traits
<
typename
std
::
remove_cv
<
detail
::
has_json_traits
<
typename
std
::
remove_cv
<
typename
std
::
remove_reference
<
T
>::
type
>::
type
>::
value
>::
type
>
typename
std
::
remove_reference
<
T
>::
type
>::
type
>::
value
>::
type
>
auto
get_impl
(
T
*
)
const
->
decltype
(
auto
get_impl
(
T
*
)
const
->
decltype
(
json_traits
<
typename
std
::
remove_cv
<
typename
std
::
remove_reference
<
json_traits
<
typename
std
::
remove_cv
<
typename
std
::
remove_reference
<
...
@@ -2717,6 +2776,24 @@ class basic_json
...
@@ -2717,6 +2776,24 @@ class basic_json
typename
std
::
remove_reference
<
T
>::
type
>::
type
>::
from_json
(
*
this
);
typename
std
::
remove_reference
<
T
>::
type
>::
type
>::
from_json
(
*
this
);
}
}
// this one is quite atrocious
// this overload is chosen ONLY if json_traits struct is not specialized, and if the expression nlohmann::from_json(*this, T&) is valid
// I chose to prefer the json_traits specialization if it exists, since it's a more advanced use.
// But we can of course change this behaviour
template
<
typename
T
>
auto
get_impl
(
T
*
)
const
->
typename
std
::
enable_if
<
not
detail
::
has_json_traits
<
typename
std
::
remove_cv
<
T
>::
type
>::
value
,
typename
std
::
remove_cv
<
typename
std
::
remove_reference
<
decltype
(
::
nlohmann
::
from_json
(
std
::
declval
<
basic_json
>
(),
std
::
declval
<
T
&>
()),
std
::
declval
<
T
>
())
>::
type
>::
type
>::
type
{
typename
std
::
remove_cv
<
typename
std
::
remove_reference
<
T
>::
type
>::
type
ret
;
::
nlohmann
::
from_json
(
*
this
,
ret
);
return
ret
;
}
/// get an object (explicit)
/// get an object (explicit)
template
<
class
T
,
template
<
class
T
,
typename
std
::
enable_if
<
typename
std
::
enable_if
<
...
@@ -2750,7 +2827,7 @@ class basic_json
...
@@ -2750,7 +2827,7 @@ class basic_json
not
std
::
is_same
<
basic_json_t
,
typename
T
::
value_type
>::
value
and
not
std
::
is_same
<
basic_json_t
,
typename
T
::
value_type
>::
value
and
not
std
::
is_arithmetic
<
T
>::
value
and
not
std
::
is_arithmetic
<
T
>::
value
and
not
std
::
is_convertible
<
std
::
string
,
T
>::
value
and
not
std
::
is_convertible
<
std
::
string
,
T
>::
value
and
not
has_mapped_type
<
T
>::
value
,
int
>::
type
=
0
>
not
detail
::
has_mapped_type
<
T
>::
value
,
int
>::
type
=
0
>
T
get_impl
(
T
*
/*unused*/
)
const
T
get_impl
(
T
*
/*unused*/
)
const
{
{
if
(
is_array
())
if
(
is_array
())
...
@@ -2791,7 +2868,7 @@ class basic_json
...
@@ -2791,7 +2868,7 @@ class basic_json
/// get an array (explicit)
/// get an array (explicit)
template
<
class
T
,
typename
std
::
enable_if
<
template
<
class
T
,
typename
std
::
enable_if
<
std
::
is_same
<
basic_json
,
typename
T
::
value_type
>::
value
and
std
::
is_same
<
basic_json
,
typename
T
::
value_type
>::
value
and
not
has_mapped_type
<
T
>::
value
,
int
>::
type
=
0
>
not
detail
::
has_mapped_type
<
T
>::
value
,
int
>::
type
=
0
>
T
get_impl
(
T
*
/*unused*/
)
const
T
get_impl
(
T
*
/*unused*/
)
const
{
{
if
(
is_array
())
if
(
is_array
())
...
...
test/src/unit-constructor3.cpp
View file @
fe628b58
...
@@ -42,22 +42,12 @@ struct pod_type {
...
@@ -42,22 +42,12 @@ struct pod_type {
short
c
;
short
c
;
};
};
inline
bool
operator
==
(
pod_type
const
&
lhs
,
pod_type
const
&
rhs
)
noexcept
{
return
std
::
tie
(
lhs
.
a
,
lhs
.
b
,
lhs
.
c
)
==
std
::
tie
(
rhs
.
a
,
rhs
.
b
,
rhs
.
c
);
}
struct
bit_more_complex_type
{
struct
bit_more_complex_type
{
pod_type
a
;
pod_type
a
;
pod_type
b
;
pod_type
b
;
std
::
string
c
;
std
::
string
c
;
};
};
inline
bool
operator
==
(
bit_more_complex_type
const
&
lhs
,
bit_more_complex_type
const
&
rhs
)
noexcept
{
return
std
::
tie
(
lhs
.
a
,
lhs
.
b
,
lhs
.
c
)
==
std
::
tie
(
rhs
.
a
,
rhs
.
b
,
rhs
.
c
);
}
// best optional implementation ever
// best optional implementation ever
template
<
typename
T
>
template
<
typename
T
>
class
optional_type
class
optional_type
...
@@ -68,11 +58,97 @@ public:
...
@@ -68,11 +58,97 @@ public:
explicit
operator
bool
()
const
noexcept
{
return
_val
!=
nullptr
;
}
explicit
operator
bool
()
const
noexcept
{
return
_val
!=
nullptr
;
}
T
const
&
operator
*
()
const
{
return
*
_val
;
}
T
const
&
operator
*
()
const
{
return
*
_val
;
}
optional_type
&
operator
=
(
T
const
&
t
)
{
_val
=
std
::
make_shared
<
T
>
(
t
);
return
*
this
;
}
private
:
private
:
std
::
shared_ptr
<
T
>
_val
;
std
::
shared_ptr
<
T
>
_val
;
};
};
struct
no_json_traits_type
{
int
a
;
};
// free to/from_json functions
json
to_json
(
empty_type
)
{
return
json
::
object
();
}
json
to_json
(
pod_type
const
&
p
)
{
return
{{
"a"
,
p
.
a
},
{
"b"
,
p
.
b
},
{
"c"
,
p
.
c
}};
}
json
to_json
(
bit_more_complex_type
const
&
p
)
{
using
nlohmann
::
to_json
;
return
json
{{
"a"
,
to_json
(
p
.
a
)},
{
"b"
,
to_json
(
p
.
b
)},
{
"c"
,
p
.
c
}};
}
template
<
typename
T
>
json
to_json
(
optional_type
<
T
>
const
&
opt
)
{
using
nlohmann
::
to_json
;
if
(
!
opt
)
return
nullptr
;
return
to_json
(
*
opt
);
}
json
to_json
(
no_json_traits_type
const
&
p
)
{
json
ret
;
ret
[
"a"
]
=
p
.
a
;
return
ret
;
}
void
from_json
(
json
const
&
j
,
empty_type
&
t
)
{
assert
(
j
.
empty
());
t
=
empty_type
{};
}
void
from_json
(
json
const
&
j
,
pod_type
&
t
)
{
t
=
{
j
[
"a"
].
get
<
int
>
(),
j
[
"b"
].
get
<
char
>
(),
j
[
"c"
].
get
<
short
>
()};
}
void
from_json
(
json
const
&
j
,
bit_more_complex_type
&
t
)
{
// relying on json_traits struct here..
t
=
{
j
[
"a"
].
get
<
udt
::
pod_type
>
(),
j
[
"b"
].
get
<
udt
::
pod_type
>
(),
j
[
"c"
].
get
<
std
::
string
>
()};
}
void
from_json
(
json
const
&
j
,
no_json_traits_type
&
t
)
{
t
.
a
=
j
[
"a"
].
get
<
int
>
();
}
template
<
typename
T
>
void
from_json
(
json
const
&
j
,
optional_type
<
T
>&
t
)
{
if
(
j
.
is_null
())
t
=
optional_type
<
T
>
{};
else
t
=
j
.
get
<
T
>
();
}
inline
bool
operator
==
(
pod_type
const
&
lhs
,
pod_type
const
&
rhs
)
noexcept
{
return
std
::
tie
(
lhs
.
a
,
lhs
.
b
,
lhs
.
c
)
==
std
::
tie
(
rhs
.
a
,
rhs
.
b
,
rhs
.
c
);
}
inline
bool
operator
==
(
bit_more_complex_type
const
&
lhs
,
bit_more_complex_type
const
&
rhs
)
noexcept
{
return
std
::
tie
(
lhs
.
a
,
lhs
.
b
,
lhs
.
c
)
==
std
::
tie
(
rhs
.
a
,
rhs
.
b
,
rhs
.
c
);
}
template
<
typename
T
>
template
<
typename
T
>
inline
bool
operator
==
(
optional_type
<
T
>
const
&
lhs
,
optional_type
<
T
>
const
&
rhs
)
inline
bool
operator
==
(
optional_type
<
T
>
const
&
lhs
,
optional_type
<
T
>
const
&
rhs
)
{
{
...
@@ -82,6 +158,11 @@ inline bool operator==(optional_type<T> const& lhs, optional_type<T> const& rhs)
...
@@ -82,6 +158,11 @@ inline bool operator==(optional_type<T> const& lhs, optional_type<T> const& rhs)
return
false
;
return
false
;
return
*
lhs
==
*
rhs
;
return
*
lhs
==
*
rhs
;
}
}
inline
bool
operator
==
(
no_json_traits_type
const
&
lhs
,
no_json_traits_type
const
&
rhs
)
{
return
lhs
.
a
==
rhs
.
a
;
}
}
}
namespace
nlohmann
namespace
nlohmann
...
@@ -163,7 +244,7 @@ TEST_CASE("constructors for user-defined types", "[udt]")
...
@@ -163,7 +244,7 @@ TEST_CASE("constructors for user-defined types", "[udt]")
{
{
SECTION
(
"empty type"
)
SECTION
(
"empty type"
)
{
{
udt
::
empty_type
const
e
;
udt
::
empty_type
const
e
{}
;
auto
const
j
=
json
{
e
};
auto
const
j
=
json
{
e
};
auto
k
=
json
::
object
();
auto
k
=
json
::
object
();
CHECK
(
j
==
k
);
CHECK
(
j
==
k
);
...
@@ -300,3 +381,118 @@ TEST_CASE("get<> for user-defined types", "[udt]")
...
@@ -300,3 +381,118 @@ TEST_CASE("get<> for user-defined types", "[udt]")
}
}
}
}
}
}
TEST_CASE
(
"to_json free function"
,
"[udt]"
)
{
SECTION
(
"pod_type"
)
{
auto
const
e
=
udt
::
pod_type
{
42
,
42
,
42
};
auto
const
expected
=
json
{{
"a"
,
42
},
{
"b"
,
42
},
{
"c"
,
42
}};
auto
const
j
=
nlohmann
::
to_json
(
e
);
CHECK
(
j
==
expected
);
}
SECTION
(
"bit_more_complex_type"
)
{
auto
const
e
=
udt
::
bit_more_complex_type
{{
42
,
42
,
42
},
{
41
,
41
,
41
},
"forty"
};
auto
const
expected
=
json
{{
"a"
,
{{
"a"
,
42
},
{
"b"
,
42
},
{
"c"
,
42
}}},
{
"b"
,
{{
"a"
,
41
},
{
"b"
,
41
},
{
"c"
,
41
}}},
{
"c"
,
"forty"
}};
auto
const
j
=
nlohmann
::
to_json
(
e
);
CHECK
(
j
==
expected
);
}
SECTION
(
"optional_type"
)
{
SECTION
(
"from null"
)
{
udt
::
optional_type
<
udt
::
pod_type
>
o
;
json
expected
;
auto
const
j
=
nlohmann
::
to_json
(
o
);
CHECK
(
expected
==
j
);
}
SECTION
(
"from value"
)
{
udt
::
optional_type
<
udt
::
pod_type
>
o
{{
42
,
42
,
42
}};
auto
const
expected
=
json
{{
"a"
,
42
},
{
"b"
,
42
},
{
"c"
,
42
}};
auto
const
j
=
nlohmann
::
to_json
(
o
);
CHECK
(
expected
==
j
);
}
}
SECTION
(
"no json_traits specialization"
)
{
udt
::
no_json_traits_type
t
{
42
};
json
expected
;
expected
[
"a"
]
=
42
;
auto
const
j
=
nlohmann
::
to_json
(
t
);
CHECK
(
j
==
expected
);
}
}
TEST_CASE
(
"from_json free function"
,
"[udt]"
)
{
SECTION
(
"pod_type"
)
{
auto
const
expected
=
udt
::
pod_type
{
42
,
42
,
42
};
auto
const
j
=
json
{{
"a"
,
42
},
{
"b"
,
42
},
{
"c"
,
42
}};
udt
::
pod_type
p
;
nlohmann
::
from_json
(
j
,
p
);
CHECK
(
p
==
expected
);
}
SECTION
(
"bit_more_complex_type"
)
{
auto
const
expected
=
udt
::
bit_more_complex_type
{{
42
,
42
,
42
},
{
41
,
41
,
41
},
"forty"
};
auto
const
j
=
json
{{
"a"
,
{{
"a"
,
42
},
{
"b"
,
42
},
{
"c"
,
42
}}},
{
"b"
,
{{
"a"
,
41
},
{
"b"
,
41
},
{
"c"
,
41
}}},
{
"c"
,
"forty"
}};
udt
::
bit_more_complex_type
p
;
nlohmann
::
from_json
(
j
,
p
);
CHECK
(
p
==
expected
);
}
SECTION
(
"optional_type"
)
{
SECTION
(
"from null"
)
{
udt
::
optional_type
<
udt
::
pod_type
>
expected
;
json
j
;
udt
::
optional_type
<
udt
::
pod_type
>
o
;
nlohmann
::
from_json
(
j
,
o
);
CHECK
(
expected
==
o
);
}
SECTION
(
"from value"
)
{
udt
::
optional_type
<
udt
::
pod_type
>
expected
{{
42
,
42
,
42
}};
auto
const
j
=
json
{{
"a"
,
42
},
{
"b"
,
42
},
{
"c"
,
42
}};
udt
::
optional_type
<
udt
::
pod_type
>
o
;
nlohmann
::
from_json
(
j
,
o
);
CHECK
(
expected
==
o
);
}
}
SECTION
(
"no json_traits specialization"
)
{
udt
::
no_json_traits_type
expected
{
42
};
udt
::
no_json_traits_type
res
;
json
j
;
j
[
"a"
]
=
42
;
nlohmann
::
from_json
(
j
,
res
);
CHECK
(
res
==
expected
);
res
=
j
.
get
<
udt
::
no_json_traits_type
>
();
CHECK
(
res
==
expected
);
}
}
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