Implement bitfields for better readability over masks
This commit is contained in:
commit
7d08aa759b
11
.travis.yml
11
.travis.yml
@ -1,6 +1,7 @@
|
||||
language: cpp
|
||||
|
||||
sudo: false
|
||||
dist: trusty
|
||||
sudo: required
|
||||
|
||||
# from http://stackoverflow.com/a/32127147/266378
|
||||
matrix:
|
||||
@ -56,3 +57,11 @@ script:
|
||||
- make CXX=$COMPILER CXXFLAGS="-lstdc++"
|
||||
- ./json_unit "*"
|
||||
- valgrind --error-exitcode=1 --leak-check=full ./json_unit
|
||||
|
||||
notifications:
|
||||
webhooks:
|
||||
urls:
|
||||
- https://webhooks.gitter.im/e/f1196addb0e97a5ff396
|
||||
on_success: change
|
||||
on_failure: always
|
||||
on_start: never
|
||||
|
||||
181
ChangeLog.md
Normal file
181
ChangeLog.md
Normal file
@ -0,0 +1,181 @@
|
||||
# Change Log
|
||||
All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
## [Unreleased](https://github.com/nlohmann/json/tree/HEAD)
|
||||
|
||||
[Full Changelog](https://github.com/nlohmann/json/compare/v1.1.0...HEAD)
|
||||
|
||||
- Issue \#178 - Extending support to full uint64\_t/int64\_t range and unsigned type \(updated\) [\#193](https://github.com/nlohmann/json/pull/193) ([twelsby](https://github.com/twelsby))
|
||||
|
||||
- GCC/clang floating point parsing bug in strtod\(\) [\#195](https://github.com/nlohmann/json/issues/195)
|
||||
- Floating point exceptions [\#181](https://github.com/nlohmann/json/issues/181)
|
||||
- Implicit assignment to std::string fails [\#144](https://github.com/nlohmann/json/issues/144)
|
||||
- Issue \#195 - update Travis to Trusty due to gcc/clang strtod\(\) bug [\#196](https://github.com/nlohmann/json/pull/196) ([twelsby](https://github.com/twelsby))
|
||||
|
||||
- Integer conversion to unsigned [\#178](https://github.com/nlohmann/json/issues/178)
|
||||
|
||||
- Fix broken link [\#197](https://github.com/nlohmann/json/pull/197) ([vog](https://github.com/vog))
|
||||
|
||||
## [v1.1.0](https://github.com/nlohmann/json/releases/tag/v1.1.0) (2016-01-24)
|
||||
[Full Changelog](https://github.com/nlohmann/json/compare/v1.0.0...v1.1.0)
|
||||
|
||||
- JSON performance benchmark comparision [\#177](https://github.com/nlohmann/json/issues/177)
|
||||
- Since re2c is often ignored in pull requests, it may make sense to make a contributing.md file [\#175](https://github.com/nlohmann/json/issues/175)
|
||||
- Add assertions [\#168](https://github.com/nlohmann/json/issues/168)
|
||||
- range based for loop for objects [\#83](https://github.com/nlohmann/json/issues/83)
|
||||
- Implementation of get\_ref\(\) [\#184](https://github.com/nlohmann/json/pull/184) ([dariomt](https://github.com/dariomt))
|
||||
|
||||
- Small error in pull \#185 [\#194](https://github.com/nlohmann/json/issues/194)
|
||||
- Bugs in miloyip/nativejson-benchmark: floating-point parsing [\#186](https://github.com/nlohmann/json/issues/186)
|
||||
- Cannot index by key of type static constexpr const char\* [\#171](https://github.com/nlohmann/json/issues/171)
|
||||
- Fixed Issue \#171 - added two extra template overloads of operator\[\] for T\* arguments [\#189](https://github.com/nlohmann/json/pull/189) ([twelsby](https://github.com/twelsby))
|
||||
- Fixed issue \#167 - removed operator ValueType\(\) condition for VS2015 [\#188](https://github.com/nlohmann/json/pull/188) ([twelsby](https://github.com/twelsby))
|
||||
|
||||
- Floating point equality [\#185](https://github.com/nlohmann/json/issues/185)
|
||||
- Unused variables in catch [\#180](https://github.com/nlohmann/json/issues/180)
|
||||
- Typo in documentation [\#179](https://github.com/nlohmann/json/issues/179)
|
||||
- Android? [\#172](https://github.com/nlohmann/json/issues/172)
|
||||
- MSVC 2015 build fails when attempting to compare object\_t [\#167](https://github.com/nlohmann/json/issues/167)
|
||||
- Member detector is not portable [\#166](https://github.com/nlohmann/json/issues/166)
|
||||
- Unnecessary const\_cast [\#162](https://github.com/nlohmann/json/issues/162)
|
||||
- Consider submitting this to the Boost Library Incubator [\#66](https://github.com/nlohmann/json/issues/66)
|
||||
|
||||
- Fixed Issue \#186 - add strto\(f|d|ld\) overload wrappers, "-0.0" special case and FP trailing zero [\#191](https://github.com/nlohmann/json/pull/191) ([twelsby](https://github.com/twelsby))
|
||||
- Issue \#185 - remove approx\(\) and use \#pragma to kill warnings [\#190](https://github.com/nlohmann/json/pull/190) ([twelsby](https://github.com/twelsby))
|
||||
- Fixed some typos in CONTRIBUTING.md [\#182](https://github.com/nlohmann/json/pull/182) ([nibroc](https://github.com/nibroc))
|
||||
|
||||
## [v1.0.0](https://github.com/nlohmann/json/releases/tag/v1.0.0) (2015-12-27)
|
||||
[Full Changelog](https://github.com/nlohmann/json/compare/v1.0.0-rc1...v1.0.0)
|
||||
|
||||
- add key name to exception [\#160](https://github.com/nlohmann/json/issues/160)
|
||||
- prevent json.hpp from emitting compiler warnings [\#154](https://github.com/nlohmann/json/issues/154)
|
||||
- json::parse\(string\) does not check utf8 bom [\#152](https://github.com/nlohmann/json/issues/152)
|
||||
- unsigned 64bit values output as signed [\#151](https://github.com/nlohmann/json/issues/151)
|
||||
- Wish feature: json5 [\#150](https://github.com/nlohmann/json/issues/150)
|
||||
- overload of at\(\) with default value [\#133](https://github.com/nlohmann/json/issues/133)
|
||||
- Memory leak in face of exceptions [\#118](https://github.com/nlohmann/json/issues/118)
|
||||
- Find and Count for arrays [\#117](https://github.com/nlohmann/json/issues/117)
|
||||
- dynamically constructing an arbitrarily nested object [\#114](https://github.com/nlohmann/json/issues/114)
|
||||
- object field accessors [\#103](https://github.com/nlohmann/json/issues/103)
|
||||
- v8pp and json [\#95](https://github.com/nlohmann/json/issues/95)
|
||||
- Wishlist [\#65](https://github.com/nlohmann/json/issues/65)
|
||||
- Windows/Visual Studio \(through 2013\) is unsupported [\#62](https://github.com/nlohmann/json/issues/62)
|
||||
|
||||
- Bug in basic\_json::operator\[\] const overload [\#135](https://github.com/nlohmann/json/issues/135)
|
||||
- wrong enable\_if for const pointer \(instead of pointer-to-const\) [\#134](https://github.com/nlohmann/json/issues/134)
|
||||
- Visual Studio 14 Debug assertion failed [\#125](https://github.com/nlohmann/json/issues/125)
|
||||
- Compile error with g++ 4.9.3 cygwin 64-bit [\#112](https://github.com/nlohmann/json/issues/112)
|
||||
- error: unterminated raw string [\#109](https://github.com/nlohmann/json/issues/109)
|
||||
- \[clang-3.6.2\] string/sstream with number to json issue [\#107](https://github.com/nlohmann/json/issues/107)
|
||||
|
||||
- Getting member discarding qualifyer [\#159](https://github.com/nlohmann/json/issues/159)
|
||||
- basic\_json::iterator::value\(\) output includes quotes while basic\_json::iterator::key\(\) doesn't [\#158](https://github.com/nlohmann/json/issues/158)
|
||||
- Indexing `const basic\_json\<\>` with `const basic\_string\<char\>` [\#157](https://github.com/nlohmann/json/issues/157)
|
||||
- token\_type\_name\(token\_type t\): not all control paths return a value [\#156](https://github.com/nlohmann/json/issues/156)
|
||||
- Unable to compile on MSVC 2015 with SDL checking enabled: This function or variable may be unsafe. [\#149](https://github.com/nlohmann/json/issues/149)
|
||||
- dump\(\) convert strings encoded by utf-8 to shift-jis on windows 10. [\#147](https://github.com/nlohmann/json/issues/147)
|
||||
- Unable to get field names in a json object [\#145](https://github.com/nlohmann/json/issues/145)
|
||||
- json.hpp:5746:32: error: 'to\_string' is not a member of 'std' [\#136](https://github.com/nlohmann/json/issues/136)
|
||||
- Returning any data type [\#113](https://github.com/nlohmann/json/issues/113)
|
||||
- vector\<json\> copy constructor really weird [\#108](https://github.com/nlohmann/json/issues/108)
|
||||
- maintaining order of keys during iteration [\#106](https://github.com/nlohmann/json/issues/106)
|
||||
|
||||
- Replace sprintf with hex function, this fixes \#149 [\#153](https://github.com/nlohmann/json/pull/153) ([whackashoe](https://github.com/whackashoe))
|
||||
- Fix character skipping after a surrogate pair [\#146](https://github.com/nlohmann/json/pull/146) ([robertmrk](https://github.com/robertmrk))
|
||||
- Detect correctly pointer-to-const [\#137](https://github.com/nlohmann/json/pull/137) ([dariomt](https://github.com/dariomt))
|
||||
- disabled "CopyAssignable" test for MSVC in Debug mode, see \#125 [\#131](https://github.com/nlohmann/json/pull/131) ([dariomt](https://github.com/dariomt))
|
||||
- removed stream operator for iterator, resolution for \#125 [\#130](https://github.com/nlohmann/json/pull/130) ([dariomt](https://github.com/dariomt))
|
||||
- fixed typos in comments for examples [\#129](https://github.com/nlohmann/json/pull/129) ([dariomt](https://github.com/dariomt))
|
||||
- Remove superfluous inefficiency [\#126](https://github.com/nlohmann/json/pull/126) ([d-frey](https://github.com/d-frey))
|
||||
- remove invalid parameter '-stdlib=libc++' in CMakeLists.txt [\#124](https://github.com/nlohmann/json/pull/124) ([emvivre](https://github.com/emvivre))
|
||||
- exception-safe object creation, fixes \#118 [\#122](https://github.com/nlohmann/json/pull/122) ([d-frey](https://github.com/d-frey))
|
||||
- Fix small oversight. [\#121](https://github.com/nlohmann/json/pull/121) ([ColinH](https://github.com/ColinH))
|
||||
- Overload parse\(\) to accept an rvalue reference [\#120](https://github.com/nlohmann/json/pull/120) ([silverweed](https://github.com/silverweed))
|
||||
- Use the right variable name in doc string [\#115](https://github.com/nlohmann/json/pull/115) ([whoshuu](https://github.com/whoshuu))
|
||||
|
||||
## [v1.0.0-rc1](https://github.com/nlohmann/json/releases/tag/v1.0.0-rc1) (2015-07-26)
|
||||
- Adjust wording to JSON RFC [\#97](https://github.com/nlohmann/json/issues/97)
|
||||
- access by \(const\) reference [\#91](https://github.com/nlohmann/json/issues/91)
|
||||
- is\_integer and is\_float tests [\#90](https://github.com/nlohmann/json/issues/90)
|
||||
- MinGW have no std::to\_string [\#80](https://github.com/nlohmann/json/issues/80)
|
||||
- erase elements using iterators [\#57](https://github.com/nlohmann/json/issues/57)
|
||||
- Removing item from array [\#56](https://github.com/nlohmann/json/issues/56)
|
||||
- Serialize/Deserialize like PHP? [\#55](https://github.com/nlohmann/json/issues/55)
|
||||
- Document erase, count, and iterators key and value [\#52](https://github.com/nlohmann/json/issues/52)
|
||||
- Supported compilers [\#50](https://github.com/nlohmann/json/issues/50)
|
||||
- Use non-member begin/end [\#48](https://github.com/nlohmann/json/issues/48)
|
||||
- Erase key [\#47](https://github.com/nlohmann/json/issues/47)
|
||||
- Key iterator [\#46](https://github.com/nlohmann/json/issues/46)
|
||||
- Add count member function [\#45](https://github.com/nlohmann/json/issues/45)
|
||||
- Printing attribute names [\#39](https://github.com/nlohmann/json/issues/39)
|
||||
- Avoid using spaces when encoding without pretty print [\#31](https://github.com/nlohmann/json/issues/31)
|
||||
- Cannot encode long numbers [\#30](https://github.com/nlohmann/json/issues/30)
|
||||
- Creating an empty array [\#27](https://github.com/nlohmann/json/issues/27)
|
||||
- Custom allocator support [\#25](https://github.com/nlohmann/json/issues/25)
|
||||
- create a header-only version [\#16](https://github.com/nlohmann/json/issues/16)
|
||||
- Add to\_string overload for indentation [\#13](https://github.com/nlohmann/json/issues/13)
|
||||
- move code into namespace [\#9](https://github.com/nlohmann/json/issues/9)
|
||||
- free functions for explicit objects and arrays in initializer lists [\#8](https://github.com/nlohmann/json/issues/8)
|
||||
- Test case coverage [\#2](https://github.com/nlohmann/json/issues/2)
|
||||
- Parse streams incrementally. [\#40](https://github.com/nlohmann/json/pull/40) ([aburgh](https://github.com/aburgh))
|
||||
|
||||
- Binary string causes numbers to be dumped as hex [\#101](https://github.com/nlohmann/json/issues/101)
|
||||
- failed to iterator json object with reverse\_iterator [\#100](https://github.com/nlohmann/json/issues/100)
|
||||
- static analysis warnings [\#94](https://github.com/nlohmann/json/issues/94)
|
||||
- reverse\_iterator operator inheritance problem [\#93](https://github.com/nlohmann/json/issues/93)
|
||||
- Nonstandard integer type [\#89](https://github.com/nlohmann/json/issues/89)
|
||||
- lexer::get\_number return NAN [\#82](https://github.com/nlohmann/json/issues/82)
|
||||
- Handle infinity and NaN cases [\#70](https://github.com/nlohmann/json/issues/70)
|
||||
- errors in g++-4.8.1 [\#68](https://github.com/nlohmann/json/issues/68)
|
||||
- Double quotation mark is not parsed correctly [\#60](https://github.com/nlohmann/json/issues/60)
|
||||
- Do not use std::to\_string [\#51](https://github.com/nlohmann/json/issues/51)
|
||||
- Confused about iterating through json objects [\#49](https://github.com/nlohmann/json/issues/49)
|
||||
- Problem getting vector \(array\) of strings [\#44](https://github.com/nlohmann/json/issues/44)
|
||||
- Compilation error due to assuming that private=public [\#43](https://github.com/nlohmann/json/issues/43)
|
||||
- Use of deprecated implicit copy constructor [\#42](https://github.com/nlohmann/json/issues/42)
|
||||
- dumping a small number\_float just outputs 0.000000 [\#37](https://github.com/nlohmann/json/issues/37)
|
||||
- Avoid using spaces when encoding without pretty print [\#31](https://github.com/nlohmann/json/issues/31)
|
||||
- Cannot encode long numbers [\#30](https://github.com/nlohmann/json/issues/30)
|
||||
- segmentation fault when iterating over empty arrays/objects [\#28](https://github.com/nlohmann/json/issues/28)
|
||||
- Improper parsing of JSON string "\\" [\#17](https://github.com/nlohmann/json/issues/17)
|
||||
- Don't return "const values" [\#15](https://github.com/nlohmann/json/issues/15)
|
||||
- string parser does not recognize uncompliant strings [\#12](https://github.com/nlohmann/json/issues/12)
|
||||
- free functions for explicit objects and arrays in initializer lists [\#8](https://github.com/nlohmann/json/issues/8)
|
||||
- Runtime error in Travis job [\#1](https://github.com/nlohmann/json/issues/1)
|
||||
- Fix compilation of json\_unit with GCC 5 [\#59](https://github.com/nlohmann/json/pull/59) ([dkopecek](https://github.com/dkopecek))
|
||||
|
||||
- Finish documenting the public interface in Doxygen [\#102](https://github.com/nlohmann/json/issues/102)
|
||||
- 'noexcept' : unknown override specifier [\#99](https://github.com/nlohmann/json/issues/99)
|
||||
- Keys when iterating over objects [\#67](https://github.com/nlohmann/json/issues/67)
|
||||
- Complete brief documentation [\#61](https://github.com/nlohmann/json/issues/61)
|
||||
- Get coverage back to 100% [\#58](https://github.com/nlohmann/json/issues/58)
|
||||
- possible double-free in find function [\#11](https://github.com/nlohmann/json/issues/11)
|
||||
- UTF-8 encoding/deconding/testing [\#10](https://github.com/nlohmann/json/issues/10)
|
||||
- Add unit tests [\#4](https://github.com/nlohmann/json/issues/4)
|
||||
- Drop C++98 support [\#3](https://github.com/nlohmann/json/issues/3)
|
||||
|
||||
- Keyword 'inline' is useless when member functions are defined in headers [\#87](https://github.com/nlohmann/json/pull/87) ([ahamez](https://github.com/ahamez))
|
||||
- Remove useless typename [\#86](https://github.com/nlohmann/json/pull/86) ([ahamez](https://github.com/ahamez))
|
||||
- Avoid warning with Xcode's clang [\#85](https://github.com/nlohmann/json/pull/85) ([ahamez](https://github.com/ahamez))
|
||||
- Fix typos [\#73](https://github.com/nlohmann/json/pull/73) ([aqnouch](https://github.com/aqnouch))
|
||||
- Replace `default\_callback` function with `nullptr` and check for null… [\#72](https://github.com/nlohmann/json/pull/72) ([aburgh](https://github.com/aburgh))
|
||||
- support enum [\#71](https://github.com/nlohmann/json/pull/71) ([likebeta](https://github.com/likebeta))
|
||||
- Fix performance regression introduced with the parsing callback feature. [\#69](https://github.com/nlohmann/json/pull/69) ([aburgh](https://github.com/aburgh))
|
||||
- Improve the implementations of the comparission-operators [\#63](https://github.com/nlohmann/json/pull/63) ([Florianjw](https://github.com/Florianjw))
|
||||
- Feature/small float serialization [\#38](https://github.com/nlohmann/json/pull/38) ([jrandall](https://github.com/jrandall))
|
||||
- template version with re2c scanner [\#36](https://github.com/nlohmann/json/pull/36) ([nlohmann](https://github.com/nlohmann))
|
||||
- more descriptive documentation in example [\#33](https://github.com/nlohmann/json/pull/33) ([luxe](https://github.com/luxe))
|
||||
- Fix string conversion under Clang [\#26](https://github.com/nlohmann/json/pull/26) ([wancw](https://github.com/wancw))
|
||||
- Fixed dumping of strings [\#24](https://github.com/nlohmann/json/pull/24) ([Teemperor](https://github.com/Teemperor))
|
||||
- Added a remark to the readme that coverage is GCC only for now [\#23](https://github.com/nlohmann/json/pull/23) ([Teemperor](https://github.com/Teemperor))
|
||||
- Unicode escaping [\#22](https://github.com/nlohmann/json/pull/22) ([Teemperor](https://github.com/Teemperor))
|
||||
- Implemented the JSON spec for string parsing for everything but the \uXXXX escaping [\#21](https://github.com/nlohmann/json/pull/21) ([Teemperor](https://github.com/Teemperor))
|
||||
- add the std iterator typedefs to iterator and const\_iterator [\#19](https://github.com/nlohmann/json/pull/19) ([kirkshoop](https://github.com/kirkshoop))
|
||||
- Fixed escaped quotes [\#18](https://github.com/nlohmann/json/pull/18) ([Teemperor](https://github.com/Teemperor))
|
||||
- Fix double delete on std::bad\_alloc exception [\#14](https://github.com/nlohmann/json/pull/14) ([elliotgoodrich](https://github.com/elliotgoodrich))
|
||||
- Added CMake and lcov [\#6](https://github.com/nlohmann/json/pull/6) ([Teemperor](https://github.com/Teemperor))
|
||||
- Version 2.0 [\#5](https://github.com/nlohmann/json/pull/5) ([nlohmann](https://github.com/nlohmann))
|
||||
|
||||
|
||||
|
||||
\* *This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)*
|
||||
12
Makefile
12
Makefile
@ -1,4 +1,4 @@
|
||||
.PHONY: pretty clean
|
||||
.PHONY: pretty clean ChangeLog.md
|
||||
|
||||
# used programs
|
||||
RE2C = re2c
|
||||
@ -59,3 +59,13 @@ pretty:
|
||||
json_benchmarks: benchmarks/benchmarks.cpp benchmarks/benchpress.hpp benchmarks/cxxopts.hpp src/json.hpp
|
||||
$(CXX) -std=c++11 $(CXXFLAGS) -O3 -flto -I src -I benchmarks $< $(LDFLAGS) -o $@
|
||||
./json_benchmarks
|
||||
|
||||
|
||||
##########################################################################
|
||||
# changelog
|
||||
##########################################################################
|
||||
|
||||
ChangeLog.md:
|
||||
github_changelog_generator -o ChangeLog.md --simple-list --release-url https://github.com/nlohmann/json/releases/tag/%s
|
||||
gsed -i 's|https://github.com/nlohmann/json/releases/tag/HEAD|https://github.com/nlohmann/json/tree/HEAD|' ChangeLog.md
|
||||
gsed -i '2i All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/).' ChangeLog.md
|
||||
|
||||
15
README.md
15
README.md
@ -3,11 +3,12 @@
|
||||
[](https://travis-ci.org/nlohmann/json)
|
||||
[](https://ci.appveyor.com/project/nlohmann/json)
|
||||
[](https://coveralls.io/r/nlohmann/json)
|
||||
[](http://melpon.org/wandbox/permlink/GnGKwji06WeVonlI)
|
||||
[](http://melpon.org/wandbox/permlink/WSW3gHHE4UcZ9K3G)
|
||||
[](http://nlohmann.github.io/json)
|
||||
[](https://raw.githubusercontent.com/nlohmann/json/master/LICENSE.MIT)
|
||||
[](https://github.com/nlohmann/json/releases)
|
||||
[](http://github.com/nlohmann/json/issues)
|
||||
[](https://gitter.im/nlohmann/json?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
|
||||
|
||||
## Design goals
|
||||
|
||||
@ -21,11 +22,11 @@ There are myriads of [JSON](http://json.org) libraries out there, and each may e
|
||||
|
||||
Other aspects were not so important to us:
|
||||
|
||||
- **Memory efficiency**. Each JSON object has an overhead of one pointer (the maximal size of a union) and one enumeration element (1 byte). The default generalization uses the following C++ data types: `std::string` for strings, `int64_t` or `double` for numbers, `std::map` for objects, `std::vector` for arrays, and `bool` for Booleans. However, you can template the generalized class `basic_json` to your needs.
|
||||
- **Memory efficiency**. Each JSON object has an overhead of one pointer (the maximal size of a union) and one enumeration element (1 byte). The default generalization uses the following C++ data types: `std::string` for strings, `int64_t`, `uint64_t` or `double` for numbers, `std::map` for objects, `std::vector` for arrays, and `bool` for Booleans. However, you can template the generalized class `basic_json` to your needs.
|
||||
|
||||
- **Speed**. We currently implement the parser as naive [recursive descent parser](http://en.wikipedia.org/wiki/Recursive_descent_parser) with hand coded string handling. It is fast enough, but a [LALR-parser](http://en.wikipedia.org/wiki/LALR_parser) with a decent regular expression processor should be even faster (but would consist of more files which makes the integration harder).
|
||||
|
||||
See the [https://github.com/nlohmann/json/blob/master/CONTRIBUTING.md#please-dont](contribution guidelines) for more information.
|
||||
See the [contribution guidelines](https://github.com/nlohmann/json/blob/master/CONTRIBUTING.md#please-dont) for more information.
|
||||
|
||||
## Integration
|
||||
|
||||
@ -390,13 +391,15 @@ I deeply appreciate the help of the following people.
|
||||
- [406345](https://github.com/406345) fixed two small warnings.
|
||||
- [Glen Fernandes](https://github.com/glenfe) noted a potential portability problem in the `has_mapped_type` function.
|
||||
- [Corbin Hughes](https://github.com/nibroc) fixed some typos in the contribution guidelines.
|
||||
- [twelsby](https://github.com/twelsby) fixed the array subscript operator, an issue that failed the MSVC build, and floating-point parsing/dumping.
|
||||
- [twelsby](https://github.com/twelsby) fixed the array subscript operator, an issue that failed the MSVC build, and floating-point parsing/dumping. He further added support for unsigned integer numbers.
|
||||
- [Volker Diels-Grabsch](https://github.com/vog) fixed a link in the README file.
|
||||
|
||||
Thanks a lot for helping out!
|
||||
|
||||
## Notes
|
||||
|
||||
- The code contains numerous debug assertions which can be switched off by defining the preprocessor macro `NDEBUG`, see the [documentation of `assert`](http://en.cppreference.com/w/cpp/error/assert).
|
||||
- The code contains numerous debug **assertions** which can be switched off by defining the preprocessor macro `NDEBUG`, see the [documentation of `assert`](http://en.cppreference.com/w/cpp/error/assert).
|
||||
- As the exact type of a number is not defined in the [JSON specification](http://rfc7159.net/rfc7159), this library tries to choose the best fitting C++ number type automatically. As a result, the type `double` may be used to store numbers which may yield [**floating-point exceptions**](https://github.com/nlohmann/json/issues/181) in certain rare situations if floating-point exceptions have been unmasked in the calling code. These exceptions are not caused by the library and need to be fixed in the calling code, such as by re-masking the exceptions prior to calling library functions.
|
||||
|
||||
## Execute unit tests
|
||||
|
||||
@ -407,7 +410,7 @@ $ make
|
||||
$ ./json_unit "*"
|
||||
|
||||
===============================================================================
|
||||
All tests passed (3343329 assertions in 29 test cases)
|
||||
All tests passed (3344278 assertions in 29 test cases)
|
||||
```
|
||||
|
||||
For more information, have a look at the file [.travis.yml](https://github.com/nlohmann/json/blob/master/.travis.yml).
|
||||
|
||||
@ -1,45 +0,0 @@
|
||||
# JSON for Modern C++
|
||||
|
||||
## Version 1.0.0
|
||||
|
||||
- Release date: 2015-12-28
|
||||
- MD5: 331c30e4407ecdcf591e9e3ed85100d0
|
||||
|
||||
### Summary
|
||||
|
||||
This is the first official release. Compared to the [prerelease version 1.0.0-rc1](https://github.com/nlohmann/json/releases/tag/v1.0.0-rc1), only a few minor improvements have been made:
|
||||
|
||||
### Changes
|
||||
|
||||
- *Changed*: A **UTF-8 byte order mark** is silently ignored.
|
||||
- *Changed*: `sprintf` is no longer used.
|
||||
- *Changed*: `iterator_wrapper` also works for const objects; note: the name may change!
|
||||
- *Changed*: **Error messages** during deserialization have been improved.
|
||||
- *Added*: The `parse` function now also works with type `std::istream&&`.
|
||||
- *Added*: Function `value(key, default_value)` returns either a copy of an object's element at the specified key or a given default value if no element with the key exists.
|
||||
- *Added*: Public functions are tagged with the version they were introduced. This shall allow for better **versioning** in the future.
|
||||
- *Added*: All public functions and types are **documented** (see http://nlohmann.github.io/json/) including executable examples.
|
||||
- *Added*: Allocation of all types (in particular arrays, strings, and objects) is now exception-safe.
|
||||
- *Added*: They descriptions of thrown exceptions have been overworked and are part of the tests suite and documentation.
|
||||
|
||||
## Version 1.0.0-rc1
|
||||
|
||||
- Release date: 2015-07-26
|
||||
- MD5: fac5948417ed49bfd0852a0e9dd36935
|
||||
|
||||
### Summary
|
||||
|
||||
The 1.0.0 release should be the first "official" release after the initial announcement of the class in January 2015 via reddit ("0.1.0") and a heavily overworked second version ("0.2.0") in February.
|
||||
|
||||
### Changes
|
||||
|
||||
- *Changed:* In the generic class `basic_json`, all JSON value types (array, object, string, bool, integer number, and floating-point) are now **templated**. That is, you can choose whether you like a `std::list` for your arrays or an `std::unordered_map` for your objects. The specialization `json` sets some reasonable defaults.
|
||||
- *Changed:* The library now consists of a **single header**, called `json.hpp`. Consequently, build systems such as Automake or CMake are not any longer required.
|
||||
- *Changed:* The **deserialization** is now supported by a lexer generated with [re2c](http://re2c.org) from file [`src/json.hpp.re2c`](https://github.com/nlohmann/json/blob/master/src/json.hpp.re2c). As a result, we strictly follow the JSON specification. Note neither the tool re2c nor its input are required to use the class.
|
||||
- *Added:* The library now satisfies the [**ReversibleContainer**](http://en.cppreference.com/w/cpp/concept/ReversibleContainer) requirement. It hence provides four different iterators (`iterator`, `const_iterator`, `reverse_iterator`, and `const_reverse_iterator`), comparison functions, `swap()`, `size()`, `max_size()`, and `empty()` member functions.
|
||||
- *Added*: The class uses **user-defined allocators** which default to `std::allocator`, but can be templated via parameter `Allocator`.
|
||||
- *Added:* To simplify pretty-printing, the `std::setw` **stream manipulator** has been overloaded to set the desired indentation. Pretty-printing a JSON object `j` is as simple as `std::cout << std::setw(4) << j << '\n'`.
|
||||
- *Changed*: The type `json::value_t::number` is now called `json::value_t::number_integer` to be more symmetric compared to `json::value_t::number_float`.
|
||||
- *Added*: The documentation is generated with Doxygen and hosted at [nlohmann.github.io/json](http://nlohmann.github.io/json/). Every public member function is thoroughly described including an example which also can be [tried online](http://melpon.org/wandbox/permlink/GnGKwji06WeVonlI).
|
||||
- *Added*: The class is heavily unit-tested (3341774 assertions) and has a [line coverage of 100%](https://coveralls.io/github/nlohmann/json). With every commit, the code is compiled with g++ 4.9, g++ 5.0, Clang 3.6 (thanks to [Travis CI](https://travis-ci.org/nlohmann/json)), and Microsoft Visual Studio 14 2015 (thanks to [AppVeyor](https://ci.appveyor.com/project/nlohmann/json)).
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
#---------------------------------------------------------------------------
|
||||
DOXYFILE_ENCODING = UTF-8
|
||||
PROJECT_NAME = "JSON for Modern C++"
|
||||
PROJECT_NUMBER = 1.0.0
|
||||
PROJECT_NUMBER = 2.0.0
|
||||
PROJECT_BRIEF =
|
||||
PROJECT_LOGO =
|
||||
OUTPUT_DIRECTORY = .
|
||||
|
||||
@ -1 +1 @@
|
||||
<a target="_blank" href="http://melpon.org/wandbox/permlink/GnGKwji06WeVonlI"><b>online</b></a>
|
||||
<a target="_blank" href="http://melpon.org/wandbox/permlink/vsDHoEGWuGiwM0oh"><b>online</b></a>
|
||||
@ -1,7 +1,7 @@
|
||||
null
|
||||
false
|
||||
0
|
||||
0
|
||||
0.0
|
||||
{}
|
||||
[]
|
||||
""
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
null
|
||||
false
|
||||
0
|
||||
0
|
||||
0.0
|
||||
{}
|
||||
[]
|
||||
""
|
||||
|
||||
@ -8,6 +8,7 @@ int main()
|
||||
json j_null;
|
||||
json j_boolean = true;
|
||||
json j_number_integer = 17;
|
||||
json j_number_unsigned_integer = 12345678987654321u;
|
||||
json j_number_float = 23.42;
|
||||
json j_object = {{"one", 1}, {"two", 2}};
|
||||
json j_array = {1, 2, 4, 8, 16};
|
||||
@ -18,6 +19,7 @@ int main()
|
||||
std::cout << j_null.is_array() << '\n';
|
||||
std::cout << j_boolean.is_array() << '\n';
|
||||
std::cout << j_number_integer.is_array() << '\n';
|
||||
std::cout << j_number_unsigned_integer.is_array() << '\n';
|
||||
std::cout << j_number_float.is_array() << '\n';
|
||||
std::cout << j_object.is_array() << '\n';
|
||||
std::cout << j_array.is_array() << '\n';
|
||||
|
||||
@ -1 +1 @@
|
||||
<a target="_blank" href="http://melpon.org/wandbox/permlink/pX9pR42isGha24Up"><b>online</b></a>
|
||||
<a target="_blank" href="http://melpon.org/wandbox/permlink/NTSNuQecVsmv3guC"><b>online</b></a>
|
||||
@ -3,5 +3,6 @@ false
|
||||
false
|
||||
false
|
||||
false
|
||||
false
|
||||
true
|
||||
false
|
||||
|
||||
@ -8,6 +8,7 @@ int main()
|
||||
json j_null;
|
||||
json j_boolean = true;
|
||||
json j_number_integer = 17;
|
||||
json j_number_unsigned_integer = 12345678987654321u;
|
||||
json j_number_float = 23.42;
|
||||
json j_object = {{"one", 1}, {"two", 2}};
|
||||
json j_array = {1, 2, 4, 8, 16};
|
||||
@ -18,6 +19,7 @@ int main()
|
||||
std::cout << j_null.is_boolean() << '\n';
|
||||
std::cout << j_boolean.is_boolean() << '\n';
|
||||
std::cout << j_number_integer.is_boolean() << '\n';
|
||||
std::cout << j_number_unsigned_integer.is_boolean() << '\n';
|
||||
std::cout << j_number_float.is_boolean() << '\n';
|
||||
std::cout << j_object.is_boolean() << '\n';
|
||||
std::cout << j_array.is_boolean() << '\n';
|
||||
|
||||
@ -1 +1 @@
|
||||
<a target="_blank" href="http://melpon.org/wandbox/permlink/yBDoHvFIsRqoo7Ca"><b>online</b></a>
|
||||
<a target="_blank" href="http://melpon.org/wandbox/permlink/3ZOet3bImwKg2vMb"><b>online</b></a>
|
||||
@ -5,3 +5,4 @@ false
|
||||
false
|
||||
false
|
||||
false
|
||||
false
|
||||
|
||||
@ -8,6 +8,7 @@ int main()
|
||||
json j_null;
|
||||
json j_boolean = true;
|
||||
json j_number_integer = 17;
|
||||
json j_number_unsigned_integer = 12345678987654321u;
|
||||
json j_number_float = 23.42;
|
||||
json j_object = {{"one", 1}, {"two", 2}};
|
||||
json j_array = {1, 2, 4, 8, 16};
|
||||
@ -18,6 +19,7 @@ int main()
|
||||
std::cout << j_null.is_discarded() << '\n';
|
||||
std::cout << j_boolean.is_discarded() << '\n';
|
||||
std::cout << j_number_integer.is_discarded() << '\n';
|
||||
std::cout << j_number_unsigned_integer.is_discarded() << '\n';
|
||||
std::cout << j_number_float.is_discarded() << '\n';
|
||||
std::cout << j_object.is_discarded() << '\n';
|
||||
std::cout << j_array.is_discarded() << '\n';
|
||||
|
||||
@ -1 +1 @@
|
||||
<a target="_blank" href="http://melpon.org/wandbox/permlink/Fz9sE7wOVCDCxuqw"><b>online</b></a>
|
||||
<a target="_blank" href="http://melpon.org/wandbox/permlink/a0c6rKo8VbeOBAmD"><b>online</b></a>
|
||||
@ -5,3 +5,4 @@ false
|
||||
false
|
||||
false
|
||||
false
|
||||
false
|
||||
|
||||
@ -8,6 +8,7 @@ int main()
|
||||
json j_null;
|
||||
json j_boolean = true;
|
||||
json j_number_integer = 17;
|
||||
json j_number_unsigned_integer = 12345678987654321u;
|
||||
json j_number_float = 23.42;
|
||||
json j_object = {{"one", 1}, {"two", 2}};
|
||||
json j_array = {1, 2, 4, 8, 16};
|
||||
@ -18,6 +19,7 @@ int main()
|
||||
std::cout << j_null.is_null() << '\n';
|
||||
std::cout << j_boolean.is_null() << '\n';
|
||||
std::cout << j_number_integer.is_null() << '\n';
|
||||
std::cout << j_number_unsigned_integer.is_null() << '\n';
|
||||
std::cout << j_number_float.is_null() << '\n';
|
||||
std::cout << j_object.is_null() << '\n';
|
||||
std::cout << j_array.is_null() << '\n';
|
||||
|
||||
@ -1 +1 @@
|
||||
<a target="_blank" href="http://melpon.org/wandbox/permlink/CwckRKEAALOpqiq7"><b>online</b></a>
|
||||
<a target="_blank" href="http://melpon.org/wandbox/permlink/z9pBPy4eSYMCZgEr"><b>online</b></a>
|
||||
@ -5,3 +5,4 @@ false
|
||||
false
|
||||
false
|
||||
false
|
||||
false
|
||||
|
||||
@ -8,6 +8,7 @@ int main()
|
||||
json j_null;
|
||||
json j_boolean = true;
|
||||
json j_number_integer = 17;
|
||||
json j_number_unsigned_integer = 12345678987654321u;
|
||||
json j_number_float = 23.42;
|
||||
json j_object = {{"one", 1}, {"two", 2}};
|
||||
json j_array = {1, 2, 4, 8, 16};
|
||||
@ -18,6 +19,7 @@ int main()
|
||||
std::cout << j_null.is_number() << '\n';
|
||||
std::cout << j_boolean.is_number() << '\n';
|
||||
std::cout << j_number_integer.is_number() << '\n';
|
||||
std::cout << j_number_unsigned_integer.is_number() << '\n';
|
||||
std::cout << j_number_float.is_number() << '\n';
|
||||
std::cout << j_object.is_number() << '\n';
|
||||
std::cout << j_array.is_number() << '\n';
|
||||
|
||||
@ -1 +1 @@
|
||||
<a target="_blank" href="http://melpon.org/wandbox/permlink/xVKMzHSvo4XHFyxV"><b>online</b></a>
|
||||
<a target="_blank" href="http://melpon.org/wandbox/permlink/1rel3xdea4ADiKds"><b>online</b></a>
|
||||
@ -2,6 +2,7 @@ false
|
||||
false
|
||||
true
|
||||
true
|
||||
true
|
||||
false
|
||||
false
|
||||
false
|
||||
|
||||
@ -8,6 +8,7 @@ int main()
|
||||
json j_null;
|
||||
json j_boolean = true;
|
||||
json j_number_integer = 17;
|
||||
json j_number_unsigned_integer = 12345678987654321u;
|
||||
json j_number_float = 23.42;
|
||||
json j_object = {{"one", 1}, {"two", 2}};
|
||||
json j_array = {1, 2, 4, 8, 16};
|
||||
@ -18,6 +19,7 @@ int main()
|
||||
std::cout << j_null.is_number_float() << '\n';
|
||||
std::cout << j_boolean.is_number_float() << '\n';
|
||||
std::cout << j_number_integer.is_number_float() << '\n';
|
||||
std::cout << j_number_unsigned_integer.is_number_float() << '\n';
|
||||
std::cout << j_number_float.is_number_float() << '\n';
|
||||
std::cout << j_object.is_number_float() << '\n';
|
||||
std::cout << j_array.is_number_float() << '\n';
|
||||
|
||||
@ -1 +1 @@
|
||||
<a target="_blank" href="http://melpon.org/wandbox/permlink/SbPvCBbOwWkIH5RX"><b>online</b></a>
|
||||
<a target="_blank" href="http://melpon.org/wandbox/permlink/vEZZNyL8GPbAfAsJ"><b>online</b></a>
|
||||
@ -1,6 +1,7 @@
|
||||
false
|
||||
false
|
||||
false
|
||||
false
|
||||
true
|
||||
false
|
||||
false
|
||||
|
||||
@ -8,6 +8,7 @@ int main()
|
||||
json j_null;
|
||||
json j_boolean = true;
|
||||
json j_number_integer = 17;
|
||||
json j_number_unsigned_integer = 12345678987654321u;
|
||||
json j_number_float = 23.42;
|
||||
json j_object = {{"one", 1}, {"two", 2}};
|
||||
json j_array = {1, 2, 4, 8, 16};
|
||||
@ -18,6 +19,7 @@ int main()
|
||||
std::cout << j_null.is_number_integer() << '\n';
|
||||
std::cout << j_boolean.is_number_integer() << '\n';
|
||||
std::cout << j_number_integer.is_number_integer() << '\n';
|
||||
std::cout << j_number_unsigned_integer.is_number_integer() << '\n';
|
||||
std::cout << j_number_float.is_number_integer() << '\n';
|
||||
std::cout << j_object.is_number_integer() << '\n';
|
||||
std::cout << j_array.is_number_integer() << '\n';
|
||||
|
||||
@ -1 +1 @@
|
||||
<a target="_blank" href="http://melpon.org/wandbox/permlink/CVMYqyeIFOKcBZZU"><b>online</b></a>
|
||||
<a target="_blank" href="http://melpon.org/wandbox/permlink/bulo75cZB0cPINgL"><b>online</b></a>
|
||||
@ -1,6 +1,7 @@
|
||||
false
|
||||
false
|
||||
true
|
||||
true
|
||||
false
|
||||
false
|
||||
false
|
||||
|
||||
27
doc/examples/is_number_unsigned.cpp
Normal file
27
doc/examples/is_number_unsigned.cpp
Normal file
@ -0,0 +1,27 @@
|
||||
#include <json.hpp>
|
||||
|
||||
using namespace nlohmann;
|
||||
|
||||
int main()
|
||||
{
|
||||
// create JSON values
|
||||
json j_null;
|
||||
json j_boolean = true;
|
||||
json j_number_integer = 17;
|
||||
json j_number_unsigned_integer = 12345678987654321u;
|
||||
json j_number_float = 23.42;
|
||||
json j_object = {{"one", 1}, {"two", 2}};
|
||||
json j_array = {1, 2, 4, 8, 16};
|
||||
json j_string = "Hello, world";
|
||||
|
||||
// call is_number_unsigned()
|
||||
std::cout << std::boolalpha;
|
||||
std::cout << j_null.is_number_unsigned() << '\n';
|
||||
std::cout << j_boolean.is_number_unsigned() << '\n';
|
||||
std::cout << j_number_integer.is_number_unsigned() << '\n';
|
||||
std::cout << j_number_unsigned_integer.is_number_unsigned() << '\n';
|
||||
std::cout << j_number_float.is_number_unsigned() << '\n';
|
||||
std::cout << j_object.is_number_unsigned() << '\n';
|
||||
std::cout << j_array.is_number_unsigned() << '\n';
|
||||
std::cout << j_string.is_number_unsigned() << '\n';
|
||||
}
|
||||
1
doc/examples/is_number_unsigned.link
Normal file
1
doc/examples/is_number_unsigned.link
Normal file
@ -0,0 +1 @@
|
||||
<a target="_blank" href="http://melpon.org/wandbox/permlink/h4s4VitQ3VmCOEXr"><b>online</b></a>
|
||||
8
doc/examples/is_number_unsigned.output
Normal file
8
doc/examples/is_number_unsigned.output
Normal file
@ -0,0 +1,8 @@
|
||||
false
|
||||
false
|
||||
false
|
||||
true
|
||||
false
|
||||
false
|
||||
false
|
||||
false
|
||||
@ -9,6 +9,7 @@ int main()
|
||||
json j_boolean = true;
|
||||
json j_number_integer = 17;
|
||||
json j_number_float = 23.42;
|
||||
json j_number_unsigned_integer = 12345678987654321u;
|
||||
json j_object = {{"one", 1}, {"two", 2}};
|
||||
json j_array = {1, 2, 4, 8, 16};
|
||||
json j_string = "Hello, world";
|
||||
@ -18,6 +19,7 @@ int main()
|
||||
std::cout << j_null.is_object() << '\n';
|
||||
std::cout << j_boolean.is_object() << '\n';
|
||||
std::cout << j_number_integer.is_object() << '\n';
|
||||
std::cout << j_number_unsigned_integer.is_object() << '\n';
|
||||
std::cout << j_number_float.is_object() << '\n';
|
||||
std::cout << j_object.is_object() << '\n';
|
||||
std::cout << j_array.is_object() << '\n';
|
||||
|
||||
@ -1 +1 @@
|
||||
<a target="_blank" href="http://melpon.org/wandbox/permlink/uXT6peoqwN6DIFAr"><b>online</b></a>
|
||||
<a target="_blank" href="http://melpon.org/wandbox/permlink/40lrBaplftujclBr"><b>online</b></a>
|
||||
@ -2,6 +2,7 @@ false
|
||||
false
|
||||
false
|
||||
false
|
||||
false
|
||||
true
|
||||
false
|
||||
false
|
||||
|
||||
@ -9,6 +9,7 @@ int main()
|
||||
json j_boolean = true;
|
||||
json j_number_integer = 17;
|
||||
json j_number_float = 23.42;
|
||||
json j_number_unsigned_integer = 12345678987654321u;
|
||||
json j_object = {{"one", 1}, {"two", 2}};
|
||||
json j_array = {1, 2, 4, 8, 16};
|
||||
json j_string = "Hello, world";
|
||||
@ -18,6 +19,7 @@ int main()
|
||||
std::cout << j_null.is_primitive() << '\n';
|
||||
std::cout << j_boolean.is_primitive() << '\n';
|
||||
std::cout << j_number_integer.is_primitive() << '\n';
|
||||
std::cout << j_number_unsigned_integer.is_primitive() << '\n';
|
||||
std::cout << j_number_float.is_primitive() << '\n';
|
||||
std::cout << j_object.is_primitive() << '\n';
|
||||
std::cout << j_array.is_primitive() << '\n';
|
||||
|
||||
@ -1 +1 @@
|
||||
<a target="_blank" href="http://melpon.org/wandbox/permlink/f5AMxY70IoQ4o0wb"><b>online</b></a>
|
||||
<a target="_blank" href="http://melpon.org/wandbox/permlink/zZYJHMvzYyYkNoAU"><b>online</b></a>
|
||||
@ -2,6 +2,7 @@ true
|
||||
true
|
||||
true
|
||||
true
|
||||
true
|
||||
false
|
||||
false
|
||||
true
|
||||
|
||||
@ -9,6 +9,7 @@ int main()
|
||||
json j_boolean = true;
|
||||
json j_number_integer = 17;
|
||||
json j_number_float = 23.42;
|
||||
json j_number_unsigned_integer = 12345678987654321u;
|
||||
json j_object = {{"one", 1}, {"two", 2}};
|
||||
json j_array = {1, 2, 4, 8, 16};
|
||||
json j_string = "Hello, world";
|
||||
@ -18,6 +19,7 @@ int main()
|
||||
std::cout << j_null.is_string() << '\n';
|
||||
std::cout << j_boolean.is_string() << '\n';
|
||||
std::cout << j_number_integer.is_string() << '\n';
|
||||
std::cout << j_number_unsigned_integer.is_string() << '\n';
|
||||
std::cout << j_number_float.is_string() << '\n';
|
||||
std::cout << j_object.is_string() << '\n';
|
||||
std::cout << j_array.is_string() << '\n';
|
||||
|
||||
@ -1 +1 @@
|
||||
<a target="_blank" href="http://melpon.org/wandbox/permlink/ILh5L9NsOSQ29Cg4"><b>online</b></a>
|
||||
<a target="_blank" href="http://melpon.org/wandbox/permlink/1x7B5XrHtV8RTROC"><b>online</b></a>
|
||||
@ -4,4 +4,5 @@ false
|
||||
false
|
||||
false
|
||||
false
|
||||
false
|
||||
true
|
||||
|
||||
@ -9,6 +9,7 @@ int main()
|
||||
json j_boolean = true;
|
||||
json j_number_integer = 17;
|
||||
json j_number_float = 23.42;
|
||||
json j_number_unsigned_integer = 12345678987654321u;
|
||||
json j_object = {{"one", 1}, {"two", 2}};
|
||||
json j_array = {1, 2, 4, 8, 16};
|
||||
json j_string = "Hello, world";
|
||||
@ -18,6 +19,7 @@ int main()
|
||||
std::cout << j_null.is_structured() << '\n';
|
||||
std::cout << j_boolean.is_structured() << '\n';
|
||||
std::cout << j_number_integer.is_structured() << '\n';
|
||||
std::cout << j_number_unsigned_integer.is_structured() << '\n';
|
||||
std::cout << j_number_float.is_structured() << '\n';
|
||||
std::cout << j_object.is_structured() << '\n';
|
||||
std::cout << j_array.is_structured() << '\n';
|
||||
|
||||
@ -1 +1 @@
|
||||
<a target="_blank" href="http://melpon.org/wandbox/permlink/D9WgQUo2eieU7kqs"><b>online</b></a>
|
||||
<a target="_blank" href="http://melpon.org/wandbox/permlink/kXpxIk6MP6OxEvwu"><b>online</b></a>
|
||||
@ -2,6 +2,7 @@ false
|
||||
false
|
||||
false
|
||||
false
|
||||
false
|
||||
true
|
||||
true
|
||||
false
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
[1,2,3] == [1,2,4] false
|
||||
{"A":"a","B":"b"} == {"A":"a","B":"b"} true
|
||||
17 == 17 true
|
||||
17 == 17.0 true
|
||||
"foo" == "bar" false
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
[1,2,3] == [1,2,4] true
|
||||
{"A":"a","B":"b"} == {"A":"a","B":"b"} false
|
||||
17 == 17 false
|
||||
17 == 17.0 false
|
||||
"foo" == "bar" true
|
||||
|
||||
455
src/json.hpp
455
src/json.hpp
@ -32,7 +32,7 @@ Class @ref nlohmann::basic_json is a good entry point for the documentation.
|
||||
@author [Niels Lohmann](http://nlohmann.me)
|
||||
@see https://github.com/nlohmann/json to download the source code
|
||||
|
||||
@version 1.0.0
|
||||
@version 2.0.0
|
||||
*/
|
||||
|
||||
#ifndef NLOHMANN_JSON_HPP
|
||||
@ -124,8 +124,8 @@ default; will be used in @ref string_t)
|
||||
in @ref boolean_t)
|
||||
@tparam NumberIntegerType type for JSON integer numbers (@c `int64_t` by
|
||||
default; will be used in @ref number_integer_t)
|
||||
@tparam NumberUnsignedType type for JSON unsigned integer numbers (@c `uint64_t` by
|
||||
default; will be used in @ref number_unsigned_t)
|
||||
@tparam NumberUnsignedType type for JSON unsigned integer numbers (@c
|
||||
`uint64_t` by default; will be used in @ref number_unsigned_t)
|
||||
@tparam NumberFloatType type for JSON floating-point numbers (@c `double` by
|
||||
default; will be used in @ref number_float_t)
|
||||
@tparam AllocatorType type of the allocator to use (@c `std::allocator` by
|
||||
@ -218,13 +218,11 @@ class basic_json
|
||||
|
||||
/// the type of an element reference
|
||||
using reference = value_type&;
|
||||
|
||||
/// the type of an element const reference
|
||||
using const_reference = const value_type&;
|
||||
|
||||
/// a type to represent differences between iterators
|
||||
using difference_type = std::ptrdiff_t;
|
||||
|
||||
/// a type to represent container sizes
|
||||
using size_type = std::size_t;
|
||||
|
||||
@ -340,6 +338,14 @@ class basic_json
|
||||
@sa @ref array_t -- type for an array value
|
||||
|
||||
@since version 1.0.0
|
||||
|
||||
@note The order name/value pairs are added to the object is *not* preserved
|
||||
by the library. Therefore, iterating an object may return name/value pairs
|
||||
in a different order than they were originally stored. In fact, keys will
|
||||
be traversed in alphabetical order as `std::map` with `std::less` is used
|
||||
by default. Please note this behavior conforms to [RFC
|
||||
7159](http://rfc7159.net/rfc7159), because any order implements the
|
||||
specified "unordered" nature of JSON objects.
|
||||
*/
|
||||
using object_t = ObjectType<StringType,
|
||||
basic_json,
|
||||
@ -582,11 +588,11 @@ class basic_json
|
||||
> An implementation may set limits on the range and precision of numbers.
|
||||
|
||||
When the default type is used, the maximal integer number that can be
|
||||
stored is `18446744073709551615` (UINT64_MAX) and the minimal integer number
|
||||
that can be stored is `0`. Integer numbers
|
||||
that are out of range will yield over/underflow when used in a constructor.
|
||||
During deserialization, too large or small integer numbers will be
|
||||
automatically be stored as @ref number_integer_t or @ref number_float_t.
|
||||
stored is `18446744073709551615` (UINT64_MAX) and the minimal integer
|
||||
number that can be stored is `0`. Integer numbers that are out of range
|
||||
will yield over/underflow when used in a constructor. During
|
||||
deserialization, too large or small integer numbers will be automatically
|
||||
be stored as @ref number_integer_t or @ref number_float_t.
|
||||
|
||||
[RFC 7159](http://rfc7159.net/rfc7159) further states:
|
||||
> Note that when such software is used, numbers that are integers and are
|
||||
@ -694,7 +700,7 @@ class basic_json
|
||||
|
||||
@since version 1.0.0
|
||||
*/
|
||||
enum class value_t : uint16_t
|
||||
enum class value_t : uint8_t
|
||||
{
|
||||
null, ///< null value
|
||||
object, ///< object (unordered set of name/value pairs)
|
||||
@ -704,12 +710,78 @@ class basic_json
|
||||
number_integer, ///< number value (integer)
|
||||
number_unsigned,///< number value (unsigned integer)
|
||||
number_float, ///< number value (floating-point)
|
||||
discarded, ///< discarded by the the parser callback function
|
||||
precision_mask = 0xFF
|
||||
discarded ///< discarded by the the parser callback function
|
||||
};
|
||||
|
||||
|
||||
private:
|
||||
|
||||
/*!
|
||||
@brief a type to hold JSON type information
|
||||
|
||||
This bitfield type holds information about JSON types. It is internally
|
||||
used to hold the basic JSON type enumeration, as well as additional
|
||||
information in the case of values that have been parsed from a string
|
||||
including whether of not it was created directly or parsed, and
|
||||
in the case of floating point numbers the number of significant
|
||||
figures in the original representaiton and if it was in exponential
|
||||
form, if a '+' was included in the exponent and the capitilization of
|
||||
the exponent marker. The sole purpose of this information is to permit
|
||||
accurate round trips.
|
||||
|
||||
@since version 2.0.0
|
||||
*/
|
||||
union type_data_t {
|
||||
struct {
|
||||
uint16_t type : 4;
|
||||
uint16_t parsed : 1;
|
||||
uint16_t has_exp : 1;
|
||||
uint16_t exp_plus : 1;
|
||||
uint16_t exp_cap : 1;
|
||||
uint16_t precision : 8;
|
||||
} bits;
|
||||
uint16_t data;
|
||||
|
||||
// Return the type
|
||||
value_t get() const
|
||||
{
|
||||
return static_cast<value_t>(bits.type);
|
||||
}
|
||||
|
||||
// Test type for equality (ignore other fields)
|
||||
bool operator==(const value_t& rhs) const
|
||||
{
|
||||
return static_cast<value_t>(bits.type) == rhs;
|
||||
}
|
||||
|
||||
// Assignment
|
||||
type_data_t & operator=(value_t rhs)
|
||||
{
|
||||
bits.type = static_cast<uint16_t>(rhs);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Construct from value_t
|
||||
type_data_t(value_t t) noexcept
|
||||
{
|
||||
*reinterpret_cast<uint16_t*>(this) = 0;
|
||||
bits.type = static_cast<uint16_t>(t);
|
||||
}
|
||||
|
||||
// Default constructor
|
||||
type_data_t() noexcept
|
||||
{
|
||||
data = 0;
|
||||
bits.type = reinterpret_cast<uint16_t>(value_t::null);
|
||||
}
|
||||
|
||||
// Copy constructor
|
||||
type_data_t(const type_data_t& t) noexcept
|
||||
{
|
||||
data = t.data;
|
||||
}
|
||||
};
|
||||
|
||||
/// helper for exception-safe object creation
|
||||
template<typename T, typename... Args>
|
||||
static T* create(Args&& ... args)
|
||||
@ -1366,8 +1438,8 @@ class basic_json
|
||||
|
||||
Create an unsigned number JSON value with a given content. This constructor
|
||||
allows any type that can be used to construct values of type @ref
|
||||
number_unsigned_t. Examples may include the types `unsigned int`, `uint32_t`,
|
||||
or `unsigned short`.
|
||||
number_unsigned_t. Examples may include the types `unsigned int`,
|
||||
`uint32_t`, or `unsigned short`.
|
||||
|
||||
@tparam CompatibleNumberUnsignedType an integer type which is compatible to
|
||||
@ref number_unsigned_t.
|
||||
@ -1381,13 +1453,13 @@ class basic_json
|
||||
|
||||
@since version 2.0.0
|
||||
*/
|
||||
template<typename CompatibleNumberUnsignedType, typename
|
||||
std::enable_if<
|
||||
std::is_constructible<number_unsigned_t, CompatibleNumberUnsignedType>::value and
|
||||
std::numeric_limits<CompatibleNumberUnsignedType>::is_integer and
|
||||
!std::numeric_limits<CompatibleNumberUnsignedType>::is_signed,
|
||||
CompatibleNumberUnsignedType>::type
|
||||
= 0>
|
||||
template < typename CompatibleNumberUnsignedType, typename
|
||||
std::enable_if <
|
||||
std::is_constructible<number_unsigned_t, CompatibleNumberUnsignedType>::value and
|
||||
std::numeric_limits<CompatibleNumberUnsignedType>::is_integer and
|
||||
!std::numeric_limits<CompatibleNumberUnsignedType>::is_signed,
|
||||
CompatibleNumberUnsignedType >::type
|
||||
= 0 >
|
||||
basic_json(const CompatibleNumberUnsignedType val) noexcept
|
||||
: m_type(value_t::number_unsigned),
|
||||
m_value(static_cast<number_unsigned_t>(val))
|
||||
@ -1747,7 +1819,7 @@ class basic_json
|
||||
}
|
||||
|
||||
// check if iterator range is complete for primitive values
|
||||
switch (static_cast<value_t>(static_cast<int>(m_type) & static_cast<int>(value_t::precision_mask)))
|
||||
switch (m_type.get())
|
||||
{
|
||||
case value_t::boolean:
|
||||
case value_t::number_float:
|
||||
@ -1768,7 +1840,7 @@ class basic_json
|
||||
}
|
||||
}
|
||||
|
||||
switch (static_cast<value_t>(static_cast<int>(m_type) & static_cast<int>(value_t::precision_mask)))
|
||||
switch (m_type.get())
|
||||
{
|
||||
case value_t::number_integer:
|
||||
{
|
||||
@ -1852,7 +1924,7 @@ class basic_json
|
||||
basic_json(const basic_json& other)
|
||||
: m_type(other.m_type)
|
||||
{
|
||||
switch (static_cast<value_t>(static_cast<int>(m_type) & static_cast<int>(value_t::precision_mask)))
|
||||
switch (m_type.get())
|
||||
{
|
||||
case value_t::object:
|
||||
{
|
||||
@ -1982,7 +2054,7 @@ class basic_json
|
||||
*/
|
||||
~basic_json()
|
||||
{
|
||||
switch (m_type)
|
||||
switch (m_type.get())
|
||||
{
|
||||
case value_t::object:
|
||||
{
|
||||
@ -2082,7 +2154,7 @@ class basic_json
|
||||
*/
|
||||
value_t type() const noexcept
|
||||
{
|
||||
return static_cast<value_t>(static_cast<int>(m_type) & static_cast<int>(value_t::precision_mask));
|
||||
return m_type.get();
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -2180,7 +2252,8 @@ class basic_json
|
||||
|
||||
@sa @ref is_number_integer() -- check if value is an integer or unsigned
|
||||
integer number
|
||||
@sa @ref is_number_unsigned() -- check if value is an unsigned integer number
|
||||
@sa @ref is_number_unsigned() -- check if value is an unsigned integer
|
||||
number
|
||||
@sa @ref is_number_float() -- check if value is a floating-point number
|
||||
|
||||
@since version 1.0.0
|
||||
@ -2205,7 +2278,8 @@ class basic_json
|
||||
JSON types.,is_number_integer}
|
||||
|
||||
@sa @ref is_number() -- check if value is a number
|
||||
@sa @ref is_number_unsigned() -- check if value is an unsigned integer number
|
||||
@sa @ref is_number_unsigned() -- check if value is an unsigned integer
|
||||
number
|
||||
@sa @ref is_number_float() -- check if value is a floating-point number
|
||||
|
||||
@since version 1.0.0
|
||||
@ -2218,13 +2292,16 @@ class basic_json
|
||||
/*!
|
||||
@brief return whether value is an unsigned integer number
|
||||
|
||||
This function returns true iff the JSON value is an unsigned integer number.
|
||||
This excludes floating-point and (signed) integer values.
|
||||
This function returns true iff the JSON value is an unsigned integer
|
||||
number. This excludes floating-point and (signed) integer values.
|
||||
|
||||
@return `true` if type is an unsigned integer number, `false` otherwise.
|
||||
|
||||
@complexity Constant.
|
||||
|
||||
@liveexample{The following code exemplifies @ref is_number_unsigned for all
|
||||
JSON types.,is_number_unsigned}
|
||||
|
||||
@sa @ref is_number() -- check if value is a number
|
||||
@sa @ref is_number_integer() -- check if value is an integer or unsigned
|
||||
integer number
|
||||
@ -2252,13 +2329,14 @@ class basic_json
|
||||
|
||||
@sa @ref is_number() -- check if value is number
|
||||
@sa @ref is_number_integer() -- check if value is an integer number
|
||||
@sa @ref is_number_unsigned() -- check if value is an unsigned integer number
|
||||
@sa @ref is_number_unsigned() -- check if value is an unsigned integer
|
||||
number
|
||||
|
||||
@since version 1.0.0
|
||||
*/
|
||||
bool is_number_float() const noexcept
|
||||
{
|
||||
return (static_cast<value_t>(static_cast<int>(m_type) & static_cast<int>(value_t::precision_mask))) == value_t::number_float;
|
||||
return m_type == value_t::number_float;
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -2359,7 +2437,7 @@ class basic_json
|
||||
*/
|
||||
operator value_t() const noexcept
|
||||
{
|
||||
return (static_cast<value_t>(static_cast<int>(m_type) & static_cast<int>(value_t::precision_mask)));
|
||||
return m_type.get();
|
||||
}
|
||||
|
||||
/// @}
|
||||
@ -2514,7 +2592,7 @@ class basic_json
|
||||
, int>::type = 0>
|
||||
T get_impl(T*) const
|
||||
{
|
||||
switch (static_cast<value_t>(static_cast<int>(m_type) & static_cast<int>(value_t::precision_mask)))
|
||||
switch (m_type.get())
|
||||
{
|
||||
case value_t::number_integer:
|
||||
{
|
||||
@ -2835,7 +2913,7 @@ class basic_json
|
||||
|
||||
@liveexample{The example shows several calls to `get_ref()`.,get_ref}
|
||||
|
||||
@since version 1.0.1
|
||||
@since version 1.1.0
|
||||
*/
|
||||
template<typename ReferenceType, typename
|
||||
std::enable_if<
|
||||
@ -2890,14 +2968,14 @@ class basic_json
|
||||
|
||||
@since version 1.0.0
|
||||
*/
|
||||
template<typename ValueType, typename
|
||||
std::enable_if<
|
||||
not std::is_pointer<ValueType>::value
|
||||
and not std::is_same<ValueType, typename string_t::value_type>::value
|
||||
template < typename ValueType, typename
|
||||
std::enable_if <
|
||||
not std::is_pointer<ValueType>::value
|
||||
and not std::is_same<ValueType, typename string_t::value_type>::value
|
||||
#ifndef _MSC_VER // Fix for issue #167 operator<< abiguity under VS2015
|
||||
and not std::is_same<ValueType, std::initializer_list<typename string_t::value_type>>::value
|
||||
and not std::is_same<ValueType, std::initializer_list<typename string_t::value_type>>::value
|
||||
#endif
|
||||
, int>::type = 0>
|
||||
, int >::type = 0 >
|
||||
operator ValueType() const
|
||||
{
|
||||
// delegate the call to get<>() const
|
||||
@ -3365,7 +3443,7 @@ class basic_json
|
||||
with range checking
|
||||
@sa @ref value() for access by value with a default value
|
||||
|
||||
@since version 1.0.1
|
||||
@since version 1.1.0
|
||||
*/
|
||||
template<typename T>
|
||||
reference operator[](T* key)
|
||||
@ -3414,7 +3492,7 @@ class basic_json
|
||||
with range checking
|
||||
@sa @ref value() for access by value with a default value
|
||||
|
||||
@since version 1.0.1
|
||||
@since version 1.1.0
|
||||
*/
|
||||
template<typename T>
|
||||
const_reference operator[](T* key) const
|
||||
@ -3646,7 +3724,7 @@ class basic_json
|
||||
|
||||
InteratorType result = end();
|
||||
|
||||
switch (static_cast<value_t>(static_cast<int>(m_type) & static_cast<int>(value_t::precision_mask)))
|
||||
switch (m_type.get())
|
||||
{
|
||||
case value_t::boolean:
|
||||
case value_t::number_float:
|
||||
@ -3665,7 +3743,7 @@ class basic_json
|
||||
m_value.string = nullptr;
|
||||
}
|
||||
|
||||
m_type = value_t::null;
|
||||
m_type = type_data_t(value_t::null);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -3752,7 +3830,7 @@ class basic_json
|
||||
|
||||
InteratorType result = end();
|
||||
|
||||
switch (static_cast<value_t>(static_cast<int>(m_type) & static_cast<int>(value_t::precision_mask)))
|
||||
switch (m_type.get())
|
||||
{
|
||||
case value_t::boolean:
|
||||
case value_t::number_float:
|
||||
@ -3771,7 +3849,7 @@ class basic_json
|
||||
m_value.string = nullptr;
|
||||
}
|
||||
|
||||
m_type = value_t::null;
|
||||
m_type = type_data_t(value_t::null);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -4260,7 +4338,7 @@ class basic_json
|
||||
*/
|
||||
bool empty() const noexcept
|
||||
{
|
||||
switch (m_type)
|
||||
switch (m_type.get())
|
||||
{
|
||||
case value_t::null:
|
||||
{
|
||||
@ -4318,7 +4396,7 @@ class basic_json
|
||||
*/
|
||||
size_type size() const noexcept
|
||||
{
|
||||
switch (m_type)
|
||||
switch (m_type.get())
|
||||
{
|
||||
case value_t::null:
|
||||
{
|
||||
@ -4380,7 +4458,7 @@ class basic_json
|
||||
*/
|
||||
size_type max_size() const noexcept
|
||||
{
|
||||
switch (m_type)
|
||||
switch (m_type.get())
|
||||
{
|
||||
case value_t::array:
|
||||
{
|
||||
@ -4439,7 +4517,7 @@ class basic_json
|
||||
*/
|
||||
void clear() noexcept
|
||||
{
|
||||
switch (m_type)
|
||||
switch (m_type.get())
|
||||
{
|
||||
case value_t::number_integer:
|
||||
{
|
||||
@ -4532,7 +4610,7 @@ class basic_json
|
||||
assert(m_value.array != nullptr);
|
||||
m_value.array->push_back(std::move(val));
|
||||
// invalidate object
|
||||
val.m_type = value_t::null;
|
||||
val.m_type = type_data_t(value_t::null);
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -5557,7 +5635,7 @@ class basic_json
|
||||
/// return the type as string
|
||||
string_t type_name() const
|
||||
{
|
||||
switch (m_type)
|
||||
switch (m_type.get())
|
||||
{
|
||||
case value_t::null:
|
||||
return "null";
|
||||
@ -5763,7 +5841,7 @@ class basic_json
|
||||
// variable to hold indentation for recursive calls
|
||||
unsigned int new_indent = current_indent;
|
||||
|
||||
switch (static_cast<value_t>(static_cast<int>(m_type) & static_cast<int>(value_t::precision_mask)))
|
||||
switch (m_type.get())
|
||||
{
|
||||
case value_t::object:
|
||||
{
|
||||
@ -5874,25 +5952,58 @@ class basic_json
|
||||
|
||||
case value_t::number_float:
|
||||
{
|
||||
// If the number was parsed from a string use the same precision
|
||||
// otherwise 15 digits of precision allows round-trip IEEE 754
|
||||
// string->double->string; to be safe, we read this value from
|
||||
// std::numeric_limits<number_float_t>::digits10
|
||||
int precision = static_cast<int>(m_type) >> 8;
|
||||
if (!precision) precision = std::numeric_limits<double>::digits10;
|
||||
// Buffer size: precision (2^8-1 = 255) + other ('-.e-xxx' = 7) + null (1)
|
||||
char buf[263];
|
||||
int len;
|
||||
|
||||
// Special case for zero - use fixed precision to get "0.0"
|
||||
if (m_value.number_float == 0)
|
||||
if (m_type.bits.parsed)
|
||||
{
|
||||
// Number was parsed from a string so use the same precision
|
||||
if (m_type.bits.has_exp)
|
||||
{
|
||||
o << std::fixed << std::setprecision(1);
|
||||
// Exponent - output in exponential form - handle capitalization of e/E
|
||||
if (m_type.bits.exp_cap)
|
||||
{
|
||||
len = snprintf(buf, sizeof(buf), "%.*E", m_type.bits.precision, m_value.number_float) + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
len = snprintf(buf, sizeof(buf), "%.*e", m_type.bits.precision, m_value.number_float) + 1;
|
||||
}
|
||||
|
||||
// Remove '+' sign from the exponent if necessary
|
||||
if (!m_type.bits.exp_plus)
|
||||
{
|
||||
if (static_cast<size_t>(len) > sizeof(buf)) len = sizeof(buf);
|
||||
for (size_t i = 0; i < static_cast<size_t>(len); i++)
|
||||
{
|
||||
if (buf[i] == '+')
|
||||
{
|
||||
for (; i + 1 < static_cast<size_t>(len); i++) buf[i] = buf[i + 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// std::defaultfloat not supported in gcc version < 5
|
||||
o.unsetf(std::ios_base::floatfield);
|
||||
o << std::setprecision(precision);
|
||||
// No exponent - output as a decimal
|
||||
snprintf(buf, sizeof(buf), "%.*f", m_type.bits.precision, m_value.number_float);
|
||||
}
|
||||
o << m_value.number_float;
|
||||
}
|
||||
else if (m_value.number_float == 0)
|
||||
{
|
||||
// Special case for zero - use fixed precision to get "0.0"
|
||||
snprintf(buf, sizeof(buf), "%#.1f", m_value.number_float);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Otherwise 15 digits of precision allows round-trip IEEE 754
|
||||
// string->double->string; to be safe, we read this value from
|
||||
// std::numeric_limits<number_float_t>::digits10
|
||||
snprintf(buf, sizeof(buf), "%.*g", std::numeric_limits<double>::digits10, m_value.number_float);
|
||||
}
|
||||
|
||||
o << buf;
|
||||
return;
|
||||
}
|
||||
|
||||
@ -5916,7 +6027,7 @@ class basic_json
|
||||
//////////////////////
|
||||
|
||||
/// the type of the current element
|
||||
value_t m_type = value_t::null;
|
||||
type_data_t m_type = type_data_t(value_t::null);
|
||||
|
||||
/// the value of the current element
|
||||
json_value m_value = {};
|
||||
@ -6140,7 +6251,7 @@ class basic_json
|
||||
{
|
||||
assert(m_object != nullptr);
|
||||
|
||||
switch (m_object->m_type)
|
||||
switch (m_object->m_type.get())
|
||||
{
|
||||
case basic_json::value_t::object:
|
||||
{
|
||||
@ -6167,7 +6278,7 @@ class basic_json
|
||||
{
|
||||
assert(m_object != nullptr);
|
||||
|
||||
switch (m_object->m_type)
|
||||
switch (m_object->m_type.get())
|
||||
{
|
||||
case basic_json::value_t::object:
|
||||
{
|
||||
@ -6213,7 +6324,7 @@ class basic_json
|
||||
{
|
||||
assert(m_object != nullptr);
|
||||
|
||||
switch (m_object->m_type)
|
||||
switch (m_object->m_type.get())
|
||||
{
|
||||
case basic_json::value_t::object:
|
||||
{
|
||||
@ -6249,7 +6360,7 @@ class basic_json
|
||||
{
|
||||
assert(m_object != nullptr);
|
||||
|
||||
switch (m_object->m_type)
|
||||
switch (m_object->m_type.get())
|
||||
{
|
||||
case basic_json::value_t::object:
|
||||
{
|
||||
@ -6279,7 +6390,7 @@ class basic_json
|
||||
{
|
||||
assert(m_object != nullptr);
|
||||
|
||||
switch (m_object->m_type)
|
||||
switch (m_object->m_type.get())
|
||||
{
|
||||
case basic_json::value_t::object:
|
||||
{
|
||||
@ -6319,7 +6430,7 @@ class basic_json
|
||||
{
|
||||
assert(m_object != nullptr);
|
||||
|
||||
switch (m_object->m_type)
|
||||
switch (m_object->m_type.get())
|
||||
{
|
||||
case basic_json::value_t::object:
|
||||
{
|
||||
@ -6362,7 +6473,7 @@ class basic_json
|
||||
{
|
||||
assert(m_object != nullptr);
|
||||
|
||||
switch (m_object->m_type)
|
||||
switch (m_object->m_type.get())
|
||||
{
|
||||
case basic_json::value_t::object:
|
||||
{
|
||||
@ -6399,7 +6510,7 @@ class basic_json
|
||||
{
|
||||
assert(m_object != nullptr);
|
||||
|
||||
switch (m_object->m_type)
|
||||
switch (m_object->m_type.get())
|
||||
{
|
||||
case basic_json::value_t::object:
|
||||
{
|
||||
@ -6434,7 +6545,7 @@ class basic_json
|
||||
|
||||
assert(m_object != nullptr);
|
||||
|
||||
switch (m_object->m_type)
|
||||
switch (m_object->m_type.get())
|
||||
{
|
||||
case basic_json::value_t::object:
|
||||
{
|
||||
@ -6470,7 +6581,7 @@ class basic_json
|
||||
|
||||
assert(m_object != nullptr);
|
||||
|
||||
switch (m_object->m_type)
|
||||
switch (m_object->m_type.get())
|
||||
{
|
||||
case basic_json::value_t::object:
|
||||
{
|
||||
@ -6512,7 +6623,7 @@ class basic_json
|
||||
{
|
||||
assert(m_object != nullptr);
|
||||
|
||||
switch (m_object->m_type)
|
||||
switch (m_object->m_type.get())
|
||||
{
|
||||
case basic_json::value_t::object:
|
||||
{
|
||||
@ -6562,7 +6673,7 @@ class basic_json
|
||||
{
|
||||
assert(m_object != nullptr);
|
||||
|
||||
switch (m_object->m_type)
|
||||
switch (m_object->m_type.get())
|
||||
{
|
||||
case basic_json::value_t::object:
|
||||
{
|
||||
@ -6586,7 +6697,7 @@ class basic_json
|
||||
{
|
||||
assert(m_object != nullptr);
|
||||
|
||||
switch (m_object->m_type)
|
||||
switch (m_object->m_type.get())
|
||||
{
|
||||
case basic_json::value_t::object:
|
||||
{
|
||||
@ -7654,10 +7765,10 @@ basic_json_parser_64:
|
||||
|
||||
@return the floating point number
|
||||
|
||||
@warning This function uses `std::strtof`, `std::strtod`, or
|
||||
`std::strtold` which use the current C locale to determine which
|
||||
character is used as decimal point character. This may yield to parse
|
||||
errors if the locale does not used `.`.
|
||||
@bug This function uses `std::strtof`, `std::strtod`, or `std::strtold`
|
||||
which use the current C locale to determine which character is used as
|
||||
decimal point character. This may yield to parse errors if the locale
|
||||
does not used `.`.
|
||||
*/
|
||||
long double str_to_float_t(long double* /* type */, char** endptr) const
|
||||
{
|
||||
@ -7715,42 +7826,104 @@ basic_json_parser_64:
|
||||
@return @a true if the cast was performed without error, @a false otherwise
|
||||
*/
|
||||
template <typename T_A, typename T_B>
|
||||
bool attempt_cast(T_A source, T_B & dest) const
|
||||
bool attempt_cast(T_A source, T_B& dest) const
|
||||
{
|
||||
dest = static_cast<T_B>(source);
|
||||
return (source == static_cast<T_A>(dest));
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief peek ahead and guess the number type and floating point representation
|
||||
|
||||
This function scans the number to identify the number type. In addition it
|
||||
counts the significant figures after the decimal point, whether the
|
||||
number is in exponential or decimal form, the capitalization of the
|
||||
exponent marker, and if the optional '+' is present in the exponent. This
|
||||
information is necessary to perform accurate round trips of floating point
|
||||
numbers.
|
||||
|
||||
@param[out] type @ref type_data_t object to receive the type information.
|
||||
*/
|
||||
void guess_type(type_data_t & type) const
|
||||
{
|
||||
const lexer::lexer_char_t *curptr = m_start;
|
||||
type.bits.parsed = true;
|
||||
|
||||
uint8_t found_radix_point = 0;
|
||||
uint8_t precision = 0;
|
||||
|
||||
// Look for sign
|
||||
if (*curptr == '-') {
|
||||
type = value_t::number_integer;
|
||||
curptr++;
|
||||
}
|
||||
else {
|
||||
type = value_t::number_unsigned;
|
||||
if (*curptr == '+') curptr++;
|
||||
}
|
||||
|
||||
// Count the significant figures
|
||||
for (; curptr < m_cursor; curptr++)
|
||||
{
|
||||
|
||||
// Quickly skip tests if a digit
|
||||
if (*curptr < '0' || *curptr > '9')
|
||||
{
|
||||
if (*curptr == '.')
|
||||
{
|
||||
// Don't count '.' but change to float
|
||||
type = value_t::number_float;
|
||||
|
||||
// Reset precision count
|
||||
precision = 0;
|
||||
found_radix_point = 0xFF;
|
||||
continue;
|
||||
}
|
||||
// Assume exponent (if not it is a bad number and will fail
|
||||
// parse anyway - could throw here instead): change to
|
||||
// float, stop counting and record exponent details
|
||||
type = value_t::number_float;
|
||||
type.bits.has_exp = true;
|
||||
|
||||
// Exponent capitalization
|
||||
type.bits.exp_cap = (*curptr == 'E');
|
||||
|
||||
// Exponent '+' sign
|
||||
type.bits.exp_plus = (*(++curptr) == '+');
|
||||
break;
|
||||
}
|
||||
precision++;
|
||||
}
|
||||
|
||||
// If no radix was found then precision would now be set to
|
||||
// the number of digits, which is wrong - clear it
|
||||
type.bits.precision = precision & found_radix_point;
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief return number value for number tokens
|
||||
|
||||
This function translates the last token into the most appropriate
|
||||
number type (either integer, unsigned integer or floating point),
|
||||
which is passed back to the caller via the result parameter. The pointer
|
||||
@a m_start points to the beginning of the parsed number. We first examine
|
||||
the first character to determine the sign of the number and then pass
|
||||
this pointer to either @a std::strtoull (if positive) or @a std::strtoll
|
||||
(if negative), both of which set @a endptr to the first character past the
|
||||
converted number. If this pointer is not the same as @a m_cursor, then
|
||||
either more or less characters have been used during the comparison.
|
||||
This function translates the last token into the most appropriate number
|
||||
type (either integer, unsigned integer or floating point), which is
|
||||
passed back to the caller via the result parameter.
|
||||
|
||||
This can happen for inputs like "01" which will be treated like number 0
|
||||
followed by number 1. This will also occur for valid floating point
|
||||
inputs like "12e3" will be incorrectly read as 12. Numbers that are too
|
||||
large or too small for a signed/unsigned long long will cause a range
|
||||
error (@a errno set to ERANGE). The parsed number is cast to a @ref
|
||||
number_integer_t/@ref number_unsigned_t using the helper function @ref attempt_cast,
|
||||
which returns @a false if the cast could not be peformed without error.
|
||||
First @ref guess_type() is called to determine the type and to retrieve
|
||||
information about the floating point representation (if applicable)
|
||||
that can be used to accurately render the number to a string later.
|
||||
|
||||
In any of these cases (more/less characters read, range error or a cast
|
||||
error) the pointer is passed to @a std:strtod, which also sets @a endptr to the
|
||||
first character past the converted number. The resulting @ref number_float_t
|
||||
is then cast to a @ref number_integer_t/@ref number_unsigned_t using
|
||||
@ref attempt_cast and if no error occurs is stored in that form, otherwise
|
||||
it is stored as a @ref number_float_t.
|
||||
Depending on the type, either @a std::strtoull (if number_unsigned_t) or
|
||||
@a std::strtoll (if number_integer_t) is then called to attempt to parse the
|
||||
number as an integer. Numbers that are too large or too small for a
|
||||
signed/unsigned long long will cause a range error (@a errno set to ERANGE).
|
||||
The parsed number is cast to a @ref number_integer_t/@ref number_unsigned_t
|
||||
using the helper function @ref attempt_cast, which returns @a false if the
|
||||
cast could not be peformed without error.
|
||||
|
||||
A final comparison is made of @a endptr and if still not the same as
|
||||
@ref m_cursor a bad input is assumed and @a result parameter is set to NAN.
|
||||
In either of these cases (range error or a cast error) the number is parsed
|
||||
using @a std:strtod (or @a std:strtof or @a std::strtold), which sets
|
||||
@a endptr to the first character past the converted number. If it is not
|
||||
the same as @ref m_cursor a bad input is assumed and @a result parameter is
|
||||
set to NAN.
|
||||
|
||||
@param[out] result @ref basic_json object to receive the number, or NAN if the
|
||||
conversion read past the current token. The latter case needs to be
|
||||
@ -7760,72 +7933,48 @@ basic_json_parser_64:
|
||||
{
|
||||
assert(m_start != nullptr);
|
||||
|
||||
// Count the significant figures
|
||||
int precision = 0;
|
||||
{
|
||||
const lexer::lexer_char_t *curptr;
|
||||
|
||||
// Assume unsigned integer for now
|
||||
result.m_type = value_t::number_unsigned;
|
||||
for (curptr = m_start; curptr < m_cursor; curptr++) {
|
||||
switch (*curptr) {
|
||||
case '-':
|
||||
// Found minus sign: change to integer
|
||||
result.m_type = value_t::number_integer;
|
||||
case '.':
|
||||
// Don't count either '.' or '-'
|
||||
continue;
|
||||
case 'e':
|
||||
case 'E':
|
||||
// Found exponent: change to float and stop counting
|
||||
result.m_type = value_t::number_float;
|
||||
break;
|
||||
default:
|
||||
// Found a signficant figure
|
||||
precision++;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Characters after number - shouldn't happen, but try parsing as float
|
||||
if (curptr != m_cursor) result.m_type = value_t::number_float;
|
||||
}
|
||||
guess_type(result.m_type);
|
||||
|
||||
errno = 0;
|
||||
typename string_t::value_type* endptr = 0;
|
||||
|
||||
// Attempt to parse it as an integer - first checking for a negative number
|
||||
// Attempt to parse it as an integer
|
||||
if (result.m_type == value_t::number_unsigned)
|
||||
{
|
||||
// Positive, parse with strtoull and attempt cast to number_unsigned_t
|
||||
if (!attempt_cast(std::strtoull(reinterpret_cast<typename string_t::const_pointer>(m_start), &endptr, 10), result.m_value.number_unsigned))
|
||||
if (!attempt_cast(std::strtoull(reinterpret_cast<typename string_t::const_pointer>(m_start), NULL,
|
||||
10), result.m_value.number_unsigned))
|
||||
{
|
||||
result.m_type = value_t::number_float; // Cast failed due to overflow - store as float
|
||||
}
|
||||
}
|
||||
else if (result.m_type == value_t::number_integer)
|
||||
{
|
||||
// Negative, parse with strtoll and attempt cast to number_integer_t
|
||||
if (!attempt_cast(std::strtoll(reinterpret_cast<typename string_t::const_pointer>(m_start), &endptr, 10), result.m_value.number_unsigned))
|
||||
if (!attempt_cast(std::strtoll(reinterpret_cast<typename string_t::const_pointer>(m_start), NULL,
|
||||
10), result.m_value.number_integer))
|
||||
{
|
||||
result.m_type = value_t::number_float; // Cast failed due to overflow - store as float
|
||||
}
|
||||
}
|
||||
|
||||
// Check the end of the number was reached and no range error occurred
|
||||
if (reinterpret_cast<lexer_char_t*>(endptr) != m_cursor || errno == ERANGE) result.m_type = value_t::number_float;
|
||||
if (errno == ERANGE) result.m_type = value_t::number_float;
|
||||
|
||||
if (result.m_type == value_t::number_float)
|
||||
{
|
||||
// Either the number won't fit in an integer (range error from strtoull/strtoll or overflow on cast) or there was
|
||||
// something else after the number, which could be an exponent
|
||||
// Either the number won't fit in an integer (range error from
|
||||
// strtoull/strtoll or overflow on cast) or there was something
|
||||
// else after the number, which could be an exponent
|
||||
|
||||
// Parse with strtod
|
||||
typename string_t::value_type* endptr;
|
||||
result.m_value.number_float = str_to_float_t(static_cast<number_float_t*>(nullptr), &endptr);
|
||||
|
||||
// Add the precision bits
|
||||
result.m_type = static_cast<value_t>(static_cast<int>(result.m_type) | (precision << 8));
|
||||
|
||||
// Anything after the number is an error
|
||||
if (reinterpret_cast<lexer_char_t*>(endptr) != m_cursor && *m_cursor != '.')
|
||||
{
|
||||
throw std::invalid_argument(std::string("parse error - ") + get_token() + " is not a number");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -8197,5 +8346,3 @@ inline nlohmann::json operator "" _json(const char* s, std::size_t)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
@ -32,7 +32,7 @@ Class @ref nlohmann::basic_json is a good entry point for the documentation.
|
||||
@author [Niels Lohmann](http://nlohmann.me)
|
||||
@see https://github.com/nlohmann/json to download the source code
|
||||
|
||||
@version 1.0.0
|
||||
@version 2.0.0
|
||||
*/
|
||||
|
||||
#ifndef NLOHMANN_JSON_HPP
|
||||
@ -124,8 +124,8 @@ default; will be used in @ref string_t)
|
||||
in @ref boolean_t)
|
||||
@tparam NumberIntegerType type for JSON integer numbers (@c `int64_t` by
|
||||
default; will be used in @ref number_integer_t)
|
||||
@tparam NumberUnsignedType type for JSON unsigned integer numbers (@c `uint64_t` by
|
||||
default; will be used in @ref number_unsigned_t)
|
||||
@tparam NumberUnsignedType type for JSON unsigned integer numbers (@c
|
||||
`uint64_t` by default; will be used in @ref number_unsigned_t)
|
||||
@tparam NumberFloatType type for JSON floating-point numbers (@c `double` by
|
||||
default; will be used in @ref number_float_t)
|
||||
@tparam AllocatorType type of the allocator to use (@c `std::allocator` by
|
||||
@ -218,13 +218,11 @@ class basic_json
|
||||
|
||||
/// the type of an element reference
|
||||
using reference = value_type&;
|
||||
|
||||
/// the type of an element const reference
|
||||
using const_reference = const value_type&;
|
||||
|
||||
/// a type to represent differences between iterators
|
||||
using difference_type = std::ptrdiff_t;
|
||||
|
||||
/// a type to represent container sizes
|
||||
using size_type = std::size_t;
|
||||
|
||||
@ -340,6 +338,14 @@ class basic_json
|
||||
@sa @ref array_t -- type for an array value
|
||||
|
||||
@since version 1.0.0
|
||||
|
||||
@note The order name/value pairs are added to the object is *not* preserved
|
||||
by the library. Therefore, iterating an object may return name/value pairs
|
||||
in a different order than they were originally stored. In fact, keys will
|
||||
be traversed in alphabetical order as `std::map` with `std::less` is used
|
||||
by default. Please note this behavior conforms to [RFC
|
||||
7159](http://rfc7159.net/rfc7159), because any order implements the
|
||||
specified "unordered" nature of JSON objects.
|
||||
*/
|
||||
using object_t = ObjectType<StringType,
|
||||
basic_json,
|
||||
@ -582,11 +588,11 @@ class basic_json
|
||||
> An implementation may set limits on the range and precision of numbers.
|
||||
|
||||
When the default type is used, the maximal integer number that can be
|
||||
stored is `18446744073709551615` (UINT64_MAX) and the minimal integer number
|
||||
that can be stored is `0`. Integer numbers
|
||||
that are out of range will yield over/underflow when used in a constructor.
|
||||
During deserialization, too large or small integer numbers will be
|
||||
automatically be stored as @ref number_integer_t or @ref number_float_t.
|
||||
stored is `18446744073709551615` (UINT64_MAX) and the minimal integer
|
||||
number that can be stored is `0`. Integer numbers that are out of range
|
||||
will yield over/underflow when used in a constructor. During
|
||||
deserialization, too large or small integer numbers will be automatically
|
||||
be stored as @ref number_integer_t or @ref number_float_t.
|
||||
|
||||
[RFC 7159](http://rfc7159.net/rfc7159) further states:
|
||||
> Note that when such software is used, numbers that are integers and are
|
||||
@ -694,7 +700,7 @@ class basic_json
|
||||
|
||||
@since version 1.0.0
|
||||
*/
|
||||
enum class value_t : uint16_t
|
||||
enum class value_t : uint8_t
|
||||
{
|
||||
null, ///< null value
|
||||
object, ///< object (unordered set of name/value pairs)
|
||||
@ -704,12 +710,78 @@ class basic_json
|
||||
number_integer, ///< number value (integer)
|
||||
number_unsigned,///< number value (unsigned integer)
|
||||
number_float, ///< number value (floating-point)
|
||||
discarded, ///< discarded by the the parser callback function
|
||||
precision_mask = 0xFF
|
||||
discarded ///< discarded by the the parser callback function
|
||||
};
|
||||
|
||||
|
||||
private:
|
||||
|
||||
/*!
|
||||
@brief a type to hold JSON type information
|
||||
|
||||
This bitfield type holds information about JSON types. It is internally
|
||||
used to hold the basic JSON type enumeration, as well as additional
|
||||
information in the case of values that have been parsed from a string
|
||||
including whether of not it was created directly or parsed, and
|
||||
in the case of floating point numbers the number of significant
|
||||
figures in the original representaiton and if it was in exponential
|
||||
form, if a '+' was included in the exponent and the capitilization of
|
||||
the exponent marker. The sole purpose of this information is to permit
|
||||
accurate round trips.
|
||||
|
||||
@since version 2.0.0
|
||||
*/
|
||||
union type_data_t {
|
||||
struct {
|
||||
uint16_t type : 4;
|
||||
uint16_t parsed : 1;
|
||||
uint16_t has_exp : 1;
|
||||
uint16_t exp_plus : 1;
|
||||
uint16_t exp_cap : 1;
|
||||
uint16_t precision : 8;
|
||||
} bits;
|
||||
uint16_t data;
|
||||
|
||||
// Return the type
|
||||
value_t get() const
|
||||
{
|
||||
return static_cast<value_t>(bits.type);
|
||||
}
|
||||
|
||||
// Test type for equality (ignore other fields)
|
||||
bool operator==(const value_t& rhs) const
|
||||
{
|
||||
return static_cast<value_t>(bits.type) == rhs;
|
||||
}
|
||||
|
||||
// Assignment
|
||||
type_data_t & operator=(value_t rhs)
|
||||
{
|
||||
bits.type = static_cast<uint16_t>(rhs);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Construct from value_t
|
||||
type_data_t(value_t t) noexcept
|
||||
{
|
||||
*reinterpret_cast<uint16_t*>(this) = 0;
|
||||
bits.type = static_cast<uint16_t>(t);
|
||||
}
|
||||
|
||||
// Default constructor
|
||||
type_data_t() noexcept
|
||||
{
|
||||
data = 0;
|
||||
bits.type = reinterpret_cast<uint16_t>(value_t::null);
|
||||
}
|
||||
|
||||
// Copy constructor
|
||||
type_data_t(const type_data_t& t) noexcept
|
||||
{
|
||||
data = t.data;
|
||||
}
|
||||
};
|
||||
|
||||
/// helper for exception-safe object creation
|
||||
template<typename T, typename... Args>
|
||||
static T* create(Args&& ... args)
|
||||
@ -1366,8 +1438,8 @@ class basic_json
|
||||
|
||||
Create an unsigned number JSON value with a given content. This constructor
|
||||
allows any type that can be used to construct values of type @ref
|
||||
number_unsigned_t. Examples may include the types `unsigned int`, `uint32_t`,
|
||||
or `unsigned short`.
|
||||
number_unsigned_t. Examples may include the types `unsigned int`,
|
||||
`uint32_t`, or `unsigned short`.
|
||||
|
||||
@tparam CompatibleNumberUnsignedType an integer type which is compatible to
|
||||
@ref number_unsigned_t.
|
||||
@ -1381,13 +1453,13 @@ class basic_json
|
||||
|
||||
@since version 2.0.0
|
||||
*/
|
||||
template<typename CompatibleNumberUnsignedType, typename
|
||||
std::enable_if<
|
||||
std::is_constructible<number_unsigned_t, CompatibleNumberUnsignedType>::value and
|
||||
std::numeric_limits<CompatibleNumberUnsignedType>::is_integer and
|
||||
!std::numeric_limits<CompatibleNumberUnsignedType>::is_signed,
|
||||
CompatibleNumberUnsignedType>::type
|
||||
= 0>
|
||||
template < typename CompatibleNumberUnsignedType, typename
|
||||
std::enable_if <
|
||||
std::is_constructible<number_unsigned_t, CompatibleNumberUnsignedType>::value and
|
||||
std::numeric_limits<CompatibleNumberUnsignedType>::is_integer and
|
||||
!std::numeric_limits<CompatibleNumberUnsignedType>::is_signed,
|
||||
CompatibleNumberUnsignedType >::type
|
||||
= 0 >
|
||||
basic_json(const CompatibleNumberUnsignedType val) noexcept
|
||||
: m_type(value_t::number_unsigned),
|
||||
m_value(static_cast<number_unsigned_t>(val))
|
||||
@ -1747,7 +1819,7 @@ class basic_json
|
||||
}
|
||||
|
||||
// check if iterator range is complete for primitive values
|
||||
switch (static_cast<value_t>(static_cast<int>(m_type) & static_cast<int>(value_t::precision_mask)))
|
||||
switch (m_type.get())
|
||||
{
|
||||
case value_t::boolean:
|
||||
case value_t::number_float:
|
||||
@ -1768,7 +1840,7 @@ class basic_json
|
||||
}
|
||||
}
|
||||
|
||||
switch (static_cast<value_t>(static_cast<int>(m_type) & static_cast<int>(value_t::precision_mask)))
|
||||
switch (m_type.get())
|
||||
{
|
||||
case value_t::number_integer:
|
||||
{
|
||||
@ -1852,7 +1924,7 @@ class basic_json
|
||||
basic_json(const basic_json& other)
|
||||
: m_type(other.m_type)
|
||||
{
|
||||
switch (static_cast<value_t>(static_cast<int>(m_type) & static_cast<int>(value_t::precision_mask)))
|
||||
switch (m_type.get())
|
||||
{
|
||||
case value_t::object:
|
||||
{
|
||||
@ -1982,7 +2054,7 @@ class basic_json
|
||||
*/
|
||||
~basic_json()
|
||||
{
|
||||
switch (m_type)
|
||||
switch (m_type.get())
|
||||
{
|
||||
case value_t::object:
|
||||
{
|
||||
@ -2082,7 +2154,7 @@ class basic_json
|
||||
*/
|
||||
value_t type() const noexcept
|
||||
{
|
||||
return static_cast<value_t>(static_cast<int>(m_type) & static_cast<int>(value_t::precision_mask));
|
||||
return m_type.get();
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -2180,7 +2252,8 @@ class basic_json
|
||||
|
||||
@sa @ref is_number_integer() -- check if value is an integer or unsigned
|
||||
integer number
|
||||
@sa @ref is_number_unsigned() -- check if value is an unsigned integer number
|
||||
@sa @ref is_number_unsigned() -- check if value is an unsigned integer
|
||||
number
|
||||
@sa @ref is_number_float() -- check if value is a floating-point number
|
||||
|
||||
@since version 1.0.0
|
||||
@ -2205,7 +2278,8 @@ class basic_json
|
||||
JSON types.,is_number_integer}
|
||||
|
||||
@sa @ref is_number() -- check if value is a number
|
||||
@sa @ref is_number_unsigned() -- check if value is an unsigned integer number
|
||||
@sa @ref is_number_unsigned() -- check if value is an unsigned integer
|
||||
number
|
||||
@sa @ref is_number_float() -- check if value is a floating-point number
|
||||
|
||||
@since version 1.0.0
|
||||
@ -2218,13 +2292,16 @@ class basic_json
|
||||
/*!
|
||||
@brief return whether value is an unsigned integer number
|
||||
|
||||
This function returns true iff the JSON value is an unsigned integer number.
|
||||
This excludes floating-point and (signed) integer values.
|
||||
This function returns true iff the JSON value is an unsigned integer
|
||||
number. This excludes floating-point and (signed) integer values.
|
||||
|
||||
@return `true` if type is an unsigned integer number, `false` otherwise.
|
||||
|
||||
@complexity Constant.
|
||||
|
||||
@liveexample{The following code exemplifies @ref is_number_unsigned for all
|
||||
JSON types.,is_number_unsigned}
|
||||
|
||||
@sa @ref is_number() -- check if value is a number
|
||||
@sa @ref is_number_integer() -- check if value is an integer or unsigned
|
||||
integer number
|
||||
@ -2252,13 +2329,14 @@ class basic_json
|
||||
|
||||
@sa @ref is_number() -- check if value is number
|
||||
@sa @ref is_number_integer() -- check if value is an integer number
|
||||
@sa @ref is_number_unsigned() -- check if value is an unsigned integer number
|
||||
@sa @ref is_number_unsigned() -- check if value is an unsigned integer
|
||||
number
|
||||
|
||||
@since version 1.0.0
|
||||
*/
|
||||
bool is_number_float() const noexcept
|
||||
{
|
||||
return (static_cast<value_t>(static_cast<int>(m_type) & static_cast<int>(value_t::precision_mask))) == value_t::number_float;
|
||||
return m_type == value_t::number_float;
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -2359,7 +2437,7 @@ class basic_json
|
||||
*/
|
||||
operator value_t() const noexcept
|
||||
{
|
||||
return (static_cast<value_t>(static_cast<int>(m_type) & static_cast<int>(value_t::precision_mask)));
|
||||
return m_type.get();
|
||||
}
|
||||
|
||||
/// @}
|
||||
@ -2514,7 +2592,7 @@ class basic_json
|
||||
, int>::type = 0>
|
||||
T get_impl(T*) const
|
||||
{
|
||||
switch (static_cast<value_t>(static_cast<int>(m_type) & static_cast<int>(value_t::precision_mask)))
|
||||
switch (m_type.get())
|
||||
{
|
||||
case value_t::number_integer:
|
||||
{
|
||||
@ -2835,7 +2913,7 @@ class basic_json
|
||||
|
||||
@liveexample{The example shows several calls to `get_ref()`.,get_ref}
|
||||
|
||||
@since version 1.0.1
|
||||
@since version 1.1.0
|
||||
*/
|
||||
template<typename ReferenceType, typename
|
||||
std::enable_if<
|
||||
@ -2890,14 +2968,14 @@ class basic_json
|
||||
|
||||
@since version 1.0.0
|
||||
*/
|
||||
template<typename ValueType, typename
|
||||
std::enable_if<
|
||||
not std::is_pointer<ValueType>::value
|
||||
and not std::is_same<ValueType, typename string_t::value_type>::value
|
||||
template < typename ValueType, typename
|
||||
std::enable_if <
|
||||
not std::is_pointer<ValueType>::value
|
||||
and not std::is_same<ValueType, typename string_t::value_type>::value
|
||||
#ifndef _MSC_VER // Fix for issue #167 operator<< abiguity under VS2015
|
||||
and not std::is_same<ValueType, std::initializer_list<typename string_t::value_type>>::value
|
||||
and not std::is_same<ValueType, std::initializer_list<typename string_t::value_type>>::value
|
||||
#endif
|
||||
, int>::type = 0>
|
||||
, int >::type = 0 >
|
||||
operator ValueType() const
|
||||
{
|
||||
// delegate the call to get<>() const
|
||||
@ -3365,7 +3443,7 @@ class basic_json
|
||||
with range checking
|
||||
@sa @ref value() for access by value with a default value
|
||||
|
||||
@since version 1.0.1
|
||||
@since version 1.1.0
|
||||
*/
|
||||
template<typename T>
|
||||
reference operator[](T* key)
|
||||
@ -3414,7 +3492,7 @@ class basic_json
|
||||
with range checking
|
||||
@sa @ref value() for access by value with a default value
|
||||
|
||||
@since version 1.0.1
|
||||
@since version 1.1.0
|
||||
*/
|
||||
template<typename T>
|
||||
const_reference operator[](T* key) const
|
||||
@ -3646,7 +3724,7 @@ class basic_json
|
||||
|
||||
InteratorType result = end();
|
||||
|
||||
switch (static_cast<value_t>(static_cast<int>(m_type) & static_cast<int>(value_t::precision_mask)))
|
||||
switch (m_type.get())
|
||||
{
|
||||
case value_t::boolean:
|
||||
case value_t::number_float:
|
||||
@ -3665,7 +3743,7 @@ class basic_json
|
||||
m_value.string = nullptr;
|
||||
}
|
||||
|
||||
m_type = value_t::null;
|
||||
m_type = type_data_t(value_t::null);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -3752,7 +3830,7 @@ class basic_json
|
||||
|
||||
InteratorType result = end();
|
||||
|
||||
switch (static_cast<value_t>(static_cast<int>(m_type) & static_cast<int>(value_t::precision_mask)))
|
||||
switch (m_type.get())
|
||||
{
|
||||
case value_t::boolean:
|
||||
case value_t::number_float:
|
||||
@ -3771,7 +3849,7 @@ class basic_json
|
||||
m_value.string = nullptr;
|
||||
}
|
||||
|
||||
m_type = value_t::null;
|
||||
m_type = type_data_t(value_t::null);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -4260,7 +4338,7 @@ class basic_json
|
||||
*/
|
||||
bool empty() const noexcept
|
||||
{
|
||||
switch (m_type)
|
||||
switch (m_type.get())
|
||||
{
|
||||
case value_t::null:
|
||||
{
|
||||
@ -4318,7 +4396,7 @@ class basic_json
|
||||
*/
|
||||
size_type size() const noexcept
|
||||
{
|
||||
switch (m_type)
|
||||
switch (m_type.get())
|
||||
{
|
||||
case value_t::null:
|
||||
{
|
||||
@ -4380,7 +4458,7 @@ class basic_json
|
||||
*/
|
||||
size_type max_size() const noexcept
|
||||
{
|
||||
switch (m_type)
|
||||
switch (m_type.get())
|
||||
{
|
||||
case value_t::array:
|
||||
{
|
||||
@ -4439,7 +4517,7 @@ class basic_json
|
||||
*/
|
||||
void clear() noexcept
|
||||
{
|
||||
switch (m_type)
|
||||
switch (m_type.get())
|
||||
{
|
||||
case value_t::number_integer:
|
||||
{
|
||||
@ -4532,7 +4610,7 @@ class basic_json
|
||||
assert(m_value.array != nullptr);
|
||||
m_value.array->push_back(std::move(val));
|
||||
// invalidate object
|
||||
val.m_type = value_t::null;
|
||||
val.m_type = type_data_t(value_t::null);
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -5557,7 +5635,7 @@ class basic_json
|
||||
/// return the type as string
|
||||
string_t type_name() const
|
||||
{
|
||||
switch (m_type)
|
||||
switch (m_type.get())
|
||||
{
|
||||
case value_t::null:
|
||||
return "null";
|
||||
@ -5763,7 +5841,7 @@ class basic_json
|
||||
// variable to hold indentation for recursive calls
|
||||
unsigned int new_indent = current_indent;
|
||||
|
||||
switch (static_cast<value_t>(static_cast<int>(m_type) & static_cast<int>(value_t::precision_mask)))
|
||||
switch (m_type.get())
|
||||
{
|
||||
case value_t::object:
|
||||
{
|
||||
@ -5874,25 +5952,58 @@ class basic_json
|
||||
|
||||
case value_t::number_float:
|
||||
{
|
||||
// If the number was parsed from a string use the same precision
|
||||
// otherwise 15 digits of precision allows round-trip IEEE 754
|
||||
// string->double->string; to be safe, we read this value from
|
||||
// std::numeric_limits<number_float_t>::digits10
|
||||
int precision = static_cast<int>(m_type) >> 8;
|
||||
if (!precision) precision = std::numeric_limits<double>::digits10;
|
||||
// Buffer size: precision (2^8-1 = 255) + other ('-.e-xxx' = 7) + null (1)
|
||||
char buf[263];
|
||||
int len;
|
||||
|
||||
// Special case for zero - use fixed precision to get "0.0"
|
||||
if (m_value.number_float == 0)
|
||||
if (m_type.bits.parsed)
|
||||
{
|
||||
// Number was parsed from a string so use the same precision
|
||||
if (m_type.bits.has_exp)
|
||||
{
|
||||
o << std::fixed << std::setprecision(1);
|
||||
// Exponent - output in exponential form - handle capitalization of e/E
|
||||
if (m_type.bits.exp_cap)
|
||||
{
|
||||
len = snprintf(buf, sizeof(buf), "%.*E", m_type.bits.precision, m_value.number_float) + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
len = snprintf(buf, sizeof(buf), "%.*e", m_type.bits.precision, m_value.number_float) + 1;
|
||||
}
|
||||
|
||||
// Remove '+' sign from the exponent if necessary
|
||||
if (!m_type.bits.exp_plus)
|
||||
{
|
||||
if (static_cast<size_t>(len) > sizeof(buf)) len = sizeof(buf);
|
||||
for (size_t i = 0; i < static_cast<size_t>(len); i++)
|
||||
{
|
||||
if (buf[i] == '+')
|
||||
{
|
||||
for (; i + 1 < static_cast<size_t>(len); i++) buf[i] = buf[i + 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// std::defaultfloat not supported in gcc version < 5
|
||||
o.unsetf(std::ios_base::floatfield);
|
||||
o << std::setprecision(precision);
|
||||
// No exponent - output as a decimal
|
||||
snprintf(buf, sizeof(buf), "%.*f", m_type.bits.precision, m_value.number_float);
|
||||
}
|
||||
o << m_value.number_float;
|
||||
}
|
||||
else if (m_value.number_float == 0)
|
||||
{
|
||||
// Special case for zero - use fixed precision to get "0.0"
|
||||
snprintf(buf, sizeof(buf), "%#.1f", m_value.number_float);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Otherwise 15 digits of precision allows round-trip IEEE 754
|
||||
// string->double->string; to be safe, we read this value from
|
||||
// std::numeric_limits<number_float_t>::digits10
|
||||
snprintf(buf, sizeof(buf), "%.*g", std::numeric_limits<double>::digits10, m_value.number_float);
|
||||
}
|
||||
|
||||
o << buf;
|
||||
return;
|
||||
}
|
||||
|
||||
@ -5916,7 +6027,7 @@ class basic_json
|
||||
//////////////////////
|
||||
|
||||
/// the type of the current element
|
||||
value_t m_type = value_t::null;
|
||||
type_data_t m_type = type_data_t(value_t::null);
|
||||
|
||||
/// the value of the current element
|
||||
json_value m_value = {};
|
||||
@ -6140,7 +6251,7 @@ class basic_json
|
||||
{
|
||||
assert(m_object != nullptr);
|
||||
|
||||
switch (m_object->m_type)
|
||||
switch (m_object->m_type.get())
|
||||
{
|
||||
case basic_json::value_t::object:
|
||||
{
|
||||
@ -6167,7 +6278,7 @@ class basic_json
|
||||
{
|
||||
assert(m_object != nullptr);
|
||||
|
||||
switch (m_object->m_type)
|
||||
switch (m_object->m_type.get())
|
||||
{
|
||||
case basic_json::value_t::object:
|
||||
{
|
||||
@ -6213,7 +6324,7 @@ class basic_json
|
||||
{
|
||||
assert(m_object != nullptr);
|
||||
|
||||
switch (m_object->m_type)
|
||||
switch (m_object->m_type.get())
|
||||
{
|
||||
case basic_json::value_t::object:
|
||||
{
|
||||
@ -6249,7 +6360,7 @@ class basic_json
|
||||
{
|
||||
assert(m_object != nullptr);
|
||||
|
||||
switch (m_object->m_type)
|
||||
switch (m_object->m_type.get())
|
||||
{
|
||||
case basic_json::value_t::object:
|
||||
{
|
||||
@ -6279,7 +6390,7 @@ class basic_json
|
||||
{
|
||||
assert(m_object != nullptr);
|
||||
|
||||
switch (m_object->m_type)
|
||||
switch (m_object->m_type.get())
|
||||
{
|
||||
case basic_json::value_t::object:
|
||||
{
|
||||
@ -6319,7 +6430,7 @@ class basic_json
|
||||
{
|
||||
assert(m_object != nullptr);
|
||||
|
||||
switch (m_object->m_type)
|
||||
switch (m_object->m_type.get())
|
||||
{
|
||||
case basic_json::value_t::object:
|
||||
{
|
||||
@ -6362,7 +6473,7 @@ class basic_json
|
||||
{
|
||||
assert(m_object != nullptr);
|
||||
|
||||
switch (m_object->m_type)
|
||||
switch (m_object->m_type.get())
|
||||
{
|
||||
case basic_json::value_t::object:
|
||||
{
|
||||
@ -6399,7 +6510,7 @@ class basic_json
|
||||
{
|
||||
assert(m_object != nullptr);
|
||||
|
||||
switch (m_object->m_type)
|
||||
switch (m_object->m_type.get())
|
||||
{
|
||||
case basic_json::value_t::object:
|
||||
{
|
||||
@ -6434,7 +6545,7 @@ class basic_json
|
||||
|
||||
assert(m_object != nullptr);
|
||||
|
||||
switch (m_object->m_type)
|
||||
switch (m_object->m_type.get())
|
||||
{
|
||||
case basic_json::value_t::object:
|
||||
{
|
||||
@ -6470,7 +6581,7 @@ class basic_json
|
||||
|
||||
assert(m_object != nullptr);
|
||||
|
||||
switch (m_object->m_type)
|
||||
switch (m_object->m_type.get())
|
||||
{
|
||||
case basic_json::value_t::object:
|
||||
{
|
||||
@ -6512,7 +6623,7 @@ class basic_json
|
||||
{
|
||||
assert(m_object != nullptr);
|
||||
|
||||
switch (m_object->m_type)
|
||||
switch (m_object->m_type.get())
|
||||
{
|
||||
case basic_json::value_t::object:
|
||||
{
|
||||
@ -6562,7 +6673,7 @@ class basic_json
|
||||
{
|
||||
assert(m_object != nullptr);
|
||||
|
||||
switch (m_object->m_type)
|
||||
switch (m_object->m_type.get())
|
||||
{
|
||||
case basic_json::value_t::object:
|
||||
{
|
||||
@ -6586,7 +6697,7 @@ class basic_json
|
||||
{
|
||||
assert(m_object != nullptr);
|
||||
|
||||
switch (m_object->m_type)
|
||||
switch (m_object->m_type.get())
|
||||
{
|
||||
case basic_json::value_t::object:
|
||||
{
|
||||
@ -7336,10 +7447,10 @@ class basic_json
|
||||
|
||||
@return the floating point number
|
||||
|
||||
@warning This function uses `std::strtof`, `std::strtod`, or
|
||||
`std::strtold` which use the current C locale to determine which
|
||||
character is used as decimal point character. This may yield to parse
|
||||
errors if the locale does not used `.`.
|
||||
@bug This function uses `std::strtof`, `std::strtod`, or `std::strtold`
|
||||
which use the current C locale to determine which character is used as
|
||||
decimal point character. This may yield to parse errors if the locale
|
||||
does not used `.`.
|
||||
*/
|
||||
long double str_to_float_t(long double* /* type */, char** endptr) const
|
||||
{
|
||||
@ -7397,42 +7508,104 @@ class basic_json
|
||||
@return @a true if the cast was performed without error, @a false otherwise
|
||||
*/
|
||||
template <typename T_A, typename T_B>
|
||||
bool attempt_cast(T_A source, T_B & dest) const
|
||||
bool attempt_cast(T_A source, T_B& dest) const
|
||||
{
|
||||
dest = static_cast<T_B>(source);
|
||||
return (source == static_cast<T_A>(dest));
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief peek ahead and guess the number type and floating point representation
|
||||
|
||||
This function scans the number to identify the number type. In addition it
|
||||
counts the significant figures after the decimal point, whether the
|
||||
number is in exponential or decimal form, the capitalization of the
|
||||
exponent marker, and if the optional '+' is present in the exponent. This
|
||||
information is necessary to perform accurate round trips of floating point
|
||||
numbers.
|
||||
|
||||
@param[out] type @ref type_data_t object to receive the type information.
|
||||
*/
|
||||
void guess_type(type_data_t & type) const
|
||||
{
|
||||
const lexer::lexer_char_t *curptr = m_start;
|
||||
type.bits.parsed = true;
|
||||
|
||||
uint8_t found_radix_point = 0;
|
||||
uint8_t precision = 0;
|
||||
|
||||
// Look for sign
|
||||
if (*curptr == '-') {
|
||||
type = value_t::number_integer;
|
||||
curptr++;
|
||||
}
|
||||
else {
|
||||
type = value_t::number_unsigned;
|
||||
if (*curptr == '+') curptr++;
|
||||
}
|
||||
|
||||
// Count the significant figures
|
||||
for (; curptr < m_cursor; curptr++)
|
||||
{
|
||||
|
||||
// Quickly skip tests if a digit
|
||||
if (*curptr < '0' || *curptr > '9')
|
||||
{
|
||||
if (*curptr == '.')
|
||||
{
|
||||
// Don't count '.' but change to float
|
||||
type = value_t::number_float;
|
||||
|
||||
// Reset precision count
|
||||
precision = 0;
|
||||
found_radix_point = 0xFF;
|
||||
continue;
|
||||
}
|
||||
// Assume exponent (if not it is a bad number and will fail
|
||||
// parse anyway - could throw here instead): change to
|
||||
// float, stop counting and record exponent details
|
||||
type = value_t::number_float;
|
||||
type.bits.has_exp = true;
|
||||
|
||||
// Exponent capitalization
|
||||
type.bits.exp_cap = (*curptr == 'E');
|
||||
|
||||
// Exponent '+' sign
|
||||
type.bits.exp_plus = (*(++curptr) == '+');
|
||||
break;
|
||||
}
|
||||
precision++;
|
||||
}
|
||||
|
||||
// If no radix was found then precision would now be set to
|
||||
// the number of digits, which is wrong - clear it
|
||||
type.bits.precision = precision & found_radix_point;
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief return number value for number tokens
|
||||
|
||||
This function translates the last token into the most appropriate
|
||||
number type (either integer, unsigned integer or floating point),
|
||||
which is passed back to the caller via the result parameter. The pointer
|
||||
@a m_start points to the beginning of the parsed number. We first examine
|
||||
the first character to determine the sign of the number and then pass
|
||||
this pointer to either @a std::strtoull (if positive) or @a std::strtoll
|
||||
(if negative), both of which set @a endptr to the first character past the
|
||||
converted number. If this pointer is not the same as @a m_cursor, then
|
||||
either more or less characters have been used during the comparison.
|
||||
This function translates the last token into the most appropriate number
|
||||
type (either integer, unsigned integer or floating point), which is
|
||||
passed back to the caller via the result parameter.
|
||||
|
||||
This can happen for inputs like "01" which will be treated like number 0
|
||||
followed by number 1. This will also occur for valid floating point
|
||||
inputs like "12e3" will be incorrectly read as 12. Numbers that are too
|
||||
large or too small for a signed/unsigned long long will cause a range
|
||||
error (@a errno set to ERANGE). The parsed number is cast to a @ref
|
||||
number_integer_t/@ref number_unsigned_t using the helper function @ref attempt_cast,
|
||||
which returns @a false if the cast could not be peformed without error.
|
||||
First @ref guess_type() is called to determine the type and to retrieve
|
||||
information about the floating point representation (if applicable)
|
||||
that can be used to accurately render the number to a string later.
|
||||
|
||||
In any of these cases (more/less characters read, range error or a cast
|
||||
error) the pointer is passed to @a std:strtod, which also sets @a endptr to the
|
||||
first character past the converted number. The resulting @ref number_float_t
|
||||
is then cast to a @ref number_integer_t/@ref number_unsigned_t using
|
||||
@ref attempt_cast and if no error occurs is stored in that form, otherwise
|
||||
it is stored as a @ref number_float_t.
|
||||
Depending on the type, either @a std::strtoull (if number_unsigned_t) or
|
||||
@a std::strtoll (if number_integer_t) is then called to attempt to parse the
|
||||
number as an integer. Numbers that are too large or too small for a
|
||||
signed/unsigned long long will cause a range error (@a errno set to ERANGE).
|
||||
The parsed number is cast to a @ref number_integer_t/@ref number_unsigned_t
|
||||
using the helper function @ref attempt_cast, which returns @a false if the
|
||||
cast could not be peformed without error.
|
||||
|
||||
A final comparison is made of @a endptr and if still not the same as
|
||||
@ref m_cursor a bad input is assumed and @a result parameter is set to NAN.
|
||||
In either of these cases (range error or a cast error) the number is parsed
|
||||
using @a std:strtod (or @a std:strtof or @a std::strtold), which sets
|
||||
@a endptr to the first character past the converted number. If it is not
|
||||
the same as @ref m_cursor a bad input is assumed and @a result parameter is
|
||||
set to NAN.
|
||||
|
||||
@param[out] result @ref basic_json object to receive the number, or NAN if the
|
||||
conversion read past the current token. The latter case needs to be
|
||||
@ -7442,72 +7615,48 @@ class basic_json
|
||||
{
|
||||
assert(m_start != nullptr);
|
||||
|
||||
// Count the significant figures
|
||||
int precision = 0;
|
||||
{
|
||||
const lexer::lexer_char_t *curptr;
|
||||
|
||||
// Assume unsigned integer for now
|
||||
result.m_type = value_t::number_unsigned;
|
||||
for (curptr = m_start; curptr < m_cursor; curptr++) {
|
||||
switch (*curptr) {
|
||||
case '-':
|
||||
// Found minus sign: change to integer
|
||||
result.m_type = value_t::number_integer;
|
||||
case '.':
|
||||
// Don't count either '.' or '-'
|
||||
continue;
|
||||
case 'e':
|
||||
case 'E':
|
||||
// Found exponent: change to float and stop counting
|
||||
result.m_type = value_t::number_float;
|
||||
break;
|
||||
default:
|
||||
// Found a signficant figure
|
||||
precision++;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Characters after number - shouldn't happen, but try parsing as float
|
||||
if (curptr != m_cursor) result.m_type = value_t::number_float;
|
||||
}
|
||||
guess_type(result.m_type);
|
||||
|
||||
errno = 0;
|
||||
typename string_t::value_type* endptr = 0;
|
||||
|
||||
// Attempt to parse it as an integer - first checking for a negative number
|
||||
// Attempt to parse it as an integer
|
||||
if (result.m_type == value_t::number_unsigned)
|
||||
{
|
||||
// Positive, parse with strtoull and attempt cast to number_unsigned_t
|
||||
if (!attempt_cast(std::strtoull(reinterpret_cast<typename string_t::const_pointer>(m_start), &endptr, 10), result.m_value.number_unsigned))
|
||||
if (!attempt_cast(std::strtoull(reinterpret_cast<typename string_t::const_pointer>(m_start), NULL,
|
||||
10), result.m_value.number_unsigned))
|
||||
{
|
||||
result.m_type = value_t::number_float; // Cast failed due to overflow - store as float
|
||||
}
|
||||
}
|
||||
else if (result.m_type == value_t::number_integer)
|
||||
{
|
||||
// Negative, parse with strtoll and attempt cast to number_integer_t
|
||||
if (!attempt_cast(std::strtoll(reinterpret_cast<typename string_t::const_pointer>(m_start), &endptr, 10), result.m_value.number_unsigned))
|
||||
if (!attempt_cast(std::strtoll(reinterpret_cast<typename string_t::const_pointer>(m_start), NULL,
|
||||
10), result.m_value.number_integer))
|
||||
{
|
||||
result.m_type = value_t::number_float; // Cast failed due to overflow - store as float
|
||||
}
|
||||
}
|
||||
|
||||
// Check the end of the number was reached and no range error occurred
|
||||
if (reinterpret_cast<lexer_char_t*>(endptr) != m_cursor || errno == ERANGE) result.m_type = value_t::number_float;
|
||||
if (errno == ERANGE) result.m_type = value_t::number_float;
|
||||
|
||||
if (result.m_type == value_t::number_float)
|
||||
{
|
||||
// Either the number won't fit in an integer (range error from strtoull/strtoll or overflow on cast) or there was
|
||||
// something else after the number, which could be an exponent
|
||||
// Either the number won't fit in an integer (range error from
|
||||
// strtoull/strtoll or overflow on cast) or there was something
|
||||
// else after the number, which could be an exponent
|
||||
|
||||
// Parse with strtod
|
||||
typename string_t::value_type* endptr;
|
||||
result.m_value.number_float = str_to_float_t(static_cast<number_float_t*>(nullptr), &endptr);
|
||||
|
||||
// Add the precision bits
|
||||
result.m_type = static_cast<value_t>(static_cast<int>(result.m_type) | (precision << 8));
|
||||
|
||||
// Anything after the number is an error
|
||||
if (reinterpret_cast<lexer_char_t*>(endptr) != m_cursor && *m_cursor != '.')
|
||||
{
|
||||
throw std::invalid_argument(std::string("parse error - ") + get_token() + " is not a number");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -7879,5 +8028,3 @@ inline nlohmann::json operator "" _json(const char* s, std::size_t)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
1
test/json_roundtrip/roundtrip28.json
Normal file
1
test/json_roundtrip/roundtrip28.json
Normal file
@ -0,0 +1 @@
|
||||
[4.940656458412e-324]
|
||||
1
test/json_roundtrip/roundtrip29.json
Normal file
1
test/json_roundtrip/roundtrip29.json
Normal file
@ -0,0 +1 @@
|
||||
[2.2250738585072e-308]
|
||||
1
test/json_roundtrip/roundtrip30.json
Normal file
1
test/json_roundtrip/roundtrip30.json
Normal file
@ -0,0 +1 @@
|
||||
[1.2345E-30]
|
||||
1
test/json_roundtrip/roundtrip31.json
Normal file
1
test/json_roundtrip/roundtrip31.json
Normal file
@ -0,0 +1 @@
|
||||
[1.2345E+30]
|
||||
1
test/json_roundtrip/roundtrip32.json
Normal file
1
test/json_roundtrip/roundtrip32.json
Normal file
@ -0,0 +1 @@
|
||||
[1.2345e+30]
|
||||
@ -924,7 +924,8 @@ TEST_CASE("constructors")
|
||||
|
||||
SECTION("object with error")
|
||||
{
|
||||
CHECK_THROWS_AS(json::object({ {"one", 1}, {"two", 1u}, {"three", 2.2}, {"four", false}, 13 }), std::logic_error);
|
||||
CHECK_THROWS_AS(json::object({ {"one", 1}, {"two", 1u}, {"three", 2.2}, {"four", false}, 13 }),
|
||||
std::logic_error);
|
||||
CHECK_THROWS_WITH(json::object({ {"one", 1}, {"two", 1u}, {"three", 2.2}, {"four", false}, 13 }),
|
||||
"cannot create object from initializer list");
|
||||
}
|
||||
@ -5435,7 +5436,7 @@ TEST_CASE("iterators")
|
||||
|
||||
SECTION("object")
|
||||
{
|
||||
json j = {{"A", 1},{"B", 2},{"C", 3}};
|
||||
json j = {{"A", 1}, {"B", 2}, {"C", 3}};
|
||||
json j_const(j);
|
||||
|
||||
SECTION("json + begin/end")
|
||||
@ -9672,7 +9673,7 @@ TEST_CASE("parser class")
|
||||
// i.e. -(2**63) -> (2**64)-1.
|
||||
|
||||
// -(2**63) ** Note: compilers see negative literals as negated positive numbers (hence the -1))
|
||||
CHECK(json::parser("-9223372036854775808").parse().get<int64_t>() == -9223372036854775807-1);
|
||||
CHECK(json::parser("-9223372036854775808").parse().get<int64_t>() == -9223372036854775807 - 1);
|
||||
// (2**63)-1
|
||||
CHECK(json::parser("9223372036854775807").parse().get<int64_t>() == 9223372036854775807);
|
||||
// (2**64)-1
|
||||
@ -9718,14 +9719,17 @@ TEST_CASE("parser class")
|
||||
CHECK_THROWS_AS(json::parser("-0e-:").parse(), std::invalid_argument);
|
||||
CHECK_THROWS_AS(json::parser("-0f").parse(), std::invalid_argument);
|
||||
|
||||
CHECK_THROWS_WITH(json::parser("01").parse(), "parse error - 0 is not a number");
|
||||
CHECK_THROWS_WITH(json::parser("01").parse(),
|
||||
"parse error - unexpected number literal; expected end of input");
|
||||
CHECK_THROWS_WITH(json::parser("--1").parse(), "parse error - unexpected '-'");
|
||||
CHECK_THROWS_WITH(json::parser("1.").parse(), "parse error - unexpected '.'; expected end of input");
|
||||
CHECK_THROWS_WITH(json::parser("1.").parse(),
|
||||
"parse error - unexpected '.'; expected end of input");
|
||||
CHECK_THROWS_WITH(json::parser("1E").parse(),
|
||||
"parse error - unexpected 'E'; expected end of input");
|
||||
CHECK_THROWS_WITH(json::parser("1E-").parse(),
|
||||
"parse error - unexpected 'E'; expected end of input");
|
||||
CHECK_THROWS_WITH(json::parser("1.E1").parse(), "parse error - unexpected '.'; expected end of input");
|
||||
CHECK_THROWS_WITH(json::parser("1.E1").parse(),
|
||||
"parse error - unexpected '.'; expected end of input");
|
||||
CHECK_THROWS_WITH(json::parser("-1E").parse(),
|
||||
"parse error - unexpected 'E'; expected end of input");
|
||||
CHECK_THROWS_WITH(json::parser("-0E#").parse(),
|
||||
@ -9767,7 +9771,8 @@ TEST_CASE("parser class")
|
||||
CHECK_THROWS_AS(json::parser("1E.").parse(), std::invalid_argument);
|
||||
CHECK_THROWS_AS(json::parser("1E/").parse(), std::invalid_argument);
|
||||
CHECK_THROWS_AS(json::parser("1E:").parse(), std::invalid_argument);
|
||||
CHECK_THROWS_WITH(json::parser("0.").parse(), "parse error - unexpected '.'; expected end of input");
|
||||
CHECK_THROWS_WITH(json::parser("0.").parse(),
|
||||
"parse error - unexpected '.'; expected end of input");
|
||||
CHECK_THROWS_WITH(json::parser("-").parse(), "parse error - unexpected '-'");
|
||||
CHECK_THROWS_WITH(json::parser("--").parse(),
|
||||
"parse error - unexpected '-'");
|
||||
@ -11765,7 +11770,12 @@ TEST_CASE("compliance tests from nativejson-benchmark")
|
||||
"test/json_roundtrip/roundtrip24.json",
|
||||
"test/json_roundtrip/roundtrip25.json",
|
||||
"test/json_roundtrip/roundtrip26.json",
|
||||
"test/json_roundtrip/roundtrip27.json"
|
||||
"test/json_roundtrip/roundtrip27.json",
|
||||
"test/json_roundtrip/roundtrip28.json",
|
||||
"test/json_roundtrip/roundtrip29.json",
|
||||
"test/json_roundtrip/roundtrip30.json",
|
||||
"test/json_roundtrip/roundtrip31.json",
|
||||
"test/json_roundtrip/roundtrip32.json"
|
||||
})
|
||||
{
|
||||
CAPTURE(filename);
|
||||
@ -12076,7 +12086,8 @@ TEST_CASE("regression tests")
|
||||
SECTION("issue #89 - nonstandard integer type")
|
||||
{
|
||||
// create JSON class with nonstandard integer number type
|
||||
using custom_json = nlohmann::basic_json<std::map, std::vector, std::string, bool, int32_t, uint32_t, float>;
|
||||
using custom_json =
|
||||
nlohmann::basic_json<std::map, std::vector, std::string, bool, int32_t, uint32_t, float>;
|
||||
custom_json j;
|
||||
j["int_1"] = 1;
|
||||
// we need to cast to int to compile with Catch - the value is int32_t
|
||||
@ -12092,17 +12103,17 @@ TEST_CASE("regression tests")
|
||||
// unsigned integer parsing - expected to overflow and be stored as a float
|
||||
j = custom_json::parse("4294967296"); // 2^32
|
||||
CHECK(static_cast<int>(j.type()) == static_cast<int>(custom_json::value_t::number_float));
|
||||
CHECK(j.get<float>() == 4294967296.0);
|
||||
CHECK(j.get<float>() == 4294967296.0f);
|
||||
|
||||
// integer object creation - expected to wrap and still be stored as an integer
|
||||
j = -2147483649LL; // -2^31-1
|
||||
CHECK(static_cast<int>(j.type()) == static_cast<int>(custom_json::value_t::number_integer));
|
||||
CHECK(j.get<int32_t>() == 2147483647.0); // Wrap
|
||||
CHECK(j.get<int32_t>() == 2147483647.0f); // Wrap
|
||||
|
||||
// integer parsing - expected to overflow and be stored as a float
|
||||
j = custom_json::parse("-2147483648"); // -2^31
|
||||
// integer parsing - expected to overflow and be stored as a float with rounding
|
||||
j = custom_json::parse("-2147483649"); // -2^31
|
||||
CHECK(static_cast<int>(j.type()) == static_cast<int>(custom_json::value_t::number_float));
|
||||
CHECK(j.get<float>() == -2147483648.0);
|
||||
CHECK(j.get<float>() == -2147483650.0f);
|
||||
}
|
||||
|
||||
SECTION("issue #93 reverse_iterator operator inheritance problem")
|
||||
@ -12263,12 +12274,8 @@ TEST_CASE("regression tests")
|
||||
j = json::parse("0.999999999999999944488848768742172978818416595458984374");
|
||||
CHECK(j.get<double>() == 0.99999999999999989);
|
||||
|
||||
// Test fails under GCC/clang due to strtod() error (may originate in libstdc++
|
||||
// but seems to have been fixed in the most current versions - just not on Travis)
|
||||
#if !defined(__clang__) && !defined(__GNUC__) && !defined(__GNUG__)
|
||||
j = json::parse("1.00000000000000011102230246251565404236316680908203126");
|
||||
CHECK(j.get<double>() == 1.00000000000000022);
|
||||
#endif
|
||||
|
||||
j = json::parse("7205759403792793199999e-5");
|
||||
CHECK(j.get<double>() == 72057594037927928.0);
|
||||
@ -12285,15 +12292,18 @@ TEST_CASE("regression tests")
|
||||
// create JSON class with nonstandard float number type
|
||||
|
||||
// float
|
||||
nlohmann::basic_json<std::map, std::vector, std::string, bool, int32_t, uint32_t, float> j_float = 1.23e25f;
|
||||
nlohmann::basic_json<std::map, std::vector, std::string, bool, int32_t, uint32_t, float> j_float =
|
||||
1.23e25f;
|
||||
CHECK(j_float.get<float>() == 1.23e25f);
|
||||
|
||||
// double
|
||||
nlohmann::basic_json<std::map, std::vector, std::string, bool, int64_t, uint64_t, double> j_double = 1.23e35f;
|
||||
nlohmann::basic_json<std::map, std::vector, std::string, bool, int64_t, uint64_t, double> j_double =
|
||||
1.23e35f;
|
||||
CHECK(j_double.get<double>() == 1.23e35f);
|
||||
|
||||
// long double
|
||||
nlohmann::basic_json<std::map, std::vector, std::string, bool, int64_t, uint64_t, long double> j_long_double = 1.23e45L;
|
||||
nlohmann::basic_json<std::map, std::vector, std::string, bool, int64_t, uint64_t, long double>
|
||||
j_long_double = 1.23e45L;
|
||||
CHECK(j_long_double.get<long double>() == 1.23e45L);
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user