For more details see: https://github.com/miloyip/rapidjson/issues/132
This commit tries to minimize the required code changes and forwards the `Handler::Key()` calls to `Handler::String()` wherever possible in order to not break existing code; or at least not code deriving from `BaseReaderHandler` when implementing a custom `Handler`.
The `ShortString` can represent zero-terminated strings up to `MaxSize` chars (excluding the terminating zero) and store a value to determine the length of the contained string in the last character `str[LenPos]` by storing `MaxSize - length` there. If the string to store has the maximal length of `MaxSize` (excluding the terminating zero) then `str[LenPos]` will store `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 `11`-chars strings in 32-bit mode and `15`-chars strings in 64-bit mode inline (for `UTF8`-encoded strings).
Since the payload (the `Data` union) of the current implementation of `GenericValue` is `12 bytes` (32 bit) or `16 bytes` (64 bit) it could store `UTF8`-encoded strings up to `10` or `14` chars plus the `terminating zero` character plus the string length:
``` C++
struct ShortString {
enum { MaxSize = sizeof(GenericValue::String) / sizeof(Ch) - sizeof(unsigned char) };
Ch str[MaxSize];
unsigned char length;
}; // at most as many bytes as "String" above => 12 bytes in 32-bit mode, 16 bytes in 64-bit mode
```
This is achieved by introducing additional `kInlineStrFlag` and `kShortStringFlag` flags. When setting a new string value in `SetStringRaw(s, alloc)` it is first checked if the string is short enough to fit into the `inline string buffer` and if so the given source string will be copied into the new `ShortString` target instead of allocating additional memory for it.
As mentioned by @kosta-github in http://git.io/0gkYSg, the currently
used growth factor of 2 is suboptimal for memory performance. An
extensive discussion can be found at [1].
This patch reduces the array/object capacity growth factor to 1.5, as
many C++ implementations have chosen to use. In order to avoid
floating-point arithmetics for computing the new capacity, I did not
add any customization parameter for the factor and used a shift+add
instead.
[1] https://github.com/facebook/folly/blob/master/folly/docs/FBVector.md
Some 64-bit integers cannot be represented losslessly as a double.
Due to a typo in the operator==, the comparison has been performed
after a double conversion in too many cases.
Added basic detection of `noexcept` support for some compilers, added
corresponding RAPIDJSON_NOEXCEPT annotations to
* non-allocating constructors
* (move) assignment
* Swap
This commit adds an IsGenericValue meta function to match arbitrary
instantiations of the GenericValue template (or derived classes).
This meta function is used in the SFINAE-checks to avoid matching
the generic APIs (operator=,==,!=; AddMember, PushBack) for instances
of the main template. This avoids ambiguities with the GenericValue
overloads.
Several GenericValue functions take a const-reference to another GenericValue
only. These functions can safely accept values with a different allocator
type.
The following functions are therefore extended by a SourceAllocator template
parameter in this commit:
- operator==/!=/[]
- HasMember, FindMember, RemoveMember
- StringEqual
Before applying the simplifications in ed282b814, the SFINAE check for the
GenericValue(bool) constructor has been broken in MSVC 2005. Add a static
assert as a safe-guard against future reappearance of this problem.
As reported in #113, recent versions of Clang complain about
ambiguous overloads for some comparison operator instantiations,
especially if the deduced template type is a GenericValue.
Add an explicit, non-templated version for now (which is a better
match).
This only solves part of the problem, as comparisons between
* GenericValue & GenericDocument
* GenericValue with different SourceAllocator types
will still cause ambiguities.
Some users may want to use RapidJSON with std::string objects. This commits
adds an (opt-in) feature to include some basic support. The implementation
uses std::basic_string<Ch> as generic string type.
Support currently covers:
* construction
* comparison
No special APIs for AddMember or PushBack have been added, as std::string
most probably requires copying (or an explicit StringRef() call).
By restructuring the call forwarding of the various operator== and
operator!= overloads, new overloads can be added by simply adding an
additional member operator==.
Additionally, the "Ch*" overloads are dropped in favour of an SFINAE
version that removes the pointer variants from matching the templated
operator== (see also operator=).