Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in / Register
Toggle navigation
R
rapidjson
Project
Project
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
Packages
Packages
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
submodule
rapidjson
Commits
e731726c
Commit
e731726c
authored
Feb 15, 2016
by
Milo Yip
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Optimize memory consumption with RAPIDJSON_48BITPOINTER_OPTIMIZATION
#330
parent
90c0235f
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
200 additions
and
135 deletions
+200
-135
document.h
include/rapidjson/document.h
+156
-134
rapidjson.h
include/rapidjson/rapidjson.h
+32
-1
valuetest.cpp
test/unittest/valuetest.cpp
+12
-0
No files found.
include/rapidjson/document.h
View file @
e731726c
...
...
@@ -295,7 +295,7 @@ struct GenericStringRef {
*/
#endif
explicit
GenericStringRef
(
const
CharType
*
str
)
:
s
(
str
),
length
(
internal
::
StrLen
(
str
)){
RAPIDJSON_ASSERT
(
s
!=
NULL
);
}
:
s
(
str
),
length
(
internal
::
StrLen
(
str
)){
RAPIDJSON_ASSERT
(
s
!=
0
);
}
//! Create constant string reference from pointer and length
#ifndef __clang__ // -Wdocumentation
...
...
@@ -307,7 +307,7 @@ struct GenericStringRef {
*/
#endif
GenericStringRef
(
const
CharType
*
str
,
SizeType
len
)
:
s
(
str
),
length
(
len
)
{
RAPIDJSON_ASSERT
(
s
!=
NULL
);
}
:
s
(
str
),
length
(
len
)
{
RAPIDJSON_ASSERT
(
s
!=
0
);
}
//! implicit conversion to plain CharType pointer
operator
const
Ch
*
()
const
{
return
s
;
}
...
...
@@ -425,12 +425,12 @@ public:
//@{
//! Default constructor creates a null value.
GenericValue
()
RAPIDJSON_NOEXCEPT
:
data_
()
,
flags_
(
kNullFlag
)
{
}
GenericValue
()
RAPIDJSON_NOEXCEPT
:
data_
()
{
data_
.
f
.
flags
=
kNullFlag
;
}
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
//! Move constructor in C++11
GenericValue
(
GenericValue
&&
rhs
)
RAPIDJSON_NOEXCEPT
:
data_
(
rhs
.
data_
)
,
flags_
(
rhs
.
flags_
)
{
rhs
.
flags_
=
kNullFlag
;
// give up contents
GenericValue
(
GenericValue
&&
rhs
)
RAPIDJSON_NOEXCEPT
:
data_
(
rhs
.
data_
)
{
rhs
.
data_
.
f
.
flags
=
kNullFlag
;
// give up contents
}
#endif
...
...
@@ -455,13 +455,13 @@ public:
\param type Type of the value.
\note Default content for number is zero.
*/
explicit
GenericValue
(
Type
type
)
RAPIDJSON_NOEXCEPT
:
data_
()
,
flags_
()
{
static
const
u
nsigned
defaultFlags
[
7
]
=
{
explicit
GenericValue
(
Type
type
)
RAPIDJSON_NOEXCEPT
:
data_
()
{
static
const
u
int16_t
defaultFlags
[
7
]
=
{
kNullFlag
,
kFalseFlag
,
kTrueFlag
,
kObjectFlag
,
kArrayFlag
,
kShortStringFlag
,
kNumberAnyFlag
};
RAPIDJSON_ASSERT
(
type
<=
kNumberType
);
flags_
=
defaultFlags
[
type
];
data_
.
f
.
flags
=
defaultFlags
[
type
];
// Use ShortString to store empty string.
if
(
type
==
kStringType
)
...
...
@@ -490,70 +490,71 @@ public:
#else
explicit
GenericValue
(
bool
b
)
RAPIDJSON_NOEXCEPT
#endif
:
data_
()
,
flags_
(
b
?
kTrueFlag
:
kFalseFlag
)
{
:
data_
()
{
// safe-guard against failing SFINAE
RAPIDJSON_STATIC_ASSERT
((
internal
::
IsSame
<
bool
,
T
>::
Value
));
data_
.
f
.
flags
=
b
?
kTrueFlag
:
kFalseFlag
;
}
//! Constructor for int value.
explicit
GenericValue
(
int
i
)
RAPIDJSON_NOEXCEPT
:
data_
()
,
flags_
(
kNumberIntFlag
)
{
explicit
GenericValue
(
int
i
)
RAPIDJSON_NOEXCEPT
:
data_
()
{
data_
.
n
.
i64
=
i
;
if
(
i
>=
0
)
flags_
|=
kUintFlag
|
kUint64Flag
;
data_
.
f
.
flags
=
(
i
>=
0
)
?
(
kNumberIntFlag
|
kUintFlag
|
kUint64Flag
)
:
kNumberIntFlag
;
}
//! Constructor for unsigned value.
explicit
GenericValue
(
unsigned
u
)
RAPIDJSON_NOEXCEPT
:
data_
()
,
flags_
(
kNumberUintFlag
)
{
explicit
GenericValue
(
unsigned
u
)
RAPIDJSON_NOEXCEPT
:
data_
()
{
data_
.
n
.
u64
=
u
;
if
(
!
(
u
&
0x80000000
))
flags_
|=
kIntFlag
|
kInt64Flag
;
data_
.
f
.
flags
=
(
u
&
0x80000000
)
?
kNumberUintFlag
:
(
kNumberUintFlag
|
kIntFlag
|
kInt64Flag
);
}
//! Constructor for int64_t value.
explicit
GenericValue
(
int64_t
i64
)
RAPIDJSON_NOEXCEPT
:
data_
()
,
flags_
(
kNumberInt64Flag
)
{
explicit
GenericValue
(
int64_t
i64
)
RAPIDJSON_NOEXCEPT
:
data_
()
{
data_
.
n
.
i64
=
i64
;
data_
.
f
.
flags
=
kNumberInt64Flag
;
if
(
i64
>=
0
)
{
flags_
|=
kNumberUint64Flag
;
data_
.
f
.
flags
|=
kNumberUint64Flag
;
if
(
!
(
static_cast
<
uint64_t
>
(
i64
)
&
RAPIDJSON_UINT64_C2
(
0xFFFFFFFF
,
0x00000000
)))
flags_
|=
kUintFlag
;
data_
.
f
.
flags
|=
kUintFlag
;
if
(
!
(
static_cast
<
uint64_t
>
(
i64
)
&
RAPIDJSON_UINT64_C2
(
0xFFFFFFFF
,
0x80000000
)))
flags_
|=
kIntFlag
;
data_
.
f
.
flags
|=
kIntFlag
;
}
else
if
(
i64
>=
static_cast
<
int64_t
>
(
RAPIDJSON_UINT64_C2
(
0xFFFFFFFF
,
0x80000000
)))
flags_
|=
kIntFlag
;
data_
.
f
.
flags
|=
kIntFlag
;
}
//! Constructor for uint64_t value.
explicit
GenericValue
(
uint64_t
u64
)
RAPIDJSON_NOEXCEPT
:
data_
()
,
flags_
(
kNumberUint64Flag
)
{
explicit
GenericValue
(
uint64_t
u64
)
RAPIDJSON_NOEXCEPT
:
data_
()
{
data_
.
n
.
u64
=
u64
;
data_
.
f
.
flags
=
kNumberUint64Flag
;
if
(
!
(
u64
&
RAPIDJSON_UINT64_C2
(
0x80000000
,
0x00000000
)))
flags_
|=
kInt64Flag
;
data_
.
f
.
flags
|=
kInt64Flag
;
if
(
!
(
u64
&
RAPIDJSON_UINT64_C2
(
0xFFFFFFFF
,
0x00000000
)))
flags_
|=
kUintFlag
;
data_
.
f
.
flags
|=
kUintFlag
;
if
(
!
(
u64
&
RAPIDJSON_UINT64_C2
(
0xFFFFFFFF
,
0x80000000
)))
flags_
|=
kIntFlag
;
data_
.
f
.
flags
|=
kIntFlag
;
}
//! Constructor for double value.
explicit
GenericValue
(
double
d
)
RAPIDJSON_NOEXCEPT
:
data_
()
,
flags_
(
kNumberDoubleFlag
)
{
data_
.
n
.
d
=
d
;
}
explicit
GenericValue
(
double
d
)
RAPIDJSON_NOEXCEPT
:
data_
()
{
data_
.
n
.
d
=
d
;
data_
.
f
.
flags
=
kNumberDoubleFlag
;
}
//! Constructor for constant string (i.e. do not make a copy of string)
GenericValue
(
const
Ch
*
s
,
SizeType
length
)
RAPIDJSON_NOEXCEPT
:
data_
()
,
flags_
()
{
SetStringRaw
(
StringRef
(
s
,
length
));
}
GenericValue
(
const
Ch
*
s
,
SizeType
length
)
RAPIDJSON_NOEXCEPT
:
data_
()
{
SetStringRaw
(
StringRef
(
s
,
length
));
}
//! Constructor for constant string (i.e. do not make a copy of string)
explicit
GenericValue
(
StringRefType
s
)
RAPIDJSON_NOEXCEPT
:
data_
()
,
flags_
()
{
SetStringRaw
(
s
);
}
explicit
GenericValue
(
StringRefType
s
)
RAPIDJSON_NOEXCEPT
:
data_
()
{
SetStringRaw
(
s
);
}
//! Constructor for copy-string (i.e. do make a copy of string)
GenericValue
(
const
Ch
*
s
,
SizeType
length
,
Allocator
&
allocator
)
:
data_
()
,
flags_
()
{
SetStringRaw
(
StringRef
(
s
,
length
),
allocator
);
}
GenericValue
(
const
Ch
*
s
,
SizeType
length
,
Allocator
&
allocator
)
:
data_
()
{
SetStringRaw
(
StringRef
(
s
,
length
),
allocator
);
}
//! Constructor for copy-string (i.e. do make a copy of string)
GenericValue
(
const
Ch
*
s
,
Allocator
&
allocator
)
:
data_
()
,
flags_
()
{
SetStringRaw
(
StringRef
(
s
),
allocator
);
}
GenericValue
(
const
Ch
*
s
,
Allocator
&
allocator
)
:
data_
()
{
SetStringRaw
(
StringRef
(
s
),
allocator
);
}
#if RAPIDJSON_HAS_STDSTRING
//! Constructor for copy-string from a string object (i.e. do make a copy of string)
/*! \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING.
*/
GenericValue
(
const
std
::
basic_string
<
Ch
>&
s
,
Allocator
&
allocator
)
:
data_
()
,
flags_
()
{
SetStringRaw
(
StringRef
(
s
),
allocator
);
}
GenericValue
(
const
std
::
basic_string
<
Ch
>&
s
,
Allocator
&
allocator
)
:
data_
()
{
SetStringRaw
(
StringRef
(
s
),
allocator
);
}
#endif
//! Destructor.
...
...
@@ -561,21 +562,24 @@ public:
*/
~
GenericValue
()
{
if
(
Allocator
::
kNeedFree
)
{
// Shortcut by Allocator's trait
switch
(
flags_
)
{
switch
(
data_
.
f
.
flags
)
{
case
kArrayFlag
:
for
(
GenericValue
*
v
=
data_
.
a
.
elements
;
v
!=
data_
.
a
.
elements
+
data_
.
a
.
size
;
++
v
)
v
->~
GenericValue
();
Allocator
::
Free
(
data_
.
a
.
elements
);
{
GenericValue
*
e
=
GetElementsPointer
();
for
(
GenericValue
*
v
=
e
;
v
!=
e
+
data_
.
a
.
size
;
++
v
)
v
->~
GenericValue
();
Allocator
::
Free
(
e
);
}
break
;
case
kObjectFlag
:
for
(
MemberIterator
m
=
MemberBegin
();
m
!=
MemberEnd
();
++
m
)
m
->~
Member
();
Allocator
::
Free
(
data_
.
o
.
members
);
Allocator
::
Free
(
GetMembersPointer
()
);
break
;
case
kCopyStringFlag
:
Allocator
::
Free
(
const_cast
<
Ch
*>
(
data_
.
s
.
str
));
Allocator
::
Free
(
GetStringPointer
(
));
break
;
default
:
...
...
@@ -773,20 +777,20 @@ public:
//!@name Type
//@{
Type
GetType
()
const
{
return
static_cast
<
Type
>
(
flags_
&
kTypeMask
);
}
bool
IsNull
()
const
{
return
flags_
==
kNullFlag
;
}
bool
IsFalse
()
const
{
return
flags_
==
kFalseFlag
;
}
bool
IsTrue
()
const
{
return
flags_
==
kTrueFlag
;
}
bool
IsBool
()
const
{
return
(
flags_
&
kBoolFlag
)
!=
0
;
}
bool
IsObject
()
const
{
return
flags_
==
kObjectFlag
;
}
bool
IsArray
()
const
{
return
flags_
==
kArrayFlag
;
}
bool
IsNumber
()
const
{
return
(
flags_
&
kNumberFlag
)
!=
0
;
}
bool
IsInt
()
const
{
return
(
flags_
&
kIntFlag
)
!=
0
;
}
bool
IsUint
()
const
{
return
(
flags_
&
kUintFlag
)
!=
0
;
}
bool
IsInt64
()
const
{
return
(
flags_
&
kInt64Flag
)
!=
0
;
}
bool
IsUint64
()
const
{
return
(
flags_
&
kUint64Flag
)
!=
0
;
}
bool
IsDouble
()
const
{
return
(
flags_
&
kDoubleFlag
)
!=
0
;
}
bool
IsString
()
const
{
return
(
flags_
&
kStringFlag
)
!=
0
;
}
Type
GetType
()
const
{
return
static_cast
<
Type
>
(
data_
.
f
.
flags
&
kTypeMask
);
}
bool
IsNull
()
const
{
return
data_
.
f
.
flags
==
kNullFlag
;
}
bool
IsFalse
()
const
{
return
data_
.
f
.
flags
==
kFalseFlag
;
}
bool
IsTrue
()
const
{
return
data_
.
f
.
flags
==
kTrueFlag
;
}
bool
IsBool
()
const
{
return
(
data_
.
f
.
flags
&
kBoolFlag
)
!=
0
;
}
bool
IsObject
()
const
{
return
data_
.
f
.
flags
==
kObjectFlag
;
}
bool
IsArray
()
const
{
return
data_
.
f
.
flags
==
kArrayFlag
;
}
bool
IsNumber
()
const
{
return
(
data_
.
f
.
flags
&
kNumberFlag
)
!=
0
;
}
bool
IsInt
()
const
{
return
(
data_
.
f
.
flags
&
kIntFlag
)
!=
0
;
}
bool
IsUint
()
const
{
return
(
data_
.
f
.
flags
&
kUintFlag
)
!=
0
;
}
bool
IsInt64
()
const
{
return
(
data_
.
f
.
flags
&
kInt64Flag
)
!=
0
;
}
bool
IsUint64
()
const
{
return
(
data_
.
f
.
flags
&
kUint64Flag
)
!=
0
;
}
bool
IsDouble
()
const
{
return
(
data_
.
f
.
flags
&
kDoubleFlag
)
!=
0
;
}
bool
IsString
()
const
{
return
(
data_
.
f
.
flags
&
kStringFlag
)
!=
0
;
}
// Checks whether a number can be losslessly converted to a double.
bool
IsLosslessDouble
()
const
{
...
...
@@ -806,7 +810,7 @@ public:
// Checks whether a number is a float (possible lossy).
bool
IsFloat
()
const
{
if
((
flags_
&
kDoubleFlag
)
==
0
)
if
((
data_
.
f
.
flags
&
kDoubleFlag
)
==
0
)
return
false
;
double
d
=
GetDouble
();
return
d
>=
-
3.4028234e38
&&
d
<=
3.4028234e38
;
...
...
@@ -831,7 +835,7 @@ public:
//!@name Bool
//@{
bool
GetBool
()
const
{
RAPIDJSON_ASSERT
(
IsBool
());
return
flags_
==
kTrueFlag
;
}
bool
GetBool
()
const
{
RAPIDJSON_ASSERT
(
IsBool
());
return
data_
.
f
.
flags
==
kTrueFlag
;
}
//!< Set boolean value
/*! \post IsBool() == true */
GenericValue
&
SetBool
(
bool
b
)
{
this
->~
GenericValue
();
new
(
this
)
GenericValue
(
b
);
return
*
this
;
}
...
...
@@ -905,16 +909,16 @@ public:
//! Const member iterator
/*! \pre IsObject() == true */
ConstMemberIterator
MemberBegin
()
const
{
RAPIDJSON_ASSERT
(
IsObject
());
return
ConstMemberIterator
(
data_
.
o
.
members
);
}
ConstMemberIterator
MemberBegin
()
const
{
RAPIDJSON_ASSERT
(
IsObject
());
return
ConstMemberIterator
(
GetMembersPointer
()
);
}
//! Const \em past-the-end member iterator
/*! \pre IsObject() == true */
ConstMemberIterator
MemberEnd
()
const
{
RAPIDJSON_ASSERT
(
IsObject
());
return
ConstMemberIterator
(
data_
.
o
.
members
+
data_
.
o
.
size
);
}
ConstMemberIterator
MemberEnd
()
const
{
RAPIDJSON_ASSERT
(
IsObject
());
return
ConstMemberIterator
(
GetMembersPointer
()
+
data_
.
o
.
size
);
}
//! Member iterator
/*! \pre IsObject() == true */
MemberIterator
MemberBegin
()
{
RAPIDJSON_ASSERT
(
IsObject
());
return
MemberIterator
(
data_
.
o
.
members
);
}
MemberIterator
MemberBegin
()
{
RAPIDJSON_ASSERT
(
IsObject
());
return
MemberIterator
(
GetMembersPointer
()
);
}
//! \em Past-the-end member iterator
/*! \pre IsObject() == true */
MemberIterator
MemberEnd
()
{
RAPIDJSON_ASSERT
(
IsObject
());
return
MemberIterator
(
data_
.
o
.
members
+
data_
.
o
.
size
);
}
MemberIterator
MemberEnd
()
{
RAPIDJSON_ASSERT
(
IsObject
());
return
MemberIterator
(
GetMembersPointer
()
+
data_
.
o
.
size
);
}
//! Check whether a member exists in the object.
/*!
...
...
@@ -1024,16 +1028,17 @@ public:
if
(
o
.
size
>=
o
.
capacity
)
{
if
(
o
.
capacity
==
0
)
{
o
.
capacity
=
kDefaultObjectCapacity
;
o
.
members
=
reinterpret_cast
<
Member
*>
(
allocator
.
Malloc
(
o
.
capacity
*
sizeof
(
Member
)));
SetMembersPointer
(
reinterpret_cast
<
Member
*>
(
allocator
.
Malloc
(
o
.
capacity
*
sizeof
(
Member
)
)));
}
else
{
SizeType
oldCapacity
=
o
.
capacity
;
o
.
capacity
+=
(
oldCapacity
+
1
)
/
2
;
// grow by factor 1.5
o
.
members
=
reinterpret_cast
<
Member
*>
(
allocator
.
Realloc
(
o
.
members
,
oldCapacity
*
sizeof
(
Member
),
o
.
capacity
*
sizeof
(
Member
)));
SetMembersPointer
(
reinterpret_cast
<
Member
*>
(
allocator
.
Realloc
(
GetMembersPointer
(),
oldCapacity
*
sizeof
(
Member
),
o
.
capacity
*
sizeof
(
Member
)
)));
}
}
o
.
members
[
o
.
size
].
name
.
RawAssign
(
name
);
o
.
members
[
o
.
size
].
value
.
RawAssign
(
value
);
Member
*
members
=
GetMembersPointer
();
members
[
o
.
size
].
name
.
RawAssign
(
name
);
members
[
o
.
size
].
value
.
RawAssign
(
value
);
o
.
size
++
;
return
*
this
;
}
...
...
@@ -1212,18 +1217,14 @@ public:
MemberIterator
RemoveMember
(
MemberIterator
m
)
{
RAPIDJSON_ASSERT
(
IsObject
());
RAPIDJSON_ASSERT
(
data_
.
o
.
size
>
0
);
RAPIDJSON_ASSERT
(
data_
.
o
.
members
!=
0
);
RAPIDJSON_ASSERT
(
GetMembersPointer
()
!=
0
);
RAPIDJSON_ASSERT
(
m
>=
MemberBegin
()
&&
m
<
MemberEnd
());
MemberIterator
last
(
data_
.
o
.
members
+
(
data_
.
o
.
size
-
1
));
if
(
data_
.
o
.
size
>
1
&&
m
!=
last
)
{
// Move the last one to this place
*
m
=
*
last
;
}
else
{
// Only one left, just destroy
m
->~
Member
();
}
MemberIterator
last
(
GetMembersPointer
()
+
(
data_
.
o
.
size
-
1
));
if
(
data_
.
o
.
size
>
1
&&
m
!=
last
)
*
m
=
*
last
;
// Move the last one to this place
else
m
->~
Member
();
// Only one left, just destroy
--
data_
.
o
.
size
;
return
m
;
}
...
...
@@ -1253,7 +1254,7 @@ public:
MemberIterator
EraseMember
(
ConstMemberIterator
first
,
ConstMemberIterator
last
)
{
RAPIDJSON_ASSERT
(
IsObject
());
RAPIDJSON_ASSERT
(
data_
.
o
.
size
>
0
);
RAPIDJSON_ASSERT
(
data_
.
o
.
members
!=
0
);
RAPIDJSON_ASSERT
(
GetMembersPointer
()
!=
0
);
RAPIDJSON_ASSERT
(
first
>=
MemberBegin
());
RAPIDJSON_ASSERT
(
first
<=
last
);
RAPIDJSON_ASSERT
(
last
<=
MemberEnd
());
...
...
@@ -1315,8 +1316,9 @@ public:
*/
void
Clear
()
{
RAPIDJSON_ASSERT
(
IsArray
());
for
(
SizeType
i
=
0
;
i
<
data_
.
a
.
size
;
++
i
)
data_
.
a
.
elements
[
i
].
~
GenericValue
();
GenericValue
*
e
=
GetElementsPointer
();
for
(
GenericValue
*
v
=
e
;
v
!=
e
+
data_
.
a
.
size
;
++
v
)
v
->~
GenericValue
();
data_
.
a
.
size
=
0
;
}
...
...
@@ -1328,16 +1330,16 @@ public:
GenericValue
&
operator
[](
SizeType
index
)
{
RAPIDJSON_ASSERT
(
IsArray
());
RAPIDJSON_ASSERT
(
index
<
data_
.
a
.
size
);
return
data_
.
a
.
elements
[
index
];
return
GetElementsPointer
()
[
index
];
}
const
GenericValue
&
operator
[](
SizeType
index
)
const
{
return
const_cast
<
GenericValue
&>
(
*
this
)[
index
];
}
//! Element iterator
/*! \pre IsArray() == true */
ValueIterator
Begin
()
{
RAPIDJSON_ASSERT
(
IsArray
());
return
data_
.
a
.
elements
;
}
ValueIterator
Begin
()
{
RAPIDJSON_ASSERT
(
IsArray
());
return
GetElementsPointer
()
;
}
//! \em Past-the-end element iterator
/*! \pre IsArray() == true */
ValueIterator
End
()
{
RAPIDJSON_ASSERT
(
IsArray
());
return
data_
.
a
.
elements
+
data_
.
a
.
size
;
}
ValueIterator
End
()
{
RAPIDJSON_ASSERT
(
IsArray
());
return
GetElementsPointer
()
+
data_
.
a
.
size
;
}
//! Constant element iterator
/*! \pre IsArray() == true */
ConstValueIterator
Begin
()
const
{
return
const_cast
<
GenericValue
&>
(
*
this
).
Begin
();
}
...
...
@@ -1354,7 +1356,7 @@ public:
GenericValue
&
Reserve
(
SizeType
newCapacity
,
Allocator
&
allocator
)
{
RAPIDJSON_ASSERT
(
IsArray
());
if
(
newCapacity
>
data_
.
a
.
capacity
)
{
data_
.
a
.
elements
=
static_cast
<
GenericValue
*>
(
allocator
.
Realloc
(
data_
.
a
.
elements
,
data_
.
a
.
capacity
*
sizeof
(
GenericValue
),
newCapacity
*
sizeof
(
GenericValue
)));
SetElementsPointer
(
reinterpret_cast
<
GenericValue
*>
(
allocator
.
Realloc
(
GetElementsPointer
(),
data_
.
a
.
capacity
*
sizeof
(
GenericValue
),
newCapacity
*
sizeof
(
GenericValue
)
)));
data_
.
a
.
capacity
=
newCapacity
;
}
return
*
this
;
...
...
@@ -1374,7 +1376,7 @@ public:
RAPIDJSON_ASSERT
(
IsArray
());
if
(
data_
.
a
.
size
>=
data_
.
a
.
capacity
)
Reserve
(
data_
.
a
.
capacity
==
0
?
kDefaultArrayCapacity
:
(
data_
.
a
.
capacity
+
(
data_
.
a
.
capacity
+
1
)
/
2
),
allocator
);
data_
.
a
.
elements
[
data_
.
a
.
size
++
].
RawAssign
(
value
);
GetElementsPointer
()
[
data_
.
a
.
size
++
].
RawAssign
(
value
);
return
*
this
;
}
...
...
@@ -1428,7 +1430,7 @@ public:
GenericValue
&
PopBack
()
{
RAPIDJSON_ASSERT
(
IsArray
());
RAPIDJSON_ASSERT
(
!
Empty
());
data_
.
a
.
elements
[
--
data_
.
a
.
size
].
~
GenericValue
();
GetElementsPointer
()
[
--
data_
.
a
.
size
].
~
GenericValue
();
return
*
this
;
}
...
...
@@ -1454,7 +1456,7 @@ public:
ValueIterator
Erase
(
ConstValueIterator
first
,
ConstValueIterator
last
)
{
RAPIDJSON_ASSERT
(
IsArray
());
RAPIDJSON_ASSERT
(
data_
.
a
.
size
>
0
);
RAPIDJSON_ASSERT
(
data_
.
a
.
elements
!=
0
);
RAPIDJSON_ASSERT
(
GetElementsPointer
()
!=
0
);
RAPIDJSON_ASSERT
(
first
>=
Begin
());
RAPIDJSON_ASSERT
(
first
<=
last
);
RAPIDJSON_ASSERT
(
last
<=
End
());
...
...
@@ -1471,21 +1473,21 @@ public:
//!@name Number
//@{
int
GetInt
()
const
{
RAPIDJSON_ASSERT
(
flags_
&
kIntFlag
);
return
data_
.
n
.
i
.
i
;
}
unsigned
GetUint
()
const
{
RAPIDJSON_ASSERT
(
flags_
&
kUintFlag
);
return
data_
.
n
.
u
.
u
;
}
int64_t
GetInt64
()
const
{
RAPIDJSON_ASSERT
(
flags_
&
kInt64Flag
);
return
data_
.
n
.
i64
;
}
uint64_t
GetUint64
()
const
{
RAPIDJSON_ASSERT
(
flags_
&
kUint64Flag
);
return
data_
.
n
.
u64
;
}
int
GetInt
()
const
{
RAPIDJSON_ASSERT
(
data_
.
f
.
flags
&
kIntFlag
);
return
data_
.
n
.
i
.
i
;
}
unsigned
GetUint
()
const
{
RAPIDJSON_ASSERT
(
data_
.
f
.
flags
&
kUintFlag
);
return
data_
.
n
.
u
.
u
;
}
int64_t
GetInt64
()
const
{
RAPIDJSON_ASSERT
(
data_
.
f
.
flags
&
kInt64Flag
);
return
data_
.
n
.
i64
;
}
uint64_t
GetUint64
()
const
{
RAPIDJSON_ASSERT
(
data_
.
f
.
flags
&
kUint64Flag
);
return
data_
.
n
.
u64
;
}
//! Get the value as double type.
/*! \note If the value is 64-bit integer type, it may lose precision. Use \c IsLosslessDouble() to check whether the converison is lossless.
*/
double
GetDouble
()
const
{
RAPIDJSON_ASSERT
(
IsNumber
());
if
((
flags_
&
kDoubleFlag
)
!=
0
)
return
data_
.
n
.
d
;
// exact type, no conversion.
if
((
flags_
&
kIntFlag
)
!=
0
)
return
data_
.
n
.
i
.
i
;
// int -> double
if
((
flags_
&
kUintFlag
)
!=
0
)
return
data_
.
n
.
u
.
u
;
// unsigned -> double
if
((
flags_
&
kInt64Flag
)
!=
0
)
return
static_cast
<
double
>
(
data_
.
n
.
i64
);
// int64_t -> double (may lose precision)
RAPIDJSON_ASSERT
((
flags_
&
kUint64Flag
)
!=
0
);
return
static_cast
<
double
>
(
data_
.
n
.
u64
);
// uint64_t -> double (may lose precision)
if
((
data_
.
f
.
flags
&
kDoubleFlag
)
!=
0
)
return
data_
.
n
.
d
;
// exact type, no conversion.
if
((
data_
.
f
.
flags
&
kIntFlag
)
!=
0
)
return
data_
.
n
.
i
.
i
;
// int -> double
if
((
data_
.
f
.
flags
&
kUintFlag
)
!=
0
)
return
data_
.
n
.
u
.
u
;
// unsigned -> double
if
((
data_
.
f
.
flags
&
kInt64Flag
)
!=
0
)
return
static_cast
<
double
>
(
data_
.
n
.
i64
);
// int64_t -> double (may lose precision)
RAPIDJSON_ASSERT
((
data_
.
f
.
flags
&
kUint64Flag
)
!=
0
);
return
static_cast
<
double
>
(
data_
.
n
.
u64
);
// uint64_t -> double (may lose precision)
}
//! Get the value as float type.
...
...
@@ -1508,12 +1510,12 @@ public:
//!@name String
//@{
const
Ch
*
GetString
()
const
{
RAPIDJSON_ASSERT
(
IsString
());
return
(
(
flags_
&
kInlineStrFlag
)
?
data_
.
ss
.
str
:
data_
.
s
.
str
);
}
const
Ch
*
GetString
()
const
{
RAPIDJSON_ASSERT
(
IsString
());
return
(
data_
.
f
.
flags
&
kInlineStrFlag
)
?
data_
.
ss
.
str
:
GetStringPointer
(
);
}
//! Get the length of string.
/*! Since rapidjson permits "\\u0000" in the json string, strlen(v.GetString()) may not equal to v.GetStringLength().
*/
SizeType
GetStringLength
()
const
{
RAPIDJSON_ASSERT
(
IsString
());
return
((
flags_
&
kInlineStrFlag
)
?
(
data_
.
ss
.
GetLength
())
:
data_
.
s
.
length
);
}
SizeType
GetStringLength
()
const
{
RAPIDJSON_ASSERT
(
IsString
());
return
((
data_
.
f
.
flags
&
kInlineStrFlag
)
?
(
data_
.
ss
.
GetLength
())
:
data_
.
s
.
length
);
}
//! Set this value as a string without copying source string.
/*! This version has better performance with supplied length, and also support string containing null character.
...
...
@@ -1582,7 +1584,7 @@ public:
return
false
;
for
(
ConstMemberIterator
m
=
MemberBegin
();
m
!=
MemberEnd
();
++
m
)
{
RAPIDJSON_ASSERT
(
m
->
name
.
IsString
());
// User may change the type of name by MemberIterator.
if
(
RAPIDJSON_UNLIKELY
(
!
handler
.
Key
(
m
->
name
.
GetString
(),
m
->
name
.
GetStringLength
(),
(
m
->
name
.
flags_
&
kCopyFlag
)
!=
0
)))
if
(
RAPIDJSON_UNLIKELY
(
!
handler
.
Key
(
m
->
name
.
GetString
(),
m
->
name
.
GetStringLength
(),
(
m
->
name
.
data_
.
f
.
flags
&
kCopyFlag
)
!=
0
)))
return
false
;
if
(
RAPIDJSON_UNLIKELY
(
!
m
->
value
.
Accept
(
handler
)))
return
false
;
...
...
@@ -1592,13 +1594,13 @@ public:
case
kArrayType
:
if
(
RAPIDJSON_UNLIKELY
(
!
handler
.
StartArray
()))
return
false
;
for
(
const
GenericValue
*
v
=
data_
.
a
.
elements
;
v
!=
data_
.
a
.
elements
+
data_
.
a
.
size
;
++
v
)
for
(
const
GenericValue
*
v
=
Begin
();
v
!=
End
()
;
++
v
)
if
(
RAPIDJSON_UNLIKELY
(
!
v
->
Accept
(
handler
)))
return
false
;
return
handler
.
EndArray
(
data_
.
a
.
size
);
case
kStringType
:
return
handler
.
String
(
GetString
(),
GetStringLength
(),
(
flags_
&
kCopyFlag
)
!=
0
);
return
handler
.
String
(
GetString
(),
GetStringLength
(),
(
data_
.
f
.
flags
&
kCopyFlag
)
!=
0
);
default
:
RAPIDJSON_ASSERT
(
GetType
()
==
kNumberType
);
...
...
@@ -1615,16 +1617,16 @@ private:
template
<
typename
,
typename
,
typename
>
friend
class
GenericDocument
;
enum
{
kBoolFlag
=
0x100
,
kNumberFlag
=
0x20
0
,
kIntFlag
=
0x40
0
,
kUintFlag
=
0x80
0
,
kInt64Flag
=
0x100
0
,
kUint64Flag
=
0x20
00
,
kDoubleFlag
=
0x40
00
,
kStringFlag
=
0x1000
00
,
kCopyFlag
=
0x2000
00
,
kInlineStrFlag
=
0x400
000
,
kBoolFlag
=
0x0008
,
kNumberFlag
=
0x001
0
,
kIntFlag
=
0x002
0
,
kUintFlag
=
0x004
0
,
kInt64Flag
=
0x008
0
,
kUint64Flag
=
0x01
00
,
kDoubleFlag
=
0x02
00
,
kStringFlag
=
0x04
00
,
kCopyFlag
=
0x08
00
,
kInlineStrFlag
=
0x1
000
,
// Initial flags of different types.
kNullFlag
=
kNullType
,
...
...
@@ -1642,16 +1644,27 @@ private:
kObjectFlag
=
kObjectType
,
kArrayFlag
=
kArrayType
,
kTypeMask
=
0x
FF
// bitwise-and with mask of 0xFF can be optimized by compiler
kTypeMask
=
0x
07
};
static
const
SizeType
kDefaultArrayCapacity
=
16
;
static
const
SizeType
kDefaultObjectCapacity
=
16
;
struct
Flag
{
#if RAPIDJSON_48BITPOINTER_OPTIMIZATION
char
payload
[
sizeof
(
SizeType
)
*
2
+
6
];
// 2 x SizeType + lower 48-bit pointer
#elif RAPIDJSON_64BIT
char
payload
[
Sizeof
(
SizeType
)
*
2
+
sizeof
(
void
*
)
+
6
];
// 6 padding bytes
#else
char
payload
[
Sizeof
(
SizeType
)
*
2
+
sizeof
(
void
*
)
+
2
];
// 2 padding bytes
#endif
uint16_t
flags
;
};
struct
String
{
const
Ch
*
str
;
SizeType
length
;
unsigned
hashcode
;
//!< reserved
SizeType
hashcode
;
//!< reserved
const
Ch
*
str
;
};
// 12 bytes in 32-bit mode, 16 bytes in 64-bit mode
// implementation detail: ShortString can represent zero-terminated strings up to MaxSize chars
...
...
@@ -1660,10 +1673,10 @@ private:
// to store has the maximal length of MaxSize then str[LenPos] will be 0 and therefore act as
// the string terminator as well. For getting the string length back from that value just use
// "MaxSize - str[LenPos]".
// This allows to store 1
1-chars strings in 32-bit mode and 15-chars strings in 64-bit mode
// inline (for `UTF8`-encoded strings).
// This allows to store 1
3-chars strings in 32-bit mode, 21-chars strings in 64-bit mode,
//
13-chars strings for RAPIDJSON_48BITPOINTER_OPTIMIZATION=1
inline (for `UTF8`-encoded strings).
struct
ShortString
{
enum
{
MaxChars
=
sizeof
(
String
)
/
sizeof
(
Ch
),
MaxSize
=
MaxChars
-
1
,
LenPos
=
MaxSize
};
enum
{
MaxChars
=
sizeof
(
Flag
::
payload
)
/
sizeof
(
Ch
),
MaxSize
=
MaxChars
-
1
,
LenPos
=
MaxSize
};
Ch
str
[
MaxChars
];
inline
static
bool
Usable
(
SizeType
len
)
{
return
(
MaxSize
>=
len
);
}
...
...
@@ -1698,15 +1711,15 @@ private:
};
// 8 bytes
struct
Object
{
Member
*
members
;
SizeType
size
;
SizeType
capacity
;
Member
*
members
;
};
// 12 bytes in 32-bit mode, 16 bytes in 64-bit mode
struct
Array
{
GenericValue
*
elements
;
SizeType
size
;
SizeType
capacity
;
GenericValue
*
elements
;
};
// 12 bytes in 32-bit mode, 16 bytes in 64-bit mode
union
Data
{
...
...
@@ -1715,51 +1728,61 @@ private:
Number
n
;
Object
o
;
Array
a
;
};
// 12 bytes in 32-bit mode, 16 bytes in 64-bit mode
Flag
f
;
};
// 16 bytes in 32-bit mode, 24 bytes in 64-bit mode, 16 bytes in 64-bit with RAPIDJSON_48BITPOINTER_OPTIMIZATION
RAPIDJSON_FORCEINLINE
Ch
*
GetStringPointer
()
const
{
return
RAPIDJSON_GETPOINTER
(
Ch
,
data_
.
s
.
str
);
}
RAPIDJSON_FORCEINLINE
const
Ch
*
SetStringPointer
(
const
Ch
*
str
)
{
return
RAPIDJSON_SETPOINTER
(
Ch
,
data_
.
s
.
str
,
str
);
}
RAPIDJSON_FORCEINLINE
GenericValue
*
GetElementsPointer
()
const
{
return
RAPIDJSON_GETPOINTER
(
GenericValue
,
data_
.
a
.
elements
);
}
RAPIDJSON_FORCEINLINE
const
GenericValue
*
SetElementsPointer
(
const
GenericValue
*
elements
)
{
return
RAPIDJSON_SETPOINTER
(
GenericValue
,
data_
.
a
.
elements
,
elements
);
}
RAPIDJSON_FORCEINLINE
Member
*
GetMembersPointer
()
const
{
return
RAPIDJSON_GETPOINTER
(
Member
,
data_
.
o
.
members
);
}
RAPIDJSON_FORCEINLINE
const
Member
*
SetMembersPointer
(
const
Member
*
members
)
{
return
RAPIDJSON_SETPOINTER
(
Member
,
data_
.
o
.
members
,
members
);
}
// Initialize this value as array with initial data, without calling destructor.
void
SetArrayRaw
(
GenericValue
*
values
,
SizeType
count
,
Allocator
&
allocator
)
{
flags_
=
kArrayFlag
;
data_
.
f
.
flags
=
kArrayFlag
;
if
(
count
)
{
data_
.
a
.
elements
=
static_cast
<
GenericValue
*>
(
allocator
.
Malloc
(
count
*
sizeof
(
GenericValue
)));
std
::
memcpy
(
data_
.
a
.
elements
,
values
,
count
*
sizeof
(
GenericValue
));
GenericValue
*
e
=
static_cast
<
GenericValue
*>
(
allocator
.
Malloc
(
count
*
sizeof
(
GenericValue
)));
SetElementsPointer
(
e
);
std
::
memcpy
(
e
,
values
,
count
*
sizeof
(
GenericValue
));
}
else
data_
.
a
.
elements
=
NULL
;
SetElementsPointer
(
0
)
;
data_
.
a
.
size
=
data_
.
a
.
capacity
=
count
;
}
//! Initialize this value as object with initial data, without calling destructor.
void
SetObjectRaw
(
Member
*
members
,
SizeType
count
,
Allocator
&
allocator
)
{
flags_
=
kObjectFlag
;
data_
.
f
.
flags
=
kObjectFlag
;
if
(
count
)
{
data_
.
o
.
members
=
static_cast
<
Member
*>
(
allocator
.
Malloc
(
count
*
sizeof
(
Member
)));
std
::
memcpy
(
data_
.
o
.
members
,
members
,
count
*
sizeof
(
Member
));
Member
*
m
=
static_cast
<
Member
*>
(
allocator
.
Malloc
(
count
*
sizeof
(
Member
)));
SetMembersPointer
(
m
);
std
::
memcpy
(
m
,
members
,
count
*
sizeof
(
Member
));
}
else
data_
.
o
.
members
=
NULL
;
SetMembersPointer
(
0
)
;
data_
.
o
.
size
=
data_
.
o
.
capacity
=
count
;
}
//! Initialize this value as constant string, without calling destructor.
void
SetStringRaw
(
StringRefType
s
)
RAPIDJSON_NOEXCEPT
{
flags_
=
kConstStringFlag
;
data_
.
s
.
str
=
s
;
data_
.
f
.
flags
=
kConstStringFlag
;
SetStringPointer
(
s
)
;
data_
.
s
.
length
=
s
.
length
;
}
//! Initialize this value as copy string with initial data, without calling destructor.
void
SetStringRaw
(
StringRefType
s
,
Allocator
&
allocator
)
{
Ch
*
str
=
NULL
;
if
(
ShortString
::
Usable
(
s
.
length
))
{
flags_
=
kShortStringFlag
;
Ch
*
str
=
0
;
if
(
ShortString
::
Usable
(
s
.
length
))
{
data_
.
f
.
flags
=
kShortStringFlag
;
data_
.
ss
.
SetLength
(
s
.
length
);
str
=
data_
.
ss
.
str
;
}
else
{
flags_
=
kCopyStringFlag
;
data_
.
f
.
flags
=
kCopyStringFlag
;
data_
.
s
.
length
=
s
.
length
;
str
=
static_cast
<
Ch
*>
(
allocator
.
Malloc
((
s
.
length
+
1
)
*
sizeof
(
Ch
)));
data_
.
s
.
str
=
str
;
SetStringPointer
(
str
)
;
}
std
::
memcpy
(
str
,
s
,
s
.
length
*
sizeof
(
Ch
));
str
[
s
.
length
]
=
'\0'
;
...
...
@@ -1768,8 +1791,8 @@ private:
//! Assignment without calling destructor
void
RawAssign
(
GenericValue
&
rhs
)
RAPIDJSON_NOEXCEPT
{
data_
=
rhs
.
data_
;
flags_
=
rhs
.
flags_
;
rhs
.
flags_
=
kNullFlag
;
// data_.f.flags = rhs.data_.f.flags
;
rhs
.
data_
.
f
.
flags
=
kNullFlag
;
}
template
<
typename
SourceAllocator
>
...
...
@@ -1789,7 +1812,6 @@ private:
}
Data
data_
;
unsigned
flags_
;
};
//! GenericValue with UTF8 encoding
...
...
@@ -2158,15 +2180,15 @@ GenericValue<Encoding,Allocator>::GenericValue(const GenericValue<Encoding,Sourc
}
break
;
case
kStringType
:
if
(
rhs
.
flags_
==
kConstStringFlag
)
{
flags_
=
rhs
.
flags_
;
if
(
rhs
.
data_
.
f
.
flags
==
kConstStringFlag
)
{
data_
.
f
.
flags
=
rhs
.
data_
.
f
.
flags
;
data_
=
*
reinterpret_cast
<
const
Data
*>
(
&
rhs
.
data_
);
}
else
{
SetStringRaw
(
StringRef
(
rhs
.
GetString
(),
rhs
.
GetStringLength
()),
allocator
);
}
break
;
default
:
flags_
=
rhs
.
flags_
;
data_
.
f
.
flags
=
rhs
.
data_
.
f
.
flags
;
data_
=
*
reinterpret_cast
<
const
Data
*>
(
&
rhs
.
data_
);
break
;
}
...
...
include/rapidjson/rapidjson.h
View file @
e731726c
...
...
@@ -265,7 +265,8 @@
\param x pointer to align
Some machines require strict data alignment. Currently the default uses 4 bytes
alignment. User can customize by defining the RAPIDJSON_ALIGN function macro.
alignment on 32-bit platforms and 8 bytes alignment for 64-bit platforms.
User can customize by defining the RAPIDJSON_ALIGN function macro.
*/
#ifndef RAPIDJSON_ALIGN
#if RAPIDJSON_64BIT == 1
...
...
@@ -288,6 +289,36 @@
#define RAPIDJSON_UINT64_C2(high32, low32) ((static_cast<uint64_t>(high32) << 32) | static_cast<uint64_t>(low32))
#endif
///////////////////////////////////////////////////////////////////////////////
// RAPIDJSON_48BITPOINTER_OPTIMIZATION
//! Use only lower 48-bit address for some pointers.
/*!
\ingroup RAPIDJSON_CONFIG
This optimization uses the fact that current X86-64 architecture only implement lower 48-bit virtual address.
The higher 16-bit can be used for storing other data.
\c GenericValue uses this optimization to reduce its size form 24 bytes to 16 bytes in 64-bit architecture.
*/
#ifndef RAPIDJSON_48BITPOINTER_OPTIMIZATION
#if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || defined(_M_X64) || defined(_M_AMD64)
#define RAPIDJSON_48BITPOINTER_OPTIMIZATION 1
#else
#define RAPIDJSON_48BITPOINTER_OPTIMIZATION 0
#endif
#endif // RAPIDJSON_48BITPOINTER_OPTIMIZATION
#if RAPIDJSON_48BITPOINTER_OPTIMIZATION == 1
#if RAPIDJSON_64BIT != 1
#error RAPIDJSON_48BITPOINTER_OPTIMIZATION can only be set to 1 when RAPIDJSON_64BIT=1
#endif
#define RAPIDJSON_SETPOINTER(type, p, x) (p = reinterpret_cast<type *>((reinterpret_cast<uintptr_t>(p) & static_cast<uintptr_t>(RAPIDJSON_UINT64_C2(0xFFFF0000, 0x00000000))) | reinterpret_cast<uintptr_t>(reinterpret_cast<const void*>(x))))
#define RAPIDJSON_GETPOINTER(type, p) (reinterpret_cast<type *>(reinterpret_cast<uintptr_t>(p) & static_cast<uintptr_t>(RAPIDJSON_UINT64_C2(0x0000FFFF, 0xFFFFFFFF))))
#else
#define RAPIDJSON_SETPOINTER(type, p, x) (p = (x))
#define RAPIDJSON_GETPOINTER(type, p) (p)
#endif
///////////////////////////////////////////////////////////////////////////////
// RAPIDJSON_SSE2/RAPIDJSON_SSE42/RAPIDJSON_SIMD
...
...
test/unittest/valuetest.cpp
View file @
e731726c
...
...
@@ -23,6 +23,18 @@ RAPIDJSON_DIAG_OFF(c++98-compat)
using
namespace
rapidjson
;
TEST
(
Value
,
Size
)
{
if
(
sizeof
(
SizeType
)
==
4
)
{
#if RAPIDJSON_48BITPOINTER_OPTIMIZATION
EXPECT_EQ
(
16
,
sizeof
(
Value
));
#elif RAPIDJSON_64BIT
EXPECT_EQ
(
24
,
sizeof
(
Value
));
#else
EXPECT_EQ
(
16
,
sizeof
(
Value
));
#endif
}
}
TEST
(
Value
,
DefaultConstructor
)
{
Value
x
;
EXPECT_EQ
(
kNullType
,
x
.
GetType
());
...
...
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