138 lines
4.2 KiB
C++
138 lines
4.2 KiB
C++
//-----------------------------------------------------------------------------
|
|
// ___ __ _ _
|
|
// / _ \__ _ _ __ ___ ___ / /(_)_ __ | | __
|
|
// / /_)/ _` | '__/ __|/ _ \/ / | | '_ \| |/ /
|
|
// / ___/ (_| | | \__ \ __/ /__| | | | | <
|
|
// \/ \__,_|_| |___/\___\____/_|_| |_|_|\_\ .
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
// 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 <bits/iterator_concepts.h>
|
|
#include <ranges>
|
|
|
|
#include <fmt/format.h>
|
|
|
|
namespace msgpack {
|
|
|
|
template <std::ranges::view V>
|
|
requires std::ranges::input_range<V>
|
|
&& std::same_as<token, std::ranges::range_value_t<V>>
|
|
struct map_view : public std::ranges::view_interface<map_view<V>> {
|
|
public:
|
|
class sentinel;
|
|
|
|
class iterator {
|
|
friend class sentinel;
|
|
|
|
using base_iterator = std::ranges::iterator_t<V>;
|
|
using base_sentinel = std::ranges::sentinel_t<V>;
|
|
using base_value_type = std::ranges::range_value_t<V>;
|
|
using base_reference = std::ranges::range_reference_t<V>;
|
|
|
|
base_iterator next(base_iterator current, std::size_t n = 1) {
|
|
while (n && current != std::ranges::end(*base_)) {
|
|
if (auto m = current->template get<map_desc>(); m) {
|
|
n += m->count * 2;
|
|
} else if (auto m = current->template get<array_desc>(); m) {
|
|
n += m->count;
|
|
}
|
|
++current;
|
|
--n;
|
|
}
|
|
return current;
|
|
}
|
|
|
|
public:
|
|
using value_type = std::pair<base_value_type, base_value_type>;
|
|
using reference = std::pair<base_reference, base_reference>;
|
|
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<msgpack::map_desc>()->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 <class Range>
|
|
map_view(Range&&) -> map_view<std::views::all_t<Range>>;
|
|
|
|
} // namespace msgpack
|
|
|
|
#endif // msgpack_token_views_f19c250e782ed51c
|