Compare commits

...

633 Commits

Author SHA1 Message Date
Niels Lohmann
fec56a1a16 Merge branch 'release/3.10.4' 2021-10-16 14:47:12 +02:00
Niels Lohmann
a09bfa5faa 🔖 set version to 3.10.4 2021-10-16 13:34:31 +02:00
Niels Lohmann
80cf9d7065 Revert invalid fix (#3082)
*  revert invalid fix
2021-10-16 13:27:28 +02:00
Niels Lohmann
ba046e4ea4 Allow to use get with explicit constructor (#3079)
*  remove "fix" that caused #3077
2021-10-14 21:01:14 +02:00
Théo DELRIEU
0e694b4060 fix std::filesystem::path regression (#3073)
* meta: rework is_compatible/is_constructible_string_type

These type traits performed an incorrect and insufficient check.

Converting to a std::filesystem::path used to work by accident thanks to
these brittle constraints, but the clean-up performed in #3020 broke them.

* support std::filesystem::path

Fixes #3070
2021-10-14 19:19:46 +02:00
Niels Lohmann
4b1cb9eee1 Merge branch 'release/3.10.3' into develop 2021-10-08 14:39:34 +02:00
Niels Lohmann
aa0e847e5b Merge branch 'release/3.10.3' 2021-10-08 14:39:21 +02:00
Niels Lohmann
ab6a2c7425 🔖 set version to 3.10.3 2021-10-08 13:58:48 +02:00
Théo DELRIEU
80df5e8de6 meta: fix is_compatible/constructible traits (#3020)
The previous version relied on the existence of an 'iterator' type.

As mentioned in comments, this is not the proper way to do it and
causes issues with certain types (e.g. views from range-v3).

Add a 'is_range' trait that properly detects the return type of
'begin'/'end', and use it in instead.
2021-10-07 12:32:25 +02:00
Carl Smedstad
62f2997b79 Fix assertion failure for JSON_DIAGNOSTICS (#3037)
* Fix assertion failure #3032
2021-10-07 12:24:09 +02:00
Niels Lohmann
ea528bbfda 📝 fixed Clang version (#3040) 2021-09-28 12:36:42 +02:00
Niels Lohmann
0b345b20c8 Allow allocators for output_vector_adapter (#2989)
* ♻️ allow allocators for vectors

*  add regression tests
2021-09-12 18:55:47 +02:00
Anthony VH
58b83b71dc Set parent pointers for values inserted via update() (fixes #3007). (#3008)
* Set parent pointers for values inserted via update() (fixes #3007).

* Moved test for #3007 to proper file.

* Enable access to private members in diagnostics unit tests.

* Make style consistent with rest of code.

* Forced amalgamate rerun.

* Refactor test for #3007 so it doesn't use private members. Also extend to test both update() functions.

* Added fix for #3007 to update(const_iterator, const_iterator) as well.

* Added failing example code from #3007 as extra test.
2021-09-12 18:51:25 +02:00
Niels Lohmann
bbdb29c658 Update docset generation script (#2967)
* 📝 update docset generation script

* 📝 update documentation
2021-09-01 08:43:10 +02:00
Niels Lohmann
fd0aa4fb0d 👷 re-add Clang 12 (#2986) 2021-08-30 10:54:14 +02:00
Niels Lohmann
e0b02c355e Use new Docker image (#2981) 2021-08-29 18:05:31 +02:00
Niels Lohmann
9dfd91695c Merge branch 'release/3.10.2' into develop 2021-08-26 09:08:33 +02:00
Niels Lohmann
626e7d61e4 Merge branch 'release/3.10.2' 2021-08-26 09:08:14 +02:00
Niels Lohmann
33b674b4b2 🔖 set version to 3.10.2 2021-08-26 08:13:04 +02:00
Giovanni Cerretani
28a169725e Fix -Wunused warnings on JSON_DIAGNOSTICS (#2976)
* Fix #2975

Define JSON_DIAGNOSTICS to 0 if not defined to fix annoying Wundef warnings.

* amalgamated
2021-08-26 07:35:01 +02:00
Niels Lohmann
1fd2213fd2 Merge branch 'release/3.10.1' into develop 2021-08-24 21:08:43 +02:00
Niels Lohmann
b488724ecd Merge branch 'release/3.10.1' 2021-08-24 21:08:29 +02:00
Niels Lohmann
8ad66e9136 🔖 set version to 3.10.1 2021-08-24 20:19:55 +02:00
mb0202
7194245a31 Fixed typo in parse.md (#2968)
Changed a potential typo: "charater" -> "character"
2021-08-24 08:08:02 +02:00
Niels Lohmann
34e2c4ab88 📝 add link to Homebrew package (#2966) 2021-08-22 21:58:37 +02:00
Niels Lohmann
c753165db6 Fix parent update for diagnostics with ordered_json (#2963)
🐛 fix parent update for diagnostics with ordered_json
2021-08-22 20:30:20 +02:00
Niels Lohmann
f03127eb69 Set stack size for some unit tests when using MSVC (#2961)
* 🏁 set stack size for some unit tests
2021-08-21 13:55:06 +02:00
Niels Lohmann
cb053bceb1 Merge pull request #2960 from nlohmann/issue2958
Add regression test
2021-08-20 16:34:38 +02:00
Niels Lohmann
97c7a35a2b add regression test 2021-08-20 14:49:58 +02:00
Niels Lohmann
eb6541a30c Merge pull request #2959 from nlohmann/issue2938
Update Travis badge
2021-08-20 13:56:16 +02:00
Niels Lohmann
e8e93ee43b 👷 update Travis badge 2021-08-20 13:53:31 +02:00
Niels Lohmann
611fd22557 Merge pull request #2957 from Hallot/bug/fix-some-clang-warnings
Fix some extra ";" clang warnings
2021-08-20 13:32:38 +02:00
Pierre Hallot
433604843d Fix extra ";" clang warnings 2021-08-19 17:04:34 +02:00
Niels Lohmann
44ffaa052c Merge pull request #2943 from amirmasoudabdol/patch-1
Updating the Homebrew Command
2021-08-19 12:03:52 +02:00
Amir Masoud Abdol
14af5d4a9f fixing the doc files 2021-08-19 09:31:39 +02:00
Niels Lohmann
273d911252 Merge pull request #2954 from nlohmann/issue2944 2021-08-19 06:37:42 +02:00
Niels Lohmann
55281e03af 📝 add documentation for integration via vcpkg 2021-08-18 21:25:23 +02:00
Niels Lohmann
23e3b622aa 📝 add documentation for integration via vcpkg 2021-08-18 20:49:13 +02:00
Niels Lohmann
abd829e6c6 Merge pull request #2950 from senyai/patch-2
🚨 fix gdb_pretty_printer failure on basic types
2021-08-18 20:07:28 +02:00
Niels Lohmann
5cf5ccd108 Merge pull request #2948 from nlohmann/missing_header
Add header to use value_t
2021-08-18 20:07:05 +02:00
Niels Lohmann
5a04042cad Merge pull request #2947 from nlohmann/issue2946
Skip some tests if JSON_Install is not set
2021-08-18 20:06:44 +02:00
Niels Lohmann
f8bc22c741 Merge pull request #2945 from nlohmann/issue2941
Remove outdated json_unit test binary
2021-08-18 20:06:00 +02:00
Niels Lohmann
de4a6346c7 Merge pull request #2952 from nlohmann/fewer_appveyor_builds
Avoid duplicate AppVeyor builds
2021-08-18 20:04:25 +02:00
Niels Lohmann
f79bed6d39 👷 avoid duplicate AppVeyor builds 2021-08-18 19:53:35 +02:00
Arseniy Terekhin
355fa6c35c 🚨 gdb_pretty_printer failure on basic types
name can be None, and `re.search` fails on `None`;
replaced `re` by `str.startswith` and `str.endswith`
2021-08-18 19:29:50 +03:00
Amir Masoud Abdol
b65748f763 Using the homebrew/core Formula
I've submitted a PR on [homebrew/core](https://github.com/Homebrew/homebrew-core/pull/83479) that updates their Formula. After that one is set, we can merge this and let users use the default formula, and we don't have to maintain two separate Formulas.
2021-08-18 16:49:51 +02:00
Niels Lohmann
cfb71ad1bf 🐛 adding missing header 2021-08-18 13:33:35 +02:00
Niels Lohmann
54d9cd5a12 🔧 guard tests with JSON_Install flag 2021-08-18 13:24:12 +02:00
Niels Lohmann
5d3ad31d7e 🔥 remove outdated json_unit binary 2021-08-18 12:41:03 +02:00
Amir Masoud Abdol
8e4996c156 Updating the Homebrew Command
This resolves a conflict, and stops Homebrew from using the default formula.
2021-08-18 11:55:25 +02:00
Niels Lohmann
f42a74b8f5 Merge branch 'release/3.10.0' into develop 2021-08-17 20:40:42 +02:00
Niels Lohmann
0b7471b0f7 Merge branch 'release/3.10.0' 2021-08-17 20:40:25 +02:00
Niels Lohmann
1de378f580 🔖 set version to 3.10.0 2021-08-17 15:23:23 +02:00
Niels Lohmann
8cae9d7cd2 Overwork warning flags (#2936)
* ⚗️ update warning flags
2021-08-17 14:43:43 +02:00
Niels Lohmann
f1e63a8322 👷 run CI for release branches 2021-08-16 15:40:57 +02:00
Niels Lohmann
fa5d3b5a9b 👷 run CI for release branches 2021-08-15 22:49:31 +02:00
Niels Lohmann
09237272bc 👥 update documentation 2021-08-15 21:05:26 +02:00
Niels Lohmann
1300d2e4c3 Merge pull request #2908 from nlohmann/issue2863
Fix binary subtypes
2021-08-14 14:27:58 +02:00
Niels Lohmann
1aceeff3fc 🚨 fix C4244 warning 2021-08-14 13:40:52 +02:00
Niels Lohmann
0a0eb7a850 Merge branch 'develop' of https://github.com/nlohmann/json into issue2863
 Conflicts:
	.github/workflows/windows.yml
2021-08-14 11:19:48 +02:00
Niels Lohmann
6ac037c1f6 Merge pull request #2930 from nlohmann/msvc_warnings_as_error 2021-08-13 21:23:24 +02:00
Niels Lohmann
e5ef44c4dd Merge pull request #2927 from fhuberts/fix-switch-enum 2021-08-13 19:32:39 +02:00
Niels Lohmann
4b0e04eb68 🚨 fix C4100 warnings 2021-08-13 17:03:55 +02:00
Ferry Huberts
cdbc50b9a8 Again forgot to amalgate (sigh)
Signed-off-by: Ferry Huberts <ferry.huberts@pelagic.nl>
2021-08-13 15:33:05 +02:00
Ferry Huberts
364a21be6b Add coverage exclusion comments, as requested
Signed-off-by: Ferry Huberts <ferry.huberts@pelagic.nl>
2021-08-13 15:30:55 +02:00
Ferry Huberts
95b73bcd01 Forgot to amalgate
Signed-off-by: Ferry Huberts <ferry.huberts@pelagic.nl>
2021-08-13 14:22:18 +02:00
Niels Lohmann
288cdf9af7 ⚗️ add -WX flag to MSVC builds 2021-08-13 14:07:17 +02:00
Ferry Huberts
e7a69b8d31 Adjust more files after actually building like the CI
Signed-off-by: Ferry Huberts <ferry.huberts@pelagic.nl>
2021-08-13 14:00:00 +02:00
Niels Lohmann
fecb01858b ⚗️ add -WX flag to MSVC builds 2021-08-13 13:28:17 +02:00
Niels Lohmann
789280fcb2 🚨 fix C4309 warning 2021-08-13 13:20:26 +02:00
Niels Lohmann
e65db83448 ⚗️ add -WX flag to MSVC builds 2021-08-13 12:42:38 +02:00
Ferry Huberts
832cee5b77 Adjust warnings flags, as requested
Signed-off-by: Ferry Huberts <ferry.huberts@pelagic.nl>
2021-08-12 19:49:54 +02:00
Ferry Huberts
44d60f8d14 All: fix warnings when compiling with -Wswitch-enum
Signed-off-by: Ferry Huberts <ferry.huberts@pelagic.nl>
2021-08-12 16:33:50 +02:00
Niels Lohmann
910fabf8f0 Merge pull request #2925 from nlohmann/issue2924
Guard GCC pragmas
2021-08-12 07:58:50 +02:00
Niels Lohmann
e20f3f95eb 🚨 guard GCC pragmas #2924 2021-08-11 23:55:46 +02:00
Niels Lohmann
57d31d1b83 Merge pull request #2898 from nlohmann/issue2824
Add regression test
2021-08-11 13:02:49 +02:00
Niels Lohmann
8ae31a56a5 Merge branch 'develop' of https://github.com/nlohmann/json into issue2824 2021-08-11 08:06:32 +02:00
Niels Lohmann
68d8661f1b 📝 update documentation 2021-08-11 08:06:25 +02:00
Niels Lohmann
b792bf5660 ⚗️ try minimal example 2021-08-10 10:29:13 +02:00
Niels Lohmann
26569f8ecc ⚗️ try minimal example 2021-08-10 10:09:31 +02:00
Niels Lohmann
edc203a837 ⚗️ try minimal example 2021-08-10 08:35:14 +02:00
Niels Lohmann
0d530c9de8 ⚗️ try minimal example 2021-08-10 08:22:21 +02:00
Niels Lohmann
36394cc262 ⚗️ try minimal example 2021-08-09 21:58:05 +02:00
Niels Lohmann
83c005f881 ⚗️ try minimal example 2021-08-09 21:43:03 +02:00
Niels Lohmann
523f7c2c9d 💡 update documentation 2021-08-08 13:24:17 +02:00
Niels Lohmann
db7ccafbda 💚 fix MSVC build 2021-08-07 13:55:25 +02:00
Niels Lohmann
a4c3cf7798 💚 fix MSVC build 2021-08-07 13:40:01 +02:00
Niels Lohmann
346c9c1a19 💚 fix MSVC build 2021-08-07 13:37:17 +02:00
Niels Lohmann
c5928501b0 💚 fix MSVC build 2021-08-07 13:19:25 +02:00
Niels Lohmann
176e9bf0ab add tests for CBOR 2021-08-07 13:14:08 +02:00
Niels Lohmann
b74474e3fd 💚 fix MSVC build 2021-08-07 13:14:00 +02:00
Niels Lohmann
89c98dfc20 add option to process binary subtypes in CBOR 2021-08-06 16:41:01 +02:00
Niels Lohmann
51a9880022 add tests for CBOR 2021-08-06 15:31:11 +02:00
Niels Lohmann
b7db1d68d9 ♻️ fix CBOR and BSON 2021-08-06 14:36:38 +02:00
Niels Lohmann
046df035fa ♻️ change type of binary subtype 2021-08-06 13:45:35 +02:00
Niels Lohmann
3eb1fb6be7 ♻️ change type of binary subtype 2021-08-06 13:26:00 +02:00
Niels Lohmann
5c38e76c11 Merge branch 'develop' of https://github.com/nlohmann/json into issue2863 2021-08-06 13:23:26 +02:00
Niels Lohmann
359f6723fc Merge pull request #2911 from Finkman/develop
Supress -Wfloat-equal on intended float comparisions
2021-08-06 12:58:34 +02:00
Sven Fink
3f5545f99b Remove -Wfloat-equal suppressions on tests 2021-08-04 09:14:45 +02:00
Sven Fink
353d59717e Add more suppressions on float comparisons 2021-08-04 08:34:53 +02:00
Sven Fink
095aae19fe Supress -Wfloat-equal on intended float comparisions 2021-08-03 08:58:38 +02:00
Niels Lohmann
7c19aa2210 ♻️ overwork byte_container_with_subtype 2021-08-01 22:00:57 +02:00
Niels Lohmann
eb488bb4d9 📝 add note for wstring handling 2021-08-01 20:54:02 +02:00
Niels Lohmann
c3df4ffd5a 🚨 fix warning 2021-08-01 14:08:14 +02:00
Niels Lohmann
5a1bc76f34 ⚗️ switch off exceptions 2021-08-01 13:34:55 +02:00
Niels Lohmann
e7260f07f5 Merge branch 'develop' of https://github.com/nlohmann/json into issue2824 2021-08-01 13:07:43 +02:00
Niels Lohmann
a54403290e 📄 add CITATION file 2021-08-01 12:42:59 +02:00
Niels Lohmann
9ed027ac10 Merge pull request #2902 from nlohmann/issue2893
Fix useless-cast warnings
2021-07-31 20:42:55 +02:00
Niels Lohmann
8676f6745e add regression test #2824 2021-07-30 21:18:25 +02:00
Niels Lohmann
f4716a0d42 🚨 fix useless-cast warnings 2021-07-30 21:12:55 +02:00
Niels Lohmann
9a459e1bd5 🚨 fix useless-cast warnings 2021-07-30 15:20:22 +02:00
Niels Lohmann
c7822840eb add regression test #2824 2021-07-30 15:00:54 +02:00
Niels Lohmann
7feb2c20cf 🚨 fix useless-cast warnings 2021-07-30 14:48:25 +02:00
Niels Lohmann
2c030bac2c add regression test #2824 2021-07-30 14:41:06 +02:00
Niels Lohmann
1c030cccf1 add regression test #2824 2021-07-29 15:23:21 +02:00
Niels Lohmann
a563338039 Merge pull request #2825 from ldionne/ldionne-lazy
Properly constrain the basic_json conversion operator
2021-07-22 12:24:56 +02:00
Niels Lohmann
19a5e12136 CMake cleanup (#2885)
* 🔥 clean CMake files and Makefile
* 💡 update documentation
2021-07-22 09:25:55 +02:00
Niels Lohmann
eba82ecd62 Refactor Unicode tests (#2889)
* ♻️ split Unicode tests
2021-07-21 21:17:01 +02:00
Louis Dionne
b0e5965d71 Properly constrain the basic_json conversion operator
Fixes #2491
2021-07-19 11:16:27 -04:00
Niels Lohmann
03270ef090 👥 update contributors 2021-07-19 16:57:15 +02:00
Niels Lohmann
45016c4429 ⬆️ update Doxyfile 2021-07-19 16:56:43 +02:00
Niels Lohmann
7066ab128f 🎨 reindent code 2021-07-19 16:56:28 +02:00
Niels Lohmann
926fab47d0 📝 fix GIF examples #2457 2021-07-17 14:43:01 +02:00
Niels Lohmann
a0863b8c20 📝 add support section 2021-07-17 13:44:54 +02:00
Niels Lohmann
517aeec299 Merge remote-tracking branch 'origin/develop' into develop 2021-07-17 12:39:45 +02:00
Niels Lohmann
8f0a880c89 Merge pull request #2879 from nlohmann/issue2598
Avoid string in case of empty CBOR objects
2021-07-17 12:38:33 +02:00
Niels Lohmann
3db8903f29 📝 restructure README 2021-07-16 15:00:11 +02:00
Niels Lohmann
fb1ee4f94b 📝 update documentation 2021-07-16 14:41:14 +02:00
Niels Lohmann
835749efcc add test for JSON_SystemInclude flag 2021-07-16 12:34:15 +02:00
Niels Lohmann
fb31616a61 Merge remote-tracking branch 'origin/develop' into develop 2021-07-16 12:27:53 +02:00
Niels Lohmann
b2d21067d1 Merge pull request #2762 from jpl-mac/no.tidy.warnings.dev
Add a cmake option to use SYSTEM in target_include_directories
2021-07-16 12:06:26 +02:00
Niels Lohmann
c65369acbe 👷 fix Codacity badge 2021-07-16 11:44:07 +02:00
Niels Lohmann
f907f9502d Merge pull request #2875 from nlohmann/issue2592
Suppress C4127 warning in unit-json_pointer.cpp
2021-07-16 10:11:29 +02:00
Niels Lohmann
b7cc47089f avoid string in case of empty objects 2021-07-16 09:27:18 +02:00
Niels Lohmann
c89e23c69b Merge pull request #2874 from nlohmann/issue2572
Fix truncation warning
2021-07-16 07:54:48 +02:00
Niels Lohmann
f883ddd1c2 Merge pull request #2872 from nlohmann/issue2865
Fix memory leak in to_json
2021-07-16 06:52:28 +02:00
Niels Lohmann
92ec35735c Merge branch 'develop' of https://github.com/nlohmann/json into issue2592 2021-07-15 22:28:03 +02:00
Niels Lohmann
953dcfb611 🚨 fix warning #2572 2021-07-15 22:00:16 +02:00
Niels Lohmann
996ac1c017 Merge branch 'develop' of https://github.com/nlohmann/json into issue2572
 Conflicts:
	include/nlohmann/detail/output/serializer.hpp
	single_include/nlohmann/json.hpp
2021-07-15 21:57:52 +02:00
Niels Lohmann
3e4723a49f 🔨 remove noexcept annotation 2021-07-15 21:49:09 +02:00
Niels Lohmann
ecaac22656 💡 add comment to describe j.m_value.destroy(j.m_type) calls 2021-07-15 20:34:50 +02:00
Niels Lohmann
f6863e062c 🐛 fix leak for all types 2021-07-15 20:32:37 +02:00
Niels Lohmann
0011cd1b72 🐛 fix leak for strings 2021-07-15 13:12:21 +02:00
Niels Lohmann
0f8666ecdc 🐛 fix leak for strings 2021-07-15 13:03:20 +02:00
Niels Lohmann
c1298e69a6 🐛 fix leak for strings 2021-07-15 12:52:17 +02:00
Niels Lohmann
6cbdc83994 🐛 fix leak for strings 2021-07-15 12:47:15 +02:00
Niels Lohmann
149ded856f ♻️ simplify destroy() function for primitive types 2021-07-15 12:46:48 +02:00
Niels Lohmann
db98073930 add regression test 2021-07-15 09:02:24 +02:00
Niels Lohmann
c9c5c016a2 Merge pull request #2866 from nlohmann/issue2838 2021-07-14 12:04:37 +02:00
Niels Lohmann
4e92a61784 Merge pull request #2795 from turintech/develop
Specified git branch for google benchmark fetch in benchmark test
2021-07-13 16:58:25 +02:00
Niels Lohmann
a711e1f5a7 🚨 fix warnings 2021-07-13 15:37:57 +02:00
Niels Lohmann
3bb9467073 ♻️ move capacity check to set_parent function 2021-07-13 15:27:27 +02:00
Niels Lohmann
bc7e8faa4f 🔥 remove duplicated line 2021-07-12 19:21:07 +02:00
Niels Lohmann
b0730f29cf 🐛 fix logics 2021-07-12 15:24:06 +02:00
Niels Lohmann
d40e98ecef 🐛 fix assertion failure #2838 2021-07-12 13:38:28 +02:00
Niels Lohmann
9426074ce8 Merge pull request #2861 from nlohmann/documentation
Update documentation
2021-07-11 14:15:41 +02:00
Niels Lohmann
249688037f ⚗️ fix coverage 2021-07-11 09:33:43 +02:00
Niels Lohmann
7442c24662 🚨 suppress missingReturn warnings 2021-07-10 13:44:13 +02:00
Niels Lohmann
a82f66beed 📝 document JSON_NO_IO macro #2842 2021-07-10 12:51:18 +02:00
Niels Lohmann
5c8d0af5ce 📝 add comment for handling of negative zeros #2854 2021-07-10 12:50:59 +02:00
Niels Lohmann
098bbab029 Merge remote-tracking branch 'origin/develop' into develop 2021-07-06 08:46:51 +02:00
Niels Lohmann
71fd9bd954 📝 fix documentation (#2845) 2021-07-06 08:46:17 +02:00
Rafail Giavrimis
b7e493e98a Specified git branch for google benchmark fetch
The default branch was renamed from "master" to "main", which breaks the cloning process.
2021-06-27 17:52:28 +03:00
Niels Lohmann
6471a63115 Merge pull request #2729 from theShmoo/without-io
Possibility to use without the dependency to file io and streams to use in intel sgx enclaves
2021-06-26 12:50:06 +02:00
Niels Lohmann
624f59eacb Merge pull request #2826 from justanotheranonymoususer/patch-1
Consistency with `using` in README.md
2021-06-21 14:48:39 +02:00
justanotheranonymoususer
e970f31066 Update arbitrary_types.md 2021-06-18 12:44:27 +03:00
justanotheranonymoususer
c3d7fcb76c Update README.md 2021-06-18 11:04:53 +03:00
justanotheranonymoususer
9710108d6a Consistency with using in README.md 2021-06-17 21:39:29 +03:00
David Pfahler
572343be63 Merge branch 'nlohmann:develop' into without-io 2021-06-15 12:24:19 +02:00
Niels Lohmann
18a5f4c7ca Merge pull request #2790 from nlohmann/macos_standards
Add C++ standards to macOS matrix
2021-06-14 20:23:21 +02:00
David Pfahler
aa849a2275 Merge branch 'nlohmann:develop' into without-io 2021-06-14 08:22:49 +02:00
Niels Lohmann
71a514a651 Merge pull request #2770 from jasmcaus/patch-1
Keep consistent formatting
2021-06-14 07:18:46 +02:00
Niels Lohmann
fde6e1f800 Merge branch 'develop' of https://github.com/nlohmann/json into macos_standards 2021-06-14 07:17:47 +02:00
Niels Lohmann
95ad4ae071 Merge pull request #2817 from nlohmann/fix_ci
Fix CI
2021-06-14 07:16:32 +02:00
Niels Lohmann
802895b483 👷 remove Clang 10 2021-06-13 14:14:10 +02:00
Niels Lohmann
032f32ebe4 👷 add Clang 12 2021-06-13 14:04:20 +02:00
David Pfahler
e939b59683 fixed amalgation file for #2728 2021-05-31 14:27:23 +02:00
David Pfahler
ae9bbbc941 include io only if JSON_NO_IO is not set for #2728 2021-05-31 14:26:45 +02:00
Niels Lohmann
30e52eb046 👷 execute all tests 2021-05-30 13:28:58 +02:00
Niels Lohmann
2b685c744b 👷 reduce load 2021-05-29 13:10:28 +02:00
Niels Lohmann
9f5ee3f145 👷 fix syntax 2021-05-28 22:27:46 +02:00
Niels Lohmann
311730bc3d 👷 add C++ standards to macOS matrix #2491 2021-05-28 22:23:50 +02:00
Niels Lohmann
e10a3fac8a Merge pull request #2789 from TotalCaesar659/patch-2
Update URLs to HTTPS
2021-05-28 10:31:04 +02:00
TotalCaesar659
9a599ae63a Update URLs to HTTPS 2021-05-28 00:53:17 +03:00
Jason Dsouza
f118091eaa Update CMakeLists.txt 2021-05-15 23:39:15 +05:30
Niels Lohmann
0972f7ff0e Merge pull request #2771 from offa/conan_package_url
Link to Conan Center package added
2021-05-15 19:26:34 +02:00
offa
7935a683f5 link to conan package in readme 2021-05-12 16:46:32 +02:00
Jason Dsouza
6d7959e05d Keep consistent formatting 2021-05-12 19:25:06 +05:30
Niels Lohmann
7cafc5c63f 📝 document Drone CI 2021-05-10 14:23:27 +02:00
Niels Lohmann
e856b50791 🔥 remove arm build 2021-05-09 14:22:46 +02:00
Niels Lohmann
a44b29ecf1 🔧 fix paths 2021-05-09 13:52:16 +02:00
Niels Lohmann
014724f362 ⚗️ change path 2021-05-09 13:49:42 +02:00
Niels Lohmann
0c62748b75 🔧 change repository 2021-05-09 13:46:48 +02:00
Niels Lohmann
c73bd8b251 🔧 ignore certificate 2021-05-09 13:44:21 +02:00
Niels Lohmann
3685dbdcfd 🔧 checkout cmake via git 2021-05-09 13:41:40 +02:00
Niels Lohmann
9746f72d71 🔨 do not check certificate 2021-05-09 13:34:28 +02:00
Niels Lohmann
df6fa6c11c 👷 arm and arm64 2021-05-09 13:32:50 +02:00
Niels Lohmann
e6e7309514 👷 arm and arm64 2021-05-09 13:31:27 +02:00
Niels Lohmann
42f2512290 🔧 skip slow tests 2021-05-09 13:00:35 +02:00
Niels Lohmann
f3193e1e94 🔧 build ctest 2021-05-09 11:07:57 +02:00
Niels Lohmann
9ec8f4efa8 🔧 fix ctest path 2021-05-09 10:39:37 +02:00
Niels Lohmann
27a71ccdd8 🔧 fix path 2021-05-08 20:42:24 +02:00
Niels Lohmann
a6e2fd1b15 🔧 use built CMake 2021-05-08 14:41:43 +02:00
Niels Lohmann
77a5cd247e 🔧 build cmake 2021-05-08 13:56:19 +02:00
Niels Lohmann
1d8869f8bc 👷 add Drone CI 2021-05-08 13:33:30 +02:00
Jean-Philippe Lemieux
afbb84b2c8 Add a cmake option to use SYSTEM in target_include_directories
Without SYSTEM static analysis like clang-tidy raise warnings on
json.hpp.  This is not desirable for projects embedding nlohmann_json

Tests:
- Validated that without the option OFF the warnings are raised as
  before
- Validated that with the option ON the warnings are silenced
2021-05-05 16:19:24 -04:00
Niels Lohmann
fc2f7116fe Merge pull request #2756 from nlohmann/issue2755
replace EOF with std::char_traits<char>::eof()
2021-05-04 12:56:46 +02:00
Niels Lohmann
b08139ea4b ♻️ replace EOF with std::char_traits<char>::eof() 2021-05-04 10:22:34 +02:00
Niels Lohmann
d4f446592f Merge pull request #2754 from mortenfyhn/patch-1
Fix typo in README
2021-05-03 12:24:55 +02:00
Morten Fyhn Amundsen
193bf9d6b6 Fix typo in README 2021-05-03 09:46:00 +02:00
Niels Lohmann
b2e784c33b Merge pull request #2749 from nlohmann/docs 2021-04-29 23:05:33 +02:00
Niels Lohmann
d0ab2b86c3 📝 update documentation 2021-04-29 17:19:57 +02:00
Niels Lohmann
8a29a6ecf4 Merge pull request #2731 from theShmoo/custom-cpp-version
Fixes #2730
2021-04-29 09:55:16 +02:00
Niels Lohmann
07344fdd09 Merge pull request #2747 from nlohmann/docs
Add documentation for numbers
2021-04-28 22:06:25 +02:00
Niels Lohmann
cdfe865486 📝 add documentation for numbers 2021-04-28 20:33:05 +02:00
David Pfahler
d140a1c777 fixed amalgamation file 2021-04-26 08:39:24 +02:00
David Pfahler
5a77314c5e replaced define
JSON_VERSION_IS_PREDEFINED with JSON_HAS_CPP_11
2021-04-26 08:09:36 +02:00
Niels Lohmann
a34e011e24 Merge pull request #2576 from AnthonyVH/non_default_constructable_stl_containers
Add support for deserialization of STL containers of non-default constructable types (fixes #2574).
2021-04-25 15:22:37 +02:00
Niels Lohmann
f1600cd26b Merge pull request #2737 from nlohmann/upgrade_ci
Use Clang 12 in CI
2021-04-25 15:20:42 +02:00
Niels Lohmann
f6e9654aaa 🔇 suppress unsigned integer warnings 2021-04-25 14:33:12 +02:00
Niels Lohmann
52717b7473 👷 add clang 11 2021-04-24 14:27:13 +02:00
Niels Lohmann
608fbffcb1 📝 update compiler versions 2021-04-24 13:51:53 +02:00
Niels Lohmann
0638a27ed3 👷 add step for Infer 2021-04-24 13:50:30 +02:00
Niels Lohmann
10fc5162e7 ⬆️ use Clang 12 where available 2021-04-24 13:24:36 +02:00
Niels Lohmann
9774e53cd6 Merge pull request #2707 from raduteo/patch-2
Update json.hpp
2021-04-23 09:48:38 +02:00
David Pfahler
0a2de2f5b9 fixed amalgation file for #2728 2021-04-21 12:54:55 +02:00
David Pfahler
6b267e3cb1 fixed amalgation file for #2730 2021-04-21 12:53:58 +02:00
David Pfahler
38952643c5 generate amalgation to fix CI for #2730 2021-04-21 12:46:37 +02:00
David Pfahler
31c4c8f36c Fixes #2730
Added define JSON_VERSION_IS_PREDEFINED
for skipping automatic JSON_HAS_CPP_* detection
2021-04-21 11:03:28 +02:00
David Pfahler
1a1381f071 Fixes #2728
includes some macros to be defined for using without file io.
2021-04-21 10:24:01 +02:00
raduteo
35d79203ec Update json.hpp 2021-04-12 19:47:02 -04:00
raduteo
e8dbd7be86 Update json.hpp
Proposed fix for #2706
2021-04-09 09:35:58 -04:00
Niels Lohmann
7126d88803 Merge pull request #2690 from doronbehar/patch-1
pkg-config.pc.in: Don't concatenate paths
2021-03-30 07:50:28 +02:00
Doron Behar
53a9850eeb pkg-config.pc.in: Don't concatenate paths
See: https://github.com/jtojnar/cmake-snips#assuming-cmake_install_dir-is-relative-path
2021-03-29 21:43:49 +00:00
Niels Lohmann
3f33c21725 Merge pull request #2689 from nlohmann/ci_matrix
add more CI steps
2021-03-29 09:25:04 +02:00
Niels Lohmann
d927f44576 💚 fix build 2021-03-28 15:30:37 +02:00
Niels Lohmann
077fe41a82 🚧 do not check pushes to non-default branches 2021-03-28 14:59:42 +02:00
Niels Lohmann
ae99a31bea 🚧 add more CI tests 2021-03-28 14:48:58 +02:00
Niels Lohmann
f268035946 👷 consolidate CI 2021-03-28 13:37:04 +02:00
Niels Lohmann
1f1fa9f30e 🔥 remove some Travis builds 2021-03-27 14:44:39 +01:00
Niels Lohmann
c591b6ca6c 👷 move some MSVC jobs from AppVeyor to GitHub Actions 2021-03-27 10:43:05 +01:00
Niels Lohmann
5213ae56ac Merge pull request #2687 from musicinmybrain/nonconstant-sigstksz
Update doctest from 2.4.4 to 2.4.6 (fixes #2686)
2021-03-27 07:06:04 +01:00
Benjamin A. Beasley
ef826b6fba Update doctest from 2.4.4 to 2.4.6 (fixes #2686) 2021-03-25 13:16:04 -04:00
Niels Lohmann
823801879a Merge pull request #2683 from nlohmann/license_fix
License fix
2021-03-25 13:04:55 +01:00
Niels Lohmann
4a344e1ef0 Merge pull request #2375 from karzhenkov/fix-travis-release
Properly select "Release" build for Travis
2021-03-25 12:14:22 +01:00
Anthony VH
2b865131d8 Fixing CI errors. 2021-03-24 23:33:21 +01:00
Niels Lohmann
9d57351175 🐛 set correct value for JSON_ImplicitConversions in ci_test_noimplicitconversions 2021-03-24 20:27:12 +01:00
Alexander Karzhenkov
bf75a1b91d Merge branch 'develop' into #2375
# Conflicts:
#	.travis.yml
2021-03-24 20:33:35 +05:00
Anthony VH
8e79917d32 Fix clang-tidy complaints. 2021-03-24 13:27:59 +01:00
Niels Lohmann
41dbd50313 📄 use code from Google Abseil 2021-03-24 13:27:00 +01:00
Anthony VH
322bc99d8e Reran amalgamate. 2021-03-24 13:03:36 +01:00
Niels Lohmann
ca9a1f2fd4 📝 add note to outdated exceptions 2021-03-24 12:46:34 +01:00
Anthony VH
333612ce35 Merge remote-tracking branch 'upstream/develop' into non_default_constructable_stl_containers 2021-03-24 12:33:57 +01:00
Niels Lohmann
6f551930e5 🚨 add new CI and fix warnings (#2561)
* ⚗️ move CI targets to CMake
* ♻️ add target for cpplint
* ♻️ add target for self-contained binaries
* ♻️ add targets for iwyu and infer
* 🔊 add version output
* ♻️ add target for oclint
* 🚨 fix warnings
* ♻️ rename targets
* ♻️ use iwyu properly
* 🚨 fix warnings
* ♻️ use iwyu properly
* ♻️ add target for benchmarks
* ♻️ add target for CMake flags
* 👷 use GitHub Actions
* ⚗️ try to install Clang 11
* ⚗️ try to install GCC 11
* ⚗️ try to install Clang 11
* ⚗️ try to install GCC 11
* ⚗️ add clang analyze target
* 🔥 remove Google Benchmark
* ⬆️ Google Benchmark 1.5.2
* 🔥 use fetchcontent
* 🐧 add target to download a Linux version of CMake
* 🔨 fix dependency
* 🚨 fix includes
* 🚨 fix comment
* 🔧 adjust flags for GCC 11.0.0 20210110 (experimental)
* 🐳 user Docker image to run CI
* 🔧 add target for Valgrind
* 👷 add target for Valgrind tests
* ⚗️ add Dart
*  remove Dart
* ⚗️ do not call ctest in test subdirectory
* ⚗️ download test data explicitly
* ⚗️ only execute Valgrind tests
* ⚗️ fix labels
* 🔥 remove unneeded jobs
* 🔨 cleanup
* 🐛 fix OCLint call
*  add targets for offline and git-independent tests
*  add targets for C++ language versions and reproducible tests
* 🔨 clean up
* 👷 add CI steps for cppcheck and cpplint
* 🚨 fix warnings from Clang-Tidy
* 👷 add CI steps for Clang-Tidy
* 🚨 fix warnings
* 🔧 select proper binary
* 🚨 fix warnings
* 🚨 suppress some unhelpful warnings
* 🚨 fix warnings
* 🎨 fix format
* 🚨 fix warnings
* 👷 add CI steps for Sanitizers
* 🚨 fix warnings
*  add optimization to sanitizer build
* 🚨 fix warnings
* 🚨 add missing header
* 🚨 fix warnings
* 👷 add CI step for coverage
* 👷 add CI steps for disabled exceptions and implicit conversions
* 🚨 fix warnings
* 👷 add CI steps for checking indentation
* 🐛 fix variable use
* 💚 fix build
*  remove CircleCI
* 👷 add CI step for diagnostics
* 🚨 fix warning
* 🔥 clean Travis
2021-03-24 07:15:18 +01:00
Niels Lohmann
6b74772fe8 Merge pull request #2673 from remyjette/remove-exception-annotation
Remove HEDLEY annotation from exception::what()
2021-03-23 07:48:00 +01:00
Niels Lohmann
80e7d6fd9f Merge pull request #2679 from frasermarlow/patch-1
Update parse_exceptions.md - correct `json::exception::parse_error`
2021-03-23 07:44:32 +01:00
Niels Lohmann
098dd6bf34 Merge pull request #2659 from abbaswasim/patch-1
Fix amount of entries in the json object
2021-03-23 07:22:44 +01:00
Fraser
90d51b9205 Update parse_exceptions.md
Referring to https://github.com/nlohmann/json/blob/develop/doc/examples/parse_error.cpp  and https://json.nlohmann.me/home/exceptions/
(and also based on testing), the catch command should reference `catch (json::parse_error& ex)` and not `catch (json::exception::parse_error& ex)`
2021-03-18 12:25:12 -04:00
Remy Jette
0a9ec38f44 Remove HEDLEY annotation from exception::what()
The latest MSVC compiler throws the following warning on
nlohmann::detail::exception::what() if /analyze is enabled:

```
vcruntime_exception.h(93) : warning C28204: 'what' has an override at
`nlohmann\json\develop\single_include\nlohmann\json.hpp(2644)`
and only the override is annotated for return: when an override is
annotated, the base (this function) should be similarly annotated.
```

See https://godbolt.org/z/r331h4
2021-03-15 17:45:40 -07:00
abbaswasim
ddbdb65834 Fix amount of entries in the json object
After the initial j.push_back() calls there is another j.emplace_back() call that makes the size == 4 not 3.
2021-03-02 01:42:33 +00:00
Niels Lohmann
176d8e261a Merge pull request #2562 from nlohmann/diagnostics
Better diagnostics
2021-02-10 07:20:54 +01:00
Niels Lohmann
bb90e34d22 ⬆️ Hedley v15 2021-02-07 17:47:08 +01:00
Niels Lohmann
56a6dec0de 🔀 merge develop branch 2021-02-07 17:46:11 +01:00
Niels Lohmann
4917e7c259 Merge branch 'develop' of https://github.com/nlohmann/json into diagnostics
 Conflicts:
	include/nlohmann/detail/input/parser.hpp
	single_include/nlohmann/json.hpp
2021-02-07 17:45:09 +01:00
Niels Lohmann
e754ef7087 Merge pull request #2625 from wawiesel/patch-1
Fix missing 1.78 in example in README.md
2021-02-07 14:26:38 +01:00
William A. Wieselquist
567e2e3412 Fix missing 1.78 in example in README.md 2021-02-06 14:48:12 -05:00
Niels Lohmann
6d4eed5aeb 🚨 fix warning 2021-01-30 12:51:54 +01:00
Niels Lohmann
27b44cb17b Merge branch 'issue2615' of https://github.com/nlohmann/json into develop 2021-01-28 14:47:28 +01:00
Niels Lohmann
9f6b78ee5a 📝 add documentation 2021-01-27 14:34:10 +01:00
Niels Lohmann
5b0c804630 🐛 properly assign two labels to one test case #2596 2021-01-27 14:22:58 +01:00
Niels Lohmann
ffdeb77468 🚨 fix warnings #2615 2021-01-27 12:54:46 +01:00
Niels Lohmann
3b63a47270 🚨 suppress warning 2021-01-26 20:53:02 +01:00
Niels Lohmann
524eea5887 👌 remove unused template parameter 2021-01-26 17:49:15 +01:00
Niels Lohmann
74cc0ab470 ♻️ remove diagnostics_t class 2021-01-25 13:47:50 +01:00
Anthony VH
130382f2a9 Remove comment about GCC commit which didn't really relate to the code. 2021-01-24 20:02:24 +01:00
Niels Lohmann
e8dba10f53 add test 2021-01-24 17:45:48 +01:00
Niels Lohmann
c190a72f3d 👌 apply suggestion
Co-authored-by: Alexander Karzhenkov <karzhenkov@mail.ru>
2021-01-24 17:45:08 +01:00
Niels Lohmann
b83fe5dbf2 Merge pull request #2607 from nlohmann/issue1952
Add GDB pretty printer
2021-01-24 13:58:20 +01:00
Niels Lohmann
380a613f2b 🐛 fix bug in diagnostics_t 2021-01-23 20:58:59 +01:00
Anthony VH
848927ae90 Updated comments as requested. 2021-01-23 18:24:47 +01:00
Niels Lohmann
312a998873 🚸 add GDB pretty printer 2021-01-23 13:26:44 +01:00
Niels Lohmann
7b7da08fb6 📝 update documentation 2021-01-23 10:04:19 +01:00
Niels Lohmann
42218cac1b ⚗️ try 9 bytes 2021-01-21 22:01:09 +01:00
Niels Lohmann
d00ad33e46 📝 update documentation 2021-01-21 21:47:19 +01:00
Niels Lohmann
51ac6000d2 improve coverage 2021-01-21 13:36:23 +01:00
Niels Lohmann
d6ff059a90 👌 addressed review comments 2021-01-20 15:05:07 +01:00
Niels Lohmann
33379684b4 improve coverage 2021-01-17 22:52:40 +01:00
Niels Lohmann
5ec0980514 💚 fix build 2021-01-17 16:51:14 +01:00
Niels Lohmann
65107f7c9d 💚 fix build 2021-01-17 13:32:36 +01:00
Niels Lohmann
e23af7434d 🚨 fix warnings 2021-01-17 13:32:26 +01:00
Niels Lohmann
aeecc09ba1 add tests for diagnostics 2021-01-16 15:33:19 +01:00
Niels Lohmann
e9d641130d 🐛 proper JSON Pointer escape in diagnostic messages 2021-01-16 15:33:05 +01:00
Niels Lohmann
29f7abf57d 🚨 fix format-truncation warning #2572 2021-01-15 17:01:47 +01:00
Niels Lohmann
7633a21e6c 💚 fix build 2021-01-15 16:58:05 +01:00
Niels Lohmann
b0d8628c49 👌 address comments 2021-01-15 16:54:00 +01:00
Niels Lohmann
1a467a8c4e Merge branch 'develop' of https://github.com/nlohmann/json into diagnostics 2021-01-15 16:48:50 +01:00
Niels Lohmann
f8037660d0 ♻️ add iterator set_parent function 2021-01-14 22:43:52 +01:00
Niels Lohmann
92fa1d9582 Merge pull request #2582 from bl-ue/patch-1
readme: fix tilde character display
2021-01-14 22:11:33 +01:00
Niels Lohmann
0d1fb383b7 👌 address comment 2021-01-14 22:05:08 +01:00
bl-ue
c9d325b64b readme: fix tilde character display 2021-01-14 15:59:28 -05:00
Niels Lohmann
a77621687a 📝 fix comment 2021-01-14 21:56:19 +01:00
Niels Lohmann
b9d3aa4067 ♻️ split set_parent function 2021-01-14 21:55:49 +01:00
Niels Lohmann
10751d1189 Merge branch 'develop' of https://github.com/nlohmann/json into diagnostics 2021-01-14 21:38:48 +01:00
Anthony VH
6eb37e9b78 Only add conditional constexpr to get() for >= C++14 to work around errors on older compilers. 2021-01-14 12:41:30 +01:00
Anthony VH
d7c0f157c5 Merged from_json for pair and tuple to try to fix C2995 error in old MSVC versions. 2021-01-13 20:47:03 +01:00
Anthony VH
fbf6df63d9 Enable member function calls in trailing return decltype expressions for older compilers. 2021-01-13 00:12:51 +01:00
Anthony VH
fc8c584288 Regenerated single include. 2021-01-12 18:29:05 +01:00
Anthony VH
6ef1614fa9 Refactor json::get() to use priority_tag. 2021-01-12 18:28:47 +01:00
Anthony VH
6278f31d23 Simplify from_json overloads. 2021-01-12 18:28:29 +01:00
Anthony VH
6ebf274ca0 Add internal version of is_default_constructible to work around LWG 2367. 2021-01-12 18:28:00 +01:00
Anthony VH
672e8bfc1d Fixed std::pair trying to deserialize via array functions. 2021-01-11 18:16:15 +01:00
Niels Lohmann
14be8c69fe 💰 add sponsor 2021-01-11 08:00:49 +01:00
Niels Lohmann
ff57bdcc8b 🐛 fix invariants 2021-01-10 22:40:50 +01:00
Anthony VH
23f462b598 Reduced code duplication, renamed tag to identity_tag. 2021-01-10 19:23:32 +01:00
Niels Lohmann
9d0150c234 ♻️ simplify code 2021-01-10 15:04:14 +01:00
Niels Lohmann
1d6ba22f15 ♻️ simplify code 2021-01-10 14:10:59 +01:00
Niels Lohmann
a83404525e 🚨 fix warnings 2021-01-10 13:39:36 +01:00
Niels Lohmann
e160749003 ♻️ move diagnostic code in header 2021-01-09 19:21:18 +01:00
Anthony VH
1b113f73c2 Added extra tests to improve coverage. 2021-01-09 17:54:56 +01:00
Anthony VH
c0a8b45bbb Renamed template parameter and added some comments. 2021-01-09 17:45:56 +01:00
Anthony VH
1e825e4f92 Add support for deserialization of STL containers of non-default constructable types (fixes #2574). 2021-01-09 00:08:27 +01:00
Niels Lohmann
43cd5c8a4d 👌 fix constructor 2021-01-08 18:00:23 +01:00
Niels Lohmann
d4a91b7445 👌 clean operator[] 2021-01-08 11:29:28 +01:00
Niels Lohmann
e4af1ddb18 👌 fix operator[] 2021-01-08 11:21:41 +01:00
Niels Lohmann
04a0a07159 👌 fix move constructor and move assignment 2021-01-08 11:21:03 +01:00
Niels Lohmann
0617bd248d 👌 fix operator[] 2021-01-08 11:10:24 +01:00
Niels Lohmann
ddc3bb1992 👌 remove unnecessary assignment from destructor 2021-01-08 11:09:58 +01:00
Niels Lohmann
7cdf34b21e Merge branch 'develop' of https://github.com/nlohmann/json into diagnostics 2021-01-08 10:20:34 +01:00
Niels Lohmann
01f6b2e741 📄 update copyright year 2021-01-03 20:54:17 +01:00
Niels Lohmann
085d497bf7 📄 update copyright year 2021-01-03 20:28:06 +01:00
Niels Lohmann
294fa343d5 🐛 fix bug in move constructor 2021-01-03 20:06:32 +01:00
Niels Lohmann
ec0b1798bc 🚧 implement more parent relations 2021-01-02 21:36:11 +01:00
Niels Lohmann
7323a8eb4e 🚧 add tests 2021-01-02 16:13:04 +01:00
Niels Lohmann
09cd4ed125 🚧 fix preprocessor check 2021-01-02 14:10:40 +01:00
Niels Lohmann
c6e7fa21ed 🚧 fix preprocessor check 2021-01-02 13:58:05 +01:00
Niels Lohmann
ecaab32ef0 🚧 add switch for diagnostics 2021-01-02 13:45:00 +01:00
Niels Lohmann
7b047861b0 🚧 add diagnostics to exceptions 2021-01-02 13:44:41 +01:00
Niels Lohmann
a4d491e22d 🚧 better diagnostics 2021-01-01 17:23:10 +01:00
Niels Lohmann
68c3696382 Merge pull request #2560 from nlohmann/issue2324
Add switch to skip non-reproducible tests.
2020-12-31 14:35:45 +01:00
Niels Lohmann
1587acdb1d 📝 adjust wording 2020-12-31 14:34:37 +01:00
Niels Lohmann
be32cd0196 Merge branch 'develop' of https://github.com/nlohmann/json into issue2324 2020-12-31 14:33:09 +01:00
Niels Lohmann
00e3f69a26 ⬆️ update Doxyfile for doxygen 1.9.0 2020-12-30 20:31:16 +01:00
Niels Lohmann
581f92b601 Merge branch 'develop' of https://github.com/nlohmann/json into issue2324 2020-12-30 20:23:07 +01:00
Niels Lohmann
a8398a7151 Merge pull request #2550 from nlohmann/std_bytes
Allow parsing from std::byte containers
2020-12-30 08:33:52 +01:00
Niels Lohmann
fc7e181cbf ⚗️ fix string representation 2020-12-29 22:21:31 +01:00
Niels Lohmann
bdb2469c31 🚨 fix warnings 2020-12-29 21:36:30 +01:00
Niels Lohmann
c886646707 🚨 fix warning 2020-12-29 21:04:41 +01:00
Niels Lohmann
4402176df5 add regression test 2020-12-29 20:52:57 +01:00
Niels Lohmann
e4fc598466 ⚗️ add C++20 build 2020-12-29 20:45:56 +01:00
Niels Lohmann
77be4f6aaf ⚗️ add C++20 build 2020-12-29 20:32:07 +01:00
Niels Lohmann
91d7aa571f ⚗️ add C++20 build 2020-12-29 20:30:50 +01:00
Niels Lohmann
ca51dc62f2 ⚗️ try to use Clang 10 2020-12-29 20:21:43 +01:00
Niels Lohmann
433da31334 ⚗️ try to use GCC 10 2020-12-29 20:16:51 +01:00
Niels Lohmann
7b98df515f add regression test 2020-12-29 14:48:18 +01:00
Niels Lohmann
98b2152452 Merge branch 'develop' of https://github.com/nlohmann/json into std_bytes 2020-12-29 14:37:46 +01:00
Niels Lohmann
ff3863dc1d Merge pull request #2553 from jasujm/jasujm/input_adapter_custom_container
Fix compilation of input_adapter(container) in edge cases
2020-12-29 14:37:20 +01:00
Jaakko Moisio
467f622c65 Fix compilation of input_adapter(container) in edge cases
This fixes a compilation issue with the library if trying to use containers that
don't have non-member `begin()` and `end()` functions via ADL.

This patch extends the `using std::begin` and `using std::end` declarations to
also cover the return type deduction of the input_adapter() template
specialization for containers. The previous implementation only enabled the
detection of `std::begin()` and `std::end()` in the function body, making the
specialization unusable for container types that only have member `begin()` and
`end()` functions.

It is not typical to have `using` declarations in the namespace scope in a
header file. But a C++11 implementation can't rely on fully automatic return
type deduction, and needs to rely on ADL enabled helper templates. To prevent
the using declarations leaking, they are enclosed in another nested namespace.
2020-12-28 22:21:02 +01:00
Niels Lohmann
5dd06714b1 🐛 allow parsing from std::byte containers #2546 2020-12-28 11:31:21 +01:00
Niels Lohmann
dfedefb993 🚨 fix warnings 2020-12-26 17:56:16 +01:00
Alexander Karzhenkov
903b8a6e04 Build as "Debug" for coverage test 2020-12-26 21:14:16 +05:00
Niels Lohmann
f15d447522 🚨 fix warnings 2020-12-26 14:55:19 +01:00
Alexander Karzhenkov
10db9184a3 Configure Travis to build "Release" instead of "Debug" 2020-12-23 20:56:13 +05:00
Alexander Karzhenkov
7092890ff1 Properly select the build type for Travis 2020-12-22 18:24:00 +05:00
Niels Lohmann
f78d456075 Merge pull request #2540 from karzhenkov/disrupt-cxx17-tests
Travis doesn't run any tests in C++17 mode
2020-12-21 20:58:06 +01:00
Alexander Karzhenkov
9493f4beb1 Advance gcc library version for clang++-7 2020-12-20 23:50:28 +05:00
Alexander Karzhenkov
cd7acc1dc5 Include <string_view> in "nlohmann/json.hpp" when C++17 is used 2020-12-20 19:40:36 +05:00
Alexander Karzhenkov
39b8d6bd33 Restore intentionally disrupted C++17 tests 2020-12-20 12:43:35 +05:00
Alexander Karzhenkov
aae0e4959e Fix travis configuration to enable C++17 tests 2020-12-20 10:18:41 +05:00
Alexander Karzhenkov
8247a217bb Disrupt all C++17 tests to check if they are executed 2020-12-19 18:58:49 +05:00
Niels Lohmann
c3c574cf96 Merge pull request #2538 from YarikTH/feature/doctest_v2.4.3
Doctest is updated to v2.4.3
2020-12-18 22:10:42 +01:00
Krylov Yaroslav
a1772743a1 Doctest is updated to v2.4.3 2020-12-18 07:27:22 +03:00
Niels Lohmann
8593260044 Merge pull request #2537 from nlohmann/fix_warnings
Fix warnings
2020-12-17 21:48:16 +01:00
Niels Lohmann
c026e1a475 🚨 fix warnings 2020-12-16 21:44:35 +01:00
Niels Lohmann
af8c6e7aa9 Merge pull request #2533 from nlohmann/c++_future
Do not unconditionally redefine C++14 constructs
2020-12-16 20:54:09 +01:00
Niels Lohmann
5c1a5bc9c1 Merge pull request #2534 from nlohmann/clarify_license
Clarify license of is_complete_type implementation
2020-12-16 20:53:38 +01:00
Niels Lohmann
45810082d4 Merge pull request #2536 from nlohmann/shadowing
Fix a shadowing warning
2020-12-16 20:52:46 +01:00
Niels Lohmann
5cc5285fe8 🚨 fix shadowing warning 2020-12-15 22:15:36 +01:00
Niels Lohmann
94d177e09a 📄 clarify license 2020-12-14 14:58:59 +01:00
Niels Lohmann
467986fe98 ♻️ do not unconditionally redefine C++14 constructs 2020-12-14 14:31:27 +01:00
Niels Lohmann
2fc1f694ad Merge pull request #2514 from globberwops/develop
Add MAIN_PROJECT check for test and install options
2020-12-14 13:41:46 +01:00
Martin Stump
1771e9249f Remove comment on CTest inclusion
Co-authored-by: Niels Lohmann <niels.lohmann@gmail.com>
2020-12-14 10:59:38 +01:00
Niels Lohmann
85ffc85a29 🎨 amalgamate code 2020-12-14 10:38:49 +01:00
Martin Stump
ea759d0360 Compare to CMAKE_CURRENT_SOURCE_DIR for main project check 2020-12-13 20:34:51 +01:00
Niels Lohmann
97fe455ad5 Merge branch 'develop' of https://github.com/nlohmann/json into develop 2020-12-12 17:17:43 +01:00
Niels Lohmann
d028eff9e1 📦 add license to include.zip #2487 2020-12-12 17:17:38 +01:00
Niels Lohmann
be32cc4f5e Merge pull request #2525 from YarikTH/feature/doctest_v2.4.1
Doctest is updated to v2.4.1
2020-12-12 15:08:55 +01:00
Niels Lohmann
47c2004f7f Merge branch 'develop' of https://github.com/nlohmann/json into develop 2020-12-12 14:10:05 +01:00
Niels Lohmann
fc4040ce9d 🔨 clean up CI 2020-12-12 14:09:50 +01:00
Krylov Yaroslav
6390fca71a Doctest is updated to v2.4.1 2020-12-12 05:27:03 +03:00
Niels Lohmann
260be043ba Merge pull request #2406 from leozz37/develop
📝  add CPM.Cmake example
2020-12-11 14:47:18 +01:00
Niels Lohmann
5026acd70c Merge pull request #2444 from linev/fix_gcc48_warn
Change argument name "subtype" in byte_container_with_subtype
2020-12-11 13:46:41 +01:00
Sergey Linev
30dd0c0f09 Change underscore placement 2020-12-11 13:43:17 +01:00
Niels Lohmann
3ad6992f50 Merge pull request #2405 from karzhenkov/fix-json_ref-move
Fix move constructor of json_ref
2020-12-11 13:36:33 +01:00
Niels Lohmann
e3643aadf7 Merge pull request #2447 from jbzdarkid/develop
Add asserts to suppress C28020
2020-12-11 13:27:52 +01:00
Niels Lohmann
d9e2b191ad Merge pull request #2512 from YarikTH/issue2490
Ranged insert test section is added in unit-ordered_json.cpp
2020-12-11 13:21:33 +01:00
Martin Stump
790508887e Set MAIN_PROJECT=OFF initially 2020-12-09 12:39:44 +01:00
Martin Stump
5c589dd138 Add MAIN_PROJECT check for test and install options 2020-12-09 11:37:01 +01:00
Krylov Yaroslav
972c15f26e ordered_map::insert(InputIt first, InputIt last) is added 2020-12-07 20:15:41 +03:00
Krylov Yaroslav
5155cc2c48 Ranged insert test section is added in unit-ordered_json.cpp 2020-12-07 19:47:41 +03:00
Niels Lohmann
d8d8cbf6e0 🔨 fix site URL 2020-12-07 15:30:28 +01:00
Niels Lohmann
3322c9df6e 🔒 use HTTPS 2020-12-06 14:41:48 +01:00
jbzdarkid
cde29b3a11 Merge branch 'develop' of https://github.com/nlohmann/json into develop 2020-12-03 12:47:34 -08:00
Niels Lohmann
eaac918034 👷 remove clang9 CI 2020-12-02 08:58:45 +01:00
Joseph Blackman
9f45d314d5 Apply suggestions from code review
Co-authored-by: Niels Lohmann <niels.lohmann@gmail.com>
2020-11-24 11:02:58 -08:00
jbzdarkid
64ff1cf90d Add asserts to suppress C28020 2020-10-26 13:57:38 -07:00
Sergey Linev
71cb7d12da Change argument name "subtype" in byte_container_with_subtype
Fix warnings on older g++ 4.8

declaration of ‘subtype’ shadows a member of 'this'
2020-10-23 13:52:24 +02:00
Alexander Karzhenkov
42a9dc0bc3 Improve json_ref implementation 2020-09-27 10:45:21 +05:00
leozz37
b273f28dae 📝 add CPM.Cmake example 2020-09-26 19:16:03 -03:00
Niels Lohmann
fd7a9f6007 💰 add sponsor 2020-09-23 19:55:03 +02:00
Niels Lohmann
1bcabd9e83 📝 fix URLs to documentation 2020-09-02 22:25:32 +02:00
Niels Lohmann
1047d09b2a annotate non-reproducible tests #2324 2020-08-30 13:23:34 +02:00
Niels Lohmann
d9843fc9fc 📝 add note for Intel compilers #2346 2020-08-29 12:46:47 +02:00
Niels Lohmann
6030a11051 Merge pull request #2367 from nlohmann/hedley14
Update Hedley
2020-08-26 08:13:43 +02:00
Niels Lohmann
14f8be11ce Merge branch 'develop' of https://github.com/nlohmann/json into hedley14 2020-08-24 16:12:11 +02:00
Niels Lohmann
b9d76516a2 Merge pull request #2363 from nlohmann/issue2360
Fix and extend documentation of discarded values
2020-08-20 11:38:43 +02:00
Niels Lohmann
9d81eedb42 📝 fix and extend documentation of discarded values 2020-08-19 20:26:30 +02:00
Niels Lohmann
b386f4de0b 📝 fix and extend documentation of discarded values 2020-08-19 20:26:06 +02:00
Niels Lohmann
3be6ee3525 🚚 remove < from filename to fix Windows build 2020-08-16 21:39:40 +02:00
Niels Lohmann
fe507a7ee8 🚚 remove < from filename to fix Windows build 2020-08-16 21:36:21 +02:00
Niels Lohmann
6b04f05eba 📝 add more API documentation 2020-08-16 21:23:44 +02:00
Niels Lohmann
5c4cc20ed8 📝 add more API documentation 2020-08-16 20:48:10 +02:00
Niels Lohmann
a430d25f22 📝 add more API documentation 2020-08-16 14:48:48 +02:00
Niels Lohmann
fb5c20134f 📝 add more API documentation 2020-08-16 14:27:26 +02:00
Niels Lohmann
d8ed98a7af 📝 add more API documentation 2020-08-15 15:18:07 +02:00
Niels Lohmann
1ce0ed5a52 👷 ignore gh-pages branch in CircleCI 2020-08-14 13:58:55 +02:00
Niels Lohmann
0c2088823d 👷 ignore gh-pages branch in CircleCI 2020-08-14 13:56:42 +02:00
Niels Lohmann
fb8adb8e93 👷 ignore gh-pages branch in CircleCI 2020-08-14 13:52:42 +02:00
Niels Lohmann
f6c2947f1e 📝 add more API documentation 2020-08-14 13:47:54 +02:00
Niels Lohmann
0356e0c75b 📝 add more API documentation 2020-08-14 13:05:16 +02:00
Niels Lohmann
6674561d6a 📝 add more API documentation 2020-08-14 10:48:32 +02:00
Niels Lohmann
772f37c12d Merge pull request #2354 from rbuch/develop
Fix typos in documentation
2020-08-14 06:04:56 +02:00
Ronak Buch
67d822d951 Fix typos in documentation 2020-08-13 15:44:58 -04:00
Niels Lohmann
298420263b 🚚 remove quotes from filename to fix Windows build 2020-08-13 15:12:41 +02:00
Niels Lohmann
dd2fb3b454 📝 add more API documentation 2020-08-13 15:03:28 +02:00
Niels Lohmann
ce6adc447a 📝 add more API documentation 2020-08-13 14:04:08 +02:00
Niels Lohmann
d360fec216 📝 add offline pages for docset 2020-08-13 13:35:05 +02:00
Niels Lohmann
178125ff9b 📝 add docset 2020-08-13 10:52:20 +02:00
Niels Lohmann
8d0aa09ab5 Merge pull request #2352 from nlohmann/private_macro
Remove "#define private public" from tests
2020-08-13 10:06:59 +02:00
Niels Lohmann
874f49e945 📝 add more API documentation 2020-08-12 14:29:25 +02:00
Niels Lohmann
fe89049aee 📝 add more API documentation 2020-08-12 13:41:59 +02:00
Niels Lohmann
9d726c25d5 ♻️ remove "#define private public" 2020-08-12 13:30:06 +02:00
Niels Lohmann
411fc3249b ⬆️ Hedley 14 (dev branch) 2020-08-12 13:00:57 +02:00
Niels Lohmann
b888afe5f4 Merge pull request #2349 from nlohmann/issue2348
Remove -Wimplicit-fallthrough warning
2020-08-11 09:05:02 +02:00
Niels Lohmann
37ce871eeb Merge pull request #2347 from nlohmann/no_exceptions
Fix code to work without exceptions
2020-08-10 22:47:27 +02:00
Niels Lohmann
dd8cb2acc1 🚨 remove -Wimplicit-fallthrough warning #2348 2020-08-10 20:48:39 +02:00
Niels Lohmann
4080d0b1a4 add test to compile without exceptions 2020-08-10 09:48:11 +02:00
Niels Lohmann
1b28a58280 Merge remote-tracking branch 'origin/develop' into develop 2020-08-10 09:24:25 +02:00
Niels Lohmann
824d55bf26 📝 fix documentation #1668 2020-08-10 09:24:11 +02:00
Niels Lohmann
e030d26089 Merge pull request #2344 from ongjunjie/fix-cmake-overwrite-compiler
fix cmake script overwriting compiler path
2020-08-08 12:15:10 +02:00
Jun Jie
41a99567e0 fix cmake script overwriting compiler path
This fixes #2343
2020-08-07 16:08:02 +08:00
Niels Lohmann
db78ac1d77 Merge branch 'release/3.9.1' into develop 2020-08-06 13:49:29 +02:00
Niels Lohmann
350ff4f7ce Merge branch 'release/3.9.1' into master 2020-08-06 13:49:17 +02:00
Niels Lohmann
b3e5cb7f20 🔖 set version to 3.9.1 2020-08-06 13:45:29 +02:00
Niels Lohmann
f4155e4727 Merge pull request #2333 from nlohmann/fallthrough
Fix fallthrough warning
2020-08-01 15:32:21 +02:00
Niels Lohmann
8a54617240 Merge pull request #2332 from nlohmann/issue2330
Fix lexer to properly cope with repeated comments
2020-08-01 12:29:33 +02:00
Niels Lohmann
0326e4e2a6 🚨 fix fallthrough warning 2020-07-31 19:24:03 +02:00
Niels Lohmann
3888b1642a 🐛 fix lexer to properly cope with repeated comments #2330 2020-07-31 18:59:22 +02:00
Niels Lohmann
1da931730a Merge pull request #2327 from nlohmann/issue2326
Fix name of Homebrew formula in documentation
2020-07-31 08:00:08 +02:00
Niels Lohmann
1eedee5e4e Merge pull request #2319 from nlohmann/issue2315
Fix a bug due to missing overloads in ordered_map container
2020-07-31 07:59:18 +02:00
Niels Lohmann
501ad6fc59 📝 fix name of Homebrew formula #2326 2020-07-30 13:31:00 +02:00
Niels Lohmann
35daa5c00b Merge pull request #2320 from wx257osn2/fix-typo
fix typo
2020-07-30 12:27:16 +02:00
Niels Lohmann
2326abc547 ♻️ split regression tests 2020-07-30 12:13:05 +02:00
Niels Lohmann
f13af83a94 🐛 add more functions from std::map to nlohmann::ordered_map 2020-07-28 21:47:06 +02:00
I
2d3fe9d135 fix typo 2020-07-28 21:54:53 +09:00
Niels Lohmann
e590604822 🐛 fix a bug due to missing overloads in ordered_map container 2020-07-28 14:20:31 +02:00
Niels Lohmann
1b8efed06f Merge pull request #2318 from eli-schwartz/installfix
cmake: install pkg-config file relative to current_binary_dir
2020-07-28 13:25:04 +02:00
Niels Lohmann
7d01a9e875 Merge branch 'develop' into installfix 2020-07-28 13:24:54 +02:00
Niels Lohmann
b3da8b325a Merge pull request #2314 from xvitaly/fix-path
Fixed installation of pkg-config file on other than Ubuntu
2020-07-28 13:24:08 +02:00
Eli Schwartz
aa06a4761e cmake: install pkg-config file relative to current_binary_dir
When the testsuite is enabled, the "cmake_add_subdirectory" test
adds a second copy of the project into the build configuration, and the
project files are installed twice.

This becomes super problematic when it tries to install a file from
CMAKE_BINARY_DIR which is only available in CMAKE_CURRENT_BINARY_DIR
and bombs out with the following error message:

```
[...]
-- Installing: <DESTDIR>/usr/lib/cmake/nlohmann_json/nlohmann_jsonTargets.cmake
CMake Error at test/cmake_add_subdirectory/nlohmann_json/cmake_install.cmake:73 (file):
  file INSTALL cannot find
  "......./nlohmann-json/builddir/test/cmake_add_subdirectory/nlohmann_json.pc":
  No such file or directory.
Call Stack (most recent call first):
  test/cmake_add_subdirectory/cmake_install.cmake:47 (include)
  test/cmake_install.cmake:49 (include)
  cmake_install.cmake:94 (include)
```
2020-07-27 18:15:18 -04:00
Vitaly Zaitsev
8f9dc7eabe Fixed installation of pkg-config file on other than Ubuntu
distributions.

Signed-off-by: Vitaly Zaitsev <vitaly@easycoding.org>
2020-07-27 16:54:16 +02:00
Niels Lohmann
d34771cafc Merge branch 'release/3.9.0' into develop 2020-07-27 15:54:39 +02:00
Niels Lohmann
36e5ecf66d Merge branch 'release/3.9.0' 2020-07-27 15:54:24 +02:00
Niels Lohmann
e110667d21 🔖 set version to 3.9.0 2020-07-27 15:48:09 +02:00
Niels Lohmann
c006fc9bec 📝 add more documentation 2020-07-27 14:07:13 +02:00
Niels Lohmann
84c0c76849 🚧 add Clang-Tidy configuration 2020-07-27 09:15:57 +02:00
Niels Lohmann
2f05f5175c 🚧 add Clang-Tidy configuration 2020-07-26 22:38:14 +02:00
Niels Lohmann
1b06184f22 👥 update list of contributors 2020-07-26 20:50:04 +02:00
Niels Lohmann
84a899f511 👥 update list of contributors 2020-07-26 14:54:51 +02:00
Niels Lohmann
7a4841a42a 📝 add binary() function to SAX documentation 2020-07-26 14:40:46 +02:00
Niels Lohmann
bbcdf18ba5 🚚 move test utils header file 2020-07-26 14:07:34 +02:00
Niels Lohmann
e22cbacc41 🚨 fix warning 2020-07-26 12:12:17 +02:00
Niels Lohmann
67ed63b196 Merge pull request #2312 from nlohmann/docs
Update documentation
2020-07-26 10:06:01 +02:00
Niels Lohmann
a34070d36a fix test for meta() function 2020-07-25 22:28:14 +02:00
Niels Lohmann
9c75c7eace 🔧 clean generated XML files 2020-07-25 22:04:42 +02:00
Niels Lohmann
7bd6242f04 📝 add more documentation 2020-07-25 22:00:28 +02:00
Niels Lohmann
808aca41aa Merge pull request #2305 from AODQ/develop
fixes unused variable 'ex' for #2304
2020-07-25 21:51:54 +02:00
Niels Lohmann
63e7c40e35 Merge pull request #2297 from nlohmann/issue2286
Add support for high-precision numbers in UBJSON encoding
2020-07-25 21:50:53 +02:00
Niels Lohmann
1816aae862 Merge branch 'develop' of https://github.com/nlohmann/json into docs 2020-07-25 21:48:51 +02:00
Niels Lohmann
980f8c6f61 🔀 merge develop branch 2020-07-25 21:45:47 +02:00
Niels Lohmann
42f8708940 Merge branch 'develop' of https://github.com/nlohmann/json into issue2286
 Conflicts:
	single_include/nlohmann/json.hpp
2020-07-25 21:44:58 +02:00
Niels Lohmann
40b78d3847 Merge pull request #2308 from nlohmann/cbor_tags
Fix bug in CBOR tag handling
2020-07-25 19:43:11 +02:00
Niels Lohmann
fad14aabe7 📝 update output of meta function 2020-07-25 14:41:06 +02:00
Niels Lohmann
6e5be17b62 📝 add more documentation 2020-07-25 14:40:50 +02:00
Niels Lohmann
62f98b7537 Merge branch 'develop' of https://github.com/nlohmann/json into docs 2020-07-25 11:20:13 +02:00
Niels Lohmann
a1dbfcd736 Merge pull request #2306 from jwittbrodt/develop
added inline to NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE macro
2020-07-25 10:52:56 +02:00
Niels Lohmann
c00c3162b2 Merge branch 'develop' into develop 2020-07-25 10:52:42 +02:00
Niels Lohmann
448ceb2e12 Merge pull request #2303 from nlohmann/cleanup
Cleanup
2020-07-25 05:41:51 +02:00
aodq
15ec0fe150 change c-style cast to static_cast for #2304 2020-07-24 16:21:30 -04:00
Niels Lohmann
58167173a2 📝 add more documentation 2020-07-24 15:25:53 +02:00
Niels Lohmann
d8d499ce9b 📝 add more documentation 2020-07-24 14:35:52 +02:00
Niels Lohmann
480ad529e3 🐛 fix bug in CBOR tag handling 2020-07-24 14:18:39 +02:00
Niels Lohmann
a84370c61f 📝 add more documentation 2020-07-24 14:04:58 +02:00
Niels Lohmann
33662417c1 improve coverage 2020-07-24 09:32:03 +02:00
Jonas Wittbrodt
0f22ed0b5b added inline to DEFINE_TYPE macro 2020-07-23 19:24:21 +02:00
aodq
12885446d8 fixes unused variable 'ex' for #2304 2020-07-23 13:21:38 -04:00
Niels Lohmann
3c7dc635e7 🙈 extend ignore list 2020-07-23 14:19:57 +02:00
Niels Lohmann
27232455c8 📝 update documentation 2020-07-23 14:17:02 +02:00
Niels Lohmann
59cb7674be 📝 update documentation 2020-07-23 14:15:20 +02:00
Niels Lohmann
0cd120f7e1 🚨 fix UBSAN warning 2020-07-23 14:06:09 +02:00
Niels Lohmann
bba57cc4af 🚨 fix UBSAN warning 2020-07-23 14:02:49 +02:00
Niels Lohmann
e571c67c0d 🚨 fix implicit conversion warning when opening binary file 2020-07-23 14:02:12 +02:00
Niels Lohmann
43e07bb92d Merge pull request #2301 from nlohmann/regression2281
Add test with multiple translation units
2020-07-23 13:14:24 +02:00
Niels Lohmann
fb22233f34 🔊 add message if implicit conversions are switched off 2020-07-23 13:11:48 +02:00
Niels Lohmann
f9b71afebf 🚚 unify cmake build dir names 2020-07-23 13:02:53 +02:00
Niels Lohmann
8159091d8f 🔀 rename variable to avoid shadowing 2020-07-23 12:58:09 +02:00
Niels Lohmann
230dcfb7a3 🚨 add prefix to avoid shadowing 2020-07-23 12:57:52 +02:00
Niels Lohmann
b315fe484a 🔀 merge develop branch 2020-07-23 12:30:26 +02:00
Niels Lohmann
a33c3fdf25 Merge branch 'develop' of https://github.com/nlohmann/json into issue2286
 Conflicts:
	single_include/nlohmann/json.hpp
2020-07-23 12:30:07 +02:00
Niels Lohmann
88122467bd ♻️ pull code into function 2020-07-23 12:16:18 +02:00
Niels Lohmann
a048b72fe1 Merge pull request #1559 from theodelrieu/feat/explicit_conversion_operator
Feat/explicit conversion operator
2020-07-23 08:52:51 +02:00
Niels Lohmann
484029b51c Merge pull request #2299 from nlohmann/fix_warnings
Fix unused parameter
2020-07-22 18:43:33 +02:00
Niels Lohmann
a6d112ffbf add regression test for #2281 2020-07-22 13:39:40 +02:00
Niels Lohmann
2301bd1177 add regression test for #2281 2020-07-22 13:24:07 +02:00
Niels Lohmann
c4356c68e0 add regression test for #2281 2020-07-22 12:38:39 +02:00
Niels Lohmann
4d63252c6c add regression test for #2281 2020-07-22 12:23:58 +02:00
Niels Lohmann
a7c4c84d68 add regression test for #2281 2020-07-22 12:03:37 +02:00
Théo DELRIEU
797329315a add a CI job for explicit conversions on every os 2020-07-22 10:49:01 +02:00
Théo DELRIEU
74b446f5fd add a switch to enable implicit conversions (defaults to true)
wrap implicit conversions tests around the JSON_USE_IMPLICIT_CONVERSIONS
macro
2020-07-22 10:49:01 +02:00
Niels Lohmann
2cd10a7405 Merge pull request #2300 from nlohmann/gihub_actions
Merge Gitlab actions
2020-07-22 09:45:55 +02:00
Niels Lohmann
6bd38a2cb9 👷 merge Gitlab actions 2020-07-22 09:02:55 +02:00
Niels Lohmann
8b14c9b305 🚨 fix warnings 2020-07-21 23:00:56 +02:00
Niels Lohmann
3bb43ecd51 🔀 merge develop branch 2020-07-21 22:02:14 +02:00
Niels Lohmann
3249a4d821 Merge branch 'develop' of https://github.com/nlohmann/json into issue2286
 Conflicts:
	single_include/nlohmann/json.hpp
2020-07-21 22:01:32 +02:00
Niels Lohmann
96e9f66025 🔇 remove debug output 2020-07-21 22:01:15 +02:00
Niels Lohmann
8046754c15 🔊 add debug output to tests 2020-07-21 12:44:38 +02:00
Niels Lohmann
b1903fff1f 💚 fix build 2020-07-21 09:09:30 +02:00
Niels Lohmann
1339d6b683 🐛 add missing EOF check 2020-07-20 22:40:28 +02:00
Niels Lohmann
a9117828e1 🚨 fix warnings 2020-07-20 22:38:00 +02:00
Niels Lohmann
8344857764 Merge pull request #2287 from pfeatherstone/develop
Serialisation macros: increase upper bound on number of member variables
2020-07-20 21:35:55 +02:00
Niels Lohmann
4a5277d09d 📝 update documentation 2020-07-20 14:11:43 +02:00
Niels Lohmann
8aa6da61dc 🚧 support for UBJSON high-precision numbers #2286 2020-07-20 13:57:19 +02:00
Niels Lohmann
7360e09830 🚧 support for UBJSON high-precision numbers #2286 2020-07-20 13:12:20 +02:00
pf
35b899e988 [JSON] initialise all member variables. Maybe this will shut valgrind up. std::tie probably wasn't the problem initially 2020-07-20 10:51:43 +01:00
Niels Lohmann
7cf2fe149c 🚧 support for UBJSON high-precision numbers #2286 2020-07-20 09:42:37 +02:00
pf
7660ea12f6 [JSON] drop use of std::tie and std::tupe for operator== overload. valgrind and clang < 4 complain 2020-07-20 08:31:56 +01:00
Niels Lohmann
893eda8353 Merge pull request #2294 from jprochazk/develop
fix eof for get_binary and get_string
2020-07-20 08:02:03 +02:00
pf
678d310b85 [JSON] don't know why CHECK doesn't like "CHECK(obj1 == obj2)". So using a temporary bool. 2020-07-19 21:29:39 +01:00
pf
e83ddb185d [JSON] use CHECK from doctest 2020-07-19 21:25:27 +01:00
pf
254f0e3cee [JSON] CHECK in doctest only accepts std::string ? Use assert statement instead. Does the job 2020-07-19 18:22:16 +01:00
pf
578217eaa3 [JSON] doctest: need another section ? 2020-07-19 18:17:03 +01:00
pf
6d9b2040ab [JSON] as per Nlohmann's suggestion, added unit tests for the (de)serialisation macros 2020-07-19 18:12:13 +01:00
pf
75a6888d55 [JSON] since we no longer use a netbeans project for the (de)serialisation macro building code, can revert the changes made to the .gitignore file 2020-07-19 18:11:37 +01:00
pf
8f14aaa13f [JSON] as per Nlohmann's suggestion, moved the macro builder code to third_party directory 2020-07-19 18:10:08 +01:00
jprochazk
851315c878 add regression test 2020-07-19 18:35:58 +02:00
pf
f7374c9a8d Merge branch 'develop' of https://github.com/pfeatherstone/json into develop 2020-07-19 17:32:35 +01:00
pf
0a158ee830 [JSON] rough and ready code for generating (de)serialisation macros. Current upper bound on number of member variables is set to 64 2020-07-19 17:32:16 +01:00
pf
21bd6e971b [JSON] - dirty code for building intrusive and non-intrusive serialisation/deserialisation macros for custom types
- updated .gitignore file to ignore private netbeans project configurations
2020-07-19 17:26:56 +01:00
pf
0b744e1ed0 [JSON] - dirty code for building intrusive and non-intrusive serialisation/deserialisation macros for custom types
- used code to increase the upper bound on number of member variables to 64
2020-07-19 17:26:56 +01:00
pf
8a045713ed [JSON] - dirty code for building intrusive and non-intrusive serialisation/deserialisation macros for custom types
- used code to increase the upper bound on number of member variables to 64
2020-07-19 17:26:56 +01:00
pf
a575008c48 [JSON] - dirty code for building intrusive and non-intrusive serialisation/deserialisation macros for custom types
- updated .gitignore file to ignore "dist" and "build" directories in netbeans project
2020-07-19 17:26:56 +01:00
pf
5eb739a585 [JSON] - dirty code for building intrusive and non-intrusive serialisation/deserialisation macros for custom types
- netbeans project configurations
2020-07-19 17:26:56 +01:00
pf
68122fe0ed [JSON] dirty code for building intrusive and non-intrusive serialisation/deserialisation macros for custom types 2020-07-19 17:26:56 +01:00
Niels Lohmann
b1da58b76b Merge pull request #2282 from nlohmann/missing_sax_check
Add static assertion for missing binary function in SAX interface
2020-07-19 18:09:08 +02:00
Niels Lohmann
1fd6c5882a Merge pull request #2285 from T0b1-iOS/develop
add inline specifier for detail::combine
2020-07-19 17:55:51 +02:00
jprochazk
d371a5283c run amalgamate 2020-07-19 10:57:17 +02:00
jprochazk
ab25de05f7 fix: return -> result.push_back 2020-07-19 10:51:13 +02:00
jprochazk
a3a9d5665e add break to binary_reader::get_binary and get_string 2020-07-19 09:35:49 +02:00
pf
0d2d088b97 [JSON] - dirty code for building intrusive and non-intrusive serialisation/deserialisation macros for custom types
- updated .gitignore file to ignore private netbeans project configurations
2020-07-18 16:13:56 +01:00
pf
c122d8a94f [JSON] - dirty code for building intrusive and non-intrusive serialisation/deserialisation macros for custom types
- used code to increase the upper bound on number of member variables to 64
2020-07-18 16:12:49 +01:00
pf
4706d6e976 [JSON] - dirty code for building intrusive and non-intrusive serialisation/deserialisation macros for custom types
- used code to increase the upper bound on number of member variables to 64
2020-07-18 16:12:27 +01:00
pf
9afe757648 [JSON] - dirty code for building intrusive and non-intrusive serialisation/deserialisation macros for custom types
- updated .gitignore file to ignore "dist" and "build" directories in netbeans project
2020-07-18 16:11:34 +01:00
pf
8730af0788 [JSON] - dirty code for building intrusive and non-intrusive serialisation/deserialisation macros for custom types
- netbeans project configurations
2020-07-18 16:10:32 +01:00
pf
beb1fb48f0 [JSON] dirty code for building intrusive and non-intrusive serialisation/deserialisation macros for custom types 2020-07-18 16:08:29 +01:00
T0b1-iOS
88243b3f8c run amalgamate 2020-07-18 07:09:56 +02:00
T0b1-iOS
281349d0d6 add inline specifier for detail::combine 2020-07-18 06:28:11 +02:00
Niels Lohmann
43ab8a2357 Merge pull request #2279 from nlohmann/issue1818
Add test for target_include_directories
2020-07-18 06:12:57 +02:00
Niels Lohmann
7fc4b2901a 🚸 add static assertion for missing binary function in SAX interface 2020-07-17 20:41:11 +02:00
Niels Lohmann
2fd57d3ed1 add test for target_include_directories #1818 2020-07-17 14:26:22 +02:00
Niels Lohmann
a10d486e36 Merge pull request #2244 from matthewbauer/tag-cbor
Tag binary values in cbor if set
2020-07-17 14:05:48 +02:00
Niels Lohmann
e65cc9dccb Merge pull request #2274 from nlohmann/analyzers
Clean up maintainer Makefiles and fix some linter warnings
2020-07-17 14:01:19 +02:00
Niels Lohmann
548e7e54c9 Merge pull request #2273 from nlohmann/issue1968
Add option to ignore CBOR tags
2020-07-17 13:59:55 +02:00
Niels Lohmann
6023a7ccd9 Merge branch 'develop' into analyzers 2020-07-17 13:59:32 +02:00
Niels Lohmann
270f1ae482 Merge pull request #2269 from nlohmann/hash
Hash function without allocation
2020-07-17 13:57:47 +02:00
Niels Lohmann
d047b3d495 🚨 remove linter warning 2020-07-16 14:45:39 +02:00
Niels Lohmann
26196f25f6 🔥 remove test Makefile targets (all handled by CMake) 2020-07-16 13:38:25 +02:00
Niels Lohmann
3d60befde3 🔧 adjust analysis targets 2020-07-16 12:14:06 +02:00
Niels Lohmann
7f6ea47bdb 🔧 adjust analysis targets 2020-07-16 09:44:07 +02:00
Niels Lohmann
4c59d6aaef 🔥 remove leftover 2020-07-16 09:43:35 +02:00
Niels Lohmann
23c97f4aa5 Merge pull request #2268 from t-b/feature/add-clang-cl
Add ClangCL for MSVC
2020-07-16 07:40:58 +02:00
Niels Lohmann
93cdf05928 add tests 2020-07-15 14:23:22 +02:00
Niels Lohmann
01e196f6b6 Merge branch 'develop' of https://github.com/nlohmann/json into issue1968 2020-07-15 13:50:00 +02:00
Niels Lohmann
b821ed074f 💡 add documentation 2020-07-15 13:45:16 +02:00
Niels Lohmann
496ddd127c 💚 make test deterministic 2020-07-15 12:14:30 +02:00
Niels Lohmann
9449dfcc6a 💚 add test cases for hash 2020-07-15 09:27:01 +02:00
Thomas Braun
25a59b59f2 Github Actions: Add ClangCL on Windows
MS Visual Studio 2019 has builtin support for other compiler toolsets [1].

This commit adds support for compiling using LLVM/Clang 10 using Visual
Studio.

ClangCL pretends to be MSVC so the usual MSVC flags apply, see also [2].
For detecting if ClangCL is used, newer cmake verisons (>= 3.15) have
builtin support using CMAKE_CXX_COMPILER_FRONTEND_VARIANT [3], for older
ones a workaround is available using CMAKE_CXX_SIMULATE_ID [4].

[1]: https://devblogs.microsoft.com/cppblog/clang-llvm-support-in-visual-studio/
[2]: https://clang.llvm.org/docs/UsersManual.html#clang-cl
[3]: https://stackoverflow.com/a/10055571
[4]: 4fe34b2d29
2020-07-14 16:02:44 +02:00
Thomas Braun
6d7f8b3793 README.md: Remove trailing whitespace 2020-07-14 15:36:42 +02:00
Niels Lohmann
33b0bed7fe 💚 fix compilation 2020-07-14 14:34:55 +02:00
Niels Lohmann
5b229f4cce hash function without allocation 2020-07-14 14:31:19 +02:00
Niels Lohmann
1a521cbd36 Merge pull request #2264 from t-b/feature/use-proper-SED-in-makefile
Makefile: Always use SED variable
2020-07-14 14:07:33 +02:00
Niels Lohmann
8921e5e5db Merge pull request #2262 from nlohmann/more_ci
Add Xcode 12 CI
2020-07-13 21:04:57 +02:00
Thomas Braun
88adffdaba Makefile: Always use SED variable
We need to have a proper sed, even on MacOSX. So let's use the variable
introduced in 191aa0fd (🔧 overworked maintaner targets,
2019-03-28) in more places.
2020-07-13 14:44:40 +02:00
Niels Lohmann
938b867450 📝 add Xcode 12 to CI list 2020-07-12 21:45:00 +02:00
Niels Lohmann
3952739189 add CBOR tag handler #1968 2020-07-12 16:51:43 +02:00
Niels Lohmann
a244531627 ♻️ overwork Travis YAML 2020-07-12 15:33:16 +02:00
Matthew Bauer
dd08f7705f Add simple test for cbor byte 2020-07-06 18:06:10 -04:00
Matthew Bauer
e54f03f73b Tag binary values in cbor if set
CBOR has tags, which work similarly to "subtype"s:

https://www.iana.org/assignments/cbor-tags/cbor-tags.xhtml

Unsure if this makes sense. Note that the subtype must just be one
byte wide.
2020-07-02 17:40:02 -04:00
Niels Lohmann
fbec662afa Merge branch 'release/3.8.0' 2020-06-14 17:44:01 +02:00
Niels Lohmann
456478b3c5 Merge branch 'release/3.7.3' 2019-11-17 12:21:32 +01:00
Niels Lohmann
5f09b502b6 Merge branch 'release/3.7.2' 2019-11-10 21:39:02 +01:00
Niels Lohmann
43e4db6141 Merge branch 'release/3.7.1' 2019-11-06 20:33:52 +01:00
Niels Lohmann
ea60d40f4a Merge branch 'release/3.7.0' 2019-07-28 21:23:24 +02:00
Niels Lohmann
3c4c69a24e 🚨 fix linter warning 2019-07-21 13:56:13 +02:00
Niels Lohmann
295732a817 Merge branch 'release/3.6.1' 2019-03-20 21:03:30 +01:00
Niels Lohmann
944267f522 Merge branch 'release/3.6.0' 2019-03-20 00:38:16 +01:00
Niels Lohmann
cebb4e052a Merge branch 'release/3.5.0' 2018-12-22 00:01:18 +01:00
Niels Lohmann
6708f22cd4 Merge branch 'release/3.4.0' 2018-10-30 22:20:12 +01:00
Niels Lohmann
aafad2be1f Merge branch 'release/3.3.0' 2018-10-05 12:59:28 +02:00
Niels Lohmann
8c20571136 Merge branch 'release/3.2.0' 2018-08-20 19:36:10 +02:00
Niels Lohmann
183390c10b Merge branch 'release/3.1.2' 2018-03-14 21:47:50 +01:00
Niels Lohmann
c8ea63a31b Merge branch 'release/3.1.1' 2018-02-13 19:36:20 +01:00
Niels Lohmann
15acf260ca Merge branch 'release/3.1.0' 2018-02-02 00:05:55 +01:00
Niels Lohmann
a43347e1f9 Merge branch 'develop' 2017-12-29 20:35:02 +01:00
Niels Lohmann
5681e55da8 Merge branch 'release/3.0.1' 2017-12-29 20:24:20 +01:00
Niels Lohmann
9f81beb5e2 Merge branch 'release/3.0.0' 2017-12-17 11:04:04 +01:00
Niels Lohmann
c0d511ea50 🔀 merge branch 'release/2.1.1' 2017-02-25 16:36:46 +01:00
Niels Lohmann
1e99a0273f 🔀 merge branch 'release/2.1.0' 2017-01-28 18:42:27 +01:00
Niels Lohmann
528bc96d7e Merge branch 'develop' 2017-01-02 16:41:33 +01:00
Niels Lohmann
1c98ce869c 🔀 merge branch 'release/2.0.10' 2017-01-02 16:37:52 +01:00
Niels Lohmann
6df60b0448 🔀 Merge branch 'release/2.0.9' 2016-12-16 21:34:54 +01:00
Niels Lohmann
272ebdc900 🔖 Merge branch 'release/2.0.8' 2016-12-02 20:07:14 +01:00
Niels
79a9d00e15 Merge branch 'develop' 2016-11-03 18:54:59 +01:00
Niels
a4d13c92ba Merge branch 'release/2.0.7' 2016-11-02 20:52:24 +01:00
Niels
60bba02cc6 Merge branch 'release/2.0.6' 2016-10-15 16:47:56 +02:00
392 changed files with 27076 additions and 20943 deletions

View File

@@ -1,48 +0,0 @@
version: 2
jobs:
build_stable:
docker:
- image: debian:stretch
steps:
- checkout
- run:
name: Install required tools
command: 'apt-get update && apt-get install -y gcc g++ git cmake'
- run:
name: Run CMake
command: 'mkdir build ; cd build ; cmake .. -DJSON_BuildTests=On'
- run:
name: Compile
command: 'cmake --build build'
- run:
name: Execute test suite
command: 'cd build ; ctest --output-on-failure -j 2'
build_bleeding_edge:
docker:
- image: archlinux
steps:
- checkout
- run:
name: Install required tools
command: 'pacman -Sy --noconfirm base base-devel gcc git cmake'
- run:
name: Run CMake
command: 'mkdir build ; cd build ; cmake .. -DJSON_BuildTests=On'
- run:
name: Compile
command: 'cmake --build build'
- run:
name: Execute test suite
command: 'cd build ; ctest --output-on-failure -j 2'
workflows:
version: 2
build_and_test_all:
jobs:
- build_stable
- build_bleeding_edge

84
.clang-format Normal file
View File

@@ -0,0 +1,84 @@
#AccessModifierOffset: 2
AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: false
#AlignConsecutiveBitFields: false
AlignConsecutiveDeclarations: false
AlignConsecutiveMacros: false
AlignEscapedNewlines: Right
#AlignOperands: AlignAfterOperator
AlignTrailingComments: true
AllowAllArgumentsOnNextLine: false
AllowAllConstructorInitializersOnNextLine: false
AllowAllParametersOfDeclarationOnNextLine: false
AllowShortBlocksOnASingleLine: Empty
AllowShortCaseLabelsOnASingleLine: false
#AllowShortEnumsOnASingleLine: true
AllowShortFunctionsOnASingleLine: Empty
AllowShortIfStatementsOnASingleLine: Never
AllowShortLambdasOnASingleLine: Empty
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: Yes
BinPackArguments: false
BinPackParameters: false
#BitFieldColonSpacing: Both
BreakBeforeBraces: Custom # or Allman
BraceWrapping:
AfterCaseLabel: true
AfterClass: true
AfterControlStatement: Always
AfterEnum: true
AfterFunction: true
AfterNamespace: false
AfterStruct: true
AfterUnion: true
AfterExternBlock: false
BeforeCatch: true
BeforeElse: true
#BeforeLambdaBody: false
#BeforeWhile: false
SplitEmptyFunction: false
SplitEmptyRecord: false
SplitEmptyNamespace: false
BreakBeforeTernaryOperators: true
BreakConstructorInitializers: BeforeComma
BreakStringLiterals: false
ColumnLimit: 0
CompactNamespaces: false
ConstructorInitializerIndentWidth: 2
Cpp11BracedListStyle: true
PointerAlignment: Left
FixNamespaceComments: true
IncludeBlocks: Preserve
#IndentCaseBlocks: false
IndentCaseLabels: true
IndentGotoLabels: false
IndentPPDirectives: BeforeHash
IndentWidth: 4
KeepEmptyLinesAtTheStartOfBlocks: false
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ReflowComments: false
SortIncludes: true
SortUsingDeclarations: true
SpaceAfterCStyleCast: false
SpaceAfterLogicalNot: false
SpaceAfterTemplateKeyword: false
SpaceBeforeAssignmentOperators: true
SpaceBeforeCpp11BracedList: false
SpaceBeforeParens: ControlStatements
SpaceBeforeRangeBasedForLoopColon: true
SpaceBeforeSquareBrackets: false
SpaceInEmptyBlock: false
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 2
SpacesInAngles: false
SpacesInCStyleCastParentheses: false
SpacesInConditionalStatement: false
SpacesInContainerLiterals: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: c++11
TabWidth: 4
UseTab: Never

View File

@@ -1,23 +1,47 @@
Checks: '*,
-altera-struct-pack-align,
-android-cloexec-fopen,
-concurrency-mt-unsafe,
-cppcoreguidelines-avoid-goto,
-cppcoreguidelines-avoid-magic-numbers,
-cppcoreguidelines-avoid-non-const-global-variables,
-cppcoreguidelines-macro-usage,
-cppcoreguidelines-pro-bounds-array-to-pointer-decay,
-cppcoreguidelines-pro-bounds-constant-array-index,
-cppcoreguidelines-pro-bounds-pointer-arithmetic,
-cppcoreguidelines-pro-type-reinterpret-cast,
-cppcoreguidelines-pro-type-union-access,
-fuchsia-default-arguments-calls,
-fuchsia-default-arguments-declarations,
-fuchsia-overloaded-operator,
-google-explicit-constructor,
-google-readability-function-size,
-google-runtime-int,
-google-runtime-references,
-hicpp-avoid-goto,
-hicpp-explicit-conversions,
-hicpp-function-size,
-hicpp-no-array-decay,
-hicpp-no-assembler,
-hicpp-signed-bitwise,
-hicpp-uppercase-literal-suffix,
-llvm-header-guard,
-llvm-include-order,
-llvmlibc-*,
-misc-no-recursion,
-misc-non-private-member-variables-in-classes,
-modernize-use-trailing-return-type,
-readability-function-size,
-readability-function-cognitive-complexity,
-readability-magic-numbers,
-readability-redundant-access-specifiers,
-readability-uppercase-literal-suffix'
CheckOptions:
- key: hicpp-special-member-functions.AllowSoleDefaultDtor
value: 1
WarningsAsErrors: '*'
#HeaderFilterRegex: '.*nlohmann.*'
HeaderFilterRegex: '.*hpp$'

22
.drone.yml Normal file
View File

@@ -0,0 +1,22 @@
kind: pipeline
name: test-on-arm64
platform:
arch: arm64
steps:
- name: build
image: gcc
commands:
- wget https://github.com/Kitware/CMake/releases/download/v3.20.2/cmake-3.20.2.tar.gz
- tar xfz cmake-3.20.2.tar.gz
- cd cmake-3.20.2
- ./configure
- make cmake ctest -j10
- cd ..
- mkdir build
- cd build
- ../cmake-3.20.2/bin/cmake .. -DJSON_FastTests=ON
- make -j10
- cd test
- ../../cmake-3.20.2/bin/ctest -j10

View File

@@ -58,7 +58,7 @@ To make changes, you need to edit the following files:
- Specifically, I am aware of compilation problems with **Microsoft Visual Studio** (there even is an [issue label](https://github.com/nlohmann/json/issues?utf8=✓&q=label%3A%22visual+studio%22+) for these kind of bugs). I understand that even in 2016, complete C++11 support isn't there yet. But please also understand that I do not want to drop features or uglify the code just to make Microsoft's sub-standard compiler happy. The past has shown that there are ways to express the functionality such that the code compiles with the most recent MSVC - unfortunately, this is not the main objective of the project.
- Please refrain from proposing changes that would **break [JSON](https://json.org) conformance**. If you propose a conformant extension of JSON to be supported by the library, please motivate this extension.
- We shall not extend the library to **support comments**. There is quite some [controversy](https://www.reddit.com/r/programming/comments/4v6chu/why_json_doesnt_support_comments_douglas_crockford/) around this topic, and there were quite some [issues](https://github.com/nlohmann/json/issues/376) on this. We believe that JSON is fine without comments.
- We do not preserve the **insertion order of object elements**. The [JSON standard](https://tools.ietf.org/html/rfc7159.html) defines objects as "an unordered collection of zero or more name/value pairs". To this end, this library does not preserve insertion order of name/value pairs. (In fact, keys will be traversed in alphabetical order as `std::map` with `std::less` is used by default.) Note this behavior conforms to the standard, and we shall not change it to any other order. If you do want to preserve the insertion order, you can specialize the object type with containers like [`tsl::ordered_map`](https://github.com/Tessil/ordered-map) or [`nlohmann::fifo_map`](https://github.com/nlohmann/fifo_map).
- We do not preserve the **insertion order of object elements**. The [JSON standard](https://tools.ietf.org/html/rfc8259.html) defines objects as "an unordered collection of zero or more name/value pairs". To this end, this library does not preserve insertion order of name/value pairs. (In fact, keys will be traversed in alphabetical order as `std::map` with `std::less` is used by default.) Note this behavior conforms to the standard, and we shall not change it to any other order. If you do want to preserve the insertion order, you can specialize the object type with containers like [`tsl::ordered_map`](https://github.com/Tessil/ordered-map) or [`nlohmann::fifo_map`](https://github.com/nlohmann/fifo_map).
- Please do not open pull requests that address **multiple issues**.

View File

@@ -47,7 +47,7 @@ assignees: ''
<!-- Please add an `x` to the respective line. -->
- [ ] latest release version 3.7.3
- [ ] latest release version 3.10.4
- [ ] other release - please state the version: ___
- [ ] the `develop` branch

View File

@@ -2,10 +2,11 @@ name: "Code scanning - action"
on:
push:
branches: [develop, ]
branches:
- develop
- master
- release/*
pull_request:
# The branches below must be a subset of the branches above
branches: [develop]
schedule:
- cron: '0 19 * * 1'

View File

@@ -1,17 +1,44 @@
name: macOS
on: [push, pull_request]
on:
push:
branches:
- develop
- master
- release/*
pull_request:
jobs:
build:
runs-on: macos-latest
xcode:
runs-on: macos-10.15
strategy:
matrix:
xcode: [12.4, 12.3, 12.2, 12.1.1, 12.1, 12, 11.7, 11.6, 11.5, 11.4.1, 11.3.1, 11.2.1, 10.3]
env:
DEVELOPER_DIR: /Applications/Xcode_${{ matrix.xcode }}.app/Contents/Developer
steps:
- uses: actions/checkout@v1
- name: cmake
run: cmake -S . -B build -D CMAKE_BUILD_TYPE=Debug -DJSON_BuildTests=On
- name: build
run: cmake --build build --parallel 10
- name: test
run: cd build ; ctest -j 10 --output-on-failure
- uses: actions/checkout@v2
- name: cmake
run: cmake -S . -B build -D CMAKE_BUILD_TYPE=Debug -DJSON_BuildTests=On -DJSON_FastTests=ON
- name: build
run: cmake --build build --parallel 10
- name: test
run: cd build ; ctest -j 10 --output-on-failure
xcode_standards:
runs-on: macos-10.15
strategy:
matrix:
standard: [11, 14, 17, 20]
env:
DEVELOPER_DIR: /Applications/Xcode_12.4.app/Contents/Developer
steps:
- uses: actions/checkout@v2
- name: cmake
run: cmake -S . -B build -D CMAKE_BUILD_TYPE=Debug -DJSON_BuildTests=On -DCMAKE_CXX_STANDARD=${{ matrix.standard }} -DCMAKE_CXX_STANDARD_REQUIRED=ON
- name: build
run: cmake --build build --parallel 10
- name: test
run: cd build ; ctest -j 10 --output-on-failure

View File

@@ -1,17 +1,103 @@
name: Ubuntu
on: [push, pull_request]
on:
push:
branches:
- develop
- master
- release/*
pull_request:
jobs:
build:
ci_test_clang:
runs-on: ubuntu-latest
container: ghcr.io/nlohmann/json-ci:v1.0.0
steps:
- uses: actions/checkout@v1
- name: cmake
run: cmake -S . -B build -D CMAKE_BUILD_TYPE=Debug -DJSON_BuildTests=On
- name: build
run: cmake --build build --parallel 10
- name: test
run: cd build ; ctest -j 10 --output-on-failure
- uses: actions/checkout@v2
- name: cmake
run: cmake -S . -B build -DJSON_CI=On
- name: build
run: cmake --build build --target ci_test_clang
ci_test_gcc:
runs-on: ubuntu-latest
container: ghcr.io/nlohmann/json-ci:v1.0.0
steps:
- uses: actions/checkout@v2
- name: cmake
run: cmake -S . -B build -DJSON_CI=On
- name: build
run: cmake --build build --target ci_test_gcc
ci_static_analysis:
runs-on: ubuntu-latest
container: ghcr.io/nlohmann/json-ci:v1.0.0
strategy:
matrix:
target: [ci_clang_tidy, ci_cppcheck, ci_test_valgrind, ci_test_clang_sanitizer, ci_test_amalgamation, ci_clang_analyze, ci_cpplint, ci_cmake_flags, ci_single_binaries, ci_reproducible_tests, ci_non_git_tests, ci_offline_testdata, ci_infer]
steps:
- uses: actions/checkout@v2
- name: cmake
run: cmake -S . -B build -DJSON_CI=On
- name: build
run: cmake --build build --target ${{ matrix.target }}
ci_cmake_options:
runs-on: ubuntu-latest
container: ghcr.io/nlohmann/json-ci:v1.0.0
strategy:
matrix:
target: [ci_test_diagnostics, ci_test_noexceptions, ci_test_noimplicitconversions]
steps:
- uses: actions/checkout@v2
- name: cmake
run: cmake -S . -B build -DJSON_CI=On
- name: build
run: cmake --build build --target ${{ matrix.target }}
ci_test_coverage:
runs-on: ubuntu-latest
container: ghcr.io/nlohmann/json-ci:v1.0.0
steps:
- uses: actions/checkout@v2
- name: cmake
run: cmake -S . -B build -DJSON_CI=On
- name: build
run: cmake --build build --target ci_test_coverage
- name: archive coverage report
uses: actions/upload-artifact@v2
with:
name: code-coverage-report
path: /__w/json/json/build/html
- name: Coveralls
uses: coverallsapp/github-action@master
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
path-to-lcov: /__w/json/json/build/json.info.filtered.noexcept
ci_test_compilers:
runs-on: ubuntu-latest
container: ghcr.io/nlohmann/json-ci:v1.0.0
strategy:
matrix:
compiler: [g++-4.8, g++-4.9, g++-5, g++-7, g++-8, g++-9, g++-10, clang++-3.5, clang++-3.6, clang++-3.7, clang++-3.8, clang++-3.9, clang++-4.0, clang++-5.0, clang++-6.0, clang++-7, clang++-8, clang++-9, clang++-10, clang++-11, clang++-12]
steps:
- uses: actions/checkout@v2
- name: cmake
run: cmake -S . -B build -DJSON_CI=On
- name: build
run: cmake --build build --target ci_test_compiler_${{ matrix.compiler }}
ci_test_standards:
runs-on: ubuntu-latest
container: ghcr.io/nlohmann/json-ci:v1.0.0
strategy:
matrix:
standard: [11, 14, 17, 20]
compiler: [gcc, clang]
steps:
- uses: actions/checkout@v2
- name: cmake
run: cmake -S . -B build -DJSON_CI=On
- name: build
run: cmake --build build --target ci_test_${{ matrix.compiler }}_cxx${{ matrix.standard }}

View File

@@ -1,17 +1,128 @@
name: Windows
on: [push, pull_request]
on:
push:
branches:
- develop
- master
- release/*
pull_request:
jobs:
build:
mingw:
runs-on: windows-latest
strategy:
matrix:
architecture: [x64, x86]
steps:
- uses: actions/checkout@v2
- name: Set up MinGW
uses: egor-tensin/setup-mingw@v2
with:
platform: ${{ matrix.architecture }}
- name: cmake
run: cmake -S . -B build -G "MinGW Makefiles" -DCMAKE_BUILD_TYPE=Debug -DJSON_BuildTests=On
- name: build
run: cmake --build build --parallel 10
- name: test
run: cd build ; ctest -j 10 -C Debug --output-on-failure
msvc2017:
runs-on: windows-2016
strategy:
matrix:
build_type: [Debug, Release]
architecture: [Win32, x64]
steps:
- uses: actions/checkout@v2
- name: cmake
run: cmake -S . -B build -G "Visual Studio 15 2017" -A ${{ matrix.architecture }} -DJSON_BuildTests=On -DCMAKE_CXX_FLAGS="/W4 /WX"
if: matrix.build_type == 'Release' && matrix.architecture == 'x64'
- name: cmake
run: cmake -S . -B build -G "Visual Studio 15 2017" -A ${{ matrix.architecture }} -DJSON_BuildTests=On -DCMAKE_CXX_FLAGS="/W4 /WX"
if: matrix.build_type == 'Release' && matrix.architecture != 'x64'
- name: cmake
run: cmake -S . -B build -G "Visual Studio 15 2017" -A ${{ matrix.architecture }} -DJSON_BuildTests=On -DJSON_FastTests=ON -DCMAKE_CXX_FLAGS="/W4 /WX"
if: matrix.build_type == 'Debug'
- name: build
run: cmake --build build --config ${{ matrix.build_type }} --parallel 10
- name: test
run: cd build ; ctest -j 10 -C ${{ matrix.build_type }} --output-on-failure
msvc2017_latest:
runs-on: windows-2016
steps:
- uses: actions/checkout@v2
- name: cmake
run: cmake -S . -B build -G "Visual Studio 15 2017" -DJSON_BuildTests=On -DCMAKE_CXX_FLAGS="/permissive- /std:c++latest /utf-8 /W4 /WX"
- name: build
run: cmake --build build --config Release --parallel 10
- name: test
run: cd build ; ctest -j 10 -C Release --output-on-failure
msvc2019:
runs-on: windows-latest
strategy:
matrix:
build_type: [Debug, Release]
architecture: [Win32, x64]
steps:
- uses: actions/checkout@v2
- name: cmake
run: cmake -S . -B build -G "Visual Studio 16 2019" -A ${{ matrix.architecture }} -DJSON_BuildTests=On -DCMAKE_CXX_FLAGS="/W4 /WX"
if: matrix.build_type == 'Release'
- name: cmake
run: cmake -S . -B build -G "Visual Studio 16 2019" -A ${{ matrix.architecture }} -DJSON_BuildTests=On -DJSON_FastTests=ON -DCMAKE_CXX_FLAGS="/W4 /WX"
if: matrix.build_type == 'Debug'
- name: build
run: cmake --build build --config ${{ matrix.build_type }} --parallel 10
- name: test
run: cd build ; ctest -j 10 -C ${{ matrix.build_type }} --output-on-failure
msvc2019_latest:
runs-on: windows-latest
steps:
- uses: actions/checkout@v1
- uses: actions/checkout@v2
- name: cmake
run: cmake -S . -B build -G "Visual Studio 16 2019" -D CMAKE_BUILD_TYPE=Debug -DJSON_BuildTests=On
run: cmake -S . -B build -G "Visual Studio 16 2019" -DJSON_BuildTests=On -DCMAKE_CXX_FLAGS="/permissive- /std:c++latest /utf-8 /W4 /WX"
- name: build
run: cmake --build build --parallel 10
run: cmake --build build --config Release --parallel 10
- name: test
run: cd build ; ctest -j 10 -C Debug --exclude-regex "test-unicode" --output-on-failure
run: cd build ; ctest -j 10 -C Release --output-on-failure
clang:
runs-on: windows-latest
strategy:
matrix:
version: [11, 12]
steps:
- uses: actions/checkout@v2
- name: install Clang
run: curl -fsSL -o LLVM${{ matrix.version }}.exe https://github.com/llvm/llvm-project/releases/download/llvmorg-${{ matrix.version }}.0.0/LLVM-${{ matrix.version }}.0.0-win64.exe ; 7z x LLVM${{ matrix.version }}.exe -y -o"C:/Program Files/LLVM"
- name: cmake
run: cmake -S . -B build -DCMAKE_CXX_COMPILER="C:/Program Files/LLVM/bin/clang++.exe" -G"MinGW Makefiles" -DCMAKE_BUILD_TYPE=Debug -DJSON_BuildTests=On
- name: build
run: cmake --build build --parallel 10
- name: test
run: cd build ; ctest -j 10 -C Debug --exclude-regex "test-unicode" --output-on-failure
clang-cl-11:
runs-on: windows-latest
strategy:
matrix:
architecture: [Win32, x64]
steps:
- uses: actions/checkout@v2
- name: cmake
run: cmake -S . -B build -G "Visual Studio 16 2019" -A ${{ matrix.architecture }} -T ClangCL -DJSON_BuildTests=On
- name: build
run: cmake --build build --config Debug --parallel 10
- name: test
run: cd build ; ctest -j 10 -C Debug --exclude-regex "test-unicode" --output-on-failure

View File

@@ -1,32 +0,0 @@
name: Windows
on: [push, pull_request]
jobs:
clang9:
runs-on: windows-latest
steps:
- uses: actions/checkout@v1
- name: install Clang
run: curl -fsSL -o LLVM9.exe https://releases.llvm.org/9.0.0/LLVM-9.0.0-win64.exe ; 7z x LLVM9.exe -y -o"C:/Program Files/LLVM"
- name: cmake
run: cmake -S . -B build -DCMAKE_CXX_COMPILER="C:/Program Files/LLVM/bin/clang++.exe" -G"MinGW Makefiles" -DCMAKE_BUILD_TYPE=Debug -DJSON_BuildTests=On
- name: build
run: cmake --build build --parallel 10
- name: test
run: cd build ; ctest -j 10 -C Debug --exclude-regex "test-unicode" --output-on-failure
clang10:
runs-on: windows-latest
steps:
- uses: actions/checkout@v1
- name: install Clang
run: curl -fsSL -o LLVM10.exe https://github.com/llvm/llvm-project/releases/download/llvmorg-10.0.0/LLVM-10.0.0-win64.exe ; 7z x LLVM10.exe -y -o"C:/Program Files/LLVM"
- name: cmake
run: cmake -S . -B build -DCMAKE_CXX_COMPILER="C:/Program Files/LLVM/bin/clang++.exe" -G"MinGW Makefiles" -DCMAKE_BUILD_TYPE=Debug -DJSON_BuildTests=On
- name: build
run: cmake --build build --parallel 10
- name: test
run: cd build ; ctest -j 10 -C Debug --exclude-regex "test-unicode" --output-on-failure

9
.gitignore vendored
View File

@@ -12,23 +12,22 @@ build
build_coverage
clang_analyze_build
doc/xml
doc/html
me.nlohmann.json.docset
benchmarks/files/numbers/*.json
.wsjcpp-logs/*
.wsjcpp/*
.idea
cmake-build-debug
/cmake-build-*
test/test-*
/.vs
doc/html
doc/mkdocs/venv/
doc/mkdocs/docs/images
doc/mkdocs/docs/examples
doc/mkdocs/site
doc/mkdocs/docs/__pycache__/
/doc/docset/JSON_for_Modern_C++.docset/
/doc/docset/JSON_for_Modern_C++.tgz

View File

@@ -10,17 +10,6 @@ sudo: required
group: edge
###################
# global settings #
###################
env:
global:
# The next declaration is the encrypted COVERITY_SCAN_TOKEN, created
# via the "travis encrypt" command using the project repo's public key
- secure: "m89SSgE+ASLO38rSKx7MTXK3n5NkP9bIx95jwY71YEiuFzib30PDJ/DifKnXxBjvy/AkCGztErQRk/8ZCvq+4HXozU2knEGnL/RUitvlwbhzfh2D4lmS3BvWBGS3N3NewoPBrRmdcvnT0xjOGXxtZaJ3P74TkB9GBnlz/HmKORA="
################
# build matrix #
################
@@ -28,87 +17,6 @@ env:
matrix:
include:
# Valgrind
- os: linux
compiler: gcc
env:
- COMPILER=g++-4.9
- CMAKE_OPTIONS=-DJSON_Valgrind=ON
addons:
apt:
sources: ['ubuntu-toolchain-r-test']
packages: ['g++-4.9', 'valgrind', 'ninja-build']
# clang sanitizer
- os: linux
compiler: clang
env:
- COMPILER=clang++-7
- CMAKE_OPTIONS=-DJSON_Sanitizer=ON
- UBSAN_OPTIONS=print_stacktrace=1,suppressions=$(pwd)/test/src/UBSAN.supp
addons:
apt:
sources: ['ubuntu-toolchain-r-test', 'llvm-toolchain-trusty-7']
packages: ['g++-6', 'clang-7', 'ninja-build']
before_script:
- export PATH=$PATH:/usr/lib/llvm-7/bin
# cppcheck
- os: linux
compiler: gcc
env:
- COMPILER=g++-4.9
- SPECIAL=cppcheck
addons:
apt:
sources: ['ubuntu-toolchain-r-test']
packages: ['g++-4.9', 'cppcheck', 'ninja-build']
after_success:
- make cppcheck
# no exceptions
- os: linux
compiler: gcc
env:
- COMPILER=g++-4.9
- CMAKE_OPTIONS=-DJSON_NoExceptions=ON
addons:
apt:
sources: ['ubuntu-toolchain-r-test']
packages: ['g++-4.9', 'ninja-build']
# check amalgamation
- os: linux
compiler: gcc
env:
- COMPILER=g++-4.9
- SPECIAL=amalgamation
- MULTIPLE_HEADERS=ON
addons:
apt:
sources: ['ubuntu-toolchain-r-test']
packages: ['g++-4.9', 'astyle', 'ninja-build']
after_success:
- make check-amalgamation
# Coveralls (http://gronlier.fr/blog/2015/01/adding-code-coverage-to-your-c-project/)
- os: linux
compiler: gcc
dist: bionic
addons:
apt:
sources: ['ubuntu-toolchain-r-test']
packages: ['g++-7', 'ninja-build']
before_script:
- pip install --user cpp-coveralls
after_success:
- coveralls --build-root test --include include/nlohmann --gcov 'gcov-7' --gcov-options '\-lp'
env:
- COMPILER=g++-7
- CMAKE_OPTIONS=-DJSON_Coverage=ON
- MULTIPLE_HEADERS=ON
# Coverity (only for branch coverity_scan)
- os: linux
@@ -129,53 +37,17 @@ matrix:
env:
- SPECIAL=coverity
- COMPILER=clang++-3.6
# The next declaration is the encrypted COVERITY_SCAN_TOKEN, created
# via the "travis encrypt" command using the project repo's public key
- secure: "m89SSgE+ASLO38rSKx7MTXK3n5NkP9bIx95jwY71YEiuFzib30PDJ/DifKnXxBjvy/AkCGztErQRk/8ZCvq+4HXozU2knEGnL/RUitvlwbhzfh2D4lmS3BvWBGS3N3NewoPBrRmdcvnT0xjOGXxtZaJ3P74TkB9GBnlz/HmKORA="
# OSX / Clang
- os: osx
osx_image: xcode9.3
- os: osx
osx_image: xcode9.4
- os: osx
osx_image: xcode10
- os: osx
osx_image: xcode10.1
- os: osx
osx_image: xcode10.2
- os: osx
osx_image: xcode11.2
# Linux / GCC
- os: linux
compiler: gcc
env: COMPILER=g++-4.8
addons:
apt:
sources: ['ubuntu-toolchain-r-test']
packages: ['g++-4.8', 'ninja-build']
- os: linux
compiler: gcc
env: COMPILER=g++-4.9
addons:
apt:
sources: ['ubuntu-toolchain-r-test']
packages: ['g++-4.9', 'ninja-build']
- os: linux
compiler: gcc
env: COMPILER=g++-5
addons:
apt:
sources: ['ubuntu-toolchain-r-test']
packages: ['g++-5', 'ninja-build']
- os: linux
compiler: gcc
env: COMPILER=g++-6
@@ -184,124 +56,6 @@ matrix:
sources: ['ubuntu-toolchain-r-test']
packages: ['g++-6', 'ninja-build']
- os: linux
compiler: gcc
env: COMPILER=g++-7
addons:
apt:
sources: ['ubuntu-toolchain-r-test']
packages: ['g++-7', 'ninja-build']
- os: linux
compiler: gcc
env: COMPILER=g++-8
addons:
apt:
sources: ['ubuntu-toolchain-r-test']
packages: ['g++-8', 'ninja-build']
- os: linux
compiler: gcc
env: COMPILER=g++-9
addons:
apt:
sources: ['ubuntu-toolchain-r-test']
packages: ['g++-9', 'ninja-build']
- os: linux
compiler: gcc
env:
- COMPILER=g++-9
- CXXFLAGS=-std=c++2a
addons:
apt:
sources: ['ubuntu-toolchain-r-test']
packages: ['g++-9', 'ninja-build']
# Linux / Clang
- os: linux
compiler: clang
env: COMPILER=clang++-3.5
addons:
apt:
sources: ['ubuntu-toolchain-r-test', 'llvm-toolchain-precise-3.5']
packages: ['g++-6', 'clang-3.5', 'ninja-build']
- os: linux
compiler: clang
env: COMPILER=clang++-3.6
addons:
apt:
sources: ['ubuntu-toolchain-r-test', 'llvm-toolchain-precise-3.6']
packages: ['g++-6', 'clang-3.6', 'ninja-build']
- os: linux
compiler: clang
env: COMPILER=clang++-3.7
addons:
apt:
sources: ['ubuntu-toolchain-r-test', 'llvm-toolchain-precise-3.7']
packages: ['g++-6', 'clang-3.7', 'ninja-build']
- os: linux
compiler: clang
env: COMPILER=clang++-3.8
addons:
apt:
sources: ['ubuntu-toolchain-r-test']
packages: ['g++-6', 'clang-3.8', 'ninja-build']
- os: linux
compiler: clang
env: COMPILER=clang++-3.9
addons:
apt:
sources: ['ubuntu-toolchain-r-test']
packages: ['g++-6', 'clang-3.9', 'ninja-build']
- os: linux
compiler: clang
env: COMPILER=clang++-4.0
addons:
apt:
sources: ['ubuntu-toolchain-r-test', 'llvm-toolchain-trusty-4.0']
packages: ['g++-6', 'clang-4.0', 'ninja-build']
- os: linux
compiler: clang
env: COMPILER=clang++-5.0
addons:
apt:
sources: ['ubuntu-toolchain-r-test', 'llvm-toolchain-trusty-5.0']
packages: ['g++-6', 'clang-5.0', 'ninja-build']
- os: linux
compiler: clang
env: COMPILER=clang++-6.0
addons:
apt:
sources: ['ubuntu-toolchain-r-test', 'llvm-toolchain-trusty-6.0']
packages: ['g++-6', 'clang-6.0', 'ninja-build']
- os: linux
compiler: clang
env: COMPILER=clang++-7
addons:
apt:
sources: ['ubuntu-toolchain-r-test', 'llvm-toolchain-trusty-7']
packages: ['g++-6', 'clang-7', 'ninja-build']
- os: linux
compiler: clang
env:
- COMPILER=clang++-7
- CXXFLAGS=-std=c++1z
addons:
apt:
sources: ['ubuntu-toolchain-r-test', 'llvm-toolchain-trusty-7']
packages: ['g++-6', 'clang-7', 'ninja-build']
################
# build script #
################
@@ -318,13 +72,17 @@ script:
# make sure CXX is correctly set
- if [[ "${COMPILER}" != "" ]]; then export CXX=${COMPILER}; fi
# by default, use the single-header version
- if [[ "${MULTIPLE_HEADERS}" == "" ]]; then export MULTIPLE_HEADERS=OFF; fi
# append CXX_STANDARD to CMAKE_OPTIONS if required
- CMAKE_OPTIONS+=${CXX_STANDARD:+ -DCMAKE_CXX_STANDARD=$CXX_STANDARD -DCMAKE_CXX_STANDARD_REQUIRED=ON}
# build configuration
- CMAKE_OPTIONS+=" -DCMAKE_BUILD_TYPE=Release"
# compile and execute unit tests
- mkdir -p build && cd build
- cmake .. ${CMAKE_OPTIONS} -DJSON_MultipleHeaders=${MULTIPLE_HEADERS} -DJSON_BuildTests=On -GNinja && cmake --build . --config Release
- ctest -C Release --timeout 2700 -V -j
- cmake .. ${CMAKE_OPTIONS} -DJSON_BuildTests=On -GNinja && cmake --build .
- ctest --timeout 2700 -V -j
- cd ..
# check if homebrew works (only checks develop branch)

14
CITATION.cff Normal file
View File

@@ -0,0 +1,14 @@
cff-version: 1.1.0
message: "If you use this software, please cite it as below."
authors:
- family-names: Lohmann
given-names: Niels
orcid: https://orcid.org/0000-0001-9037-795X
email: mail@nlohmann.me
website: https://nlohmann.me
title: "JSON for Modern C++"
version: 3.10.4
date-released: 2021
license: MIT
repository-code: "https://github.com/nlohmann"
url: https://json.nlohmann.me

View File

@@ -4,7 +4,16 @@ cmake_minimum_required(VERSION 3.1)
## PROJECT
## name and version
##
project(nlohmann_json VERSION 3.8.0 LANGUAGES CXX)
project(nlohmann_json VERSION 3.10.4 LANGUAGES CXX)
##
## MAIN_PROJECT CHECK
## determine if nlohmann_json is built as a subproject (using add_subdirectory) or if it is the main project
##
set(MAIN_PROJECT OFF)
if (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
set(MAIN_PROJECT ON)
endif()
##
## INCLUDE
@@ -21,9 +30,17 @@ if (POLICY CMP0077)
cmake_policy(SET CMP0077 NEW)
endif ()
option(JSON_BuildTests "Build the unit tests when BUILD_TESTING is enabled." ON)
option(JSON_Install "Install CMake targets during install step." ON)
option(JSON_MultipleHeaders "Use non-amalgamated version of the library." OFF)
option(JSON_BuildTests "Build the unit tests when BUILD_TESTING is enabled." ${MAIN_PROJECT})
option(JSON_CI "Enable CI build targets." OFF)
option(JSON_Diagnostics "Use extended diagnostic messages." OFF)
option(JSON_ImplicitConversions "Enable implicit conversions." ON)
option(JSON_Install "Install CMake targets during install step." ${MAIN_PROJECT})
option(JSON_MultipleHeaders "Use non-amalgamated version of the library." OFF)
option(JSON_SystemInclude "Include as system headers (skip for clang-tidy)." OFF)
if (JSON_CI)
include(cmake/ci.cmake)
endif ()
##
## CONFIGURATION
@@ -39,6 +56,7 @@ set(NLOHMANN_JSON_CMAKE_CONFIG_DIR "${CMAKE_CURRENT_BINARY_DIR}")
set(NLOHMANN_JSON_CMAKE_VERSION_CONFIG_FILE "${NLOHMANN_JSON_CMAKE_CONFIG_DIR}/${PROJECT_NAME}ConfigVersion.cmake")
set(NLOHMANN_JSON_CMAKE_PROJECT_CONFIG_FILE "${NLOHMANN_JSON_CMAKE_CONFIG_DIR}/${PROJECT_NAME}Config.cmake")
set(NLOHMANN_JSON_CMAKE_PROJECT_TARGETS_FILE "${NLOHMANN_JSON_CMAKE_CONFIG_DIR}/${PROJECT_NAME}Targets.cmake")
set(NLOHMANN_JSON_PKGCONFIG_INSTALL_DIR "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
if (JSON_MultipleHeaders)
set(NLOHMANN_JSON_INCLUDE_BUILD_DIR "${PROJECT_SOURCE_DIR}/include/")
@@ -48,6 +66,18 @@ else()
message(STATUS "Using the single-header code from ${NLOHMANN_JSON_INCLUDE_BUILD_DIR}")
endif()
if (NOT JSON_ImplicitConversions)
message(STATUS "Implicit conversions are disabled")
endif()
if (JSON_Diagnostics)
message(STATUS "Diagnostics enabled")
endif()
if (JSON_SystemInclude)
set(NLOHMANN_JSON_SYSTEM_INCLUDE "SYSTEM")
endif()
##
## TARGET
## create target and add include path
@@ -60,9 +90,16 @@ else()
target_compile_features(${NLOHMANN_JSON_TARGET_NAME} INTERFACE cxx_std_11)
endif()
target_include_directories(
target_compile_definitions(
${NLOHMANN_JSON_TARGET_NAME}
INTERFACE
JSON_USE_IMPLICIT_CONVERSIONS=$<BOOL:${JSON_ImplicitConversions}>
JSON_DIAGNOSTICS=$<BOOL:${JSON_Diagnostics}>
)
target_include_directories(
${NLOHMANN_JSON_TARGET_NAME}
${NLOHMANN_JSON_SYSTEM_INCLUDE} INTERFACE
$<BUILD_INTERFACE:${NLOHMANN_JSON_INCLUDE_BUILD_DIR}>
$<INSTALL_INTERFACE:include>
)
@@ -81,17 +118,16 @@ endif()
# Install a pkg-config file, so other tools can find this.
CONFIGURE_FILE(
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/pkg-config.pc.in"
"${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc"
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/pkg-config.pc.in"
"${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc"
)
##
## TESTS
## create and configure the unit test target
##
include(CTest) #adds option BUILD_TESTING (default ON)
if(BUILD_TESTING AND JSON_BuildTests)
if (JSON_BuildTests)
include(CTest)
enable_testing()
add_subdirectory(test)
endif()
@@ -129,7 +165,7 @@ if(JSON_Install)
FILES ${NLOHMANN_NATVIS_FILE}
DESTINATION .
)
endif()
endif()
export(
TARGETS ${NLOHMANN_JSON_TARGET_NAME}
NAMESPACE ${PROJECT_NAME}::
@@ -146,7 +182,7 @@ endif()
DESTINATION ${NLOHMANN_JSON_CONFIG_INSTALL_DIR}
)
install(
FILES "${CMAKE_BINARY_DIR}/${PROJECT_NAME}.pc"
DESTINATION lib/pkgconfig
FILES "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc"
DESTINATION ${NLOHMANN_JSON_PKGCONFIG_INSTALL_DIR}
)
endif()

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
MIT License
Copyright (c) 2013-2020 Niels Lohmann
Copyright (c) 2013-2021 Niels Lohmann
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

457
Makefile
View File

@@ -5,7 +5,7 @@
##########################################################################
# directory to recent compiler binaries
COMPILER_DIR=/Users/niels/Documents/projects/compilers/local/bin
COMPILER_DIR=/usr/local/opt/llvm/bin
# find GNU sed to use `-i` parameter
SED:=$(shell command -v gsed || which sed)
@@ -30,53 +30,18 @@ AMALGAMATED_FILE=single_include/nlohmann/json.hpp
all:
@echo "amalgamate - amalgamate file single_include/nlohmann/json.hpp from the include/nlohmann sources"
@echo "ChangeLog.md - generate ChangeLog file"
@echo "check - compile and execute test suite"
@echo "check-amalgamation - check whether sources have been amalgamated"
@echo "clean - remove built files"
@echo "coverage - create coverage information with lcov"
@echo "cppcheck - analyze code with cppcheck"
@echo "cpplint - analyze code with cpplint"
@echo "clang_tidy - analyze code with Clang-Tidy"
@echo "clang_analyze - analyze code with Clang-Analyzer"
@echo "doctest - compile example files and check their output"
@echo "fuzz_testing - prepare fuzz testing of the JSON parser"
@echo "fuzz_testing_bson - prepare fuzz testing of the BSON parser"
@echo "fuzz_testing_cbor - prepare fuzz testing of the CBOR parser"
@echo "fuzz_testing_msgpack - prepare fuzz testing of the MessagePack parser"
@echo "fuzz_testing_ubjson - prepare fuzz testing of the UBJSON parser"
@echo "json_unit - create single-file test executable"
@echo "pedantic_clang - run Clang with maximal warning flags"
@echo "pedantic_gcc - run GCC with maximal warning flags"
@echo "pretty - beautify code with Artistic Style"
@echo "run_benchmarks - build and run benchmarks"
##########################################################################
# unit tests
##########################################################################
# build unit tests
json_unit:
@$(MAKE) json_unit -C test
# run unit tests
check:
$(MAKE) check -C test
##########################################################################
# coverage
##########################################################################
coverage:
rm -fr build_coverage
mkdir build_coverage
cd build_coverage ; cmake .. -GNinja -DCMAKE_BUILD_TYPE=Debug -DJSON_Coverage=ON -DJSON_MultipleHeaders=ON
cd build_coverage ; ninja
cd build_coverage ; ctest -j10
cd build_coverage ; ninja lcov_html
open build_coverage/test/html/index.html
##########################################################################
# documentation tests
##########################################################################
@@ -86,314 +51,16 @@ doctest:
$(MAKE) check_output -C doc
##########################################################################
# warning detector
##########################################################################
# calling Clang with all warnings, except:
# -Wno-c++2a-compat: u8 literals will behave differently in C++20...
# -Wno-deprecated-declarations: the library deprecated some functions
# -Wno-documentation-unknown-command: code uses user-defined commands like @complexity
# -Wno-exit-time-destructors: warning in json code triggered by NLOHMANN_JSON_SERIALIZE_ENUM
# -Wno-float-equal: not all comparisons in the tests can be replaced by Approx
# -Wno-keyword-macro: unit-tests use "#define private public"
# -Wno-missing-prototypes: for NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE
# -Wno-padded: padding is nothing to warn about
# -Wno-range-loop-analysis: items tests "for(const auto i...)"
# -Wno-switch-enum -Wno-covered-switch-default: pedantic/contradicting warnings about switches
# -Wno-weak-vtables: exception class is defined inline, but has virtual method
pedantic_clang:
rm -fr build_pedantic
CXXFLAGS=" \
-std=c++11 -Wno-c++98-compat -Wno-c++98-compat-pedantic \
-Werror \
-Weverything \
-Wno-c++2a-compat \
-Wno-deprecated-declarations \
-Wno-documentation-unknown-command \
-Wno-exit-time-destructors \
-Wno-float-equal \
-Wno-keyword-macro \
-Wno-missing-prototypes \
-Wno-padded \
-Wno-range-loop-analysis \
-Wno-switch-enum -Wno-covered-switch-default \
-Wno-weak-vtables" cmake -S . -B build_pedantic -GNinja -DCMAKE_BUILD_TYPE=Debug -DJSON_MultipleHeaders=ON -DJSON_BuildTests=On
cmake --build build_pedantic
# calling GCC with most warnings
pedantic_gcc:
rm -fr build_pedantic
CXXFLAGS=" \
-std=c++11 \
-pedantic \
-Werror \
--all-warnings \
--extra-warnings \
-W \
-Wno-abi-tag \
-Waddress \
-Waddress-of-packed-member \
-Wno-aggregate-return \
-Waggressive-loop-optimizations \
-Waligned-new=all \
-Wall \
-Walloc-zero \
-Walloca \
-Wanalyzer-double-fclose \
-Wanalyzer-double-free \
-Wanalyzer-exposure-through-output-file \
-Wanalyzer-file-leak \
-Wanalyzer-free-of-non-heap \
-Wanalyzer-malloc-leak \
-Wanalyzer-null-argument \
-Wanalyzer-null-dereference \
-Wanalyzer-possible-null-argument \
-Wanalyzer-possible-null-dereference \
-Wanalyzer-stale-setjmp-buffer \
-Wanalyzer-tainted-array-index \
-Wanalyzer-too-complex \
-Wanalyzer-unsafe-call-within-signal-handler \
-Wanalyzer-use-after-free \
-Wanalyzer-use-of-pointer-in-stale-stack-frame \
-Warith-conversion \
-Warray-bounds \
-Warray-bounds=2 \
-Wattribute-alias=2 \
-Wattribute-warning \
-Wattributes \
-Wbool-compare \
-Wbool-operation \
-Wbuiltin-declaration-mismatch \
-Wbuiltin-macro-redefined \
-Wc++0x-compat \
-Wc++11-compat \
-Wc++14-compat \
-Wc++17-compat \
-Wc++1z-compat \
-Wc++20-compat \
-Wc++2a-compat \
-Wcannot-profile \
-Wcast-align \
-Wcast-align=strict \
-Wcast-function-type \
-Wcast-qual \
-Wcatch-value=3 \
-Wchar-subscripts \
-Wclass-conversion \
-Wclass-memaccess \
-Wclobbered \
-Wcomma-subscript \
-Wcomment \
-Wcomments \
-Wconditionally-supported \
-Wconversion \
-Wconversion-null \
-Wcoverage-mismatch \
-Wcpp \
-Wctor-dtor-privacy \
-Wdangling-else \
-Wdate-time \
-Wdelete-incomplete \
-Wdelete-non-virtual-dtor \
-Wdeprecated \
-Wdeprecated-copy \
-Wdeprecated-copy-dtor \
-Wdeprecated-declarations \
-Wdisabled-optimization \
-Wdiv-by-zero \
-Wdouble-promotion \
-Wduplicated-branches \
-Wduplicated-cond \
-Weffc++ \
-Wempty-body \
-Wendif-labels \
-Wenum-compare \
-Wexpansion-to-defined \
-Wextra \
-Wextra-semi \
-Wfloat-conversion \
-Wfloat-equal \
-Wformat -Wformat-contains-nul \
-Wformat -Wformat-extra-args \
-Wformat -Wformat-nonliteral \
-Wformat -Wformat-security \
-Wformat -Wformat-y2k \
-Wformat -Wformat-zero-length \
-Wformat-diag \
-Wformat-overflow=2 \
-Wformat-signedness \
-Wformat-truncation=2 \
-Wformat=2 \
-Wframe-address \
-Wfree-nonheap-object \
-Whsa \
-Wif-not-aligned \
-Wignored-attributes \
-Wignored-qualifiers \
-Wimplicit-fallthrough=5 \
-Winaccessible-base \
-Winherited-variadic-ctor \
-Winit-list-lifetime \
-Winit-self \
-Winline \
-Wint-in-bool-context \
-Wint-to-pointer-cast \
-Winvalid-memory-model \
-Winvalid-offsetof \
-Winvalid-pch \
-Wliteral-suffix \
-Wlogical-not-parentheses \
-Wlogical-op \
-Wno-long-long \
-Wlto-type-mismatch \
-Wmain \
-Wmaybe-uninitialized \
-Wmemset-elt-size \
-Wmemset-transposed-args \
-Wmisleading-indentation \
-Wmismatched-tags \
-Wmissing-attributes \
-Wmissing-braces \
-Wno-missing-declarations \
-Wmissing-field-initializers \
-Wmissing-include-dirs \
-Wmissing-profile \
-Wmultichar \
-Wmultiple-inheritance \
-Wmultistatement-macros \
-Wno-namespaces \
-Wnarrowing \
-Wno-noexcept \
-Wnoexcept-type \
-Wnon-template-friend \
-Wnon-virtual-dtor \
-Wnonnull \
-Wnonnull-compare \
-Wnonportable-cfstrings \
-Wnormalized=nfkc \
-Wnull-dereference \
-Wodr \
-Wold-style-cast \
-Wopenmp-simd \
-Woverflow \
-Woverlength-strings \
-Woverloaded-virtual \
-Wpacked \
-Wpacked-bitfield-compat \
-Wpacked-not-aligned \
-Wno-padded \
-Wparentheses \
-Wpedantic \
-Wpessimizing-move \
-Wplacement-new=2 \
-Wpmf-conversions \
-Wpointer-arith \
-Wpointer-compare \
-Wpragmas \
-Wprio-ctor-dtor \
-Wpsabi \
-Wredundant-decls \
-Wredundant-move \
-Wredundant-tags \
-Wregister \
-Wreorder \
-Wrestrict \
-Wreturn-local-addr \
-Wreturn-type \
-Wscalar-storage-order \
-Wsequence-point \
-Wshadow=compatible-local \
-Wshadow=global \
-Wshadow=local \
-Wshift-count-negative \
-Wshift-count-overflow \
-Wshift-negative-value \
-Wshift-overflow=2 \
-Wsign-compare \
-Wsign-conversion \
-Wsign-promo \
-Wsized-deallocation \
-Wsizeof-array-argument \
-Wsizeof-pointer-div \
-Wsizeof-pointer-memaccess \
-Wstack-protector \
-Wstrict-aliasing \
-Wstrict-aliasing=3 \
-Wstrict-null-sentinel \
-Wstrict-overflow \
-Wstrict-overflow=5 \
-Wstring-compare \
-Wstringop-overflow \
-Wstringop-overflow=4 \
-Wstringop-truncation \
-Wsubobject-linkage \
-Wsuggest-attribute=cold \
-Wsuggest-attribute=const \
-Wsuggest-attribute=format \
-Wsuggest-attribute=malloc \
-Wsuggest-attribute=noreturn \
-Wsuggest-attribute=pure \
-Wsuggest-final-methods \
-Wsuggest-final-types \
-Wsuggest-override \
-Wswitch \
-Wswitch-bool \
-Wswitch-default \
-Wno-switch-enum \
-Wswitch-outside-range \
-Wswitch-unreachable \
-Wsync-nand \
-Wsynth \
-Wno-system-headers \
-Wtautological-compare \
-Wno-templates \
-Wterminate \
-Wtrampolines \
-Wtrigraphs \
-Wtype-limits \
-Wundef \
-Wuninitialized \
-Wunknown-pragmas \
-Wunreachable-code \
-Wunsafe-loop-optimizations \
-Wunused \
-Wunused-but-set-parameter \
-Wunused-but-set-variable \
-Wunused-const-variable=2 \
-Wunused-function \
-Wunused-label \
-Wno-unused-local-typedefs \
-Wunused-macros \
-Wunused-parameter \
-Wunused-result \
-Wunused-value \
-Wunused-variable \
-Wuseless-cast \
-Wvarargs \
-Wvariadic-macros \
-Wvector-operation-performance \
-Wvirtual-inheritance \
-Wvirtual-move-assign \
-Wvla \
-Wvolatile \
-Wvolatile-register-var \
-Wwrite-strings \
-Wzero-as-null-pointer-constant \
-Wzero-length-bounds \
" cmake -S . -B build_pedantic -GNinja -DCMAKE_BUILD_TYPE=Debug -DJSON_MultipleHeaders=ON -DJSON_BuildTests=On
cmake --build build_pedantic
##########################################################################
# benchmarks
##########################################################################
run_benchmarks:
rm -fr build_benchmarks
mkdir build_benchmarks
cd build_benchmarks ; cmake ../benchmarks -GNinja -DCMAKE_BUILD_TYPE=Release -DJSON_BuildTests=On
cd build_benchmarks ; ninja
cd build_benchmarks ; ./json_benchmarks
rm -fr cmake-build-benchmarks
mkdir cmake-build-benchmarks
cd cmake-build-benchmarks ; cmake ../benchmarks -GNinja -DCMAKE_BUILD_TYPE=Release -DJSON_BuildTests=On
cd cmake-build-benchmarks ; ninja
cd cmake-build-benchmarks ; ./json_benchmarks
##########################################################################
# fuzzing
@@ -459,61 +126,14 @@ fuzzing-stop:
# Static analysis
##########################################################################
# call cppcheck <http://cppcheck.sourceforge.net>
# Note: this target is called by Travis
cppcheck:
cppcheck --enable=warning --inline-suppr --inconclusive --force --std=c++11 $(AMALGAMATED_FILE) --error-exitcode=1
# call Clang Static Analyzer <https://clang-analyzer.llvm.org>
clang_analyze:
rm -fr clang_analyze_build
mkdir clang_analyze_build
cd clang_analyze_build ; CCC_CXX=$(COMPILER_DIR)/clang++ CXX=$(COMPILER_DIR)/clang++ $(COMPILER_DIR)/scan-build cmake .. -GNinja -DJSON_BuildTests=On
cd clang_analyze_build ; \
$(COMPILER_DIR)/scan-build \
-enable-checker alpha.core.BoolAssignment,alpha.core.CallAndMessageUnInitRefArg,alpha.core.CastSize,alpha.core.CastToStruct,alpha.core.Conversion,alpha.core.DynamicTypeChecker,alpha.core.FixedAddr,alpha.core.PointerArithm,alpha.core.PointerSub,alpha.core.SizeofPtr,alpha.core.StackAddressAsyncEscape,alpha.core.TestAfterDivZero,alpha.deadcode.UnreachableCode,core.builtin.BuiltinFunctions,core.builtin.NoReturnFunctions,core.CallAndMessage,core.DivideZero,core.DynamicTypePropagation,core.NonnilStringConstants,core.NonNullParamChecker,core.NullDereference,core.StackAddressEscape,core.UndefinedBinaryOperatorResult,core.uninitialized.ArraySubscript,core.uninitialized.Assign,core.uninitialized.Branch,core.uninitialized.CapturedBlockVariable,core.uninitialized.UndefReturn,core.VLASize,cplusplus.InnerPointer,cplusplus.Move,cplusplus.NewDelete,cplusplus.NewDeleteLeaks,cplusplus.SelfAssignment,deadcode.DeadStores,nullability.NullableDereferenced,nullability.NullablePassedToNonnull,nullability.NullableReturnedFromNonnull,nullability.NullPassedToNonnull,nullability.NullReturnedFromNonnull \
--use-c++=$(COMPILER_DIR)/clang++ -analyze-headers -o report ninja
open clang_analyze_build/report/*/index.html
# call cpplint <https://github.com/cpplint/cpplint>
# Note: some errors expected due to false positives
cpplint:
third_party/cpplint/cpplint.py \
--filter=-whitespace,-legal,-readability/alt_tokens,-runtime/references,-runtime/explicit \
--quiet --recursive $(SRCS)
# call Clang-Tidy <https://clang.llvm.org/extra/clang-tidy/>
clang_tidy:
$(COMPILER_DIR)/clang-tidy $(AMALGAMATED_FILE) -- -Iinclude -std=c++11
# call PVS-Studio Analyzer <https://www.viva64.com/en/pvs-studio/>
pvs_studio:
rm -fr pvs_studio_build
mkdir pvs_studio_build
cd pvs_studio_build ; cmake .. -DCMAKE_EXPORT_COMPILE_COMMANDS=On
cd pvs_studio_build ; pvs-studio-analyzer analyze -j 10
cd pvs_studio_build ; plog-converter -a'GA:1,2;64:1;CS' -t fullhtml PVS-Studio.log -o pvs
open pvs_studio_build/pvs/index.html
# call Infer <https://fbinfer.com> static analyzer
infer:
rm -fr infer_build
mkdir infer_build
cd infer_build ; infer compile -- cmake .. ; infer run -- make -j 4
# call OCLint <http://oclint.org> static analyzer
oclint:
oclint $(SRCS) -report-type html -enable-global-analysis -o oclint_report.html -max-priority-1=10000 -max-priority-2=10000 -max-priority-3=10000 -- -std=c++11 -Iinclude
open oclint_report.html
# execute the test suite with Clang sanitizers (address and undefined behavior)
clang_sanitize:
rm -fr clang_sanitize_build
mkdir clang_sanitize_build
cd clang_sanitize_build ; CXX=$(COMPILER_DIR)/clang++ cmake .. -DJSON_Sanitizer=On -DJSON_MultipleHeaders=ON -DJSON_BuildTests=On -GNinja
cd clang_sanitize_build ; ninja
cd clang_sanitize_build ; ctest -j10
rm -fr cmake-build-pvs-studio
mkdir cmake-build-pvs-studio
cd cmake-build-pvs-studio ; cmake .. -DCMAKE_EXPORT_COMPILE_COMMANDS=On -DJSON_MultipleHeaders=ON
cd cmake-build-pvs-studio ; pvs-studio-analyzer analyze -j 10
cd cmake-build-pvs-studio ; plog-converter -a'GA:1,2;64:1;CS' -t fullhtml PVS-Studio.log -o pvs
open cmake-build-pvs-studio/pvs/index.html
##########################################################################
# Code format and source amalgamation
@@ -540,7 +160,11 @@ pretty:
--preserve-date \
--suffix=none \
--formatted \
$(SRCS) $(AMALGAMATED_FILE) test/src/*.cpp benchmarks/src/benchmarks.cpp doc/examples/*.cpp
$(SRCS) $(AMALGAMATED_FILE) test/src/*.cpp test/src/*.hpp benchmarks/src/benchmarks.cpp doc/examples/*.cpp
# call the Clang-Format on all source files
pretty_format:
for FILE in $(SRCS) $(AMALGAMATED_FILE) test/src/*.cpp test/src/*.hpp benchmarks/src/benchmarks.cpp doc/examples/*.cpp; do echo $$FILE; clang-format -i $$FILE; done
# create single header file
amalgamate: $(AMALGAMATED_FILE)
@@ -558,42 +182,6 @@ check-amalgamation:
@diff $(AMALGAMATED_FILE) $(AMALGAMATED_FILE)~ || (echo "===================================================================\n Amalgamation required! Please read the contribution guidelines\n in file .github/CONTRIBUTING.md.\n===================================================================" ; mv $(AMALGAMATED_FILE)~ $(AMALGAMATED_FILE) ; false)
@mv $(AMALGAMATED_FILE)~ $(AMALGAMATED_FILE)
# check if every header in nlohmann includes sufficient headers to be compiled individually
check-single-includes:
@for x in $(SRCS); do \
echo "Checking self-sufficiency of $$x..." ; \
echo "#include <$$x>\nint main() {}\n" | sed 's|include/||' > single_include_test.cpp; \
$(CXX) $(CXXFLAGS) -Iinclude -std=c++11 single_include_test.cpp -o single_include_test; \
rm -f single_include_test.cpp single_include_test; \
done
##########################################################################
# CMake
##########################################################################
# grep "^option" CMakeLists.txt test/CMakeLists.txt | sed 's/(/ /' | awk '{print $2}' | xargs
# check if all flags of our CMake files work
check_cmake_flags_do:
$(CMAKE_BINARY) --version
for flag in '' JSON_BuildTests JSON_Install JSON_MultipleHeaders JSON_Sanitizer JSON_Valgrind JSON_NoExceptions JSON_Coverage; do \
rm -fr cmake_build; \
mkdir cmake_build; \
echo "$(CMAKE_BINARY) .. -D$$flag=On" ; \
cd cmake_build ; \
CXX=g++-8 $(CMAKE_BINARY) .. -D$$flag=On -DCMAKE_CXX_COMPILE_FEATURES="cxx_std_11;cxx_range_for" -DCMAKE_CXX_FLAGS="-std=gnu++11" ; \
test -f Makefile || exit 1 ; \
cd .. ; \
done;
# call target `check_cmake_flags_do` twice: once for minimal required CMake version 3.1.0 and once for the installed version
check_cmake_flags:
wget https://github.com/Kitware/CMake/releases/download/v3.1.0/cmake-3.1.0-Darwin64.tar.gz
tar xfz cmake-3.1.0-Darwin64.tar.gz
CMAKE_BINARY=$(abspath cmake-3.1.0-Darwin64/CMake.app/Contents/bin/cmake) $(MAKE) check_cmake_flags_do
CMAKE_BINARY=$(shell which cmake) $(MAKE) check_cmake_flags_do
##########################################################################
# ChangeLog
@@ -621,7 +209,7 @@ ChangeLog.md:
release:
rm -fr release_files
mkdir release_files
zip -9 --recurse-paths -X include.zip $(SRCS) $(AMALGAMATED_FILE) meson.build
zip -9 --recurse-paths -X include.zip $(SRCS) $(AMALGAMATED_FILE) meson.build LICENSE.MIT
gpg --armor --detach-sig include.zip
mv include.zip include.zip.asc release_files
gpg --armor --detach-sig $(AMALGAMATED_FILE)
@@ -640,9 +228,8 @@ clean:
rm -fr json_unit json_benchmarks fuzz fuzz-testing *.dSYM test/*.dSYM oclint_report.html
rm -fr benchmarks/files/numbers/*.json
rm -fr cmake-3.1.0-Darwin64.tar.gz cmake-3.1.0-Darwin64
rm -fr build_coverage build_benchmarks fuzz-testing clang_analyze_build pvs_studio_build infer_build clang_sanitize_build cmake_build
rm -fr cmake-build-benchmarks cmake-build-pedantic fuzz-testing cmake-build-clang-analyze cmake-build-pvs-studio cmake-build-infer cmake_build
$(MAKE) clean -Cdoc
$(MAKE) clean -Ctest
##########################################################################
# Thirdparty code
@@ -651,6 +238,8 @@ clean:
update_hedley:
rm -f include/nlohmann/thirdparty/hedley/hedley.hpp include/nlohmann/thirdparty/hedley/hedley_undef.hpp
curl https://raw.githubusercontent.com/nemequ/hedley/master/hedley.h -o include/nlohmann/thirdparty/hedley/hedley.hpp
gsed -i 's/HEDLEY_/JSON_HEDLEY_/g' include/nlohmann/thirdparty/hedley/hedley.hpp
grep "[[:blank:]]*#[[:blank:]]*undef" include/nlohmann/thirdparty/hedley/hedley.hpp | grep -v "__" | sort | uniq | gsed 's/ //g' | gsed 's/undef/undef /g' > include/nlohmann/thirdparty/hedley/hedley_undef.hpp
$(SED) -i 's/HEDLEY_/JSON_HEDLEY_/g' include/nlohmann/thirdparty/hedley/hedley.hpp
grep "[[:blank:]]*#[[:blank:]]*undef" include/nlohmann/thirdparty/hedley/hedley.hpp | grep -v "__" | sort | uniq | $(SED) 's/ //g' | $(SED) 's/undef/undef /g' > include/nlohmann/thirdparty/hedley/hedley_undef.hpp
$(SED) -i '1s/^/#pragma once\n\n/' include/nlohmann/thirdparty/hedley/hedley.hpp
$(SED) -i '1s/^/#pragma once\n\n/' include/nlohmann/thirdparty/hedley/hedley_undef.hpp
$(MAKE) amalgamate

575
README.md
View File

@@ -1,20 +1,18 @@
[![JSON for Modern C++](https://raw.githubusercontent.com/nlohmann/json/master/doc/json.gif)](https://github.com/nlohmann/json/releases)
[![Build Status](https://travis-ci.org/nlohmann/json.svg?branch=master)](https://travis-ci.org/nlohmann/json)
[![Build Status](https://app.travis-ci.com/nlohmann/json.svg?branch=develop)](https://app.travis-ci.com/nlohmann/json)
[![Build Status](https://ci.appveyor.com/api/projects/status/1acb366xfyg3qybk/branch/develop?svg=true)](https://ci.appveyor.com/project/nlohmann/json)
[![Ubuntu](https://github.com/nlohmann/json/workflows/Ubuntu/badge.svg)](https://github.com/nlohmann/json/actions?query=workflow%3AUbuntu)
[![macOS](https://github.com/nlohmann/json/workflows/macOS/badge.svg)](https://github.com/nlohmann/json/actions?query=workflow%3AmacOS)
[![Windows](https://github.com/nlohmann/json/workflows/Windows/badge.svg)](https://github.com/nlohmann/json/actions?query=workflow%3AWindows)
[![Build Status](https://circleci.com/gh/nlohmann/json.svg?style=svg)](https://circleci.com/gh/nlohmann/json)
[![Coverage Status](https://coveralls.io/repos/github/nlohmann/json/badge.svg?branch=develop)](https://coveralls.io/github/nlohmann/json?branch=develop)
[![Coverity Scan Build Status](https://scan.coverity.com/projects/5550/badge.svg)](https://scan.coverity.com/projects/nlohmann-json)
[![Codacy Badge](https://api.codacy.com/project/badge/Grade/f3732b3327e34358a0e9d1fe9f661f08)](https://www.codacy.com/app/nlohmann/json?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=nlohmann/json&amp;utm_campaign=Badge_Grade)
[![Codacy Badge](https://app.codacy.com/project/badge/Grade/e0d1a9d5d6fd46fcb655c4cb930bb3e8)](https://www.codacy.com/gh/nlohmann/json/dashboard?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=nlohmann/json&amp;utm_campaign=Badge_Grade)
[![Language grade: C/C++](https://img.shields.io/lgtm/grade/cpp/g/nlohmann/json.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/nlohmann/json/context:cpp)
[![Fuzzing Status](https://oss-fuzz-build-logs.storage.googleapis.com/badges/json.svg)](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:json)
[![Try online](https://img.shields.io/badge/try-online-blue.svg)](https://wandbox.org/permlink/3lCHrFUZANONKv7a)
[![Try online](https://img.shields.io/badge/try-online-blue.svg)](https://wandbox.org/permlink/1mp10JbaANo6FUc7)
[![Documentation](https://img.shields.io/badge/docs-doxygen-blue.svg)](https://nlohmann.github.io/json/doxygen/index.html)
[![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/nlohmann/json/master/LICENSE.MIT)
[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fnlohmann%2Fjson.svg?type=shield)](https://app.fossa.com/projects/git%2Bgithub.com%2Fnlohmann%2Fjson?ref=badge_shield)
[![GitHub Releases](https://img.shields.io/github/release/nlohmann/json.svg)](https://github.com/nlohmann/json/releases)
[![GitHub Downloads](https://img.shields.io/github/downloads/nlohmann/json/total)](https://github.com/nlohmann/json/releases)
[![GitHub Issues](https://img.shields.io/github/issues/nlohmann/json.svg)](https://github.com/nlohmann/json/issues)
@@ -24,10 +22,7 @@
- [Design goals](#design-goals)
- [Sponsors](#sponsors)
- [Integration](#integration)
- [CMake](#cmake)
- [Package Managers](#package-managers)
- [Pkg-config](#pkg-config)
- [Support](#support) ([documentation](https://json.nlohmann.me), [FAQ](http://127.0.0.1:8000/home/faq/), [discussions](https://github.com/nlohmann/json/discussions), [API](https://json.nlohmann.me/api/basic_json/), [bug issues](https://github.com/nlohmann/json/issues))
- [Examples](#examples)
- [JSON as first-class data type](#json-as-first-class-data-type)
- [Serialization / Deserialization](#serialization--deserialization)
@@ -40,6 +35,10 @@
- [Specializing enum conversion](#specializing-enum-conversion)
- [Binary formats (BSON, CBOR, MessagePack, and UBJSON)](#binary-formats-bson-cbor-messagepack-and-ubjson)
- [Supported compilers](#supported-compilers)
- [Integration](#integration)
- [CMake](#cmake)
- [Package Managers](#package-managers)
- [Pkg-config](#pkg-config)
- [License](#license)
- [Contact](#contact)
- [Thanks](#thanks)
@@ -76,178 +75,26 @@ You can sponsor this library at [GitHub Sponsors](https://github.com/sponsors/nl
- [Michael Hartmann](https://github.com/reFX-Mike)
- [Stefan Hagen](https://github.com/sthagen)
- [Steve Sperandeo](https://github.com/homer6)
- [Robert Jefe Lindstädt](https://github.com/eljefedelrodeodeljefe)
- [Steve Wagner](https://github.com/ciroque)
Thanks everyone!
## Support
## Integration
:question: If you have a **question**, please check if it is already answered in the [**FAQ**](https://json.nlohmann.me/home/faq/) or the [**Q&A**](https://github.com/nlohmann/json/discussions/categories/q-a) section. If not, please [**ask a new question**](https://github.com/nlohmann/json/discussions/new) there.
[`json.hpp`](https://github.com/nlohmann/json/blob/develop/single_include/nlohmann/json.hpp) is the single required file in `single_include/nlohmann` or [released here](https://github.com/nlohmann/json/releases). You need to add
:books: If you want to **learn more** about how to use the library, check out the rest of the [**README**](#examples), have a look at [**code examples**](https://github.com/nlohmann/json/tree/develop/doc/examples), or browse through the [**help pages**](https://json.nlohmann.me).
```cpp
#include <nlohmann/json.hpp>
:construction: If you want to understand the **API** better, check out the [**API Reference**](https://json.nlohmann.me/api/basic_json/) or the [**Doxygen documentation**](https://json.nlohmann.me/doxygen/index.html).
// for convenience
using json = nlohmann::json;
```
:bug: If you found a **bug**, please check the [**FAQ**](https://json.nlohmann.me/home/faq/) if it is a known issue or the result of a design decision. Please also have a look at the [**issue list**](https://github.com/nlohmann/json/issues) before you [**create a new issue**](https://github.com/nlohmann/json/issues/new/choose). Please provide as many information as possible to help us understand and reproduce your issue.
to the files you want to process JSON and set the necessary switches to enable C++11 (e.g., `-std=c++11` for GCC and Clang).
You can further use file [`include/nlohmann/json_fwd.hpp`](https://github.com/nlohmann/json/blob/develop/include/nlohmann/json_fwd.hpp) for forward-declarations. The installation of json_fwd.hpp (as part of cmake's install step), can be achieved by setting `-DJSON_MultipleHeaders=ON`.
### CMake
You can also use the `nlohmann_json::nlohmann_json` interface target in CMake. This target populates the appropriate usage requirements for `INTERFACE_INCLUDE_DIRECTORIES` to point to the appropriate include directories and `INTERFACE_COMPILE_FEATURES` for the necessary C++11 flags.
#### External
To use this library from a CMake project, you can locate it directly with `find_package()` and use the namespaced imported target from the generated package configuration:
```cmake
# CMakeLists.txt
find_package(nlohmann_json 3.2.0 REQUIRED)
...
add_library(foo ...)
...
target_link_libraries(foo PRIVATE nlohmann_json::nlohmann_json)
```
The package configuration file, `nlohmann_jsonConfig.cmake`, can be used either from an install tree or directly out of the build tree.
#### Embedded
To embed the library directly into an existing CMake project, place the entire source tree in a subdirectory and call `add_subdirectory()` in your `CMakeLists.txt` file:
```cmake
# Typically you don't care so much for a third party library's tests to be
# run from your own project's code.
set(JSON_BuildTests OFF CACHE INTERNAL "")
# If you only include this third party in PRIVATE source files, you do not
# need to install it when your main project gets installed.
# set(JSON_Install OFF CACHE INTERNAL "")
# Don't use include(nlohmann_json/CMakeLists.txt) since that carries with it
# unintended consequences that will break the build. It's generally
# discouraged (although not necessarily well documented as such) to use
# include(...) for pulling in other CMake projects anyways.
add_subdirectory(nlohmann_json)
...
add_library(foo ...)
...
target_link_libraries(foo PRIVATE nlohmann_json::nlohmann_json)
```
##### Embedded (FetchContent)
Since CMake v3.11,
[FetchContent](https://cmake.org/cmake/help/v3.11/module/FetchContent.html) can
be used to automatically download the repository as a dependency at configure type.
Example:
```cmake
include(FetchContent)
FetchContent_Declare(json
GIT_REPOSITORY https://github.com/nlohmann/json.git
GIT_TAG v3.7.3)
FetchContent_GetProperties(json)
if(NOT json_POPULATED)
FetchContent_Populate(json)
add_subdirectory(${json_SOURCE_DIR} ${json_BINARY_DIR} EXCLUDE_FROM_ALL)
endif()
target_link_libraries(foo PRIVATE nlohmann_json::nlohmann_json)
```
**Note**: The repository https://github.com/nlohmann/json download size is huge.
It contains all the dataset used for the benchmarks. You might want to depend on
a smaller repository. For instance, you might want to replace the URL above by
https://github.com/ArthurSonzogni/nlohmann_json_cmake_fetchcontent
#### Supporting Both
To allow your project to support either an externally supplied or an embedded JSON library, you can use a pattern akin to the following:
``` cmake
# Top level CMakeLists.txt
project(FOO)
...
option(FOO_USE_EXTERNAL_JSON "Use an external JSON library" OFF)
...
add_subdirectory(thirdparty)
...
add_library(foo ...)
...
# Note that the namespaced target will always be available regardless of the
# import method
target_link_libraries(foo PRIVATE nlohmann_json::nlohmann_json)
```
```cmake
# thirdparty/CMakeLists.txt
...
if(FOO_USE_EXTERNAL_JSON)
find_package(nlohmann_json 3.2.0 REQUIRED)
else()
set(JSON_BuildTests OFF CACHE INTERNAL "")
add_subdirectory(nlohmann_json)
endif()
...
```
`thirdparty/nlohmann_json` is then a complete copy of this source tree.
### Package Managers
:beer: If you are using OS X and [Homebrew](https://brew.sh), just type `brew tap nlohmann/json` and `brew install nlohmann-json` and you're set. If you want the bleeding edge rather than the latest release, use `brew install nlohmann-json --HEAD`.
If you are using the [Meson Build System](https://mesonbuild.com), add this source tree as a [meson subproject](https://mesonbuild.com/Subprojects.html#using-a-subproject). You may also use the `include.zip` published in this project's [Releases](https://github.com/nlohmann/json/releases) to reduce the size of the vendored source tree. Alternatively, you can get a wrap file by downloading it from [Meson WrapDB](https://wrapdb.mesonbuild.com/nlohmann_json), or simply use `meson wrap install nlohmann_json`. Please see the meson project for any issues regarding the packaging.
The provided meson.build can also be used as an alternative to cmake for installing `nlohmann_json` system-wide in which case a pkg-config file is installed. To use it, simply have your build system require the `nlohmann_json` pkg-config dependency. In Meson, it is preferred to use the [`dependency()`](https://mesonbuild.com/Reference-manual.html#dependency) object with a subproject fallback, rather than using the subproject directly.
If you are using [Conan](https://www.conan.io/) to manage your dependencies, merely add `nlohmann_json/x.y.z` to your `conanfile`'s requires, where `x.y.z` is the release version you want to use. Please file issues [here](https://github.com/conan-io/conan-center-index/issues) if you experience problems with the packages.
If you are using [Spack](https://www.spack.io/) to manage your dependencies, you can use the [`nlohmann-json` package](https://spack.readthedocs.io/en/latest/package_list.html#nlohmann-json). Please see the [spack project](https://github.com/spack/spack) for any issues regarding the packaging.
If you are using [hunter](https://github.com/cpp-pm/hunter) on your project for external dependencies, then you can use the [nlohmann_json package](https://hunter.readthedocs.io/en/latest/packages/pkg/nlohmann_json.html). Please see the hunter project for any issues regarding the packaging.
If you are using [Buckaroo](https://buckaroo.pm), you can install this library's module with `buckaroo add github.com/buckaroo-pm/nlohmann-json`. Please file issues [here](https://github.com/buckaroo-pm/nlohmann-json). There is a demo repo [here](https://github.com/njlr/buckaroo-nholmann-json-example).
If you are using [vcpkg](https://github.com/Microsoft/vcpkg/) on your project for external dependencies, then you can use the [nlohmann-json package](https://github.com/Microsoft/vcpkg/tree/master/ports/nlohmann-json). Please see the vcpkg project for any issues regarding the packaging.
If you are using [cget](https://cget.readthedocs.io/en/latest/), you can install the latest development version with `cget install nlohmann/json`. A specific version can be installed with `cget install nlohmann/json@v3.1.0`. Also, the multiple header version can be installed by adding the `-DJSON_MultipleHeaders=ON` flag (i.e., `cget install nlohmann/json -DJSON_MultipleHeaders=ON`).
If you are using [CocoaPods](https://cocoapods.org), you can use the library by adding pod `"nlohmann_json", '~>3.1.2'` to your podfile (see [an example](https://bitbucket.org/benman/nlohmann_json-cocoapod/src/master/)). Please file issues [here](https://bitbucket.org/benman/nlohmann_json-cocoapod/issues?status=new&status=open).
If you are using [NuGet](https://www.nuget.org), you can use the package [nlohmann.json](https://www.nuget.org/packages/nlohmann.json/). Please check [this extensive description](https://github.com/nlohmann/json/issues/1132#issuecomment-452250255) on how to use the package. Please files issues [here](https://github.com/hnkb/nlohmann-json-nuget/issues).
If you are using [conda](https://conda.io/), you can use the package [nlohmann_json](https://github.com/conda-forge/nlohmann_json-feedstock) from [conda-forge](https://conda-forge.org) executing `conda install -c conda-forge nlohmann_json`. Please file issues [here](https://github.com/conda-forge/nlohmann_json-feedstock/issues).
If you are using [MSYS2](https://www.msys2.org/), your can use the [mingw-w64-nlohmann-json](https://packages.msys2.org/base/mingw-w64-nlohmann-json) package, just type `pacman -S mingw-w64-i686-nlohmann-json` or `pacman -S mingw-w64-x86_64-nlohmann-json` for installation. Please file issues [here](https://github.com/msys2/MINGW-packages/issues/new?title=%5Bnlohmann-json%5D) if you experience problems with the packages.
If you are using [`build2`](https://build2.org), you can use the [`nlohmann-json`](https://cppget.org/nlohmann-json) package from the public repository https://cppget.org or directly from the [package's sources repository](https://github.com/build2-packaging/nlohmann-json). In your project's `manifest` file, just add `depends: nlohmann-json` (probably with some [version constraints](https://build2.org/build2-toolchain/doc/build2-toolchain-intro.xhtml#guide-add-remove-deps)). If you are not familiar with using dependencies in `build2`, [please read this introduction](https://build2.org/build2-toolchain/doc/build2-toolchain-intro.xhtml).
Please file issues [here](https://github.com/build2-packaging/nlohmann-json) if you experience problems with the packages.
If you are using [`wsjcpp`](https://wsjcpp.org), you can use the command `wsjcpp install "https://github.com/nlohmann/json:develop"` to get the latest version. Note you can change the branch ":develop" to an existing tag or another branch.
### Pkg-config
If you are using bare Makefiles, you can use `pkg-config` to generate the include flags that point to where the library is installed:
```sh
pkg-config nlohmann_json --cflags
```
Users of the Meson build system will also be able to use a system wide library, which will be found by `pkg-config`:
```meson
json = dependency('nlohmann_json', required: true)
```
There is also a [**docset**](https://github.com/Kapeli/Dash-User-Contributions/tree/master/docsets/JSON_for_Modern_C%2B%2B) for the documentation browsers [Dash](https://kapeli.com/dash), [Velocity](https://velocity.silverlakesoftware.com), and [Zeal](https://zealdocs.org) that contains the full [documentation](https://json.nlohmann.me) as offline resource.
## Examples
Beside the examples below, you may want to check the [documentation](https://nlohmann.github.io/json/) where each function contains a separate code example (e.g., check out [`emplace()`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_a5338e282d1d02bed389d852dd670d98d.html#a5338e282d1d02bed389d852dd670d98d)). All [example files](https://github.com/nlohmann/json/tree/develop/doc/examples) can be compiled and executed on their own (e.g., file [emplace.cpp](https://github.com/nlohmann/json/blob/develop/doc/examples/emplace.cpp)).
Beside the examples below, you may want to check the [documentation](https://nlohmann.github.io/json/) where each function contains a separate code example (e.g., check out [`emplace()`](https://nlohmann.github.io/json/api/basic_json/emplace/)). All [example files](https://github.com/nlohmann/json/tree/develop/doc/examples) can be compiled and executed on their own (e.g., file [emplace.cpp](https://github.com/nlohmann/json/blob/develop/doc/examples/emplace.cpp)).
### JSON as first-class data type
@@ -316,7 +163,7 @@ json j2 = {
};
```
Note that in all these cases, you never need to "tell" the compiler which JSON value type you want to use. If you want to be explicit or express some edge cases, the functions [`json::array()`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_a9ad7ec0bc1082ed09d10900fbb20a21f.html#a9ad7ec0bc1082ed09d10900fbb20a21f) and [`json::object()`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_aaf509a7c029100d292187068f61c99b8.html#aaf509a7c029100d292187068f61c99b8) will help:
Note that in all these cases, you never need to "tell" the compiler which JSON value type you want to use. If you want to be explicit or express some edge cases, the functions [`json::array()`](https://nlohmann.github.io/json/api/basic_json/array/) and [`json::object()`](https://nlohmann.github.io/json/api/basic_json/object/) will help:
```cpp
// a way to express the empty array []
@@ -351,11 +198,11 @@ auto j2 = R"(
Note that without appending the `_json` suffix, the passed string literal is not parsed, but just used as JSON string value. That is, `json j = "{ \"happy\": true, \"pi\": 3.141 }"` would just store the string `"{ "happy": true, "pi": 3.141 }"` rather than parsing the actual object.
The above example can also be expressed explicitly using [`json::parse()`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_a265a473e939184aa42655c9ccdf34e58.html#a265a473e939184aa42655c9ccdf34e58):
The above example can also be expressed explicitly using [`json::parse()`](https://nlohmann.github.io/json/api/basic_json/parse/):
```cpp
// parse explicitly
auto j3 = json::parse("{ \"happy\": true, \"pi\": 3.141 }");
auto j3 = json::parse(R"({"happy": true, "pi": 3.141})");
```
You can also get a string representation of a JSON value (serialize):
@@ -394,9 +241,9 @@ std::cout << cpp_string << " == " << cpp_string2 << " == " << j_string.get<std::
std::cout << j_string << " == " << serialized_string << std::endl;
```
[`.dump()`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_a50ec80b02d0f3f51130d4abb5d1cfdc5.html#a50ec80b02d0f3f51130d4abb5d1cfdc5) always returns the serialized value, and [`.get<std::string>()`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_aa6602bb24022183ab989439e19345d08.html#aa6602bb24022183ab989439e19345d08) returns the originally stored string value.
[`.dump()`](https://nlohmann.github.io/json/api/basic_json/dump/) returns the originally stored string value.
Note the library only supports UTF-8. When you store strings with different encodings in the library, calling [`dump()`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_a50ec80b02d0f3f51130d4abb5d1cfdc5.html#a50ec80b02d0f3f51130d4abb5d1cfdc5) may throw an exception unless `json::error_handler_t::replace` or `json::error_handler_t::ignore` are used as error handlers.
Note the library only supports UTF-8. When you store strings with different encodings in the library, calling [`dump()`](https://nlohmann.github.io/json/api/basic_json/dump/) may throw an exception unless `json::error_handler_t::replace` or `json::error_handler_t::ignore` are used as error handlers.
#### To/from streams (e.g. files, string streams)
@@ -483,7 +330,7 @@ MyIterator begin(MyContainer& tgt) {
}
MyIterator end(const MyContainer&) {
return {};
return {};
}
void foo() {
@@ -512,6 +359,8 @@ bool number_float(number_float_t val, const string_t& s);
// called when a string is parsed; value is passed and can be safely moved away
bool string(string_t& val);
// called when a binary value is parsed; value is passed and can be safely moved away
bool binary(binary_t& val);
// called when an object or array begins or ends, resp. The number of elements is passed (or -1 if not known)
bool start_object(std::size_t elements);
@@ -565,10 +414,10 @@ j[1] = 42;
bool foo = j.at(2);
// comparison
j == "[\"foo\", 42, true]"_json; // true
j == R"(["foo", 1, true, 1.78])"_json; // true
// other stuff
j.size(); // 3 entries
j.size(); // 4 entries
j.empty(); // false
j.type(); // json::value_t::array
j.clear(); // the array is empty again
@@ -761,7 +610,8 @@ j_document.merge_patch(j_patch);
Supported types can be implicitly converted to JSON values.
It is recommended to **NOT USE** implicit conversions **FROM** a JSON value.
You can find more details about this recommendation [here](https://www.github.com/nlohmann/json/issues/958).
You can find more details about this recommendation [here](https://www.github.com/nlohmann/json/issues/958).
You can switch off implicit conversions by defining `JSON_USE_IMPLICIT_CONVERSIONS` to `0` before including the `json.hpp` header. When using CMake, you can also achieve this by setting the option `JSON_ImplicitConversions` to `OFF`.
```cpp
// strings
@@ -858,7 +708,7 @@ assert(p == p2);
To make this work with one of your types, you only need to provide two functions:
```cpp
using nlohmann::json;
using json = nlohmann::json;
namespace ns {
void to_json(json& j, const person& p) {
@@ -881,7 +731,7 @@ Some important things:
* Those methods **MUST** be in your type's namespace (which can be the global namespace), or the library will not be able to locate them (in this example, they are in namespace `ns`, where `person` is defined).
* Those methods **MUST** be available (e.g., proper headers must be included) everywhere you use these conversions. Look at [issue 1108](https://github.com/nlohmann/json/issues/1108) for errors that may occur otherwise.
* When using `get<your_type>()`, `your_type` **MUST** be [DefaultConstructible](https://en.cppreference.com/w/cpp/named_req/DefaultConstructible). (There is a way to bypass this requirement described later.)
* In function `from_json`, use function [`at()`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_a93403e803947b86f4da2d1fb3345cf2c.html#a93403e803947b86f4da2d1fb3345cf2c) to access the object values rather than `operator[]`. In case a key does not exist, `at` throws an exception that you can handle, whereas `operator[]` exhibits undefined behavior.
* In function `from_json`, use function [`at()`](https://nlohmann.github.io/json/api/basic_json/at/) to access the object values rather than `operator[]`. In case a key does not exist, `at` throws an exception that you can handle, whereas `operator[]` exhibits undefined behavior.
* You do not need to add serializers or deserializers for STL types like `std::vector`: the library already implements these.
#### Simplify your life with macros
@@ -914,7 +764,7 @@ namespace ns {
std::string street;
int housenumber;
int postcode;
public:
NLOHMANN_DEFINE_TYPE_INTRUSIVE(address, street, housenumber, postcode)
};
@@ -1114,7 +964,7 @@ Other Important points:
### Binary formats (BSON, CBOR, MessagePack, and UBJSON)
Though JSON is a ubiquitous data format, it is not a very compact format suitable for data exchange, for instance over a network. Hence, the library supports [BSON](http://bsonspec.org) (Binary JSON), [CBOR](https://cbor.io) (Concise Binary Object Representation), [MessagePack](https://msgpack.org), and [UBJSON](http://ubjson.org) (Universal Binary JSON Specification) to efficiently encode JSON values to byte vectors and to decode such vectors.
Though JSON is a ubiquitous data format, it is not a very compact format suitable for data exchange, for instance over a network. Hence, the library supports [BSON](https://bsonspec.org) (Binary JSON), [CBOR](https://cbor.io) (Concise Binary Object Representation), [MessagePack](https://msgpack.org), and [UBJSON](https://ubjson.org) (Universal Binary JSON Specification) to efficiently encode JSON values to byte vectors and to decode such vectors.
```cpp
// create a JSON value
@@ -1186,11 +1036,11 @@ auto cbor = json::to_msgpack(j); // 0xD5 (fixext2), 0x10, 0xCA, 0xFE
## Supported compilers
Though it's 2020 already, the support for C++11 is still a bit sparse. Currently, the following compilers are known to work:
Though it's 2021 already, the support for C++11 is still a bit sparse. Currently, the following compilers are known to work:
- GCC 4.8 - 10.1 (and possibly later)
- Clang 3.4 - 10.0 (and possibly later)
- Apple Clang 9.1 - 12.0 (and possibly later)
- GCC 4.8 - 11.0 (and possibly later)
- Clang 3.4 - 13.0 (and possibly later)
- Apple Clang 9.1 - 12.4 (and possibly later)
- Intel C++ Compiler 17.0.2 (and possibly later)
- Microsoft Visual C++ 2015 / Build Tools 14.0.25123.0 (and possibly later)
- Microsoft Visual C++ 2017 / Build Tools 15.5.180.51428 (and possibly later)
@@ -1215,52 +1065,245 @@ Please note:
- Unsupported versions of GCC and Clang are rejected by `#error` directives. This can be switched off by defining `JSON_SKIP_UNSUPPORTED_COMPILER_CHECK`. Note that you can expect no support in this case.
The following compilers are currently used in continuous integration at [Travis](https://travis-ci.org/nlohmann/json), [AppVeyor](https://ci.appveyor.com/project/nlohmann/json), [GitHub Actions](https://github.com/nlohmann/json/actions), and [CircleCI](https://circleci.com/gh/nlohmann/json):
The following compilers are currently used in continuous integration at [Travis](https://travis-ci.org/nlohmann/json), [AppVeyor](https://ci.appveyor.com/project/nlohmann/json), [Drone CI](https://cloud.drone.io/nlohmann/json), and [GitHub Actions](https://github.com/nlohmann/json/actions):
| Compiler | Operating System | CI Provider |
|-------------------------------------------------------------------|--------------------|----------------|
| Apple Clang 10.0.1 (clang-1001.0.46.4); Xcode 10.2.1 | macOS 10.14.4 | Travis |
| Apple Clang 10.0.1 (clang-1001.0.46.4); Xcode 10.3 | macOS 10.15.7 | GitHub Actions |
| Apple Clang 11.0.0 (clang-1100.0.33.12); Xcode 11.2.1 | macOS 10.15.7 | GitHub Actions |
| Apple Clang 11.0.0 (clang-1100.0.33.17); Xcode 11.3.1 | macOS 10.15.7 | GitHub Actions |
| Apple Clang 11.0.3 (clang-1103.0.32.59); Xcode 11.4.1 | macOS 10.15.7 | GitHub Actions |
| Apple Clang 11.0.3 (clang-1103.0.32.62); Xcode 11.5 | macOS 10.15.7 | GitHub Actions |
| Apple Clang 11.0.3 (clang-1103.0.32.62); Xcode 11.6 | macOS 10.15.7 | GitHub Actions |
| Apple Clang 11.0.3 (clang-1103.0.32.62); Xcode 11.7 | macOS 10.15.7 | GitHub Actions |
| Apple Clang 12.0.0 (clang-1200.0.32.2); Xcode 12 | macOS 10.15.7 | GitHub Actions |
| Apple Clang 12.0.0 (clang-1200.0.32.21); Xcode 12.1 | macOS 10.15.7 | GitHub Actions |
| Apple Clang 12.0.0 (clang-1200.0.32.21); Xcode 12.1.1 | macOS 10.15.7 | GitHub Actions |
| Apple Clang 12.0.0 (clang-1200.0.32.27); Xcode 12.2 | macOS 10.15.7 | GitHub Actions |
| Apple Clang 12.0.0 (clang-1200.0.32.28); Xcode 12.3 | macOS 10.15.7 | GitHub Actions |
| Apple Clang 12.0.0 (clang-1200.0.32.29); Xcode 12.4 | macOS 10.15.7 | GitHub Actions |
| GCC 4.8.5 (Ubuntu 4.8.5-4ubuntu2) | Ubuntu 20.04.2 LTS | GitHub Actions |
| GCC 4.9.3 (Ubuntu 4.9.3-13ubuntu2) | Ubuntu 20.04.2 LTS | GitHub Actions |
| GCC 5.4.0 (Ubuntu 5.4.0-6ubuntu1~16.04.12) | Ubuntu 20.04.2 LTS | GitHub Actions |
| GCC 6.5.0 (Ubuntu 6.5.0-2ubuntu1~14.04.1) | Ubuntu 14.04.5 LTS | Travis |
| GCC 7.5.0 (Ubuntu 7.5.0-6ubuntu2) | Ubuntu 20.04.2 LTS | GitHub Actions |
| GCC 8.1.0 (x86_64-posix-seh-rev0, Built by MinGW-W64 project) | Windows-10.0.17763 | GitHub Actions |
| GCC 8.1.0 (i686-posix-dwarf-rev0, Built by MinGW-W64 project) | Windows-10.0.17763 | GitHub Actions |
| GCC 8.4.0 (Ubuntu 8.4.0-3ubuntu2) | Ubuntu 20.04.2 LTS | GitHub Actions |
| GCC 9.3.0 (Ubuntu 9.3.0-17ubuntu1~20.04) | Ubuntu 20.04.2 LTS | GitHub Actions |
| GCC 10.2.0 (Ubuntu 10.2.0-5ubuntu1~20.04) | Ubuntu 20.04.2 LTS | GitHub Actions |
| GCC 11.0.1 20210321 (experimental) | Ubuntu 20.04.2 LTS | GitHub Actions |
| GCC 11.1.0 | Ubuntu (aarch64) | Drone CI |
| Clang 3.5.2 (3.5.2-3ubuntu1) | Ubuntu 20.04.2 LTS | GitHub Actions |
| Clang 3.6.2 (3.6.2-3ubuntu2) | Ubuntu 20.04.2 LTS | GitHub Actions |
| Clang 3.7.1 (3.7.1-2ubuntu2) | Ubuntu 20.04.2 LTS | GitHub Actions |
| Clang 3.8.0 (3.8.0-2ubuntu4) | Ubuntu 20.04.2 LTS | GitHub Actions |
| Clang 3.9.1 (3.9.1-4ubuntu3\~16.04.2) | Ubuntu 20.04.2 LTS | GitHub Actions |
| Clang 4.0.0 (4.0.0-1ubuntu1\~16.04.2) | Ubuntu 20.04.2 LTS | GitHub Actions |
| Clang 5.0.0 (5.0.0-3\~16.04.1) | Ubuntu 20.04.2 LTS | GitHub Actions |
| Clang 6.0.1 (6.0.1-14) | Ubuntu 20.04.2 LTS | GitHub Actions |
| Clang 7.0.1 (7.0.1-12) | Ubuntu 20.04.2 LTS | GitHub Actions |
| Clang 8.0.1 (8.0.1-9) | Ubuntu 20.04.2 LTS | GitHub Actions |
| Clang 9.0.1 (9.0.1-12) | Ubuntu 20.04.2 LTS | GitHub Actions |
| Clang 10.0.0 (10.0.0-4ubuntu1) | Ubuntu 20.04.2 LTS | GitHub Actions |
| Clang 10.0.0 with GNU-like command-line | Windows-10.0.17763 | GitHub Actions |
| Clang 11.0.0 with GNU-like command-line | Windows-10.0.17763 | GitHub Actions |
| Clang 11.0.0 with MSVC-like command-line | Windows-10.0.17763 | GitHub Actions |
| Clang 11.0.0 (11.0.0-2~ubuntu20.04.1) | Ubuntu 20.04.2 LTS | GitHub Actions |
| Clang 12.0.0 (12.0.0-3ubuntu1~20.04.3) | Ubuntu 20.04.2 LTS | GitHub Actions |
| Clang 13.0.0 (13.0.0-++20210828094952+9c49fee5e7ac-1exp120210828075752.71 | Ubuntu 20.04.2 LTS | GitHub Actions |
| Visual Studio 14 2015 MSVC 19.0.24241.7 (Build Engine version 14.0.25420.1) | Windows-6.3.9600 | AppVeyor |
| Visual Studio 15 2017 MSVC 19.16.27035.0 (Build Engine version 15.9.21+g9802d43bc3 for .NET Framework) | Windows-10.0.14393 | AppVeyor |
| Visual Studio 15 2017 MSVC 19.16.27045.0 (Build Engine version 15.9.21+g9802d43bc3 for .NET Framework) | Windows-10.0.14393 | GitHub Actions |
| Visual Studio 16 2019 MSVC 19.28.29912.0 (Build Engine version 16.9.0+57a23d249 for .NET Framework) | Windows-10.0.17763 | GitHub Actions |
| Visual Studio 16 2019 MSVC 19.28.29912.0 (Build Engine version 16.9.0+57a23d249 for .NET Framework) | Windows-10.0.17763 | AppVeyor |
## Integration
[`json.hpp`](https://github.com/nlohmann/json/blob/develop/single_include/nlohmann/json.hpp) is the single required file in `single_include/nlohmann` or [released here](https://github.com/nlohmann/json/releases). You need to add
```cpp
#include <nlohmann/json.hpp>
// for convenience
using json = nlohmann::json;
```
to the files you want to process JSON and set the necessary switches to enable C++11 (e.g., `-std=c++11` for GCC and Clang).
You can further use file [`include/nlohmann/json_fwd.hpp`](https://github.com/nlohmann/json/blob/develop/include/nlohmann/json_fwd.hpp) for forward-declarations. The installation of json_fwd.hpp (as part of cmake's install step), can be achieved by setting `-DJSON_MultipleHeaders=ON`.
### CMake
You can also use the `nlohmann_json::nlohmann_json` interface target in CMake. This target populates the appropriate usage requirements for `INTERFACE_INCLUDE_DIRECTORIES` to point to the appropriate include directories and `INTERFACE_COMPILE_FEATURES` for the necessary C++11 flags.
#### External
To use this library from a CMake project, you can locate it directly with `find_package()` and use the namespaced imported target from the generated package configuration:
```cmake
# CMakeLists.txt
find_package(nlohmann_json 3.2.0 REQUIRED)
...
add_library(foo ...)
...
target_link_libraries(foo PRIVATE nlohmann_json::nlohmann_json)
```
The package configuration file, `nlohmann_jsonConfig.cmake`, can be used either from an install tree or directly out of the build tree.
#### Embedded
To embed the library directly into an existing CMake project, place the entire source tree in a subdirectory and call `add_subdirectory()` in your `CMakeLists.txt` file:
```cmake
# Typically you don't care so much for a third party library's tests to be
# run from your own project's code.
set(JSON_BuildTests OFF CACHE INTERNAL "")
# If you only include this third party in PRIVATE source files, you do not
# need to install it when your main project gets installed.
# set(JSON_Install OFF CACHE INTERNAL "")
# Don't use include(nlohmann_json/CMakeLists.txt) since that carries with it
# unintended consequences that will break the build. It's generally
# discouraged (although not necessarily well documented as such) to use
# include(...) for pulling in other CMake projects anyways.
add_subdirectory(nlohmann_json)
...
add_library(foo ...)
...
target_link_libraries(foo PRIVATE nlohmann_json::nlohmann_json)
```
##### Embedded (FetchContent)
Since CMake v3.11,
[FetchContent](https://cmake.org/cmake/help/v3.11/module/FetchContent.html) can
be used to automatically download the repository as a dependency at configure time.
Example:
```cmake
include(FetchContent)
FetchContent_Declare(json
GIT_REPOSITORY https://github.com/nlohmann/json.git
GIT_TAG v3.7.3)
FetchContent_GetProperties(json)
if(NOT json_POPULATED)
FetchContent_Populate(json)
add_subdirectory(${json_SOURCE_DIR} ${json_BINARY_DIR} EXCLUDE_FROM_ALL)
endif()
target_link_libraries(foo PRIVATE nlohmann_json::nlohmann_json)
```
**Note**: The repository https://github.com/nlohmann/json download size is huge.
It contains all the dataset used for the benchmarks. You might want to depend on
a smaller repository. For instance, you might want to replace the URL above by
https://github.com/ArthurSonzogni/nlohmann_json_cmake_fetchcontent
#### Supporting Both
To allow your project to support either an externally supplied or an embedded JSON library, you can use a pattern akin to the following:
``` cmake
# Top level CMakeLists.txt
project(FOO)
...
option(FOO_USE_EXTERNAL_JSON "Use an external JSON library" OFF)
...
add_subdirectory(thirdparty)
...
add_library(foo ...)
...
# Note that the namespaced target will always be available regardless of the
# import method
target_link_libraries(foo PRIVATE nlohmann_json::nlohmann_json)
```
```cmake
# thirdparty/CMakeLists.txt
...
if(FOO_USE_EXTERNAL_JSON)
find_package(nlohmann_json 3.2.0 REQUIRED)
else()
set(JSON_BuildTests OFF CACHE INTERNAL "")
add_subdirectory(nlohmann_json)
endif()
...
```
`thirdparty/nlohmann_json` is then a complete copy of this source tree.
### Package Managers
:beer: If you are using OS X and [Homebrew](https://brew.sh), just type `brew install nlohmann-json` and you're set. If you want the bleeding edge rather than the latest release, use `brew install nlohmann-json --HEAD`. See [nlohmann-json](https://formulae.brew.sh/formula/nlohmann-json) for more information.
If you are using the [Meson Build System](https://mesonbuild.com), add this source tree as a [meson subproject](https://mesonbuild.com/Subprojects.html#using-a-subproject). You may also use the `include.zip` published in this project's [Releases](https://github.com/nlohmann/json/releases) to reduce the size of the vendored source tree. Alternatively, you can get a wrap file by downloading it from [Meson WrapDB](https://wrapdb.mesonbuild.com/nlohmann_json), or simply use `meson wrap install nlohmann_json`. Please see the meson project for any issues regarding the packaging.
The provided meson.build can also be used as an alternative to cmake for installing `nlohmann_json` system-wide in which case a pkg-config file is installed. To use it, simply have your build system require the `nlohmann_json` pkg-config dependency. In Meson, it is preferred to use the [`dependency()`](https://mesonbuild.com/Reference-manual.html#dependency) object with a subproject fallback, rather than using the subproject directly.
If you are using [Conan](https://www.conan.io/) to manage your dependencies, merely add [`nlohmann_json/x.y.z`](https://conan.io/center/nlohmann_json) to your `conanfile`'s requires, where `x.y.z` is the release version you want to use. Please file issues [here](https://github.com/conan-io/conan-center-index/issues) if you experience problems with the packages.
If you are using [Spack](https://www.spack.io/) to manage your dependencies, you can use the [`nlohmann-json` package](https://spack.readthedocs.io/en/latest/package_list.html#nlohmann-json). Please see the [spack project](https://github.com/spack/spack) for any issues regarding the packaging.
If you are using [hunter](https://github.com/cpp-pm/hunter) on your project for external dependencies, then you can use the [nlohmann_json package](https://hunter.readthedocs.io/en/latest/packages/pkg/nlohmann_json.html). Please see the hunter project for any issues regarding the packaging.
If you are using [Buckaroo](https://buckaroo.pm), you can install this library's module with `buckaroo add github.com/buckaroo-pm/nlohmann-json`. Please file issues [here](https://github.com/buckaroo-pm/nlohmann-json). There is a demo repo [here](https://github.com/njlr/buckaroo-nholmann-json-example).
If you are using [vcpkg](https://github.com/Microsoft/vcpkg/) on your project for external dependencies, then you can install the [nlohmann-json package](https://github.com/Microsoft/vcpkg/tree/master/ports/nlohmann-json) with `vcpkg install nlohmann-json` and follow the then displayed descriptions. Please see the vcpkg project for any issues regarding the packaging.
If you are using [cget](https://cget.readthedocs.io/en/latest/), you can install the latest development version with `cget install nlohmann/json`. A specific version can be installed with `cget install nlohmann/json@v3.1.0`. Also, the multiple header version can be installed by adding the `-DJSON_MultipleHeaders=ON` flag (i.e., `cget install nlohmann/json -DJSON_MultipleHeaders=ON`).
If you are using [CocoaPods](https://cocoapods.org), you can use the library by adding pod `"nlohmann_json", '~>3.1.2'` to your podfile (see [an example](https://bitbucket.org/benman/nlohmann_json-cocoapod/src/master/)). Please file issues [here](https://bitbucket.org/benman/nlohmann_json-cocoapod/issues?status=new&status=open).
If you are using [NuGet](https://www.nuget.org), you can use the package [nlohmann.json](https://www.nuget.org/packages/nlohmann.json/). Please check [this extensive description](https://github.com/nlohmann/json/issues/1132#issuecomment-452250255) on how to use the package. Please files issues [here](https://github.com/hnkb/nlohmann-json-nuget/issues).
If you are using [conda](https://conda.io/), you can use the package [nlohmann_json](https://github.com/conda-forge/nlohmann_json-feedstock) from [conda-forge](https://conda-forge.org) executing `conda install -c conda-forge nlohmann_json`. Please file issues [here](https://github.com/conda-forge/nlohmann_json-feedstock/issues).
If you are using [MSYS2](https://www.msys2.org/), you can use the [mingw-w64-nlohmann-json](https://packages.msys2.org/base/mingw-w64-nlohmann-json) package, just type `pacman -S mingw-w64-i686-nlohmann-json` or `pacman -S mingw-w64-x86_64-nlohmann-json` for installation. Please file issues [here](https://github.com/msys2/MINGW-packages/issues/new?title=%5Bnlohmann-json%5D) if you experience problems with the packages.
If you are using [MacPorts](https://ports.macports.org), execute `sudo port install nlohmann-json` to install the [nlohmann-json](https://ports.macports.org/port/nlohmann-json/) package.
If you are using [`build2`](https://build2.org), you can use the [`nlohmann-json`](https://cppget.org/nlohmann-json) package from the public repository https://cppget.org or directly from the [package's sources repository](https://github.com/build2-packaging/nlohmann-json). In your project's `manifest` file, just add `depends: nlohmann-json` (probably with some [version constraints](https://build2.org/build2-toolchain/doc/build2-toolchain-intro.xhtml#guide-add-remove-deps)). If you are not familiar with using dependencies in `build2`, [please read this introduction](https://build2.org/build2-toolchain/doc/build2-toolchain-intro.xhtml).
Please file issues [here](https://github.com/build2-packaging/nlohmann-json) if you experience problems with the packages.
If you are using [`wsjcpp`](https://wsjcpp.org), you can use the command `wsjcpp install "https://github.com/nlohmann/json:develop"` to get the latest version. Note you can change the branch ":develop" to an existing tag or another branch.
If you are using [`CPM.cmake`](https://github.com/TheLartians/CPM.cmake), you can check this [`example`](https://github.com/TheLartians/CPM.cmake/tree/master/examples/json). After [adding CPM script](https://github.com/TheLartians/CPM.cmake#adding-cpm) to your project, implement the following snippet to your CMake:
```cmake
CPMAddPackage(
NAME nlohmann_json
GITHUB_REPOSITORY nlohmann/json
VERSION 3.9.1)
```
### Pkg-config
If you are using bare Makefiles, you can use `pkg-config` to generate the include flags that point to where the library is installed:
```sh
pkg-config nlohmann_json --cflags
```
Users of the Meson build system will also be able to use a system wide library, which will be found by `pkg-config`:
```meson
json = dependency('nlohmann_json', required: true)
```
| Compiler | Operating System | CI Provider |
|-----------------------------------------------------------------|--------------------|----------------|
| Apple Clang 9.1.0 (clang-902.0.39.1); Xcode 9.3 | macOS 10.13.3 | Travis |
| Apple Clang 9.1.0 (clang-902.0.39.2); Xcode 9.4.1 | macOS 10.13.6 | Travis |
| Apple Clang 10.0.0 (clang-1000.11.45.2); Xcode 10.0 | macOS 10.13.6 | Travis |
| Apple Clang 10.0.0 (clang-1000.11.45.5); Xcode 10.1 | macOS 10.13.6 | Travis |
| Apple Clang 10.0.1 (clang-1001.0.46.4); Xcode 10.2.1 | macOS 10.14.4 | Travis |
| Apple Clang 11.0.0 (clang-1100.0.33.12); Xcode 11.2.1 | macOS 10.14.6 | Travis |
| Apple Clang 11.0.3 (clang-1103.0.32.59); Xcode 11.4.1 | macOS 10.15.4 | GitHub Actions |
| Clang 3.5.0 (3.5.0-4ubuntu2~trusty2) | Ubuntu 14.04.5 LTS | Travis |
| Clang 3.6.2 (3.6.2-svn240577-1~exp1) | Ubuntu 14.04.5 LTS | Travis |
| Clang 3.7.1 (3.7.1-svn253571-1~exp1) | Ubuntu 14.04.5 LTS | Travis |
| Clang 3.8.0 (3.8.0-2ubuntu3~trusty5) | Ubuntu 14.04.5 LTS | Travis |
| Clang 3.9.1 (3.9.1-4ubuntu3~14.04.3) | Ubuntu 14.04.5 LTS | Travis |
| Clang 4.0.1 (4.0.1-svn305264-1~exp1) | Ubuntu 14.04.5 LTS | Travis |
| Clang 5.0.2 (version 5.0.2-svn328729-1~exp1~20180509123505.100) | Ubuntu 14.04.5 LTS | Travis |
| Clang 6.0.1 (6.0.1-svn334776-1~exp1~20190309042707.121) | Ubuntu 14.04.5 LTS | Travis |
| Clang 7.1.0 (7.1.0-svn353565-1~exp1~20190419134007.64) | Ubuntu 14.04.5 LTS | Travis |
| Clang 7.5.0 (Ubuntu 7.5.0-3ubuntu1~18.04) | Ubuntu 18.04.4 LTS | Travis |
| Clang 9.0.0 (x86_64-pc-windows-msvc) | Windows-10.0.17763 | GitHub Actions |
| Clang 10.0.0 (x86_64-pc-windows-msvc) | Windows-10.0.17763 | GitHub Actions |
| GCC 4.8.5 (Ubuntu 4.8.5-4ubuntu8~14.04.2) | Ubuntu 14.04.5 LTS | Travis |
| GCC 4.9.4 (Ubuntu 4.9.4-2ubuntu1~14.04.1) | Ubuntu 14.04.5 LTS | Travis |
| GCC 5.5.0 (Ubuntu 5.5.0-12ubuntu1~14.04) | Ubuntu 14.04.5 LTS | Travis |
| GCC 6.3.0 (Debian 6.3.0-18+deb9u1) | Debian 9 | Circle CI |
| GCC 6.5.0 (Ubuntu 6.5.0-2ubuntu1~14.04.1) | Ubuntu 14.04.5 LTS | Travis |
| GCC 7.3.0 (x86_64-posix-seh-rev0, Built by MinGW-W64 project) | Windows-6.3.9600 | AppVeyor |
| GCC 7.5.0 (Ubuntu 7.5.0-3ubuntu1~14.04.1) | Ubuntu 14.04.5 LTS | Travis |
| GCC 7.5.0 (Ubuntu 7.5.0-3ubuntu1~18.04) | Ubuntu 18.04.4 LTS | GitHub Actions |
| GCC 8.4.0 (Ubuntu 8.4.0-1ubuntu1~14.04) | Ubuntu 14.04.5 LTS | Travis |
| GCC 9.3.0 (Ubuntu 9.3.0-11ubuntu0~14.04) | Ubuntu 14.04.5 LTS | Travis |
| GCC 10.1.0 (Arch Linux latest) | Arch Linux | Circle CI |
| MSVC 19.0.24241.7 (Build Engine version 14.0.25420.1) | Windows-6.3.9600 | AppVeyor |
| MSVC 19.16.27035.0 (15.9.21+g9802d43bc3 for .NET Framework) | Windows-10.0.14393 | AppVeyor |
| MSVC 19.25.28614.0 (Build Engine version 16.5.0+d4cbfca49 for .NET Framework) | Windows-10.0.17763 | AppVeyor |
| MSVC 19.25.28614.0 (Build Engine version 16.5.0+d4cbfca49 for .NET Framework) | Windows-10.0.17763 | GitHub Actions |
## License
<img align="right" src="http://opensource.org/trademarks/opensource/OSI-Approved-License-100x137.png">
<img align="right" src="https://opensource.org/trademarks/opensource/OSI-Approved-License-100x137.png">
The class is licensed under the [MIT License](http://opensource.org/licenses/MIT):
The class is licensed under the [MIT License](https://opensource.org/licenses/MIT):
Copyright &copy; 2013-2019 [Niels Lohmann](http://nlohmann.me)
Copyright &copy; 2013-2021 [Niels Lohmann](https://nlohmann.me)
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
@@ -1270,12 +1313,14 @@ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR I
* * *
The class contains the UTF-8 Decoder from Bjoern Hoehrmann which is licensed under the [MIT License](http://opensource.org/licenses/MIT) (see above). Copyright &copy; 2008-2009 [Björn Hoehrmann](https://bjoern.hoehrmann.de/) <bjoern@hoehrmann.de>
The class contains the UTF-8 Decoder from Bjoern Hoehrmann which is licensed under the [MIT License](https://opensource.org/licenses/MIT) (see above). Copyright &copy; 2008-2009 [Björn Hoehrmann](https://bjoern.hoehrmann.de/) <bjoern@hoehrmann.de>
The class contains a slightly modified version of the Grisu2 algorithm from Florian Loitsch which is licensed under the [MIT License](http://opensource.org/licenses/MIT) (see above). Copyright &copy; 2009 [Florian Loitsch](https://florian.loitsch.com/)
The class contains a slightly modified version of the Grisu2 algorithm from Florian Loitsch which is licensed under the [MIT License](https://opensource.org/licenses/MIT) (see above). Copyright &copy; 2009 [Florian Loitsch](https://florian.loitsch.com/)
The class contains a copy of [Hedley](https://nemequ.github.io/hedley/) from Evan Nemerson which is licensed as [CC0-1.0](https://creativecommons.org/publicdomain/zero/1.0/).
The class contains parts of [Google Abseil](https://github.com/abseil/abseil-cpp) which is licensed under the [Apache 2.0 License](https://opensource.org/licenses/Apache-2.0).
## Contact
If you have questions regarding the library, I would like to invite you to [open an issue at GitHub](https://github.com/nlohmann/json/issues/new/choose). Please describe your request, problem, or question as detailed as possible, and also mention the version of the library you are using as well as the version of your compiler and operating system. Opening an issue at GitHub allows other users and contributors to this library to collaborate. For instance, I have little experience with MSVC, and most issues in this regard have been solved by a growing community. If you have a look at the [closed issues](https://github.com/nlohmann/json/issues?q=is%3Aissue+is%3Aclosed), you will see that we react quite timely in most cases.
@@ -1506,6 +1551,52 @@ I deeply appreciate the help of the following people.
- [XyFreak](https://github.com/XyFreak) fixed a compiler warning.
- [TotalCaesar659](https://github.com/TotalCaesar659) fixed links in the README.
- [Tanuj Garg](https://github.com/tanuj208) improved the fuzzer coverage for UBSAN input.
- [AODQ](https://github.com/AODQ) fixed a compiler warning.
- [jwittbrodt](https://github.com/jwittbrodt) made `NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE` inline.
- [pfeatherstone](https://github.com/pfeatherstone) improved the upper bound of arguments of the `NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE`/`NLOHMANN_DEFINE_TYPE_INTRUSIVE` macros.
- [Jan Procházka](https://github.com/jprochazk) fixed a bug in the CBOR parser for binary and string values.
- [T0b1-iOS](https://github.com/T0b1-iOS) fixed a bug in the new hash implementation.
- [Matthew Bauer](https://github.com/matthewbauer) adjusted the CBOR writer to create tags for binary subtypes.
- [gatopeich](https://github.com/gatopeich) implemented an ordered map container for `nlohmann::ordered_json`.
- [Érico Nogueira Rolim](https://github.com/ericonr) added support for pkg-config.
- [KonanM](https://github.com/KonanM) proposed an implementation for the `NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE`/`NLOHMANN_DEFINE_TYPE_INTRUSIVE` macros.
- [Guillaume Racicot](https://github.com/gracicot) implemented `string_view` support and allowed C++20 support.
- [Alex Reinking](https://github.com/alexreinking) improved CMake support for `FetchContent`.
- [Hannes Domani](https://github.com/ssbssa) provided a GDB pretty printer.
- Lars Wirzenius reviewed the README file.
- [Jun Jie](https://github.com/ongjunjie) fixed a compiler path in the CMake scripts.
- [Ronak Buch](https://github.com/rbuch) fixed typos in the documentation.
- [Alexander Karzhenkov](https://github.com/karzhenkov) fixed a move constructor and the Travis builds.
- [Leonardo Lima](https://github.com/leozz37) added CPM.Cmake support.
- [Joseph Blackman](https://github.com/jbzdarkid) fixed a warning.
- [Yaroslav](https://github.com/YarikTH) updated doctest and implemented unit tests.
- [Martin Stump](https://github.com/globberwops) fixed a bug in the CMake files.
- [Jaakko Moisio](https://github.com/jasujm) fixed a bug in the input adapters.
- [bl-ue](https://github.com/bl-ue) fixed some Markdown issues in the README file.
- [William A. Wieselquist](https://github.com/wawiesel) fixed an example from the README.
- [abbaswasim](https://github.com/abbaswasim) fixed an example from the README.
- [Remy Jette](https://github.com/remyjette) fixed a warning.
- [Fraser](https://github.com/frasermarlow) fixed the documentation.
- [Ben Beasley](https://github.com/musicinmybrain) updated doctest.
- [Doron Behar](https://github.com/doronbehar) fixed pkg-config.pc.
- [raduteo](https://github.com/raduteo) fixed a warning.
- [David Pfahler](https://github.com/theShmoo) added the possibility to compile the library without I/O support.
- [Morten Fyhn Amundsen](https://github.com/mortenfyhn) fixed a typo.
- [jpl-mac](https://github.com/jpl-mac) allowed to treat the library as a system header in CMake.
- [Jason Dsouza](https://github.com/jasmcaus) fixed the indentation of the CMake file.
- [offa](https://github.com/offa) added a link to Conan Center to the documentation.
- [TotalCaesar659](https://github.com/TotalCaesar659) updated the links in the documentation to use HTTPS.
- [Rafail Giavrimis](https://github.com/grafail) fixed the Google Benchmark default branch.
- [Louis Dionne](https://github.com/ldionne) fixed a conversion operator.
- [justanotheranonymoususer](https://github.com/justanotheranonymoususer) made the examples in the README more consistent.
- [Finkman](https://github.com/Finkman) suppressed some `-Wfloat-equal` warnings.
- [Ferry Huberts](https://github.com/fhuberts) fixed `-Wswitch-enum` warnings.
- [Arseniy Terekhin](https://github.com/senyai) made the GDB pretty-printer robust against unset variable names.
- [Amir Masoud Abdol](https://github.com/amirmasoudabdol) updated the Homebrew command as nlohmann/json is now in homebrew-core.
- [Hallot](https://github.com/Hallot) fixed some `-Wextra-semi-stmt warnings`.
- [Giovanni Cerretani](https://github.com/gcerretani) fixed `-Wunused` warnings on `JSON_DIAGNOSTICS`.
- [Bogdan Popescu](https://github.com/Kapeli) hosts the [docset](https://github.com/Kapeli/Dash-User-Contributions/tree/master/docsets/JSON_for_Modern_C%2B%2B) for offline documentation viewers.
- [Carl Smedstad](https://github.com/carlsmedstad) fixed an assertion error when using `JSON_DIAGNOSTICS`.
Thanks a lot for helping out! Please [let me know](mailto:mail@nlohmann.me) if I forgot someone.
@@ -1518,7 +1609,6 @@ The library itself consists of a single header file licensed under the MIT licen
- [**American fuzzy lop**](https://lcamtuf.coredump.cx/afl/) for fuzz testing
- [**AppVeyor**](https://www.appveyor.com) for [continuous integration](https://ci.appveyor.com/project/nlohmann/json) on Windows
- [**Artistic Style**](http://astyle.sourceforge.net) for automatic source code indentation
- [**CircleCI**](https://circleci.com) for [continuous integration](https://circleci.com/gh/nlohmann/json).
- [**Clang**](https://clang.llvm.org) for compilation with code sanitizers
- [**CMake**](https://cmake.org) for build automation
- [**Codacity**](https://www.codacy.com) for further [code analysis](https://www.codacy.com/app/nlohmann/json)
@@ -1535,10 +1625,10 @@ The library itself consists of a single header file licensed under the MIT licen
- [**libFuzzer**](https://llvm.org/docs/LibFuzzer.html) to implement fuzz testing for OSS-Fuzz
- [**OSS-Fuzz**](https://github.com/google/oss-fuzz) for continuous fuzz testing of the library ([project repository](https://github.com/google/oss-fuzz/tree/master/projects/json))
- [**Probot**](https://probot.github.io) for automating maintainer tasks such as closing stale issues, requesting missing information, or detecting toxic comments.
- [**send_to_wandbox**](https://github.com/nlohmann/json/blob/develop/doc/scripts/send_to_wandbox.py) to send code examples to [Wandbox](http://melpon.org/wandbox)
- [**send_to_wandbox**](https://github.com/nlohmann/json/blob/develop/doc/scripts/send_to_wandbox.py) to send code examples to [Wandbox](https://wandbox.org)
- [**Travis**](https://travis-ci.org) for [continuous integration](https://travis-ci.org/nlohmann/json) on Linux and macOS
- [**Valgrind**](https://valgrind.org) to check for correct memory management
- [**Wandbox**](https://wandbox.org) for [online examples](https://wandbox.org/permlink/3lCHrFUZANONKv7a)
- [**Wandbox**](https://wandbox.org) for [online examples](https://wandbox.org/permlink/1mp10JbaANo6FUc7)
## Projects using JSON for Modern C++
@@ -1558,7 +1648,8 @@ The library supports **Unicode input** as follows:
- [Unicode noncharacters](https://www.unicode.org/faq/private_use.html#nonchar1) will not be replaced by the library.
- Invalid surrogates (e.g., incomplete pairs such as `\uDEAD`) will yield parse errors.
- The strings stored in the library are UTF-8 encoded. When using the default string type (`std::string`), note that its length/size functions return the number of stored bytes rather than the number of characters or glyphs.
- When you store strings with different encodings in the library, calling [`dump()`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_a50ec80b02d0f3f51130d4abb5d1cfdc5.html#a50ec80b02d0f3f51130d4abb5d1cfdc5) may throw an exception unless `json::error_handler_t::replace` or `json::error_handler_t::ignore` are used as error handlers.
- When you store strings with different encodings in the library, calling [`dump()`](https://nlohmann.github.io/json/api/basic_json/dump/) may throw an exception unless `json::error_handler_t::replace` or `json::error_handler_t::ignore` are used as error handlers.
- To store wide strings (e.g., `std::wstring`), you need to convert them to a a UTF-8 encoded `std::string` before, see [an example](https://json.nlohmann.me/home/faq/#wide-string-handling).
### Comments in JSON
@@ -1567,7 +1658,7 @@ This library does not support comments by default. It does so for three reasons:
1. Comments are not part of the [JSON specification](https://tools.ietf.org/html/rfc8259). You may argue that `//` or `/* */` are allowed in JavaScript, but JSON is not JavaScript.
2. This was not an oversight: Douglas Crockford [wrote on this](https://plus.google.com/118095276221607585885/posts/RK8qyGVaGSr) in May 2012:
> I removed comments from JSON because I saw people were using them to hold parsing directives, a practice which would have destroyed interoperability. I know that the lack of comments makes some people sad, but it shouldn't.
> I removed comments from JSON because I saw people were using them to hold parsing directives, a practice which would have destroyed interoperability. I know that the lack of comments makes some people sad, but it shouldn't.
> Suppose you are using JSON to keep configuration files, which you would like to annotate. Go ahead and insert all the comments you like. Then pipe it through JSMin before handing it to your JSON parser.
@@ -1583,19 +1674,19 @@ If you do want to preserve the insertion order, you can try the type [`nlohmann:
### Memory Release
We checked with Valgrind and the Address Sanitizer (ASAN) that there are no memory leaks.
We checked with Valgrind and the Address Sanitizer (ASAN) that there are no memory leaks.
If you find that a parsing program with this library does not release memory, please consider the following case and it maybe unrelated to this library.
If you find that a parsing program with this library does not release memory, please consider the following case and it maybe unrelated to this library.
**Your program is compiled with glibc.** There is a tunable threshold that glibc uses to decide whether to actually return memory to the system or whether to cache it for later reuse. If in your program you make lots of small allocations and those small allocations are not a contiguous block and are presumably below the threshold, then they will not get returned to the OS.
Here is a related issue [#1924](https://github.com/nlohmann/json/issues/1924).
### Further notes
- The code contains numerous debug **assertions** which can be switched off by defining the preprocessor macro `NDEBUG`, see the [documentation of `assert`](https://en.cppreference.com/w/cpp/error/assert). In particular, note [`operator[]`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_a233b02b0839ef798942dd46157cc0fe6.html#a233b02b0839ef798942dd46157cc0fe6) implements **unchecked access** for const objects: If the given key is not present, the behavior is undefined (think of a dereferenced null pointer) and yields an [assertion failure](https://github.com/nlohmann/json/issues/289) if assertions are switched on. If you are not sure whether an element in an object exists, use checked access with the [`at()` function](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_a73ae333487310e3302135189ce8ff5d8.html#a73ae333487310e3302135189ce8ff5d8). Furthermore, you can define `JSON_ASSERT(x)` to replace calls to `assert(x)`.
- The code contains numerous debug **assertions** which can be switched off by defining the preprocessor macro `NDEBUG`, see the [documentation of `assert`](https://en.cppreference.com/w/cpp/error/assert). In particular, note [`operator[]`](https://nlohmann.github.io/json/api/basic_json/operator%5B%5D/) implements **unchecked access** for const objects: If the given key is not present, the behavior is undefined (think of a dereferenced null pointer) and yields an [assertion failure](https://github.com/nlohmann/json/issues/289) if assertions are switched on. If you are not sure whether an element in an object exists, use checked access with the [`at()` function](https://nlohmann.github.io/json/api/basic_json/at/). Furthermore, you can define `JSON_ASSERT(x)` to replace calls to `assert(x)`.
- As the exact type of a number is not defined in the [JSON specification](https://tools.ietf.org/html/rfc8259.html), 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.
- The code can be compiled without C++ **runtime type identification** features; that is, you can use the `-fno-rtti` compiler flag.
- **Exceptions** are used widely within the library. They can, however, be switched off with either using the compiler flag `-fno-exceptions` or by defining the symbol `JSON_NOEXCEPTION`. In this case, exceptions are replaced by `abort()` calls. You can further control this behavior by defining `JSON_THROW_USER´` (overriding `throw`), `JSON_TRY_USER` (overriding `try`), and `JSON_CATCH_USER` (overriding `catch`). Note that `JSON_THROW_USER` should leave the current scope (e.g., by throwing or aborting), as continuing after it may yield undefined behavior.
- **Exceptions** are used widely within the library. They can, however, be switched off with either using the compiler flag `-fno-exceptions` or by defining the symbol `JSON_NOEXCEPTION`. In this case, exceptions are replaced by `abort()` calls. You can further control this behavior by defining `JSON_THROW_USER` (overriding `throw`), `JSON_TRY_USER` (overriding `try`), and `JSON_CATCH_USER` (overriding `catch`). Note that `JSON_THROW_USER` should leave the current scope (e.g., by throwing or aborting), as continuing after it may yield undefined behavior. Note the explanatory [`what()`](https://en.cppreference.com/w/cpp/error/exception/what) string of exceptions is not available for MSVC if exceptions are disabled, see [#2824](https://github.com/nlohmann/json/discussions/2824).
## Execute unit tests
@@ -1611,4 +1702,10 @@ $ ctest --output-on-failure
Note that during the `ctest` stage, several JSON test files are downloaded from an [external repository](https://github.com/nlohmann/json_test_data). If policies forbid downloading artifacts during testing, you can download the files yourself and pass the directory with the test files via `-DJSON_TestDataDirectory=path` to CMake. Then, no Internet connectivity is required. See [issue #2189](https://github.com/nlohmann/json/issues/2189) for more information.
In case you have downloaded the library rather than checked out the code via Git, test `cmake_fetch_content_configure`. Please execute `ctest -LE git_required` to skip these tests. See [issue #2189](https://github.com/nlohmann/json/issues/2189) for more information.
In case you have downloaded the library rather than checked out the code via Git, test `cmake_fetch_content_configure` will fail. Please execute `ctest -LE git_required` to skip these tests. See [issue #2189](https://github.com/nlohmann/json/issues/2189) for more information.
Some tests change the installed files and hence make the whole process not reproducible. Please execute `ctest -LE not_reproducible` to skip these tests. See [issue #2324](https://github.com/nlohmann/json/issues/2324) for more information.
Note you need to call `cmake -LE "not_reproducible|git_required"` to exclude both labels. See [issue #2596](https://github.com/nlohmann/json/issues/2596) for more information.
As Intel compilers use unsafe floating point optimization by default, the unit tests may fail. Use flag [`/fp:precise`](https://software.intel.com/content/www/us/en/develop/documentation/cpp-compiler-developer-guide-and-reference/top/compiler-reference/compiler-options/compiler-option-details/floating-point-options/fp-model-fp.html) then.

View File

@@ -5,114 +5,65 @@ environment:
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
configuration: Debug
platform: x86
CXX_FLAGS: ""
LINKER_FLAGS: ""
CXX_FLAGS: "/W4 /WX"
CMAKE_OPTIONS: ""
GENERATOR: Visual Studio 14 2015
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
configuration: Debug
platform: x86
CXX_FLAGS: ""
LINKER_FLAGS: ""
GENERATOR: Visual Studio 15 2017
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
configuration: Debug
platform: x86
CXX_FLAGS: ""
LINKER_FLAGS: ""
GENERATOR: Visual Studio 16 2019
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
configuration: Debug
platform: x64
CXX_FLAGS: ""
LINKER_FLAGS: ""
GENERATOR: Visual Studio 16 2019
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
configuration: Debug
COMPILER: mingw
platform: x86
CXX_FLAGS: ""
LINKER_FLAGS: ""
GENERATOR: Ninja
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
configuration: Release
COMPILER: mingw
platform: x86
CXX_FLAGS: ""
LINKER_FLAGS: ""
GENERATOR: Ninja
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
configuration: Release
platform: x86
CXX_FLAGS: ""
LINKER_FLAGS: ""
CXX_FLAGS: "/W4 /WX"
CMAKE_OPTIONS: ""
GENERATOR: Visual Studio 14 2015
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
configuration: Release
platform: x86
name: with_win_header
CXX_FLAGS: ""
LINKER_FLAGS: ""
CXX_FLAGS: "/W4 /WX"
CMAKE_OPTIONS: ""
GENERATOR: Visual Studio 14 2015
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
configuration: Release
platform: x86
CXX_FLAGS: "/permissive- /std:c++latest /utf-8"
LINKER_FLAGS: ""
CXX_FLAGS: "/permissive- /std:c++latest /utf-8 /W4 /WX"
CMAKE_OPTIONS: ""
GENERATOR: Visual Studio 15 2017
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
configuration: Release
platform: x86
CXX_FLAGS: ""
LINKER_FLAGS: ""
CXX_FLAGS: "/W4 /WX"
CMAKE_OPTIONS: "-DJSON_ImplicitConversions=OFF"
GENERATOR: Visual Studio 16 2019
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
configuration: Release
platform: x64
CXX_FLAGS: ""
LINKER_FLAGS: ""
CXX_FLAGS: "/W4 /WX"
CMAKE_OPTIONS: ""
GENERATOR: Visual Studio 14 2015
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
configuration: Release
platform: x64
CXX_FLAGS: "/permissive- /std:c++latest /Zc:__cplusplus /utf-8 /F4000000"
LINKER_FLAGS: "/STACK:4000000"
CXX_FLAGS: "/permissive- /std:c++latest /Zc:__cplusplus /utf-8 /W4 /WX"
CMAKE_OPTIONS: ""
GENERATOR: Visual Studio 15 2017
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
configuration: Release
platform: x64
CXX_FLAGS: ""
LINKER_FLAGS: ""
GENERATOR: Visual Studio 16 2019
init:
- cmake --version
- msbuild /version
install:
- if "%COMPILER%"=="mingw" appveyor DownloadFile https://github.com/ninja-build/ninja/releases/download/v1.6.0/ninja-win.zip -FileName ninja.zip
- if "%COMPILER%"=="mingw" 7z x ninja.zip -oC:\projects\deps\ninja > nul
- if "%COMPILER%"=="mingw" set PATH=C:\projects\deps\ninja;%PATH%
- if "%COMPILER%"=="mingw" set PATH=C:\mingw-w64\x86_64-7.3.0-posix-seh-rt_v5-rev0\mingw64\bin;%PATH%
- if "%COMPILER%"=="mingw" g++ --version
- if "%platform%"=="x86" set GENERATOR_PLATFORM=Win32
before_build:
# for with_win_header build, inject the inclusion of Windows.h to the single-header library
- ps: if ($env:name -Eq "with_win_header") { $header_path = "single_include\nlohmann\json.hpp" }
- ps: if ($env:name -Eq "with_win_header") { "#include <Windows.h>`n" + (Get-Content $header_path | Out-String) | Set-Content $header_path }
- if "%GENERATOR%"=="Ninja" (cmake . -G "%GENERATOR%" -DCMAKE_BUILD_TYPE="%configuration%" -DCMAKE_CXX_FLAGS="%CXX_FLAGS%" -DCMAKE_EXE_LINKER_FLAGS="%LINKER_FLAGS%" -DCMAKE_IGNORE_PATH="C:/Program Files/Git/usr/bin" -DJSON_BuildTests=On) else (cmake . -G "%GENERATOR%" -A "%GENERATOR_PLATFORM%" -DCMAKE_CXX_FLAGS="%CXX_FLAGS%" -DCMAKE_EXE_LINKER_FLAGS="%LINKER_FLAGS%" -DCMAKE_IGNORE_PATH="C:/Program Files/Git/usr/bin" -DJSON_BuildTests=On)
- cmake . -G "%GENERATOR%" -A "%GENERATOR_PLATFORM%" -DCMAKE_CXX_FLAGS="%CXX_FLAGS%" -DCMAKE_IGNORE_PATH="C:/Program Files/Git/usr/bin" -DJSON_BuildTests=On "%CMAKE_OPTIONS%"
build_script:
- cmake --build . --config "%configuration%"
@@ -124,3 +75,9 @@ test_script:
# occasional timeouts on AppVeyor.
# More info: https://github.com/nlohmann/json/pull/1570
- if "%configuration%"=="Debug" ctest --exclude-regex "test-unicode" -C "%configuration%" -V -j
# only build PRs and commits to develop branch
# (see https://help.appveyor.com/discussions/questions/55079-two-builds-per-commit-to-pull-request)
branches:
only:
- develop

View File

@@ -1,18 +1,26 @@
cmake_minimum_required(VERSION 3.8)
cmake_minimum_required(VERSION 3.11)
project(JSON_Benchmarks LANGUAGES CXX)
# set compiler flags
if((CMAKE_CXX_COMPILER_ID MATCHES GNU) OR (CMAKE_CXX_COMPILER_ID MATCHES Clang))
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -flto -DNDEBUG -O3")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -flto -DNDEBUG -O3")
endif()
# configure Google Benchmarks
set(BENCHMARK_ENABLE_TESTING OFF CACHE INTERNAL "" FORCE)
add_subdirectory(thirdparty/benchmark)
include(FetchContent)
FetchContent_Declare(
benchmark
GIT_REPOSITORY https://github.com/google/benchmark.git
GIT_TAG origin/main
GIT_SHALLOW TRUE
)
# header directories
include_directories(thirdparty)
include_directories(${CMAKE_SOURCE_DIR}/../single_include)
FetchContent_GetProperties(benchmark)
if(NOT benchmark_POPULATED)
FetchContent_Populate(benchmark)
set(BENCHMARK_ENABLE_TESTING OFF CACHE INTERNAL "" FORCE)
add_subdirectory(${benchmark_SOURCE_DIR} ${benchmark_BINARY_DIR})
endif()
# download test data
include(${CMAKE_SOURCE_DIR}/../cmake/download_test_data.cmake)
@@ -22,4 +30,4 @@ add_executable(json_benchmarks src/benchmarks.cpp)
target_compile_features(json_benchmarks PRIVATE cxx_std_11)
target_link_libraries(json_benchmarks benchmark ${CMAKE_THREAD_LIBS_INIT})
add_dependencies(json_benchmarks download_test_data)
target_include_directories(json_benchmarks PRIVATE ${CMAKE_BINARY_DIR}/include)
target_include_directories(json_benchmarks PRIVATE ${CMAKE_SOURCE_DIR}/../single_include ${CMAKE_BINARY_DIR}/include)

View File

@@ -1,46 +0,0 @@
# This is the official list of benchmark authors for copyright purposes.
# This file is distinct from the CONTRIBUTORS files.
# See the latter for an explanation.
#
# Names should be added to this file as:
# Name or Organization <email address>
# The email address is not required for organizations.
#
# Please keep the list sorted.
Albert Pretorius <pretoalb@gmail.com>
Arne Beer <arne@twobeer.de>
Carto
Christopher Seymour <chris.j.seymour@hotmail.com>
David Coeurjolly <david.coeurjolly@liris.cnrs.fr>
Deniz Evrenci <denizevrenci@gmail.com>
Dirac Research
Dominik Czarnota <dominik.b.czarnota@gmail.com>
Eric Fiselier <eric@efcs.ca>
Eugene Zhuk <eugene.zhuk@gmail.com>
Evgeny Safronov <division494@gmail.com>
Felix Homann <linuxaudio@showlabor.de>
Google Inc.
International Business Machines Corporation
Ismael Jimenez Martinez <ismael.jimenez.martinez@gmail.com>
Jern-Kuan Leong <jernkuan@gmail.com>
JianXiong Zhou <zhoujianxiong2@gmail.com>
Joao Paulo Magalhaes <joaoppmagalhaes@gmail.com>
Jussi Knuuttila <jussi.knuuttila@gmail.com>
Kaito Udagawa <umireon@gmail.com>
Kishan Kumar <kumar.kishan@outlook.com>
Lei Xu <eddyxu@gmail.com>
Matt Clarkson <mattyclarkson@gmail.com>
Maxim Vafin <maxvafin@gmail.com>
MongoDB Inc.
Nick Hutchinson <nshutchinson@gmail.com>
Oleksandr Sochka <sasha.sochka@gmail.com>
Paul Redmond <paul.redmond@gmail.com>
Radoslav Yovchev <radoslav.tm@gmail.com>
Roman Lebedev <lebedev.ri@gmail.com>
Shuo Chen <chenshuo@chenshuo.com>
Steinar H. Gunderson <sgunderson@bigfoot.com>
Stripe, Inc.
Yixuan Qiu <yixuanq@gmail.com>
Yusuke Suzuki <utatane.tea@gmail.com>
Zbigniew Skowron <zbychs@gmail.com>

View File

@@ -1,42 +0,0 @@
licenses(["notice"])
config_setting(
name = "windows",
values = {
"cpu": "x64_windows",
},
visibility = [":__subpackages__"],
)
cc_library(
name = "benchmark",
srcs = glob(
[
"src/*.cc",
"src/*.h",
],
exclude = ["src/benchmark_main.cc"],
),
hdrs = ["include/benchmark/benchmark.h"],
linkopts = select({
":windows": ["-DEFAULTLIB:shlwapi.lib"],
"//conditions:default": ["-pthread"],
}),
strip_include_prefix = "include",
visibility = ["//visibility:public"],
)
cc_library(
name = "benchmark_main",
srcs = ["src/benchmark_main.cc"],
hdrs = ["include/benchmark/benchmark.h"],
strip_include_prefix = "include",
visibility = ["//visibility:public"],
deps = [":benchmark"],
)
cc_library(
name = "benchmark_internal_headers",
hdrs = glob(["src/*.h"]),
visibility = ["//test:__pkg__"],
)

View File

@@ -1,251 +0,0 @@
cmake_minimum_required (VERSION 2.8.12)
project (benchmark)
foreach(p
CMP0054 # CMake 3.1
CMP0056 # export EXE_LINKER_FLAGS to try_run
CMP0057 # Support no if() IN_LIST operator
)
if(POLICY ${p})
cmake_policy(SET ${p} NEW)
endif()
endforeach()
option(BENCHMARK_ENABLE_TESTING "Enable testing of the benchmark library." ON)
option(BENCHMARK_ENABLE_EXCEPTIONS "Enable the use of exceptions in the benchmark library." ON)
option(BENCHMARK_ENABLE_LTO "Enable link time optimisation of the benchmark library." OFF)
option(BENCHMARK_USE_LIBCXX "Build and test using libc++ as the standard library." OFF)
option(BENCHMARK_BUILD_32_BITS "Build a 32 bit version of the library." OFF)
option(BENCHMARK_ENABLE_INSTALL "Enable installation of benchmark. (Projects embedding benchmark may want to turn this OFF.)" ON)
# Allow unmet dependencies to be met using CMake's ExternalProject mechanics, which
# may require downloading the source code.
option(BENCHMARK_DOWNLOAD_DEPENDENCIES "Allow the downloading and in-tree building of unmet dependencies" OFF)
# This option can be used to disable building and running unit tests which depend on gtest
# in cases where it is not possible to build or find a valid version of gtest.
option(BENCHMARK_ENABLE_GTEST_TESTS "Enable building the unit tests which depend on gtest" ON)
set(ENABLE_ASSEMBLY_TESTS_DEFAULT OFF)
function(should_enable_assembly_tests)
if(CMAKE_BUILD_TYPE)
string(TOLOWER ${CMAKE_BUILD_TYPE} CMAKE_BUILD_TYPE_LOWER)
if (${CMAKE_BUILD_TYPE_LOWER} MATCHES "coverage")
# FIXME: The --coverage flag needs to be removed when building assembly
# tests for this to work.
return()
endif()
endif()
if (MSVC)
return()
elseif(NOT CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64")
return()
elseif(NOT CMAKE_SIZEOF_VOID_P EQUAL 8)
# FIXME: Make these work on 32 bit builds
return()
elseif(BENCHMARK_BUILD_32_BITS)
# FIXME: Make these work on 32 bit builds
return()
endif()
find_program(LLVM_FILECHECK_EXE FileCheck)
if (LLVM_FILECHECK_EXE)
set(LLVM_FILECHECK_EXE "${LLVM_FILECHECK_EXE}" CACHE PATH "llvm filecheck" FORCE)
message(STATUS "LLVM FileCheck Found: ${LLVM_FILECHECK_EXE}")
else()
message(STATUS "Failed to find LLVM FileCheck")
return()
endif()
set(ENABLE_ASSEMBLY_TESTS_DEFAULT ON PARENT_SCOPE)
endfunction()
should_enable_assembly_tests()
# This option disables the building and running of the assembly verification tests
option(BENCHMARK_ENABLE_ASSEMBLY_TESTS "Enable building and running the assembly tests"
${ENABLE_ASSEMBLY_TESTS_DEFAULT})
# Make sure we can import out CMake functions
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules")
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
# Read the git tags to determine the project version
include(GetGitVersion)
get_git_version(GIT_VERSION)
# Tell the user what versions we are using
string(REGEX MATCH "[0-9]+\\.[0-9]+\\.[0-9]+" VERSION ${GIT_VERSION})
message("-- Version: ${VERSION}")
# The version of the libraries
set(GENERIC_LIB_VERSION ${VERSION})
string(SUBSTRING ${VERSION} 0 1 GENERIC_LIB_SOVERSION)
# Import our CMake modules
include(CheckCXXCompilerFlag)
include(AddCXXCompilerFlag)
include(CXXFeatureCheck)
if (BENCHMARK_BUILD_32_BITS)
add_required_cxx_compiler_flag(-m32)
endif()
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
# Turn compiler warnings up to 11
string(REGEX REPLACE "[-/]W[1-4]" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4")
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
if (NOT BENCHMARK_ENABLE_EXCEPTIONS)
add_cxx_compiler_flag(-EHs-)
add_cxx_compiler_flag(-EHa-)
endif()
# Link time optimisation
if (BENCHMARK_ENABLE_LTO)
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /GL")
set(CMAKE_STATIC_LINKER_FLAGS_RELEASE "${CMAKE_STATIC_LINKER_FLAGS_RELEASE} /LTCG")
set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} /LTCG")
set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /LTCG")
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} /GL")
string(REGEX REPLACE "[-/]INCREMENTAL" "/INCREMENTAL:NO" CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO}")
set(CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO} /LTCG")
string(REGEX REPLACE "[-/]INCREMENTAL" "/INCREMENTAL:NO" CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO}")
set(CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO} /LTCG")
string(REGEX REPLACE "[-/]INCREMENTAL" "/INCREMENTAL:NO" CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO}")
set(CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO} /LTCG")
set(CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL} /GL")
set(CMAKE_STATIC_LINKER_FLAGS_MINSIZEREL "${CMAKE_STATIC_LINKER_FLAGS_MINSIZEREL} /LTCG")
set(CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL "${CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL} /LTCG")
set(CMAKE_EXE_LINKER_FLAGS_MINSIZEREL "${CMAKE_EXE_LINKER_FLAGS_MINSIZEREL} /LTCG")
endif()
else()
# Try and enable C++11. Don't use C++14 because it doesn't work in some
# configurations.
add_cxx_compiler_flag(-std=c++11)
if (NOT HAVE_CXX_FLAG_STD_CXX11)
add_cxx_compiler_flag(-std=c++0x)
endif()
# Turn compiler warnings up to 11
add_cxx_compiler_flag(-Wall)
add_cxx_compiler_flag(-Wextra)
add_cxx_compiler_flag(-Wshadow)
add_cxx_compiler_flag(-Werror RELEASE)
add_cxx_compiler_flag(-Werror RELWITHDEBINFO)
add_cxx_compiler_flag(-Werror MINSIZEREL)
add_cxx_compiler_flag(-pedantic)
add_cxx_compiler_flag(-pedantic-errors)
add_cxx_compiler_flag(-Wshorten-64-to-32)
add_cxx_compiler_flag(-Wfloat-equal)
add_cxx_compiler_flag(-fstrict-aliasing)
if (NOT BENCHMARK_ENABLE_EXCEPTIONS)
add_cxx_compiler_flag(-fno-exceptions)
endif()
if (HAVE_CXX_FLAG_FSTRICT_ALIASING)
if (NOT CMAKE_CXX_COMPILER_ID STREQUAL "Intel") #ICC17u2: Many false positives for Wstrict-aliasing
add_cxx_compiler_flag(-Wstrict-aliasing)
endif()
endif()
# ICC17u2: overloaded virtual function "benchmark::Fixture::SetUp" is only partially overridden
# (because of deprecated overload)
add_cxx_compiler_flag(-wd654)
add_cxx_compiler_flag(-Wthread-safety)
if (HAVE_CXX_FLAG_WTHREAD_SAFETY)
cxx_feature_check(THREAD_SAFETY_ATTRIBUTES)
endif()
# On most UNIX like platforms g++ and clang++ define _GNU_SOURCE as a
# predefined macro, which turns on all of the wonderful libc extensions.
# However g++ doesn't do this in Cygwin so we have to define it ourselfs
# since we depend on GNU/POSIX/BSD extensions.
if (CYGWIN)
add_definitions(-D_GNU_SOURCE=1)
endif()
# Link time optimisation
if (BENCHMARK_ENABLE_LTO)
add_cxx_compiler_flag(-flto)
if ("${CMAKE_C_COMPILER_ID}" STREQUAL "GNU")
find_program(GCC_AR gcc-ar)
if (GCC_AR)
set(CMAKE_AR ${GCC_AR})
endif()
find_program(GCC_RANLIB gcc-ranlib)
if (GCC_RANLIB)
set(CMAKE_RANLIB ${GCC_RANLIB})
endif()
elseif("${CMAKE_C_COMPILER_ID}" STREQUAL "Clang")
include(llvm-toolchain)
endif()
endif()
# Coverage build type
set(BENCHMARK_CXX_FLAGS_COVERAGE "${CMAKE_CXX_FLAGS_DEBUG}"
CACHE STRING "Flags used by the C++ compiler during coverage builds."
FORCE)
set(BENCHMARK_EXE_LINKER_FLAGS_COVERAGE "${CMAKE_EXE_LINKER_FLAGS_DEBUG}"
CACHE STRING "Flags used for linking binaries during coverage builds."
FORCE)
set(BENCHMARK_SHARED_LINKER_FLAGS_COVERAGE "${CMAKE_SHARED_LINKER_FLAGS_DEBUG}"
CACHE STRING "Flags used by the shared libraries linker during coverage builds."
FORCE)
mark_as_advanced(
BENCHMARK_CXX_FLAGS_COVERAGE
BENCHMARK_EXE_LINKER_FLAGS_COVERAGE
BENCHMARK_SHARED_LINKER_FLAGS_COVERAGE)
set(CMAKE_BUILD_TYPE "${CMAKE_BUILD_TYPE}" CACHE STRING
"Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel Coverage.")
add_cxx_compiler_flag(--coverage COVERAGE)
endif()
if (BENCHMARK_USE_LIBCXX)
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
add_cxx_compiler_flag(-stdlib=libc++)
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR
"${CMAKE_CXX_COMPILER_ID}" STREQUAL "Intel")
add_cxx_compiler_flag(-nostdinc++)
message("libc++ header path must be manually specified using CMAKE_CXX_FLAGS")
# Adding -nodefaultlibs directly to CMAKE_<TYPE>_LINKER_FLAGS will break
# configuration checks such as 'find_package(Threads)'
list(APPEND BENCHMARK_CXX_LINKER_FLAGS -nodefaultlibs)
# -lc++ cannot be added directly to CMAKE_<TYPE>_LINKER_FLAGS because
# linker flags appear before all linker inputs and -lc++ must appear after.
list(APPEND BENCHMARK_CXX_LIBRARIES c++)
else()
message(FATAL_ERROR "-DBENCHMARK_USE_LIBCXX:BOOL=ON is not supported for compiler")
endif()
endif(BENCHMARK_USE_LIBCXX)
# C++ feature checks
# Determine the correct regular expression engine to use
cxx_feature_check(STD_REGEX)
cxx_feature_check(GNU_POSIX_REGEX)
cxx_feature_check(POSIX_REGEX)
if(NOT HAVE_STD_REGEX AND NOT HAVE_GNU_POSIX_REGEX AND NOT HAVE_POSIX_REGEX)
message(FATAL_ERROR "Failed to determine the source files for the regular expression backend")
endif()
if (NOT BENCHMARK_ENABLE_EXCEPTIONS AND HAVE_STD_REGEX
AND NOT HAVE_GNU_POSIX_REGEX AND NOT HAVE_POSIX_REGEX)
message(WARNING "Using std::regex with exceptions disabled is not fully supported")
endif()
cxx_feature_check(STEADY_CLOCK)
# Ensure we have pthreads
find_package(Threads REQUIRED)
# Set up directories
include_directories(${PROJECT_SOURCE_DIR}/include)
# Build the targets
add_subdirectory(src)
if (BENCHMARK_ENABLE_TESTING)
enable_testing()
if (BENCHMARK_ENABLE_GTEST_TESTS)
include(HandleGTest)
endif()
add_subdirectory(test)
endif()

View File

@@ -1,58 +0,0 @@
# How to contribute #
We'd love to accept your patches and contributions to this project. There are
a just a few small guidelines you need to follow.
## Contributor License Agreement ##
Contributions to any Google project must be accompanied by a Contributor
License Agreement. This is not a copyright **assignment**, it simply gives
Google permission to use and redistribute your contributions as part of the
project.
* If you are an individual writing original source code and you're sure you
own the intellectual property, then you'll need to sign an [individual
CLA][].
* If you work for a company that wants to allow you to contribute your work,
then you'll need to sign a [corporate CLA][].
You generally only need to submit a CLA once, so if you've already submitted
one (even if it was for a different project), you probably don't need to do it
again.
[individual CLA]: https://developers.google.com/open-source/cla/individual
[corporate CLA]: https://developers.google.com/open-source/cla/corporate
Once your CLA is submitted (or if you already submitted one for
another Google project), make a commit adding yourself to the
[AUTHORS][] and [CONTRIBUTORS][] files. This commit can be part
of your first [pull request][].
[AUTHORS]: AUTHORS
[CONTRIBUTORS]: CONTRIBUTORS
## Submitting a patch ##
1. It's generally best to start by opening a new issue describing the bug or
feature you're intending to fix. Even if you think it's relatively minor,
it's helpful to know what people are working on. Mention in the initial
issue that you are planning to work on that bug or feature so that it can
be assigned to you.
1. Follow the normal process of [forking][] the project, and setup a new
branch to work in. It's important that each group of changes be done in
separate branches in order to ensure that a pull request only includes the
commits related to that bug or feature.
1. Do your best to have [well-formed commit messages][] for each change.
This provides consistency throughout the project, and ensures that commit
messages are able to be formatted properly by various git tools.
1. Finally, push the commits to your fork and submit a [pull request][].
[forking]: https://help.github.com/articles/fork-a-repo
[well-formed commit messages]: http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html
[pull request]: https://help.github.com/articles/creating-a-pull-request

View File

@@ -1,65 +0,0 @@
# People who have agreed to one of the CLAs and can contribute patches.
# The AUTHORS file lists the copyright holders; this file
# lists people. For example, Google employees are listed here
# but not in AUTHORS, because Google holds the copyright.
#
# Names should be added to this file only after verifying that
# the individual or the individual's organization has agreed to
# the appropriate Contributor License Agreement, found here:
#
# https://developers.google.com/open-source/cla/individual
# https://developers.google.com/open-source/cla/corporate
#
# The agreement for individuals can be filled out on the web.
#
# When adding J Random Contributor's name to this file,
# either J's name or J's organization's name should be
# added to the AUTHORS file, depending on whether the
# individual or corporate CLA was used.
#
# Names should be added to this file as:
# Name <email address>
#
# Please keep the list sorted.
Albert Pretorius <pretoalb@gmail.com>
Arne Beer <arne@twobeer.de>
Billy Robert O'Neal III <billy.oneal@gmail.com> <bion@microsoft.com>
Chris Kennelly <ckennelly@google.com> <ckennelly@ckennelly.com>
Christopher Seymour <chris.j.seymour@hotmail.com>
David Coeurjolly <david.coeurjolly@liris.cnrs.fr>
Deniz Evrenci <denizevrenci@gmail.com>
Dominic Hamon <dma@stripysock.com> <dominic@google.com>
Dominik Czarnota <dominik.b.czarnota@gmail.com>
Eric Fiselier <eric@efcs.ca>
Eugene Zhuk <eugene.zhuk@gmail.com>
Evgeny Safronov <division494@gmail.com>
Felix Homann <linuxaudio@showlabor.de>
Ismael Jimenez Martinez <ismael.jimenez.martinez@gmail.com>
Jern-Kuan Leong <jernkuan@gmail.com>
JianXiong Zhou <zhoujianxiong2@gmail.com>
Joao Paulo Magalhaes <joaoppmagalhaes@gmail.com>
John Millikin <jmillikin@stripe.com>
Jussi Knuuttila <jussi.knuuttila@gmail.com>
Kai Wolf <kai.wolf@gmail.com>
Kishan Kumar <kumar.kishan@outlook.com>
Kaito Udagawa <umireon@gmail.com>
Lei Xu <eddyxu@gmail.com>
Matt Clarkson <mattyclarkson@gmail.com>
Maxim Vafin <maxvafin@gmail.com>
Nick Hutchinson <nshutchinson@gmail.com>
Oleksandr Sochka <sasha.sochka@gmail.com>
Pascal Leroy <phl@google.com>
Paul Redmond <paul.redmond@gmail.com>
Pierre Phaneuf <pphaneuf@google.com>
Radoslav Yovchev <radoslav.tm@gmail.com>
Raul Marin <rmrodriguez@cartodb.com>
Ray Glover <ray.glover@uk.ibm.com>
Robert Guo <robert.guo@mongodb.com>
Roman Lebedev <lebedev.ri@gmail.com>
Shuo Chen <chenshuo@chenshuo.com>
Tobias Ulvgård <tobias.ulvgard@dirac.se>
Tom Madams <tom.ej.madams@gmail.com> <tmadams@google.com>
Yixuan Qiu <yixuanq@gmail.com>
Yusuke Suzuki <utatane.tea@gmail.com>
Zbigniew Skowron <zbychs@gmail.com>

View File

@@ -1,202 +0,0 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@@ -1,950 +0,0 @@
# benchmark
[![Build Status](https://travis-ci.org/google/benchmark.svg?branch=master)](https://travis-ci.org/google/benchmark)
[![Build status](https://ci.appveyor.com/api/projects/status/u0qsyp7t1tk7cpxs/branch/master?svg=true)](https://ci.appveyor.com/project/google/benchmark/branch/master)
[![Coverage Status](https://coveralls.io/repos/google/benchmark/badge.svg)](https://coveralls.io/r/google/benchmark)
[![slackin](https://slackin-iqtfqnpzxd.now.sh/badge.svg)](https://slackin-iqtfqnpzxd.now.sh/)
A library to support the benchmarking of functions, similar to unit-tests.
Discussion group: https://groups.google.com/d/forum/benchmark-discuss
IRC channel: https://freenode.net #googlebenchmark
[Known issues and common problems](#known-issues)
[Additional Tooling Documentation](docs/tools.md)
[Assembly Testing Documentation](docs/AssemblyTests.md)
## Building
The basic steps for configuring and building the library look like this:
```bash
$ git clone https://github.com/google/benchmark.git
# Benchmark requires Google Test as a dependency. Add the source tree as a subdirectory.
$ git clone https://github.com/google/googletest.git benchmark/googletest
$ mkdir build && cd build
$ cmake -G <generator> [options] ../benchmark
# Assuming a makefile generator was used
$ make
```
Note that Google Benchmark requires Google Test to build and run the tests. This
dependency can be provided two ways:
* Checkout the Google Test sources into `benchmark/googletest` as above.
* Otherwise, if `-DBENCHMARK_DOWNLOAD_DEPENDENCIES=ON` is specified during
configuration, the library will automatically download and build any required
dependencies.
If you do not wish to build and run the tests, add `-DBENCHMARK_ENABLE_GTEST_TESTS=OFF`
to `CMAKE_ARGS`.
## Installation Guide
For Ubuntu and Debian Based System
First make sure you have git and cmake installed (If not please install it)
```
sudo apt-get install git
sudo apt-get install cmake
```
Now, let's clone the repository and build it
```
git clone https://github.com/google/benchmark.git
cd benchmark
git clone https://github.com/google/googletest.git
mkdir build
cd build
cmake .. -DCMAKE_BUILD_TYPE=RELEASE
make
```
We need to install the library globally now
```
sudo make install
```
Now you have google/benchmark installed in your machine
Note: Don't forget to link to pthread library while building
## Stable and Experimental Library Versions
The main branch contains the latest stable version of the benchmarking library;
the API of which can be considered largely stable, with source breaking changes
being made only upon the release of a new major version.
Newer, experimental, features are implemented and tested on the
[`v2` branch](https://github.com/google/benchmark/tree/v2). Users who wish
to use, test, and provide feedback on the new features are encouraged to try
this branch. However, this branch provides no stability guarantees and reserves
the right to change and break the API at any time.
##Prerequisite knowledge
Before attempting to understand this framework one should ideally have some familiarity with the structure and format of the Google Test framework, upon which it is based. Documentation for Google Test, including a "Getting Started" (primer) guide, is available here:
https://github.com/google/googletest/blob/master/googletest/docs/Documentation.md
## Example usage
### Basic usage
Define a function that executes the code to be measured.
```c++
#include <benchmark/benchmark.h>
static void BM_StringCreation(benchmark::State& state) {
for (auto _ : state)
std::string empty_string;
}
// Register the function as a benchmark
BENCHMARK(BM_StringCreation);
// Define another benchmark
static void BM_StringCopy(benchmark::State& state) {
std::string x = "hello";
for (auto _ : state)
std::string copy(x);
}
BENCHMARK(BM_StringCopy);
BENCHMARK_MAIN();
```
Don't forget to inform your linker to add benchmark library e.g. through
`-lbenchmark` compilation flag. Alternatively, you may leave out the
`BENCHMARK_MAIN();` at the end of the source file and link against
`-lbenchmark_main` to get the same default behavior.
The benchmark library will reporting the timing for the code within the `for(...)` loop.
### Passing arguments
Sometimes a family of benchmarks can be implemented with just one routine that
takes an extra argument to specify which one of the family of benchmarks to
run. For example, the following code defines a family of benchmarks for
measuring the speed of `memcpy()` calls of different lengths:
```c++
static void BM_memcpy(benchmark::State& state) {
char* src = new char[state.range(0)];
char* dst = new char[state.range(0)];
memset(src, 'x', state.range(0));
for (auto _ : state)
memcpy(dst, src, state.range(0));
state.SetBytesProcessed(int64_t(state.iterations()) *
int64_t(state.range(0)));
delete[] src;
delete[] dst;
}
BENCHMARK(BM_memcpy)->Arg(8)->Arg(64)->Arg(512)->Arg(1<<10)->Arg(8<<10);
```
The preceding code is quite repetitive, and can be replaced with the following
short-hand. The following invocation will pick a few appropriate arguments in
the specified range and will generate a benchmark for each such argument.
```c++
BENCHMARK(BM_memcpy)->Range(8, 8<<10);
```
By default the arguments in the range are generated in multiples of eight and
the command above selects [ 8, 64, 512, 4k, 8k ]. In the following code the
range multiplier is changed to multiples of two.
```c++
BENCHMARK(BM_memcpy)->RangeMultiplier(2)->Range(8, 8<<10);
```
Now arguments generated are [ 8, 16, 32, 64, 128, 256, 512, 1024, 2k, 4k, 8k ].
You might have a benchmark that depends on two or more inputs. For example, the
following code defines a family of benchmarks for measuring the speed of set
insertion.
```c++
static void BM_SetInsert(benchmark::State& state) {
std::set<int> data;
for (auto _ : state) {
state.PauseTiming();
data = ConstructRandomSet(state.range(0));
state.ResumeTiming();
for (int j = 0; j < state.range(1); ++j)
data.insert(RandomNumber());
}
}
BENCHMARK(BM_SetInsert)
->Args({1<<10, 128})
->Args({2<<10, 128})
->Args({4<<10, 128})
->Args({8<<10, 128})
->Args({1<<10, 512})
->Args({2<<10, 512})
->Args({4<<10, 512})
->Args({8<<10, 512});
```
The preceding code is quite repetitive, and can be replaced with the following
short-hand. The following macro will pick a few appropriate arguments in the
product of the two specified ranges and will generate a benchmark for each such
pair.
```c++
BENCHMARK(BM_SetInsert)->Ranges({{1<<10, 8<<10}, {128, 512}});
```
For more complex patterns of inputs, passing a custom function to `Apply` allows
programmatic specification of an arbitrary set of arguments on which to run the
benchmark. The following example enumerates a dense range on one parameter,
and a sparse range on the second.
```c++
static void CustomArguments(benchmark::internal::Benchmark* b) {
for (int i = 0; i <= 10; ++i)
for (int j = 32; j <= 1024*1024; j *= 8)
b->Args({i, j});
}
BENCHMARK(BM_SetInsert)->Apply(CustomArguments);
```
### Calculate asymptotic complexity (Big O)
Asymptotic complexity might be calculated for a family of benchmarks. The
following code will calculate the coefficient for the high-order term in the
running time and the normalized root-mean square error of string comparison.
```c++
static void BM_StringCompare(benchmark::State& state) {
std::string s1(state.range(0), '-');
std::string s2(state.range(0), '-');
for (auto _ : state) {
benchmark::DoNotOptimize(s1.compare(s2));
}
state.SetComplexityN(state.range(0));
}
BENCHMARK(BM_StringCompare)
->RangeMultiplier(2)->Range(1<<10, 1<<18)->Complexity(benchmark::oN);
```
As shown in the following invocation, asymptotic complexity might also be
calculated automatically.
```c++
BENCHMARK(BM_StringCompare)
->RangeMultiplier(2)->Range(1<<10, 1<<18)->Complexity();
```
The following code will specify asymptotic complexity with a lambda function,
that might be used to customize high-order term calculation.
```c++
BENCHMARK(BM_StringCompare)->RangeMultiplier(2)
->Range(1<<10, 1<<18)->Complexity([](int n)->double{return n; });
```
### Templated benchmarks
Templated benchmarks work the same way: This example produces and consumes
messages of size `sizeof(v)` `range_x` times. It also outputs throughput in the
absence of multiprogramming.
```c++
template <class Q> int BM_Sequential(benchmark::State& state) {
Q q;
typename Q::value_type v;
for (auto _ : state) {
for (int i = state.range(0); i--; )
q.push(v);
for (int e = state.range(0); e--; )
q.Wait(&v);
}
// actually messages, not bytes:
state.SetBytesProcessed(
static_cast<int64_t>(state.iterations())*state.range(0));
}
BENCHMARK_TEMPLATE(BM_Sequential, WaitQueue<int>)->Range(1<<0, 1<<10);
```
Three macros are provided for adding benchmark templates.
```c++
#ifdef BENCHMARK_HAS_CXX11
#define BENCHMARK_TEMPLATE(func, ...) // Takes any number of parameters.
#else // C++ < C++11
#define BENCHMARK_TEMPLATE(func, arg1)
#endif
#define BENCHMARK_TEMPLATE1(func, arg1)
#define BENCHMARK_TEMPLATE2(func, arg1, arg2)
```
### A Faster KeepRunning loop
In C++11 mode, a ranged-based for loop should be used in preference to
the `KeepRunning` loop for running the benchmarks. For example:
```c++
static void BM_Fast(benchmark::State &state) {
for (auto _ : state) {
FastOperation();
}
}
BENCHMARK(BM_Fast);
```
The reason the ranged-for loop is faster than using `KeepRunning`, is
because `KeepRunning` requires a memory load and store of the iteration count
ever iteration, whereas the ranged-for variant is able to keep the iteration count
in a register.
For example, an empty inner loop of using the ranged-based for method looks like:
```asm
# Loop Init
mov rbx, qword ptr [r14 + 104]
call benchmark::State::StartKeepRunning()
test rbx, rbx
je .LoopEnd
.LoopHeader: # =>This Inner Loop Header: Depth=1
add rbx, -1
jne .LoopHeader
.LoopEnd:
```
Compared to an empty `KeepRunning` loop, which looks like:
```asm
.LoopHeader: # in Loop: Header=BB0_3 Depth=1
cmp byte ptr [rbx], 1
jne .LoopInit
.LoopBody: # =>This Inner Loop Header: Depth=1
mov rax, qword ptr [rbx + 8]
lea rcx, [rax + 1]
mov qword ptr [rbx + 8], rcx
cmp rax, qword ptr [rbx + 104]
jb .LoopHeader
jmp .LoopEnd
.LoopInit:
mov rdi, rbx
call benchmark::State::StartKeepRunning()
jmp .LoopBody
.LoopEnd:
```
Unless C++03 compatibility is required, the ranged-for variant of writing
the benchmark loop should be preferred.
## Passing arbitrary arguments to a benchmark
In C++11 it is possible to define a benchmark that takes an arbitrary number
of extra arguments. The `BENCHMARK_CAPTURE(func, test_case_name, ...args)`
macro creates a benchmark that invokes `func` with the `benchmark::State` as
the first argument followed by the specified `args...`.
The `test_case_name` is appended to the name of the benchmark and
should describe the values passed.
```c++
template <class ...ExtraArgs>
void BM_takes_args(benchmark::State& state, ExtraArgs&&... extra_args) {
[...]
}
// Registers a benchmark named "BM_takes_args/int_string_test" that passes
// the specified values to `extra_args`.
BENCHMARK_CAPTURE(BM_takes_args, int_string_test, 42, std::string("abc"));
```
Note that elements of `...args` may refer to global variables. Users should
avoid modifying global state inside of a benchmark.
## Using RegisterBenchmark(name, fn, args...)
The `RegisterBenchmark(name, func, args...)` function provides an alternative
way to create and register benchmarks.
`RegisterBenchmark(name, func, args...)` creates, registers, and returns a
pointer to a new benchmark with the specified `name` that invokes
`func(st, args...)` where `st` is a `benchmark::State` object.
Unlike the `BENCHMARK` registration macros, which can only be used at the global
scope, the `RegisterBenchmark` can be called anywhere. This allows for
benchmark tests to be registered programmatically.
Additionally `RegisterBenchmark` allows any callable object to be registered
as a benchmark. Including capturing lambdas and function objects.
For Example:
```c++
auto BM_test = [](benchmark::State& st, auto Inputs) { /* ... */ };
int main(int argc, char** argv) {
for (auto& test_input : { /* ... */ })
benchmark::RegisterBenchmark(test_input.name(), BM_test, test_input);
benchmark::Initialize(&argc, argv);
benchmark::RunSpecifiedBenchmarks();
}
```
### Multithreaded benchmarks
In a multithreaded test (benchmark invoked by multiple threads simultaneously),
it is guaranteed that none of the threads will start until all have reached
the start of the benchmark loop, and all will have finished before any thread
exits the benchmark loop. (This behavior is also provided by the `KeepRunning()`
API) As such, any global setup or teardown can be wrapped in a check against the thread
index:
```c++
static void BM_MultiThreaded(benchmark::State& state) {
if (state.thread_index == 0) {
// Setup code here.
}
for (auto _ : state) {
// Run the test as normal.
}
if (state.thread_index == 0) {
// Teardown code here.
}
}
BENCHMARK(BM_MultiThreaded)->Threads(2);
```
If the benchmarked code itself uses threads and you want to compare it to
single-threaded code, you may want to use real-time ("wallclock") measurements
for latency comparisons:
```c++
BENCHMARK(BM_test)->Range(8, 8<<10)->UseRealTime();
```
Without `UseRealTime`, CPU time is used by default.
## Manual timing
For benchmarking something for which neither CPU time nor real-time are
correct or accurate enough, completely manual timing is supported using
the `UseManualTime` function.
When `UseManualTime` is used, the benchmarked code must call
`SetIterationTime` once per iteration of the benchmark loop to
report the manually measured time.
An example use case for this is benchmarking GPU execution (e.g. OpenCL
or CUDA kernels, OpenGL or Vulkan or Direct3D draw calls), which cannot
be accurately measured using CPU time or real-time. Instead, they can be
measured accurately using a dedicated API, and these measurement results
can be reported back with `SetIterationTime`.
```c++
static void BM_ManualTiming(benchmark::State& state) {
int microseconds = state.range(0);
std::chrono::duration<double, std::micro> sleep_duration {
static_cast<double>(microseconds)
};
for (auto _ : state) {
auto start = std::chrono::high_resolution_clock::now();
// Simulate some useful workload with a sleep
std::this_thread::sleep_for(sleep_duration);
auto end = std::chrono::high_resolution_clock::now();
auto elapsed_seconds =
std::chrono::duration_cast<std::chrono::duration<double>>(
end - start);
state.SetIterationTime(elapsed_seconds.count());
}
}
BENCHMARK(BM_ManualTiming)->Range(1, 1<<17)->UseManualTime();
```
### Preventing optimisation
To prevent a value or expression from being optimized away by the compiler
the `benchmark::DoNotOptimize(...)` and `benchmark::ClobberMemory()`
functions can be used.
```c++
static void BM_test(benchmark::State& state) {
for (auto _ : state) {
int x = 0;
for (int i=0; i < 64; ++i) {
benchmark::DoNotOptimize(x += i);
}
}
}
```
`DoNotOptimize(<expr>)` forces the *result* of `<expr>` to be stored in either
memory or a register. For GNU based compilers it acts as read/write barrier
for global memory. More specifically it forces the compiler to flush pending
writes to memory and reload any other values as necessary.
Note that `DoNotOptimize(<expr>)` does not prevent optimizations on `<expr>`
in any way. `<expr>` may even be removed entirely when the result is already
known. For example:
```c++
/* Example 1: `<expr>` is removed entirely. */
int foo(int x) { return x + 42; }
while (...) DoNotOptimize(foo(0)); // Optimized to DoNotOptimize(42);
/* Example 2: Result of '<expr>' is only reused */
int bar(int) __attribute__((const));
while (...) DoNotOptimize(bar(0)); // Optimized to:
// int __result__ = bar(0);
// while (...) DoNotOptimize(__result__);
```
The second tool for preventing optimizations is `ClobberMemory()`. In essence
`ClobberMemory()` forces the compiler to perform all pending writes to global
memory. Memory managed by block scope objects must be "escaped" using
`DoNotOptimize(...)` before it can be clobbered. In the below example
`ClobberMemory()` prevents the call to `v.push_back(42)` from being optimized
away.
```c++
static void BM_vector_push_back(benchmark::State& state) {
for (auto _ : state) {
std::vector<int> v;
v.reserve(1);
benchmark::DoNotOptimize(v.data()); // Allow v.data() to be clobbered.
v.push_back(42);
benchmark::ClobberMemory(); // Force 42 to be written to memory.
}
}
```
Note that `ClobberMemory()` is only available for GNU or MSVC based compilers.
### Set time unit manually
If a benchmark runs a few milliseconds it may be hard to visually compare the
measured times, since the output data is given in nanoseconds per default. In
order to manually set the time unit, you can specify it manually:
```c++
BENCHMARK(BM_test)->Unit(benchmark::kMillisecond);
```
## Controlling number of iterations
In all cases, the number of iterations for which the benchmark is run is
governed by the amount of time the benchmark takes. Concretely, the number of
iterations is at least one, not more than 1e9, until CPU time is greater than
the minimum time, or the wallclock time is 5x minimum time. The minimum time is
set as a flag `--benchmark_min_time` or per benchmark by calling `MinTime` on
the registered benchmark object.
## Reporting the mean, median and standard deviation by repeated benchmarks
By default each benchmark is run once and that single result is reported.
However benchmarks are often noisy and a single result may not be representative
of the overall behavior. For this reason it's possible to repeatedly rerun the
benchmark.
The number of runs of each benchmark is specified globally by the
`--benchmark_repetitions` flag or on a per benchmark basis by calling
`Repetitions` on the registered benchmark object. When a benchmark is run more
than once the mean, median and standard deviation of the runs will be reported.
Additionally the `--benchmark_report_aggregates_only={true|false}` flag or
`ReportAggregatesOnly(bool)` function can be used to change how repeated tests
are reported. By default the result of each repeated run is reported. When this
option is `true` only the mean, median and standard deviation of the runs is reported.
Calling `ReportAggregatesOnly(bool)` on a registered benchmark object overrides
the value of the flag for that benchmark.
## User-defined statistics for repeated benchmarks
While having mean, median and standard deviation is nice, this may not be
enough for everyone. For example you may want to know what is the largest
observation, e.g. because you have some real-time constraints. This is easy.
The following code will specify a custom statistic to be calculated, defined
by a lambda function.
```c++
void BM_spin_empty(benchmark::State& state) {
for (auto _ : state) {
for (int x = 0; x < state.range(0); ++x) {
benchmark::DoNotOptimize(x);
}
}
}
BENCHMARK(BM_spin_empty)
->ComputeStatistics("max", [](const std::vector<double>& v) -> double {
return *(std::max_element(std::begin(v), std::end(v)));
})
->Arg(512);
```
## Fixtures
Fixture tests are created by
first defining a type that derives from `::benchmark::Fixture` and then
creating/registering the tests using the following macros:
* `BENCHMARK_F(ClassName, Method)`
* `BENCHMARK_DEFINE_F(ClassName, Method)`
* `BENCHMARK_REGISTER_F(ClassName, Method)`
For Example:
```c++
class MyFixture : public benchmark::Fixture {};
BENCHMARK_F(MyFixture, FooTest)(benchmark::State& st) {
for (auto _ : st) {
...
}
}
BENCHMARK_DEFINE_F(MyFixture, BarTest)(benchmark::State& st) {
for (auto _ : st) {
...
}
}
/* BarTest is NOT registered */
BENCHMARK_REGISTER_F(MyFixture, BarTest)->Threads(2);
/* BarTest is now registered */
```
### Templated fixtures
Also you can create templated fixture by using the following macros:
* `BENCHMARK_TEMPLATE_F(ClassName, Method, ...)`
* `BENCHMARK_TEMPLATE_DEFINE_F(ClassName, Method, ...)`
For example:
```c++
template<typename T>
class MyFixture : public benchmark::Fixture {};
BENCHMARK_TEMPLATE_F(MyFixture, IntTest, int)(benchmark::State& st) {
for (auto _ : st) {
...
}
}
BENCHMARK_TEMPLATE_DEFINE_F(MyFixture, DoubleTest, double)(benchmark::State& st) {
for (auto _ : st) {
...
}
}
BENCHMARK_REGISTER_F(MyFixture, DoubleTest)->Threads(2);
```
## User-defined counters
You can add your own counters with user-defined names. The example below
will add columns "Foo", "Bar" and "Baz" in its output:
```c++
static void UserCountersExample1(benchmark::State& state) {
double numFoos = 0, numBars = 0, numBazs = 0;
for (auto _ : state) {
// ... count Foo,Bar,Baz events
}
state.counters["Foo"] = numFoos;
state.counters["Bar"] = numBars;
state.counters["Baz"] = numBazs;
}
```
The `state.counters` object is a `std::map` with `std::string` keys
and `Counter` values. The latter is a `double`-like class, via an implicit
conversion to `double&`. Thus you can use all of the standard arithmetic
assignment operators (`=,+=,-=,*=,/=`) to change the value of each counter.
In multithreaded benchmarks, each counter is set on the calling thread only.
When the benchmark finishes, the counters from each thread will be summed;
the resulting sum is the value which will be shown for the benchmark.
The `Counter` constructor accepts two parameters: the value as a `double`
and a bit flag which allows you to show counters as rates and/or as
per-thread averages:
```c++
// sets a simple counter
state.counters["Foo"] = numFoos;
// Set the counter as a rate. It will be presented divided
// by the duration of the benchmark.
state.counters["FooRate"] = Counter(numFoos, benchmark::Counter::kIsRate);
// Set the counter as a thread-average quantity. It will
// be presented divided by the number of threads.
state.counters["FooAvg"] = Counter(numFoos, benchmark::Counter::kAvgThreads);
// There's also a combined flag:
state.counters["FooAvgRate"] = Counter(numFoos,benchmark::Counter::kAvgThreadsRate);
```
When you're compiling in C++11 mode or later you can use `insert()` with
`std::initializer_list`:
```c++
// With C++11, this can be done:
state.counters.insert({{"Foo", numFoos}, {"Bar", numBars}, {"Baz", numBazs}});
// ... instead of:
state.counters["Foo"] = numFoos;
state.counters["Bar"] = numBars;
state.counters["Baz"] = numBazs;
```
### Counter reporting
When using the console reporter, by default, user counters are are printed at
the end after the table, the same way as ``bytes_processed`` and
``items_processed``. This is best for cases in which there are few counters,
or where there are only a couple of lines per benchmark. Here's an example of
the default output:
```
------------------------------------------------------------------------------
Benchmark Time CPU Iterations UserCounters...
------------------------------------------------------------------------------
BM_UserCounter/threads:8 2248 ns 10277 ns 68808 Bar=16 Bat=40 Baz=24 Foo=8
BM_UserCounter/threads:1 9797 ns 9788 ns 71523 Bar=2 Bat=5 Baz=3 Foo=1024m
BM_UserCounter/threads:2 4924 ns 9842 ns 71036 Bar=4 Bat=10 Baz=6 Foo=2
BM_UserCounter/threads:4 2589 ns 10284 ns 68012 Bar=8 Bat=20 Baz=12 Foo=4
BM_UserCounter/threads:8 2212 ns 10287 ns 68040 Bar=16 Bat=40 Baz=24 Foo=8
BM_UserCounter/threads:16 1782 ns 10278 ns 68144 Bar=32 Bat=80 Baz=48 Foo=16
BM_UserCounter/threads:32 1291 ns 10296 ns 68256 Bar=64 Bat=160 Baz=96 Foo=32
BM_UserCounter/threads:4 2615 ns 10307 ns 68040 Bar=8 Bat=20 Baz=12 Foo=4
BM_Factorial 26 ns 26 ns 26608979 40320
BM_Factorial/real_time 26 ns 26 ns 26587936 40320
BM_CalculatePiRange/1 16 ns 16 ns 45704255 0
BM_CalculatePiRange/8 73 ns 73 ns 9520927 3.28374
BM_CalculatePiRange/64 609 ns 609 ns 1140647 3.15746
BM_CalculatePiRange/512 4900 ns 4901 ns 142696 3.14355
```
If this doesn't suit you, you can print each counter as a table column by
passing the flag `--benchmark_counters_tabular=true` to the benchmark
application. This is best for cases in which there are a lot of counters, or
a lot of lines per individual benchmark. Note that this will trigger a
reprinting of the table header any time the counter set changes between
individual benchmarks. Here's an example of corresponding output when
`--benchmark_counters_tabular=true` is passed:
```
---------------------------------------------------------------------------------------
Benchmark Time CPU Iterations Bar Bat Baz Foo
---------------------------------------------------------------------------------------
BM_UserCounter/threads:8 2198 ns 9953 ns 70688 16 40 24 8
BM_UserCounter/threads:1 9504 ns 9504 ns 73787 2 5 3 1
BM_UserCounter/threads:2 4775 ns 9550 ns 72606 4 10 6 2
BM_UserCounter/threads:4 2508 ns 9951 ns 70332 8 20 12 4
BM_UserCounter/threads:8 2055 ns 9933 ns 70344 16 40 24 8
BM_UserCounter/threads:16 1610 ns 9946 ns 70720 32 80 48 16
BM_UserCounter/threads:32 1192 ns 9948 ns 70496 64 160 96 32
BM_UserCounter/threads:4 2506 ns 9949 ns 70332 8 20 12 4
--------------------------------------------------------------
Benchmark Time CPU Iterations
--------------------------------------------------------------
BM_Factorial 26 ns 26 ns 26392245 40320
BM_Factorial/real_time 26 ns 26 ns 26494107 40320
BM_CalculatePiRange/1 15 ns 15 ns 45571597 0
BM_CalculatePiRange/8 74 ns 74 ns 9450212 3.28374
BM_CalculatePiRange/64 595 ns 595 ns 1173901 3.15746
BM_CalculatePiRange/512 4752 ns 4752 ns 147380 3.14355
BM_CalculatePiRange/4k 37970 ns 37972 ns 18453 3.14184
BM_CalculatePiRange/32k 303733 ns 303744 ns 2305 3.14162
BM_CalculatePiRange/256k 2434095 ns 2434186 ns 288 3.1416
BM_CalculatePiRange/1024k 9721140 ns 9721413 ns 71 3.14159
BM_CalculatePi/threads:8 2255 ns 9943 ns 70936
```
Note above the additional header printed when the benchmark changes from
``BM_UserCounter`` to ``BM_Factorial``. This is because ``BM_Factorial`` does
not have the same counter set as ``BM_UserCounter``.
## Exiting Benchmarks in Error
When errors caused by external influences, such as file I/O and network
communication, occur within a benchmark the
`State::SkipWithError(const char* msg)` function can be used to skip that run
of benchmark and report the error. Note that only future iterations of the
`KeepRunning()` are skipped. For the ranged-for version of the benchmark loop
Users must explicitly exit the loop, otherwise all iterations will be performed.
Users may explicitly return to exit the benchmark immediately.
The `SkipWithError(...)` function may be used at any point within the benchmark,
including before and after the benchmark loop.
For example:
```c++
static void BM_test(benchmark::State& state) {
auto resource = GetResource();
if (!resource.good()) {
state.SkipWithError("Resource is not good!");
// KeepRunning() loop will not be entered.
}
for (state.KeepRunning()) {
auto data = resource.read_data();
if (!resource.good()) {
state.SkipWithError("Failed to read data!");
break; // Needed to skip the rest of the iteration.
}
do_stuff(data);
}
}
static void BM_test_ranged_fo(benchmark::State & state) {
state.SkipWithError("test will not be entered");
for (auto _ : state) {
state.SkipWithError("Failed!");
break; // REQUIRED to prevent all further iterations.
}
}
```
## Running a subset of the benchmarks
The `--benchmark_filter=<regex>` option can be used to only run the benchmarks
which match the specified `<regex>`. For example:
```bash
$ ./run_benchmarks.x --benchmark_filter=BM_memcpy/32
Run on (1 X 2300 MHz CPU )
2016-06-25 19:34:24
Benchmark Time CPU Iterations
----------------------------------------------------
BM_memcpy/32 11 ns 11 ns 79545455
BM_memcpy/32k 2181 ns 2185 ns 324074
BM_memcpy/32 12 ns 12 ns 54687500
BM_memcpy/32k 1834 ns 1837 ns 357143
```
## Output Formats
The library supports multiple output formats. Use the
`--benchmark_format=<console|json|csv>` flag to set the format type. `console`
is the default format.
The Console format is intended to be a human readable format. By default
the format generates color output. Context is output on stderr and the
tabular data on stdout. Example tabular output looks like:
```
Benchmark Time(ns) CPU(ns) Iterations
----------------------------------------------------------------------
BM_SetInsert/1024/1 28928 29349 23853 133.097kB/s 33.2742k items/s
BM_SetInsert/1024/8 32065 32913 21375 949.487kB/s 237.372k items/s
BM_SetInsert/1024/10 33157 33648 21431 1.13369MB/s 290.225k items/s
```
The JSON format outputs human readable json split into two top level attributes.
The `context` attribute contains information about the run in general, including
information about the CPU and the date.
The `benchmarks` attribute contains a list of every benchmark run. Example json
output looks like:
```json
{
"context": {
"date": "2015/03/17-18:40:25",
"num_cpus": 40,
"mhz_per_cpu": 2801,
"cpu_scaling_enabled": false,
"build_type": "debug"
},
"benchmarks": [
{
"name": "BM_SetInsert/1024/1",
"iterations": 94877,
"real_time": 29275,
"cpu_time": 29836,
"bytes_per_second": 134066,
"items_per_second": 33516
},
{
"name": "BM_SetInsert/1024/8",
"iterations": 21609,
"real_time": 32317,
"cpu_time": 32429,
"bytes_per_second": 986770,
"items_per_second": 246693
},
{
"name": "BM_SetInsert/1024/10",
"iterations": 21393,
"real_time": 32724,
"cpu_time": 33355,
"bytes_per_second": 1199226,
"items_per_second": 299807
}
]
}
```
The CSV format outputs comma-separated values. The `context` is output on stderr
and the CSV itself on stdout. Example CSV output looks like:
```
name,iterations,real_time,cpu_time,bytes_per_second,items_per_second,label
"BM_SetInsert/1024/1",65465,17890.7,8407.45,475768,118942,
"BM_SetInsert/1024/8",116606,18810.1,9766.64,3.27646e+06,819115,
"BM_SetInsert/1024/10",106365,17238.4,8421.53,4.74973e+06,1.18743e+06,
```
## Output Files
The library supports writing the output of the benchmark to a file specified
by `--benchmark_out=<filename>`. The format of the output can be specified
using `--benchmark_out_format={json|console|csv}`. Specifying
`--benchmark_out` does not suppress the console output.
## Debug vs Release
By default, benchmark builds as a debug library. You will see a warning in the output when this is the case. To build it as a release library instead, use:
```
cmake -DCMAKE_BUILD_TYPE=Release
```
To enable link-time optimisation, use
```
cmake -DCMAKE_BUILD_TYPE=Release -DBENCHMARK_ENABLE_LTO=true
```
If you are using gcc, you might need to set `GCC_AR` and `GCC_RANLIB` cmake cache variables, if autodetection fails.
If you are using clang, you may need to set `LLVMAR_EXECUTABLE`, `LLVMNM_EXECUTABLE` and `LLVMRANLIB_EXECUTABLE` cmake cache variables.
## Linking against the library
When the library is built using GCC it is necessary to link with `-pthread`,
due to how GCC implements `std::thread`.
For GCC 4.x failing to link to pthreads will lead to runtime exceptions, not linker errors.
See [issue #67](https://github.com/google/benchmark/issues/67) for more details.
## Compiler Support
Google Benchmark uses C++11 when building the library. As such we require
a modern C++ toolchain, both compiler and standard library.
The following minimum versions are strongly recommended build the library:
* GCC 4.8
* Clang 3.4
* Visual Studio 2013
* Intel 2015 Update 1
Anything older *may* work.
Note: Using the library and its headers in C++03 is supported. C++11 is only
required to build the library.
## Disable CPU frequency scaling
If you see this error:
```
***WARNING*** CPU scaling is enabled, the benchmark real time measurements may be noisy and will incur extra overhead.
```
you might want to disable the CPU frequency scaling while running the benchmark:
```bash
sudo cpupower frequency-set --governor performance
./mybench
sudo cpupower frequency-set --governor powersave
```
# Known Issues
### Windows with CMake
* Users must manually link `shlwapi.lib`. Failure to do so may result
in unresolved symbols.
### Solaris
* Users must explicitly link with kstat library (-lkstat compilation flag).

View File

@@ -1,7 +0,0 @@
workspace(name = "com_github_google_benchmark")
http_archive(
name = "com_google_googletest",
urls = ["https://github.com/google/googletest/archive/3f0cf6b62ad1eb50d8736538363d3580dd640c3e.zip"],
strip_prefix = "googletest-3f0cf6b62ad1eb50d8736538363d3580dd640c3e",
)

View File

@@ -1,56 +0,0 @@
version: '{build}'
image: Visual Studio 2017
configuration:
- Debug
- Release
environment:
matrix:
- compiler: msvc-15-seh
generator: "Visual Studio 15 2017"
- compiler: msvc-15-seh
generator: "Visual Studio 15 2017 Win64"
- compiler: msvc-14-seh
generator: "Visual Studio 14 2015"
- compiler: msvc-14-seh
generator: "Visual Studio 14 2015 Win64"
- compiler: msvc-12-seh
generator: "Visual Studio 12 2013"
- compiler: msvc-12-seh
generator: "Visual Studio 12 2013 Win64"
- compiler: gcc-5.3.0-posix
generator: "MinGW Makefiles"
cxx_path: 'C:\mingw-w64\i686-5.3.0-posix-dwarf-rt_v4-rev0\mingw32\bin'
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
matrix:
fast_finish: true
install:
# git bash conflicts with MinGW makefiles
- if "%generator%"=="MinGW Makefiles" (set "PATH=%PATH:C:\Program Files\Git\usr\bin;=%")
- if not "%cxx_path%"=="" (set "PATH=%PATH%;%cxx_path%")
build_script:
- md _build -Force
- cd _build
- echo %configuration%
- cmake -G "%generator%" "-DCMAKE_BUILD_TYPE=%configuration%" -DBENCHMARK_DOWNLOAD_DEPENDENCIES=ON ..
- cmake --build . --config %configuration%
test_script:
- ctest -c %configuration% --timeout 300 --output-on-failure
artifacts:
- path: '_build/CMakeFiles/*.log'
name: logs
- path: '_build/Testing/**/*.xml'
name: test_results

View File

@@ -1,74 +0,0 @@
# - Adds a compiler flag if it is supported by the compiler
#
# This function checks that the supplied compiler flag is supported and then
# adds it to the corresponding compiler flags
#
# add_cxx_compiler_flag(<FLAG> [<VARIANT>])
#
# - Example
#
# include(AddCXXCompilerFlag)
# add_cxx_compiler_flag(-Wall)
# add_cxx_compiler_flag(-no-strict-aliasing RELEASE)
# Requires CMake 2.6+
if(__add_cxx_compiler_flag)
return()
endif()
set(__add_cxx_compiler_flag INCLUDED)
include(CheckCXXCompilerFlag)
function(mangle_compiler_flag FLAG OUTPUT)
string(TOUPPER "HAVE_CXX_FLAG_${FLAG}" SANITIZED_FLAG)
string(REPLACE "+" "X" SANITIZED_FLAG ${SANITIZED_FLAG})
string(REGEX REPLACE "[^A-Za-z_0-9]" "_" SANITIZED_FLAG ${SANITIZED_FLAG})
string(REGEX REPLACE "_+" "_" SANITIZED_FLAG ${SANITIZED_FLAG})
set(${OUTPUT} "${SANITIZED_FLAG}" PARENT_SCOPE)
endfunction(mangle_compiler_flag)
function(add_cxx_compiler_flag FLAG)
mangle_compiler_flag("${FLAG}" MANGLED_FLAG)
set(OLD_CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS}")
set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} ${FLAG}")
check_cxx_compiler_flag("${FLAG}" ${MANGLED_FLAG})
set(CMAKE_REQUIRED_FLAGS "${OLD_CMAKE_REQUIRED_FLAGS}")
if(${MANGLED_FLAG})
set(VARIANT ${ARGV1})
if(ARGV1)
string(TOUPPER "_${VARIANT}" VARIANT)
endif()
set(CMAKE_CXX_FLAGS${VARIANT} "${CMAKE_CXX_FLAGS${VARIANT}} ${BENCHMARK_CXX_FLAGS${VARIANT}} ${FLAG}" PARENT_SCOPE)
endif()
endfunction()
function(add_required_cxx_compiler_flag FLAG)
mangle_compiler_flag("${FLAG}" MANGLED_FLAG)
set(OLD_CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS}")
set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} ${FLAG}")
check_cxx_compiler_flag("${FLAG}" ${MANGLED_FLAG})
set(CMAKE_REQUIRED_FLAGS "${OLD_CMAKE_REQUIRED_FLAGS}")
if(${MANGLED_FLAG})
set(VARIANT ${ARGV1})
if(ARGV1)
string(TOUPPER "_${VARIANT}" VARIANT)
endif()
set(CMAKE_CXX_FLAGS${VARIANT} "${CMAKE_CXX_FLAGS${VARIANT}} ${FLAG}" PARENT_SCOPE)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${FLAG}" PARENT_SCOPE)
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${FLAG}" PARENT_SCOPE)
set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${FLAG}" PARENT_SCOPE)
set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} ${FLAG}" PARENT_SCOPE)
else()
message(FATAL_ERROR "Required flag '${FLAG}' is not supported by the compiler")
endif()
endfunction()
function(check_cxx_warning_flag FLAG)
mangle_compiler_flag("${FLAG}" MANGLED_FLAG)
set(OLD_CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS}")
# Add -Werror to ensure the compiler generates an error if the warning flag
# doesn't exist.
set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -Werror ${FLAG}")
check_cxx_compiler_flag("${FLAG}" ${MANGLED_FLAG})
set(CMAKE_REQUIRED_FLAGS "${OLD_CMAKE_REQUIRED_FLAGS}")
endfunction()

View File

@@ -1,64 +0,0 @@
# - Compile and run code to check for C++ features
#
# This functions compiles a source file under the `cmake` folder
# and adds the corresponding `HAVE_[FILENAME]` flag to the CMake
# environment
#
# cxx_feature_check(<FLAG> [<VARIANT>])
#
# - Example
#
# include(CXXFeatureCheck)
# cxx_feature_check(STD_REGEX)
# Requires CMake 2.8.12+
if(__cxx_feature_check)
return()
endif()
set(__cxx_feature_check INCLUDED)
function(cxx_feature_check FILE)
string(TOLOWER ${FILE} FILE)
string(TOUPPER ${FILE} VAR)
string(TOUPPER "HAVE_${VAR}" FEATURE)
if (DEFINED HAVE_${VAR})
set(HAVE_${VAR} 1 PARENT_SCOPE)
add_definitions(-DHAVE_${VAR})
return()
endif()
if (NOT DEFINED COMPILE_${FEATURE})
message("-- Performing Test ${FEATURE}")
if(CMAKE_CROSSCOMPILING)
try_compile(COMPILE_${FEATURE}
${CMAKE_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/cmake/${FILE}.cpp
CMAKE_FLAGS ${BENCHMARK_CXX_LINKER_FLAGS}
LINK_LIBRARIES ${BENCHMARK_CXX_LIBRARIES})
if(COMPILE_${FEATURE})
message(WARNING
"If you see build failures due to cross compilation, try setting HAVE_${VAR} to 0")
set(RUN_${FEATURE} 0)
else()
set(RUN_${FEATURE} 1)
endif()
else()
message("-- Performing Test ${FEATURE}")
try_run(RUN_${FEATURE} COMPILE_${FEATURE}
${CMAKE_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/cmake/${FILE}.cpp
CMAKE_FLAGS ${BENCHMARK_CXX_LINKER_FLAGS}
LINK_LIBRARIES ${BENCHMARK_CXX_LIBRARIES})
endif()
endif()
if(RUN_${FEATURE} EQUAL 0)
message("-- Performing Test ${FEATURE} -- success")
set(HAVE_${VAR} 1 PARENT_SCOPE)
add_definitions(-DHAVE_${VAR})
else()
if(NOT COMPILE_${FEATURE})
message("-- Performing Test ${FEATURE} -- failed to compile")
else()
message("-- Performing Test ${FEATURE} -- compiled but failed to run")
endif()
endif()
endfunction()

View File

@@ -1 +0,0 @@
include("${CMAKE_CURRENT_LIST_DIR}/@targets_export_name@.cmake")

View File

@@ -1,54 +0,0 @@
# - Returns a version string from Git tags
#
# This function inspects the annotated git tags for the project and returns a string
# into a CMake variable
#
# get_git_version(<var>)
#
# - Example
#
# include(GetGitVersion)
# get_git_version(GIT_VERSION)
#
# Requires CMake 2.8.11+
find_package(Git)
if(__get_git_version)
return()
endif()
set(__get_git_version INCLUDED)
function(get_git_version var)
if(GIT_EXECUTABLE)
execute_process(COMMAND ${GIT_EXECUTABLE} describe --match "v[0-9]*.[0-9]*.[0-9]*" --abbrev=8
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
RESULT_VARIABLE status
OUTPUT_VARIABLE GIT_VERSION
ERROR_QUIET)
if(${status})
set(GIT_VERSION "v0.0.0")
else()
string(STRIP ${GIT_VERSION} GIT_VERSION)
string(REGEX REPLACE "-[0-9]+-g" "-" GIT_VERSION ${GIT_VERSION})
endif()
# Work out if the repository is dirty
execute_process(COMMAND ${GIT_EXECUTABLE} update-index -q --refresh
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
OUTPUT_QUIET
ERROR_QUIET)
execute_process(COMMAND ${GIT_EXECUTABLE} diff-index --name-only HEAD --
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
OUTPUT_VARIABLE GIT_DIFF_INDEX
ERROR_QUIET)
string(COMPARE NOTEQUAL "${GIT_DIFF_INDEX}" "" GIT_DIRTY)
if (${GIT_DIRTY})
set(GIT_VERSION "${GIT_VERSION}-dirty")
endif()
else()
set(GIT_VERSION "v0.0.0")
endif()
message("-- git Version: ${GIT_VERSION}")
set(${var} ${GIT_VERSION} PARENT_SCOPE)
endfunction()

View File

@@ -1,113 +0,0 @@
include(split_list)
macro(build_external_gtest)
include(ExternalProject)
set(GTEST_FLAGS "")
if (BENCHMARK_USE_LIBCXX)
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
list(APPEND GTEST_FLAGS -stdlib=libc++)
else()
message(WARNING "Unsupported compiler (${CMAKE_CXX_COMPILER}) when using libc++")
endif()
endif()
if (BENCHMARK_BUILD_32_BITS)
list(APPEND GTEST_FLAGS -m32)
endif()
if (NOT "${CMAKE_CXX_FLAGS}" STREQUAL "")
list(APPEND GTEST_FLAGS ${CMAKE_CXX_FLAGS})
endif()
string(TOUPPER "${CMAKE_BUILD_TYPE}" GTEST_BUILD_TYPE)
if ("${GTEST_BUILD_TYPE}" STREQUAL "COVERAGE")
set(GTEST_BUILD_TYPE "DEBUG")
endif()
# FIXME: Since 10/Feb/2017 the googletest trunk has had a bug where
# -Werror=unused-function fires during the build on OS X. This is a temporary
# workaround to keep our travis bots from failing. It should be removed
# once gtest is fixed.
if (NOT "${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
list(APPEND GTEST_FLAGS "-Wno-unused-function")
endif()
split_list(GTEST_FLAGS)
set(EXCLUDE_FROM_ALL_OPT "")
set(EXCLUDE_FROM_ALL_VALUE "")
if (${CMAKE_VERSION} VERSION_GREATER "3.0.99")
set(EXCLUDE_FROM_ALL_OPT "EXCLUDE_FROM_ALL")
set(EXCLUDE_FROM_ALL_VALUE "ON")
endif()
ExternalProject_Add(googletest
${EXCLUDE_FROM_ALL_OPT} ${EXCLUDE_FROM_ALL_VALUE}
GIT_REPOSITORY https://github.com/google/googletest.git
GIT_TAG master
PREFIX "${CMAKE_BINARY_DIR}/googletest"
INSTALL_DIR "${CMAKE_BINARY_DIR}/googletest"
CMAKE_CACHE_ARGS
-DCMAKE_BUILD_TYPE:STRING=${GTEST_BUILD_TYPE}
-DCMAKE_C_COMPILER:STRING=${CMAKE_C_COMPILER}
-DCMAKE_CXX_COMPILER:STRING=${CMAKE_CXX_COMPILER}
-DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
-DCMAKE_INSTALL_LIBDIR:PATH=<INSTALL_DIR>/lib
-DCMAKE_CXX_FLAGS:STRING=${GTEST_FLAGS}
-Dgtest_force_shared_crt:BOOL=ON
)
ExternalProject_Get_Property(googletest install_dir)
set(GTEST_INCLUDE_DIRS ${install_dir}/include)
file(MAKE_DIRECTORY ${GTEST_INCLUDE_DIRS})
set(LIB_SUFFIX "${CMAKE_STATIC_LIBRARY_SUFFIX}")
set(LIB_PREFIX "${CMAKE_STATIC_LIBRARY_PREFIX}")
if("${GTEST_BUILD_TYPE}" STREQUAL "DEBUG")
set(LIB_SUFFIX "d${CMAKE_STATIC_LIBRARY_SUFFIX}")
endif()
# Use gmock_main instead of gtest_main because it initializes gtest as well.
# Note: The libraries are listed in reverse order of their dependancies.
foreach(LIB gtest gmock gmock_main)
add_library(${LIB} UNKNOWN IMPORTED)
set_target_properties(${LIB} PROPERTIES
IMPORTED_LOCATION ${install_dir}/lib/${LIB_PREFIX}${LIB}${LIB_SUFFIX}
INTERFACE_INCLUDE_DIRECTORIES ${GTEST_INCLUDE_DIRS}
INTERFACE_LINK_LIBRARIES "${GTEST_BOTH_LIBRARIES}"
)
add_dependencies(${LIB} googletest)
list(APPEND GTEST_BOTH_LIBRARIES ${LIB})
endforeach()
endmacro(build_external_gtest)
if (BENCHMARK_ENABLE_GTEST_TESTS)
if (IS_DIRECTORY ${CMAKE_SOURCE_DIR}/googletest)
set(GTEST_ROOT "${CMAKE_SOURCE_DIR}/googletest")
set(INSTALL_GTEST OFF CACHE INTERNAL "")
set(INSTALL_GMOCK OFF CACHE INTERNAL "")
add_subdirectory(${CMAKE_SOURCE_DIR}/googletest)
set(GTEST_BOTH_LIBRARIES gtest gmock gmock_main)
foreach(HEADER test mock)
# CMake 2.8 and older don't respect INTERFACE_INCLUDE_DIRECTORIES, so we
# have to add the paths ourselves.
set(HFILE g${HEADER}/g${HEADER}.h)
set(HPATH ${GTEST_ROOT}/google${HEADER}/include)
find_path(HEADER_PATH_${HEADER} ${HFILE}
NO_DEFAULT_PATHS
HINTS ${HPATH}
)
if (NOT HEADER_PATH_${HEADER})
message(FATAL_ERROR "Failed to find header ${HFILE} in ${HPATH}")
endif()
list(APPEND GTEST_INCLUDE_DIRS ${HEADER_PATH_${HEADER}})
endforeach()
elseif(BENCHMARK_DOWNLOAD_DEPENDENCIES)
build_external_gtest()
else()
find_package(GTest REQUIRED)
find_path(GMOCK_INCLUDE_DIRS gmock/gmock.h
HINTS ${GTEST_INCLUDE_DIRS})
if (NOT GMOCK_INCLUDE_DIRS)
message(FATAL_ERROR "Failed to find header gmock/gmock.h with hint ${GTEST_INCLUDE_DIRS}")
endif()
set(GTEST_INCLUDE_DIRS ${GTEST_INCLUDE_DIRS} ${GMOCK_INCLUDE_DIRS})
# FIXME: We don't currently require the gmock library to build the tests,
# and it's likely we won't find it, so we don't try. As long as we've
# found the gmock/gmock.h header and gtest_main that should be good enough.
endif()
endif()

View File

@@ -1,16 +0,0 @@
include(FeatureSummary)
find_program(LLVMAR_EXECUTABLE
NAMES llvm-ar
DOC "The llvm-ar executable"
)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(LLVMAr
DEFAULT_MSG
LLVMAR_EXECUTABLE)
SET_PACKAGE_PROPERTIES(LLVMAr PROPERTIES
URL https://llvm.org/docs/CommandGuide/llvm-ar.html
DESCRIPTION "create, modify, and extract from archives"
)

View File

@@ -1,16 +0,0 @@
include(FeatureSummary)
find_program(LLVMNM_EXECUTABLE
NAMES llvm-nm
DOC "The llvm-nm executable"
)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(LLVMNm
DEFAULT_MSG
LLVMNM_EXECUTABLE)
SET_PACKAGE_PROPERTIES(LLVMNm PROPERTIES
URL https://llvm.org/docs/CommandGuide/llvm-nm.html
DESCRIPTION "list LLVM bitcode and object files symbol table"
)

View File

@@ -1,15 +0,0 @@
include(FeatureSummary)
find_program(LLVMRANLIB_EXECUTABLE
NAMES llvm-ranlib
DOC "The llvm-ranlib executable"
)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(LLVMRanLib
DEFAULT_MSG
LLVMRANLIB_EXECUTABLE)
SET_PACKAGE_PROPERTIES(LLVMRanLib PROPERTIES
DESCRIPTION "generate index for LLVM archive"
)

View File

@@ -1,11 +0,0 @@
prefix=@CMAKE_INSTALL_PREFIX@
exec_prefix=${prefix}
libdir=${prefix}/lib
includedir=${prefix}/include
Name: @PROJECT_NAME@
Description: Google microbenchmark framework
Version: @VERSION@
Libs: -L${libdir} -lbenchmark
Cflags: -I${includedir}

View File

@@ -1,12 +0,0 @@
#include <gnuregex.h>
#include <string>
int main() {
std::string str = "test0159";
regex_t re;
int ec = regcomp(&re, "^[a-z]+[0-9]+$", REG_EXTENDED | REG_NOSUB);
if (ec != 0) {
return ec;
}
return regexec(&re, str.c_str(), 0, nullptr, 0) ? -1 : 0;
}

View File

@@ -1,8 +0,0 @@
find_package(LLVMAr REQUIRED)
set(CMAKE_AR "${LLVMAR_EXECUTABLE}" CACHE FILEPATH "" FORCE)
find_package(LLVMNm REQUIRED)
set(CMAKE_NM "${LLVMNM_EXECUTABLE}" CACHE FILEPATH "" FORCE)
find_package(LLVMRanLib REQUIRED)
set(CMAKE_RANLIB "${LLVMRANLIB_EXECUTABLE}" CACHE FILEPATH "" FORCE)

View File

@@ -1,14 +0,0 @@
#include <regex.h>
#include <string>
int main() {
std::string str = "test0159";
regex_t re;
int ec = regcomp(&re, "^[a-z]+[0-9]+$", REG_EXTENDED | REG_NOSUB);
if (ec != 0) {
return ec;
}
int ret = regexec(&re, str.c_str(), 0, nullptr, 0) ? -1 : 0;
regfree(&re);
return ret;
}

View File

@@ -1,3 +0,0 @@
macro(split_list listname)
string(REPLACE ";" " " ${listname} "${${listname}}")
endmacro()

View File

@@ -1,10 +0,0 @@
#include <regex>
#include <string>
int main() {
const std::string str = "test0159";
std::regex re;
re = std::regex("^[a-z]+[0-9]+$",
std::regex_constants::extended | std::regex_constants::nosubs);
return std::regex_search(str, re) ? 0 : -1;
}

View File

@@ -1,7 +0,0 @@
#include <chrono>
int main() {
typedef std::chrono::steady_clock Clock;
Clock::time_point tp = Clock::now();
((void)tp);
}

View File

@@ -1,4 +0,0 @@
#define HAVE_THREAD_SAFETY_ATTRIBUTES
#include "../src/mutex.h"
int main() {}

View File

@@ -1,147 +0,0 @@
# Assembly Tests
The Benchmark library provides a number of functions whose primary
purpose in to affect assembly generation, including `DoNotOptimize`
and `ClobberMemory`. In addition there are other functions,
such as `KeepRunning`, for which generating good assembly is paramount.
For these functions it's important to have tests that verify the
correctness and quality of the implementation. This requires testing
the code generated by the compiler.
This document describes how the Benchmark library tests compiler output,
as well as how to properly write new tests.
## Anatomy of a Test
Writing a test has two steps:
* Write the code you want to generate assembly for.
* Add `// CHECK` lines to match against the verified assembly.
Example:
```c++
// CHECK-LABEL: test_add:
extern "C" int test_add() {
extern int ExternInt;
return ExternInt + 1;
// CHECK: movl ExternInt(%rip), %eax
// CHECK: addl %eax
// CHECK: ret
}
```
#### LLVM Filecheck
[LLVM's Filecheck](https://llvm.org/docs/CommandGuide/FileCheck.html)
is used to test the generated assembly against the `// CHECK` lines
specified in the tests source file. Please see the documentation
linked above for information on how to write `CHECK` directives.
#### Tips and Tricks:
* Tests should match the minimal amount of output required to establish
correctness. `CHECK` directives don't have to match on the exact next line
after the previous match, so tests should omit checks for unimportant
bits of assembly. ([`CHECK-NEXT`](https://llvm.org/docs/CommandGuide/FileCheck.html#the-check-next-directive)
can be used to ensure a match occurs exactly after the previous match).
* The tests are compiled with `-O3 -g0`. So we're only testing the
optimized output.
* The assembly output is further cleaned up using `tools/strip_asm.py`.
This removes comments, assembler directives, and unused labels before
the test is run.
* The generated and stripped assembly file for a test is output under
`<build-directory>/test/<test-name>.s`
* Filecheck supports using [`CHECK` prefixes](https://llvm.org/docs/CommandGuide/FileCheck.html#cmdoption-check-prefixes)
to specify lines that should only match in certain situations.
The Benchmark tests use `CHECK-CLANG` and `CHECK-GNU` for lines that
are only expected to match Clang or GCC's output respectively. Normal
`CHECK` lines match against all compilers. (Note: `CHECK-NOT` and
`CHECK-LABEL` are NOT prefixes. They are versions of non-prefixed
`CHECK` lines)
* Use `extern "C"` to disable name mangling for specific functions. This
makes them easier to name in the `CHECK` lines.
## Problems Writing Portable Tests
Writing tests which check the code generated by a compiler are
inherently non-portable. Different compilers and even different compiler
versions may generate entirely different code. The Benchmark tests
must tolerate this.
LLVM Filecheck provides a number of mechanisms to help write
"more portable" tests; including [matching using regular expressions](https://llvm.org/docs/CommandGuide/FileCheck.html#filecheck-pattern-matching-syntax),
allowing the creation of [named variables](https://llvm.org/docs/CommandGuide/FileCheck.html#filecheck-variables)
for later matching, and [checking non-sequential matches](https://llvm.org/docs/CommandGuide/FileCheck.html#the-check-dag-directive).
#### Capturing Variables
For example, say GCC stores a variable in a register but Clang stores
it in memory. To write a test that tolerates both cases we "capture"
the destination of the store, and then use the captured expression
to write the remainder of the test.
```c++
// CHECK-LABEL: test_div_no_op_into_shr:
extern "C" void test_div_no_op_into_shr(int value) {
int divisor = 2;
benchmark::DoNotOptimize(divisor); // hide the value from the optimizer
return value / divisor;
// CHECK: movl $2, [[DEST:.*]]
// CHECK: idivl [[DEST]]
// CHECK: ret
}
```
#### Using Regular Expressions to Match Differing Output
Often tests require testing assembly lines which may subtly differ
between compilers or compiler versions. A common example of this
is matching stack frame addresses. In this case regular expressions
can be used to match the differing bits of output. For example:
```c++
int ExternInt;
struct Point { int x, y, z; };
// CHECK-LABEL: test_store_point:
extern "C" void test_store_point() {
Point p{ExternInt, ExternInt, ExternInt};
benchmark::DoNotOptimize(p);
// CHECK: movl ExternInt(%rip), %eax
// CHECK: movl %eax, -{{[0-9]+}}(%rsp)
// CHECK: movl %eax, -{{[0-9]+}}(%rsp)
// CHECK: movl %eax, -{{[0-9]+}}(%rsp)
// CHECK: ret
}
```
## Current Requirements and Limitations
The tests require Filecheck to be installed along the `PATH` of the
build machine. Otherwise the tests will be disabled.
Additionally, as mentioned in the previous section, codegen tests are
inherently non-portable. Currently the tests are limited to:
* x86_64 targets.
* Compiled with GCC or Clang
Further work could be done, at least on a limited basis, to extend the
tests to other architectures and compilers (using `CHECK` prefixes).
Furthermore, the tests fail for builds which specify additional flags
that modify code generation, including `--coverage` or `-fsanitize=`.

View File

@@ -1,242 +0,0 @@
# Benchmark Tools
## compare_bench.py
The `compare_bench.py` utility which can be used to compare the result of benchmarks.
The program is invoked like:
``` bash
$ compare_bench.py <old-benchmark> <new-benchmark> [benchmark options]...
```
Where `<old-benchmark>` and `<new-benchmark>` either specify a benchmark executable file, or a JSON output file. The type of the input file is automatically detected. If a benchmark executable is specified then the benchmark is run to obtain the results. Otherwise the results are simply loaded from the output file.
`[benchmark options]` will be passed to the benchmarks invocations. They can be anything that binary accepts, be it either normal `--benchmark_*` parameters, or some custom parameters your binary takes.
The sample output using the JSON test files under `Inputs/` gives:
``` bash
$ ./compare_bench.py ./gbench/Inputs/test1_run1.json ./gbench/Inputs/test1_run2.json
Comparing ./gbench/Inputs/test1_run1.json to ./gbench/Inputs/test1_run2.json
Benchmark Time CPU Time Old Time New CPU Old CPU New
-------------------------------------------------------------------------------------------------------------
BM_SameTimes +0.0000 +0.0000 10 10 10 10
BM_2xFaster -0.5000 -0.5000 50 25 50 25
BM_2xSlower +1.0000 +1.0000 50 100 50 100
BM_1PercentFaster -0.0100 -0.0100 100 99 100 99
BM_1PercentSlower +0.0100 +0.0100 100 101 100 101
BM_10PercentFaster -0.1000 -0.1000 100 90 100 90
BM_10PercentSlower +0.1000 +0.1000 100 110 100 110
BM_100xSlower +99.0000 +99.0000 100 10000 100 10000
BM_100xFaster -0.9900 -0.9900 10000 100 10000 100
BM_10PercentCPUToTime +0.1000 -0.1000 100 110 100 90
BM_ThirdFaster -0.3333 -0.3334 100 67 100 67
BM_BadTimeUnit -0.9000 +0.2000 0 0 0 1
```
As you can note, the values in `Time` and `CPU` columns are calculated as `(new - old) / |old|`.
When a benchmark executable is run, the raw output from the benchmark is printed in real time to stdout. The sample output using `benchmark/basic_test` for both arguments looks like:
```
./compare_bench.py test/basic_test test/basic_test --benchmark_filter=BM_empty.*
RUNNING: test/basic_test --benchmark_filter=BM_empty.* --benchmark_out=/tmp/tmpN7LF3a
Run on (8 X 4000 MHz CPU s)
2017-11-07 23:28:36
---------------------------------------------------------------------
Benchmark Time CPU Iterations
---------------------------------------------------------------------
BM_empty 4 ns 4 ns 170178757
BM_empty/threads:8 1 ns 7 ns 103868920
BM_empty_stop_start 0 ns 0 ns 1000000000
BM_empty_stop_start/threads:8 0 ns 0 ns 1403031720
RUNNING: /test/basic_test --benchmark_filter=BM_empty.* --benchmark_out=/tmp/tmplvrIp8
Run on (8 X 4000 MHz CPU s)
2017-11-07 23:28:38
---------------------------------------------------------------------
Benchmark Time CPU Iterations
---------------------------------------------------------------------
BM_empty 4 ns 4 ns 169534855
BM_empty/threads:8 1 ns 7 ns 104188776
BM_empty_stop_start 0 ns 0 ns 1000000000
BM_empty_stop_start/threads:8 0 ns 0 ns 1404159424
Comparing ../build/test/basic_test to ../build/test/basic_test
Benchmark Time CPU Time Old Time New CPU Old CPU New
---------------------------------------------------------------------------------------------------------------------
BM_empty -0.0048 -0.0049 4 4 4 4
BM_empty/threads:8 -0.0123 -0.0054 1 1 7 7
BM_empty_stop_start -0.0000 -0.0000 0 0 0 0
BM_empty_stop_start/threads:8 -0.0029 +0.0001 0 0 0 0
```
As you can note, the values in `Time` and `CPU` columns are calculated as `(new - old) / |old|`.
Obviously this example doesn't give any useful output, but it's intended to show the output format when 'compare_bench.py' needs to run benchmarks.
## compare.py
The `compare.py` can be used to compare the result of benchmarks.
There are three modes of operation:
1. Just compare two benchmarks, what `compare_bench.py` did.
The program is invoked like:
``` bash
$ compare.py benchmarks <benchmark_baseline> <benchmark_contender> [benchmark options]...
```
Where `<benchmark_baseline>` and `<benchmark_contender>` either specify a benchmark executable file, or a JSON output file. The type of the input file is automatically detected. If a benchmark executable is specified then the benchmark is run to obtain the results. Otherwise the results are simply loaded from the output file.
`[benchmark options]` will be passed to the benchmarks invocations. They can be anything that binary accepts, be it either normal `--benchmark_*` parameters, or some custom parameters your binary takes.
Example output:
```
$ ./compare.py benchmarks ./a.out ./a.out
RUNNING: ./a.out --benchmark_out=/tmp/tmprBT5nW
Run on (8 X 4000 MHz CPU s)
2017-11-07 21:16:44
------------------------------------------------------
Benchmark Time CPU Iterations
------------------------------------------------------
BM_memcpy/8 36 ns 36 ns 19101577 211.669MB/s
BM_memcpy/64 76 ns 76 ns 9412571 800.199MB/s
BM_memcpy/512 84 ns 84 ns 8249070 5.64771GB/s
BM_memcpy/1024 116 ns 116 ns 6181763 8.19505GB/s
BM_memcpy/8192 643 ns 643 ns 1062855 11.8636GB/s
BM_copy/8 222 ns 222 ns 3137987 34.3772MB/s
BM_copy/64 1608 ns 1608 ns 432758 37.9501MB/s
BM_copy/512 12589 ns 12589 ns 54806 38.7867MB/s
BM_copy/1024 25169 ns 25169 ns 27713 38.8003MB/s
BM_copy/8192 201165 ns 201112 ns 3486 38.8466MB/s
RUNNING: ./a.out --benchmark_out=/tmp/tmpt1wwG_
Run on (8 X 4000 MHz CPU s)
2017-11-07 21:16:53
------------------------------------------------------
Benchmark Time CPU Iterations
------------------------------------------------------
BM_memcpy/8 36 ns 36 ns 19397903 211.255MB/s
BM_memcpy/64 73 ns 73 ns 9691174 839.635MB/s
BM_memcpy/512 85 ns 85 ns 8312329 5.60101GB/s
BM_memcpy/1024 118 ns 118 ns 6438774 8.11608GB/s
BM_memcpy/8192 656 ns 656 ns 1068644 11.6277GB/s
BM_copy/8 223 ns 223 ns 3146977 34.2338MB/s
BM_copy/64 1611 ns 1611 ns 435340 37.8751MB/s
BM_copy/512 12622 ns 12622 ns 54818 38.6844MB/s
BM_copy/1024 25257 ns 25239 ns 27779 38.6927MB/s
BM_copy/8192 205013 ns 205010 ns 3479 38.108MB/s
Comparing ./a.out to ./a.out
Benchmark Time CPU Time Old Time New CPU Old CPU New
------------------------------------------------------------------------------------------------------
BM_memcpy/8 +0.0020 +0.0020 36 36 36 36
BM_memcpy/64 -0.0468 -0.0470 76 73 76 73
BM_memcpy/512 +0.0081 +0.0083 84 85 84 85
BM_memcpy/1024 +0.0098 +0.0097 116 118 116 118
BM_memcpy/8192 +0.0200 +0.0203 643 656 643 656
BM_copy/8 +0.0046 +0.0042 222 223 222 223
BM_copy/64 +0.0020 +0.0020 1608 1611 1608 1611
BM_copy/512 +0.0027 +0.0026 12589 12622 12589 12622
BM_copy/1024 +0.0035 +0.0028 25169 25257 25169 25239
BM_copy/8192 +0.0191 +0.0194 201165 205013 201112 205010
```
What it does is for the every benchmark from the first run it looks for the benchmark with exactly the same name in the second run, and then compares the results. If the names differ, the benchmark is omitted from the diff.
As you can note, the values in `Time` and `CPU` columns are calculated as `(new - old) / |old|`.
2. Compare two different filters of one benchmark
The program is invoked like:
``` bash
$ compare.py filters <benchmark> <filter_baseline> <filter_contender> [benchmark options]...
```
Where `<benchmark>` either specify a benchmark executable file, or a JSON output file. The type of the input file is automatically detected. If a benchmark executable is specified then the benchmark is run to obtain the results. Otherwise the results are simply loaded from the output file.
Where `<filter_baseline>` and `<filter_contender>` are the same regex filters that you would pass to the `[--benchmark_filter=<regex>]` parameter of the benchmark binary.
`[benchmark options]` will be passed to the benchmarks invocations. They can be anything that binary accepts, be it either normal `--benchmark_*` parameters, or some custom parameters your binary takes.
Example output:
```
$ ./compare.py filters ./a.out BM_memcpy BM_copy
RUNNING: ./a.out --benchmark_filter=BM_memcpy --benchmark_out=/tmp/tmpBWKk0k
Run on (8 X 4000 MHz CPU s)
2017-11-07 21:37:28
------------------------------------------------------
Benchmark Time CPU Iterations
------------------------------------------------------
BM_memcpy/8 36 ns 36 ns 17891491 211.215MB/s
BM_memcpy/64 74 ns 74 ns 9400999 825.646MB/s
BM_memcpy/512 87 ns 87 ns 8027453 5.46126GB/s
BM_memcpy/1024 111 ns 111 ns 6116853 8.5648GB/s
BM_memcpy/8192 657 ns 656 ns 1064679 11.6247GB/s
RUNNING: ./a.out --benchmark_filter=BM_copy --benchmark_out=/tmp/tmpAvWcOM
Run on (8 X 4000 MHz CPU s)
2017-11-07 21:37:33
----------------------------------------------------
Benchmark Time CPU Iterations
----------------------------------------------------
BM_copy/8 227 ns 227 ns 3038700 33.6264MB/s
BM_copy/64 1640 ns 1640 ns 426893 37.2154MB/s
BM_copy/512 12804 ns 12801 ns 55417 38.1444MB/s
BM_copy/1024 25409 ns 25407 ns 27516 38.4365MB/s
BM_copy/8192 202986 ns 202990 ns 3454 38.4871MB/s
Comparing BM_memcpy to BM_copy (from ./a.out)
Benchmark Time CPU Time Old Time New CPU Old CPU New
--------------------------------------------------------------------------------------------------------------------
[BM_memcpy vs. BM_copy]/8 +5.2829 +5.2812 36 227 36 227
[BM_memcpy vs. BM_copy]/64 +21.1719 +21.1856 74 1640 74 1640
[BM_memcpy vs. BM_copy]/512 +145.6487 +145.6097 87 12804 87 12801
[BM_memcpy vs. BM_copy]/1024 +227.1860 +227.1776 111 25409 111 25407
[BM_memcpy vs. BM_copy]/8192 +308.1664 +308.2898 657 202986 656 202990
```
As you can see, it applies filter to the benchmarks, both when running the benchmark, and before doing the diff. And to make the diff work, the matches are replaced with some common string. Thus, you can compare two different benchmark families within one benchmark binary.
As you can note, the values in `Time` and `CPU` columns are calculated as `(new - old) / |old|`.
3. Compare filter one from benchmark one to filter two from benchmark two:
The program is invoked like:
``` bash
$ compare.py filters <benchmark_baseline> <filter_baseline> <benchmark_contender> <filter_contender> [benchmark options]...
```
Where `<benchmark_baseline>` and `<benchmark_contender>` either specify a benchmark executable file, or a JSON output file. The type of the input file is automatically detected. If a benchmark executable is specified then the benchmark is run to obtain the results. Otherwise the results are simply loaded from the output file.
Where `<filter_baseline>` and `<filter_contender>` are the same regex filters that you would pass to the `[--benchmark_filter=<regex>]` parameter of the benchmark binary.
`[benchmark options]` will be passed to the benchmarks invocations. They can be anything that binary accepts, be it either normal `--benchmark_*` parameters, or some custom parameters your binary takes.
Example output:
```
$ ./compare.py benchmarksfiltered ./a.out BM_memcpy ./a.out BM_copy
RUNNING: ./a.out --benchmark_filter=BM_memcpy --benchmark_out=/tmp/tmp_FvbYg
Run on (8 X 4000 MHz CPU s)
2017-11-07 21:38:27
------------------------------------------------------
Benchmark Time CPU Iterations
------------------------------------------------------
BM_memcpy/8 37 ns 37 ns 18953482 204.118MB/s
BM_memcpy/64 74 ns 74 ns 9206578 828.245MB/s
BM_memcpy/512 91 ns 91 ns 8086195 5.25476GB/s
BM_memcpy/1024 120 ns 120 ns 5804513 7.95662GB/s
BM_memcpy/8192 664 ns 664 ns 1028363 11.4948GB/s
RUNNING: ./a.out --benchmark_filter=BM_copy --benchmark_out=/tmp/tmpDfL5iE
Run on (8 X 4000 MHz CPU s)
2017-11-07 21:38:32
----------------------------------------------------
Benchmark Time CPU Iterations
----------------------------------------------------
BM_copy/8 230 ns 230 ns 2985909 33.1161MB/s
BM_copy/64 1654 ns 1653 ns 419408 36.9137MB/s
BM_copy/512 13122 ns 13120 ns 53403 37.2156MB/s
BM_copy/1024 26679 ns 26666 ns 26575 36.6218MB/s
BM_copy/8192 215068 ns 215053 ns 3221 36.3283MB/s
Comparing BM_memcpy (from ./a.out) to BM_copy (from ./a.out)
Benchmark Time CPU Time Old Time New CPU Old CPU New
--------------------------------------------------------------------------------------------------------------------
[BM_memcpy vs. BM_copy]/8 +5.1649 +5.1637 37 230 37 230
[BM_memcpy vs. BM_copy]/64 +21.4352 +21.4374 74 1654 74 1653
[BM_memcpy vs. BM_copy]/512 +143.6022 +143.5865 91 13122 91 13120
[BM_memcpy vs. BM_copy]/1024 +221.5903 +221.4790 120 26679 120 26666
[BM_memcpy vs. BM_copy]/8192 +322.9059 +323.0096 664 215068 664 215053
```
This is a mix of the previous two modes, two (potentially different) benchmark binaries are run, and a different filter is applied to each one.
As you can note, the values in `Time` and `CPU` columns are calculated as `(new - old) / |old|`.

File diff suppressed because it is too large Load Diff

View File

@@ -1,320 +0,0 @@
#! /usr/bin/env python
# encoding: utf-8
import argparse
import errno
import logging
import os
import platform
import re
import sys
import subprocess
import tempfile
try:
import winreg
except ImportError:
import _winreg as winreg
try:
import urllib.request as request
except ImportError:
import urllib as request
try:
import urllib.parse as parse
except ImportError:
import urlparse as parse
class EmptyLogger(object):
'''
Provides an implementation that performs no logging
'''
def debug(self, *k, **kw):
pass
def info(self, *k, **kw):
pass
def warn(self, *k, **kw):
pass
def error(self, *k, **kw):
pass
def critical(self, *k, **kw):
pass
def setLevel(self, *k, **kw):
pass
urls = (
'http://downloads.sourceforge.net/project/mingw-w64/Toolchains%20'
'targetting%20Win32/Personal%20Builds/mingw-builds/installer/'
'repository.txt',
'http://downloads.sourceforge.net/project/mingwbuilds/host-windows/'
'repository.txt'
)
'''
A list of mingw-build repositories
'''
def repository(urls = urls, log = EmptyLogger()):
'''
Downloads and parse mingw-build repository files and parses them
'''
log.info('getting mingw-builds repository')
versions = {}
re_sourceforge = re.compile(r'http://sourceforge.net/projects/([^/]+)/files')
re_sub = r'http://downloads.sourceforge.net/project/\1'
for url in urls:
log.debug(' - requesting: %s', url)
socket = request.urlopen(url)
repo = socket.read()
if not isinstance(repo, str):
repo = repo.decode();
socket.close()
for entry in repo.split('\n')[:-1]:
value = entry.split('|')
version = tuple([int(n) for n in value[0].strip().split('.')])
version = versions.setdefault(version, {})
arch = value[1].strip()
if arch == 'x32':
arch = 'i686'
elif arch == 'x64':
arch = 'x86_64'
arch = version.setdefault(arch, {})
threading = arch.setdefault(value[2].strip(), {})
exceptions = threading.setdefault(value[3].strip(), {})
revision = exceptions.setdefault(int(value[4].strip()[3:]),
re_sourceforge.sub(re_sub, value[5].strip()))
return versions
def find_in_path(file, path=None):
'''
Attempts to find an executable in the path
'''
if platform.system() == 'Windows':
file += '.exe'
if path is None:
path = os.environ.get('PATH', '')
if type(path) is type(''):
path = path.split(os.pathsep)
return list(filter(os.path.exists,
map(lambda dir, file=file: os.path.join(dir, file), path)))
def find_7zip(log = EmptyLogger()):
'''
Attempts to find 7zip for unpacking the mingw-build archives
'''
log.info('finding 7zip')
path = find_in_path('7z')
if not path:
key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, r'SOFTWARE\7-Zip')
path, _ = winreg.QueryValueEx(key, 'Path')
path = [os.path.join(path, '7z.exe')]
log.debug('found \'%s\'', path[0])
return path[0]
find_7zip()
def unpack(archive, location, log = EmptyLogger()):
'''
Unpacks a mingw-builds archive
'''
sevenzip = find_7zip(log)
log.info('unpacking %s', os.path.basename(archive))
cmd = [sevenzip, 'x', archive, '-o' + location, '-y']
log.debug(' - %r', cmd)
with open(os.devnull, 'w') as devnull:
subprocess.check_call(cmd, stdout = devnull)
def download(url, location, log = EmptyLogger()):
'''
Downloads and unpacks a mingw-builds archive
'''
log.info('downloading MinGW')
log.debug(' - url: %s', url)
log.debug(' - location: %s', location)
re_content = re.compile(r'attachment;[ \t]*filename=(")?([^"]*)(")?[\r\n]*')
stream = request.urlopen(url)
try:
content = stream.getheader('Content-Disposition') or ''
except AttributeError:
content = stream.headers.getheader('Content-Disposition') or ''
matches = re_content.match(content)
if matches:
filename = matches.group(2)
else:
parsed = parse.urlparse(stream.geturl())
filename = os.path.basename(parsed.path)
try:
os.makedirs(location)
except OSError as e:
if e.errno == errno.EEXIST and os.path.isdir(location):
pass
else:
raise
archive = os.path.join(location, filename)
with open(archive, 'wb') as out:
while True:
buf = stream.read(1024)
if not buf:
break
out.write(buf)
unpack(archive, location, log = log)
os.remove(archive)
possible = os.path.join(location, 'mingw64')
if not os.path.exists(possible):
possible = os.path.join(location, 'mingw32')
if not os.path.exists(possible):
raise ValueError('Failed to find unpacked MinGW: ' + possible)
return possible
def root(location = None, arch = None, version = None, threading = None,
exceptions = None, revision = None, log = EmptyLogger()):
'''
Returns the root folder of a specific version of the mingw-builds variant
of gcc. Will download the compiler if needed
'''
# Get the repository if we don't have all the information
if not (arch and version and threading and exceptions and revision):
versions = repository(log = log)
# Determine some defaults
version = version or max(versions.keys())
if not arch:
arch = platform.machine().lower()
if arch == 'x86':
arch = 'i686'
elif arch == 'amd64':
arch = 'x86_64'
if not threading:
keys = versions[version][arch].keys()
if 'posix' in keys:
threading = 'posix'
elif 'win32' in keys:
threading = 'win32'
else:
threading = keys[0]
if not exceptions:
keys = versions[version][arch][threading].keys()
if 'seh' in keys:
exceptions = 'seh'
elif 'sjlj' in keys:
exceptions = 'sjlj'
else:
exceptions = keys[0]
if revision == None:
revision = max(versions[version][arch][threading][exceptions].keys())
if not location:
location = os.path.join(tempfile.gettempdir(), 'mingw-builds')
# Get the download url
url = versions[version][arch][threading][exceptions][revision]
# Tell the user whatzzup
log.info('finding MinGW %s', '.'.join(str(v) for v in version))
log.debug(' - arch: %s', arch)
log.debug(' - threading: %s', threading)
log.debug(' - exceptions: %s', exceptions)
log.debug(' - revision: %s', revision)
log.debug(' - url: %s', url)
# Store each specific revision differently
slug = '{version}-{arch}-{threading}-{exceptions}-rev{revision}'
slug = slug.format(
version = '.'.join(str(v) for v in version),
arch = arch,
threading = threading,
exceptions = exceptions,
revision = revision
)
if arch == 'x86_64':
root_dir = os.path.join(location, slug, 'mingw64')
elif arch == 'i686':
root_dir = os.path.join(location, slug, 'mingw32')
else:
raise ValueError('Unknown MinGW arch: ' + arch)
# Download if needed
if not os.path.exists(root_dir):
downloaded = download(url, os.path.join(location, slug), log = log)
if downloaded != root_dir:
raise ValueError('The location of mingw did not match\n%s\n%s'
% (downloaded, root_dir))
return root_dir
def str2ver(string):
'''
Converts a version string into a tuple
'''
try:
version = tuple(int(v) for v in string.split('.'))
if len(version) is not 3:
raise ValueError()
except ValueError:
raise argparse.ArgumentTypeError(
'please provide a three digit version string')
return version
def main():
'''
Invoked when the script is run directly by the python interpreter
'''
parser = argparse.ArgumentParser(
description = 'Downloads a specific version of MinGW',
formatter_class = argparse.ArgumentDefaultsHelpFormatter
)
parser.add_argument('--location',
help = 'the location to download the compiler to',
default = os.path.join(tempfile.gettempdir(), 'mingw-builds'))
parser.add_argument('--arch', required = True, choices = ['i686', 'x86_64'],
help = 'the target MinGW architecture string')
parser.add_argument('--version', type = str2ver,
help = 'the version of GCC to download')
parser.add_argument('--threading', choices = ['posix', 'win32'],
help = 'the threading type of the compiler')
parser.add_argument('--exceptions', choices = ['sjlj', 'seh', 'dwarf'],
help = 'the method to throw exceptions')
parser.add_argument('--revision', type=int,
help = 'the revision of the MinGW release')
group = parser.add_mutually_exclusive_group()
group.add_argument('-v', '--verbose', action='store_true',
help='increase the script output verbosity')
group.add_argument('-q', '--quiet', action='store_true',
help='only print errors and warning')
args = parser.parse_args()
# Create the logger
logger = logging.getLogger('mingw')
handler = logging.StreamHandler()
formatter = logging.Formatter('%(message)s')
handler.setFormatter(formatter)
logger.addHandler(handler)
logger.setLevel(logging.INFO)
if args.quiet:
logger.setLevel(logging.WARN)
if args.verbose:
logger.setLevel(logging.DEBUG)
# Get MinGW
root_dir = root(location = args.location, arch = args.arch,
version = args.version, threading = args.threading,
exceptions = args.exceptions, revision = args.revision,
log = logger)
sys.stdout.write('%s\n' % os.path.join(root_dir, 'bin'))
if __name__ == '__main__':
try:
main()
except IOError as e:
sys.stderr.write('IO error: %s\n' % e)
sys.exit(1)
except OSError as e:
sys.stderr.write('OS error: %s\n' % e)
sys.exit(1)
except KeyboardInterrupt as e:
sys.stderr.write('Killed\n')
sys.exit(1)

View File

@@ -1,16 +0,0 @@
# How to release
* Make sure you're on master and synced to HEAD
* Ensure the project builds and tests run (sanity check only, obviously)
* `parallel -j0 exec ::: test/*_test` can help ensure everything at least
passes
* Prepare release notes
* `git log $(git describe --abbrev=0 --tags)..HEAD` gives you the list of
commits between the last annotated tag and HEAD
* Pick the most interesting.
* Create a release through github's interface
* Note this will create a lightweight tag.
* Update this to an annotated tag:
* `git pull --tags`
* `git tag -a -f <tag> <tag>`
* `git push --force origin`

View File

@@ -1,105 +0,0 @@
# Allow the source files to find headers in src/
include_directories(${PROJECT_SOURCE_DIR}/src)
if (DEFINED BENCHMARK_CXX_LINKER_FLAGS)
list(APPEND CMAKE_SHARED_LINKER_FLAGS ${BENCHMARK_CXX_LINKER_FLAGS})
list(APPEND CMAKE_MODULE_LINKER_FLAGS ${BENCHMARK_CXX_LINKER_FLAGS})
endif()
file(GLOB
SOURCE_FILES
*.cc
${PROJECT_SOURCE_DIR}/include/benchmark/*.h
${CMAKE_CURRENT_SOURCE_DIR}/*.h)
list(FILTER SOURCE_FILES EXCLUDE REGEX "benchmark_main\\.cc")
add_library(benchmark ${SOURCE_FILES})
set_target_properties(benchmark PROPERTIES
OUTPUT_NAME "benchmark"
VERSION ${GENERIC_LIB_VERSION}
SOVERSION ${GENERIC_LIB_SOVERSION}
)
target_include_directories(benchmark PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/../include>
)
# Link threads.
target_link_libraries(benchmark ${BENCHMARK_CXX_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT})
find_library(LIBRT rt)
if(LIBRT)
target_link_libraries(benchmark ${LIBRT})
endif()
# We need extra libraries on Windows
if(${CMAKE_SYSTEM_NAME} MATCHES "Windows")
target_link_libraries(benchmark Shlwapi)
endif()
# We need extra libraries on Solaris
if(${CMAKE_SYSTEM_NAME} MATCHES "SunOS")
target_link_libraries(benchmark kstat)
endif()
# Benchmark main library
add_library(benchmark_main "benchmark_main.cc")
set_target_properties(benchmark_main PROPERTIES
OUTPUT_NAME "benchmark_main"
VERSION ${GENERIC_LIB_VERSION}
SOVERSION ${GENERIC_LIB_SOVERSION}
)
target_include_directories(benchmark PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/../include>
)
target_link_libraries(benchmark_main benchmark)
set(include_install_dir "include")
set(lib_install_dir "lib/")
set(bin_install_dir "bin/")
set(config_install_dir "lib/cmake/${PROJECT_NAME}")
set(pkgconfig_install_dir "lib/pkgconfig")
set(generated_dir "${CMAKE_CURRENT_BINARY_DIR}/generated")
set(version_config "${generated_dir}/${PROJECT_NAME}ConfigVersion.cmake")
set(project_config "${generated_dir}/${PROJECT_NAME}Config.cmake")
set(pkg_config "${generated_dir}/${PROJECT_NAME}.pc")
set(targets_export_name "${PROJECT_NAME}Targets")
set(namespace "${PROJECT_NAME}::")
include(CMakePackageConfigHelpers)
write_basic_package_version_file(
"${version_config}" VERSION ${GIT_VERSION} COMPATIBILITY SameMajorVersion
)
configure_file("${PROJECT_SOURCE_DIR}/cmake/Config.cmake.in" "${project_config}" @ONLY)
configure_file("${PROJECT_SOURCE_DIR}/cmake/benchmark.pc.in" "${pkg_config}" @ONLY)
if (BENCHMARK_ENABLE_INSTALL)
# Install target (will install the library to specified CMAKE_INSTALL_PREFIX variable)
install(
TARGETS benchmark benchmark_main
EXPORT ${targets_export_name}
ARCHIVE DESTINATION ${lib_install_dir}
LIBRARY DESTINATION ${lib_install_dir}
RUNTIME DESTINATION ${bin_install_dir}
INCLUDES DESTINATION ${include_install_dir})
install(
DIRECTORY "${PROJECT_SOURCE_DIR}/include/benchmark"
DESTINATION ${include_install_dir}
FILES_MATCHING PATTERN "*.*h")
install(
FILES "${project_config}" "${version_config}"
DESTINATION "${config_install_dir}")
install(
FILES "${pkg_config}"
DESTINATION "${pkgconfig_install_dir}")
install(
EXPORT "${targets_export_name}"
NAMESPACE "${namespace}"
DESTINATION "${config_install_dir}")
endif()

View File

@@ -1,33 +0,0 @@
#ifndef BENCHMARK_ARRAYSIZE_H_
#define BENCHMARK_ARRAYSIZE_H_
#include "internal_macros.h"
namespace benchmark {
namespace internal {
// The arraysize(arr) macro returns the # of elements in an array arr.
// The expression is a compile-time constant, and therefore can be
// used in defining new arrays, for example. If you use arraysize on
// a pointer by mistake, you will get a compile-time error.
//
// This template function declaration is used in defining arraysize.
// Note that the function doesn't need an implementation, as we only
// use its type.
template <typename T, size_t N>
char (&ArraySizeHelper(T (&array)[N]))[N];
// That gcc wants both of these prototypes seems mysterious. VC, for
// its part, can't decide which to use (another mystery). Matching of
// template overloads: the final frontier.
#ifndef COMPILER_MSVC
template <typename T, size_t N>
char (&ArraySizeHelper(const T (&array)[N]))[N];
#endif
#define arraysize(array) (sizeof(::benchmark::internal::ArraySizeHelper(array)))
} // end namespace internal
} // end namespace benchmark
#endif // BENCHMARK_ARRAYSIZE_H_

View File

@@ -1,630 +0,0 @@
// Copyright 2015 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "benchmark/benchmark.h"
#include "benchmark_api_internal.h"
#include "internal_macros.h"
#ifndef BENCHMARK_OS_WINDOWS
#ifndef BENCHMARK_OS_FUCHSIA
#include <sys/resource.h>
#endif
#include <sys/time.h>
#include <unistd.h>
#endif
#include <algorithm>
#include <atomic>
#include <condition_variable>
#include <cstdio>
#include <cstdlib>
#include <fstream>
#include <iostream>
#include <memory>
#include <string>
#include <thread>
#include "check.h"
#include "colorprint.h"
#include "commandlineflags.h"
#include "complexity.h"
#include "counter.h"
#include "internal_macros.h"
#include "log.h"
#include "mutex.h"
#include "re.h"
#include "statistics.h"
#include "string_util.h"
#include "thread_manager.h"
#include "thread_timer.h"
DEFINE_bool(benchmark_list_tests, false,
"Print a list of benchmarks. This option overrides all other "
"options.");
DEFINE_string(benchmark_filter, ".",
"A regular expression that specifies the set of benchmarks "
"to execute. If this flag is empty, no benchmarks are run. "
"If this flag is the string \"all\", all benchmarks linked "
"into the process are run.");
DEFINE_double(benchmark_min_time, 0.5,
"Minimum number of seconds we should run benchmark before "
"results are considered significant. For cpu-time based "
"tests, this is the lower bound on the total cpu time "
"used by all threads that make up the test. For real-time "
"based tests, this is the lower bound on the elapsed time "
"of the benchmark execution, regardless of number of "
"threads.");
DEFINE_int32(benchmark_repetitions, 1,
"The number of runs of each benchmark. If greater than 1, the "
"mean and standard deviation of the runs will be reported.");
DEFINE_bool(benchmark_report_aggregates_only, false,
"Report the result of each benchmark repetitions. When 'true' is "
"specified only the mean, standard deviation, and other statistics "
"are reported for repeated benchmarks.");
DEFINE_string(benchmark_format, "console",
"The format to use for console output. Valid values are "
"'console', 'json', or 'csv'.");
DEFINE_string(benchmark_out_format, "json",
"The format to use for file output. Valid values are "
"'console', 'json', or 'csv'.");
DEFINE_string(benchmark_out, "", "The file to write additional output to");
DEFINE_string(benchmark_color, "auto",
"Whether to use colors in the output. Valid values: "
"'true'/'yes'/1, 'false'/'no'/0, and 'auto'. 'auto' means to use "
"colors if the output is being sent to a terminal and the TERM "
"environment variable is set to a terminal type that supports "
"colors.");
DEFINE_bool(benchmark_counters_tabular, false,
"Whether to use tabular format when printing user counters to "
"the console. Valid values: 'true'/'yes'/1, 'false'/'no'/0."
"Defaults to false.");
DEFINE_int32(v, 0, "The level of verbose logging to output");
namespace benchmark {
namespace {
static const size_t kMaxIterations = 1000000000;
} // end namespace
namespace internal {
void UseCharPointer(char const volatile*) {}
namespace {
BenchmarkReporter::Run CreateRunReport(
const benchmark::internal::Benchmark::Instance& b,
const internal::ThreadManager::Result& results,
double seconds) {
// Create report about this benchmark run.
BenchmarkReporter::Run report;
report.benchmark_name = b.name;
report.error_occurred = results.has_error_;
report.error_message = results.error_message_;
report.report_label = results.report_label_;
// This is the total iterations across all threads.
report.iterations = results.iterations;
report.time_unit = b.time_unit;
if (!report.error_occurred) {
double bytes_per_second = 0;
if (results.bytes_processed > 0 && seconds > 0.0) {
bytes_per_second = (results.bytes_processed / seconds);
}
double items_per_second = 0;
if (results.items_processed > 0 && seconds > 0.0) {
items_per_second = (results.items_processed / seconds);
}
if (b.use_manual_time) {
report.real_accumulated_time = results.manual_time_used;
} else {
report.real_accumulated_time = results.real_time_used;
}
report.cpu_accumulated_time = results.cpu_time_used;
report.bytes_per_second = bytes_per_second;
report.items_per_second = items_per_second;
report.complexity_n = results.complexity_n;
report.complexity = b.complexity;
report.complexity_lambda = b.complexity_lambda;
report.statistics = b.statistics;
report.counters = results.counters;
internal::Finish(&report.counters, seconds, b.threads);
}
return report;
}
// Execute one thread of benchmark b for the specified number of iterations.
// Adds the stats collected for the thread into *total.
void RunInThread(const benchmark::internal::Benchmark::Instance* b,
size_t iters, int thread_id,
internal::ThreadManager* manager) {
internal::ThreadTimer timer;
State st(iters, b->arg, thread_id, b->threads, &timer, manager);
b->benchmark->Run(st);
CHECK(st.iterations() >= st.max_iterations)
<< "Benchmark returned before State::KeepRunning() returned false!";
{
MutexLock l(manager->GetBenchmarkMutex());
internal::ThreadManager::Result& results = manager->results;
results.iterations += st.iterations();
results.cpu_time_used += timer.cpu_time_used();
results.real_time_used += timer.real_time_used();
results.manual_time_used += timer.manual_time_used();
results.bytes_processed += st.bytes_processed();
results.items_processed += st.items_processed();
results.complexity_n += st.complexity_length_n();
internal::Increment(&results.counters, st.counters);
}
manager->NotifyThreadComplete();
}
std::vector<BenchmarkReporter::Run> RunBenchmark(
const benchmark::internal::Benchmark::Instance& b,
std::vector<BenchmarkReporter::Run>* complexity_reports) {
std::vector<BenchmarkReporter::Run> reports; // return value
const bool has_explicit_iteration_count = b.iterations != 0;
size_t iters = has_explicit_iteration_count ? b.iterations : 1;
std::unique_ptr<internal::ThreadManager> manager;
std::vector<std::thread> pool(b.threads - 1);
const int repeats =
b.repetitions != 0 ? b.repetitions : FLAGS_benchmark_repetitions;
const bool report_aggregates_only =
repeats != 1 &&
(b.report_mode == internal::RM_Unspecified
? FLAGS_benchmark_report_aggregates_only
: b.report_mode == internal::RM_ReportAggregatesOnly);
for (int repetition_num = 0; repetition_num < repeats; repetition_num++) {
for (;;) {
// Try benchmark
VLOG(2) << "Running " << b.name << " for " << iters << "\n";
manager.reset(new internal::ThreadManager(b.threads));
for (std::size_t ti = 0; ti < pool.size(); ++ti) {
pool[ti] = std::thread(&RunInThread, &b, iters,
static_cast<int>(ti + 1), manager.get());
}
RunInThread(&b, iters, 0, manager.get());
manager->WaitForAllThreads();
for (std::thread& thread : pool) thread.join();
internal::ThreadManager::Result results;
{
MutexLock l(manager->GetBenchmarkMutex());
results = manager->results;
}
manager.reset();
// Adjust real/manual time stats since they were reported per thread.
results.real_time_used /= b.threads;
results.manual_time_used /= b.threads;
VLOG(2) << "Ran in " << results.cpu_time_used << "/"
<< results.real_time_used << "\n";
// Base decisions off of real time if requested by this benchmark.
double seconds = results.cpu_time_used;
if (b.use_manual_time) {
seconds = results.manual_time_used;
} else if (b.use_real_time) {
seconds = results.real_time_used;
}
const double min_time =
!IsZero(b.min_time) ? b.min_time : FLAGS_benchmark_min_time;
// Determine if this run should be reported; Either it has
// run for a sufficient amount of time or because an error was reported.
const bool should_report = repetition_num > 0
|| has_explicit_iteration_count // An exact iteration count was requested
|| results.has_error_
|| iters >= kMaxIterations // No chance to try again, we hit the limit.
|| seconds >= min_time // the elapsed time is large enough
// CPU time is specified but the elapsed real time greatly exceeds the
// minimum time. Note that user provided timers are except from this
// sanity check.
|| ((results.real_time_used >= 5 * min_time) && !b.use_manual_time);
if (should_report) {
BenchmarkReporter::Run report = CreateRunReport(b, results, seconds);
if (!report.error_occurred && b.complexity != oNone)
complexity_reports->push_back(report);
reports.push_back(report);
break;
}
// See how much iterations should be increased by
// Note: Avoid division by zero with max(seconds, 1ns).
double multiplier = min_time * 1.4 / std::max(seconds, 1e-9);
// If our last run was at least 10% of FLAGS_benchmark_min_time then we
// use the multiplier directly. Otherwise we use at most 10 times
// expansion.
// NOTE: When the last run was at least 10% of the min time the max
// expansion should be 14x.
bool is_significant = (seconds / min_time) > 0.1;
multiplier = is_significant ? multiplier : std::min(10.0, multiplier);
if (multiplier <= 1.0) multiplier = 2.0;
double next_iters = std::max(multiplier * iters, iters + 1.0);
if (next_iters > kMaxIterations) {
next_iters = kMaxIterations;
}
VLOG(3) << "Next iters: " << next_iters << ", " << multiplier << "\n";
iters = static_cast<int>(next_iters + 0.5);
}
}
// Calculate additional statistics
auto stat_reports = ComputeStats(reports);
if ((b.complexity != oNone) && b.last_benchmark_instance) {
auto additional_run_stats = ComputeBigO(*complexity_reports);
stat_reports.insert(stat_reports.end(), additional_run_stats.begin(),
additional_run_stats.end());
complexity_reports->clear();
}
if (report_aggregates_only) reports.clear();
reports.insert(reports.end(), stat_reports.begin(), stat_reports.end());
return reports;
}
} // namespace
} // namespace internal
State::State(size_t max_iters, const std::vector<int64_t>& ranges, int thread_i,
int n_threads, internal::ThreadTimer* timer,
internal::ThreadManager* manager)
: total_iterations_(0),
batch_leftover_(0),
max_iterations(max_iters),
started_(false),
finished_(false),
error_occurred_(false),
range_(ranges),
bytes_processed_(0),
items_processed_(0),
complexity_n_(0),
counters(),
thread_index(thread_i),
threads(n_threads),
timer_(timer),
manager_(manager) {
CHECK(max_iterations != 0) << "At least one iteration must be run";
CHECK_LT(thread_index, threads) << "thread_index must be less than threads";
// Note: The use of offsetof below is technically undefined until C++17
// because State is not a standard layout type. However, all compilers
// currently provide well-defined behavior as an extension (which is
// demonstrated since constexpr evaluation must diagnose all undefined
// behavior). However, GCC and Clang also warn about this use of offsetof,
// which must be suppressed.
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Winvalid-offsetof"
#endif
// Offset tests to ensure commonly accessed data is on the first cache line.
const int cache_line_size = 64;
static_assert(offsetof(State, error_occurred_) <=
(cache_line_size - sizeof(error_occurred_)), "");
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
}
void State::PauseTiming() {
// Add in time accumulated so far
CHECK(started_ && !finished_ && !error_occurred_);
timer_->StopTimer();
}
void State::ResumeTiming() {
CHECK(started_ && !finished_ && !error_occurred_);
timer_->StartTimer();
}
void State::SkipWithError(const char* msg) {
CHECK(msg);
error_occurred_ = true;
{
MutexLock l(manager_->GetBenchmarkMutex());
if (manager_->results.has_error_ == false) {
manager_->results.error_message_ = msg;
manager_->results.has_error_ = true;
}
}
total_iterations_ = 0;
if (timer_->running()) timer_->StopTimer();
}
void State::SetIterationTime(double seconds) {
timer_->SetIterationTime(seconds);
}
void State::SetLabel(const char* label) {
MutexLock l(manager_->GetBenchmarkMutex());
manager_->results.report_label_ = label;
}
void State::StartKeepRunning() {
CHECK(!started_ && !finished_);
started_ = true;
total_iterations_ = error_occurred_ ? 0 : max_iterations;
manager_->StartStopBarrier();
if (!error_occurred_) ResumeTiming();
}
void State::FinishKeepRunning() {
CHECK(started_ && (!finished_ || error_occurred_));
if (!error_occurred_) {
PauseTiming();
}
// Total iterations has now wrapped around past 0. Fix this.
total_iterations_ = 0;
finished_ = true;
manager_->StartStopBarrier();
}
namespace internal {
namespace {
void RunBenchmarks(const std::vector<Benchmark::Instance>& benchmarks,
BenchmarkReporter* console_reporter,
BenchmarkReporter* file_reporter) {
// Note the file_reporter can be null.
CHECK(console_reporter != nullptr);
// Determine the width of the name field using a minimum width of 10.
bool has_repetitions = FLAGS_benchmark_repetitions > 1;
size_t name_field_width = 10;
size_t stat_field_width = 0;
for (const Benchmark::Instance& benchmark : benchmarks) {
name_field_width =
std::max<size_t>(name_field_width, benchmark.name.size());
has_repetitions |= benchmark.repetitions > 1;
for(const auto& Stat : *benchmark.statistics)
stat_field_width = std::max<size_t>(stat_field_width, Stat.name_.size());
}
if (has_repetitions) name_field_width += 1 + stat_field_width;
// Print header here
BenchmarkReporter::Context context;
context.name_field_width = name_field_width;
// Keep track of running times of all instances of current benchmark
std::vector<BenchmarkReporter::Run> complexity_reports;
// We flush streams after invoking reporter methods that write to them. This
// ensures users get timely updates even when streams are not line-buffered.
auto flushStreams = [](BenchmarkReporter* reporter) {
if (!reporter) return;
std::flush(reporter->GetOutputStream());
std::flush(reporter->GetErrorStream());
};
if (console_reporter->ReportContext(context) &&
(!file_reporter || file_reporter->ReportContext(context))) {
flushStreams(console_reporter);
flushStreams(file_reporter);
for (const auto& benchmark : benchmarks) {
std::vector<BenchmarkReporter::Run> reports =
RunBenchmark(benchmark, &complexity_reports);
console_reporter->ReportRuns(reports);
if (file_reporter) file_reporter->ReportRuns(reports);
flushStreams(console_reporter);
flushStreams(file_reporter);
}
}
console_reporter->Finalize();
if (file_reporter) file_reporter->Finalize();
flushStreams(console_reporter);
flushStreams(file_reporter);
}
std::unique_ptr<BenchmarkReporter> CreateReporter(
std::string const& name, ConsoleReporter::OutputOptions output_opts) {
typedef std::unique_ptr<BenchmarkReporter> PtrType;
if (name == "console") {
return PtrType(new ConsoleReporter(output_opts));
} else if (name == "json") {
return PtrType(new JSONReporter);
} else if (name == "csv") {
return PtrType(new CSVReporter);
} else {
std::cerr << "Unexpected format: '" << name << "'\n";
std::exit(1);
}
}
} // end namespace
bool IsZero(double n) {
return std::abs(n) < std::numeric_limits<double>::epsilon();
}
ConsoleReporter::OutputOptions GetOutputOptions(bool force_no_color) {
int output_opts = ConsoleReporter::OO_Defaults;
if ((FLAGS_benchmark_color == "auto" && IsColorTerminal()) ||
IsTruthyFlagValue(FLAGS_benchmark_color)) {
output_opts |= ConsoleReporter::OO_Color;
} else {
output_opts &= ~ConsoleReporter::OO_Color;
}
if(force_no_color) {
output_opts &= ~ConsoleReporter::OO_Color;
}
if(FLAGS_benchmark_counters_tabular) {
output_opts |= ConsoleReporter::OO_Tabular;
} else {
output_opts &= ~ConsoleReporter::OO_Tabular;
}
return static_cast< ConsoleReporter::OutputOptions >(output_opts);
}
} // end namespace internal
size_t RunSpecifiedBenchmarks() {
return RunSpecifiedBenchmarks(nullptr, nullptr);
}
size_t RunSpecifiedBenchmarks(BenchmarkReporter* console_reporter) {
return RunSpecifiedBenchmarks(console_reporter, nullptr);
}
size_t RunSpecifiedBenchmarks(BenchmarkReporter* console_reporter,
BenchmarkReporter* file_reporter) {
std::string spec = FLAGS_benchmark_filter;
if (spec.empty() || spec == "all")
spec = "."; // Regexp that matches all benchmarks
// Setup the reporters
std::ofstream output_file;
std::unique_ptr<BenchmarkReporter> default_console_reporter;
std::unique_ptr<BenchmarkReporter> default_file_reporter;
if (!console_reporter) {
default_console_reporter = internal::CreateReporter(
FLAGS_benchmark_format, internal::GetOutputOptions());
console_reporter = default_console_reporter.get();
}
auto& Out = console_reporter->GetOutputStream();
auto& Err = console_reporter->GetErrorStream();
std::string const& fname = FLAGS_benchmark_out;
if (fname.empty() && file_reporter) {
Err << "A custom file reporter was provided but "
"--benchmark_out=<file> was not specified."
<< std::endl;
std::exit(1);
}
if (!fname.empty()) {
output_file.open(fname);
if (!output_file.is_open()) {
Err << "invalid file name: '" << fname << std::endl;
std::exit(1);
}
if (!file_reporter) {
default_file_reporter = internal::CreateReporter(
FLAGS_benchmark_out_format, ConsoleReporter::OO_None);
file_reporter = default_file_reporter.get();
}
file_reporter->SetOutputStream(&output_file);
file_reporter->SetErrorStream(&output_file);
}
std::vector<internal::Benchmark::Instance> benchmarks;
if (!FindBenchmarksInternal(spec, &benchmarks, &Err)) return 0;
if (benchmarks.empty()) {
Err << "Failed to match any benchmarks against regex: " << spec << "\n";
return 0;
}
if (FLAGS_benchmark_list_tests) {
for (auto const& benchmark : benchmarks) Out << benchmark.name << "\n";
} else {
internal::RunBenchmarks(benchmarks, console_reporter, file_reporter);
}
return benchmarks.size();
}
namespace internal {
void PrintUsageAndExit() {
fprintf(stdout,
"benchmark"
" [--benchmark_list_tests={true|false}]\n"
" [--benchmark_filter=<regex>]\n"
" [--benchmark_min_time=<min_time>]\n"
" [--benchmark_repetitions=<num_repetitions>]\n"
" [--benchmark_report_aggregates_only={true|false}\n"
" [--benchmark_format=<console|json|csv>]\n"
" [--benchmark_out=<filename>]\n"
" [--benchmark_out_format=<json|console|csv>]\n"
" [--benchmark_color={auto|true|false}]\n"
" [--benchmark_counters_tabular={true|false}]\n"
" [--v=<verbosity>]\n");
exit(0);
}
void ParseCommandLineFlags(int* argc, char** argv) {
using namespace benchmark;
BenchmarkReporter::Context::executable_name = argv[0];
for (int i = 1; i < *argc; ++i) {
if (ParseBoolFlag(argv[i], "benchmark_list_tests",
&FLAGS_benchmark_list_tests) ||
ParseStringFlag(argv[i], "benchmark_filter", &FLAGS_benchmark_filter) ||
ParseDoubleFlag(argv[i], "benchmark_min_time",
&FLAGS_benchmark_min_time) ||
ParseInt32Flag(argv[i], "benchmark_repetitions",
&FLAGS_benchmark_repetitions) ||
ParseBoolFlag(argv[i], "benchmark_report_aggregates_only",
&FLAGS_benchmark_report_aggregates_only) ||
ParseStringFlag(argv[i], "benchmark_format", &FLAGS_benchmark_format) ||
ParseStringFlag(argv[i], "benchmark_out", &FLAGS_benchmark_out) ||
ParseStringFlag(argv[i], "benchmark_out_format",
&FLAGS_benchmark_out_format) ||
ParseStringFlag(argv[i], "benchmark_color", &FLAGS_benchmark_color) ||
// "color_print" is the deprecated name for "benchmark_color".
// TODO: Remove this.
ParseStringFlag(argv[i], "color_print", &FLAGS_benchmark_color) ||
ParseBoolFlag(argv[i], "benchmark_counters_tabular",
&FLAGS_benchmark_counters_tabular) ||
ParseInt32Flag(argv[i], "v", &FLAGS_v)) {
for (int j = i; j != *argc - 1; ++j) argv[j] = argv[j + 1];
--(*argc);
--i;
} else if (IsFlag(argv[i], "help")) {
PrintUsageAndExit();
}
}
for (auto const* flag :
{&FLAGS_benchmark_format, &FLAGS_benchmark_out_format})
if (*flag != "console" && *flag != "json" && *flag != "csv") {
PrintUsageAndExit();
}
if (FLAGS_benchmark_color.empty()) {
PrintUsageAndExit();
}
}
int InitializeStreams() {
static std::ios_base::Init init;
return 0;
}
} // end namespace internal
void Initialize(int* argc, char** argv) {
internal::ParseCommandLineFlags(argc, argv);
internal::LogLevel() = FLAGS_v;
}
bool ReportUnrecognizedArguments(int argc, char** argv) {
for (int i = 1; i < argc; ++i) {
fprintf(stderr, "%s: error: unrecognized command-line flag: %s\n", argv[0], argv[i]);
}
return argc > 1;
}
} // end namespace benchmark

View File

@@ -1,47 +0,0 @@
#ifndef BENCHMARK_API_INTERNAL_H
#define BENCHMARK_API_INTERNAL_H
#include "benchmark/benchmark.h"
#include <cmath>
#include <iosfwd>
#include <limits>
#include <string>
#include <vector>
namespace benchmark {
namespace internal {
// Information kept per benchmark we may want to run
struct Benchmark::Instance {
std::string name;
Benchmark* benchmark;
ReportMode report_mode;
std::vector<int64_t> arg;
TimeUnit time_unit;
int range_multiplier;
bool use_real_time;
bool use_manual_time;
BigO complexity;
BigOFunc* complexity_lambda;
UserCounters counters;
const std::vector<Statistics>* statistics;
bool last_benchmark_instance;
int repetitions;
double min_time;
size_t iterations;
int threads; // Number of concurrent threads to us
};
bool FindBenchmarksInternal(const std::string& re,
std::vector<Benchmark::Instance>* benchmarks,
std::ostream* Err);
bool IsZero(double n);
ConsoleReporter::OutputOptions GetOutputOptions(bool force_no_color = false);
} // end namespace internal
} // end namespace benchmark
#endif // BENCHMARK_API_INTERNAL_H

View File

@@ -1,17 +0,0 @@
// Copyright 2018 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "benchmark/benchmark.h"
BENCHMARK_MAIN();

View File

@@ -1,461 +0,0 @@
// Copyright 2015 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "benchmark_register.h"
#ifndef BENCHMARK_OS_WINDOWS
#ifndef BENCHMARK_OS_FUCHSIA
#include <sys/resource.h>
#endif
#include <sys/time.h>
#include <unistd.h>
#endif
#include <algorithm>
#include <atomic>
#include <condition_variable>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <fstream>
#include <iostream>
#include <memory>
#include <sstream>
#include <thread>
#include "benchmark/benchmark.h"
#include "benchmark_api_internal.h"
#include "check.h"
#include "commandlineflags.h"
#include "complexity.h"
#include "internal_macros.h"
#include "log.h"
#include "mutex.h"
#include "re.h"
#include "statistics.h"
#include "string_util.h"
#include "timers.h"
namespace benchmark {
namespace {
// For non-dense Range, intermediate values are powers of kRangeMultiplier.
static const int kRangeMultiplier = 8;
// The size of a benchmark family determines is the number of inputs to repeat
// the benchmark on. If this is "large" then warn the user during configuration.
static const size_t kMaxFamilySize = 100;
} // end namespace
namespace internal {
//=============================================================================//
// BenchmarkFamilies
//=============================================================================//
// Class for managing registered benchmarks. Note that each registered
// benchmark identifies a family of related benchmarks to run.
class BenchmarkFamilies {
public:
static BenchmarkFamilies* GetInstance();
// Registers a benchmark family and returns the index assigned to it.
size_t AddBenchmark(std::unique_ptr<Benchmark> family);
// Clear all registered benchmark families.
void ClearBenchmarks();
// Extract the list of benchmark instances that match the specified
// regular expression.
bool FindBenchmarks(std::string re,
std::vector<Benchmark::Instance>* benchmarks,
std::ostream* Err);
private:
BenchmarkFamilies() {}
std::vector<std::unique_ptr<Benchmark>> families_;
Mutex mutex_;
};
BenchmarkFamilies* BenchmarkFamilies::GetInstance() {
static BenchmarkFamilies instance;
return &instance;
}
size_t BenchmarkFamilies::AddBenchmark(std::unique_ptr<Benchmark> family) {
MutexLock l(mutex_);
size_t index = families_.size();
families_.push_back(std::move(family));
return index;
}
void BenchmarkFamilies::ClearBenchmarks() {
MutexLock l(mutex_);
families_.clear();
families_.shrink_to_fit();
}
bool BenchmarkFamilies::FindBenchmarks(
std::string spec, std::vector<Benchmark::Instance>* benchmarks,
std::ostream* ErrStream) {
CHECK(ErrStream);
auto& Err = *ErrStream;
// Make regular expression out of command-line flag
std::string error_msg;
Regex re;
bool isNegativeFilter = false;
if(spec[0] == '-') {
spec.replace(0, 1, "");
isNegativeFilter = true;
}
if (!re.Init(spec, &error_msg)) {
Err << "Could not compile benchmark re: " << error_msg << std::endl;
return false;
}
// Special list of thread counts to use when none are specified
const std::vector<int> one_thread = {1};
MutexLock l(mutex_);
for (std::unique_ptr<Benchmark>& family : families_) {
// Family was deleted or benchmark doesn't match
if (!family) continue;
if (family->ArgsCnt() == -1) {
family->Args({});
}
const std::vector<int>* thread_counts =
(family->thread_counts_.empty()
? &one_thread
: &static_cast<const std::vector<int>&>(family->thread_counts_));
const size_t family_size = family->args_.size() * thread_counts->size();
// The benchmark will be run at least 'family_size' different inputs.
// If 'family_size' is very large warn the user.
if (family_size > kMaxFamilySize) {
Err << "The number of inputs is very large. " << family->name_
<< " will be repeated at least " << family_size << " times.\n";
}
// reserve in the special case the regex ".", since we know the final
// family size.
if (spec == ".") benchmarks->reserve(family_size);
for (auto const& args : family->args_) {
for (int num_threads : *thread_counts) {
Benchmark::Instance instance;
instance.name = family->name_;
instance.benchmark = family.get();
instance.report_mode = family->report_mode_;
instance.arg = args;
instance.time_unit = family->time_unit_;
instance.range_multiplier = family->range_multiplier_;
instance.min_time = family->min_time_;
instance.iterations = family->iterations_;
instance.repetitions = family->repetitions_;
instance.use_real_time = family->use_real_time_;
instance.use_manual_time = family->use_manual_time_;
instance.complexity = family->complexity_;
instance.complexity_lambda = family->complexity_lambda_;
instance.statistics = &family->statistics_;
instance.threads = num_threads;
// Add arguments to instance name
size_t arg_i = 0;
for (auto const& arg : args) {
instance.name += "/";
if (arg_i < family->arg_names_.size()) {
const auto& arg_name = family->arg_names_[arg_i];
if (!arg_name.empty()) {
instance.name +=
StrFormat("%s:", family->arg_names_[arg_i].c_str());
}
}
instance.name += StrFormat("%d", arg);
++arg_i;
}
if (!IsZero(family->min_time_))
instance.name += StrFormat("/min_time:%0.3f", family->min_time_);
if (family->iterations_ != 0)
instance.name += StrFormat("/iterations:%d", family->iterations_);
if (family->repetitions_ != 0)
instance.name += StrFormat("/repeats:%d", family->repetitions_);
if (family->use_manual_time_) {
instance.name += "/manual_time";
} else if (family->use_real_time_) {
instance.name += "/real_time";
}
// Add the number of threads used to the name
if (!family->thread_counts_.empty()) {
instance.name += StrFormat("/threads:%d", instance.threads);
}
if ((re.Match(instance.name) && !isNegativeFilter) ||
(!re.Match(instance.name) && isNegativeFilter)) {
instance.last_benchmark_instance = (&args == &family->args_.back());
benchmarks->push_back(std::move(instance));
}
}
}
}
return true;
}
Benchmark* RegisterBenchmarkInternal(Benchmark* bench) {
std::unique_ptr<Benchmark> bench_ptr(bench);
BenchmarkFamilies* families = BenchmarkFamilies::GetInstance();
families->AddBenchmark(std::move(bench_ptr));
return bench;
}
// FIXME: This function is a hack so that benchmark.cc can access
// `BenchmarkFamilies`
bool FindBenchmarksInternal(const std::string& re,
std::vector<Benchmark::Instance>* benchmarks,
std::ostream* Err) {
return BenchmarkFamilies::GetInstance()->FindBenchmarks(re, benchmarks, Err);
}
//=============================================================================//
// Benchmark
//=============================================================================//
Benchmark::Benchmark(const char* name)
: name_(name),
report_mode_(RM_Unspecified),
time_unit_(kNanosecond),
range_multiplier_(kRangeMultiplier),
min_time_(0),
iterations_(0),
repetitions_(0),
use_real_time_(false),
use_manual_time_(false),
complexity_(oNone),
complexity_lambda_(nullptr) {
ComputeStatistics("mean", StatisticsMean);
ComputeStatistics("median", StatisticsMedian);
ComputeStatistics("stddev", StatisticsStdDev);
}
Benchmark::~Benchmark() {}
Benchmark* Benchmark::Arg(int64_t x) {
CHECK(ArgsCnt() == -1 || ArgsCnt() == 1);
args_.push_back({x});
return this;
}
Benchmark* Benchmark::Unit(TimeUnit unit) {
time_unit_ = unit;
return this;
}
Benchmark* Benchmark::Range(int64_t start, int64_t limit) {
CHECK(ArgsCnt() == -1 || ArgsCnt() == 1);
std::vector<int64_t> arglist;
AddRange(&arglist, start, limit, range_multiplier_);
for (int64_t i : arglist) {
args_.push_back({i});
}
return this;
}
Benchmark* Benchmark::Ranges(
const std::vector<std::pair<int64_t, int64_t>>& ranges) {
CHECK(ArgsCnt() == -1 || ArgsCnt() == static_cast<int>(ranges.size()));
std::vector<std::vector<int64_t>> arglists(ranges.size());
std::size_t total = 1;
for (std::size_t i = 0; i < ranges.size(); i++) {
AddRange(&arglists[i], ranges[i].first, ranges[i].second,
range_multiplier_);
total *= arglists[i].size();
}
std::vector<std::size_t> ctr(arglists.size(), 0);
for (std::size_t i = 0; i < total; i++) {
std::vector<int64_t> tmp;
tmp.reserve(arglists.size());
for (std::size_t j = 0; j < arglists.size(); j++) {
tmp.push_back(arglists[j].at(ctr[j]));
}
args_.push_back(std::move(tmp));
for (std::size_t j = 0; j < arglists.size(); j++) {
if (ctr[j] + 1 < arglists[j].size()) {
++ctr[j];
break;
}
ctr[j] = 0;
}
}
return this;
}
Benchmark* Benchmark::ArgName(const std::string& name) {
CHECK(ArgsCnt() == -1 || ArgsCnt() == 1);
arg_names_ = {name};
return this;
}
Benchmark* Benchmark::ArgNames(const std::vector<std::string>& names) {
CHECK(ArgsCnt() == -1 || ArgsCnt() == static_cast<int>(names.size()));
arg_names_ = names;
return this;
}
Benchmark* Benchmark::DenseRange(int64_t start, int64_t limit, int step) {
CHECK(ArgsCnt() == -1 || ArgsCnt() == 1);
CHECK_GE(start, 0);
CHECK_LE(start, limit);
for (int64_t arg = start; arg <= limit; arg += step) {
args_.push_back({arg});
}
return this;
}
Benchmark* Benchmark::Args(const std::vector<int64_t>& args) {
CHECK(ArgsCnt() == -1 || ArgsCnt() == static_cast<int>(args.size()));
args_.push_back(args);
return this;
}
Benchmark* Benchmark::Apply(void (*custom_arguments)(Benchmark* benchmark)) {
custom_arguments(this);
return this;
}
Benchmark* Benchmark::RangeMultiplier(int multiplier) {
CHECK(multiplier > 1);
range_multiplier_ = multiplier;
return this;
}
Benchmark* Benchmark::MinTime(double t) {
CHECK(t > 0.0);
CHECK(iterations_ == 0);
min_time_ = t;
return this;
}
Benchmark* Benchmark::Iterations(size_t n) {
CHECK(n > 0);
CHECK(IsZero(min_time_));
iterations_ = n;
return this;
}
Benchmark* Benchmark::Repetitions(int n) {
CHECK(n > 0);
repetitions_ = n;
return this;
}
Benchmark* Benchmark::ReportAggregatesOnly(bool value) {
report_mode_ = value ? RM_ReportAggregatesOnly : RM_Default;
return this;
}
Benchmark* Benchmark::UseRealTime() {
CHECK(!use_manual_time_)
<< "Cannot set UseRealTime and UseManualTime simultaneously.";
use_real_time_ = true;
return this;
}
Benchmark* Benchmark::UseManualTime() {
CHECK(!use_real_time_)
<< "Cannot set UseRealTime and UseManualTime simultaneously.";
use_manual_time_ = true;
return this;
}
Benchmark* Benchmark::Complexity(BigO complexity) {
complexity_ = complexity;
return this;
}
Benchmark* Benchmark::Complexity(BigOFunc* complexity) {
complexity_lambda_ = complexity;
complexity_ = oLambda;
return this;
}
Benchmark* Benchmark::ComputeStatistics(std::string name,
StatisticsFunc* statistics) {
statistics_.emplace_back(name, statistics);
return this;
}
Benchmark* Benchmark::Threads(int t) {
CHECK_GT(t, 0);
thread_counts_.push_back(t);
return this;
}
Benchmark* Benchmark::ThreadRange(int min_threads, int max_threads) {
CHECK_GT(min_threads, 0);
CHECK_GE(max_threads, min_threads);
AddRange(&thread_counts_, min_threads, max_threads, 2);
return this;
}
Benchmark* Benchmark::DenseThreadRange(int min_threads, int max_threads,
int stride) {
CHECK_GT(min_threads, 0);
CHECK_GE(max_threads, min_threads);
CHECK_GE(stride, 1);
for (auto i = min_threads; i < max_threads; i += stride) {
thread_counts_.push_back(i);
}
thread_counts_.push_back(max_threads);
return this;
}
Benchmark* Benchmark::ThreadPerCpu() {
thread_counts_.push_back(CPUInfo::Get().num_cpus);
return this;
}
void Benchmark::SetName(const char* name) { name_ = name; }
int Benchmark::ArgsCnt() const {
if (args_.empty()) {
if (arg_names_.empty()) return -1;
return static_cast<int>(arg_names_.size());
}
return static_cast<int>(args_.front().size());
}
//=============================================================================//
// FunctionBenchmark
//=============================================================================//
void FunctionBenchmark::Run(State& st) { func_(st); }
} // end namespace internal
void ClearRegisteredBenchmarks() {
internal::BenchmarkFamilies::GetInstance()->ClearBenchmarks();
}
} // end namespace benchmark

View File

@@ -1,33 +0,0 @@
#ifndef BENCHMARK_REGISTER_H
#define BENCHMARK_REGISTER_H
#include <vector>
#include "check.h"
template <typename T>
void AddRange(std::vector<T>* dst, T lo, T hi, int mult) {
CHECK_GE(lo, 0);
CHECK_GE(hi, lo);
CHECK_GE(mult, 2);
// Add "lo"
dst->push_back(lo);
static const T kmax = std::numeric_limits<T>::max();
// Now space out the benchmarks in multiples of "mult"
for (T i = 1; i < kmax / mult; i *= mult) {
if (i >= hi) break;
if (i > lo) {
dst->push_back(i);
}
}
// Add "hi" (if different from "lo")
if (hi != lo) {
dst->push_back(hi);
}
}
#endif // BENCHMARK_REGISTER_H

View File

@@ -1,79 +0,0 @@
#ifndef CHECK_H_
#define CHECK_H_
#include <cstdlib>
#include <ostream>
#include <cmath>
#include "internal_macros.h"
#include "log.h"
namespace benchmark {
namespace internal {
typedef void(AbortHandlerT)();
inline AbortHandlerT*& GetAbortHandler() {
static AbortHandlerT* handler = &std::abort;
return handler;
}
BENCHMARK_NORETURN inline void CallAbortHandler() {
GetAbortHandler()();
std::abort(); // fallback to enforce noreturn
}
// CheckHandler is the class constructed by failing CHECK macros. CheckHandler
// will log information about the failures and abort when it is destructed.
class CheckHandler {
public:
CheckHandler(const char* check, const char* file, const char* func, int line)
: log_(GetErrorLogInstance()) {
log_ << file << ":" << line << ": " << func << ": Check `" << check
<< "' failed. ";
}
LogType& GetLog() { return log_; }
BENCHMARK_NORETURN ~CheckHandler() BENCHMARK_NOEXCEPT_OP(false) {
log_ << std::endl;
CallAbortHandler();
}
CheckHandler& operator=(const CheckHandler&) = delete;
CheckHandler(const CheckHandler&) = delete;
CheckHandler() = delete;
private:
LogType& log_;
};
} // end namespace internal
} // end namespace benchmark
// The CHECK macro returns a std::ostream object that can have extra information
// written to it.
#ifndef NDEBUG
#define CHECK(b) \
(b ? ::benchmark::internal::GetNullLogInstance() \
: ::benchmark::internal::CheckHandler(#b, __FILE__, __func__, __LINE__) \
.GetLog())
#else
#define CHECK(b) ::benchmark::internal::GetNullLogInstance()
#endif
#define CHECK_EQ(a, b) CHECK((a) == (b))
#define CHECK_NE(a, b) CHECK((a) != (b))
#define CHECK_GE(a, b) CHECK((a) >= (b))
#define CHECK_LE(a, b) CHECK((a) <= (b))
#define CHECK_GT(a, b) CHECK((a) > (b))
#define CHECK_LT(a, b) CHECK((a) < (b))
#define CHECK_FLOAT_EQ(a, b, eps) CHECK(std::fabs((a) - (b)) < (eps))
#define CHECK_FLOAT_NE(a, b, eps) CHECK(std::fabs((a) - (b)) >= (eps))
#define CHECK_FLOAT_GE(a, b, eps) CHECK((a) - (b) > -(eps))
#define CHECK_FLOAT_LE(a, b, eps) CHECK((b) - (a) > -(eps))
#define CHECK_FLOAT_GT(a, b, eps) CHECK((a) - (b) > (eps))
#define CHECK_FLOAT_LT(a, b, eps) CHECK((b) - (a) > (eps))
#endif // CHECK_H_

View File

@@ -1,188 +0,0 @@
// Copyright 2015 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "colorprint.h"
#include <cstdarg>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <memory>
#include <string>
#include "check.h"
#include "internal_macros.h"
#ifdef BENCHMARK_OS_WINDOWS
#include <Windows.h>
#include <io.h>
#else
#include <unistd.h>
#endif // BENCHMARK_OS_WINDOWS
namespace benchmark {
namespace {
#ifdef BENCHMARK_OS_WINDOWS
typedef WORD PlatformColorCode;
#else
typedef const char* PlatformColorCode;
#endif
PlatformColorCode GetPlatformColorCode(LogColor color) {
#ifdef BENCHMARK_OS_WINDOWS
switch (color) {
case COLOR_RED:
return FOREGROUND_RED;
case COLOR_GREEN:
return FOREGROUND_GREEN;
case COLOR_YELLOW:
return FOREGROUND_RED | FOREGROUND_GREEN;
case COLOR_BLUE:
return FOREGROUND_BLUE;
case COLOR_MAGENTA:
return FOREGROUND_BLUE | FOREGROUND_RED;
case COLOR_CYAN:
return FOREGROUND_BLUE | FOREGROUND_GREEN;
case COLOR_WHITE: // fall through to default
default:
return 0;
}
#else
switch (color) {
case COLOR_RED:
return "1";
case COLOR_GREEN:
return "2";
case COLOR_YELLOW:
return "3";
case COLOR_BLUE:
return "4";
case COLOR_MAGENTA:
return "5";
case COLOR_CYAN:
return "6";
case COLOR_WHITE:
return "7";
default:
return nullptr;
};
#endif
}
} // end namespace
std::string FormatString(const char* msg, va_list args) {
// we might need a second shot at this, so pre-emptivly make a copy
va_list args_cp;
va_copy(args_cp, args);
std::size_t size = 256;
char local_buff[256];
auto ret = vsnprintf(local_buff, size, msg, args_cp);
va_end(args_cp);
// currently there is no error handling for failure, so this is hack.
CHECK(ret >= 0);
if (ret == 0) // handle empty expansion
return {};
else if (static_cast<size_t>(ret) < size)
return local_buff;
else {
// we did not provide a long enough buffer on our first attempt.
size = (size_t)ret + 1; // + 1 for the null byte
std::unique_ptr<char[]> buff(new char[size]);
ret = vsnprintf(buff.get(), size, msg, args);
CHECK(ret > 0 && ((size_t)ret) < size);
return buff.get();
}
}
std::string FormatString(const char* msg, ...) {
va_list args;
va_start(args, msg);
auto tmp = FormatString(msg, args);
va_end(args);
return tmp;
}
void ColorPrintf(std::ostream& out, LogColor color, const char* fmt, ...) {
va_list args;
va_start(args, fmt);
ColorPrintf(out, color, fmt, args);
va_end(args);
}
void ColorPrintf(std::ostream& out, LogColor color, const char* fmt,
va_list args) {
#ifdef BENCHMARK_OS_WINDOWS
((void)out); // suppress unused warning
const HANDLE stdout_handle = GetStdHandle(STD_OUTPUT_HANDLE);
// Gets the current text color.
CONSOLE_SCREEN_BUFFER_INFO buffer_info;
GetConsoleScreenBufferInfo(stdout_handle, &buffer_info);
const WORD old_color_attrs = buffer_info.wAttributes;
// We need to flush the stream buffers into the console before each
// SetConsoleTextAttribute call lest it affect the text that is already
// printed but has not yet reached the console.
fflush(stdout);
SetConsoleTextAttribute(stdout_handle,
GetPlatformColorCode(color) | FOREGROUND_INTENSITY);
vprintf(fmt, args);
fflush(stdout);
// Restores the text color.
SetConsoleTextAttribute(stdout_handle, old_color_attrs);
#else
const char* color_code = GetPlatformColorCode(color);
if (color_code) out << FormatString("\033[0;3%sm", color_code);
out << FormatString(fmt, args) << "\033[m";
#endif
}
bool IsColorTerminal() {
#if BENCHMARK_OS_WINDOWS
// On Windows the TERM variable is usually not set, but the
// console there does support colors.
return 0 != _isatty(_fileno(stdout));
#else
// On non-Windows platforms, we rely on the TERM variable. This list of
// supported TERM values is copied from Google Test:
// <https://github.com/google/googletest/blob/master/googletest/src/gtest.cc#L2925>.
const char* const SUPPORTED_TERM_VALUES[] = {
"xterm", "xterm-color", "xterm-256color",
"screen", "screen-256color", "tmux",
"tmux-256color", "rxvt-unicode", "rxvt-unicode-256color",
"linux", "cygwin",
};
const char* const term = getenv("TERM");
bool term_supports_color = false;
for (const char* candidate : SUPPORTED_TERM_VALUES) {
if (term && 0 == strcmp(term, candidate)) {
term_supports_color = true;
break;
}
}
return 0 != isatty(fileno(stdout)) && term_supports_color;
#endif // BENCHMARK_OS_WINDOWS
}
} // end namespace benchmark

View File

@@ -1,33 +0,0 @@
#ifndef BENCHMARK_COLORPRINT_H_
#define BENCHMARK_COLORPRINT_H_
#include <cstdarg>
#include <iostream>
#include <string>
namespace benchmark {
enum LogColor {
COLOR_DEFAULT,
COLOR_RED,
COLOR_GREEN,
COLOR_YELLOW,
COLOR_BLUE,
COLOR_MAGENTA,
COLOR_CYAN,
COLOR_WHITE
};
std::string FormatString(const char* msg, va_list args);
std::string FormatString(const char* msg, ...);
void ColorPrintf(std::ostream& out, LogColor color, const char* fmt,
va_list args);
void ColorPrintf(std::ostream& out, LogColor color, const char* fmt, ...);
// Returns true if stdout appears to be a terminal that supports colored
// output, false otherwise.
bool IsColorTerminal();
} // end namespace benchmark
#endif // BENCHMARK_COLORPRINT_H_

View File

@@ -1,218 +0,0 @@
// Copyright 2015 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "commandlineflags.h"
#include <cctype>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <limits>
namespace benchmark {
// Parses 'str' for a 32-bit signed integer. If successful, writes
// the result to *value and returns true; otherwise leaves *value
// unchanged and returns false.
bool ParseInt32(const std::string& src_text, const char* str, int32_t* value) {
// Parses the environment variable as a decimal integer.
char* end = nullptr;
const long long_value = strtol(str, &end, 10); // NOLINT
// Has strtol() consumed all characters in the string?
if (*end != '\0') {
// No - an invalid character was encountered.
std::cerr << src_text << " is expected to be a 32-bit integer, "
<< "but actually has value \"" << str << "\".\n";
return false;
}
// Is the parsed value in the range of an Int32?
const int32_t result = static_cast<int32_t>(long_value);
if (long_value == std::numeric_limits<long>::max() ||
long_value == std::numeric_limits<long>::min() ||
// The parsed value overflows as a long. (strtol() returns
// LONG_MAX or LONG_MIN when the input overflows.)
result != long_value
// The parsed value overflows as an Int32.
) {
std::cerr << src_text << " is expected to be a 32-bit integer, "
<< "but actually has value \"" << str << "\", "
<< "which overflows.\n";
return false;
}
*value = result;
return true;
}
// Parses 'str' for a double. If successful, writes the result to *value and
// returns true; otherwise leaves *value unchanged and returns false.
bool ParseDouble(const std::string& src_text, const char* str, double* value) {
// Parses the environment variable as a decimal integer.
char* end = nullptr;
const double double_value = strtod(str, &end); // NOLINT
// Has strtol() consumed all characters in the string?
if (*end != '\0') {
// No - an invalid character was encountered.
std::cerr << src_text << " is expected to be a double, "
<< "but actually has value \"" << str << "\".\n";
return false;
}
*value = double_value;
return true;
}
// Returns the name of the environment variable corresponding to the
// given flag. For example, FlagToEnvVar("foo") will return
// "BENCHMARK_FOO" in the open-source version.
static std::string FlagToEnvVar(const char* flag) {
const std::string flag_str(flag);
std::string env_var;
for (size_t i = 0; i != flag_str.length(); ++i)
env_var += static_cast<char>(::toupper(flag_str.c_str()[i]));
return "BENCHMARK_" + env_var;
}
// Reads and returns the Boolean environment variable corresponding to
// the given flag; if it's not set, returns default_value.
//
// The value is considered true iff it's not "0".
bool BoolFromEnv(const char* flag, bool default_value) {
const std::string env_var = FlagToEnvVar(flag);
const char* const string_value = getenv(env_var.c_str());
return string_value == nullptr ? default_value
: strcmp(string_value, "0") != 0;
}
// Reads and returns a 32-bit integer stored in the environment
// variable corresponding to the given flag; if it isn't set or
// doesn't represent a valid 32-bit integer, returns default_value.
int32_t Int32FromEnv(const char* flag, int32_t default_value) {
const std::string env_var = FlagToEnvVar(flag);
const char* const string_value = getenv(env_var.c_str());
if (string_value == nullptr) {
// The environment variable is not set.
return default_value;
}
int32_t result = default_value;
if (!ParseInt32(std::string("Environment variable ") + env_var, string_value,
&result)) {
std::cout << "The default value " << default_value << " is used.\n";
return default_value;
}
return result;
}
// Reads and returns the string environment variable corresponding to
// the given flag; if it's not set, returns default_value.
const char* StringFromEnv(const char* flag, const char* default_value) {
const std::string env_var = FlagToEnvVar(flag);
const char* const value = getenv(env_var.c_str());
return value == nullptr ? default_value : value;
}
// Parses a string as a command line flag. The string should have
// the format "--flag=value". When def_optional is true, the "=value"
// part can be omitted.
//
// Returns the value of the flag, or nullptr if the parsing failed.
const char* ParseFlagValue(const char* str, const char* flag,
bool def_optional) {
// str and flag must not be nullptr.
if (str == nullptr || flag == nullptr) return nullptr;
// The flag must start with "--".
const std::string flag_str = std::string("--") + std::string(flag);
const size_t flag_len = flag_str.length();
if (strncmp(str, flag_str.c_str(), flag_len) != 0) return nullptr;
// Skips the flag name.
const char* flag_end = str + flag_len;
// When def_optional is true, it's OK to not have a "=value" part.
if (def_optional && (flag_end[0] == '\0')) return flag_end;
// If def_optional is true and there are more characters after the
// flag name, or if def_optional is false, there must be a '=' after
// the flag name.
if (flag_end[0] != '=') return nullptr;
// Returns the string after "=".
return flag_end + 1;
}
bool ParseBoolFlag(const char* str, const char* flag, bool* value) {
// Gets the value of the flag as a string.
const char* const value_str = ParseFlagValue(str, flag, true);
// Aborts if the parsing failed.
if (value_str == nullptr) return false;
// Converts the string value to a bool.
*value = IsTruthyFlagValue(value_str);
return true;
}
bool ParseInt32Flag(const char* str, const char* flag, int32_t* value) {
// Gets the value of the flag as a string.
const char* const value_str = ParseFlagValue(str, flag, false);
// Aborts if the parsing failed.
if (value_str == nullptr) return false;
// Sets *value to the value of the flag.
return ParseInt32(std::string("The value of flag --") + flag, value_str,
value);
}
bool ParseDoubleFlag(const char* str, const char* flag, double* value) {
// Gets the value of the flag as a string.
const char* const value_str = ParseFlagValue(str, flag, false);
// Aborts if the parsing failed.
if (value_str == nullptr) return false;
// Sets *value to the value of the flag.
return ParseDouble(std::string("The value of flag --") + flag, value_str,
value);
}
bool ParseStringFlag(const char* str, const char* flag, std::string* value) {
// Gets the value of the flag as a string.
const char* const value_str = ParseFlagValue(str, flag, false);
// Aborts if the parsing failed.
if (value_str == nullptr) return false;
*value = value_str;
return true;
}
bool IsFlag(const char* str, const char* flag) {
return (ParseFlagValue(str, flag, true) != nullptr);
}
bool IsTruthyFlagValue(const std::string& value) {
if (value.empty()) return true;
char ch = value[0];
return isalnum(ch) &&
!(ch == '0' || ch == 'f' || ch == 'F' || ch == 'n' || ch == 'N');
}
} // end namespace benchmark

View File

@@ -1,79 +0,0 @@
#ifndef BENCHMARK_COMMANDLINEFLAGS_H_
#define BENCHMARK_COMMANDLINEFLAGS_H_
#include <cstdint>
#include <string>
// Macro for referencing flags.
#define FLAG(name) FLAGS_##name
// Macros for declaring flags.
#define DECLARE_bool(name) extern bool FLAG(name)
#define DECLARE_int32(name) extern int32_t FLAG(name)
#define DECLARE_int64(name) extern int64_t FLAG(name)
#define DECLARE_double(name) extern double FLAG(name)
#define DECLARE_string(name) extern std::string FLAG(name)
// Macros for defining flags.
#define DEFINE_bool(name, default_val, doc) bool FLAG(name) = (default_val)
#define DEFINE_int32(name, default_val, doc) int32_t FLAG(name) = (default_val)
#define DEFINE_int64(name, default_val, doc) int64_t FLAG(name) = (default_val)
#define DEFINE_double(name, default_val, doc) double FLAG(name) = (default_val)
#define DEFINE_string(name, default_val, doc) \
std::string FLAG(name) = (default_val)
namespace benchmark {
// Parses 'str' for a 32-bit signed integer. If successful, writes the result
// to *value and returns true; otherwise leaves *value unchanged and returns
// false.
bool ParseInt32(const std::string& src_text, const char* str, int32_t* value);
// Parses a bool/Int32/string from the environment variable
// corresponding to the given Google Test flag.
bool BoolFromEnv(const char* flag, bool default_val);
int32_t Int32FromEnv(const char* flag, int32_t default_val);
double DoubleFromEnv(const char* flag, double default_val);
const char* StringFromEnv(const char* flag, const char* default_val);
// Parses a string for a bool flag, in the form of either
// "--flag=value" or "--flag".
//
// In the former case, the value is taken as true if it passes IsTruthyValue().
//
// In the latter case, the value is taken as true.
//
// On success, stores the value of the flag in *value, and returns
// true. On failure, returns false without changing *value.
bool ParseBoolFlag(const char* str, const char* flag, bool* value);
// Parses a string for an Int32 flag, in the form of
// "--flag=value".
//
// On success, stores the value of the flag in *value, and returns
// true. On failure, returns false without changing *value.
bool ParseInt32Flag(const char* str, const char* flag, int32_t* value);
// Parses a string for a Double flag, in the form of
// "--flag=value".
//
// On success, stores the value of the flag in *value, and returns
// true. On failure, returns false without changing *value.
bool ParseDoubleFlag(const char* str, const char* flag, double* value);
// Parses a string for a string flag, in the form of
// "--flag=value".
//
// On success, stores the value of the flag in *value, and returns
// true. On failure, returns false without changing *value.
bool ParseStringFlag(const char* str, const char* flag, std::string* value);
// Returns true if the string matches the flag.
bool IsFlag(const char* str, const char* flag);
// Returns true unless value starts with one of: '0', 'f', 'F', 'n' or 'N', or
// some non-alphanumeric character. As a special case, also returns true if
// value is the empty string.
bool IsTruthyFlagValue(const std::string& value);
} // end namespace benchmark
#endif // BENCHMARK_COMMANDLINEFLAGS_H_

View File

@@ -1,220 +0,0 @@
// Copyright 2016 Ismael Jimenez Martinez. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Source project : https://github.com/ismaelJimenez/cpp.leastsq
// Adapted to be used with google benchmark
#include "benchmark/benchmark.h"
#include <algorithm>
#include <cmath>
#include "check.h"
#include "complexity.h"
namespace benchmark {
// Internal function to calculate the different scalability forms
BigOFunc* FittingCurve(BigO complexity) {
switch (complexity) {
case oN:
return [](int64_t n) -> double { return static_cast<double>(n); };
case oNSquared:
return [](int64_t n) -> double { return std::pow(n, 2); };
case oNCubed:
return [](int64_t n) -> double { return std::pow(n, 3); };
case oLogN:
return [](int64_t n) { return log2(n); };
case oNLogN:
return [](int64_t n) { return n * log2(n); };
case o1:
default:
return [](int64_t) { return 1.0; };
}
}
// Function to return an string for the calculated complexity
std::string GetBigOString(BigO complexity) {
switch (complexity) {
case oN:
return "N";
case oNSquared:
return "N^2";
case oNCubed:
return "N^3";
case oLogN:
return "lgN";
case oNLogN:
return "NlgN";
case o1:
return "(1)";
default:
return "f(N)";
}
}
// Find the coefficient for the high-order term in the running time, by
// minimizing the sum of squares of relative error, for the fitting curve
// given by the lambda expression.
// - n : Vector containing the size of the benchmark tests.
// - time : Vector containing the times for the benchmark tests.
// - fitting_curve : lambda expression (e.g. [](int64_t n) {return n; };).
// For a deeper explanation on the algorithm logic, look the README file at
// http://github.com/ismaelJimenez/Minimal-Cpp-Least-Squared-Fit
LeastSq MinimalLeastSq(const std::vector<int64_t>& n,
const std::vector<double>& time,
BigOFunc* fitting_curve) {
double sigma_gn = 0.0;
double sigma_gn_squared = 0.0;
double sigma_time = 0.0;
double sigma_time_gn = 0.0;
// Calculate least square fitting parameter
for (size_t i = 0; i < n.size(); ++i) {
double gn_i = fitting_curve(n[i]);
sigma_gn += gn_i;
sigma_gn_squared += gn_i * gn_i;
sigma_time += time[i];
sigma_time_gn += time[i] * gn_i;
}
LeastSq result;
result.complexity = oLambda;
// Calculate complexity.
result.coef = sigma_time_gn / sigma_gn_squared;
// Calculate RMS
double rms = 0.0;
for (size_t i = 0; i < n.size(); ++i) {
double fit = result.coef * fitting_curve(n[i]);
rms += pow((time[i] - fit), 2);
}
// Normalized RMS by the mean of the observed values
double mean = sigma_time / n.size();
result.rms = sqrt(rms / n.size()) / mean;
return result;
}
// Find the coefficient for the high-order term in the running time, by
// minimizing the sum of squares of relative error.
// - n : Vector containing the size of the benchmark tests.
// - time : Vector containing the times for the benchmark tests.
// - complexity : If different than oAuto, the fitting curve will stick to
// this one. If it is oAuto, it will be calculated the best
// fitting curve.
LeastSq MinimalLeastSq(const std::vector<int64_t>& n,
const std::vector<double>& time, const BigO complexity) {
CHECK_EQ(n.size(), time.size());
CHECK_GE(n.size(), 2); // Do not compute fitting curve is less than two
// benchmark runs are given
CHECK_NE(complexity, oNone);
LeastSq best_fit;
if (complexity == oAuto) {
std::vector<BigO> fit_curves = {oLogN, oN, oNLogN, oNSquared, oNCubed};
// Take o1 as default best fitting curve
best_fit = MinimalLeastSq(n, time, FittingCurve(o1));
best_fit.complexity = o1;
// Compute all possible fitting curves and stick to the best one
for (const auto& fit : fit_curves) {
LeastSq current_fit = MinimalLeastSq(n, time, FittingCurve(fit));
if (current_fit.rms < best_fit.rms) {
best_fit = current_fit;
best_fit.complexity = fit;
}
}
} else {
best_fit = MinimalLeastSq(n, time, FittingCurve(complexity));
best_fit.complexity = complexity;
}
return best_fit;
}
std::vector<BenchmarkReporter::Run> ComputeBigO(
const std::vector<BenchmarkReporter::Run>& reports) {
typedef BenchmarkReporter::Run Run;
std::vector<Run> results;
if (reports.size() < 2) return results;
// Accumulators.
std::vector<int64_t> n;
std::vector<double> real_time;
std::vector<double> cpu_time;
// Populate the accumulators.
for (const Run& run : reports) {
CHECK_GT(run.complexity_n, 0) << "Did you forget to call SetComplexityN?";
n.push_back(run.complexity_n);
real_time.push_back(run.real_accumulated_time / run.iterations);
cpu_time.push_back(run.cpu_accumulated_time / run.iterations);
}
LeastSq result_cpu;
LeastSq result_real;
if (reports[0].complexity == oLambda) {
result_cpu = MinimalLeastSq(n, cpu_time, reports[0].complexity_lambda);
result_real = MinimalLeastSq(n, real_time, reports[0].complexity_lambda);
} else {
result_cpu = MinimalLeastSq(n, cpu_time, reports[0].complexity);
result_real = MinimalLeastSq(n, real_time, result_cpu.complexity);
}
std::string benchmark_name =
reports[0].benchmark_name.substr(0, reports[0].benchmark_name.find('/'));
// Get the data from the accumulator to BenchmarkReporter::Run's.
Run big_o;
big_o.benchmark_name = benchmark_name + "_BigO";
big_o.iterations = 0;
big_o.real_accumulated_time = result_real.coef;
big_o.cpu_accumulated_time = result_cpu.coef;
big_o.report_big_o = true;
big_o.complexity = result_cpu.complexity;
// All the time results are reported after being multiplied by the
// time unit multiplier. But since RMS is a relative quantity it
// should not be multiplied at all. So, here, we _divide_ it by the
// multiplier so that when it is multiplied later the result is the
// correct one.
double multiplier = GetTimeUnitMultiplier(reports[0].time_unit);
// Only add label to mean/stddev if it is same for all runs
Run rms;
big_o.report_label = reports[0].report_label;
rms.benchmark_name = benchmark_name + "_RMS";
rms.report_label = big_o.report_label;
rms.iterations = 0;
rms.real_accumulated_time = result_real.rms / multiplier;
rms.cpu_accumulated_time = result_cpu.rms / multiplier;
rms.report_rms = true;
rms.complexity = result_cpu.complexity;
// don't forget to keep the time unit, or we won't be able to
// recover the correct value.
rms.time_unit = reports[0].time_unit;
results.push_back(big_o);
results.push_back(rms);
return results;
}
} // end namespace benchmark

View File

@@ -1,55 +0,0 @@
// Copyright 2016 Ismael Jimenez Martinez. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Source project : https://github.com/ismaelJimenez/cpp.leastsq
// Adapted to be used with google benchmark
#ifndef COMPLEXITY_H_
#define COMPLEXITY_H_
#include <string>
#include <vector>
#include "benchmark/benchmark.h"
namespace benchmark {
// Return a vector containing the bigO and RMS information for the specified
// list of reports. If 'reports.size() < 2' an empty vector is returned.
std::vector<BenchmarkReporter::Run> ComputeBigO(
const std::vector<BenchmarkReporter::Run>& reports);
// This data structure will contain the result returned by MinimalLeastSq
// - coef : Estimated coeficient for the high-order term as
// interpolated from data.
// - rms : Normalized Root Mean Squared Error.
// - complexity : Scalability form (e.g. oN, oNLogN). In case a scalability
// form has been provided to MinimalLeastSq this will return
// the same value. In case BigO::oAuto has been selected, this
// parameter will return the best fitting curve detected.
struct LeastSq {
LeastSq() : coef(0.0), rms(0.0), complexity(oNone) {}
double coef;
double rms;
BigO complexity;
};
// Function to return an string for the calculated complexity
std::string GetBigOString(BigO complexity);
} // end namespace benchmark
#endif // COMPLEXITY_H_

View File

@@ -1,182 +0,0 @@
// Copyright 2015 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "benchmark/benchmark.h"
#include "complexity.h"
#include "counter.h"
#include <algorithm>
#include <cstdint>
#include <cstdio>
#include <iostream>
#include <string>
#include <tuple>
#include <vector>
#include "check.h"
#include "colorprint.h"
#include "commandlineflags.h"
#include "internal_macros.h"
#include "string_util.h"
#include "timers.h"
namespace benchmark {
bool ConsoleReporter::ReportContext(const Context& context) {
name_field_width_ = context.name_field_width;
printed_header_ = false;
prev_counters_.clear();
PrintBasicContext(&GetErrorStream(), context);
#ifdef BENCHMARK_OS_WINDOWS
if ((output_options_ & OO_Color) && &std::cout != &GetOutputStream()) {
GetErrorStream()
<< "Color printing is only supported for stdout on windows."
" Disabling color printing\n";
output_options_ = static_cast< OutputOptions >(output_options_ & ~OO_Color);
}
#endif
return true;
}
void ConsoleReporter::PrintHeader(const Run& run) {
std::string str = FormatString("%-*s %13s %13s %10s", static_cast<int>(name_field_width_),
"Benchmark", "Time", "CPU", "Iterations");
if(!run.counters.empty()) {
if(output_options_ & OO_Tabular) {
for(auto const& c : run.counters) {
str += FormatString(" %10s", c.first.c_str());
}
} else {
str += " UserCounters...";
}
}
str += "\n";
std::string line = std::string(str.length(), '-');
GetOutputStream() << line << "\n" << str << line << "\n";
}
void ConsoleReporter::ReportRuns(const std::vector<Run>& reports) {
for (const auto& run : reports) {
// print the header:
// --- if none was printed yet
bool print_header = !printed_header_;
// --- or if the format is tabular and this run
// has different fields from the prev header
print_header |= (output_options_ & OO_Tabular) &&
(!internal::SameNames(run.counters, prev_counters_));
if (print_header) {
printed_header_ = true;
prev_counters_ = run.counters;
PrintHeader(run);
}
// As an alternative to printing the headers like this, we could sort
// the benchmarks by header and then print. But this would require
// waiting for the full results before printing, or printing twice.
PrintRunData(run);
}
}
static void IgnoreColorPrint(std::ostream& out, LogColor, const char* fmt,
...) {
va_list args;
va_start(args, fmt);
out << FormatString(fmt, args);
va_end(args);
}
void ConsoleReporter::PrintRunData(const Run& result) {
typedef void(PrinterFn)(std::ostream&, LogColor, const char*, ...);
auto& Out = GetOutputStream();
PrinterFn* printer = (output_options_ & OO_Color) ?
(PrinterFn*)ColorPrintf : IgnoreColorPrint;
auto name_color =
(result.report_big_o || result.report_rms) ? COLOR_BLUE : COLOR_GREEN;
printer(Out, name_color, "%-*s ", name_field_width_,
result.benchmark_name.c_str());
if (result.error_occurred) {
printer(Out, COLOR_RED, "ERROR OCCURRED: \'%s\'",
result.error_message.c_str());
printer(Out, COLOR_DEFAULT, "\n");
return;
}
// Format bytes per second
std::string rate;
if (result.bytes_per_second > 0) {
rate = StrCat(" ", HumanReadableNumber(result.bytes_per_second), "B/s");
}
// Format items per second
std::string items;
if (result.items_per_second > 0) {
items =
StrCat(" ", HumanReadableNumber(result.items_per_second), " items/s");
}
const double real_time = result.GetAdjustedRealTime();
const double cpu_time = result.GetAdjustedCPUTime();
if (result.report_big_o) {
std::string big_o = GetBigOString(result.complexity);
printer(Out, COLOR_YELLOW, "%10.2f %s %10.2f %s ", real_time, big_o.c_str(),
cpu_time, big_o.c_str());
} else if (result.report_rms) {
printer(Out, COLOR_YELLOW, "%10.0f %% %10.0f %% ", real_time * 100,
cpu_time * 100);
} else {
const char* timeLabel = GetTimeUnitString(result.time_unit);
printer(Out, COLOR_YELLOW, "%10.0f %s %10.0f %s ", real_time, timeLabel,
cpu_time, timeLabel);
}
if (!result.report_big_o && !result.report_rms) {
printer(Out, COLOR_CYAN, "%10lld", result.iterations);
}
for (auto& c : result.counters) {
const std::size_t cNameLen = std::max(std::string::size_type(10),
c.first.length());
auto const& s = HumanReadableNumber(c.second.value, 1000);
if (output_options_ & OO_Tabular) {
if (c.second.flags & Counter::kIsRate) {
printer(Out, COLOR_DEFAULT, " %*s/s", cNameLen - 2, s.c_str());
} else {
printer(Out, COLOR_DEFAULT, " %*s", cNameLen, s.c_str());
}
} else {
const char* unit = (c.second.flags & Counter::kIsRate) ? "/s" : "";
printer(Out, COLOR_DEFAULT, " %s=%s%s", c.first.c_str(), s.c_str(),
unit);
}
}
if (!rate.empty()) {
printer(Out, COLOR_DEFAULT, " %*s", 13, rate.c_str());
}
if (!items.empty()) {
printer(Out, COLOR_DEFAULT, " %*s", 18, items.c_str());
}
if (!result.report_label.empty()) {
printer(Out, COLOR_DEFAULT, " %s", result.report_label.c_str());
}
printer(Out, COLOR_DEFAULT, "\n");
}
} // end namespace benchmark

View File

@@ -1,68 +0,0 @@
// Copyright 2015 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "counter.h"
namespace benchmark {
namespace internal {
double Finish(Counter const& c, double cpu_time, double num_threads) {
double v = c.value;
if (c.flags & Counter::kIsRate) {
v /= cpu_time;
}
if (c.flags & Counter::kAvgThreads) {
v /= num_threads;
}
return v;
}
void Finish(UserCounters *l, double cpu_time, double num_threads) {
for (auto &c : *l) {
c.second.value = Finish(c.second, cpu_time, num_threads);
}
}
void Increment(UserCounters *l, UserCounters const& r) {
// add counters present in both or just in *l
for (auto &c : *l) {
auto it = r.find(c.first);
if (it != r.end()) {
c.second.value = c.second + it->second;
}
}
// add counters present in r, but not in *l
for (auto const &tc : r) {
auto it = l->find(tc.first);
if (it == l->end()) {
(*l)[tc.first] = tc.second;
}
}
}
bool SameNames(UserCounters const& l, UserCounters const& r) {
if (&l == &r) return true;
if (l.size() != r.size()) {
return false;
}
for (auto const& c : l) {
if (r.find(c.first) == r.end()) {
return false;
}
}
return true;
}
} // end namespace internal
} // end namespace benchmark

View File

@@ -1,26 +0,0 @@
// Copyright 2015 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "benchmark/benchmark.h"
namespace benchmark {
// these counter-related functions are hidden to reduce API surface.
namespace internal {
void Finish(UserCounters *l, double time, double num_threads);
void Increment(UserCounters *l, UserCounters const& r);
bool SameNames(UserCounters const& l, UserCounters const& r);
} // end namespace internal
} //end namespace benchmark

View File

@@ -1,149 +0,0 @@
// Copyright 2015 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "benchmark/benchmark.h"
#include "complexity.h"
#include <algorithm>
#include <cstdint>
#include <iostream>
#include <string>
#include <tuple>
#include <vector>
#include "string_util.h"
#include "timers.h"
#include "check.h"
// File format reference: http://edoceo.com/utilitas/csv-file-format.
namespace benchmark {
namespace {
std::vector<std::string> elements = {
"name", "iterations", "real_time", "cpu_time",
"time_unit", "bytes_per_second", "items_per_second", "label",
"error_occurred", "error_message"};
} // namespace
bool CSVReporter::ReportContext(const Context& context) {
PrintBasicContext(&GetErrorStream(), context);
return true;
}
void CSVReporter::ReportRuns(const std::vector<Run> & reports) {
std::ostream& Out = GetOutputStream();
if (!printed_header_) {
// save the names of all the user counters
for (const auto& run : reports) {
for (const auto& cnt : run.counters) {
user_counter_names_.insert(cnt.first);
}
}
// print the header
for (auto B = elements.begin(); B != elements.end();) {
Out << *B++;
if (B != elements.end()) Out << ",";
}
for (auto B = user_counter_names_.begin(); B != user_counter_names_.end();) {
Out << ",\"" << *B++ << "\"";
}
Out << "\n";
printed_header_ = true;
} else {
// check that all the current counters are saved in the name set
for (const auto& run : reports) {
for (const auto& cnt : run.counters) {
CHECK(user_counter_names_.find(cnt.first) != user_counter_names_.end())
<< "All counters must be present in each run. "
<< "Counter named \"" << cnt.first
<< "\" was not in a run after being added to the header";
}
}
}
// print results for each run
for (const auto& run : reports) {
PrintRunData(run);
}
}
void CSVReporter::PrintRunData(const Run & run) {
std::ostream& Out = GetOutputStream();
// Field with embedded double-quote characters must be doubled and the field
// delimited with double-quotes.
std::string name = run.benchmark_name;
ReplaceAll(&name, "\"", "\"\"");
Out << '"' << name << "\",";
if (run.error_occurred) {
Out << std::string(elements.size() - 3, ',');
Out << "true,";
std::string msg = run.error_message;
ReplaceAll(&msg, "\"", "\"\"");
Out << '"' << msg << "\"\n";
return;
}
// Do not print iteration on bigO and RMS report
if (!run.report_big_o && !run.report_rms) {
Out << run.iterations;
}
Out << ",";
Out << run.GetAdjustedRealTime() << ",";
Out << run.GetAdjustedCPUTime() << ",";
// Do not print timeLabel on bigO and RMS report
if (run.report_big_o) {
Out << GetBigOString(run.complexity);
} else if (!run.report_rms) {
Out << GetTimeUnitString(run.time_unit);
}
Out << ",";
if (run.bytes_per_second > 0.0) {
Out << run.bytes_per_second;
}
Out << ",";
if (run.items_per_second > 0.0) {
Out << run.items_per_second;
}
Out << ",";
if (!run.report_label.empty()) {
// Field with embedded double-quote characters must be doubled and the field
// delimited with double-quotes.
std::string label = run.report_label;
ReplaceAll(&label, "\"", "\"\"");
Out << "\"" << label << "\"";
}
Out << ",,"; // for error_occurred and error_message
// Print user counters
for (const auto &ucn : user_counter_names_) {
auto it = run.counters.find(ucn);
if(it == run.counters.end()) {
Out << ",";
} else {
Out << "," << it->second;
}
}
Out << '\n';
}
} // end namespace benchmark

View File

@@ -1,177 +0,0 @@
// ----------------------------------------------------------------------
// CycleClock
// A CycleClock tells you the current time in Cycles. The "time"
// is actually time since power-on. This is like time() but doesn't
// involve a system call and is much more precise.
//
// NOTE: Not all cpu/platform/kernel combinations guarantee that this
// clock increments at a constant rate or is synchronized across all logical
// cpus in a system.
//
// If you need the above guarantees, please consider using a different
// API. There are efforts to provide an interface which provides a millisecond
// granularity and implemented as a memory read. A memory read is generally
// cheaper than the CycleClock for many architectures.
//
// Also, in some out of order CPU implementations, the CycleClock is not
// serializing. So if you're trying to count at cycles granularity, your
// data might be inaccurate due to out of order instruction execution.
// ----------------------------------------------------------------------
#ifndef BENCHMARK_CYCLECLOCK_H_
#define BENCHMARK_CYCLECLOCK_H_
#include <cstdint>
#include "benchmark/benchmark.h"
#include "internal_macros.h"
#if defined(BENCHMARK_OS_MACOSX)
#include <mach/mach_time.h>
#endif
// For MSVC, we want to use '_asm rdtsc' when possible (since it works
// with even ancient MSVC compilers), and when not possible the
// __rdtsc intrinsic, declared in <intrin.h>. Unfortunately, in some
// environments, <windows.h> and <intrin.h> have conflicting
// declarations of some other intrinsics, breaking compilation.
// Therefore, we simply declare __rdtsc ourselves. See also
// http://connect.microsoft.com/VisualStudio/feedback/details/262047
#if defined(COMPILER_MSVC) && !defined(_M_IX86)
extern "C" uint64_t __rdtsc();
#pragma intrinsic(__rdtsc)
#endif
#ifndef BENCHMARK_OS_WINDOWS
#include <sys/time.h>
#include <time.h>
#endif
#ifdef BENCHMARK_OS_EMSCRIPTEN
#include <emscripten.h>
#endif
namespace benchmark {
// NOTE: only i386 and x86_64 have been well tested.
// PPC, sparc, alpha, and ia64 are based on
// http://peter.kuscsik.com/wordpress/?p=14
// with modifications by m3b. See also
// https://setisvn.ssl.berkeley.edu/svn/lib/fftw-3.0.1/kernel/cycle.h
namespace cycleclock {
// This should return the number of cycles since power-on. Thread-safe.
inline BENCHMARK_ALWAYS_INLINE int64_t Now() {
#if defined(BENCHMARK_OS_MACOSX)
// this goes at the top because we need ALL Macs, regardless of
// architecture, to return the number of "mach time units" that
// have passed since startup. See sysinfo.cc where
// InitializeSystemInfo() sets the supposed cpu clock frequency of
// macs to the number of mach time units per second, not actual
// CPU clock frequency (which can change in the face of CPU
// frequency scaling). Also note that when the Mac sleeps, this
// counter pauses; it does not continue counting, nor does it
// reset to zero.
return mach_absolute_time();
#elif defined(BENCHMARK_OS_EMSCRIPTEN)
// this goes above x86-specific code because old versions of Emscripten
// define __x86_64__, although they have nothing to do with it.
return static_cast<int64_t>(emscripten_get_now() * 1e+6);
#elif defined(__i386__)
int64_t ret;
__asm__ volatile("rdtsc" : "=A"(ret));
return ret;
#elif defined(__x86_64__) || defined(__amd64__)
uint64_t low, high;
__asm__ volatile("rdtsc" : "=a"(low), "=d"(high));
return (high << 32) | low;
#elif defined(__powerpc__) || defined(__ppc__)
// This returns a time-base, which is not always precisely a cycle-count.
int64_t tbl, tbu0, tbu1;
asm("mftbu %0" : "=r"(tbu0));
asm("mftb %0" : "=r"(tbl));
asm("mftbu %0" : "=r"(tbu1));
tbl &= -static_cast<int64_t>(tbu0 == tbu1);
// high 32 bits in tbu1; low 32 bits in tbl (tbu0 is garbage)
return (tbu1 << 32) | tbl;
#elif defined(__sparc__)
int64_t tick;
asm(".byte 0x83, 0x41, 0x00, 0x00");
asm("mov %%g1, %0" : "=r"(tick));
return tick;
#elif defined(__ia64__)
int64_t itc;
asm("mov %0 = ar.itc" : "=r"(itc));
return itc;
#elif defined(COMPILER_MSVC) && defined(_M_IX86)
// Older MSVC compilers (like 7.x) don't seem to support the
// __rdtsc intrinsic properly, so I prefer to use _asm instead
// when I know it will work. Otherwise, I'll use __rdtsc and hope
// the code is being compiled with a non-ancient compiler.
_asm rdtsc
#elif defined(COMPILER_MSVC)
return __rdtsc();
#elif defined(BENCHMARK_OS_NACL)
// Native Client validator on x86/x86-64 allows RDTSC instructions,
// and this case is handled above. Native Client validator on ARM
// rejects MRC instructions (used in the ARM-specific sequence below),
// so we handle it here. Portable Native Client compiles to
// architecture-agnostic bytecode, which doesn't provide any
// cycle counter access mnemonics.
// Native Client does not provide any API to access cycle counter.
// Use clock_gettime(CLOCK_MONOTONIC, ...) instead of gettimeofday
// because is provides nanosecond resolution (which is noticable at
// least for PNaCl modules running on x86 Mac & Linux).
// Initialize to always return 0 if clock_gettime fails.
struct timespec ts = { 0, 0 };
clock_gettime(CLOCK_MONOTONIC, &ts);
return static_cast<int64_t>(ts.tv_sec) * 1000000000 + ts.tv_nsec;
#elif defined(__aarch64__)
// System timer of ARMv8 runs at a different frequency than the CPU's.
// The frequency is fixed, typically in the range 1-50MHz. It can be
// read at CNTFRQ special register. We assume the OS has set up
// the virtual timer properly.
int64_t virtual_timer_value;
asm volatile("mrs %0, cntvct_el0" : "=r"(virtual_timer_value));
return virtual_timer_value;
#elif defined(__ARM_ARCH)
// V6 is the earliest arch that has a standard cyclecount
// Native Client validator doesn't allow MRC instructions.
#if (__ARM_ARCH >= 6)
uint32_t pmccntr;
uint32_t pmuseren;
uint32_t pmcntenset;
// Read the user mode perf monitor counter access permissions.
asm volatile("mrc p15, 0, %0, c9, c14, 0" : "=r"(pmuseren));
if (pmuseren & 1) { // Allows reading perfmon counters for user mode code.
asm volatile("mrc p15, 0, %0, c9, c12, 1" : "=r"(pmcntenset));
if (pmcntenset & 0x80000000ul) { // Is it counting?
asm volatile("mrc p15, 0, %0, c9, c13, 0" : "=r"(pmccntr));
// The counter is set up to count every 64th cycle
return static_cast<int64_t>(pmccntr) * 64; // Should optimize to << 6
}
}
#endif
struct timeval tv;
gettimeofday(&tv, nullptr);
return static_cast<int64_t>(tv.tv_sec) * 1000000 + tv.tv_usec;
#elif defined(__mips__)
// mips apparently only allows rdtsc for superusers, so we fall
// back to gettimeofday. It's possible clock_gettime would be better.
struct timeval tv;
gettimeofday(&tv, nullptr);
return static_cast<int64_t>(tv.tv_sec) * 1000000 + tv.tv_usec;
#elif defined(__s390__) // Covers both s390 and s390x.
// Return the CPU clock.
uint64_t tsc;
asm("stck %0" : "=Q" (tsc) : : "cc");
return tsc;
#else
// The soft failover to a generic implementation is automatic only for ARM.
// For other platforms the developer is expected to make an attempt to create
// a fast implementation and use generic version if nothing better is available.
#error You need to define CycleTimer for your OS and CPU
#endif
}
} // end namespace cycleclock
} // end namespace benchmark
#endif // BENCHMARK_CYCLECLOCK_H_

View File

@@ -1,89 +0,0 @@
#ifndef BENCHMARK_INTERNAL_MACROS_H_
#define BENCHMARK_INTERNAL_MACROS_H_
#include "benchmark/benchmark.h"
#ifndef __has_feature
#define __has_feature(x) 0
#endif
#ifndef __has_builtin
#define __has_builtin(x) 0
#endif
#if defined(__clang__)
#if !defined(COMPILER_CLANG)
#define COMPILER_CLANG
#endif
#elif defined(_MSC_VER)
#if !defined(COMPILER_MSVC)
#define COMPILER_MSVC
#endif
#elif defined(__GNUC__)
#if !defined(COMPILER_GCC)
#define COMPILER_GCC
#endif
#endif
#if __has_feature(cxx_attributes)
#define BENCHMARK_NORETURN [[noreturn]]
#elif defined(__GNUC__)
#define BENCHMARK_NORETURN __attribute__((noreturn))
#elif defined(COMPILER_MSVC)
#define BENCHMARK_NORETURN __declspec(noreturn)
#else
#define BENCHMARK_NORETURN
#endif
#if defined(__CYGWIN__)
#define BENCHMARK_OS_CYGWIN 1
#elif defined(_WIN32)
#define BENCHMARK_OS_WINDOWS 1
#elif defined(__APPLE__)
#define BENCHMARK_OS_APPLE 1
#include "TargetConditionals.h"
#if defined(TARGET_OS_MAC)
#define BENCHMARK_OS_MACOSX 1
#if defined(TARGET_OS_IPHONE)
#define BENCHMARK_OS_IOS 1
#endif
#endif
#elif defined(__FreeBSD__)
#define BENCHMARK_OS_FREEBSD 1
#elif defined(__NetBSD__)
#define BENCHMARK_OS_NETBSD 1
#elif defined(__OpenBSD__)
#define BENCHMARK_OS_OPENBSD 1
#elif defined(__linux__)
#define BENCHMARK_OS_LINUX 1
#elif defined(__native_client__)
#define BENCHMARK_OS_NACL 1
#elif defined(__EMSCRIPTEN__)
#define BENCHMARK_OS_EMSCRIPTEN 1
#elif defined(__rtems__)
#define BENCHMARK_OS_RTEMS 1
#elif defined(__Fuchsia__)
#define BENCHMARK_OS_FUCHSIA 1
#elif defined (__SVR4) && defined (__sun)
#define BENCHMARK_OS_SOLARIS 1
#endif
#if !__has_feature(cxx_exceptions) && !defined(__cpp_exceptions) \
&& !defined(__EXCEPTIONS)
#define BENCHMARK_HAS_NO_EXCEPTIONS
#endif
#if defined(COMPILER_CLANG) || defined(COMPILER_GCC)
#define BENCHMARK_MAYBE_UNUSED __attribute__((unused))
#else
#define BENCHMARK_MAYBE_UNUSED
#endif
#if defined(COMPILER_GCC) || __has_builtin(__builtin_unreachable)
#define BENCHMARK_UNREACHABLE() __builtin_unreachable()
#elif defined(COMPILER_MSVC)
#define BENCHMARK_UNREACHABLE() __assume(false)
#else
#define BENCHMARK_UNREACHABLE() ((void)0)
#endif
#endif // BENCHMARK_INTERNAL_MACROS_H_

View File

@@ -1,205 +0,0 @@
// Copyright 2015 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "benchmark/benchmark.h"
#include "complexity.h"
#include <algorithm>
#include <cstdint>
#include <iostream>
#include <string>
#include <tuple>
#include <vector>
#include <iomanip> // for setprecision
#include <limits>
#include "string_util.h"
#include "timers.h"
namespace benchmark {
namespace {
std::string FormatKV(std::string const& key, std::string const& value) {
return StrFormat("\"%s\": \"%s\"", key.c_str(), value.c_str());
}
std::string FormatKV(std::string const& key, const char* value) {
return StrFormat("\"%s\": \"%s\"", key.c_str(), value);
}
std::string FormatKV(std::string const& key, bool value) {
return StrFormat("\"%s\": %s", key.c_str(), value ? "true" : "false");
}
std::string FormatKV(std::string const& key, int64_t value) {
std::stringstream ss;
ss << '"' << key << "\": " << value;
return ss.str();
}
std::string FormatKV(std::string const& key, double value) {
std::stringstream ss;
ss << '"' << key << "\": ";
const auto max_digits10 = std::numeric_limits<decltype (value)>::max_digits10;
const auto max_fractional_digits10 = max_digits10 - 1;
ss << std::scientific << std::setprecision(max_fractional_digits10) << value;
return ss.str();
}
int64_t RoundDouble(double v) { return static_cast<int64_t>(v + 0.5); }
} // end namespace
bool JSONReporter::ReportContext(const Context& context) {
std::ostream& out = GetOutputStream();
out << "{\n";
std::string inner_indent(2, ' ');
// Open context block and print context information.
out << inner_indent << "\"context\": {\n";
std::string indent(4, ' ');
std::string walltime_value = LocalDateTimeString();
out << indent << FormatKV("date", walltime_value) << ",\n";
if (Context::executable_name) {
out << indent << FormatKV("executable", Context::executable_name) << ",\n";
}
CPUInfo const& info = context.cpu_info;
out << indent << FormatKV("num_cpus", static_cast<int64_t>(info.num_cpus))
<< ",\n";
out << indent
<< FormatKV("mhz_per_cpu",
RoundDouble(info.cycles_per_second / 1000000.0))
<< ",\n";
out << indent << FormatKV("cpu_scaling_enabled", info.scaling_enabled)
<< ",\n";
out << indent << "\"caches\": [\n";
indent = std::string(6, ' ');
std::string cache_indent(8, ' ');
for (size_t i = 0; i < info.caches.size(); ++i) {
auto& CI = info.caches[i];
out << indent << "{\n";
out << cache_indent << FormatKV("type", CI.type) << ",\n";
out << cache_indent << FormatKV("level", static_cast<int64_t>(CI.level))
<< ",\n";
out << cache_indent
<< FormatKV("size", static_cast<int64_t>(CI.size) * 1000u) << ",\n";
out << cache_indent
<< FormatKV("num_sharing", static_cast<int64_t>(CI.num_sharing))
<< "\n";
out << indent << "}";
if (i != info.caches.size() - 1) out << ",";
out << "\n";
}
indent = std::string(4, ' ');
out << indent << "],\n";
#if defined(NDEBUG)
const char build_type[] = "release";
#else
const char build_type[] = "debug";
#endif
out << indent << FormatKV("library_build_type", build_type) << "\n";
// Close context block and open the list of benchmarks.
out << inner_indent << "},\n";
out << inner_indent << "\"benchmarks\": [\n";
return true;
}
void JSONReporter::ReportRuns(std::vector<Run> const& reports) {
if (reports.empty()) {
return;
}
std::string indent(4, ' ');
std::ostream& out = GetOutputStream();
if (!first_report_) {
out << ",\n";
}
first_report_ = false;
for (auto it = reports.begin(); it != reports.end(); ++it) {
out << indent << "{\n";
PrintRunData(*it);
out << indent << '}';
auto it_cp = it;
if (++it_cp != reports.end()) {
out << ",\n";
}
}
}
void JSONReporter::Finalize() {
// Close the list of benchmarks and the top level object.
GetOutputStream() << "\n ]\n}\n";
}
void JSONReporter::PrintRunData(Run const& run) {
std::string indent(6, ' ');
std::ostream& out = GetOutputStream();
out << indent << FormatKV("name", run.benchmark_name) << ",\n";
if (run.error_occurred) {
out << indent << FormatKV("error_occurred", run.error_occurred) << ",\n";
out << indent << FormatKV("error_message", run.error_message) << ",\n";
}
if (!run.report_big_o && !run.report_rms) {
out << indent << FormatKV("iterations", run.iterations) << ",\n";
out << indent
<< FormatKV("real_time", run.GetAdjustedRealTime())
<< ",\n";
out << indent
<< FormatKV("cpu_time", run.GetAdjustedCPUTime());
out << ",\n"
<< indent << FormatKV("time_unit", GetTimeUnitString(run.time_unit));
} else if (run.report_big_o) {
out << indent
<< FormatKV("cpu_coefficient", run.GetAdjustedCPUTime())
<< ",\n";
out << indent
<< FormatKV("real_coefficient", run.GetAdjustedRealTime())
<< ",\n";
out << indent << FormatKV("big_o", GetBigOString(run.complexity)) << ",\n";
out << indent << FormatKV("time_unit", GetTimeUnitString(run.time_unit));
} else if (run.report_rms) {
out << indent
<< FormatKV("rms", run.GetAdjustedCPUTime());
}
if (run.bytes_per_second > 0.0) {
out << ",\n"
<< indent
<< FormatKV("bytes_per_second", run.bytes_per_second);
}
if (run.items_per_second > 0.0) {
out << ",\n"
<< indent
<< FormatKV("items_per_second", run.items_per_second);
}
for(auto &c : run.counters) {
out << ",\n"
<< indent
<< FormatKV(c.first, c.second);
}
if (!run.report_label.empty()) {
out << ",\n" << indent << FormatKV("label", run.report_label);
}
out << '\n';
}
} // end namespace benchmark

View File

@@ -1,73 +0,0 @@
#ifndef BENCHMARK_LOG_H_
#define BENCHMARK_LOG_H_
#include <iostream>
#include <ostream>
#include "benchmark/benchmark.h"
namespace benchmark {
namespace internal {
typedef std::basic_ostream<char>&(EndLType)(std::basic_ostream<char>&);
class LogType {
friend LogType& GetNullLogInstance();
friend LogType& GetErrorLogInstance();
// FIXME: Add locking to output.
template <class Tp>
friend LogType& operator<<(LogType&, Tp const&);
friend LogType& operator<<(LogType&, EndLType*);
private:
LogType(std::ostream* out) : out_(out) {}
std::ostream* out_;
BENCHMARK_DISALLOW_COPY_AND_ASSIGN(LogType);
};
template <class Tp>
LogType& operator<<(LogType& log, Tp const& value) {
if (log.out_) {
*log.out_ << value;
}
return log;
}
inline LogType& operator<<(LogType& log, EndLType* m) {
if (log.out_) {
*log.out_ << m;
}
return log;
}
inline int& LogLevel() {
static int log_level = 0;
return log_level;
}
inline LogType& GetNullLogInstance() {
static LogType log(nullptr);
return log;
}
inline LogType& GetErrorLogInstance() {
static LogType log(&std::clog);
return log;
}
inline LogType& GetLogInstanceForLevel(int level) {
if (level <= LogLevel()) {
return GetErrorLogInstance();
}
return GetNullLogInstance();
}
} // end namespace internal
} // end namespace benchmark
#define VLOG(x) \
(::benchmark::internal::GetLogInstanceForLevel(x) << "-- LOG(" << x << "):" \
" ")
#endif

View File

@@ -1,155 +0,0 @@
#ifndef BENCHMARK_MUTEX_H_
#define BENCHMARK_MUTEX_H_
#include <condition_variable>
#include <mutex>
#include "check.h"
// Enable thread safety attributes only with clang.
// The attributes can be safely erased when compiling with other compilers.
#if defined(HAVE_THREAD_SAFETY_ATTRIBUTES)
#define THREAD_ANNOTATION_ATTRIBUTE__(x) __attribute__((x))
#else
#define THREAD_ANNOTATION_ATTRIBUTE__(x) // no-op
#endif
#define CAPABILITY(x) THREAD_ANNOTATION_ATTRIBUTE__(capability(x))
#define SCOPED_CAPABILITY THREAD_ANNOTATION_ATTRIBUTE__(scoped_lockable)
#define GUARDED_BY(x) THREAD_ANNOTATION_ATTRIBUTE__(guarded_by(x))
#define PT_GUARDED_BY(x) THREAD_ANNOTATION_ATTRIBUTE__(pt_guarded_by(x))
#define ACQUIRED_BEFORE(...) \
THREAD_ANNOTATION_ATTRIBUTE__(acquired_before(__VA_ARGS__))
#define ACQUIRED_AFTER(...) \
THREAD_ANNOTATION_ATTRIBUTE__(acquired_after(__VA_ARGS__))
#define REQUIRES(...) \
THREAD_ANNOTATION_ATTRIBUTE__(requires_capability(__VA_ARGS__))
#define REQUIRES_SHARED(...) \
THREAD_ANNOTATION_ATTRIBUTE__(requires_shared_capability(__VA_ARGS__))
#define ACQUIRE(...) \
THREAD_ANNOTATION_ATTRIBUTE__(acquire_capability(__VA_ARGS__))
#define ACQUIRE_SHARED(...) \
THREAD_ANNOTATION_ATTRIBUTE__(acquire_shared_capability(__VA_ARGS__))
#define RELEASE(...) \
THREAD_ANNOTATION_ATTRIBUTE__(release_capability(__VA_ARGS__))
#define RELEASE_SHARED(...) \
THREAD_ANNOTATION_ATTRIBUTE__(release_shared_capability(__VA_ARGS__))
#define TRY_ACQUIRE(...) \
THREAD_ANNOTATION_ATTRIBUTE__(try_acquire_capability(__VA_ARGS__))
#define TRY_ACQUIRE_SHARED(...) \
THREAD_ANNOTATION_ATTRIBUTE__(try_acquire_shared_capability(__VA_ARGS__))
#define EXCLUDES(...) THREAD_ANNOTATION_ATTRIBUTE__(locks_excluded(__VA_ARGS__))
#define ASSERT_CAPABILITY(x) THREAD_ANNOTATION_ATTRIBUTE__(assert_capability(x))
#define ASSERT_SHARED_CAPABILITY(x) \
THREAD_ANNOTATION_ATTRIBUTE__(assert_shared_capability(x))
#define RETURN_CAPABILITY(x) THREAD_ANNOTATION_ATTRIBUTE__(lock_returned(x))
#define NO_THREAD_SAFETY_ANALYSIS \
THREAD_ANNOTATION_ATTRIBUTE__(no_thread_safety_analysis)
namespace benchmark {
typedef std::condition_variable Condition;
// NOTE: Wrappers for std::mutex and std::unique_lock are provided so that
// we can annotate them with thread safety attributes and use the
// -Wthread-safety warning with clang. The standard library types cannot be
// used directly because they do not provided the required annotations.
class CAPABILITY("mutex") Mutex {
public:
Mutex() {}
void lock() ACQUIRE() { mut_.lock(); }
void unlock() RELEASE() { mut_.unlock(); }
std::mutex& native_handle() { return mut_; }
private:
std::mutex mut_;
};
class SCOPED_CAPABILITY MutexLock {
typedef std::unique_lock<std::mutex> MutexLockImp;
public:
MutexLock(Mutex& m) ACQUIRE(m) : ml_(m.native_handle()) {}
~MutexLock() RELEASE() {}
MutexLockImp& native_handle() { return ml_; }
private:
MutexLockImp ml_;
};
class Barrier {
public:
Barrier(int num_threads) : running_threads_(num_threads) {}
// Called by each thread
bool wait() EXCLUDES(lock_) {
bool last_thread = false;
{
MutexLock ml(lock_);
last_thread = createBarrier(ml);
}
if (last_thread) phase_condition_.notify_all();
return last_thread;
}
void removeThread() EXCLUDES(lock_) {
MutexLock ml(lock_);
--running_threads_;
if (entered_ != 0) phase_condition_.notify_all();
}
private:
Mutex lock_;
Condition phase_condition_;
int running_threads_;
// State for barrier management
int phase_number_ = 0;
int entered_ = 0; // Number of threads that have entered this barrier
// Enter the barrier and wait until all other threads have also
// entered the barrier. Returns iff this is the last thread to
// enter the barrier.
bool createBarrier(MutexLock& ml) REQUIRES(lock_) {
CHECK_LT(entered_, running_threads_);
entered_++;
if (entered_ < running_threads_) {
// Wait for all threads to enter
int phase_number_cp = phase_number_;
auto cb = [this, phase_number_cp]() {
return this->phase_number_ > phase_number_cp ||
entered_ == running_threads_; // A thread has aborted in error
};
phase_condition_.wait(ml.native_handle(), cb);
if (phase_number_ > phase_number_cp) return false;
// else (running_threads_ == entered_) and we are the last thread.
}
// Last thread has reached the barrier
phase_number_++;
entered_ = 0;
return true;
}
};
} // end namespace benchmark
#endif // BENCHMARK_MUTEX_H_

View File

@@ -1,152 +0,0 @@
// Copyright 2015 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef BENCHMARK_RE_H_
#define BENCHMARK_RE_H_
#include "internal_macros.h"
#if !defined(HAVE_STD_REGEX) && \
!defined(HAVE_GNU_POSIX_REGEX) && \
!defined(HAVE_POSIX_REGEX)
// No explicit regex selection; detect based on builtin hints.
#if defined(BENCHMARK_OS_LINUX) || defined(BENCHMARK_OS_APPLE)
#define HAVE_POSIX_REGEX 1
#elif __cplusplus >= 199711L
#define HAVE_STD_REGEX 1
#endif
#endif
// Prefer C regex libraries when compiling w/o exceptions so that we can
// correctly report errors.
#if defined(BENCHMARK_HAS_NO_EXCEPTIONS) && \
defined(BENCHMARK_HAVE_STD_REGEX) && \
(defined(HAVE_GNU_POSIX_REGEX) || defined(HAVE_POSIX_REGEX))
#undef HAVE_STD_REGEX
#endif
#if defined(HAVE_STD_REGEX)
#include <regex>
#elif defined(HAVE_GNU_POSIX_REGEX)
#include <gnuregex.h>
#elif defined(HAVE_POSIX_REGEX)
#include <regex.h>
#else
#error No regular expression backend was found!
#endif
#include <string>
#include "check.h"
namespace benchmark {
// A wrapper around the POSIX regular expression API that provides automatic
// cleanup
class Regex {
public:
Regex() : init_(false) {}
~Regex();
// Compile a regular expression matcher from spec. Returns true on success.
//
// On failure (and if error is not nullptr), error is populated with a human
// readable error message if an error occurs.
bool Init(const std::string& spec, std::string* error);
// Returns whether str matches the compiled regular expression.
bool Match(const std::string& str);
private:
bool init_;
// Underlying regular expression object
#if defined(HAVE_STD_REGEX)
std::regex re_;
#elif defined(HAVE_POSIX_REGEX) || defined(HAVE_GNU_POSIX_REGEX)
regex_t re_;
#else
#error No regular expression backend implementation available
#endif
};
#if defined(HAVE_STD_REGEX)
inline bool Regex::Init(const std::string& spec, std::string* error) {
#ifdef BENCHMARK_HAS_NO_EXCEPTIONS
((void)error); // suppress unused warning
#else
try {
#endif
re_ = std::regex(spec, std::regex_constants::extended);
init_ = true;
#ifndef BENCHMARK_HAS_NO_EXCEPTIONS
} catch (const std::regex_error& e) {
if (error) {
*error = e.what();
}
}
#endif
return init_;
}
inline Regex::~Regex() {}
inline bool Regex::Match(const std::string& str) {
if (!init_) {
return false;
}
return std::regex_search(str, re_);
}
#else
inline bool Regex::Init(const std::string& spec, std::string* error) {
int ec = regcomp(&re_, spec.c_str(), REG_EXTENDED | REG_NOSUB);
if (ec != 0) {
if (error) {
size_t needed = regerror(ec, &re_, nullptr, 0);
char* errbuf = new char[needed];
regerror(ec, &re_, errbuf, needed);
// regerror returns the number of bytes necessary to null terminate
// the string, so we move that when assigning to error.
CHECK_NE(needed, 0);
error->assign(errbuf, needed - 1);
delete[] errbuf;
}
return false;
}
init_ = true;
return true;
}
inline Regex::~Regex() {
if (init_) {
regfree(&re_);
}
}
inline bool Regex::Match(const std::string& str) {
if (!init_) {
return false;
}
return regexec(&re_, str.c_str(), 0, nullptr, 0) == 0;
}
#endif
} // end namespace benchmark
#endif // BENCHMARK_RE_H_

View File

@@ -1,87 +0,0 @@
// Copyright 2015 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "benchmark/benchmark.h"
#include "timers.h"
#include <cstdlib>
#include <iostream>
#include <tuple>
#include <vector>
#include "check.h"
namespace benchmark {
BenchmarkReporter::BenchmarkReporter()
: output_stream_(&std::cout), error_stream_(&std::cerr) {}
BenchmarkReporter::~BenchmarkReporter() {}
void BenchmarkReporter::PrintBasicContext(std::ostream *out,
Context const &context) {
CHECK(out) << "cannot be null";
auto &Out = *out;
Out << LocalDateTimeString() << "\n";
if (context.executable_name)
Out << "Running " << context.executable_name << "\n";
const CPUInfo &info = context.cpu_info;
Out << "Run on (" << info.num_cpus << " X "
<< (info.cycles_per_second / 1000000.0) << " MHz CPU "
<< ((info.num_cpus > 1) ? "s" : "") << ")\n";
if (info.caches.size() != 0) {
Out << "CPU Caches:\n";
for (auto &CInfo : info.caches) {
Out << " L" << CInfo.level << " " << CInfo.type << " "
<< (CInfo.size / 1000) << "K";
if (CInfo.num_sharing != 0)
Out << " (x" << (info.num_cpus / CInfo.num_sharing) << ")";
Out << "\n";
}
}
if (info.scaling_enabled) {
Out << "***WARNING*** CPU scaling is enabled, the benchmark "
"real time measurements may be noisy and will incur extra "
"overhead.\n";
}
#ifndef NDEBUG
Out << "***WARNING*** Library was built as DEBUG. Timings may be "
"affected.\n";
#endif
}
// No initializer because it's already initialized to NULL.
const char* BenchmarkReporter::Context::executable_name;
BenchmarkReporter::Context::Context() : cpu_info(CPUInfo::Get()) {}
double BenchmarkReporter::Run::GetAdjustedRealTime() const {
double new_time = real_accumulated_time * GetTimeUnitMultiplier(time_unit);
if (iterations != 0) new_time /= static_cast<double>(iterations);
return new_time;
}
double BenchmarkReporter::Run::GetAdjustedCPUTime() const {
double new_time = cpu_accumulated_time * GetTimeUnitMultiplier(time_unit);
if (iterations != 0) new_time /= static_cast<double>(iterations);
return new_time;
}
} // end namespace benchmark

View File

@@ -1,51 +0,0 @@
// Copyright 2015 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "sleep.h"
#include <cerrno>
#include <cstdlib>
#include <ctime>
#include "internal_macros.h"
#ifdef BENCHMARK_OS_WINDOWS
#include <Windows.h>
#endif
namespace benchmark {
#ifdef BENCHMARK_OS_WINDOWS
// Window's Sleep takes milliseconds argument.
void SleepForMilliseconds(int milliseconds) { Sleep(milliseconds); }
void SleepForSeconds(double seconds) {
SleepForMilliseconds(static_cast<int>(kNumMillisPerSecond * seconds));
}
#else // BENCHMARK_OS_WINDOWS
void SleepForMicroseconds(int microseconds) {
struct timespec sleep_time;
sleep_time.tv_sec = microseconds / kNumMicrosPerSecond;
sleep_time.tv_nsec = (microseconds % kNumMicrosPerSecond) * kNumNanosPerMicro;
while (nanosleep(&sleep_time, &sleep_time) != 0 && errno == EINTR)
; // Ignore signals and wait for the full interval to elapse.
}
void SleepForMilliseconds(int milliseconds) {
SleepForMicroseconds(milliseconds * kNumMicrosPerMilli);
}
void SleepForSeconds(double seconds) {
SleepForMicroseconds(static_cast<int>(seconds * kNumMicrosPerSecond));
}
#endif // BENCHMARK_OS_WINDOWS
} // end namespace benchmark

View File

@@ -1,15 +0,0 @@
#ifndef BENCHMARK_SLEEP_H_
#define BENCHMARK_SLEEP_H_
namespace benchmark {
const int kNumMillisPerSecond = 1000;
const int kNumMicrosPerMilli = 1000;
const int kNumMicrosPerSecond = kNumMillisPerSecond * 1000;
const int kNumNanosPerMicro = 1000;
const int kNumNanosPerSecond = kNumNanosPerMicro * kNumMicrosPerSecond;
void SleepForMilliseconds(int milliseconds);
void SleepForSeconds(double seconds);
} // end namespace benchmark
#endif // BENCHMARK_SLEEP_H_

View File

@@ -1,178 +0,0 @@
// Copyright 2016 Ismael Jimenez Martinez. All rights reserved.
// Copyright 2017 Roman Lebedev. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "benchmark/benchmark.h"
#include <algorithm>
#include <cmath>
#include <string>
#include <vector>
#include <numeric>
#include "check.h"
#include "statistics.h"
namespace benchmark {
auto StatisticsSum = [](const std::vector<double>& v) {
return std::accumulate(v.begin(), v.end(), 0.0);
};
double StatisticsMean(const std::vector<double>& v) {
if (v.empty()) return 0.0;
return StatisticsSum(v) * (1.0 / v.size());
}
double StatisticsMedian(const std::vector<double>& v) {
if (v.size() < 3) return StatisticsMean(v);
std::vector<double> copy(v);
auto center = copy.begin() + v.size() / 2;
std::nth_element(copy.begin(), center, copy.end());
// did we have an odd number of samples?
// if yes, then center is the median
// it no, then we are looking for the average between center and the value before
if(v.size() % 2 == 1)
return *center;
auto center2 = copy.begin() + v.size() / 2 - 1;
std::nth_element(copy.begin(), center2, copy.end());
return (*center + *center2) / 2.0;
}
// Return the sum of the squares of this sample set
auto SumSquares = [](const std::vector<double>& v) {
return std::inner_product(v.begin(), v.end(), v.begin(), 0.0);
};
auto Sqr = [](const double dat) { return dat * dat; };
auto Sqrt = [](const double dat) {
// Avoid NaN due to imprecision in the calculations
if (dat < 0.0) return 0.0;
return std::sqrt(dat);
};
double StatisticsStdDev(const std::vector<double>& v) {
const auto mean = StatisticsMean(v);
if (v.empty()) return mean;
// Sample standard deviation is undefined for n = 1
if (v.size() == 1)
return 0.0;
const double avg_squares = SumSquares(v) * (1.0 / v.size());
return Sqrt(v.size() / (v.size() - 1.0) * (avg_squares - Sqr(mean)));
}
std::vector<BenchmarkReporter::Run> ComputeStats(
const std::vector<BenchmarkReporter::Run>& reports) {
typedef BenchmarkReporter::Run Run;
std::vector<Run> results;
auto error_count =
std::count_if(reports.begin(), reports.end(),
[](Run const& run) { return run.error_occurred; });
if (reports.size() - error_count < 2) {
// We don't report aggregated data if there was a single run.
return results;
}
// Accumulators.
std::vector<double> real_accumulated_time_stat;
std::vector<double> cpu_accumulated_time_stat;
std::vector<double> bytes_per_second_stat;
std::vector<double> items_per_second_stat;
real_accumulated_time_stat.reserve(reports.size());
cpu_accumulated_time_stat.reserve(reports.size());
bytes_per_second_stat.reserve(reports.size());
items_per_second_stat.reserve(reports.size());
// All repetitions should be run with the same number of iterations so we
// can take this information from the first benchmark.
int64_t const run_iterations = reports.front().iterations;
// create stats for user counters
struct CounterStat {
Counter c;
std::vector<double> s;
};
std::map< std::string, CounterStat > counter_stats;
for(Run const& r : reports) {
for(auto const& cnt : r.counters) {
auto it = counter_stats.find(cnt.first);
if(it == counter_stats.end()) {
counter_stats.insert({cnt.first, {cnt.second, std::vector<double>{}}});
it = counter_stats.find(cnt.first);
it->second.s.reserve(reports.size());
} else {
CHECK_EQ(counter_stats[cnt.first].c.flags, cnt.second.flags);
}
}
}
// Populate the accumulators.
for (Run const& run : reports) {
CHECK_EQ(reports[0].benchmark_name, run.benchmark_name);
CHECK_EQ(run_iterations, run.iterations);
if (run.error_occurred) continue;
real_accumulated_time_stat.emplace_back(run.real_accumulated_time);
cpu_accumulated_time_stat.emplace_back(run.cpu_accumulated_time);
items_per_second_stat.emplace_back(run.items_per_second);
bytes_per_second_stat.emplace_back(run.bytes_per_second);
// user counters
for(auto const& cnt : run.counters) {
auto it = counter_stats.find(cnt.first);
CHECK_NE(it, counter_stats.end());
it->second.s.emplace_back(cnt.second);
}
}
// Only add label if it is same for all runs
std::string report_label = reports[0].report_label;
for (std::size_t i = 1; i < reports.size(); i++) {
if (reports[i].report_label != report_label) {
report_label = "";
break;
}
}
for(const auto& Stat : *reports[0].statistics) {
// Get the data from the accumulator to BenchmarkReporter::Run's.
Run data;
data.benchmark_name = reports[0].benchmark_name + "_" + Stat.name_;
data.report_label = report_label;
data.iterations = run_iterations;
data.real_accumulated_time = Stat.compute_(real_accumulated_time_stat);
data.cpu_accumulated_time = Stat.compute_(cpu_accumulated_time_stat);
data.bytes_per_second = Stat.compute_(bytes_per_second_stat);
data.items_per_second = Stat.compute_(items_per_second_stat);
data.time_unit = reports[0].time_unit;
// user counters
for(auto const& kv : counter_stats) {
const auto uc_stat = Stat.compute_(kv.second.s);
auto c = Counter(uc_stat, counter_stats[kv.first].c.flags);
data.counters[kv.first] = c;
}
results.push_back(data);
}
return results;
}
} // end namespace benchmark

View File

@@ -1,37 +0,0 @@
// Copyright 2016 Ismael Jimenez Martinez. All rights reserved.
// Copyright 2017 Roman Lebedev. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef STATISTICS_H_
#define STATISTICS_H_
#include <vector>
#include "benchmark/benchmark.h"
namespace benchmark {
// Return a vector containing the mean, median and standard devation information
// (and any user-specified info) for the specified list of reports. If 'reports'
// contains less than two non-errored runs an empty vector is returned
std::vector<BenchmarkReporter::Run> ComputeStats(
const std::vector<BenchmarkReporter::Run>& reports);
double StatisticsMean(const std::vector<double>& v);
double StatisticsMedian(const std::vector<double>& v);
double StatisticsStdDev(const std::vector<double>& v);
} // end namespace benchmark
#endif // STATISTICS_H_

View File

@@ -1,172 +0,0 @@
#include "string_util.h"
#include <array>
#include <cmath>
#include <cstdarg>
#include <cstdio>
#include <memory>
#include <sstream>
#include "arraysize.h"
namespace benchmark {
namespace {
// kilo, Mega, Giga, Tera, Peta, Exa, Zetta, Yotta.
const char kBigSIUnits[] = "kMGTPEZY";
// Kibi, Mebi, Gibi, Tebi, Pebi, Exbi, Zebi, Yobi.
const char kBigIECUnits[] = "KMGTPEZY";
// milli, micro, nano, pico, femto, atto, zepto, yocto.
const char kSmallSIUnits[] = "munpfazy";
// We require that all three arrays have the same size.
static_assert(arraysize(kBigSIUnits) == arraysize(kBigIECUnits),
"SI and IEC unit arrays must be the same size");
static_assert(arraysize(kSmallSIUnits) == arraysize(kBigSIUnits),
"Small SI and Big SI unit arrays must be the same size");
static const int64_t kUnitsSize = arraysize(kBigSIUnits);
void ToExponentAndMantissa(double val, double thresh, int precision,
double one_k, std::string* mantissa,
int64_t* exponent) {
std::stringstream mantissa_stream;
if (val < 0) {
mantissa_stream << "-";
val = -val;
}
// Adjust threshold so that it never excludes things which can't be rendered
// in 'precision' digits.
const double adjusted_threshold =
std::max(thresh, 1.0 / std::pow(10.0, precision));
const double big_threshold = adjusted_threshold * one_k;
const double small_threshold = adjusted_threshold;
// Values in ]simple_threshold,small_threshold[ will be printed as-is
const double simple_threshold = 0.01;
if (val > big_threshold) {
// Positive powers
double scaled = val;
for (size_t i = 0; i < arraysize(kBigSIUnits); ++i) {
scaled /= one_k;
if (scaled <= big_threshold) {
mantissa_stream << scaled;
*exponent = i + 1;
*mantissa = mantissa_stream.str();
return;
}
}
mantissa_stream << val;
*exponent = 0;
} else if (val < small_threshold) {
// Negative powers
if (val < simple_threshold) {
double scaled = val;
for (size_t i = 0; i < arraysize(kSmallSIUnits); ++i) {
scaled *= one_k;
if (scaled >= small_threshold) {
mantissa_stream << scaled;
*exponent = -static_cast<int64_t>(i + 1);
*mantissa = mantissa_stream.str();
return;
}
}
}
mantissa_stream << val;
*exponent = 0;
} else {
mantissa_stream << val;
*exponent = 0;
}
*mantissa = mantissa_stream.str();
}
std::string ExponentToPrefix(int64_t exponent, bool iec) {
if (exponent == 0) return "";
const int64_t index = (exponent > 0 ? exponent - 1 : -exponent - 1);
if (index >= kUnitsSize) return "";
const char* array =
(exponent > 0 ? (iec ? kBigIECUnits : kBigSIUnits) : kSmallSIUnits);
if (iec)
return array[index] + std::string("i");
else
return std::string(1, array[index]);
}
std::string ToBinaryStringFullySpecified(double value, double threshold,
int precision, double one_k = 1024.0) {
std::string mantissa;
int64_t exponent;
ToExponentAndMantissa(value, threshold, precision, one_k, &mantissa,
&exponent);
return mantissa + ExponentToPrefix(exponent, false);
}
} // end namespace
void AppendHumanReadable(int n, std::string* str) {
std::stringstream ss;
// Round down to the nearest SI prefix.
ss << ToBinaryStringFullySpecified(n, 1.0, 0);
*str += ss.str();
}
std::string HumanReadableNumber(double n, double one_k) {
// 1.1 means that figures up to 1.1k should be shown with the next unit down;
// this softens edge effects.
// 1 means that we should show one decimal place of precision.
return ToBinaryStringFullySpecified(n, 1.1, 1, one_k);
}
std::string StrFormatImp(const char* msg, va_list args) {
// we might need a second shot at this, so pre-emptivly make a copy
va_list args_cp;
va_copy(args_cp, args);
// TODO(ericwf): use std::array for first attempt to avoid one memory
// allocation guess what the size might be
std::array<char, 256> local_buff;
std::size_t size = local_buff.size();
// 2015-10-08: vsnprintf is used instead of snd::vsnprintf due to a limitation
// in the android-ndk
auto ret = vsnprintf(local_buff.data(), size, msg, args_cp);
va_end(args_cp);
// handle empty expansion
if (ret == 0) return std::string{};
if (static_cast<std::size_t>(ret) < size)
return std::string(local_buff.data());
// we did not provide a long enough buffer on our first attempt.
// add 1 to size to account for null-byte in size cast to prevent overflow
size = static_cast<std::size_t>(ret) + 1;
auto buff_ptr = std::unique_ptr<char[]>(new char[size]);
// 2015-10-08: vsnprintf is used instead of snd::vsnprintf due to a limitation
// in the android-ndk
ret = vsnprintf(buff_ptr.get(), size, msg, args);
return std::string(buff_ptr.get());
}
std::string StrFormat(const char* format, ...) {
va_list args;
va_start(args, format);
std::string tmp = StrFormatImp(format, args);
va_end(args);
return tmp;
}
void ReplaceAll(std::string* str, const std::string& from,
const std::string& to) {
std::size_t start = 0;
while ((start = str->find(from, start)) != std::string::npos) {
str->replace(start, from.length(), to);
start += to.length();
}
}
} // end namespace benchmark

View File

@@ -1,40 +0,0 @@
#ifndef BENCHMARK_STRING_UTIL_H_
#define BENCHMARK_STRING_UTIL_H_
#include <sstream>
#include <string>
#include <utility>
#include "internal_macros.h"
namespace benchmark {
void AppendHumanReadable(int n, std::string* str);
std::string HumanReadableNumber(double n, double one_k = 1024.0);
std::string StrFormat(const char* format, ...);
inline std::ostream& StrCatImp(std::ostream& out) BENCHMARK_NOEXCEPT {
return out;
}
template <class First, class... Rest>
inline std::ostream& StrCatImp(std::ostream& out, First&& f,
Rest&&... rest) {
out << std::forward<First>(f);
return StrCatImp(out, std::forward<Rest>(rest)...);
}
template <class... Args>
inline std::string StrCat(Args&&... args) {
std::ostringstream ss;
StrCatImp(ss, std::forward<Args>(args)...);
return ss.str();
}
void ReplaceAll(std::string* str, const std::string& from,
const std::string& to);
} // end namespace benchmark
#endif // BENCHMARK_STRING_UTIL_H_

View File

@@ -1,587 +0,0 @@
// Copyright 2015 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "internal_macros.h"
#ifdef BENCHMARK_OS_WINDOWS
#include <Shlwapi.h>
#undef StrCat // Don't let StrCat in string_util.h be renamed to lstrcatA
#include <VersionHelpers.h>
#include <Windows.h>
#else
#include <fcntl.h>
#ifndef BENCHMARK_OS_FUCHSIA
#include <sys/resource.h>
#endif
#include <sys/time.h>
#include <sys/types.h> // this header must be included before 'sys/sysctl.h' to avoid compilation error on FreeBSD
#include <unistd.h>
#if defined BENCHMARK_OS_FREEBSD || defined BENCHMARK_OS_MACOSX || \
defined BENCHMARK_OS_NETBSD || defined BENCHMARK_OS_OPENBSD
#define BENCHMARK_HAS_SYSCTL
#include <sys/sysctl.h>
#endif
#endif
#if defined(BENCHMARK_OS_SOLARIS)
#include <kstat.h>
#endif
#include <algorithm>
#include <array>
#include <bitset>
#include <cerrno>
#include <climits>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <fstream>
#include <iostream>
#include <iterator>
#include <limits>
#include <memory>
#include <sstream>
#include "check.h"
#include "cycleclock.h"
#include "internal_macros.h"
#include "log.h"
#include "sleep.h"
#include "string_util.h"
namespace benchmark {
namespace {
void PrintImp(std::ostream& out) { out << std::endl; }
template <class First, class... Rest>
void PrintImp(std::ostream& out, First&& f, Rest&&... rest) {
out << std::forward<First>(f);
PrintImp(out, std::forward<Rest>(rest)...);
}
template <class... Args>
BENCHMARK_NORETURN void PrintErrorAndDie(Args&&... args) {
PrintImp(std::cerr, std::forward<Args>(args)...);
std::exit(EXIT_FAILURE);
}
#ifdef BENCHMARK_HAS_SYSCTL
/// ValueUnion - A type used to correctly alias the byte-for-byte output of
/// `sysctl` with the result type it's to be interpreted as.
struct ValueUnion {
union DataT {
uint32_t uint32_value;
uint64_t uint64_value;
// For correct aliasing of union members from bytes.
char bytes[8];
};
using DataPtr = std::unique_ptr<DataT, decltype(&std::free)>;
// The size of the data union member + its trailing array size.
size_t Size;
DataPtr Buff;
public:
ValueUnion() : Size(0), Buff(nullptr, &std::free) {}
explicit ValueUnion(size_t BuffSize)
: Size(sizeof(DataT) + BuffSize),
Buff(::new (std::malloc(Size)) DataT(), &std::free) {}
ValueUnion(ValueUnion&& other) = default;
explicit operator bool() const { return bool(Buff); }
char* data() const { return Buff->bytes; }
std::string GetAsString() const { return std::string(data()); }
int64_t GetAsInteger() const {
if (Size == sizeof(Buff->uint32_value))
return static_cast<int32_t>(Buff->uint32_value);
else if (Size == sizeof(Buff->uint64_value))
return static_cast<int64_t>(Buff->uint64_value);
BENCHMARK_UNREACHABLE();
}
uint64_t GetAsUnsigned() const {
if (Size == sizeof(Buff->uint32_value))
return Buff->uint32_value;
else if (Size == sizeof(Buff->uint64_value))
return Buff->uint64_value;
BENCHMARK_UNREACHABLE();
}
template <class T, int N>
std::array<T, N> GetAsArray() {
const int ArrSize = sizeof(T) * N;
CHECK_LE(ArrSize, Size);
std::array<T, N> Arr;
std::memcpy(Arr.data(), data(), ArrSize);
return Arr;
}
};
ValueUnion GetSysctlImp(std::string const& Name) {
#if defined BENCHMARK_OS_OPENBSD
int mib[2];
mib[0] = CTL_HW;
if ((Name == "hw.ncpu") || (Name == "hw.cpuspeed")){
ValueUnion buff(sizeof(int));
if (Name == "hw.ncpu") {
mib[1] = HW_NCPU;
} else {
mib[1] = HW_CPUSPEED;
}
if (sysctl(mib, 2, buff.data(), &buff.Size, nullptr, 0) == -1) {
return ValueUnion();
}
return buff;
}
return ValueUnion();
#else
size_t CurBuffSize = 0;
if (sysctlbyname(Name.c_str(), nullptr, &CurBuffSize, nullptr, 0) == -1)
return ValueUnion();
ValueUnion buff(CurBuffSize);
if (sysctlbyname(Name.c_str(), buff.data(), &buff.Size, nullptr, 0) == 0)
return buff;
return ValueUnion();
#endif
}
BENCHMARK_MAYBE_UNUSED
bool GetSysctl(std::string const& Name, std::string* Out) {
Out->clear();
auto Buff = GetSysctlImp(Name);
if (!Buff) return false;
Out->assign(Buff.data());
return true;
}
template <class Tp,
class = typename std::enable_if<std::is_integral<Tp>::value>::type>
bool GetSysctl(std::string const& Name, Tp* Out) {
*Out = 0;
auto Buff = GetSysctlImp(Name);
if (!Buff) return false;
*Out = static_cast<Tp>(Buff.GetAsUnsigned());
return true;
}
template <class Tp, size_t N>
bool GetSysctl(std::string const& Name, std::array<Tp, N>* Out) {
auto Buff = GetSysctlImp(Name);
if (!Buff) return false;
*Out = Buff.GetAsArray<Tp, N>();
return true;
}
#endif
template <class ArgT>
bool ReadFromFile(std::string const& fname, ArgT* arg) {
*arg = ArgT();
std::ifstream f(fname.c_str());
if (!f.is_open()) return false;
f >> *arg;
return f.good();
}
bool CpuScalingEnabled(int num_cpus) {
// We don't have a valid CPU count, so don't even bother.
if (num_cpus <= 0) return false;
#ifndef BENCHMARK_OS_WINDOWS
// On Linux, the CPUfreq subsystem exposes CPU information as files on the
// local file system. If reading the exported files fails, then we may not be
// running on Linux, so we silently ignore all the read errors.
std::string res;
for (int cpu = 0; cpu < num_cpus; ++cpu) {
std::string governor_file =
StrCat("/sys/devices/system/cpu/cpu", cpu, "/cpufreq/scaling_governor");
if (ReadFromFile(governor_file, &res) && res != "performance") return true;
}
#endif
return false;
}
int CountSetBitsInCPUMap(std::string Val) {
auto CountBits = [](std::string Part) {
using CPUMask = std::bitset<sizeof(std::uintptr_t) * CHAR_BIT>;
Part = "0x" + Part;
CPUMask Mask(std::stoul(Part, nullptr, 16));
return static_cast<int>(Mask.count());
};
size_t Pos;
int total = 0;
while ((Pos = Val.find(',')) != std::string::npos) {
total += CountBits(Val.substr(0, Pos));
Val = Val.substr(Pos + 1);
}
if (!Val.empty()) {
total += CountBits(Val);
}
return total;
}
BENCHMARK_MAYBE_UNUSED
std::vector<CPUInfo::CacheInfo> GetCacheSizesFromKVFS() {
std::vector<CPUInfo::CacheInfo> res;
std::string dir = "/sys/devices/system/cpu/cpu0/cache/";
int Idx = 0;
while (true) {
CPUInfo::CacheInfo info;
std::string FPath = StrCat(dir, "index", Idx++, "/");
std::ifstream f(StrCat(FPath, "size").c_str());
if (!f.is_open()) break;
std::string suffix;
f >> info.size;
if (f.fail())
PrintErrorAndDie("Failed while reading file '", FPath, "size'");
if (f.good()) {
f >> suffix;
if (f.bad())
PrintErrorAndDie(
"Invalid cache size format: failed to read size suffix");
else if (f && suffix != "K")
PrintErrorAndDie("Invalid cache size format: Expected bytes ", suffix);
else if (suffix == "K")
info.size *= 1000;
}
if (!ReadFromFile(StrCat(FPath, "type"), &info.type))
PrintErrorAndDie("Failed to read from file ", FPath, "type");
if (!ReadFromFile(StrCat(FPath, "level"), &info.level))
PrintErrorAndDie("Failed to read from file ", FPath, "level");
std::string map_str;
if (!ReadFromFile(StrCat(FPath, "shared_cpu_map"), &map_str))
PrintErrorAndDie("Failed to read from file ", FPath, "shared_cpu_map");
info.num_sharing = CountSetBitsInCPUMap(map_str);
res.push_back(info);
}
return res;
}
#ifdef BENCHMARK_OS_MACOSX
std::vector<CPUInfo::CacheInfo> GetCacheSizesMacOSX() {
std::vector<CPUInfo::CacheInfo> res;
std::array<uint64_t, 4> CacheCounts{{0, 0, 0, 0}};
GetSysctl("hw.cacheconfig", &CacheCounts);
struct {
std::string name;
std::string type;
int level;
size_t num_sharing;
} Cases[] = {{"hw.l1dcachesize", "Data", 1, CacheCounts[1]},
{"hw.l1icachesize", "Instruction", 1, CacheCounts[1]},
{"hw.l2cachesize", "Unified", 2, CacheCounts[2]},
{"hw.l3cachesize", "Unified", 3, CacheCounts[3]}};
for (auto& C : Cases) {
int val;
if (!GetSysctl(C.name, &val)) continue;
CPUInfo::CacheInfo info;
info.type = C.type;
info.level = C.level;
info.size = val;
info.num_sharing = static_cast<int>(C.num_sharing);
res.push_back(std::move(info));
}
return res;
}
#elif defined(BENCHMARK_OS_WINDOWS)
std::vector<CPUInfo::CacheInfo> GetCacheSizesWindows() {
std::vector<CPUInfo::CacheInfo> res;
DWORD buffer_size = 0;
using PInfo = SYSTEM_LOGICAL_PROCESSOR_INFORMATION;
using CInfo = CACHE_DESCRIPTOR;
using UPtr = std::unique_ptr<PInfo, decltype(&std::free)>;
GetLogicalProcessorInformation(nullptr, &buffer_size);
UPtr buff((PInfo*)malloc(buffer_size), &std::free);
if (!GetLogicalProcessorInformation(buff.get(), &buffer_size))
PrintErrorAndDie("Failed during call to GetLogicalProcessorInformation: ",
GetLastError());
PInfo* it = buff.get();
PInfo* end = buff.get() + (buffer_size / sizeof(PInfo));
for (; it != end; ++it) {
if (it->Relationship != RelationCache) continue;
using BitSet = std::bitset<sizeof(ULONG_PTR) * CHAR_BIT>;
BitSet B(it->ProcessorMask);
// To prevent duplicates, only consider caches where CPU 0 is specified
if (!B.test(0)) continue;
CInfo* Cache = &it->Cache;
CPUInfo::CacheInfo C;
C.num_sharing = static_cast<int>(B.count());
C.level = Cache->Level;
C.size = Cache->Size;
switch (Cache->Type) {
case CacheUnified:
C.type = "Unified";
break;
case CacheInstruction:
C.type = "Instruction";
break;
case CacheData:
C.type = "Data";
break;
case CacheTrace:
C.type = "Trace";
break;
default:
C.type = "Unknown";
break;
}
res.push_back(C);
}
return res;
}
#endif
std::vector<CPUInfo::CacheInfo> GetCacheSizes() {
#ifdef BENCHMARK_OS_MACOSX
return GetCacheSizesMacOSX();
#elif defined(BENCHMARK_OS_WINDOWS)
return GetCacheSizesWindows();
#else
return GetCacheSizesFromKVFS();
#endif
}
int GetNumCPUs() {
#ifdef BENCHMARK_HAS_SYSCTL
int NumCPU = -1;
if (GetSysctl("hw.ncpu", &NumCPU)) return NumCPU;
fprintf(stderr, "Err: %s\n", strerror(errno));
std::exit(EXIT_FAILURE);
#elif defined(BENCHMARK_OS_WINDOWS)
SYSTEM_INFO sysinfo;
// Use memset as opposed to = {} to avoid GCC missing initializer false
// positives.
std::memset(&sysinfo, 0, sizeof(SYSTEM_INFO));
GetSystemInfo(&sysinfo);
return sysinfo.dwNumberOfProcessors; // number of logical
// processors in the current
// group
#elif defined(BENCHMARK_OS_SOLARIS)
// Returns -1 in case of a failure.
int NumCPU = sysconf(_SC_NPROCESSORS_ONLN);
if (NumCPU < 0) {
fprintf(stderr,
"sysconf(_SC_NPROCESSORS_ONLN) failed with error: %s\n",
strerror(errno));
}
return NumCPU;
#else
int NumCPUs = 0;
int MaxID = -1;
std::ifstream f("/proc/cpuinfo");
if (!f.is_open()) {
std::cerr << "failed to open /proc/cpuinfo\n";
return -1;
}
const std::string Key = "processor";
std::string ln;
while (std::getline(f, ln)) {
if (ln.empty()) continue;
size_t SplitIdx = ln.find(':');
std::string value;
if (SplitIdx != std::string::npos) value = ln.substr(SplitIdx + 1);
if (ln.size() >= Key.size() && ln.compare(0, Key.size(), Key) == 0) {
NumCPUs++;
if (!value.empty()) {
int CurID = std::stoi(value);
MaxID = std::max(CurID, MaxID);
}
}
}
if (f.bad()) {
std::cerr << "Failure reading /proc/cpuinfo\n";
return -1;
}
if (!f.eof()) {
std::cerr << "Failed to read to end of /proc/cpuinfo\n";
return -1;
}
f.close();
if ((MaxID + 1) != NumCPUs) {
fprintf(stderr,
"CPU ID assignments in /proc/cpuinfo seem messed up."
" This is usually caused by a bad BIOS.\n");
}
return NumCPUs;
#endif
BENCHMARK_UNREACHABLE();
}
double GetCPUCyclesPerSecond() {
#if defined BENCHMARK_OS_LINUX || defined BENCHMARK_OS_CYGWIN
long freq;
// If the kernel is exporting the tsc frequency use that. There are issues
// where cpuinfo_max_freq cannot be relied on because the BIOS may be
// exporintg an invalid p-state (on x86) or p-states may be used to put the
// processor in a new mode (turbo mode). Essentially, those frequencies
// cannot always be relied upon. The same reasons apply to /proc/cpuinfo as
// well.
if (ReadFromFile("/sys/devices/system/cpu/cpu0/tsc_freq_khz", &freq)
// If CPU scaling is in effect, we want to use the *maximum* frequency,
// not whatever CPU speed some random processor happens to be using now.
|| ReadFromFile("/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq",
&freq)) {
// The value is in kHz (as the file name suggests). For example, on a
// 2GHz warpstation, the file contains the value "2000000".
return freq * 1000.0;
}
const double error_value = -1;
double bogo_clock = error_value;
std::ifstream f("/proc/cpuinfo");
if (!f.is_open()) {
std::cerr << "failed to open /proc/cpuinfo\n";
return error_value;
}
auto startsWithKey = [](std::string const& Value, std::string const& Key) {
if (Key.size() > Value.size()) return false;
auto Cmp = [&](char X, char Y) {
return std::tolower(X) == std::tolower(Y);
};
return std::equal(Key.begin(), Key.end(), Value.begin(), Cmp);
};
std::string ln;
while (std::getline(f, ln)) {
if (ln.empty()) continue;
size_t SplitIdx = ln.find(':');
std::string value;
if (SplitIdx != std::string::npos) value = ln.substr(SplitIdx + 1);
// When parsing the "cpu MHz" and "bogomips" (fallback) entries, we only
// accept positive values. Some environments (virtual machines) report zero,
// which would cause infinite looping in WallTime_Init.
if (startsWithKey(ln, "cpu MHz")) {
if (!value.empty()) {
double cycles_per_second = std::stod(value) * 1000000.0;
if (cycles_per_second > 0) return cycles_per_second;
}
} else if (startsWithKey(ln, "bogomips")) {
if (!value.empty()) {
bogo_clock = std::stod(value) * 1000000.0;
if (bogo_clock < 0.0) bogo_clock = error_value;
}
}
}
if (f.bad()) {
std::cerr << "Failure reading /proc/cpuinfo\n";
return error_value;
}
if (!f.eof()) {
std::cerr << "Failed to read to end of /proc/cpuinfo\n";
return error_value;
}
f.close();
// If we found the bogomips clock, but nothing better, we'll use it (but
// we're not happy about it); otherwise, fallback to the rough estimation
// below.
if (bogo_clock >= 0.0) return bogo_clock;
#elif defined BENCHMARK_HAS_SYSCTL
constexpr auto* FreqStr =
#if defined(BENCHMARK_OS_FREEBSD) || defined(BENCHMARK_OS_NETBSD)
"machdep.tsc_freq";
#elif defined BENCHMARK_OS_OPENBSD
"hw.cpuspeed";
#else
"hw.cpufrequency";
#endif
unsigned long long hz = 0;
#if defined BENCHMARK_OS_OPENBSD
if (GetSysctl(FreqStr, &hz)) return hz * 1000000;
#else
if (GetSysctl(FreqStr, &hz)) return hz;
#endif
fprintf(stderr, "Unable to determine clock rate from sysctl: %s: %s\n",
FreqStr, strerror(errno));
#elif defined BENCHMARK_OS_WINDOWS
// In NT, read MHz from the registry. If we fail to do so or we're in win9x
// then make a crude estimate.
DWORD data, data_size = sizeof(data);
if (IsWindowsXPOrGreater() &&
SUCCEEDED(
SHGetValueA(HKEY_LOCAL_MACHINE,
"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0",
"~MHz", nullptr, &data, &data_size)))
return static_cast<double>((int64_t)data *
(int64_t)(1000 * 1000)); // was mhz
#elif defined (BENCHMARK_OS_SOLARIS)
kstat_ctl_t *kc = kstat_open();
if (!kc) {
std::cerr << "failed to open /dev/kstat\n";
return -1;
}
kstat_t *ksp = kstat_lookup(kc, (char*)"cpu_info", -1, (char*)"cpu_info0");
if (!ksp) {
std::cerr << "failed to lookup in /dev/kstat\n";
return -1;
}
if (kstat_read(kc, ksp, NULL) < 0) {
std::cerr << "failed to read from /dev/kstat\n";
return -1;
}
kstat_named_t *knp =
(kstat_named_t*)kstat_data_lookup(ksp, (char*)"current_clock_Hz");
if (!knp) {
std::cerr << "failed to lookup data in /dev/kstat\n";
return -1;
}
if (knp->data_type != KSTAT_DATA_UINT64) {
std::cerr << "current_clock_Hz is of unexpected data type: "
<< knp->data_type << "\n";
return -1;
}
double clock_hz = knp->value.ui64;
kstat_close(kc);
return clock_hz;
#endif
// If we've fallen through, attempt to roughly estimate the CPU clock rate.
const int estimate_time_ms = 1000;
const auto start_ticks = cycleclock::Now();
SleepForMilliseconds(estimate_time_ms);
return static_cast<double>(cycleclock::Now() - start_ticks);
}
} // end namespace
const CPUInfo& CPUInfo::Get() {
static const CPUInfo* info = new CPUInfo();
return *info;
}
CPUInfo::CPUInfo()
: num_cpus(GetNumCPUs()),
cycles_per_second(GetCPUCyclesPerSecond()),
caches(GetCacheSizes()),
scaling_enabled(CpuScalingEnabled(num_cpus)) {}
} // end namespace benchmark

View File

@@ -1,66 +0,0 @@
#ifndef BENCHMARK_THREAD_MANAGER_H
#define BENCHMARK_THREAD_MANAGER_H
#include <atomic>
#include "benchmark/benchmark.h"
#include "mutex.h"
namespace benchmark {
namespace internal {
class ThreadManager {
public:
ThreadManager(int num_threads)
: alive_threads_(num_threads), start_stop_barrier_(num_threads) {}
Mutex& GetBenchmarkMutex() const RETURN_CAPABILITY(benchmark_mutex_) {
return benchmark_mutex_;
}
bool StartStopBarrier() EXCLUDES(end_cond_mutex_) {
return start_stop_barrier_.wait();
}
void NotifyThreadComplete() EXCLUDES(end_cond_mutex_) {
start_stop_barrier_.removeThread();
if (--alive_threads_ == 0) {
MutexLock lock(end_cond_mutex_);
end_condition_.notify_all();
}
}
void WaitForAllThreads() EXCLUDES(end_cond_mutex_) {
MutexLock lock(end_cond_mutex_);
end_condition_.wait(lock.native_handle(),
[this]() { return alive_threads_ == 0; });
}
public:
struct Result {
int64_t iterations = 0;
double real_time_used = 0;
double cpu_time_used = 0;
double manual_time_used = 0;
int64_t bytes_processed = 0;
int64_t items_processed = 0;
int64_t complexity_n = 0;
std::string report_label_;
std::string error_message_;
bool has_error_ = false;
UserCounters counters;
};
GUARDED_BY(GetBenchmarkMutex()) Result results;
private:
mutable Mutex benchmark_mutex_;
std::atomic<int> alive_threads_;
Barrier start_stop_barrier_;
Mutex end_cond_mutex_;
Condition end_condition_;
};
} // namespace internal
} // namespace benchmark
#endif // BENCHMARK_THREAD_MANAGER_H

View File

@@ -1,69 +0,0 @@
#ifndef BENCHMARK_THREAD_TIMER_H
#define BENCHMARK_THREAD_TIMER_H
#include "check.h"
#include "timers.h"
namespace benchmark {
namespace internal {
class ThreadTimer {
public:
ThreadTimer() = default;
// Called by each thread
void StartTimer() {
running_ = true;
start_real_time_ = ChronoClockNow();
start_cpu_time_ = ThreadCPUUsage();
}
// Called by each thread
void StopTimer() {
CHECK(running_);
running_ = false;
real_time_used_ += ChronoClockNow() - start_real_time_;
// Floating point error can result in the subtraction producing a negative
// time. Guard against that.
cpu_time_used_ += std::max<double>(ThreadCPUUsage() - start_cpu_time_, 0);
}
// Called by each thread
void SetIterationTime(double seconds) { manual_time_used_ += seconds; }
bool running() const { return running_; }
// REQUIRES: timer is not running
double real_time_used() {
CHECK(!running_);
return real_time_used_;
}
// REQUIRES: timer is not running
double cpu_time_used() {
CHECK(!running_);
return cpu_time_used_;
}
// REQUIRES: timer is not running
double manual_time_used() {
CHECK(!running_);
return manual_time_used_;
}
private:
bool running_ = false; // Is the timer running
double start_real_time_ = 0; // If running_
double start_cpu_time_ = 0; // If running_
// Accumulated time so far (does not contain current slice if running_)
double real_time_used_ = 0;
double cpu_time_used_ = 0;
// Manually set iteration time. User sets this with SetIterationTime(seconds).
double manual_time_used_ = 0;
};
} // namespace internal
} // namespace benchmark
#endif // BENCHMARK_THREAD_TIMER_H

View File

@@ -1,217 +0,0 @@
// Copyright 2015 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "timers.h"
#include "internal_macros.h"
#ifdef BENCHMARK_OS_WINDOWS
#include <Shlwapi.h>
#undef StrCat // Don't let StrCat in string_util.h be renamed to lstrcatA
#include <VersionHelpers.h>
#include <Windows.h>
#else
#include <fcntl.h>
#ifndef BENCHMARK_OS_FUCHSIA
#include <sys/resource.h>
#endif
#include <sys/time.h>
#include <sys/types.h> // this header must be included before 'sys/sysctl.h' to avoid compilation error on FreeBSD
#include <unistd.h>
#if defined BENCHMARK_OS_FREEBSD || defined BENCHMARK_OS_MACOSX
#include <sys/sysctl.h>
#endif
#if defined(BENCHMARK_OS_MACOSX)
#include <mach/mach_init.h>
#include <mach/mach_port.h>
#include <mach/thread_act.h>
#endif
#endif
#ifdef BENCHMARK_OS_EMSCRIPTEN
#include <emscripten.h>
#endif
#include <cerrno>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <iostream>
#include <limits>
#include <mutex>
#include "check.h"
#include "log.h"
#include "sleep.h"
#include "string_util.h"
namespace benchmark {
// Suppress unused warnings on helper functions.
#if defined(__GNUC__)
#pragma GCC diagnostic ignored "-Wunused-function"
#endif
namespace {
#if defined(BENCHMARK_OS_WINDOWS)
double MakeTime(FILETIME const& kernel_time, FILETIME const& user_time) {
ULARGE_INTEGER kernel;
ULARGE_INTEGER user;
kernel.HighPart = kernel_time.dwHighDateTime;
kernel.LowPart = kernel_time.dwLowDateTime;
user.HighPart = user_time.dwHighDateTime;
user.LowPart = user_time.dwLowDateTime;
return (static_cast<double>(kernel.QuadPart) +
static_cast<double>(user.QuadPart)) *
1e-7;
}
#elif !defined(BENCHMARK_OS_FUCHSIA)
double MakeTime(struct rusage const& ru) {
return (static_cast<double>(ru.ru_utime.tv_sec) +
static_cast<double>(ru.ru_utime.tv_usec) * 1e-6 +
static_cast<double>(ru.ru_stime.tv_sec) +
static_cast<double>(ru.ru_stime.tv_usec) * 1e-6);
}
#endif
#if defined(BENCHMARK_OS_MACOSX)
double MakeTime(thread_basic_info_data_t const& info) {
return (static_cast<double>(info.user_time.seconds) +
static_cast<double>(info.user_time.microseconds) * 1e-6 +
static_cast<double>(info.system_time.seconds) +
static_cast<double>(info.system_time.microseconds) * 1e-6);
}
#endif
#if defined(CLOCK_PROCESS_CPUTIME_ID) || defined(CLOCK_THREAD_CPUTIME_ID)
double MakeTime(struct timespec const& ts) {
return ts.tv_sec + (static_cast<double>(ts.tv_nsec) * 1e-9);
}
#endif
BENCHMARK_NORETURN static void DiagnoseAndExit(const char* msg) {
std::cerr << "ERROR: " << msg << std::endl;
std::exit(EXIT_FAILURE);
}
} // end namespace
double ProcessCPUUsage() {
#if defined(BENCHMARK_OS_WINDOWS)
HANDLE proc = GetCurrentProcess();
FILETIME creation_time;
FILETIME exit_time;
FILETIME kernel_time;
FILETIME user_time;
if (GetProcessTimes(proc, &creation_time, &exit_time, &kernel_time,
&user_time))
return MakeTime(kernel_time, user_time);
DiagnoseAndExit("GetProccessTimes() failed");
#elif defined(BENCHMARK_OS_EMSCRIPTEN)
// clock_gettime(CLOCK_PROCESS_CPUTIME_ID, ...) returns 0 on Emscripten.
// Use Emscripten-specific API. Reported CPU time would be exactly the
// same as total time, but this is ok because there aren't long-latency
// syncronous system calls in Emscripten.
return emscripten_get_now() * 1e-3;
#elif defined(CLOCK_PROCESS_CPUTIME_ID) && !defined(BENCHMARK_OS_MACOSX)
// FIXME We want to use clock_gettime, but its not available in MacOS 10.11. See
// https://github.com/google/benchmark/pull/292
struct timespec spec;
if (clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &spec) == 0)
return MakeTime(spec);
DiagnoseAndExit("clock_gettime(CLOCK_PROCESS_CPUTIME_ID, ...) failed");
#else
struct rusage ru;
if (getrusage(RUSAGE_SELF, &ru) == 0) return MakeTime(ru);
DiagnoseAndExit("getrusage(RUSAGE_SELF, ...) failed");
#endif
}
double ThreadCPUUsage() {
#if defined(BENCHMARK_OS_WINDOWS)
HANDLE this_thread = GetCurrentThread();
FILETIME creation_time;
FILETIME exit_time;
FILETIME kernel_time;
FILETIME user_time;
GetThreadTimes(this_thread, &creation_time, &exit_time, &kernel_time,
&user_time);
return MakeTime(kernel_time, user_time);
#elif defined(BENCHMARK_OS_MACOSX)
// FIXME We want to use clock_gettime, but its not available in MacOS 10.11. See
// https://github.com/google/benchmark/pull/292
mach_msg_type_number_t count = THREAD_BASIC_INFO_COUNT;
thread_basic_info_data_t info;
mach_port_t thread = pthread_mach_thread_np(pthread_self());
if (thread_info(thread, THREAD_BASIC_INFO, (thread_info_t)&info, &count) ==
KERN_SUCCESS) {
return MakeTime(info);
}
DiagnoseAndExit("ThreadCPUUsage() failed when evaluating thread_info");
#elif defined(BENCHMARK_OS_EMSCRIPTEN)
// Emscripten doesn't support traditional threads
return ProcessCPUUsage();
#elif defined(BENCHMARK_OS_RTEMS)
// RTEMS doesn't support CLOCK_THREAD_CPUTIME_ID. See
// https://github.com/RTEMS/rtems/blob/master/cpukit/posix/src/clockgettime.c
return ProcessCPUUsage();
#elif defined(BENCHMARK_OS_SOLARIS)
struct rusage ru;
if (getrusage(RUSAGE_LWP, &ru) == 0) return MakeTime(ru);
DiagnoseAndExit("getrusage(RUSAGE_LWP, ...) failed");
#elif defined(CLOCK_THREAD_CPUTIME_ID)
struct timespec ts;
if (clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts) == 0) return MakeTime(ts);
DiagnoseAndExit("clock_gettime(CLOCK_THREAD_CPUTIME_ID, ...) failed");
#else
#error Per-thread timing is not available on your system.
#endif
}
namespace {
std::string DateTimeString(bool local) {
typedef std::chrono::system_clock Clock;
std::time_t now = Clock::to_time_t(Clock::now());
const std::size_t kStorageSize = 128;
char storage[kStorageSize];
std::size_t written;
if (local) {
#if defined(BENCHMARK_OS_WINDOWS)
written =
std::strftime(storage, sizeof(storage), "%x %X", ::localtime(&now));
#else
std::tm timeinfo;
::localtime_r(&now, &timeinfo);
written = std::strftime(storage, sizeof(storage), "%F %T", &timeinfo);
#endif
} else {
#if defined(BENCHMARK_OS_WINDOWS)
written = std::strftime(storage, sizeof(storage), "%x %X", ::gmtime(&now));
#else
std::tm timeinfo;
::gmtime_r(&now, &timeinfo);
written = std::strftime(storage, sizeof(storage), "%F %T", &timeinfo);
#endif
}
CHECK(written < kStorageSize);
((void)written); // prevent unused variable in optimized mode.
return std::string(storage);
}
} // end namespace
std::string LocalDateTimeString() { return DateTimeString(true); }
} // end namespace benchmark

View File

@@ -1,48 +0,0 @@
#ifndef BENCHMARK_TIMERS_H
#define BENCHMARK_TIMERS_H
#include <chrono>
#include <string>
namespace benchmark {
// Return the CPU usage of the current process
double ProcessCPUUsage();
// Return the CPU usage of the children of the current process
double ChildrenCPUUsage();
// Return the CPU usage of the current thread
double ThreadCPUUsage();
#if defined(HAVE_STEADY_CLOCK)
template <bool HighResIsSteady = std::chrono::high_resolution_clock::is_steady>
struct ChooseSteadyClock {
typedef std::chrono::high_resolution_clock type;
};
template <>
struct ChooseSteadyClock<false> {
typedef std::chrono::steady_clock type;
};
#endif
struct ChooseClockType {
#if defined(HAVE_STEADY_CLOCK)
typedef ChooseSteadyClock<>::type type;
#else
typedef std::chrono::high_resolution_clock type;
#endif
};
inline double ChronoClockNow() {
typedef ChooseClockType::type ClockType;
using FpSeconds = std::chrono::duration<double, std::chrono::seconds::period>;
return FpSeconds(ClockType::now().time_since_epoch()).count();
}
std::string LocalDateTimeString();
} // end namespace benchmark
#endif // BENCHMARK_TIMERS_H

View File

@@ -1,316 +0,0 @@
#!/usr/bin/env python
"""
compare.py - versatile benchmark output compare tool
"""
import argparse
from argparse import ArgumentParser
import sys
import gbench
from gbench import util, report
from gbench.util import *
def check_inputs(in1, in2, flags):
"""
Perform checking on the user provided inputs and diagnose any abnormalities
"""
in1_kind, in1_err = classify_input_file(in1)
in2_kind, in2_err = classify_input_file(in2)
output_file = find_benchmark_flag('--benchmark_out=', flags)
output_type = find_benchmark_flag('--benchmark_out_format=', flags)
if in1_kind == IT_Executable and in2_kind == IT_Executable and output_file:
print(("WARNING: '--benchmark_out=%s' will be passed to both "
"benchmarks causing it to be overwritten") % output_file)
if in1_kind == IT_JSON and in2_kind == IT_JSON and len(flags) > 0:
print("WARNING: passing optional flags has no effect since both "
"inputs are JSON")
if output_type is not None and output_type != 'json':
print(("ERROR: passing '--benchmark_out_format=%s' to 'compare.py`"
" is not supported.") % output_type)
sys.exit(1)
def create_parser():
parser = ArgumentParser(
description='versatile benchmark output compare tool')
subparsers = parser.add_subparsers(
help='This tool has multiple modes of operation:',
dest='mode')
parser_a = subparsers.add_parser(
'benchmarks',
help='The most simple use-case, compare all the output of these two benchmarks')
baseline = parser_a.add_argument_group(
'baseline', 'The benchmark baseline')
baseline.add_argument(
'test_baseline',
metavar='test_baseline',
type=argparse.FileType('r'),
nargs=1,
help='A benchmark executable or JSON output file')
contender = parser_a.add_argument_group(
'contender', 'The benchmark that will be compared against the baseline')
contender.add_argument(
'test_contender',
metavar='test_contender',
type=argparse.FileType('r'),
nargs=1,
help='A benchmark executable or JSON output file')
parser_a.add_argument(
'benchmark_options',
metavar='benchmark_options',
nargs=argparse.REMAINDER,
help='Arguments to pass when running benchmark executables')
parser_b = subparsers.add_parser(
'filters', help='Compare filter one with the filter two of benchmark')
baseline = parser_b.add_argument_group(
'baseline', 'The benchmark baseline')
baseline.add_argument(
'test',
metavar='test',
type=argparse.FileType('r'),
nargs=1,
help='A benchmark executable or JSON output file')
baseline.add_argument(
'filter_baseline',
metavar='filter_baseline',
type=str,
nargs=1,
help='The first filter, that will be used as baseline')
contender = parser_b.add_argument_group(
'contender', 'The benchmark that will be compared against the baseline')
contender.add_argument(
'filter_contender',
metavar='filter_contender',
type=str,
nargs=1,
help='The second filter, that will be compared against the baseline')
parser_b.add_argument(
'benchmark_options',
metavar='benchmark_options',
nargs=argparse.REMAINDER,
help='Arguments to pass when running benchmark executables')
parser_c = subparsers.add_parser(
'benchmarksfiltered',
help='Compare filter one of first benchmark with filter two of the second benchmark')
baseline = parser_c.add_argument_group(
'baseline', 'The benchmark baseline')
baseline.add_argument(
'test_baseline',
metavar='test_baseline',
type=argparse.FileType('r'),
nargs=1,
help='A benchmark executable or JSON output file')
baseline.add_argument(
'filter_baseline',
metavar='filter_baseline',
type=str,
nargs=1,
help='The first filter, that will be used as baseline')
contender = parser_c.add_argument_group(
'contender', 'The benchmark that will be compared against the baseline')
contender.add_argument(
'test_contender',
metavar='test_contender',
type=argparse.FileType('r'),
nargs=1,
help='The second benchmark executable or JSON output file, that will be compared against the baseline')
contender.add_argument(
'filter_contender',
metavar='filter_contender',
type=str,
nargs=1,
help='The second filter, that will be compared against the baseline')
parser_c.add_argument(
'benchmark_options',
metavar='benchmark_options',
nargs=argparse.REMAINDER,
help='Arguments to pass when running benchmark executables')
return parser
def main():
# Parse the command line flags
parser = create_parser()
args, unknown_args = parser.parse_known_args()
if args.mode is None:
parser.print_help()
exit(1)
assert not unknown_args
benchmark_options = args.benchmark_options
if args.mode == 'benchmarks':
test_baseline = args.test_baseline[0].name
test_contender = args.test_contender[0].name
filter_baseline = ''
filter_contender = ''
# NOTE: if test_baseline == test_contender, you are analyzing the stdev
description = 'Comparing %s to %s' % (test_baseline, test_contender)
elif args.mode == 'filters':
test_baseline = args.test[0].name
test_contender = args.test[0].name
filter_baseline = args.filter_baseline[0]
filter_contender = args.filter_contender[0]
# NOTE: if filter_baseline == filter_contender, you are analyzing the
# stdev
description = 'Comparing %s to %s (from %s)' % (
filter_baseline, filter_contender, args.test[0].name)
elif args.mode == 'benchmarksfiltered':
test_baseline = args.test_baseline[0].name
test_contender = args.test_contender[0].name
filter_baseline = args.filter_baseline[0]
filter_contender = args.filter_contender[0]
# NOTE: if test_baseline == test_contender and
# filter_baseline == filter_contender, you are analyzing the stdev
description = 'Comparing %s (from %s) to %s (from %s)' % (
filter_baseline, test_baseline, filter_contender, test_contender)
else:
# should never happen
print("Unrecognized mode of operation: '%s'" % args.mode)
parser.print_help()
exit(1)
check_inputs(test_baseline, test_contender, benchmark_options)
options_baseline = []
options_contender = []
if filter_baseline and filter_contender:
options_baseline = ['--benchmark_filter=%s' % filter_baseline]
options_contender = ['--benchmark_filter=%s' % filter_contender]
# Run the benchmarks and report the results
json1 = json1_orig = gbench.util.run_or_load_benchmark(
test_baseline, benchmark_options + options_baseline)
json2 = json2_orig = gbench.util.run_or_load_benchmark(
test_contender, benchmark_options + options_contender)
# Now, filter the benchmarks so that the difference report can work
if filter_baseline and filter_contender:
replacement = '[%s vs. %s]' % (filter_baseline, filter_contender)
json1 = gbench.report.filter_benchmark(
json1_orig, filter_baseline, replacement)
json2 = gbench.report.filter_benchmark(
json2_orig, filter_contender, replacement)
# Diff and output
output_lines = gbench.report.generate_difference_report(json1, json2)
print(description)
for ln in output_lines:
print(ln)
import unittest
class TestParser(unittest.TestCase):
def setUp(self):
self.parser = create_parser()
testInputs = os.path.join(
os.path.dirname(
os.path.realpath(__file__)),
'gbench',
'Inputs')
self.testInput0 = os.path.join(testInputs, 'test1_run1.json')
self.testInput1 = os.path.join(testInputs, 'test1_run2.json')
def test_benchmarks_basic(self):
parsed = self.parser.parse_args(
['benchmarks', self.testInput0, self.testInput1])
self.assertEqual(parsed.mode, 'benchmarks')
self.assertEqual(parsed.test_baseline[0].name, self.testInput0)
self.assertEqual(parsed.test_contender[0].name, self.testInput1)
self.assertFalse(parsed.benchmark_options)
def test_benchmarks_with_remainder(self):
parsed = self.parser.parse_args(
['benchmarks', self.testInput0, self.testInput1, 'd'])
self.assertEqual(parsed.mode, 'benchmarks')
self.assertEqual(parsed.test_baseline[0].name, self.testInput0)
self.assertEqual(parsed.test_contender[0].name, self.testInput1)
self.assertEqual(parsed.benchmark_options, ['d'])
def test_benchmarks_with_remainder_after_doubleminus(self):
parsed = self.parser.parse_args(
['benchmarks', self.testInput0, self.testInput1, '--', 'e'])
self.assertEqual(parsed.mode, 'benchmarks')
self.assertEqual(parsed.test_baseline[0].name, self.testInput0)
self.assertEqual(parsed.test_contender[0].name, self.testInput1)
self.assertEqual(parsed.benchmark_options, ['e'])
def test_filters_basic(self):
parsed = self.parser.parse_args(
['filters', self.testInput0, 'c', 'd'])
self.assertEqual(parsed.mode, 'filters')
self.assertEqual(parsed.test[0].name, self.testInput0)
self.assertEqual(parsed.filter_baseline[0], 'c')
self.assertEqual(parsed.filter_contender[0], 'd')
self.assertFalse(parsed.benchmark_options)
def test_filters_with_remainder(self):
parsed = self.parser.parse_args(
['filters', self.testInput0, 'c', 'd', 'e'])
self.assertEqual(parsed.mode, 'filters')
self.assertEqual(parsed.test[0].name, self.testInput0)
self.assertEqual(parsed.filter_baseline[0], 'c')
self.assertEqual(parsed.filter_contender[0], 'd')
self.assertEqual(parsed.benchmark_options, ['e'])
def test_filters_with_remainder_after_doubleminus(self):
parsed = self.parser.parse_args(
['filters', self.testInput0, 'c', 'd', '--', 'f'])
self.assertEqual(parsed.mode, 'filters')
self.assertEqual(parsed.test[0].name, self.testInput0)
self.assertEqual(parsed.filter_baseline[0], 'c')
self.assertEqual(parsed.filter_contender[0], 'd')
self.assertEqual(parsed.benchmark_options, ['f'])
def test_benchmarksfiltered_basic(self):
parsed = self.parser.parse_args(
['benchmarksfiltered', self.testInput0, 'c', self.testInput1, 'e'])
self.assertEqual(parsed.mode, 'benchmarksfiltered')
self.assertEqual(parsed.test_baseline[0].name, self.testInput0)
self.assertEqual(parsed.filter_baseline[0], 'c')
self.assertEqual(parsed.test_contender[0].name, self.testInput1)
self.assertEqual(parsed.filter_contender[0], 'e')
self.assertFalse(parsed.benchmark_options)
def test_benchmarksfiltered_with_remainder(self):
parsed = self.parser.parse_args(
['benchmarksfiltered', self.testInput0, 'c', self.testInput1, 'e', 'f'])
self.assertEqual(parsed.mode, 'benchmarksfiltered')
self.assertEqual(parsed.test_baseline[0].name, self.testInput0)
self.assertEqual(parsed.filter_baseline[0], 'c')
self.assertEqual(parsed.test_contender[0].name, self.testInput1)
self.assertEqual(parsed.filter_contender[0], 'e')
self.assertEqual(parsed.benchmark_options[0], 'f')
def test_benchmarksfiltered_with_remainder_after_doubleminus(self):
parsed = self.parser.parse_args(
['benchmarksfiltered', self.testInput0, 'c', self.testInput1, 'e', '--', 'g'])
self.assertEqual(parsed.mode, 'benchmarksfiltered')
self.assertEqual(parsed.test_baseline[0].name, self.testInput0)
self.assertEqual(parsed.filter_baseline[0], 'c')
self.assertEqual(parsed.test_contender[0].name, self.testInput1)
self.assertEqual(parsed.filter_contender[0], 'e')
self.assertEqual(parsed.benchmark_options[0], 'g')
if __name__ == '__main__':
# unittest.main()
main()
# vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4
# kate: tab-width: 4; replace-tabs on; indent-width 4; tab-indents: off;
# kate: indent-mode python; remove-trailing-spaces modified;

View File

@@ -1,67 +0,0 @@
#!/usr/bin/env python
"""
compare_bench.py - Compare two benchmarks or their results and report the
difference.
"""
import argparse
from argparse import ArgumentParser
import sys
import gbench
from gbench import util, report
from gbench.util import *
def check_inputs(in1, in2, flags):
"""
Perform checking on the user provided inputs and diagnose any abnormalities
"""
in1_kind, in1_err = classify_input_file(in1)
in2_kind, in2_err = classify_input_file(in2)
output_file = find_benchmark_flag('--benchmark_out=', flags)
output_type = find_benchmark_flag('--benchmark_out_format=', flags)
if in1_kind == IT_Executable and in2_kind == IT_Executable and output_file:
print(("WARNING: '--benchmark_out=%s' will be passed to both "
"benchmarks causing it to be overwritten") % output_file)
if in1_kind == IT_JSON and in2_kind == IT_JSON and len(flags) > 0:
print("WARNING: passing --benchmark flags has no effect since both "
"inputs are JSON")
if output_type is not None and output_type != 'json':
print(("ERROR: passing '--benchmark_out_format=%s' to 'compare_bench.py`"
" is not supported.") % output_type)
sys.exit(1)
def main():
parser = ArgumentParser(
description='compare the results of two benchmarks')
parser.add_argument(
'test1', metavar='test1', type=str, nargs=1,
help='A benchmark executable or JSON output file')
parser.add_argument(
'test2', metavar='test2', type=str, nargs=1,
help='A benchmark executable or JSON output file')
parser.add_argument(
'benchmark_options', metavar='benchmark_options', nargs=argparse.REMAINDER,
help='Arguments to pass when running benchmark executables'
)
args, unknown_args = parser.parse_known_args()
# Parse the command line flags
test1 = args.test1[0]
test2 = args.test2[0]
if unknown_args:
# should never happen
print("Unrecognized positional argument arguments: '%s'"
% unknown_args)
exit(1)
benchmark_options = args.benchmark_options
check_inputs(test1, test2, benchmark_options)
# Run the benchmarks and report the results
json1 = gbench.util.run_or_load_benchmark(test1, benchmark_options)
json2 = gbench.util.run_or_load_benchmark(test2, benchmark_options)
output_lines = gbench.report.generate_difference_report(json1, json2)
print('Comparing %s to %s' % (test1, test2))
for ln in output_lines:
print(ln)
if __name__ == '__main__':
main()

View File

@@ -1,102 +0,0 @@
{
"context": {
"date": "2016-08-02 17:44:46",
"num_cpus": 4,
"mhz_per_cpu": 4228,
"cpu_scaling_enabled": false,
"library_build_type": "release"
},
"benchmarks": [
{
"name": "BM_SameTimes",
"iterations": 1000,
"real_time": 10,
"cpu_time": 10,
"time_unit": "ns"
},
{
"name": "BM_2xFaster",
"iterations": 1000,
"real_time": 50,
"cpu_time": 50,
"time_unit": "ns"
},
{
"name": "BM_2xSlower",
"iterations": 1000,
"real_time": 50,
"cpu_time": 50,
"time_unit": "ns"
},
{
"name": "BM_1PercentFaster",
"iterations": 1000,
"real_time": 100,
"cpu_time": 100,
"time_unit": "ns"
},
{
"name": "BM_1PercentSlower",
"iterations": 1000,
"real_time": 100,
"cpu_time": 100,
"time_unit": "ns"
},
{
"name": "BM_10PercentFaster",
"iterations": 1000,
"real_time": 100,
"cpu_time": 100,
"time_unit": "ns"
},
{
"name": "BM_10PercentSlower",
"iterations": 1000,
"real_time": 100,
"cpu_time": 100,
"time_unit": "ns"
},
{
"name": "BM_100xSlower",
"iterations": 1000,
"real_time": 100,
"cpu_time": 100,
"time_unit": "ns"
},
{
"name": "BM_100xFaster",
"iterations": 1000,
"real_time": 10000,
"cpu_time": 10000,
"time_unit": "ns"
},
{
"name": "BM_10PercentCPUToTime",
"iterations": 1000,
"real_time": 100,
"cpu_time": 100,
"time_unit": "ns"
},
{
"name": "BM_ThirdFaster",
"iterations": 1000,
"real_time": 100,
"cpu_time": 100,
"time_unit": "ns"
},
{
"name": "BM_BadTimeUnit",
"iterations": 1000,
"real_time": 0.4,
"cpu_time": 0.5,
"time_unit": "s"
},
{
"name": "BM_DifferentTimeUnit",
"iterations": 1,
"real_time": 1,
"cpu_time": 1,
"time_unit": "s"
}
]
}

View File

@@ -1,102 +0,0 @@
{
"context": {
"date": "2016-08-02 17:44:46",
"num_cpus": 4,
"mhz_per_cpu": 4228,
"cpu_scaling_enabled": false,
"library_build_type": "release"
},
"benchmarks": [
{
"name": "BM_SameTimes",
"iterations": 1000,
"real_time": 10,
"cpu_time": 10,
"time_unit": "ns"
},
{
"name": "BM_2xFaster",
"iterations": 1000,
"real_time": 25,
"cpu_time": 25,
"time_unit": "ns"
},
{
"name": "BM_2xSlower",
"iterations": 20833333,
"real_time": 100,
"cpu_time": 100,
"time_unit": "ns"
},
{
"name": "BM_1PercentFaster",
"iterations": 1000,
"real_time": 98.9999999,
"cpu_time": 98.9999999,
"time_unit": "ns"
},
{
"name": "BM_1PercentSlower",
"iterations": 1000,
"real_time": 100.9999999,
"cpu_time": 100.9999999,
"time_unit": "ns"
},
{
"name": "BM_10PercentFaster",
"iterations": 1000,
"real_time": 90,
"cpu_time": 90,
"time_unit": "ns"
},
{
"name": "BM_10PercentSlower",
"iterations": 1000,
"real_time": 110,
"cpu_time": 110,
"time_unit": "ns"
},
{
"name": "BM_100xSlower",
"iterations": 1000,
"real_time": 1.0000e+04,
"cpu_time": 1.0000e+04,
"time_unit": "ns"
},
{
"name": "BM_100xFaster",
"iterations": 1000,
"real_time": 100,
"cpu_time": 100,
"time_unit": "ns"
},
{
"name": "BM_10PercentCPUToTime",
"iterations": 1000,
"real_time": 110,
"cpu_time": 90,
"time_unit": "ns"
},
{
"name": "BM_ThirdFaster",
"iterations": 1000,
"real_time": 66.665,
"cpu_time": 66.664,
"time_unit": "ns"
},
{
"name": "BM_BadTimeUnit",
"iterations": 1000,
"real_time": 0.04,
"cpu_time": 0.6,
"time_unit": "s"
},
{
"name": "BM_DifferentTimeUnit",
"iterations": 1,
"real_time": 1,
"cpu_time": 1,
"time_unit": "ns"
}
]
}

View File

@@ -1,81 +0,0 @@
{
"context": {
"date": "2016-08-02 17:44:46",
"num_cpus": 4,
"mhz_per_cpu": 4228,
"cpu_scaling_enabled": false,
"library_build_type": "release"
},
"benchmarks": [
{
"name": "BM_Hi",
"iterations": 1234,
"real_time": 42,
"cpu_time": 24,
"time_unit": "ms"
},
{
"name": "BM_Zero",
"iterations": 1000,
"real_time": 10,
"cpu_time": 10,
"time_unit": "ns"
},
{
"name": "BM_Zero/4",
"iterations": 4000,
"real_time": 40,
"cpu_time": 40,
"time_unit": "ns"
},
{
"name": "Prefix/BM_Zero",
"iterations": 2000,
"real_time": 20,
"cpu_time": 20,
"time_unit": "ns"
},
{
"name": "Prefix/BM_Zero/3",
"iterations": 3000,
"real_time": 30,
"cpu_time": 30,
"time_unit": "ns"
},
{
"name": "BM_One",
"iterations": 5000,
"real_time": 5,
"cpu_time": 5,
"time_unit": "ns"
},
{
"name": "BM_One/4",
"iterations": 2000,
"real_time": 20,
"cpu_time": 20,
"time_unit": "ns"
},
{
"name": "Prefix/BM_One",
"iterations": 1000,
"real_time": 10,
"cpu_time": 10,
"time_unit": "ns"
},
{
"name": "Prefix/BM_One/3",
"iterations": 1500,
"real_time": 15,
"cpu_time": 15,
"time_unit": "ns"
},
{
"name": "BM_Bye",
"iterations": 5321,
"real_time": 11,
"cpu_time": 63,
"time_unit": "ns"
}
]
}

View File

@@ -1,8 +0,0 @@
"""Google Benchmark tooling"""
__author__ = 'Eric Fiselier'
__email__ = 'eric@efcs.ca'
__versioninfo__ = (0, 5, 0)
__version__ = '.'.join(str(v) for v in __versioninfo__) + 'dev'
__all__ = []

View File

@@ -1,208 +0,0 @@
"""report.py - Utilities for reporting statistics about benchmark results
"""
import os
import re
import copy
class BenchmarkColor(object):
def __init__(self, name, code):
self.name = name
self.code = code
def __repr__(self):
return '%s%r' % (self.__class__.__name__,
(self.name, self.code))
def __format__(self, format):
return self.code
# Benchmark Colors Enumeration
BC_NONE = BenchmarkColor('NONE', '')
BC_MAGENTA = BenchmarkColor('MAGENTA', '\033[95m')
BC_CYAN = BenchmarkColor('CYAN', '\033[96m')
BC_OKBLUE = BenchmarkColor('OKBLUE', '\033[94m')
BC_HEADER = BenchmarkColor('HEADER', '\033[92m')
BC_WARNING = BenchmarkColor('WARNING', '\033[93m')
BC_WHITE = BenchmarkColor('WHITE', '\033[97m')
BC_FAIL = BenchmarkColor('FAIL', '\033[91m')
BC_ENDC = BenchmarkColor('ENDC', '\033[0m')
BC_BOLD = BenchmarkColor('BOLD', '\033[1m')
BC_UNDERLINE = BenchmarkColor('UNDERLINE', '\033[4m')
def color_format(use_color, fmt_str, *args, **kwargs):
"""
Return the result of 'fmt_str.format(*args, **kwargs)' after transforming
'args' and 'kwargs' according to the value of 'use_color'. If 'use_color'
is False then all color codes in 'args' and 'kwargs' are replaced with
the empty string.
"""
assert use_color is True or use_color is False
if not use_color:
args = [arg if not isinstance(arg, BenchmarkColor) else BC_NONE
for arg in args]
kwargs = {key: arg if not isinstance(arg, BenchmarkColor) else BC_NONE
for key, arg in kwargs.items()}
return fmt_str.format(*args, **kwargs)
def find_longest_name(benchmark_list):
"""
Return the length of the longest benchmark name in a given list of
benchmark JSON objects
"""
longest_name = 1
for bc in benchmark_list:
if len(bc['name']) > longest_name:
longest_name = len(bc['name'])
return longest_name
def calculate_change(old_val, new_val):
"""
Return a float representing the decimal change between old_val and new_val.
"""
if old_val == 0 and new_val == 0:
return 0.0
if old_val == 0:
return float(new_val - old_val) / (float(old_val + new_val) / 2)
return float(new_val - old_val) / abs(old_val)
def filter_benchmark(json_orig, family, replacement=""):
"""
Apply a filter to the json, and only leave the 'family' of benchmarks.
"""
regex = re.compile(family)
filtered = {}
filtered['benchmarks'] = []
for be in json_orig['benchmarks']:
if not regex.search(be['name']):
continue
filteredbench = copy.deepcopy(be) # Do NOT modify the old name!
filteredbench['name'] = regex.sub(replacement, filteredbench['name'])
filtered['benchmarks'].append(filteredbench)
return filtered
def generate_difference_report(json1, json2, use_color=True):
"""
Calculate and report the difference between each test of two benchmarks
runs specified as 'json1' and 'json2'.
"""
first_col_width = find_longest_name(json1['benchmarks'])
def find_test(name):
for b in json2['benchmarks']:
if b['name'] == name:
return b
return None
first_col_width = max(first_col_width, len('Benchmark'))
first_line = "{:<{}s}Time CPU Time Old Time New CPU Old CPU New".format(
'Benchmark', 12 + first_col_width)
output_strs = [first_line, '-' * len(first_line)]
gen = (bn for bn in json1['benchmarks'] if 'real_time' in bn and 'cpu_time' in bn)
for bn in gen:
other_bench = find_test(bn['name'])
if not other_bench:
continue
if bn['time_unit'] != other_bench['time_unit']:
continue
def get_color(res):
if res > 0.05:
return BC_FAIL
elif res > -0.07:
return BC_WHITE
else:
return BC_CYAN
fmt_str = "{}{:<{}s}{endc}{}{:+16.4f}{endc}{}{:+16.4f}{endc}{:14.0f}{:14.0f}{endc}{:14.0f}{:14.0f}"
tres = calculate_change(bn['real_time'], other_bench['real_time'])
cpures = calculate_change(bn['cpu_time'], other_bench['cpu_time'])
output_strs += [color_format(use_color, fmt_str,
BC_HEADER, bn['name'], first_col_width,
get_color(tres), tres, get_color(cpures), cpures,
bn['real_time'], other_bench['real_time'],
bn['cpu_time'], other_bench['cpu_time'],
endc=BC_ENDC)]
return output_strs
###############################################################################
# Unit tests
import unittest
class TestReportDifference(unittest.TestCase):
def load_results(self):
import json
testInputs = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'Inputs')
testOutput1 = os.path.join(testInputs, 'test1_run1.json')
testOutput2 = os.path.join(testInputs, 'test1_run2.json')
with open(testOutput1, 'r') as f:
json1 = json.load(f)
with open(testOutput2, 'r') as f:
json2 = json.load(f)
return json1, json2
def test_basic(self):
expect_lines = [
['BM_SameTimes', '+0.0000', '+0.0000', '10', '10', '10', '10'],
['BM_2xFaster', '-0.5000', '-0.5000', '50', '25', '50', '25'],
['BM_2xSlower', '+1.0000', '+1.0000', '50', '100', '50', '100'],
['BM_1PercentFaster', '-0.0100', '-0.0100', '100', '99', '100', '99'],
['BM_1PercentSlower', '+0.0100', '+0.0100', '100', '101', '100', '101'],
['BM_10PercentFaster', '-0.1000', '-0.1000', '100', '90', '100', '90'],
['BM_10PercentSlower', '+0.1000', '+0.1000', '100', '110', '100', '110'],
['BM_100xSlower', '+99.0000', '+99.0000', '100', '10000', '100', '10000'],
['BM_100xFaster', '-0.9900', '-0.9900', '10000', '100', '10000', '100'],
['BM_10PercentCPUToTime', '+0.1000', '-0.1000', '100', '110', '100', '90'],
['BM_ThirdFaster', '-0.3333', '-0.3334', '100', '67', '100', '67'],
['BM_BadTimeUnit', '-0.9000', '+0.2000', '0', '0', '0', '1'],
]
json1, json2 = self.load_results()
output_lines_with_header = generate_difference_report(json1, json2, use_color=False)
output_lines = output_lines_with_header[2:]
print("\n".join(output_lines_with_header))
self.assertEqual(len(output_lines), len(expect_lines))
for i in range(0, len(output_lines)):
parts = [x for x in output_lines[i].split(' ') if x]
self.assertEqual(len(parts), 7)
self.assertEqual(parts, expect_lines[i])
class TestReportDifferenceBetweenFamilies(unittest.TestCase):
def load_result(self):
import json
testInputs = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'Inputs')
testOutput = os.path.join(testInputs, 'test2_run.json')
with open(testOutput, 'r') as f:
json = json.load(f)
return json
def test_basic(self):
expect_lines = [
['.', '-0.5000', '-0.5000', '10', '5', '10', '5'],
['./4', '-0.5000', '-0.5000', '40', '20', '40', '20'],
['Prefix/.', '-0.5000', '-0.5000', '20', '10', '20', '10'],
['Prefix/./3', '-0.5000', '-0.5000', '30', '15', '30', '15'],
]
json = self.load_result()
json1 = filter_benchmark(json, "BM_Z.ro", ".")
json2 = filter_benchmark(json, "BM_O.e", ".")
output_lines_with_header = generate_difference_report(json1, json2, use_color=False)
output_lines = output_lines_with_header[2:]
print("\n")
print("\n".join(output_lines_with_header))
self.assertEqual(len(output_lines), len(expect_lines))
for i in range(0, len(output_lines)):
parts = [x for x in output_lines[i].split(' ') if x]
self.assertEqual(len(parts), 7)
self.assertEqual(parts, expect_lines[i])
if __name__ == '__main__':
unittest.main()
# vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4
# kate: tab-width: 4; replace-tabs on; indent-width 4; tab-indents: off;
# kate: indent-mode python; remove-trailing-spaces modified;

View File

@@ -1,159 +0,0 @@
"""util.py - General utilities for running, loading, and processing benchmarks
"""
import json
import os
import tempfile
import subprocess
import sys
# Input file type enumeration
IT_Invalid = 0
IT_JSON = 1
IT_Executable = 2
_num_magic_bytes = 2 if sys.platform.startswith('win') else 4
def is_executable_file(filename):
"""
Return 'True' if 'filename' names a valid file which is likely
an executable. A file is considered an executable if it starts with the
magic bytes for a EXE, Mach O, or ELF file.
"""
if not os.path.isfile(filename):
return False
with open(filename, mode='rb') as f:
magic_bytes = f.read(_num_magic_bytes)
if sys.platform == 'darwin':
return magic_bytes in [
b'\xfe\xed\xfa\xce', # MH_MAGIC
b'\xce\xfa\xed\xfe', # MH_CIGAM
b'\xfe\xed\xfa\xcf', # MH_MAGIC_64
b'\xcf\xfa\xed\xfe', # MH_CIGAM_64
b'\xca\xfe\xba\xbe', # FAT_MAGIC
b'\xbe\xba\xfe\xca' # FAT_CIGAM
]
elif sys.platform.startswith('win'):
return magic_bytes == b'MZ'
else:
return magic_bytes == b'\x7FELF'
def is_json_file(filename):
"""
Returns 'True' if 'filename' names a valid JSON output file.
'False' otherwise.
"""
try:
with open(filename, 'r') as f:
json.load(f)
return True
except:
pass
return False
def classify_input_file(filename):
"""
Return a tuple (type, msg) where 'type' specifies the classified type
of 'filename'. If 'type' is 'IT_Invalid' then 'msg' is a human readable
string represeting the error.
"""
ftype = IT_Invalid
err_msg = None
if not os.path.exists(filename):
err_msg = "'%s' does not exist" % filename
elif not os.path.isfile(filename):
err_msg = "'%s' does not name a file" % filename
elif is_executable_file(filename):
ftype = IT_Executable
elif is_json_file(filename):
ftype = IT_JSON
else:
err_msg = "'%s' does not name a valid benchmark executable or JSON file" % filename
return ftype, err_msg
def check_input_file(filename):
"""
Classify the file named by 'filename' and return the classification.
If the file is classified as 'IT_Invalid' print an error message and exit
the program.
"""
ftype, msg = classify_input_file(filename)
if ftype == IT_Invalid:
print("Invalid input file: %s" % msg)
sys.exit(1)
return ftype
def find_benchmark_flag(prefix, benchmark_flags):
"""
Search the specified list of flags for a flag matching `<prefix><arg>` and
if it is found return the arg it specifies. If specified more than once the
last value is returned. If the flag is not found None is returned.
"""
assert prefix.startswith('--') and prefix.endswith('=')
result = None
for f in benchmark_flags:
if f.startswith(prefix):
result = f[len(prefix):]
return result
def remove_benchmark_flags(prefix, benchmark_flags):
"""
Return a new list containing the specified benchmark_flags except those
with the specified prefix.
"""
assert prefix.startswith('--') and prefix.endswith('=')
return [f for f in benchmark_flags if not f.startswith(prefix)]
def load_benchmark_results(fname):
"""
Read benchmark output from a file and return the JSON object.
REQUIRES: 'fname' names a file containing JSON benchmark output.
"""
with open(fname, 'r') as f:
return json.load(f)
def run_benchmark(exe_name, benchmark_flags):
"""
Run a benchmark specified by 'exe_name' with the specified
'benchmark_flags'. The benchmark is run directly as a subprocess to preserve
real time console output.
RETURNS: A JSON object representing the benchmark output
"""
output_name = find_benchmark_flag('--benchmark_out=',
benchmark_flags)
is_temp_output = False
if output_name is None:
is_temp_output = True
thandle, output_name = tempfile.mkstemp()
os.close(thandle)
benchmark_flags = list(benchmark_flags) + \
['--benchmark_out=%s' % output_name]
cmd = [exe_name] + benchmark_flags
print("RUNNING: %s" % ' '.join(cmd))
exitCode = subprocess.call(cmd)
if exitCode != 0:
print('TEST FAILED...')
sys.exit(exitCode)
json_res = load_benchmark_results(output_name)
if is_temp_output:
os.unlink(output_name)
return json_res
def run_or_load_benchmark(filename, benchmark_flags):
"""
Get the results for a specified benchmark. If 'filename' specifies
an executable benchmark then the results are generated by running the
benchmark. Otherwise 'filename' must name a valid JSON output file,
which is loaded and the result returned.
"""
ftype = check_input_file(filename)
if ftype == IT_JSON:
return load_benchmark_results(filename)
elif ftype == IT_Executable:
return run_benchmark(filename, benchmark_flags)
else:
assert False # This branch is unreachable

View File

@@ -1,151 +0,0 @@
#!/usr/bin/env python
"""
strip_asm.py - Cleanup ASM output for the specified file
"""
from argparse import ArgumentParser
import sys
import os
import re
def find_used_labels(asm):
found = set()
label_re = re.compile("\s*j[a-z]+\s+\.L([a-zA-Z0-9][a-zA-Z0-9_]*)")
for l in asm.splitlines():
m = label_re.match(l)
if m:
found.add('.L%s' % m.group(1))
return found
def normalize_labels(asm):
decls = set()
label_decl = re.compile("^[.]{0,1}L([a-zA-Z0-9][a-zA-Z0-9_]*)(?=:)")
for l in asm.splitlines():
m = label_decl.match(l)
if m:
decls.add(m.group(0))
if len(decls) == 0:
return asm
needs_dot = next(iter(decls))[0] != '.'
if not needs_dot:
return asm
for ld in decls:
asm = re.sub("(^|\s+)" + ld + "(?=:|\s)", '\\1.' + ld, asm)
return asm
def transform_labels(asm):
asm = normalize_labels(asm)
used_decls = find_used_labels(asm)
new_asm = ''
label_decl = re.compile("^\.L([a-zA-Z0-9][a-zA-Z0-9_]*)(?=:)")
for l in asm.splitlines():
m = label_decl.match(l)
if not m or m.group(0) in used_decls:
new_asm += l
new_asm += '\n'
return new_asm
def is_identifier(tk):
if len(tk) == 0:
return False
first = tk[0]
if not first.isalpha() and first != '_':
return False
for i in range(1, len(tk)):
c = tk[i]
if not c.isalnum() and c != '_':
return False
return True
def process_identifiers(l):
"""
process_identifiers - process all identifiers and modify them to have
consistent names across all platforms; specifically across ELF and MachO.
For example, MachO inserts an additional understore at the beginning of
names. This function removes that.
"""
parts = re.split(r'([a-zA-Z0-9_]+)', l)
new_line = ''
for tk in parts:
if is_identifier(tk):
if tk.startswith('__Z'):
tk = tk[1:]
elif tk.startswith('_') and len(tk) > 1 and \
tk[1].isalpha() and tk[1] != 'Z':
tk = tk[1:]
new_line += tk
return new_line
def process_asm(asm):
"""
Strip the ASM of unwanted directives and lines
"""
new_contents = ''
asm = transform_labels(asm)
# TODO: Add more things we want to remove
discard_regexes = [
re.compile("\s+\..*$"), # directive
re.compile("\s*#(NO_APP|APP)$"), #inline ASM
re.compile("\s*#.*$"), # comment line
re.compile("\s*\.globa?l\s*([.a-zA-Z_][a-zA-Z0-9$_.]*)"), #global directive
re.compile("\s*\.(string|asciz|ascii|[1248]?byte|short|word|long|quad|value|zero)"),
]
keep_regexes = [
]
fn_label_def = re.compile("^[a-zA-Z_][a-zA-Z0-9_.]*:")
for l in asm.splitlines():
# Remove Mach-O attribute
l = l.replace('@GOTPCREL', '')
add_line = True
for reg in discard_regexes:
if reg.match(l) is not None:
add_line = False
break
for reg in keep_regexes:
if reg.match(l) is not None:
add_line = True
break
if add_line:
if fn_label_def.match(l) and len(new_contents) != 0:
new_contents += '\n'
l = process_identifiers(l)
new_contents += l
new_contents += '\n'
return new_contents
def main():
parser = ArgumentParser(
description='generate a stripped assembly file')
parser.add_argument(
'input', metavar='input', type=str, nargs=1,
help='An input assembly file')
parser.add_argument(
'out', metavar='output', type=str, nargs=1,
help='The output file')
args, unknown_args = parser.parse_known_args()
input = args.input[0]
output = args.out[0]
if not os.path.isfile(input):
print(("ERROR: input file '%s' does not exist") % input)
sys.exit(1)
contents = None
with open(input, 'r') as f:
contents = f.read()
new_contents = process_asm(contents)
with open(output, 'w') as f:
f.write(new_contents)
if __name__ == '__main__':
main()
# vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4
# kate: tab-width: 4; replace-tabs on; indent-width 4; tab-indents: off;
# kate: indent-mode python; remove-trailing-spaces modified;

837
cmake/ci.cmake Normal file
View File

@@ -0,0 +1,837 @@
# number of parallel jobs for CTest
set(N 10)
###############################################################################
# Needed tools.
###############################################################################
include(FindPython3)
find_package(Python3 COMPONENTS Interpreter)
find_program(ASTYLE_TOOL NAMES astyle)
execute_process(COMMAND ${ASTYLE_TOOL} --version OUTPUT_VARIABLE ASTYLE_TOOL_VERSION ERROR_VARIABLE ASTYLE_TOOL_VERSION)
string(REGEX MATCH "[0-9]+(\\.[0-9]+)+" ASTYLE_TOOL_VERSION "${ASTYLE_TOOL_VERSION}")
message(STATUS "🔖 Artistic Style ${ASTYLE_TOOL_VERSION} (${ASTYLE_TOOL})")
find_program(CLANG_TOOL NAMES clang++-HEAD clang++-13 clang++-12 clang++-11 clang++)
execute_process(COMMAND ${CLANG_TOOL} --version OUTPUT_VARIABLE CLANG_TOOL_VERSION ERROR_VARIABLE CLANG_TOOL_VERSION)
string(REGEX MATCH "[0-9]+(\\.[0-9]+)+" CLANG_TOOL_VERSION "${CLANG_TOOL_VERSION}")
message(STATUS "🔖 Clang ${CLANG_TOOL_VERSION} (${CLANG_TOOL})")
find_program(CLANG_TIDY_TOOL NAMES clang-tidy-12 clang-tidy-11 clang-tidy)
execute_process(COMMAND ${CLANG_TIDY_TOOL} --version OUTPUT_VARIABLE CLANG_TIDY_TOOL_VERSION ERROR_VARIABLE CLANG_TIDY_TOOL_VERSION)
string(REGEX MATCH "[0-9]+(\\.[0-9]+)+" CLANG_TIDY_TOOL_VERSION "${CLANG_TIDY_TOOL_VERSION}")
message(STATUS "🔖 Clang-Tidy ${CLANG_TIDY_TOOL_VERSION} (${CLANG_TIDY_TOOL})")
message(STATUS "🔖 CMake ${CMAKE_VERSION} (${CMAKE_COMMAND})")
find_program(CPPCHECK_TOOL NAMES cppcheck)
execute_process(COMMAND ${CPPCHECK_TOOL} --version OUTPUT_VARIABLE CPPCHECK_TOOL_VERSION ERROR_VARIABLE CPPCHECK_TOOL_VERSION)
string(REGEX MATCH "[0-9]+(\\.[0-9]+)+" CPPCHECK_TOOL_VERSION "${CPPCHECK_TOOL_VERSION}")
message(STATUS "🔖 Cppcheck ${CPPCHECK_TOOL_VERSION} (${CPPCHECK_TOOL})")
find_program(GCC_TOOL NAMES g++-HEAD g++-11 g++-latest)
execute_process(COMMAND ${GCC_TOOL} --version OUTPUT_VARIABLE GCC_TOOL_VERSION ERROR_VARIABLE GCC_TOOL_VERSION)
string(REGEX MATCH "[0-9]+(\\.[0-9]+)+" GCC_TOOL_VERSION "${GCC_TOOL_VERSION}")
message(STATUS "🔖 GCC ${GCC_TOOL_VERSION} (${GCC_TOOL})")
find_program(GCOV_TOOL NAMES gcov-HEAD gcov-11 gcov-10 gcov)
execute_process(COMMAND ${GCOV_TOOL} --version OUTPUT_VARIABLE GCOV_TOOL_VERSION ERROR_VARIABLE GCOV_TOOL_VERSION)
string(REGEX MATCH "[0-9]+(\\.[0-9]+)+" GCOV_TOOL_VERSION "${GCOV_TOOL_VERSION}")
message(STATUS "🔖 GCOV ${GCOV_TOOL_VERSION} (${GCOV_TOOL})")
find_program(GIT_TOOL NAMES git)
execute_process(COMMAND ${GIT_TOOL} --version OUTPUT_VARIABLE GIT_TOOL_VERSION ERROR_VARIABLE GIT_TOOL_VERSION)
string(REGEX MATCH "[0-9]+(\\.[0-9]+)+" GIT_TOOL_VERSION "${GIT_TOOL_VERSION}")
message(STATUS "🔖 Git ${GIT_TOOL_VERSION} (${GIT_TOOL})")
find_program(IWYU_TOOL NAMES include-what-you-use iwyu)
execute_process(COMMAND ${IWYU_TOOL} --version OUTPUT_VARIABLE IWYU_TOOL_VERSION ERROR_VARIABLE IWYU_TOOL_VERSION)
string(REGEX MATCH "[0-9]+(\\.[0-9]+)+" IWYU_TOOL_VERSION "${IWYU_TOOL_VERSION}")
message(STATUS "🔖 include-what-you-use ${IWYU_TOOL_VERSION} (${IWYU_TOOL})")
find_program(INFER_TOOL NAMES infer)
execute_process(COMMAND ${INFER_TOOL} --version OUTPUT_VARIABLE INFER_TOOL_VERSION ERROR_VARIABLE INFER_TOOL_VERSION)
string(REGEX MATCH "[0-9]+(\\.[0-9]+)+" INFER_TOOL_VERSION "${INFER_TOOL_VERSION}")
message(STATUS "🔖 Infer ${INFER_TOOL_VERSION} (${INFER_TOOL})")
find_program(LCOV_TOOL NAMES lcov)
execute_process(COMMAND ${LCOV_TOOL} --version OUTPUT_VARIABLE LCOV_TOOL_VERSION ERROR_VARIABLE LCOV_TOOL_VERSION)
string(REGEX MATCH "[0-9]+(\\.[0-9]+)+" LCOV_TOOL_VERSION "${LCOV_TOOL_VERSION}")
message(STATUS "🔖 LCOV ${LCOV_TOOL_VERSION} (${LCOV_TOOL})")
find_program(NINJA_TOOL NAMES ninja)
execute_process(COMMAND ${NINJA_TOOL} --version OUTPUT_VARIABLE NINJA_TOOL_VERSION ERROR_VARIABLE NINJA_TOOL_VERSION)
string(REGEX MATCH "[0-9]+(\\.[0-9]+)+" NINJA_TOOL_VERSION "${NINJA_TOOL_VERSION}")
message(STATUS "🔖 Ninja ${NINJA_TOOL_VERSION} (${NINJA_TOOL})")
find_program(OCLINT_TOOL NAMES oclint-json-compilation-database)
find_program(OCLINT_VERSION_TOOL NAMES oclint)
execute_process(COMMAND ${OCLINT_VERSION_TOOL} --version OUTPUT_VARIABLE OCLINT_TOOL_VERSION ERROR_VARIABLE OCLINT_TOOL_VERSION)
string(REGEX MATCH "[0-9]+(\\.[0-9]+)+" OCLINT_TOOL_VERSION "${OCLINT_TOOL_VERSION}")
message(STATUS "🔖 OCLint ${OCLINT_TOOL_VERSION} (${OCLINT_TOOL})")
find_program(VALGRIND_TOOL NAMES valgrind)
execute_process(COMMAND ${VALGRIND_TOOL} --version OUTPUT_VARIABLE VALGRIND_TOOL_VERSION ERROR_VARIABLE VALGRIND_TOOL_VERSION)
string(REGEX MATCH "[0-9]+(\\.[0-9]+)+" VALGRIND_TOOL_VERSION "${VALGRIND_TOOL_VERSION}")
message(STATUS "🔖 Valgrind ${VALGRIND_TOOL_VERSION} (${VALGRIND_TOOL})")
find_program(GENHTML_TOOL NAMES genhtml)
find_program(PLOG_CONVERTER_TOOL NAMES plog-converter)
find_program(PVS_STUDIO_ANALYZER_TOOL NAMES pvs-studio-analyzer)
find_program(SCAN_BUILD_TOOL NAMES scan-build-12 scan-build-11 scan-build)
# the individual source files
file(GLOB_RECURSE SRC_FILES ${PROJECT_SOURCE_DIR}/include/nlohmann/*.hpp)
###############################################################################
# Thorough check with recent compilers
###############################################################################
# Ignored Clang warnings:
# -Wno-c++98-compat The library targets C++11.
# -Wno-c++98-compat-pedantic The library targets C++11.
# -Wno-deprecated-declarations The library contains annotations for deprecated functions.
# -Wno-extra-semi-stmt The library uses std::assert which triggers this warning.
# -Wno-padded We do not care about padding warnings.
# -Wno-covered-switch-default All switches list all cases and a default case.
# -Wno-weak-vtables The library is header-only.
# -Wreserved-identifier See https://github.com/onqtam/doctest/issues/536.
set(CLANG_CXXFLAGS "-std=c++11 \
-Werror \
-Weverything \
-Wno-c++98-compat \
-Wno-c++98-compat-pedantic \
-Wno-deprecated-declarations \
-Wno-extra-semi-stmt \
-Wno-padded \
-Wno-covered-switch-default \
-Wno-weak-vtables \
-Wno-reserved-identifier \
")
# Ignored GCC warnings:
# -Wno-abi-tag We do not care about ABI tags.
# -Wno-aggregate-return The library uses aggregate returns.
# -Wno-long-long The library uses the long long type to interface with system functions.
# -Wno-namespaces The library uses namespaces.
# -Wno-padded We do not care about padding warnings.
# -Wno-system-headers We do not care about warnings in system headers.
# -Wno-templates The library uses templates.
set(GCC_CXXFLAGS "-std=c++11 \
-pedantic \
-Werror \
--all-warnings \
--extra-warnings \
-W \
-WNSObject-attribute \
-Wno-abi-tag \
-Waddress \
-Waddress-of-packed-member \
-Wno-aggregate-return \
-Waggressive-loop-optimizations \
-Waligned-new=all \
-Wall \
-Walloc-zero \
-Walloca \
-Wanalyzer-double-fclose \
-Wanalyzer-double-free \
-Wanalyzer-exposure-through-output-file \
-Wanalyzer-file-leak \
-Wanalyzer-free-of-non-heap \
-Wanalyzer-malloc-leak \
-Wanalyzer-mismatching-deallocation \
-Wanalyzer-null-argument \
-Wanalyzer-null-dereference \
-Wanalyzer-possible-null-argument \
-Wanalyzer-possible-null-dereference \
-Wanalyzer-shift-count-negative \
-Wanalyzer-shift-count-overflow \
-Wanalyzer-stale-setjmp-buffer \
-Wanalyzer-tainted-array-index \
-Wanalyzer-too-complex \
-Wanalyzer-unsafe-call-within-signal-handler \
-Wanalyzer-use-after-free \
-Wanalyzer-use-of-pointer-in-stale-stack-frame \
-Wanalyzer-write-to-const \
-Wanalyzer-write-to-string-literal \
-Warith-conversion \
-Warray-bounds \
-Warray-bounds=2 \
-Warray-parameter=2 \
-Wattribute-alias=2 \
-Wattribute-warning \
-Wattributes \
-Wbool-compare \
-Wbool-operation \
-Wbuiltin-declaration-mismatch \
-Wbuiltin-macro-redefined \
-Wc++0x-compat \
-Wc++11-compat \
-Wc++14-compat \
-Wc++17-compat \
-Wc++1z-compat \
-Wc++20-compat \
-Wc++2a-compat \
-Wcannot-profile \
-Wcast-align \
-Wcast-align=strict \
-Wcast-function-type \
-Wcast-qual \
-Wcatch-value=3 \
-Wchar-subscripts \
-Wclass-conversion \
-Wclass-memaccess \
-Wclobbered \
-Wcomma-subscript \
-Wcomment \
-Wcomments \
-Wconditionally-supported \
-Wconversion \
-Wconversion-null \
-Wcoverage-mismatch \
-Wcpp \
-Wctad-maybe-unsupported \
-Wctor-dtor-privacy \
-Wdangling-else \
-Wdate-time \
-Wdelete-incomplete \
-Wdelete-non-virtual-dtor \
-Wdeprecated \
-Wdeprecated-copy \
-Wdeprecated-copy-dtor \
-Wdeprecated-declarations \
-Wdeprecated-enum-enum-conversion \
-Wdeprecated-enum-float-conversion \
-Wdisabled-optimization \
-Wdiv-by-zero \
-Wdouble-promotion \
-Wduplicated-branches \
-Wduplicated-cond \
-Weffc++ \
-Wempty-body \
-Wendif-labels \
-Wenum-compare \
-Wenum-conversion \
-Wexpansion-to-defined \
-Wextra \
-Wextra-semi \
-Wfloat-conversion \
-Wfloat-equal \
-Wformat-contains-nul \
-Wformat-diag \
-Wformat-extra-args \
-Wformat-nonliteral \
-Wformat-overflow=2 \
-Wformat-security \
-Wformat-signedness \
-Wformat-truncation=2 \
-Wformat-y2k \
-Wformat-zero-length \
-Wformat=2 \
-Wframe-address \
-Wfree-nonheap-object \
-Whsa \
-Wif-not-aligned \
-Wignored-attributes \
-Wignored-qualifiers \
-Wimplicit-fallthrough=5 \
-Winaccessible-base \
-Winherited-variadic-ctor \
-Winit-list-lifetime \
-Winit-self \
-Winline \
-Wint-in-bool-context \
-Wint-to-pointer-cast \
-Winvalid-memory-model \
-Winvalid-offsetof \
-Winvalid-pch \
-Wliteral-suffix \
-Wlogical-not-parentheses \
-Wlogical-op \
-Wno-long-long \
-Wlto-type-mismatch \
-Wmain \
-Wmaybe-uninitialized \
-Wmemset-elt-size \
-Wmemset-transposed-args \
-Wmisleading-indentation \
-Wmismatched-dealloc \
-Wmismatched-new-delete \
-Wmismatched-tags \
-Wmissing-attributes \
-Wmissing-braces \
-Wmissing-declarations \
-Wmissing-field-initializers \
-Wmissing-include-dirs \
-Wmissing-profile \
-Wmultichar \
-Wmultiple-inheritance \
-Wmultistatement-macros \
-Wno-namespaces \
-Wnarrowing \
-Wnoexcept \
-Wnoexcept-type \
-Wnon-template-friend \
-Wnon-virtual-dtor \
-Wnonnull \
-Wnonnull-compare \
-Wnormalized=nfkc \
-Wnull-dereference \
-Wodr \
-Wold-style-cast \
-Wopenmp-simd \
-Woverflow \
-Woverlength-strings \
-Woverloaded-virtual \
-Wpacked \
-Wpacked-bitfield-compat \
-Wpacked-not-aligned \
-Wno-padded \
-Wparentheses \
-Wpedantic \
-Wpessimizing-move \
-Wplacement-new=2 \
-Wpmf-conversions \
-Wpointer-arith \
-Wpointer-compare \
-Wpragmas \
-Wprio-ctor-dtor \
-Wpsabi \
-Wrange-loop-construct \
-Wredundant-decls \
-Wredundant-move \
-Wredundant-tags \
-Wregister \
-Wreorder \
-Wrestrict \
-Wreturn-local-addr \
-Wreturn-type \
-Wscalar-storage-order \
-Wsequence-point \
-Wshadow=compatible-local \
-Wshadow=global \
-Wshadow=local \
-Wshift-count-negative \
-Wshift-count-overflow \
-Wshift-negative-value \
-Wshift-overflow=2 \
-Wsign-compare \
-Wsign-conversion \
-Wsign-promo \
-Wsized-deallocation \
-Wsizeof-array-argument \
-Wsizeof-array-div \
-Wsizeof-pointer-div \
-Wsizeof-pointer-memaccess \
-Wstack-protector \
-Wstrict-aliasing \
-Wstrict-aliasing=3 \
-Wstrict-null-sentinel \
-Wstrict-overflow \
-Wstrict-overflow=5 \
-Wstring-compare \
-Wstringop-overflow=4 \
-Wstringop-overread \
-Wstringop-truncation \
-Wsubobject-linkage \
-Wsuggest-attribute=cold \
-Wsuggest-attribute=const \
-Wsuggest-attribute=format \
-Wsuggest-attribute=malloc \
-Wsuggest-attribute=noreturn \
-Wsuggest-attribute=pure \
-Wsuggest-final-methods \
-Wsuggest-final-types \
-Wsuggest-override \
-Wswitch \
-Wswitch-bool \
-Wswitch-default \
-Wswitch-enum \
-Wswitch-outside-range \
-Wswitch-unreachable \
-Wsync-nand \
-Wsynth \
-Wno-system-headers \
-Wtautological-compare \
-Wno-templates \
-Wterminate \
-Wtrampolines \
-Wtrigraphs \
-Wtsan \
-Wtype-limits \
-Wundef \
-Wuninitialized \
-Wunknown-pragmas \
-Wunreachable-code \
-Wunsafe-loop-optimizations \
-Wunused \
-Wunused-but-set-parameter \
-Wunused-but-set-variable \
-Wunused-const-variable=2 \
-Wunused-function \
-Wunused-label \
-Wunused-local-typedefs \
-Wunused-macros \
-Wunused-parameter \
-Wunused-result \
-Wunused-value \
-Wunused-variable \
-Wuseless-cast \
-Wvarargs \
-Wvariadic-macros \
-Wvector-operation-performance \
-Wvexing-parse \
-Wvirtual-inheritance \
-Wvirtual-move-assign \
-Wvla \
-Wvla-parameter \
-Wvolatile \
-Wvolatile-register-var \
-Wwrite-strings \
-Wzero-as-null-pointer-constant \
-Wzero-length-bounds \
")
add_custom_target(ci_test_gcc
COMMAND CXX=${GCC_TOOL} CXXFLAGS=${GCC_CXXFLAGS} ${CMAKE_COMMAND}
-DCMAKE_BUILD_TYPE=Debug -GNinja
-DJSON_BuildTests=ON -DJSON_MultipleHeaders=ON
-S${PROJECT_SOURCE_DIR} -B${PROJECT_BINARY_DIR}/build_gcc
COMMAND ${CMAKE_COMMAND} --build ${PROJECT_BINARY_DIR}/build_gcc
COMMAND cd ${PROJECT_BINARY_DIR}/build_gcc && ${CMAKE_CTEST_COMMAND} --parallel ${N} --output-on-failure
COMMENT "Compile and test with GCC using maximal warning flags"
)
add_custom_target(ci_test_clang
COMMAND CXX=${CLANG_TOOL} CXXFLAGS=${CLANG_CXXFLAGS} ${CMAKE_COMMAND}
-DCMAKE_BUILD_TYPE=Debug -GNinja
-DJSON_BuildTests=ON -DJSON_MultipleHeaders=ON
-S${PROJECT_SOURCE_DIR} -B${PROJECT_BINARY_DIR}/build_clang
COMMAND ${CMAKE_COMMAND} --build ${PROJECT_BINARY_DIR}/build_clang
COMMAND cd ${PROJECT_BINARY_DIR}/build_clang && ${CMAKE_CTEST_COMMAND} --parallel ${N} --output-on-failure
COMMENT "Compile and test with Clang using maximal warning flags"
)
###############################################################################
# Different C++ Standards.
###############################################################################
foreach(CXX_STANDARD 11 14 17 20)
add_custom_target(ci_test_gcc_cxx${CXX_STANDARD}
COMMAND CXX=${GCC_TOOL} ${CMAKE_COMMAND}
-DCMAKE_BUILD_TYPE=Debug -GNinja
-DCMAKE_CXX_STANDARD=${CXX_STANDARD} -DCMAKE_CXX_STANDARD_REQUIRED=ON
-DJSON_BuildTests=ON -DJSON_FastTests=ON
-S${PROJECT_SOURCE_DIR} -B${PROJECT_BINARY_DIR}/build_gcc_cxx${CXX_STANDARD}
COMMAND ${CMAKE_COMMAND} --build ${PROJECT_BINARY_DIR}/build_gcc_cxx${CXX_STANDARD}
COMMAND cd ${PROJECT_BINARY_DIR}/build_gcc_cxx${CXX_STANDARD} && ${CMAKE_CTEST_COMMAND} --parallel ${N} --output-on-failure
COMMENT "Compile and test with GCC for C++${CXX_STANDARD}"
)
add_custom_target(ci_test_clang_cxx${CXX_STANDARD}
COMMAND CXX=${CLANG_TOOL} ${CMAKE_COMMAND}
-DCMAKE_BUILD_TYPE=Debug -GNinja
-DCMAKE_CXX_STANDARD=${CXX_STANDARD} -DCMAKE_CXX_STANDARD_REQUIRED=ON
-DJSON_BuildTests=ON
-S${PROJECT_SOURCE_DIR} -B${PROJECT_BINARY_DIR}/build_clang_cxx${CXX_STANDARD}
COMMAND ${CMAKE_COMMAND} --build ${PROJECT_BINARY_DIR}/build_clang_cxx${CXX_STANDARD}
COMMAND cd ${PROJECT_BINARY_DIR}/build_clang_cxx${CXX_STANDARD} && ${CMAKE_CTEST_COMMAND} --parallel ${N} --output-on-failure
COMMENT "Compile and test with Clang for C++${CXX_STANDARD}"
)
endforeach()
###############################################################################
# Disable exceptions.
###############################################################################
add_custom_target(ci_test_noexceptions
COMMAND CXX=${CLANG_TOOL} ${CMAKE_COMMAND}
-DCMAKE_BUILD_TYPE=Debug -GNinja
-DJSON_BuildTests=ON -DJSON_MultipleHeaders=ON -DCMAKE_CXX_FLAGS=-DJSON_NOEXCEPTION -DDOCTEST_TEST_FILTER=--no-throw
-S${PROJECT_SOURCE_DIR} -B${PROJECT_BINARY_DIR}/build_noexceptions
COMMAND ${CMAKE_COMMAND} --build ${PROJECT_BINARY_DIR}/build_noexceptions
COMMAND cd ${PROJECT_BINARY_DIR}/build_noexceptions && ${CMAKE_CTEST_COMMAND} --parallel ${N} --output-on-failure
COMMENT "Compile and test with exceptions switched off"
)
###############################################################################
# Disable implicit conversions.
###############################################################################
add_custom_target(ci_test_noimplicitconversions
COMMAND CXX=${CLANG_TOOL} ${CMAKE_COMMAND}
-DCMAKE_BUILD_TYPE=Debug -GNinja
-DJSON_BuildTests=ON -DJSON_MultipleHeaders=ON -DJSON_ImplicitConversions=OFF
-S${PROJECT_SOURCE_DIR} -B${PROJECT_BINARY_DIR}/build_noimplicitconversions
COMMAND ${CMAKE_COMMAND} --build ${PROJECT_BINARY_DIR}/build_noimplicitconversions
COMMAND cd ${PROJECT_BINARY_DIR}/build_noimplicitconversions && ${CMAKE_CTEST_COMMAND} --parallel ${N} --output-on-failure
COMMENT "Compile and test with implicit conversions switched off"
)
###############################################################################
# Enable improved diagnostics.
###############################################################################
add_custom_target(ci_test_diagnostics
COMMAND CXX=${CLANG_TOOL} ${CMAKE_COMMAND}
-DCMAKE_BUILD_TYPE=Debug -GNinja
-DJSON_BuildTests=ON -DJSON_MultipleHeaders=ON -DJSON_Diagnostics=ON
-S${PROJECT_SOURCE_DIR} -B${PROJECT_BINARY_DIR}/build_diagnostics
COMMAND ${CMAKE_COMMAND} --build ${PROJECT_BINARY_DIR}/build_diagnostics
COMMAND cd ${PROJECT_BINARY_DIR}/build_diagnostics && ${CMAKE_CTEST_COMMAND} --parallel ${N} --output-on-failure
COMMENT "Compile and test with improved diagnostics enabled"
)
###############################################################################
# Coverage.
###############################################################################
add_custom_target(ci_test_coverage
COMMAND CXX=g++ ${CMAKE_COMMAND}
-DCMAKE_BUILD_TYPE=Debug -GNinja -DCMAKE_CXX_FLAGS="--coverage;-fprofile-arcs;-ftest-coverage"
-DJSON_BuildTests=ON -DJSON_MultipleHeaders=ON
-S${PROJECT_SOURCE_DIR} -B${PROJECT_BINARY_DIR}/build_coverage
COMMAND ${CMAKE_COMMAND} --build ${PROJECT_BINARY_DIR}/build_coverage
COMMAND cd ${PROJECT_BINARY_DIR}/build_coverage && ${CMAKE_CTEST_COMMAND} --parallel ${N} --output-on-failure
COMMAND ${LCOV_TOOL} --directory . --capture --output-file json.info --rc lcov_branch_coverage=1
COMMAND ${LCOV_TOOL} -e json.info ${SRC_FILES} --output-file json.info.filtered --rc lcov_branch_coverage=1
COMMAND ${CMAKE_SOURCE_DIR}/test/thirdparty/imapdl/filterbr.py json.info.filtered > json.info.filtered.noexcept
COMMAND genhtml --title "JSON for Modern C++" --legend --demangle-cpp --output-directory html --show-details --branch-coverage json.info.filtered.noexcept
COMMENT "Compile and test with coverage"
)
###############################################################################
# Sanitizers.
###############################################################################
set(CLANG_CXX_FLAGS_SANITIZER "-g -O1 -fsanitize=address -fsanitize=undefined -fsanitize=integer -fsanitize=nullability -fno-omit-frame-pointer -fno-sanitize-recover=all -fno-sanitize=unsigned-integer-overflow -fno-sanitize=unsigned-shift-base")
add_custom_target(ci_test_clang_sanitizer
COMMAND CXX=${CLANG_TOOL} CXXFLAGS=${CLANG_CXX_FLAGS_SANITIZER} ${CMAKE_COMMAND}
-DCMAKE_BUILD_TYPE=Debug -GNinja
-DJSON_BuildTests=ON
-S${PROJECT_SOURCE_DIR} -B${PROJECT_BINARY_DIR}/build_clang_sanitizer
COMMAND ${CMAKE_COMMAND} --build ${PROJECT_BINARY_DIR}/build_clang_sanitizer
COMMAND cd ${PROJECT_BINARY_DIR}/build_clang_sanitizer && ${CMAKE_CTEST_COMMAND} --parallel ${N} --output-on-failure
COMMENT "Compile and test with sanitizers"
)
###############################################################################
# Check if header is amalgamated and sources are properly indented.
###############################################################################
set(ASTYLE_FLAGS --style=allman --indent=spaces=4 --indent-modifiers --indent-switches --indent-preproc-block --indent-preproc-define --indent-col1-comments --pad-oper --pad-header --align-pointer=type --align-reference=type --add-brackets --convert-tabs --close-templates --lineend=linux --preserve-date --formatted)
file(GLOB_RECURSE INDENT_FILES
${PROJECT_SOURCE_DIR}/include/nlohmann/*.hpp
${PROJECT_SOURCE_DIR}/test/src/*.cpp
${PROJECT_SOURCE_DIR}/test/src/*.hpp
${PROJECT_SOURCE_DIR}/benchmarks/src/benchmarks.cpp
${PROJECT_SOURCE_DIR}/doc/examples/*.cpp
)
add_custom_target(ci_test_amalgamation
COMMAND rm -fr ${PROJECT_SOURCE_DIR}/single_include/nlohmann/json.hpp~
COMMAND cp ${PROJECT_SOURCE_DIR}/single_include/nlohmann/json.hpp ${PROJECT_SOURCE_DIR}/single_include/nlohmann/json.hpp~
COMMAND ${Python3_EXECUTABLE} ${PROJECT_SOURCE_DIR}/third_party/amalgamate/amalgamate.py -c ${PROJECT_SOURCE_DIR}/third_party/amalgamate/config.json -s .
COMMAND ${ASTYLE_TOOL} ${ASTYLE_FLAGS} --suffix=none --quiet ${PROJECT_SOURCE_DIR}/single_include/nlohmann/json.hpp
COMMAND diff ${PROJECT_SOURCE_DIR}/single_include/nlohmann/json.hpp~ ${PROJECT_SOURCE_DIR}/single_include/nlohmann/json.hpp
COMMAND ${ASTYLE_TOOL} ${ASTYLE_FLAGS} ${INDENT_FILES}
COMMAND cd ${PROJECT_SOURCE_DIR} && for FILE in `find . -name '*.orig'`\; do false \; done
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
COMMENT "Check amalagamation and indentation"
)
###############################################################################
# Valgrind.
###############################################################################
add_custom_target(ci_test_valgrind
COMMAND CXX=${GCC_TOOL} ${CMAKE_COMMAND}
-DCMAKE_BUILD_TYPE=Debug -GNinja
-DJSON_BuildTests=ON -DJSON_Valgrind=ON
-S${PROJECT_SOURCE_DIR} -B${PROJECT_BINARY_DIR}/build_valgrind
COMMAND ${CMAKE_COMMAND} --build ${PROJECT_BINARY_DIR}/build_valgrind
COMMAND cd ${PROJECT_BINARY_DIR}/build_valgrind && ${CMAKE_CTEST_COMMAND} -L valgrind --parallel ${N} --output-on-failure
COMMENT "Compile and test with Valgrind"
)
###############################################################################
# Check code with Clang Static Analyzer.
###############################################################################
set(CLANG_ANALYZER_CHECKS "fuchsia.HandleChecker,nullability.NullableDereferenced,nullability.NullablePassedToNonnull,nullability.NullableReturnedFromNonnull,optin.cplusplus.UninitializedObject,optin.cplusplus.VirtualCall,optin.mpi.MPI-Checker,optin.osx.OSObjectCStyleCast,optin.osx.cocoa.localizability.EmptyLocalizationContextChecker,optin.osx.cocoa.localizability.NonLocalizedStringChecker,optin.performance.GCDAntipattern,optin.performance.Padding,optin.portability.UnixAPI,security.FloatLoopCounter,security.insecureAPI.DeprecatedOrUnsafeBufferHandling,security.insecureAPI.bcmp,security.insecureAPI.bcopy,security.insecureAPI.bzero,security.insecureAPI.rand,security.insecureAPI.strcpy,valist.CopyToSelf,valist.Uninitialized,valist.Unterminated,webkit.NoUncountedMemberChecker,webkit.RefCntblBaseVirtualDtor,core.CallAndMessage,core.DivideZero,core.NonNullParamChecker,core.NullDereference,core.StackAddressEscape,core.UndefinedBinaryOperatorResult,core.VLASize,core.uninitialized.ArraySubscript,core.uninitialized.Assign,core.uninitialized.Branch,core.uninitialized.CapturedBlockVariable,core.uninitialized.UndefReturn,cplusplus.InnerPointer,cplusplus.Move,cplusplus.NewDelete,cplusplus.NewDeleteLeaks,cplusplus.PlacementNew,cplusplus.PureVirtualCall,deadcode.DeadStores,nullability.NullPassedToNonnull,nullability.NullReturnedFromNonnull,osx.API,osx.MIG,osx.NumberObjectConversion,osx.OSObjectRetainCount,osx.ObjCProperty,osx.SecKeychainAPI,osx.cocoa.AtSync,osx.cocoa.AutoreleaseWrite,osx.cocoa.ClassRelease,osx.cocoa.Dealloc,osx.cocoa.IncompatibleMethodTypes,osx.cocoa.Loops,osx.cocoa.MissingSuperCall,osx.cocoa.NSAutoreleasePool,osx.cocoa.NSError,osx.cocoa.NilArg,osx.cocoa.NonNilReturnValue,osx.cocoa.ObjCGenerics,osx.cocoa.RetainCount,osx.cocoa.RunLoopAutoreleaseLeak,osx.cocoa.SelfInit,osx.cocoa.SuperDealloc,osx.cocoa.UnusedIvars,osx.cocoa.VariadicMethodTypes,osx.coreFoundation.CFError,osx.coreFoundation.CFNumber,osx.coreFoundation.CFRetainRelease,osx.coreFoundation.containers.OutOfBounds,osx.coreFoundation.containers.PointerSizedValues,security.insecureAPI.UncheckedReturn,security.insecureAPI.decodeValueOfObjCType,security.insecureAPI.getpw,security.insecureAPI.gets,security.insecureAPI.mkstemp,security.insecureAPI.mktemp,security.insecureAPI.vfork,unix.API,unix.Malloc,unix.MallocSizeof,unix.MismatchedDeallocator,unix.Vfork,unix.cstring.BadSizeArg,unix.cstring.NullArg")
add_custom_target(ci_clang_analyze
COMMAND CXX=${CLANG_TOOL} ${CMAKE_COMMAND}
-DCMAKE_BUILD_TYPE=Debug -GNinja
-DJSON_BuildTests=ON
-S${PROJECT_SOURCE_DIR} -B${PROJECT_BINARY_DIR}/build_clang_analyze
COMMAND cd ${PROJECT_BINARY_DIR}/build_clang_analyze && ${SCAN_BUILD_TOOL} -enable-checker ${CLANG_ANALYZER_CHECKS} --use-c++=${CLANG_TOOL} -analyze-headers -o ${PROJECT_BINARY_DIR}/report ninja
COMMENT "Check code with Clang Analyzer"
)
###############################################################################
# Check code with Cppcheck.
###############################################################################
add_custom_target(ci_cppcheck
COMMAND ${CPPCHECK_TOOL} --enable=warning --suppress=missingReturn --inline-suppr --inconclusive --force --std=c++11 ${PROJECT_SOURCE_DIR}/single_include/nlohmann/json.hpp --error-exitcode=1
COMMENT "Check code with Cppcheck"
)
###############################################################################
# Check code with cpplint.
###############################################################################
add_custom_target(ci_cpplint
COMMAND ${Python3_EXECUTABLE} ${CMAKE_SOURCE_DIR}/third_party/cpplint/cpplint.py --filter=-whitespace,-legal,-runtime/references,-runtime/explicit,-runtime/indentation_namespace,-readability/casting,-readability/nolint --quiet --recursive ${SRC_FILES}
COMMENT "Check code with cpplint"
)
###############################################################################
# Check code with OCLint.
###############################################################################
file(COPY ${PROJECT_SOURCE_DIR}/single_include/nlohmann/json.hpp DESTINATION ${PROJECT_BINARY_DIR}/src_single)
file(RENAME ${PROJECT_BINARY_DIR}/src_single/json.hpp ${PROJECT_BINARY_DIR}/src_single/all.cpp)
file(APPEND "${PROJECT_BINARY_DIR}/src_single/all.cpp" "\n\nint main()\n{}\n")
add_executable(single_all ${PROJECT_BINARY_DIR}/src_single/all.cpp)
target_compile_features(single_all PRIVATE cxx_std_11)
add_custom_target(ci_oclint
COMMAND ${CMAKE_COMMAND}
-DCMAKE_BUILD_TYPE=Debug
-DCMAKE_EXPORT_COMPILE_COMMANDS=ON
-DJSON_BuildTests=OFF -DJSON_CI=ON
-S${PROJECT_SOURCE_DIR} -B${PROJECT_BINARY_DIR}/build_oclint
COMMAND ${OCLINT_TOOL} -i ${PROJECT_BINARY_DIR}/build_oclint/src_single/all.cpp -p ${PROJECT_BINARY_DIR}/build_oclint --
-report-type html -enable-global-analysis --max-priority-1=0 --max-priority-2=1000 --max-priority-3=2000
--disable-rule=MultipleUnaryOperator
--disable-rule=DoubleNegative
--disable-rule=ShortVariableName
--disable-rule=GotoStatement
--disable-rule=LongLine
-o ${PROJECT_BINARY_DIR}/build_oclint/oclint_report.html
COMMENT "Check code with OCLint"
)
###############################################################################
# Check code with Clang-Tidy.
###############################################################################
add_custom_target(ci_clang_tidy
COMMAND CXX=${CLANG_TOOL} ${CMAKE_COMMAND}
-DCMAKE_BUILD_TYPE=Debug -GNinja
-DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DCMAKE_CXX_CLANG_TIDY=${CLANG_TIDY_TOOL}
-DJSON_BuildTests=ON -DJSON_MultipleHeaders=ON
-S${PROJECT_SOURCE_DIR} -B${PROJECT_BINARY_DIR}/build_clang_tidy
COMMAND ${CMAKE_COMMAND} --build ${PROJECT_BINARY_DIR}/build_clang_tidy
COMMENT "Check code with Clang-Tidy"
)
###############################################################################
# Check code with PVS-Studio Analyzer <https://www.viva64.com/en/pvs-studio/>.
###############################################################################
add_custom_target(ci_pvs_studio
COMMAND CXX=${CLANG_TOOL} ${CMAKE_COMMAND}
-DCMAKE_BUILD_TYPE=Debug
-DCMAKE_EXPORT_COMPILE_COMMANDS=ON
-DJSON_BuildTests=ON
-S${PROJECT_SOURCE_DIR} -B${PROJECT_BINARY_DIR}/build_pvs_studio
COMMAND cd ${PROJECT_BINARY_DIR}/build_pvs_studio && ${PVS_STUDIO_ANALYZER_TOOL} analyze -j 10
COMMAND cd ${PROJECT_BINARY_DIR}/build_pvs_studio && ${PLOG_CONVERTER_TOOL} -a'GA:1,2;64:1;CS' -t fullhtml PVS-Studio.log -o pvs
COMMENT "Check code with PVS Studio"
)
###############################################################################
# Check code with Infer <https://fbinfer.com> static analyzer.
###############################################################################
add_custom_target(ci_infer
COMMAND mkdir -p ${PROJECT_BINARY_DIR}/build_infer
COMMAND cd ${PROJECT_BINARY_DIR}/build_infer && ${INFER_TOOL} compile -- ${CMAKE_COMMAND} -DCMAKE_BUILD_TYPE=Debug ${PROJECT_SOURCE_DIR} -DJSON_BuildTests=ON -DJSON_MultipleHeaders=ON
COMMAND cd ${PROJECT_BINARY_DIR}/build_infer && ${INFER_TOOL} run -- make
COMMENT "Check code with Infer"
)
###############################################################################
# Run test suite with previously downloaded test data.
###############################################################################
add_custom_target(ci_offline_testdata
COMMAND mkdir -p ${PROJECT_BINARY_DIR}/build_offline_testdata/test_data
COMMAND cd ${PROJECT_BINARY_DIR}/build_offline_testdata/test_data && ${GIT_TOOL} clone -c advice.detachedHead=false --branch v3.0.0 https://github.com/nlohmann/json_test_data.git --quiet --depth 1
COMMAND ${CMAKE_COMMAND}
-DCMAKE_BUILD_TYPE=Debug -GNinja
-DJSON_BuildTests=ON -DJSON_FastTests=ON -DJSON_TestDataDirectory=${PROJECT_BINARY_DIR}/build_offline_testdata/test_data/json_test_data
-S${PROJECT_SOURCE_DIR} -B${PROJECT_BINARY_DIR}/build_offline_testdata
COMMAND ${CMAKE_COMMAND} --build ${PROJECT_BINARY_DIR}/build_offline_testdata
COMMAND cd ${PROJECT_BINARY_DIR}/build_offline_testdata && ${CMAKE_CTEST_COMMAND} --parallel ${N} --output-on-failure
COMMENT "Check code with previously downloaded test data"
)
###############################################################################
# Run test suite when project was not checked out from Git
###############################################################################
add_custom_target(ci_non_git_tests
COMMAND mkdir -p ${PROJECT_BINARY_DIR}/build_non_git_tests/sources
COMMAND cd ${PROJECT_SOURCE_DIR} && for FILE in `${GIT_TOOL} ls-tree --name-only HEAD`\; do cp -r $$FILE ${PROJECT_BINARY_DIR}/build_non_git_tests/sources \; done
COMMAND ${CMAKE_COMMAND}
-DCMAKE_BUILD_TYPE=Debug -GNinja
-DJSON_BuildTests=ON -DJSON_FastTests=ON
-S${PROJECT_BINARY_DIR}/build_non_git_tests/sources -B${PROJECT_BINARY_DIR}/build_non_git_tests
COMMAND ${CMAKE_COMMAND} --build ${PROJECT_BINARY_DIR}/build_non_git_tests
COMMAND cd ${PROJECT_BINARY_DIR}/build_non_git_tests && ${CMAKE_CTEST_COMMAND} --parallel ${N} -LE git_required --output-on-failure
COMMENT "Check code when project was not checked out from Git"
)
###############################################################################
# Run test suite and exclude tests that change installed files
###############################################################################
add_custom_target(ci_reproducible_tests
COMMAND ${CMAKE_COMMAND}
-DCMAKE_BUILD_TYPE=Debug -GNinja
-DJSON_BuildTests=ON -DJSON_FastTests=ON
-S${PROJECT_SOURCE_DIR} -B${PROJECT_BINARY_DIR}/build_reproducible_tests
COMMAND ${CMAKE_COMMAND} --build ${PROJECT_BINARY_DIR}/build_reproducible_tests
COMMAND cd ${PROJECT_BINARY_DIR}/build_reproducible_tests && ${CMAKE_CTEST_COMMAND} --parallel ${N} -LE not_reproducible --output-on-failure
COMMENT "Check code and exclude tests that change installed files"
)
###############################################################################
# Check if every header in the include folder includes sufficient headers to
# be compiled individually.
###############################################################################
set(iwyu_path_and_options ${IWYU_TOOL} -Xiwyu --max_line_length=300)
foreach(SRC_FILE ${SRC_FILES})
# get relative path of the header file
file(RELATIVE_PATH RELATIVE_SRC_FILE "${PROJECT_SOURCE_DIR}/include/nlohmann" "${SRC_FILE}")
# replace slashes and strip suffix
string(REPLACE "/" "_" RELATIVE_SRC_FILE "${RELATIVE_SRC_FILE}")
string(REPLACE ".hpp" "" RELATIVE_SRC_FILE "${RELATIVE_SRC_FILE}")
# create code file
file(WRITE "${PROJECT_BINARY_DIR}/src_single/${RELATIVE_SRC_FILE}.cpp" "#include \"${SRC_FILE}\" // IWYU pragma: keep\n\nint main()\n{}\n")
# create executable
add_executable(single_${RELATIVE_SRC_FILE} EXCLUDE_FROM_ALL ${PROJECT_BINARY_DIR}/src_single/${RELATIVE_SRC_FILE}.cpp)
target_include_directories(single_${RELATIVE_SRC_FILE} PRIVATE ${PROJECT_SOURCE_DIR}/include)
target_compile_features(single_${RELATIVE_SRC_FILE} PRIVATE cxx_std_11)
set_property(TARGET single_${RELATIVE_SRC_FILE} PROPERTY CXX_INCLUDE_WHAT_YOU_USE "${iwyu_path_and_options}")
# remember binary for ci_single_binaries target
list(APPEND single_binaries single_${RELATIVE_SRC_FILE})
endforeach()
add_custom_target(ci_single_binaries
DEPENDS ${single_binaries}
COMMENT "Check if headers are self-contained"
)
###############################################################################
# Benchmarks
###############################################################################
add_custom_target(ci_benchmarks
COMMAND ${CMAKE_COMMAND}
-DCMAKE_BUILD_TYPE=Release -GNinja
-S${PROJECT_SOURCE_DIR}/benchmarks -B${PROJECT_BINARY_DIR}/build_benchmarks
COMMAND ${CMAKE_COMMAND} --build ${PROJECT_BINARY_DIR}/build_benchmarks --target json_benchmarks
COMMAND cd ${PROJECT_BINARY_DIR}/build_benchmarks && ./json_benchmarks
COMMENT "Run benchmarks"
)
###############################################################################
# CMake flags
###############################################################################
if (APPLE)
set(CMAKE_310_BINARY ${PROJECT_BINARY_DIR}/cmake-3.1.0-Darwin64/CMake.app/Contents/bin/cmake)
add_custom_command(
OUTPUT ${CMAKE_310_BINARY}
COMMAND wget https://github.com/Kitware/CMake/releases/download/v3.1.0/cmake-3.1.0-Darwin64.tar.gz
COMMAND tar xfz cmake-3.1.0-Darwin64.tar.gz
COMMAND rm cmake-3.1.0-Darwin64.tar.gz
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
COMMENT "Download CMake 3.1.0"
)
else()
set(CMAKE_310_BINARY ${PROJECT_BINARY_DIR}/cmake-3.1.0-Linux-x86_64/bin/cmake)
add_custom_command(
OUTPUT ${CMAKE_310_BINARY}
COMMAND wget https://github.com/Kitware/CMake/releases/download/v3.1.0/cmake-3.1.0-Linux-x86_64.tar.gz
COMMAND tar xfz cmake-3.1.0-Linux-x86_64.tar.gz
COMMAND rm cmake-3.1.0-Linux-x86_64.tar.gz
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
COMMENT "Download CMake 3.1.0"
)
endif()
set(JSON_CMAKE_FLAGS "JSON_BuildTests;JSON_Install;JSON_MultipleHeaders;JSON_ImplicitConversions;JSON_Valgrind;JSON_Diagnostics;JSON_SystemInclude")
foreach(JSON_CMAKE_FLAG ${JSON_CMAKE_FLAGS})
string(TOLOWER "ci_cmake_flag_${JSON_CMAKE_FLAG}" JSON_CMAKE_FLAG_TARGET)
add_custom_target("${JSON_CMAKE_FLAG_TARGET}"
COMMENT "Check CMake flag ${JSON_CMAKE_FLAG} (CMake ${CMAKE_VERSION})"
COMMAND ${CMAKE_COMMAND}
-Werror=dev
-D${JSON_CMAKE_FLAG}=ON
-S${PROJECT_SOURCE_DIR} -B${PROJECT_BINARY_DIR}/build_${JSON_CMAKE_FLAG_TARGET}
)
add_custom_target("${JSON_CMAKE_FLAG_TARGET}_31"
COMMENT "Check CMake flag ${JSON_CMAKE_FLAG} (CMake 3.1)"
COMMAND mkdir ${PROJECT_BINARY_DIR}/build_${JSON_CMAKE_FLAG_TARGET}_31
COMMAND cd ${PROJECT_BINARY_DIR}/build_${JSON_CMAKE_FLAG_TARGET}_31 && ${CMAKE_310_BINARY}
-Werror=dev ${PROJECT_SOURCE_DIR}
-D${JSON_CMAKE_FLAG}=ON
-DCMAKE_CXX_COMPILE_FEATURES="cxx_range_for" -DCMAKE_CXX_FLAGS="-std=gnu++11"
DEPENDS ${CMAKE_310_BINARY}
)
list(APPEND JSON_CMAKE_FLAG_TARGETS ${JSON_CMAKE_FLAG_TARGET} ${JSON_CMAKE_FLAG_TARGET}_31)
list(APPEND JSON_CMAKE_FLAG_BUILD_DIRS ${PROJECT_BINARY_DIR}/build_${JSON_CMAKE_FLAG_TARGET} ${PROJECT_BINARY_DIR}/build_${JSON_CMAKE_FLAG_TARGET}_31)
endforeach()
add_custom_target(ci_cmake_flags
DEPENDS ${JSON_CMAKE_FLAG_TARGETS}
COMMENT "Check CMake flags"
)
###############################################################################
# Use more installed compilers.
###############################################################################
foreach(COMPILER g++-4.8 g++-4.9 g++-5 g++-7 g++-8 g++-9 g++-10 clang++-3.5 clang++-3.6 clang++-3.7 clang++-3.8 clang++-3.9 clang++-4.0 clang++-5.0 clang++-6.0 clang++-7 clang++-8 clang++-9 clang++-10 clang++-11 clang++-12)
find_program(COMPILER_TOOL NAMES ${COMPILER})
if (COMPILER_TOOL)
add_custom_target(ci_test_compiler_${COMPILER}
COMMAND CXX=${COMPILER} ${CMAKE_COMMAND}
-DCMAKE_BUILD_TYPE=Debug -GNinja
-DJSON_BuildTests=ON -DJSON_FastTests=ON
-S${PROJECT_SOURCE_DIR} -B${PROJECT_BINARY_DIR}/build_compiler_${COMPILER}
COMMAND ${CMAKE_COMMAND} --build ${PROJECT_BINARY_DIR}/build_compiler_${COMPILER}
COMMAND cd ${PROJECT_BINARY_DIR}/build_compiler_${COMPILER} && ${CMAKE_CTEST_COMMAND} --parallel ${N} --exclude-regex "test-unicode" --output-on-failure
COMMENT "Compile and test with ${COMPILER}"
)
endif()
unset(COMPILER_TOOL CACHE)
endforeach()
###############################################################################
# Clean up all generated files.
###############################################################################
add_custom_target(ci_clean
COMMAND rm -fr ${PROJECT_BINARY_DIR}/build_* cmake-3.1.0-Darwin64 ${JSON_CMAKE_FLAG_BUILD_DIRS} ${single_binaries}
COMMENT "Clean generated directories"
)

View File

@@ -48,7 +48,7 @@ message(STATUS "Operating system: ${OS_VERSION_STRINGS}")
# determine the compiler (for debug and support purposes)
if (MSVC)
execute_process(COMMAND ${CMAKE_CXX_COMPILER} OUTPUT_VARIABLE CXX_VERSION_RESULT OUTPUT_STRIP_TRAILING_WHITESPACE ERROR_VARIABLE CXX_VERSION_RESULT ERROR_STRIP_TRAILING_WHITESPACE)
set(CMAKE_CXX_COMPILER "${CXX_VERSION_RESULT}; MSVC_VERSION=${MSVC_VERSION}; MSVC_TOOLSET_VERSION=${MSVC_TOOLSET_VERSION}")
set(CXX_VERSION_RESULT "${CXX_VERSION_RESULT}; MSVC_VERSION=${MSVC_VERSION}; MSVC_TOOLSET_VERSION=${MSVC_TOOLSET_VERSION}")
else()
execute_process(COMMAND ${CMAKE_CXX_COMPILER} --version OUTPUT_VARIABLE CXX_VERSION_RESULT OUTPUT_STRIP_TRAILING_WHITESPACE)
endif()

View File

@@ -1,4 +1,4 @@
Name: ${PROJECT_NAME}
Description: JSON for Modern C++
Version: ${PROJECT_VERSION}
Cflags: -I${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_INCLUDEDIR}
Cflags: -I${CMAKE_INSTALL_FULL_INCLUDEDIR}

View File

@@ -1,11 +1,11 @@
# Doxyfile 1.8.19
# Doxyfile 1.9.1
#---------------------------------------------------------------------------
# Project related configuration options
#---------------------------------------------------------------------------
DOXYFILE_ENCODING = UTF-8
PROJECT_NAME = "JSON for Modern C++"
PROJECT_NUMBER = 3.8.0
PROJECT_NUMBER = 3.10.4
PROJECT_BRIEF =
PROJECT_LOGO =
OUTPUT_DIRECTORY = .
@@ -26,6 +26,7 @@ JAVADOC_AUTOBRIEF = NO
JAVADOC_BANNER = NO
QT_AUTOBRIEF = NO
MULTILINE_CPP_IS_BRIEF = NO
PYTHON_DOCSTRING = YES
INHERIT_DOCS = YES
SEPARATE_MEMBER_PAGES = YES
TAB_SIZE = 4
@@ -54,6 +55,7 @@ INLINE_GROUPED_CLASSES = NO
INLINE_SIMPLE_STRUCTS = NO
TYPEDEF_HIDES_STRUCT = NO
LOOKUP_CACHE_SIZE = 0
NUM_PROC_THREADS = 1
#---------------------------------------------------------------------------
# Build related configuration options
#---------------------------------------------------------------------------
@@ -65,6 +67,7 @@ EXTRACT_STATIC = YES
EXTRACT_LOCAL_CLASSES = YES
EXTRACT_LOCAL_METHODS = YES
EXTRACT_ANON_NSPACES = YES
RESOLVE_UNNAMED_PARAMS = YES
HIDE_UNDOC_MEMBERS = NO
HIDE_UNDOC_CLASSES = NO
HIDE_FRIEND_COMPOUNDS = NO
@@ -143,7 +146,6 @@ VERBATIM_HEADERS = NO
# Configuration options related to the alphabetical class index
#---------------------------------------------------------------------------
ALPHABETICAL_INDEX = YES
COLS_IN_ALPHA_INDEX = 5
IGNORE_PREFIX =
#---------------------------------------------------------------------------
# Configuration options related to the HTML output
@@ -250,7 +252,7 @@ MAN_LINKS = NO
#---------------------------------------------------------------------------
# Configuration options related to the XML output
#---------------------------------------------------------------------------
GENERATE_XML = YES
GENERATE_XML = NO
XML_OUTPUT = xml
XML_PROGRAMLISTING = YES
XML_NS_MEMB_FILE_SCOPE = NO
@@ -307,6 +309,8 @@ COLLABORATION_GRAPH = NO
GROUP_GRAPHS = YES
UML_LOOK = YES
UML_LIMIT_NUM_FIELDS = 10
DOT_UML_DETAILS = NO
DOT_WRAP_THRESHOLD = 17
TEMPLATE_RELATIONS = NO
INCLUDE_GRAPH = NO
INCLUDED_BY_GRAPH = NO

Some files were not shown because too many files have changed in this diff Show More