From d2bea0c228b46766e928ec6e8836ff1eb36b4b49 Mon Sep 17 00:00:00 2001 From: Joe Jevnik Date: Tue, 21 Jul 2020 13:27:39 -0400 Subject: [PATCH] Add support for C++ 20 ranges. (#1050) C++ 20 adds a new feature called "ranges", which provides components for dealing with sequences of values: https://en.cppreference.com/w/cpp/ranges. A range is like a normal object containing `begin` and `end`, except there are also composable operations like maps, filters, joins, etc. The iterator objects returned by a range's `begin` and `end` require a more strict set of operations than is needed for a range-for loop. This PR adds the extra operations needed to support turning `dom::array` and `dom::object` into a range. This PR does not depend on any C++ 20 behavior, the added operators are all valid C++ 11, and are already part of the LegacyIterator concepts. This PR adds extra code behind: `#if defined(__cpp_lib_ranges)` guards, which is the new C++ 20 specified feature test macro for ranges support. When ranges support is detected, extra compile time checks are added to ensure that `dom::array` and `dom::object` satisfy the range concept. No runtime tests have been added yet because these compile time checks should be sufficient. If desired, the `static_assert` code could be moved out of the actual code headers and put into a test file. --- include/simdjson/dom/array.h | 33 ++++++++- include/simdjson/dom/object.h | 36 +++++++++- include/simdjson/inline/array.h | 27 +++++-- include/simdjson/inline/object.h | 20 ++++++ singleheader/amalgamate_demo.cpp | 2 +- singleheader/simdjson.cpp | 10 +-- singleheader/simdjson.h | 118 ++++++++++++++++++++++++++++--- 7 files changed, 225 insertions(+), 21 deletions(-) diff --git a/include/simdjson/dom/array.h b/include/simdjson/dom/array.h index a54383b4..09f82b0b 100644 --- a/include/simdjson/dom/array.h +++ b/include/simdjson/dom/array.h @@ -23,10 +23,13 @@ public: class iterator { public: + using value_type = element; + using difference_type = std::ptrdiff_t; + /** * Get the actual value */ - inline element operator*() const noexcept; + inline value_type operator*() const noexcept; /** * Get the next value. * @@ -34,12 +37,28 @@ public: * */ inline iterator& operator++() noexcept; + /** + * Get the next value. + * + * Part of the std::iterator interface. + */ + inline iterator operator++(int) noexcept; /** * Check if these values come from the same place in the JSON. * * Part of the std::iterator interface. */ inline bool operator!=(const iterator& other) const noexcept; + inline bool operator==(const iterator& other) const noexcept; + + inline bool operator<(const iterator& other) const noexcept; + inline bool operator<=(const iterator& other) const noexcept; + inline bool operator>=(const iterator& other) const noexcept; + inline bool operator>(const iterator& other) const noexcept; + + iterator() noexcept = default; + iterator(const iterator&) noexcept = default; + iterator& operator=(const iterator&) noexcept = default; private: really_inline iterator(const internal::tape_ref &tape) noexcept; internal::tape_ref tape; @@ -155,4 +174,16 @@ inline std::ostream& operator<<(std::ostream& out, const simdjson_result + +namespace std::ranges { +template<> +inline constexpr bool enable_view = true; +} + +static_assert(std::ranges::view); +static_assert(std::ranges::sized_range); +#endif + #endif // SIMDJSON_DOM_ARRAY_H diff --git a/include/simdjson/dom/object.h b/include/simdjson/dom/object.h index e054cb17..ed626c10 100644 --- a/include/simdjson/dom/object.h +++ b/include/simdjson/dom/object.h @@ -24,10 +24,13 @@ public: class iterator { public: + using value_type = key_value_pair; + using difference_type = std::ptrdiff_t; + /** * Get the actual key/value pair */ - inline const key_value_pair operator*() const noexcept; + inline const value_type operator*() const noexcept; /** * Get the next key/value pair. * @@ -36,11 +39,24 @@ public: */ inline iterator& operator++() noexcept; /** - * Check if these key value pairs come from the same place in the JSON. + * Get the next key/value pair. + * + * Part of the std::iterator interface. + * + */ + inline iterator operator++(int) noexcept; + /** + * Check if these values come from the same place in the JSON. * * Part of the std::iterator interface. */ inline bool operator!=(const iterator& other) const noexcept; + inline bool operator==(const iterator& other) const noexcept; + + inline bool operator<(const iterator& other) const noexcept; + inline bool operator<=(const iterator& other) const noexcept; + inline bool operator>=(const iterator& other) const noexcept; + inline bool operator>(const iterator& other) const noexcept; /** * Get the key of this key/value pair. */ @@ -69,6 +85,10 @@ public: * Get the value of this key/value pair. */ inline element value() const noexcept; + + iterator() noexcept = default; + iterator(const iterator&) noexcept = default; + iterator& operator=(const iterator&) noexcept = default; private: really_inline iterator(const internal::tape_ref &tape) noexcept; @@ -261,4 +281,16 @@ inline std::ostream& operator<<(std::ostream& out, const simdjson_result + +namespace std::ranges { +template<> +inline constexpr bool enable_view = true; +} + +static_assert(std::ranges::view); +static_assert(std::ranges::sized_range); +#endif + #endif // SIMDJSON_DOM_OBJECT_H diff --git a/include/simdjson/inline/array.h b/include/simdjson/inline/array.h index 790977dd..8cc78432 100644 --- a/include/simdjson/inline/array.h +++ b/include/simdjson/inline/array.h @@ -106,14 +106,33 @@ really_inline array::iterator::iterator(const internal::tape_ref &_tape) noexcep inline element array::iterator::operator*() const noexcept { return element(tape); } -inline bool array::iterator::operator!=(const array::iterator& other) const noexcept { - return tape.json_index != other.tape.json_index; -} inline array::iterator& array::iterator::operator++() noexcept { tape.json_index = tape.after_element(); return *this; } - +inline array::iterator array::iterator::operator++(int) noexcept { + array::iterator out = *this; + ++*this; + return out; +} +inline bool array::iterator::operator!=(const array::iterator& other) const noexcept { + return tape.json_index != other.tape.json_index; +} +inline bool array::iterator::operator==(const array::iterator& other) const noexcept { + return tape.json_index == other.tape.json_index; +} +inline bool array::iterator::operator<(const array::iterator& other) const noexcept { + return tape.json_index < other.tape.json_index; +} +inline bool array::iterator::operator<=(const array::iterator& other) const noexcept { + return tape.json_index <= other.tape.json_index; +} +inline bool array::iterator::operator>=(const array::iterator& other) const noexcept { + return tape.json_index >= other.tape.json_index; +} +inline bool array::iterator::operator>(const array::iterator& other) const noexcept { + return tape.json_index > other.tape.json_index; +} inline std::ostream& operator<<(std::ostream& out, const array &value) { return out << minify(value); } diff --git a/include/simdjson/inline/object.h b/include/simdjson/inline/object.h index f12a5252..74a05a81 100644 --- a/include/simdjson/inline/object.h +++ b/include/simdjson/inline/object.h @@ -149,11 +149,31 @@ inline const key_value_pair object::iterator::operator*() const noexcept { inline bool object::iterator::operator!=(const object::iterator& other) const noexcept { return tape.json_index != other.tape.json_index; } +inline bool object::iterator::operator==(const object::iterator& other) const noexcept { + return tape.json_index == other.tape.json_index; +} +inline bool object::iterator::operator<(const object::iterator& other) const noexcept { + return tape.json_index < other.tape.json_index; +} +inline bool object::iterator::operator<=(const object::iterator& other) const noexcept { + return tape.json_index <= other.tape.json_index; +} +inline bool object::iterator::operator>=(const object::iterator& other) const noexcept { + return tape.json_index >= other.tape.json_index; +} +inline bool object::iterator::operator>(const object::iterator& other) const noexcept { + return tape.json_index > other.tape.json_index; +} inline object::iterator& object::iterator::operator++() noexcept { tape.json_index++; tape.json_index = tape.after_element(); return *this; } +inline object::iterator object::iterator::operator++(int) noexcept { + object::iterator out = *this; + ++*this; + return out; +} inline std::string_view object::iterator::key() const noexcept { return tape.get_string_view(); } diff --git a/singleheader/amalgamate_demo.cpp b/singleheader/amalgamate_demo.cpp index e485458f..7b675e39 100644 --- a/singleheader/amalgamate_demo.cpp +++ b/singleheader/amalgamate_demo.cpp @@ -1,4 +1,4 @@ -/* auto-generated on Mon Jul 6 18:16:52 EDT 2020. Do not edit! */ +/* auto-generated on Sun 19 Jul 2020 11:55:45 PM EDT. Do not edit! */ #include #include "simdjson.h" diff --git a/singleheader/simdjson.cpp b/singleheader/simdjson.cpp index dae19e04..4cd47640 100644 --- a/singleheader/simdjson.cpp +++ b/singleheader/simdjson.cpp @@ -1,4 +1,4 @@ -/* auto-generated on Mon Jul 6 18:16:52 EDT 2020. Do not edit! */ +/* auto-generated on Sun 19 Jul 2020 11:55:45 PM EDT. Do not edit! */ /* begin file src/simdjson.cpp */ #include "simdjson.h" @@ -4610,7 +4610,7 @@ namespace logger { namespace stage2 { namespace atomparsing { -really_inline uint32_t string_to_uint32(const char* str) { return *reinterpret_cast(str); } +really_inline uint32_t string_to_uint32(const char* str) { uint32_t val; std::memcpy(&val, str, sizeof(uint32_t)); return val; } WARN_UNUSED really_inline uint32_t str4ncmp(const uint8_t *src, const char* atom) { @@ -6704,7 +6704,7 @@ namespace logger { namespace stage2 { namespace atomparsing { -really_inline uint32_t string_to_uint32(const char* str) { return *reinterpret_cast(str); } +really_inline uint32_t string_to_uint32(const char* str) { uint32_t val; std::memcpy(&val, str, sizeof(uint32_t)); return val; } WARN_UNUSED really_inline uint32_t str4ncmp(const uint8_t *src, const char* atom) { @@ -9926,7 +9926,7 @@ namespace logger { namespace stage2 { namespace atomparsing { -really_inline uint32_t string_to_uint32(const char* str) { return *reinterpret_cast(str); } +really_inline uint32_t string_to_uint32(const char* str) { uint32_t val; std::memcpy(&val, str, sizeof(uint32_t)); return val; } WARN_UNUSED really_inline uint32_t str4ncmp(const uint8_t *src, const char* atom) { @@ -13124,7 +13124,7 @@ namespace logger { namespace stage2 { namespace atomparsing { -really_inline uint32_t string_to_uint32(const char* str) { return *reinterpret_cast(str); } +really_inline uint32_t string_to_uint32(const char* str) { uint32_t val; std::memcpy(&val, str, sizeof(uint32_t)); return val; } WARN_UNUSED really_inline uint32_t str4ncmp(const uint8_t *src, const char* atom) { diff --git a/singleheader/simdjson.h b/singleheader/simdjson.h index 0fe96e93..872d9967 100644 --- a/singleheader/simdjson.h +++ b/singleheader/simdjson.h @@ -1,4 +1,4 @@ -/* auto-generated on Mon Jul 6 18:16:52 EDT 2020. Do not edit! */ +/* auto-generated on Sun 19 Jul 2020 11:55:45 PM EDT. Do not edit! */ /* begin file include/simdjson.h */ #ifndef SIMDJSON_H #define SIMDJSON_H @@ -3073,10 +3073,13 @@ public: class iterator { public: + using value_type = element; + using difference_type = std::ptrdiff_t; + /** * Get the actual value */ - inline element operator*() const noexcept; + inline value_type operator*() const noexcept; /** * Get the next value. * @@ -3084,12 +3087,28 @@ public: * */ inline iterator& operator++() noexcept; + /** + * Get the next value. + * + * Part of the std::iterator interface. + */ + inline iterator operator++(int) noexcept; /** * Check if these values come from the same place in the JSON. * * Part of the std::iterator interface. */ inline bool operator!=(const iterator& other) const noexcept; + inline bool operator==(const iterator& other) const noexcept; + + inline bool operator<(const iterator& other) const noexcept; + inline bool operator<=(const iterator& other) const noexcept; + inline bool operator>=(const iterator& other) const noexcept; + inline bool operator>(const iterator& other) const noexcept; + + iterator() noexcept = default; + iterator(const iterator&) noexcept = default; + iterator& operator=(const iterator&) noexcept = default; private: really_inline iterator(const internal::tape_ref &tape) noexcept; internal::tape_ref tape; @@ -3205,6 +3224,18 @@ inline std::ostream& operator<<(std::ostream& out, const simdjson_result + +namespace std::ranges { +template<> +inline constexpr bool enable_view = true; +} + +static_assert(std::ranges::view); +static_assert(std::ranges::sized_range); +#endif + #endif // SIMDJSON_DOM_ARRAY_H /* end file include/simdjson/minify.h */ /* begin file include/simdjson/dom/document_stream.h */ @@ -4539,10 +4570,13 @@ public: class iterator { public: + using value_type = key_value_pair; + using difference_type = std::ptrdiff_t; + /** * Get the actual key/value pair */ - inline const key_value_pair operator*() const noexcept; + inline const value_type operator*() const noexcept; /** * Get the next key/value pair. * @@ -4551,11 +4585,24 @@ public: */ inline iterator& operator++() noexcept; /** - * Check if these key value pairs come from the same place in the JSON. + * Get the next key/value pair. + * + * Part of the std::iterator interface. + * + */ + inline iterator operator++(int) noexcept; + /** + * Check if these values come from the same place in the JSON. * * Part of the std::iterator interface. */ inline bool operator!=(const iterator& other) const noexcept; + inline bool operator==(const iterator& other) const noexcept; + + inline bool operator<(const iterator& other) const noexcept; + inline bool operator<=(const iterator& other) const noexcept; + inline bool operator>=(const iterator& other) const noexcept; + inline bool operator>(const iterator& other) const noexcept; /** * Get the key of this key/value pair. */ @@ -4584,6 +4631,10 @@ public: * Get the value of this key/value pair. */ inline element value() const noexcept; + + iterator() noexcept = default; + iterator(const iterator&) noexcept = default; + iterator& operator=(const iterator&) noexcept = default; private: really_inline iterator(const internal::tape_ref &tape) noexcept; @@ -4776,6 +4827,18 @@ inline std::ostream& operator<<(std::ostream& out, const simdjson_result + +namespace std::ranges { +template<> +inline constexpr bool enable_view = true; +} + +static_assert(std::ranges::view); +static_assert(std::ranges::sized_range); +#endif + #endif // SIMDJSON_DOM_OBJECT_H /* end file include/simdjson/dom/object.h */ @@ -5379,14 +5442,33 @@ really_inline array::iterator::iterator(const internal::tape_ref &_tape) noexcep inline element array::iterator::operator*() const noexcept { return element(tape); } -inline bool array::iterator::operator!=(const array::iterator& other) const noexcept { - return tape.json_index != other.tape.json_index; -} inline array::iterator& array::iterator::operator++() noexcept { tape.json_index = tape.after_element(); return *this; } - +inline array::iterator array::iterator::operator++(int) noexcept { + array::iterator out = *this; + ++*this; + return out; +} +inline bool array::iterator::operator!=(const array::iterator& other) const noexcept { + return tape.json_index != other.tape.json_index; +} +inline bool array::iterator::operator==(const array::iterator& other) const noexcept { + return tape.json_index == other.tape.json_index; +} +inline bool array::iterator::operator<(const array::iterator& other) const noexcept { + return tape.json_index < other.tape.json_index; +} +inline bool array::iterator::operator<=(const array::iterator& other) const noexcept { + return tape.json_index <= other.tape.json_index; +} +inline bool array::iterator::operator>=(const array::iterator& other) const noexcept { + return tape.json_index >= other.tape.json_index; +} +inline bool array::iterator::operator>(const array::iterator& other) const noexcept { + return tape.json_index > other.tape.json_index; +} inline std::ostream& operator<<(std::ostream& out, const array &value) { return out << minify(value); } @@ -6659,11 +6741,31 @@ inline const key_value_pair object::iterator::operator*() const noexcept { inline bool object::iterator::operator!=(const object::iterator& other) const noexcept { return tape.json_index != other.tape.json_index; } +inline bool object::iterator::operator==(const object::iterator& other) const noexcept { + return tape.json_index == other.tape.json_index; +} +inline bool object::iterator::operator<(const object::iterator& other) const noexcept { + return tape.json_index < other.tape.json_index; +} +inline bool object::iterator::operator<=(const object::iterator& other) const noexcept { + return tape.json_index <= other.tape.json_index; +} +inline bool object::iterator::operator>=(const object::iterator& other) const noexcept { + return tape.json_index >= other.tape.json_index; +} +inline bool object::iterator::operator>(const object::iterator& other) const noexcept { + return tape.json_index > other.tape.json_index; +} inline object::iterator& object::iterator::operator++() noexcept { tape.json_index++; tape.json_index = tape.after_element(); return *this; } +inline object::iterator object::iterator::operator++(int) noexcept { + object::iterator out = *this; + ++*this; + return out; +} inline std::string_view object::iterator::key() const noexcept { return tape.get_string_view(); }