//----------------------------------------------------------------------------- // ___ __ _ _ // / _ \__ _ _ __ ___ ___ / /(_)_ __ | | __ // / /_)/ _` | '__/ __|/ _ \/ / | | '_ \| |/ / // / ___/ (_| | | \__ \ __/ /__| | | | | < // \/ \__,_|_| |___/\___\____/_|_| |_|_|\_\ . // //----------------------------------------------------------------------------- // Author: Kurt Sassenrath // Module: msgpack // // Token view utilities. // // MessagePack maps and arrays are nested, and the token reader only parses // out the type. This file provides utilities for iterating over these // "container" formats without incurring additional overhead on the parser when // it is not needed. // // Copyright (c) 2023 Kurt Sassenrath. // // License TBD. //----------------------------------------------------------------------------- #ifndef msgpack_token_views_f19c250e782ed51c #define msgpack_token_views_f19c250e782ed51c #include "type.h" #include #include #include namespace msgpack { template requires std::ranges::input_range && std::same_as> struct map_view : public std::ranges::view_interface> { public: class sentinel; class iterator { friend class sentinel; using base_iterator = std::ranges::iterator_t; using base_sentinel = std::ranges::sentinel_t; using base_value_type = std::ranges::range_value_t; using base_reference = std::ranges::range_reference_t; base_iterator next(base_iterator current, std::size_t n = 1) { while (n && current != std::ranges::end(*base_)) { if (auto m = current->template get(); m) { n += m->count * 2; } else if (auto m = current->template get(); m) { n += m->count; } ++current; --n; } return current; } public: using value_type = std::pair; using reference = std::pair; using difference_type = std::ptrdiff_t; using iterator_category = std::input_iterator_tag; iterator() = default; iterator(V const& base) : base_{&base} , k_{std::ranges::begin(base)} { // Ensure that k_ points to a map_desc. If not, then we // effectively treat this as the end. if (k_->type() == msgpack::format::type::map) { remaining_ = k_->template get()->count + 1; // Advance to the first entry in the map. ++k_; v_ = next(k_); } } [[nodiscard]] reference operator*() const { return {*k_, *v_}; } iterator& operator++() { k_ = next(v_); v_ = next(k_); --remaining_; return *this; } [[nodiscard]] iterator operator++(int) { auto tmp = *this; ++(*this); return tmp; } [[nodiscard]] bool operator==(iterator const& rhs) const { return k_ == rhs.remaining_ && base_ == rhs.base_; } private: V const* base_{}; base_iterator k_{}; base_iterator v_{}; std::size_t remaining_{}; }; class sentinel { public: [[nodiscard]] bool operator==(sentinel const&) const { return true; } [[nodiscard]] bool operator==(iterator const& rhs) const { return rhs.remaining_ == 0 || rhs.k_ == std::ranges::end(*rhs.base_); } }; constexpr map_view() noexcept = default; constexpr map_view(V base) : base_{std::move(base)} {} [[nodiscard]] constexpr iterator begin() const { return {base_}; } [[nodiscard]] constexpr sentinel end() const { return {}; } private: V base_; }; template map_view(Range&&) -> map_view>; } // namespace msgpack #endif // msgpack_token_views_f19c250e782ed51c