From 9148ae53f9cbf6485cd67d919f3359800cbb0d15 Mon Sep 17 00:00:00 2001 From: Wieczorek Bartosz Date: Sun, 26 Feb 2017 09:32:45 +0100 Subject: [PATCH] add tao cpp lib into project, small fixes --- CMakeLists.txt | 2 + share/CMakeLists.txt | 1 + share/include/tao/json.hh | 44 + .../tao/json/external/akrzemi1/CMakeLists.txt | 11 + .../json/external/akrzemi1/LICENSE_1_0.txt | 23 + .../tao/json/external/akrzemi1/README.md | 39 + .../tao/json/external/akrzemi1/copyright.txt | 10 + .../tao/json/external/akrzemi1/optional.hpp | 1042 ++++++++ .../json/external/akrzemi1/test_optional.cpp | 1459 +++++++++++ .../external/akrzemi1/test_type_traits.cpp | 66 + share/include/tao/json/external/double.hh | 2137 +++++++++++++++++ share/include/tao/json/external/operators.hpp | 658 +++++ share/include/tao/json/external/optional.hpp | 33 + share/include/tao/json/external/pegtl.hh | 22 + .../tao/json/external/pegtl/action_input.hh | 116 + .../external/pegtl/analysis/analyze_cycles.hh | 129 + .../json/external/pegtl/analysis/counted.hh | 22 + .../json/external/pegtl/analysis/generic.hh | 33 + .../external/pegtl/analysis/grammar_info.hh | 35 + .../external/pegtl/analysis/insert_guard.hh | 59 + .../external/pegtl/analysis/insert_rules.hh | 37 + .../json/external/pegtl/analysis/rule_info.hh | 31 + .../json/external/pegtl/analysis/rule_type.hh | 23 + .../tao/json/external/pegtl/analyze.hh | 19 + .../tao/json/external/pegtl/apply_mode.hh | 17 + .../include/tao/json/external/pegtl/ascii.hh | 47 + .../tao/json/external/pegtl/buffer_input.hh | 171 ++ .../tao/json/external/pegtl/contrib/abnf.hh | 36 + .../json/external/pegtl/contrib/alphabet.hh | 69 + .../json/external/pegtl/contrib/changes.hh | 68 + .../tao/json/external/pegtl/contrib/http.hh | 145 ++ .../tao/json/external/pegtl/contrib/json.hh | 89 + .../json/external/pegtl/contrib/raw_string.hh | 164 ++ .../json/external/pegtl/contrib/unescape.hh | 180 ++ .../tao/json/external/pegtl/contrib/uri.hh | 108 + .../tao/json/external/pegtl/cr_crlf_eol.hh | 29 + .../include/tao/json/external/pegtl/cr_eol.hh | 29 + .../tao/json/external/pegtl/crlf_eol.hh | 29 + share/include/tao/json/external/pegtl/eol.hh | 22 + .../tao/json/external/pegtl/file_parser.hh | 43 + .../tao/json/external/pegtl/input_error.hh | 34 + .../json/external/pegtl/internal/action.hh | 36 + .../tao/json/external/pegtl/internal/any.hh | 59 + .../tao/json/external/pegtl/internal/at.hh | 43 + .../json/external/pegtl/internal/bump_util.hh | 50 + .../tao/json/external/pegtl/internal/bytes.hh | 45 + .../json/external/pegtl/internal/control.hh | 36 + .../external/pegtl/internal/cstream_reader.hh | 43 + .../external/pegtl/internal/cstring_reader.hh | 45 + .../json/external/pegtl/internal/demangle.hh | 36 + .../pegtl/internal/demangle_cxxabi.hh | 26 + .../external/pegtl/internal/demangle_nop.hh | 22 + .../json/external/pegtl/internal/disable.hh | 36 + .../json/external/pegtl/internal/discard.hh | 34 + .../external/pegtl/internal/discard_if.hh | 40 + .../json/external/pegtl/internal/enable.hh | 36 + .../tao/json/external/pegtl/internal/eof.hh | 33 + .../tao/json/external/pegtl/internal/eol.hh | 34 + .../json/external/pegtl/internal/eol_impl.hh | 108 + .../tao/json/external/pegtl/internal/eolf.hh | 35 + .../external/pegtl/internal/file_mapper.hh | 85 + .../external/pegtl/internal/file_opener.hh | 65 + .../external/pegtl/internal/file_reader.hh | 83 + .../json/external/pegtl/internal/if_must.hh | 21 + .../external/pegtl/internal/if_must_else.hh | 21 + .../external/pegtl/internal/if_then_else.hh | 42 + .../external/pegtl/internal/input_data.hh | 67 + .../external/pegtl/internal/input_mark.hh | 89 + .../external/pegtl/internal/input_pair.hh | 29 + .../external/pegtl/internal/istream_reader.hh | 42 + .../json/external/pegtl/internal/istring.hh | 89 + .../tao/json/external/pegtl/internal/list.hh | 21 + .../json/external/pegtl/internal/list_must.hh | 22 + .../json/external/pegtl/internal/list_tail.hh | 22 + .../external/pegtl/internal/list_tail_pad.hh | 24 + .../tao/json/external/pegtl/internal/minus.hh | 46 + .../tao/json/external/pegtl/internal/must.hh | 49 + .../json/external/pegtl/internal/not_at.hh | 43 + .../tao/json/external/pegtl/internal/one.hh | 73 + .../tao/json/external/pegtl/internal/opt.hh | 49 + .../tao/json/external/pegtl/internal/pad.hh | 21 + .../json/external/pegtl/internal/pad_opt.hh | 22 + .../json/external/pegtl/internal/peek_char.hh | 31 + .../external/pegtl/internal/peek_utf16.hh | 48 + .../external/pegtl/internal/peek_utf32.hh | 47 + .../json/external/pegtl/internal/peek_utf8.hh | 82 + .../external/pegtl/internal/pegtl_string.hh | 91 + .../tao/json/external/pegtl/internal/plus.hh | 46 + .../tao/json/external/pegtl/internal/raise.hh | 39 + .../tao/json/external/pegtl/internal/range.hh | 60 + .../json/external/pegtl/internal/ranges.hh | 92 + .../tao/json/external/pegtl/internal/rep.hh | 53 + .../json/external/pegtl/internal/rep_min.hh | 22 + .../external/pegtl/internal/rep_min_max.hh | 70 + .../json/external/pegtl/internal/rep_opt.hh | 37 + .../json/external/pegtl/internal/require.hh | 34 + .../pegtl/internal/result_on_found.hh | 21 + .../pegtl/internal/rule_conjunction.hh | 34 + .../external/pegtl/internal/rule_match_one.hh | 43 + .../pegtl/internal/rule_match_three.hh | 42 + .../external/pegtl/internal/rule_match_two.hh | 68 + .../tao/json/external/pegtl/internal/rules.hh | 54 + .../tao/json/external/pegtl/internal/seq.hh | 55 + .../external/pegtl/internal/skip_control.hh | 28 + .../tao/json/external/pegtl/internal/sor.hh | 46 + .../tao/json/external/pegtl/internal/star.hh | 41 + .../json/external/pegtl/internal/star_must.hh | 21 + .../tao/json/external/pegtl/internal/state.hh | 55 + .../json/external/pegtl/internal/string.hh | 56 + .../json/external/pegtl/internal/trivial.hh | 34 + .../external/pegtl/internal/try_catch_type.hh | 53 + .../tao/json/external/pegtl/internal/until.hh | 68 + .../tao/json/external/pegtl/lf_crlf_eol.hh | 34 + .../include/tao/json/external/pegtl/lf_eol.hh | 29 + .../tao/json/external/pegtl/memory_input.hh | 143 ++ .../tao/json/external/pegtl/mmap_parser.hh | 74 + .../include/tao/json/external/pegtl/normal.hh | 46 + .../tao/json/external/pegtl/nothing.hh | 18 + .../include/tao/json/external/pegtl/parse.hh | 140 ++ .../tao/json/external/pegtl/parse_error.hh | 38 + .../tao/json/external/pegtl/position_info.hh | 46 + .../tao/json/external/pegtl/read_parser.hh | 42 + .../include/tao/json/external/pegtl/rules.hh | 58 + .../tao/json/external/pegtl/string_parser.hh | 62 + .../include/tao/json/external/pegtl/trace.hh | 125 + .../include/tao/json/external/pegtl/utf16.hh | 26 + .../include/tao/json/external/pegtl/utf32.hh | 26 + share/include/tao/json/external/pegtl/utf8.hh | 26 + share/include/tao/json/from_stream.hh | 52 + share/include/tao/json/from_string.hh | 83 + share/include/tao/json/internal/action.hh | 222 ++ share/include/tao/json/internal/control.hh | 41 + share/include/tao/json/internal/errors.hh | 58 + share/include/tao/json/internal/escape.hh | 76 + .../include/tao/json/internal/get_by_enum.hh | 126 + share/include/tao/json/internal/grammar.hh | 149 ++ .../tao/json/internal/integer_sequence.hh | 80 + share/include/tao/json/internal/key_state.hh | 37 + .../include/tao/json/internal/number_state.hh | 79 + share/include/tao/json/internal/sha256.hh | 214 ++ .../include/tao/json/internal/string_state.hh | 37 + share/include/tao/json/internal/throw.hh | 24 + .../tao/json/internal/totally_ordered.hh | 457 ++++ .../tao/json/internal/unescape_action.hh | 30 + .../include/tao/json/internal/uri_fragment.hh | 182 ++ .../include/tao/json/internal/value_union.hh | 48 + share/include/tao/json/pair.hh | 42 + share/include/tao/json/parse_file.hh | 40 + share/include/tao/json/patch.hh | 109 + share/include/tao/json/pointer.hh | 300 +++ share/include/tao/json/reference.hh | 114 + share/include/tao/json/sax/compare.hh | 262 ++ share/include/tao/json/sax/debug.hh | 116 + share/include/tao/json/sax/discard.hh | 47 + share/include/tao/json/sax/from_stream.hh | 41 + share/include/tao/json/sax/from_string.hh | 51 + share/include/tao/json/sax/from_value.hh | 136 ++ share/include/tao/json/sax/hash.hh | 164 ++ share/include/tao/json/sax/parse_file.hh | 32 + share/include/tao/json/sax/tee.hh | 249 ++ .../include/tao/json/sax/to_pretty_stream.hh | 151 ++ share/include/tao/json/sax/to_stream.hh | 131 + share/include/tao/json/sax/to_string.hh | 33 + share/include/tao/json/sax/to_value.hh | 117 + .../tao/json/sax/validate_event_order.hh | 360 +++ share/include/tao/json/schema.hh | 1726 +++++++++++++ share/include/tao/json/self_contained.hh | 100 + share/include/tao/json/single.hh | 35 + share/include/tao/json/stream.hh | 39 + share/include/tao/json/to_stream.hh | 37 + share/include/tao/json/to_string.hh | 36 + share/include/tao/json/traits.hh | 410 ++++ share/include/tao/json/type.hh | 83 + share/include/tao/json/value.hh | 1239 ++++++++++ sql/schema.sql | 4 +- src/app/main.cpp | 19 +- src/eedb/auth/PgUserAuth.cpp | 214 +- src/eedb/auth/PgUserAuth.hpp | 10 +- src/eedb/model/auth_token.h | 16 - src/eedb/model/user_history.h | 6 +- 180 files changed, 19931 insertions(+), 90 deletions(-) create mode 100644 share/include/tao/json.hh create mode 100644 share/include/tao/json/external/akrzemi1/CMakeLists.txt create mode 100644 share/include/tao/json/external/akrzemi1/LICENSE_1_0.txt create mode 100644 share/include/tao/json/external/akrzemi1/README.md create mode 100644 share/include/tao/json/external/akrzemi1/copyright.txt create mode 100644 share/include/tao/json/external/akrzemi1/optional.hpp create mode 100644 share/include/tao/json/external/akrzemi1/test_optional.cpp create mode 100644 share/include/tao/json/external/akrzemi1/test_type_traits.cpp create mode 100644 share/include/tao/json/external/double.hh create mode 100644 share/include/tao/json/external/operators.hpp create mode 100644 share/include/tao/json/external/optional.hpp create mode 100644 share/include/tao/json/external/pegtl.hh create mode 100644 share/include/tao/json/external/pegtl/action_input.hh create mode 100644 share/include/tao/json/external/pegtl/analysis/analyze_cycles.hh create mode 100644 share/include/tao/json/external/pegtl/analysis/counted.hh create mode 100644 share/include/tao/json/external/pegtl/analysis/generic.hh create mode 100644 share/include/tao/json/external/pegtl/analysis/grammar_info.hh create mode 100644 share/include/tao/json/external/pegtl/analysis/insert_guard.hh create mode 100644 share/include/tao/json/external/pegtl/analysis/insert_rules.hh create mode 100644 share/include/tao/json/external/pegtl/analysis/rule_info.hh create mode 100644 share/include/tao/json/external/pegtl/analysis/rule_type.hh create mode 100644 share/include/tao/json/external/pegtl/analyze.hh create mode 100644 share/include/tao/json/external/pegtl/apply_mode.hh create mode 100644 share/include/tao/json/external/pegtl/ascii.hh create mode 100644 share/include/tao/json/external/pegtl/buffer_input.hh create mode 100644 share/include/tao/json/external/pegtl/contrib/abnf.hh create mode 100644 share/include/tao/json/external/pegtl/contrib/alphabet.hh create mode 100644 share/include/tao/json/external/pegtl/contrib/changes.hh create mode 100644 share/include/tao/json/external/pegtl/contrib/http.hh create mode 100644 share/include/tao/json/external/pegtl/contrib/json.hh create mode 100644 share/include/tao/json/external/pegtl/contrib/raw_string.hh create mode 100644 share/include/tao/json/external/pegtl/contrib/unescape.hh create mode 100644 share/include/tao/json/external/pegtl/contrib/uri.hh create mode 100644 share/include/tao/json/external/pegtl/cr_crlf_eol.hh create mode 100644 share/include/tao/json/external/pegtl/cr_eol.hh create mode 100644 share/include/tao/json/external/pegtl/crlf_eol.hh create mode 100644 share/include/tao/json/external/pegtl/eol.hh create mode 100644 share/include/tao/json/external/pegtl/file_parser.hh create mode 100644 share/include/tao/json/external/pegtl/input_error.hh create mode 100644 share/include/tao/json/external/pegtl/internal/action.hh create mode 100644 share/include/tao/json/external/pegtl/internal/any.hh create mode 100644 share/include/tao/json/external/pegtl/internal/at.hh create mode 100644 share/include/tao/json/external/pegtl/internal/bump_util.hh create mode 100644 share/include/tao/json/external/pegtl/internal/bytes.hh create mode 100644 share/include/tao/json/external/pegtl/internal/control.hh create mode 100644 share/include/tao/json/external/pegtl/internal/cstream_reader.hh create mode 100644 share/include/tao/json/external/pegtl/internal/cstring_reader.hh create mode 100644 share/include/tao/json/external/pegtl/internal/demangle.hh create mode 100644 share/include/tao/json/external/pegtl/internal/demangle_cxxabi.hh create mode 100644 share/include/tao/json/external/pegtl/internal/demangle_nop.hh create mode 100644 share/include/tao/json/external/pegtl/internal/disable.hh create mode 100644 share/include/tao/json/external/pegtl/internal/discard.hh create mode 100644 share/include/tao/json/external/pegtl/internal/discard_if.hh create mode 100644 share/include/tao/json/external/pegtl/internal/enable.hh create mode 100644 share/include/tao/json/external/pegtl/internal/eof.hh create mode 100644 share/include/tao/json/external/pegtl/internal/eol.hh create mode 100644 share/include/tao/json/external/pegtl/internal/eol_impl.hh create mode 100644 share/include/tao/json/external/pegtl/internal/eolf.hh create mode 100644 share/include/tao/json/external/pegtl/internal/file_mapper.hh create mode 100644 share/include/tao/json/external/pegtl/internal/file_opener.hh create mode 100644 share/include/tao/json/external/pegtl/internal/file_reader.hh create mode 100644 share/include/tao/json/external/pegtl/internal/if_must.hh create mode 100644 share/include/tao/json/external/pegtl/internal/if_must_else.hh create mode 100644 share/include/tao/json/external/pegtl/internal/if_then_else.hh create mode 100644 share/include/tao/json/external/pegtl/internal/input_data.hh create mode 100644 share/include/tao/json/external/pegtl/internal/input_mark.hh create mode 100644 share/include/tao/json/external/pegtl/internal/input_pair.hh create mode 100644 share/include/tao/json/external/pegtl/internal/istream_reader.hh create mode 100644 share/include/tao/json/external/pegtl/internal/istring.hh create mode 100644 share/include/tao/json/external/pegtl/internal/list.hh create mode 100644 share/include/tao/json/external/pegtl/internal/list_must.hh create mode 100644 share/include/tao/json/external/pegtl/internal/list_tail.hh create mode 100644 share/include/tao/json/external/pegtl/internal/list_tail_pad.hh create mode 100644 share/include/tao/json/external/pegtl/internal/minus.hh create mode 100644 share/include/tao/json/external/pegtl/internal/must.hh create mode 100644 share/include/tao/json/external/pegtl/internal/not_at.hh create mode 100644 share/include/tao/json/external/pegtl/internal/one.hh create mode 100644 share/include/tao/json/external/pegtl/internal/opt.hh create mode 100644 share/include/tao/json/external/pegtl/internal/pad.hh create mode 100644 share/include/tao/json/external/pegtl/internal/pad_opt.hh create mode 100644 share/include/tao/json/external/pegtl/internal/peek_char.hh create mode 100644 share/include/tao/json/external/pegtl/internal/peek_utf16.hh create mode 100644 share/include/tao/json/external/pegtl/internal/peek_utf32.hh create mode 100644 share/include/tao/json/external/pegtl/internal/peek_utf8.hh create mode 100644 share/include/tao/json/external/pegtl/internal/pegtl_string.hh create mode 100644 share/include/tao/json/external/pegtl/internal/plus.hh create mode 100644 share/include/tao/json/external/pegtl/internal/raise.hh create mode 100644 share/include/tao/json/external/pegtl/internal/range.hh create mode 100644 share/include/tao/json/external/pegtl/internal/ranges.hh create mode 100644 share/include/tao/json/external/pegtl/internal/rep.hh create mode 100644 share/include/tao/json/external/pegtl/internal/rep_min.hh create mode 100644 share/include/tao/json/external/pegtl/internal/rep_min_max.hh create mode 100644 share/include/tao/json/external/pegtl/internal/rep_opt.hh create mode 100644 share/include/tao/json/external/pegtl/internal/require.hh create mode 100644 share/include/tao/json/external/pegtl/internal/result_on_found.hh create mode 100644 share/include/tao/json/external/pegtl/internal/rule_conjunction.hh create mode 100644 share/include/tao/json/external/pegtl/internal/rule_match_one.hh create mode 100644 share/include/tao/json/external/pegtl/internal/rule_match_three.hh create mode 100644 share/include/tao/json/external/pegtl/internal/rule_match_two.hh create mode 100644 share/include/tao/json/external/pegtl/internal/rules.hh create mode 100644 share/include/tao/json/external/pegtl/internal/seq.hh create mode 100644 share/include/tao/json/external/pegtl/internal/skip_control.hh create mode 100644 share/include/tao/json/external/pegtl/internal/sor.hh create mode 100644 share/include/tao/json/external/pegtl/internal/star.hh create mode 100644 share/include/tao/json/external/pegtl/internal/star_must.hh create mode 100644 share/include/tao/json/external/pegtl/internal/state.hh create mode 100644 share/include/tao/json/external/pegtl/internal/string.hh create mode 100644 share/include/tao/json/external/pegtl/internal/trivial.hh create mode 100644 share/include/tao/json/external/pegtl/internal/try_catch_type.hh create mode 100644 share/include/tao/json/external/pegtl/internal/until.hh create mode 100644 share/include/tao/json/external/pegtl/lf_crlf_eol.hh create mode 100644 share/include/tao/json/external/pegtl/lf_eol.hh create mode 100644 share/include/tao/json/external/pegtl/memory_input.hh create mode 100644 share/include/tao/json/external/pegtl/mmap_parser.hh create mode 100644 share/include/tao/json/external/pegtl/normal.hh create mode 100644 share/include/tao/json/external/pegtl/nothing.hh create mode 100644 share/include/tao/json/external/pegtl/parse.hh create mode 100644 share/include/tao/json/external/pegtl/parse_error.hh create mode 100644 share/include/tao/json/external/pegtl/position_info.hh create mode 100644 share/include/tao/json/external/pegtl/read_parser.hh create mode 100644 share/include/tao/json/external/pegtl/rules.hh create mode 100644 share/include/tao/json/external/pegtl/string_parser.hh create mode 100644 share/include/tao/json/external/pegtl/trace.hh create mode 100644 share/include/tao/json/external/pegtl/utf16.hh create mode 100644 share/include/tao/json/external/pegtl/utf32.hh create mode 100644 share/include/tao/json/external/pegtl/utf8.hh create mode 100644 share/include/tao/json/from_stream.hh create mode 100644 share/include/tao/json/from_string.hh create mode 100644 share/include/tao/json/internal/action.hh create mode 100644 share/include/tao/json/internal/control.hh create mode 100644 share/include/tao/json/internal/errors.hh create mode 100644 share/include/tao/json/internal/escape.hh create mode 100644 share/include/tao/json/internal/get_by_enum.hh create mode 100644 share/include/tao/json/internal/grammar.hh create mode 100644 share/include/tao/json/internal/integer_sequence.hh create mode 100644 share/include/tao/json/internal/key_state.hh create mode 100644 share/include/tao/json/internal/number_state.hh create mode 100644 share/include/tao/json/internal/sha256.hh create mode 100644 share/include/tao/json/internal/string_state.hh create mode 100644 share/include/tao/json/internal/throw.hh create mode 100644 share/include/tao/json/internal/totally_ordered.hh create mode 100644 share/include/tao/json/internal/unescape_action.hh create mode 100644 share/include/tao/json/internal/uri_fragment.hh create mode 100644 share/include/tao/json/internal/value_union.hh create mode 100644 share/include/tao/json/pair.hh create mode 100644 share/include/tao/json/parse_file.hh create mode 100644 share/include/tao/json/patch.hh create mode 100644 share/include/tao/json/pointer.hh create mode 100644 share/include/tao/json/reference.hh create mode 100644 share/include/tao/json/sax/compare.hh create mode 100644 share/include/tao/json/sax/debug.hh create mode 100644 share/include/tao/json/sax/discard.hh create mode 100644 share/include/tao/json/sax/from_stream.hh create mode 100644 share/include/tao/json/sax/from_string.hh create mode 100644 share/include/tao/json/sax/from_value.hh create mode 100644 share/include/tao/json/sax/hash.hh create mode 100644 share/include/tao/json/sax/parse_file.hh create mode 100644 share/include/tao/json/sax/tee.hh create mode 100644 share/include/tao/json/sax/to_pretty_stream.hh create mode 100644 share/include/tao/json/sax/to_stream.hh create mode 100644 share/include/tao/json/sax/to_string.hh create mode 100644 share/include/tao/json/sax/to_value.hh create mode 100644 share/include/tao/json/sax/validate_event_order.hh create mode 100644 share/include/tao/json/schema.hh create mode 100644 share/include/tao/json/self_contained.hh create mode 100644 share/include/tao/json/single.hh create mode 100644 share/include/tao/json/stream.hh create mode 100644 share/include/tao/json/to_stream.hh create mode 100644 share/include/tao/json/to_string.hh create mode 100644 share/include/tao/json/traits.hh create mode 100644 share/include/tao/json/type.hh create mode 100644 share/include/tao/json/value.hh diff --git a/CMakeLists.txt b/CMakeLists.txt index 5ee8da1..3df9ef9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,5 +11,7 @@ find_package(Wt REQUIRED) find_package(Sqlpp11 REQUIRED) find_package(PostgreSQL REQUIRED) +include_directories(share/include) +add_subdirectory(share) add_subdirectory(src) add_subdirectory(tests) diff --git a/share/CMakeLists.txt b/share/CMakeLists.txt index e69de29..8b13789 100644 --- a/share/CMakeLists.txt +++ b/share/CMakeLists.txt @@ -0,0 +1 @@ + diff --git a/share/include/tao/json.hh b/share/include/tao/json.hh new file mode 100644 index 0000000..beebaef --- /dev/null +++ b/share/include/tao/json.hh @@ -0,0 +1,44 @@ +// Copyright (c) 2015-2016 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/taocpp/json/ + +#ifndef TAOCPP_JSON_INCLUDE_JSON_HH +#define TAOCPP_JSON_INCLUDE_JSON_HH + +// DOM value +#include "json/value.hh" + +// SAX producers +//#include "json/sax/from_stream.hh" // includes PEGTL header/grammar +#include "json/sax/from_string.hh" // includes PEGTL header/grammar +#include "json/sax/parse_file.hh" // includes PEGTL header/grammar +#include "json/sax/from_value.hh" // DOM to SAX + +// SAX consumers +#include "json/sax/to_stream.hh" +#include "json/sax/to_pretty_stream.hh" +#include "json/sax/to_string.hh" +#include "json/sax/to_value.hh" // SAX to DOM + +// SAX other +#include "json/sax/hash.hh" +#include "json/sax/discard.hh" +#include "json/sax/tee.hh" +#include "json/sax/validate_event_order.hh" +#include "json/sax/debug.hh" + +// DOM producers +#include "json/from_string.hh" // includes PEGTL header/grammar +#include "json/parse_file.hh" // includes PEGTL header/grammar + +// DOM writers +#include "json/to_stream.hh" +#include "json/to_string.hh" +#include "json/stream.hh" // operator<< + +// DOM support +#include "json/self_contained.hh" +#include "json/patch.hh" +//#include "json/diff.hh" +#include "json/schema.hh" + +#endif diff --git a/share/include/tao/json/external/akrzemi1/CMakeLists.txt b/share/include/tao/json/external/akrzemi1/CMakeLists.txt new file mode 100644 index 0000000..07f38f7 --- /dev/null +++ b/share/include/tao/json/external/akrzemi1/CMakeLists.txt @@ -0,0 +1,11 @@ +project(optional) +cmake_minimum_required(VERSION 2.8) +enable_testing() + +set(CMAKE_CXX_FLAGS "-std=c++11 -Wall -Wextra") + +add_executable(test_optional test_optional.cpp) +add_executable(test_type_traits test_type_traits.cpp) + +add_test(test_optional test_optional) +add_test(test_type_traits test_type_traits) diff --git a/share/include/tao/json/external/akrzemi1/LICENSE_1_0.txt b/share/include/tao/json/external/akrzemi1/LICENSE_1_0.txt new file mode 100644 index 0000000..36b7cd9 --- /dev/null +++ b/share/include/tao/json/external/akrzemi1/LICENSE_1_0.txt @@ -0,0 +1,23 @@ +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/share/include/tao/json/external/akrzemi1/README.md b/share/include/tao/json/external/akrzemi1/README.md new file mode 100644 index 0000000..aee8dae --- /dev/null +++ b/share/include/tao/json/external/akrzemi1/README.md @@ -0,0 +1,39 @@ +Optional +======== + +A single-header header-only library for representing optional (nullable) objects for C++14 (and C++11 to some extent) and passing them by value. This is the reference implementation of proposal N3793 (see http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3793.html). Optional is now accepted into Library Fundamentals Technical Specification (see http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3848.html). The interface is based on Fernando Cacciola's Boost.Optional library (see http://www.boost.org/doc/libs/1_52_0/libs/optional/doc/html/index.html) + + +Usage +----- + +```cpp +optional readInt(); // this function may return int or a not-an-int + +if (optional oi = readInt()) // did I get a real int + cout << "my int is: " << *oi; // use my int +else + cout << "I have no int"; +``` + +For more usage examples and the overview see http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3527.html + + +Supported compilers +------------------- + +Clang 3.2, Clang 3.4, G++ 4.7.2, G++ 4.8.1. Tested only with libstdc++, versions 20130531, 20120920, 20110428. Others have reported it also works with libc++. + + + +Known Issues +------------ + + - Currently, the reference (and the only known) impementation of certain pieces of functionality explore what C++11 identifies as undefined behavior (see national body comment FI 15: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3770.html#FI15). This is mostly why Optional was removed from C++14 and put into Library Fundamentals TS. Luckily what the Standard identifies as UB is well defined on all known platforms. We expect that the C++14 wil fix this problem, so that our trick becomes well-defined. + - In libstdc++ versions below 20130531 the constructor taking `initializer_list` argument is not `constexpr`. This is because `initializer_list` operations are not `constexpr` in C++11. This works however in version 20130531. It is also not enabled for libc++ because I do not have access to it and do nto know if it provides `constexpr` `initializer_list`. + - In G++ 4.7.2 and 4.8.0 member function `value_or` does not have rvalue reference overload. These compilers do not support rvalue overloding on `*this`. + - In order for the library to work with slightly older compilers, we emulate some missing type traits. On some platforms we cannot correctly detect the available features, and attempts at workarounds for missing type trait definitions can cause compile-time errors. Define macro `TR2_OPTIONAL_DISABLE_EMULATION_OF_TYPE_TRAITS` if you know that all the necessary type traits are defined, and no emulation is required. + +License +------- +Distributed under the [Boost Software License, Version 1.0](http://www.boost.org/LICENSE_1_0.txt). diff --git a/share/include/tao/json/external/akrzemi1/copyright.txt b/share/include/tao/json/external/akrzemi1/copyright.txt new file mode 100644 index 0000000..1641c3c --- /dev/null +++ b/share/include/tao/json/external/akrzemi1/copyright.txt @@ -0,0 +1,10 @@ +Copyright (C) 2011-2012 Andrzej Krzemienski + +Distributed under the Boost Software License, Version 1.0 +(see accompanying file LICENSE_1_0.txt or a copy at +http://www.boost.org/LICENSE_1_0.txt) + +The idea and interface is based on Boost.Optional library +authored by Fernando Luis Cacciola Carballal + +Home at https://github.com/akrzemi1/Optional \ No newline at end of file diff --git a/share/include/tao/json/external/akrzemi1/optional.hpp b/share/include/tao/json/external/akrzemi1/optional.hpp new file mode 100644 index 0000000..99565f5 --- /dev/null +++ b/share/include/tao/json/external/akrzemi1/optional.hpp @@ -0,0 +1,1042 @@ +// Copyright (C) 2011 - 2012 Andrzej Krzemienski. +// +// Use, modification, and distribution is subject to the Boost Software +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// The idea and interface is based on Boost.Optional library +// authored by Fernando Luis Cacciola Carballal + +# ifndef ___OPTIONAL_HPP___ +# define ___OPTIONAL_HPP___ + +# include +# include +# include +# include +# include +# include +# include + +# define TR2_OPTIONAL_REQUIRES(...) typename enable_if<__VA_ARGS__::value, bool>::type = false + +# if defined __GNUC__ // NOTE: GNUC is also defined for Clang +# if (__GNUC__ == 4) && (__GNUC_MINOR__ >= 8) +# define TR2_OPTIONAL_GCC_4_8_AND_HIGHER___ +# elif (__GNUC__ > 4) +# define TR2_OPTIONAL_GCC_4_8_AND_HIGHER___ +# endif +# +# if (__GNUC__ == 4) && (__GNUC_MINOR__ >= 7) +# define TR2_OPTIONAL_GCC_4_7_AND_HIGHER___ +# elif (__GNUC__ > 4) +# define TR2_OPTIONAL_GCC_4_7_AND_HIGHER___ +# endif +# +# if (__GNUC__ == 4) && (__GNUC_MINOR__ == 8) && (__GNUC_PATCHLEVEL__ >= 1) +# define TR2_OPTIONAL_GCC_4_8_1_AND_HIGHER___ +# elif (__GNUC__ == 4) && (__GNUC_MINOR__ >= 9) +# define TR2_OPTIONAL_GCC_4_8_1_AND_HIGHER___ +# elif (__GNUC__ > 4) +# define TR2_OPTIONAL_GCC_4_8_1_AND_HIGHER___ +# endif +# endif +# +# if defined __clang_major__ +# if (__clang_major__ == 3 && __clang_minor__ >= 5) +# define TR2_OPTIONAL_CLANG_3_5_AND_HIGHTER_ +# elif (__clang_major__ > 3) +# define TR2_OPTIONAL_CLANG_3_5_AND_HIGHTER_ +# endif +# if defined TR2_OPTIONAL_CLANG_3_5_AND_HIGHTER_ +# define TR2_OPTIONAL_CLANG_3_4_2_AND_HIGHER_ +# elif (__clang_major__ == 3 && __clang_minor__ == 4 && __clang_patchlevel__ >= 2) +# define TR2_OPTIONAL_CLANG_3_4_2_AND_HIGHER_ +# endif +# endif +# +# if defined _MSC_VER +# if (_MSC_VER >= 1900) +# define TR2_OPTIONAL_MSVC_2015_AND_HIGHER___ +# endif +# endif + +# if defined __clang__ +# if (__clang_major__ > 2) || (__clang_major__ == 2) && (__clang_minor__ >= 9) +# define OPTIONAL_HAS_THIS_RVALUE_REFS 1 +# else +# define OPTIONAL_HAS_THIS_RVALUE_REFS 0 +# endif +# elif defined TR2_OPTIONAL_GCC_4_8_1_AND_HIGHER___ +# define OPTIONAL_HAS_THIS_RVALUE_REFS 1 +# elif defined TR2_OPTIONAL_MSVC_2015_AND_HIGHER___ +# define OPTIONAL_HAS_THIS_RVALUE_REFS 1 +# else +# define OPTIONAL_HAS_THIS_RVALUE_REFS 0 +# endif + + +# if defined TR2_OPTIONAL_GCC_4_8_1_AND_HIGHER___ +# define OPTIONAL_HAS_CONSTEXPR_INIT_LIST 1 +# define OPTIONAL_CONSTEXPR_INIT_LIST constexpr +# else +# define OPTIONAL_HAS_CONSTEXPR_INIT_LIST 0 +# define OPTIONAL_CONSTEXPR_INIT_LIST +# endif + +# if defined TR2_OPTIONAL_CLANG_3_5_AND_HIGHTER_ && (defined __cplusplus) && (__cplusplus != 201103L) +# define OPTIONAL_HAS_MOVE_ACCESSORS 1 +# else +# define OPTIONAL_HAS_MOVE_ACCESSORS 0 +# endif + +# // In C++11 constexpr implies const, so we need to make non-const members also non-constexpr +# if (defined __cplusplus) && (__cplusplus == 201103L) +# define OPTIONAL_MUTABLE_CONSTEXPR +# else +# define OPTIONAL_MUTABLE_CONSTEXPR constexpr +# endif + +namespace std{ + +namespace experimental{ + +// BEGIN workaround for missing is_trivially_destructible +# if defined TR2_OPTIONAL_GCC_4_8_AND_HIGHER___ + // leave it: it is already there +# elif defined TR2_OPTIONAL_CLANG_3_4_2_AND_HIGHER_ + // leave it: it is already there +# elif defined TR2_OPTIONAL_MSVC_2015_AND_HIGHER___ + // leave it: it is already there +# elif defined TR2_OPTIONAL_DISABLE_EMULATION_OF_TYPE_TRAITS + // leave it: the user doesn't want it +# else + template + using is_trivially_destructible = std::has_trivial_destructor; +# endif +// END workaround for missing is_trivially_destructible + +# if (defined TR2_OPTIONAL_GCC_4_7_AND_HIGHER___) + // leave it; our metafunctions are already defined. +# elif defined TR2_OPTIONAL_CLANG_3_4_2_AND_HIGHER_ + // leave it; our metafunctions are already defined. +# elif defined TR2_OPTIONAL_MSVC_2015_AND_HIGHER___ + // leave it: it is already there +# elif defined TR2_OPTIONAL_DISABLE_EMULATION_OF_TYPE_TRAITS + // leave it: the user doesn't want it +# else + + +// workaround for missing traits in GCC and CLANG +template +struct is_nothrow_move_constructible +{ + constexpr static bool value = std::is_nothrow_constructible::value; +}; + + +template +struct is_assignable +{ + template + constexpr static bool has_assign(...) { return false; } + + template () = std::declval(), true)) > + // the comma operator is necessary for the cases where operator= returns void + constexpr static bool has_assign(bool) { return true; } + + constexpr static bool value = has_assign(true); +}; + + +template +struct is_nothrow_move_assignable +{ + template + struct has_nothrow_move_assign { + constexpr static bool value = false; + }; + + template + struct has_nothrow_move_assign { + constexpr static bool value = noexcept( std::declval() = std::declval() ); + }; + + constexpr static bool value = has_nothrow_move_assign::value>::value; +}; +// end workaround + + +# endif + + + +// 20.5.4, optional for object types +template class optional; + +// 20.5.5, optional for lvalue reference types +template class optional; + + +// workaround: std utility functions aren't constexpr yet +template inline constexpr T&& constexpr_forward(typename std::remove_reference::type& t) noexcept +{ + return static_cast(t); +} + +template inline constexpr T&& constexpr_forward(typename std::remove_reference::type&& t) noexcept +{ + static_assert(!std::is_lvalue_reference::value, "!!"); + return static_cast(t); +} + +template inline constexpr typename std::remove_reference::type&& constexpr_move(T&& t) noexcept +{ + return static_cast::type&&>(t); +} + + +#if defined NDEBUG +# define TR2_OPTIONAL_ASSERTED_EXPRESSION(CHECK, EXPR) (EXPR) +#else +# define TR2_OPTIONAL_ASSERTED_EXPRESSION(CHECK, EXPR) ((CHECK) ? (EXPR) : ([]{assert(!#CHECK);}(), (EXPR))) +#endif + + +namespace detail_ +{ + +// static_addressof: a constexpr version of addressof +template +struct has_overloaded_addressof +{ + template + constexpr static bool has_overload(...) { return false; } + + template ().operator&()) > + constexpr static bool has_overload(bool) { return true; } + + constexpr static bool value = has_overload(true); +}; + +template )> +constexpr T* static_addressof(T& ref) +{ + return &ref; +} + +template )> +T* static_addressof(T& ref) +{ + return std::addressof(ref); +} + + +// the call to convert(b) has return type A and converts b to type A iff b decltype(b) is implicitly convertible to A +template +U convert(U v) { return v; } + +} // namespace detail + + +constexpr struct trivial_init_t{} trivial_init{}; + + +// 20.5.6, In-place construction +constexpr struct in_place_t{} in_place{}; + + +// 20.5.7, Disengaged state indicator +struct nullopt_t +{ + struct init{}; + constexpr explicit nullopt_t(init){} +}; +constexpr nullopt_t nullopt{nullopt_t::init()}; + + +// 20.5.8, class bad_optional_access +class bad_optional_access : public logic_error { +public: + explicit bad_optional_access(const string& what_arg) : logic_error{what_arg} {} + explicit bad_optional_access(const char* what_arg) : logic_error{what_arg} {} +}; + + +template +union storage_t +{ + unsigned char dummy_; + T value_; + + constexpr storage_t( trivial_init_t ) noexcept : dummy_() {}; + + template + constexpr storage_t( Args&&... args ) : value_(constexpr_forward(args)...) {} + + ~storage_t(){} +}; + + +template +union constexpr_storage_t +{ + unsigned char dummy_; + T value_; + + constexpr constexpr_storage_t( trivial_init_t ) noexcept : dummy_() {}; + + template + constexpr constexpr_storage_t( Args&&... args ) : value_(constexpr_forward(args)...) {} + + ~constexpr_storage_t() = default; +}; + + +template +struct optional_base +{ + bool init_; + storage_t storage_; + + constexpr optional_base() noexcept : init_(false), storage_(trivial_init) {}; + + explicit constexpr optional_base(const T& v) : init_(true), storage_(v) {} + + explicit constexpr optional_base(T&& v) : init_(true), storage_(constexpr_move(v)) {} + + template explicit optional_base(in_place_t, Args&&... args) + : init_(true), storage_(constexpr_forward(args)...) {} + + template >)> + explicit optional_base(in_place_t, std::initializer_list il, Args&&... args) + : init_(true), storage_(il, std::forward(args)...) {} + + ~optional_base() { if (init_) storage_.value_.T::~T(); } +}; + + +template +struct constexpr_optional_base +{ + bool init_; + constexpr_storage_t storage_; + + constexpr constexpr_optional_base() noexcept : init_(false), storage_(trivial_init) {}; + + explicit constexpr constexpr_optional_base(const T& v) : init_(true), storage_(v) {} + + explicit constexpr constexpr_optional_base(T&& v) : init_(true), storage_(constexpr_move(v)) {} + + template explicit constexpr constexpr_optional_base(in_place_t, Args&&... args) + : init_(true), storage_(constexpr_forward(args)...) {} + + template >)> + OPTIONAL_CONSTEXPR_INIT_LIST explicit constexpr_optional_base(in_place_t, std::initializer_list il, Args&&... args) + : init_(true), storage_(il, std::forward(args)...) {} + + ~constexpr_optional_base() = default; +}; + +template +using OptionalBase = typename std::conditional< + is_trivially_destructible::value, + constexpr_optional_base, + optional_base +>::type; + + + +template +class optional : private OptionalBase +{ + static_assert( !std::is_same::type, nullopt_t>::value, "bad T" ); + static_assert( !std::is_same::type, in_place_t>::value, "bad T" ); + + + constexpr bool initialized() const noexcept { return OptionalBase::init_; } + T* dataptr() { return std::addressof(OptionalBase::storage_.value_); } + constexpr const T* dataptr() const { return detail_::static_addressof(OptionalBase::storage_.value_); } + +# if OPTIONAL_HAS_THIS_RVALUE_REFS == 1 + constexpr const T& contained_val() const& { return OptionalBase::storage_.value_; } +# if OPTIONAL_HAS_MOVE_ACCESSORS == 1 + OPTIONAL_MUTABLE_CONSTEXPR T&& contained_val() && { return std::move(OptionalBase::storage_.value_); } + OPTIONAL_MUTABLE_CONSTEXPR T& contained_val() & { return OptionalBase::storage_.value_; } +# else + T& contained_val() & { return OptionalBase::storage_.value_; } + T&& contained_val() && { return std::move(OptionalBase::storage_.value_); } +# endif +# else + constexpr const T& contained_val() const { return OptionalBase::storage_.value_; } + T& contained_val() { return OptionalBase::storage_.value_; } +# endif + + void clear() noexcept { + if (initialized()) dataptr()->T::~T(); + OptionalBase::init_ = false; + } + + template + void initialize(Args&&... args) noexcept(noexcept(T(std::forward(args)...))) + { + assert(!OptionalBase::init_); + ::new (static_cast(dataptr())) T(std::forward(args)...); + OptionalBase::init_ = true; + } + + template + void initialize(std::initializer_list il, Args&&... args) noexcept(noexcept(T(il, std::forward(args)...))) + { + assert(!OptionalBase::init_); + ::new (static_cast(dataptr())) T(il, std::forward(args)...); + OptionalBase::init_ = true; + } + +public: + typedef T value_type; + + // 20.5.5.1, constructors + constexpr optional() noexcept : OptionalBase() {}; + constexpr optional(nullopt_t) noexcept : OptionalBase() {}; + + optional(const optional& rhs) + : OptionalBase() + { + if (rhs.initialized()) { + ::new (static_cast(dataptr())) T(*rhs); + OptionalBase::init_ = true; + } + } + + optional(optional&& rhs) noexcept(is_nothrow_move_constructible::value) + : OptionalBase() + { + if (rhs.initialized()) { + ::new (static_cast(dataptr())) T(std::move(*rhs)); + OptionalBase::init_ = true; + } + } + + constexpr optional(const T& v) : OptionalBase(v) {} + + constexpr optional(T&& v) : OptionalBase(constexpr_move(v)) {} + + template + explicit constexpr optional(in_place_t, Args&&... args) + : OptionalBase(in_place_t{}, constexpr_forward(args)...) {} + + template >)> + OPTIONAL_CONSTEXPR_INIT_LIST explicit optional(in_place_t, std::initializer_list il, Args&&... args) + : OptionalBase(in_place_t{}, il, constexpr_forward(args)...) {} + + // 20.5.4.2, Destructor + ~optional() = default; + + // 20.5.4.3, assignment + optional& operator=(nullopt_t) noexcept + { + clear(); + return *this; + } + + optional& operator=(const optional& rhs) + { + if (initialized() == true && rhs.initialized() == false) clear(); + else if (initialized() == false && rhs.initialized() == true) initialize(*rhs); + else if (initialized() == true && rhs.initialized() == true) contained_val() = *rhs; + return *this; + } + + optional& operator=(optional&& rhs) + noexcept(is_nothrow_move_assignable::value && is_nothrow_move_constructible::value) + { + if (initialized() == true && rhs.initialized() == false) clear(); + else if (initialized() == false && rhs.initialized() == true) initialize(std::move(*rhs)); + else if (initialized() == true && rhs.initialized() == true) contained_val() = std::move(*rhs); + return *this; + } + + template + auto operator=(U&& v) + -> typename enable_if + < + is_same::type, T>::value, + optional& + >::type + { + if (initialized()) { contained_val() = std::forward(v); } + else { initialize(std::forward(v)); } + return *this; + } + + + template + void emplace(Args&&... args) + { + clear(); + initialize(std::forward(args)...); + } + + template + void emplace(initializer_list il, Args&&... args) + { + clear(); + initialize(il, std::forward(args)...); + } + + // 20.5.4.4, Swap + void swap(optional& rhs) noexcept(is_nothrow_move_constructible::value && noexcept(swap(declval(), declval()))) + { + if (initialized() == true && rhs.initialized() == false) { rhs.initialize(std::move(**this)); clear(); } + else if (initialized() == false && rhs.initialized() == true) { initialize(std::move(*rhs)); rhs.clear(); } + else if (initialized() == true && rhs.initialized() == true) { using std::swap; swap(**this, *rhs); } + } + + // 20.5.4.5, Observers + + explicit constexpr operator bool() const noexcept { return initialized(); } + + constexpr T const* operator ->() const { + return TR2_OPTIONAL_ASSERTED_EXPRESSION(initialized(), dataptr()); + } + +# if OPTIONAL_HAS_MOVE_ACCESSORS == 1 + + OPTIONAL_MUTABLE_CONSTEXPR T* operator ->() { + assert (initialized()); + return dataptr(); + } + + constexpr T const& operator *() const& { + return TR2_OPTIONAL_ASSERTED_EXPRESSION(initialized(), contained_val()); + } + + OPTIONAL_MUTABLE_CONSTEXPR T& operator *() & { + assert (initialized()); + return contained_val(); + } + + OPTIONAL_MUTABLE_CONSTEXPR T&& operator *() && { + assert (initialized()); + return constexpr_move(contained_val()); + } + + constexpr T const& value() const& { + return initialized() ? contained_val() : (throw bad_optional_access("bad optional access"), contained_val()); + } + + OPTIONAL_MUTABLE_CONSTEXPR T& value() & { + return initialized() ? contained_val() : (throw bad_optional_access("bad optional access"), contained_val()); + } + + OPTIONAL_MUTABLE_CONSTEXPR T&& value() && { + if (!initialized()) throw bad_optional_access("bad optional access"); + return std::move(contained_val()); + } + +# else + + T* operator ->() { + assert (initialized()); + return dataptr(); + } + + constexpr T const& operator *() const { + return TR2_OPTIONAL_ASSERTED_EXPRESSION(initialized(), contained_val()); + } + + T& operator *() { + assert (initialized()); + return contained_val(); + } + + constexpr T const& value() const { + return initialized() ? contained_val() : (throw bad_optional_access("bad optional access"), contained_val()); + } + + T& value() { + return initialized() ? contained_val() : (throw bad_optional_access("bad optional access"), contained_val()); + } + +# endif + +# if OPTIONAL_HAS_THIS_RVALUE_REFS == 1 + + template + constexpr T value_or(V&& v) const& + { + return *this ? **this : detail_::convert(constexpr_forward(v)); + } + +# if OPTIONAL_HAS_MOVE_ACCESSORS == 1 + + template + OPTIONAL_MUTABLE_CONSTEXPR T value_or(V&& v) && + { + return *this ? constexpr_move(const_cast&>(*this).contained_val()) : detail_::convert(constexpr_forward(v)); + } + +# else + + template + T value_or(V&& v) && + { + return *this ? constexpr_move(const_cast&>(*this).contained_val()) : detail_::convert(constexpr_forward(v)); + } + +# endif + +# else + + template + constexpr T value_or(V&& v) const + { + return *this ? **this : detail_::convert(constexpr_forward(v)); + } + +# endif + +}; + + +template +class optional +{ + static_assert( !std::is_same::value, "bad T" ); + static_assert( !std::is_same::value, "bad T" ); + T* ref; + +public: + + // 20.5.5.1, construction/destruction + constexpr optional() noexcept : ref(nullptr) {} + + constexpr optional(nullopt_t) noexcept : ref(nullptr) {} + + constexpr optional(T& v) noexcept : ref(detail_::static_addressof(v)) {} + + optional(T&&) = delete; + + constexpr optional(const optional& rhs) noexcept : ref(rhs.ref) {} + + explicit constexpr optional(in_place_t, T& v) noexcept : ref(detail_::static_addressof(v)) {} + + explicit optional(in_place_t, T&&) = delete; + + ~optional() = default; + + // 20.5.5.2, mutation + optional& operator=(nullopt_t) noexcept { + ref = nullptr; + return *this; + } + + // optional& operator=(const optional& rhs) noexcept { + // ref = rhs.ref; + // return *this; + // } + + // optional& operator=(optional&& rhs) noexcept { + // ref = rhs.ref; + // return *this; + // } + + template + auto operator=(U&& rhs) noexcept + -> typename enable_if + < + is_same::type, optional>::value, + optional& + >::type + { + ref = rhs.ref; + return *this; + } + + template + auto operator=(U&& rhs) noexcept + -> typename enable_if + < + !is_same::type, optional>::value, + optional& + >::type + = delete; + + void emplace(T& v) noexcept { + ref = detail_::static_addressof(v); + } + + void emplace(T&&) = delete; + + + void swap(optional& rhs) noexcept + { + std::swap(ref, rhs.ref); + } + + // 20.5.5.3, observers + constexpr T* operator->() const { + return TR2_OPTIONAL_ASSERTED_EXPRESSION(ref, ref); + } + + constexpr T& operator*() const { + return TR2_OPTIONAL_ASSERTED_EXPRESSION(ref, *ref); + } + + constexpr T& value() const { + return ref ? *ref : (throw bad_optional_access("bad optional access"), *ref); + } + + explicit constexpr operator bool() const noexcept { + return ref != nullptr; + } + + template + constexpr typename decay::type value_or(V&& v) const + { + return *this ? **this : detail_::convert::type>(constexpr_forward(v)); + } +}; + + +template +class optional +{ + static_assert( sizeof(T) == 0, "optional rvalue references disallowed" ); +}; + + +// 20.5.8, Relational operators +template constexpr bool operator==(const optional& x, const optional& y) +{ + return bool(x) != bool(y) ? false : bool(x) == false ? true : *x == *y; +} + +template constexpr bool operator!=(const optional& x, const optional& y) +{ + return !(x == y); +} + +template constexpr bool operator<(const optional& x, const optional& y) +{ + return (!y) ? false : (!x) ? true : *x < *y; +} + +template constexpr bool operator>(const optional& x, const optional& y) +{ + return (y < x); +} + +template constexpr bool operator<=(const optional& x, const optional& y) +{ + return !(y < x); +} + +template constexpr bool operator>=(const optional& x, const optional& y) +{ + return !(x < y); +} + + +// 20.5.9, Comparison with nullopt +template constexpr bool operator==(const optional& x, nullopt_t) noexcept +{ + return (!x); +} + +template constexpr bool operator==(nullopt_t, const optional& x) noexcept +{ + return (!x); +} + +template constexpr bool operator!=(const optional& x, nullopt_t) noexcept +{ + return bool(x); +} + +template constexpr bool operator!=(nullopt_t, const optional& x) noexcept +{ + return bool(x); +} + +template constexpr bool operator<(const optional&, nullopt_t) noexcept +{ + return false; +} + +template constexpr bool operator<(nullopt_t, const optional& x) noexcept +{ + return bool(x); +} + +template constexpr bool operator<=(const optional& x, nullopt_t) noexcept +{ + return (!x); +} + +template constexpr bool operator<=(nullopt_t, const optional&) noexcept +{ + return true; +} + +template constexpr bool operator>(const optional& x, nullopt_t) noexcept +{ + return bool(x); +} + +template constexpr bool operator>(nullopt_t, const optional&) noexcept +{ + return false; +} + +template constexpr bool operator>=(const optional&, nullopt_t) noexcept +{ + return true; +} + +template constexpr bool operator>=(nullopt_t, const optional& x) noexcept +{ + return (!x); +} + + + +// 20.5.10, Comparison with T +template constexpr bool operator==(const optional& x, const T& v) +{ + return bool(x) ? *x == v : false; +} + +template constexpr bool operator==(const T& v, const optional& x) +{ + return bool(x) ? v == *x : false; +} + +template constexpr bool operator!=(const optional& x, const T& v) +{ + return bool(x) ? *x != v : true; +} + +template constexpr bool operator!=(const T& v, const optional& x) +{ + return bool(x) ? v != *x : true; +} + +template constexpr bool operator<(const optional& x, const T& v) +{ + return bool(x) ? *x < v : true; +} + +template constexpr bool operator>(const T& v, const optional& x) +{ + return bool(x) ? v > *x : true; +} + +template constexpr bool operator>(const optional& x, const T& v) +{ + return bool(x) ? *x > v : false; +} + +template constexpr bool operator<(const T& v, const optional& x) +{ + return bool(x) ? v < *x : false; +} + +template constexpr bool operator>=(const optional& x, const T& v) +{ + return bool(x) ? *x >= v : false; +} + +template constexpr bool operator<=(const T& v, const optional& x) +{ + return bool(x) ? v <= *x : false; +} + +template constexpr bool operator<=(const optional& x, const T& v) +{ + return bool(x) ? *x <= v : true; +} + +template constexpr bool operator>=(const T& v, const optional& x) +{ + return bool(x) ? v >= *x : true; +} + + +// Comparison of optional with T +template constexpr bool operator==(const optional& x, const T& v) +{ + return bool(x) ? *x == v : false; +} + +template constexpr bool operator==(const T& v, const optional& x) +{ + return bool(x) ? v == *x : false; +} + +template constexpr bool operator!=(const optional& x, const T& v) +{ + return bool(x) ? *x != v : true; +} + +template constexpr bool operator!=(const T& v, const optional& x) +{ + return bool(x) ? v != *x : true; +} + +template constexpr bool operator<(const optional& x, const T& v) +{ + return bool(x) ? *x < v : true; +} + +template constexpr bool operator>(const T& v, const optional& x) +{ + return bool(x) ? v > *x : true; +} + +template constexpr bool operator>(const optional& x, const T& v) +{ + return bool(x) ? *x > v : false; +} + +template constexpr bool operator<(const T& v, const optional& x) +{ + return bool(x) ? v < *x : false; +} + +template constexpr bool operator>=(const optional& x, const T& v) +{ + return bool(x) ? *x >= v : false; +} + +template constexpr bool operator<=(const T& v, const optional& x) +{ + return bool(x) ? v <= *x : false; +} + +template constexpr bool operator<=(const optional& x, const T& v) +{ + return bool(x) ? *x <= v : true; +} + +template constexpr bool operator>=(const T& v, const optional& x) +{ + return bool(x) ? v >= *x : true; +} + +// Comparison of optional with T +template constexpr bool operator==(const optional& x, const T& v) +{ + return bool(x) ? *x == v : false; +} + +template constexpr bool operator==(const T& v, const optional& x) +{ + return bool(x) ? v == *x : false; +} + +template constexpr bool operator!=(const optional& x, const T& v) +{ + return bool(x) ? *x != v : true; +} + +template constexpr bool operator!=(const T& v, const optional& x) +{ + return bool(x) ? v != *x : true; +} + +template constexpr bool operator<(const optional& x, const T& v) +{ + return bool(x) ? *x < v : true; +} + +template constexpr bool operator>(const T& v, const optional& x) +{ + return bool(x) ? v > *x : true; +} + +template constexpr bool operator>(const optional& x, const T& v) +{ + return bool(x) ? *x > v : false; +} + +template constexpr bool operator<(const T& v, const optional& x) +{ + return bool(x) ? v < *x : false; +} + +template constexpr bool operator>=(const optional& x, const T& v) +{ + return bool(x) ? *x >= v : false; +} + +template constexpr bool operator<=(const T& v, const optional& x) +{ + return bool(x) ? v <= *x : false; +} + +template constexpr bool operator<=(const optional& x, const T& v) +{ + return bool(x) ? *x <= v : true; +} + +template constexpr bool operator>=(const T& v, const optional& x) +{ + return bool(x) ? v >= *x : true; +} + + +// 20.5.12, Specialized algorithms +template +void swap(optional& x, optional& y) noexcept(noexcept(x.swap(y))) +{ + x.swap(y); +} + + +template +constexpr optional::type> make_optional(T&& v) +{ + return optional::type>(constexpr_forward(v)); +} + +template +constexpr optional make_optional(reference_wrapper v) +{ + return optional(v.get()); +} + + +} // namespace experimental +} // namespace std + +namespace std +{ + template + struct hash> + { + typedef typename hash::result_type result_type; + typedef std::experimental::optional argument_type; + + constexpr result_type operator()(argument_type const& arg) const { + return arg ? std::hash{}(*arg) : result_type{}; + } + }; + + template + struct hash> + { + typedef typename hash::result_type result_type; + typedef std::experimental::optional argument_type; + + constexpr result_type operator()(argument_type const& arg) const { + return arg ? std::hash{}(*arg) : result_type{}; + } + }; +} + +# undef TR2_OPTIONAL_REQUIRES +# undef TR2_OPTIONAL_ASSERTED_EXPRESSION + +# endif //___OPTIONAL_HPP___ diff --git a/share/include/tao/json/external/akrzemi1/test_optional.cpp b/share/include/tao/json/external/akrzemi1/test_optional.cpp new file mode 100644 index 0000000..8ed356a --- /dev/null +++ b/share/include/tao/json/external/akrzemi1/test_optional.cpp @@ -0,0 +1,1459 @@ +// Copyright (C) 2011 - 2012 Andrzej Krzemienski. +// +// Use, modification, and distribution is subject to the Boost Software +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// The idea and interface is based on Boost.Optional library +// authored by Fernando Luis Cacciola Carballal + +# include "optional.hpp" +# include +# include +# include +# include + + + +struct caller { + template caller(T fun) { fun(); } +}; +# define CAT2(X, Y) X ## Y +# define CAT(X, Y) CAT2(X, Y) +# define TEST(NAME) caller CAT(__VAR, __LINE__) = [] + +enum State +{ + sDefaultConstructed, + sValueCopyConstructed, + sValueMoveConstructed, + sCopyConstructed, + sMoveConstructed, + sMoveAssigned, + sCopyAssigned, + sValueCopyAssigned, + sValueMoveAssigned, + sMovedFrom, + sValueConstructed +}; + +struct OracleVal +{ + State s; + int i; + OracleVal(int i = 0) : s(sValueConstructed), i(i) {} +}; + +struct Oracle +{ + State s; + OracleVal val; + + Oracle() : s(sDefaultConstructed) {} + Oracle(const OracleVal& v) : s(sValueCopyConstructed), val(v) {} + Oracle(OracleVal&& v) : s(sValueMoveConstructed), val(std::move(v)) {v.s = sMovedFrom;} + Oracle(const Oracle& o) : s(sCopyConstructed), val(o.val) {} + Oracle(Oracle&& o) : s(sMoveConstructed), val(std::move(o.val)) {o.s = sMovedFrom;} + + Oracle& operator=(const OracleVal& v) { s = sValueCopyConstructed; val = v; return *this; } + Oracle& operator=(OracleVal&& v) { s = sValueMoveConstructed; val = std::move(v); v.s = sMovedFrom; return *this; } + Oracle& operator=(const Oracle& o) { s = sCopyConstructed; val = o.val; return *this; } + Oracle& operator=(Oracle&& o) { s = sMoveConstructed; val = std::move(o.val); o.s = sMovedFrom; return *this; } +}; + +struct Guard +{ + std::string val; + Guard() : val{} {} + explicit Guard(std::string s, int = 0) : val(s) {} + Guard(const Guard&) = delete; + Guard(Guard&&) = delete; + void operator=(const Guard&) = delete; + void operator=(Guard&&) = delete; +}; + +struct ExplicitStr +{ + std::string s; + explicit ExplicitStr(const char* chp) : s(chp) {}; +}; + +struct Date +{ + int i; + Date() = delete; + Date(int i) : i{i} {}; + Date(Date&& d) : i(d.i) { d.i = 0; } + Date(const Date&) = delete; + Date& operator=(const Date&) = delete; + Date& operator=(Date&& d) { i = d.i; d.i = 0; return *this;}; +}; + +bool operator==( Oracle const& a, Oracle const& b ) { return a.val.i == b.val.i; } +bool operator!=( Oracle const& a, Oracle const& b ) { return a.val.i != b.val.i; } + + +namespace tr2 = std::experimental; + + +TEST(disengaged_ctor) +{ + tr2::optional o1; + assert (!o1); + + tr2::optional o2 = tr2::nullopt; + assert (!o2); + + tr2::optional o3 = o2; + assert (!o3); + + assert (o1 == tr2::nullopt); + assert (o1 == tr2::optional{}); + assert (!o1); + assert (bool(o1) == false); + + assert (o2 == tr2::nullopt); + assert (o2 == tr2::optional{}); + assert (!o2); + assert (bool(o2) == false); + + assert (o3 == tr2::nullopt); + assert (o3 == tr2::optional{}); + assert (!o3); + assert (bool(o3) == false); + + assert (o1 == o2); + assert (o2 == o1); + assert (o1 == o3); + assert (o3 == o1); + assert (o2 == o3); + assert (o3 == o2); +}; + + +TEST(value_ctor) +{ + OracleVal v; + tr2::optional oo1(v); + assert (oo1 != tr2::nullopt); + assert (oo1 != tr2::optional{}); + assert (oo1 == tr2::optional{v}); + assert (!!oo1); + assert (bool(oo1)); + // NA: assert (oo1->s == sValueCopyConstructed); + assert (oo1->s == sMoveConstructed); + assert (v.s == sValueConstructed); + + tr2::optional oo2(std::move(v)); + assert (oo2 != tr2::nullopt); + assert (oo2 != tr2::optional{}); + assert (oo2 == oo1); + assert (!!oo2); + assert (bool(oo2)); + // NA: assert (oo2->s == sValueMoveConstructed); + assert (oo2->s == sMoveConstructed); + assert (v.s == sMovedFrom); + + { + OracleVal v; + tr2::optional oo1{tr2::in_place, v}; + assert (oo1 != tr2::nullopt); + assert (oo1 != tr2::optional{}); + assert (oo1 == tr2::optional{v}); + assert (!!oo1); + assert (bool(oo1)); + assert (oo1->s == sValueCopyConstructed); + assert (v.s == sValueConstructed); + + tr2::optional oo2{tr2::in_place, std::move(v)}; + assert (oo2 != tr2::nullopt); + assert (oo2 != tr2::optional{}); + assert (oo2 == oo1); + assert (!!oo2); + assert (bool(oo2)); + assert (oo2->s == sValueMoveConstructed); + assert (v.s == sMovedFrom); + } +}; + + +TEST(assignment) +{ + tr2::optional oi; + oi = tr2::optional{1}; + assert (*oi == 1); + + oi = tr2::nullopt; + assert (!oi); + + oi = 2; + assert (*oi == 2); + + oi = {}; + assert (!oi); +}; + + +template +struct MoveAware +{ + T val; + bool moved; + MoveAware(T val) : val(val), moved(false) {} + MoveAware(MoveAware const&) = delete; + MoveAware(MoveAware&& rhs) : val(rhs.val), moved(rhs.moved) { + rhs.moved = true; + } + MoveAware& operator=(MoveAware const&) = delete; + MoveAware& operator=(MoveAware&& rhs) { + val = (rhs.val); + moved = (rhs.moved); + rhs.moved = true; + return *this; + } +}; + +TEST(moved_from_state) +{ + // first, test mock: + MoveAware i{1}, j{2}; + assert (i.val == 1); + assert (!i.moved); + assert (j.val == 2); + assert (!j.moved); + + MoveAware k = std::move(i); + assert (k.val == 1); + assert (!k.moved); + assert (i.val == 1); + assert (i.moved); + + k = std::move(j); + assert (k.val == 2); + assert (!k.moved); + assert (j.val == 2); + assert (j.moved); + + // now, test optional + tr2::optional> oi{1}, oj{2}; + assert (oi); + assert (!oi->moved); + assert (oj); + assert (!oj->moved); + + tr2::optional> ok = std::move(oi); + assert (ok); + assert (!ok->moved); + assert (oi); + assert (oi->moved); + + ok = std::move(oj); + assert (ok); + assert (!ok->moved); + assert (oj); + assert (oj->moved); +}; + + +TEST(copy_move_ctor_optional_int) +{ + tr2::optional oi; + tr2::optional oj = oi; + + assert (!oj); + assert (oj == oi); + assert (oj == tr2::nullopt); + assert (!bool(oj)); + + oi = 1; + tr2::optional ok = oi; + assert (!!ok); + assert (bool(ok)); + assert (ok == oi); + assert (ok != oj); + assert (*ok == 1); + + tr2::optional ol = std::move(oi); + assert (!!ol); + assert (bool(ol)); + assert (ol == oi); + assert (ol != oj); + assert (*ol == 1); +}; + + +TEST(optional_optional) +{ + tr2::optional> oi1 = tr2::nullopt; + assert (oi1 == tr2::nullopt); + assert (!oi1); + + { + tr2::optional> oi2 {tr2::in_place}; + assert (oi2 != tr2::nullopt); + assert (bool(oi2)); + assert (*oi2 == tr2::nullopt); + //assert (!(*oi2)); + //std::cout << typeid(**oi2).name() << std::endl; + } + + { + tr2::optional> oi2 {tr2::in_place, tr2::nullopt}; + assert (oi2 != tr2::nullopt); + assert (bool(oi2)); + assert (*oi2 == tr2::nullopt); + assert (!*oi2); + } + + { + tr2::optional> oi2 {tr2::optional{}}; + assert (oi2 != tr2::nullopt); + assert (bool(oi2)); + assert (*oi2 == tr2::nullopt); + assert (!*oi2); + } + + tr2::optional oi; + auto ooi = tr2::make_optional(oi); + static_assert( std::is_same>, decltype(ooi)>::value, ""); + +}; + +TEST(example_guard) +{ + using namespace tr2; + //FAILS: optional ogx(Guard("res1")); + //FAILS: optional ogx = "res1"; + //FAILS: optional ogx("res1"); + optional oga; // Guard is non-copyable (and non-moveable) + optional ogb(in_place, "res1"); // initialzes the contained value with "res1" + assert (bool(ogb)); + assert (ogb->val == "res1"); + + optional ogc(in_place); // default-constructs the contained value + assert (bool(ogc)); + assert (ogc->val == ""); + + oga.emplace("res1"); // initialzes the contained value with "res1" + assert (bool(oga)); + assert (oga->val == "res1"); + + oga.emplace(); // destroys the contained value and + // default-constructs the new one + assert (bool(oga)); + assert (oga->val == ""); + + oga = nullopt; // OK: make disengaged the optional Guard + assert (!(oga)); + //FAILS: ogb = {}; // ERROR: Guard is not Moveable +}; + + +void process(){} +void process(int ){} +void processNil(){} + + +TEST(example1) +{ + using namespace tr2; + optional oi; // create disengaged object + optional oj = nullopt; // alternative syntax + oi = oj; // assign disengaged object + optional ok = oj; // ok is disengaged + + if (oi) assert(false); // 'if oi is engaged...' + if (!oi) assert(true); // 'if oi is disengaged...' + + if (oi != nullopt) assert(false); // 'if oi is engaged...' + if (oi == nullopt) assert(true); // 'if oi is disengaged...' + + assert(oi == ok); // two disengaged optionals compare equal + + /////////////////////////////////////////////////////////////////////////// + optional ol{1}; // ol is engaged; its contained value is 1 + ok = 2; // ok becomes engaged; its contained value is 2 + oj = ol; // oj becomes engaged; its contained value is 1 + + assert(oi != ol); // disengaged != engaged + assert(ok != ol); // different contained values + assert(oj == ol); // same contained value + assert(oi < ol); // disengaged < engaged + assert(ol < ok); // less by contained value + + ///////////////////////////////////////////////////////////////////////////// + optional om{1}; // om is engaged; its contained value is 1 + optional on = om; // on is engaged; its contained value is 1 + om = 2; // om is engaged; its contained value is 2 + assert (on != om); // on still contains 3. They are not pointers + + ///////////////////////////////////////////////////////////////////////////// + int i = *ol; // i obtains the value contained in ol + assert (i == 1); + *ol = 9; // the object contained in ol becomes 9 + assert(*ol == 9); + assert(ol == make_optional(9)); + + /////////////////////////////////// + int p = 1; + optional op = p; + assert(*op == 1); + p = 2; + assert(*op == 1); // value contained in op is separated from p + + //////////////////////////////// + if (ol) + process(*ol); // use contained value if present + else + process(); // proceed without contained value + + if (!om) + processNil(); + else + process(*om); + + ///////////////////////////////////////// + process(ol.value_or(0)); // use 0 if ol is disengaged + + //////////////////////////////////////////// + ok = nullopt; // if ok was engaged calls T's dtor + oj = {}; // assigns a temporary disengaged optional +}; + + +TEST(example_guard) +{ + using std::experimental::optional; + const optional c = 4; + int i = *c; // i becomes 4 + assert (i == 4); + // FAILS: *c = i; // ERROR: cannot assign to const int& +}; + + +TEST(example_ref) +{ + using namespace std::experimental; + int i = 1; + int j = 2; + optional ora; // disengaged optional reference to int + optional orb = i; // contained reference refers to object i + + *orb = 3; // i becomes 3 + // FAILS: ora = j; // ERROR: optional refs do not have assignment from T + // FAILS: ora = {j}; // ERROR: optional refs do not have copy/move assignment + // FAILS: ora = orb; // ERROR: no copy/move assignment + ora.emplace(j); // OK: contained reference refers to object j + ora.emplace(i); // OK: contained reference now refers to object i + + ora = nullopt; // OK: ora becomes disengaged +}; + + +template +T getValue( tr2::optional newVal = tr2::nullopt, tr2::optional storeHere = tr2::nullopt ) +{ + T cached{}; + + if (newVal) { + cached = *newVal; + + if (storeHere) { + *storeHere = *newVal; // LEGAL: assigning T to T + } + } + return cached; +} + +TEST(example_optional_arg) +{ + int iii = 0; + iii = getValue(iii, iii); + iii = getValue(iii); + iii = getValue(); + + { + using namespace std::experimental; + optional grd1{in_place, "res1", 1}; // guard 1 initialized + optional grd2; + + grd2.emplace("res2", 2); // guard 2 initialized + grd1 = nullopt; // guard 1 released + + } // guard 2 released (in dtor) +}; + + +std::tuple getStartMidEnd() { return std::tuple{Date{1}, Date{2}, Date{3}}; } +void run(Date const&, Date const&, Date const&) {} + +TEST(example_date) +{ + using namespace std::experimental; + optional start, mid, end; // Date doesn't have default ctor (no good default date) + + std::tie(start, mid, end) = getStartMidEnd(); + run(*start, *mid, *end); +}; + + +std::experimental::optional readNextChar(){ return{}; } + +void run(std::experimental::optional) {} +void run(std::complex) {} + + +template +void assign_norebind(tr2::optional& optref, T& obj) +{ + if (optref) *optref = obj; + else optref.emplace(obj); +} + +template void unused(T&&) {} + +TEST(example_conceptual_model) +{ + using namespace std::experimental; + + optional oi = 0; + optional oj = 1; + optional ok = nullopt; + + oi = 1; + oj = nullopt; + ok = 0; + + unused(oi == nullopt); + unused(oj == 0); + unused(ok == 1); +}; + +TEST(example_rationale) +{ + using namespace std::experimental; + if (optional ch = readNextChar()) { + unused(ch); + // ... + } + + ////////////////////////////////// + optional opt1 = nullopt; + optional opt2 = {}; + + opt1 = nullopt; + opt2 = {}; + + if (opt1 == nullopt) {} + if (!opt2) {} + if (opt2 == optional{}) {} + + + + //////////////////////////////// + + run(nullopt); // pick the second overload + // FAILS: run({}); // ambiguous + + if (opt1 == nullopt) {} // fine + // FAILS: if (opt2 == {}) {} // ilegal + + //////////////////////////////// + assert (optional{} < optional{0}); + assert (optional{0} < optional{1}); + assert (!(optional{} < optional{}) ); + assert (!(optional{1} < optional{1})); + + assert (optional{} != optional{0}); + assert (optional{0} != optional{1}); + assert (optional{} == optional{} ); + assert (optional{0} == optional{0}); + + ///////////////////////////////// + optional o; + o = make_optional(1); // copy/move assignment + o = 1; // assignment from T + o.emplace(1); // emplacement + + //////////////////////////////////// + int isas = 0, i = 9; + optional asas = i; + assign_norebind(asas, isas); + + ///////////////////////////////////// + ////tr2::optional> ov2 = {2, 3}; + ////assert (bool(ov2)); + ////assert ((*ov2)[1] == 3); + //// + //////////////////////////////// + ////std::vector v = {1, 2, 4, 8}; + ////optional> ov = {1, 2, 4, 8}; + + ////assert (v == *ov); + //// + ////ov = {1, 2, 4, 8}; + + ////std::allocator a; + ////optional> ou { in_place, {1, 2, 4, 8}, a }; + + ////assert (ou == ov); + + ////////////////////////////// + // inconvenient syntax: + { + + tr2::optional> ov2{tr2::in_place, {2, 3}}; + + assert (bool(ov2)); + assert ((*ov2)[1] == 3); + + //////////////////////////// + + std::vector v = {1, 2, 4, 8}; + optional> ov{tr2::in_place, {1, 2, 4, 8}}; + + assert (v == *ov); + + ov.emplace({1, 2, 4, 8}); +/* + std::allocator a; + optional> ou { in_place, {1, 2, 4, 8}, a }; + + assert (ou == ov); +*/ + } + + ///////////////////////////////// + { + typedef int T; + optional> ot {in_place}; + optional> ou {in_place, nullopt}; + optional> ov {optional{}}; + + optional oi; + auto ooi = make_optional(oi); + static_assert( std::is_same>, decltype(ooi)>::value, ""); + } +}; + + +bool fun(std::string , std::experimental::optional oi = std::experimental::nullopt) +{ + return bool(oi); +} + +TEST(example_converting_ctor) +{ + using namespace std::experimental; + + assert (true == fun("dog", 2)); + assert (false == fun("dog")); + assert (false == fun("dog", nullopt)); // just to be explicit +}; + + +TEST(bad_comparison) +{ + tr2::optional oi, oj; + int i; + bool b = (oi == oj); + b = (oi >= i); + b = (oi == i); + unused(b); +}; + + +//// NOT APPLICABLE ANYMORE +////TEST(perfect_ctor) +////{ +//// //tr2::optional ois = "OS"; +//// assert (*ois == "OS"); +//// +//// // FAILS: tr2::optional oes = "OS"; +//// tr2::optional oes{"OS"}; +//// assert (oes->s == "OS"); +////}; + +TEST(value_or) +{ + tr2::optional oi = 1; + int i = oi.value_or(0); + assert (i == 1); + + oi = tr2::nullopt; + assert (oi.value_or(3) == 3); + + tr2::optional os{"AAA"}; + assert (os.value_or("BBB") == "AAA"); + os = {}; + assert (os.value_or("BBB") == "BBB"); +}; + +TEST(mixed_order) +{ + using namespace std::experimental; + + optional oN {nullopt}; + optional o0 {0}; + optional o1 {1}; + + assert ( (oN < 0)); + assert ( (oN < 1)); + assert (!(o0 < 0)); + assert ( (o0 < 1)); + assert (!(o1 < 0)); + assert (!(o1 < 1)); + + assert (!(oN >= 0)); + assert (!(oN >= 1)); + assert ( (o0 >= 0)); + assert (!(o0 >= 1)); + assert ( (o1 >= 0)); + assert ( (o1 >= 1)); + + assert (!(oN > 0)); + assert (!(oN > 1)); + assert (!(o0 > 0)); + assert (!(o0 > 1)); + assert ( (o1 > 0)); + assert (!(o1 > 1)); + + assert ( (oN <= 0)); + assert ( (oN <= 1)); + assert ( (o0 <= 0)); + assert ( (o0 <= 1)); + assert (!(o1 <= 0)); + assert ( (o1 <= 1)); + + assert ( (0 > oN)); + assert ( (1 > oN)); + assert (!(0 > o0)); + assert ( (1 > o0)); + assert (!(0 > o1)); + assert (!(1 > o1)); + + assert (!(0 <= oN)); + assert (!(1 <= oN)); + assert ( (0 <= o0)); + assert (!(1 <= o0)); + assert ( (0 <= o1)); + assert ( (1 <= o1)); + + assert (!(0 < oN)); + assert (!(1 < oN)); + assert (!(0 < o0)); + assert (!(1 < o0)); + assert ( (0 < o1)); + assert (!(1 < o1)); + + assert ( (0 >= oN)); + assert ( (1 >= oN)); + assert ( (0 >= o0)); + assert ( (1 >= o0)); + assert (!(0 >= o1)); + assert ( (1 >= o1)); +}; + +struct BadRelops +{ + int i; +}; + +constexpr bool operator<(BadRelops a, BadRelops b) { return a.i < b.i; } +constexpr bool operator>(BadRelops a, BadRelops b) { return a.i < b.i; } // intentional error! + +TEST(bad_relops) +{ + using namespace std::experimental; + BadRelops a{1}, b{2}; + assert (a < b); + assert (a > b); + + optional oa = a, ob = b; + assert (oa < ob); + assert (!(oa > ob)); + + assert (oa < b); + assert (oa > b); + + optional ra = a, rb = b; + assert (ra < rb); + assert (!(ra > rb)); + + assert (ra < b); + assert (ra > b); +}; + + +TEST(mixed_equality) +{ + using namespace std::experimental; + + assert (make_optional(0) == 0); + assert (make_optional(1) == 1); + assert (make_optional(0) != 1); + assert (make_optional(1) != 0); + + optional oN {nullopt}; + optional o0 {0}; + optional o1 {1}; + + assert (o0 == 0); + assert ( 0 == o0); + assert (o1 == 1); + assert ( 1 == o1); + assert (o1 != 0); + assert ( 0 != o1); + assert (o0 != 1); + assert ( 1 != o0); + + assert ( 1 != oN); + assert ( 0 != oN); + assert (oN != 1); + assert (oN != 0); + assert (!( 1 == oN)); + assert (!( 0 == oN)); + assert (!(oN == 1)); + assert (!(oN == 0)); + + std::string cat{"cat"}, dog{"dog"}; + optional oNil{}, oDog{"dog"}, oCat{"cat"}; + + assert (oCat == cat); + assert ( cat == oCat); + assert (oDog == dog); + assert ( dog == oDog); + assert (oDog != cat); + assert ( cat != oDog); + assert (oCat != dog); + assert ( dog != oCat); + + assert ( dog != oNil); + assert ( cat != oNil); + assert (oNil != dog); + assert (oNil != cat); + assert (!( dog == oNil)); + assert (!( cat == oNil)); + assert (!(oNil == dog)); + assert (!(oNil == cat)); +}; + +TEST(const_propagation) +{ + using namespace std::experimental; + + optional mmi{0}; + static_assert(std::is_same::value, "WTF"); + + const optional cmi{0}; + static_assert(std::is_same::value, "WTF"); + + optional mci{0}; + static_assert(std::is_same::value, "WTF"); + + optional cci{0}; + static_assert(std::is_same::value, "WTF"); +}; + + +static_assert(std::is_base_of::value, ""); + +TEST(safe_value) +{ + using namespace std::experimental; + + try { + optional ovN{}, ov1{1}; + + int& r1 = ov1.value(); + assert (r1 == 1); + + try { + ovN.value(); + assert (false); + } + catch (bad_optional_access const&) { + } + + { // ref variant + int i1 = 1; + optional orN{}, or1{i1}; + + int& r2 = or1.value(); + assert (r2 == 1); + + try { + orN.value(); + assert (false); + } + catch (bad_optional_access const&) { + } + } + } + catch(...) { + assert (false); + } +}; + +TEST(optional_ref) +{ + using namespace tr2; + // FAILS: optional orr; + // FAILS: optional on; + int i = 8; + optional ori; + assert (!ori); + ori.emplace(i); + assert (bool(ori)); + assert (*ori == 8); + assert (&*ori == &i); + *ori = 9; + assert (i == 9); + + // FAILS: int& ir = ori.value_or(i); + int ii = ori.value_or(i); + assert (ii == 9); + ii = 7; + assert (*ori == 9); + + int j = 22; + auto&& oj = make_optional(std::ref(j)); + *oj = 23; + assert (&*oj == &j); + assert (j == 23); +}; + +TEST(optional_ref_const_propagation) +{ + using namespace std::experimental; + + int i = 9; + const optional mi = i; + int& r = *mi; + optional ci = i; + static_assert(std::is_same::value, "WTF"); + static_assert(std::is_same::value, "WTF"); + + unused(r); +}; + +TEST(optional_ref_assign) +{ + using namespace std::experimental; + + int i = 9; + optional ori = i; + + int j = 1; + ori = optional{j}; + ori = {j}; + // FAILS: ori = j; + + optional orx = ori; + ori = orx; + + optional orj = j; + + assert (ori); + assert (*ori == 1); + assert (ori == orj); + assert (i == 9); + + *ori = 2; + assert (*ori == 2); + assert (ori == 2); + assert (2 == ori); + assert (ori != 3); + + assert (ori == orj); + assert (j == 2); + assert (i == 9); + + ori = {}; + assert (!ori); + assert (ori != orj); + assert (j == 2); + assert (i == 9); +}; + + +TEST(optional_ref_swap) +{ + using namespace std::experimental; + int i = 0; + int j = 1; + optional oi = i; + optional oj = j; + + assert (&*oi == &i); + assert (&*oj == &j); + + swap(oi, oj); + assert (&*oi == &j); + assert (&*oj == &i); +}; + +TEST(optional_initialization) +{ + using namespace tr2; + using std::string; + string s = "STR"; + + optional os{s}; + optional ot = s; + optional ou{"STR"}; + optional ov = string{"STR"}; + +}; + +#include + +TEST(optional_hashing) +{ + using namespace tr2; + using std::string; + + std::hash hi; + std::hash> hoi; + std::hash hs; + std::hash> hos; + + assert (hi(0) == hoi(optional{0})); + assert (hi(1) == hoi(optional{1})); + assert (hi(3198) == hoi(optional{3198})); + + assert (hs("") == hos(optional{""})); + assert (hs("0") == hos(optional{"0"})); + assert (hs("Qa1#") == hos(optional{"Qa1#"})); + + std::unordered_set> set; + assert(set.find({"Qa1#"}) == set.end()); + + set.insert({"0"}); + assert(set.find({"Qa1#"}) == set.end()); + + set.insert({"Qa1#"}); + assert(set.find({"Qa1#"}) != set.end()); +}; + + +// optional_ref_emulation +template +struct generic +{ + typedef T type; +}; + +template +struct generic +{ + typedef std::reference_wrapper type; +}; + +template +using Generic = typename generic::type; + +template +bool generic_fun() +{ + std::experimental::optional> op; + return bool(op); +} + +TEST(optional_ref_emulation) +{ + using namespace std::experimental; + optional> oi = 1; + assert (*oi == 1); + + int i = 8; + int j = 4; + optional> ori {i}; + assert (*ori == 8); + assert ((void*)&*ori != (void*)&i); // !DIFFERENT THAN optional + + *ori = j; + assert (*ori == 4); +}; + + +# if OPTIONAL_HAS_THIS_RVALUE_REFS == 1 +TEST(moved_on_value_or) +{ + using namespace tr2; + optional oo{in_place}; + + assert (oo); + assert (oo->s == sDefaultConstructed); + + Oracle o = std::move(oo).value_or( Oracle{OracleVal{}} ); + assert (oo); + assert (oo->s == sMovedFrom); + assert (o.s == sMoveConstructed); + + optional> om {in_place, 1}; + assert (om); + assert (om->moved == false); + + /*MoveAware m =*/ std::move(om).value_or( MoveAware{1} ); + assert (om); + assert (om->moved == true); + +# if OPTIONAL_HAS_MOVE_ACCESSORS == 1 + { + Date d = optional{in_place, 1}.value(); + assert (d.i); // to silence compiler warning + + Date d2 = *optional{in_place, 1}; + assert (d2.i); // to silence compiler warning + } +# endif +}; +# endif + + +TEST(optional_ref_hashing) +{ + using namespace tr2; + using std::string; + + std::hash hi; + std::hash> hoi; + std::hash hs; + std::hash> hos; + + int i0 = 0; + int i1 = 1; + assert (hi(0) == hoi(optional{i0})); + assert (hi(1) == hoi(optional{i1})); + + string s{""}; + string s0{"0"}; + string sCAT{"CAT"}; + assert (hs("") == hos(optional{s})); + assert (hs("0") == hos(optional{s0})); + assert (hs("CAT") == hos(optional{sCAT})); + + std::unordered_set> set; + assert(set.find({sCAT}) == set.end()); + + set.insert({s0}); + assert(set.find({sCAT}) == set.end()); + + set.insert({sCAT}); + assert(set.find({sCAT}) != set.end()); +}; + +struct Combined +{ + int m = 0; + int n = 1; + + constexpr Combined() : m{5}, n{6} {} + constexpr Combined(int m, int n) : m{m}, n{n} {} +}; + +struct Nasty +{ + int m = 0; + int n = 1; + + constexpr Nasty() : m{5}, n{6} {} + constexpr Nasty(int m, int n) : m{m}, n{n} {} + + int operator&() { return n; } + int operator&() const { return n; } +}; + +TEST(arrow_operator) +{ + using namespace std::experimental; + + optional oc1{in_place, 1, 2}; + assert (oc1); + assert (oc1->m == 1); + assert (oc1->n == 2); + + optional on{in_place, 1, 2}; + assert (on); + assert (on->m == 1); + assert (on->n == 2); +}; + +TEST(arrow_wit_optional_ref) +{ + using namespace std::experimental; + + Combined c{1, 2}; + optional oc = c; + assert (oc); + assert (oc->m == 1); + assert (oc->n == 2); + + Nasty n{1, 2}; + Nasty m{3, 4}; + Nasty p{5, 6}; + + optional on{n}; + assert (on); + assert (on->m == 1); + assert (on->n == 2); + + on = {m}; + assert (on); + assert (on->m == 3); + assert (on->n == 4); + + on.emplace(p); + assert (on); + assert (on->m == 5); + assert (on->n == 6); + + optional om{in_place, n}; + assert (om); + assert (om->m == 1); + assert (om->n == 2); +}; + +TEST(no_dangling_reference_in_value) +{ + // this mostly tests compiler warnings + using namespace std::experimental; + optional oi {2}; + unused (oi.value()); + const optional coi {3}; + unused (coi.value()); +}; + +struct CountedObject +{ + static int _counter; + bool _throw; + CountedObject(bool b) : _throw(b) { ++_counter; } + CountedObject(CountedObject const& rhs) : _throw(rhs._throw) { if (_throw) throw int(); } + ~CountedObject() { --_counter; } +}; + +int CountedObject::_counter = 0; + +TEST(exception_safety) +{ + using namespace std::experimental; + try { + optional oo(in_place, true); // throw + optional o1(oo); + } + catch(...) + { + // + } + assert(CountedObject::_counter == 0); + + try { + optional oo(in_place, true); // throw + optional o1(std::move(oo)); // now move + } + catch(...) + { + // + } + assert(CountedObject::_counter == 0); +}; + +//// constexpr tests + +// these 4 classes have different noexcept signatures in move operations +struct NothrowBoth { + NothrowBoth(NothrowBoth&&) noexcept(true) {}; + void operator=(NothrowBoth&&) noexcept(true) {}; +}; +struct NothrowCtor { + NothrowCtor(NothrowCtor&&) noexcept(true) {}; + void operator=(NothrowCtor&&) noexcept(false) {}; +}; +struct NothrowAssign { + NothrowAssign(NothrowAssign&&) noexcept(false) {}; + void operator=(NothrowAssign&&) noexcept(true) {}; +}; +struct NothrowNone { + NothrowNone(NothrowNone&&) noexcept(false) {}; + void operator=(NothrowNone&&) noexcept(false) {}; +}; + +void test_noexcept() +{ + { + tr2::optional b1, b2; + static_assert(noexcept(tr2::optional{tr2::constexpr_move(b1)}), "bad noexcept!"); + static_assert(noexcept(b1 = tr2::constexpr_move(b2)), "bad noexcept!"); + } + { + tr2::optional c1, c2; + static_assert(noexcept(tr2::optional{tr2::constexpr_move(c1)}), "bad noexcept!"); + static_assert(!noexcept(c1 = tr2::constexpr_move(c2)), "bad noexcept!"); + } + { + tr2::optional a1, a2; + static_assert(!noexcept(tr2::optional{tr2::constexpr_move(a1)}), "bad noexcept!"); + static_assert(!noexcept(a1 = tr2::constexpr_move(a2)), "bad noexcept!"); + } + { + tr2::optional n1, n2; + static_assert(!noexcept(tr2::optional{tr2::constexpr_move(n1)}), "bad noexcept!"); + static_assert(!noexcept(n1 = tr2::constexpr_move(n2)), "bad noexcept!"); + } +} + + +void constexpr_test_disengaged() +{ + constexpr tr2::optional g0{}; + constexpr tr2::optional g1{tr2::nullopt}; + static_assert( !g0, "initialized!" ); + static_assert( !g1, "initialized!" ); + + static_assert( bool(g1) == bool(g0), "ne!" ); + + static_assert( g1 == g0, "ne!" ); + static_assert( !(g1 != g0), "ne!" ); + static_assert( g1 >= g0, "ne!" ); + static_assert( !(g1 > g0), "ne!" ); + static_assert( g1 <= g0, "ne!" ); + static_assert( !(g1 = tr2::nullopt, "!" ); + static_assert( !(g1 > tr2::nullopt), "!" ); + + static_assert( (tr2::nullopt == g0), "!" ); + static_assert( !(tr2::nullopt != g0), "!" ); + static_assert( (tr2::nullopt >= g0), "!" ); + static_assert( !(tr2::nullopt > g0), "!" ); + static_assert( (tr2::nullopt <= g0), "!" ); + static_assert( !(tr2::nullopt < g0), "!" ); + + static_assert( (g1 != tr2::optional(1)), "!" ); + static_assert( !(g1 == tr2::optional(1)), "!" ); + static_assert( (g1 < tr2::optional(1)), "!" ); + static_assert( (g1 <= tr2::optional(1)), "!" ); + static_assert( !(g1 > tr2::optional(1)), "!" ); + static_assert( !(g1 > tr2::optional(1)), "!" ); +} + + +constexpr tr2::optional g0{}; +constexpr tr2::optional g2{2}; +static_assert( g2, "not initialized!" ); +static_assert( *g2 == 2, "not 2!" ); +static_assert( g2 == tr2::optional(2), "not 2!" ); +static_assert( g2 != g0, "eq!" ); + +# if OPTIONAL_HAS_MOVE_ACCESSORS == 1 +static_assert( *tr2::optional{3} == 3, "WTF!" ); +static_assert( tr2::optional{3}.value() == 3, "WTF!" ); +static_assert( tr2::optional{3}.value_or(1) == 3, "WTF!" ); +static_assert( tr2::optional{}.value_or(4) == 4, "WTF!" ); +# endif + +constexpr tr2::optional gc0{tr2::in_place}; +static_assert(gc0->n == 6, "WTF!"); + +// optional refs +int gi = 0; +constexpr tr2::optional gori = gi; +constexpr tr2::optional gorn{}; +constexpr int& gri = *gori; +static_assert(gori, "WTF"); +static_assert(!gorn, "WTF"); +static_assert(gori != tr2::nullopt, "WTF"); +static_assert(gorn == tr2::nullopt, "WTF"); +static_assert(&gri == &*gori, "WTF"); + +constexpr int gci = 1; +constexpr tr2::optional gorci = gci; +constexpr tr2::optional gorcn{}; + +static_assert(gorcn < gorci, "WTF"); +static_assert(gorcn <= gorci, "WTF"); +static_assert(gorci == gorci, "WTF"); +static_assert(*gorci == 1, "WTF"); +static_assert(gorci == gci, "WTF"); + +namespace constexpr_optional_ref_and_arrow +{ + using namespace std::experimental; + constexpr Combined c{1, 2}; + constexpr optional oc = c; + static_assert(oc, "WTF!"); + static_assert(oc->m == 1, "WTF!"); + static_assert(oc->n == 2, "WTF!"); +} + +#if OPTIONAL_HAS_CONSTEXPR_INIT_LIST + +namespace InitList +{ + using namespace std::experimental; + + struct ConstInitLister + { + template + constexpr ConstInitLister(std::initializer_list il) : len (il.size()) {} + size_t len; + }; + + constexpr ConstInitLister CIL {2, 3, 4}; + static_assert(CIL.len == 3, "WTF!"); + + constexpr optional oil {in_place, {4, 5, 6, 7}}; + static_assert(oil, "WTF!"); + static_assert(oil->len == 4, "WTF!"); +} + +#endif // OPTIONAL_HAS_CONSTEXPR_INIT_LIST + +// end constexpr tests + + +#include + + +struct VEC +{ + std::vector v; + template + VEC( X&&...x) : v(std::forward(x)...) {} + + template + VEC(std::initializer_list il, X&&...x) : v(il, std::forward(x)...) {} +}; + + + +int main() { + tr2::optional oi = 1; + assert (bool(oi)); + oi.operator=({}); + assert (!oi); + + VEC v = {5, 6}; + + if (OPTIONAL_HAS_THIS_RVALUE_REFS) + std::cout << "Optional has rvalue references for *this" << std::endl; + else + std::cout << "Optional doesn't have rvalue references for *this" << std::endl; + + if (OPTIONAL_HAS_CONSTEXPR_INIT_LIST) + std::cout << "Optional has constexpr initializer_list" << std::endl; + else + std::cout << "Optional doesn't have constexpr initializer_list" << std::endl; + + if (OPTIONAL_HAS_MOVE_ACCESSORS) + std::cout << "Optional has constexpr move accessors" << std::endl; + else + std::cout << "Optional doesn't have constexpr move accessors" << std::endl; +} + diff --git a/share/include/tao/json/external/akrzemi1/test_type_traits.cpp b/share/include/tao/json/external/akrzemi1/test_type_traits.cpp new file mode 100644 index 0000000..8ec82b7 --- /dev/null +++ b/share/include/tao/json/external/akrzemi1/test_type_traits.cpp @@ -0,0 +1,66 @@ +// Copyright (C) 2011 - 2012 Andrzej Krzemienski. +// +// Use, modification, and distribution is subject to the Boost Software +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#if (defined __clang__) + namespace std { class type_info; } +#endif + +# include "optional.hpp" + +namespace std { namespace experimental { + +struct Val +{ + Val(){} + Val( Val const & ){} + Val( Val && ) noexcept {} + + Val & operator=( Val const & ) = delete; + Val & operator=( Val && ) noexcept = delete; +}; + +struct Safe +{ + Safe(){} + Safe( Safe const & ){} + Safe( Safe && ) noexcept {} + + Safe & operator=( Safe const & ){ return *this; } + Safe & operator=( Safe && ) noexcept { return *this; } +}; + +struct Unsafe +{ + Unsafe(){} + Unsafe( Unsafe const & ){} + Unsafe( Unsafe && ){} + + Unsafe & operator=( Unsafe const & ){ return *this; } + Unsafe & operator=( Unsafe && ) { return *this; } +}; + +struct VoidNothrowBoth +{ + VoidNothrowBoth(VoidNothrowBoth&&) noexcept(true) {}; + void operator=(VoidNothrowBoth&&) noexcept(true) {}; // note void return type +}; + + +static_assert(is_nothrow_move_constructible::value, "WTF!"); +static_assert(!is_nothrow_move_constructible::value, "WTF!"); + +static_assert(is_assignable::value, "WTF!"); +static_assert(!is_assignable::value, "WTF!"); + +static_assert(is_nothrow_move_assignable::value, "WTF!"); +static_assert(!is_nothrow_move_assignable::value, "WTF!"); + +static_assert(is_nothrow_move_constructible::value, "WTF!"); +static_assert(is_nothrow_move_assignable::value, "WTF!"); + +}} // namespace std::experimental + +int main() { } diff --git a/share/include/tao/json/external/double.hh b/share/include/tao/json/external/double.hh new file mode 100644 index 0000000..c01d47c --- /dev/null +++ b/share/include/tao/json/external/double.hh @@ -0,0 +1,2137 @@ +// This header include/tao/json/external/double.hh contains +// modified portions of the double-conversion library from +// https://www.github.com/google/double-conversion +// which is licensed as follows: + +// Copyright 2006-2011 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef TAOCPP_JSON_INCLUDE_EXTERNAL_DOUBLE_HH +#define TAOCPP_JSON_INCLUDE_EXTERNAL_DOUBLE_HH + +#include +#include +#include +#include +#include + +#include + +#ifndef ASSERT +#define ASSERT( eXPReSSioN ) ((void)0) +#endif +#ifndef UNIMPLEMENTED +#define UNIMPLEMENTED() (abort()) +#endif +#ifndef UNREACHABLE +#define UNREACHABLE() (abort()) +#endif + +// Double operations detection based on target architecture. +// Linux uses a 80bit wide floating point stack on x86. This induces double +// rounding, which in turn leads to wrong results. +// An easy way to test if the floating-point operations are correct is to +// evaluate: 89255.0/1e22. If the floating-point stack is 64 bits wide then +// the result is equal to 89255e-22. +// The best way to test this, is to create a division-function and to compare +// the output of the division with the expected result. (Inlining must be +// disabled.) +// On Linux,x86 89255e-22 != Div_double(89255.0/1e22) +#if defined(_M_X64) || defined(__x86_64__) || \ + defined(__ARMEL__) || defined(__avr32__) || \ + defined(__hppa__) || defined(__ia64__) || \ + defined(__mips__) || \ + defined(__powerpc__) || defined(__ppc__) || defined(__ppc64__) || \ + defined(_POWER) || defined(_ARCH_PPC) || defined(_ARCH_PPC64) || \ + defined(__sparc__) || defined(__sparc) || defined(__s390__) || \ + defined(__SH4__) || defined(__alpha__) || \ + defined(_MIPS_ARCH_MIPS32R2) || \ + defined(__AARCH64EL__) || defined(__aarch64__) +#define DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS 1 +#elif defined(__mc68000__) +#undef DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS +#elif defined(_M_IX86) || defined(__i386__) || defined(__i386) +#if defined(_WIN32) +// Windows uses a 64bit wide floating point stack. +#define DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS 1 +#else +#undef DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS +#endif // _WIN32 +#else +#error Target architecture was not detected as supported by Double-Conversion. +#endif + +#if defined(__GNUC__) +#define DOUBLE_CONVERSION_UNUSED __attribute__((unused)) +#else +#define DOUBLE_CONVERSION_UNUSED +#endif + +#if defined(_WIN32) && !defined(__MINGW32__) + +typedef signed char int8_t; +typedef unsigned char uint8_t; +typedef short int16_t; // NOLINT +typedef unsigned short uint16_t; // NOLINT +typedef int int32_t; +typedef unsigned int uint32_t; +typedef __int64 int64_t; +typedef unsigned __int64 uint64_t; + +// intptr_t and friends are defined in crtdefs.h through stdio.h. + +#else + +#include + +#endif + +typedef uint16_t uc16; + +#define UINT64_2PART_C(a, b) (((static_cast(a) << 32) + 0x##b##u)) + +#ifndef GDCV8_ARRAY_SIZE +#define GDCV8_ARRAY_SIZE(a) \ + ((sizeof(a) / sizeof(*(a))) / \ + static_cast(!(sizeof(a) % sizeof(*(a))))) +#endif + +#ifndef DISALLOW_COPY_AND_ASSIGN +#define DISALLOW_COPY_AND_ASSIGN(TypeName) \ + TypeName(const TypeName&) = delete; \ + void operator=(const TypeName&) = delete +#endif + +#ifndef DISALLOW_IMPLICIT_CONSTRUCTORS +#define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \ + TypeName() = delete; \ + DISALLOW_COPY_AND_ASSIGN(TypeName) +#endif + +namespace json_double_conversion +{ + static const int kCharSize = sizeof( char ); + + template + static T Max(T a, T b) { + return a < b ? b : a; + } + + template + static T Min(T a, T b) { + return a < b ? a : b; + } + + inline int StrLength(const char* string) { + size_t length = strlen(string); + ASSERT(length == static_cast(static_cast(length))); + return static_cast(length); + } + + template + class Vector { + public: + Vector() : start_(NULL), length_(0) {} + Vector(T* data, int len) : start_(data), length_(len) { + ASSERT(len == 0 || (len > 0 && data != NULL)); + } + + Vector SubVector(int from, int to) { + ASSERT(to <= length_); + ASSERT(from < to); + ASSERT(0 <= from); + return Vector(start() + from, to - from); + } + + int length() const { return length_; } + + bool is_empty() const { return length_ == 0; } + + T* start() const { return start_; } + + T& operator[](int index) const { + ASSERT(0 <= index && index < length_); + return start_[index]; + } + + T& first() { return start_[0]; } + + T& last() { return start_[length_ - 1]; } + + private: + T* start_; + int length_; + }; + + template + inline Dest BitCast(const Source& source) { + DOUBLE_CONVERSION_UNUSED + typedef char VerifySizesAreEqual[sizeof(Dest) == sizeof(Source) ? 1 : -1]; + + Dest dest; + memmove(&dest, &source, sizeof(dest)); + return dest; + } + + template + inline Dest BitCast(Source* source) { + return BitCast(reinterpret_cast(source)); + } + + class Bignum + { + public: + static const int kMaxSignificantBits = 3584; + + Bignum(); + void AssignUInt16(uint16_t value); + void AssignUInt64(uint64_t value); + void AssignBignum(const Bignum& other); + + void AssignDecimalString(Vector value); + void AssignHexString(Vector value); + + void AssignPowerUInt16(uint16_t base, int exponent); + + void AddUInt64(uint64_t operand); + void AddBignum(const Bignum& other); + void SubtractBignum(const Bignum& other); + + void Square(); + void ShiftLeft(int shift_amount); + void MultiplyByUInt32(uint32_t factor); + void MultiplyByUInt64(uint64_t factor); + void MultiplyByPowerOfTen(int exponent); + void Times10() { return MultiplyByUInt32(10); } + uint16_t DivideModuloIntBignum(const Bignum& other); + + bool ToHexString(char* buffer, int buffer_size) const; + + static int Compare(const Bignum& a, const Bignum& b); + static bool Equal(const Bignum& a, const Bignum& b) { + return Compare(a, b) == 0; + } + static bool LessEqual(const Bignum& a, const Bignum& b) { + return Compare(a, b) <= 0; + } + static bool Less(const Bignum& a, const Bignum& b) { + return Compare(a, b) < 0; + } + static int PlusCompare(const Bignum& a, const Bignum& b, const Bignum& c); + static bool PlusEqual(const Bignum& a, const Bignum& b, const Bignum& c) { + return PlusCompare(a, b, c) == 0; + } + static bool PlusLessEqual(const Bignum& a, const Bignum& b, const Bignum& c) { + return PlusCompare(a, b, c) <= 0; + } + static bool PlusLess(const Bignum& a, const Bignum& b, const Bignum& c) { + return PlusCompare(a, b, c) < 0; + } + private: + typedef uint32_t Chunk; + typedef uint64_t DoubleChunk; + + static const int kChunkSize = sizeof(Chunk) * 8; + static const int kDoubleChunkSize = sizeof(DoubleChunk) * 8; + static const int kBigitSize = 28; + static const Chunk kBigitMask = (1 << kBigitSize) - 1; + static const int kBigitCapacity = kMaxSignificantBits / kBigitSize; + + void EnsureCapacity(int size) { + if (size > kBigitCapacity) { + UNREACHABLE(); + } + } + void Align(const Bignum& other); + void Clamp(); + bool IsClamped() const; + void Zero(); + + void BigitsShiftLeft(int shift_amount); + int BigitLength() const { return used_digits_ + exponent_; } + Chunk BigitAt(int index) const; + void SubtractTimes(const Bignum& other, int factor); + + Chunk bigits_buffer_[kBigitCapacity]; + Vector bigits_; + int used_digits_; + int exponent_; + + Bignum( const Bignum & ) = delete; + void operator= ( const Bignum & ) = delete; + }; + + inline Bignum::Bignum() + : bigits_(bigits_buffer_, kBigitCapacity), used_digits_(0), exponent_(0) { + for (int i = 0; i < kBigitCapacity; ++i) { + bigits_[i] = 0; + } + } + + template + inline int BitSize(S value) { + (void) value; // Mark variable as used. + return 8 * sizeof(value); + } + + inline void Bignum::AssignUInt16(uint16_t value) { + ASSERT(kBigitSize >= BitSize(value)); + Zero(); + if (value == 0) return; + + EnsureCapacity(1); + bigits_[0] = value; + used_digits_ = 1; + } + + inline void Bignum::AssignUInt64(uint64_t value) { + const int kUInt64Size = 64; + + Zero(); + if (value == 0) return; + + int needed_bigits = kUInt64Size / kBigitSize + 1; + EnsureCapacity(needed_bigits); + for (int i = 0; i < needed_bigits; ++i) { + bigits_[i] = value & kBigitMask; + value = value >> kBigitSize; + } + used_digits_ = needed_bigits; + Clamp(); + } + + inline void Bignum::AssignBignum(const Bignum& other) { + exponent_ = other.exponent_; + for (int i = 0; i < other.used_digits_; ++i) { + bigits_[i] = other.bigits_[i]; + } + for (int i = other.used_digits_; i < used_digits_; ++i) { + bigits_[i] = 0; + } + used_digits_ = other.used_digits_; + } + + + inline uint64_t ReadUInt64(Vector buffer, + int from, + int digits_to_read) { + uint64_t result = 0; + for (int i = from; i < from + digits_to_read; ++i) { + int digit = buffer[i] - '0'; + ASSERT(0 <= digit && digit <= 9); + result = result * 10 + digit; + } + return result; + } + + inline void Bignum::AssignDecimalString(Vector value) { + const int kMaxUint64DecimalDigits = 19; + Zero(); + int length = value.length(); + unsigned int pos = 0; + while (length >= kMaxUint64DecimalDigits) { + uint64_t digits = ReadUInt64(value, pos, kMaxUint64DecimalDigits); + pos += kMaxUint64DecimalDigits; + length -= kMaxUint64DecimalDigits; + MultiplyByPowerOfTen(kMaxUint64DecimalDigits); + AddUInt64(digits); + } + uint64_t digits = ReadUInt64(value, pos, length); + MultiplyByPowerOfTen(length); + AddUInt64(digits); + Clamp(); + } + + inline int HexCharValue(char c) { + if ('0' <= c && c <= '9') return c - '0'; + if ('a' <= c && c <= 'f') return 10 + c - 'a'; + ASSERT('A' <= c && c <= 'F'); + return 10 + c - 'A'; + } + + inline void Bignum::AssignHexString(Vector value) { + Zero(); + int length = value.length(); + + int needed_bigits = length * 4 / kBigitSize + 1; + EnsureCapacity(needed_bigits); + int string_index = length - 1; + for (int i = 0; i < needed_bigits - 1; ++i) { + Chunk current_bigit = 0; + for (int j = 0; j < kBigitSize / 4; j++) { + current_bigit += HexCharValue(value[string_index--]) << (j * 4); + } + bigits_[i] = current_bigit; + } + used_digits_ = needed_bigits - 1; + + Chunk most_significant_bigit = 0; + for (int j = 0; j <= string_index; ++j) { + most_significant_bigit <<= 4; + most_significant_bigit += HexCharValue(value[j]); + } + if (most_significant_bigit != 0) { + bigits_[used_digits_] = most_significant_bigit; + used_digits_++; + } + Clamp(); + } + + inline void Bignum::AddUInt64(uint64_t operand) { + if (operand == 0) return; + Bignum other; + other.AssignUInt64(operand); + AddBignum(other); + } + + inline void Bignum::AddBignum(const Bignum& other) { + ASSERT(IsClamped()); + ASSERT(other.IsClamped()); + Align(other); + EnsureCapacity(1 + Max(BigitLength(), other.BigitLength()) - exponent_); + Chunk carry = 0; + int bigit_pos = other.exponent_ - exponent_; + ASSERT(bigit_pos >= 0); + for (int i = 0; i < other.used_digits_; ++i) { + Chunk sum = bigits_[bigit_pos] + other.bigits_[i] + carry; + bigits_[bigit_pos] = sum & kBigitMask; + carry = sum >> kBigitSize; + bigit_pos++; + } + while (carry != 0) { + Chunk sum = bigits_[bigit_pos] + carry; + bigits_[bigit_pos] = sum & kBigitMask; + carry = sum >> kBigitSize; + bigit_pos++; + } + used_digits_ = Max(bigit_pos, used_digits_); + ASSERT(IsClamped()); + } + + inline void Bignum::SubtractBignum(const Bignum& other) { + ASSERT(IsClamped()); + ASSERT(other.IsClamped()); + ASSERT(LessEqual(other, *this)); + Align(other); + + int offset = other.exponent_ - exponent_; + Chunk borrow = 0; + int i; + for (i = 0; i < other.used_digits_; ++i) { + ASSERT((borrow == 0) || (borrow == 1)); + Chunk difference = bigits_[i + offset] - other.bigits_[i] - borrow; + bigits_[i + offset] = difference & kBigitMask; + borrow = difference >> (kChunkSize - 1); + } + while (borrow != 0) { + Chunk difference = bigits_[i + offset] - borrow; + bigits_[i + offset] = difference & kBigitMask; + borrow = difference >> (kChunkSize - 1); + ++i; + } + Clamp(); + } + + inline void Bignum::ShiftLeft(int shift_amount) { + if (used_digits_ == 0) return; + exponent_ += shift_amount / kBigitSize; + int local_shift = shift_amount % kBigitSize; + EnsureCapacity(used_digits_ + 1); + BigitsShiftLeft(local_shift); + } + + inline void Bignum::MultiplyByUInt32(uint32_t factor) { + if (factor == 1) return; + if (factor == 0) { + Zero(); + return; + } + if (used_digits_ == 0) return; + ASSERT(kDoubleChunkSize >= kBigitSize + 32 + 1); + DoubleChunk carry = 0; + for (int i = 0; i < used_digits_; ++i) { + DoubleChunk product = static_cast(factor) * bigits_[i] + carry; + bigits_[i] = static_cast(product & kBigitMask); + carry = (product >> kBigitSize); + } + while (carry != 0) { + EnsureCapacity(used_digits_ + 1); + bigits_[used_digits_] = carry & kBigitMask; + used_digits_++; + carry >>= kBigitSize; + } + } + + inline void Bignum::MultiplyByUInt64(uint64_t factor) { + if (factor == 1) return; + if (factor == 0) { + Zero(); + return; + } + ASSERT(kBigitSize < 32); + uint64_t carry = 0; + uint64_t low = factor & 0xFFFFFFFF; + uint64_t high = factor >> 32; + for (int i = 0; i < used_digits_; ++i) { + uint64_t product_low = low * bigits_[i]; + uint64_t product_high = high * bigits_[i]; + uint64_t tmp = (carry & kBigitMask) + product_low; + bigits_[i] = tmp & kBigitMask; + carry = (carry >> kBigitSize) + (tmp >> kBigitSize) + + (product_high << (32 - kBigitSize)); + } + while (carry != 0) { + EnsureCapacity(used_digits_ + 1); + bigits_[used_digits_] = carry & kBigitMask; + used_digits_++; + carry >>= kBigitSize; + } + } + + inline void Bignum::MultiplyByPowerOfTen(int exponent) { + const uint64_t kFive27 = UINT64_2PART_C(0x6765c793, fa10079d); + const uint16_t kFive1 = 5; + const uint16_t kFive2 = kFive1 * 5; + const uint16_t kFive3 = kFive2 * 5; + const uint16_t kFive4 = kFive3 * 5; + const uint16_t kFive5 = kFive4 * 5; + const uint16_t kFive6 = kFive5 * 5; + const uint32_t kFive7 = kFive6 * 5; + const uint32_t kFive8 = kFive7 * 5; + const uint32_t kFive9 = kFive8 * 5; + const uint32_t kFive10 = kFive9 * 5; + const uint32_t kFive11 = kFive10 * 5; + const uint32_t kFive12 = kFive11 * 5; + const uint32_t kFive13 = kFive12 * 5; + const uint32_t kFive1_to_12[] = + { kFive1, kFive2, kFive3, kFive4, kFive5, kFive6, + kFive7, kFive8, kFive9, kFive10, kFive11, kFive12 }; + + ASSERT(exponent >= 0); + if (exponent == 0) return; + if (used_digits_ == 0) return; + int remaining_exponent = exponent; + while (remaining_exponent >= 27) { + MultiplyByUInt64(kFive27); + remaining_exponent -= 27; + } + while (remaining_exponent >= 13) { + MultiplyByUInt32(kFive13); + remaining_exponent -= 13; + } + if (remaining_exponent > 0) { + MultiplyByUInt32(kFive1_to_12[remaining_exponent - 1]); + } + ShiftLeft(exponent); + } + + inline void Bignum::Square() { + ASSERT(IsClamped()); + int product_length = 2 * used_digits_; + EnsureCapacity(product_length); + + if ((1 << (2 * (kChunkSize - kBigitSize))) <= used_digits_) { + UNIMPLEMENTED(); + } + DoubleChunk accumulator = 0; + int copy_offset = used_digits_; + for (int i = 0; i < used_digits_; ++i) { + bigits_[copy_offset + i] = bigits_[i]; + } + for (int i = 0; i < used_digits_; ++i) { + int bigit_index1 = i; + int bigit_index2 = 0; + while (bigit_index1 >= 0) { + Chunk chunk1 = bigits_[copy_offset + bigit_index1]; + Chunk chunk2 = bigits_[copy_offset + bigit_index2]; + accumulator += static_cast(chunk1) * chunk2; + bigit_index1--; + bigit_index2++; + } + bigits_[i] = static_cast(accumulator) & kBigitMask; + accumulator >>= kBigitSize; + } + for (int i = used_digits_; i < product_length; ++i) { + int bigit_index1 = used_digits_ - 1; + int bigit_index2 = i - bigit_index1; + while (bigit_index2 < used_digits_) { + Chunk chunk1 = bigits_[copy_offset + bigit_index1]; + Chunk chunk2 = bigits_[copy_offset + bigit_index2]; + accumulator += static_cast(chunk1) * chunk2; + bigit_index1--; + bigit_index2++; + } + bigits_[i] = static_cast(accumulator) & kBigitMask; + accumulator >>= kBigitSize; + } + ASSERT(accumulator == 0); + used_digits_ = product_length; + exponent_ *= 2; + Clamp(); + } + + inline void Bignum::AssignPowerUInt16(uint16_t base, int power_exponent) { + ASSERT(base != 0); + ASSERT(power_exponent >= 0); + if (power_exponent == 0) { + AssignUInt16(1); + return; + } + Zero(); + int shifts = 0; + while ((base & 1) == 0) { + base >>= 1; + shifts++; + } + int bit_size = 0; + int tmp_base = base; + while (tmp_base != 0) { + tmp_base >>= 1; + bit_size++; + } + int final_size = bit_size * power_exponent; + EnsureCapacity(final_size / kBigitSize + 2); + int mask = 1; + while (power_exponent >= mask) mask <<= 1; + mask >>= 2; + uint64_t this_value = base; + bool delayed_multipliciation = false; + const uint64_t max_32bits = 0xFFFFFFFF; + while (mask != 0 && this_value <= max_32bits) { + this_value = this_value * this_value; + if ((power_exponent & mask) != 0) { + uint64_t base_bits_mask = + ~((static_cast(1) << (64 - bit_size)) - 1); + bool high_bits_zero = (this_value & base_bits_mask) == 0; + if (high_bits_zero) { + this_value *= base; + } else { + delayed_multipliciation = true; + } + } + mask >>= 1; + } + AssignUInt64(this_value); + if (delayed_multipliciation) { + MultiplyByUInt32(base); + } + while (mask != 0) { + Square(); + if ((power_exponent & mask) != 0) { + MultiplyByUInt32(base); + } + mask >>= 1; + } + ShiftLeft(shifts * power_exponent); + } + + inline uint16_t Bignum::DivideModuloIntBignum(const Bignum& other) { + ASSERT(IsClamped()); + ASSERT(other.IsClamped()); + ASSERT(other.used_digits_ > 0); + + if (BigitLength() < other.BigitLength()) { + return 0; + } + Align(other); + + uint16_t result = 0; + + while (BigitLength() > other.BigitLength()) { + ASSERT(other.bigits_[other.used_digits_ - 1] >= ((1 << kBigitSize) / 16)); + ASSERT(bigits_[used_digits_ - 1] < 0x10000); + result += static_cast(bigits_[used_digits_ - 1]); + SubtractTimes(other, bigits_[used_digits_ - 1]); + } + ASSERT(BigitLength() == other.BigitLength()); + + Chunk this_bigit = bigits_[used_digits_ - 1]; + Chunk other_bigit = other.bigits_[other.used_digits_ - 1]; + + if (other.used_digits_ == 1) { + int quotient = this_bigit / other_bigit; + bigits_[used_digits_ - 1] = this_bigit - other_bigit * quotient; + ASSERT(quotient < 0x10000); + result += static_cast(quotient); + Clamp(); + return result; + } + int division_estimate = this_bigit / (other_bigit + 1); + ASSERT(division_estimate < 0x10000); + result += static_cast(division_estimate); + SubtractTimes(other, division_estimate); + + if (other_bigit * (division_estimate + 1) > this_bigit) { + return result; + } + while (LessEqual(other, *this)) { + SubtractBignum(other); + result++; + } + return result; + } + + template + inline int SizeInHexChars(S number) { + ASSERT(number > 0); + int result = 0; + while (number != 0) { + number >>= 4; + result++; + } + return result; + } + + inline char HexCharOfValue(int value) { + ASSERT(0 <= value && value <= 16); + if (value < 10) return static_cast(value + '0'); + return static_cast(value - 10 + 'A'); + } + + inline bool Bignum::ToHexString(char* buffer, int buffer_size) const { + ASSERT(IsClamped()); + ASSERT(kBigitSize % 4 == 0); + const int kHexCharsPerBigit = kBigitSize / 4; + + if (used_digits_ == 0) { + if (buffer_size < 2) return false; + buffer[0] = '0'; + buffer[1] = '\0'; + return true; + } + int needed_chars = (BigitLength() - 1) * kHexCharsPerBigit + + SizeInHexChars(bigits_[used_digits_ - 1]) + 1; + if (needed_chars > buffer_size) return false; + int string_index = needed_chars - 1; + buffer[string_index--] = '\0'; + for (int i = 0; i < exponent_; ++i) { + for (int j = 0; j < kHexCharsPerBigit; ++j) { + buffer[string_index--] = '0'; + } + } + for (int i = 0; i < used_digits_ - 1; ++i) { + Chunk current_bigit = bigits_[i]; + for (int j = 0; j < kHexCharsPerBigit; ++j) { + buffer[string_index--] = HexCharOfValue(current_bigit & 0xF); + current_bigit >>= 4; + } + } + Chunk most_significant_bigit = bigits_[used_digits_ - 1]; + while (most_significant_bigit != 0) { + buffer[string_index--] = HexCharOfValue(most_significant_bigit & 0xF); + most_significant_bigit >>= 4; + } + return true; + } + + inline Bignum::Chunk Bignum::BigitAt(int index) const { + if (index >= BigitLength()) return 0; + if (index < exponent_) return 0; + return bigits_[index - exponent_]; + } + + inline int Bignum::Compare(const Bignum& a, const Bignum& b) { + ASSERT(a.IsClamped()); + ASSERT(b.IsClamped()); + int bigit_length_a = a.BigitLength(); + int bigit_length_b = b.BigitLength(); + if (bigit_length_a < bigit_length_b) return -1; + if (bigit_length_a > bigit_length_b) return +1; + for (int i = bigit_length_a - 1; i >= Min(a.exponent_, b.exponent_); --i) { + Chunk bigit_a = a.BigitAt(i); + Chunk bigit_b = b.BigitAt(i); + if (bigit_a < bigit_b) return -1; + if (bigit_a > bigit_b) return +1; + } + return 0; + } + + inline int Bignum::PlusCompare(const Bignum& a, const Bignum& b, const Bignum& c) { + ASSERT(a.IsClamped()); + ASSERT(b.IsClamped()); + ASSERT(c.IsClamped()); + if (a.BigitLength() < b.BigitLength()) { + return PlusCompare(b, a, c); + } + if (a.BigitLength() + 1 < c.BigitLength()) return -1; + if (a.BigitLength() > c.BigitLength()) return +1; + if (a.exponent_ >= b.BigitLength() && a.BigitLength() < c.BigitLength()) { + return -1; + } + Chunk borrow = 0; + int min_exponent = Min(Min(a.exponent_, b.exponent_), c.exponent_); + for (int i = c.BigitLength() - 1; i >= min_exponent; --i) { + Chunk chunk_a = a.BigitAt(i); + Chunk chunk_b = b.BigitAt(i); + Chunk chunk_c = c.BigitAt(i); + Chunk sum = chunk_a + chunk_b; + if (sum > chunk_c + borrow) { + return +1; + } else { + borrow = chunk_c + borrow - sum; + if (borrow > 1) return -1; + borrow <<= kBigitSize; + } + } + if (borrow == 0) return 0; + return -1; + } + + inline void Bignum::Clamp() { + while (used_digits_ > 0 && bigits_[used_digits_ - 1] == 0) { + used_digits_--; + } + if (used_digits_ == 0) { + exponent_ = 0; + } + } + + inline bool Bignum::IsClamped() const { + return used_digits_ == 0 || bigits_[used_digits_ - 1] != 0; + } + + inline void Bignum::Zero() { + for (int i = 0; i < used_digits_; ++i) { + bigits_[i] = 0; + } + used_digits_ = 0; + exponent_ = 0; + } + + inline void Bignum::Align(const Bignum& other) { + if (exponent_ > other.exponent_) { + int zero_digits = exponent_ - other.exponent_; + EnsureCapacity(used_digits_ + zero_digits); + for (int i = used_digits_ - 1; i >= 0; --i) { + bigits_[i + zero_digits] = bigits_[i]; + } + for (int i = 0; i < zero_digits; ++i) { + bigits_[i] = 0; + } + used_digits_ += zero_digits; + exponent_ -= zero_digits; + ASSERT(used_digits_ >= 0); + ASSERT(exponent_ >= 0); + } + } + + inline void Bignum::BigitsShiftLeft(int shift_amount) { + ASSERT(shift_amount < kBigitSize); + ASSERT(shift_amount >= 0); + Chunk carry = 0; + for (int i = 0; i < used_digits_; ++i) { + Chunk new_carry = bigits_[i] >> (kBigitSize - shift_amount); + bigits_[i] = ((bigits_[i] << shift_amount) + carry) & kBigitMask; + carry = new_carry; + } + if (carry != 0) { + bigits_[used_digits_] = carry; + used_digits_++; + } + } + + inline void Bignum::SubtractTimes(const Bignum& other, int factor) { + ASSERT(exponent_ <= other.exponent_); + if (factor < 3) { + for (int i = 0; i < factor; ++i) { + SubtractBignum(other); + } + return; + } + Chunk borrow = 0; + int exponent_diff = other.exponent_ - exponent_; + for (int i = 0; i < other.used_digits_; ++i) { + DoubleChunk product = static_cast(factor) * other.bigits_[i]; + DoubleChunk remove = borrow + product; + Chunk difference = bigits_[i + exponent_diff] - (remove & kBigitMask); + bigits_[i + exponent_diff] = difference & kBigitMask; + borrow = static_cast((difference >> (kChunkSize - 1)) + + (remove >> kBigitSize)); + } + for (int i = other.used_digits_ + exponent_diff; i < used_digits_; ++i) { + if (borrow == 0) return; + Chunk difference = bigits_[i] - borrow; + bigits_[i] = difference & kBigitMask; + borrow = difference >> (kChunkSize - 1); + } + Clamp(); + } + + class DiyFp + { + public: + static const int kSignificandSize = 64; + + DiyFp() : f_(0), e_(0) {} + DiyFp(uint64_t significand, int exponent) : f_(significand), e_(exponent) {} + + void Subtract(const DiyFp& other) { + ASSERT(e_ == other.e_); + ASSERT(f_ >= other.f_); + f_ -= other.f_; + } + + static DiyFp Minus(const DiyFp& a, const DiyFp& b) { + DiyFp result = a; + result.Subtract(b); + return result; + } + + void Multiply(const DiyFp& other) + { + const uint64_t kM32 = 0xFFFFFFFFU; + uint64_t a = f_ >> 32; + uint64_t b = f_ & kM32; + uint64_t c = other.f_ >> 32; + uint64_t d = other.f_ & kM32; + uint64_t ac = a * c; + uint64_t bc = b * c; + uint64_t ad = a * d; + uint64_t bd = b * d; + uint64_t tmp = (bd >> 32) + (ad & kM32) + (bc & kM32); + tmp += 1U << 31; + uint64_t result_f = ac + (ad >> 32) + (bc >> 32) + (tmp >> 32); + e_ += other.e_ + 64; + f_ = result_f; + } + + static DiyFp Times(const DiyFp& a, const DiyFp& b) + { + DiyFp result = a; + result.Multiply(b); + return result; + } + + void Normalize() { + ASSERT(f_ != 0); + uint64_t significand = f_; + int exponent = e_; + + const uint64_t k10MSBits = UINT64_2PART_C(0xFFC00000, 00000000); + while ((significand & k10MSBits) == 0) { + significand <<= 10; + exponent -= 10; + } + while ((significand & kUint64MSB) == 0) { + significand <<= 1; + exponent--; + } + f_ = significand; + e_ = exponent; + } + + static DiyFp Normalize(const DiyFp& a) { + DiyFp result = a; + result.Normalize(); + return result; + } + + uint64_t f() const { return f_; } + int e() const { return e_; } + + void set_f(uint64_t new_value) { f_ = new_value; } + void set_e(int new_value) { e_ = new_value; } + + private: + static const uint64_t kUint64MSB = UINT64_2PART_C(0x80000000, 00000000); + + uint64_t f_; + int e_; + }; + + static uint64_t double_to_uint64(double d) { return BitCast(d); } + static double uint64_to_double(uint64_t d64) { return BitCast(d64); } + + class Double { + public: + static const uint64_t kSignMask = UINT64_2PART_C(0x80000000, 00000000); + static const uint64_t kExponentMask = UINT64_2PART_C(0x7FF00000, 00000000); + static const uint64_t kSignificandMask = UINT64_2PART_C(0x000FFFFF, FFFFFFFF); + static const uint64_t kHiddenBit = UINT64_2PART_C(0x00100000, 00000000); + static const int kPhysicalSignificandSize = 52; + static const int kSignificandSize = 53; + + Double() : d64_(0) {} + explicit Double(double d) : d64_(double_to_uint64(d)) {} + explicit Double(uint64_t d64) : d64_(d64) {} + explicit Double(DiyFp diy_fp) + : d64_(DiyFpToUint64(diy_fp)) {} + + DiyFp AsDiyFp() const { + ASSERT(Sign() > 0); + ASSERT(!IsSpecial()); + return DiyFp(Significand(), Exponent()); + } + + DiyFp AsNormalizedDiyFp() const { + ASSERT(value() > 0.0); + uint64_t f = Significand(); + int e = Exponent(); + + while ((f & kHiddenBit) == 0) { + f <<= 1; + e--; + } + f <<= DiyFp::kSignificandSize - kSignificandSize; + e -= DiyFp::kSignificandSize - kSignificandSize; + return DiyFp(f, e); + } + + uint64_t AsUint64() const { + return d64_; + } + + double NextDouble() const { + if (d64_ == kInfinity) return Double(kInfinity).value(); + if (Sign() < 0 && Significand() == 0) { + return 0.0; + } + if (Sign() < 0) { + return Double(d64_ - 1).value(); + } else { + return Double(d64_ + 1).value(); + } + } + + double PreviousDouble() const { + if (d64_ == (kInfinity | kSignMask)) return -Double::Infinity(); + if (Sign() < 0) { + return Double(d64_ + 1).value(); + } else { + if (Significand() == 0) return -0.0; + return Double(d64_ - 1).value(); + } + } + + int Exponent() const { + if (IsDenormal()) return kDenormalExponent; + + uint64_t d64 = AsUint64(); + int biased_e = + static_cast((d64 & kExponentMask) >> kPhysicalSignificandSize); + return biased_e - kExponentBias; + } + + uint64_t Significand() const { + uint64_t d64 = AsUint64(); + uint64_t significand = d64 & kSignificandMask; + if (!IsDenormal()) { + return significand + kHiddenBit; + } else { + return significand; + } + } + + bool IsDenormal() const { + uint64_t d64 = AsUint64(); + return (d64 & kExponentMask) == 0; + } + + bool IsSpecial() const { + uint64_t d64 = AsUint64(); + return (d64 & kExponentMask) == kExponentMask; + } + + bool IsNan() const { + uint64_t d64 = AsUint64(); + return ((d64 & kExponentMask) == kExponentMask) && + ((d64 & kSignificandMask) != 0); + } + + bool IsInfinite() const { + uint64_t d64 = AsUint64(); + return ((d64 & kExponentMask) == kExponentMask) && + ((d64 & kSignificandMask) == 0); + } + + int Sign() const { + uint64_t d64 = AsUint64(); + return (d64 & kSignMask) == 0? 1: -1; + } + + DiyFp UpperBoundary() const { + ASSERT(Sign() > 0); + return DiyFp(Significand() * 2 + 1, Exponent() - 1); + } + + void NormalizedBoundaries(DiyFp* out_m_minus, DiyFp* out_m_plus) const { + ASSERT(value() > 0.0); + DiyFp v = this->AsDiyFp(); + DiyFp m_plus = DiyFp::Normalize(DiyFp((v.f() << 1) + 1, v.e() - 1)); + DiyFp m_minus; + if (LowerBoundaryIsCloser()) { + m_minus = DiyFp((v.f() << 2) - 1, v.e() - 2); + } else { + m_minus = DiyFp((v.f() << 1) - 1, v.e() - 1); + } + m_minus.set_f(m_minus.f() << (m_minus.e() - m_plus.e())); + m_minus.set_e(m_plus.e()); + *out_m_plus = m_plus; + *out_m_minus = m_minus; + } + + bool LowerBoundaryIsCloser() const { + bool physical_significand_is_zero = ((AsUint64() & kSignificandMask) == 0); + return physical_significand_is_zero && (Exponent() != kDenormalExponent); + } + + double value() const { return uint64_to_double(d64_); } + + static int SignificandSizeForOrderOfMagnitude(int order) { + if (order >= (kDenormalExponent + kSignificandSize)) { + return kSignificandSize; + } + if (order <= kDenormalExponent) return 0; + return order - kDenormalExponent; + } + + static double Infinity() { + return Double(kInfinity).value(); + } + + static double NaN() { + return Double(kNaN).value(); + } + + private: + static const int kExponentBias = 0x3FF + kPhysicalSignificandSize; + static const int kDenormalExponent = -kExponentBias + 1; + static const int kMaxExponent = 0x7FF - kExponentBias; + static const uint64_t kInfinity = UINT64_2PART_C(0x7FF00000, 00000000); + static const uint64_t kNaN = UINT64_2PART_C(0x7FF80000, 00000000); + + const uint64_t d64_; + + static uint64_t DiyFpToUint64(DiyFp diy_fp) { + uint64_t significand = diy_fp.f(); + int exponent = diy_fp.e(); + while (significand > kHiddenBit + kSignificandMask) { + significand >>= 1; + exponent++; + } + if (exponent >= kMaxExponent) { + return kInfinity; + } + if (exponent < kDenormalExponent) { + return 0; + } + while (exponent > kDenormalExponent && (significand & kHiddenBit) == 0) { + significand <<= 1; + exponent--; + } + uint64_t biased_exponent; + if (exponent == kDenormalExponent && (significand & kHiddenBit) == 0) { + biased_exponent = 0; + } else { + biased_exponent = static_cast(exponent + kExponentBias); + } + return (significand & kSignificandMask) | + (biased_exponent << kPhysicalSignificandSize); + } + + DISALLOW_COPY_AND_ASSIGN(Double); + }; + + struct PowersOfTenCache + { + static const int kDecimalExponentDistance = 8; + + static const int kMinDecimalExponent = -348; + static const int kMaxDecimalExponent = 340; + + static void GetCachedPowerForBinaryExponentRange(int min_exponent, + int max_exponent, + DiyFp* power, + int* decimal_exponent); + + static void GetCachedPowerForDecimalExponent(int requested_exponent, + DiyFp* power, + int* found_exponent); + }; + + struct CachedPower { + uint64_t significand; + int16_t binary_exponent; + int16_t decimal_exponent; + }; + + static const CachedPower kCachedPowers[] = { + {UINT64_2PART_C(0xfa8fd5a0, 081c0288), -1220, -348}, + {UINT64_2PART_C(0xbaaee17f, a23ebf76), -1193, -340}, + {UINT64_2PART_C(0x8b16fb20, 3055ac76), -1166, -332}, + {UINT64_2PART_C(0xcf42894a, 5dce35ea), -1140, -324}, + {UINT64_2PART_C(0x9a6bb0aa, 55653b2d), -1113, -316}, + {UINT64_2PART_C(0xe61acf03, 3d1a45df), -1087, -308}, + {UINT64_2PART_C(0xab70fe17, c79ac6ca), -1060, -300}, + {UINT64_2PART_C(0xff77b1fc, bebcdc4f), -1034, -292}, + {UINT64_2PART_C(0xbe5691ef, 416bd60c), -1007, -284}, + {UINT64_2PART_C(0x8dd01fad, 907ffc3c), -980, -276}, + {UINT64_2PART_C(0xd3515c28, 31559a83), -954, -268}, + {UINT64_2PART_C(0x9d71ac8f, ada6c9b5), -927, -260}, + {UINT64_2PART_C(0xea9c2277, 23ee8bcb), -901, -252}, + {UINT64_2PART_C(0xaecc4991, 4078536d), -874, -244}, + {UINT64_2PART_C(0x823c1279, 5db6ce57), -847, -236}, + {UINT64_2PART_C(0xc2109436, 4dfb5637), -821, -228}, + {UINT64_2PART_C(0x9096ea6f, 3848984f), -794, -220}, + {UINT64_2PART_C(0xd77485cb, 25823ac7), -768, -212}, + {UINT64_2PART_C(0xa086cfcd, 97bf97f4), -741, -204}, + {UINT64_2PART_C(0xef340a98, 172aace5), -715, -196}, + {UINT64_2PART_C(0xb23867fb, 2a35b28e), -688, -188}, + {UINT64_2PART_C(0x84c8d4df, d2c63f3b), -661, -180}, + {UINT64_2PART_C(0xc5dd4427, 1ad3cdba), -635, -172}, + {UINT64_2PART_C(0x936b9fce, bb25c996), -608, -164}, + {UINT64_2PART_C(0xdbac6c24, 7d62a584), -582, -156}, + {UINT64_2PART_C(0xa3ab6658, 0d5fdaf6), -555, -148}, + {UINT64_2PART_C(0xf3e2f893, dec3f126), -529, -140}, + {UINT64_2PART_C(0xb5b5ada8, aaff80b8), -502, -132}, + {UINT64_2PART_C(0x87625f05, 6c7c4a8b), -475, -124}, + {UINT64_2PART_C(0xc9bcff60, 34c13053), -449, -116}, + {UINT64_2PART_C(0x964e858c, 91ba2655), -422, -108}, + {UINT64_2PART_C(0xdff97724, 70297ebd), -396, -100}, + {UINT64_2PART_C(0xa6dfbd9f, b8e5b88f), -369, -92}, + {UINT64_2PART_C(0xf8a95fcf, 88747d94), -343, -84}, + {UINT64_2PART_C(0xb9447093, 8fa89bcf), -316, -76}, + {UINT64_2PART_C(0x8a08f0f8, bf0f156b), -289, -68}, + {UINT64_2PART_C(0xcdb02555, 653131b6), -263, -60}, + {UINT64_2PART_C(0x993fe2c6, d07b7fac), -236, -52}, + {UINT64_2PART_C(0xe45c10c4, 2a2b3b06), -210, -44}, + {UINT64_2PART_C(0xaa242499, 697392d3), -183, -36}, + {UINT64_2PART_C(0xfd87b5f2, 8300ca0e), -157, -28}, + {UINT64_2PART_C(0xbce50864, 92111aeb), -130, -20}, + {UINT64_2PART_C(0x8cbccc09, 6f5088cc), -103, -12}, + {UINT64_2PART_C(0xd1b71758, e219652c), -77, -4}, + {UINT64_2PART_C(0x9c400000, 00000000), -50, 4}, + {UINT64_2PART_C(0xe8d4a510, 00000000), -24, 12}, + {UINT64_2PART_C(0xad78ebc5, ac620000), 3, 20}, + {UINT64_2PART_C(0x813f3978, f8940984), 30, 28}, + {UINT64_2PART_C(0xc097ce7b, c90715b3), 56, 36}, + {UINT64_2PART_C(0x8f7e32ce, 7bea5c70), 83, 44}, + {UINT64_2PART_C(0xd5d238a4, abe98068), 109, 52}, + {UINT64_2PART_C(0x9f4f2726, 179a2245), 136, 60}, + {UINT64_2PART_C(0xed63a231, d4c4fb27), 162, 68}, + {UINT64_2PART_C(0xb0de6538, 8cc8ada8), 189, 76}, + {UINT64_2PART_C(0x83c7088e, 1aab65db), 216, 84}, + {UINT64_2PART_C(0xc45d1df9, 42711d9a), 242, 92}, + {UINT64_2PART_C(0x924d692c, a61be758), 269, 100}, + {UINT64_2PART_C(0xda01ee64, 1a708dea), 295, 108}, + {UINT64_2PART_C(0xa26da399, 9aef774a), 322, 116}, + {UINT64_2PART_C(0xf209787b, b47d6b85), 348, 124}, + {UINT64_2PART_C(0xb454e4a1, 79dd1877), 375, 132}, + {UINT64_2PART_C(0x865b8692, 5b9bc5c2), 402, 140}, + {UINT64_2PART_C(0xc83553c5, c8965d3d), 428, 148}, + {UINT64_2PART_C(0x952ab45c, fa97a0b3), 455, 156}, + {UINT64_2PART_C(0xde469fbd, 99a05fe3), 481, 164}, + {UINT64_2PART_C(0xa59bc234, db398c25), 508, 172}, + {UINT64_2PART_C(0xf6c69a72, a3989f5c), 534, 180}, + {UINT64_2PART_C(0xb7dcbf53, 54e9bece), 561, 188}, + {UINT64_2PART_C(0x88fcf317, f22241e2), 588, 196}, + {UINT64_2PART_C(0xcc20ce9b, d35c78a5), 614, 204}, + {UINT64_2PART_C(0x98165af3, 7b2153df), 641, 212}, + {UINT64_2PART_C(0xe2a0b5dc, 971f303a), 667, 220}, + {UINT64_2PART_C(0xa8d9d153, 5ce3b396), 694, 228}, + {UINT64_2PART_C(0xfb9b7cd9, a4a7443c), 720, 236}, + {UINT64_2PART_C(0xbb764c4c, a7a44410), 747, 244}, + {UINT64_2PART_C(0x8bab8eef, b6409c1a), 774, 252}, + {UINT64_2PART_C(0xd01fef10, a657842c), 800, 260}, + {UINT64_2PART_C(0x9b10a4e5, e9913129), 827, 268}, + {UINT64_2PART_C(0xe7109bfb, a19c0c9d), 853, 276}, + {UINT64_2PART_C(0xac2820d9, 623bf429), 880, 284}, + {UINT64_2PART_C(0x80444b5e, 7aa7cf85), 907, 292}, + {UINT64_2PART_C(0xbf21e440, 03acdd2d), 933, 300}, + {UINT64_2PART_C(0x8e679c2f, 5e44ff8f), 960, 308}, + {UINT64_2PART_C(0xd433179d, 9c8cb841), 986, 316}, + {UINT64_2PART_C(0x9e19db92, b4e31ba9), 1013, 324}, + {UINT64_2PART_C(0xeb96bf6e, badf77d9), 1039, 332}, + {UINT64_2PART_C(0xaf87023b, 9bf0ee6b), 1066, 340}, + }; + + static const int kCachedPowersLength = GDCV8_ARRAY_SIZE(kCachedPowers); + static const int kCachedPowersOffset = 348; + static const double kD_1_LOG2_10 = 0.30102999566398114; + + inline void PowersOfTenCache::GetCachedPowerForBinaryExponentRange( + int min_exponent, + int max_exponent, + DiyFp* power, + int* decimal_exponent) { + int kQ = DiyFp::kSignificandSize; + double k = ceil((min_exponent + kQ - 1) * kD_1_LOG2_10); + int foo = kCachedPowersOffset; + int index = + (foo + static_cast(k) - 1) / kDecimalExponentDistance + 1; + ASSERT(0 <= index && index < kCachedPowersLength); + CachedPower cached_power = kCachedPowers[index]; + ASSERT(min_exponent <= cached_power.binary_exponent); + (void) max_exponent; + ASSERT(cached_power.binary_exponent <= max_exponent); + *decimal_exponent = cached_power.decimal_exponent; + *power = DiyFp(cached_power.significand, cached_power.binary_exponent); + } + + inline void PowersOfTenCache::GetCachedPowerForDecimalExponent(int requested_exponent, + DiyFp* power, + int* found_exponent) { + ASSERT(kMinDecimalExponent <= requested_exponent); + ASSERT(requested_exponent < kMaxDecimalExponent + kDecimalExponentDistance); + int index = + (requested_exponent + kCachedPowersOffset) / kDecimalExponentDistance; + CachedPower cached_power = kCachedPowers[index]; + *power = DiyFp(cached_power.significand, cached_power.binary_exponent); + *found_exponent = cached_power.decimal_exponent; + ASSERT(*found_exponent <= requested_exponent); + ASSERT(requested_exponent < *found_exponent + kDecimalExponentDistance); + } + + static const int kMaxExactDoubleIntegerDecimalDigits = 15; + static const int kMaxUint64DecimalDigits = 19; + + static const int kMaxDecimalPower = 309; + static const int kMinDecimalPower = -324; + + static const uint64_t kMaxUint64 = UINT64_2PART_C(0xFFFFFFFF, FFFFFFFF); + + static const double exact_powers_of_ten[] = { + 1.0, // 10^0 + 10.0, + 100.0, + 1000.0, + 10000.0, + 100000.0, + 1000000.0, + 10000000.0, + 100000000.0, + 1000000000.0, + 10000000000.0, // 10^10 + 100000000000.0, + 1000000000000.0, + 10000000000000.0, + 100000000000000.0, + 1000000000000000.0, + 10000000000000000.0, + 100000000000000000.0, + 1000000000000000000.0, + 10000000000000000000.0, + 100000000000000000000.0, // 10^20 + 1000000000000000000000.0, + 10000000000000000000000.0 + }; + + static const int kExactPowersOfTenSize = GDCV8_ARRAY_SIZE(exact_powers_of_ten); + static const int kMaxSignificantDecimalDigits = 780; + + inline Vector TrimLeadingZeros(Vector buffer) { + for (int i = 0; i < buffer.length(); i++) { + if (buffer[i] != '0') { + return buffer.SubVector(i, buffer.length()); + } + } + return Vector(buffer.start(), 0); + } + + inline Vector TrimTrailingZeros(Vector buffer) { + for (int i = buffer.length() - 1; i >= 0; --i) { + if (buffer[i] != '0') { + return buffer.SubVector(0, i + 1); + } + } + return Vector(buffer.start(), 0); + } + + inline void CutToMaxSignificantDigits(Vector buffer, + int exponent, + char* significant_buffer, + int* significant_exponent) { + for (int i = 0; i < kMaxSignificantDecimalDigits - 1; ++i) { + significant_buffer[i] = buffer[i]; + } + ASSERT(buffer[buffer.length() - 1] != '0'); + significant_buffer[kMaxSignificantDecimalDigits - 1] = '1'; + *significant_exponent = + exponent + (buffer.length() - kMaxSignificantDecimalDigits); + } + + inline void TrimAndCut(Vector buffer, int exponent, + char* buffer_copy_space, int space_size, + Vector* trimmed, int* updated_exponent) { + Vector right_trimmed = TrimTrailingZeros(buffer); + exponent -= right_trimmed.length(); + if (right_trimmed.length() > kMaxSignificantDecimalDigits) { + (void) space_size; + ASSERT(space_size >= kMaxSignificantDecimalDigits); + CutToMaxSignificantDigits(right_trimmed, exponent, + buffer_copy_space, updated_exponent); + *trimmed = Vector(buffer_copy_space, + kMaxSignificantDecimalDigits); + } else { + *trimmed = right_trimmed; + *updated_exponent = exponent; + } + } + + inline uint64_t ReadUint64(Vector buffer, + int* number_of_read_digits) { + uint64_t result = 0; + int i = 0; + while (i < buffer.length() && result <= (kMaxUint64 / 10 - 1)) { + int digit = buffer[i++] - '0'; + ASSERT(0 <= digit && digit <= 9); + result = 10 * result + digit; + } + *number_of_read_digits = i; + return result; + } + + inline void ReadDiyFp(Vector buffer, + DiyFp* result, + int* remaining_decimals) { + int read_digits; + uint64_t significand = ReadUint64(buffer, &read_digits); + if (buffer.length() == read_digits) { + *result = DiyFp(significand, 0); + *remaining_decimals = 0; + } else { + if (buffer[read_digits] >= '5') { + significand++; + } + int exponent = 0; + *result = DiyFp(significand, exponent); + *remaining_decimals = buffer.length() - read_digits; + } + } + + inline bool DoubleStrtod(Vector trimmed, + int exponent, + double* result) { +#if !defined(DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS) + // On x86 the floating-point stack can be 64 or 80 bits wide. If it is + // 80 bits wide (as is the case on Linux) then double-rounding occurs and the + // result is not accurate. + // We know that Windows32 uses 64 bits and is therefore accurate. + // Note that the ARM simulator is compiled for 32bits. It therefore exhibits + // the same problem. + return false; +#endif + if (trimmed.length() <= kMaxExactDoubleIntegerDecimalDigits) { + int read_digits; + if (exponent < 0 && -exponent < kExactPowersOfTenSize) { + *result = static_cast(ReadUint64(trimmed, &read_digits)); + ASSERT(read_digits == trimmed.length()); + *result /= exact_powers_of_ten[-exponent]; + return true; + } + if (0 <= exponent && exponent < kExactPowersOfTenSize) { + *result = static_cast(ReadUint64(trimmed, &read_digits)); + ASSERT(read_digits == trimmed.length()); + *result *= exact_powers_of_ten[exponent]; + return true; + } + int remaining_digits = + kMaxExactDoubleIntegerDecimalDigits - trimmed.length(); + if ((0 <= exponent) && + (exponent - remaining_digits < kExactPowersOfTenSize)) { + *result = static_cast(ReadUint64(trimmed, &read_digits)); + ASSERT(read_digits == trimmed.length()); + *result *= exact_powers_of_ten[remaining_digits]; + *result *= exact_powers_of_ten[exponent - remaining_digits]; + return true; + } + } + return false; + } + + inline DiyFp AdjustmentPowerOfTen(int exponent) { + ASSERT(0 < exponent); + ASSERT(exponent < PowersOfTenCache::kDecimalExponentDistance); + ASSERT(PowersOfTenCache::kDecimalExponentDistance == 8); + switch (exponent) { + case 1: return DiyFp(UINT64_2PART_C(0xa0000000, 00000000), -60); + case 2: return DiyFp(UINT64_2PART_C(0xc8000000, 00000000), -57); + case 3: return DiyFp(UINT64_2PART_C(0xfa000000, 00000000), -54); + case 4: return DiyFp(UINT64_2PART_C(0x9c400000, 00000000), -50); + case 5: return DiyFp(UINT64_2PART_C(0xc3500000, 00000000), -47); + case 6: return DiyFp(UINT64_2PART_C(0xf4240000, 00000000), -44); + case 7: return DiyFp(UINT64_2PART_C(0x98968000, 00000000), -40); + default: + UNREACHABLE(); + } + } + + inline bool DiyFpStrtod(Vector buffer, + int exponent, + double* result) { + DiyFp input; + int remaining_decimals; + ReadDiyFp(buffer, &input, &remaining_decimals); + const int kDenominatorLog = 3; + const int kDenominator = 1 << kDenominatorLog; + exponent += remaining_decimals; + uint64_t error = (remaining_decimals == 0 ? 0 : kDenominator / 2); + + int old_e = input.e(); + input.Normalize(); + error <<= old_e - input.e(); + + ASSERT(exponent <= PowersOfTenCache::kMaxDecimalExponent); + if (exponent < PowersOfTenCache::kMinDecimalExponent) { + *result = 0.0; + return true; + } + DiyFp cached_power; + int cached_decimal_exponent; + PowersOfTenCache::GetCachedPowerForDecimalExponent(exponent, + &cached_power, + &cached_decimal_exponent); + + if (cached_decimal_exponent != exponent) { + int adjustment_exponent = exponent - cached_decimal_exponent; + DiyFp adjustment_power = AdjustmentPowerOfTen(adjustment_exponent); + input.Multiply(adjustment_power); + if (kMaxUint64DecimalDigits - buffer.length() >= adjustment_exponent) { + ASSERT(DiyFp::kSignificandSize == 64); + } else { + error += kDenominator / 2; + } + } + + input.Multiply(cached_power); + int error_b = kDenominator / 2; + int error_ab = (error == 0 ? 0 : 1); + int fixed_error = kDenominator / 2; + error += error_b + error_ab + fixed_error; + + old_e = input.e(); + input.Normalize(); + error <<= old_e - input.e(); + + int order_of_magnitude = DiyFp::kSignificandSize + input.e(); + int effective_significand_size = + Double::SignificandSizeForOrderOfMagnitude(order_of_magnitude); + int precision_digits_count = + DiyFp::kSignificandSize - effective_significand_size; + if (precision_digits_count + kDenominatorLog >= DiyFp::kSignificandSize) { + int shift_amount = (precision_digits_count + kDenominatorLog) - + DiyFp::kSignificandSize + 1; + input.set_f(input.f() >> shift_amount); + input.set_e(input.e() + shift_amount); + error = (error >> shift_amount) + 1 + kDenominator; + precision_digits_count -= shift_amount; + } + ASSERT(DiyFp::kSignificandSize == 64); + ASSERT(precision_digits_count < 64); + uint64_t one64 = 1; + uint64_t precision_bits_mask = (one64 << precision_digits_count) - 1; + uint64_t precision_bits = input.f() & precision_bits_mask; + uint64_t half_way = one64 << (precision_digits_count - 1); + precision_bits *= kDenominator; + half_way *= kDenominator; + DiyFp rounded_input(input.f() >> precision_digits_count, + input.e() + precision_digits_count); + if (precision_bits >= half_way + error) { + rounded_input.set_f(rounded_input.f() + 1); + } + *result = Double(rounded_input).value(); + if (half_way - error < precision_bits && precision_bits < half_way + error) { + return false; + } else { + return true; + } + } + + inline int CompareBufferWithDiyFp(Vector buffer, + int exponent, + DiyFp diy_fp) { + ASSERT(buffer.length() + exponent <= kMaxDecimalPower + 1); + ASSERT(buffer.length() + exponent > kMinDecimalPower); + ASSERT(buffer.length() <= kMaxSignificantDecimalDigits); + ASSERT(((kMaxDecimalPower + 1) * 333 / 100) < Bignum::kMaxSignificantBits); + Bignum buffer_bignum; + Bignum diy_fp_bignum; + buffer_bignum.AssignDecimalString(buffer); + diy_fp_bignum.AssignUInt64(diy_fp.f()); + if (exponent >= 0) { + buffer_bignum.MultiplyByPowerOfTen(exponent); + } else { + diy_fp_bignum.MultiplyByPowerOfTen(-exponent); + } + if (diy_fp.e() > 0) { + diy_fp_bignum.ShiftLeft(diy_fp.e()); + } else { + buffer_bignum.ShiftLeft(-diy_fp.e()); + } + return Bignum::Compare(buffer_bignum, diy_fp_bignum); + } + + inline bool ComputeGuess(Vector trimmed, int exponent, + double* guess) { + if (trimmed.length() == 0) { + *guess = 0.0; + return true; + } + if (exponent + trimmed.length() - 1 >= kMaxDecimalPower) { + *guess = Double::Infinity(); + return true; + } + if (exponent + trimmed.length() <= kMinDecimalPower) { + *guess = 0.0; + return true; + } + + if (DoubleStrtod(trimmed, exponent, guess) || + DiyFpStrtod(trimmed, exponent, guess)) { + return true; + } + if (*guess == Double::Infinity()) { + return true; + } + return false; + } + + inline double Strtod( Vector< const char > buffer, int exponent ) + { + double guess; + if (ComputeGuess(buffer, exponent, &guess)) { + return guess; + } + DiyFp upper_boundary = Double(guess).UpperBoundary(); + int comparison = CompareBufferWithDiyFp(buffer, exponent, upper_boundary); + if (comparison < 0) { + return guess; + } else if (comparison > 0) { + return Double(guess).NextDouble(); + } else if ((Double(guess).Significand() & 1) == 0) { + return guess; + } else { + return Double(guess).NextDouble(); + } + } + + namespace + { + const int kBase10MaximalLength = 17; + const int kMaxExponentialDigits = 120; + const int kDecimalRepCapacity = kMaxExponentialDigits + 2; + const int kFastDtoaMaximalLength = 17; + const int kMinimalTargetExponent = -60; + const int kMaximalTargetExponent = -32; + + const unsigned int kSmallPowersOfTen[] = {0, 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000}; + + } // + + inline void BiggestPowerTen(uint32_t number, + int number_bits, + uint32_t* power, + int* exponent_plus_one) { + ASSERT(number < (1u << (number_bits + 1))); + int exponent_plus_one_guess = ((number_bits + 1) * 1233 >> 12); + exponent_plus_one_guess++; + if (number < kSmallPowersOfTen[exponent_plus_one_guess]) { + exponent_plus_one_guess--; + } + *power = kSmallPowersOfTen[exponent_plus_one_guess]; + *exponent_plus_one = exponent_plus_one_guess; + } + + inline bool RoundWeed(Vector buffer, + int length, + uint64_t distance_too_high_w, + uint64_t unsafe_interval, + uint64_t rest, + uint64_t ten_kappa, + uint64_t unit) { + uint64_t small_distance = distance_too_high_w - unit; + uint64_t big_distance = distance_too_high_w + unit; + ASSERT(rest <= unsafe_interval); + while (rest < small_distance && + unsafe_interval - rest >= ten_kappa && + (rest + ten_kappa < small_distance || + small_distance - rest >= rest + ten_kappa - small_distance)) { + buffer[length - 1]--; + rest += ten_kappa; + } + if (rest < big_distance && + unsafe_interval - rest >= ten_kappa && + (rest + ten_kappa < big_distance || + big_distance - rest > rest + ten_kappa - big_distance)) { + return false; + } + return (2 * unit <= rest) && (rest <= unsafe_interval - 4 * unit); + } + + inline bool DigitGen(DiyFp low, + DiyFp w, + DiyFp high, + Vector buffer, + int* length, + int* kappa) { + ASSERT(low.e() == w.e() && w.e() == high.e()); + ASSERT(low.f() + 1 <= high.f() - 1); + ASSERT(kMinimalTargetExponent <= w.e() && w.e() <= kMaximalTargetExponent); + uint64_t unit = 1; + DiyFp too_low = DiyFp(low.f() - unit, low.e()); + DiyFp too_high = DiyFp(high.f() + unit, high.e()); + DiyFp unsafe_interval = DiyFp::Minus(too_high, too_low); + DiyFp one = DiyFp(static_cast(1) << -w.e(), w.e()); + uint32_t integrals = static_cast(too_high.f() >> -one.e()); + uint64_t fractionals = too_high.f() & (one.f() - 1); + uint32_t divisor; + int divisor_exponent_plus_one; + BiggestPowerTen(integrals, DiyFp::kSignificandSize - (-one.e()), + &divisor, &divisor_exponent_plus_one); + *kappa = divisor_exponent_plus_one; + *length = 0; + while (*kappa > 0) { + int digit = integrals / divisor; + ASSERT(digit <= 9); + buffer[*length] = static_cast('0' + digit); + (*length)++; + integrals %= divisor; + (*kappa)--; + uint64_t rest = + (static_cast(integrals) << -one.e()) + fractionals; + if (rest < unsafe_interval.f()) { + return RoundWeed(buffer, *length, DiyFp::Minus(too_high, w).f(), + unsafe_interval.f(), rest, + static_cast(divisor) << -one.e(), unit); + } + divisor /= 10; + } + ASSERT(one.e() >= -60); + ASSERT(fractionals < one.f()); + ASSERT(UINT64_2PART_C(0xFFFFFFFF, FFFFFFFF) / 10 >= one.f()); + for (;;) { + fractionals *= 10; + unit *= 10; + unsafe_interval.set_f(unsafe_interval.f() * 10); + int digit = static_cast(fractionals >> -one.e()); + ASSERT(digit <= 9); + buffer[*length] = static_cast('0' + digit); + (*length)++; + fractionals &= one.f() - 1; + (*kappa)--; + if (fractionals < unsafe_interval.f()) { + return RoundWeed(buffer, *length, DiyFp::Minus(too_high, w).f() * unit, + unsafe_interval.f(), fractionals, one.f(), unit); + } + } + } + + inline bool Grisu3( const double v, + Vector buffer, + int * length, + int * decimal_exponent ) + { + DiyFp w = Double(v).AsNormalizedDiyFp(); + DiyFp boundary_minus, boundary_plus; + Double(v).NormalizedBoundaries(&boundary_minus, &boundary_plus); + ASSERT(boundary_plus.e() == w.e()); + DiyFp ten_mk; + int mk; + int ten_mk_minimal_binary_exponent = + kMinimalTargetExponent - (w.e() + DiyFp::kSignificandSize); + int ten_mk_maximal_binary_exponent = + kMaximalTargetExponent - (w.e() + DiyFp::kSignificandSize); + PowersOfTenCache::GetCachedPowerForBinaryExponentRange(ten_mk_minimal_binary_exponent, + ten_mk_maximal_binary_exponent, + &ten_mk, &mk); + ASSERT((kMinimalTargetExponent <= w.e() + ten_mk.e() + + DiyFp::kSignificandSize) && + (kMaximalTargetExponent >= w.e() + ten_mk.e() + + DiyFp::kSignificandSize)); + DiyFp scaled_w = DiyFp::Times(w, ten_mk); + ASSERT(scaled_w.e() == + boundary_plus.e() + ten_mk.e() + DiyFp::kSignificandSize); + DiyFp scaled_boundary_minus = DiyFp::Times(boundary_minus, ten_mk); + DiyFp scaled_boundary_plus = DiyFp::Times(boundary_plus, ten_mk); + int kappa; + bool result = DigitGen(scaled_boundary_minus, scaled_w, scaled_boundary_plus, + buffer, length, &kappa); + *decimal_exponent = -mk + kappa; + return result; + } + + inline bool FastDtoa( const double v, + Vector< char > buffer, + int * length, + int * decimal_point ) + { + int decimal_exponent = 0; + if ( Grisu3(v, buffer, length, &decimal_exponent) ) { + *decimal_point = *length + decimal_exponent; + buffer[*length] = '\0'; + return true; + } + return false; + } + + static int NormalizedExponent(uint64_t significand, int exponent) { + ASSERT(significand != 0); + while ((significand & Double::kHiddenBit) == 0) { + significand = significand << 1; + exponent = exponent - 1; + } + return exponent; + } + + inline int EstimatePower(int exponent) { + const double k1Log10 = 0.30102999566398114; + const int kSignificandSize = Double::kSignificandSize; + double estimate = ceil((exponent + kSignificandSize - 1) * k1Log10 - 1e-10); + return static_cast(estimate); + } + + inline void InitialScaledStartValuesPositiveExponent(uint64_t significand, int exponent, + int estimated_power, bool need_boundary_deltas, + Bignum* numerator, Bignum* denominator, + Bignum* delta_minus, Bignum* delta_plus) { + ASSERT(estimated_power >= 0); + numerator->AssignUInt64(significand); + numerator->ShiftLeft(exponent); + denominator->AssignPowerUInt16(10, estimated_power); + + if (need_boundary_deltas) { + denominator->ShiftLeft(1); + numerator->ShiftLeft(1); + delta_plus->AssignUInt16(1); + delta_plus->ShiftLeft(exponent); + delta_minus->AssignUInt16(1); + delta_minus->ShiftLeft(exponent); + } + } + + inline void InitialScaledStartValuesNegativeExponentPositivePower( + uint64_t significand, int exponent, + int estimated_power, bool need_boundary_deltas, + Bignum* numerator, Bignum* denominator, + Bignum* delta_minus, Bignum* delta_plus) { + numerator->AssignUInt64(significand); + denominator->AssignPowerUInt16(10, estimated_power); + denominator->ShiftLeft(-exponent); + + if (need_boundary_deltas) { + denominator->ShiftLeft(1); + numerator->ShiftLeft(1); + delta_plus->AssignUInt16(1); + delta_minus->AssignUInt16(1); + } + } + + inline void InitialScaledStartValuesNegativeExponentNegativePower( + uint64_t significand, int exponent, + int estimated_power, bool need_boundary_deltas, + Bignum* numerator, Bignum* denominator, + Bignum* delta_minus, Bignum* delta_plus) { + Bignum* power_ten = numerator; + power_ten->AssignPowerUInt16(10, -estimated_power); + + if (need_boundary_deltas) { + delta_plus->AssignBignum(*power_ten); + delta_minus->AssignBignum(*power_ten); + } + ASSERT(numerator == power_ten); + numerator->MultiplyByUInt64(significand); + denominator->AssignUInt16(1); + denominator->ShiftLeft(-exponent); + + if (need_boundary_deltas) { + numerator->ShiftLeft(1); + denominator->ShiftLeft(1); + } + } + + inline void InitialScaledStartValues(uint64_t significand, + int exponent, + bool lower_boundary_is_closer, + int estimated_power, + bool need_boundary_deltas, + Bignum* numerator, + Bignum* denominator, + Bignum* delta_minus, + Bignum* delta_plus) { + if (exponent >= 0) { + InitialScaledStartValuesPositiveExponent( + significand, exponent, estimated_power, need_boundary_deltas, + numerator, denominator, delta_minus, delta_plus); + } else if (estimated_power >= 0) { + InitialScaledStartValuesNegativeExponentPositivePower( + significand, exponent, estimated_power, need_boundary_deltas, + numerator, denominator, delta_minus, delta_plus); + } else { + InitialScaledStartValuesNegativeExponentNegativePower( + significand, exponent, estimated_power, need_boundary_deltas, + numerator, denominator, delta_minus, delta_plus); + } + if (need_boundary_deltas && lower_boundary_is_closer) { + denominator->ShiftLeft(1); + numerator->ShiftLeft(1); + delta_plus->ShiftLeft(1); + } + } + + inline void GenerateShortestDigits(Bignum* numerator, Bignum* denominator, + Bignum* delta_minus, Bignum* delta_plus, + bool is_even, + Vector buffer, int* length); + + inline void FixupMultiply10(int estimated_power, bool is_even, + int* decimal_point, + Bignum* numerator, Bignum* denominator, + Bignum* delta_minus, Bignum* delta_plus) { + bool in_range; + if (is_even) { + in_range = Bignum::PlusCompare(*numerator, *delta_plus, *denominator) >= 0; + } else { + in_range = Bignum::PlusCompare(*numerator, *delta_plus, *denominator) > 0; + } + if (in_range) { + *decimal_point = estimated_power + 1; + } else { + *decimal_point = estimated_power; + numerator->Times10(); + if (Bignum::Equal(*delta_minus, *delta_plus)) { + delta_minus->Times10(); + delta_plus->AssignBignum(*delta_minus); + } else { + delta_minus->Times10(); + delta_plus->Times10(); + } + } + } + + inline void BignumDtoa(const double v, Vector buffer, int* length, int* decimal_point) { + ASSERT(v > 0); + ASSERT(!Double(v).IsSpecial()); + uint64_t significand; + int exponent; + bool lower_boundary_is_closer; + significand = Double(v).Significand(); + exponent = Double(v).Exponent(); + lower_boundary_is_closer = Double(v).LowerBoundaryIsCloser(); + const bool need_boundary_deltas = true; + + bool is_even = (significand & 1) == 0; + int normalized_exponent = NormalizedExponent(significand, exponent); + int estimated_power = EstimatePower(normalized_exponent); + + Bignum numerator; + Bignum denominator; + Bignum delta_minus; + Bignum delta_plus; + ASSERT(Bignum::kMaxSignificantBits >= 324*4); + InitialScaledStartValues(significand, exponent, lower_boundary_is_closer, + estimated_power, need_boundary_deltas, + &numerator, &denominator, + &delta_minus, &delta_plus); + FixupMultiply10(estimated_power, is_even, decimal_point, + &numerator, &denominator, + &delta_minus, &delta_plus); + GenerateShortestDigits(&numerator, &denominator, + &delta_minus, &delta_plus, + is_even, buffer, length); + buffer[*length] = '\0'; + } + + inline void GenerateShortestDigits(Bignum* numerator, Bignum* denominator, + Bignum* delta_minus, Bignum* delta_plus, + bool is_even, + Vector buffer, int* length) { + if (Bignum::Equal(*delta_minus, *delta_plus)) { + delta_plus = delta_minus; + } + *length = 0; + for (;;) { + uint16_t digit; + digit = numerator->DivideModuloIntBignum(*denominator); + ASSERT(digit <= 9); + buffer[(*length)++] = static_cast(digit + '0'); + + bool in_delta_room_minus; + bool in_delta_room_plus; + if (is_even) { + in_delta_room_minus = Bignum::LessEqual(*numerator, *delta_minus); + } else { + in_delta_room_minus = Bignum::Less(*numerator, *delta_minus); + } + if (is_even) { + in_delta_room_plus = + Bignum::PlusCompare(*numerator, *delta_plus, *denominator) >= 0; + } else { + in_delta_room_plus = + Bignum::PlusCompare(*numerator, *delta_plus, *denominator) > 0; + } + if (!in_delta_room_minus && !in_delta_room_plus) { + numerator->Times10(); + delta_minus->Times10(); + if (delta_minus != delta_plus) { + delta_plus->Times10(); + } + } else if (in_delta_room_minus && in_delta_room_plus) { + int compare = Bignum::PlusCompare(*numerator, *numerator, *denominator); + if (compare < 0) { + } else if (compare > 0) { + ASSERT(buffer[(*length) - 1] != '9'); + buffer[(*length) - 1]++; + } else { + if ((buffer[(*length) - 1] - '0') % 2 == 0) { + } else { + ASSERT(buffer[(*length) - 1] != '9'); + buffer[(*length) - 1]++; + } + } + return; + } else if (in_delta_room_minus) { + return; + } else { + ASSERT(buffer[(*length) -1] != '9'); + buffer[(*length) - 1]++; + return; + } + } + } + + inline bool DoubleToAscii( double v, + char * buffer, + int buffer_length, + std::ostream & oss, + int * length, + int * point ) + { + if ( Double( v ).Sign() < 0 ) { + oss << '-'; + v = -v; + } + if ( v == 0.0 ) { + oss << "0.0"; + return true; + } + Vector< char > vector( buffer, buffer_length ); + + if ( ! FastDtoa(v, vector, length, point) ) { + BignumDtoa( v, vector, length, point ); + vector[ * length ] = '\0'; + } + return false; + } + + inline void CreateDecimalRepresentation(const char* decimal_digits, + int length, + int decimal_point, + int digits_after_point, + std::ostream & oss) { + if (decimal_point <= 0) { + oss << '0'; + if (digits_after_point > 0) { + oss << '.'; + for ( int i = 0; i < -decimal_point; ++i ) { + oss << '0'; + } + ASSERT(length <= digits_after_point - (-decimal_point)); + oss.write( decimal_digits, length ); + int remaining_digits = digits_after_point - (-decimal_point) - length; + for ( int i = 0; i < remaining_digits; ++i ) { + oss << '0'; + } + } + } else if (decimal_point >= length) { + oss.write( decimal_digits, length ); + for ( int i = 0; i < decimal_point - length; ++i ) { + oss << '0'; + } + if (digits_after_point > 0) { + oss << '.'; + for ( int i = 0; i < digits_after_point; ++i ) { + oss << '0'; + } + } + } else { + ASSERT(digits_after_point > 0); + oss.write( decimal_digits, decimal_point ); + oss << '.'; + ASSERT(length - decimal_point <= digits_after_point); + oss.write( decimal_digits + decimal_point, length - decimal_point ); + int remaining_digits = digits_after_point - (length - decimal_point); + for ( int i = 0; i < remaining_digits; ++i ) { + oss << '0'; + } + } + if (digits_after_point == 0) { + oss << '.'; + oss << '0'; + } + } + + inline void CreateExponentialRepresentation(const char* decimal_digits, + int length, + int exponent, + std::ostream & oss) { + ASSERT(length != 0); + oss << decimal_digits[ 0 ]; + if (length != 1) { + oss << '.'; + oss.write( decimal_digits + 1, length - 1 ); + } + oss << 'e'; + if (exponent < 0) { + oss << '-'; + exponent = -exponent; + } else { + // oss << '+'; + } + if (exponent == 0) { + oss << '0'; + return; + } + oss << exponent; + } + + inline void Dtostr( std::ostream & oss, const double value ) + { + int decimal_point; + const int kDecimalRepCapacity = kBase10MaximalLength + 1; // Plus 1 is '\0'. + char decimal_rep[ kDecimalRepCapacity ]; + int decimal_rep_length; + + if ( ! DoubleToAscii(value, decimal_rep, kDecimalRepCapacity, + oss, &decimal_rep_length, &decimal_point) ) + { + const int exponent = decimal_point - 1; + if ((-6 <= exponent) && + (exponent < 21)) { + CreateDecimalRepresentation(decimal_rep, decimal_rep_length, + decimal_point, + Max(0, decimal_rep_length - decimal_point), + oss); + } else { + CreateExponentialRepresentation(decimal_rep, decimal_rep_length, exponent, + oss); + } + } + } + +} // json_double_conversion + +#endif diff --git a/share/include/tao/json/external/operators.hpp b/share/include/tao/json/external/operators.hpp new file mode 100644 index 0000000..15e6f92 --- /dev/null +++ b/share/include/tao/json/external/operators.hpp @@ -0,0 +1,658 @@ +// The Art of C++ / Operators +// Copyright (c) 2013-2016 Daniel Frey +// Please see LICENSE for license or visit https://github.com/taocpp/operators/ + +#ifndef TAOCPP_OPERATORS_INCLUDE_OPERATORS_HPP +#define TAOCPP_OPERATORS_INCLUDE_OPERATORS_HPP + +#include + +#ifndef TAOCPP_NO_RVALUE_REFERENCE_RESULTS +#define TAOCPP_OPERATORS_BASIC_OP( name, op ) \ + template< typename T, typename U = T > \ + class name \ + { \ + friend T operator op( const T& lhs, const U& rhs ) \ + noexcept( noexcept( T( lhs ), std::declval< T& >() op##= rhs, T( std::declval< T& >() ) ) ) \ + { \ + T nrv( lhs ); \ + nrv op##= rhs; \ + return nrv; \ + } \ + \ + friend T operator op( const T& lhs, U&& rhs ) \ + noexcept( noexcept( T( lhs ), std::declval< T& >() op##= std::move( rhs ), T( std::declval< T& >() ) ) ) \ + { \ + T nrv( lhs ); \ + nrv op##= std::move( rhs ); \ + return nrv; \ + } \ + \ + friend T&& operator op( T&& lhs, const U& rhs ) \ + noexcept( noexcept( lhs op##= rhs ) ) \ + { \ + lhs op##= rhs; \ + return std::move( lhs ); \ + } \ + \ + friend T&& operator op( T&& lhs, U&& rhs ) \ + noexcept( noexcept( lhs op##= std::move( rhs ) ) ) \ + { \ + lhs op##= std::move( rhs ); \ + return std::move( lhs ); \ + } \ + } +#else +#define TAOCPP_OPERATORS_BASIC_OP( name, op ) \ + template< typename T, typename U = T > \ + class name \ + { \ + friend T operator op( const T& lhs, const U& rhs ) \ + noexcept( noexcept( T( lhs ), std::declval< T& >() op##= rhs, T( std::declval< T& >() ) ) ) \ + { \ + T nrv( lhs ); \ + nrv op##= rhs; \ + return nrv; \ + } \ + \ + friend T operator op( const T& lhs, U&& rhs ) \ + noexcept( noexcept( T( lhs ), std::declval< T& >() op##= std::move( rhs ), T( std::declval< T& >() ) ) ) \ + { \ + T nrv( lhs ); \ + nrv op##= std::move( rhs ); \ + return nrv; \ + } \ + \ + friend T operator op( T&& lhs, const U& rhs ) \ + noexcept( noexcept( T( std::move( lhs ) ), std::declval< T& >() op##= rhs, T( std::declval< T& >() ) ) ) \ + { \ + T nrv( std::move( lhs ) ); \ + nrv op##= rhs; \ + return nrv; \ + } \ + \ + friend T operator op( T&& lhs, U&& rhs ) \ + noexcept( noexcept( T( std::move( lhs ) ), std::declval< T& >() op##= std::move( rhs ), T( std::declval< T& >() ) ) ) \ + { \ + T nrv( std::move( lhs ) ); \ + nrv op##= std::move( rhs ); \ + return nrv; \ + } \ + } +#endif + +#define TAOCPP_OPERATORS_BASIC_OP_LEFT( name, op ) \ + template< typename T, typename U > \ + class name##_left \ + { \ + friend T operator op( const U& lhs, const T& rhs ) \ + noexcept( noexcept( T( lhs ), std::declval< T& >() op##= rhs, T( std::declval< T& >() ) ) ) \ + { \ + T nrv( lhs ); \ + nrv op##= rhs; \ + return nrv; \ + } \ + \ + friend T operator op( const U& lhs, T&& rhs ) \ + noexcept( noexcept( T( lhs ), std::declval< T& >() op##= std::move( rhs ), T( std::declval< T& >() ) ) ) \ + { \ + T nrv( lhs ); \ + nrv op##= std::move( rhs ); \ + return nrv; \ + } \ + \ + friend T operator op( U&& lhs, const T& rhs ) \ + noexcept( noexcept( T( std::move( lhs ) ), std::declval< T& >() op##= rhs, T( std::declval< T& >() ) ) ) \ + { \ + T nrv( std::move( lhs ) ); \ + nrv op##= rhs; \ + return nrv; \ + } \ + \ + friend T operator op( U&& lhs, T&& rhs ) \ + noexcept( noexcept( T( std::move( lhs ) ), std::declval< T& >() op##= std::move( rhs ), T( std::declval< T& >() ) ) ) \ + { \ + T nrv( std::move( lhs ) ); \ + nrv op##= std::move( rhs ); \ + return nrv; \ + } \ + } + +#ifndef TAOCPP_NO_RVALUE_REFERENCE_RESULTS +#define TAOCPP_OPERATORS_BASIC_OP_COMMUTATIVE( name, op ) \ + template< typename T, typename U = T > \ + class commutative_##name \ + { \ + friend T operator op( const T& lhs, const U& rhs ) \ + noexcept( noexcept( T( lhs ), std::declval< T& >() op##= rhs, T( std::declval< T& >() ) ) ) \ + { \ + T nrv( lhs ); \ + nrv op##= rhs; \ + return nrv; \ + } \ + \ + friend T operator op( const T& lhs, U&& rhs ) \ + noexcept( noexcept( T( lhs ), std::declval< T& >() op##= std::move( rhs ), T( std::declval< T& >() ) ) ) \ + { \ + T nrv( lhs ); \ + nrv op##= std::move( rhs ); \ + return nrv; \ + } \ + \ + friend T&& operator op( T&& lhs, const U& rhs ) \ + noexcept( noexcept( lhs op##= rhs ) ) \ + { \ + lhs op##= rhs; \ + return std::move( lhs ); \ + } \ + \ + friend T&& operator op( T&& lhs, U&& rhs ) \ + noexcept( noexcept( lhs op##= std::move( rhs ) ) ) \ + { \ + lhs op##= std::move( rhs ); \ + return std::move( lhs ); \ + } \ + \ + friend T operator op( const U& lhs, const T& rhs ) \ + noexcept( noexcept( T( rhs ), std::declval< T& >() op##= lhs, T( std::declval< T& >() ) ) ) \ + { \ + T nrv( rhs ); \ + nrv op##= lhs; \ + return nrv; \ + } \ + \ + friend T&& operator op( const U& lhs, T&& rhs ) \ + noexcept( noexcept( rhs op##= lhs ) ) \ + { \ + rhs op##= lhs; \ + return std::move( rhs ); \ + } \ + \ + friend T operator op( U&& lhs, const T& rhs ) \ + noexcept( noexcept( T( rhs ), std::declval< T& >() op##= std::move( lhs ) ) ) \ + { \ + T nrv( rhs ); \ + nrv op##= std::move( lhs ); \ + return nrv; \ + } \ + \ + friend T&& operator op( U&& lhs, T&& rhs ) \ + noexcept( noexcept( rhs op##= std::move( lhs ) ) ) \ + { \ + rhs op##= std::move( lhs ); \ + return std::move( rhs ); \ + } \ + }; \ + \ + template< typename T > \ + class commutative_##name< T > \ + { \ + friend T operator op( const T& lhs, const T& rhs ) \ + noexcept( noexcept( T( lhs ), std::declval< T& >() op##= rhs, T( std::declval< T& >() ) ) ) \ + { \ + T nrv( lhs ); \ + nrv op##= rhs; \ + return nrv; \ + } \ + \ + friend T&& operator op( const T& lhs, T&& rhs ) \ + noexcept( noexcept( rhs op##= lhs ) ) \ + { \ + rhs op##= lhs; \ + return std::move( rhs ); \ + } \ + \ + friend T&& operator op( T&& lhs, const T& rhs ) \ + noexcept( noexcept( lhs op##= rhs ) ) \ + { \ + lhs op##= rhs; \ + return std::move( lhs ); \ + } \ + \ + friend T&& operator op( T&& lhs, T&& rhs ) \ + noexcept( noexcept( lhs op##= std::move( rhs ) ) ) \ + { \ + lhs op##= std::move( rhs ); \ + return std::move( lhs ); \ + } \ + } +#else +#define TAOCPP_OPERATORS_BASIC_OP_COMMUTATIVE( name, op ) \ + template< typename T, typename U = T > \ + class commutative_##name \ + { \ + friend T operator op( const T& lhs, const U& rhs ) \ + noexcept( noexcept( T( lhs ), std::declval< T& >() op##= rhs, T( std::declval< T& >() ) ) ) \ + { \ + T nrv( lhs ); \ + nrv op##= rhs; \ + return nrv; \ + } \ + \ + friend T operator op( const T& lhs, U&& rhs ) \ + noexcept( noexcept( T( lhs ), std::declval< T& >() op##= std::move( rhs ), T( std::declval< T& >() ) ) ) \ + { \ + T nrv( lhs ); \ + nrv op##= std::move( rhs ); \ + return nrv; \ + } \ + \ + friend T operator op( T&& lhs, const U& rhs ) \ + noexcept( noexcept( T( std::move( lhs ) ), std::declval< T& >() op##= rhs, T( std::declval< T& >() ) ) ) \ + { \ + T nrv( std::move( lhs ) ); \ + nrv op##= rhs; \ + return nrv; \ + } \ + \ + friend T operator op( T&& lhs, U&& rhs ) \ + noexcept( noexcept( T( std::move( lhs ) ), std::declval< T& >() op##= std::move( rhs ), T( std::declval< T& >() ) ) ) \ + { \ + T nrv( std::move( lhs ) ); \ + nrv op##= std::move( rhs ); \ + return nrv; \ + } \ + \ + friend T operator op( const U& lhs, const T& rhs ) \ + noexcept( noexcept( T( rhs ), std::declval< T& >() op##= lhs, T( std::declval< T& >() ) ) ) \ + { \ + T nrv( rhs ); \ + nrv op##= lhs; \ + return nrv; \ + } \ + \ + friend T operator op( const U& lhs, T&& rhs ) \ + noexcept( noexcept( T( std::move( rhs ) ), std::declval< T& >() op##= lhs, T( std::declval< T& >() ) ) ) \ + { \ + T nrv( std::move( rhs ) ); \ + nrv op##= lhs; \ + return nrv; \ + } \ + \ + friend T operator op( U&& lhs, const T& rhs ) \ + noexcept( noexcept( T( rhs ), std::declval< T& >() op##= std::move( lhs ) ) ) \ + { \ + T nrv( rhs ); \ + nrv op##= std::move( lhs ); \ + return nrv; \ + } \ + \ + friend T operator op( U&& lhs, T&& rhs ) \ + noexcept( noexcept( T( std::move( rhs ) ), std::declval< T& >() op##= std::move( lhs ) ) ) \ + { \ + T nrv( std::move( rhs ) ); \ + nrv op##= std::move( lhs ); \ + return nrv; \ + } \ + }; \ + \ + template< typename T > \ + class commutative_##name< T > \ + { \ + friend T operator op( const T& lhs, const T& rhs ) \ + noexcept( noexcept( T( lhs ), std::declval< T& >() op##= rhs, T( std::declval< T& >() ) ) ) \ + { \ + T nrv( lhs ); \ + nrv op##= rhs; \ + return nrv; \ + } \ + \ + friend T operator op( const T& lhs, T&& rhs ) \ + noexcept( noexcept( T( lhs ), std::declval< T& >() op##= std::move( rhs ), T( std::declval< T& >() ) ) ) \ + { \ + T nrv( lhs ); \ + nrv op##= std::move( rhs ); \ + return nrv; \ + } \ + \ + friend T operator op( T&& lhs, const T& rhs ) \ + noexcept( noexcept( T( std::move( lhs ) ), std::declval< T& >() op##= rhs, T( std::declval< T& >() ) ) ) \ + { \ + T nrv( std::move( lhs ) ); \ + nrv op##= rhs; \ + return nrv; \ + } \ + \ + friend T operator op( T&& lhs, T&& rhs ) \ + noexcept( noexcept( T( std::move( lhs ) ), std::declval< T& >() op##= std::move( rhs ), T( std::declval< T& >() ) ) ) \ + { \ + T nrv( std::move( lhs ) ); \ + nrv op##= std::move( rhs ); \ + return nrv; \ + } \ + } +#endif + +namespace tao +{ + namespace operators + { + template< typename T, typename U = T > + class equality_comparable + { + friend bool operator!=( const T& lhs, const U& rhs ) + noexcept( noexcept( static_cast< bool >( lhs == rhs ) ) ) + { + return !static_cast< bool >( lhs == rhs ); + } + + friend bool operator==( const U& lhs, const T& rhs ) + noexcept( noexcept( static_cast< bool >( rhs == lhs ) ) ) + { + return static_cast< bool >( rhs == lhs ); + } + + friend bool operator!=( const U& lhs, const T& rhs ) + noexcept( noexcept( static_cast< bool >( rhs != lhs ) ) ) + { + return static_cast< bool >( rhs != lhs ); + } + }; + + template< typename T > + class equality_comparable< T > + { + friend bool operator!=( const T& lhs, const T& rhs ) + noexcept( noexcept( static_cast< bool >( lhs == rhs ) ) ) + { + return !static_cast< bool >( lhs == rhs ); + } + }; + + template< typename T, typename U = T > + class less_than_comparable + { + friend bool operator<=( const T& lhs, const U& rhs ) + noexcept( noexcept( static_cast< bool >( lhs > rhs ) ) ) + { + return !static_cast< bool >( lhs > rhs ); + } + + friend bool operator>=( const T& lhs, const U& rhs ) + noexcept( noexcept( static_cast< bool >( lhs < rhs ) ) ) + { + return !static_cast< bool >( lhs < rhs ); + } + + friend bool operator<( const U& lhs, const T& rhs ) + noexcept( noexcept( static_cast< bool >( rhs > lhs ) ) ) + { + return static_cast< bool >( rhs > lhs ); + } + + friend bool operator>( const U& lhs, const T& rhs ) + noexcept( noexcept( static_cast< bool >( rhs < lhs ) ) ) + { + return static_cast< bool >( rhs < lhs ); + } + + friend bool operator<=( const U& lhs, const T& rhs ) + noexcept( noexcept( static_cast< bool >( rhs >= lhs ) ) ) + { + return static_cast< bool >( rhs >= lhs ); + } + + friend bool operator>=( const U& lhs, const T& rhs ) + noexcept( noexcept( static_cast< bool >( rhs <= lhs ) ) ) + { + return static_cast< bool >( rhs <= lhs ); + } + }; + + template< typename T > + class less_than_comparable< T > + { + friend bool operator>( const T& lhs, const T& rhs ) + noexcept( noexcept( static_cast< bool >( rhs < lhs ) ) ) + { + return static_cast< bool >( rhs < lhs ); + } + + friend bool operator<=( const T& lhs, const T& rhs ) + noexcept( noexcept( static_cast< bool >( rhs < lhs ) ) ) + { + return !static_cast< bool >( rhs < lhs ); + } + + friend bool operator>=( const T& lhs, const T& rhs ) + noexcept( noexcept( static_cast< bool >( lhs < rhs ) ) ) + { + return !static_cast< bool >( lhs < rhs ); + } + }; + + template< typename T, typename U = T > + class totally_ordered + : less_than_comparable< T, U >, equality_comparable< T, U > + { + }; + + template< typename T, typename U = T > + class equivalent + { + friend bool operator==( const T& lhs, const U& rhs ) + noexcept( noexcept( static_cast< bool >( lhs < rhs ), static_cast< bool >( lhs > rhs ) ) ) + { + return !static_cast< bool >( lhs < rhs ) && !static_cast< bool >( lhs > rhs ); + } + }; + + template< typename T > + class equivalent< T > + { + friend bool operator==( const T& lhs, const T& rhs ) + noexcept( noexcept( static_cast< bool >( lhs < rhs ) ) ) + { + return !static_cast< bool >( lhs < rhs ) && !static_cast< bool >( rhs < lhs ); + } + }; + + template< typename T, typename U = T > + class partially_ordered + { + friend bool operator<=( const T& lhs, const U& rhs ) + noexcept( noexcept( static_cast< bool >( lhs < rhs ), static_cast< bool >( lhs == rhs ) ) ) + { + return static_cast< bool >( lhs < rhs ) || static_cast< bool >( lhs == rhs ); + } + + friend bool operator>=( const T& lhs, const U& rhs ) + noexcept( noexcept( static_cast< bool >( lhs > rhs ), static_cast< bool >( lhs == rhs ) ) ) + { + return static_cast< bool >( lhs > rhs ) || static_cast< bool >( lhs == rhs ); + } + + friend bool operator<( const U& lhs, const T& rhs ) + noexcept( noexcept( static_cast< bool >( rhs > lhs ) ) ) + { + return static_cast< bool >( rhs > lhs ); + } + + friend bool operator>( const U& lhs, const T& rhs ) + noexcept( noexcept( static_cast< bool >( rhs < lhs ) ) ) + { + return static_cast< bool >( rhs < lhs ); + } + + friend bool operator<=( const U& lhs, const T& rhs ) + noexcept( noexcept( static_cast< bool >( rhs >= lhs ) ) ) + { + return static_cast< bool >( rhs >= lhs ); + } + + friend bool operator>=( const U& lhs, const T& rhs ) + noexcept( noexcept( static_cast< bool >( rhs <= lhs ) ) ) + { + return static_cast< bool >( rhs <= lhs ); + } + }; + + template< typename T > + class partially_ordered< T > + { + friend bool operator>( const T& lhs, const T& rhs ) + noexcept( noexcept( static_cast< bool >( rhs < lhs ) ) ) + { + return static_cast< bool >( rhs < lhs ); + } + + friend bool operator<=( const T& lhs, const T& rhs ) + noexcept( noexcept( static_cast< bool >( lhs < rhs ), static_cast< bool >( lhs == rhs ) ) ) + { + return static_cast< bool >( lhs < rhs ) || static_cast< bool >( lhs == rhs ); + } + + friend bool operator>=( const T& lhs, const T& rhs ) + noexcept( noexcept( static_cast< bool >( rhs < lhs ), static_cast< bool >( lhs == rhs ) ) ) + { + return static_cast< bool >( rhs < lhs ) || static_cast< bool >( lhs == rhs ); + } + }; + + TAOCPP_OPERATORS_BASIC_OP( addable, + ); + TAOCPP_OPERATORS_BASIC_OP_LEFT( addable, + ); + TAOCPP_OPERATORS_BASIC_OP_COMMUTATIVE( addable, + ); + + TAOCPP_OPERATORS_BASIC_OP( subtractable, - ); + TAOCPP_OPERATORS_BASIC_OP_LEFT( subtractable, - ); + + TAOCPP_OPERATORS_BASIC_OP( multipliable, * ); + TAOCPP_OPERATORS_BASIC_OP_LEFT( multipliable, * ); + TAOCPP_OPERATORS_BASIC_OP_COMMUTATIVE( multipliable, * ); + + TAOCPP_OPERATORS_BASIC_OP( dividable, / ); + TAOCPP_OPERATORS_BASIC_OP_LEFT( dividable, / ); + + TAOCPP_OPERATORS_BASIC_OP( modable, % ); + TAOCPP_OPERATORS_BASIC_OP_LEFT( modable, % ); + + template< typename T, typename U = T > + class ring + : commutative_addable< T, U >, subtractable< T, U >, subtractable_left< T, U >, multipliable< T, U > + { + }; + + template< typename T > + class ring< T > + : commutative_addable< T >, subtractable< T >, multipliable< T > + { + }; + + template< typename T, typename U = T > + class ordered_ring + : ring< T, U >, totally_ordered< T, U > + { + }; + + template< typename T, typename U = T > + class commutative_ring + : commutative_addable< T, U >, subtractable< T, U >, subtractable_left< T, U >, commutative_multipliable< T, U > + { + }; + + template< typename T > + class commutative_ring< T > + : commutative_addable< T >, subtractable< T >, commutative_multipliable< T > + { + }; + + template< typename T, typename U = T > + class ordered_commutative_ring + : commutative_ring< T, U >, totally_ordered< T, U > + { + }; + + template< typename T, typename U = T > + class field + : commutative_ring< T, U >, dividable< T, U >, dividable_left< T, U > + { + }; + + template< typename T > + class field< T > + : commutative_ring< T >, dividable< T > + { + }; + + template< typename T, typename U = T > + class ordered_field + : field< T, U >, totally_ordered< T, U > + { + }; + + TAOCPP_OPERATORS_BASIC_OP( andable, & ); + TAOCPP_OPERATORS_BASIC_OP_LEFT( andable, & ); + TAOCPP_OPERATORS_BASIC_OP_COMMUTATIVE( andable, & ); + + TAOCPP_OPERATORS_BASIC_OP( orable, | ); + TAOCPP_OPERATORS_BASIC_OP_LEFT( orable, | ); + TAOCPP_OPERATORS_BASIC_OP_COMMUTATIVE( orable, | ); + + TAOCPP_OPERATORS_BASIC_OP( xorable, ^ ); + TAOCPP_OPERATORS_BASIC_OP_LEFT( xorable, ^ ); + TAOCPP_OPERATORS_BASIC_OP_COMMUTATIVE( xorable, ^ ); + + template< typename T, typename U = T > + class bitwise + : andable< T, U >, orable< T, U >, xorable< T, U > + { + }; + + template< typename T, typename U > + class bitwise_left + : andable_left< T, U >, orable_left< T, U >, xorable_left< T, U > + { + }; + + template< typename T, typename U = T > + class commutative_bitwise + : commutative_andable< T, U >, commutative_orable< T, U >, commutative_xorable< T, U > + { + }; + + TAOCPP_OPERATORS_BASIC_OP( left_shiftable, << ); + TAOCPP_OPERATORS_BASIC_OP( right_shiftable, >> ); + + template< typename T, typename U = T > + class shiftable + : left_shiftable< T, U >, right_shiftable< T, U > + { + }; + + template< typename T > + class incrementable + { + friend T operator++( T& arg, int ) + noexcept( noexcept( T( arg ), ++arg, T( std::declval< T >() ) ) ) + { + const T nrv( arg ); + ++arg; + return nrv; + } + }; + + template< typename T > + class decrementable + { + friend T operator--( T& arg, int ) + noexcept( noexcept( T( arg ), --arg, T( std::declval< T >() ) ) ) + { + const T nrv( arg ); + --arg; + return nrv; + } + }; + + template< typename T > + class unit_steppable + : incrementable< T >, decrementable< T > + { + }; + } +} + +#undef TAOCPP_OPERATORS_BASIC_OP +#undef TAOCPP_OPERATORS_BASIC_OP_LEFT +#undef TAOCPP_OPERATORS_BASIC_OP_COMMUTATIVE + +#endif diff --git a/share/include/tao/json/external/optional.hpp b/share/include/tao/json/external/optional.hpp new file mode 100644 index 0000000..08a7d57 --- /dev/null +++ b/share/include/tao/json/external/optional.hpp @@ -0,0 +1,33 @@ +// The Art of C++ +// Copyright (c) 2016 Daniel Frey + +#ifndef TAOCPP_INCLUDE_OPTIONAL_HPP +#define TAOCPP_INCLUDE_OPTIONAL_HPP + +#ifndef TAOCPP_USE_STD_OPTIONAL +#if __cplusplus >= 201799L // TODO: Fix when C++17 is published with support for std::optional +#include +#define TAOCPP_USE_STD_OPTIONAL +#elif ( __cplusplus >= 201402L ) && (__GNUC__ == 4) && (__GNUC_MINOR__ >= 9) +#include +#else +#include "akrzemi1/optional.hpp" +#endif +#endif + +namespace tao +{ +#if TAOCPP_USE_STD_OPTIONAL + using std::optional; + using std::nullopt; + using std::in_place; + using std::make_optional; +#else + using std::experimental::optional; + using std::experimental::nullopt; + using std::experimental::in_place; + using std::experimental::make_optional; +#endif +} + +#endif diff --git a/share/include/tao/json/external/pegtl.hh b/share/include/tao/json/external/pegtl.hh new file mode 100644 index 0000000..1d9dc35 --- /dev/null +++ b/share/include/tao/json/external/pegtl.hh @@ -0,0 +1,22 @@ +// Copyright (c) 2014-2016 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_HH +#define TAO_CPP_PEGTL_HH + +#include "pegtl/parse.hh" +#include "pegtl/rules.hh" +#include "pegtl/ascii.hh" +#include "pegtl/utf8.hh" +#include "pegtl/utf16.hh" +#include "pegtl/utf32.hh" + +// The following files can be included whenever needed; they +// are not included by default because they include . +// #include "pegtl/trace.hh" +// #include "pegtl/analyze.hh" + +#include "pegtl/string_parser.hh" +#include "pegtl/file_parser.hh" + +#endif diff --git a/share/include/tao/json/external/pegtl/action_input.hh b/share/include/tao/json/external/pegtl/action_input.hh new file mode 100644 index 0000000..08e0307 --- /dev/null +++ b/share/include/tao/json/external/pegtl/action_input.hh @@ -0,0 +1,116 @@ +// Copyright (c) 2016 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_ACTION_INPUT_HH +#define TAO_CPP_PEGTL_ACTION_INPUT_HH + +#include +#include + +#include "eol.hh" +#include "position_info.hh" +#include "internal/input_data.hh" +#include "internal/input_mark.hh" + +namespace tao_json_pegtl +{ + template< typename Eol > + class basic_memory_input; + + template< typename Eol > + class basic_action_input + { + public: + using eol_t = Eol; + + using mark_t = internal::input_mark; + using data_t = internal::input_data; + + using action_t = basic_action_input< Eol >; + using memory_t = basic_memory_input< Eol >; + + using position_t = position_info; + using exception_t = basic_parse_error< position_info >; + + basic_action_input( const internal::input_mark & m, const internal::input_data & d ) + : m_data( m.byte(), m.line(), m.byte_in_line(), m.begin(), d.begin, d.source ) + { } + + basic_action_input( const std::size_t in_byte, const std::size_t in_line, const std::size_t in_byte_in_line, const char * in_begin, const char * in_end, const char * in_source ) + : m_data( in_byte, in_line, in_byte_in_line, in_begin, in_end, in_source ) + { } + + bool empty() const + { + return m_data.begin == m_data.end; + } + + std::size_t size( const std::size_t = 0 ) const + { + return m_data.end - m_data.begin; + } + + const char * begin() const + { + return m_data.begin; + } + + const char * end( const std::size_t = 0 ) const + { + return m_data.end; + } + + std::size_t byte() const + { + return m_data.byte; + } + + std::size_t line() const + { + return m_data.line; + } + + std::size_t byte_in_line() const + { + return m_data.byte_in_line; + } + + const char * source() const + { + return m_data.source; + } + + std::string string() const + { + return std::string( m_data.begin, m_data.end ); + } + + char peek_char( const std::size_t offset = 0 ) const + { + return m_data.begin[ offset ]; + } + + unsigned char peek_byte( const std::size_t offset = 0 ) const + { + return static_cast< unsigned char >( peek_char( offset ) ); + } + + const internal::input_data & data() const + { + return m_data; + } + + position_t position() const + { + return position_info( m_data ); + } + + private: + internal::input_data m_data; + }; + + using action_input = basic_action_input< lf_crlf_eol >; + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/analysis/analyze_cycles.hh b/share/include/tao/json/external/pegtl/analysis/analyze_cycles.hh new file mode 100644 index 0000000..7b695bb --- /dev/null +++ b/share/include/tao/json/external/pegtl/analysis/analyze_cycles.hh @@ -0,0 +1,129 @@ +// Copyright (c) 2014-2016 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_ANALYSIS_ANALYZE_CYCLES_HH +#define TAO_CPP_PEGTL_ANALYSIS_ANALYZE_CYCLES_HH + +#include + +#include +#include + +#include +#include + +#include "grammar_info.hh" +#include "insert_guard.hh" + +namespace tao_json_pegtl +{ + namespace analysis + { + class analyze_cycles_impl + { + protected: + explicit + analyze_cycles_impl( const bool verbose ) + : m_verbose( verbose ), + m_problems( 0 ) + { } + + const bool m_verbose; + unsigned m_problems; + grammar_info m_info; + std::set< std::string > m_stack; + std::map< std::string, bool > m_cache; + std::map< std::string, bool > m_results; + + const std::map< std::string, rule_info >::const_iterator find( const std::string & name ) const + { + const auto iter = m_info.map.find( name ); + assert( iter != m_info.map.end() ); + return iter; + } + + bool work( const std::map< std::string, rule_info >::const_iterator & start, const bool accum ) + { + const auto j = m_cache.find( start->first ); + + if ( j != m_cache.end() ) { + return j->second; + } + if ( const auto g = make_insert_guard( m_stack, start->first ) ) { + switch ( start->second.type ) { + case rule_type::ANY: { + bool a = false; + for ( const auto & r : start->second.rules ) { + a = a || work( find( r ), accum || a ); + } + return m_cache[ start->first ] = true; + } + case rule_type::OPT: { + bool a = false; + for ( const auto & r : start->second.rules ) { + a = a || work( find( r ), accum || a ); + } + return m_cache[ start->first ] = false; + } + case rule_type::SEQ: { + bool a = false; + for ( const auto & r : start->second.rules ) { + a = a || work( find( r ), accum || a ); + } + return m_cache[ start->first ] = a; + } + case rule_type::SOR: { + bool a = true; + for ( const auto & r : start->second.rules ) { + a = a && work( find( r ), accum ); + } + return m_cache[ start->first ] = a; + } + } + throw std::runtime_error( "code should be unreachable" ); // LCOV_EXCL_LINE + } + if ( ! accum ) { + ++m_problems; + if ( m_verbose ) { + std::cout << "problem: cycle without progress detected at rule class " << start->first << std::endl; + } + } + return m_cache[ start->first ] = accum; + } + }; + + template< typename Grammar > + class analyze_cycles + : private analyze_cycles_impl + { + public: + explicit + analyze_cycles( const bool verbose ) + : analyze_cycles_impl( verbose ) + { + Grammar::analyze_t::template insert< Grammar >( m_info ); + } + + std::size_t problems() + { + for ( auto i = m_info.map.begin(); i != m_info.map.end(); ++i ) { + m_results[ i->first ] = work( i, false ); + m_cache.clear(); + } + return m_problems; + } + + template< typename Rule > + bool consumes() const + { + const auto i = m_results.find( internal::demangle< Rule >() ); + assert( i != m_results.end() ); + return i->second; + } + }; + + } // namespace analysis + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/analysis/counted.hh b/share/include/tao/json/external/pegtl/analysis/counted.hh new file mode 100644 index 0000000..bbfdf9c --- /dev/null +++ b/share/include/tao/json/external/pegtl/analysis/counted.hh @@ -0,0 +1,22 @@ +// Copyright (c) 2014-2016 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_ANALYSIS_COUNTED_HH +#define TAO_CPP_PEGTL_ANALYSIS_COUNTED_HH + +#include "generic.hh" + +namespace tao_json_pegtl +{ + namespace analysis + { + template< rule_type Type, unsigned Count, typename ... Rules > + struct counted + : generic< ( Count != 0 ) ? Type : rule_type::OPT, Rules ... > + { }; + + } // namespace analysis + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/analysis/generic.hh b/share/include/tao/json/external/pegtl/analysis/generic.hh new file mode 100644 index 0000000..c311eb9 --- /dev/null +++ b/share/include/tao/json/external/pegtl/analysis/generic.hh @@ -0,0 +1,33 @@ +// Copyright (c) 2014-2015 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_ANALYSIS_GENERIC_HH +#define TAO_CPP_PEGTL_ANALYSIS_GENERIC_HH + +#include "rule_type.hh" +#include "insert_rules.hh" +#include "grammar_info.hh" + +namespace tao_json_pegtl +{ + namespace analysis + { + template< rule_type Type, typename ... Rules > + struct generic + { + template< typename Name > + static std::string insert( grammar_info & g ) + { + const auto r = g.insert< Name >( Type ); + if ( r.second ) { + insert_rules< Rules ... >::insert( g, r.first->second ); + } + return r.first->first; + } + }; + + } // namespace analysis + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/analysis/grammar_info.hh b/share/include/tao/json/external/pegtl/analysis/grammar_info.hh new file mode 100644 index 0000000..7543c98 --- /dev/null +++ b/share/include/tao/json/external/pegtl/analysis/grammar_info.hh @@ -0,0 +1,35 @@ +// Copyright (c) 2014-2015 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_ANALYSIS_GRAMMAR_INFO_HH +#define TAO_CPP_PEGTL_ANALYSIS_GRAMMAR_INFO_HH + +#include +#include +#include + +#include "../internal/demangle.hh" + +#include "rule_info.hh" + +namespace tao_json_pegtl +{ + namespace analysis + { + struct grammar_info + { + using map_t = std::map< std::string, rule_info >; + map_t map; + + template< typename Name > + std::pair< map_t::iterator, bool > insert( const rule_type type ) + { + return map.insert( map_t::value_type( internal::demangle< Name >(), rule_info( type ) ) ); + } + }; + + } // namespace analysis + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/analysis/insert_guard.hh b/share/include/tao/json/external/pegtl/analysis/insert_guard.hh new file mode 100644 index 0000000..c3749c9 --- /dev/null +++ b/share/include/tao/json/external/pegtl/analysis/insert_guard.hh @@ -0,0 +1,59 @@ +// Copyright (c) 2014-2017 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_ANALYSIS_INSERT_GUARD_HH +#define TAO_CPP_PEGTL_ANALYSIS_INSERT_GUARD_HH + +#include + +namespace tao_json_pegtl +{ + namespace analysis + { + template< typename C > + class insert_guard + { + public: + insert_guard( insert_guard && g ) noexcept + : m_i( g.m_i ), + m_c( g.m_c ) + { + g.m_c = 0; + } + + insert_guard( C & cs, const typename C::value_type & ts ) + : m_i( cs.insert( ts ) ), + m_c( & cs ) + { } + + ~insert_guard() + { + if ( m_c && m_i.second ) { + m_c->erase( m_i.first ); + } + } + + insert_guard( const insert_guard & ) = delete; + void operator= ( const insert_guard & ) = delete; + + explicit operator bool () const + { + return m_i.second; + } + + private: + const std::pair< typename C::iterator, bool > m_i; + C * m_c; + }; + + template< typename C, typename T > + insert_guard< C > make_insert_guard( C & c, const T & t ) + { + return insert_guard< C >( c, t ); + } + + } // namespace analysis + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/analysis/insert_rules.hh b/share/include/tao/json/external/pegtl/analysis/insert_rules.hh new file mode 100644 index 0000000..ef9d396 --- /dev/null +++ b/share/include/tao/json/external/pegtl/analysis/insert_rules.hh @@ -0,0 +1,37 @@ +// Copyright (c) 2014-2015 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_ANALYSIS_INSERT_RULES_HH +#define TAO_CPP_PEGTL_ANALYSIS_INSERT_RULES_HH + +#include "rule_info.hh" +#include "grammar_info.hh" + +namespace tao_json_pegtl +{ + namespace analysis + { + template< typename ... > struct insert_rules; + + template<> + struct insert_rules<> + { + static void insert( grammar_info &, rule_info & ) + { } + }; + + template< typename Rule, typename ... Rules > + struct insert_rules< Rule, Rules ... > + { + static void insert( grammar_info & g, rule_info & r ) + { + r.rules.push_back( Rule::analyze_t::template insert< Rule >( g ) ); + insert_rules< Rules ... >::insert( g, r ); + } + }; + + } // namespace analysis + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/analysis/rule_info.hh b/share/include/tao/json/external/pegtl/analysis/rule_info.hh new file mode 100644 index 0000000..12d2d64 --- /dev/null +++ b/share/include/tao/json/external/pegtl/analysis/rule_info.hh @@ -0,0 +1,31 @@ +// Copyright (c) 2014-2015 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_ANALYSIS_RULE_INFO_HH +#define TAO_CPP_PEGTL_ANALYSIS_RULE_INFO_HH + +#include +#include + +#include "rule_type.hh" + +namespace tao_json_pegtl +{ + namespace analysis + { + struct rule_info + { + explicit + rule_info( const rule_type in_type ) + : type( in_type ) + { } + + rule_type type; + std::vector< std::string > rules; + }; + + } // namespace analysis + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/analysis/rule_type.hh b/share/include/tao/json/external/pegtl/analysis/rule_type.hh new file mode 100644 index 0000000..e0d33ed --- /dev/null +++ b/share/include/tao/json/external/pegtl/analysis/rule_type.hh @@ -0,0 +1,23 @@ +// Copyright (c) 2014-2015 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_ANALYSIS_RULE_TYPE_HH +#define TAO_CPP_PEGTL_ANALYSIS_RULE_TYPE_HH + +namespace tao_json_pegtl +{ + namespace analysis + { + enum class rule_type : char + { + ANY, // Consumption-on-success is always true; assumes bounded repetition of conjunction of sub-rules. + OPT, // Consumption-on-success not necessarily true; assumes bounded repetition of conjunction of sub-rules. + SEQ, // Consumption-on-success depends on consumption of (non-zero bounded repetition of) conjunction of sub-rules. + SOR // Consumption-on-success depends on consumption of (non-zero bounded repetition of) disjunction of sub-rules. + }; + + } // namespace analysis + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/analyze.hh b/share/include/tao/json/external/pegtl/analyze.hh new file mode 100644 index 0000000..dce1dd9 --- /dev/null +++ b/share/include/tao/json/external/pegtl/analyze.hh @@ -0,0 +1,19 @@ +// Copyright (c) 2014-2015 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_ANALYZE_HH +#define TAO_CPP_PEGTL_ANALYZE_HH + +#include "analysis/analyze_cycles.hh" + +namespace tao_json_pegtl +{ + template< typename Rule > + std::size_t analyze( const bool verbose = true ) + { + return analysis::analyze_cycles< Rule >( verbose ).problems(); + } + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/apply_mode.hh b/share/include/tao/json/external/pegtl/apply_mode.hh new file mode 100644 index 0000000..f38fbc9 --- /dev/null +++ b/share/include/tao/json/external/pegtl/apply_mode.hh @@ -0,0 +1,17 @@ +// Copyright (c) 2014-2015 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_APPLY_MODE_HH +#define TAO_CPP_PEGTL_APPLY_MODE_HH + +namespace tao_json_pegtl +{ + enum class apply_mode : bool + { + ACTION = true, + NOTHING = false + }; + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/ascii.hh b/share/include/tao/json/external/pegtl/ascii.hh new file mode 100644 index 0000000..553768a --- /dev/null +++ b/share/include/tao/json/external/pegtl/ascii.hh @@ -0,0 +1,47 @@ +// Copyright (c) 2014-2016 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_ASCII_HH +#define TAO_CPP_PEGTL_ASCII_HH + +#include "internal/rules.hh" +#include "internal/result_on_found.hh" + +namespace tao_json_pegtl +{ + inline namespace ascii + { + struct alnum : internal::ranges< internal::peek_char, 'a', 'z', 'A', 'Z', '0', '9' > {}; + struct alpha : internal::ranges< internal::peek_char, 'a', 'z', 'A', 'Z' > {}; + struct any : internal::any< internal::peek_char > {}; + struct blank : internal::one< internal::result_on_found::SUCCESS, internal::peek_char, ' ', '\t' > {}; + struct digit : internal::range< internal::result_on_found::SUCCESS, internal::peek_char, '0', '9' > {}; + struct eol : internal::eol {}; + struct eolf : internal::eolf {}; + struct identifier_first : internal::ranges< internal::peek_char, 'a', 'z', 'A', 'Z', '_' > {}; + struct identifier_other : internal::ranges< internal::peek_char, 'a', 'z', 'A', 'Z', '0', '9', '_' > {}; + struct identifier : internal::seq< identifier_first, internal::star< identifier_other > > {}; + template< char ... Cs > struct istring : internal::istring< Cs ... > {}; + struct lower : internal::range< internal::result_on_found::SUCCESS, internal::peek_char, 'a', 'z' > {}; + template< char ... Cs > struct not_one : internal::one< internal::result_on_found::FAILURE, internal::peek_char, Cs ... > {}; + template< char Lo, char Hi > struct not_range : internal::range< internal::result_on_found::FAILURE, internal::peek_char, Lo, Hi > {}; + struct nul : internal::one< internal::result_on_found::SUCCESS, internal::peek_char, char( 0 ) > {}; + template< char ... Cs > struct one : internal::one< internal::result_on_found::SUCCESS, internal::peek_char, Cs ... > {}; + struct print : internal::range< internal::result_on_found::SUCCESS, internal::peek_char, char( 32 ), char( 126 ) > {}; + template< char Lo, char Hi > struct range : internal::range< internal::result_on_found::SUCCESS, internal::peek_char, Lo, Hi > {}; + template< char ... Cs > struct ranges : internal::ranges< internal::peek_char, Cs ... > {}; + struct seven : internal::range< internal::result_on_found::SUCCESS, internal::peek_char, char( 0 ), char( 127 ) > {}; + struct shebang : internal::if_must< internal::string< '#', '!' >, internal::until< internal::eolf > > {}; + struct space : internal::one< internal::result_on_found::SUCCESS, internal::peek_char, ' ', '\n', '\r', '\t', '\v', '\f' > {}; + template< char ... Cs > struct string : internal::string< Cs ... > {}; + template< char C > struct two : internal::string< C, C > {}; + struct upper : internal::range< internal::result_on_found::SUCCESS, internal::peek_char, 'A', 'Z' > {}; + struct xdigit : internal::ranges< internal::peek_char, '0', '9', 'a', 'f', 'A', 'F' > {}; + + } // namespace ascii + +} // namespace tao_json_pegtl + +#include "internal/pegtl_string.hh" + +#endif diff --git a/share/include/tao/json/external/pegtl/buffer_input.hh b/share/include/tao/json/external/pegtl/buffer_input.hh new file mode 100644 index 0000000..825e017 --- /dev/null +++ b/share/include/tao/json/external/pegtl/buffer_input.hh @@ -0,0 +1,171 @@ +// Copyright (c) 2016 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_BUFFER_INPUT_HH +#define TAO_CPP_PEGTL_BUFFER_INPUT_HH + +#include +#include +#include + +#include "eol.hh" +#include "position_info.hh" +#include "internal/input_data.hh" +#include "internal/input_mark.hh" + +namespace tao_json_pegtl +{ + template< typename Eol > + class basic_action_input; + + template< typename Eol > + class basic_memory_input; + + template< typename Eol, typename Reader > + class basic_buffer_input + { + public: + using eol_t = Eol; + + using reader_t = Reader; + + using mark_t = internal::input_mark; + using data_t = internal::input_data; + + using action_t = basic_action_input< Eol >; + using memory_t = basic_memory_input< Eol >; + + using position_t = position_info; + using exception_t = basic_parse_error< position_info >; + + + template< typename ... As > + basic_buffer_input( const char * in_source, const std::size_t maximum, As && ... as ) + : m_reader( std::forward< As >( as ) ... ), + m_maximum( maximum ), + m_buffer( new char[ maximum ] ), + m_data( 0, 1, 0, m_buffer.get(), m_buffer.get(), in_source ) + + { } + + basic_buffer_input( const basic_buffer_input & ) = delete; + void operator= ( const basic_buffer_input & ) = delete; + + bool empty() + { + require( 1 ); + return m_data.begin == m_data.end; + } + + std::size_t size( const std::size_t amount ) + { + require( amount ); + return m_data.end - m_data.begin; + } + + const char * begin() const + { + return m_data.begin; + } + + const char * end( const std::size_t amount ) + { + require( amount ); + return m_data.end; + } + + std::size_t byte() const + { + return m_data.byte; + } + + std::size_t line() const + { + return m_data.line; + } + + std::size_t byte_in_line() const + { + return m_data.byte_in_line; + } + + const char * source() const + { + return m_data.source; + } + + char peek_char( const std::size_t offset = 0 ) const + { + return m_data.begin[ offset ]; + } + + unsigned char peek_byte( const std::size_t offset = 0 ) const + { + return static_cast< unsigned char >( peek_char( offset ) ); + } + + void bump( const std::size_t count = 1 ) + { + m_data.bump( count, Eol::ch ); + } + + void bump_in_this_line( const std::size_t count = 1 ) + { + m_data.bump_in_this_line( count ); + } + + void bump_to_next_line( const std::size_t count = 1 ) + { + m_data.bump_to_next_line( count ); + } + + void discard() + { + const auto s = m_data.end - m_data.begin; + std::memmove( m_buffer.get(), m_data.begin, s ); + m_data.begin = m_buffer.get(); + m_data.end = m_buffer.get() + s; + } + + void require( const std::size_t amount ) + { + if ( m_data.begin + amount > m_data.end ) { + if ( m_data.begin + amount <= m_buffer.get() + m_maximum ) { + if ( const auto r = m_reader( const_cast< char * >( m_data.end ), amount - std::size_t( m_data.end - m_data.begin ) ) ) { + m_data.end += r; + } + else { + m_maximum = 0; + } + } + } + } + + internal::input_mark mark() + { + return internal::input_mark( m_data ); + } + + const internal::input_data & data() const + { + return m_data; + } + + position_t position() const + { + return position_info( m_data ); + } + + private: + Reader m_reader; + std::size_t m_maximum; + std::unique_ptr< char[] > m_buffer; + internal::input_data m_data; + }; + + template< typename Reader > + using buffer_input = basic_buffer_input< lf_crlf_eol, Reader >; + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/contrib/abnf.hh b/share/include/tao/json/external/pegtl/contrib/abnf.hh new file mode 100644 index 0000000..762f92f --- /dev/null +++ b/share/include/tao/json/external/pegtl/contrib/abnf.hh @@ -0,0 +1,36 @@ +// Copyright (c) 2014-2015 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_CONTRIB_ABNF_HH +#define TAO_CPP_PEGTL_CONTRIB_ABNF_HH + +#include "../internal/rules.hh" + +namespace tao_json_pegtl +{ + namespace abnf + { + // Core ABNF rules according to RFC 5234, Appendix B + + struct ALPHA : internal::ranges< internal::peek_char, 'a', 'z', 'A', 'Z' > {}; + struct BIT : internal::one< internal::result_on_found::SUCCESS, internal::peek_char, '0', '1' > {}; + struct CHAR : internal::range< internal::result_on_found::SUCCESS, internal::peek_char, char( 1 ), char( 127 ) > {}; + struct CR : internal::one< internal::result_on_found::SUCCESS, internal::peek_char, '\r' > {}; + struct CRLF : internal::string< '\r', '\n' > {}; + struct CTL : internal::ranges< internal::peek_char, char( 0 ), char( 31 ), char( 127 ) > {}; + struct DIGIT : internal::range< internal::result_on_found::SUCCESS, internal::peek_char, '0', '9' > {}; + struct DQUOTE : internal::one< internal::result_on_found::SUCCESS, internal::peek_char, '"' > {}; + struct HEXDIG : internal::ranges< internal::peek_char, '0', '9', 'a', 'f', 'A', 'F' > {}; + struct HTAB : internal::one< internal::result_on_found::SUCCESS, internal::peek_char, '\t' > {}; + struct LF : internal::one< internal::result_on_found::SUCCESS, internal::peek_char, '\n' > {}; + struct LWSP : internal::star< internal::sor< internal::string< '\r', '\n' >, internal::one< internal::result_on_found::SUCCESS, internal::peek_char, ' ', '\t' > >, internal::one< internal::result_on_found::SUCCESS, internal::peek_char, ' ', '\t' > > {}; + struct OCTET : internal::any< internal::peek_char > {}; + struct SP : internal::one< internal::result_on_found::SUCCESS, internal::peek_char, ' ' > {}; + struct VCHAR : internal::range< internal::result_on_found::SUCCESS, internal::peek_char, char( 33 ), char( 126 ) > {}; + struct WSP : internal::one< internal::result_on_found::SUCCESS, internal::peek_char, ' ', '\t' > {}; + + } // namespace abnf + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/contrib/alphabet.hh b/share/include/tao/json/external/pegtl/contrib/alphabet.hh new file mode 100644 index 0000000..eb4d3ef --- /dev/null +++ b/share/include/tao/json/external/pegtl/contrib/alphabet.hh @@ -0,0 +1,69 @@ +// Copyright (c) 2015 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_CONTRIB_ALPHABET_HH +#define TAO_CPP_PEGTL_CONTRIB_ALPHABET_HH + +namespace tao_json_pegtl +{ + inline namespace alphabet + { + static const int a = 'a'; + static const int b = 'b'; + static const int c = 'c'; + static const int d = 'd'; + static const int e = 'e'; + static const int f = 'f'; + static const int g = 'g'; + static const int h = 'h'; + static const int i = 'i'; + static const int j = 'j'; + static const int k = 'k'; + static const int l = 'l'; + static const int m = 'm'; + static const int n = 'n'; + static const int o = 'o'; + static const int p = 'p'; + static const int q = 'q'; + static const int r = 'r'; + static const int s = 's'; + static const int t = 't'; + static const int u = 'u'; + static const int v = 'v'; + static const int w = 'w'; + static const int x = 'x'; + static const int y = 'y'; + static const int z = 'z'; + + static const int A = 'A'; + static const int B = 'B'; + static const int C = 'C'; + static const int D = 'D'; + static const int E = 'E'; + static const int F = 'F'; + static const int G = 'G'; + static const int H = 'H'; + static const int I = 'I'; + static const int J = 'J'; + static const int K = 'K'; + static const int L = 'L'; + static const int M = 'M'; + static const int N = 'N'; + static const int O = 'O'; + static const int P = 'P'; + static const int Q = 'Q'; + static const int R = 'R'; + static const int S = 'S'; + static const int T = 'T'; + static const int U = 'U'; + static const int V = 'V'; + static const int W = 'W'; + static const int X = 'X'; + static const int Y = 'Y'; + static const int Z = 'Z'; + + } // namespace alphabet + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/contrib/changes.hh b/share/include/tao/json/external/pegtl/contrib/changes.hh new file mode 100644 index 0000000..0be03f8 --- /dev/null +++ b/share/include/tao/json/external/pegtl/contrib/changes.hh @@ -0,0 +1,68 @@ +// Copyright (c) 2015 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_CONTRIB_CHANGES_HH +#define TAO_CPP_PEGTL_CONTRIB_CHANGES_HH + +#include + +#include "../normal.hh" + +namespace tao_json_pegtl +{ + namespace internal + { + struct dummy_disabled_state + { + template< typename ... Ts > + void success( Ts && ... ) + { } + }; + + template< tao_json_pegtl::apply_mode A, typename State > + using state_disable_helper = typename std::conditional< A == tao_json_pegtl::apply_mode::ACTION, State, dummy_disabled_state >::type; + + } // namespace internal + + template< typename Rule, typename State, template< typename ... > class Base = tao_json_pegtl::normal > + struct change_state + : public Base< Rule > + { + template< tao_json_pegtl::apply_mode A, template< typename ... > class Action, template< typename ... > class Control, typename Input, typename ... States > + static bool match( Input & in, States && ... st ) + { + internal::state_disable_helper< A, State > s; + + if ( Base< Rule >::template match< A, Action, Control >( in, s ) ) { + s.success( st ... ); + return true; + } + return false; + } + }; + + template< typename Rule, template< typename ... > class Action, template< typename ... > class Base = tao_json_pegtl::normal > + struct change_action + : public Base< Rule > + { + template< tao_json_pegtl::apply_mode A, template< typename ... > class, template< typename ... > class Control, typename Input, typename ... States > + static bool match( Input & in, States && ... st ) + { + return Base< Rule >::template match< A, Action, Control >( in, st ... ); + } + }; + + template< template< typename ... > class Action, template< typename ... > class Base > + struct change_both_helper + { + template< typename T > using change_action = change_action< T, Action, Base >; + }; + + template< typename Rule, typename State, template< typename ... > class Action, template< typename ... > class Base = tao_json_pegtl::normal > + struct change_state_and_action + : public change_state< Rule, State, change_both_helper< Action, Base >::template change_action > + { }; + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/contrib/http.hh b/share/include/tao/json/external/pegtl/contrib/http.hh new file mode 100644 index 0000000..27f0e6c --- /dev/null +++ b/share/include/tao/json/external/pegtl/contrib/http.hh @@ -0,0 +1,145 @@ +// Copyright (c) 2014-2016 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_CONTRIB_HTTP_HH +#define TAO_CPP_PEGTL_CONTRIB_HTTP_HH + +#include "../rules.hh" +#include "../ascii.hh" +#include "../utf8.hh" +#include "abnf.hh" +#include "uri.hh" + +namespace tao_json_pegtl +{ + namespace http + { + // HTTP 1.1 grammar according to RFC 7230. + + // This grammar is a direct PEG translation of the original HTTP grammar. + // It should be considered experimental -- in case of any issues, in particular + // missing anchor rules for actions, please contact the developers. + + using namespace abnf; + + using OWS = star< WSP >; // optional whitespace + using RWS = plus< WSP >; // required whitespace + using BWS = OWS; // "bad" whitespace + + // cppcheck-suppress constStatement + using obs_text = not_range< 0x00, 0x7F >; + using obs_fold = seq< CRLF, plus< WSP > >; + + struct tchar : sor< ALPHA, DIGIT, one< '!', '#', '$', '%', '&', '\'', '*', '+', '-', '.', '^', '_', '`', '|', '~' > > {}; + struct token : plus< tchar > {}; + + struct field_name : token {}; + + struct field_vchar : sor< VCHAR, obs_text > {}; + struct field_content : list< field_vchar, plus< WSP > > {}; + struct field_value : star< sor< field_content, obs_fold > > {}; + + struct header_field : seq< field_name, one< ':' >, OWS, field_value, OWS > {}; + + struct method : token {}; + + struct absolute_path : plus< one< '/' >, uri::segment > {}; + + struct origin_form : seq< absolute_path, uri::opt_query > {}; + struct absolute_form : uri::absolute_URI {}; + struct authority_form : uri::authority {}; + struct asterisk_form : one< '*' > {}; + + struct request_target : sor< origin_form, absolute_form, authority_form, asterisk_form > {}; + + struct status_code : rep< 3, DIGIT > {}; + struct reason_phrase : star< sor< VCHAR, obs_text, WSP > > {}; + + struct HTTP_version : if_must< pegtl_string_t( "HTTP/" ), DIGIT, one< '.' >, DIGIT > {}; + + struct request_line : if_must< method, SP, request_target, SP, HTTP_version, CRLF > {}; + struct status_line : if_must< HTTP_version, SP, status_code, SP, reason_phrase, CRLF > {}; + struct start_line : sor< request_line, status_line > {}; + + struct message_body : star< OCTET > {}; + struct HTTP_message : seq< start_line, star< header_field, CRLF >, CRLF, opt< message_body > > {}; + + struct Content_Length : plus< DIGIT > {}; + + struct uri_host : uri::host {}; + struct port : uri::port {}; + + struct Host : seq< uri_host, opt< one< ':' >, port > > {}; + + // PEG are different from CFGs! (this replaces ctext and qdtext) + using text = sor< HTAB, range< 0x20, 0x7E >, obs_text >; + + struct quoted_pair : if_must< one< '\\' >, sor< VCHAR, obs_text, WSP > > {}; + struct quoted_string : if_must< DQUOTE, until< DQUOTE, sor< quoted_pair, text > > > {}; + + struct transfer_parameter : seq< token, BWS, one< '=' >, BWS, sor< token, quoted_string > > {}; + struct transfer_extension : seq< token, star< OWS, one< ';' >, OWS, transfer_parameter > > {}; + struct transfer_coding : sor< pegtl_istring_t( "chunked" ), + pegtl_istring_t( "compress" ), + pegtl_istring_t( "deflate" ), + pegtl_istring_t( "gzip" ), + transfer_extension > {}; + + struct rank : sor< seq< one< '0' >, opt< one< '.' >, rep_opt< 3, DIGIT > > >, + seq< one< '1' >, opt< one< '.' >, rep_opt< 3, one< '0' > > > > > {}; + + struct t_ranking : seq< OWS, one< ';' >, OWS, one< 'q', 'Q' >, one< '=' >, rank > {}; + struct t_codings : sor< pegtl_istring_t( "trailers" ), seq< transfer_coding, opt< t_ranking > > > {}; + + struct TE : opt< sor< one< ',' >, t_codings >, star< OWS, one< ',' >, opt< OWS, t_codings > > > {}; + + template< typename T > + using make_comma_list = seq< star< one< ',' >, OWS >, T, star< OWS, one< ',' >, opt< OWS, T > > >; + + struct connection_option : token {}; + struct Connection : make_comma_list< connection_option > {}; + + struct Trailer : make_comma_list< field_name > {}; + + struct Transfer_Encoding : make_comma_list< transfer_coding > {}; + + struct protocol_name : token {}; + struct protocol_version : token {}; + struct protocol : seq< protocol_name, opt< one< '/' >, protocol_version > > {}; + struct Upgrade : make_comma_list< protocol > {}; + + struct pseudonym : token {}; + + struct received_protocol : seq< opt< protocol_name, one< '/' > >, protocol_version > {}; + struct received_by : sor< seq< uri_host, opt< one< ':' >, port > >, pseudonym > {}; + + struct comment : if_must< one< '(' >, until< one< ')' >, sor< comment, quoted_pair, text > > > {}; + + struct Via : make_comma_list< seq< received_protocol, RWS, received_by, opt< RWS, comment > > > {}; + + struct http_URI : if_must< pegtl_istring_t( "http://" ), uri::authority, uri::path_abempty, uri::opt_query, uri::opt_fragment > {}; + struct https_URI : if_must< pegtl_istring_t( "https://" ), uri::authority, uri::path_abempty, uri::opt_query, uri::opt_fragment > {}; + + struct partial_URI : seq< uri::relative_part, uri::opt_query > {}; + + struct chunk_size : plus< HEXDIG > {}; + + struct chunk_ext_name : token {}; + struct chunk_ext_val : sor< quoted_string, token > {}; + struct chunk_ext : star< if_must< one< ';' >, chunk_ext_name, if_must< one< '=' >, chunk_ext_val > > > {}; + + struct chunk_data : until< at< CRLF >, OCTET > {}; + + struct chunk : seq< chunk_size, opt< chunk_ext >, CRLF, chunk_data, CRLF > {}; + + struct last_chunk : seq< plus< one< '0' > >, opt< chunk_ext >, CRLF > {}; + + struct trailer_part : star< header_field, CRLF > {}; + + struct chunked_body : seq< until< last_chunk, chunk >, trailer_part, CRLF > {}; + + } // namespace http + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/contrib/json.hh b/share/include/tao/json/external/pegtl/contrib/json.hh new file mode 100644 index 0000000..38ba790 --- /dev/null +++ b/share/include/tao/json/external/pegtl/contrib/json.hh @@ -0,0 +1,89 @@ +// Copyright (c) 2014-2015 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_CONTRIB_JSON_HH +#define TAO_CPP_PEGTL_CONTRIB_JSON_HH + +#include "../rules.hh" +#include "../ascii.hh" +#include "../utf8.hh" +#include "abnf.hh" + +namespace tao_json_pegtl +{ + namespace json + { + // JSON grammar according to RFC 7159 (for UTF-8 encoded JSON only). + + struct ws : one< ' ', '\t', '\n', '\r' > {}; + + template< typename R, typename P = ws > struct padr : internal::seq< R, internal::star< P > > {}; + + struct begin_array : padr< one< '[' > > {}; + struct begin_object : padr< one< '{' > > {}; + struct end_array : one< ']' > {}; + struct end_object : one< '}' > {}; + struct name_separator : pad< one< ':' >, ws > {}; + struct value_separator : padr< one< ',' > > {}; + + struct false_ : pegtl_string_t( "false" ) {}; + struct null : pegtl_string_t( "null" ) {}; + struct true_ : pegtl_string_t( "true" ) {}; + + struct digits : plus< abnf::DIGIT > {}; + struct exp : seq< one< 'e', 'E' >, opt< one< '-', '+'> >, must< digits > > {}; + struct frac : if_must< one< '.' >, digits > {}; + struct int_ : sor< one< '0' >, digits > {}; + struct number : seq< opt< one< '-' > >, int_, opt< frac >, opt< exp > > {}; + + struct xdigit : abnf::HEXDIG {}; + struct unicode : list< seq< one< 'u' >, rep< 4, must< xdigit > > >, one< '\\' > > {}; + struct escaped_char : one< '"', '\\', '/', 'b', 'f', 'n', 'r', 't' > {}; + struct escaped : sor< escaped_char, unicode > {}; + struct unescaped : utf8::range< 0x20, 0x10FFFF > {}; + struct char_ : if_then_else< one< '\\' >, must< escaped >, unescaped > {}; + + struct string_content : until< at< one< '"' > >, must< char_ > > {}; + struct string : seq< one< '"' >, must< string_content >, any > + { + using content = string_content; + }; + + struct key_content : until< at< one< '"' > >, must< char_ > > {}; + struct key : seq< one< '"' >, must< key_content >, any > + { + using content = key_content; + }; + + struct value; + + struct array_element; + struct array_content : opt< list_must< array_element, value_separator > > {}; + struct array : seq< begin_array, array_content, must< end_array > > + { + using begin = begin_array; + using end = end_array; + using element = array_element; + using content = array_content; + }; + + struct member : if_must< key, name_separator, value > {}; + struct object_content : opt< list_must< member, value_separator > > {}; + struct object : seq< begin_object, object_content, must< end_object > > + { + using begin = begin_object; + using end = end_object; + using element = member; + using content = object_content; + }; + + struct value : padr< sor< string, number, object, array, false_, true_, null > > {}; + struct array_element : seq< value > {}; + + struct text : seq< star< ws >, value > {}; + + } // namespace json + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/contrib/raw_string.hh b/share/include/tao/json/external/pegtl/contrib/raw_string.hh new file mode 100644 index 0000000..dc2b7c5 --- /dev/null +++ b/share/include/tao/json/external/pegtl/contrib/raw_string.hh @@ -0,0 +1,164 @@ +// Copyright (c) 2014-2017 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_CONTRIB_RAW_STRING_HH +#define TAO_CPP_PEGTL_CONTRIB_RAW_STRING_HH + +#include "../action_input.hh" +#include "../apply_mode.hh" +#include "../nothing.hh" + +#include "../internal/must.hh" +#include "../internal/until.hh" +#include "../internal/state.hh" +#include "../internal/skip_control.hh" + +#include "../analysis/generic.hh" + +namespace tao_json_pegtl +{ + namespace internal + { + template< char Open, char Intermediate, char Close > + struct raw_string_tag + { }; + + template< typename Tag > + struct raw_string_state + { + template< typename Input, typename ... States > + raw_string_state( const Input & in, States && ... ) + : byte( in.byte() ), + line( in.line() ), + byte_in_line( in.byte_in_line() ), + size( in.size( 0 ) ) + { } + + template< apply_mode A, template< typename ... > class Action, template< typename ... > class Control, typename Input, typename ... States > + typename std::enable_if< ( ( A == apply_mode::ACTION ) && ( ! is_nothing< Action, Tag >::value ) ) >::type + success( const Input & in, States && ... st ) const + { + using eol_t = typename Input::eol_t; + using action_t = typename Input::action_t; + const auto * const begin = in.begin() - size + in.size( 0 ) + count; + action_t action_in( byte, line, byte_in_line, begin + ( ( * begin ) == eol_t::ch ), in.begin() - count, in.source() ); + Action< Tag >::apply( const_cast< const action_t & >( action_in ), st ... ); + } + + template< apply_mode A, template< typename ... > class Action, template< typename ... > class Control, typename Input, typename ... States > + typename std::enable_if< ! ( ( A == apply_mode::ACTION ) && ( ! is_nothing< Action, Tag >::value ) ) >::type + success( const Input &, States && ... ) const + { } + + raw_string_state( const raw_string_state & ) = delete; + void operator= ( const raw_string_state & ) = delete; + + std::size_t byte; + std::size_t line; + std::size_t byte_in_line; + std::size_t size; + std::size_t count = 0; + }; + + template< typename Tag, char Open, char Intermediate > + struct raw_string_open + { + using analyze_t = analysis::generic< analysis::rule_type::ANY >; + + template< apply_mode A, template< typename ... > class Action, template< typename ... > class Control, typename Input > + static bool match( Input & in, raw_string_state< Tag > & ls ) + { + if ( in.empty() || ( in.peek_char( 0 ) != Open ) ) { + return false; + } + for ( std::size_t i = 1; i < in.size( i + 1 ); ++i ) { + switch ( const auto c = in.peek_char( i ) ) { + case Open: + ls.count = i + 1; + in.bump( ls.count ); + return true; + case Intermediate: + break; + default: + return false; + } + } + return false; + } + }; + + template< typename Tag, char Intermediate, char Close > + struct raw_string_close + { + using analyze_t = analysis::generic< analysis::rule_type::ANY >; + + template< apply_mode A, template< typename ... > class Action, template< typename ... > class Control, typename Input > + static bool match( Input & in, const raw_string_state< Tag > & ls ) + { + if ( in.size( ls.count ) < ls.count ) { + return false; + } + if ( in.peek_char( 0 ) != Close ) { + return false; + } + if ( in.peek_char( ls.count - 1 ) != Close ) { + return false; + } + for ( std::size_t i = 0; i < ls.count - 2; ++i ) { + if ( in.peek_char( i + 1 ) != Intermediate ) { + return false; + } + } + in.bump( ls.count ); + return true; + } + }; + + template< typename Tag, char Open, char Intermediate > + struct skip_control< raw_string_open< Tag, Open, Intermediate > > : std::true_type {}; + + template< typename Tag, char Intermediate, char Close > + struct skip_control< raw_string_close< Tag, Intermediate, Close > > : std::true_type {}; + + } // namespace internal + + // raw_string matches Lua-style long literals. + // + // The following description was taken from the Lua documentation + // (see http://www.lua.org/docs.html): + // + // - An "opening long bracket of level n" is defined as an opening square + // bracket followed by n equal signs followed by another opening square + // bracket. So, an opening long bracket of level 0 is written as `[[`, + // an opening long bracket of level 1 is written as `[=[`, and so on. + // - A "closing long bracket" is defined similarly; for instance, a closing + // long bracket of level 4 is written as `]====]`. + // - A "long literal" starts with an opening long bracket of any level and + // ends at the first closing long bracket of the same level. It can + // contain any text except a closing bracket of the same level. + // - Literals in this bracketed form can run for several lines, do not + // interpret any escape sequences, and ignore long brackets of any other + // level. + // - For convenience, when the opening long bracket is immediately followed + // by a newline, the newline is not included in the string. + // + // Note that unlike Lua's long literal, a raw_string is customizable to use + // other characters than `[`, `=` and `]` for matching. Also note that Lua + // introduced newline-specific replacements in Lua 5.2, which we do not + // support on the grammar level. + + template< char Open, char Intermediate, char Close, typename Tag = internal::raw_string_tag< Open, Intermediate, Close > > + struct raw_string : internal::state< internal::raw_string_state< Tag >, + internal::raw_string_open< Tag, Open, Intermediate >, + internal::must< internal::until< internal::raw_string_close< Tag, Intermediate, Close > > > > + { + // This is used to bind an action to the content. + using content = Tag; + + // This is used for error-reporting when a raw string is not closed properly. + using close = internal::until< internal::raw_string_close< Tag, Intermediate, Close > >; + }; + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/contrib/unescape.hh b/share/include/tao/json/external/pegtl/contrib/unescape.hh new file mode 100644 index 0000000..eaeca70 --- /dev/null +++ b/share/include/tao/json/external/pegtl/contrib/unescape.hh @@ -0,0 +1,180 @@ +// Copyright (c) 2014-2016 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_CONTRIB_UNESCAPE_HH +#define TAO_CPP_PEGTL_CONTRIB_UNESCAPE_HH + +#include +#include + +#include "../ascii.hh" +#include "../parse_error.hh" + +namespace tao_json_pegtl +{ + namespace unescape + { + struct state + { + std::string unescaped; + }; + + // Utility functions for the unescape actions. + + inline bool utf8_append_utf32( std::string & string, const unsigned utf32 ) + { + if ( utf32 <= 0x7f ) { + string += char( utf32 & 0xff ); + return true; + } + if ( utf32 <= 0x7ff ) { + char tmp[] = { char( ( ( utf32 & 0x7c0 ) >> 6 ) | 0xc0 ), + char( ( ( utf32 & 0x03f ) ) | 0x80 ) }; + string.append( tmp, sizeof( tmp ) ); + return true; + } + if ( utf32 <= 0xffff ) { + char tmp[] = { char( ( ( utf32 & 0xf000 ) >> 12 ) | 0xe0 ), + char( ( ( utf32 & 0x0fc0 ) >> 6 ) | 0x80 ), + char( ( ( utf32 & 0x003f ) ) | 0x80 ) }; + string.append( tmp, sizeof( tmp ) ); + return true; + } + if ( utf32 <= 0x10ffff ) { + char tmp[] = { char( ( ( utf32 & 0x1c0000 ) >> 18 ) | 0xf0 ), + char( ( ( utf32 & 0x03f000 ) >> 12 ) | 0x80 ), + char( ( ( utf32 & 0x000fc0 ) >> 6 ) | 0x80 ), + char( ( ( utf32 & 0x00003f ) ) | 0x80 ) }; + string.append( tmp, sizeof( tmp ) ); + return true; + } + return false; + } + + // This function MUST only be called for characters matching tao_json_pegtl::ascii::xdigit! + template< typename I > + I unhex_char( const char c ) + { + switch ( c ) { + case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': + return I( c - '0' ); + case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': + return I( c - 'a' + 10 ); + case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': + return I( c - 'A' + 10 ); + } + throw std::runtime_error( "invalid character in unhex" ); // LCOV_EXCL_LINE + } + + template< typename I > + I unhex_string( const char * begin, const char * const end ) + { + I r = 0; + while ( begin != end ) { + r <<= 4; + r += unhex_char< I >( *begin++ ); + } + return r; + } + + // Actions for common unescape situations. + + struct append_all + { + template< typename Input, typename State > + static void apply( const Input & in, State & st ) + { + st.unescaped.append( in.begin(), in.size() ); + } + }; + + // This action MUST be called for a character matching T which MUST be tao_json_pegtl::one< ... >. + template< typename T, char ... Rs > + struct unescape_c + { + template< typename Input, typename State > + static void apply( const Input & in, State & st ) + { + assert( in.size() == 1 ); + st.unescaped += apply_one( * in.begin(), static_cast< const T * >( nullptr ) ); + } + + template< char ... Qs > + static char apply_one( const char c, const one< Qs ... > * ) + { + static_assert( sizeof ... ( Qs ) == sizeof ... ( Rs ), "size mismatch between escaped characters and their mappings" ); + return apply_two( c, { Qs ... }, { Rs ... } ); + } + + static char apply_two( const char c, const std::initializer_list< char > & q, const std::initializer_list< char > & r ) + { + for ( std::size_t i = 0; i < q.size(); ++i ) { + if ( * ( q.begin() + i ) == c ) { + return * ( r.begin() + i ); + } + } + throw std::runtime_error( "invalid character in unescape" ); // LCOV_EXCL_LINE + } + }; + + // See examples/unescape.cc for why the following two actions + // skip the first input character. They also MUST be called + // with non-empty matched inputs! + + struct unescape_u + { + template< typename Input, typename State > + static void apply( const Input & in, State & st ) + { + assert( ! in.empty() ); // First character MUST be present, usually 'u' or 'U'. + if ( ! utf8_append_utf32( st.unescaped, unhex_string< unsigned >( in.begin() + 1, in.end() ) ) ) { + using exception_t = typename Input::exception_t; + throw exception_t( "invalid escaped unicode code point", in ); + } + } + }; + + struct unescape_x + { + template< typename Input, typename State > + static void apply( const Input & in, State & st ) + { + assert( ! in.empty() ); // First character MUST be present, usually 'x'. + st.unescaped += unhex_string< char >( in.begin() + 1, in.end() ); + } + }; + + // The unescape_j action is similar to unescape_u, however unlike + // unescape_u it + // (a) assumes exactly 4 hexdigits per escape sequence, + // (b) accepts multiple consecutive escaped 16-bit values. + // When applied to more than one escape sequence, unescape_j + // translates UTF-16 surrogate pairs in the input into a single + // UTF-8 sequence in st.unescaped, as required for JSON by RFC 7159. + + struct unescape_j + { + template< typename Input, typename State > + static void apply( const Input & in, State & st ) + { + assert( ( ( in.size() + 1 ) % 6 ) == 0 ); // Expects multiple "\\u1234", starting with the first "u". + for ( const char * b = in.begin() + 1; b < in.end(); b += 6 ) { + const auto c = unhex_string< unsigned >( b, b + 4 ); + if ( ( 0xd800 <= c ) && ( c <= 0xdbff ) && ( b + 6 < in.end() ) ) { + const auto d = unhex_string< unsigned >( b + 6, b + 10 ); + if ( ( 0xdc00 <= d ) && ( d <= 0xdfff ) ) { + b += 6; + utf8_append_utf32( st.unescaped, ( ( ( c & 0x03ff ) << 10 ) | ( d & 0x03ff ) ) + 0x10000 ); + continue; + } + } + utf8_append_utf32( st.unescaped, c ); + } + } + }; + + } // namespace unescape + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/contrib/uri.hh b/share/include/tao/json/external/pegtl/contrib/uri.hh new file mode 100644 index 0000000..9114f10 --- /dev/null +++ b/share/include/tao/json/external/pegtl/contrib/uri.hh @@ -0,0 +1,108 @@ +// Copyright (c) 2014-2015 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_CONTRIB_URI_HH +#define TAO_CPP_PEGTL_CONTRIB_URI_HH + +#include "../rules.hh" +#include "../ascii.hh" +#include "../utf8.hh" +#include "abnf.hh" + +namespace tao_json_pegtl +{ + namespace uri + { + // URI grammar according to RFC 3986. + + // This grammar is a direct PEG translation of the original URI grammar. + // It should be considered experimental -- in case of any issues, in particular + // missing anchor rules for actions, please contact the developers. + + // Note that this grammar has multiple top-level rules. + + using namespace abnf; + + using dot = one< '.' >; + using colon = one< ':' >; + + struct dec_octet : sor< one< '0' >, + rep_min_max< 1, 2, DIGIT >, + seq< one< '1' >, DIGIT, DIGIT >, + seq< one< '2' >, range< '0', '4' >, DIGIT >, + seq< string< '2', '5' >, range< '0', '5' > > > {}; + + struct IPv4address : seq< dec_octet, dot, dec_octet, dot, dec_octet, dot, dec_octet > {}; + + struct h16 : rep_min_max< 1, 4, HEXDIG > {}; + struct ls32 : sor< seq< h16, colon, h16 >, IPv4address > {}; + + struct dcolon : two< ':' > {}; + + struct IPv6address : sor< seq< rep< 6, h16, colon >, ls32 >, + seq< dcolon, rep< 5, h16, colon >, ls32 >, + seq< opt< h16 >, dcolon, rep< 4, h16, colon >, ls32 >, + seq< opt< h16, opt< colon, h16 > >, dcolon, rep< 3, h16, colon >, ls32 >, + seq< opt< h16, rep_opt< 2, colon, h16 > >, dcolon, rep< 2, h16, colon >, ls32 >, + seq< opt< h16, rep_opt< 3, colon, h16 > >, dcolon, h16, colon, ls32 >, + seq< opt< h16, rep_opt< 4, colon, h16 > >, dcolon, ls32 >, + seq< opt< h16, rep_opt< 5, colon, h16 > >, dcolon, h16 >, + seq< opt< h16, rep_opt< 6, colon, h16 > >, dcolon > > {}; + + struct gen_delims : one< ':', '/', '?', '#', '[', ']', '@' > {}; + struct sub_delims : one< '!', '$', '&', '\'', '(', ')', '*', '+', ',', ';', '=' > {}; + + struct unreserved : sor< ALPHA, DIGIT, one< '-', '.', '_', '~' > > {}; + struct reserved : sor< gen_delims, sub_delims > {}; + + struct IPvFuture : if_must< one< 'v' >, plus< HEXDIG >, dot, plus< sor< unreserved, sub_delims, colon > > > {}; + + struct IP_literal : if_must< one< '[' >, sor< IPvFuture, IPv6address >, one< ']' > > {}; + + struct pct_encoded : if_must< one< '%' >, HEXDIG, HEXDIG > {}; + struct pchar : sor< unreserved, pct_encoded, sub_delims, one< ':', '@' > > {}; + + struct query : star< sor< pchar, one< '/', '?' > > > {}; + struct fragment : star< sor< pchar, one< '/', '?' > > > {}; + + struct segment : star< pchar > {}; + struct segment_nz : plus< pchar > {}; + struct segment_nz_nc : plus< sor< unreserved, pct_encoded, sub_delims, one< '@' > > > {}; // non-zero-length segment without any colon ":" + + struct path_abempty : star< one< '/' >, segment > {}; + struct path_absolute : seq< one< '/' >, opt< segment_nz, star< one< '/' >, segment > > > {}; + struct path_noscheme : seq< segment_nz_nc, star< one< '/' >, segment > > {}; + struct path_rootless : seq< segment_nz, star< one< '/' >, segment > > {}; + struct path_empty : success {}; + + struct path : sor< path_noscheme, // begins with a non-colon segment + path_rootless, // begins with a segment + path_absolute, // begins with "/" but not "//" + path_abempty > {}; // begins with "/" or is empty + + struct reg_name : star< sor< unreserved, pct_encoded, sub_delims > > {}; + + struct port : star< DIGIT > {}; + struct host : sor< IP_literal, IPv4address, reg_name > {}; + struct userinfo : star< sor< unreserved, pct_encoded, sub_delims, colon > > {}; + struct authority : seq< opt< userinfo, one< '@' > >, host, opt< colon, port > > {}; + + struct scheme : seq< ALPHA, star< sor< ALPHA, DIGIT, one< '+', '-', '.' > > > > {}; + + using dslash = two< '/' >; + using opt_query = opt< if_must< one< '?' >, query > >; + using opt_fragment = opt< if_must< one< '#' >, fragment > >; + + struct hier_part : sor< if_must< dslash, authority, path_abempty >, path_rootless, path_absolute, path_empty > {}; + struct relative_part : sor< if_must< dslash, authority, path_abempty >, path_noscheme, path_absolute, path_empty > {}; + struct relative_ref : seq< relative_part, opt_query, opt_fragment > {}; + + struct URI : seq< scheme, one< ':' >, hier_part, opt_query, opt_fragment > {}; + struct URI_reference : sor< URI, relative_ref > {}; + struct absolute_URI : seq< scheme, one< ':' >, hier_part, opt_query > {}; + + } // namespace uri + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/cr_crlf_eol.hh b/share/include/tao/json/external/pegtl/cr_crlf_eol.hh new file mode 100644 index 0000000..4e052b3 --- /dev/null +++ b/share/include/tao/json/external/pegtl/cr_crlf_eol.hh @@ -0,0 +1,29 @@ +// Copyright (c) 2016 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_CR_CRLF_EOL_HH +#define TAO_CPP_PEGTL_CR_CRLF_EOL_HH + +namespace tao_json_pegtl +{ + struct cr_crlf_eol + { + static constexpr int ch = '\r'; + + template< typename Input > + static eol_pair match( Input & in ) + { + eol_pair p = { false, in.size( 2 ) }; + if ( p.second ) { + if ( in.peek_char() == '\r' ) { + in.bump_to_next_line( 1 + ( ( p.second > 1 ) && ( in.peek_char( 1 ) == '\n' ) ) ); + p.first = true; + } + } + return p; + } + }; + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/cr_eol.hh b/share/include/tao/json/external/pegtl/cr_eol.hh new file mode 100644 index 0000000..91041ba --- /dev/null +++ b/share/include/tao/json/external/pegtl/cr_eol.hh @@ -0,0 +1,29 @@ +// Copyright (c) 2016 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_CR_EOL_HH +#define TAO_CPP_PEGTL_CR_EOL_HH + +namespace tao_json_pegtl +{ + struct cr_eol + { + static constexpr int ch = '\r'; + + template< typename Input > + static eol_pair match( Input & in ) + { + eol_pair p = { false, in.size( 1 ) }; + if ( p.second ) { + if ( in.peek_char() == '\r' ) { + in.bump_to_next_line(); + p.first = true; + } + } + return p; + } + }; + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/crlf_eol.hh b/share/include/tao/json/external/pegtl/crlf_eol.hh new file mode 100644 index 0000000..f11d61a --- /dev/null +++ b/share/include/tao/json/external/pegtl/crlf_eol.hh @@ -0,0 +1,29 @@ +// Copyright (c) 2016 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_CRLF_EOL_HH +#define TAO_CPP_PEGTL_CRLF_EOL_HH + +namespace tao_json_pegtl +{ + struct crlf_eol + { + static constexpr int ch = '\n'; + + template< typename Input > + static eol_pair match( Input & in ) + { + eol_pair p = { false, in.size( 2 ) }; + if ( p.second > 1 ) { + if ( ( in.peek_char() == '\r' ) && ( in.peek_char( 1 ) == '\n' ) ) { + in.bump_to_next_line( 2 ); + p.first = true; + } + } + return p; + } + }; + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/eol.hh b/share/include/tao/json/external/pegtl/eol.hh new file mode 100644 index 0000000..dcc9962 --- /dev/null +++ b/share/include/tao/json/external/pegtl/eol.hh @@ -0,0 +1,22 @@ +// Copyright (c) 2016 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_EOL_HH +#define TAO_CPP_PEGTL_EOL_HH + +#include +#include + +namespace tao_json_pegtl +{ + using eol_pair = std::pair< bool, std::size_t >; + +} // namespace tao_json_pegtl + +#include "lf_eol.hh" +#include "cr_eol.hh" +#include "crlf_eol.hh" +#include "lf_crlf_eol.hh" +#include "cr_crlf_eol.hh" + +#endif diff --git a/share/include/tao/json/external/pegtl/file_parser.hh b/share/include/tao/json/external/pegtl/file_parser.hh new file mode 100644 index 0000000..a29cdcc --- /dev/null +++ b/share/include/tao/json/external/pegtl/file_parser.hh @@ -0,0 +1,43 @@ +// Copyright (c) 2015-2016 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_FILE_PARSER_HH +#define TAO_CPP_PEGTL_FILE_PARSER_HH + +#include "read_parser.hh" + +#if defined (__unix__) || (defined (__APPLE__) && defined (__MACH__)) +#include // Required for _POSIX_MAPPED_FILES +#endif + +#if defined(_POSIX_MAPPED_FILES) +#include "mmap_parser.hh" +#endif + +namespace tao_json_pegtl +{ +#if defined(_POSIX_MAPPED_FILES) + using file_parser = mmap_parser; + template< typename Eol > + using basic_file_parser = basic_mmap_parser< Eol >; +#else + using file_parser = read_parser; + template< typename Eol > + using basic_file_parser = basic_read_parser< Eol >; +#endif + + template< typename Rule, template< typename ... > class Action = nothing, template< typename ... > class Control = normal, typename ... States > + bool parse_file( const std::string & filename, States && ... st ) + { + return file_parser( filename ).parse< Rule, Action, Control >( st ... ); + } + + template< typename Rule, template< typename ... > class Action = nothing, template< typename ... > class Control = normal, typename Outer, typename ... States > + bool parse_file_nested( Outer & oi, const std::string & filename, States && ... st ) + { + return basic_file_parser< typename Outer::eol >( filename ).template parse_nested< Rule, Action, Control >( oi, st ... ); + } + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/input_error.hh b/share/include/tao/json/external/pegtl/input_error.hh new file mode 100644 index 0000000..f78be54 --- /dev/null +++ b/share/include/tao/json/external/pegtl/input_error.hh @@ -0,0 +1,34 @@ +// Copyright (c) 2014-2016 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_INPUT_ERROR_HH +#define TAO_CPP_PEGTL_INPUT_ERROR_HH + +#include +#include +#include + +namespace tao_json_pegtl +{ + struct input_error + : std::runtime_error + { + input_error( const std::string & message, const int in_errorno ) + : std::runtime_error( message ), + errorno( in_errorno ) + { } + + int errorno; + }; + +#define TAO_CPP_PEGTL_THROW_INPUT_ERROR( MESSAGE ) \ + do { \ + const int errorno = errno; \ + std::ostringstream oss; \ + oss << "pegtl: " << MESSAGE << " errno " << errorno; \ + throw tao_json_pegtl::input_error( oss.str(), errorno ); \ + } while ( false ) + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/internal/action.hh b/share/include/tao/json/external/pegtl/internal/action.hh new file mode 100644 index 0000000..3f3b654 --- /dev/null +++ b/share/include/tao/json/external/pegtl/internal/action.hh @@ -0,0 +1,36 @@ +// Copyright (c) 2014-2015 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_INTERNAL_ACTION_HH +#define TAO_CPP_PEGTL_INTERNAL_ACTION_HH + +#include "skip_control.hh" +#include "seq.hh" +#include "rule_match_three.hh" + +#include "../analysis/generic.hh" + +namespace tao_json_pegtl +{ + namespace internal + { + template< template< typename ... > class Action, typename ... Rules > + struct action + { + using analyze_t = analysis::generic< analysis::rule_type::SEQ, Rules ... >; + + template< apply_mode A, template< typename ... > class, template< typename ... > class Control, typename Input, typename ... States > + static bool match( Input & in, States && ... st ) + { + return rule_match_three< seq< Rules ... >, A, Action, Control >::match( in, st ... ); + } + }; + + template< template< typename ... > class Action, typename ... Rules > + struct skip_control< action< Action, Rules ... > > : std::true_type {}; + + } // namespace internal + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/internal/any.hh b/share/include/tao/json/external/pegtl/internal/any.hh new file mode 100644 index 0000000..01fa9af --- /dev/null +++ b/share/include/tao/json/external/pegtl/internal/any.hh @@ -0,0 +1,59 @@ +// Copyright (c) 2014-2016 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_INTERNAL_ANY_HH +#define TAO_CPP_PEGTL_INTERNAL_ANY_HH + +#include "skip_control.hh" +#include "peek_char.hh" + +#include "../analysis/generic.hh" + +namespace tao_json_pegtl +{ + namespace internal + { + template< typename Peek > struct any; + + template< typename Peek > + struct skip_control< any< Peek > > : std::true_type {}; + + template<> + struct any< peek_char > + { + using analyze_t = analysis::generic< analysis::rule_type::ANY >; + + template< typename Input > + static bool match( Input & in ) + { + if ( ! in.empty() ) { + in.bump(); + return true; + } + return false; + } + }; + + template< typename Peek > + struct any + { + using analyze_t = analysis::generic< analysis::rule_type::ANY >; + + template< typename Input > + static bool match( Input & in ) + { + if ( ! in.empty() ) { + if ( const auto t = Peek::peek( in ) ) { + in.bump( t.size ); + return true; + } + } + return false; + } + }; + + } // namespace internal + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/internal/at.hh b/share/include/tao/json/external/pegtl/internal/at.hh new file mode 100644 index 0000000..3fe998b --- /dev/null +++ b/share/include/tao/json/external/pegtl/internal/at.hh @@ -0,0 +1,43 @@ +// Copyright (c) 2014-2015 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_INTERNAL_AT_HH +#define TAO_CPP_PEGTL_INTERNAL_AT_HH + +#include "skip_control.hh" +#include "trivial.hh" +#include "rule_conjunction.hh" + +#include "../analysis/generic.hh" + +namespace tao_json_pegtl +{ + namespace internal + { + template< typename ... Rules > struct at; + + template< typename ... Rules > + struct skip_control< at< Rules ... > > : std::true_type {}; + + template<> + struct at<> + : trivial< true > {}; + + template< typename ... Rules > + struct at + { + using analyze_t = analysis::generic< analysis::rule_type::OPT, Rules ... >; + + template< apply_mode, template< typename ... > class Action, template< typename ... > class Control, typename Input, typename ... States > + static bool match( Input & in, States && ... st ) + { + auto m = in.mark(); + return rule_conjunction< Rules ... >::template match< apply_mode::NOTHING, Action, Control >( in, st ... ); + } + }; + + } // namespace internal + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/internal/bump_util.hh b/share/include/tao/json/external/pegtl/internal/bump_util.hh new file mode 100644 index 0000000..3f7be2c --- /dev/null +++ b/share/include/tao/json/external/pegtl/internal/bump_util.hh @@ -0,0 +1,50 @@ +// Copyright (c) 2015-2016 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_INTERNAL_BUMP_UTIL_HH +#define TAO_CPP_PEGTL_INTERNAL_BUMP_UTIL_HH + +#include +#include + +#include "result_on_found.hh" + +namespace tao_json_pegtl +{ + namespace internal + { + template< bool > struct bump_impl; + + template<> struct bump_impl< true > + { + template< typename Input > + static void bump( Input & in, const std::size_t count ) + { + in.bump( count ); + } + }; + + template<> struct bump_impl< false > + { + template< typename Input > + static void bump( Input & in, const std::size_t count ) + { + in.bump_in_this_line( count ); + } + }; + + template< bool ... > struct bool_list {}; + template< bool ... Bs > using bool_and = std::is_same< bool_list< Bs..., true >, bool_list< true, Bs... > >; + + template< result_on_found R, typename Input, typename Char, Char ... Cs > + void bump( Input & in, const std::size_t count ) + { + using eol_t = typename Input::eol_t; + bump_impl< bool_and< ( Cs != eol_t::ch ) ... >::value != bool( R ) >::bump( in, count ); + } + + } // namespace internal + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/internal/bytes.hh b/share/include/tao/json/external/pegtl/internal/bytes.hh new file mode 100644 index 0000000..26f8b9e --- /dev/null +++ b/share/include/tao/json/external/pegtl/internal/bytes.hh @@ -0,0 +1,45 @@ +// Copyright (c) 2014-2016 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_INTERNAL_BYTES_HH +#define TAO_CPP_PEGTL_INTERNAL_BYTES_HH + +#include "skip_control.hh" + +#include "../analysis/counted.hh" + +namespace tao_json_pegtl +{ + namespace internal + { + template< unsigned Num > + struct bytes + { + using analyze_t = analysis::counted< analysis::rule_type::ANY, Num >; + + // suppress warning with GCC 4.7 + template< typename T1, typename T2 > + static inline bool dummy_greater_or_equal( const T1 a, const T2 b ) + { + return a >= b; + } + + template< typename Input > + static bool match( Input & in ) + { + if ( dummy_greater_or_equal( in.size( Num ), Num ) ) { + in.bump( Num ); + return true; + } + return false; + } + }; + + template< unsigned Num > + struct skip_control< bytes< Num > > : std::true_type {}; + + } // namespace internal + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/internal/control.hh b/share/include/tao/json/external/pegtl/internal/control.hh new file mode 100644 index 0000000..118c47c --- /dev/null +++ b/share/include/tao/json/external/pegtl/internal/control.hh @@ -0,0 +1,36 @@ +// Copyright (c) 2014-2015 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_INTERNAL_CONTROL_HH +#define TAO_CPP_PEGTL_INTERNAL_CONTROL_HH + +#include "skip_control.hh" +#include "seq.hh" +#include "rule_match_three.hh" + +#include "../analysis/generic.hh" + +namespace tao_json_pegtl +{ + namespace internal + { + template< template< typename ... > class Control, typename ... Rules > + struct control + { + using analyze_t = analysis::generic< analysis::rule_type::SEQ, Rules ... >; + + template< apply_mode A, template< typename ... > class Action, template< typename ... > class, typename Input, typename ... States > + static bool match( Input & in, States && ... st ) + { + return rule_match_three< seq< Rules ... >, A, Action, Control >::match( in, st ... ); + } + }; + + template< template< typename ... > class Control, typename ... Rules > + struct skip_control< control< Control, Rules ... > > : std::true_type {}; + + } // namespace internal + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/internal/cstream_reader.hh b/share/include/tao/json/external/pegtl/internal/cstream_reader.hh new file mode 100644 index 0000000..be8502d --- /dev/null +++ b/share/include/tao/json/external/pegtl/internal/cstream_reader.hh @@ -0,0 +1,43 @@ +// Copyright (c) 2016 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_INTERNAL_CSTREAM_READER_HH +#define TAO_CPP_PEGTL_INTERNAL_CSTREAM_READER_HH + +#include +#include + +#include "../input_error.hh" + +namespace tao_json_pegtl +{ + namespace internal + { + struct cstream_reader + { + explicit + cstream_reader( std::FILE * s ) + : m_cstream( s ) + { } + + std::size_t operator() ( char * buffer, const std::size_t length ) + { + if ( const auto r = std::fread( buffer, 1, length, m_cstream ) ) { + return r; + } + if ( std::feof( m_cstream ) != 0 ) { + return 0; + } + // Please contact us if you know how to provoke the following exception. + // The example on cppreference.com doesn't work, at least not on Mac OS X. + TAO_CPP_PEGTL_THROW_INPUT_ERROR( "error in fread() from cstream" ); // LCOV_EXCL_LINE + } + + std::FILE * m_cstream; + }; + + } // namespace internal + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/internal/cstring_reader.hh b/share/include/tao/json/external/pegtl/internal/cstring_reader.hh new file mode 100644 index 0000000..126db33 --- /dev/null +++ b/share/include/tao/json/external/pegtl/internal/cstring_reader.hh @@ -0,0 +1,45 @@ +// Copyright (c) 2016 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_INTERNAL_CSTRING_READER_HH +#define TAO_CPP_PEGTL_INTERNAL_CSTRING_READER_HH + +#include +#include + +#include "../input_error.hh" + +namespace tao_json_pegtl +{ + namespace internal + { + struct cstring_reader + { + explicit + cstring_reader( const char * zero_terminated ) + : m_cstring( zero_terminated ) + { + assert( m_cstring ); + } + + std::size_t operator() ( char * buffer, const std::size_t length ) + { + std::size_t i = 0; + char c; + + while ( ( i < length ) && ( ( c = m_cstring[ i ] ) != 0 ) ) { + *buffer++ = c; + ++i; + } + m_cstring += i; + return i; + } + + const char * m_cstring; + }; + + } // namespace internal + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/internal/demangle.hh b/share/include/tao/json/external/pegtl/internal/demangle.hh new file mode 100644 index 0000000..70f4563 --- /dev/null +++ b/share/include/tao/json/external/pegtl/internal/demangle.hh @@ -0,0 +1,36 @@ +// Copyright (c) 2014-2015 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_INTERNAL_DEMANGLE_HH +#define TAO_CPP_PEGTL_INTERNAL_DEMANGLE_HH + +#include +#include + +#if defined(__GLIBCXX__) +#include "demangle_cxxabi.hh" +#elif defined(__has_include) +#if __has_include() +#include "demangle_cxxabi.hh" +#else +#include "demangle_nop.hh" +#endif +#else +#include "demangle_nop.hh" +#endif + +namespace tao_json_pegtl +{ + namespace internal + { + template< typename T > + std::string demangle() + { + return demangle( typeid( T ).name() ); + } + + } // namespace internal + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/internal/demangle_cxxabi.hh b/share/include/tao/json/external/pegtl/internal/demangle_cxxabi.hh new file mode 100644 index 0000000..9988b02 --- /dev/null +++ b/share/include/tao/json/external/pegtl/internal/demangle_cxxabi.hh @@ -0,0 +1,26 @@ +// Copyright (c) 2014-2015 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_INTERNAL_DEMANGLE_CXXABI_HH +#define TAO_CPP_PEGTL_INTERNAL_DEMANGLE_CXXABI_HH + +#include +#include +#include +#include + +namespace tao_json_pegtl +{ + namespace internal + { + inline std::string demangle( const char * symbol ) + { + const std::unique_ptr< char, decltype( & std::free ) > demangled( abi::__cxa_demangle( symbol, nullptr, nullptr, nullptr ), & std::free ); + return demangled ? demangled.get() : symbol; + } + + } // namespace internal + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/internal/demangle_nop.hh b/share/include/tao/json/external/pegtl/internal/demangle_nop.hh new file mode 100644 index 0000000..c03d145 --- /dev/null +++ b/share/include/tao/json/external/pegtl/internal/demangle_nop.hh @@ -0,0 +1,22 @@ +// Copyright (c) 2014-2015 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_INTERNAL_DEMANGLE_NOP_HH +#define TAO_CPP_PEGTL_INTERNAL_DEMANGLE_NOP_HH + +#include + +namespace tao_json_pegtl +{ + namespace internal + { + inline std::string demangle( const char * symbol ) + { + return symbol; + } + + } // namespace internal + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/internal/disable.hh b/share/include/tao/json/external/pegtl/internal/disable.hh new file mode 100644 index 0000000..bd307dc --- /dev/null +++ b/share/include/tao/json/external/pegtl/internal/disable.hh @@ -0,0 +1,36 @@ +// Copyright (c) 2014-2015 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_INTERNAL_DISABLE_HH +#define TAO_CPP_PEGTL_INTERNAL_DISABLE_HH + +#include "skip_control.hh" +#include "seq.hh" +#include "rule_match_three.hh" + +#include "../analysis/generic.hh" + +namespace tao_json_pegtl +{ + namespace internal + { + template< typename ... Rules > + struct disable + { + using analyze_t = analysis::generic< analysis::rule_type::SEQ, Rules ... >; + + template< apply_mode, template< typename ... > class Action, template< typename ... > class Control, typename Input, typename ... States > + static bool match( Input & in, States && ... st ) + { + return rule_match_three< seq< Rules ... >, apply_mode::NOTHING, Action, Control >::match( in, st ... ); + } + }; + + template< typename ... Rules > + struct skip_control< disable< Rules ... > > : std::true_type {}; + + } // namespace internal + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/internal/discard.hh b/share/include/tao/json/external/pegtl/internal/discard.hh new file mode 100644 index 0000000..0efd6c0 --- /dev/null +++ b/share/include/tao/json/external/pegtl/internal/discard.hh @@ -0,0 +1,34 @@ +// Copyright (c) 2016 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_INTERNAL_DISCARD_HH +#define TAO_CPP_PEGTL_INTERNAL_DISCARD_HH + +#include "skip_control.hh" + +#include "../analysis/generic.hh" + +namespace tao_json_pegtl +{ + namespace internal + { + struct discard + { + using analyze_t = analysis::generic< analysis::rule_type::OPT >; + + template< typename Input > + static bool match( Input & in ) + { + in.discard(); + return true; + } + }; + + template<> + struct skip_control< discard > : std::true_type {}; + + } // namespace internal + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/internal/discard_if.hh b/share/include/tao/json/external/pegtl/internal/discard_if.hh new file mode 100644 index 0000000..92ee7fa --- /dev/null +++ b/share/include/tao/json/external/pegtl/internal/discard_if.hh @@ -0,0 +1,40 @@ +// Copyright (c) 2016 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_INTERNAL_DISCARD_IF_HH +#define TAO_CPP_PEGTL_INTERNAL_DISCARD_IF_HH + +#include "skip_control.hh" +#include "seq.hh" +#include "rule_match_three.hh" + +#include "../analysis/generic.hh" + +namespace tao_json_pegtl +{ + namespace internal + { + template< typename ... Rules > + struct discard_if + { + using analyze_t = analysis::generic< analysis::rule_type::SEQ, Rules ... >; + + template< apply_mode, template< typename ... > class Action, template< typename ... > class Control, typename Input, typename ... States > + static bool match( Input & in, States && ... st ) + { + if ( rule_match_three< seq< Rules ... >, apply_mode::ACTION, Action, Control >::match( in, st ... ) ) { + in.discard(); + return true; + } + return false; + } + }; + + template< typename ... Rules > + struct skip_control< discard_if< Rules ... > > : std::true_type {}; + + } // namespace internal + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/internal/enable.hh b/share/include/tao/json/external/pegtl/internal/enable.hh new file mode 100644 index 0000000..e4fce74 --- /dev/null +++ b/share/include/tao/json/external/pegtl/internal/enable.hh @@ -0,0 +1,36 @@ +// Copyright (c) 2014-2015 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_INTERNAL_ENABLE_HH +#define TAO_CPP_PEGTL_INTERNAL_ENABLE_HH + +#include "skip_control.hh" +#include "seq.hh" +#include "rule_match_three.hh" + +#include "../analysis/generic.hh" + +namespace tao_json_pegtl +{ + namespace internal + { + template< typename ... Rules > + struct enable + { + using analyze_t = analysis::generic< analysis::rule_type::SEQ, Rules ... >; + + template< apply_mode, template< typename ... > class Action, template< typename ... > class Control, typename Input, typename ... States > + static bool match( Input & in, States && ... st ) + { + return rule_match_three< seq< Rules ... >, apply_mode::ACTION, Action, Control >::match( in, st ... ); + } + }; + + template< typename ... Rules > + struct skip_control< enable< Rules ... > > : std::true_type {}; + + } // namespace internal + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/internal/eof.hh b/share/include/tao/json/external/pegtl/internal/eof.hh new file mode 100644 index 0000000..c3004ae --- /dev/null +++ b/share/include/tao/json/external/pegtl/internal/eof.hh @@ -0,0 +1,33 @@ +// Copyright (c) 2014-2015 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_INTERNAL_EOF_HH +#define TAO_CPP_PEGTL_INTERNAL_EOF_HH + +#include "skip_control.hh" + +#include "../analysis/generic.hh" + +namespace tao_json_pegtl +{ + namespace internal + { + struct eof + { + using analyze_t = analysis::generic< analysis::rule_type::OPT >; + + template< typename Input > + static bool match( Input & in ) + { + return in.empty(); + } + }; + + template<> + struct skip_control< eof > : std::true_type {}; + + } // namespace internal + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/internal/eol.hh b/share/include/tao/json/external/pegtl/internal/eol.hh new file mode 100644 index 0000000..94095a3 --- /dev/null +++ b/share/include/tao/json/external/pegtl/internal/eol.hh @@ -0,0 +1,34 @@ +// Copyright (c) 2016 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_INTERNAL_EOL_HH +#define TAO_CPP_PEGTL_INTERNAL_EOL_HH + +#include "skip_control.hh" + +#include "../analysis/generic.hh" + +namespace tao_json_pegtl +{ + namespace internal + { + struct eol + { + using analyze_t = analysis::generic< analysis::rule_type::ANY >; + + template< typename Input > + static bool match( Input & in ) + { + using eol_t = typename Input::eol_t; + return eol_t::match( in ).first; + } + }; + + template<> + struct skip_control< eol > : std::true_type {}; + + } // namespace internal + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/internal/eol_impl.hh b/share/include/tao/json/external/pegtl/internal/eol_impl.hh new file mode 100644 index 0000000..4bb3164 --- /dev/null +++ b/share/include/tao/json/external/pegtl/internal/eol_impl.hh @@ -0,0 +1,108 @@ +// Copyright (c) 2016 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_INTERNAL_EOL_IMPL_HH +#define TAO_CPP_PEGTL_INTERNAL_EOL_IMPL_HH + +#include + +#include "../eol_mode.hh" + +namespace tao_json_pegtl +{ + namespace internal + { + using eol_pair = std::pair< bool, std::size_t >; + + template< eol_mode EOL > struct eol_impl; + + template<> struct eol_impl< eol_mode::LF_ONLY > + { + template< typename Input > + static eol_pair match( Input & in ) + { + eol_pair p = { false, in.size( 1 ) }; + if ( p.second ) { + if ( in.peek_char() == '\n' ) { + in.bump_to_next_line(); + p.first = true; + } + } + return p; + } + }; + + template<> struct eol_impl< eol_mode::CR_ONLY > + { + template< typename Input > + static eol_pair match( Input & in ) + { + eol_pair p = { false, in.size( 1 ) }; + if ( p.second ) { + if ( in.peek_char() == '\r' ) { + in.bump_to_next_line(); + p.first = true; + } + } + return p; + } + }; + + template<> struct eol_impl< eol_mode::CRLF_ONLY > + { + template< typename Input > + static eol_pair match( Input & in ) + { + eol_pair p = { false, in.size( 2 ) }; + if ( p.second > 1 ) { + if ( ( in.peek_char() == '\r' ) && ( in.peek_char( 1 ) == '\n' ) ) { + in.bump_to_next_line( 2 ); + p.first = true; + } + } + return p; + } + }; + + template<> struct eol_impl< eol_mode::LF_WITH_CRLF > + { + template< typename Input > + static eol_pair match( Input & in ) + { + eol_pair p = { false, in.size( 2 ) }; + if ( p.second ) { + const auto a = in.peek_char(); + if ( a == '\n' ) { + in.bump_to_next_line(); + p.first = true; + } + else if ( ( a == '\r' ) && ( p.second > 1 ) && ( in.peek_char( 1 ) == '\n' ) ) { + in.bump_to_next_line( 2 ); + p.first = true; + } + } + return p; + } + }; + + template<> struct eol_impl< eol_mode::CR_WITH_CRLF > + { + template< typename Input > + static eol_pair match( Input & in ) + { + eol_pair p = { false, in.size( 2 ) }; + if ( p.second ) { + if ( in.peek_char() == '\r' ) { + in.bump_to_next_line( 1 + ( ( p.second > 1 ) && ( in.peek_char( 1 ) == '\n' ) ) ); + p.first = true; + } + } + return p; + } + }; + + } // namespace internal + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/internal/eolf.hh b/share/include/tao/json/external/pegtl/internal/eolf.hh new file mode 100644 index 0000000..07d268e --- /dev/null +++ b/share/include/tao/json/external/pegtl/internal/eolf.hh @@ -0,0 +1,35 @@ +// Copyright (c) 2014-2016 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_INTERNAL_EOLF_HH +#define TAO_CPP_PEGTL_INTERNAL_EOLF_HH + +#include "skip_control.hh" + +#include "../analysis/generic.hh" + +namespace tao_json_pegtl +{ + namespace internal + { + struct eolf + { + using analyze_t = analysis::generic< analysis::rule_type::OPT >; + + template< typename Input > + static bool match( Input & in ) + { + using eol_t = typename Input::eol_t; + const auto p = eol_t::match( in ); + return p.first || ( ! p.second ); + } + }; + + template<> + struct skip_control< eolf > : std::true_type {}; + + } // namespace internal + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/internal/file_mapper.hh b/share/include/tao/json/external/pegtl/internal/file_mapper.hh new file mode 100644 index 0000000..7ef9183 --- /dev/null +++ b/share/include/tao/json/external/pegtl/internal/file_mapper.hh @@ -0,0 +1,85 @@ +// Copyright (c) 2014-2016 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_INTERNAL_FILE_MAPPER_HH +#define TAO_CPP_PEGTL_INTERNAL_FILE_MAPPER_HH + +#include +#include + +#include "file_opener.hh" +#include "../input_error.hh" + +namespace tao_json_pegtl +{ + namespace internal + { + class file_mapper + { + public: + explicit + file_mapper( const std::string & filename ) + : file_mapper( file_opener( filename ) ) + { } + + explicit + file_mapper( const file_opener & reader ) + : m_size( reader.size() ), + m_data( static_cast< const char * >( ::mmap( nullptr, m_size, PROT_READ, MAP_FILE | MAP_PRIVATE, reader.m_fd, 0 ) ) ) + { + if ( m_size && ( intptr_t( m_data ) == -1 ) ) { + TAO_CPP_PEGTL_THROW_INPUT_ERROR( "unable to mmap() file " << reader.m_source << " descriptor " << reader.m_fd ); + } + } + + ~file_mapper() + { + ::munmap( const_cast< char * >( m_data ), m_size ); // Legacy C interface requires pointer-to-mutable but does not write through the pointer. + } + + file_mapper( const file_mapper & ) = delete; + void operator= ( const file_mapper & ) = delete; + + bool empty() const + { + return m_size == 0; + } + + std::size_t size() const + { + return m_size; + } + + using iterator = const char *; + using const_iterator = const char *; + + iterator data() const + { + return m_data; + } + + iterator begin() const + { + return m_data; + } + + iterator end() const + { + return m_data + m_size; + } + + std::string string() const + { + return std::string( m_data, m_size ); + } + + private: + const std::size_t m_size; + const char * const m_data; + }; + + } // namespace internal + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/internal/file_opener.hh b/share/include/tao/json/external/pegtl/internal/file_opener.hh new file mode 100644 index 0000000..a5c221d --- /dev/null +++ b/share/include/tao/json/external/pegtl/internal/file_opener.hh @@ -0,0 +1,65 @@ +// Copyright (c) 2014-2016 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_INTERNAL_FILE_OPENER_HH +#define TAO_CPP_PEGTL_INTERNAL_FILE_OPENER_HH + +#include +#include +#include +#include + +#include + +#include "../input_error.hh" + +namespace tao_json_pegtl +{ + namespace internal + { + struct file_opener + { + explicit + file_opener( std::string filename ) + : m_source( std::move( filename ) ), + m_fd( open() ) + { } + + ~file_opener() + { + ::close( m_fd ); + } + + file_opener( const file_opener & ) = delete; + void operator= ( const file_opener & ) = delete; + + std::size_t size() const + { + struct stat st; + errno = 0; + if ( ::fstat( m_fd, & st ) < 0 ) { + TAO_CPP_PEGTL_THROW_INPUT_ERROR( "unable to fstat() file " << m_source << " descriptor " << m_fd ); + } + return std::size_t( st.st_size ); + } + + const std::string m_source; + const int m_fd; + + private: + int open() const + { + errno = 0; + const int fd = ::open( m_source.c_str(), O_RDONLY ); + if ( fd >= 0 ) { + return fd; + } + TAO_CPP_PEGTL_THROW_INPUT_ERROR( "unable to open() file " << m_source << " for reading" ); + } + }; + + } // namespace internal + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/internal/file_reader.hh b/share/include/tao/json/external/pegtl/internal/file_reader.hh new file mode 100644 index 0000000..04fe2b2 --- /dev/null +++ b/share/include/tao/json/external/pegtl/internal/file_reader.hh @@ -0,0 +1,83 @@ +// Copyright (c) 2014-2017 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_INTERNAL_FILE_READER_HH +#define TAO_CPP_PEGTL_INTERNAL_FILE_READER_HH + +#include +#include +#include +#include + +#include "../input_error.hh" + +namespace tao_json_pegtl +{ + namespace internal + { + class file_reader + { + public: + explicit + file_reader( std::string filename ) + : m_source( std::move( filename ) ), + m_file( open(), & std::fclose ) + { } + + file_reader( const file_reader & ) = delete; + void operator= ( const file_reader & ) = delete; + + std::size_t size() const + { + errno = 0; + if ( std::fseek( m_file.get(), 0, SEEK_END ) != 0 ) { + TAO_CPP_PEGTL_THROW_INPUT_ERROR( "unable to fseek() to end of file " << m_source ); // LCOV_EXCL_LINE + } + errno = 0; + const auto s = std::ftell( m_file.get() ); + if ( s < 0 ) { + TAO_CPP_PEGTL_THROW_INPUT_ERROR( "unable to ftell() file size of file " << m_source ); // LCOV_EXCL_LINE + } + errno = 0; + if ( std::fseek( m_file.get(), 0, SEEK_SET ) != 0 ) { + TAO_CPP_PEGTL_THROW_INPUT_ERROR( "unable to fseek() to beginning of file " << m_source ); // LCOV_EXCL_LINE + } + return s; + } + + std::string read() const + { + std::string nrv; + nrv.resize( size() ); + errno = 0; + if ( ( nrv.size() != 0 ) && ( std::fread( & nrv[ 0 ], nrv.size(), 1, m_file.get() ) != 1 ) ) { + TAO_CPP_PEGTL_THROW_INPUT_ERROR( "unable to fread() file " << m_source << " size " << nrv.size() ); // LCOV_EXCL_LINE + } + return nrv; + } + + private: + const std::string m_source; + const std::unique_ptr< std::FILE, decltype( & std::fclose ) > m_file; + + std::FILE * open() const + { + errno = 0; +#ifdef _WIN32 + std::FILE* file; + if ( ::fopen_s( & file, m_source.c_str(), "rb" ) == 0 ) +#else + if ( auto * file = std::fopen( m_source.c_str(), "rb" ) ) +#endif + { + return file; + } + TAO_CPP_PEGTL_THROW_INPUT_ERROR( "unable to fopen() file " << m_source << " for reading" ); + } + }; + + } // namespace internal + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/internal/if_must.hh b/share/include/tao/json/external/pegtl/internal/if_must.hh new file mode 100644 index 0000000..79742ee --- /dev/null +++ b/share/include/tao/json/external/pegtl/internal/if_must.hh @@ -0,0 +1,21 @@ +// Copyright (c) 2014-2015 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_INTERNAL_IF_MUST_HH +#define TAO_CPP_PEGTL_INTERNAL_IF_MUST_HH + +#include "seq.hh" +#include "must.hh" + +namespace tao_json_pegtl +{ + namespace internal + { + template< typename Cond, typename ... Thens > + using if_must = seq< Cond, must< Thens ... > >; + + } // namespace internal + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/internal/if_must_else.hh b/share/include/tao/json/external/pegtl/internal/if_must_else.hh new file mode 100644 index 0000000..fc5f48c --- /dev/null +++ b/share/include/tao/json/external/pegtl/internal/if_must_else.hh @@ -0,0 +1,21 @@ +// Copyright (c) 2014-2015 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_INTERNAL_IF_MUST_ELSE_HH +#define TAO_CPP_PEGTL_INTERNAL_IF_MUST_ELSE_HH + +#include "if_then_else.hh" +#include "must.hh" + +namespace tao_json_pegtl +{ + namespace internal + { + template< typename Cond, typename Then, typename Else > + using if_must_else = if_then_else< Cond, must< Then >, must< Else > >; + + } // namespace internal + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/internal/if_then_else.hh b/share/include/tao/json/external/pegtl/internal/if_then_else.hh new file mode 100644 index 0000000..db1fee1 --- /dev/null +++ b/share/include/tao/json/external/pegtl/internal/if_then_else.hh @@ -0,0 +1,42 @@ +// Copyright (c) 2014-2016 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_INTERNAL_IF_THEN_ELSE_HH +#define TAO_CPP_PEGTL_INTERNAL_IF_THEN_ELSE_HH + +#include "sor.hh" +#include "seq.hh" +#include "not_at.hh" +#include "skip_control.hh" + +#include "../analysis/generic.hh" + +namespace tao_json_pegtl +{ + namespace internal + { + template< typename Cond, typename Then, typename Else > + struct if_then_else + { + using analyze_t = analysis::generic< analysis::rule_type::SOR, seq< Cond, Then >, seq< not_at< Cond >, Else > >; + + template< apply_mode A, template< typename ... > class Action, template< typename ... > class Control, typename Input, typename ... States > + static bool match( Input & in, States && ... st ) + { + auto m = in.mark(); + + if ( Control< Cond >::template match< A, Action, Control >( in, st ... ) ) { + return m( Control< Then >::template match< A, Action, Control >( in, st ... ) ); + } + return m( Control< Else >::template match< A, Action, Control >( in, st ... ) ); + } + }; + + template< typename Cond, typename Then, typename Else > + struct skip_control< if_then_else< Cond, Then, Else > > : std::true_type {}; + + } // namespace internal + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/internal/input_data.hh b/share/include/tao/json/external/pegtl/internal/input_data.hh new file mode 100644 index 0000000..d99024a --- /dev/null +++ b/share/include/tao/json/external/pegtl/internal/input_data.hh @@ -0,0 +1,67 @@ +// Copyright (c) 2014-2016 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_INTERNAL_INPUT_DATA_HH +#define TAO_CPP_PEGTL_INTERNAL_INPUT_DATA_HH + +#include + +namespace tao_json_pegtl +{ + namespace internal + { + struct input_data + { + input_data( const std::size_t in_byte, const std::size_t in_line, const std::size_t in_byte_in_line, const char * in_begin, const char * in_end, const char * in_source ) + : byte( in_byte ), + line( in_line ), + byte_in_line( in_byte_in_line ), + begin( in_begin ), + end( in_end ), + source( in_source ) + { } + + std::size_t byte; + std::size_t line; + std::size_t byte_in_line; + + const char * begin; + const char * end; + const char * source; + + void bump( const std::size_t count, const int ch ) + { + for ( std::size_t i = 0; i < count; ++i ) { + if ( begin[ i ] == ch ) { + ++line; + byte_in_line = 0; + } + else { + ++byte_in_line; + } + } + begin += count; + byte += count; + } + + void bump_in_this_line( const std::size_t count ) + { + byte += count; + begin += count; + byte_in_line += count; + } + + void bump_to_next_line( const std::size_t count ) + { + ++line; + byte += count; + begin += count; + byte_in_line = 0; + } + }; + + } // namespace internal + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/internal/input_mark.hh b/share/include/tao/json/external/pegtl/internal/input_mark.hh new file mode 100644 index 0000000..10b244d --- /dev/null +++ b/share/include/tao/json/external/pegtl/internal/input_mark.hh @@ -0,0 +1,89 @@ +// Copyright (c) 2014-2016 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_INTERNAL_INPUT_MARK_HH +#define TAO_CPP_PEGTL_INTERNAL_INPUT_MARK_HH + +#include "input_data.hh" + +namespace tao_json_pegtl +{ + namespace internal + { + class input_mark + { + public: + explicit + input_mark( input_data & i ) + : m_byte( i.byte ), + m_line( i.line ), + m_byte_in_line( i.byte_in_line ), + m_begin( i.begin ), + m_input( & i ) + { } + + input_mark( input_mark && i ) noexcept + : m_byte( i.m_byte ), + m_line( i.m_line ), + m_byte_in_line( i.m_byte_in_line ), + m_begin( i.m_begin ), + m_input( i.m_input ) + { + i.m_input = nullptr; + } + + ~input_mark() + { + if ( m_input != nullptr ) { + m_input->byte = m_byte; + m_input->line = m_line; + m_input->byte_in_line = m_byte_in_line; + m_input->begin = m_begin; + } + } + + input_mark( const input_mark & ) = delete; + void operator= ( const input_mark & ) = delete; + + bool operator() ( const bool result ) + { + if ( result ) { + m_input = nullptr; + return true; + } + return false; + } + + std::size_t byte() const + { + return m_byte; + } + + std::size_t line() const + { + return m_line; + } + + std::size_t byte_in_line() const + { + return m_byte_in_line; + } + + const char * begin() const + { + return m_begin; + } + + private: + const std::size_t m_byte; + const std::size_t m_line; + const std::size_t m_byte_in_line; + const char * const m_begin; + input_data * m_input; + }; + + } // namespace internal + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/internal/input_pair.hh b/share/include/tao/json/external/pegtl/internal/input_pair.hh new file mode 100644 index 0000000..03a9599 --- /dev/null +++ b/share/include/tao/json/external/pegtl/internal/input_pair.hh @@ -0,0 +1,29 @@ +// Copyright (c) 2014-2015 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_INTERNAL_INPUT_PAIR_HH +#define TAO_CPP_PEGTL_INTERNAL_INPUT_PAIR_HH + +namespace tao_json_pegtl +{ + namespace internal + { + template< typename Data > + struct input_pair + { + Data data; + unsigned char size; + + using data_t = Data; + + explicit operator bool () const + { + return size > 0; + } + }; + + } // namespace internal + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/internal/istream_reader.hh b/share/include/tao/json/external/pegtl/internal/istream_reader.hh new file mode 100644 index 0000000..a785da6 --- /dev/null +++ b/share/include/tao/json/external/pegtl/internal/istream_reader.hh @@ -0,0 +1,42 @@ +// Copyright (c) 2016 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_INTERNAL_ISTREAM_READER_HH +#define TAO_CPP_PEGTL_INTERNAL_ISTREAM_READER_HH + +#include + +#include "../input_error.hh" + +namespace tao_json_pegtl +{ + namespace internal + { + struct istream_reader + { + explicit + istream_reader( std::istream & s ) + : m_istream( s ) + { } + + std::size_t operator() ( char * buffer, const std::size_t length ) + { + m_istream.read( buffer, length ); + + if ( const auto r = m_istream.gcount() ) { + return r; + } + if ( m_istream.eof() ) { + return 0; + } + TAO_CPP_PEGTL_THROW_INPUT_ERROR( "error in istream.read()" ); + } + + std::istream & m_istream; + }; + + } // namespace internal + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/internal/istring.hh b/share/include/tao/json/external/pegtl/internal/istring.hh new file mode 100644 index 0000000..d0bab46 --- /dev/null +++ b/share/include/tao/json/external/pegtl/internal/istring.hh @@ -0,0 +1,89 @@ +// Copyright (c) 2014-2016 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_INTERNAL_ISTRING_HH +#define TAO_CPP_PEGTL_INTERNAL_ISTRING_HH + +#include + +#include "result_on_found.hh" +#include "skip_control.hh" +#include "bump_util.hh" +#include "trivial.hh" + +#include "../analysis/counted.hh" + +namespace tao_json_pegtl +{ + namespace internal + { + template< char C > + using is_alpha = std::integral_constant< bool, ( ( 'a' <= C ) && ( C <= 'z' ) ) || ( ( 'A' <= C ) && ( C <= 'Z' ) ) >; + + template< char C, bool A = is_alpha< C >::value > struct ichar_equal; + + template< char C > struct ichar_equal< C, true > + { + static bool match( const char c ) + { + return ( C | 0x20 ) == ( c | 0x20 ); + } + }; + + template< char C > struct ichar_equal< C, false > + { + static bool match( const char c ) + { + return c == C; + } + }; + + template< char ... Cs > struct istring_equal; + + template<> struct istring_equal<> + { + static bool match( const char * ) + { + return true; + } + }; + + template< char C, char ... Cs > struct istring_equal< C, Cs ... > + { + static bool match( const char * r ) + { + return ichar_equal< C >::match( * r ) && istring_equal< Cs ... >::match( r + 1 ); + } + }; + + template< char ... Cs > struct istring; + + template< char ... Cs > + struct skip_control< istring< Cs ... > > : std::true_type {}; + + template<> struct istring<> + : trivial< true > {}; + + template< char ... Cs > + struct istring + { + using analyze_t = analysis::counted< analysis::rule_type::ANY, sizeof ... ( Cs ) >; + + template< typename Input > + static bool match( Input & in ) + { + if ( in.size( sizeof ... ( Cs ) ) >= sizeof ... ( Cs ) ) { + if ( istring_equal< Cs ... >::match( in.begin() ) ) { + bump< result_on_found::SUCCESS, Input, char, Cs ... >( in, sizeof ... ( Cs ) ); + return true; + } + } + return false; + } + }; + + } // namespace internal + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/internal/list.hh b/share/include/tao/json/external/pegtl/internal/list.hh new file mode 100644 index 0000000..b1cd56c --- /dev/null +++ b/share/include/tao/json/external/pegtl/internal/list.hh @@ -0,0 +1,21 @@ +// Copyright (c) 2014-2015 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_INTERNAL_LIST_HH +#define TAO_CPP_PEGTL_INTERNAL_LIST_HH + +#include "seq.hh" +#include "star.hh" + +namespace tao_json_pegtl +{ + namespace internal + { + template< typename Rule, typename Sep > + using list = seq< Rule, star< Sep, Rule > >; + + } // namespace internal + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/internal/list_must.hh b/share/include/tao/json/external/pegtl/internal/list_must.hh new file mode 100644 index 0000000..c3e18a0 --- /dev/null +++ b/share/include/tao/json/external/pegtl/internal/list_must.hh @@ -0,0 +1,22 @@ +// Copyright (c) 2014-2015 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_INTERNAL_LIST_MUST_HH +#define TAO_CPP_PEGTL_INTERNAL_LIST_MUST_HH + +#include "seq.hh" +#include "star.hh" +#include "must.hh" + +namespace tao_json_pegtl +{ + namespace internal + { + template< typename Rule, typename Sep > + using list_must = seq< Rule, star< Sep, must< Rule > > >; + + } // namespace internal + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/internal/list_tail.hh b/share/include/tao/json/external/pegtl/internal/list_tail.hh new file mode 100644 index 0000000..5dfd312 --- /dev/null +++ b/share/include/tao/json/external/pegtl/internal/list_tail.hh @@ -0,0 +1,22 @@ +// Copyright (c) 2014-2015 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_INTERNAL_LIST_TAIL_HH +#define TAO_CPP_PEGTL_INTERNAL_LIST_TAIL_HH + +#include "seq.hh" +#include "list.hh" +#include "opt.hh" + +namespace tao_json_pegtl +{ + namespace internal + { + template< typename Rule, typename Sep > + using list_tail = seq< list< Rule, Sep >, opt< Sep > >; + + } // namespace internal + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/internal/list_tail_pad.hh b/share/include/tao/json/external/pegtl/internal/list_tail_pad.hh new file mode 100644 index 0000000..6168d7f --- /dev/null +++ b/share/include/tao/json/external/pegtl/internal/list_tail_pad.hh @@ -0,0 +1,24 @@ +// Copyright (c) 2014-2015 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_INTERNAL_LIST_TAIL_PAD_HH +#define TAO_CPP_PEGTL_INTERNAL_LIST_TAIL_PAD_HH + +#include "seq.hh" +#include "list.hh" +#include "pad.hh" +#include "opt.hh" +#include "star.hh" + +namespace tao_json_pegtl +{ + namespace internal + { + template< typename Rule, typename Sep, typename Pad > + using list_tail_pad = seq< list< Rule, pad< Sep, Pad > >, opt< star< Pad >, Sep > >; + + } // namespace internal + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/internal/minus.hh b/share/include/tao/json/external/pegtl/internal/minus.hh new file mode 100644 index 0000000..2f5da19 --- /dev/null +++ b/share/include/tao/json/external/pegtl/internal/minus.hh @@ -0,0 +1,46 @@ +// Copyright (c) 2016 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_INTERNAL_MINUS_HH +#define TAO_CPP_PEGTL_INTERNAL_MINUS_HH + +#include "skip_control.hh" + +#include "../apply_mode.hh" +#include "../memory_input.hh" + +namespace tao_json_pegtl +{ + namespace internal + { + template< typename M, typename S > + struct minus + { + using analyze_t = typename M::analyze_t; // NOTE: S is currently ignored for analyze(). + + template< apply_mode A, template< typename ... > class Action, template< typename ... > class Control, typename Input, typename ... States > + static bool match( Input & in, States && ... st ) + { + auto m = in.mark(); + + if ( ! Control< M >::template match< A, Action, Control >( in, st ... ) ) { + return false; + } + using memory_t = typename Input::memory_t; + memory_t i2( m, in.data() ); + + if ( ! Control< S >::template match< apply_mode::NOTHING, Action, Control >( i2, st ... ) ) { + return m( true ); + } + return m( ! i2.empty() ); + } + }; + + template< typename M, typename S > + struct skip_control< minus< M, S > > : std::true_type {}; + + } // namespace internal + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/internal/must.hh b/share/include/tao/json/external/pegtl/internal/must.hh new file mode 100644 index 0000000..867645a --- /dev/null +++ b/share/include/tao/json/external/pegtl/internal/must.hh @@ -0,0 +1,49 @@ +// Copyright (c) 2014-2015 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_INTERNAL_MUST_HH +#define TAO_CPP_PEGTL_INTERNAL_MUST_HH + +#include "seq.hh" +#include "raise.hh" +#include "skip_control.hh" + +namespace tao_json_pegtl +{ + namespace internal + { + // The general case simply applies must<> to each member of the + // 'Rules' parameter pack individually, below is the specialization + // which implements the case for a single rule. + + template< typename ... Rules > + struct must + : seq< must< Rules > ... > {}; + + // While in theory the implementation for a single rule could + // be simplified to must< Rule > = sor< Rule, raise< Rule > >, this + // would result in some unnecessary run-time overhead. + + template< typename Rule > + struct must< Rule > + { + using analyze_t = typename Rule::analyze_t; + + template< apply_mode A, template< typename ... > class Action, template< typename ... > class Control, typename Input, typename ... States > + static bool match( Input & in, States && ... st ) + { + if ( ! Control< Rule >::template match< A, Action, Control >( in, st ... ) ) { + raise< Rule >::template match< A, Action, Control >( in, st ... ); + } + return true; + } + }; + + template< typename ... Rules > + struct skip_control< must< Rules ... > > : std::true_type {}; + + } // namespace internal + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/internal/not_at.hh b/share/include/tao/json/external/pegtl/internal/not_at.hh new file mode 100644 index 0000000..33f895e --- /dev/null +++ b/share/include/tao/json/external/pegtl/internal/not_at.hh @@ -0,0 +1,43 @@ +// Copyright (c) 2014-2015 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_INTERNAL_NOT_AT_HH +#define TAO_CPP_PEGTL_INTERNAL_NOT_AT_HH + +#include "trivial.hh" +#include "skip_control.hh" +#include "rule_conjunction.hh" + +#include "../analysis/generic.hh" + +namespace tao_json_pegtl +{ + namespace internal + { + template< typename ... Rules > struct not_at; + + template< typename ... Rules > + struct skip_control< not_at< Rules ... > > : std::true_type {}; + + template<> + struct not_at<> + : trivial< false > {}; + + template< typename ... Rules > + struct not_at + { + using analyze_t = analysis::generic< analysis::rule_type::OPT, Rules ... >; + + template< apply_mode, template< typename ... > class Action, template< typename ... > class Control, typename Input, typename ... States > + static bool match( Input & in, States && ... st ) + { + auto m = in.mark(); + return ! rule_conjunction< Rules ... >::template match< apply_mode::NOTHING, Action, Control >( in, st ... ); + } + }; + + } // namespace internal + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/internal/one.hh b/share/include/tao/json/external/pegtl/internal/one.hh new file mode 100644 index 0000000..12e8fc6 --- /dev/null +++ b/share/include/tao/json/external/pegtl/internal/one.hh @@ -0,0 +1,73 @@ +// Copyright (c) 2014-2015 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_INTERNAL_ONE_HH +#define TAO_CPP_PEGTL_INTERNAL_ONE_HH + +#include +#include + +#include "bump_util.hh" +#include "skip_control.hh" +#include "result_on_found.hh" + +#include "../analysis/generic.hh" + +namespace tao_json_pegtl +{ + namespace internal + { + template< typename Char > + bool contains( const Char c, const std::initializer_list< Char > & l ) + { + return std::find( l.begin(), l.end(), c ) != l.end(); + } + + template< result_on_found R, typename Peek, typename Peek::data_t ... Cs > + struct one + { + using analyze_t = analysis::generic< analysis::rule_type::ANY >; + + template< typename Input > + static bool match( Input & in ) + { + if ( ! in.empty() ) { + if ( const auto t = Peek::peek( in ) ) { + if ( contains( t.data, { Cs ... } ) == bool( R ) ) { + bump< R, Input, typename Peek::data_t, Cs ... >( in, t.size ); + return true; + } + } + } + return false; + } + }; + + template< result_on_found R, typename Peek, typename Peek::data_t C > + struct one< R, Peek, C > + { + using analyze_t = analysis::generic< analysis::rule_type::ANY >; + + template< typename Input > + static bool match( Input & in ) + { + if ( ! in.empty() ) { + if ( const auto t = Peek::peek( in ) ) { + if ( ( t.data == C ) == bool( R ) ) { + bump< R, Input, typename Peek::data_t, C >( in, t.size ); + return true; + } + } + } + return false; + } + }; + + template< result_on_found R, typename Peek, typename Peek::data_t ... Cs > + struct skip_control< one< R, Peek, Cs ... > > : std::true_type {}; + + } // namespace internal + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/internal/opt.hh b/share/include/tao/json/external/pegtl/internal/opt.hh new file mode 100644 index 0000000..d872f52 --- /dev/null +++ b/share/include/tao/json/external/pegtl/internal/opt.hh @@ -0,0 +1,49 @@ +// Copyright (c) 2014-2016 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_INTERNAL_OPT_HH +#define TAO_CPP_PEGTL_INTERNAL_OPT_HH + +#include + +#include "skip_control.hh" +#include "rule_match_three.hh" +#include "seq.hh" +#include "trivial.hh" + +#include "../apply_mode.hh" +#include "../analysis/generic.hh" + +namespace tao_json_pegtl +{ + namespace internal + { + template< typename ... Rules > struct opt; + + template< typename ... Rules > + struct skip_control< opt< Rules ... > > : std::true_type {}; + + template<> + struct opt<> + : trivial< true > {}; + + template< typename ... Rules > + struct opt + { + using analyze_t = analysis::generic< analysis::rule_type::OPT, Rules ... >; + + template< apply_mode A, template< typename ... > class Action, template< typename ... > class Control, typename Input, typename ... States > + static bool match( Input & in, States && ... st ) + { + if ( ! in.empty() ) { + rule_match_three< seq< Rules ... >, A, Action, Control >::match( in, st ... ); + } + return true; + } + }; + + } // namespace internal + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/internal/pad.hh b/share/include/tao/json/external/pegtl/internal/pad.hh new file mode 100644 index 0000000..3a04f56 --- /dev/null +++ b/share/include/tao/json/external/pegtl/internal/pad.hh @@ -0,0 +1,21 @@ +// Copyright (c) 2014-2015 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_INTERNAL_PAD_HH +#define TAO_CPP_PEGTL_INTERNAL_PAD_HH + +#include "seq.hh" +#include "star.hh" + +namespace tao_json_pegtl +{ + namespace internal + { + template< typename Rule, typename Pad1, typename Pad2 = Pad1 > + using pad = seq< star< Pad1 >, Rule, star< Pad2 > >; + + } // namespace internal + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/internal/pad_opt.hh b/share/include/tao/json/external/pegtl/internal/pad_opt.hh new file mode 100644 index 0000000..a7de7d3 --- /dev/null +++ b/share/include/tao/json/external/pegtl/internal/pad_opt.hh @@ -0,0 +1,22 @@ +// Copyright (c) 2014-2015 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_INTERNAL_PAD_OPT_HH +#define TAO_CPP_PEGTL_INTERNAL_PAD_OPT_HH + +#include "seq.hh" +#include "opt.hh" +#include "star.hh" + +namespace tao_json_pegtl +{ + namespace internal + { + template< typename Rule, typename Pad > + using pad_opt = seq< star< Pad >, opt< Rule, star< Pad > > >; + + } // namespace internal + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/internal/peek_char.hh b/share/include/tao/json/external/pegtl/internal/peek_char.hh new file mode 100644 index 0000000..2be93d7 --- /dev/null +++ b/share/include/tao/json/external/pegtl/internal/peek_char.hh @@ -0,0 +1,31 @@ +// Copyright (c) 2014-2015 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_INTERNAL_PEEK_CHAR_HH +#define TAO_CPP_PEGTL_INTERNAL_PEEK_CHAR_HH + +#include + +#include "input_pair.hh" + +namespace tao_json_pegtl +{ + namespace internal + { + struct peek_char + { + using data_t = char; + using pair_t = input_pair< char >; + + template< typename Input > + static pair_t peek( Input & in, const std::size_t o = 0 ) + { + return { in.peek_char( o ), 1 }; + } + }; + + } // namespace internal + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/internal/peek_utf16.hh b/share/include/tao/json/external/pegtl/internal/peek_utf16.hh new file mode 100644 index 0000000..8b9994e --- /dev/null +++ b/share/include/tao/json/external/pegtl/internal/peek_utf16.hh @@ -0,0 +1,48 @@ +// Copyright (c) 2014-2016 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_INTERNAL_PEEK_UTF16_HH +#define TAO_CPP_PEGTL_INTERNAL_PEEK_UTF16_HH + +#include + +#include "input_pair.hh" + +namespace tao_json_pegtl +{ + namespace internal + { + struct peek_utf16 + { + using data_t = char32_t; + using pair_t = input_pair< char32_t >; + + using short_t = std::make_unsigned< char16_t >::type; + + static_assert( sizeof( short_t ) == 2, "expected size 2 for 16bit value" ); + static_assert( sizeof( char16_t ) == 2, "expected size 2 for 16bit value" ); + + template< typename Input > + static pair_t peek( Input & in ) + { + const std::size_t s = in.size( 4 ); + if ( s >= 2 ) { + const char32_t t = * reinterpret_cast< const short_t * >( in.begin() ); + if ( ( t < 0xd800 ) || ( t > 0xdbff ) || ( s < 4 ) ) { + return { t, 2 }; + } + const char32_t u = * reinterpret_cast< const short_t * >( in.begin() + 2 ); + if ( ( u < 0xdc00 ) || ( u > 0xdfff ) ) { + return { t, 2 }; + } + return { ( ( ( t & 0x03ff ) << 10 ) | ( u & 0x03ff ) ) + 0x10000, 4 }; + } + return { 0, 0 }; + } + }; + + } // namespace internal + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/internal/peek_utf32.hh b/share/include/tao/json/external/pegtl/internal/peek_utf32.hh new file mode 100644 index 0000000..c5fe766 --- /dev/null +++ b/share/include/tao/json/external/pegtl/internal/peek_utf32.hh @@ -0,0 +1,47 @@ +// Copyright (c) 2014-2016 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_INTERNAL_PEEK_UTF32_HH +#define TAO_CPP_PEGTL_INTERNAL_PEEK_UTF32_HH + +#include + +#include "input_pair.hh" + +namespace tao_json_pegtl +{ + namespace internal + { + struct peek_utf32 + { + using data_t = char32_t; + using pair_t = input_pair< char32_t >; + + static_assert( sizeof( char32_t ) == 4, "expected size 4 for 32bit value" ); + + // suppress warning with GCC 4.7 + template< typename T > + static inline bool dummy_less_or_equal( const T a, const T b ) + { + return a <= b; + } + + template< typename Input > + static pair_t peek( Input & in ) + { + const std::size_t s = in.size( 4 ); + if ( s >= 4 ) { + const char32_t t = * reinterpret_cast< const char32_t * >( in.begin() ); + if ( dummy_less_or_equal< char32_t >( 0, t ) && dummy_less_or_equal< char32_t >( t, 0x10ffff ) ) { + return { t, 4 }; + } + } + return { 0, 0 }; + } + }; + + } // namespace internal + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/internal/peek_utf8.hh b/share/include/tao/json/external/pegtl/internal/peek_utf8.hh new file mode 100644 index 0000000..dbdbd00 --- /dev/null +++ b/share/include/tao/json/external/pegtl/internal/peek_utf8.hh @@ -0,0 +1,82 @@ +// Copyright (c) 2014-2016 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_INTERNAL_PEEK_UTF8_HH +#define TAO_CPP_PEGTL_INTERNAL_PEEK_UTF8_HH + +#include "input_pair.hh" + +namespace tao_json_pegtl +{ + namespace internal + { + struct peek_utf8 + { + using data_t = char32_t; + using pair_t = input_pair< char32_t >; + + template< typename Input > + static pair_t peek( Input & in ) + { + char32_t c0 = in.peek_byte(); + + if ( ( c0 & 0x80 ) == 0 ) { + return { c0, 1 }; + } + if ( ( c0 & 0xE0 ) == 0xC0 ) { + if ( in.size( 2 ) >= 2 ) { + const char32_t c1 = in.peek_byte( 1 ); + if ( ( c1 & 0xC0 ) == 0x80 ) { + c0 &= 0x1F; + c0 <<= 6; + c0 |= ( c1 & 0x3F ); + if ( c0 >= 0x80 ) { + return { c0, 2 }; + } + } + } + } + else if ( ( c0 & 0xF0 ) == 0xE0 ) { + if ( in.size( 3 ) >= 3 ) { + const char32_t c1 = in.peek_byte( 1 ); + const char32_t c2 = in.peek_byte( 2 ); + if( ( ( c1 & 0xC0 ) == 0x80 ) && ( ( c2 & 0xC0 ) == 0x80 ) ) { + c0 &= 0x0F; + c0 <<= 6; + c0 |= ( c1 & 0x3F ); + c0 <<= 6; + c0 |= ( c2 & 0x3F ); + if ( c0 >= 0x800 ) { + return { c0, 3 }; + } + } + } + } + else if ( ( c0 & 0xF8 ) == 0xF0 ) { + if ( in.size( 4 ) >= 4 ) { + const char32_t c1 = in.peek_byte( 1 ); + const char32_t c2 = in.peek_byte( 2 ); + const char32_t c3 = in.peek_byte( 3 ); + if ( ( ( c1 & 0xC0 ) == 0x80 ) && ( ( c2 & 0xC0 ) == 0x80 ) && ( ( c3 & 0xC0 ) == 0x80 ) ) { + c0 &= 0x07; + c0 <<= 6; + c0 |= ( c1 & 0x3F ); + c0 <<= 6; + c0 |= ( c2 & 0x3F ); + c0 <<= 6; + c0 |= ( c3 & 0x3F ); + if ( c0 >= 0x10000 && c0 <= 0x10FFFF ) { + return { c0, 4 }; + } + } + } + } + return { 0, 0 }; + } + }; + + } // namespace internal + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/internal/pegtl_string.hh b/share/include/tao/json/external/pegtl/internal/pegtl_string.hh new file mode 100644 index 0000000..3a1d305 --- /dev/null +++ b/share/include/tao/json/external/pegtl/internal/pegtl_string.hh @@ -0,0 +1,91 @@ +// Copyright (c) 2015-2016 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_INTERNAL_TAO_CPP_PEGTL_STRING_HH +#define TAO_CPP_PEGTL_INTERNAL_TAO_CPP_PEGTL_STRING_HH + +#include +#include + +#include "../ascii.hh" + +namespace tao_json_pegtl +{ + // Inspired by https://github.com/irrequietus/typestring + // Rewritten and reduced to what is needed for the PEGTL + // and to work with Visual Studio 2015. + + namespace internal + { + template< typename, typename, typename, typename, typename, typename, typename, typename > + struct string_join; + + template< template< char ... > class S, char ... C0s, char ... C1s, char ... C2s, char ... C3s, char ... C4s, char ... C5s, char ... C6s, char ... C7s > + struct string_join< S< C0s ... >, S< C1s ... >, S< C2s ... >, S< C3s ... >, S< C4s ... >, S< C5s ... >, S< C6s ... >, S< C7s ... > > + { + using type = S< C0s ..., C1s ..., C2s ..., C3s ..., C4s ..., C5s ..., C6s ..., C7s ... >; + }; + + template< template< char ... > class S, char, bool > + struct string_at + { + using type = S<>; + }; + + template< template< char ... > class S, char C > + struct string_at< S, C, true > + { + using type = S< C >; + }; + + template< typename T, std::size_t S > + struct string_max_length + { + static_assert( S <= 512, "String longer than 512 (excluding terminating \\0)!" ); + using type = T; + }; + + } // namespace internal + +} // namespace tao_json_pegtl + +#define TAO_CPP_PEGTL_INTERNAL_EMPTY() +#define TAO_CPP_PEGTL_INTERNAL_DEFER( X ) X TAO_CPP_PEGTL_INTERNAL_EMPTY() +#define TAO_CPP_PEGTL_INTERNAL_EXPAND(...) __VA_ARGS__ + +#define TAO_CPP_PEGTL_INTERNAL_STRING_AT( S, x, n ) \ + tao_json_pegtl::internal::string_at< S, ( 0##n < sizeof( x ) ) ? x[ 0##n ] : 0, ( 0##n < sizeof( x ) - 1 ) >::type + +#define TAO_CPP_PEGTL_INTERNAL_JOIN_8( M, S, x, n ) \ + tao_json_pegtl::internal::string_join< \ + TAO_CPP_PEGTL_INTERNAL_DEFER( M )( S, x, n##0 ), \ + TAO_CPP_PEGTL_INTERNAL_DEFER( M )( S, x, n##1 ), \ + TAO_CPP_PEGTL_INTERNAL_DEFER( M )( S, x, n##2 ), \ + TAO_CPP_PEGTL_INTERNAL_DEFER( M )( S, x, n##3 ), \ + TAO_CPP_PEGTL_INTERNAL_DEFER( M )( S, x, n##4 ), \ + TAO_CPP_PEGTL_INTERNAL_DEFER( M )( S, x, n##5 ), \ + TAO_CPP_PEGTL_INTERNAL_DEFER( M )( S, x, n##6 ), \ + TAO_CPP_PEGTL_INTERNAL_DEFER( M )( S, x, n##7 )>::type + +#define TAO_CPP_PEGTL_INTERNAL_STRING_8( S, x, n ) \ + TAO_CPP_PEGTL_INTERNAL_JOIN_8( TAO_CPP_PEGTL_INTERNAL_STRING_AT, S, x, n ) + +#define TAO_CPP_PEGTL_INTERNAL_STRING_64( S, x, n ) \ + TAO_CPP_PEGTL_INTERNAL_JOIN_8( TAO_CPP_PEGTL_INTERNAL_STRING_8, S, x, n ) + +#define TAO_CPP_PEGTL_INTERNAL_STRING_512( S, x, n ) \ + TAO_CPP_PEGTL_INTERNAL_JOIN_8( TAO_CPP_PEGTL_INTERNAL_STRING_64, S, x, n ) + +#define TAO_CPP_PEGTL_INTERNAL_STRING( S, x ) \ + TAO_CPP_PEGTL_INTERNAL_EXPAND( \ + TAO_CPP_PEGTL_INTERNAL_EXPAND( \ + TAO_CPP_PEGTL_INTERNAL_EXPAND( \ + tao_json_pegtl::internal::string_max_length< TAO_CPP_PEGTL_INTERNAL_STRING_512( S, x, ), sizeof( x ) - 1 >::type ) ) ) + +#define tao_json_pegtl_string_t( x ) \ + TAO_CPP_PEGTL_INTERNAL_STRING( tao_json_pegtl::ascii::string, x ) + +#define tao_json_pegtl_istring_t( x ) \ + TAO_CPP_PEGTL_INTERNAL_STRING( tao_json_pegtl::ascii::istring, x ) + +#endif diff --git a/share/include/tao/json/external/pegtl/internal/plus.hh b/share/include/tao/json/external/pegtl/internal/plus.hh new file mode 100644 index 0000000..8712c97 --- /dev/null +++ b/share/include/tao/json/external/pegtl/internal/plus.hh @@ -0,0 +1,46 @@ +// Copyright (c) 2014-2016 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_INTERNAL_PLUS_HH +#define TAO_CPP_PEGTL_INTERNAL_PLUS_HH + +#include + +#include "opt.hh" +#include "rule_match_three.hh" +#include "seq.hh" +#include "star.hh" +#include "skip_control.hh" + +#include "../apply_mode.hh" +#include "../analysis/generic.hh" + +namespace tao_json_pegtl +{ + namespace internal + { + // While plus<> could easily be implemented with + // seq< Rule, Rules ..., star< Rule, Rules ... > > we + // provide an explicit implementation to optimize away + // the otherwise created input mark. + + template< typename Rule, typename ... Rules > + struct plus + { + using analyze_t = analysis::generic< analysis::rule_type::SEQ, Rule, Rules ..., opt< plus > >; + + template< apply_mode A, template< typename ... > class Action, template< typename ... > class Control, typename Input, typename ... States > + static bool match( Input & in, States && ... st ) + { + return rule_match_three< seq< Rule, Rules ... >, A, Action, Control >::match( in, st ... ) && rule_match_three< star< Rule, Rules ... >, A, Action, Control >::match( in, st ... ); + } + }; + + template< typename Rule, typename ... Rules > + struct skip_control< plus< Rule, Rules ... > > : std::true_type {}; + + } // namespace internal + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/internal/raise.hh b/share/include/tao/json/external/pegtl/internal/raise.hh new file mode 100644 index 0000000..c78ce18 --- /dev/null +++ b/share/include/tao/json/external/pegtl/internal/raise.hh @@ -0,0 +1,39 @@ +// Copyright (c) 2014-2016 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_INTERNAL_RAISE_HH +#define TAO_CPP_PEGTL_INTERNAL_RAISE_HH + +#include +#include + +#include "skip_control.hh" + +#include "../apply_mode.hh" +#include "../analysis/generic.hh" + +namespace tao_json_pegtl +{ + namespace internal + { + template< typename T > + struct raise + { + using analyze_t = analysis::generic< analysis::rule_type::ANY >; + + template< apply_mode A, template< typename ... > class Action, template< typename ... > class Control, typename Input, typename ... States > + static bool match( Input & in, States && ... st ) + { + Control< T >::raise( const_cast< const Input & >( in ), st ... ); + std::abort(); // LCOV_EXCL_LINE + } + }; + + template< typename T > + struct skip_control< raise< T > > : std::true_type {}; + + } // namespace internal + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/internal/range.hh b/share/include/tao/json/external/pegtl/internal/range.hh new file mode 100644 index 0000000..ca32a51 --- /dev/null +++ b/share/include/tao/json/external/pegtl/internal/range.hh @@ -0,0 +1,60 @@ +// Copyright (c) 2014-2015 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_INTERNAL_RANGE_HH +#define TAO_CPP_PEGTL_INTERNAL_RANGE_HH + +#include "any.hh" +#include "bump_util.hh" +#include "skip_control.hh" +#include "result_on_found.hh" + +#include "../analysis/generic.hh" + +namespace tao_json_pegtl +{ + namespace internal + { + template< result_on_found R, typename Peek, typename Peek::data_t Lo, typename Peek::data_t Hi > + struct range + { + using analyze_t = analysis::generic< analysis::rule_type::ANY >; + + template< int Eol > + struct can_match_eol + { + static constexpr bool value = ( ( ( Lo <= Eol ) && ( Eol <= Hi ) ) == bool( R ) ); + }; + + // suppress warning with GCC 4.7 + template< typename T > + static inline bool dummy_less_or_equal( const T a, const T b ) + { + return a <= b; + } + + template< typename Input > + static bool match( Input & in ) + { + using eol_t = typename Input::eol_t; + + if ( ! in.empty() ) { + if ( const auto t = Peek::peek( in ) ) { + if ( ( dummy_less_or_equal( Lo, t.data ) && dummy_less_or_equal( t.data, Hi ) ) == bool( R ) ) { + bump_impl< can_match_eol< eol_t::ch >::value >::bump( in, t.size ); + return true; + } + } + } + return false; + } + }; + + template< result_on_found R, typename Peek, typename Peek::data_t Lo, typename Peek::data_t Hi > + struct skip_control< range< R, Peek, Lo, Hi > > : std::true_type {}; + + } // namespace internal + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/internal/ranges.hh b/share/include/tao/json/external/pegtl/internal/ranges.hh new file mode 100644 index 0000000..dfe3118 --- /dev/null +++ b/share/include/tao/json/external/pegtl/internal/ranges.hh @@ -0,0 +1,92 @@ +// Copyright (c) 2014-2015 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_INTERNAL_RANGES_HH +#define TAO_CPP_PEGTL_INTERNAL_RANGES_HH + +#include "any.hh" +#include "range.hh" +#include "bump_util.hh" +#include "skip_control.hh" + +#include "../analysis/generic.hh" + +namespace tao_json_pegtl +{ + namespace internal + { + template< int Eol, typename Char, Char ... Cs > struct ranges_impl; + + template< int Eol, typename Char > + struct ranges_impl< Eol, Char > + { + static constexpr bool can_match_eol = false; + + static bool match( const Char ) + { + return false; + } + }; + + template< int Eol, typename Char, Char Eq > + struct ranges_impl< Eol, Char, Eq > + { + static constexpr bool can_match_eol = ( Eq == Eol ); + + static bool match( const Char c ) + { + return c == Eq; + } + }; + + template< int Eol, typename Char, Char Lo, Char Hi, Char ... Cs > + struct ranges_impl< Eol, Char, Lo, Hi, Cs ... > + { + static constexpr bool can_match_eol = ( ( ( Lo <= Eol ) && ( Eol <= Hi ) ) || ranges_impl< Eol, Char, Cs ... >::can_match_eol ); + + static bool match( const Char c ) + { + return ( ( Lo <= c ) && ( c <= Hi ) ) || ranges_impl< Eol, Char, Cs ... >::match( c ); + } + }; + + template< typename Peek, typename Peek::data_t ... Cs > + struct ranges + { + using analyze_t = analysis::generic< analysis::rule_type::ANY >; + + template< int Eol > + struct can_match_eol + { + static constexpr bool value = ranges_impl< Eol, typename Peek::data_t, Cs ... >::can_match_eol; + }; + + template< typename Input > + static bool match( Input & in ) + { + using eol_t = typename Input::eol_t; + + if ( ! in.empty() ) { + if ( const auto t = Peek::peek( in ) ) { + if ( ranges_impl< eol_t::ch, typename Peek::data_t, Cs ... >::match( t.data ) ) { + bump_impl< can_match_eol< eol_t::ch >::value >::bump( in, t.size ); + return true; + } + } + } + return false; + } + }; + + template< typename Peek, typename Peek::data_t Lo, typename Peek::data_t Hi > + struct ranges< Peek, Lo, Hi > + : range< result_on_found::SUCCESS, Peek, Lo, Hi > {}; + + template< typename Peek, typename Peek::data_t ... Cs > + struct skip_control< ranges< Peek, Cs ... > > : std::true_type {}; + + } // namespace internal + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/internal/rep.hh b/share/include/tao/json/external/pegtl/internal/rep.hh new file mode 100644 index 0000000..7e27551 --- /dev/null +++ b/share/include/tao/json/external/pegtl/internal/rep.hh @@ -0,0 +1,53 @@ +// Copyright (c) 2014-2015 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_INTERNAL_REP_HH +#define TAO_CPP_PEGTL_INTERNAL_REP_HH + +#include "skip_control.hh" +#include "trivial.hh" +#include "rule_conjunction.hh" + +#include "../analysis/counted.hh" + +namespace tao_json_pegtl +{ + namespace internal + { + template< unsigned Num, typename ... Rules > struct rep; + + template< unsigned Num, typename ... Rules > + struct skip_control< rep< Num, Rules ... > > : std::true_type {}; + + template< unsigned Num > + struct rep< Num > + : trivial< true > {}; + + template< typename Rule, typename ... Rules > + struct rep< 0, Rule, Rules ... > + : trivial< true > {}; + + template< unsigned Num, typename ... Rules > + struct rep + { + using analyze_t = analysis::counted< analysis::rule_type::SEQ, Num, Rules ... >; + + template< apply_mode A, template< typename ... > class Action, template< typename ... > class Control, typename Input, typename ... States > + static bool match( Input & in, States && ... st ) + { + auto m = in.mark(); + + for ( unsigned i = 0; i != Num; ++i ) { + if ( ! rule_conjunction< Rules ... >::template match< A, Action, Control >( in, st ... ) ) { + return false; + } + } + return m( true ); + } + }; + + } // namespace internal + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/internal/rep_min.hh b/share/include/tao/json/external/pegtl/internal/rep_min.hh new file mode 100644 index 0000000..d7830ea --- /dev/null +++ b/share/include/tao/json/external/pegtl/internal/rep_min.hh @@ -0,0 +1,22 @@ +// Copyright (c) 2014-2015 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_INTERNAL_REP_MIN_HH +#define TAO_CPP_PEGTL_INTERNAL_REP_MIN_HH + +#include "seq.hh" +#include "rep.hh" +#include "star.hh" + +namespace tao_json_pegtl +{ + namespace internal + { + template< unsigned Min, typename Rule, typename ... Rules > + using rep_min = seq< rep< Min, Rule, Rules ... >, star< Rule, Rules ... > >; + + } // namespace internal + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/internal/rep_min_max.hh b/share/include/tao/json/external/pegtl/internal/rep_min_max.hh new file mode 100644 index 0000000..494cc5e --- /dev/null +++ b/share/include/tao/json/external/pegtl/internal/rep_min_max.hh @@ -0,0 +1,70 @@ +// Copyright (c) 2014-2016 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_INTERNAL_REP_MIN_MAX_HH +#define TAO_CPP_PEGTL_INTERNAL_REP_MIN_MAX_HH + +#include + +#include "skip_control.hh" +#include "trivial.hh" +#include "not_at.hh" +#include "rule_conjunction.hh" +#include "rule_match_three.hh" +#include "seq.hh" + +#include "../apply_mode.hh" +#include "../analysis/counted.hh" + +namespace tao_json_pegtl +{ + namespace internal + { + template< unsigned Min, unsigned Max, typename ... Rules > struct rep_min_max; + + template< unsigned Min, unsigned Max, typename ... Rules > + struct skip_control< rep_min_max< Min, Max, Rules ... > > : std::true_type {}; + + template< unsigned Min, unsigned Max > + struct rep_min_max< Min, Max > + : trivial< false > + { + static_assert( Min <= Max, "invalid rep_min_max rule (maximum number of repetitions smaller than minimum)" ); + }; + + template< typename Rule, typename ... Rules > + struct rep_min_max< 0, 0, Rule, Rules ... > + : not_at< Rule, Rules ... > + { }; + + template< unsigned Min, unsigned Max, typename ... Rules > + struct rep_min_max + { + using analyze_t = analysis::counted< analysis::rule_type::SEQ, Min, Rules ... >; + + static_assert( Min <= Max, "invalid rep_min_max rule (maximum number of repetitions smaller than minimum)" ); + + template< apply_mode A, template< typename ... > class Action, template< typename ... > class Control, typename Input, typename ... States > + static bool match( Input & in, States && ... st ) + { + auto m = in.mark(); + + for ( unsigned i = 0; i != Min; ++i ) { + if ( ! rule_conjunction< Rules ... >::template match< A, Action, Control >( in, st ... ) ) { + return false; + } + } + for ( unsigned i = Min; i != Max; ++i ) { + if ( ! rule_match_three< seq< Rules ... >, A, Action, Control >::match( in, st ... ) ) { + return m( true ); + } + } + return m( rule_match_three< not_at< Rules ... >, A, Action, Control >::match( in, st ... ) ); + } + }; + + } // namespace internal + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/internal/rep_opt.hh b/share/include/tao/json/external/pegtl/internal/rep_opt.hh new file mode 100644 index 0000000..e097a6e --- /dev/null +++ b/share/include/tao/json/external/pegtl/internal/rep_opt.hh @@ -0,0 +1,37 @@ +// Copyright (c) 2014-2015 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_INTERNAL_REP_OPT_HH +#define TAO_CPP_PEGTL_INTERNAL_REP_OPT_HH + +#include "skip_control.hh" +#include "rule_match_three.hh" +#include "seq.hh" + +#include "../analysis/generic.hh" + +namespace tao_json_pegtl +{ + namespace internal + { + template< unsigned Max, typename ... Rules > + struct rep_opt + { + using analyze_t = analysis::generic< analysis::rule_type::OPT, Rules ... >; + + template< apply_mode A, template< typename ... > class Action, template< typename ... > class Control, typename Input, typename ... States > + static bool match( Input & in, States && ... st ) + { + for ( unsigned i = 0; ( i != Max ) && rule_match_three< seq< Rules ... >, A, Action, Control >::match( in, st ... ); ++i ) {} + return true; + } + }; + + template< unsigned Max, typename ... Rules > + struct skip_control< rep_opt< Max, Rules ... > > : std::true_type {}; + + } // namespace internal + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/internal/require.hh b/share/include/tao/json/external/pegtl/internal/require.hh new file mode 100644 index 0000000..32ded28 --- /dev/null +++ b/share/include/tao/json/external/pegtl/internal/require.hh @@ -0,0 +1,34 @@ +// Copyright (c) 2016 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_INTERNAL_REQUIRE_HH +#define TAO_CPP_PEGTL_INTERNAL_REQUIRE_HH + +#include "skip_control.hh" + +#include "../analysis/generic.hh" + +namespace tao_json_pegtl +{ + namespace internal + { + template< unsigned Amount > + struct require + { + using analyze_t = analysis::generic< analysis::rule_type::OPT >; + + template< typename Input > + static bool match( Input & in ) + { + return in.size( Amount ) >= Amount; + } + }; + + template< unsigned Amount > + struct skip_control< require< Amount > > : std::true_type {}; + + } // namespace internal + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/internal/result_on_found.hh b/share/include/tao/json/external/pegtl/internal/result_on_found.hh new file mode 100644 index 0000000..f6a79f9 --- /dev/null +++ b/share/include/tao/json/external/pegtl/internal/result_on_found.hh @@ -0,0 +1,21 @@ +// Copyright (c) 2014-2015 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_INTERNAL_RESULT_ON_FOUND_HH +#define TAO_CPP_PEGTL_INTERNAL_RESULT_ON_FOUND_HH + +namespace tao_json_pegtl +{ + namespace internal + { + enum class result_on_found : bool + { + SUCCESS = true, + FAILURE = false + }; + + } // namespace internal + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/internal/rule_conjunction.hh b/share/include/tao/json/external/pegtl/internal/rule_conjunction.hh new file mode 100644 index 0000000..83688d2 --- /dev/null +++ b/share/include/tao/json/external/pegtl/internal/rule_conjunction.hh @@ -0,0 +1,34 @@ +// Copyright (c) 2014-2015 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_INTERNAL_RULE_CONJUNCTION_HH +#define TAO_CPP_PEGTL_INTERNAL_RULE_CONJUNCTION_HH + +#include "../apply_mode.hh" + +namespace tao_json_pegtl +{ + namespace internal + { + template< typename ... Rules > + struct rule_conjunction + { + template< apply_mode A, template< typename ... > class Action, template< typename ... > class Control, typename Input, typename ... States > + static bool match( Input & in, States && ... st ) + { +#ifdef __cpp_fold_expressions + return ( Control< Rules >::template match< A, Action, Control >( in, st ... ) && ... ); +#else + bool result = true; + using swallow = bool[]; + (void)swallow{ result = result && Control< Rules >::template match< A, Action, Control >( in, st ... ) ..., true }; + return result; +#endif + } + }; + + } // namespace internal + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/internal/rule_match_one.hh b/share/include/tao/json/external/pegtl/internal/rule_match_one.hh new file mode 100644 index 0000000..0cda31d --- /dev/null +++ b/share/include/tao/json/external/pegtl/internal/rule_match_one.hh @@ -0,0 +1,43 @@ +// Copyright (c) 2014-2015 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_INTERNAL_RULE_MATCH_ONE_HH +#define TAO_CPP_PEGTL_INTERNAL_RULE_MATCH_ONE_HH + +#include "../apply_mode.hh" + +#include "skip_control.hh" +#include "rule_match_two.hh" +#include "rule_match_three.hh" + +namespace tao_json_pegtl +{ + namespace internal + { + // Forward to rule_match_two<> for all user-defined / -visible rules, + // but skip rule_match_two<> (which calls the control class' callbacks) + // and forward directly to rule_match_three<> when a rule is marked as + // an internal rule by skip_control<>. + + template< typename Rule, + apply_mode A, + template< typename ... > class Action, + template< typename ... > class Control, + bool = skip_control< Rule >::value > + struct rule_match_one; + + template< typename Rule, apply_mode A, template< typename ... > class Action, template< typename ... > class Control > + struct rule_match_one< Rule, A, Action, Control, false > + : rule_match_two< Rule, A, Action, Control > + { }; + + template< typename Rule, apply_mode A, template< typename ... > class Action, template< typename ... > class Control > + struct rule_match_one< Rule, A, Action, Control, true > + : rule_match_three< Rule, A, Action, Control > + { }; + + } // namespace internal + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/internal/rule_match_three.hh b/share/include/tao/json/external/pegtl/internal/rule_match_three.hh new file mode 100644 index 0000000..253e2ac --- /dev/null +++ b/share/include/tao/json/external/pegtl/internal/rule_match_three.hh @@ -0,0 +1,42 @@ +// Copyright (c) 2014-2015 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_INTERNAL_RULE_MATCH_THREE_HH +#define TAO_CPP_PEGTL_INTERNAL_RULE_MATCH_THREE_HH + +#include "../apply_mode.hh" + +namespace tao_json_pegtl +{ + namespace internal + { + // The purpose of rule_match_three<> is to allow for two different + // signatures of a rule's match()-method. A more complicated but + // more general version which takes the explicit template parameters + // for A, Action and Control, and a more simple and limited version + // which takes the input as its only parameter. The latter is often + // sufficient and helps to keep the overhead smaller. + + template< typename Rule, apply_mode A, template< typename ... > class Action, template< typename ... > class Control > + struct rule_match_three + { + template< typename Input, typename ... States > + static auto match( Input & in, States && ... st ) -> decltype( Rule::template match< A, Action, Control >( in, st ... ), true ) + { + return Rule::template match< A, Action, Control >( in, st ... ); + } + + // NOTE: The additional "int = 0" is a work-around for missing expression SFINAE in VS2015. + + template< typename Input, typename ... States, int = 0 > + static auto match( Input & in, States && ... ) -> decltype( Rule::match( in ), true ) + { + return Rule::match( in ); + } + }; + + } // namespace internal + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/internal/rule_match_two.hh b/share/include/tao/json/external/pegtl/internal/rule_match_two.hh new file mode 100644 index 0000000..087aab3 --- /dev/null +++ b/share/include/tao/json/external/pegtl/internal/rule_match_two.hh @@ -0,0 +1,68 @@ +// Copyright (c) 2014-2016 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_INTERNAL_RULE_MATCH_TWO_HH +#define TAO_CPP_PEGTL_INTERNAL_RULE_MATCH_TWO_HH + +#include "../action_input.hh" +#include "../apply_mode.hh" +#include "../nothing.hh" + +#include "rule_match_three.hh" + +namespace tao_json_pegtl +{ + namespace internal + { + // The purpose of rule_match_two is to call all necessary debug hooks of + // the control class and, if applicable, also call the action class' + // apply()-method. The latter can be disabled either explicitly (via + // disable<>) or implicitly by at<> or not_at<>. + + template< typename Rule, + apply_mode A, + template< typename ... > class Action, + template< typename ... > class Control, + bool apply_here = ( ( A == apply_mode::ACTION ) && ( ! is_nothing< Action, Rule >::value ) ) > + struct rule_match_two; + + template< typename Rule, apply_mode A, template< typename ... > class Action, template< typename ... > class Control > + struct rule_match_two< Rule, A, Action, Control, false > + { + template< typename Input, typename ... States > + static bool match( Input & in, States && ... st ) + { + Control< Rule >::start( const_cast< const Input & >( in ), st ... ); + + if ( rule_match_three< Rule, A, Action, Control >::match( in, st ... ) ) { + Control< Rule >::success( const_cast< const Input & >( in ), st ... ); + return true; + } + Control< Rule >::failure( const_cast< const Input & >( in ), st ... ); + return false; + } + }; + + template< typename Rule, apply_mode A, template< typename ... > class Action, template< typename ... > class Control > + struct rule_match_two< Rule, A, Action, Control, true > + { + template< typename Input, typename ... States > + static bool match( Input & in, States && ... st ) + { + auto m = in.mark(); + + using action_t = typename Input::action_t; + + if ( rule_match_two< Rule, A, Action, Control, false >::match( in, st ... ) ) { + Action< Rule >::apply( action_t( m, in.data() ), st ... ); + return m( true ); + } + return false; + } + }; + + } // namespace internal + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/internal/rules.hh b/share/include/tao/json/external/pegtl/internal/rules.hh new file mode 100644 index 0000000..5614dd9 --- /dev/null +++ b/share/include/tao/json/external/pegtl/internal/rules.hh @@ -0,0 +1,54 @@ +// Copyright (c) 2014-2016 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_INTERNAL_RULES_HH +#define TAO_CPP_PEGTL_INTERNAL_RULES_HH + +#include "action.hh" +#include "any.hh" +#include "at.hh" +#include "bytes.hh" +#include "control.hh" +#include "disable.hh" +#include "discard.hh" +#include "discard_if.hh" +#include "enable.hh" +#include "eof.hh" +#include "eol.hh" +#include "eolf.hh" +#include "if_must.hh" +#include "if_must_else.hh" +#include "if_then_else.hh" +#include "istring.hh" +#include "list.hh" +#include "list_must.hh" +#include "list_tail.hh" +#include "list_tail_pad.hh" +#include "minus.hh" +#include "must.hh" +#include "not_at.hh" +#include "one.hh" +#include "opt.hh" +#include "pad.hh" +#include "pad_opt.hh" +#include "plus.hh" +#include "range.hh" +#include "ranges.hh" +#include "raise.hh" +#include "rep.hh" +#include "rep_min.hh" +#include "rep_min_max.hh" +#include "rep_opt.hh" +#include "require.hh" +#include "seq.hh" +#include "skip_control.hh" +#include "sor.hh" +#include "star.hh" +#include "star_must.hh" +#include "state.hh" +#include "string.hh" +#include "trivial.hh" +#include "try_catch_type.hh" +#include "until.hh" + +#endif diff --git a/share/include/tao/json/external/pegtl/internal/seq.hh b/share/include/tao/json/external/pegtl/internal/seq.hh new file mode 100644 index 0000000..d529ff3 --- /dev/null +++ b/share/include/tao/json/external/pegtl/internal/seq.hh @@ -0,0 +1,55 @@ +// Copyright (c) 2014-2015 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_INTERNAL_SEQ_HH +#define TAO_CPP_PEGTL_INTERNAL_SEQ_HH + +#include "trivial.hh" +#include "skip_control.hh" +#include "rule_conjunction.hh" + +#include "../analysis/generic.hh" + +namespace tao_json_pegtl +{ + namespace internal + { + template< typename ... Rules > struct seq; + + template< typename ... Rules > + struct skip_control< seq< Rules ... > > : std::true_type {}; + + template<> + struct seq<> + : trivial< true > {}; + + template< typename Rule > + struct seq< Rule > + { + using analyze_t = typename Rule::analyze_t; + + template< apply_mode A, template< typename ... > class Action, template< typename ... > class Control, typename Input, typename ... States > + static bool match( Input & in, States && ... st ) + { + return Control< Rule >::template match< A, Action, Control >( in, st ... ); + } + }; + + template< typename ... Rules > + struct seq + { + using analyze_t = analysis::generic< analysis::rule_type::SEQ, Rules ... >; + + template< apply_mode A, template< typename ... > class Action, template< typename ... > class Control, typename Input, typename ... States > + static bool match( Input & in, States && ... st ) + { + auto m = in.mark(); + return m( rule_conjunction< Rules ... >::template match< A, Action, Control >( in, st ... ) ); + } + }; + + } // namespace internal + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/internal/skip_control.hh b/share/include/tao/json/external/pegtl/internal/skip_control.hh new file mode 100644 index 0000000..5588f01 --- /dev/null +++ b/share/include/tao/json/external/pegtl/internal/skip_control.hh @@ -0,0 +1,28 @@ +// Copyright (c) 2014-2015 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_INTERNAL_SKIP_CONTROL_HH +#define TAO_CPP_PEGTL_INTERNAL_SKIP_CONTROL_HH + +#include + +namespace tao_json_pegtl +{ + namespace internal + { + // This class is a simple tagging mechanism. + // By default, skip_control< Rule >::value + // is 'false'. Each internal (!) rule that should + // be hidden from the control and action class' + // callbacks simply specializes skip_control<> + // to return 'true' for the above expression. + // This is then used in rule_match_one.hh. + + template< typename Rule > + struct skip_control : std::false_type {}; + + } // namespace internal + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/internal/sor.hh b/share/include/tao/json/external/pegtl/internal/sor.hh new file mode 100644 index 0000000..28008d9 --- /dev/null +++ b/share/include/tao/json/external/pegtl/internal/sor.hh @@ -0,0 +1,46 @@ +// Copyright (c) 2014-2017 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_INTERNAL_SOR_HH +#define TAO_CPP_PEGTL_INTERNAL_SOR_HH + +#include "../apply_mode.hh" +#include "skip_control.hh" + +#include "../analysis/generic.hh" + +namespace tao_json_pegtl +{ + namespace internal + { + template< typename ... Rules > + struct sor + { + using analyze_t = analysis::generic< analysis::rule_type::SOR, Rules ... >; + + template< apply_mode A, template< typename ... > class Action, template< typename ... > class Control, typename Input, typename ... States > + static bool match( Input & in, States && ... st ) + { +#ifdef __cpp_fold_expressions + return ( Control< Rules >::template match< A, Action, Control >( in, st ... ) || ... ); +#else + bool result = false; + using swallow = bool[]; + (void)swallow{ result = result || Control< Rules >::template match< A, Action, Control >( in, st ... ) ..., true }; + return result; +#endif + } + }; + + template<> + struct sor<> + : trivial< false > {}; + + template< typename ... Rules > + struct skip_control< sor< Rules ... > > : std::true_type {}; + + } // namespace internal + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/internal/star.hh b/share/include/tao/json/external/pegtl/internal/star.hh new file mode 100644 index 0000000..669fae0 --- /dev/null +++ b/share/include/tao/json/external/pegtl/internal/star.hh @@ -0,0 +1,41 @@ +// Copyright (c) 2014-2016 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_INTERNAL_STAR_HH +#define TAO_CPP_PEGTL_INTERNAL_STAR_HH + +#include + +#include "rule_match_three.hh" +#include "seq.hh" +#include "opt.hh" +#include "skip_control.hh" + +#include "../apply_mode.hh" +#include "../analysis/generic.hh" + +namespace tao_json_pegtl +{ + namespace internal + { + template< typename Rule, typename ... Rules > + struct star + { + using analyze_t = analysis::generic< analysis::rule_type::OPT, Rule, Rules ..., star >; + + template< apply_mode A, template< typename ... > class Action, template< typename ... > class Control, typename Input, typename ... States > + static bool match( Input & in, States && ... st ) + { + while ( ( ! in.empty() ) && rule_match_three< seq< Rule, Rules ... >, A, Action, Control >::match( in, st ... ) ) {} + return true; + } + }; + + template< typename Rule, typename ... Rules > + struct skip_control< star< Rule, Rules ... > > : std::true_type {}; + + } // namespace internal + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/internal/star_must.hh b/share/include/tao/json/external/pegtl/internal/star_must.hh new file mode 100644 index 0000000..8ad7a0a --- /dev/null +++ b/share/include/tao/json/external/pegtl/internal/star_must.hh @@ -0,0 +1,21 @@ +// Copyright (c) 2014-2015 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_INTERNAL_STAR_MUST_HH +#define TAO_CPP_PEGTL_INTERNAL_STAR_MUST_HH + +#include "star.hh" +#include "if_must.hh" + +namespace tao_json_pegtl +{ + namespace internal + { + template< typename Cond, typename ... Rules > + using star_must = star< if_must< Cond, Rules ... > >; + + } // namespace internal + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/internal/state.hh b/share/include/tao/json/external/pegtl/internal/state.hh new file mode 100644 index 0000000..9c43a93 --- /dev/null +++ b/share/include/tao/json/external/pegtl/internal/state.hh @@ -0,0 +1,55 @@ +// Copyright (c) 2014-2015 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_INTERNAL_STATE_HH +#define TAO_CPP_PEGTL_INTERNAL_STATE_HH + +#include "seq.hh" +#include "rule_match_three.hh" +#include "skip_control.hh" + +#include "../analysis/generic.hh" + +namespace tao_json_pegtl +{ + namespace internal + { + template< typename State, typename ... Rules > + struct state + { + using analyze_t = analysis::generic< analysis::rule_type::SEQ, Rules ... >; + + template< apply_mode A, template< typename ... > class Action, template< typename ... > class Control, typename Input, typename ... States > + static auto success( State & s, const Input & in, States && ... st ) -> decltype( s.template success< A, Action, Control >( in, st ... ), void() ) + { + s.template success< A, Action, Control >( in, st ... ); + } + + // NOTE: The additional "int = 0" is a work-around for missing expression SFINAE in VS2015. + + template< apply_mode A, template< typename ... > class Action, template< typename ... > class Control, typename Input, typename ... States, int = 0 > + static auto success( State & s, const Input & in, States && ... st ) -> decltype( s.success( in, st ... ), void() ) + { + s.success( in, st ... ); + } + + template< apply_mode A, template< typename ... > class Action, template< typename ... > class Control, typename Input, typename ... States > + static bool match( Input & in, States && ... st ) + { + State s( const_cast< const Input & >( in ), st ... ); + if ( rule_match_three< seq< Rules ... >, A, Action, Control >::match( in, s ) ) { + success< A, Action, Control >( s, in, st ... ); + return true; + } + return false; + } + }; + + template< typename State, typename ... Rules > + struct skip_control< state< State, Rules ... > > : std::true_type {}; + + } // namespace internal + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/internal/string.hh b/share/include/tao/json/external/pegtl/internal/string.hh new file mode 100644 index 0000000..bf59a0e --- /dev/null +++ b/share/include/tao/json/external/pegtl/internal/string.hh @@ -0,0 +1,56 @@ +// Copyright (c) 2014-2016 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_INTERNAL_STRING_HH +#define TAO_CPP_PEGTL_INTERNAL_STRING_HH + +#include +#include + +#include "result_on_found.hh" +#include "skip_control.hh" +#include "bump_util.hh" +#include "trivial.hh" + +#include "../analysis/counted.hh" + +namespace tao_json_pegtl +{ + namespace internal + { + inline bool unsafe_equals( const char * s, const std::initializer_list< char > & l ) + { + return std::memcmp( s, & * l.begin(), l.size() ) == 0; + } + + template< char ... Cs > struct string; + + template< char ... Cs > + struct skip_control< string< Cs ... > > : std::true_type {}; + + template<> struct string<> + : trivial< true > {}; + + template< char ... Cs > + struct string + { + using analyze_t = analysis::counted< analysis::rule_type::ANY, sizeof ... ( Cs ) >; + + template< typename Input > + static bool match( Input & in ) + { + if ( in.size( sizeof ... ( Cs ) ) >= sizeof ... ( Cs ) ) { + if ( unsafe_equals( in.begin(), { Cs ... } ) ) { + bump< result_on_found::SUCCESS, Input, char, Cs ... >( in, sizeof ... ( Cs ) ); + return true; + } + } + return false; + } + }; + + } // namespace internal + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/internal/trivial.hh b/share/include/tao/json/external/pegtl/internal/trivial.hh new file mode 100644 index 0000000..70caccf --- /dev/null +++ b/share/include/tao/json/external/pegtl/internal/trivial.hh @@ -0,0 +1,34 @@ +// Copyright (c) 2014-2015 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_INTERNAL_TRIVIAL_HH +#define TAO_CPP_PEGTL_INTERNAL_TRIVIAL_HH + +#include "skip_control.hh" + +#include "../analysis/counted.hh" + +namespace tao_json_pegtl +{ + namespace internal + { + template< bool Result > + struct trivial + { + using analyze_t = analysis::counted< analysis::rule_type::ANY, unsigned( ! Result ) >; + + template< typename Input > + static bool match( Input & ) + { + return Result; + } + }; + + template< bool Result > + struct skip_control< trivial< Result > > : std::true_type {}; + + } // namespace internal + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/internal/try_catch_type.hh b/share/include/tao/json/external/pegtl/internal/try_catch_type.hh new file mode 100644 index 0000000..e6d8034 --- /dev/null +++ b/share/include/tao/json/external/pegtl/internal/try_catch_type.hh @@ -0,0 +1,53 @@ +// Copyright (c) 2014-2015 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_INTERNAL_TRY_CATCH_TYPE_HH +#define TAO_CPP_PEGTL_INTERNAL_TRY_CATCH_TYPE_HH + +#include + +#include "skip_control.hh" +#include "trivial.hh" +#include "rule_match_three.hh" +#include "seq.hh" + +#include "../apply_mode.hh" +#include "../analysis/generic.hh" + +namespace tao_json_pegtl +{ + namespace internal + { + template< typename Exception, typename ... Rules > struct try_catch_type; + + template< typename Exception, typename ... Rules > + struct skip_control< try_catch_type< Exception, Rules ... > > : std::true_type {}; + + template< typename Exception > + struct try_catch_type< Exception > + : trivial< true > {}; + + template< typename Exception, typename ... Rules > + struct try_catch_type + { + using analyze_t = analysis::generic< analysis::rule_type::SEQ, Rules ... >; + + template< apply_mode A, template< typename ... > class Action, template< typename ... > class Control, typename Input, typename ... States > + static bool match( Input & in, States && ... st ) + { + auto m = in.mark(); + + try { + return m( rule_match_three< seq< Rules ... >, A, Action, Control >::match( in, st ... ) ); + } + catch ( const Exception & ) { + return false; + } + } + }; + + } // namespace internal + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/internal/until.hh b/share/include/tao/json/external/pegtl/internal/until.hh new file mode 100644 index 0000000..dad481d --- /dev/null +++ b/share/include/tao/json/external/pegtl/internal/until.hh @@ -0,0 +1,68 @@ +// Copyright (c) 2014-2016 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_INTERNAL_UNTIL_HH +#define TAO_CPP_PEGTL_INTERNAL_UNTIL_HH + +#include "eof.hh" +#include "star.hh" +#include "bytes.hh" +#include "not_at.hh" +#include "skip_control.hh" +#include "rule_conjunction.hh" + +#include "../analysis/generic.hh" + +namespace tao_json_pegtl +{ + namespace internal + { + template< typename Cond, typename ... Rules > struct until; + + template< typename Cond, typename ... Rules > + struct skip_control< until< Cond, Rules ... > > : std::true_type {}; + + template< typename Cond > + struct until< Cond > + { + using analyze_t = analysis::generic< analysis::rule_type::SEQ, star< not_at< Cond >, not_at< eof >, bytes< 1 > >, Cond >; + + template< apply_mode A, template< typename ... > class Action, template< typename ... > class Control, typename Input, typename ... States > + static bool match( Input & in, States && ... st ) + { + auto m = in.mark(); + + while ( ! Control< Cond >::template match< A, Action, Control >( in, st ... ) ) { + if ( in.empty() ) { + return false; + } + in.bump(); + } + return m( true ); + } + }; + + template< typename Cond, typename ... Rules > + struct until + { + using analyze_t = analysis::generic< analysis::rule_type::SEQ, star< not_at< Cond >, not_at< eof >, Rules ... >, Cond >; + + template< apply_mode A, template< typename ... > class Action, template< typename ... > class Control, typename Input, typename ... States > + static bool match( Input & in, States && ... st ) + { + auto m = in.mark(); + + while ( ! Control< Cond >::template match< A, Action, Control >( in, st ... ) ) { + if ( in.empty() || ! rule_conjunction< Rules ... >::template match< A, Action, Control >( in, st ... ) ) { + return false; + } + } + return m( true ); + } + }; + + } // namespace internal + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/lf_crlf_eol.hh b/share/include/tao/json/external/pegtl/lf_crlf_eol.hh new file mode 100644 index 0000000..b9d9286 --- /dev/null +++ b/share/include/tao/json/external/pegtl/lf_crlf_eol.hh @@ -0,0 +1,34 @@ +// Copyright (c) 2016 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_LF_CRLF_EOL_HH +#define TAO_CPP_PEGTL_LF_CRLF_EOL_HH + +namespace tao_json_pegtl +{ + struct lf_crlf_eol + { + static constexpr int ch = '\n'; + + template< typename Input > + static eol_pair match( Input & in ) + { + eol_pair p = { false, in.size( 2 ) }; + if ( p.second ) { + const auto a = in.peek_char(); + if ( a == '\n' ) { + in.bump_to_next_line(); + p.first = true; + } + else if ( ( a == '\r' ) && ( p.second > 1 ) && ( in.peek_char( 1 ) == '\n' ) ) { + in.bump_to_next_line( 2 ); + p.first = true; + } + } + return p; + } + }; + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/lf_eol.hh b/share/include/tao/json/external/pegtl/lf_eol.hh new file mode 100644 index 0000000..d73b7fb --- /dev/null +++ b/share/include/tao/json/external/pegtl/lf_eol.hh @@ -0,0 +1,29 @@ +// Copyright (c) 2016 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_LF_EOL_HH +#define TAO_CPP_PEGTL_LF_EOL_HH + +namespace tao_json_pegtl +{ + struct lf_eol + { + static constexpr int ch = '\n'; + + template< typename Input > + static eol_pair match( Input & in ) + { + eol_pair p = { false, in.size( 1 ) }; + if ( p.second ) { + if ( in.peek_char() == '\n' ) { + in.bump_to_next_line(); + p.first = true; + } + } + return p; + } + }; + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/memory_input.hh b/share/include/tao/json/external/pegtl/memory_input.hh new file mode 100644 index 0000000..69ae880 --- /dev/null +++ b/share/include/tao/json/external/pegtl/memory_input.hh @@ -0,0 +1,143 @@ +// Copyright (c) 2014-2016 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_MEMORY_INPUT_HH +#define TAO_CPP_PEGTL_MEMORY_INPUT_HH + +#include +#include +#include + +#include "eol.hh" +#include "position_info.hh" +#include "internal/input_data.hh" +#include "internal/input_mark.hh" + +namespace tao_json_pegtl +{ + template< typename Eol > + class basic_action_input; + + template< typename Eol > + class basic_memory_input + { + public: + using eol_t = Eol; + + using mark_t = internal::input_mark; + using data_t = internal::input_data; + + using action_t = basic_action_input< Eol >; + using memory_t = basic_memory_input< Eol >; + + using position_t = position_info; + using exception_t = basic_parse_error< position_info >; + + explicit + basic_memory_input( const internal::input_data & d ) + : m_data( d ) + { } + + basic_memory_input( const internal::input_mark & m, const internal::input_data & d ) + : basic_memory_input( m.byte(), m.line(), m.byte_in_line(), m.begin(), d.begin, d.source ) + { } + + basic_memory_input( const std::size_t in_byte, const std::size_t in_line, const std::size_t in_byte_in_line, const char * in_begin, const char * in_end, const char * in_source ) + : m_data( in_byte, in_line, in_byte_in_line, in_begin, in_end, in_source ) + { } + + bool empty() const + { + return m_data.begin == m_data.end; + } + + std::size_t size( const std::size_t ) const + { + return m_data.end - m_data.begin; + } + + const char * begin() const + { + return m_data.begin; + } + + const char * end( const std::size_t ) const + { + return m_data.end; + } + + std::size_t byte() const + { + return m_data.byte; + } + + std::size_t line() const + { + return m_data.line; + } + + std::size_t byte_in_line() const + { + return m_data.byte_in_line; + } + + const char * source() const + { + return m_data.source; + } + + char peek_char( const std::size_t offset = 0 ) const + { + return m_data.begin[ offset ]; + } + + unsigned char peek_byte( const std::size_t offset = 0 ) const + { + return static_cast< unsigned char >( peek_char( offset ) ); + } + + void bump( const std::size_t count = 1 ) + { + m_data.bump( count, Eol::ch ); + } + + void bump_in_this_line( const std::size_t count = 1 ) + { + m_data.bump_in_this_line( count ); + } + + void bump_to_next_line( const std::size_t count = 1 ) + { + m_data.bump_to_next_line( count ); + } + + void discard() + { } + + void require( const std::size_t ) + { } + + internal::input_mark mark() + { + return internal::input_mark( m_data ); + } + + const internal::input_data & data() const + { + return m_data; + } + + position_t position() const + { + return position_info( m_data ); + } + + private: + internal::input_data m_data; + }; + + using memory_input = basic_memory_input< lf_crlf_eol >; + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/mmap_parser.hh b/share/include/tao/json/external/pegtl/mmap_parser.hh new file mode 100644 index 0000000..2c7b7ec --- /dev/null +++ b/share/include/tao/json/external/pegtl/mmap_parser.hh @@ -0,0 +1,74 @@ +// Copyright (c) 2014-2016 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_MMAP_PARSER_HH +#define TAO_CPP_PEGTL_MMAP_PARSER_HH + +#include + +#include "parse.hh" +#include "normal.hh" +#include "nothing.hh" +#include "eol.hh" +#include "internal/file_mapper.hh" + +namespace tao_json_pegtl +{ + template< typename Eol > + class basic_mmap_parser + { + public: + explicit + basic_mmap_parser( const std::string & filename ) + : m_file( filename ), + m_source( filename ), + m_input( 0, 1, 0, m_file.begin(), m_file.end(), m_source.c_str() ) + { } + + const std::string & source() const + { + return m_source; + } + + const memory_input & input() const + { + return m_input; + } + + template< typename Rule, template< typename ... > class Action = nothing, template< typename ... > class Control = normal, typename ... States > + bool parse( States && ... st ) + { + return parse_input< Rule, Action, Control >( m_input, st ... ); + } + + template< typename Rule, template< typename ... > class Action = nothing, template< typename ... > class Control = normal, typename Outer, typename ... States > + bool parse_nested( Outer & oi, States && ... st ) + { + return parse_input_nested< Rule, Action, Control >( oi, m_input, st ... ); + } + + using eol = Eol; + + private: + internal::file_mapper m_file; + std::string m_source; + basic_memory_input< Eol > m_input; + }; + + using mmap_parser = basic_mmap_parser< lf_crlf_eol >; + + template< typename Rule, template< typename ... > class Action = nothing, template< typename ... > class Control = normal, typename ... States > + bool parse_mmap( const std::string & filename, States && ... st ) + { + return mmap_parser( filename ).parse< Rule, Action, Control >( st ... ); + } + + template< typename Rule, template< typename ... > class Action = nothing, template< typename ... > class Control = normal, typename Outer, typename ... States > + bool parse_mmap_nested( Outer & oi, const std::string & filename, States && ... st ) + { + return basic_mmap_parser< typename Outer::eol >( filename ).template parse_nested< Rule, Action, Control >( oi, st ... ); + } + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/normal.hh b/share/include/tao/json/external/pegtl/normal.hh new file mode 100644 index 0000000..9ade931 --- /dev/null +++ b/share/include/tao/json/external/pegtl/normal.hh @@ -0,0 +1,46 @@ +// Copyright (c) 2014-2015 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_NORMAL_HH +#define TAO_CPP_PEGTL_NORMAL_HH + +#include "apply_mode.hh" +#include "parse_error.hh" + +#include "internal/demangle.hh" +#include "internal/rule_match_one.hh" + +namespace tao_json_pegtl +{ + template< typename Rule > + struct normal + { + template< typename Input, typename ... States > + static void start( const Input &, States && ... ) + { } + + template< typename Input, typename ... States > + static void success( const Input &, States && ... ) + { } + + template< typename Input, typename ... States > + static void failure( const Input &, States && ... ) + { } + + template< typename Input, typename ... States > + static void raise( const Input & in, States && ... ) + { + using exception_t = typename Input::exception_t; + throw exception_t( "parse error matching " + internal::demangle< Rule >(), in ); + } + + template< apply_mode A, template< typename ... > class Action, template< typename ... > class Control, typename Input, typename ... States > + static bool match( Input & in, States && ... st ) + { + return internal::rule_match_one< Rule, A, Action, Control >::match( in, st ... ); + } + }; + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/nothing.hh b/share/include/tao/json/external/pegtl/nothing.hh new file mode 100644 index 0000000..9e34137 --- /dev/null +++ b/share/include/tao/json/external/pegtl/nothing.hh @@ -0,0 +1,18 @@ +// Copyright (c) 2014-2015 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_NOTHING_HH +#define TAO_CPP_PEGTL_NOTHING_HH + +#include + +namespace tao_json_pegtl +{ + template< typename Rule > struct nothing {}; + + template< template< typename ... > class Action, typename Rule > + using is_nothing = std::is_base_of< nothing< Rule >, Action< Rule > >; + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/parse.hh b/share/include/tao/json/external/pegtl/parse.hh new file mode 100644 index 0000000..4c16530 --- /dev/null +++ b/share/include/tao/json/external/pegtl/parse.hh @@ -0,0 +1,140 @@ +// Copyright (c) 2014-2016 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_PARSE_HH +#define TAO_CPP_PEGTL_PARSE_HH + +#include +#include +#include + +#include "normal.hh" +#include "nothing.hh" +#include "apply_mode.hh" +#include "memory_input.hh" +#include "buffer_input.hh" + +#include "internal/cstream_reader.hh" +#include "internal/cstring_reader.hh" +#include "internal/istream_reader.hh" + +namespace tao_json_pegtl +{ + template< typename Rule, template< typename ... > class Action = nothing, template< typename ... > class Control = normal, typename Input, typename ... States > + bool parse_input( Input & in, States && ... st ) + { + return Control< Rule >::template match< apply_mode::ACTION, Action, Control >( in, st ... ); + } + + template< typename Rule, template< typename ... > class Action = nothing, template< typename ... > class Control = normal, typename ... States > + bool parse_arg( const int argn, char ** argv, States && ... st ) + { + std::ostringstream os; + os << "argv[" << argn << ']'; + const std::string source = os.str(); + assert( argv[ argn ] ); + memory_input in( 0, 1, 0, argv[ argn ], argv[ argn ] + std::strlen( argv[ argn ] ), source.c_str() ); + return parse_input< Rule, Action, Control >( in, st ... ); + } + + template< typename Rule, template< typename ... > class Action = nothing, template< typename ... > class Control = normal, typename ... States > + bool parse_memory( const char * data, const char * dend, const char * source, States && ... st ) + { + memory_input in( 0, 1, 0, data, dend, source ); + return parse_input< Rule, Action, Control >( in, st ... ); + } + + template< typename Rule, template< typename ... > class Action = nothing, template< typename ... > class Control = normal, typename ... States > + bool parse_memory( const char * data, const std::size_t size, const char * source, States && ... st ) + { + return parse_memory< Rule, Action, Control >( data, data + size, source, st ... ); + } + + template< typename Rule, template< typename ... > class Action = nothing, template< typename ... > class Control = normal, typename ... States > + bool parse_string( const std::string & data, const std::string & source, States && ... st ) + { + return parse_memory< Rule, Action, Control >( data.data(), data.data() + data.size(), source.c_str(), st ... ); + } + + template< typename Rule, template< typename ... > class Action = nothing, template< typename ... > class Control = normal, typename ... States > + bool parse_cstream( std::FILE * stream, const char * source, const std::size_t maximum, States && ... st ) + { + buffer_input< internal::cstream_reader > in( source, maximum, stream ); + return parse_input< Rule, Action, Control >( in, st ... ); + } + + template< typename Rule, template< typename ... > class Action = nothing, template< typename ... > class Control = normal, typename ... States > + bool parse_stdin( const std::size_t maximum, States && ... st ) + { + return parse_cstream< Rule, Action, Control >( stdin, "stdin", maximum, st ... ); + } + + template< typename Rule, template< typename ... > class Action = nothing, template< typename ... > class Control = normal, typename ... States > + bool parse_cstring( const char * string, const char * source, const std::size_t maximum, States && ... st ) + { + buffer_input< internal::cstring_reader > in( source, maximum, string ); + return parse_input< Rule, Action, Control >( in, st ... ); + } + + template< typename Rule, template< typename ... > class Action = nothing, template< typename ... > class Control = normal, typename ... States > + bool parse_istream( std::istream & stream, const std::string & source, const std::size_t maximum, States && ... st ) + { + buffer_input< internal::istream_reader > in( source.c_str(), maximum, stream ); + return parse_input< Rule, Action, Control >( in, st ... ); + } + + template< typename Rule, template< typename ... > class Action = nothing, template< typename ... > class Control = normal, typename Outer, typename Input, typename ... States > + bool parse_input_nested( const Outer & oi, Input & in, States && ... st ) + { + try { + return Control< Rule >::template match< apply_mode::ACTION, Action, Control >( in, st ... ); + } + catch ( parse_error & e ) { + e.positions.push_back( oi.position() ); + throw; + } + } + + template< typename Rule, template< typename ... > class Action = nothing, template< typename ... > class Control = normal, typename Outer, typename ... States > + bool parse_memory_nested( const Outer & oi, const char * data, const char * dend, const char * source, States && ... st ) + { + basic_memory_input< typename Outer::eol_t > in( 0, 1, 0, data, dend, source ); + return parse_input_nested< Rule, Action, Control >( oi, in, st ... ); + } + + template< typename Rule, template< typename ... > class Action = nothing, template< typename ... > class Control = normal, typename Outer, typename ... States > + bool parse_memory_nested( const Outer & oi, const char * data, const std::size_t size, const char * source, States && ... st ) + { + return parse_memory_nested< Rule, Action, Control >( oi, data, data + size, source, st ... ); + } + + template< typename Rule, template< typename ... > class Action = nothing, template< typename ... > class Control = normal, typename Outer, typename ... States > + bool parse_string_nested( const Outer & oi, const std::string & data, const std::string & source, States && ... st ) + { + return parse_memory_nested< Rule, Action, Control >( oi, data.data(), data.data() + data.size(), source.c_str(), st ... ); + } + + template< typename Rule, template< typename ... > class Action = nothing, template< typename ... > class Control = normal, typename Outer, typename ... States > + bool parse_cstream_nested( const Outer & oi, std::FILE * stream, const char * source, const std::size_t maximum, States && ... st ) + { + basic_buffer_input< typename Outer::eol_t, internal::cstream_reader > in( source, maximum, stream ); + return parse_input_nested< Rule, Action, Control >( oi, in, st ... ); + } + + template< typename Rule, template< typename ... > class Action = nothing, template< typename ... > class Control = normal, typename Outer, typename ... States > + bool parse_cstring_nested( const Outer & oi, const char * string, const char * source, const std::size_t maximum, States && ... st ) + { + basic_buffer_input< typename Outer::eol_t, internal::cstring_reader > in( source, maximum, string ); + return parse_input_nested< Rule, Action, Control >( oi, in, st ... ); + } + + template< typename Rule, template< typename ... > class Action = nothing, template< typename ... > class Control = normal, typename Outer, typename ... States > + bool parse_istream( const Outer & oi, std::istream & stream, const std::string & source, const std::size_t maximum, States && ... st ) + { + basic_buffer_input< typename Outer::eol_t, internal::istream_reader > in( source.c_str(), maximum, stream ); + return parse_input_nested< Rule, Action, Control >( oi, in, st ... ); + } + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/parse_error.hh b/share/include/tao/json/external/pegtl/parse_error.hh new file mode 100644 index 0000000..7e37ecf --- /dev/null +++ b/share/include/tao/json/external/pegtl/parse_error.hh @@ -0,0 +1,38 @@ +// Copyright (c) 2014-2016 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_PARSE_ERROR_HH +#define TAO_CPP_PEGTL_PARSE_ERROR_HH + +#include +#include + +#include "position_info.hh" + +namespace tao_json_pegtl +{ + template< typename Pos > + struct basic_parse_error + : public std::runtime_error + { + basic_parse_error( const std::string & message, std::vector< Pos > && in_positions ) + : std::runtime_error( message ), + positions( std::move( in_positions ) ) + { } + + template< typename Input > + basic_parse_error( const std::string & message, const Input & in ) + : std::runtime_error( to_string( in.position() ) + ": " + message ), + positions( 1, in.position() ) + { } + + using position_t = Pos; + + std::vector< Pos > positions; + }; + + using parse_error = basic_parse_error< position_info >; + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/position_info.hh b/share/include/tao/json/external/pegtl/position_info.hh new file mode 100644 index 0000000..83e0039 --- /dev/null +++ b/share/include/tao/json/external/pegtl/position_info.hh @@ -0,0 +1,46 @@ +// Copyright (c) 2014-2016 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_POSITION_INFO_HH +#define TAO_CPP_PEGTL_POSITION_INFO_HH + +#include +#include +#include +#include + +#include "internal/input_data.hh" + +namespace tao_json_pegtl +{ + struct position_info + { + explicit + position_info( const internal::input_data & d ) + : byte( d.byte ), + line( d.line ), + byte_in_line( d.byte_in_line ), + source( d.source ) + { } + + std::size_t byte; + std::size_t line; + std::size_t byte_in_line; + std::string source; + }; + + inline std::ostream & operator<< ( std::ostream & o, const position_info & p ) + { + return o << p.source << ':' << p.line << ':' << p.byte_in_line << '(' << p.byte << ')'; + } + + inline std::string to_string( const position_info & p ) + { + std::ostringstream o; + o << p; + return o.str(); + } + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/read_parser.hh b/share/include/tao/json/external/pegtl/read_parser.hh new file mode 100644 index 0000000..5146fb9 --- /dev/null +++ b/share/include/tao/json/external/pegtl/read_parser.hh @@ -0,0 +1,42 @@ +// Copyright (c) 2014-2016 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_READ_PARSER_HH +#define TAO_CPP_PEGTL_READ_PARSER_HH + +#include "eol.hh" +#include "string_parser.hh" +#include "internal/file_reader.hh" + +namespace tao_json_pegtl +{ + template< typename Eol > + class basic_read_parser + : public basic_string_parser< Eol > + { + public: + explicit + basic_read_parser( const std::string & filename ) + : basic_string_parser< Eol >( internal::file_reader( filename ).read(), filename ) + { } + + using eol = Eol; + }; + + using read_parser = basic_read_parser< lf_crlf_eol >; + + template< typename Rule, template< typename ... > class Action = nothing, template< typename ... > class Control = normal, typename ... States > + bool parse_read( const std::string & filename, States && ... st ) + { + return read_parser( filename ).parse< Rule, Action, Control >( st ... ); + } + + template< typename Rule, template< typename ... > class Action = nothing, template< typename ... > class Control = normal, typename Outer, typename ... States > + bool parse_read_nested( Outer & oi, const std::string & filename, States && ... st ) + { + return basic_read_parser< typename Outer::eol >( filename ).template parse_nested< Rule, Action, Control >( oi, st ... ); + } + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/rules.hh b/share/include/tao/json/external/pegtl/rules.hh new file mode 100644 index 0000000..c7aaf20 --- /dev/null +++ b/share/include/tao/json/external/pegtl/rules.hh @@ -0,0 +1,58 @@ +// Copyright (c) 2014-2016 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_RULES_HH +#define TAO_CPP_PEGTL_RULES_HH + +#include "parse_error.hh" + +#include "internal/rules.hh" + +namespace tao_json_pegtl +{ + template< template< typename ... > class Action, typename ... Rules > struct action : internal::action< Action, Rules ... > {}; + template< typename ... Rules > struct at : internal::at< Rules ... > {}; + template< unsigned Num > struct bytes : internal::bytes< Num > {}; + template< template< typename ... > class Control, typename ... Rules > struct control : internal::control< Control, Rules ... > {}; + template< typename ... Rules > struct disable : internal::disable< Rules ... > {}; + struct discard : internal::discard {}; + template< typename ... Rules > struct discard_if : internal::discard_if< Rules ... > {}; + template< typename ... Rules > struct enable : internal::enable< Rules ... > {}; + struct eof : internal::eof {}; + struct failure : internal::trivial< false > {}; + template< typename Cond, typename ... Thens > struct if_must : internal::if_must< Cond, Thens ... > {}; + template< typename Cond, typename Then, typename Else > struct if_must_else : internal::if_must_else< Cond, Then, Else > {}; + template< typename Cond, typename Then, typename Else > struct if_then_else : internal::if_then_else< Cond, Then, Else > {}; + template< typename Rule, typename Sep, typename Pad = void > struct list : internal::list< Rule, internal::pad< Sep, Pad > > {}; + template< typename Rule, typename Sep > struct list< Rule, Sep, void > : internal::list< Rule, Sep > {}; + template< typename Rule, typename Sep, typename Pad = void > struct list_must : internal::list_must< Rule, internal::pad< Sep, Pad > > {}; + template< typename Rule, typename Sep > struct list_must< Rule, Sep, void > : internal::list_must< Rule, Sep > {}; + template< typename Rule, typename Sep, typename Pad = void > struct list_tail : internal::list_tail_pad< Rule, Sep, Pad > {}; + template< typename Rule, typename Sep > struct list_tail< Rule, Sep, void > : internal::list_tail< Rule, Sep > {}; + template< typename M, typename S > struct minus : internal::minus< M, S > {}; + template< typename ... Rules > struct must : internal::must< Rules ... > {}; + template< typename ... Rules > struct not_at : internal::not_at< Rules ... > {}; + template< typename ... Rules > struct opt : internal::opt< Rules ... > {}; + template< typename Rule, typename Pad1, typename Pad2 = Pad1 > struct pad : internal::pad< Rule, Pad1, Pad2 > {}; + template< typename Rule, typename Pad > struct pad_opt : internal::pad_opt< Rule, Pad > {}; + template< typename Rule, typename ... Rules > struct plus : internal::plus< Rule, Rules ... > {}; + template< typename Exception > struct raise : internal::raise< Exception > {}; + template< unsigned Num, typename ... Rules > struct rep : internal::rep< Num, Rules ... > {}; + template< unsigned Max, typename ... Rules > struct rep_max : internal::rep_min_max< 0, Max, Rules ... > {}; + template< unsigned Min, typename Rule, typename ... Rules > struct rep_min : internal::rep_min< Min, Rule, Rules ... > {}; + template< unsigned Min, unsigned Max, typename ... Rules > struct rep_min_max : internal::rep_min_max< Min, Max, Rules ... > {}; + template< unsigned Max, typename ... Rules > struct rep_opt : internal::rep_opt< Max, Rules ... > {}; + template< unsigned Amount > struct require : internal::require< Amount > {}; + template< typename ... Rules > struct seq : internal::seq< Rules ... > {}; + template< typename ... Rules > struct sor : internal::sor< Rules ... > {}; + template< typename Rule, typename ... Rules > struct star : internal::star< Rule, Rules ... > {}; + template< typename Cond, typename ... Rules > struct star_must : internal::star_must< Cond, Rules ... > {}; + template< typename State, typename ... Rules > struct state : internal::state< State, Rules ... > {}; + struct success : internal::trivial< true > {}; + template< typename ... Rules > struct try_catch : internal::try_catch_type< parse_error, Rules ... > {}; + template< typename Exception, typename ... Rules > struct try_catch_type : internal::try_catch_type< Exception, Rules ... > {}; + template< typename Cond, typename ... Rules > struct until : internal::until< Cond, Rules ... > {}; + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/string_parser.hh b/share/include/tao/json/external/pegtl/string_parser.hh new file mode 100644 index 0000000..090cea6 --- /dev/null +++ b/share/include/tao/json/external/pegtl/string_parser.hh @@ -0,0 +1,62 @@ +// Copyright (c) 2014-2016 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_STRING_PARSER_HH +#define TAO_CPP_PEGTL_STRING_PARSER_HH + +#include +#include + +#include "parse.hh" +#include "normal.hh" +#include "nothing.hh" +#include "eol.hh" +#include "memory_input.hh" + +namespace tao_json_pegtl +{ + template< typename Eol > + class basic_string_parser + { + public: + basic_string_parser( std::string data, std::string in_source, const std::size_t byte = 0, const std::size_t line = 1, const std::size_t byte_in_line = 0 ) + : m_data( std::move( data ) ), + m_source( std::move( in_source ) ), + m_input( byte, line, byte_in_line, m_data.data(), m_data.data() + m_data.size(), m_source.c_str() ) + { } + + const std::string & source() const + { + return m_source; + } + + const memory_input & input() const + { + return m_input; + } + + template< typename Rule, template< typename ... > class Action = nothing, template< typename ... > class Control = normal, typename ... States > + bool parse( States && ... st ) + { + return parse_input< Rule, Action, Control >( m_input, st ... ); + } + + template< typename Rule, template< typename ... > class Action = nothing, template< typename ... > class Control = normal, typename Outer, typename ... States > + bool parse_nested( Outer & oi, States && ... st ) + { + return parse_input_nested< Rule, Action, Control >( oi, m_input, st ... ); + } + + using eol = Eol; + + private: + std::string m_data; + std::string m_source; + basic_memory_input< Eol > m_input; + }; + + using string_parser = basic_string_parser< lf_crlf_eol >; + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/trace.hh b/share/include/tao/json/external/pegtl/trace.hh new file mode 100644 index 0000000..9b6c7ec --- /dev/null +++ b/share/include/tao/json/external/pegtl/trace.hh @@ -0,0 +1,125 @@ +// Copyright (c) 2014-2016 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_TRACE_HH +#define TAO_CPP_PEGTL_TRACE_HH + +#include +#include +#include +#include +#include + +#include "parse.hh" +#include "normal.hh" +#include "nothing.hh" +#include "position_info.hh" + +#include "internal/demangle.hh" + +namespace tao_json_pegtl +{ + struct trace_state + { + unsigned rule = 0; + unsigned line = 0; + std::vector< unsigned > stack; + }; + + template< typename Rule > + struct tracer + : normal< Rule > + { + template< typename Input, typename ... States > + static void start( const Input & in, States && ... ) + { + std::cerr << in.position() << " start " << internal::demangle< Rule >() << std::endl; + } + + template< typename Input > + static void start( const Input & in, trace_state & ts ) + { + std::cerr << std::setw( 6 ) << ++ts.line << " " << std::setw( 6 ) << ++ts.rule << " " << in.position() << " start " << internal::demangle< Rule >() << std::endl; + ts.stack.push_back( ts.rule ); + } + + template< typename Input, typename ... States > + static void success( const Input & in, States && ... ) + { + std::cerr << in.position() << " success " << internal::demangle< Rule >() << std::endl; + } + + template< typename Input > + static void success( const Input & in, trace_state & ts ) + { + assert( ! ts.stack.empty() ); + std::cerr << std::setw( 6 ) << ++ts.line << " " << std::setw( 6 ) << ts.stack.back() << " " << in.position() << " success " << internal::demangle< Rule >() << std::endl; + ts.stack.pop_back(); + } + + template< typename Input, typename ... States > + static void failure( const Input & in, States && ... ) + { + std::cerr << in.position() << " failure " << internal::demangle< Rule >() << std::endl; + } + + template< typename Input > + static void failure( const Input & in, trace_state & ts ) + { + assert( ! ts.stack.empty() ); + std::cerr << std::setw( 6 ) << ++ts.line << " " << std::setw( 6 ) << ts.stack.back() << " " << in.position() << " failure " << internal::demangle< Rule >() << std::endl; + ts.stack.pop_back(); + } + }; + + template< typename Rule, template< typename ... > class Action = nothing, typename Input, typename ... States > + bool trace_input( Input & in, States && ... st ) + { + return parse_input< Rule, Action, tracer >( in, st ... ); + } + + template< typename Rule, template< typename ... > class Action = nothing, typename ... Args > + bool trace_arg( Args && ... args ) + { + return parse_arg< Rule, Action, tracer >( std::forward< Args >( args ) ... ); + } + + template< typename Rule, template< typename ... > class Action = nothing, typename ... Args > + bool trace_memory( Args && ... args ) + { + return parse_memory< Rule, Action, tracer >( std::forward< Args >( args ) ... ); + } + + template< typename Rule, template< typename ... > class Action = nothing, typename ... Args > + bool trace_string( Args && ... args ) + { + return parse_string< Rule, Action, tracer >( std::forward< Args >( args ) ... ); + } + + template< typename Rule, template< typename ... > class Action = nothing, typename ... Args > + bool trace_cstream( Args && ... args ) + { + return parse_cstream< Rule, Action, tracer >( std::forward< Args >( args ) ... ); + } + + template< typename Rule, template< typename ... > class Action = nothing, typename ... Args > + bool trace_stdin( Args && ... args ) + { + return parse_stdin< Rule, Action, tracer >( std::forward< Args >( args ) ... ); + } + + template< typename Rule, template< typename ... > class Action = nothing, typename ... Args > + bool trace_cstring( Args && ... args ) + { + return parse_cstring< Rule, Action, tracer >( std::forward< Args >( args ) ... ); + } + + template< typename Rule, template< typename ... > class Action = nothing, typename ... Args > + bool trace_istream( Args && ... args ) + { + return parse_istream< Rule, Action, tracer >( std::forward< Args >( args ) ... ); + } + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/utf16.hh b/share/include/tao/json/external/pegtl/utf16.hh new file mode 100644 index 0000000..f8b6723 --- /dev/null +++ b/share/include/tao/json/external/pegtl/utf16.hh @@ -0,0 +1,26 @@ +// Copyright (c) 2015 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_UTF16_HH +#define TAO_CPP_PEGTL_UTF16_HH + +#include "internal/rules.hh" +#include "internal/peek_utf16.hh" +#include "internal/result_on_found.hh" + +namespace tao_json_pegtl +{ + namespace utf16 + { + struct any : internal::any< internal::peek_utf16 > {}; + template< char32_t ... Cs > struct not_one : internal::one< internal::result_on_found::FAILURE, internal::peek_utf16, Cs ... > {}; + template< char32_t Lo, char32_t Hi > struct not_range : internal::range< internal::result_on_found::FAILURE, internal::peek_utf16, Lo, Hi > {}; + template< char32_t ... Cs > struct one : internal::one< internal::result_on_found::SUCCESS, internal::peek_utf16, Cs ... > {}; + template< char32_t Lo, char32_t Hi > struct range : internal::range< internal::result_on_found::SUCCESS, internal::peek_utf16, Lo, Hi > {}; + template< char32_t ... Cs > struct ranges : internal::ranges< internal::peek_utf16, Cs ... > {}; + + } // namespace utf16 + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/utf32.hh b/share/include/tao/json/external/pegtl/utf32.hh new file mode 100644 index 0000000..66db6fd --- /dev/null +++ b/share/include/tao/json/external/pegtl/utf32.hh @@ -0,0 +1,26 @@ +// Copyright (c) 2014-2015 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_UTF32_HH +#define TAO_CPP_PEGTL_UTF32_HH + +#include "internal/rules.hh" +#include "internal/peek_utf32.hh" +#include "internal/result_on_found.hh" + +namespace tao_json_pegtl +{ + namespace utf32 + { + struct any : internal::any< internal::peek_utf32 > {}; + template< char32_t ... Cs > struct not_one : internal::one< internal::result_on_found::FAILURE, internal::peek_utf32, Cs ... > {}; + template< char32_t Lo, char32_t Hi > struct not_range : internal::range< internal::result_on_found::FAILURE, internal::peek_utf32, Lo, Hi > {}; + template< char32_t ... Cs > struct one : internal::one< internal::result_on_found::SUCCESS, internal::peek_utf32, Cs ... > {}; + template< char32_t Lo, char32_t Hi > struct range : internal::range< internal::result_on_found::SUCCESS, internal::peek_utf32, Lo, Hi > {}; + template< char32_t ... Cs > struct ranges : internal::ranges< internal::peek_utf32, Cs ... > {}; + + } // namespace utf32 + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/external/pegtl/utf8.hh b/share/include/tao/json/external/pegtl/utf8.hh new file mode 100644 index 0000000..bd31da3 --- /dev/null +++ b/share/include/tao/json/external/pegtl/utf8.hh @@ -0,0 +1,26 @@ +// Copyright (c) 2014-2015 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/ + +#ifndef TAO_CPP_PEGTL_UTF8_HH +#define TAO_CPP_PEGTL_UTF8_HH + +#include "internal/rules.hh" +#include "internal/peek_utf8.hh" +#include "internal/result_on_found.hh" + +namespace tao_json_pegtl +{ + namespace utf8 + { + struct any : internal::any< internal::peek_utf8 > {}; + template< char32_t ... Cs > struct not_one : internal::one< internal::result_on_found::FAILURE, internal::peek_utf8, Cs ... > {}; + template< char32_t Lo, char32_t Hi > struct not_range : internal::range< internal::result_on_found::FAILURE, internal::peek_utf8, Lo, Hi > {}; + template< char32_t ... Cs > struct one : internal::one< internal::result_on_found::SUCCESS, internal::peek_utf8, Cs ... > {}; + template< char32_t Lo, char32_t Hi > struct range : internal::range< internal::result_on_found::SUCCESS, internal::peek_utf8, Lo, Hi > {}; + template< char32_t ... Cs > struct ranges : internal::ranges< internal::peek_utf8, Cs ... > {}; + + } // namespace utf8 + +} // namespace tao_json_pegtl + +#endif diff --git a/share/include/tao/json/from_stream.hh b/share/include/tao/json/from_stream.hh new file mode 100644 index 0000000..ee253d7 --- /dev/null +++ b/share/include/tao/json/from_stream.hh @@ -0,0 +1,52 @@ +// Copyright (c) 2015-2016 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/taocpp/json/ + +#ifndef TAOCPP_JSON_INCLUDE_FROM_STREAM_HH +#define TAOCPP_JSON_INCLUDE_FROM_STREAM_HH + +#include +#include +#include + +#include "sax/from_stream.hh" +#include "sax/to_value.hh" + +namespace tao +{ + namespace json + { + template< template< typename ... > class Traits > + basic_value< Traits > from_stream( std::istream & stream, const char * source = nullptr, const std::size_t maximum_buffer_size = 4000 ) + { + sax::to_basic_value< Traits > consumer; + sax::from_stream( stream, consumer, source, maximum_buffer_size ); + return std::move( consumer.value ); + } + + template< template< typename ... > class Traits > + basic_value< Traits > from_stream( std::istream & stream, const std::string & source, const std::size_t maximum_buffer_size = 4000 ) + { + return from_stream< Traits >( stream, source.c_str(), maximum_buffer_size ); + } + + inline value from_stream( std::istream & stream, const char * source = nullptr, const std::size_t maximum_buffer_size = 4000 ) + { + return from_stream< traits >( stream, source, maximum_buffer_size ); + } + + inline value from_stream( std::istream & stream, const std::string & source, const std::size_t maximum_buffer_size = 4000 ) + { + return from_stream< traits >( stream, source.c_str(), maximum_buffer_size ); + } + + template< template< typename ... > class Traits, typename ... Ts > + void from_stream( basic_value< Traits > & output, Ts && ... ts ) + { + output = from_stream< Traits >( std::forward< Ts >( ts ) ... ); + } + + } // json + +} // tao + +#endif diff --git a/share/include/tao/json/from_string.hh b/share/include/tao/json/from_string.hh new file mode 100644 index 0000000..021add8 --- /dev/null +++ b/share/include/tao/json/from_string.hh @@ -0,0 +1,83 @@ +// Copyright (c) 2015-2016 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/taocpp/json/ + +#ifndef TAOCPP_JSON_INCLUDE_FROM_STRING_HH +#define TAOCPP_JSON_INCLUDE_FROM_STRING_HH + +#include +#include +#include + +#include "sax/from_string.hh" +#include "sax/to_value.hh" + +namespace tao +{ + namespace json + { + template< template< typename ... > class Traits > + basic_value< Traits > from_string( const char * data, const std::size_t size, const char * source = nullptr, const std::size_t byte = 0, const std::size_t line = 1, const std::size_t column = 0 ) + { + sax::to_basic_value< Traits > consumer; + sax::from_string( data, size, consumer, source, byte, line, column ); + return std::move( consumer.value ); + } + + template< template< typename ... > class Traits > + basic_value< Traits > from_string( const char * data, const std::size_t size, const std::string & source, const std::size_t byte = 0, const std::size_t line = 1, const std::size_t column = 0 ) + { + return from_string< Traits >( data, size, source.c_str(), byte, line, column ); + } + + inline value from_string( const char * data, const std::size_t size, const char * source = nullptr, const std::size_t byte = 0, const std::size_t line = 1, const std::size_t column = 0 ) + { + return from_string< traits >( data, size, source, byte, line, column ); + } + + inline value from_string( const char * data, const std::size_t size, const std::string & source, const std::size_t byte = 0, const std::size_t line = 1, const std::size_t column = 0 ) + { + return from_string< traits >( data, size, source.c_str(), byte, line, column ); + } + + template< template< typename ... > class Traits > + basic_value< Traits > from_string( const std::string & data, const char * source = nullptr, const std::size_t byte = 0, const std::size_t line = 1, const std::size_t column = 0 ) + { + return from_string< Traits >( data.data(), data.size(), source, byte, line, column ); + } + + template< template< typename ... > class Traits > + basic_value< Traits > from_string( const std::string & data, const std::string & source, const std::size_t byte = 0, const std::size_t line = 1, const std::size_t column = 0 ) + { + return from_string< Traits >( data.data(), data.size(), source.c_str(), byte, line, column ); + } + + inline value from_string( const std::string & data, const char * source = nullptr, const std::size_t byte = 0, const std::size_t line = 1, const std::size_t column = 0 ) + { + return json::from_string( data.data(), data.size(), source, byte, line, column ); + } + + inline value from_string( const std::string & data, const std::string & source, const std::size_t byte = 0, const std::size_t line = 1, const std::size_t column = 0 ) + { + return json::from_string( data.data(), data.size(), source.c_str(), byte, line, column ); + } + + template< template< typename ... > class Traits, typename ... Ts > + void from_string( basic_value< Traits > & output, Ts && ... ts ) + { + output = from_string< Traits >( std::forward< Ts >( ts ) ... ); + } + + inline namespace literals + { + inline value operator"" _json( const char * data, const std::size_t size ) + { + return json::from_string( data, size, "literal" ); + } + + } // literals + + } // json + +} // tao + +#endif diff --git a/share/include/tao/json/internal/action.hh b/share/include/tao/json/internal/action.hh new file mode 100644 index 0000000..7da4822 --- /dev/null +++ b/share/include/tao/json/internal/action.hh @@ -0,0 +1,222 @@ +// Copyright (c) 2016 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/taocpp/json/ + +#ifndef TAOCPP_JSON_INCLUDE_INTERNAL_ACTION_HH +#define TAOCPP_JSON_INCLUDE_INTERNAL_ACTION_HH + +#include "../external/pegtl/contrib/changes.hh" + +#include "errors.hh" +#include "grammar.hh" + +#include "number_state.hh" + +namespace tao +{ + namespace json + { + namespace internal + { + template < typename Rule > + struct action : tao_json_pegtl::nothing< Rule > {}; + + template<> + struct action< rules::null > + { + template< typename Input, typename Consumer > + static void apply( const Input &, Consumer & consumer ) + { + consumer.null(); + } + }; + + template<> + struct action< rules::true_ > + { + template< typename Input, typename Consumer > + static void apply( const Input &, Consumer & consumer ) + { + consumer.boolean( true ); + } + }; + + template<> + struct action< rules::false_ > + { + template< typename Input, typename Consumer > + static void apply( const Input &, Consumer & consumer ) + { + consumer.boolean( false ); + } + }; + + template<> + struct action< rules::array::begin > + { + template< typename Input, typename Consumer > + static void apply( const Input &, Consumer & consumer ) + { + consumer.begin_array(); + } + }; + + template<> + struct action< rules::array::element > + { + template< typename Input, typename Consumer > + static void apply( const Input &, Consumer & consumer ) + { + consumer.element(); + } + }; + + template<> + struct action< rules::array::end > + { + template< typename Input, typename Consumer > + static void apply( const Input &, Consumer & consumer ) + { + consumer.end_array(); + } + }; + + template<> + struct action< rules::object::begin > + { + template< typename Input, typename Consumer > + static void apply( const Input &, Consumer & consumer ) + { + consumer.begin_object(); + } + }; + + template<> + struct action< rules::object::element > + { + template< typename Input, typename Consumer > + static void apply( const Input &, Consumer & consumer ) + { + consumer.member(); + } + }; + + template<> + struct action< rules::object::end > + { + template< typename Input, typename Consumer > + static void apply( const Input &, Consumer & consumer ) + { + consumer.end_object(); + } + }; + + template<> + struct action< rules::msign > + { + template< typename Input > + static void apply( const Input &, number_state & result ) + { + result.mneg = true; + } + }; + + template<> + struct action< rules::esign > + { + template< typename Input > + static void apply( const Input & in, number_state & result ) + { + result.eneg = ( in.peek_char() == '-' ); + } + }; + + template<> + struct action< rules::idigits > + { + template< typename Input > + static void apply( const Input & in, number_state & result ) + { + if ( in.size() > ( 1 << 20 ) ) { + throw tao_json_pegtl::parse_error( "JSON number with 1 megabyte digits", in ); + } + const auto c = std::min( in.size(), max_mantissa_digits ); + std::memcpy( result.mantissa, in.begin(), c ); + result.exponent10 += static_cast< number_state::exponent10_t >( in.size() - c ); + result.msize = static_cast< number_state::msize_t >( c ); + + for ( std::size_t i = c; i < in.size(); ++i ) { + if ( in.peek_char( i ) != '0' ) { + result.drop = true; + return; + } + } + } + }; + + template<> + struct action< rules::fdigits > + { + template< typename Input > + static void apply( const Input & in, number_state & result ) + { + result.isfp = true; + + const auto * b = in.begin(); + const auto * e = in.end(); + + while ( ( e > b ) && ( e[ -1 ] == '0' ) ) { + --e; + } + if ( ! result.msize ) { + while ( ( b < e ) && ( b[ 0 ] == '0' ) ) { + ++b; + --result.exponent10; + } + } + const auto c = std::min( std::size_t( e - b ), max_mantissa_digits - result.msize ); + std::memcpy( result.mantissa + result.msize, b, c ); + result.exponent10 -= static_cast< number_state::exponent10_t >( c ); + result.msize += static_cast< number_state::msize_t >( c ); + + for ( const auto * r = b + c; r < e; ++r ) { + if ( *r != '0' ) { + result.drop = true; + return; + } + } + } + }; + + template<> + struct action< rules::edigits > + { + template< typename Input > + static void apply( const Input & in, number_state & result ) + { + result.isfp = true; + + const char * b = in.begin(); + + while ( ( b < in.end() ) && ( b[ 0 ] == '0' ) ) { + ++b; + } + if ( ( in.end() - b ) > 9 ) { + throw tao_json_pegtl::parse_error( "JSON exponent has more than 9 significant digits", in ); + } + int exponent10 = 0; + + while ( b < in.end() ) { + exponent10 = ( exponent10 * 10 ) + ( b[ 0 ] - '0' ); + ++b; + } + result.exponent10 += ( result.eneg ? -exponent10 : exponent10 ); + } + }; + + } // internal + + } // json + +} // tao + +#endif diff --git a/share/include/tao/json/internal/control.hh b/share/include/tao/json/internal/control.hh new file mode 100644 index 0000000..e9ee7e3 --- /dev/null +++ b/share/include/tao/json/internal/control.hh @@ -0,0 +1,41 @@ +// Copyright (c) 2016 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/taocpp/json/ + +#ifndef TAOCPP_JSON_INCLUDE_INTERNAL_CONTROL_HH +#define TAOCPP_JSON_INCLUDE_INTERNAL_CONTROL_HH + +#include "../external/pegtl/contrib/changes.hh" + +#include "errors.hh" + +#include "unescape_action.hh" + +#include "number_state.hh" +#include "string_state.hh" +#include "key_state.hh" + +namespace tao +{ + namespace json + { + namespace internal + { + template< typename Rule > + struct control : errors< Rule > {}; + + template<> + struct control< rules::number > : tao_json_pegtl::change_state< rules::number, number_state, tao_json_pegtl::normal > {}; + + template<> + struct control< rules::string::content > : tao_json_pegtl::change_state_and_action< rules::string::content, string_state, unescape_action, tao_json_pegtl::normal > {}; + + template<> + struct control< rules::key::content > : tao_json_pegtl::change_state_and_action< rules::key::content, key_state, unescape_action, tao_json_pegtl::normal > {}; + + } // internal + + } // json + +} // tao + +#endif diff --git a/share/include/tao/json/internal/errors.hh b/share/include/tao/json/internal/errors.hh new file mode 100644 index 0000000..524ace7 --- /dev/null +++ b/share/include/tao/json/internal/errors.hh @@ -0,0 +1,58 @@ +// Copyright (c) 2015-2016 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/taocpp/json/ + +#ifndef TAOCPP_JSON_INCLUDE_INTERNAL_ERRORS_HH +#define TAOCPP_JSON_INCLUDE_INTERNAL_ERRORS_HH + +#include + +#include "../external/pegtl/normal.hh" +#include "../external/pegtl/parse_error.hh" + +#include "grammar.hh" + +namespace tao +{ + namespace json + { + namespace internal + { + template< typename Rule > + struct errors + : public tao_json_pegtl::normal< Rule > + { + static const std::string error_message; + + template< typename Input, typename ... States > + static void raise( const Input & in, States && ... ) + { + throw tao_json_pegtl::parse_error( error_message, in ); + } + }; + + template<> const std::string errors< rules::text >::error_message __attribute__(( weak )) = "no valid JSON"; + + template<> const std::string errors< rules::end_array >::error_message __attribute__(( weak )) = "incomplete array, expected ']'"; + template<> const std::string errors< rules::end_object >::error_message __attribute__(( weak )) = "incomplete object, expected '}'"; + template<> const std::string errors< rules::member >::error_message __attribute__(( weak )) = "expected member"; + template<> const std::string errors< rules::name_separator >::error_message __attribute__(( weak )) = "expected ':'"; + template<> const std::string errors< rules::array_element >::error_message __attribute__(( weak )) = "expected value"; + template<> const std::string errors< rules::value >::error_message __attribute__(( weak )) = "expected value"; + + template<> const std::string errors< rules::edigits >::error_message __attribute__(( weak )) = "expected at least one exponent digit"; + template<> const std::string errors< rules::fdigits >::error_message __attribute__(( weak )) = "expected at least one fraction digit"; + template<> const std::string errors< rules::xdigit >::error_message __attribute__(( weak )) = "incomplete universal character name"; + template<> const std::string errors< rules::escaped >::error_message __attribute__(( weak )) = "unknown escape sequence"; + template<> const std::string errors< rules::chars >::error_message __attribute__(( weak )) = "invalid character in string"; + template<> const std::string errors< rules::string::content >::error_message __attribute__(( weak )) = "unterminated string"; + template<> const std::string errors< rules::key::content >::error_message __attribute__(( weak )) = "unterminated key"; + + template<> const std::string errors< tao_json_pegtl::eof >::error_message __attribute__(( weak )) = "unexpected character after JSON value"; + + } // internal + + } // json + +} // tao + +#endif diff --git a/share/include/tao/json/internal/escape.hh b/share/include/tao/json/internal/escape.hh new file mode 100644 index 0000000..61ab587 --- /dev/null +++ b/share/include/tao/json/internal/escape.hh @@ -0,0 +1,76 @@ +// Copyright (c) 2016 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/taocpp/json/ + +#ifndef TAOCPP_JSON_INCLUDE_INTERNAL_ESCAPE_HH +#define TAOCPP_JSON_INCLUDE_INTERNAL_ESCAPE_HH + +#include +#include + +namespace tao +{ + namespace json + { + namespace internal + { + inline void escape( std::ostream & os, const std::string & s ) + { + static const char * h = "0123456789abcdef"; + + const char * p = s.data(); + const char * l = p; + const char * const e = s.data() + s.size(); + while ( p != e ) { + const unsigned char c = * p; + if ( c == '\\' ) { + os.write( l, p - l ); + l = ++p; + os << "\\\\"; + } + else if ( c == '"' ) { + os.write( l, p - l ); + l = ++p; + os << "\\\""; + } + else if ( c < 32 ) { + os.write( l, p - l ); + l = ++p; + switch ( c ) { + case '\b': + os << "\\b"; + break; + case '\f': + os << "\\f"; + break; + case '\n': + os << "\\n"; + break; + case '\r': + os << "\\r"; + break; + case '\t': + os << "\\t"; + break; + default: + os << "\\u00" << h[ ( c & 0xf0 ) >> 4 ] << h[ c & 0x0f ]; + } + } + else if ( c == 127 ) { + os.write( l, p - l ); + l = ++p; + os << "\\u007f"; + } + else { + ++p; + } + } + os.write( l, p - l ); + } + + } // internal + + } // json + +} // tao + +#endif diff --git a/share/include/tao/json/internal/get_by_enum.hh b/share/include/tao/json/internal/get_by_enum.hh new file mode 100644 index 0000000..6832656 --- /dev/null +++ b/share/include/tao/json/internal/get_by_enum.hh @@ -0,0 +1,126 @@ +// Copyright (c) 2015-2016 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/taocpp/json/ + +#ifndef TAOCPP_JSON_INCLUDE_INTERNAL_GET_BY_ENUM_HH +#define TAOCPP_JSON_INCLUDE_INTERNAL_GET_BY_ENUM_HH + +#include + +#include "../type.hh" + +#include "value_union.hh" + +namespace tao +{ + namespace json + { + namespace internal + { + template< type > struct get_by_enum; + + template<> struct get_by_enum< type::NULL_ > + { + template< typename V > + static null_t get( const value_union< V > & ) + { + return null; + } + }; + + template<> struct get_by_enum< type::BOOLEAN > + { + template< typename V > + static bool get( const value_union< V > & u ) + { + return u.b; + } + }; + + template<> struct get_by_enum< type::SIGNED > + { + template< typename V > + static std::int64_t get( const value_union< V > & u ) + { + return u.i; + } + }; + + template<> struct get_by_enum< type::UNSIGNED > + { + template< typename V > + static std::uint64_t get( const value_union< V > & u ) + { + return u.u; + } + }; + + template<> struct get_by_enum< type::DOUBLE > + { + template< typename V > + static double get( const value_union< V > & u ) + { + return u.d; + } + }; + + template<> struct get_by_enum< type::STRING > + { + template< typename V > + static std::string & get( value_union< V > & u ) + { + return u.s; + } + + template< typename V > + static const std::string & get( const value_union< V > & u ) + { + return u.s; + } + }; + + template<> struct get_by_enum< type::ARRAY > + { + template< typename V > + static std::vector< V > & get( value_union< V > & u ) + { + return u.a; + } + + template< typename V > + static const std::vector< V > & get( const value_union< V > & u ) + { + return u.a; + } + }; + + template<> struct get_by_enum< type::OBJECT > + { + template< typename V > + static std::map< std::string, V > & get( value_union< V > & u ) + { + return u.o; + } + + template< typename V > + static const std::map< std::string, V > & get( const value_union< V > & u ) + { + return u.o; + } + }; + + template<> struct get_by_enum< type::RAW_PTR > + { + template< typename V > + static const V * get( const value_union< V > & u ) + { + return u.p; + } + }; + + } // internal + + } // json + +} // tao + +#endif diff --git a/share/include/tao/json/internal/grammar.hh b/share/include/tao/json/internal/grammar.hh new file mode 100644 index 0000000..c775304 --- /dev/null +++ b/share/include/tao/json/internal/grammar.hh @@ -0,0 +1,149 @@ +// Copyright (c) 2015-2016 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/taocpp/json/ + +#ifndef TAOCPP_JSON_INCLUDE_INTERNAL_GRAMMAR_HH +#define TAOCPP_JSON_INCLUDE_INTERNAL_GRAMMAR_HH + +#include "../external/pegtl.hh" +#include "../external/pegtl/contrib/abnf.hh" + +namespace tao +{ + namespace json + { + namespace internal + { + namespace rules + { + using namespace tao_json_pegtl; + + struct ws : one< ' ', '\t', '\n', '\r' > {}; + + template< typename R, typename P = ws > struct padr : tao_json_pegtl::internal::seq< R, tao_json_pegtl::internal::star< P > > {}; + + struct begin_array : padr< one< '[' > > {}; + struct begin_object : padr< one< '{' > > {}; + struct end_array : one< ']' > {}; + struct end_object : one< '}' > {}; + struct name_separator : pad< one< ':' >, ws > {}; + struct value_separator : padr< one< ',' > > {}; + struct element_separator : padr< one< ',' > > {}; + + struct false_ : tao_json_pegtl_string_t( "false" ) {}; + struct null : tao_json_pegtl_string_t( "null" ) {}; + struct true_ : tao_json_pegtl_string_t( "true" ) {}; + + struct digits : plus< abnf::DIGIT > {}; + + struct zero : one< '0' > {}; + struct msign : one< '-' > {}; + struct esign : one< '-', '+' > {}; + + struct edigits : digits {}; + struct fdigits : digits {}; + struct idigits : digits {}; + + struct exp : seq< one< 'e', 'E' >, opt< esign >, must< edigits > > {}; + struct frac : if_must< one< '.' >, fdigits > {}; + struct int_ : sor< zero, idigits > {}; + struct number : seq< opt< msign >, int_, opt< frac >, opt< exp > > {}; + + struct xdigit : abnf::HEXDIG {}; + struct unicode : list< seq< one< 'u' >, rep< 4, must< xdigit > > >, one< '\\' > > {}; + struct escaped_char : one< '"', '\\', '/', 'b', 'f', 'n', 'r', 't' > {}; + struct escaped : sor< escaped_char, unicode > {}; + + struct unescaped + { + using analyze_t = analysis::generic< analysis::rule_type::ANY >; + + template< typename Input > + static bool match( Input & in ) + { + bool result = false; + + while ( ! in.empty() ) { + if ( const auto t = tao_json_pegtl::internal::peek_utf8::peek( in ) ) { + if ( ( 0x20 <= t.data ) && ( t.data <= 0x10ffff ) && ( t.data != '\\' ) && ( t.data != '"' ) ) { + in.bump_in_this_line( t.size ); + result = true; + continue; + } + } + return result; + } + throw std::logic_error( "code should be unreachable" ); // LCOV_EXCL_LINE + } + }; + + struct chars : if_then_else< one< '\\' >, must< escaped >, unescaped > {}; + + struct string_content : until< at< one< '"' > >, must< chars > > {}; + struct string : seq< one< '"' >, must< string_content >, any > + { + using content = string_content; + }; + + struct key_content : until< at< one< '"' > >, must< chars > > {}; + struct key : seq< one< '"' >, must< key_content >, any > + { + using content = key_content; + }; + + struct value; + + struct array_element; + struct array_content : opt< list_must< array_element, element_separator > > {}; + struct array : seq< begin_array, array_content, must< end_array > > + { + using begin = begin_array; + using end = end_array; + using element = array_element; + using content = array_content; + }; + + struct member : if_must< key, name_separator, value > {}; + struct object_content : opt< list_must< member, value_separator > > {}; + struct object : seq< begin_object, object_content, must< end_object > > + { + using begin = begin_object; + using end = end_object; + using element = member; + using content = object_content; + }; + + struct sor_value + { + using analyze_t = analysis::generic< analysis::rule_type::SOR, string, number, object, array, false_, true_, null >; + + template< apply_mode A, template< typename ... > class Action, template< typename ... > class Control, typename Input, typename ... States > + static bool match( Input & in, States && ... st ) + { + switch( in.peek_char() ) { + case '"': return Control< string >::template match< A, Action, Control >( in, st ... ); + case '{': return Control< object >::template match< A, Action, Control >( in, st ... ); + case '[': return Control< array >::template match< A, Action, Control >( in, st ... ); + case 'n': return Control< null >::template match< A, Action, Control >( in, st ... ); + case 't': return Control< true_ >::template match< A, Action, Control >( in, st ... ); + case 'f': return Control< false_ >::template match< A, Action, Control >( in, st ... ); + default: return Control< number >::template match< A, Action, Control >( in, st ... ); + } + } + }; + + struct value : padr< discard_if< sor_value > > {}; + struct array_element : seq< value > {}; + + struct text : seq< star< ws >, value > {}; + + } // rules + + struct grammar : tao_json_pegtl::must< rules::text, tao_json_pegtl::eof > {}; + + } // internal + + } // json + +} // tao + +#endif diff --git a/share/include/tao/json/internal/integer_sequence.hh b/share/include/tao/json/internal/integer_sequence.hh new file mode 100644 index 0000000..e49ce0d --- /dev/null +++ b/share/include/tao/json/internal/integer_sequence.hh @@ -0,0 +1,80 @@ +// Copyright (c) 2016 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/taocpp/json/ + +#ifndef TAOCPP_JSON_INCLUDE_INTERNAL_INTEGER_SEQUENCE_HPP +#define TAOCPP_JSON_INCLUDE_INTERNAL_INTEGER_SEQUENCE_HPP + +#include +#include + +namespace tao +{ + namespace json + { + namespace internal + { + template< typename T, T... Ns > + struct integer_sequence + { + using value_type = T; + + static constexpr std::size_t size() noexcept + { + return sizeof...( Ns ); + } + }; + + template< std::size_t... Ns > + using index_sequence = integer_sequence< std::size_t, Ns... >; + + template< typename, std::size_t, bool > + struct double_up; + + template< typename T, T... Ns, std::size_t N > + struct double_up< integer_sequence< T, Ns... >, N, false > + { + using type = integer_sequence< T, Ns..., ( N + Ns )... >; + }; + + template< typename T, T... Ns, std::size_t N > + struct double_up< integer_sequence< T, Ns... >, N, true > + { + using type = integer_sequence< T, Ns..., ( N + Ns )..., 2 * N >; + }; + + template< typename T, T N, typename = void > + struct generate_sequence; + + template< typename T, T N, typename > + struct generate_sequence + : double_up< typename generate_sequence< T, N / 2 >::type, N / 2, N % 2 == 1 > + {}; + + template< typename T, T N > + struct generate_sequence< T, N, typename std::enable_if< ( N == 0 ) >::type > + { + using type = integer_sequence< T >; + }; + + template< typename T, T N > + struct generate_sequence< T, N, typename std::enable_if< ( N == 1 ) >::type > + { + using type = integer_sequence< T, 0 >; + }; + + template< typename T, T N > + using make_integer_sequence = typename generate_sequence< T, N >::type; + + template< std::size_t N > + using make_index_sequence = make_integer_sequence< std::size_t, N >; + + template< typename... Ts > + using index_sequence_for = make_index_sequence< sizeof...( Ts ) >; + + } // internal + + } // json + +} // tao + +#endif // TAOCPP_JSON_INCLUDE_INTERNAL_INTEGER_SEQUENCE_HPP diff --git a/share/include/tao/json/internal/key_state.hh b/share/include/tao/json/internal/key_state.hh new file mode 100644 index 0000000..d7c031f --- /dev/null +++ b/share/include/tao/json/internal/key_state.hh @@ -0,0 +1,37 @@ +// Copyright (c) 2016 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/taocpp/json/ + +#ifndef TAOCPP_JSON_INCLUDE_INTERNAL_KEY_STATE_HH +#define TAOCPP_JSON_INCLUDE_INTERNAL_KEY_STATE_HH + +#include +#include + +namespace tao +{ + namespace json + { + namespace internal + { + struct key_state + { + key_state() = default; + key_state( const key_state & ) = delete; + void operator= ( const key_state & ) = delete; + + template< typename Consumer > + void success( Consumer & consumer ) + { + consumer.key( std::move( unescaped ) ); + } + + std::string unescaped; + }; + + } // internal + + } // json + +} // tao + +#endif diff --git a/share/include/tao/json/internal/number_state.hh b/share/include/tao/json/internal/number_state.hh new file mode 100644 index 0000000..4e48d2e --- /dev/null +++ b/share/include/tao/json/internal/number_state.hh @@ -0,0 +1,79 @@ +// Copyright (c) 2016 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/taocpp/json/ + +#ifndef TAOCPP_JSON_INCLUDE_INTERNAL_NUMBER_STATE_HH +#define TAOCPP_JSON_INCLUDE_INTERNAL_NUMBER_STATE_HH + +#include +#include +#include + +#include "../external/double.hh" + +namespace tao +{ + namespace json + { + namespace internal + { + static const std::size_t max_mantissa_digits = 772; + + struct number_state + { + using exponent10_t = int32_t; + using msize_t = uint16_t; + + number_state() {} + + number_state( const number_state & ) = delete; + void operator= ( const number_state & ) = delete; + + exponent10_t exponent10 = 0; + msize_t msize = 0; // Excluding sign. + bool isfp = false; + bool mneg = false; + bool eneg = false; + bool drop = false; + char mantissa[ max_mantissa_digits + 1 ]; + + template< typename Consumer > + void success( Consumer & consumer ) + { + if ( ! isfp && msize <= 20 ) { + mantissa[ msize ] = 0; + char * p; + errno = 0; + const std::uint64_t ull = std::strtoull( mantissa, & p, 10 ); + if ( ( errno != ERANGE ) && ( p == mantissa + msize ) ) { + if ( mneg ) { + if ( ull < 9223372036854775808ull ) { + consumer.number( -static_cast< std::int64_t >( ull ) ); + return; + } + else if ( ull == 9223372036854775808ull ) { + consumer.number( static_cast< std::int64_t >( -9223372036854775807ll - 1 ) ); + return; + } + } + else { + consumer.number( ull ); + return; + } + } + } + if ( drop ) { + mantissa[ msize++ ] = '1'; + --exponent10; + } + const auto d = json_double_conversion::Strtod( json_double_conversion::Vector< const char >( mantissa, msize ), exponent10 ); + consumer.number( mneg ? -d : d ); + } + }; + + } // internal + + } // json + +} // tao + +#endif diff --git a/share/include/tao/json/internal/sha256.hh b/share/include/tao/json/internal/sha256.hh new file mode 100644 index 0000000..a642798 --- /dev/null +++ b/share/include/tao/json/internal/sha256.hh @@ -0,0 +1,214 @@ +// Copyright (c) 2016 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/taocpp/json/ + +#ifndef TAOCPP_JSON_INCLUDE_INTERNAL_SHA256_HH +#define TAOCPP_JSON_INCLUDE_INTERNAL_SHA256_HH + +// Implements RFC 6234, SHA-256 + +#include +#include +#include +#include + +#define DBL_INT_ADD(a,b,c) if (a > 0xffffffff - (c)) ++b; a += c; + +// RFC 6234, 3.d; see also http://stackoverflow.com/a/4209604/2073257 +#define ROR( x, N ) ( ( x >> N ) | ( x << ( 32 - N ) ) ) + +// RFC 6234, 5.1 +#define CH( x, y, z ) ( ( x & y ) ^ ( ~x & z ) ) +#define MAJ( x, y, z ) ( ( x & y ) ^ ( x & z ) ^ ( y & z ) ) +#define BSIG0( x ) ( ROR( x, 2 ) ^ ROR( x, 13 ) ^ ROR( x, 22 ) ) +#define BSIG1( x ) ( ROR( x, 6 ) ^ ROR( x, 11 ) ^ ROR( x, 25 ) ) +#define SSIG0( x ) ( ROR( x, 7 ) ^ ROR( x, 18 ) ^ ( x >> 3 ) ) +#define SSIG1( x ) ( ROR( x, 17 ) ^ ROR( x, 19 ) ^ ( x >> 10 ) ) + +namespace tao +{ + namespace json + { + namespace internal + { + // RFC 6234, 5.1 + static std::uint32_t K[ 64 ] = { + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, + 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, + 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, + 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, + 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, + 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, + 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, + 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, + 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 + }; + + class sha256 + { + private: + unsigned char M[ 64 ]; + std::size_t size; + + std::uint32_t H[ 8 ]; + + // RFC 6234, 6.2 + void process() noexcept + { + std::uint32_t W[ 64 ]; + + // step 1 + for ( std::size_t t = 0, i = 0; t != 16; ++t, i += 4 ) { + W[ t ] = ( M[ i ] << 24 ) | ( M[ i + 1 ] << 16 ) | ( M[ i + 2 ] << 8 ) | ( M[ i + 3 ] ); + } + for ( std::size_t t = 16; t != 64; ++t ) { + W[ t ] = SSIG1( W[ t - 2 ] ) + W[ t - 7 ] + SSIG0( W[ t - 15 ] ) + W[ t - 16 ]; + } + + // step 2 + std::uint32_t a, b, c, d, e, f, g, h; + a = H[ 0 ]; + b = H[ 1 ]; + c = H[ 2 ]; + d = H[ 3 ]; + e = H[ 4 ]; + f = H[ 5 ]; + g = H[ 6 ]; + h = H[ 7 ]; + + // step 3 + for ( std::size_t t = 0; t != 64; ++t ) { + const std::uint32_t T1 = h + BSIG1( e ) + CH( e, f, g ) + K[ t ] + W[ t ]; + const std::uint32_t T2 = BSIG0( a ) + MAJ( a, b, c ); + h = g; + g = f; + f = e; + e = d + T1; + d = c; + c = b; + b = a; + a = T1 + T2; + } + + // step 4 + H[ 0 ] += a; + H[ 1 ] += b; + H[ 2 ] += c; + H[ 3 ] += d; + H[ 4 ] += e; + H[ 5 ] += f; + H[ 6 ] += g; + H[ 7 ] += h; + } + + public: + sha256() noexcept + { + reset(); + } + + sha256( const sha256 & ) = delete; + void operator= ( const sha256 & ) = delete; + + void reset() noexcept + { + size = 0; + + // RFC 6234, 6.1 + H[ 0 ] = 0x6a09e667; + H[ 1 ] = 0xbb67ae85; + H[ 2 ] = 0x3c6ef372; + H[ 3 ] = 0xa54ff53a; + H[ 4 ] = 0x510e527f; + H[ 5 ] = 0x9b05688c; + H[ 6 ] = 0x1f83d9ab; + H[ 7 ] = 0x5be0cd19; + } + + void feed( const unsigned char c ) noexcept + { + M[ size++ % 64 ] = c; + if ( ( size % 64 ) == 0 ) { + process(); + } + } + + void feed( const void * p, std::size_t s ) noexcept + { + const unsigned char * q = static_cast< const unsigned char * >( p ); + while ( s-- ) { + feed( *q++ ); + } + } + + void feed( const std::string & v ) noexcept + { + feed( v.data(), v.size() ); + } + + // RFC 6234, 4.1 + void store_unsafe( unsigned char * buffer ) noexcept + { + std::size_t i = size % 64; + if ( i < 56 ) { + M[ i++ ] = 0x80; + while ( i < 56 ) { + M[ i++ ] = 0x00; + } + } + else { + M[ i++ ] = 0x80; + while ( i < 64 ) { + M[ i++ ] = 0x00; + } + process(); + std::memset( M, 0, 56 ); + } + + size *= 8; + + M[ 63 ] = size; + M[ 62 ] = size >> 8; + M[ 61 ] = size >> 16; + M[ 60 ] = size >> 24; + M[ 59 ] = size >> 32; + M[ 58 ] = size >> 40; + M[ 57 ] = size >> 48; + M[ 56 ] = size >> 56; + + process(); + + for ( std::size_t i = 0; i < 4; ++i ) { + buffer[ i ] = ( H[ 0 ] >> ( 24 - i * 8 ) ) & 0xff; + buffer[ i + 4 ] = ( H[ 1 ] >> ( 24 - i * 8 ) ) & 0xff; + buffer[ i + 8 ] = ( H[ 2 ] >> ( 24 - i * 8 ) ) & 0xff; + buffer[ i + 12 ] = ( H[ 3 ] >> ( 24 - i * 8 ) ) & 0xff; + buffer[ i + 16 ] = ( H[ 4 ] >> ( 24 - i * 8 ) ) & 0xff; + buffer[ i + 20 ] = ( H[ 5 ] >> ( 24 - i * 8 ) ) & 0xff; + buffer[ i + 24 ] = ( H[ 6 ] >> ( 24 - i * 8 ) ) & 0xff; + buffer[ i + 28 ] = ( H[ 7 ] >> ( 24 - i * 8 ) ) & 0xff; + } + } + + std::string get() + { + std::string result; + result.resize( 32 ); + store_unsafe( (unsigned char *)( result.data() ) ); + return result; + } + }; + + } // internal + + } // json + +} // tao + +#endif diff --git a/share/include/tao/json/internal/string_state.hh b/share/include/tao/json/internal/string_state.hh new file mode 100644 index 0000000..4f9a2d9 --- /dev/null +++ b/share/include/tao/json/internal/string_state.hh @@ -0,0 +1,37 @@ +// Copyright (c) 2016 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/taocpp/json/ + +#ifndef TAOCPP_JSON_INCLUDE_INTERNAL_STRING_STATE_HH +#define TAOCPP_JSON_INCLUDE_INTERNAL_STRING_STATE_HH + +#include +#include + +namespace tao +{ + namespace json + { + namespace internal + { + struct string_state + { + string_state() = default; + string_state( const string_state & ) = delete; + void operator= ( const string_state & ) = delete; + + template< typename Consumer > + void success( Consumer & consumer ) + { + consumer.string( std::move( unescaped ) ); + } + + std::string unescaped; + }; + + } // internal + + } // json + +} // tao + +#endif diff --git a/share/include/tao/json/internal/throw.hh b/share/include/tao/json/internal/throw.hh new file mode 100644 index 0000000..c0d0b44 --- /dev/null +++ b/share/include/tao/json/internal/throw.hh @@ -0,0 +1,24 @@ +// Copyright (c) 2015-2016 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/taocpp/json/ + +#ifndef TAOCPP_JSON_INCLUDE_INTERNAL_THROW_HH +#define TAOCPP_JSON_INCLUDE_INTERNAL_THROW_HH + +#include +#include + +#include "../type.hh" + +#define TAOCPP_JSON_THROW_TYPE_ERROR( TyPe ) \ + do { \ + throw std::logic_error( std::string( "invalid json type '" ) + to_string( TyPe ) + '\'' ); \ + } while ( false ) + +#define TAOCPP_JSON_CHECK_TYPE_ERROR( HaVe, NeeD ) \ + do { \ + if ( ( HaVe ) != ( NeeD ) ) { \ + TAOCPP_JSON_THROW_TYPE_ERROR( HaVe ); \ + } \ + } while ( false ) + +#endif diff --git a/share/include/tao/json/internal/totally_ordered.hh b/share/include/tao/json/internal/totally_ordered.hh new file mode 100644 index 0000000..a241faf --- /dev/null +++ b/share/include/tao/json/internal/totally_ordered.hh @@ -0,0 +1,457 @@ +// Copyright (c) 2016 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/taocpp/json/ + +#ifndef TAOCPP_JSON_INCLUDE_INTERNAL_TOTALLY_ORDERED_HH +#define TAOCPP_JSON_INCLUDE_INTERNAL_TOTALLY_ORDERED_HH + +#include + +#include "../external/operators.hpp" + +#include "../type.hh" + +namespace tao +{ + namespace json + { + namespace internal + { + // helper class to generate optimized operators + + template< typename T, typename U, type E > + struct totally_ordered + : operators::totally_ordered< T, U > + { + friend bool operator==( const T & lhs, const U & rhs ) noexcept + { + if ( lhs.type() == type::RAW_PTR ) { + if ( const auto * p = lhs.unsafe_get_raw_ptr() ) { + return * p == rhs; + } + else { + return false; + } + } + return ( lhs.type() == E ) && ( lhs.T::template get< E >() == rhs ); + } + + friend bool operator<( const T & lhs, const U & rhs ) noexcept + { + if ( lhs.type() == type::RAW_PTR ) { + if ( const auto * p = lhs.unsafe_get_raw_ptr() ) { + return * p < rhs; + } + else { + return true; + } + } + return ( lhs.type() < E ) || ( ( lhs.type() == E ) && ( lhs.T::template get< E >() < rhs ) ); + } + + friend bool operator>( const T & lhs, const U & rhs ) noexcept + { + if ( lhs.type() == type::RAW_PTR ) { + if ( const auto * p = lhs.unsafe_get_raw_ptr() ) { + return * p > rhs; + } + else { + return false; + } + } + return ( lhs.type() > E ) || ( ( lhs.type() == E ) && ( lhs.T::template get< E >() > rhs ) ); + } + }; + + template< typename T > + struct totally_ordered< T, null_t, type::NULL_ > + : operators::totally_ordered< T, null_t > + { + friend bool operator==( const T & lhs, null_t ) noexcept + { + if ( lhs.type() == type::RAW_PTR ) { + if ( const auto * p = lhs.unsafe_get_raw_ptr() ) { + return * p == null; + } + else { + return true; + } + } + return lhs.type() == type::NULL_; + } + + friend bool operator<( const T &, null_t ) noexcept + { + return false; + } + + friend bool operator>( const T & lhs, null_t ) noexcept + { + if ( lhs.type() == type::RAW_PTR ) { + if ( const auto * p = lhs.unsafe_get_raw_ptr() ) { + return * p > null; + } + else { + return false; + } + } + return lhs.type() > type::NULL_; + } + }; + + template< typename T, typename U > + struct totally_ordered< T, U, type::SIGNED > + : operators::totally_ordered< T, U > + { + friend bool operator==( const T & lhs, const U & rhs ) noexcept + { + if ( lhs.type() == type::RAW_PTR ) { + if ( const auto * p = lhs.unsafe_get_raw_ptr() ) { + return * p == rhs; + } + else { + return false; + } + } + if ( lhs.type() == type::SIGNED ) { + return lhs.unsafe_get_signed() == rhs; + } + if ( lhs.type() == type::UNSIGNED ) { + return ( rhs >= 0 ) && ( lhs.unsafe_get_unsigned() == static_cast< std::uint64_t >( rhs ) ); + } + if ( lhs.type() == type::DOUBLE ) { + return lhs.unsafe_get_double() == rhs; + } + return false; + } + + friend bool operator<( const T & lhs, const U & rhs ) noexcept + { + if ( lhs.type() == type::RAW_PTR ) { + if ( const auto * p = lhs.unsafe_get_raw_ptr() ) { + return * p < rhs; + } + else { + return true; + } + } + if ( lhs.type() == type::SIGNED ) { + return lhs.unsafe_get_signed() < rhs; + } + if ( lhs.type() == type::UNSIGNED ) { + return ( rhs >= 0 ) && ( lhs.unsafe_get_unsigned() < static_cast< std::uint64_t >( rhs ) ); + } + if ( lhs.type() == type::DOUBLE ) { + return lhs.unsafe_get_double() < rhs; + } + return lhs.type() < type::SIGNED; + } + + friend bool operator>( const T & lhs, const U & rhs ) noexcept + { + if ( lhs.type() == type::RAW_PTR ) { + if ( const auto * p = lhs.unsafe_get_raw_ptr() ) { + return * p > rhs; + } + else { + return false; + } + } + if ( lhs.type() == type::SIGNED ) { + return lhs.unsafe_get_signed() > rhs; + } + if ( lhs.type() == type::UNSIGNED ) { + return ( rhs < 0 ) || ( lhs.unsafe_get_unsigned() > static_cast< std::uint64_t >( rhs ) ); + } + if ( lhs.type() == type::DOUBLE ) { + return lhs.unsafe_get_double() > rhs; + } + return lhs.type() > type::SIGNED; + } + }; + + template< typename T, typename U > + struct totally_ordered< T, U, type::UNSIGNED > + : operators::totally_ordered< T, U > + { + friend bool operator==( const T & lhs, const U & rhs ) noexcept + { + if ( lhs.type() == type::RAW_PTR ) { + if ( const auto * p = lhs.unsafe_get_raw_ptr() ) { + return * p == rhs; + } + else { + return false; + } + } + if ( lhs.type() == type::SIGNED ) { + const auto v = lhs.unsafe_get_signed(); + return ( v >= 0 ) && ( static_cast< std::uint64_t >( v ) == rhs ); + } + if ( lhs.type() == type::UNSIGNED ) { + return lhs.unsafe_get_unsigned() == rhs; + } + if ( lhs.type() == type::DOUBLE ) { + return lhs.unsafe_get_double() == rhs; + } + return false; + } + + friend bool operator<( const T & lhs, const U & rhs ) noexcept + { + if ( lhs.type() == type::RAW_PTR ) { + if ( const auto * p = lhs.unsafe_get_raw_ptr() ) { + return * p < rhs; + } + else { + return true; + } + } + if ( lhs.type() == type::SIGNED ) { + const auto v = lhs.unsafe_get_signed(); + return ( v < 0 ) || ( static_cast< std::uint64_t >( v ) < rhs ); + } + if ( lhs.type() == type::UNSIGNED ) { + return lhs.unsafe_get_unsigned() < rhs; + } + if ( lhs.type() == type::DOUBLE ) { + return lhs.unsafe_get_double() < rhs; + } + return lhs.type() < type::SIGNED; + } + + friend bool operator>( const T & lhs, const U & rhs ) noexcept + { + if ( lhs.type() == type::RAW_PTR ) { + if ( const auto * p = lhs.unsafe_get_raw_ptr() ) { + return * p > rhs; + } + else { + return false; + } + } + if ( lhs.type() == type::SIGNED ) { + const auto v = lhs.unsafe_get_signed(); + return ( v >= 0 ) && ( static_cast< std::uint64_t >( v ) > rhs ); + } + if ( lhs.type() == type::UNSIGNED ) { + return lhs.unsafe_get_unsigned() > rhs; + } + if ( lhs.type() == type::DOUBLE ) { + return lhs.unsafe_get_double() > rhs; + } + return lhs.type() > type::SIGNED; + } + }; + + template< typename T, typename U > + struct totally_ordered< T, U, type::DOUBLE > + : operators::totally_ordered< T, U > + { + friend bool operator==( const T & lhs, const U & rhs ) noexcept + { + if ( lhs.type() == type::RAW_PTR ) { + if ( const auto * p = lhs.unsafe_get_raw_ptr() ) { + return * p == rhs; + } + else { + return false; + } + } + if ( lhs.type() == type::SIGNED ) { + return lhs.unsafe_get_signed() == rhs; + } + if ( lhs.type() == type::UNSIGNED ) { + return lhs.unsafe_get_unsigned() == rhs; + } + if ( lhs.type() == type::DOUBLE ) { + return lhs.unsafe_get_double() == rhs; + } + return false; + } + + friend bool operator<( const T & lhs, const U & rhs ) noexcept + { + if ( lhs.type() == type::RAW_PTR ) { + if ( const auto * p = lhs.unsafe_get_raw_ptr() ) { + return * p < rhs; + } + else { + return true; + } + } + if ( lhs.type() == type::SIGNED ) { + return lhs.unsafe_get_signed() < rhs; + } + if ( lhs.type() == type::UNSIGNED ) { + return lhs.unsafe_get_unsigned() < rhs; + } + if ( lhs.type() == type::DOUBLE ) { + return lhs.unsafe_get_double() < rhs; + } + return lhs.type() < type::DOUBLE; + } + + friend bool operator>( const T & lhs, const U & rhs ) noexcept + { + if ( lhs.type() == type::RAW_PTR ) { + if ( const auto * p = lhs.unsafe_get_raw_ptr() ) { + return * p > rhs; + } + else { + return false; + } + } + if ( lhs.type() == type::SIGNED ) { + return lhs.unsafe_get_signed() > rhs; + } + if ( lhs.type() == type::UNSIGNED ) { + return lhs.unsafe_get_unsigned() > rhs; + } + if ( lhs.type() == type::DOUBLE ) { + return lhs.unsafe_get_double() > rhs; + } + return lhs.type() > type::DOUBLE; + } + }; + + template< typename T > + struct totally_ordered< T, empty_array_t, type::ARRAY > + : operators::totally_ordered< T, empty_array_t > + { + friend bool operator==( const T & lhs, empty_array_t rhs ) noexcept + { + return lhs == T( rhs ); + } + + friend bool operator<( const T & lhs, empty_array_t rhs ) noexcept + { + return lhs < T( rhs ); + } + + friend bool operator>( const T & lhs, empty_array_t rhs ) noexcept + { + return lhs > T( rhs ); + } + }; + + template< typename T > + struct totally_ordered< T, empty_object_t, type::OBJECT > + : operators::totally_ordered< T, empty_object_t > + { + friend bool operator==( const T & lhs, empty_object_t rhs ) noexcept + { + return lhs == T( rhs ); + } + + friend bool operator<( const T & lhs, empty_object_t rhs ) noexcept + { + return lhs < T( rhs ); + } + + friend bool operator>( const T & lhs, empty_object_t rhs ) noexcept + { + return lhs > T( rhs ); + } + }; + + template< typename T > + struct totally_ordered< T, const T *, type::RAW_PTR > + : operators::totally_ordered< T, const T * > + { + friend bool operator==( const T & lhs, const T * rhs ) noexcept + { + if ( rhs == nullptr ) { + return lhs == null; + } + return lhs == * rhs; + } + + friend bool operator<( const T & lhs, const T * rhs ) noexcept + { + if ( rhs == nullptr ) { + return lhs < null; + } + return lhs < * rhs; + } + + friend bool operator>( const T & lhs, const T * rhs ) noexcept + { + if ( rhs == nullptr ) { + return lhs > null; + } + return lhs > * rhs; + } + }; + + template< typename T > + struct totally_ordered< T, T *, type::RAW_PTR > + : operators::totally_ordered< T, T * > + { + friend bool operator==( const T & lhs, T * rhs ) noexcept + { + if ( rhs == nullptr ) { + return lhs == null; + } + return lhs == * rhs; + } + + friend bool operator<( const T & lhs, T * rhs ) noexcept + { + if ( rhs == nullptr ) { + return lhs < null; + } + return lhs < * rhs; + } + + friend bool operator>( const T & lhs, T * rhs ) noexcept + { + if ( rhs == nullptr ) { + return lhs > null; + } + return lhs > * rhs; + } + }; + + template< typename T > + struct totally_ordered< T, std::nullptr_t, type::RAW_PTR > + : operators::totally_ordered< T, std::nullptr_t > + { + friend bool operator==( const T & lhs, std::nullptr_t ) noexcept + { + if ( lhs.type() == type::RAW_PTR ) { + if ( const auto * p = lhs.unsafe_get_raw_ptr() ) { + return * p == null; + } + else { + return true; + } + } + return lhs.is_null(); + } + + friend bool operator<( const T &, std::nullptr_t ) noexcept + { + return false; + } + + friend bool operator>( const T & lhs, std::nullptr_t ) noexcept + { + if ( lhs.type() == type::RAW_PTR ) { + if ( const auto * p = lhs.unsafe_get_raw_ptr() ) { + return * p > null; + } + else { + return false; + } + } + return ! lhs.is_null(); + } + }; + + } // internal + + } // json + +} // tao + +#endif diff --git a/share/include/tao/json/internal/unescape_action.hh b/share/include/tao/json/internal/unescape_action.hh new file mode 100644 index 0000000..3ee3bc9 --- /dev/null +++ b/share/include/tao/json/internal/unescape_action.hh @@ -0,0 +1,30 @@ +// Copyright (c) 2015 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/taocpp/json/ + +#ifndef TAOCPP_JSON_INCLUDE_INTERNAL_UNESCAPE_ACTION_HH +#define TAOCPP_JSON_INCLUDE_INTERNAL_UNESCAPE_ACTION_HH + +#include "../external/pegtl/nothing.hh" +#include "../external/pegtl/contrib/unescape.hh" + +#include "grammar.hh" + +namespace tao +{ + namespace json + { + namespace internal + { + template< typename Rule > struct unescape_action : tao_json_pegtl::nothing< Rule > {}; + + template<> struct unescape_action< rules::unicode > : tao_json_pegtl::unescape::unescape_j {}; + template<> struct unescape_action< rules::escaped_char > : tao_json_pegtl::unescape::unescape_c< rules::escaped_char, '"', '\\', '/', '\b', '\f', '\n', '\r', '\t' > {}; + template<> struct unescape_action< rules::unescaped > : tao_json_pegtl::unescape::append_all {}; + + } // internal + + } // json + +} // tao + +#endif diff --git a/share/include/tao/json/internal/uri_fragment.hh b/share/include/tao/json/internal/uri_fragment.hh new file mode 100644 index 0000000..98a092a --- /dev/null +++ b/share/include/tao/json/internal/uri_fragment.hh @@ -0,0 +1,182 @@ +// Copyright (c) 2016 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/taocpp/json/ + +#ifndef TAOCPP_JSON_INCLUDE_URI_FRAGMENT_HH +#define TAOCPP_JSON_INCLUDE_URI_FRAGMENT_HH + +#include "../pointer.hh" + +#include + +namespace tao +{ + namespace json + { + namespace internal + { + const bool allowed_uri_fragment_characters[] = { + false, false, false, false, false, false, false, false, // 0 + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, // 16 + false, false, false, false, false, false, false, false, + false, true, false, false, true, false, true, true, // 32 + true, true, true, true, true, true, true, true, + true, true, true, true, true, true, true, true, // 48 + true, true, true, true, false, true, false, true, + true, true, true, true, true, true, true, true, // 64 + true, true, true, true, true, true, true, true, + true, true, true, true, true, true, true, true, // 80 + true, true, true, false, false, false, false, true, + false, true, true, true, true, true, true, true, // 96 + true, true, true, true, true, true, true, true, + true, true, true, true, true, true, true, true, // 112 + true, true, true, false, false, false, true, false, + false, false, false, false, false, false, false, false, // 128 + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false + }; + + inline char xdigit_value( const char c ) + { + switch ( c ) { + case '0': return 0; + case '1': return 1; + case '2': return 2; + case '3': return 3; + case '4': return 4; + case '5': return 5; + case '6': return 6; + case '7': return 7; + case '8': return 8; + case '9': return 9; + case 'a': case 'A': return 10; + case 'b': case 'B': return 11; + case 'c': case 'C': return 12; + case 'd': case 'D': return 13; + case 'e': case 'E': return 14; + case 'f': case 'F': return 15; + } + throw std::invalid_argument( "invalid URI Fragment escape sequence, '%' must be followed by two hexadecimal digits" ); + } + + inline pointer uri_fragment_to_pointer( const std::string & v ) + { + pointer result; + if ( v.empty() || v[ 0 ] != '#' ) { + throw std::invalid_argument( "invalid URI Fragment value, must begin with '#'" ); + } + if ( v.size() > 1 ) { + const char * p = v.data() + 1; + const char * const e = v.data() + v.size(); + if ( *p++ != '/' ) { + throw std::invalid_argument( "invalid JSON Pointer value, must be empty or begin with '/'" ); + } + std::string token; + while ( p != e ) { + const char c = *p++; + switch( c ) { + case '!': case '$': case '&': case '\'': case '(': case ')': case '*': case '+': case ',': case '-': case '.': + case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': + case ':': case ';': case '=': case '?': case '@': + case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': + case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': + case '_': + case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': + case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': + token += c; + continue; + + case '%': + if ( p != e ) { + const char h1 = xdigit_value( *p++ ); + if ( p != e ) { + const char h2 = xdigit_value( *p++ ); + token += h1 * 16 + h2; + continue; + } + } + throw std::invalid_argument( "invalid URI Fragment escape sequence, '%' must be followed by two hexadecimal digits" ); + + case '~': + if ( p != e ) { + switch ( *p++ ) { + case '0': + token += '~'; + continue; + case '1': + token += '/'; + continue; + } + } + throw std::invalid_argument( "invalid JSON Pointer escape sequence, '~' must be followed by '0' or '1'" ); + + case '/': + result += std::move( token ); + token.clear(); + continue; + + default: + throw std::invalid_argument( "invalid URI Fragment character" ); + } + } + result += std::move( token ); + } + return result; + } + + inline std::string tokens_to_uri_fragment( std::vector< token >::const_iterator it, const std::vector< token >::const_iterator & end ) + { + static const char * hex = "0123456789ABCDEF"; + + std::string result = "#"; + while ( it != end ) { + result += '/'; + for ( const unsigned char c : it->key() ) { + switch ( c ) { + case '~': + result += "~0"; + break; + case '/': + result += "~1"; + break; + default: + if ( allowed_uri_fragment_characters[ c ] ) { + result += c; + } + else { + result += '%'; + result += hex[ c >> 4 ]; + result += hex[ c & 15 ]; + } + } + } + ++it; + } + return result; + } + + inline std::string to_uri_fragment( const pointer & p ) + { + return tokens_to_uri_fragment( p.begin(), p.end() ); + } + + } // internal + + } // json + +} // tao + +#endif diff --git a/share/include/tao/json/internal/value_union.hh b/share/include/tao/json/internal/value_union.hh new file mode 100644 index 0000000..7704596 --- /dev/null +++ b/share/include/tao/json/internal/value_union.hh @@ -0,0 +1,48 @@ +// Copyright (c) 2015-2016 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/taocpp/json/ + +#ifndef TAOCPP_JSON_INCLUDE_INTERNAL_VALUE_UNION_HH +#define TAOCPP_JSON_INCLUDE_INTERNAL_VALUE_UNION_HH + +#include +#include +#include +#include + +namespace tao +{ + namespace json + { + namespace internal + { + template< typename Value > + union value_union + { + value_union() + { } + + value_union( const value_union & ) = delete; + void operator= ( const value_union & ) = delete; + + ~value_union() + { } + + bool b; + std::int64_t i; + std::uint64_t u; + double d; + + std::string s; + std::vector< Value > a; + std::map< std::string, Value > o; + + const Value * p; + }; + + } // internal + + } // json + +} // tao + +#endif diff --git a/share/include/tao/json/pair.hh b/share/include/tao/json/pair.hh new file mode 100644 index 0000000..f615b90 --- /dev/null +++ b/share/include/tao/json/pair.hh @@ -0,0 +1,42 @@ +// Copyright (c) 2016 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/taocpp/json/ + +#ifndef TAOCPP_JSON_INCLUDE_PAIR_HH +#define TAOCPP_JSON_INCLUDE_PAIR_HH + +#include +#include +#include + +namespace tao +{ + namespace json + { + template< template< typename ... > class > + class basic_value; + + template< template< typename ... > class Traits > + struct pair + { + mutable std::string key; + mutable basic_value< Traits > value; + + template< typename U > + pair( U && v ) + : key( Traits< typename std::decay< U >::type >::default_key ), + value( std::forward< U >( v ) ) + { } + + pair( std::string && k, basic_value< Traits > && v ) : key( std::move( k ) ), value( std::move( v ) ) {} + pair( std::string && k, const basic_value< Traits > & v ) : key( std::move( k ) ), value( v ) {} + pair( const std::string & k, basic_value< Traits > && v ) : key( k ), value( std::move( v ) ) {} + pair( const std::string & k, const basic_value< Traits > & v ) : key( k ), value( v ) {} + pair( const char * k, basic_value< Traits > && v ) : key( k ), value( std::move( v ) ) {} + pair( const char * k, const basic_value< Traits > & v ) : key( k ), value( v ) {} + }; + + } // json + +} // tao + +#endif diff --git a/share/include/tao/json/parse_file.hh b/share/include/tao/json/parse_file.hh new file mode 100644 index 0000000..4a8c534 --- /dev/null +++ b/share/include/tao/json/parse_file.hh @@ -0,0 +1,40 @@ +// Copyright (c) 2015-2016 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/taocpp/json/ + +#ifndef TAOCPP_JSON_INCLUDE_PARSE_FILE_HH +#define TAOCPP_JSON_INCLUDE_PARSE_FILE_HH + +#include +#include + +#include "sax/parse_file.hh" +#include "sax/to_value.hh" + +namespace tao +{ + namespace json + { + template< template< typename ... > class Traits > + basic_value< Traits > parse_file( const std::string & filename ) + { + sax::to_basic_value< Traits > consumer; + sax::parse_file( filename, consumer ); + return std::move( consumer.value ); + } + + template< template< typename ... > class Traits > + void parse_file( basic_value< Traits > & output, const std::string & filename ) + { + output = parse_file< Traits >( filename ); + } + + inline value parse_file( const std::string & filename ) + { + return parse_file< traits >( filename ); + } + + } // json + +} // tao + +#endif diff --git a/share/include/tao/json/patch.hh b/share/include/tao/json/patch.hh new file mode 100644 index 0000000..1af48b7 --- /dev/null +++ b/share/include/tao/json/patch.hh @@ -0,0 +1,109 @@ +// Copyright (c) 2016 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/taocpp/json/ + +#ifndef TAOCPP_JSON_INCLUDE_PATCH_HH +#define TAOCPP_JSON_INCLUDE_PATCH_HH + +#include +#include + +#include "value.hh" +#include "pointer.hh" + +namespace tao +{ + namespace json + { + template< template< typename ... > class Traits > + void patch_inplace( basic_value< Traits > & value, const basic_value< Traits > & patch ) + { + for( const auto & entry : patch.get_array() ) { + const auto & op = entry.at( "op" ).get_string(); + const auto & path = entry.at( "path" ).get_string(); + const pointer path_pointer( path ); + if ( op == "test" ) { + if ( value.at( path_pointer ) != entry.at( "value" ) ) { + throw std::runtime_error( "test failed for: " + path ); + } + } + else if ( op == "remove" ) { + value.erase( path_pointer ); + } + else if ( op == "add" ) { + value.insert( path_pointer, entry.at( "value" ) ); + } + else if ( op == "replace" ) { + value.at( path_pointer ) = entry.at( "value" ); + } + else if ( op == "move" ) { + const pointer from( entry.at( "from" ).get_string() ); + auto v = std::move( value.at( from ) ); + value.erase( from ); + value.insert( path_pointer, std::move( v ) ); + } + else if ( op == "copy" ) { + const pointer from( entry.at( "from" ).get_string() ); + value.insert( path_pointer, value.at( from ) ); + } + else { + throw std::runtime_error( "unknown patch operation: '" + op + '\'' ); + } + } + } + + template< template< typename ... > class Traits > + void patch_inplace( basic_value< Traits > & value, basic_value< Traits > && patch ) + { + for( const auto & entry : patch.get_array() ) { + const auto & op = entry.at( "op" ).get_string(); + const auto & path = entry.at( "path" ).get_string(); + const pointer path_pointer( path ); + if ( op == "test" ) { + if ( value.at( path_pointer ) != entry.at( "value" ) ) { + throw std::runtime_error( "test failed for: " + path ); + } + } + else if ( op == "remove" ) { + value.erase( path_pointer ); + } + else if ( op == "add" ) { + value.insert( path_pointer, std::move( entry.at( "value" ) ) ); + } + else if ( op == "replace" ) { + value.at( path_pointer ) = std::move( entry.at( "value" ) ); + } + else if ( op == "move" ) { + const pointer from( entry.at( "from" ).get_string() ); + auto v = std::move( value.at( from ) ); + value.erase( from ); + value.insert( path_pointer, std::move( v ) ); + } + else if ( op == "copy" ) { + const pointer from( entry.at( "from" ).get_string() ); + value.insert( path_pointer, value.at( from ) ); + } + else { + throw std::runtime_error( "unknown patch operation: '" + op + '\'' ); + } + } + } + + template< template< typename ... > class Traits > + basic_value< Traits > patch( basic_value< Traits > value, const basic_value< Traits > & patch ) + { + patch_inplace( value, patch ); + return std::move( value ); + } + + template< template< typename ... > class Traits > + basic_value< Traits > patch( basic_value< Traits > value, basic_value< Traits > && patch ) + { + patch_inplace( value, std::move( patch ) ); + return std::move( value ); + } + + } // json + +} // tao + +#endif diff --git a/share/include/tao/json/pointer.hh b/share/include/tao/json/pointer.hh new file mode 100644 index 0000000..7a95280 --- /dev/null +++ b/share/include/tao/json/pointer.hh @@ -0,0 +1,300 @@ +// Copyright (c) 2016 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/taocpp/json/ + +#ifndef TAOCPP_JSON_INCLUDE_POINTER_HH +#define TAOCPP_JSON_INCLUDE_POINTER_HH + +#include +#include +#include +#include +#include + +#include "external/operators.hpp" + +namespace tao +{ + namespace json + { + namespace internal + { + std::size_t token_to_index( const std::string & key ); + + } // internal + + // RFC 6901 + class token + { + private: + std::size_t m_index; + std::string m_key; + + public: + explicit token( const std::string & key ) + : m_index( internal::token_to_index( key ) ), + m_key( key ) + { } + + explicit token( std::string && key ) + : m_index( internal::token_to_index( key ) ), + m_key( std::move( key ) ) + { } + + token( const token & ) = default; + token( token && v ) noexcept + : m_index( v.m_index ), + m_key( std::move( v.m_key ) ) + { } + + token & operator= ( const token & ) = default; + token & operator= ( token && v ) noexcept + { + m_index = v.m_index; + m_key = std::move( v.m_key ); + return * this; + } + + const std::string & key() const + { + return m_key; + } + + std::size_t index() const + { + if ( m_index == std::string::npos ) { + throw std::invalid_argument( "unable to resolve JSON Pointer, invalid token for array access '" + m_key + '\'' ); + } + return m_index; + } + + friend bool operator==( const token & lhs, const token & rhs ) + { + return lhs.m_key == rhs.m_key; + } + + friend bool operator<( const token & lhs, const token & rhs ) + { + return lhs.m_key < rhs.m_key; + } + }; + + class pointer + : operators::totally_ordered< pointer > + { + private: + std::vector< token > m_tokens; + + static std::vector< token > parse( const std::string & v ) + { + std::vector< token > result; + if ( ! v.empty() ) { + const char * p = v.data(); + const char * const e = p + v.size(); + if ( *p++ != '/' ) { + throw std::invalid_argument( "invalid JSON Pointer value, must be empty or begin with '/'" ); + } + std::string token; + while ( p != e ) { + const char c = *p++; + switch( c ) { + case '~': + if ( p != e ) { + switch ( *p++ ) { + case '0': + token += '~'; + continue; + case '1': + token += '/'; + continue; + } + } + throw std::invalid_argument( "invalid JSON Pointer escape sequence, '~' must be followed by '0' or '1'" ); + + case '/': + result.emplace_back( std::move( token ) ); + token.clear(); + continue; + + default: + token += c; + } + } + result.emplace_back( std::move( token ) ); + } + return result; + } + + public: + pointer() = default; + + pointer( const pointer & ) = default; + + pointer( pointer && p ) noexcept + : m_tokens( std::move( p.m_tokens ) ) + { } + + explicit pointer( const std::string & v ) + : m_tokens( parse( v ) ) + { } + + pointer & operator= ( const pointer & ) = default; + + pointer & operator= ( pointer && p ) noexcept + { + m_tokens = std::move( p.m_tokens ); + return *this; + } + + pointer & operator= ( const std::string & v ) + { + m_tokens = parse( v ); + return *this; + } + + explicit operator bool() const noexcept + { + return ! m_tokens.empty(); + } + + std::vector< token >::const_iterator begin() const noexcept + { + return m_tokens.begin(); + } + + std::vector< token >::const_iterator end() const noexcept + { + return m_tokens.end(); + } + + void push_back( const std::string & v ) + { + m_tokens.push_back( token( v ) ); + } + + void push_back( std::string && v ) + { + m_tokens.push_back( token( std::move( v ) ) ); + } + + pointer & operator+= ( const std::string & v ) + { + push_back( v ); + return * this; + } + + pointer & operator+= ( std::string && v ) + { + push_back( std::move( v ) ); + return * this; + } + + friend bool operator== ( const pointer & lhs, const pointer & rhs ) noexcept + { + return lhs.m_tokens == rhs.m_tokens; + } + + friend bool operator< ( const pointer & lhs, const pointer & rhs ) noexcept + { + return lhs.m_tokens < rhs.m_tokens; + } + }; + + inline pointer operator+ ( const pointer & p, const std::string & v ) + { + pointer nrv( p ); + nrv += v; + return nrv; + } + + inline pointer operator+ ( const pointer & p, std::string && v ) + { + pointer nrv( p ); + nrv += std::move( v ); + return nrv; + } + + namespace internal + { + inline std::size_t token_to_index( const std::string & key ) + { + if ( ! key.empty() && key.size() <= 20 ) { + if ( key == "0" ) { + return 0; + } + else if ( ( key[ 0 ] != '0' ) && ( key.find_first_not_of( "0123456789" ) == std::string::npos ) ) { + if ( key.size() < 20 || key < "18446744073709551616" ) { + return std::stoull( key ); + } + } + } + return std::string::npos; + } + + inline std::string tokens_to_string( std::vector< token >::const_iterator it, const std::vector< token >::const_iterator & end ) + { + std::string result; + while ( it != end ) { + result += '/'; + for ( const char c : it->key() ) { + switch ( c ) { + case '~': + result += "~0"; + break; + case '/': + result += "~1"; + break; + default: + result += c; + } + } + ++it; + } + return result; + } + + inline std::string to_string( const pointer & p ) + { + return tokens_to_string( p.begin(), p.end() ); + } + + inline std::runtime_error invalid_type( const std::vector< token >::const_iterator & begin, const std::vector< token >::const_iterator & end ) + { + return std::runtime_error( "unable to resolve JSON Pointer '" + tokens_to_string( begin, end ) + "' -- value type is neither 'object' nor 'array'" ); + } + + template< typename T > + T & pointer_at( T * v, const std::vector< token >::const_iterator & begin, const std::vector< token >::const_iterator & end ) + { + auto it = begin; + while ( it != end ) { + switch ( v->type() ) { + case type::ARRAY: + v = & v->at( it->index() ); + break; + case type::OBJECT: + v = & v->at( it->key() ); + break; + default: + throw invalid_type( begin, std::next( it ) ); + } + ++it; + } + return * v; + } + + } // internal + + inline namespace literals + { + inline pointer operator"" _json_pointer( const char * data, const std::size_t size ) + { + return pointer( { data, size } ); + } + + } // literals + + } // json + +} // tao + +#endif diff --git a/share/include/tao/json/reference.hh b/share/include/tao/json/reference.hh new file mode 100644 index 0000000..738ca61 --- /dev/null +++ b/share/include/tao/json/reference.hh @@ -0,0 +1,114 @@ +// Copyright (c) 2016 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/taocpp/json/ + +#ifndef TAOCPP_JSON_INCLUDE_REFERENCE_HH +#define TAOCPP_JSON_INCLUDE_REFERENCE_HH + +#include "value.hh" +#include "pointer.hh" +#include "internal/uri_fragment.hh" + +namespace tao +{ + namespace json + { + namespace internal + { + // JSON Reference, see draft ("work in progress") RFC at + // https://tools.ietf.org/html/draft-pbryan-zyp-json-ref-03 + + // NOTE: Currently, only URI fragments are supported. + // Remote references are ignored, i.e., left untouched. + + // JSON References are replaced with a RAW_PTR, + // which might lead to infinite loops if you try + // to traverse the value. Make sure you understand + // the consequences and handle the resulting value + // accordingly! + + // Self-references will throw an exception, as well as + // references into JSON Reference additional members + // (which shall be ignored as per the specification). + + template< template< typename ... > class Traits > + void resolve_references( basic_value< Traits > & r, basic_value< Traits > & v ) + { + switch ( v.type() ) { + case type::UNINITIALIZED: + return; + case type::DISCARDED: + throw std::logic_error( "attempt to use a discarded value" ); + case type::NULL_: + case type::BOOLEAN: + case type::SIGNED: + case type::UNSIGNED: + case type::DOUBLE: + case type::STRING: + return; + case type::ARRAY: + for ( auto & e : v.unsafe_get_array() ) { + resolve_references( r, e ); + } + return; + case type::OBJECT: + for ( auto & e : v.unsafe_get_object() ) { + resolve_references( r, e.second ); + } + if ( const auto * ref = v.find( "$ref" )->skip_raw_ptr() ) { + if ( ref->is_string() ) { + const std::string & s = ref->unsafe_get_string(); + if ( ! s.empty() && s[ 0 ] == '#' ) { + const pointer ptr = internal::uri_fragment_to_pointer( s ); + const auto * p = & r; + auto it = ptr.begin(); + while ( it != ptr.end() ) { + switch ( p->type() ) { + case type::ARRAY: + p = p->at( it->index() ).skip_raw_ptr(); + break; + case type::OBJECT: + if ( const auto * r = p->find( "$ref" ) ) { + if ( r->is_string() ) { + throw std::runtime_error( "invalid JSON Reference: referencing additional data members is invalid" ); + } + } + p = p->at( it->key() ).skip_raw_ptr(); + break; + default: + throw invalid_type( ptr.begin(), std::next( it ) ); + } + ++it; + } + if ( p == & v ) { + throw std::runtime_error( "JSON Reference: invalid self reference" ); + } + v = p; + resolve_references( r, v ); + return; + } + else { + // Ignore remote references for now... + // throw std::runtime_error( "JSON Reference: unsupported or invalid URI: " + s ); + } + } + } + return; + case type::RAW_PTR: + return; + } + throw std::logic_error( "invalid value for tao::json::type" ); // LCOV_EXCL_LINE + } + + } // internal + + template< template< typename ... > class Traits > + void resolve_references( basic_value< Traits > & r ) + { + resolve_references( r, r ); + } + + } // json + +} // tao + +#endif diff --git a/share/include/tao/json/sax/compare.hh b/share/include/tao/json/sax/compare.hh new file mode 100644 index 0000000..fe4951f --- /dev/null +++ b/share/include/tao/json/sax/compare.hh @@ -0,0 +1,262 @@ +// Copyright (c) 2016 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/taocpp/json/ + +#ifndef TAOCPP_JSON_INCLUDE_SAX_COMPARE_HH +#define TAOCPP_JSON_INCLUDE_SAX_COMPARE_HH + +#include "../value.hh" + +#include +#include +#include +#include +#include + +namespace tao +{ + namespace json + { + namespace internal + { + template< template< typename ... > class Traits > + class sax_compare + { + protected: + using value_t = basic_value< Traits >; + + std::vector< const value_t * > m_current; + std::vector< std::size_t > m_array_index; + // TODO: use std::unordered_set? or even std::vector!? + std::vector< std::set< const value_t * > > m_object_keys; + bool m_match = true; + + public: + sax_compare() = default; + + sax_compare( const sax_compare & ) = delete; + sax_compare( sax_compare && ) = delete; + + void operator= ( const sax_compare & ) = delete; + void operator= ( sax_compare && ) = delete; + + void reset() noexcept + { + m_current.clear(); + m_array_index.clear(); + m_object_keys.clear(); + m_match = true; + } + + static const value_t * skip_pointer( const value_t * p ) noexcept + { + while ( p && p->is_raw_ptr() ) { + p = p->unsafe_get_raw_ptr(); + } + return p; + } + + void push( const value_t * p ) + { + m_current.push_back( skip_pointer( p ) ); + } + + bool match() const noexcept + { + return m_match; + } + + const value_t & current() const noexcept + { + return * m_current.back(); + } + + void null() noexcept + { + if ( m_match ) { + m_match = ( m_current.back() != nullptr ) && ( current().is_null() ); + } + } + + void boolean( const bool v ) noexcept + { + if ( m_match ) { + m_match = ( m_current.back() != nullptr ) && ( current() == v ); + } + } + + void number( const std::int64_t v ) noexcept + { + if ( m_match ) { + m_match = ( m_current.back() != nullptr ) && ( current() == v ); + } + } + + void number( const std::uint64_t v ) noexcept + { + if ( m_match ) { + m_match = ( m_current.back() != nullptr ) && ( current() == v ); + } + } + + void number( const double v ) noexcept + { + if ( m_match ) { + m_match = ( m_current.back() != nullptr ) && ( current() == v ); + } + } + + void string( const std::string & v ) noexcept + { + if ( m_match ) { + m_match = ( m_current.back() != nullptr ) && ( current() == v ); + } + } + + // array + void begin_array() + { + if ( m_current.back() == nullptr ) { + m_match = false; + m_current.push_back( nullptr ); + } + else { + const auto & a = current(); + if ( ! a.is_array() ) { + m_match = false; + m_current.push_back( nullptr ); + } + else if ( ! a.unsafe_get_array().empty() ) { + push( & a.unsafe_get_array().front() ); + } + else { + m_current.push_back( nullptr ); + } + } + m_array_index.push_back( 0 ); + } + + void element() noexcept + { + const auto i = ++m_array_index.back(); + if ( m_match ) { + if ( m_current.back() != nullptr ) { + const auto & a = ( * ( m_current.end() - 2 ) )->unsafe_get_array(); + if ( i < a.size() ) { + m_current.back() = skip_pointer( & a[ i ] ); + } + else { + m_current.back() = nullptr; + } + } + } + } + + void end_array() noexcept + { + m_current.pop_back(); + if ( m_match ) { + if ( m_array_index.back() != current().unsafe_get_array().size() ) { + m_match = false; + } + } + m_array_index.pop_back(); + } + + // object + void begin_object() + { + if ( m_current.back() == nullptr ) { + m_match = false; + } + else { + const auto & o = current(); + if ( ! o.is_object() ) { + m_match = false; + } + } + m_object_keys.emplace_back(); + } + + void key( const std::string & v ) + { + if ( ! m_match ) { + m_current.push_back( nullptr ); + } + else if ( const auto * p = current().unsafe_find( v ) ) { + if ( ! m_object_keys.back().insert( p ).second ) { + m_match = false; // duplicate key found! -> fail + m_current.push_back( nullptr ); + } + else { + push( p ); + } + } + else { + m_match = false; + m_current.push_back( nullptr ); + } + } + + void member() noexcept + { + m_current.pop_back(); + } + + void end_object() noexcept + { + if ( m_match ) { + if ( m_object_keys.back().size() != current().unsafe_get_object().size() ) { + m_match = false; + } + } + m_object_keys.pop_back(); + } + }; + + } // internal + + namespace sax + { + // SAX consumer that compares against a DOM value + template< template< typename ... > class Traits > + class basic_compare : public internal::sax_compare< Traits > + { + private: + using typename internal::sax_compare< Traits >::value_t; + const value_t m_value; + + public: + explicit basic_compare( const value_t & v ) + : m_value( v ) + { + reset(); + } + + explicit basic_compare( value_t && v ) + : m_value( std::move( v ) ) + { + reset(); + } + + basic_compare( const basic_compare & ) = delete; + basic_compare( basic_compare && ) = delete; + + void operator= ( const basic_compare & ) = delete; + void operator= ( basic_compare && ) = delete; + + void reset() + { + internal::sax_compare< Traits >::reset(); + internal::sax_compare< Traits >::push( & m_value ); + } + }; + + using compare = basic_compare< traits >; + + } // sax + + } // json + +} // tao + +#endif diff --git a/share/include/tao/json/sax/debug.hh b/share/include/tao/json/sax/debug.hh new file mode 100644 index 0000000..6f6b4ab --- /dev/null +++ b/share/include/tao/json/sax/debug.hh @@ -0,0 +1,116 @@ +// Copyright (c) 2016 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/taocpp/json/ + +#ifndef TAOCPP_JSON_INCLUDE_SAX_DEBUG_HH +#define TAOCPP_JSON_INCLUDE_SAX_DEBUG_HH + +#include +#include + +#include "../external/double.hh" + +#include "../internal/escape.hh" + +namespace tao +{ + namespace json + { + namespace sax + { + // SAX consumer that writes the events to a stream for debug purposed + class debug + { + private: + std::ostream & os; + + public: + explicit debug( std::ostream & os ) noexcept + : os( os ) + { } + + void null() + { + os << "null\n"; + } + + void boolean( const bool v ) + { + if ( v ) { + os << "boolean: true\n"; + } + else { + os << "boolean: false\n"; + } + } + + void number( const std::int64_t v ) + { + os << "std::int64_t: " << v << '\n'; + } + + void number( const std::uint64_t v ) + { + os << "std::uint64_t: " << v << '\n'; + } + + void number( const double v ) + { + os << "double: "; + json_double_conversion::Dtostr( os, v ); + os << '\n'; + } + + void string( const std::string & v ) + { + os << "string: \""; + internal::escape( os, v ); + os << "\"\n"; + } + + // array + void begin_array() + { + os << "begin array\n"; + } + + void element() + { + os << "element\n"; + } + + void end_array() + { + os << "end array\n"; + } + + // object + void begin_object() + { + os << "begin object\n"; + } + + void key( const std::string & v ) + { + os << "key: \""; + internal::escape( os, v ); + os << "\"\n"; + } + + void member() + { + os << "member\n"; + } + + void end_object() + { + os << "end object\n"; + } + }; + + } // sax + + } // json + +} // tao + +#endif diff --git a/share/include/tao/json/sax/discard.hh b/share/include/tao/json/sax/discard.hh new file mode 100644 index 0000000..550fd8a --- /dev/null +++ b/share/include/tao/json/sax/discard.hh @@ -0,0 +1,47 @@ +// Copyright (c) 2016 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/taocpp/json/ + +#ifndef TAOCPP_JSON_INCLUDE_SAX_DISCARD_HH +#define TAOCPP_JSON_INCLUDE_SAX_DISCARD_HH + +#include +#include + +namespace tao +{ + namespace json + { + namespace sax + { + // SAX consumer that discards events + struct discard + { + void null() {} + + void boolean( const bool ) {} + + void number( const std::int64_t ) {} + void number( const std::uint64_t ) {} + void number( const double ) {} + + void string( const std::string & ) {} + + // array + void begin_array() {} + void element() {} + void end_array() {} + + // object + void begin_object() {} + void key( const std::string & ) {} + void member() {} + void end_object() {} + }; + + } // sax + + } // json + +} // tao + +#endif diff --git a/share/include/tao/json/sax/from_stream.hh b/share/include/tao/json/sax/from_stream.hh new file mode 100644 index 0000000..c9b978e --- /dev/null +++ b/share/include/tao/json/sax/from_stream.hh @@ -0,0 +1,41 @@ +// Copyright (c) 2016 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/taocpp/json/ + +#ifndef TAOCPP_JSON_INCLUDE_SAX_FROM_STREAM_HH +#define TAOCPP_JSON_INCLUDE_SAX_FROM_STREAM_HH + +#include + +#include "../external/pegtl/parse.hh" +#include "../external/pegtl/internal/istream_reader.hh" + +#include "../internal/grammar.hh" +#include "../internal/action.hh" +#include "../internal/control.hh" + +namespace tao +{ + namespace json + { + namespace sax + { + template< typename Consumer > + inline void from_stream( std::istream & stream, Consumer & consumer, const char * source = nullptr, const std::size_t maximum_buffer_size = 4000 ) + { + tao_json_pegtl::buffer_input< tao_json_pegtl::internal::istream_reader > input( source ? source : "tao::json::sax::from_stream", maximum_buffer_size, stream ); + tao_json_pegtl::parse_input< internal::grammar, internal::action, internal::control >( input, consumer ); + } + + template< typename Consumer > + inline void from_stream( std::istream & stream, Consumer & consumer, const std::string & source, const std::size_t maximum_buffer_size = 4000 ) + { + sax::from_stream( stream, consumer, source.c_str(), maximum_buffer_size ); + } + + } // sax + + } // json + +} // tao + +#endif diff --git a/share/include/tao/json/sax/from_string.hh b/share/include/tao/json/sax/from_string.hh new file mode 100644 index 0000000..34662ef --- /dev/null +++ b/share/include/tao/json/sax/from_string.hh @@ -0,0 +1,51 @@ +// Copyright (c) 2016 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/taocpp/json/ + +#ifndef TAOCPP_JSON_INCLUDE_SAX_FROM_STRING_HH +#define TAOCPP_JSON_INCLUDE_SAX_FROM_STRING_HH + +#include "../external/pegtl/parse.hh" + +#include "../internal/grammar.hh" +#include "../internal/action.hh" +#include "../internal/control.hh" + +namespace tao +{ + namespace json + { + namespace sax + { + // SAX producer to parse a JSON string representation + template< typename Consumer > + inline void from_string( const char * data, const std::size_t size, Consumer & consumer, const char * source = nullptr, const std::size_t byte = 0, const std::size_t line = 1, const std::size_t column = 0 ) + { + tao_json_pegtl::memory_input input( byte, line, column, data, data + size, source ? source : "tao::json::sax::from_string" ); + tao_json_pegtl::parse_input< internal::grammar, internal::action, internal::control >( input, consumer ); + } + + template< typename Consumer > + inline void from_string( const char * data, const std::size_t size, Consumer & consumer, const std::string & source, const std::size_t byte = 0, const std::size_t line = 1, const std::size_t column = 0 ) + { + sax::from_string( data, size, consumer, source.c_str(), byte, line, column ); + } + + template< typename Consumer > + inline void from_string( const std::string & data, Consumer & consumer, const char * source = nullptr, const std::size_t byte = 0, const std::size_t line = 1, const std::size_t column = 0 ) + { + sax::from_string( data.data(), data.size(), consumer, source, byte, line, column ); + } + + template< typename Consumer > + inline void from_string( const std::string & data, Consumer & consumer, const std::string & source, const std::size_t byte = 0, const std::size_t line = 1, const std::size_t column = 0 ) + { + sax::from_string( data, consumer, source.c_str(), byte, line, column ); + } + + } // sax + + } // json + +} // tao + +#endif diff --git a/share/include/tao/json/sax/from_value.hh b/share/include/tao/json/sax/from_value.hh new file mode 100644 index 0000000..c3b904c --- /dev/null +++ b/share/include/tao/json/sax/from_value.hh @@ -0,0 +1,136 @@ +// Copyright (c) 2016 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/taocpp/json/ + +#ifndef TAOCPP_JSON_INCLUDE_SAX_FROM_VALUE_HH +#define TAOCPP_JSON_INCLUDE_SAX_FROM_VALUE_HH + +#include + +#include "../value.hh" + +namespace tao +{ + namespace json + { + namespace sax + { + // SAX producer to generate events from a JSON value + template< template< typename ... > class Traits, typename Consumer > + void from_value( const basic_value< Traits > & v, Consumer & consumer ) + { + switch( v.type() ) { + case type::UNINITIALIZED: + throw std::logic_error( "unable to produce events from uninitialized values" ); + case type::DISCARDED: + throw std::logic_error( "unable to produce events from discarded values" ); + case type::NULL_: + consumer.null(); + return; + case type::BOOLEAN: + consumer.boolean( v.unsafe_get_boolean() ); + return; + case type::SIGNED: + consumer.number( v.unsafe_get_signed() ); + return; + case type::UNSIGNED: + consumer.number( v.unsafe_get_unsigned() ); + return; + case type::DOUBLE: + consumer.number( v.unsafe_get_double() ); + return; + case type::STRING: + consumer.string( v.unsafe_get_string() ); + return; + case type::ARRAY: + consumer.begin_array(); + for( const auto & e : v.unsafe_get_array() ) { + sax::from_value( e, consumer ); + consumer.element(); + } + consumer.end_array(); + return; + case type::OBJECT: + consumer.begin_object(); + for( const auto & e : v.unsafe_get_object() ) { + consumer.key( e.first ); + sax::from_value( e.second, consumer ); + consumer.member(); + } + consumer.end_object(); + return; + case type::RAW_PTR: + if ( const basic_value< Traits > * p = v.unsafe_get_raw_ptr() ) { + sax::from_value( * p, consumer ); + } + else { + consumer.null(); + } + return; + } + throw std::logic_error( "invalid value for tao::json::type" ); // LCOV_EXCL_LINE + } + + // SAX producer to generate events from an rvalue JSON value + // note: strings from the source might be moved in the consumer + template< template< typename ... > class Traits, typename Consumer > + void from_value( basic_value< Traits > && v, Consumer & consumer ) + { + switch( v.type() ) { + case type::UNINITIALIZED: + throw std::logic_error( "unable to produce events from uninitialized values" ); + case type::DISCARDED: + throw std::logic_error( "unable to produce events from discarded values" ); + case type::NULL_: + consumer.null(); + return; + case type::BOOLEAN: + consumer.boolean( v.unsafe_get_boolean() ); + return; + case type::SIGNED: + consumer.number( v.unsafe_get_signed() ); + return; + case type::UNSIGNED: + consumer.number( v.unsafe_get_unsigned() ); + return; + case type::DOUBLE: + consumer.number( v.unsafe_get_double() ); + return; + case type::STRING: + consumer.string( std::move( v.unsafe_get_string() ) ); + return; + case type::ARRAY: + consumer.begin_array(); + for( auto && e : v.unsafe_get_array() ) { + sax::from_value( std::move( e ), consumer ); + consumer.element(); + } + consumer.end_array(); + return; + case type::OBJECT: + consumer.begin_object(); + for( auto && e : v.unsafe_get_object() ) { + consumer.key( std::move( e.first ) ); + sax::from_value( std::move( e.second ), consumer ); + consumer.member(); + } + consumer.end_object(); + return; + case type::RAW_PTR: + if ( const basic_value< Traits > * p = v.unsafe_get_raw_ptr() ) { + sax::from_value( * p, consumer ); + } + else { + consumer.null(); + } + return; + } + throw std::logic_error( "invalid value for tao::json::type" ); // LCOV_EXCL_LINE + } + + } // sax + + } // json + +} // tao + +#endif diff --git a/share/include/tao/json/sax/hash.hh b/share/include/tao/json/sax/hash.hh new file mode 100644 index 0000000..3a53400 --- /dev/null +++ b/share/include/tao/json/sax/hash.hh @@ -0,0 +1,164 @@ +// Copyright (c) 2016 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/taocpp/json/ + +#ifndef TAOCPP_JSON_INCLUDE_SAX_HASH_HH +#define TAOCPP_JSON_INCLUDE_SAX_HASH_HH + +#include +#include +#include +#include +#include +#include + +#include "../internal/sha256.hh" + +namespace tao +{ + namespace json + { + namespace sax + { + // SAX consumer that calculates an SHA-256 hash + class hash + { + private: + std::vector< std::unique_ptr< internal::sha256 > > m_digests; + std::vector< std::string > m_keys; + std::vector< std::map< std::string, std::string > > m_properties; + + void push() + { + m_digests.emplace_back( new internal::sha256 ); + } + + public: + hash() + { + push(); + } + + hash( const hash & ) = delete; + hash( hash && ) = delete; + + void operator= ( const hash & ) = delete; + void operator= ( hash && ) = delete; + + std::string value() const + { + return m_digests.back()->get(); + } + + void reset() + { + m_digests.back()->reset(); + } + + void null() + { + m_digests.back()->feed( 'n' ); + } + + void boolean( const bool v ) + { + m_digests.back()->feed( v ? 't' : 'f' ); + } + + void number( const std::int64_t v ) + { + if ( v >= 0 ) { + number( static_cast< std::uint64_t >( v ) ); + } + else { + m_digests.back()->feed( 'i' ); + m_digests.back()->feed( & v, sizeof( v ) ); + } + } + + void number( const std::uint64_t v ) + { + m_digests.back()->feed( 'u' ); + m_digests.back()->feed( & v, sizeof( v ) ); + } + + void number( const double v ) + { + const std::uint64_t u = v; + if ( u == v ) { + number( u ); + return; + } + const std::int64_t i = v; + if ( i == v ) { + number( i ); + return; + } + m_digests.back()->feed( 'd' ); + m_digests.back()->feed( & v, sizeof( v ) ); + } + + void string( const std::string & v ) + { + m_digests.back()->feed( 's' ); + const auto s = v.size(); + m_digests.back()->feed( & s, sizeof( s ) ); + m_digests.back()->feed( v ); + } + + // array + void begin_array() + { + m_digests.back()->feed( '[' ); + } + + void element() {} + + void end_array() + { + m_digests.back()->feed( ']' ); + } + + // object + void begin_object() + { + m_digests.back()->feed( '{' ); + m_properties.emplace_back(); + push(); + } + + void key( const std::string & v ) + { + m_digests.back()->feed( v ); + m_keys.emplace_back( m_digests.back()->get() ); + if ( m_properties.back().find( m_keys.back() ) != m_properties.back().end() ) { + throw std::runtime_error( "duplicate JSON object key: " + v ); + } + m_digests.back()->reset(); + } + + void member() + { + m_properties.back().emplace( std::move( m_keys.back() ), m_digests.back()->get() ); + m_keys.pop_back(); + m_digests.back()->reset(); + } + + void end_object() + { + m_digests.pop_back(); + for ( const auto & e : m_properties.back() ) { + m_digests.back()->feed( e.first ); + m_digests.back()->feed( e.second ); + } + m_properties.pop_back(); + m_digests.back()->feed( '}' ); + } + }; + + } // sax + + } // json + +} // tao + +#endif diff --git a/share/include/tao/json/sax/parse_file.hh b/share/include/tao/json/sax/parse_file.hh new file mode 100644 index 0000000..bdda3b4 --- /dev/null +++ b/share/include/tao/json/sax/parse_file.hh @@ -0,0 +1,32 @@ +// Copyright (c) 2016 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/taocpp/json/ + +#ifndef TAOCPP_JSON_INCLUDE_SAX_PARSE_FILE_HH +#define TAOCPP_JSON_INCLUDE_SAX_PARSE_FILE_HH + +#include "../external/pegtl/file_parser.hh" + +#include "../internal/grammar.hh" +#include "../internal/action.hh" +#include "../internal/control.hh" + +namespace tao +{ + namespace json + { + namespace sax + { + // SAX producer to parse a file containing a JSON string representation + template< typename Consumer > + void parse_file( const std::string & filename, Consumer & consumer ) + { + tao_json_pegtl::file_parser( filename ).parse< internal::grammar, internal::action, internal::control >( consumer ); + } + + } // sax + + } // json + +} // tao + +#endif diff --git a/share/include/tao/json/sax/tee.hh b/share/include/tao/json/sax/tee.hh new file mode 100644 index 0000000..b902fc0 --- /dev/null +++ b/share/include/tao/json/sax/tee.hh @@ -0,0 +1,249 @@ +// Copyright (c) 2016 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/taocpp/json/ + +#ifndef TAOCPP_JSON_INCLUDE_SAX_TEE_HH +#define TAOCPP_JSON_INCLUDE_SAX_TEE_HH + +#include +#include +#include +#include +#include + +#include "../internal/integer_sequence.hh" + +namespace tao +{ + namespace json + { + namespace internal + { + template< typename T > + struct strip_reference_wrapper + { + using type = T; + }; + + template< typename T > + struct strip_reference_wrapper< std::reference_wrapper< T > > + { + using type = T &; + }; + + template< typename T > + using decay_and_strip_t = typename strip_reference_wrapper< typename std::decay< T >::type >::type; + + template< typename > + struct sax_apply; + + template< std::size_t ... Is > + struct sax_apply< index_sequence< Is ... > > + { + using sink = bool[]; + + template< typename ... Ts > + static void null( std::tuple< Ts ... > & t ) + { + (void)sink{ ( std::get< Is >( t ).null(), true ) ... }; + } + + template< typename ... Ts > + static void boolean( std::tuple< Ts ... > & t, const bool v ) + { + (void)sink{ ( std::get< Is >( t ).boolean( v ), true ) ... }; + } + + template< typename ... Ts > + static void number( std::tuple< Ts ... > & t, const std::int64_t v ) + { + (void)sink{ ( std::get< Is >( t ).number( v ), true ) ... }; + } + + template< typename ... Ts > + static void number( std::tuple< Ts ... > & t, const std::uint64_t v ) + { + (void)sink{ ( std::get< Is >( t ).number( v ), true ) ... }; + } + + template< typename ... Ts > + static void number( std::tuple< Ts ... > & t, const double v ) + { + (void)sink{ ( std::get< Is >( t ).number( v ), true ) ... }; + } + + template< typename ... Ts > + static void string( std::tuple< Ts ... > & t, const std::string & v ) + { + (void)sink{ ( std::get< Is >( t ).string( v ), true ) ... }; + } + + // array + template< typename ... Ts > + static void begin_array( std::tuple< Ts ... > & t ) + { + (void)sink{ ( std::get< Is >( t ).begin_array(), true ) ... }; + } + + template< typename ... Ts > + static void element( std::tuple< Ts ... > & t ) + { + (void)sink{ ( std::get< Is >( t ).element(), true ) ... }; + } + + template< typename ... Ts > + static void end_array( std::tuple< Ts ... > & t ) + { + (void)sink{ ( std::get< Is >( t ).end_array(), true ) ... }; + } + + // object + template< typename ... Ts > + static void begin_object( std::tuple< Ts ... > & t ) + { + (void)sink{ ( std::get< Is >( t ).begin_object(), true ) ... }; + } + + template< typename ... Ts > + static void key( std::tuple< Ts ... > & t, const std::string & v ) + { + (void)sink{ ( std::get< Is >( t ).key( v ), true ) ... }; + } + + template< typename ... Ts > + static void member( std::tuple< Ts ... > & t ) + { + (void)sink{ ( std::get< Is >( t ).member(), true ) ... }; + } + + template< typename ... Ts > + static void end_object( std::tuple< Ts ... > & t ) + { + (void)sink{ ( std::get< Is >( t ).end_object(), true ) ... }; + } + }; + + } // internal + + namespace sax + { + // SAX consumer that forwards to two nested consumers + template< typename ... Ts > + class tee + { + private: + static_assert( sizeof ... ( Ts ) >= 1, "tao::json::sax::tee requires at least one consumer" ); + + static constexpr std::size_t S = sizeof ... ( Ts ); + + using I = internal::make_index_sequence< S >; + using H = internal::make_index_sequence< S - 1 >; + + std::tuple< Ts ... > ts; + + public: + template< typename ... Us > + tee( Us && ... us ) + : ts( std::forward< Us >( us ) ... ) + { } + + void null() + { + internal::sax_apply< I >::null( ts ); + } + + void boolean( const bool v ) + { + internal::sax_apply< I >::boolean( ts, v ); + } + + void number( const std::int64_t v ) + { + internal::sax_apply< I >::number( ts, v ); + } + + void number( const std::uint64_t v ) + { + internal::sax_apply< I >::number( ts, v ); + } + + void number( const double v ) + { + internal::sax_apply< I >::number( ts, v ); + } + + void string( const std::string & v ) + { + internal::sax_apply< I >::string( ts, v ); + } + + void string( std::string && v ) + { + internal::sax_apply< H >::string( ts, v ); + std::get< S - 1 >( ts ).string( std::move( v ) ); + } + + // array + void begin_array() + { + internal::sax_apply< I >::begin_array( ts ); + } + + void element() + { + internal::sax_apply< I >::element( ts ); + } + + void end_array() + { + internal::sax_apply< I >::end_array( ts ); + } + + // object + void begin_object() + { + internal::sax_apply< I >::begin_object( ts ); + } + + void key( const std::string & v ) + { + internal::sax_apply< I >::key( ts, v ); + } + + void key( std::string && v ) + { + internal::sax_apply< H >::key( ts, v ); + std::get< S - 1 >( ts ).key( std::move( v ) ); + } + + void member() + { + internal::sax_apply< I >::member( ts ); + } + + void end_object() + { + internal::sax_apply< I >::end_object( ts ); + } + }; + + // make_tee + template< typename ... T > + tee< internal::decay_and_strip_t< T >... > make_tee( T && ... t ) + { + return tee< internal::decay_and_strip_t< T > ... >( std::forward< T >( t ) ... ); + } + + // tie + template< typename ... T > + tee< T & ... > tie( T & ... t ) + { + return tee< T & ... >( t ... ); + } + + } // sax + + } // json + +} // tao + +#endif diff --git a/share/include/tao/json/sax/to_pretty_stream.hh b/share/include/tao/json/sax/to_pretty_stream.hh new file mode 100644 index 0000000..1e4a1d5 --- /dev/null +++ b/share/include/tao/json/sax/to_pretty_stream.hh @@ -0,0 +1,151 @@ +// Copyright (c) 2016 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/taocpp/json/ + +#ifndef TAOCPP_JSON_INCLUDE_SAX_TO_PRETTY_STREAM_HH +#define TAOCPP_JSON_INCLUDE_SAX_TO_PRETTY_STREAM_HH + +#include +#include +#include +#include + +#include "../external/double.hh" + +#include "../internal/escape.hh" + +namespace tao +{ + namespace json + { + namespace sax + { + // SAX consumer to build a JSON pretty string representation + class to_pretty_stream + { + private: + std::ostream & os; + const std::size_t indent; + + std::string current = "\n"; + bool first = true; + bool after_key = true; + + void next() + { + if ( ! first ) os.put( ',' ); + if ( after_key ) { + after_key = false; + } + else { + os << current; + } + } + + public: + to_pretty_stream( std::ostream & os, const std::size_t indent ) + : os( os ), + indent( indent ), + first( true ) + { } + + void null() + { + next(); + os.write( "null", 4 ); + } + + void boolean( const bool v ) + { + next(); + if ( v ) { + os.write( "true", 4 ); + } + else { + os.write( "false", 5 ); + } + } + + void number( const std::int64_t v ) + { + next(); + os << v; + } + + void number( const std::uint64_t v ) + { + next(); + os << v; + } + + void number( const double v ) + { + next(); + json_double_conversion::Dtostr( os, v ); + } + + void string( const std::string & v ) + { + next(); + os.put( '"' ); + internal::escape( os, v ); + os.put( '"' ); + } + + // array + void begin_array() + { + next(); + os.put( '[' ); + current.resize( current.size() + indent, ' ' ); + first = true; + } + + void element() + { + first = false; + } + + void end_array() + { + current.resize( current.size() - indent ); + if ( ! first ) os << current; + os.put( ']' ); + } + + // object + void begin_object() + { + next(); + os.put( '{' ); + current.resize( current.size() + indent, ' ' ); + first = true; + } + + void key( const std::string & v ) + { + string( v ); + os.write( ": ", 2 ); + first = true; + after_key = true; + } + + void member() + { + first = false; + } + + void end_object() + { + current.resize( current.size() - indent ); + if ( ! first ) os << current; + os.put( '}' ); + } + }; + + } // sax + + } // json + +} // tao + +#endif diff --git a/share/include/tao/json/sax/to_stream.hh b/share/include/tao/json/sax/to_stream.hh new file mode 100644 index 0000000..11cd85c --- /dev/null +++ b/share/include/tao/json/sax/to_stream.hh @@ -0,0 +1,131 @@ +// Copyright (c) 2016 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/taocpp/json/ + +#ifndef TAOCPP_JSON_INCLUDE_SAX_TO_STREAM_HH +#define TAOCPP_JSON_INCLUDE_SAX_TO_STREAM_HH + +#include +#include + +#include "../external/double.hh" + +#include "../internal/escape.hh" + +namespace tao +{ + namespace json + { + namespace sax + { + // SAX consumer to build a JSON string representation + class to_stream + { + private: + std::ostream & os; + bool first; + + void next() + { + if ( ! first ) os.put( ',' ); + } + + public: + explicit to_stream( std::ostream & os ) noexcept + : os( os ), + first( true ) + { } + + void null() + { + next(); + os.write( "null", 4 ); + } + + void boolean( const bool v ) + { + next(); + if ( v ) { + os.write( "true", 4 ); + } + else { + os.write( "false", 5 ); + } + } + + void number( const std::int64_t v ) + { + next(); + os << v; + } + + void number( const std::uint64_t v ) + { + next(); + os << v; + } + + void number( const double v ) + { + next(); + json_double_conversion::Dtostr( os, v ); + } + + void string( const std::string & v ) + { + next(); + os.put( '"' ); + internal::escape( os, v ); + os.put( '"' ); + } + + // array + void begin_array() + { + next(); + os.put( '[' ); + first = true; + } + + void element() + { + first = false; + } + + void end_array() + { + os.put( ']' ); + } + + // object + void begin_object() + { + next(); + os.put( '{' ); + first = true; + } + + void key( const std::string & v ) + { + string( v ); + os.put( ':' ); + first = true; + } + + void member() + { + first = false; + } + + void end_object() + { + os.put( '}' ); + } + }; + + } // sax + + } // json + +} // tao + +#endif diff --git a/share/include/tao/json/sax/to_string.hh b/share/include/tao/json/sax/to_string.hh new file mode 100644 index 0000000..9a4e729 --- /dev/null +++ b/share/include/tao/json/sax/to_string.hh @@ -0,0 +1,33 @@ +// Copyright (c) 2016 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/taocpp/json/ + +#ifndef TAOCPP_JSON_INCLUDE_SAX_TO_STRING_HH +#define TAOCPP_JSON_INCLUDE_SAX_TO_STRING_HH + +#include + +#include "to_stream.hh" + +namespace tao +{ + namespace json + { + namespace sax + { + // SAX consumer to build a JSON string representation + struct to_string : to_stream + { + std::ostringstream oss; + + to_string() : to_stream( oss ) {} + + std::string value() const { return oss.str(); } + }; + + } // sax + + } // json + +} // tao + +#endif diff --git a/share/include/tao/json/sax/to_value.hh b/share/include/tao/json/sax/to_value.hh new file mode 100644 index 0000000..0400a05 --- /dev/null +++ b/share/include/tao/json/sax/to_value.hh @@ -0,0 +1,117 @@ +// Copyright (c) 2016 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/taocpp/json/ + +#ifndef TAOCPP_JSON_INCLUDE_SAX_TO_VALUE_HH +#define TAOCPP_JSON_INCLUDE_SAX_TO_VALUE_HH + +#include "../value.hh" + +namespace tao +{ + namespace json + { + namespace sax + { + // SAX consumer to build a JSON value + template< template< typename ... > class Traits > + class to_basic_value + { + private: + std::vector< basic_value< Traits > > stack_; + std::vector< std::string > keys_; + + public: + basic_value< Traits > value; + + void null() + { + value.unsafe_assign_null(); + } + + void boolean( const bool v ) + { + value.unsafe_assign_bool( v ); + } + + void number( const std::int64_t v ) + { + value.unsafe_assign_signed( v ); + } + + void number( const std::uint64_t v ) + { + value.unsafe_assign_unsigned( v ); + } + + void number( const double v ) + { + value.unsafe_assign_double( v ); + } + + void string( const std::string & v ) + { + value.unsafe_emplace_string( v ); + } + + void string( std::string && v ) + { + value.unsafe_emplace_string( std::move( v ) ); + } + + // array + void begin_array() + { + stack_.push_back( empty_array ); + } + + void element() + { + stack_.back().unsafe_emplace_back( std::move( value ) ); + value.discard(); + } + + void end_array() + { + value = std::move( stack_.back() ); + stack_.pop_back(); + } + + // object + void begin_object() + { + stack_.push_back( empty_object ); + } + + void key( const std::string & v ) + { + keys_.push_back( v ); + } + + void key( std::string && v ) + { + keys_.push_back( std::move( v ) ); + } + + void member() + { + stack_.back().unsafe_emplace( std::move( keys_.back() ), std::move( value ) ); + value.discard(); + keys_.pop_back(); + } + + void end_object() + { + value = std::move( stack_.back() ); + stack_.pop_back(); + } + }; + + using to_value = to_basic_value< traits >; + + } // sax + + } // json + +} // tao + +#endif diff --git a/share/include/tao/json/sax/validate_event_order.hh b/share/include/tao/json/sax/validate_event_order.hh new file mode 100644 index 0000000..400c5cf --- /dev/null +++ b/share/include/tao/json/sax/validate_event_order.hh @@ -0,0 +1,360 @@ +// Copyright (c) 2016 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/taocpp/json/ + +#ifndef TAOCPP_JSON_INCLUDE_SAX_VALIDATE_EVENT_ORDER_HH +#define TAOCPP_JSON_INCLUDE_SAX_VALIDATE_EVENT_ORDER_HH + +#include +#include +#include +#include + +namespace tao +{ + namespace json + { + namespace sax + { + // SAX consumer that validates the order of events + class validate_event_order + { + private: + enum state_t + { + EXPECT_TOP_LEVEL_VALUE, + EXPECT_ARRAY_VALUE_OR_END, + EXPECT_ARRAY_ELEMENT, + EXPECT_OBJECT_KEY_OR_END, + EXPECT_OBJECT_VALUE, + EXPECT_OBJECT_MEMBER, + EXPECT_NOTHING + }; + + state_t state = EXPECT_TOP_LEVEL_VALUE; + std::vector< state_t > stack; + + public: + bool is_complete() const noexcept + { + return state == EXPECT_NOTHING; + } + + void null() + { + switch ( state ) { + case EXPECT_TOP_LEVEL_VALUE: + state = EXPECT_NOTHING; + return; + case EXPECT_ARRAY_VALUE_OR_END: + state = EXPECT_ARRAY_ELEMENT; + return; + case EXPECT_ARRAY_ELEMENT: + throw std::logic_error( "expected element(), but null() was called" ); + case EXPECT_OBJECT_KEY_OR_END: + throw std::logic_error( "expected key() or end_object(), but null() was called" ); + case EXPECT_OBJECT_VALUE: + state = EXPECT_OBJECT_MEMBER; + return; + case EXPECT_OBJECT_MEMBER: + throw std::logic_error( "expected member(), but null() was called" ); + case EXPECT_NOTHING: + throw std::logic_error( "expected nothing, but null() was called" ); + } + throw std::logic_error( "invalid state" ); + } + + void boolean( const bool ) + { + switch ( state ) { + case EXPECT_TOP_LEVEL_VALUE: + state = EXPECT_NOTHING; + return; + case EXPECT_ARRAY_VALUE_OR_END: + state = EXPECT_ARRAY_ELEMENT; + return; + case EXPECT_ARRAY_ELEMENT: + throw std::logic_error( "expected element(), but boolean() was called" ); + case EXPECT_OBJECT_KEY_OR_END: + throw std::logic_error( "expected key() or end_object(), but boolean() was called" ); + case EXPECT_OBJECT_VALUE: + state = EXPECT_OBJECT_MEMBER; + return; + case EXPECT_OBJECT_MEMBER: + throw std::logic_error( "expected member(), but boolean() was called" ); + case EXPECT_NOTHING: + throw std::logic_error( "expected nothing, but boolean() was called" ); + } + throw std::logic_error( "invalid state" ); + } + + void number( const std::int64_t ) + { + switch ( state ) { + case EXPECT_TOP_LEVEL_VALUE: + state = EXPECT_NOTHING; + return; + case EXPECT_ARRAY_VALUE_OR_END: + state = EXPECT_ARRAY_ELEMENT; + return; + case EXPECT_ARRAY_ELEMENT: + throw std::logic_error( "expected element(), but number(std::int64_t) was called" ); + case EXPECT_OBJECT_KEY_OR_END: + throw std::logic_error( "expected key() or end_object(), but number(std::int64_t) was called" ); + case EXPECT_OBJECT_VALUE: + state = EXPECT_OBJECT_MEMBER; + return; + case EXPECT_OBJECT_MEMBER: + throw std::logic_error( "expected member(), but number(std::int64_t) was called" ); + case EXPECT_NOTHING: + throw std::logic_error( "expected nothing, but number(std::int64_t) was called" ); + } + throw std::logic_error( "invalid state" ); + } + + void number( const std::uint64_t ) + { + switch ( state ) { + case EXPECT_TOP_LEVEL_VALUE: + state = EXPECT_NOTHING; + return; + case EXPECT_ARRAY_VALUE_OR_END: + state = EXPECT_ARRAY_ELEMENT; + return; + case EXPECT_ARRAY_ELEMENT: + throw std::logic_error( "expected element(), but number(std::uint64_t) was called" ); + case EXPECT_OBJECT_KEY_OR_END: + throw std::logic_error( "expected key() or end_object(), but number(std::uint64_t) was called" ); + case EXPECT_OBJECT_VALUE: + state = EXPECT_OBJECT_MEMBER; + return; + case EXPECT_OBJECT_MEMBER: + throw std::logic_error( "expected member(), but number(std::uint64_t) was called" ); + case EXPECT_NOTHING: + throw std::logic_error( "expected nothing, but number(std::uint64_t) was called" ); + } + throw std::logic_error( "invalid state" ); + } + + void number( const double ) + { + switch ( state ) { + case EXPECT_TOP_LEVEL_VALUE: + state = EXPECT_NOTHING; + return; + case EXPECT_ARRAY_VALUE_OR_END: + state = EXPECT_ARRAY_ELEMENT; + return; + case EXPECT_ARRAY_ELEMENT: + throw std::logic_error( "expected element(), but number(double) was called" ); + case EXPECT_OBJECT_KEY_OR_END: + throw std::logic_error( "expected key() or end_object(), but number(double) was called" ); + case EXPECT_OBJECT_VALUE: + state = EXPECT_OBJECT_MEMBER; + return; + case EXPECT_OBJECT_MEMBER: + throw std::logic_error( "expected member(), but number(double) was called" ); + case EXPECT_NOTHING: + throw std::logic_error( "expected nothing, but number(double) was called" ); + } + throw std::logic_error( "invalid state" ); + } + + void string( const std::string & ) + { + switch ( state ) { + case EXPECT_TOP_LEVEL_VALUE: + state = EXPECT_NOTHING; + return; + case EXPECT_ARRAY_VALUE_OR_END: + state = EXPECT_ARRAY_ELEMENT; + return; + case EXPECT_ARRAY_ELEMENT: + throw std::logic_error( "expected element(), but string() was called" ); + case EXPECT_OBJECT_KEY_OR_END: + throw std::logic_error( "expected key() or end_object(), but string() was called" ); + case EXPECT_OBJECT_VALUE: + state = EXPECT_OBJECT_MEMBER; + return; + case EXPECT_OBJECT_MEMBER: + throw std::logic_error( "expected member(), but string() was called" ); + case EXPECT_NOTHING: + throw std::logic_error( "expected nothing, but string() was called" ); + } + throw std::logic_error( "invalid state" ); + } + + // array + void begin_array() + { + switch ( state ) { + case EXPECT_TOP_LEVEL_VALUE: + stack.push_back( EXPECT_NOTHING ); + state = EXPECT_ARRAY_VALUE_OR_END; + return; + case EXPECT_ARRAY_VALUE_OR_END: + stack.push_back( EXPECT_ARRAY_ELEMENT ); + return; + case EXPECT_ARRAY_ELEMENT: + throw std::logic_error( "expected element(), but begin_array() was called" ); + case EXPECT_OBJECT_KEY_OR_END: + throw std::logic_error( "expected key() or end_object(), but begin_array() was called" ); + case EXPECT_OBJECT_VALUE: + stack.push_back( EXPECT_OBJECT_MEMBER ); + state = EXPECT_ARRAY_VALUE_OR_END; + return; + case EXPECT_OBJECT_MEMBER: + throw std::logic_error( "expected member(), but begin_array() was called" ); + case EXPECT_NOTHING: + throw std::logic_error( "expected nothing, but begin_array() was called" ); + } + throw std::logic_error( "invalid state" ); + } + + void element() + { + switch ( state ) { + case EXPECT_TOP_LEVEL_VALUE: + throw std::logic_error( "expected any value, but element() was called" ); + case EXPECT_ARRAY_VALUE_OR_END: + throw std::logic_error( "expected any value or end_array(), but element() was called" ); + case EXPECT_ARRAY_ELEMENT: + state = EXPECT_ARRAY_VALUE_OR_END; + return; + case EXPECT_OBJECT_KEY_OR_END: + throw std::logic_error( "expected key() or end_object(), but element() was called" ); + case EXPECT_OBJECT_VALUE: + throw std::logic_error( "expected any value, but element() was called" ); + case EXPECT_OBJECT_MEMBER: + throw std::logic_error( "expected member(), but element() was called" ); + case EXPECT_NOTHING: + throw std::logic_error( "expected nothing, but element() was called" ); + } + throw std::logic_error( "invalid state" ); + } + + void end_array() + { + switch ( state ) { + case EXPECT_TOP_LEVEL_VALUE: + throw std::logic_error( "expected any value, but end_array() was called" ); + case EXPECT_ARRAY_VALUE_OR_END: + state = stack.back(); + stack.pop_back(); + return; + case EXPECT_ARRAY_ELEMENT: + throw std::logic_error( "expected element(), but end_array() was called" ); + case EXPECT_OBJECT_KEY_OR_END: + throw std::logic_error( "expected key() or end_object(), but end_array() was called" ); + case EXPECT_OBJECT_VALUE: + throw std::logic_error( "expected any value, but end_array() was called" ); + case EXPECT_OBJECT_MEMBER: + throw std::logic_error( "expected member(), but end_array() was called" ); + case EXPECT_NOTHING: + throw std::logic_error( "expected nothing, but end_array() was called" ); + } + throw std::logic_error( "invalid state" ); + } + + // object + void begin_object() + { + switch ( state ) { + case EXPECT_TOP_LEVEL_VALUE: + stack.push_back( EXPECT_NOTHING ); + state = EXPECT_OBJECT_KEY_OR_END; + return; + case EXPECT_ARRAY_VALUE_OR_END: + stack.push_back( EXPECT_ARRAY_ELEMENT ); + state = EXPECT_OBJECT_KEY_OR_END; + return; + case EXPECT_ARRAY_ELEMENT: + throw std::logic_error( "expected element(), but begin_object() was called" ); + case EXPECT_OBJECT_KEY_OR_END: + throw std::logic_error( "expected key() or end_object(), but begin_object() was called" ); + case EXPECT_OBJECT_VALUE: + stack.push_back( EXPECT_OBJECT_MEMBER ); + state = EXPECT_OBJECT_KEY_OR_END; + return; + case EXPECT_OBJECT_MEMBER: + throw std::logic_error( "expected member(), but begin_object() was called" ); + case EXPECT_NOTHING: + throw std::logic_error( "expected nothing, but begin_object() was called" ); + } + throw std::logic_error( "invalid state" ); + } + + void key( const std::string & ) + { + switch ( state ) { + case EXPECT_TOP_LEVEL_VALUE: + throw std::logic_error( "expected any value, but key() was called" ); + case EXPECT_ARRAY_VALUE_OR_END: + throw std::logic_error( "expected any value or end_array(), but key() was called" ); + case EXPECT_ARRAY_ELEMENT: + throw std::logic_error( "expected element(), but key() was called" ); + case EXPECT_OBJECT_KEY_OR_END: + state = EXPECT_OBJECT_VALUE; + return; + case EXPECT_OBJECT_VALUE: + throw std::logic_error( "expected any value, but key() was called" ); + case EXPECT_OBJECT_MEMBER: + throw std::logic_error( "expected member(), but key() was called" ); + case EXPECT_NOTHING: + throw std::logic_error( "expected nothing, but key() was called" ); + } + throw std::logic_error( "invalid state" ); + } + + void member() + { + switch ( state ) { + case EXPECT_TOP_LEVEL_VALUE: + throw std::logic_error( "expected any value, but member() was called" ); + case EXPECT_ARRAY_VALUE_OR_END: + throw std::logic_error( "expected any value or end_array(), but member() was called" ); + case EXPECT_ARRAY_ELEMENT: + throw std::logic_error( "expected element(), but member() was called" ); + case EXPECT_OBJECT_KEY_OR_END: + throw std::logic_error( "expected key() or end_object(), but member() was called" ); + case EXPECT_OBJECT_VALUE: + throw std::logic_error( "expected any value, but member() was called" ); + case EXPECT_OBJECT_MEMBER: + state = EXPECT_OBJECT_KEY_OR_END; + return; + case EXPECT_NOTHING: + throw std::logic_error( "expected nothing, but member() was called" ); + } + throw std::logic_error( "invalid state" ); + } + + void end_object() + { + switch ( state ) { + case EXPECT_TOP_LEVEL_VALUE: + throw std::logic_error( "expected any value, but end_object() was called" ); + case EXPECT_ARRAY_VALUE_OR_END: + throw std::logic_error( "expected any value or end_array(), but end_object() was called" ); + case EXPECT_ARRAY_ELEMENT: + throw std::logic_error( "expected element(), but end_object() was called" ); + case EXPECT_OBJECT_KEY_OR_END: + state = stack.back(); + stack.pop_back(); + return; + case EXPECT_OBJECT_VALUE: + throw std::logic_error( "expected any value, but end_object() was called" ); + case EXPECT_OBJECT_MEMBER: + throw std::logic_error( "expected member(), but end_object() was called" ); + case EXPECT_NOTHING: + throw std::logic_error( "expected nothing, but end_object() was called" ); + } + throw std::logic_error( "invalid state" ); + } + }; + + } // sax + + } // json + +} // tao + +#endif diff --git a/share/include/tao/json/schema.hh b/share/include/tao/json/schema.hh new file mode 100644 index 0000000..8c6761c --- /dev/null +++ b/share/include/tao/json/schema.hh @@ -0,0 +1,1726 @@ +// Copyright (c) 2016 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/taocpp/json/ + +#ifndef TAOCPP_JSON_INCLUDE_SCHEMA_HH +#define TAOCPP_JSON_INCLUDE_SCHEMA_HH + +#include "value.hh" +#include "pointer.hh" +#include "reference.hh" +#include "sax/compare.hh" +#include "sax/hash.hh" +#include "sax/from_value.hh" +#include "external/pegtl/parse.hh" +#include "external/pegtl/contrib/uri.hh" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace tao +{ + namespace json + { + namespace internal + { + // TODO: Check if these grammars are correct. + struct local_part_label : tao_json_pegtl::plus< tao_json_pegtl::sor< tao_json_pegtl::alnum, tao_json_pegtl::one< '!', '#', '$', '%', '&', '\'', '*', '+', '-', '/', '=', '?', '^', '_', '`', '{', '|', '}', '~' > > > {}; + struct local_part : tao_json_pegtl::list_must< local_part_label, tao_json_pegtl::one< '.' > > {}; + + struct hostname_label : tao_json_pegtl::seq< tao_json_pegtl::alnum, tao_json_pegtl::rep_max< 62, tao_json_pegtl::ranges< 'a', 'z', 'A', 'Z', '0', '9', '-' > > > {}; + struct hostname : tao_json_pegtl::list_must< hostname_label, tao_json_pegtl::one< '.' > > {}; + + struct email : tao_json_pegtl::seq< local_part, tao_json_pegtl::one< '@' >, hostname > {}; + + template< typename Rule > + bool parse( const std::string & v ) + { + return tao_json_pegtl::parse_string< tao_json_pegtl::seq< Rule, tao_json_pegtl::eof > >( v, "" ); + } + + inline bool parse_date_time( const std::string & v ) + { + static std::regex re( "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:[0-5]\\d:[0-5]\\d(\\.\\d+)?(Z|[+-]\\d{2}:[0-5]\\d)$" ); + if ( ! std::regex_search( v, re ) ) { + return false; + } + + const unsigned year = ( v[ 0 ] - '0' ) * 1000 + ( v[ 1 ] - '0' ) * 100 + ( v[ 2 ] - '0' ) * 10 + ( v[ 3 ] - '0' ); + const unsigned month = ( v[ 5 ] - '0' ) * 10 + ( v[ 6 ] - '0' ); + const unsigned day = ( v[ 8 ] - '0' ) * 10 + ( v[ 9 ] - '0' ); + + if ( month == 0 || month > 12 ) { + return false; + } + if ( day == 0 || day > 31 ) { + return false; + } + if ( month == 2 ) { + const bool is_leap_year = ( year % 4 == 0 ) && ( year % 100 != 0 || year % 400 == 0 ); + if ( day > ( is_leap_year? 29 : 28 ) ) { + return false; + } + } + else if ( day == 31 ) { + switch ( month ) { + case 4: + case 6: + case 9: + case 11: + return false; + } + } + + const unsigned hour = ( v[ 11 ] - '0' ) * 10 + ( v[ 12 ] - '0' ); + if ( hour >= 24 ) { + return false; + } + + if ( * v.rbegin() != 'Z' ) { + const auto s = v.size(); + const unsigned tz_hour = ( v[ s - 5 ] - '0' ) * 10 + ( v[ s - 4 ] - '0' ); + if ( tz_hour >= 24 ) { + return false; + } + } + + return true; + } + + enum schema_flags + { + NONE = 0, + + HAS_TYPE = 1 << 0, + NULL_ = 1 << 1, + BOOLEAN = 1 << 2, + INTEGER = 1 << 3, + NUMBER = 1 << 4, + STRING = 1 << 5, + ARRAY = 1 << 6, + OBJECT = 1 << 7, + + HAS_ENUM = 1 << 8, + + HAS_MULTIPLE_OF_UNSIGNED = 1 << 9, + HAS_MULTIPLE_OF_DOUBLE = 1 << 10, + HAS_MULTIPLE_OF = 3 << 9, + + HAS_MAXIMUM_SIGNED = 1 << 11, + HAS_MAXIMUM_UNSIGNED = 1 << 12, + HAS_MAXIMUM_DOUBLE = 3 << 11, + HAS_MAXIMUM = 3 << 11, + EXCLUSIVE_MAXIMUM = 1 << 13, + + HAS_MINIMUM_SIGNED = 1 << 14, + HAS_MINIMUM_UNSIGNED = 1 << 15, + HAS_MINIMUM_DOUBLE = 3 << 14, + HAS_MINIMUM = 3 << 14, + EXCLUSIVE_MINIMUM = 1 << 16, + + HAS_MAX_LENGTH = 1 << 17, + HAS_MIN_LENGTH = 1 << 18, + + HAS_MAX_ITEMS = 1 << 19, + HAS_MIN_ITEMS = 1 << 20, + HAS_UNIQUE_ITEMS = 1 << 21, + + HAS_MAX_PROPERTIES = 1 << 22, + HAS_MIN_PROPERTIES = 1 << 23, + NO_ADDITIONAL_PROPERTIES = 1 << 24, + HAS_DEPENDENCIES = 1 << 25 + }; + + enum class schema_format + { + NONE, + DATE_TIME, + EMAIL, + HOSTNAME, + IPV4, + IPV6, + URI + }; + + inline constexpr schema_flags operator|( const schema_flags lhs, const schema_flags rhs ) noexcept + { + return static_cast< schema_flags >( static_cast< std::underlying_type< schema_flags >::type >( lhs ) | static_cast< std::underlying_type< schema_flags >::type >( rhs ) ); + } + + union schema_limit + { + std::int64_t i; + std::uint64_t u; + double d; + }; + + template< template< typename ... > class Traits > + class schema_container; + + template< template< typename ... > class Traits > + struct schema_node + { + const schema_container< Traits > * m_container; + const basic_value< Traits > * m_value; + const basic_value< Traits > * m_all_of = nullptr; + const basic_value< Traits > * m_any_of = nullptr; + const basic_value< Traits > * m_one_of = nullptr; + const basic_value< Traits > * m_not = nullptr; + const basic_value< Traits > * m_items = nullptr; + const basic_value< Traits > * m_additional_items = nullptr; + const basic_value< Traits > * m_properties = nullptr; + const basic_value< Traits > * m_additional_properties = nullptr; + + std::map< std::string, std::set< std::string > > m_property_dependencies; + std::map< std::string, const basic_value< Traits > * > m_schema_dependencies; + + std::vector< std::pair< std::regex, const basic_value< Traits > * > > m_pattern_properties; + + std::set< const basic_value< Traits > * > m_referenced_pointers; + + // number + schema_limit m_multiple_of; + schema_limit m_maximum; + schema_limit m_minimum; + + // string + std::uint64_t m_max_length; + std::uint64_t m_min_length; + std::unique_ptr< std::regex > m_pattern; + + // array + std::uint64_t m_max_items; + std::uint64_t m_min_items; + + // object + std::uint64_t m_max_properties; + std::uint64_t m_min_properties; + std::set< std::string > m_required; + + schema_flags m_flags = schema_flags::NONE; + schema_format m_format = schema_format::NONE; + + void add_type( const schema_flags v ) + { + if ( ( m_flags & v ) != 0 ) { + throw std::runtime_error( "invalid JSON Schema: duplicate primitive type" ); + } + m_flags = m_flags | v; + } + + void add_type( const std::string & v ) + { + if ( ! v.empty() ) { + switch ( v[ 0 ] ) { + case 'n': + if ( v == "number" ) { + return add_type( NUMBER ); + } + else if ( v == "null" ) { + return add_type( NULL_ ); + } + break; + case 'b': + if ( v == "boolean" ) { + return add_type( BOOLEAN ); + } + break; + case 'i': + if ( v == "integer" ) { + return add_type( INTEGER ); + } + break; + case 's': + if ( v == "string" ) { + return add_type( STRING ); + } + break; + case 'a': + if ( v == "array" ) { + return add_type( ARRAY ); + } + break; + case 'o': + if ( v == "object" ) { + return add_type( OBJECT ); + } + break; + } + } + throw std::runtime_error( "invalid JSON Schema: invalid primitive type '" + v + '\'' ); + } + + const basic_value< Traits > * find( const char * s ) const + { + const auto * p = m_value->unsafe_find( s ); + if ( p != nullptr ) { + p = p->skip_raw_ptr(); + } + return p; + } + + schema_node( const schema_container< Traits > * c, const basic_value< Traits > & v ) + : m_container( c ), + m_value( & v ) + { + // general + if ( ! m_value->is_object() ) { + throw std::runtime_error( "invalid JSON Schema: a schema must be of type 'object'" ); + } + + // title + if ( const auto * p = find( "title" ) ) { + if ( ! p->is_string() ) { + throw std::runtime_error( "invalid JSON Schema: \"title\" must be of type 'string'" ); + } + } + + // description + if ( const auto * p = find( "description" ) ) { + if ( ! p->is_string() ) { + throw std::runtime_error( "invalid JSON Schema: \"description\" must be of type 'string'" ); + } + } + + // type + if ( const auto * p = find( "type" ) ) { + switch ( p->type() ) { + case type::STRING: + add_type( p->unsafe_get_string() ); + break; + case type::ARRAY: + for ( const auto & e : p->unsafe_get_array() ) { + if ( ! e.is_string() ) { + throw std::runtime_error( "invalid JSON Schema: elements in array \"type\" must be of type 'string'" ); + } + add_type( e.unsafe_get_string() ); + } + break; + default: + throw std::runtime_error( "invalid JSON Schema: \"type\" must be of type 'string' or 'array'" ); + } + m_flags = m_flags | HAS_TYPE; + } + + // enum + if ( const auto * p = find( "enum" ) ) { + if ( ! p->is_array() ) { + throw std::runtime_error( "invalid JSON Schema: \"enum\" must be of type 'array'" ); + } + m_flags = m_flags | HAS_ENUM; + } + + // allOf + if ( const auto * p = find( "allOf" ) ) { + if ( ! p->is_array() ) { + throw std::runtime_error( "invalid JSON Schema: \"allOf\" must be of type 'array'" ); + } + if ( p->empty() ) { + throw std::runtime_error( "invalid JSON Schema: \"allOf\" must have at least one element" ); + } + for ( const auto & e : p->unsafe_get_array() ) { + m_referenced_pointers.insert( e.skip_raw_ptr() ); + } + m_all_of = p; + } + + // anyOf + if ( const auto * p = find( "anyOf" ) ) { + if ( ! p->is_array() ) { + throw std::runtime_error( "invalid JSON Schema: \"anyOf\" must be of type 'array'" ); + } + if ( p->empty() ) { + throw std::runtime_error( "invalid JSON Schema: \"anyOf\" must have at least one element" ); + } + for ( const auto & e : p->unsafe_get_array() ) { + m_referenced_pointers.insert( e.skip_raw_ptr() ); + } + m_any_of = p; + } + + // oneOf + if ( const auto * p = find( "oneOf" ) ) { + if ( ! p->is_array() ) { + throw std::runtime_error( "invalid JSON Schema: \"oneOf\" must be of type 'array'" ); + } + if ( p->empty() ) { + throw std::runtime_error( "invalid JSON Schema: \"oneOf\" must have at least one element" ); + } + for ( const auto & e : p->unsafe_get_array() ) { + m_referenced_pointers.insert( e.skip_raw_ptr() ); + } + m_one_of = p; + } + + // not + if ( const auto * p = find( "not" ) ) { + m_referenced_pointers.insert( p ); + m_not = p; + } + + // definitions + if ( const auto * p = find( "definitions" ) ) { + if ( ! p->is_object() ) { + throw std::runtime_error( "invalid JSON Schema: \"definitions\" must be of type 'object'" ); + } + for ( const auto & e : p->unsafe_get_object() ) { + m_referenced_pointers.insert( e.second.skip_raw_ptr() ); + } + } + + // multipleOf + if ( const auto * p = find( "multipleOf" ) ) { + switch ( p->type() ) { + case type::SIGNED: + { + const auto i = p->unsafe_get_signed(); + if ( i <= 0 ) { + throw std::runtime_error( "invalid JSON Schema: \"multipleOf\" must be strictly greater than zero" ); + } + m_multiple_of.u = i; + m_flags = m_flags | HAS_MULTIPLE_OF_UNSIGNED; + } + break; + case type::UNSIGNED: + { + const auto u = p->unsafe_get_unsigned(); + if ( u == 0 ) { + throw std::runtime_error( "invalid JSON Schema: \"multipleOf\" must be strictly greater than zero" ); + } + m_multiple_of.u = u; + m_flags = m_flags | HAS_MULTIPLE_OF_UNSIGNED; + } + break; + case type::DOUBLE: + { + const auto d = p->unsafe_get_double(); + if ( d <= 0 ) { + throw std::runtime_error( "invalid JSON Schema: \"multipleOf\" must be strictly greater than zero" ); + } + m_multiple_of.d = d; + m_flags = m_flags | HAS_MULTIPLE_OF_DOUBLE; + } + break; + default: + throw std::runtime_error( "invalid JSON Schema: \"multipleOf\" must be of type 'number'" ); + } + } + + // maximum + if ( const auto * p = find( "maximum" ) ) { + switch ( p->type() ) { + case type::SIGNED: + m_maximum.i = p->unsafe_get_signed(); + m_flags = m_flags | HAS_MAXIMUM_SIGNED; + break; + case type::UNSIGNED: + m_maximum.u = p->unsafe_get_unsigned(); + m_flags = m_flags | HAS_MAXIMUM_UNSIGNED; + break; + case type::DOUBLE: + m_maximum.d = p->unsafe_get_double(); + m_flags = m_flags | HAS_MAXIMUM_DOUBLE; + break; + default: + throw std::runtime_error( "invalid JSON Schema: \"maximum\" must be of type 'number'" ); + } + } + + // exclusiveMaximum + if ( const auto * p = find( "exclusiveMaximum" ) ) { + if ( ! p->is_boolean() ) { + throw std::runtime_error( "invalid JSON Schema: \"exclusiveMaximum\" must be of type 'boolean'" ); + } + if ( ( m_flags & HAS_MAXIMUM ) == 0 ) { + throw std::runtime_error( "invalid JSON Schema: \"exclusiveMaximum\" requires presence of \"maximum\"" ); + } + if ( p->get_boolean() ) { + m_flags = m_flags | EXCLUSIVE_MAXIMUM; + } + } + + // minimum + if ( const auto * p = find( "minimum" ) ) { + switch ( p->type() ) { + case type::SIGNED: + m_minimum.i = p->unsafe_get_signed(); + m_flags = m_flags | HAS_MINIMUM_SIGNED; + break; + case type::UNSIGNED: + m_minimum.u = p->unsafe_get_unsigned(); + m_flags = m_flags | HAS_MINIMUM_UNSIGNED; + break; + case type::DOUBLE: + m_minimum.d = p->unsafe_get_double(); + m_flags = m_flags | HAS_MINIMUM_DOUBLE; + break; + default: + throw std::runtime_error( "invalid JSON Schema: \"minimum\" must be of type 'number'" ); + } + } + + // exclusiveMinimum + if ( const auto * p = find( "exclusiveMinimum" ) ) { + if ( ! p->is_boolean() ) { + throw std::runtime_error( "invalid JSON Schema: \"exclusiveMinimum\" must be of type 'boolean'" ); + } + if ( ( m_flags & HAS_MINIMUM ) == 0 ) { + throw std::runtime_error( "invalid JSON Schema: \"exclusiveMinimum\" requires presence of \"minimum\"" ); + } + if ( p->get_boolean() ) { + m_flags = m_flags | EXCLUSIVE_MINIMUM; + } + } + + // maxLength + if ( const auto * p = find( "maxLength" ) ) { + switch ( p->type() ) { + case type::SIGNED: + { + const auto i = p->unsafe_get_signed(); + if ( i < 0 ) { + throw std::runtime_error( "invalid JSON Schema: \"maxLength\" must be greater than or equal to zero" ); + } + m_max_length = i; + m_flags = m_flags | HAS_MAX_LENGTH; + } + break; + case type::UNSIGNED: + m_max_length = p->unsafe_get_unsigned(); + m_flags = m_flags | HAS_MAX_LENGTH; + break; + default: + throw std::runtime_error( "invalid JSON Schema: \"maxLength\" must be of type 'integer'" ); + } + } + + // minLength + if ( const auto * p = find( "minLength" ) ) { + switch ( p->type() ) { + case type::SIGNED: + { + const auto i = p->unsafe_get_signed(); + if ( i < 0 ) { + throw std::runtime_error( "invalid JSON Schema: \"minLength\" must be greater than or equal to zero" ); + } + if ( i > 0 ) { + m_min_length = i; + m_flags = m_flags | HAS_MIN_LENGTH; + } + } + break; + case type::UNSIGNED: + { + const auto u = p->unsafe_get_unsigned(); + if ( u > 0 ) { + m_min_length = u; + m_flags = m_flags | HAS_MIN_LENGTH; + } + } + break; + default: + throw std::runtime_error( "invalid JSON Schema: \"minLength\" must be of type 'integer'" ); + } + } + + // pattern + if ( const auto * p = find( "pattern" ) ) { + if ( ! p->is_string() ) { + throw std::runtime_error( "invalid JSON Schema: \"pattern\" must be of type 'string'" ); + } + try { + m_pattern.reset( new std::regex( p->unsafe_get_string() ) ); + } + catch( const std::regex_error & e ) { + throw std::runtime_error( "invalid JSON Schema: \"pattern\" must be a regular expression: " + std::string( e.what() ) ); + } + } + + // format + // TODO: offer an option to disable "format" support? + if ( const auto * p = find( "format" ) ) { + if ( ! p->is_string() ) { + throw std::runtime_error( "invalid JSON Schema: \"format\" must be of type 'string'" ); + } + const auto & s = p->unsafe_get_string(); + if ( s == "date-time" ) { + m_format = schema_format::DATE_TIME; + } + else if ( s == "email" ) { + m_format = schema_format::EMAIL; + } + else if ( s == "hostname" ) { + m_format = schema_format::HOSTNAME; + } + else if ( s == "ipv4" ) { + m_format = schema_format::IPV4; + } + else if ( s == "ipv6" ) { + m_format = schema_format::IPV6; + } + else if ( s == "uri" ) { + m_format = schema_format::URI; + } + // unknown "format" values are ignored + } + + // items + if ( const auto * p = find( "items" ) ) { + if ( p->is_array() ) { + for ( const auto & e : p->unsafe_get_array() ) { + m_referenced_pointers.insert( e.skip_raw_ptr() ); + } + } + else if ( p->is_object() ) { + m_referenced_pointers.insert( p ); + } + else { + throw std::runtime_error( "invalid JSON Schema: \"items\" must be of type 'object' or 'array'" ); + } + m_items = p; + } + + // additionalItems + if ( const auto * p = find( "additionalItems" ) ) { + if ( p->is_object() ) { + m_referenced_pointers.insert( p ); + } + else if ( ! p->is_boolean() ) { + throw std::runtime_error( "invalid JSON Schema: \"additionalItems\" must be of type 'boolean' or 'object'" ); + } + m_additional_items = p; + } + + // maxItems + if ( const auto * p = find( "maxItems" ) ) { + switch ( p->type() ) { + case type::SIGNED: + { + const auto i = p->unsafe_get_signed(); + if ( i < 0 ) { + throw std::runtime_error( "invalid JSON Schema: \"maxItems\" must be greater than or equal to zero" ); + } + m_max_items = i; + m_flags = m_flags | HAS_MAX_ITEMS; + } + break; + case type::UNSIGNED: + m_max_items = p->unsafe_get_unsigned(); + m_flags = m_flags | HAS_MAX_ITEMS; + break; + default: + throw std::runtime_error( "invalid JSON Schema: \"maxItems\" must be of type 'integer'" ); + } + } + + // minItems + if ( const auto * p = find( "minItems" ) ) { + switch ( p->type() ) { + case type::SIGNED: + { + const auto i = p->unsafe_get_signed(); + if ( i < 0 ) { + throw std::runtime_error( "invalid JSON Schema: \"minItems\" must be greater than or equal to zero" ); + } + m_min_items = i; + m_flags = m_flags | HAS_MIN_ITEMS; + } + break; + case type::UNSIGNED: + m_min_items = p->unsafe_get_unsigned(); + m_flags = m_flags | HAS_MIN_ITEMS; + break; + default: + throw std::runtime_error( "invalid JSON Schema: \"minItems\" must be of type 'integer'" ); + } + } + + // uniqueItems + if ( const auto * p = find( "uniqueItems" ) ) { + if ( p->get_boolean() ) { + m_flags = m_flags | HAS_UNIQUE_ITEMS; + } + } + + // maxProperties + if ( const auto * p = find( "maxProperties" ) ) { + switch ( p->type() ) { + case type::SIGNED: + { + const auto i = p->unsafe_get_signed(); + if ( i < 0 ) { + throw std::runtime_error( "invalid JSON Schema: \"maxProperties\" must be greater than or equal to zero" ); + } + m_max_properties = i; + m_flags = m_flags | HAS_MAX_PROPERTIES; + } + break; + case type::UNSIGNED: + m_max_properties = p->unsafe_get_unsigned(); + m_flags = m_flags | HAS_MAX_PROPERTIES; + break; + default: + throw std::runtime_error( "invalid JSON Schema: \"maxProperties\" must be of type 'integer'" ); + } + } + + // minProperties + if ( const auto * p = find( "minProperties" ) ) { + switch ( p->type() ) { + case type::SIGNED: + { + const auto i = p->unsafe_get_signed(); + if ( i < 0 ) { + throw std::runtime_error( "invalid JSON Schema: \"minProperties\" must be greater than or equal to zero" ); + } + m_min_properties = i; + m_flags = m_flags | HAS_MIN_PROPERTIES; + } + break; + case type::UNSIGNED: + m_min_properties = p->unsafe_get_unsigned(); + m_flags = m_flags | HAS_MIN_PROPERTIES; + break; + default: + throw std::runtime_error( "invalid JSON Schema: \"minProperties\" must be of type 'integer'" ); + } + } + + // required + if ( const auto * p = find( "required" ) ) { + if ( ! p->is_array() ) { + throw std::runtime_error( "invalid JSON Schema: \"required\" must be of type 'array'" ); + } + if ( p->empty() ) { + throw std::runtime_error( "invalid JSON Schema: \"required\" must have at least one element" ); + } + for ( const auto & e : p->unsafe_get_array() ) { + if ( ! m_required.insert( e.get_string() ).second ) { + throw std::runtime_error( "invalid JSON Schema: duplicate required key" ); + } + } + } + + // properties + if ( const auto * p = find( "properties" ) ) { + if ( ! p->is_object() ) { + throw std::runtime_error( "invalid JSON Schema: \"properties\" must be of type 'object'" ); + } + for ( const auto & e : p->unsafe_get_object() ) { + m_referenced_pointers.insert( e.second.skip_raw_ptr() ); + } + m_properties = p; + } + + // patternProperties + if ( const auto * p = find( "patternProperties" ) ) { + if ( ! p->is_object() ) { + throw std::runtime_error( "invalid JSON Schema: \"patternProperties\" must be of type 'object'" ); + } + for ( const auto & e : p->unsafe_get_object() ) { + try { + m_pattern_properties.emplace_back( std::regex( e.first ), e.second.skip_raw_ptr() ); + } + catch( const std::regex_error & e ) { + throw std::runtime_error( "invalid JSON Schema: keys in object \"patternProperties\" must be regular expressions: " + std::string( e.what() ) ); + } + m_referenced_pointers.insert( e.second.skip_raw_ptr() ); + } + } + + // additionalProperties + if ( const auto * p = find( "additionalProperties" ) ) { + const type t = p->type(); + if ( t == type::OBJECT ) { + m_referenced_pointers.insert( p ); + } + else if ( t != type::BOOLEAN ) { + throw std::runtime_error( "invalid JSON Schema: \"additionalProperties\" must be of type 'boolean' or 'object'" ); + } + m_additional_properties = p; + } + + // dependencies + if ( const auto * p = find( "dependencies" ) ) { + if ( ! p->is_object() ) { + throw std::runtime_error( "invalid JSON Schema: \"dependencies\" must be of type 'object'" ); + } + for ( const auto & e : p->unsafe_get_object() ) { + const auto * p2 = e.second.skip_raw_ptr(); + if ( p2->is_object() ) { + m_schema_dependencies.emplace( e.first, p2 ); + m_referenced_pointers.insert( p2 ); + } + else if ( p2->is_array() ) { + if ( p2->empty() ) { + throw std::runtime_error( "invalid JSON Schema: values in object \"dependencies\" of type 'array' must have at least one element" ); + } + std::set< std::string > s; + for ( const auto & r : p2->unsafe_get_array() ) { + if ( ! r.is_string() ) { + throw std::runtime_error( "invalid JSON Schema: values in object \"dependencies\" of type 'array' must contain elements of type 'string'" ); + } + if ( ! s.emplace( r.unsafe_get_string() ).second ) { + throw std::runtime_error( "invalid JSON Schema: values in object \"dependencies\" of type 'array' must contain unique elements of type 'string'" ); + } + } + m_property_dependencies.emplace( e.first, std::move( s ) ); + } + else { + throw std::runtime_error( "invalid JSON Schema: values in object \"dependencies\" must be of type 'object' or 'array'" ); + } + } + if ( ! p->empty() ) { + m_flags = m_flags | HAS_DEPENDENCIES; + } + } + + // default + if ( const auto * p = find( "default" ) ) { + // TODO: the value should validate against the JSON Schema itself + } + } + + schema_node( const schema_node & ) = delete; + schema_node( schema_node && ) = delete; + + void operator= ( const schema_node & ) = delete; + void operator= ( schema_node && ) = delete; + + const std::set< const basic_value< Traits > * > & referenced_pointers() const noexcept + { + return m_referenced_pointers; + } + }; + + template< template< typename ... > class Traits > + class schema_consumer + { + private: + const std::shared_ptr< const schema_container< Traits > > m_container; + const schema_node< Traits > * const m_node; + + std::vector< std::unique_ptr< sax_compare< Traits > > > m_enum; + std::unique_ptr< sax::hash > m_hash; + std::set< std::string > m_unique; + std::set< std::string > m_keys; + std::vector< std::size_t > m_count; + std::vector< std::unique_ptr< schema_consumer > > m_properties; + std::vector< std::unique_ptr< schema_consumer > > m_all_of; + std::vector< std::unique_ptr< schema_consumer > > m_any_of; + std::vector< std::unique_ptr< schema_consumer > > m_one_of; + std::map< std::string, std::unique_ptr< schema_consumer > > m_schema_dependencies; + std::unique_ptr< schema_consumer > m_not; + std::unique_ptr< schema_consumer > m_item; + bool m_match = true; + + void validate_type( const schema_flags t ) + { + if ( ! m_count.empty() ) { + return; + } + if ( ( m_node->m_flags & HAS_TYPE ) == 0 ) { + return; + } + if ( ( m_node->m_flags & t ) == 0 ) { + m_match = false; + } + } + + // note: lambda returns true if validation failure detected + template< typename F > + void validate_enum( F && f ) + { + assert( m_match ); + if ( m_node->m_flags & HAS_ENUM ) { + m_enum.erase( std::remove_if( m_enum.begin(), m_enum.end(), [&]( const std::unique_ptr< sax_compare< Traits > > & p ){ return f( * p ); } ), m_enum.end() ); + if ( m_enum.empty() ) { + m_match = false; + } + } + } + + template< typename F > + void validate_item( F && f ) + { + if ( m_item ) { + if ( f( m_item ) ) { + m_match = false; + } + } + } + + template< typename F > + void validate_properties( F && f ) + { + for ( auto & p : m_properties ) { + if ( f( p ) ) { + m_match = false; + break; + } + } + } + + template< typename F > + void validate_schema_dependencies( F && f ) + { + auto it = m_schema_dependencies.begin(); + while ( it != m_schema_dependencies.end() ) { + if ( f( it->second ) ) { + it = m_schema_dependencies.erase( it ); + } + else { + ++it; + } + } + } + + template< typename F > + void validate_all_of( F && f ) + { + for ( auto & p : m_all_of ) { + if ( f( p ) ) { + m_match = false; + break; + } + } + } + + template< typename F > + void validate_any_of( F && f ) + { + if ( ! m_any_of.empty() ) { + m_any_of.erase( std::remove_if( m_any_of.begin(), m_any_of.end(), f ), m_any_of.end() ); + if ( m_any_of.empty() ) { + m_match = false; + } + } + } + + template< typename F > + void validate_one_of( F && f ) + { + if ( ! m_one_of.empty() ) { + m_one_of.erase( std::remove_if( m_one_of.begin(), m_one_of.end(), f ), m_one_of.end() ); + if ( m_one_of.empty() ) { + m_match = false; + } + } + } + + template< typename F > + void validate_not( F && f ) + { + if ( m_not ) { + if ( f( m_not ) ) { + m_not.reset(); + } + } + } + + // note: lambda returns true if validation failure detected + template< typename F > + void validate_collections( F && f ) + { + assert( m_match ); + const auto f2 = [&]( const std::unique_ptr< schema_consumer > & p ){ return f( * p ); }; + if ( m_match ) validate_item( f2 ); + if ( m_match ) validate_properties( f2 ); + if ( m_match ) validate_all_of( f2 ); + if ( m_match ) validate_any_of( f2 ); + if ( m_match ) validate_one_of( f2 ); + if ( m_match ) validate_not( f2 ); + if ( m_match ) validate_schema_dependencies( f2 ); + } + + static bool is_multiple_of( const double v, const double d ) + { + const auto r = std::fmod( v, d ); + if ( std::fabs( r ) < std::numeric_limits< double >::epsilon() ) { + return true; + } + if ( std::fabs( r - d ) < std::numeric_limits< double >::epsilon() ) { + return true; + } + return false; + } + + void validate_multiple_of( const std::int64_t v ) + { + switch ( m_node->m_flags & HAS_MULTIPLE_OF ) { + case HAS_MULTIPLE_OF_UNSIGNED: + if ( v < 0 ) { + if ( ( -v % m_node->m_multiple_of.u ) != 0 ) { + m_match = false; + } + } + else { + if ( ( v % m_node->m_multiple_of.u ) != 0 ) { + m_match = false; + } + } + break; + case HAS_MULTIPLE_OF_DOUBLE: + if ( ! is_multiple_of( v, m_node->m_multiple_of.d ) ) { + m_match = false; + } + break; + } + } + + void validate_multiple_of( const std::uint64_t v ) + { + switch ( m_node->m_flags & HAS_MULTIPLE_OF ) { + case HAS_MULTIPLE_OF_UNSIGNED: + if ( ( v % m_node->m_multiple_of.u ) != 0 ) { + m_match = false; + } + break; + case HAS_MULTIPLE_OF_DOUBLE: + if ( ! is_multiple_of( v, m_node->m_multiple_of.d ) ) { + m_match = false; + } + break; + } + } + + void validate_multiple_of( const double v ) + { + switch ( m_node->m_flags & HAS_MULTIPLE_OF ) { + case HAS_MULTIPLE_OF_UNSIGNED: + if ( ! is_multiple_of( v, m_node->m_multiple_of.u ) ) { + m_match = false; + } + break; + case HAS_MULTIPLE_OF_DOUBLE: + if ( ! is_multiple_of( v, m_node->m_multiple_of.d ) ) { + m_match = false; + } + break; + } + } + + void validate_number( const std::int64_t v ) + { + validate_multiple_of( v ); + switch ( m_node->m_flags & ( HAS_MAXIMUM | EXCLUSIVE_MAXIMUM ) ) { + case HAS_MAXIMUM_SIGNED: + if ( v > m_node->m_maximum.i ) { + m_match = false; + } + break; + case HAS_MAXIMUM_SIGNED | EXCLUSIVE_MAXIMUM: + if ( v >= m_node->m_maximum.i ) { + m_match = false; + } + break; + case HAS_MAXIMUM_UNSIGNED: + if ( v >= 0 && static_cast< std::uint64_t >( v ) > m_node->m_maximum.u ) { + m_match = false; + } + break; + case HAS_MAXIMUM_UNSIGNED | EXCLUSIVE_MAXIMUM: + if ( v >= 0 && static_cast< std::uint64_t >( v ) >= m_node->m_maximum.u ) { + m_match = false; + } + break; + case HAS_MAXIMUM_DOUBLE: + if ( v > m_node->m_maximum.d ) { + m_match = false; + } + break; + case HAS_MAXIMUM_DOUBLE | EXCLUSIVE_MAXIMUM: + if ( v >= m_node->m_maximum.d ) { + m_match = false; + } + break; + } + switch ( m_node->m_flags & ( HAS_MINIMUM | EXCLUSIVE_MINIMUM ) ) { + case HAS_MINIMUM_SIGNED: + if ( v < m_node->m_minimum.i ) { + m_match = false; + } + break; + case HAS_MINIMUM_SIGNED | EXCLUSIVE_MINIMUM: + if ( v <= m_node->m_minimum.i ) { + m_match = false; + } + break; + case HAS_MINIMUM_UNSIGNED: + if ( v < 0 || static_cast< std::uint64_t >( v ) < m_node->m_minimum.u ) { + m_match = false; + } + break; + case HAS_MINIMUM_UNSIGNED | EXCLUSIVE_MINIMUM: + if ( v < 0 || static_cast< std::uint64_t >( v ) <= m_node->m_minimum.u ) { + m_match = false; + } + break; + case HAS_MINIMUM_DOUBLE: + if ( v < m_node->m_minimum.d ) { + m_match = false; + } + break; + case HAS_MINIMUM_DOUBLE | EXCLUSIVE_MINIMUM: + if ( v <= m_node->m_minimum.d ) { + m_match = false; + } + break; + } + } + + void validate_number( const std::uint64_t v ) + { + validate_multiple_of( v ); + switch ( m_node->m_flags & ( HAS_MAXIMUM | EXCLUSIVE_MAXIMUM ) ) { + case HAS_MAXIMUM_SIGNED: + if ( m_node->m_maximum.i < 0 || v > static_cast< std::uint64_t >( m_node->m_maximum.i ) ) { + m_match = false; + } + break; + case HAS_MAXIMUM_SIGNED | EXCLUSIVE_MAXIMUM: + if ( m_node->m_maximum.i < 0 || v >= static_cast< std::uint64_t >( m_node->m_maximum.i ) ) { + m_match = false; + } + break; + case HAS_MAXIMUM_UNSIGNED: + if ( v > m_node->m_maximum.u ) { + m_match = false; + } + break; + case HAS_MAXIMUM_UNSIGNED | EXCLUSIVE_MAXIMUM: + if ( v >= m_node->m_maximum.u ) { + m_match = false; + } + break; + case HAS_MAXIMUM_DOUBLE: + if ( v > m_node->m_maximum.d ) { + m_match = false; + } + break; + case HAS_MAXIMUM_DOUBLE | EXCLUSIVE_MAXIMUM: + if ( v >= m_node->m_maximum.d ) { + m_match = false; + } + break; + } + switch ( m_node->m_flags & ( HAS_MINIMUM | EXCLUSIVE_MINIMUM ) ) { + case HAS_MINIMUM_SIGNED: + if ( m_node->m_minimum.i >= 0 && v < static_cast< std::uint64_t >( m_node->m_minimum.i ) ) { + m_match = false; + } + break; + case HAS_MINIMUM_SIGNED | EXCLUSIVE_MINIMUM: + if ( m_node->m_minimum.i >= 0 && v <= static_cast< std::uint64_t >( m_node->m_minimum.i ) ) { + m_match = false; + } + break; + case HAS_MINIMUM_UNSIGNED: + if ( v < m_node->m_minimum.u ) { + m_match = false; + } + break; + case HAS_MINIMUM_UNSIGNED | EXCLUSIVE_MINIMUM: + if ( v <= m_node->m_minimum.u ) { + m_match = false; + } + break; + case HAS_MINIMUM_DOUBLE: + if ( v < m_node->m_minimum.d ) { + m_match = false; + } + break; + case HAS_MINIMUM_DOUBLE | EXCLUSIVE_MINIMUM: + if ( v <= m_node->m_minimum.d ) { + m_match = false; + } + break; + } + } + + void validate_number( const double v ) + { + validate_multiple_of( v ); + switch ( m_node->m_flags & ( HAS_MAXIMUM | EXCLUSIVE_MAXIMUM ) ) { + case HAS_MAXIMUM_SIGNED: + if ( v > m_node->m_maximum.i ) { + m_match = false; + } + break; + case HAS_MAXIMUM_SIGNED | EXCLUSIVE_MAXIMUM: + if ( v >= m_node->m_maximum.i ) { + m_match = false; + } + break; + case HAS_MAXIMUM_UNSIGNED: + if ( v > m_node->m_maximum.u ) { + m_match = false; + } + break; + case HAS_MAXIMUM_UNSIGNED | EXCLUSIVE_MAXIMUM: + if ( v >= m_node->m_maximum.u ) { + m_match = false; + } + break; + case HAS_MAXIMUM_DOUBLE: + if ( v > m_node->m_maximum.d ) { + m_match = false; + } + break; + case HAS_MAXIMUM_DOUBLE | EXCLUSIVE_MAXIMUM: + if ( v >= m_node->m_maximum.d ) { + m_match = false; + } + break; + } + switch ( m_node->m_flags & ( HAS_MINIMUM | EXCLUSIVE_MINIMUM ) ) { + case HAS_MINIMUM_SIGNED: + if ( v < m_node->m_minimum.i ) { + m_match = false; + } + break; + case HAS_MINIMUM_SIGNED | EXCLUSIVE_MINIMUM: + if ( v <= m_node->m_minimum.i ) { + m_match = false; + } + break; + case HAS_MINIMUM_UNSIGNED: + if ( v < m_node->m_minimum.u ) { + m_match = false; + } + break; + case HAS_MINIMUM_UNSIGNED | EXCLUSIVE_MINIMUM: + if ( v <= m_node->m_minimum.u ) { + m_match = false; + } + break; + case HAS_MINIMUM_DOUBLE: + if ( v < m_node->m_minimum.d ) { + m_match = false; + } + break; + case HAS_MINIMUM_DOUBLE | EXCLUSIVE_MINIMUM: + if ( v <= m_node->m_minimum.d ) { + m_match = false; + } + break; + } + } + + void validate_string( const std::string & v ) + { + if ( m_node->m_flags & HAS_MAX_LENGTH && v.size() > m_node->m_max_length ) { + m_match = false; + } + if ( m_node->m_flags & HAS_MIN_LENGTH && v.size() < m_node->m_min_length ) { + m_match = false; + } + if ( m_match && m_node->m_pattern ) { + if ( ! std::regex_search( v, * m_node->m_pattern ) ) { + m_match = false; + } + } + if ( m_match && m_node->m_format != schema_format::NONE ) { + switch ( m_node->m_format ) { + case schema_format::DATE_TIME: + if ( ! internal::parse_date_time( v ) ) { + m_match = false; + } + break; + case schema_format::EMAIL: + if ( ( v.size() > 255 ) || ! internal::parse< internal::email >( v ) ) { + m_match = false; + } + break; + case schema_format::HOSTNAME: + if ( ( v.size() > 255 ) || ! internal::parse< internal::hostname >( v ) ) { + m_match = false; + } + break; + case schema_format::IPV4: + if ( ! internal::parse< tao_json_pegtl::uri::IPv4address >( v ) ) { + m_match = false; + } + break; + case schema_format::IPV6: + if ( ! internal::parse< tao_json_pegtl::uri::IPv6address >( v ) ) { + m_match = false; + } + break; + case schema_format::URI: + // TODO: What rule exactly should we apply here?? JSON Schema is not exactly the best spec I've ever read... + if ( ! internal::parse< tao_json_pegtl::uri::URI >( v ) ) { + m_match = false; + } + break; + case schema_format::NONE: + ; + } + } + } + + void validate_elements( const std::size_t v ) + { + if ( m_node->m_flags & HAS_MAX_ITEMS && v > m_node->m_max_items ) { + m_match = false; + } + if ( m_node->m_flags & HAS_MIN_ITEMS && v < m_node->m_min_items ) { + m_match = false; + } + } + + void validate_members( const std::size_t v ) + { + if ( m_node->m_flags & HAS_MAX_PROPERTIES && v > m_node->m_max_properties ) { + m_match = false; + } + if ( m_node->m_flags & HAS_MIN_PROPERTIES && v < m_node->m_min_properties ) { + m_match = false; + } + } + + public: + schema_consumer( const std::shared_ptr< const schema_container< Traits > > & c, const schema_node< Traits > & n ) + : m_container( c ), + m_node( & n ) + { + if ( m_node->m_flags & HAS_ENUM ) { + const auto & a = m_node->m_value->unsafe_at( "enum" ).unsafe_get_array(); + m_enum.reserve( a.size() ); + for ( const auto & e : a ) { + m_enum.emplace_back( new sax_compare< Traits >() ); + m_enum.back()->push( & e ); + } + } + if ( const auto * p = m_node->m_all_of ) { + for ( const auto & e : p->unsafe_get_array() ) { + m_all_of.push_back( m_container->consumer( e.skip_raw_ptr() ) ); + } + } + if ( const auto * p = m_node->m_any_of ) { + for ( const auto & e : p->unsafe_get_array() ) { + m_any_of.push_back( m_container->consumer( e.skip_raw_ptr() ) ); + } + } + if ( const auto * p = m_node->m_one_of ) { + for ( const auto & e : p->unsafe_get_array() ) { + m_one_of.push_back( m_container->consumer( e.skip_raw_ptr() ) ); + } + } + if ( const auto * p = m_node->m_not ) { + m_not = m_container->consumer( p ); + } + for ( const auto & e : m_node->m_schema_dependencies ) { + m_schema_dependencies.emplace( e.first, m_container->consumer( e.second ) ); + } + } + + schema_consumer( const schema_consumer & ) = delete; + schema_consumer( schema_consumer && ) = delete; + + void operator= ( const schema_consumer & ) = delete; + void operator= ( schema_consumer && ) = delete; + + bool finalize() + { + if ( m_match && ! m_all_of.empty() ) { + for ( auto & e : m_all_of ) { + if ( ! e->finalize() ) { + m_match = false; + break; + } + } + } + if ( m_match && ! m_any_of.empty() ) { + m_any_of.erase( std::remove_if( m_any_of.begin(), m_any_of.end(), []( const std::unique_ptr< schema_consumer > & c ){ return ! c->finalize(); } ), m_any_of.end() ); + if ( m_any_of.empty() ) { + m_match = false; + } + } + if ( m_match && ! m_one_of.empty() ) { + m_one_of.erase( std::remove_if( m_one_of.begin(), m_one_of.end(), []( const std::unique_ptr< schema_consumer > & c ){ return ! c->finalize(); } ), m_one_of.end() ); + if ( m_one_of.size() != 1 ) { + m_match = false; + } + } + if ( m_match && m_not && m_not->finalize() ) { + m_match = false; + } + if ( m_match && m_node->m_flags & HAS_DEPENDENCIES ) { + for ( const auto & e : m_node->m_schema_dependencies ) { + if ( m_keys.find( e.first ) != m_keys.end() ) { + const auto it = m_schema_dependencies.find( e.first ); + if ( it == m_schema_dependencies.end() ) { + m_match = false; + break; + } + if ( ! it->second->finalize() ) { + m_match = false; + break; + } + } + } + } + return m_match; + } + + bool match() const noexcept + { + return m_match; + } + + void null() + { + if ( m_match ) validate_type( NULL_ ); + if ( m_match ) validate_enum( []( sax_compare< Traits > & c ){ c.null(); return ! c.match(); } ); + if ( m_match ) validate_collections( []( schema_consumer & c ){ c.null(); return ! c.match(); } ); + if ( m_match && m_hash ) m_hash->null(); + } + + void boolean( const bool v ) + { + if ( m_match ) validate_type( BOOLEAN ); + if ( m_match ) validate_enum( [=]( sax_compare< Traits > & c ){ c.boolean( v ); return ! c.match(); } ); + if ( m_match ) validate_collections( [=]( schema_consumer & c ){ c.boolean( v ); return ! c.match(); } ); + if ( m_match && m_hash ) m_hash->boolean( v ); + } + + void number( const std::int64_t v ) + { + if ( m_match ) validate_type( INTEGER | NUMBER ); + if ( m_match ) validate_enum( [=]( sax_compare< Traits > & c ){ c.number( v ); return ! c.match(); } ); + if ( m_match ) validate_collections( [=]( schema_consumer & c ){ c.number( v ); return ! c.match(); } ); + if ( m_match && m_count.empty() ) validate_number( v ); + if ( m_match && m_hash ) m_hash->number( v ); + } + + void number( const std::uint64_t v ) + { + if ( m_match ) validate_type( INTEGER | NUMBER ); + if ( m_match ) validate_enum( [=]( sax_compare< Traits > & c ){ c.number( v ); return ! c.match(); } ); + if ( m_match ) validate_collections( [=]( schema_consumer & c ){ c.number( v ); return ! c.match(); } ); + if ( m_match && m_count.empty() ) validate_number( v ); + if ( m_match && m_hash ) m_hash->number( v ); + } + + void number( const double v ) + { + if ( m_match ) validate_type( NUMBER ); + if ( m_match ) validate_enum( [=]( sax_compare< Traits > & c ){ c.number( v ); return ! c.match(); } ); + if ( m_match ) validate_collections( [=]( schema_consumer & c ){ c.number( v ); return ! c.match(); } ); + if ( m_match && m_count.empty() ) validate_number( v ); + if ( m_match && m_hash ) m_hash->number( v ); + } + + void string( const std::string & v ) + { + if ( m_match ) validate_type( STRING ); + if ( m_match ) validate_enum( [&]( sax_compare< Traits > & c ){ c.string( v ); return ! c.match(); } ); + if ( m_match ) validate_collections( [&]( schema_consumer & c ){ c.string( v ); return ! c.match(); } ); + if ( m_match && m_count.empty() ) validate_string( v ); + if ( m_match && m_hash ) m_hash->string( v ); + } + + // array + void begin_array() + { + if ( m_match ) validate_type( ARRAY ); + if ( m_match ) validate_enum( []( sax_compare< Traits > & c ){ c.begin_array(); return ! c.match(); } ); + if ( m_match ) validate_collections( []( schema_consumer & c ){ c.begin_array(); return ! c.match(); } ); + if ( m_match ) { + if ( m_hash ) { + m_hash->begin_array(); + } + else if ( m_count.empty() && ( ( m_node->m_flags & HAS_UNIQUE_ITEMS ) != 0 ) ) { + m_hash.reset( new sax::hash ); + } + } + if ( m_match && m_count.empty() ) { + if ( const auto * p = m_node->m_items ) { + if ( p->is_object() ) { + m_item = m_container->consumer( p ); + } + else { + const auto & a = p->unsafe_get_array(); + if ( ! a.empty() ) { + m_item = m_container->consumer( a[ 0 ].skip_raw_ptr() ); + } + } + } + if ( ! m_item ) { + if ( const auto * p = m_node->m_additional_items ) { + if ( p->is_object() ) { + m_item = m_container->consumer( p ); + } + } + } + } + m_count.push_back( 0 ); + } + + void element() + { + if ( m_match ) validate_enum( []( sax_compare< Traits > & c ){ c.element(); return ! c.match(); } ); + if ( m_match && m_item ) { + if ( m_count.size() == 1 ) { + if ( ! m_item->finalize() ) { + m_match = false; + } + m_item.reset(); + } + } + if ( m_match ) validate_collections( []( schema_consumer & c ){ c.element(); return ! c.match(); } ); + if ( m_match && m_hash ) { + if ( m_count.size() == 1 ) { + if ( ! m_unique.emplace( m_hash->value() ).second ) { + m_match = false; + } + m_hash->reset(); + } + else { + m_hash->element(); + } + } + const auto next = ++m_count.back(); + if ( m_match && ( m_count.size() == 1 ) ) { + if ( const auto * p = m_node->m_items ) { + if ( p->is_object() ) { + m_item = m_container->consumer( p ); + } + else { + const auto & a = p->unsafe_get_array(); + if ( next < a.size() ) { + m_item = m_container->consumer( a[ next ].skip_raw_ptr() ); + } + } + } + if ( ! m_item ) { + if ( const auto * p = m_node->m_additional_items ) { + if ( p->is_object() ) { + m_item = m_container->consumer( p ); + } + } + } + } + } + + void end_array() + { + if ( m_match ) validate_enum( []( sax_compare< Traits > & c ){ c.end_array(); return ! c.match(); } ); + if ( m_match && m_item && ( m_count.size() == 1 ) ) { + if ( ! m_item->finalize() ) { + m_match = false; + } + m_item.reset(); + } + if ( m_match && ( m_count.size() == 1 ) ) { + if ( m_node->m_items && m_node->m_items->is_array() ) { + if ( m_node->m_additional_items && m_node->m_additional_items->is_boolean() ) { + if ( ! m_node->m_additional_items->get_boolean() ) { + if ( m_count.back() > m_node->m_items->unsafe_get_array().size() ) { + m_match = false; + } + } + } + } + } + if ( m_match ) validate_collections( []( schema_consumer & c ){ c.end_array(); return ! c.match(); } ); + if ( m_match && m_hash ) m_hash->end_array(); + if ( m_match && ( m_count.size() == 1 ) ) validate_elements( m_count.back() ); + m_count.pop_back(); + } + + // object + void begin_object() + { + if ( m_match ) validate_type( OBJECT ); + if ( m_match ) validate_enum( []( sax_compare< Traits > & c ){ c.begin_object(); return ! c.match(); } ); + if ( m_match ) validate_collections( []( schema_consumer & c ){ c.begin_object(); return ! c.match(); } ); + if ( m_match && m_hash ) m_hash->begin_object(); + m_count.push_back( 0 ); + } + + void key( const std::string & v ) + { + if ( m_match ) validate_enum( [&]( sax_compare< Traits > & c ){ c.key( v ); return ! c.match(); } ); + if ( m_match ) validate_collections( [&]( schema_consumer & c ){ c.key( v ); return ! c.match(); } ); + if ( m_match && m_hash ) m_hash->key( v ); + if ( m_match && ( m_count.size() == 1 ) && ( m_node->m_flags & HAS_DEPENDENCIES || ! m_node->m_required.empty() ) ) { + if ( ! m_keys.insert( v ).second ) { + // duplicate keys immediately invalidate! + // TODO: throw? + m_match = false; + } + } + if ( m_match && m_properties.empty() && ( m_count.size() == 1 ) ) { + if ( const auto * p = m_node->m_properties ) { + const auto & o = p->unsafe_get_object(); + const auto it = o.find( v ); + if ( it != o.end() ) { + m_properties.push_back( m_container->consumer( it->second.skip_raw_ptr() ) ); + } + } + for ( const auto & e : m_node->m_pattern_properties ) { + if ( std::regex_search( v, e.first ) ) { + m_properties.push_back( m_container->consumer( e.second ) ); + } + } + if ( m_properties.empty() ) { + if ( const auto * p = m_node->m_additional_properties ) { + if ( p->is_boolean() ) { + if ( ! p->unsafe_get_boolean() ) { + m_match = false; + } + } + else { + m_properties.push_back( m_container->consumer( p ) ); + } + } + } + } + } + + void member() + { + if ( m_match ) validate_enum( []( sax_compare< Traits > & c ){ c.member(); return ! c.match(); } ); + if ( m_match && ! m_properties.empty() && ( m_count.size() == 1 ) ) { + for ( auto & e : m_properties ) { + if ( ! e->finalize() ) { + m_match = false; + break; + } + } + m_properties.clear(); + } + if ( m_match ) validate_collections( []( schema_consumer & c ){ c.member(); return ! c.match(); } ); + if ( m_match && m_hash ) m_hash->member(); + ++m_count.back(); + } + + void end_object() + { + if ( m_match ) validate_enum( []( sax_compare< Traits > & c ){ c.end_object(); return ! c.match(); } ); + if ( m_match ) validate_collections( []( schema_consumer & c ){ c.end_object(); return ! c.match(); } ); + if ( m_match && m_hash ) m_hash->end_object(); + if ( m_match && ( m_count.size() == 1 ) ) validate_members( m_count.back() ); + if ( m_match && ( m_count.size() == 1 ) && ! m_node->m_required.empty() ) { + if ( ! std::includes( m_keys.begin(), m_keys.end(), m_node->m_required.begin(), m_node->m_required.end() ) ) { + m_match = false; + } + } + if ( m_match && ( m_count.size() == 1 ) && m_node->m_flags & HAS_DEPENDENCIES ) { + for ( const auto & e : m_node->m_property_dependencies ) { + if ( m_keys.find( e.first ) != m_keys.end() ) { + if ( ! std::includes( m_keys.begin(), m_keys.end(), e.second.begin(), e.second.end() ) ) { + m_match = false; + break; + } + } + } + } + m_count.pop_back(); + } + }; + + template< template< typename ... > class Traits > + class schema_container + : public std::enable_shared_from_this< schema_container< Traits > > + { + private: + basic_value< Traits > m_value; + + using nodes_t = std::map< const basic_value< Traits > *, std::unique_ptr< schema_node< Traits > > >; + nodes_t m_nodes; + + void make_node( const basic_value< Traits > * p ) + { + m_nodes.emplace( p, std::unique_ptr< schema_node< Traits > >( new schema_node< Traits >( this, * p ) ) ); + } + + public: + explicit schema_container( const basic_value< Traits > & v ) + : m_value( * v.skip_raw_ptr() ) + { + resolve_references( m_value ); + make_node( & m_value ); + while ( true ) { + std::set< const basic_value< Traits > * > required; + for ( const auto & e : m_nodes ) { + auto s = e.second->referenced_pointers(); + required.insert( s.begin(), s.end() ); + } + for ( const auto & e : m_nodes ) { + required.erase( e.first ); + } + if ( required.empty() ) { + break; + } + for ( const auto & e : required ) { + make_node( e ); + } + } + } + + std::unique_ptr< schema_consumer< Traits > > consumer( const basic_value< Traits > * p ) const + { + const auto it = m_nodes.find( p ); + if ( it == m_nodes.end() ) { + throw std::logic_error( "invalid node ptr, no schema registered" ); + } + return std::unique_ptr< schema_consumer< Traits > >( new schema_consumer< Traits >( this->shared_from_this(), * it->second ) ); + } + + std::unique_ptr< schema_consumer< Traits > > consumer() const + { + return consumer( & m_value ); + } + }; + + } // internal + + template< template< typename ... > class Traits > + class basic_schema + { + private: + const std::shared_ptr< const internal::schema_container< Traits > > m_container; + + public: + explicit basic_schema( const basic_value< Traits > & v ) + : m_container( std::make_shared< internal::schema_container< Traits > >( v ) ) + { } + + std::unique_ptr< internal::schema_consumer< Traits > > consumer() const + { + return m_container->consumer(); + } + + bool validate( const basic_value< Traits > & v ) const + { + // TODO: DOM validation should be implemented independently, + // as it could be more efficient than SAX validation! + const auto c = consumer(); + sax::from_value( v, * c ); + return c->finalize(); + } + }; + + using schema = basic_schema< traits >; + + template< template< typename ... > class Traits > + basic_schema< Traits > make_schema( const basic_value< Traits > & v ) + { + return basic_schema< Traits >( v ); + } + + } // json + +} // tao + +#endif diff --git a/share/include/tao/json/self_contained.hh b/share/include/tao/json/self_contained.hh new file mode 100644 index 0000000..5d7250a --- /dev/null +++ b/share/include/tao/json/self_contained.hh @@ -0,0 +1,100 @@ +// Copyright (c) 2016 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/taocpp/json/ + +#ifndef TAOCPP_JSON_INCLUDE_SELF_CONTAINED_HH +#define TAOCPP_JSON_INCLUDE_SELF_CONTAINED_HH + +#include "value.hh" + +namespace tao +{ + namespace json + { + // recursively checks for the existence if RAW_PTR nodes, + // returns true is no RAW_PTR nodes were found. + template< template< typename ... > class Traits > + bool is_self_contained( basic_value< Traits > & v ) noexcept + { + switch ( v.type() ) { + case type::UNINITIALIZED: + return true; + case type::DISCARDED: + // LCOV_EXCL_START + assert( v.type() != type::DISCARDED ); + return false; + // LCOV_EXCL_STOP + case type::NULL_: + case type::BOOLEAN: + case type::SIGNED: + case type::UNSIGNED: + case type::DOUBLE: + case type::STRING: + return true; + case type::ARRAY: + for ( auto & e : v.unsafe_get_array() ) { + if ( ! is_self_contained( e ) ) { + return false; + } + } + return true; + case type::OBJECT: + for ( auto & e : v.unsafe_get_object() ) { + if ( ! is_self_contained( e.second ) ) { + return false; + } + } + return true; + case type::RAW_PTR: + return false; + } + // LCOV_EXCL_START + assert( false ); + return false; + // LCOV_EXCL_STOP + } + + // removes all RAW_PTR nodes, recursively, by copying their pointed-to content + // or replacing a nullptr RAW_PTR node with a null node. + template< template< typename ... > class Traits > + void make_self_contained( basic_value< Traits > & v ) + { + switch ( v.type() ) { + case type::UNINITIALIZED: + return; + case type::DISCARDED: + throw std::logic_error( "attempt to use a discarded value" ); + case type::NULL_: + case type::BOOLEAN: + case type::SIGNED: + case type::UNSIGNED: + case type::DOUBLE: + case type::STRING: + return; + case type::ARRAY: + for ( auto & e : v.unsafe_get_array() ) { + make_self_contained( e ); + } + return; + case type::OBJECT: + for ( auto & e : v.unsafe_get_object() ) { + make_self_contained( e.second ); + } + return; + case type::RAW_PTR: + if ( const auto * p = v.unsafe_get_raw_ptr() ) { + v = * p; + make_self_contained( v ); + } + else { + v = null; + } + return; + } + throw std::logic_error( "invalid value for tao::json::type" ); // LCOV_EXCL_LINE + } + + } // json + +} // tao + +#endif diff --git a/share/include/tao/json/single.hh b/share/include/tao/json/single.hh new file mode 100644 index 0000000..df84a6b --- /dev/null +++ b/share/include/tao/json/single.hh @@ -0,0 +1,35 @@ +// Copyright (c) 2016 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/taocpp/json/ + +#ifndef TAOCPP_JSON_INCLUDE_SINGLE_HH +#define TAOCPP_JSON_INCLUDE_SINGLE_HH + +#include + +#include "pair.hh" + +namespace tao +{ + namespace json + { + template< template< typename ... > class > + class basic_value; + + template< template< typename ... > class Traits > + struct single + { + mutable basic_value< Traits > value; + + template< typename U > + single( U && v ) : value( std::forward< U >( v ) ) {} + + single( std::initializer_list< pair< Traits > > && l ) : value( std::move( l ) ) {} + single( const std::initializer_list< pair< Traits > > & l ) : value( l ) {} + single( std::initializer_list< pair< Traits > > & l ) : value( l ) {} + }; + + } // json + +} // tao + +#endif diff --git a/share/include/tao/json/stream.hh b/share/include/tao/json/stream.hh new file mode 100644 index 0000000..31792e4 --- /dev/null +++ b/share/include/tao/json/stream.hh @@ -0,0 +1,39 @@ +// Copyright (c) 2015-2016 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/taocpp/json/ + +#ifndef TAOCPP_JSON_INCLUDE_STREAM_HH +#define TAOCPP_JSON_INCLUDE_STREAM_HH + +#include +#include + +#include "value.hh" +#include "to_stream.hh" + +namespace tao +{ + namespace json + { + // Use ostream << std::setw( n ) for pretty-printing with indent n. + + template< template< typename ... > class Traits > + std::ostream & operator<< ( std::ostream & o, const basic_value< Traits > & v ) + { + const auto w = o.width(); + + o.width( 0 ); + + if ( w > 0 ) { + json::to_stream( o, v, w ); + } + else { + json::to_stream( o, v ); + } + return o; + } + + } // json + +} // tao + +#endif diff --git a/share/include/tao/json/to_stream.hh b/share/include/tao/json/to_stream.hh new file mode 100644 index 0000000..ad0c79a --- /dev/null +++ b/share/include/tao/json/to_stream.hh @@ -0,0 +1,37 @@ +// Copyright (c) 2015-2016 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/taocpp/json/ + +#ifndef TAOCPP_JSON_INCLUDE_TO_STREAM_HH +#define TAOCPP_JSON_INCLUDE_TO_STREAM_HH + +#include +#include + +#include "value.hh" +#include "sax/from_value.hh" +#include "sax/to_stream.hh" +#include "sax/to_pretty_stream.hh" + +namespace tao +{ + namespace json + { + template< template< typename ... > class Traits > + void to_stream( std::ostream & os, const basic_value< Traits > & v ) + { + sax::to_stream consumer( os ); + sax::from_value( v, consumer ); + } + + template< template< typename ... > class Traits > + void to_stream( std::ostream & os, const basic_value< Traits > & v, const std::size_t indent ) + { + sax::to_pretty_stream consumer( os, indent ); + sax::from_value( v, consumer ); + } + + } // json + +} // tao + +#endif diff --git a/share/include/tao/json/to_string.hh b/share/include/tao/json/to_string.hh new file mode 100644 index 0000000..342e9a0 --- /dev/null +++ b/share/include/tao/json/to_string.hh @@ -0,0 +1,36 @@ +// Copyright (c) 2015-2016 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/taocpp/json/ + +#ifndef TAOCPP_JSON_INCLUDE_TO_STRING_HH +#define TAOCPP_JSON_INCLUDE_TO_STRING_HH + +#include + +#include "value.hh" +#include "to_stream.hh" + +namespace tao +{ + namespace json + { + template< template< typename ... > class Traits > + std::string to_string( const basic_value< Traits > & v ) + { + std::ostringstream o; + json::to_stream( o, v ); + return o.str(); + } + + template< template< typename ... > class Traits > + std::string to_string( const basic_value< Traits > & v, const unsigned indent ) + { + std::ostringstream o; + json::to_stream( o, v, indent ); + return o.str(); + } + + } // json + +} // tao + +#endif diff --git a/share/include/tao/json/traits.hh b/share/include/tao/json/traits.hh new file mode 100644 index 0000000..b0f7363 --- /dev/null +++ b/share/include/tao/json/traits.hh @@ -0,0 +1,410 @@ +// Copyright (c) 2016 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/taocpp/json/ + +#ifndef TAOCPP_JSON_INCLUDE_TRAITS_HH +#define TAOCPP_JSON_INCLUDE_TRAITS_HH + +#include +#include +#include + +#include "type.hh" + +namespace tao +{ + namespace json + { + template< template< typename ... > class Traits > + class basic_value; + + // note: traits< ... >::assign() is always called with needs_discard(v) == false + + template< typename T, typename = void > + struct traits + { + static_assert( sizeof( T ) == 0, "no traits specialization found" ); + + template< typename V, typename U > + static void assign( V &, U && ); + }; + + template<> + struct traits< null_t > + { + template< template< typename ... > class Traits > + static void assign( basic_value< Traits > & v, null_t ) noexcept + { + v.unsafe_assign_null(); + } + }; + + template<> + struct traits< bool > + { + template< template< typename ... > class Traits > + static void assign( basic_value< Traits > & v, const bool b ) noexcept + { + v.unsafe_assign_bool( b ); + } + + template< template< typename ... > class Traits > + static void extract( const basic_value< Traits > & v, bool & b ) + { + b = v.get_boolean(); + } + }; + + namespace internal + { + template< template< typename ... > class Traits, typename T > + void unchecked_extract_number( const basic_value< Traits > & v, T & i ) + { + switch( v.type() ) { + case type::SIGNED: + i = v.unsafe_get_signed(); + break; + case type::UNSIGNED: + i = v.unsafe_get_unsigned(); + break; + case type::DOUBLE: + i = v.unsafe_get_double(); + break; + default: + TAOCPP_JSON_THROW_TYPE_ERROR( v.type() ); + } + } + } + + template<> + struct traits< signed char > + { + template< template< typename ... > class Traits > + static void assign( basic_value< Traits > & v, const signed char i ) noexcept + { + v.unsafe_assign_signed( i ); + } + + template< template< typename ... > class Traits > + static void extract( const basic_value< Traits > & v, signed char & i ) + { + internal::unchecked_extract_number( v, i ); + } + }; + + template<> + struct traits< unsigned char > + { + template< template< typename ... > class Traits > + static void assign( basic_value< Traits > & v, const unsigned char i ) noexcept + { + v.unsafe_assign_unsigned( i ); + } + + template< template< typename ... > class Traits > + static void extract( const basic_value< Traits > & v, unsigned char & i ) + { + internal::unchecked_extract_number( v, i ); + } + }; + + template<> + struct traits< signed short > + { + template< template< typename ... > class Traits > + static void assign( basic_value< Traits > & v, const signed short i ) noexcept + { + v.unsafe_assign_signed( i ); + } + + template< template< typename ... > class Traits > + static void extract( const basic_value< Traits > & v, signed short & i ) + { + internal::unchecked_extract_number( v, i ); + } + }; + + template<> + struct traits< unsigned short > + { + template< template< typename ... > class Traits > + static void assign( basic_value< Traits > & v, const unsigned short i ) noexcept + { + v.unsafe_assign_unsigned( i ); + } + + template< template< typename ... > class Traits > + static void extract( const basic_value< Traits > & v, unsigned short & i ) + { + internal::unchecked_extract_number( v, i ); + } + }; + + template<> + struct traits< signed int > + { + template< template< typename ... > class Traits > + static void assign( basic_value< Traits > & v, const signed int i ) noexcept + { + v.unsafe_assign_signed( i ); + } + + template< template< typename ... > class Traits > + static void extract( const basic_value< Traits > & v, signed int & i ) + { + internal::unchecked_extract_number( v, i ); + } + }; + + template<> + struct traits< unsigned int > + { + template< template< typename ... > class Traits > + static void assign( basic_value< Traits > & v, const unsigned int i ) noexcept + { + v.unsafe_assign_unsigned( i ); + } + + template< template< typename ... > class Traits > + static void extract( const basic_value< Traits > & v, unsigned int & i ) + { + internal::unchecked_extract_number( v, i ); + } + }; + + template<> + struct traits< signed long > + { + template< template< typename ... > class Traits > + static void assign( basic_value< Traits > & v, const signed long i ) noexcept + { + v.unsafe_assign_signed( i ); + } + + template< template< typename ... > class Traits > + static void extract( const basic_value< Traits > & v, signed long & i ) + { + internal::unchecked_extract_number( v, i ); + } + }; + + template<> + struct traits< unsigned long > + { + template< template< typename ... > class Traits > + static void assign( basic_value< Traits > & v, const unsigned long i ) noexcept + { + v.unsafe_assign_unsigned( i ); + } + + template< template< typename ... > class Traits > + static void extract( const basic_value< Traits > & v, unsigned long & i ) + { + internal::unchecked_extract_number( v, i ); + } + }; + + template<> + struct traits< signed long long > + { + template< template< typename ... > class Traits > + static void assign( basic_value< Traits > & v, const signed long long i ) noexcept + { + v.unsafe_assign_signed( i ); + } + + template< template< typename ... > class Traits > + static void extract( const basic_value< Traits > & v, signed long long & i ) + { + internal::unchecked_extract_number( v, i ); + } + }; + + template<> + struct traits< unsigned long long > + { + template< template< typename ... > class Traits > + static void assign( basic_value< Traits > & v, const unsigned long long i ) noexcept + { + v.unsafe_assign_unsigned( i ); + } + + template< template< typename ... > class Traits > + static void extract( const basic_value< Traits > & v, unsigned long long & i ) + { + internal::unchecked_extract_number( v, i ); + } + }; + + template<> + struct traits< float > + { + template< template< typename ... > class Traits > + static void assign( basic_value< Traits > & v, const float f ) + { + v.unsafe_assign_double( f ); + } + + template< template< typename ... > class Traits > + static void extract( const basic_value< Traits > & v, float & f ) + { + internal::unchecked_extract_number( v, f ); + } + }; + + template<> + struct traits< double > + { + template< template< typename ... > class Traits > + static void assign( basic_value< Traits > & v, const double d ) + { + v.unsafe_assign_double( d ); + } + + template< template< typename ... > class Traits > + static void extract( const basic_value< Traits > & v, double & f ) + { + internal::unchecked_extract_number( v, f ); + } + }; + + template<> + struct traits< empty_array_t > + { + template< template< typename ... > class Traits > + static void assign( basic_value< Traits > & v, empty_array_t ) + { + v.unsafe_emplace_array(); + } + }; + + template<> + struct traits< empty_object_t > + { + template< template< typename ... > class Traits > + static void assign( basic_value< Traits > & v, empty_object_t ) + { + v.unsafe_emplace_object(); + } + }; + + template<> + struct traits< std::string > + { + template< template< typename ... > class Traits, typename T > + static void assign( basic_value< Traits > & v, T && s ) + { + v.unsafe_emplace_string( std::forward< T >( s ) ); + } + + template< template< typename ... > class Traits > + static void extract( const basic_value< Traits > & v, std::string & s ) + { + s = v.get_string(); + } + }; + + template<> + struct traits< const std::string & > + { + template< template< typename ... > class Traits > + static const std::string & extract( const basic_value< Traits > & v ) + { + return v.get_string(); + } + }; + + template<> + struct traits< const char * > + { + template< template< typename ... > class Traits > + static void assign( basic_value< Traits > & v, const char * s ) + { + v.unsafe_emplace_string( s ); + } + + template< template< typename ... > class Traits > + static const char * extract( const basic_value< Traits > & v ) + { + return v.get_string().c_str(); + } + }; + + template< template< typename ... > class Traits > + struct traits< std::vector< basic_value< Traits > > > + { + template< typename T > + static void assign( basic_value< Traits > & v, T && a ) + { + v.unsafe_emplace_array( std::forward< T >( a ) ); + } + }; + + template< template< typename ... > class Traits > + struct traits< std::map< std::string, basic_value< Traits > > > + { + template< typename T > + static void assign( basic_value< Traits > & v, T && o ) + { + v.unsafe_emplace_object( std::forward< T >( o ) ); + } + }; + + template< template< typename ... > class Traits > + struct traits< const basic_value< Traits > * > + { + static void assign( basic_value< Traits > & v, const basic_value< Traits > * p ) noexcept + { + v.unsafe_assign_pointer( p ); + } + }; + + template< template< typename ... > class Traits > + struct traits< basic_value< Traits > * > + { + static void assign( basic_value< Traits > & v, const basic_value< Traits > * p ) noexcept + { + v.unsafe_assign_pointer( p ); + } + }; + + template<> + struct traits< std::nullptr_t > + { + template< template< typename ... > class Traits > + static void assign( basic_value< Traits > & v, std::nullptr_t ) noexcept + { + v.unsafe_assign_pointer( nullptr ); + } + }; + + template< typename T > + struct traits< optional< T > > + { + template< template< typename ... > class Traits > + static void assign( basic_value< Traits > & v, const optional< T > & o ) noexcept + { + if( o ) { + v = * o; + } + else { + v = null; + } + } + + template< template< typename ... > class Traits > + static void extract( const basic_value< Traits > & v, optional< T > & o ) + { + if( v.is_null() ) { + o = nullopt; + } + else { + o = v.template as< T >(); + } + } + }; + + } // json + +} // tao + +#endif diff --git a/share/include/tao/json/type.hh b/share/include/tao/json/type.hh new file mode 100644 index 0000000..8337c0f --- /dev/null +++ b/share/include/tao/json/type.hh @@ -0,0 +1,83 @@ +// Copyright (c) 2015-2017 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/taocpp/json/ + +#ifndef TAOCPP_JSON_INCLUDE_TYPE_HH +#define TAOCPP_JSON_INCLUDE_TYPE_HH + +#include + +#include "external/operators.hpp" + +namespace tao +{ + namespace json + { + enum class type : std::uint8_t + { + UNINITIALIZED, + DISCARDED, + NULL_, + BOOLEAN, + SIGNED, + UNSIGNED, + DOUBLE, + STRING, + ARRAY, + OBJECT, + RAW_PTR + }; + + inline bool needs_discard( const type t ) + { + switch ( t ) { + case type::STRING: + case type::ARRAY: + case type::OBJECT: + return true; + default: + return false; + } + } + + inline const char * to_string( const type t ) + { + switch ( t ) { + case type::UNINITIALIZED: + return "uninitialized"; + case type::DISCARDED: + return "discarded"; + case type::NULL_: + return "null"; + case type::BOOLEAN: + return "boolean"; + case type::SIGNED: + return "signed"; + case type::UNSIGNED: + return "unsigned"; + case type::DOUBLE: + return "double"; + case type::STRING: + return "string"; + case type::ARRAY: + return "array"; + case type::OBJECT: + return "object"; + case type::RAW_PTR: + return "raw_ptr"; + } + return "unknown"; + } + + struct null_t { constexpr explicit null_t( int ) {} }; + struct empty_array_t { constexpr explicit empty_array_t( int ) {} }; + struct empty_object_t { constexpr explicit empty_object_t( int ) {} }; + + constexpr null_t null { 0 }; + constexpr empty_array_t empty_array { 0 }; + constexpr empty_object_t empty_object { 0 }; + + } // json + +} // tao + +#endif diff --git a/share/include/tao/json/value.hh b/share/include/tao/json/value.hh new file mode 100644 index 0000000..1c4be41 --- /dev/null +++ b/share/include/tao/json/value.hh @@ -0,0 +1,1239 @@ +// Copyright (c) 2015-2016 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/taocpp/json/ + +#ifndef TAOCPP_JSON_INCLUDE_VALUE_HH +#define TAOCPP_JSON_INCLUDE_VALUE_HH + +#include +#include +#include +#include +#include + +#include "external/operators.hpp" +#include "external/optional.hpp" + +#include "internal/totally_ordered.hh" +#include "internal/value_union.hh" +#include "internal/get_by_enum.hh" +#include "internal/throw.hh" + +#include "type.hh" +#include "traits.hh" +#include "pair.hh" +#include "single.hh" +#include "pointer.hh" + +namespace tao +{ + namespace json + { + namespace internal + { + template< typename, typename, typename = void > struct has_as : std::false_type {}; + template< typename T, typename V > struct has_as< T, V, decltype( T::as( std::declval< const V & >() ), void() ) > : std::true_type {}; + + // required work-around for GCC 6 + inline void rethrow() + { + throw; + } + + } // internal + + template< template< typename ... > class Traits > + class basic_value + : operators::totally_ordered< basic_value< Traits > >, + internal::totally_ordered< basic_value< Traits >, null_t, type::NULL_ >, + internal::totally_ordered< basic_value< Traits >, bool, type::BOOLEAN >, + internal::totally_ordered< basic_value< Traits >, signed char, type::SIGNED >, + internal::totally_ordered< basic_value< Traits >, unsigned char, type::UNSIGNED >, + internal::totally_ordered< basic_value< Traits >, signed short, type::SIGNED >, + internal::totally_ordered< basic_value< Traits >, unsigned short, type::UNSIGNED >, + internal::totally_ordered< basic_value< Traits >, signed int, type::SIGNED >, + internal::totally_ordered< basic_value< Traits >, unsigned int, type::UNSIGNED >, + internal::totally_ordered< basic_value< Traits >, signed long, type::SIGNED >, + internal::totally_ordered< basic_value< Traits >, unsigned long, type::UNSIGNED >, + internal::totally_ordered< basic_value< Traits >, signed long long, type::SIGNED >, + internal::totally_ordered< basic_value< Traits >, unsigned long long, type::UNSIGNED >, + internal::totally_ordered< basic_value< Traits >, float, type::DOUBLE >, + internal::totally_ordered< basic_value< Traits >, double, type::DOUBLE >, + internal::totally_ordered< basic_value< Traits >, std::string, type::STRING >, + internal::totally_ordered< basic_value< Traits >, const char *, type::STRING >, + internal::totally_ordered< basic_value< Traits >, std::vector< basic_value< Traits > >, type::ARRAY >, + internal::totally_ordered< basic_value< Traits >, empty_array_t, type::ARRAY >, + internal::totally_ordered< basic_value< Traits >, std::map< std::string, basic_value< Traits > >, type::OBJECT >, + internal::totally_ordered< basic_value< Traits >, empty_object_t, type::OBJECT >, + internal::totally_ordered< basic_value< Traits >, const basic_value< Traits > *, type::RAW_PTR >, + internal::totally_ordered< basic_value< Traits >, basic_value< Traits > *, type::RAW_PTR >, + internal::totally_ordered< basic_value< Traits >, std::nullptr_t, type::RAW_PTR > + { + public: + using array_t = std::vector< basic_value >; + using object_t = std::map< std::string, basic_value >; + + basic_value() noexcept + { } + + basic_value( basic_value && r ) noexcept + : m_type( r.m_type ) + { + seize( std::move( r ) ); + } + + // required work-around for a bug in older GCCs (<4.9) + basic_value( const basic_value && r ) + : m_type( r.m_type ) + { + embed( r ); + } + + basic_value( const basic_value & r ) + : m_type( r.m_type ) + { + embed( r ); + } + + basic_value( basic_value & r ) + : basic_value( static_cast< const basic_value & >( r ) ) + { } + + template< typename T > + basic_value( T && v ) noexcept( noexcept( Traits< typename std::decay< T >::type >::assign( std::declval< basic_value & >(), std::forward< T >( v ) ) ) ) + { + try { + using D = typename std::decay< T >::type; + Traits< D >::assign( *this, std::forward< T >( v ) ); + } + catch( ... ) { + unsafe_discard(); + const_cast< volatile json::type & >( m_type ) = json::type::DISCARDED; + internal::rethrow(); + } + } + + basic_value( std::initializer_list< pair< Traits > > && l ) + { + try { + unsafe_assign( std::move( l ) ); + } + catch( ... ) { + unsafe_discard(); + const_cast< volatile json::type & >( m_type ) = json::type::DISCARDED; + throw; + } + } + + basic_value( const std::initializer_list< pair< Traits > > & l ) + { + try { + unsafe_assign( l ); + } + catch( ... ) { + unsafe_discard(); + const_cast< volatile json::type & >( m_type ) = json::type::DISCARDED; + throw; + } + } + + basic_value( std::initializer_list< pair< Traits > > & l ) + : basic_value( static_cast< const std::initializer_list< pair< Traits > > & >( l ) ) + { } + + ~basic_value() noexcept + { + unsafe_discard(); + assert( ( const_cast< volatile json::type & >( m_type ) = json::type::DISCARDED, true ) ); + } + + static basic_value array( std::initializer_list< single< Traits > > && l ) + { + basic_value v; + v.append( std::move( l ) ); + return v; + } + + static basic_value array( const std::initializer_list< single< Traits > > & l ) + { + basic_value v; + v.append( l ); + return v; + } + + basic_value & operator= ( basic_value v ) noexcept + { + unsafe_discard(); + m_type = v.m_type; + seize( std::move( v ) ); + return * this; + } + + void swap( basic_value & r ) noexcept + { + basic_value t( std::move( r ) ); + r = std::move( * this ); + ( * this ) = ( std::move( t ) ); + } + + json::type type() const noexcept + { + return m_type; + } + + explicit operator bool() const noexcept + { + assert( m_type != json::type::DISCARDED ); + return m_type != json::type::UNINITIALIZED; + } + + bool is_null() const noexcept + { + return m_type == json::type::NULL_; + } + + bool is_boolean() const noexcept + { + return m_type == json::type::BOOLEAN; + } + + bool is_signed() const noexcept + { + return m_type == json::type::SIGNED; + } + + bool is_unsigned() const noexcept + { + return m_type == json::type::UNSIGNED; + } + + bool is_integer() const noexcept + { + return is_signed() || is_unsigned(); + } + + bool is_double() const noexcept + { + return m_type == json::type::DOUBLE; + } + + bool is_number() const noexcept + { + return is_integer() || is_double(); + } + + bool is_string() const noexcept + { + return m_type == json::type::STRING; + } + + bool is_array() const noexcept + { + return m_type == json::type::ARRAY; + } + + bool is_object() const noexcept + { + return m_type == json::type::OBJECT; + } + + bool is_raw_ptr() const noexcept + { + return m_type == json::type::RAW_PTR; + } + + bool get_boolean() const + { + TAOCPP_JSON_CHECK_TYPE_ERROR( m_type, json::type::BOOLEAN ); + return unsafe_get_boolean(); + } + + std::int64_t get_signed() const + { + TAOCPP_JSON_CHECK_TYPE_ERROR( m_type, json::type::SIGNED ); + return unsafe_get_signed(); + } + + std::uint64_t get_unsigned() const + { + TAOCPP_JSON_CHECK_TYPE_ERROR( m_type, json::type::UNSIGNED ); + return unsafe_get_unsigned(); + } + + double get_double() const + { + TAOCPP_JSON_CHECK_TYPE_ERROR( m_type, json::type::DOUBLE ); + return unsafe_get_double(); + } + + std::string & get_string() + { + TAOCPP_JSON_CHECK_TYPE_ERROR( m_type, json::type::STRING ); + return unsafe_get_string(); + } + + const std::string & get_string() const + { + TAOCPP_JSON_CHECK_TYPE_ERROR( m_type, json::type::STRING ); + return unsafe_get_string(); + } + + array_t & get_array() + { + TAOCPP_JSON_CHECK_TYPE_ERROR( m_type, json::type::ARRAY ); + return unsafe_get_array(); + } + + const array_t & get_array() const + { + TAOCPP_JSON_CHECK_TYPE_ERROR( m_type, json::type::ARRAY ); + return unsafe_get_array(); + } + + object_t & get_object() + { + TAOCPP_JSON_CHECK_TYPE_ERROR( m_type, json::type::OBJECT ); + return unsafe_get_object(); + } + + const object_t & get_object() const + { + TAOCPP_JSON_CHECK_TYPE_ERROR( m_type, json::type::OBJECT ); + return unsafe_get_object(); + } + + const basic_value * get_raw_ptr() const + { + TAOCPP_JSON_CHECK_TYPE_ERROR( m_type, json::type::RAW_PTR ); + return unsafe_get_raw_ptr(); + } + + template< json::type E > + decltype( internal::get_by_enum< E >::get( std::declval< internal::value_union< basic_value > & >() ) ) get() + { + TAOCPP_JSON_CHECK_TYPE_ERROR( m_type, E ); + return internal::get_by_enum< E >::get( m_union ); + } + + template< json::type E > + decltype( internal::get_by_enum< E >::get( std::declval< const internal::value_union< basic_value > & >() ) ) get() const + { + TAOCPP_JSON_CHECK_TYPE_ERROR( m_type, E ); + return internal::get_by_enum< E >::get( m_union ); + } + + template< typename T > + void extract( T& v ) const + { + Traits< typename std::decay< T >::type >::extract( * this, v ); + } + + template< typename T > + typename std::enable_if< internal::has_as< Traits< T >, basic_value >::value, T >::type as() const + { + return Traits< T >::as( * this ); + } + + template< typename T > + typename std::enable_if< ! internal::has_as< Traits< T >, basic_value >::value, T >::type as() const + { + T nrv; + extract( nrv ); + return nrv; + } + + template< typename T > + tao::optional< T > optional() const + { + if ( this->is_null() ) { + return tao::nullopt; + } + else { + return this->as< T >(); + } + } + + // The unsafe_get_*() accessor functions MUST NOT be + // called when the type of the value is not the one + // corresponding to the type of the accessor! + + bool unsafe_get_boolean() const noexcept + { + return m_union.b; + } + + std::int64_t unsafe_get_signed() const noexcept + { + return m_union.i; + } + + std::uint64_t unsafe_get_unsigned() const noexcept + { + return m_union.u; + } + + double unsafe_get_double() const noexcept + { + return m_union.d; + } + + std::string & unsafe_get_string() noexcept + { + return m_union.s; + } + + const std::string & unsafe_get_string() const noexcept + { + return m_union.s; + } + + array_t & unsafe_get_array() noexcept + { + return m_union.a; + } + + const array_t & unsafe_get_array() const noexcept + { + return m_union.a; + } + + object_t & unsafe_get_object() noexcept + { + return m_union.o; + } + + const object_t & unsafe_get_object() const noexcept + { + return m_union.o; + } + + const basic_value * unsafe_get_raw_ptr() const noexcept + { + return m_union.p; + } + + template< json::type E > + decltype( internal::get_by_enum< E >::get( std::declval< internal::value_union< basic_value > & >() ) ) unsafe_get() + { + return internal::get_by_enum< E >::get( m_union ); + } + + template< json::type E > + decltype( internal::get_by_enum< E >::get( std::declval< const internal::value_union< basic_value > & >() ) ) unsafe_get() const + { + return internal::get_by_enum< E >::get( m_union ); + } + + const basic_value * skip_raw_ptr() const noexcept + { + const basic_value * p = this; + while ( p && p->is_raw_ptr() ) { + p = p->unsafe_get_raw_ptr(); + } + return p; + } + + basic_value * unsafe_find( const std::string & key ) noexcept + { + const auto it = m_union.o.find( key ); + return ( it != m_union.o.end() ) ? ( & it->second ) : nullptr; + } + + const basic_value * unsafe_find( const std::string & key ) const noexcept + { + const auto it = m_union.o.find( key ); + return ( it != m_union.o.end() ) ? ( & it->second ) : nullptr; + } + + basic_value * find( const std::string & key ) + { + TAOCPP_JSON_CHECK_TYPE_ERROR( m_type, json::type::OBJECT ); + return unsafe_find( key ); + } + + const basic_value * find( const std::string & key ) const + { + TAOCPP_JSON_CHECK_TYPE_ERROR( m_type, json::type::OBJECT ); + return unsafe_find( key ); + } + + basic_value & at( const std::size_t index ) + { + TAOCPP_JSON_CHECK_TYPE_ERROR( m_type, json::type::ARRAY ); + return m_union.a.at( index ); + } + + const basic_value & at( const std::size_t index ) const + { + TAOCPP_JSON_CHECK_TYPE_ERROR( m_type, json::type::ARRAY ); + return m_union.a.at( index ); + } + + basic_value & at( const std::string & key ) + { + TAOCPP_JSON_CHECK_TYPE_ERROR( m_type, json::type::OBJECT ); + return m_union.o.at( key ); + } + + const basic_value & at( const std::string & key ) const + { + TAOCPP_JSON_CHECK_TYPE_ERROR( m_type, json::type::OBJECT ); + return m_union.o.at( key ); + } + + basic_value & at( const pointer & k ) + { + return internal::pointer_at( this, k.begin(), k.end() ); + } + + const basic_value & at( const pointer & k ) const + { + return internal::pointer_at( this, k.begin(), k.end() ); + } + + basic_value & unsafe_at( const std::size_t index ) noexcept + { + return m_union.a[ index ]; + } + + const basic_value & unsafe_at( const std::size_t index ) const noexcept + { + return m_union.a[ index ]; + } + + basic_value & unsafe_at( const std::string & key ) noexcept + { + return m_union.o.find( key )->second; + } + + const basic_value & unsafe_at( const std::string & key ) const noexcept + { + return m_union.o.find( key )->second; + } + + void erase( const std::size_t index ) + { + TAOCPP_JSON_CHECK_TYPE_ERROR( m_type, json::type::ARRAY ); + auto & a = m_union.a; + if ( index >= a.size() ) { + throw std::out_of_range( "JSON array index out of bounds" ); + } + a.erase( a.begin() + index ); + } + + void erase( const std::string & key ) + { + TAOCPP_JSON_CHECK_TYPE_ERROR( m_type, json::type::OBJECT ); + if ( m_union.o.erase( key ) == 0 ) { + throw std::out_of_range( "JSON object key not found: " + key ); + } + } + + void erase( const pointer & k ) + { + if ( ! k ) { + throw std::runtime_error( "invalid root JSON Pointer for erase" ); + } + const auto b = k.begin(); + const auto e = std::prev( k.end() ); + basic_value & v = internal::pointer_at( this, b, e ); + switch ( v.m_type ) { + case json::type::ARRAY: + v.erase( e->index() ); + break; + case json::type::OBJECT: + v.erase( e->key() ); + break; + default: + throw internal::invalid_type( b, std::next( e ) ); + } + } + + basic_value & insert( const pointer & k, basic_value value ) + { + if ( ! k ) { + * this = std::move( value ); + return * this; + } + const auto b = k.begin(); + const auto e = std::prev( k.end() ); + basic_value & v = internal::pointer_at( this, b, e ); + switch ( v.m_type ) { + case json::type::ARRAY: + { + if ( e->key() == "-" ) { + v.unsafe_emplace_back( std::move( value ) ); + return v.m_union.a.back(); + } + const auto i = e->index(); + if ( i >= v.m_union.a.size() ) { + throw std::out_of_range( "invalid JSON Pointer '" + internal::tokens_to_string( b, std::next( e ) ) + "' -- array index out of bounds" ); + } + v.m_union.a.insert( v.m_union.a.begin() + i, std::move( value ) ); + return v.m_union.a.at( i ); + } + break; + case json::type::OBJECT: + { + const auto & k = e->key(); + const auto it = v.m_union.o.find( k ); + if ( it == v.m_union.o.end() ) { + const auto r = v.unsafe_emplace( k, std::move( value ) ); + assert( r.second ); + return r.first->second; + } + it->second = std::move( value ); + return it->second; + } + break; + default: + throw internal::invalid_type( b, std::next( e ) ); + } + } + + template< typename T > + tao::optional< T > optional( const std::string & key ) const + { + TAOCPP_JSON_CHECK_TYPE_ERROR( m_type, json::type::OBJECT ); + const auto it = m_union.o.find( key ); + if ( it == m_union.o.end() ) { + return tao::nullopt; + } + else { + return it->second.template as< T >(); + } + } + + // The unsafe_assign()-functions MUST NOT be called on a + // value v when json::needs_discard( v.type() ) is true! + + template< typename T > + void unsafe_assign( T && v ) noexcept( noexcept( Traits< typename std::decay< T >::type >::assign( std::declval< basic_value & >(), std::forward< T >( v ) ) ) ) + { + using D = typename std::decay< T >::type; + Traits< D >::assign( *this, std::forward< T >( v ) ); + } + + void unsafe_assign( std::initializer_list< pair< Traits > > && l ) + { + unsafe_emplace_object(); + for ( auto & e : l ) { + const auto r = unsafe_emplace( std::move( e.key ), std::move( e.value ) ); + if ( ! r.second ) { + throw std::runtime_error( "duplicate JSON object key: " + r.first->first ); + } + } + } + + void unsafe_assign( const std::initializer_list< pair< Traits > > & l ) + { + unsafe_emplace_object(); + for ( const auto & e : l ) { + const auto r = unsafe_emplace( e.key, e.value ); + if ( ! r.second ) { + throw std::runtime_error( "duplicate JSON object key: " + r.first->first ); + } + } + } + + void unsafe_assign( std::initializer_list< pair< Traits > > & l ) + { + unsafe_assign( static_cast< const std::initializer_list< pair< Traits > > & >( l ) ); + } + + void unsafe_assign_null() noexcept + { + m_type = json::type::NULL_; + } + + void unsafe_assign_bool( const bool b ) noexcept + { + m_union.b = b; + m_type = json::type::BOOLEAN; + } + + void unsafe_assign_signed( const std::int64_t i ) noexcept + { + m_union.i = i; + m_type = json::type::SIGNED; + } + + void unsafe_assign_unsigned( const std::uint64_t u ) noexcept + { + m_union.u = u; + m_type = json::type::UNSIGNED; + } + + void unsafe_assign_double_unchecked( const double d ) noexcept + { + // d must be a finite value! + m_union.d = d; + m_type = json::type::DOUBLE; + } + + void unsafe_assign_double( const double d ) + { + if ( ! std::isfinite( d ) ) { + throw std::runtime_error( "non-finite double value invalid for JSON" ); + } + unsafe_assign_double_unchecked( d ); + } + + template< typename ... Ts > + void unsafe_emplace_string( Ts && ... ts ) + { + new ( & m_union.s ) std::string( std::forward< Ts >( ts ) ... ); + m_type = json::type::STRING; + } + + template< typename ... Ts > + void emplace_string( Ts && ... ts ) + { + discard(); + unsafe_emplace_string( std::forward< Ts >( ts ) ... ); + } + + template< typename ... Ts > + void unsafe_emplace_array( Ts && ... ts ) + { + new ( & m_union.a ) std::vector< basic_value >( std::forward< Ts >( ts ) ... ); + m_type = json::type::ARRAY; + } + + template< typename ... Ts > + void emplace_array( Ts && ... ts ) + { + discard(); + unsafe_emplace_array( std::forward< Ts >( ts ) ... ); + } + + void prepare_array() + { + switch ( m_type ) { + case json::type::UNINITIALIZED: + unsafe_emplace_array(); + case json::type::ARRAY: + break; + default: + TAOCPP_JSON_THROW_TYPE_ERROR( m_type ); + } + } + + template< typename V > + void unsafe_emplace_back( V && v ) + { + m_union.a.emplace_back( std::forward< V >( v ) ); + } + + template< typename V > + void emplace_back( V && v ) + { + prepare_array(); + unsafe_emplace_back( std::forward< V >( v ) ); + } + + template< typename ... Ts > + void unsafe_emplace_object( Ts && ... ts ) + { + new ( & m_union.o ) std::map< std::string, basic_value >( std::forward< Ts >( ts ) ... ); + m_type = json::type::OBJECT; + } + + template< typename ... Ts > + void emplace_object( Ts && ... ts ) + { + discard(); + unsafe_emplace_object( std::forward< Ts >( ts ) ... ); + } + + void prepare_object() + { + switch ( m_type ) { + case json::type::UNINITIALIZED: + unsafe_emplace_object(); + case json::type::OBJECT: + break; + default: + TAOCPP_JSON_THROW_TYPE_ERROR( m_type ); + } + } + + template< typename K, typename V > + std::pair< typename object_t::iterator, bool > unsafe_emplace( K && k, V && v ) + { + return m_union.o.emplace( std::forward< K >( k ), std::forward< V >( v ) ); + } + + template< typename K, typename V > + std::pair< typename object_t::iterator, bool > emplace( K && k, V && v ) + { + prepare_object(); + return unsafe_emplace( std::forward< K >( k ), std::forward< V >( v ) ); + } + + void unsafe_assign_pointer( const basic_value * p ) noexcept + { + m_union.p = p; + m_type = json::type::RAW_PTR; + } + + void append( std::initializer_list< single< Traits > > && l ) + { + prepare_array(); + auto & v = unsafe_get_array(); + v.reserve( v.size() + l.size() ); + for ( auto & e : l ) { + unsafe_emplace_back( std::move( e.value ) ); + } + } + + void append( const std::initializer_list< single< Traits > > & l ) + { + prepare_array(); + auto & v = unsafe_get_array(); + v.reserve( v.size() + l.size() ); + for ( const auto & e : l ) { + unsafe_emplace_back( e.value ); + } + } + + void insert( std::initializer_list< pair< Traits > > && l ) + { + prepare_object(); + for ( auto & e : l ) { + const auto r = unsafe_emplace( std::move( e.key ), std::move( e.value ) ); + if ( ! r.second ) { + throw std::runtime_error( "duplicate JSON object key: " + r.first->first ); + } + } + } + + void insert( const std::initializer_list< pair< Traits > > & l ) + { + prepare_object(); + for ( const auto & e : l ) { + const auto r = unsafe_emplace( e.key, e.value ); + if ( ! r.second ) { + throw std::runtime_error( "duplicate JSON object key: " + r.first->first ); + } + } + } + + + basic_value & operator[] ( const std::size_t index ) noexcept + { + assert( m_type == json::type::ARRAY ); + return m_union.a[ index ]; + } + + const basic_value & operator[] ( const std::size_t index ) const noexcept + { + assert( m_type == json::type::ARRAY ); + return m_union.a[ index ]; + } + + basic_value & operator[] ( const std::string & key ) + { + prepare_object(); + return m_union.o[ key ]; + } + + basic_value & operator[] ( std::string && key ) + { + prepare_object(); + return m_union.o[ std::move( key ) ]; + } + + basic_value & operator[] ( const pointer & k ) + { + if ( ! k ) { + return * this; + } + const auto b = k.begin(); + const auto e = std::prev( k.end() ); + basic_value & v = internal::pointer_at( this, b, e ); + switch ( v.m_type ) { + case json::type::ARRAY: + { + if ( e->key() == "-" ) { + v.unsafe_emplace_back( null ); + return v.m_union.a.back(); + } + return v.at( e->index() ); + } + break; + case json::type::OBJECT: + { + const auto & k = e->key(); + const auto it = v.m_union.o.find( k ); + if ( it == v.m_union.o.end() ) { + const auto r = v.unsafe_emplace( k, null ); + assert( r.second ); + return r.first->second; + } + return it->second; + } + break; + default: + throw internal::invalid_type( b, std::next( e ) ); + } + } + + bool empty() const noexcept + { + switch ( m_type ) { + case json::type::UNINITIALIZED: + return true; + case json::type::DISCARDED: + // LCOV_EXCL_START + assert( m_type != json::type::DISCARDED ); + return true; + // LCOV_EXCL_STOP + case json::type::NULL_: + case json::type::BOOLEAN: + case json::type::SIGNED: + case json::type::UNSIGNED: + case json::type::DOUBLE: + return false; + case json::type::STRING: + return m_union.s.empty(); + case json::type::ARRAY: + return m_union.a.empty(); + case json::type::OBJECT: + return m_union.o.empty(); + case json::type::RAW_PTR: + return ! m_union.p; + } + // LCOV_EXCL_START + assert( false ); + return false; + // LCOV_EXCL_STOP + } + + void unsafe_discard() noexcept + { + switch ( m_type ) { + case json::type::UNINITIALIZED: + case json::type::DISCARDED: + case json::type::NULL_: + case json::type::BOOLEAN: + case json::type::SIGNED: + case json::type::UNSIGNED: + case json::type::DOUBLE: + case json::type::RAW_PTR: + return; + case json::type::STRING: + m_union.s.~basic_string(); + return; + case json::type::ARRAY: + m_union.a.~vector(); + return; + case json::type::OBJECT: + m_union.o.~map(); + return; + } + assert( false ); // LCOV_EXCL_LINE + } + + void discard() noexcept + { + unsafe_discard(); + m_type = json::type::DISCARDED; + } + + void reset() noexcept + { + unsafe_discard(); + m_type = json::type::UNINITIALIZED; + } + + private: + void seize( basic_value && r ) noexcept + { + switch ( r.m_type ) { + case json::type::UNINITIALIZED: + assert( ( r.m_type = json::type::DISCARDED, true ) ); + return; + case json::type::DISCARDED: + // LCOV_EXCL_START + assert( r.m_type != json::type::DISCARDED ); + return; + // LCOV_EXCL_STOP + case json::type::NULL_: + assert( ( r.m_type = json::type::DISCARDED, true ) ); + return; + case json::type::BOOLEAN: + m_union.b = r.m_union.b; + assert( ( r.m_type = json::type::DISCARDED, true ) ); + return; + case json::type::SIGNED: + m_union.i = r.m_union.i; + assert( ( r.m_type = json::type::DISCARDED, true ) ); + return; + case json::type::UNSIGNED: + m_union.u = r.m_union.u; + assert( ( r.m_type = json::type::DISCARDED, true ) ); + return; + case json::type::DOUBLE: + m_union.d = r.m_union.d; + assert( ( r.m_type = json::type::DISCARDED, true ) ); + return; + case json::type::STRING: + new ( & m_union.s ) std::string( std::move( r.m_union.s ) ); + assert( ( r.discard(), true ) ); + return; + case json::type::ARRAY: + new ( & m_union.a ) std::vector< basic_value >( std::move( r.m_union.a ) ); + assert( ( r.discard(), true ) ); + return; + case json::type::OBJECT: + new ( & m_union.o ) std::map< std::string, basic_value >( std::move( r.m_union.o ) ); + assert( ( r.discard(), true ) ); + return; + case json::type::RAW_PTR: + m_union.p = r.m_union.p; + assert( ( r.m_type = json::type::DISCARDED, true ) ); + return; + } + assert( false ); // LCOV_EXCL_LINE + } + + void embed( const basic_value & r ) + { + switch ( r.m_type ) { + case json::type::UNINITIALIZED: + return; + case json::type::DISCARDED: + throw std::logic_error( "attempt to use a discarded value" ); + case json::type::NULL_: + return; + case json::type::BOOLEAN: + m_union.b = r.m_union.b; + return; + case json::type::SIGNED: + m_union.i = r.m_union.i; + return; + case json::type::UNSIGNED: + m_union.u = r.m_union.u; + return; + case json::type::DOUBLE: + m_union.d = r.m_union.d; + return; + case json::type::STRING: + new ( & m_union.s ) std::string( r.m_union.s ); + return; + case json::type::ARRAY: + new ( & m_union.a ) std::vector< basic_value >( r.m_union.a ); + return; + case json::type::OBJECT: + new ( & m_union.o ) std::map< std::string, basic_value >( r.m_union.o ); + return; + case json::type::RAW_PTR: + m_union.p = r.m_union.p; + return; + } + assert( false ); // LCOV_EXCL_LINE + } + + json::type m_type = json::type::UNINITIALIZED; + internal::value_union< basic_value > m_union; + }; + + template< template< typename ... > class Traits > + bool operator== ( const basic_value< Traits > & lhs, const basic_value< Traits > & rhs ) noexcept + { + if ( lhs.type() == type::RAW_PTR ) { + if ( const auto * p = lhs.unsafe_get_raw_ptr() ) { + return * p == rhs; + } + else { + return null == rhs; + } + } + if ( lhs.type() != rhs.type() ) { + if ( rhs.type() == type::RAW_PTR ) { + if ( const auto * p = rhs.unsafe_get_raw_ptr() ) { + return lhs == * p; + } + else { + return lhs == null; + } + } + if ( lhs.type() == type::SIGNED ) { + if ( rhs.type() == type::UNSIGNED ) { + const auto v = lhs.unsafe_get_signed(); + return ( v >= 0 ) && ( static_cast< std::uint64_t >( v ) == rhs.unsafe_get_unsigned() ); + } + if ( rhs.type() == type::DOUBLE ) { + return lhs.unsafe_get_signed() == rhs.unsafe_get_double(); + } + } + else if ( lhs.type() == type::UNSIGNED ) { + if ( rhs.type() == type::SIGNED ) { + const auto v = rhs.unsafe_get_signed(); + return ( v >= 0 ) && ( lhs.unsafe_get_unsigned() == static_cast< std::uint64_t >( v ) ); + } + if ( rhs.type() == type::DOUBLE ) { + return lhs.unsafe_get_unsigned() == rhs.unsafe_get_double(); + } + } + else if ( lhs.type() == type::DOUBLE ) { + if ( rhs.type() == type::SIGNED ) { + return lhs.unsafe_get_double() == rhs.unsafe_get_signed(); + } + if ( rhs.type() == type::UNSIGNED ) { + return lhs.unsafe_get_double() == rhs.unsafe_get_unsigned(); + } + } + assert( lhs.type() != type::DISCARDED ); + assert( rhs.type() != type::DISCARDED ); + return false; + } + switch ( lhs.type() ) { + case type::UNINITIALIZED: + return true; + case type::DISCARDED: + // LCOV_EXCL_START + assert( lhs.type() != type::DISCARDED ); + break; + // LCOV_EXCL_STOP + case type::NULL_: + return true; + case type::BOOLEAN: + return lhs.unsafe_get_boolean() == rhs.unsafe_get_boolean(); + case type::SIGNED: + return lhs.unsafe_get_signed() == rhs.unsafe_get_signed(); + case type::UNSIGNED: + return lhs.unsafe_get_unsigned() == rhs.unsafe_get_unsigned(); + case type::DOUBLE: + return lhs.unsafe_get_double() == rhs.unsafe_get_double(); + case type::STRING: + return lhs.unsafe_get_string() == rhs.unsafe_get_string(); + case type::ARRAY: + return lhs.unsafe_get_array() == rhs.unsafe_get_array(); + case type::OBJECT: + return lhs.unsafe_get_object() == rhs.unsafe_get_object(); + case type::RAW_PTR: + break; // LCOV_EXCL_LINE + } + // LCOV_EXCL_START + assert( false ); + return false; + // LCOV_EXCL_STOP + } + + template< template< typename ... > class Traits > + bool operator< ( const basic_value< Traits > & lhs, const basic_value< Traits > & rhs ) noexcept + { + if ( lhs.type() == type::RAW_PTR ) { + if ( const auto * p = lhs.unsafe_get_raw_ptr() ) { + return * p < rhs; + } + else { + return null < rhs; + } + } + if ( lhs.type() != rhs.type() ) { + if ( rhs.type() == type::RAW_PTR ) { + if ( const auto * p = rhs.unsafe_get_raw_ptr() ) { + return lhs < * p; + } + else { + return lhs < null; + } + } + if ( lhs.type() == type::SIGNED ) { + if ( rhs.type() == type::UNSIGNED ) { + const auto v = lhs.unsafe_get_signed(); + return ( v < 0 ) || ( static_cast< std::uint64_t >( v ) < rhs.unsafe_get_unsigned() ); + } + if ( rhs.type() == type::DOUBLE ) { + return lhs.unsafe_get_signed() < rhs.unsafe_get_double(); + } + } + else if ( lhs.type() == type::UNSIGNED ) { + if ( rhs.type() == type::SIGNED ) { + const auto v = rhs.unsafe_get_signed(); + return ( v >= 0 ) && ( lhs.unsafe_get_unsigned() < static_cast< std::uint64_t >( v ) ); + } + if ( rhs.type() == type::DOUBLE ) { + return lhs.unsafe_get_unsigned() < rhs.unsafe_get_double(); + } + } + else if ( lhs.type() == type::DOUBLE ) { + if ( rhs.type() == type::SIGNED ) { + return lhs.unsafe_get_double() < rhs.unsafe_get_signed(); + } + if ( rhs.type() == type::UNSIGNED ) { + return lhs.unsafe_get_double() < rhs.unsafe_get_unsigned(); + } + } + assert( lhs.type() != type::DISCARDED ); + assert( rhs.type() != type::DISCARDED ); + return lhs.type() < rhs.type(); + } + switch ( lhs.type() ) { + case type::UNINITIALIZED: + return false; + case type::DISCARDED: + // LCOV_EXCL_START + assert( lhs.type() != type::DISCARDED ); + break; + // LCOV_EXCL_STOP + case type::NULL_: + return false; + case type::BOOLEAN: + return lhs.unsafe_get_boolean() < rhs.unsafe_get_boolean(); + case type::SIGNED: + return lhs.unsafe_get_signed() < rhs.unsafe_get_signed(); + case type::UNSIGNED: + return lhs.unsafe_get_unsigned() < rhs.unsafe_get_unsigned(); + case type::DOUBLE: + return lhs.unsafe_get_double() < rhs.unsafe_get_double(); + case type::STRING: + return lhs.unsafe_get_string() < rhs.unsafe_get_string(); + case type::ARRAY: + return lhs.unsafe_get_array() < rhs.unsafe_get_array(); + case type::OBJECT: + return lhs.unsafe_get_object() < rhs.unsafe_get_object(); + case type::RAW_PTR: + break; // LCOV_EXCL_LINE + } + // LCOV_EXCL_START + assert( false ); + return false; + // LCOV_EXCL_STOP + } + + template< template< typename ... > class Traits > + basic_value< Traits > & operator+= ( basic_value< Traits > & v, std::initializer_list< pair< Traits > > && l ) + { + v.insert( std::move( l ) ); + return v; + } + + template< template< typename ... > class Traits > + basic_value< Traits > & operator+= ( basic_value< Traits > & v, const std::initializer_list< pair< Traits > > & l ) + { + v.insert( l ); + return v; + } + + template< template< typename ... > class Traits > + basic_value< Traits > & operator-= ( basic_value< Traits > & v, std::initializer_list< std::string > l ) + { + auto & o = v.get_object(); + for ( const auto & k : l ) { + if ( o.erase( k ) == 0 ) { + throw std::runtime_error( "JSON object key not found: " + k ); + } + } + return v; + } + + using value = basic_value< traits >; + + } // json + +} // tao + +#endif diff --git a/sql/schema.sql b/sql/schema.sql index c5f3e3f..dbabf67 100644 --- a/sql/schema.sql +++ b/sql/schema.sql @@ -245,13 +245,13 @@ create table "auth_identity" ( create table "auth_token" ( "id" serial not null, - "version" integer not null, "auth_info_id" bigint, "value" varchar(64) not null, - "expires" timestamp, + "expires" timestamp not null, constraint "pk_auth_token_id" primary key("id"), constraint "fk_auth_token_auth_info_id" foreign key ("auth_info_id") references "auth_info" ("id") on delete cascade deferrable initially deferred ); +create index "ix_auth_token_value" ON "auth_token" ("value"); create or replace function update_category_parent_path() returns trigger as $$ diff --git a/src/app/main.cpp b/src/app/main.cpp index a67e128..48064b8 100644 --- a/src/app/main.cpp +++ b/src/app/main.cpp @@ -44,7 +44,7 @@ class AuthApplication : public Wt::WApplication { login_.changed().connect(this, &AuthApplication::authEvent); auto config = std::make_shared< sqlpp::postgresql::connection_config >(); - config->host = "10.154.50.222"; + config->host = "192.168.1.101"; config->port = 5432; config->user = "postgres"; config->password = "postgres"; @@ -52,7 +52,7 @@ class AuthApplication : public Wt::WApplication { config->debug = true; conn_ = std::make_unique< eedb::db::PgConnection >(config); - userDatabase_ = std::make_unique< eedb::auth::PgUserAuth >(*conn_); + userDatabase_ = std::make_unique< eedb::auth::PgUserAuth >(*conn_, env); userDatabase_->setAuthService(eedb::auth::Services::authService()); root()->addStyleClass("container"); @@ -70,7 +70,7 @@ class AuthApplication : public Wt::WApplication { _loginWidget->model()->addOAuth(eedb::auth::Services::oAuthServices()); _loginWidget->setRegistrationEnabled(true); - // authWidget->processEnvironment(); + _loginWidget->processEnvironment(); root()->addWidget(_loginWidget); } @@ -82,8 +82,8 @@ class AuthApplication : public Wt::WApplication { if(login_.loggedIn()) { Wt::WContainerWidget * container = root(); - setInternalPath("/app"); - root()->removeStyleClass("container"); + setInternalPath("/app"); + root()->removeStyleClass("container"); // Create a navigation bar with a link to a web page. Wt::WNavigationBar * navigation = new Wt::WNavigationBar(container); @@ -100,7 +100,6 @@ class AuthApplication : public Wt::WApplication { Wt::WText * searchResult = new Wt::WText("Buy or Sell... Bye!"); leftMenu->addItem("Home", new Wt::WText("There is no better place!")); - leftMenu->addItem("Layout", new Wt::WText("Layout contents"))->setLink(Wt::WLink(Wt::WLink::InternalPath, "/layout")); leftMenu->addItem("Sales", searchResult); // Setup a Right-aligned menu. @@ -130,7 +129,7 @@ class AuthApplication : public Wt::WApplication { Wt::WMenuItem * help = new Wt::WMenuItem("Help"); help->setMenu(popup); - + rightMenu->addItem(help); sessionMenu->addItem("session", _loginWidget); @@ -145,8 +144,6 @@ class AuthApplication : public Wt::WApplication { navigation->addSearch(edit, Wt::AlignRight); - // northContainer->addWidget(contentsStack); - Wt::WBorderLayout * layout = new Wt::WBorderLayout(); container->setLayout(layout); @@ -161,11 +158,9 @@ class AuthApplication : public Wt::WApplication { menu->addItem("Tab widget", new Wt::WTextArea("Tab widget contents")); menu->addItem("Menu", new Wt::WTextArea("Menu contents")); - Wt::WText * item = new Wt::WText(Wt::WString(cell).arg("North")); - item->setStyleClass("green-box"); layout->addWidget(navigation, Wt::WBorderLayout::North); - item = new Wt::WText(Wt::WString(cell).arg("West")); + Wt::WText * item = new Wt::WText(Wt::WString(cell).arg("North")); item->setStyleClass("green-box"); layout->addWidget(menu, Wt::WBorderLayout::West); diff --git a/src/eedb/auth/PgUserAuth.cpp b/src/eedb/auth/PgUserAuth.cpp index 6d0c750..df6e72a 100644 --- a/src/eedb/auth/PgUserAuth.cpp +++ b/src/eedb/auth/PgUserAuth.cpp @@ -12,13 +12,54 @@ #include #include +#include +#include +#include +#include +#include #include #include +#include #include +#include +#include + using namespace sqlpp; using namespace Wt::Auth; +using namespace std::string_literals; + +template < typename Connection > +struct TransactionGuard { + TransactionGuard(Connection & c) : _c(c) { + _c.native()->start_transaction(); + } + + ~TransactionGuard() { + _c.native()->commit_transaction(); + } + + Connection & _c; +}; + +std::string RandomString(int stringLength = 20) { + std::default_random_engine prne(std::chrono::steady_clock::now().time_since_epoch().count()); + std::uniform_int_distribution< char > uid('A', 'z'); + auto randomCharacter = std::bind(uid, prne); + std::string s(stringLength, ' '); + + std::generate(s.begin(), s.end(), [&randomCharacter]() -> char { + while(true) { + const char c = randomCharacter(); + + if(std::isalpha(c)) + return c; + } + }); + + return s; +} namespace eedb::auth { @@ -31,16 +72,18 @@ namespace { constexpr eedb::user_action t_user_action; constexpr eedb::auth_identity authIdentity; constexpr eedb::auth_info authInfo; - constexpr eedb::auth_token authToken; + constexpr eedb::auth_token t_auth_token; auto auth = t_user.join(authInfo).on(t_user.uid == authInfo.user_uid).join(authIdentity).on(authInfo.id == authIdentity.auth_info_id); auto auth_info_identity = authInfo.join(authIdentity).on(authInfo.id == authIdentity.auth_info_id); auto user_auth_info = t_user.join(authInfo).on(authInfo.user_uid == t_user.uid); - auto auth_token_info = user_auth_info.join(authToken).on(authToken.auth_info_id == authInfo.id); + auto auth_token_info = user_auth_info.join(t_auth_token).on(t_auth_token.auth_info_id == authInfo.id); } -PgUserAuth::PgUserAuth(eedb::db::PgConnection & _db) : db(_db) {} +PgUserAuth::~PgUserAuth() {} + +PgUserAuth::PgUserAuth(eedb::db::PgConnection & _db, const Wt::WEnvironment & env) : db(_db), _env(env) {} User PgUserAuth::findWithId(const std::string & id) const { const auto uid_eq = t_user.uid == std::atoi(id.c_str()); @@ -108,7 +151,7 @@ void PgUserAuth::setIdentity(const User & user, const std::string & provider, co const auto uid = std::atoi(user.id().c_str()); const auto provider_eq = authIdentity.provider == provider; - db.native()->start_transaction(); + TransactionGuard< decltype(db) > guard{db}; auto ret = db(select(authInfo.id) // .from(authInfo) // .where(authInfo.user_uid == uid)); @@ -122,8 +165,6 @@ void PgUserAuth::setIdentity(const User & user, const std::string & provider, co db(update(authIdentity) // .set(authIdentity.identity = identity.toUTF8()) // .where(authIdentity.auth_info_id == auth_info_id and provider_eq)); - - db.native()->commit_transaction(); } Wt::WString PgUserAuth::identity(const User & user, const std::string & provider) const { @@ -149,11 +190,11 @@ void PgUserAuth::removeIdentity(const User & user, const std::string & provider) } User PgUserAuth::registerNew() { - db.native()->start_transaction(); + TransactionGuard< decltype(db) > guard{db}; - auto user_id = db(sqlpp::postgresql::insert_into(t_user) // - .set(t_user.email = "", // - t_user.name = "", // + auto user_id = db(sqlpp::postgresql::insert_into(t_user) // + .set(t_user.email = RandomString(20) + "@random.org", // + t_user.name = RandomString(256), // t_user.status = -1) .returning(t_user.uid)) .front() @@ -171,12 +212,11 @@ User PgUserAuth::registerNew() { .front() .id; - db(insert_into(authIdentity) // - .set(authIdentity.identity = "", // - authIdentity.provider = "", // + db(insert_into(authIdentity) // + .set(authIdentity.identity = RandomString(256), // + authIdentity.provider = "", // authIdentity.auth_info_id = info_id)); - db.native()->commit_transaction(); return User{std::to_string(user_id), *this}; } @@ -307,22 +347,64 @@ User PgUserAuth::findWithEmailToken(const std::string & hash) const { return {std::to_string(ret.front().uid), *this}; } -void PgUserAuth::addAuthToken(const User & user, const Token & token) {} - -void PgUserAuth::removeAuthToken(const User & user, const std::string & hash) {} - -User PgUserAuth::findWithAuthToken(const std::string & hash) const { - // auto ret = db(select(auth_info.id).from(auth_info).where(auth_info == hash)); - - // if(ret.empty()) - // return {}; - // return {std::to_string(ret.front().id), *this}; +void PgUserAuth::addAuthToken(const User & user, const Token & token) { + TransactionGuard< decltype(db) > guard{db}; + auto identity_id = db(select(authInfo.id) // + .from(authInfo) // + .where(authInfo.user_uid == std::atoi(user.id().c_str()))); + db(insert_into(t_auth_token) // + .set( // + t_auth_token.auth_info_id = identity_id.front().id, // + t_auth_token.expires = std::chrono::system_clock::now() + ::sqlpp::chrono::days{14}, // + t_auth_token.value = token.hash())); } -int PgUserAuth::updateAuthToken(const User & user, const std::string & oldhash, const std::string & newhash) {} +void PgUserAuth::removeAuthToken(const User &, const std::string & hash) { + db(remove_from(t_auth_token).where(t_auth_token.value == hash)); +} + +User PgUserAuth::findWithAuthToken(const std::string & hash) const { + auto fullUser = t_auth_token // + .join(authInfo) + .on(authInfo.id == t_auth_token.auth_info_id); + + auto ret = db(select(authInfo.user_uid) // + .from(fullUser) // + .where(t_auth_token.value == hash and t_auth_token.expires > std::chrono::system_clock::now())); + + if(ret.empty()) + return {}; + return {std::to_string(ret.front().user_uid), *this}; +} + +int PgUserAuth::updateAuthToken(const User & user, const std::string & oldhash, const std::string & newhash) { + // method called only after successful login + TransactionGuard< decltype(db) > guard{db}; + using namespace std::chrono; + auto identity_id = db(select(authInfo.id) // + .from(authInfo) // + .where(authInfo.user_uid == std::atoi(user.id().c_str()))); + if(identity_id.empty()) + return 0; + + auto expires = db(sqlpp::postgresql::update(t_auth_token) // + .set(t_auth_token.value = newhash) + .where(t_auth_token.value == oldhash) + .returning(t_auth_token.expires)); + + if(expires.empty()) + return 0; + + const tao::json::value data{ + {"status"s, "success"}, // + {"method"s, "token"}, // + {"user_address"s, _env.clientAddress()}, // + {"user_agent"s, _env.userAgent()}, // + {"user_locale"s, _env.locale().name()}, // + {"referer", _env.referer()}, // + {"url_scheme", _env.urlScheme()} // + }; -void PgUserAuth::setFailedLoginAttempts(const User & user, int count) { - db.native()->start_transaction(); auto action_id = db(select(t_user_action.id) // .from(t_user_action) // .where(t_user_action.name == "login")); @@ -331,19 +413,44 @@ void PgUserAuth::setFailedLoginAttempts(const User & user, int count) { .set(t_user_action.name = "login") // .returning(t_user_action.id)); - if(count) { - db(insert_into(t_user_history) - .set(t_user_history.user_id = std::atoi(user.id().c_str()), - t_user_history.action_id = action_id.front().id, // - t_user_history.data = R"( { "status":"failed" } )")); + db(insert_into(t_user_history) + .set(t_user_history.user_id = std::atoi(user.id().c_str()), + t_user_history.action_id = action_id.front().id, // + t_user_history.data = tao::json::to_string(data))); - } else { - db(insert_into(t_user_history) - .set(t_user_history.user_id = std::atoi(user.id().c_str()), - t_user_history.action_id = action_id.front().id, // - t_user_history.data = R"( { "status":"success" } )")); - } - db.native()->commit_transaction(); + auto now = sqlpp::time_point::_cpp_value_type::clock::now(); + auto diff = expires.front().expires.value() - now; + int seconds = std::chrono::duration_cast< duration< int > >(diff).count(); + return seconds; +} + +void PgUserAuth::setFailedLoginAttempts(const User & user, int count) { + TransactionGuard< decltype(db) > guard{db}; + + auto getStatus = [count]() { return count ? "failed"s : "success"s; }; + + const tao::json::value data{ + {"status"s, getStatus()}, // + {"method"s, "password"}, // + {"user_address"s, _env.clientAddress()}, // + {"user_agent"s, _env.userAgent()}, // + {"user_locale"s, _env.locale().name()}, // + {"referer", _env.referer()}, // + {"url_scheme", _env.urlScheme()} // + }; + + auto action_id = db(select(t_user_action.id) // + .from(t_user_action) // + .where(t_user_action.name == "login")); + if(action_id.empty()) + action_id = db(postgresql::insert_into(t_user_action) // + .set(t_user_action.name = "login") // + .returning(t_user_action.id)); + + db(insert_into(t_user_history) + .set(t_user_history.user_id = std::atoi(user.id().c_str()), + t_user_history.action_id = action_id.front().id, // + t_user_history.data = tao::json::to_string(data))); } int PgUserAuth::failedLoginAttempts(const User & user) const { @@ -362,25 +469,22 @@ int PgUserAuth::failedLoginAttempts(const User & user) const { return static_cast< int >(res.front().count); } -void PgUserAuth::setLastLoginAttempt(const User & user, const Wt::WDateTime & t) { - // auto exp = ::date::floor<::std::chrono::milliseconds >(std::chrono::system_clock::from_time_t(t.toTime_t())); - // db(update(authInfo) // - // .set(authInfo.last_login_attempt = exp) // - // .where(authInfo.user_uid == std::atoi(user.id().c_str()))); -} +void PgUserAuth::setLastLoginAttempt(const User &, const Wt::WDateTime &) {} Wt::WDateTime PgUserAuth::lastLoginAttempt(const User & user) const { - // auto res = db(select(authInfo.last_login_attempt) // - // .from(authInfo) // - // .where(authInfo.user_uid == std::atoi(user.id().c_str()))); - // if(res.empty()) - // return {}; + auto res = db(select(t_user_history._when) // + .from(t_user_history.inner_join(t_user_action).on(t_user_history.action_id == t_user_action.id)) // + .where(t_user_action.name == "login" and t_user_history.user_id == std::atoi(user.id().c_str())) // + .order_by(t_user_history.id.desc()) // + .limit(1u)); + if(res.empty()) + return {}; - // auto lastLogin = Wt::WDateTime(); - // auto time = res.front().last_login_attempt.value(); - // auto systime = std::chrono::system_clock::to_time_t(time); - // lastLogin.setTime_t(systime); - // return lastLogin; + auto lastLogin = Wt::WDateTime(); + auto time = res.front()._when.value(); + auto systime = std::chrono::system_clock::to_time_t(time); + lastLogin.setTime_t(systime); + return lastLogin; } AbstractUserDatabase::Transaction * PgUserAuth::startTransaction() { diff --git a/src/eedb/auth/PgUserAuth.hpp b/src/eedb/auth/PgUserAuth.hpp index 6fec29d..168c7bd 100644 --- a/src/eedb/auth/PgUserAuth.hpp +++ b/src/eedb/auth/PgUserAuth.hpp @@ -6,6 +6,10 @@ namespace eedb::db { class PgConnection; } +namespace Wt { +class WEnviroment; +} + namespace Wt::Auth { class AuthService; } @@ -18,7 +22,8 @@ class PgUserAuth : public Wt::Auth::AbstractUserDatabase { _authService = s; } - PgUserAuth(eedb::db::PgConnection & db); + virtual ~PgUserAuth(); + PgUserAuth(eedb::db::PgConnection & db, const Wt::WEnvironment & env); Transaction * startTransaction() override; @@ -48,7 +53,7 @@ class PgUserAuth : public Wt::Auth::AbstractUserDatabase { Wt::Auth::User::EmailTokenRole emailTokenRole(const Wt::Auth::User & user) const override; void addAuthToken(const Wt::Auth::User & user, const Wt::Auth::Token & token) override; - void removeAuthToken(const Wt::Auth::User & user, const std::string & hash) override; + void removeAuthToken(const Wt::Auth::User &, const std::string & hash) override; Wt::Auth::User findWithAuthToken(const std::string & hash) const override; int updateAuthToken(const Wt::Auth::User & user, const std::string & oldhash, const std::string & newhash) override; @@ -59,6 +64,7 @@ class PgUserAuth : public Wt::Auth::AbstractUserDatabase { private: eedb::db::PgConnection & db; + const Wt::WEnvironment & _env; const Wt::Auth::AuthService * _authService; }; } diff --git a/src/eedb/model/auth_token.h b/src/eedb/model/auth_token.h index a85a1ce..df6eae0 100644 --- a/src/eedb/model/auth_token.h +++ b/src/eedb/model/auth_token.h @@ -24,21 +24,6 @@ namespace eedb { using _traits = ::sqlpp::make_traits<::sqlpp::integer, sqlpp::tag::must_not_insert, sqlpp::tag::must_not_update>; }; - struct Version { - struct _alias_t { - static constexpr const char _literal[] ="version"; - using _name_t = sqlpp::make_char_sequence; - template - struct _member_t { - T version; - T &operator()() { return version; } - const T &operator()() const { return version; } - }; - }; - - using _traits = ::sqlpp::make_traits<::sqlpp::integer, sqlpp::tag::require_insert>; - }; - struct Auth_info_id { struct _alias_t { static constexpr const char _literal[] ="auth_info_id"; @@ -87,7 +72,6 @@ namespace eedb { struct auth_token : sqlpp::table_t { diff --git a/src/eedb/model/user_history.h b/src/eedb/model/user_history.h index 249d8d0..ea646a4 100644 --- a/src/eedb/model/user_history.h +++ b/src/eedb/model/user_history.h @@ -75,9 +75,9 @@ namespace eedb { using _name_t = sqlpp::make_char_sequence; template struct _member_t { - T when; - T &operator()() { return when; } - const T &operator()() const { return when; } + T _when; + T &operator()() { return _when; } + const T &operator()() const { return _when; } }; };