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.
This commit is contained in:
Joe Jevnik 2020-07-21 13:27:39 -04:00 committed by GitHub
parent f016c2b72f
commit d2bea0c228
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 225 additions and 21 deletions

View File

@ -23,10 +23,13 @@ public:
class iterator { class iterator {
public: public:
using value_type = element;
using difference_type = std::ptrdiff_t;
/** /**
* Get the actual value * Get the actual value
*/ */
inline element operator*() const noexcept; inline value_type operator*() const noexcept;
/** /**
* Get the next value. * Get the next value.
* *
@ -34,12 +37,28 @@ public:
* *
*/ */
inline iterator& operator++() noexcept; 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. * Check if these values come from the same place in the JSON.
* *
* Part of the std::iterator interface. * 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;
inline bool operator>(const iterator& other) const noexcept;
iterator() noexcept = default;
iterator(const iterator&) noexcept = default;
iterator& operator=(const iterator&) noexcept = default;
private: private:
really_inline iterator(const internal::tape_ref &tape) noexcept; really_inline iterator(const internal::tape_ref &tape) noexcept;
internal::tape_ref tape; internal::tape_ref tape;
@ -155,4 +174,16 @@ inline std::ostream& operator<<(std::ostream& out, const simdjson_result<dom::ar
} // namespace simdjson } // namespace simdjson
#if defined(__cpp_lib_ranges)
#include <ranges>
namespace std::ranges {
template<>
inline constexpr bool enable_view<simdjson::dom::array> = true;
}
static_assert(std::ranges::view<simdjson::dom::array>);
static_assert(std::ranges::sized_range<simdjson::dom::array>);
#endif
#endif // SIMDJSON_DOM_ARRAY_H #endif // SIMDJSON_DOM_ARRAY_H

View File

@ -24,10 +24,13 @@ public:
class iterator { class iterator {
public: public:
using value_type = key_value_pair;
using difference_type = std::ptrdiff_t;
/** /**
* Get the actual key/value pair * 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. * Get the next key/value pair.
* *
@ -36,11 +39,24 @@ public:
*/ */
inline iterator& operator++() noexcept; 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. * 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;
inline bool operator>(const iterator& other) const noexcept;
/** /**
* Get the key of this key/value pair. * Get the key of this key/value pair.
*/ */
@ -69,6 +85,10 @@ public:
* Get the value of this key/value pair. * Get the value of this key/value pair.
*/ */
inline element value() const noexcept; inline element value() const noexcept;
iterator() noexcept = default;
iterator(const iterator&) noexcept = default;
iterator& operator=(const iterator&) noexcept = default;
private: private:
really_inline iterator(const internal::tape_ref &tape) noexcept; really_inline iterator(const internal::tape_ref &tape) noexcept;
@ -261,4 +281,16 @@ inline std::ostream& operator<<(std::ostream& out, const simdjson_result<dom::ob
} // namespace simdjson } // namespace simdjson
#if defined(__cpp_lib_ranges)
#include <ranges>
namespace std::ranges {
template<>
inline constexpr bool enable_view<simdjson::dom::object> = true;
}
static_assert(std::ranges::view<simdjson::dom::object>);
static_assert(std::ranges::sized_range<simdjson::dom::object>);
#endif
#endif // SIMDJSON_DOM_OBJECT_H #endif // SIMDJSON_DOM_OBJECT_H

View File

@ -106,14 +106,33 @@ really_inline array::iterator::iterator(const internal::tape_ref &_tape) noexcep
inline element array::iterator::operator*() const noexcept { inline element array::iterator::operator*() const noexcept {
return element(tape); 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 { inline array::iterator& array::iterator::operator++() noexcept {
tape.json_index = tape.after_element(); tape.json_index = tape.after_element();
return *this; 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) { inline std::ostream& operator<<(std::ostream& out, const array &value) {
return out << minify<array>(value); return out << minify<array>(value);
} }

View File

@ -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 { inline bool object::iterator::operator!=(const object::iterator& other) const noexcept {
return tape.json_index != other.tape.json_index; 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 { inline object::iterator& object::iterator::operator++() noexcept {
tape.json_index++; tape.json_index++;
tape.json_index = tape.after_element(); tape.json_index = tape.after_element();
return *this; 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 { inline std::string_view object::iterator::key() const noexcept {
return tape.get_string_view(); return tape.get_string_view();
} }

View File

@ -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 <iostream> #include <iostream>
#include "simdjson.h" #include "simdjson.h"

View File

@ -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 */ /* begin file src/simdjson.cpp */
#include "simdjson.h" #include "simdjson.h"
@ -4610,7 +4610,7 @@ namespace logger {
namespace stage2 { namespace stage2 {
namespace atomparsing { namespace atomparsing {
really_inline uint32_t string_to_uint32(const char* str) { return *reinterpret_cast<const uint32_t *>(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 WARN_UNUSED
really_inline uint32_t str4ncmp(const uint8_t *src, const char* atom) { really_inline uint32_t str4ncmp(const uint8_t *src, const char* atom) {
@ -6704,7 +6704,7 @@ namespace logger {
namespace stage2 { namespace stage2 {
namespace atomparsing { namespace atomparsing {
really_inline uint32_t string_to_uint32(const char* str) { return *reinterpret_cast<const uint32_t *>(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 WARN_UNUSED
really_inline uint32_t str4ncmp(const uint8_t *src, const char* atom) { really_inline uint32_t str4ncmp(const uint8_t *src, const char* atom) {
@ -9926,7 +9926,7 @@ namespace logger {
namespace stage2 { namespace stage2 {
namespace atomparsing { namespace atomparsing {
really_inline uint32_t string_to_uint32(const char* str) { return *reinterpret_cast<const uint32_t *>(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 WARN_UNUSED
really_inline uint32_t str4ncmp(const uint8_t *src, const char* atom) { really_inline uint32_t str4ncmp(const uint8_t *src, const char* atom) {
@ -13124,7 +13124,7 @@ namespace logger {
namespace stage2 { namespace stage2 {
namespace atomparsing { namespace atomparsing {
really_inline uint32_t string_to_uint32(const char* str) { return *reinterpret_cast<const uint32_t *>(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 WARN_UNUSED
really_inline uint32_t str4ncmp(const uint8_t *src, const char* atom) { really_inline uint32_t str4ncmp(const uint8_t *src, const char* atom) {

View File

@ -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 */ /* begin file include/simdjson.h */
#ifndef SIMDJSON_H #ifndef SIMDJSON_H
#define SIMDJSON_H #define SIMDJSON_H
@ -3073,10 +3073,13 @@ public:
class iterator { class iterator {
public: public:
using value_type = element;
using difference_type = std::ptrdiff_t;
/** /**
* Get the actual value * Get the actual value
*/ */
inline element operator*() const noexcept; inline value_type operator*() const noexcept;
/** /**
* Get the next value. * Get the next value.
* *
@ -3084,12 +3087,28 @@ public:
* *
*/ */
inline iterator& operator++() noexcept; 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. * Check if these values come from the same place in the JSON.
* *
* Part of the std::iterator interface. * 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;
inline bool operator>(const iterator& other) const noexcept;
iterator() noexcept = default;
iterator(const iterator&) noexcept = default;
iterator& operator=(const iterator&) noexcept = default;
private: private:
really_inline iterator(const internal::tape_ref &tape) noexcept; really_inline iterator(const internal::tape_ref &tape) noexcept;
internal::tape_ref tape; internal::tape_ref tape;
@ -3205,6 +3224,18 @@ inline std::ostream& operator<<(std::ostream& out, const simdjson_result<dom::ar
} // namespace simdjson } // namespace simdjson
#if defined(__cpp_lib_ranges)
#include <ranges>
namespace std::ranges {
template<>
inline constexpr bool enable_view<simdjson::dom::array> = true;
}
static_assert(std::ranges::view<simdjson::dom::array>);
static_assert(std::ranges::sized_range<simdjson::dom::array>);
#endif
#endif // SIMDJSON_DOM_ARRAY_H #endif // SIMDJSON_DOM_ARRAY_H
/* end file include/simdjson/minify.h */ /* end file include/simdjson/minify.h */
/* begin file include/simdjson/dom/document_stream.h */ /* begin file include/simdjson/dom/document_stream.h */
@ -4539,10 +4570,13 @@ public:
class iterator { class iterator {
public: public:
using value_type = key_value_pair;
using difference_type = std::ptrdiff_t;
/** /**
* Get the actual key/value pair * 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. * Get the next key/value pair.
* *
@ -4551,11 +4585,24 @@ public:
*/ */
inline iterator& operator++() noexcept; 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. * 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;
inline bool operator>(const iterator& other) const noexcept;
/** /**
* Get the key of this key/value pair. * Get the key of this key/value pair.
*/ */
@ -4584,6 +4631,10 @@ public:
* Get the value of this key/value pair. * Get the value of this key/value pair.
*/ */
inline element value() const noexcept; inline element value() const noexcept;
iterator() noexcept = default;
iterator(const iterator&) noexcept = default;
iterator& operator=(const iterator&) noexcept = default;
private: private:
really_inline iterator(const internal::tape_ref &tape) noexcept; really_inline iterator(const internal::tape_ref &tape) noexcept;
@ -4776,6 +4827,18 @@ inline std::ostream& operator<<(std::ostream& out, const simdjson_result<dom::ob
} // namespace simdjson } // namespace simdjson
#if defined(__cpp_lib_ranges)
#include <ranges>
namespace std::ranges {
template<>
inline constexpr bool enable_view<simdjson::dom::object> = true;
}
static_assert(std::ranges::view<simdjson::dom::object>);
static_assert(std::ranges::sized_range<simdjson::dom::object>);
#endif
#endif // SIMDJSON_DOM_OBJECT_H #endif // SIMDJSON_DOM_OBJECT_H
/* end file include/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 { inline element array::iterator::operator*() const noexcept {
return element(tape); 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 { inline array::iterator& array::iterator::operator++() noexcept {
tape.json_index = tape.after_element(); tape.json_index = tape.after_element();
return *this; 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) { inline std::ostream& operator<<(std::ostream& out, const array &value) {
return out << minify<array>(value); return out << minify<array>(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 { inline bool object::iterator::operator!=(const object::iterator& other) const noexcept {
return tape.json_index != other.tape.json_index; 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 { inline object::iterator& object::iterator::operator++() noexcept {
tape.json_index++; tape.json_index++;
tape.json_index = tape.after_element(); tape.json_index = tape.after_element();
return *this; 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 { inline std::string_view object::iterator::key() const noexcept {
return tape.get_string_view(); return tape.get_string_view();
} }