Implement bitfields for better readability over masks

This commit is contained in:
Trevor Welsby 2016-01-29 18:52:25 +10:00
commit 7d08aa759b
55 changed files with 1002 additions and 466 deletions

View File

@ -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
View 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)*

View File

@ -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

View File

@ -3,11 +3,12 @@
[![Build Status](https://travis-ci.org/nlohmann/json.svg?branch=master)](https://travis-ci.org/nlohmann/json)
[![Build Status](https://ci.appveyor.com/api/projects/status/1acb366xfyg3qybk?svg=true)](https://ci.appveyor.com/project/nlohmann/json)
[![Coverage Status](https://img.shields.io/coveralls/nlohmann/json.svg)](https://coveralls.io/r/nlohmann/json)
[![Try online](https://img.shields.io/badge/try-online-blue.svg)](http://melpon.org/wandbox/permlink/GnGKwji06WeVonlI)
[![Try online](https://img.shields.io/badge/try-online-blue.svg)](http://melpon.org/wandbox/permlink/WSW3gHHE4UcZ9K3G)
[![Documentation Status](https://img.shields.io/badge/docs-doxygen-blue.svg)](http://nlohmann.github.io/json)
[![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/nlohmann/json/master/LICENSE.MIT)
[![Github Releases](https://img.shields.io/github/release/nlohmann/json.svg)](https://github.com/nlohmann/json/releases)
[![Github Issues](https://img.shields.io/github/issues/nlohmann/json.svg)](http://github.com/nlohmann/json/issues)
[![Gitter](https://badges.gitter.im/nlohmann/json.svg)](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).

View File

@ -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)).

View File

@ -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 = .

View File

@ -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>

View File

@ -1,7 +1,7 @@
null
false
0
0
0.0
{}
[]
""

View File

@ -1,7 +1,7 @@
null
false
0
0
0.0
{}
[]
""

View File

@ -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';

View File

@ -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>

View File

@ -3,5 +3,6 @@ false
false
false
false
false
true
false

View File

@ -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';

View File

@ -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>

View File

@ -5,3 +5,4 @@ false
false
false
false
false

View File

@ -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';

View File

@ -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>

View File

@ -5,3 +5,4 @@ false
false
false
false
false

View File

@ -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';

View File

@ -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>

View File

@ -5,3 +5,4 @@ false
false
false
false
false

View File

@ -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';

View File

@ -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>

View File

@ -2,6 +2,7 @@ false
false
true
true
true
false
false
false

View File

@ -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';

View File

@ -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>

View File

@ -1,6 +1,7 @@
false
false
false
false
true
false
false

View File

@ -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';

View File

@ -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>

View File

@ -1,6 +1,7 @@
false
false
true
true
false
false
false

View 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';
}

View File

@ -0,0 +1 @@
<a target="_blank" href="http://melpon.org/wandbox/permlink/h4s4VitQ3VmCOEXr"><b>online</b></a>

View File

@ -0,0 +1,8 @@
false
false
false
true
false
false
false
false

View File

@ -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';

View File

@ -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>

View File

@ -2,6 +2,7 @@ false
false
false
false
false
true
false
false

View File

@ -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';

View File

@ -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>

View File

@ -2,6 +2,7 @@ true
true
true
true
true
false
false
true

View File

@ -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';

View File

@ -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>

View File

@ -4,4 +4,5 @@ false
false
false
false
false
true

View File

@ -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';

View File

@ -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>

View File

@ -2,6 +2,7 @@ false
false
false
false
false
true
true
false

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -0,0 +1 @@
[4.940656458412e-324]

View File

@ -0,0 +1 @@
[2.2250738585072e-308]

View File

@ -0,0 +1 @@
[1.2345E-30]

View File

@ -0,0 +1 @@
[1.2345E+30]

View File

@ -0,0 +1 @@
[1.2345e+30]

View File

@ -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);
}
}