mirror of
https://github.com/boostorg/parser.git
synced 2026-01-20 04:42:22 +00:00
Compare commits
1 Commits
boost-1.88
...
packrat
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
06fb60c78f |
@@ -51,14 +51,16 @@ namespace boost { namespace parser {
|
||||
typename S,
|
||||
typename ErrorHandler,
|
||||
typename GlobalState>
|
||||
using minimal_parse_context = decltype(detail::make_context<false, false>(
|
||||
std::declval<I>(),
|
||||
std::declval<S>(),
|
||||
std::declval<bool &>(),
|
||||
std::declval<int &>(),
|
||||
std::declval<ErrorHandler const &>(),
|
||||
std::declval<detail::nope &>(),
|
||||
std::declval<detail::symbol_table_tries_t &>()));
|
||||
using minimal_parse_context =
|
||||
decltype(detail::make_context<false, false>(
|
||||
std::declval<I>(),
|
||||
std::declval<S>(),
|
||||
std::declval<bool &>(),
|
||||
std::declval<int &>(),
|
||||
std::declval<ErrorHandler const &>(),
|
||||
std::declval<detail::nope &>(),
|
||||
std::declval<detail::symbol_table_tries_t &>(),
|
||||
std::declval<detail::nope &>()));
|
||||
|
||||
template<typename T, typename I, typename S, typename GlobalState>
|
||||
concept error_handler =
|
||||
|
||||
44
include/boost/parser/detail/counted_iterator.hpp
Normal file
44
include/boost/parser/detail/counted_iterator.hpp
Normal file
@@ -0,0 +1,44 @@
|
||||
#ifndef BOOST_PARSER_DETAIL_COUNTED_ITERATOR_HPP
|
||||
#define BOOST_PARSER_DETAIL_COUNTED_ITERATOR_HPP
|
||||
|
||||
#include <boost/parser/detail/stl_interfaces/iterator_interface.hpp>
|
||||
|
||||
|
||||
namespace boost::parser::detail {
|
||||
|
||||
template<typename I, typename S>
|
||||
struct counted_iterator
|
||||
: stl_interfaces::iterator_interface<
|
||||
counted_iterator<I, S>,
|
||||
std::forward_iterator_tag,
|
||||
std::remove_cv_t<
|
||||
std::remove_reference_t<decltype(*std::declval<I>())>>,
|
||||
decltype(*std::declval<I>())>
|
||||
{
|
||||
constexpr counted_iterator() = default;
|
||||
constexpr explicit counted_iterator(I & it) : it_(it) {}
|
||||
|
||||
constexpr size_t count() const { return count_; }
|
||||
constexpr bool operator==(S last) const { return it_ == last; }
|
||||
constexpr I base() const { return it_; }
|
||||
|
||||
constexpr counted_iterator & operator++()
|
||||
{
|
||||
++it_;
|
||||
++count_;
|
||||
return this;
|
||||
}
|
||||
|
||||
private:
|
||||
friend stl_interfaces::access;
|
||||
|
||||
constexpr I & base_reference() { return it_; }
|
||||
constexpr I base_reference() const { return it_; }
|
||||
|
||||
I it_ = I();
|
||||
size_t count_ = 0;
|
||||
};
|
||||
//
|
||||
}
|
||||
|
||||
#endif
|
||||
458
include/boost/parser/detail/memos.hpp
Normal file
458
include/boost/parser/detail/memos.hpp
Normal file
@@ -0,0 +1,458 @@
|
||||
#ifndef BOOST_PARSER_DETAIL_MEMOS_HPP
|
||||
#define BOOST_PARSER_DETAIL_MEMOS_HPP
|
||||
|
||||
#if __has_include(<boost/unordered/unordered_flat_map.hpp>)
|
||||
#include <boost/unordered/unordered_flat_map.hpp>
|
||||
#define BOOST_PARSER_HAVE_BOOST_UNORDERED_FLAT_MAP 1
|
||||
#define BOOST_PARSER_MEMO_NS boost_unordered_flat_map
|
||||
#else
|
||||
#define BOOST_PARSER_HAVE_BOOST_UNORDERED_FLAT_MAP 0
|
||||
#define BOOST_PARSER_MEMO_NS std_containers
|
||||
#endif
|
||||
|
||||
#include <algorithm>
|
||||
#include <type_traits>
|
||||
#include <typeinfo>
|
||||
#include <unordered_map>
|
||||
#include <variant> // monostate
|
||||
#include <vector>
|
||||
|
||||
|
||||
namespace boost::parser::detail {
|
||||
|
||||
inline constexpr unsigned int next_pot(unsigned int i)
|
||||
{
|
||||
--i;
|
||||
i |= i >> 1;
|
||||
i |= i >> 2;
|
||||
i |= i >> 4;
|
||||
i |= i >> 8;
|
||||
i |= i >> 16;
|
||||
return ++i;
|
||||
}
|
||||
|
||||
template<int Size, int Align>
|
||||
struct trivial_type
|
||||
{};
|
||||
template<typename T>
|
||||
using trivial_type_for = trivial_type<sizeof(T), alignof(T)>;
|
||||
|
||||
template<typename T, int N>
|
||||
struct list_node
|
||||
{
|
||||
list_node() = default;
|
||||
list_node(list_node * n) : next(n) {}
|
||||
~list_node()
|
||||
{
|
||||
for (int i = 0; i < size; ++i) {
|
||||
void * pos = buf + i * sizeof(T);
|
||||
T * obj = static_cast<T *>(pos);
|
||||
obj->~T();
|
||||
}
|
||||
}
|
||||
void * push() { return buf + size++ * sizeof(T); }
|
||||
void * get(int n) { return buf + n * sizeof(T); }
|
||||
alignas(T[N]) std::byte buf[sizeof(T[N])];
|
||||
list_node * next = nullptr;
|
||||
int size = 0;
|
||||
};
|
||||
|
||||
template<int Size, int Align, int N>
|
||||
struct list_node<trivial_type<Size, Align>, N>
|
||||
{
|
||||
list_node() = default;
|
||||
list_node(list_node * n) : next(n) {}
|
||||
~list_node() {}
|
||||
void * push() { return buf + size++ * Size; }
|
||||
void * get(int n) { return buf + n * Size; }
|
||||
alignas(Align) std::byte buf[Size * N];
|
||||
list_node * next = nullptr;
|
||||
int size = 0;
|
||||
};
|
||||
|
||||
template<typename T, int N>
|
||||
struct linked_list
|
||||
{
|
||||
using list_node_type = list_node<T, N>;
|
||||
|
||||
linked_list() = default;
|
||||
linked_list(linked_list const &) = delete;
|
||||
linked_list & operator=(linked_list const &) = delete;
|
||||
~linked_list()
|
||||
{
|
||||
while (head_) {
|
||||
auto * node = head_;
|
||||
head_ = head_->next;
|
||||
delete node;
|
||||
}
|
||||
}
|
||||
|
||||
// The bool indicates whether placement new is required.
|
||||
std::pair<void *, bool> push()
|
||||
{
|
||||
if (next_.node) {
|
||||
if (next_.idx == next_.node->size) {
|
||||
next_.node = next_.node->next;
|
||||
next_.idx = 0;
|
||||
}
|
||||
if (next_.node && next_.idx < next_.node->size)
|
||||
return {next_.node->get(next_.idx++), false};
|
||||
}
|
||||
|
||||
if (!head_)
|
||||
head_ = new list_node_type();
|
||||
else if (head_->size == N)
|
||||
head_ = new list_node_type(head_);
|
||||
return {head_->push(), true};
|
||||
}
|
||||
|
||||
void reclaim() { next_ = {head_, 0}; }
|
||||
|
||||
private:
|
||||
struct position
|
||||
{
|
||||
list_node_type * node = nullptr;
|
||||
int idx = 0;
|
||||
};
|
||||
list_node_type * head_ = nullptr;
|
||||
position next_{};
|
||||
};
|
||||
|
||||
// http://jonkagstrom.com/mx3/mx3_rev2.html
|
||||
inline size_t hash_mix(size_t x)
|
||||
{
|
||||
size_t const m = 0xe9846af9b1a615d;
|
||||
x ^= x >> 32;
|
||||
x *= m;
|
||||
x ^= x >> 32;
|
||||
x *= m;
|
||||
x ^= x >> 28;
|
||||
return x;
|
||||
}
|
||||
|
||||
inline size_t hash_combine(size_t seed) { return seed; }
|
||||
template<typename T, typename... Ts>
|
||||
size_t hash_combine(size_t seed, T const & x, Ts const &... xs)
|
||||
{
|
||||
auto next_seed =
|
||||
detail::hash_mix(seed + 0x9e3779b9 + std::hash<T>{}(x));
|
||||
return detail::hash_combine(next_seed, xs...);
|
||||
}
|
||||
|
||||
struct memo_items_base
|
||||
{
|
||||
memo_items_base(size_t id_token)
|
||||
#if !BOOST_PARSER_HAVE_BOOST_UNORDERED_FLAT_MAP
|
||||
:
|
||||
id_token_(id_token)
|
||||
#endif
|
||||
{}
|
||||
virtual ~memo_items_base() = 0;
|
||||
virtual std::pair<void *, bool> new_item() = 0;
|
||||
virtual void reclaim() = 0;
|
||||
#if !BOOST_PARSER_HAVE_BOOST_UNORDERED_FLAT_MAP
|
||||
size_t const id_token_ = 0;
|
||||
#endif
|
||||
};
|
||||
|
||||
inline memo_items_base::~memo_items_base() {}
|
||||
|
||||
inline constexpr size_t max_tidy_bytes = 16; // TODO: Tune.
|
||||
|
||||
template<typename T>
|
||||
constexpr bool tidy = std::is_trivially_copyable_v<T> &&
|
||||
std::is_trivially_destructible_v<T> &&
|
||||
sizeof(T) < max_tidy_bytes;
|
||||
template<typename T>
|
||||
constexpr bool fat = 256 < sizeof(T);
|
||||
|
||||
template<typename T, bool Fat = fat<T>>
|
||||
struct memo_items_impl : memo_items_base
|
||||
{
|
||||
memo_items_impl() : memo_items_base(typeid(T).hash_code()) {}
|
||||
|
||||
virtual ~memo_items_impl() = default;
|
||||
|
||||
virtual std::pair<void *, bool> new_item() { return list_.push(); }
|
||||
virtual void reclaim() { list_.reclaim(); }
|
||||
|
||||
private:
|
||||
linked_list<T, 16> list_; // TODO: Try with other values of N too.
|
||||
};
|
||||
|
||||
template<int Size, int Align, bool Fat>
|
||||
struct memo_items_impl<trivial_type<Size, Align>, Fat> : memo_items_base
|
||||
{
|
||||
memo_items_impl() :
|
||||
memo_items_base(typeid(trivial_type<Size, Align>).hash_code())
|
||||
{}
|
||||
|
||||
virtual ~memo_items_impl() = default;
|
||||
|
||||
virtual std::pair<void *, bool> new_item() { return list_.push(); }
|
||||
virtual void reclaim() { list_.reclaim(); }
|
||||
|
||||
private:
|
||||
linked_list<trivial_type<Size, Align>, 64> list_;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct memo_items_impl<T, true> : memo_items_base
|
||||
{
|
||||
memo_items_impl() : memo_items_base(typeid(T).hash_code()) {}
|
||||
|
||||
virtual ~memo_items_impl() = default;
|
||||
|
||||
virtual std::pair<void *, bool> new_item() { return list_.push(); }
|
||||
virtual void reclaim() { list_.reclaim(); }
|
||||
|
||||
private:
|
||||
linked_list<T, 1> list_;
|
||||
};
|
||||
|
||||
struct identity
|
||||
{
|
||||
template<typename T>
|
||||
constexpr decltype(auto) operator()(T && x) const
|
||||
{
|
||||
return (T &&) x;
|
||||
}
|
||||
};
|
||||
|
||||
inline namespace BOOST_PARSER_MEMO_NS {
|
||||
|
||||
template<
|
||||
typename Key,
|
||||
typename OtherDatum = std::monostate,
|
||||
typename Proj = identity>
|
||||
struct memos
|
||||
{
|
||||
memos() = default;
|
||||
explicit memos(Proj proj) : proj_(std::move(proj)) {}
|
||||
~memos()
|
||||
{
|
||||
#if BOOST_PARSER_HAVE_BOOST_UNORDERED_FLAT_MAP
|
||||
for (auto [key, value] : memo_items_) {
|
||||
delete value;
|
||||
}
|
||||
#else
|
||||
for (auto value : memo_items_) {
|
||||
delete value;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
enum kind { success, failure };
|
||||
|
||||
template<typename A>
|
||||
struct monostate_ptr_like
|
||||
{
|
||||
monostate_ptr_like() : valid(false) {}
|
||||
explicit monostate_ptr_like(bool v) : valid(v) {}
|
||||
explicit operator bool() const { return valid; }
|
||||
bool operator==(nullptr_t) const { return !valid; }
|
||||
A & operator*() { return value; }
|
||||
A const & operator*() const { return value; }
|
||||
A value = A();
|
||||
bool valid = false;
|
||||
static_assert(std::is_empty_v<A>);
|
||||
};
|
||||
|
||||
template<typename A, bool Empty = std::is_empty_v<A>>
|
||||
struct ref
|
||||
{
|
||||
ref() = default;
|
||||
ref(A * v, OtherDatum * od) : valid(true), value(v), datum(od)
|
||||
{}
|
||||
explicit operator bool() const { return valid; }
|
||||
kind get_kind() const
|
||||
{
|
||||
return value == nullptr ? failure : success;
|
||||
}
|
||||
|
||||
bool valid = false;
|
||||
A * value = nullptr;
|
||||
OtherDatum * datum = 0;
|
||||
};
|
||||
template<typename A>
|
||||
struct ref<A, true>
|
||||
{
|
||||
ref() = default;
|
||||
ref(A *, OtherDatum * od) : valid(true), value(true), datum(od)
|
||||
{}
|
||||
explicit operator bool() const { return valid; }
|
||||
kind get_kind() const
|
||||
{
|
||||
return value == nullptr ? failure : success;
|
||||
}
|
||||
|
||||
bool valid = false;
|
||||
monostate_ptr_like<A> value;
|
||||
OtherDatum * datum = 0;
|
||||
};
|
||||
|
||||
template<typename A, bool Empty = std::is_empty_v<A>>
|
||||
struct const_ref
|
||||
{
|
||||
const_ref() = default;
|
||||
const_ref(A const * v, OtherDatum const * od) :
|
||||
valid(true), value(v), datum(od)
|
||||
{}
|
||||
explicit operator bool() const { return valid; }
|
||||
kind get_kind() const
|
||||
{
|
||||
return value == nullptr ? failure : success;
|
||||
}
|
||||
|
||||
bool valid = false;
|
||||
A const * value = nullptr;
|
||||
OtherDatum const * datum = 0;
|
||||
};
|
||||
template<typename A>
|
||||
struct const_ref<A, true>
|
||||
{
|
||||
const_ref() = default;
|
||||
const_ref(A const *, OtherDatum const * od) :
|
||||
valid(true), value(true), datum(od)
|
||||
{}
|
||||
explicit operator bool() const { return valid; }
|
||||
kind get_kind() const
|
||||
{
|
||||
return value == nullptr ? failure : success;
|
||||
}
|
||||
|
||||
bool valid = false;
|
||||
monostate_ptr_like<A> value;
|
||||
OtherDatum const * datum = 0;
|
||||
};
|
||||
|
||||
template<typename P, typename A, typename... Params>
|
||||
ref<A> insert(kind k, Key key, Params const &... params)
|
||||
{
|
||||
if constexpr (!(std::is_constructible_v<std::hash<Params>> &&
|
||||
...)) {
|
||||
return {};
|
||||
} else {
|
||||
auto const hash = detail::hash_combine(
|
||||
proj_(key),
|
||||
typeid(P).hash_code(),
|
||||
typeid(A).hash_code(),
|
||||
std::hash<Params>{}(params)...);
|
||||
entry & obj_and_other = table_[hash];
|
||||
if (!obj_and_other.obj && k == success) {
|
||||
auto const id =
|
||||
tidy<A> ? typeid(trivial_type_for<A>).hash_code()
|
||||
: typeid(A).hash_code();
|
||||
if (std::is_empty_v<A>) {
|
||||
obj_and_other = {nullptr, OtherDatum()};
|
||||
} else {
|
||||
#if BOOST_PARSER_HAVE_BOOST_UNORDERED_FLAT_MAP
|
||||
memo_items_base *& items = memo_items_[id];
|
||||
if (!items) {
|
||||
if (tidy<A>) {
|
||||
items = new memo_items_impl<
|
||||
trivial_type_for<A>>;
|
||||
} else {
|
||||
items = new memo_items_impl<A>;
|
||||
}
|
||||
}
|
||||
auto [pos, needs_construction] = items->new_item();
|
||||
A * obj = needs_construction
|
||||
? new (pos) A()
|
||||
: static_cast<A *>(pos);
|
||||
obj_and_other = {obj, OtherDatum()};
|
||||
#else
|
||||
auto it = std::lower_bound(
|
||||
memo_items_.begin(),
|
||||
memo_items_.end(),
|
||||
id,
|
||||
[](memo_items_base * base, size_t id) {
|
||||
return base->id_token_ < id;
|
||||
});
|
||||
if (it == memo_items_.end() ||
|
||||
(*it)->id_token_ != id) {
|
||||
if (tidy<A>) {
|
||||
it = memo_items_.insert(
|
||||
it,
|
||||
new memo_items_impl<
|
||||
trivial_type_for<A>>);
|
||||
} else {
|
||||
it = memo_items_.insert(
|
||||
it, new memo_items_impl<A>);
|
||||
}
|
||||
}
|
||||
auto [pos, needs_construction] = (*it)->new_item();
|
||||
A * obj = needs_construction
|
||||
? new (pos) A()
|
||||
: static_cast<A *>(pos);
|
||||
obj_and_other = {obj, OtherDatum()};
|
||||
#endif
|
||||
}
|
||||
}
|
||||
return {
|
||||
static_cast<A *>(obj_and_other.obj),
|
||||
&obj_and_other.datum};
|
||||
}
|
||||
}
|
||||
|
||||
template<typename P, typename A, typename... Params>
|
||||
const_ref<A> find(Key key, Params const &... params) const
|
||||
{
|
||||
if constexpr (!(std::is_constructible_v<std::hash<Params>> &&
|
||||
...)) {
|
||||
return {};
|
||||
} else {
|
||||
auto const hash = detail::hash_combine(
|
||||
proj_(key),
|
||||
typeid(P).hash_code(),
|
||||
typeid(A).hash_code(),
|
||||
std::hash<Params>{}(params)...);
|
||||
auto it = table_.find(hash);
|
||||
if (it == table_.end()) {
|
||||
return {};
|
||||
} else {
|
||||
return {
|
||||
static_cast<A const *>(it->second.obj),
|
||||
&it->second.datum};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void reclaim()
|
||||
{
|
||||
#if BOOST_PARSER_HAVE_BOOST_UNORDERED_FLAT_MAP
|
||||
for (auto [key, items] : memo_items_) {
|
||||
items->reclaim();
|
||||
}
|
||||
#else
|
||||
for (auto items : memo_items_) {
|
||||
items->reclaim();
|
||||
}
|
||||
#endif
|
||||
table_.clear();
|
||||
}
|
||||
|
||||
// For testing.
|
||||
size_t item_stores() const { return memo_items_.size(); }
|
||||
size_t items() const { return table_.size(); }
|
||||
|
||||
private:
|
||||
struct entry
|
||||
{
|
||||
void * obj;
|
||||
[[maybe_unused]] OtherDatum datum;
|
||||
};
|
||||
|
||||
#if BOOST_PARSER_HAVE_BOOST_UNORDERED_FLAT_MAP
|
||||
boost::unordered_flat_map<size_t, memo_items_base *> memo_items_;
|
||||
boost::unordered_flat_map<size_t, entry> table_;
|
||||
#else
|
||||
std::vector<memo_items_base *> memo_items_;
|
||||
std::unordered_map<size_t, entry> table_;
|
||||
#endif
|
||||
Proj proj_;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -8,6 +8,7 @@
|
||||
|
||||
#include <boost/parser/config.hpp>
|
||||
#include <boost/parser/error_handling_fwd.hpp>
|
||||
#include <boost/parser/detail/memos.hpp>
|
||||
|
||||
#include <any>
|
||||
#include <cstdint>
|
||||
@@ -79,7 +80,8 @@ namespace boost { namespace parser {
|
||||
bool UseCallbacks,
|
||||
typename Iter,
|
||||
typename Sentinel,
|
||||
typename ErrorHandler>
|
||||
typename ErrorHandler,
|
||||
typename Memos>
|
||||
inline auto make_context(
|
||||
Iter first,
|
||||
Sentinel last,
|
||||
@@ -87,7 +89,8 @@ namespace boost { namespace parser {
|
||||
int & indent,
|
||||
ErrorHandler const & error_handler,
|
||||
nope &,
|
||||
symbol_table_tries_t & symbol_table_tries) noexcept;
|
||||
symbol_table_tries_t & symbol_table_tries,
|
||||
Memos & memos) noexcept;
|
||||
|
||||
struct skip_skipper;
|
||||
|
||||
@@ -417,7 +420,8 @@ namespace boost { namespace parser {
|
||||
template<
|
||||
typename Parser,
|
||||
typename GlobalState = detail::nope,
|
||||
typename ErrorHandler = default_error_handler>
|
||||
typename ErrorHandler = default_error_handler,
|
||||
bool Memoize = false>
|
||||
struct parser_interface;
|
||||
|
||||
using no_attribute = detail::nope;
|
||||
|
||||
@@ -210,6 +210,7 @@ namespace boost::parser {
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
bool Memoize,
|
||||
typename SkipParser
|
||||
#if !BOOST_PARSER_USE_CONCEPTS
|
||||
,
|
||||
@@ -231,12 +232,14 @@ namespace boost::parser {
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
Memoize,
|
||||
SkipParser>>
|
||||
{
|
||||
constexpr replace_view() = default;
|
||||
constexpr replace_view(
|
||||
V base,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler, Memoize> const &
|
||||
parser,
|
||||
parser_interface<SkipParser> const & skip,
|
||||
ReplacementV replacement,
|
||||
trace trace_mode = trace::off) :
|
||||
@@ -248,7 +251,8 @@ namespace boost::parser {
|
||||
{}
|
||||
constexpr replace_view(
|
||||
V base,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler, Memoize> const &
|
||||
parser,
|
||||
ReplacementV replacement,
|
||||
trace trace_mode = trace::off) :
|
||||
base_(std::move(base)),
|
||||
@@ -395,7 +399,7 @@ namespace boost::parser {
|
||||
private:
|
||||
V base_;
|
||||
ReplacementV replacement_;
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> parser_;
|
||||
parser_interface<Parser, GlobalState, ErrorHandler, Memoize> parser_;
|
||||
parser_interface<SkipParser> skip_;
|
||||
trace trace_mode_;
|
||||
};
|
||||
@@ -407,10 +411,11 @@ namespace boost::parser {
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
bool Memoize,
|
||||
typename SkipParser>
|
||||
replace_view(
|
||||
V &&,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler>,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler, Memoize>,
|
||||
parser_interface<SkipParser>,
|
||||
ReplacementV &&,
|
||||
trace)
|
||||
@@ -420,6 +425,7 @@ namespace boost::parser {
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
Memoize,
|
||||
SkipParser>;
|
||||
|
||||
template<
|
||||
@@ -428,10 +434,11 @@ namespace boost::parser {
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
bool Memoize,
|
||||
typename SkipParser>
|
||||
replace_view(
|
||||
V &&,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler>,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler, Memoize>,
|
||||
parser_interface<SkipParser>,
|
||||
ReplacementV &&)
|
||||
-> replace_view<
|
||||
@@ -440,6 +447,7 @@ namespace boost::parser {
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
Memoize,
|
||||
SkipParser>;
|
||||
|
||||
template<
|
||||
@@ -447,10 +455,11 @@ namespace boost::parser {
|
||||
typename ReplacementV,
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler>
|
||||
typename ErrorHandler,
|
||||
bool Memoize>
|
||||
replace_view(
|
||||
V &&,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler>,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler, Memoize>,
|
||||
ReplacementV &&,
|
||||
trace)
|
||||
-> replace_view<
|
||||
@@ -459,6 +468,7 @@ namespace boost::parser {
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
Memoize,
|
||||
parser_interface<eps_parser<detail::phony>>>;
|
||||
|
||||
template<
|
||||
@@ -466,10 +476,11 @@ namespace boost::parser {
|
||||
typename ReplacementV,
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler>
|
||||
typename ErrorHandler,
|
||||
bool Memoize>
|
||||
replace_view(
|
||||
V &&,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler>,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler, Memoize>,
|
||||
ReplacementV &&)
|
||||
-> replace_view<
|
||||
detail::text::detail::all_t<V>,
|
||||
@@ -477,6 +488,7 @@ namespace boost::parser {
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
Memoize,
|
||||
parser_interface<eps_parser<detail::phony>>>;
|
||||
|
||||
namespace detail {
|
||||
@@ -486,6 +498,7 @@ namespace boost::parser {
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
typename Memoize,
|
||||
typename SkipParser>
|
||||
using replace_view_expr = decltype(replace_view<
|
||||
V,
|
||||
@@ -493,10 +506,14 @@ namespace boost::parser {
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
Memoize::value,
|
||||
SkipParser>(
|
||||
std::declval<V>(),
|
||||
std::declval<
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> const &>(),
|
||||
std::declval<parser_interface<
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
Memoize::value> const &>(),
|
||||
std::declval<parser_interface<SkipParser> const &>(),
|
||||
std::declval<ReplacementV>(),
|
||||
trace::on));
|
||||
@@ -507,6 +524,7 @@ namespace boost::parser {
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
bool Memoize,
|
||||
typename SkipParser>
|
||||
constexpr bool can_replace_view = is_detected_v<
|
||||
replace_view_expr,
|
||||
@@ -515,6 +533,7 @@ namespace boost::parser {
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
std::bool_constant<Memoize>,
|
||||
SkipParser>;
|
||||
|
||||
struct replace_impl
|
||||
@@ -527,6 +546,7 @@ namespace boost::parser {
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
bool Memoize,
|
||||
typename SkipParser>
|
||||
requires
|
||||
// clang-format off
|
||||
@@ -545,11 +565,12 @@ namespace boost::parser {
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
Memoize,
|
||||
SkipParser>
|
||||
// clang-format off
|
||||
[[nodiscard]] constexpr auto operator()(
|
||||
R && r,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> const &
|
||||
parser_interface<Parser, GlobalState, ErrorHandler, Memoize> const &
|
||||
parser,
|
||||
parser_interface<SkipParser> const & skip,
|
||||
ReplacementR && replacement,
|
||||
@@ -573,7 +594,8 @@ namespace boost::parser {
|
||||
range_like ReplacementR,
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler>
|
||||
typename ErrorHandler,
|
||||
bool Memoize>
|
||||
requires
|
||||
// clang-format off
|
||||
(std::is_pointer_v<std::remove_cvref_t<R>> ||
|
||||
@@ -591,11 +613,12 @@ namespace boost::parser {
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
Memoize,
|
||||
parser_interface<eps_parser<detail::phony>>>
|
||||
// clang-format off
|
||||
[[nodiscard]] constexpr auto operator()(
|
||||
R && r,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> const &
|
||||
parser_interface<Parser, GlobalState, ErrorHandler, Memoize> const &
|
||||
parser,
|
||||
ReplacementR && replacement,
|
||||
trace trace_mode = trace::off) const
|
||||
@@ -616,14 +639,18 @@ namespace boost::parser {
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
bool Memoize,
|
||||
typename SkipParser,
|
||||
typename ReplacementR = trace,
|
||||
typename Trace = trace,
|
||||
typename Enable = std::enable_if_t<is_parsable_range_like_v<R>>>
|
||||
[[nodiscard]] constexpr auto operator()(
|
||||
R && r,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> const &
|
||||
parser,
|
||||
parser_interface<
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
Memoize> const & parser,
|
||||
SkipParser && skip,
|
||||
ReplacementR && replacement = ReplacementR{},
|
||||
Trace trace_mode = Trace{}) const
|
||||
@@ -666,11 +693,15 @@ namespace boost::parser {
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
bool Memoize,
|
||||
typename SkipParser>
|
||||
[[nodiscard]] constexpr auto impl(
|
||||
R && r,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> const &
|
||||
parser,
|
||||
parser_interface<
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
Memoize> const & parser,
|
||||
parser_interface<SkipParser> const & skip,
|
||||
ReplacementR && replacement,
|
||||
trace trace_mode = trace::off) const
|
||||
@@ -709,6 +740,7 @@ template<
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
bool Memoize,
|
||||
typename SkipParser>
|
||||
constexpr bool std::ranges::enable_borrowed_range<boost::parser::replace_view<
|
||||
V,
|
||||
@@ -716,6 +748,7 @@ constexpr bool std::ranges::enable_borrowed_range<boost::parser::replace_view<
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
Memoize,
|
||||
SkipParser>> = std::ranges::enable_borrowed_range<V> &&
|
||||
std::ranges::enable_borrowed_range<ReplacementV>;
|
||||
#endif
|
||||
|
||||
@@ -93,10 +93,12 @@ namespace boost::parser {
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
bool Memoize,
|
||||
typename SkipParser>
|
||||
auto search_impl(
|
||||
R && r,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler, Memoize> const &
|
||||
parser,
|
||||
parser_interface<SkipParser> const & skip,
|
||||
trace trace_mode)
|
||||
{
|
||||
@@ -127,6 +129,7 @@ namespace boost::parser {
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
bool Memoize,
|
||||
typename SkipParser>
|
||||
#if BOOST_PARSER_USE_CONCEPTS
|
||||
std::ranges::borrowed_subrange_t<R>
|
||||
@@ -135,7 +138,8 @@ namespace boost::parser {
|
||||
#endif
|
||||
search_repack_shim(
|
||||
R && r,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler, Memoize> const &
|
||||
parser,
|
||||
parser_interface<SkipParser> const & skip,
|
||||
trace trace_mode)
|
||||
{
|
||||
@@ -172,6 +176,7 @@ namespace boost::parser {
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
bool Memoize,
|
||||
typename SkipParser
|
||||
#if !BOOST_PARSER_USE_CONCEPTS
|
||||
,
|
||||
@@ -180,7 +185,8 @@ namespace boost::parser {
|
||||
>
|
||||
auto search(
|
||||
R && r,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler, Memoize> const &
|
||||
parser,
|
||||
parser_interface<SkipParser> const & skip,
|
||||
trace trace_mode = trace::off)
|
||||
{
|
||||
@@ -210,11 +216,13 @@ namespace boost::parser {
|
||||
detail::is_parsable_iter_v<I> &&
|
||||
detail::is_equality_comparable_with_v<I, S>>
|
||||
#endif
|
||||
>
|
||||
,
|
||||
bool Memoize>
|
||||
auto search(
|
||||
I first,
|
||||
S last,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler, Memoize> const &
|
||||
parser,
|
||||
parser_interface<SkipParser> const & skip,
|
||||
trace trace_mode = trace::off)
|
||||
{
|
||||
@@ -234,7 +242,8 @@ namespace boost::parser {
|
||||
#endif
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler
|
||||
typename ErrorHandler,
|
||||
bool Memoize
|
||||
#if !BOOST_PARSER_USE_CONCEPTS
|
||||
,
|
||||
typename Enable = std::enable_if_t<detail::is_parsable_range_like_v<R>>
|
||||
@@ -242,7 +251,8 @@ namespace boost::parser {
|
||||
>
|
||||
auto search(
|
||||
R && r,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler, Memoize> const &
|
||||
parser,
|
||||
trace trace_mode = trace::off)
|
||||
{
|
||||
return parser::search(
|
||||
@@ -273,11 +283,13 @@ namespace boost::parser {
|
||||
detail::is_parsable_iter_v<I> &&
|
||||
detail::is_equality_comparable_with_v<I, S>>
|
||||
#endif
|
||||
>
|
||||
,
|
||||
bool Memoize>
|
||||
auto search(
|
||||
I first,
|
||||
S last,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler, Memoize> const &
|
||||
parser,
|
||||
trace trace_mode = trace::off)
|
||||
{
|
||||
return parser::search(
|
||||
@@ -299,15 +311,22 @@ namespace boost::parser {
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
bool Memoize,
|
||||
typename SkipParser>
|
||||
struct search_all_view
|
||||
: detail::stl_interfaces::view_interface<
|
||||
search_all_view<V, Parser, GlobalState, ErrorHandler, SkipParser>>
|
||||
: detail::stl_interfaces::view_interface<search_all_view<
|
||||
V,
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
Memoize,
|
||||
SkipParser>>
|
||||
{
|
||||
constexpr search_all_view() = default;
|
||||
constexpr search_all_view(
|
||||
V base,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler, Memoize> const &
|
||||
parser,
|
||||
parser_interface<SkipParser> const & skip,
|
||||
trace trace_mode = trace::off) :
|
||||
base_(std::move(base)),
|
||||
@@ -317,7 +336,8 @@ namespace boost::parser {
|
||||
{}
|
||||
constexpr search_all_view(
|
||||
V base,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler, Memoize> const &
|
||||
parser,
|
||||
trace trace_mode = trace::off) :
|
||||
base_(std::move(base)),
|
||||
parser_(parser),
|
||||
@@ -421,7 +441,7 @@ namespace boost::parser {
|
||||
|
||||
private:
|
||||
V base_;
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> parser_;
|
||||
parser_interface<Parser, GlobalState, ErrorHandler, Memoize> parser_;
|
||||
parser_interface<SkipParser> skip_;
|
||||
trace trace_mode_;
|
||||
};
|
||||
@@ -432,10 +452,11 @@ namespace boost::parser {
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
bool Memoize,
|
||||
typename SkipParser>
|
||||
search_all_view(
|
||||
V &&,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler>,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler, Memoize>,
|
||||
parser_interface<SkipParser>,
|
||||
trace)
|
||||
-> search_all_view<
|
||||
@@ -443,6 +464,7 @@ namespace boost::parser {
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
Memoize,
|
||||
SkipParser>;
|
||||
|
||||
template<
|
||||
@@ -450,43 +472,52 @@ namespace boost::parser {
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
bool Memoize,
|
||||
typename SkipParser>
|
||||
search_all_view(
|
||||
V &&,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler>,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler, Memoize>,
|
||||
parser_interface<SkipParser>)
|
||||
-> search_all_view<
|
||||
detail::text::detail::all_t<V>,
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
Memoize,
|
||||
SkipParser>;
|
||||
|
||||
template<
|
||||
typename V,
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler>
|
||||
typename ErrorHandler,
|
||||
bool Memoize>
|
||||
search_all_view(
|
||||
V &&, parser_interface<Parser, GlobalState, ErrorHandler>, trace)
|
||||
V &&,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler, Memoize>,
|
||||
trace)
|
||||
-> search_all_view<
|
||||
detail::text::detail::all_t<V>,
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
Memoize,
|
||||
parser_interface<eps_parser<detail::phony>>>;
|
||||
|
||||
template<
|
||||
typename V,
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler>
|
||||
search_all_view(V &&, parser_interface<Parser, GlobalState, ErrorHandler>)
|
||||
typename ErrorHandler,
|
||||
bool Memoize>
|
||||
search_all_view(
|
||||
V &&, parser_interface<Parser, GlobalState, ErrorHandler, Memoize>)
|
||||
-> search_all_view<
|
||||
detail::text::detail::all_t<V>,
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
Memoize,
|
||||
parser_interface<eps_parser<detail::phony>>>;
|
||||
|
||||
namespace detail {
|
||||
@@ -495,16 +526,21 @@ namespace boost::parser {
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
typename Memoize,
|
||||
typename SkipParser>
|
||||
using search_all_view_expr = decltype(search_all_view<
|
||||
V,
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
Memoize::value,
|
||||
SkipParser>(
|
||||
std::declval<V>(),
|
||||
std::declval<
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> const &>(),
|
||||
std::declval<parser_interface<
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
Memoize::value> const &>(),
|
||||
std::declval<parser_interface<SkipParser> const &>(),
|
||||
trace::on));
|
||||
|
||||
@@ -513,6 +549,7 @@ namespace boost::parser {
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
bool Memoize,
|
||||
typename SkipParser>
|
||||
constexpr bool can_search_all_view = is_detected_v<
|
||||
search_all_view_expr,
|
||||
@@ -520,6 +557,7 @@ namespace boost::parser {
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
std::bool_constant<Memoize>,
|
||||
SkipParser>;
|
||||
|
||||
struct search_all_impl
|
||||
@@ -530,7 +568,7 @@ namespace boost::parser {
|
||||
parsable_range_like R,
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
typename ErrorHandler, bool Memoize,
|
||||
typename SkipParser>
|
||||
requires(
|
||||
std::is_pointer_v<std::remove_cvref_t<R>> ||
|
||||
@@ -540,11 +578,12 @@ namespace boost::parser {
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
Memoize,
|
||||
SkipParser>
|
||||
// clang-format off
|
||||
[[nodiscard]] constexpr auto operator()(
|
||||
R && r,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> const &
|
||||
parser_interface<Parser, GlobalState, ErrorHandler, Memoize> const &
|
||||
parser,
|
||||
parser_interface<SkipParser> const & skip,
|
||||
trace trace_mode = trace::off) const
|
||||
@@ -558,7 +597,7 @@ namespace boost::parser {
|
||||
parsable_range_like R,
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler>
|
||||
typename ErrorHandler, bool Memoize>
|
||||
requires(
|
||||
std::is_pointer_v<std::remove_cvref_t<R>> ||
|
||||
std::ranges::viewable_range<R>) &&
|
||||
@@ -567,11 +606,12 @@ namespace boost::parser {
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
Memoize,
|
||||
parser_interface<eps_parser<detail::phony>>>
|
||||
// clang-format off
|
||||
[[nodiscard]] constexpr auto operator()(
|
||||
R && r,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> const &
|
||||
parser_interface<Parser, GlobalState, ErrorHandler, Memoize> const &
|
||||
parser,
|
||||
trace trace_mode = trace::off) const
|
||||
// clang-format on
|
||||
@@ -590,14 +630,18 @@ namespace boost::parser {
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
bool Memoize,
|
||||
typename SkipParser =
|
||||
parser_interface<eps_parser<detail::phony>>,
|
||||
typename Trace = trace,
|
||||
typename Enable = std::enable_if_t<is_parsable_range_like_v<R>>>
|
||||
[[nodiscard]] constexpr auto operator()(
|
||||
R && r,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> const &
|
||||
parser,
|
||||
parser_interface<
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
Memoize> const & parser,
|
||||
SkipParser const & skip = SkipParser{},
|
||||
Trace trace_mode = Trace{}) const
|
||||
{
|
||||
@@ -631,11 +675,15 @@ namespace boost::parser {
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
bool Memoize,
|
||||
typename SkipParser>
|
||||
[[nodiscard]] constexpr auto impl(
|
||||
R && r,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> const &
|
||||
parser,
|
||||
parser_interface<
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
Memoize> const & parser,
|
||||
parser_interface<SkipParser> const & skip,
|
||||
trace trace_mode = trace::off) const
|
||||
{
|
||||
@@ -663,11 +711,16 @@ template<
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
bool Memoize,
|
||||
typename SkipParser>
|
||||
constexpr bool std::ranges::enable_borrowed_range<
|
||||
boost::parser::
|
||||
search_all_view<V, Parser, GlobalState, ErrorHandler, SkipParser>> =
|
||||
std::ranges::enable_borrowed_range<V>;
|
||||
constexpr bool
|
||||
std::ranges::enable_borrowed_range<boost::parser::search_all_view<
|
||||
V,
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
Memoize,
|
||||
SkipParser>> = std::ranges::enable_borrowed_range<V>;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -18,15 +18,21 @@ namespace boost::parser {
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
bool Memoize,
|
||||
typename SkipParser>
|
||||
struct split_view
|
||||
: detail::stl_interfaces::view_interface<
|
||||
split_view<V, Parser, GlobalState, ErrorHandler, SkipParser>>
|
||||
struct split_view : detail::stl_interfaces::view_interface<split_view<
|
||||
V,
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
Memoize,
|
||||
SkipParser>>
|
||||
{
|
||||
constexpr split_view() = default;
|
||||
constexpr split_view(
|
||||
V base,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler, Memoize> const &
|
||||
parser,
|
||||
parser_interface<SkipParser> const & skip,
|
||||
trace trace_mode = trace::off) :
|
||||
base_(std::move(base)),
|
||||
@@ -36,7 +42,8 @@ namespace boost::parser {
|
||||
{}
|
||||
constexpr split_view(
|
||||
V base,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler, Memoize> const &
|
||||
parser,
|
||||
trace trace_mode = trace::off) :
|
||||
base_(std::move(base)),
|
||||
parser_(parser),
|
||||
@@ -147,7 +154,7 @@ namespace boost::parser {
|
||||
|
||||
private:
|
||||
V base_;
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> parser_;
|
||||
parser_interface<Parser, GlobalState, ErrorHandler, Memoize> parser_;
|
||||
parser_interface<SkipParser> skip_;
|
||||
trace trace_mode_;
|
||||
};
|
||||
@@ -158,10 +165,11 @@ namespace boost::parser {
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
bool Memoize,
|
||||
typename SkipParser>
|
||||
split_view(
|
||||
V &&,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler>,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler, Memoize>,
|
||||
parser_interface<SkipParser>,
|
||||
trace)
|
||||
-> split_view<
|
||||
@@ -169,6 +177,7 @@ namespace boost::parser {
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
Memoize,
|
||||
SkipParser>;
|
||||
|
||||
template<
|
||||
@@ -176,43 +185,52 @@ namespace boost::parser {
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
bool Memoize,
|
||||
typename SkipParser>
|
||||
split_view(
|
||||
V &&,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler>,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler, Memoize>,
|
||||
parser_interface<SkipParser>)
|
||||
-> split_view<
|
||||
detail::text::detail::all_t<V>,
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
Memoize,
|
||||
SkipParser>;
|
||||
|
||||
template<
|
||||
typename V,
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler>
|
||||
typename ErrorHandler,
|
||||
bool Memoize>
|
||||
split_view(
|
||||
V &&, parser_interface<Parser, GlobalState, ErrorHandler>, trace)
|
||||
V &&,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler, Memoize>,
|
||||
trace)
|
||||
-> split_view<
|
||||
detail::text::detail::all_t<V>,
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
Memoize,
|
||||
parser_interface<eps_parser<detail::phony>>>;
|
||||
|
||||
template<
|
||||
typename V,
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler>
|
||||
split_view(V &&, parser_interface<Parser, GlobalState, ErrorHandler>)
|
||||
typename ErrorHandler,
|
||||
bool Memoize>
|
||||
split_view(
|
||||
V &&, parser_interface<Parser, GlobalState, ErrorHandler, Memoize>)
|
||||
-> split_view<
|
||||
detail::text::detail::all_t<V>,
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
Memoize,
|
||||
parser_interface<eps_parser<detail::phony>>>;
|
||||
|
||||
namespace detail {
|
||||
@@ -221,16 +239,21 @@ namespace boost::parser {
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
typename Memoize,
|
||||
typename SkipParser>
|
||||
using split_view_expr = decltype(split_view<
|
||||
V,
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
SkipParser>(
|
||||
V,
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
Memoize::value,
|
||||
SkipParser>(
|
||||
std::declval<V>(),
|
||||
std::declval<
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> const &>(),
|
||||
std::declval<parser_interface<
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
Memoize::value> const &>(),
|
||||
std::declval<parser_interface<SkipParser> const &>(),
|
||||
trace::on));
|
||||
|
||||
@@ -239,6 +262,7 @@ namespace boost::parser {
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
bool Memoize,
|
||||
typename SkipParser>
|
||||
constexpr bool can_split_view = is_detected_v<
|
||||
split_view_expr,
|
||||
@@ -246,6 +270,7 @@ namespace boost::parser {
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
std::bool_constant<Memoize>,
|
||||
SkipParser>;
|
||||
|
||||
struct split_impl
|
||||
@@ -257,6 +282,7 @@ namespace boost::parser {
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
bool Memoize,
|
||||
typename SkipParser>
|
||||
requires(
|
||||
std::is_pointer_v<std::remove_cvref_t<R>> ||
|
||||
@@ -266,11 +292,12 @@ namespace boost::parser {
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
Memoize,
|
||||
SkipParser>
|
||||
// clang-format off
|
||||
[[nodiscard]] constexpr auto operator()(
|
||||
R && r,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> const &
|
||||
parser_interface<Parser, GlobalState, ErrorHandler, Memoize> const &
|
||||
parser,
|
||||
parser_interface<SkipParser> const & skip,
|
||||
trace trace_mode = trace::off) const
|
||||
@@ -284,7 +311,8 @@ namespace boost::parser {
|
||||
parsable_range_like R,
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler>
|
||||
typename ErrorHandler,
|
||||
bool Memoize>
|
||||
requires(
|
||||
std::is_pointer_v<std::remove_cvref_t<R>> ||
|
||||
std::ranges::viewable_range<R>) &&
|
||||
@@ -293,11 +321,12 @@ namespace boost::parser {
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
Memoize,
|
||||
parser_interface<eps_parser<detail::phony>>>
|
||||
// clang-format off
|
||||
[[nodiscard]] constexpr auto operator()(
|
||||
R && r,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> const &
|
||||
parser_interface<Parser, GlobalState, ErrorHandler, Memoize> const &
|
||||
parser,
|
||||
trace trace_mode = trace::off) const
|
||||
// clang-format on
|
||||
@@ -316,14 +345,18 @@ namespace boost::parser {
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
bool Memoize,
|
||||
typename SkipParser =
|
||||
parser_interface<eps_parser<detail::phony>>,
|
||||
typename Trace = trace,
|
||||
typename Enable = std::enable_if_t<is_parsable_range_like_v<R>>>
|
||||
[[nodiscard]] constexpr auto operator()(
|
||||
R && r,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> const &
|
||||
parser,
|
||||
parser_interface<
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
Memoize> const & parser,
|
||||
SkipParser const & skip = SkipParser{},
|
||||
Trace trace_mode = Trace{}) const
|
||||
{
|
||||
@@ -357,11 +390,15 @@ namespace boost::parser {
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
bool Memoize,
|
||||
typename SkipParser>
|
||||
[[nodiscard]] constexpr auto impl(
|
||||
R && r,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> const &
|
||||
parser,
|
||||
parser_interface<
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
Memoize> const & parser,
|
||||
parser_interface<SkipParser> const & skip,
|
||||
trace trace_mode = trace::off) const
|
||||
{
|
||||
@@ -389,10 +426,11 @@ template<
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
bool Memoize,
|
||||
typename SkipParser>
|
||||
constexpr bool std::ranges::enable_borrowed_range<
|
||||
boost::parser::
|
||||
split_view<V, Parser, GlobalState, ErrorHandler, SkipParser>> =
|
||||
split_view<V, Parser, GlobalState, ErrorHandler, Memoize, SkipParser>> =
|
||||
std::ranges::enable_borrowed_range<V>;
|
||||
#endif
|
||||
|
||||
|
||||
@@ -212,10 +212,12 @@ namespace boost::parser {
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
bool Memoize,
|
||||
typename SkipParser>
|
||||
auto attr_search_impl(
|
||||
R && r,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler, Memoize> const &
|
||||
parser,
|
||||
parser_interface<SkipParser> const & skip,
|
||||
trace trace_mode)
|
||||
{
|
||||
@@ -282,10 +284,12 @@ namespace boost::parser {
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
bool Memoize,
|
||||
typename SkipParser>
|
||||
auto attr_search_repack_shim(
|
||||
R && r,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler, Memoize> const &
|
||||
parser,
|
||||
parser_interface<SkipParser> const & skip,
|
||||
trace trace_mode)
|
||||
{
|
||||
@@ -334,6 +338,7 @@ namespace boost::parser {
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
bool Memoize,
|
||||
typename SkipParser
|
||||
#if !BOOST_PARSER_USE_CONCEPTS
|
||||
,
|
||||
@@ -351,6 +356,7 @@ namespace boost::parser {
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
Memoize,
|
||||
SkipParser>>
|
||||
{
|
||||
private:
|
||||
@@ -361,7 +367,8 @@ namespace boost::parser {
|
||||
constexpr transform_replace_view() = default;
|
||||
constexpr transform_replace_view(
|
||||
V base,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler, Memoize> const &
|
||||
parser,
|
||||
parser_interface<SkipParser> const & skip,
|
||||
F f,
|
||||
trace trace_mode = trace::off) :
|
||||
@@ -373,7 +380,8 @@ namespace boost::parser {
|
||||
{}
|
||||
constexpr transform_replace_view(
|
||||
V base,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler, Memoize> const &
|
||||
parser,
|
||||
F f,
|
||||
trace trace_mode = trace::off) :
|
||||
base_(std::move(base)),
|
||||
@@ -518,7 +526,7 @@ namespace boost::parser {
|
||||
private:
|
||||
V base_;
|
||||
F f_;
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> parser_;
|
||||
parser_interface<Parser, GlobalState, ErrorHandler, Memoize> parser_;
|
||||
parser_interface<SkipParser> skip_;
|
||||
trace trace_mode_;
|
||||
};
|
||||
@@ -530,10 +538,11 @@ namespace boost::parser {
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
bool Memoize,
|
||||
typename SkipParser>
|
||||
transform_replace_view(
|
||||
V &&,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler>,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler, Memoize>,
|
||||
parser_interface<SkipParser>,
|
||||
F &&,
|
||||
trace)
|
||||
@@ -543,6 +552,7 @@ namespace boost::parser {
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
Memoize,
|
||||
SkipParser>;
|
||||
|
||||
template<
|
||||
@@ -551,10 +561,11 @@ namespace boost::parser {
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
bool Memoize,
|
||||
typename SkipParser>
|
||||
transform_replace_view(
|
||||
V &&,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler>,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler, Memoize>,
|
||||
parser_interface<SkipParser>,
|
||||
F &&)
|
||||
-> transform_replace_view<
|
||||
@@ -563,6 +574,7 @@ namespace boost::parser {
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
Memoize,
|
||||
SkipParser>;
|
||||
|
||||
template<
|
||||
@@ -570,15 +582,20 @@ namespace boost::parser {
|
||||
typename F,
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler>
|
||||
typename ErrorHandler,
|
||||
bool Memoize>
|
||||
transform_replace_view(
|
||||
V &&, parser_interface<Parser, GlobalState, ErrorHandler>, F &&, trace)
|
||||
V &&,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler, Memoize>,
|
||||
F &&,
|
||||
trace)
|
||||
-> transform_replace_view<
|
||||
detail::text::detail::all_t<V>,
|
||||
detail::remove_cv_ref_t<F>,
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
Memoize,
|
||||
parser_interface<eps_parser<detail::phony>>>;
|
||||
|
||||
template<
|
||||
@@ -586,15 +603,19 @@ namespace boost::parser {
|
||||
typename F,
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler>
|
||||
typename ErrorHandler,
|
||||
bool Memoize>
|
||||
transform_replace_view(
|
||||
V &&, parser_interface<Parser, GlobalState, ErrorHandler>, F &&)
|
||||
V &&,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler, Memoize>,
|
||||
F &&)
|
||||
-> transform_replace_view<
|
||||
detail::text::detail::all_t<V>,
|
||||
detail::remove_cv_ref_t<F>,
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
Memoize,
|
||||
parser_interface<eps_parser<detail::phony>>>;
|
||||
|
||||
namespace detail {
|
||||
@@ -604,6 +625,7 @@ namespace boost::parser {
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
typename Memoize,
|
||||
typename SkipParser>
|
||||
using transform_replace_view_expr = decltype(transform_replace_view<
|
||||
V,
|
||||
@@ -611,10 +633,14 @@ namespace boost::parser {
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
Memoize::value,
|
||||
SkipParser>(
|
||||
std::declval<V>(),
|
||||
std::declval<
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> const &>(),
|
||||
std::declval<parser_interface<
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
Memoize::value> const &>(),
|
||||
std::declval<parser_interface<SkipParser> const &>(),
|
||||
std::declval<F>(),
|
||||
trace::on));
|
||||
@@ -625,6 +651,7 @@ namespace boost::parser {
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
bool Memoize,
|
||||
typename SkipParser>
|
||||
constexpr bool can_transform_replace_view = is_detected_v<
|
||||
transform_replace_view_expr,
|
||||
@@ -633,6 +660,7 @@ namespace boost::parser {
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
std::bool_constant<Memoize>,
|
||||
SkipParser>;
|
||||
|
||||
struct transform_replace_impl
|
||||
@@ -645,6 +673,7 @@ namespace boost::parser {
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
bool Memoize,
|
||||
typename SkipParser>
|
||||
requires
|
||||
// clang-format off
|
||||
@@ -663,11 +692,12 @@ namespace boost::parser {
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
Memoize,
|
||||
SkipParser>
|
||||
// clang-format off
|
||||
[[nodiscard]] constexpr auto operator()(
|
||||
R && r,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> const &
|
||||
parser_interface<Parser, GlobalState, ErrorHandler, Memoize> const &
|
||||
parser,
|
||||
parser_interface<SkipParser> const & skip,
|
||||
F && f,
|
||||
@@ -690,7 +720,8 @@ namespace boost::parser {
|
||||
std::move_constructible F,
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler>
|
||||
typename ErrorHandler,
|
||||
bool Memoize>
|
||||
requires
|
||||
// clang-format off
|
||||
(std::is_pointer_v<std::remove_cvref_t<R>> ||
|
||||
@@ -708,11 +739,12 @@ namespace boost::parser {
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
Memoize,
|
||||
parser_interface<eps_parser<detail::phony>>>
|
||||
// clang-format off
|
||||
[[nodiscard]] constexpr auto operator()(
|
||||
R && r,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> const &
|
||||
parser_interface<Parser, GlobalState, ErrorHandler, Memoize> const &
|
||||
parser,
|
||||
F && f,
|
||||
trace trace_mode = trace::off) const
|
||||
@@ -733,14 +765,18 @@ namespace boost::parser {
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
bool Memoize,
|
||||
typename SkipParser,
|
||||
typename F = trace,
|
||||
typename Trace = trace,
|
||||
typename Enable = std::enable_if_t<is_parsable_range_like_v<R>>>
|
||||
[[nodiscard]] constexpr auto operator()(
|
||||
R && r,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> const &
|
||||
parser,
|
||||
parser_interface<
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
Memoize> const & parser,
|
||||
SkipParser && skip,
|
||||
F && f = F{},
|
||||
Trace trace_mode = Trace{}) const
|
||||
@@ -787,11 +823,15 @@ namespace boost::parser {
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
bool Memoize,
|
||||
typename SkipParser>
|
||||
[[nodiscard]] constexpr auto impl(
|
||||
R && r,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> const &
|
||||
parser,
|
||||
parser_interface<
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
Memoize> const & parser,
|
||||
parser_interface<SkipParser> const & skip,
|
||||
F && f,
|
||||
trace trace_mode = trace::off) const
|
||||
@@ -830,6 +870,7 @@ template<
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
bool Memoize,
|
||||
typename SkipParser>
|
||||
constexpr bool
|
||||
std::ranges::enable_borrowed_range<boost::parser::transform_replace_view<
|
||||
@@ -838,6 +879,7 @@ constexpr bool
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
Memoize,
|
||||
SkipParser>> = std::ranges::enable_borrowed_range<V> &&
|
||||
(std::ranges::enable_borrowed_range<F> ||
|
||||
boost::parser::detail::tidy_func<F>);
|
||||
|
||||
@@ -46,6 +46,7 @@ macro(add_test_executable name)
|
||||
add_test(NAME ${name} COMMAND ${name} --gtest_catch_exceptions=1)
|
||||
endmacro()
|
||||
|
||||
add_test_executable(memos)
|
||||
add_test_executable(all_t)
|
||||
add_test_executable(search)
|
||||
add_test_executable(split)
|
||||
|
||||
452
test/memos.cpp
Normal file
452
test/memos.cpp
Normal file
@@ -0,0 +1,452 @@
|
||||
/**
|
||||
* Copyright (C) 2024 T. Zachary Laine
|
||||
*
|
||||
* Distributed under 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)
|
||||
*/
|
||||
|
||||
#include <boost/parser/detail/memos.hpp>
|
||||
|
||||
#include <variant> // for monostate
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
|
||||
using namespace boost::parser;
|
||||
|
||||
TEST(memos, linked_list_1)
|
||||
{
|
||||
{
|
||||
detail::linked_list<std::string, 1> list;
|
||||
}
|
||||
{
|
||||
detail::linked_list<std::string, 1> list;
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
auto [pos, needs_new] = list.push();
|
||||
std::string * str = needs_new ? new (pos) std::string()
|
||||
: static_cast<std::string *>(pos);
|
||||
*str = 'a' + i;
|
||||
}
|
||||
}
|
||||
{
|
||||
detail::linked_list<int, 1> list;
|
||||
}
|
||||
{
|
||||
detail::linked_list<int, 1> list;
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
auto [pos, needs_new] = list.push();
|
||||
int * j = needs_new ? new (pos) int() : static_cast<int *>(pos);
|
||||
*j = i;
|
||||
}
|
||||
}
|
||||
|
||||
// reclaim, no reuse
|
||||
{
|
||||
detail::linked_list<std::string, 1> list;
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
auto [pos, needs_new] = list.push();
|
||||
std::string * str = needs_new ? new (pos) std::string()
|
||||
: static_cast<std::string *>(pos);
|
||||
*str = 'a' + i;
|
||||
}
|
||||
list.reclaim();
|
||||
}
|
||||
{
|
||||
detail::linked_list<int, 1> list;
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
auto [pos, needs_new] = list.push();
|
||||
int * j = needs_new ? new (pos) int() : static_cast<int *>(pos);
|
||||
*j = i;
|
||||
}
|
||||
list.reclaim();
|
||||
}
|
||||
|
||||
// reclaim, partial reuse
|
||||
{
|
||||
detail::linked_list<std::string, 1> list;
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
auto [pos, needs_new] = list.push();
|
||||
std::string * str = needs_new ? new (pos) std::string()
|
||||
: static_cast<std::string *>(pos);
|
||||
*str = 'a' + i;
|
||||
}
|
||||
list.reclaim();
|
||||
|
||||
for (int i = 0; i < 9; ++i) {
|
||||
auto [pos, needs_new] = list.push();
|
||||
std::string * str = needs_new ? new (pos) std::string()
|
||||
: static_cast<std::string *>(pos);
|
||||
char const expected[] = {char('a' + (16 - 1) - i), 0};
|
||||
EXPECT_EQ(*str, expected);
|
||||
*str = "reused";
|
||||
}
|
||||
}
|
||||
{
|
||||
detail::linked_list<int, 1> list;
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
auto [pos, needs_new] = list.push();
|
||||
int * j = needs_new ? new (pos) int() : static_cast<int *>(pos);
|
||||
*j = i;
|
||||
}
|
||||
list.reclaim();
|
||||
|
||||
for (int i = 0; i < 9; ++i) {
|
||||
auto [pos, needs_new] = list.push();
|
||||
int * j = needs_new ? new (pos) int() : static_cast<int *>(pos);
|
||||
EXPECT_EQ(*j, (16 - 1) - i);
|
||||
*j = -1;
|
||||
}
|
||||
}
|
||||
|
||||
// reclaim, full reuse
|
||||
{
|
||||
detail::linked_list<std::string, 1> list;
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
auto [pos, needs_new] = list.push();
|
||||
std::string * str = needs_new ? new (pos) std::string()
|
||||
: static_cast<std::string *>(pos);
|
||||
*str = 'a' + i;
|
||||
}
|
||||
list.reclaim();
|
||||
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
auto [pos, needs_new] = list.push();
|
||||
std::string * str = needs_new ? new (pos) std::string()
|
||||
: static_cast<std::string *>(pos);
|
||||
char const expected[] = {char('a' + (16 - 1) - i), 0};
|
||||
EXPECT_EQ(*str, expected);
|
||||
*str = "reused";
|
||||
}
|
||||
}
|
||||
{
|
||||
detail::linked_list<int, 1> list;
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
auto [pos, needs_new] = list.push();
|
||||
int * j = needs_new ? new (pos) int() : static_cast<int *>(pos);
|
||||
*j = i;
|
||||
}
|
||||
list.reclaim();
|
||||
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
auto [pos, needs_new] = list.push();
|
||||
int * j = needs_new ? new (pos) int() : static_cast<int *>(pos);
|
||||
EXPECT_EQ(*j, (16 - 1) - i);
|
||||
*j = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(memos, linked_list_8)
|
||||
{
|
||||
{
|
||||
detail::linked_list<std::string, 8> list;
|
||||
}
|
||||
{
|
||||
detail::linked_list<std::string, 8> list;
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
auto [pos, needs_new] = list.push();
|
||||
std::string * str = needs_new ? new (pos) std::string()
|
||||
: static_cast<std::string *>(pos);
|
||||
*str = 'a' + i;
|
||||
}
|
||||
}
|
||||
{
|
||||
detail::linked_list<int, 8> list;
|
||||
}
|
||||
{
|
||||
detail::linked_list<int, 8> list;
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
auto [pos, needs_new] = list.push();
|
||||
int * j = needs_new ? new (pos) int() : static_cast<int *>(pos);
|
||||
*j = i;
|
||||
}
|
||||
}
|
||||
|
||||
// reclaim, no reuse
|
||||
{
|
||||
detail::linked_list<std::string, 8> list;
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
auto [pos, needs_new] = list.push();
|
||||
std::string * str = needs_new ? new (pos) std::string()
|
||||
: static_cast<std::string *>(pos);
|
||||
*str = 'a' + i;
|
||||
}
|
||||
list.reclaim();
|
||||
}
|
||||
{
|
||||
detail::linked_list<int, 8> list;
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
auto [pos, needs_new] = list.push();
|
||||
int * j = needs_new ? new (pos) int() : static_cast<int *>(pos);
|
||||
*j = i;
|
||||
}
|
||||
list.reclaim();
|
||||
}
|
||||
|
||||
// reclaim, partial reuse
|
||||
{
|
||||
detail::linked_list<std::string, 8> list;
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
auto [pos, needs_new] = list.push();
|
||||
std::string * str = needs_new ? new (pos) std::string()
|
||||
: static_cast<std::string *>(pos);
|
||||
*str = 'a' + i;
|
||||
}
|
||||
list.reclaim();
|
||||
|
||||
for (int i = 0; i < 9; ++i) {
|
||||
auto [pos, needs_new] = list.push();
|
||||
std::string * str = needs_new ? new (pos) std::string()
|
||||
: static_cast<std::string *>(pos);
|
||||
char c = i < 8 ? char('a' + i + 8) : char('a' + i - 8);
|
||||
char const expected[] = {c, 0};
|
||||
EXPECT_EQ(*str, expected);
|
||||
*str = "reused";
|
||||
}
|
||||
}
|
||||
{
|
||||
detail::linked_list<int, 8> list;
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
auto [pos, needs_new] = list.push();
|
||||
int * j = needs_new ? new (pos) int() : static_cast<int *>(pos);
|
||||
*j = i;
|
||||
}
|
||||
list.reclaim();
|
||||
|
||||
for (int i = 0; i < 9; ++i) {
|
||||
auto [pos, needs_new] = list.push();
|
||||
int * j = needs_new ? new (pos) int() : static_cast<int *>(pos);
|
||||
if (i < 8)
|
||||
EXPECT_EQ(*j, i + 8);
|
||||
else
|
||||
EXPECT_EQ(*j, i - 8);
|
||||
*j = -1;
|
||||
}
|
||||
}
|
||||
|
||||
// reclaim, full reuse
|
||||
{
|
||||
detail::linked_list<std::string, 8> list;
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
auto [pos, needs_new] = list.push();
|
||||
std::string * str = needs_new ? new (pos) std::string()
|
||||
: static_cast<std::string *>(pos);
|
||||
*str = 'a' + i;
|
||||
}
|
||||
list.reclaim();
|
||||
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
auto [pos, needs_new] = list.push();
|
||||
std::string * str = needs_new ? new (pos) std::string()
|
||||
: static_cast<std::string *>(pos);
|
||||
char c = i < 8 ? char('a' + i + 8) : char('a' + i - 8);
|
||||
char const expected[] = {c, 0};
|
||||
EXPECT_EQ(*str, expected);
|
||||
*str = "reused";
|
||||
}
|
||||
}
|
||||
{
|
||||
detail::linked_list<int, 8> list;
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
auto [pos, needs_new] = list.push();
|
||||
int * j = needs_new ? new (pos) int() : static_cast<int *>(pos);
|
||||
*j = i;
|
||||
}
|
||||
list.reclaim();
|
||||
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
auto [pos, needs_new] = list.push();
|
||||
int * j = needs_new ? new (pos) int() : static_cast<int *>(pos);
|
||||
if (i < 8)
|
||||
EXPECT_EQ(*j, i + 8);
|
||||
else
|
||||
EXPECT_EQ(*j, i - 8);
|
||||
*j = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct one
|
||||
{};
|
||||
struct two
|
||||
{};
|
||||
|
||||
TEST(memos, basic)
|
||||
{
|
||||
constexpr auto failure = detail::memos<size_t, size_t>::failure;
|
||||
constexpr auto success = detail::memos<size_t, size_t>::success;
|
||||
|
||||
{
|
||||
detail::memos<size_t, size_t> memos;
|
||||
}
|
||||
{
|
||||
detail::memos<size_t, size_t> memos;
|
||||
detail::memos<size_t, size_t>::const_ref<int> ref = memos.find<one, int>(13);
|
||||
EXPECT_FALSE(ref);
|
||||
EXPECT_EQ(ref.valid, false);
|
||||
EXPECT_EQ(ref.value, nullptr);
|
||||
EXPECT_EQ(ref.datum, nullptr);
|
||||
}
|
||||
{
|
||||
detail::memos<size_t, size_t> memos;
|
||||
detail::memos<size_t, size_t>::ref<int> ref =
|
||||
memos.insert<one, int>(failure, 13);
|
||||
EXPECT_TRUE(ref);
|
||||
EXPECT_EQ(ref.get_kind(), failure);
|
||||
EXPECT_EQ(ref.valid, true);
|
||||
EXPECT_EQ(ref.value, nullptr);
|
||||
EXPECT_NE(ref.datum, nullptr);
|
||||
EXPECT_EQ(*ref.datum, 0);
|
||||
|
||||
EXPECT_FALSE((memos.find<one, int>(12)));
|
||||
EXPECT_FALSE((memos.find<one, int>(13, 42)));
|
||||
EXPECT_FALSE((memos.find<two, int>(13)));
|
||||
EXPECT_FALSE((memos.find<one, double>(13)));
|
||||
|
||||
detail::memos<size_t, size_t>::const_ref<int> cref = memos.find<one, int>(13);
|
||||
EXPECT_TRUE(cref);
|
||||
EXPECT_EQ(cref.get_kind(), failure);
|
||||
EXPECT_EQ(cref.valid, true);
|
||||
EXPECT_EQ(cref.value, nullptr);
|
||||
EXPECT_NE(cref.datum, nullptr);
|
||||
EXPECT_EQ(*cref.datum, 0);
|
||||
}
|
||||
{
|
||||
detail::memos<size_t, size_t> memos;
|
||||
detail::memos<size_t, size_t>::ref<int> ref =
|
||||
memos.insert<one, int>(success, 13);
|
||||
EXPECT_TRUE(ref);
|
||||
EXPECT_EQ(ref.get_kind(), success);
|
||||
EXPECT_EQ(ref.valid, true);
|
||||
EXPECT_NE(ref.value, nullptr);
|
||||
EXPECT_NE(ref.datum, nullptr);
|
||||
EXPECT_EQ(*ref.datum, 0);
|
||||
|
||||
EXPECT_FALSE((memos.find<one, int>(12)));
|
||||
EXPECT_FALSE((memos.find<one, int>(13, 42)));
|
||||
EXPECT_FALSE((memos.find<two, int>(13)));
|
||||
EXPECT_FALSE((memos.find<one, double>(13)));
|
||||
|
||||
detail::memos<size_t, size_t>::const_ref<int> cref = memos.find<one, int>(13);
|
||||
EXPECT_TRUE(cref);
|
||||
EXPECT_EQ(cref.get_kind(), success);
|
||||
EXPECT_EQ(cref.valid, true);
|
||||
EXPECT_NE(cref.value, nullptr);
|
||||
EXPECT_NE(cref.datum, nullptr);
|
||||
EXPECT_EQ(*cref.datum, 0);
|
||||
}
|
||||
|
||||
// types sharing the same trivial_type<size, align>
|
||||
{
|
||||
detail::memos<size_t, size_t> memos;
|
||||
detail::memos<size_t, size_t>::ref<int> ref =
|
||||
memos.insert<one, int>(success, 13);
|
||||
EXPECT_TRUE(ref);
|
||||
EXPECT_EQ(ref.get_kind(), success);
|
||||
EXPECT_EQ(ref.valid, true);
|
||||
EXPECT_NE(ref.value, nullptr);
|
||||
EXPECT_NE(ref.datum, nullptr);
|
||||
EXPECT_EQ(*ref.datum, 0);
|
||||
|
||||
*ref.value = 42;
|
||||
|
||||
EXPECT_FALSE((memos.find<one, int>(12)));
|
||||
EXPECT_FALSE((memos.find<one, int>(13, 42)));
|
||||
EXPECT_FALSE((memos.find<two, int>(13)));
|
||||
EXPECT_FALSE((memos.find<one, float>(13)));
|
||||
|
||||
detail::memos<size_t, size_t>::const_ref<int> cref = memos.find<one, int>(13);
|
||||
EXPECT_TRUE(cref);
|
||||
EXPECT_EQ(cref.get_kind(), success);
|
||||
EXPECT_EQ(cref.valid, true);
|
||||
EXPECT_NE(cref.value, nullptr);
|
||||
EXPECT_EQ(*cref.value, 42);
|
||||
EXPECT_NE(cref.datum, nullptr);
|
||||
EXPECT_EQ(*cref.datum, 0);
|
||||
|
||||
detail::memos<size_t, size_t>::ref<float> ref2 =
|
||||
memos.insert<one, float>(success, 18);
|
||||
EXPECT_TRUE(ref2);
|
||||
EXPECT_EQ(ref2.get_kind(), success);
|
||||
EXPECT_EQ(ref2.valid, true);
|
||||
EXPECT_NE(ref2.value, nullptr);
|
||||
EXPECT_NE(ref2.datum, nullptr);
|
||||
EXPECT_EQ(*ref2.datum, 0);
|
||||
|
||||
*ref2.value = 13.0f;
|
||||
|
||||
EXPECT_FALSE((memos.find<one, float>(17)));
|
||||
EXPECT_FALSE((memos.find<one, float>(18, 42)));
|
||||
EXPECT_FALSE((memos.find<two, float>(18)));
|
||||
EXPECT_FALSE((memos.find<one, char32_t>(18)));
|
||||
|
||||
detail::memos<size_t, size_t>::const_ref<float> cref2 = memos.find<one, float>(18);
|
||||
EXPECT_TRUE(cref2);
|
||||
EXPECT_EQ(cref2.get_kind(), success);
|
||||
EXPECT_EQ(cref2.valid, true);
|
||||
EXPECT_NE(cref2.value, nullptr);
|
||||
EXPECT_EQ(*cref2.value, 13.0f);
|
||||
EXPECT_NE(cref2.datum, nullptr);
|
||||
EXPECT_EQ(*cref2.datum, 0);
|
||||
|
||||
detail::memos<size_t, size_t>::ref<char32_t> ref3 =
|
||||
memos.insert<two, char32_t>(success, 21);
|
||||
EXPECT_TRUE(ref3);
|
||||
EXPECT_EQ(ref3.get_kind(), success);
|
||||
EXPECT_EQ(ref3.valid, true);
|
||||
EXPECT_TRUE(ref3.value);
|
||||
EXPECT_NE(ref3.datum, nullptr);
|
||||
EXPECT_EQ(*ref3.datum, 0);
|
||||
|
||||
*ref3.value = U'c';
|
||||
|
||||
EXPECT_FALSE((memos.find<two, char32_t>(20)));
|
||||
EXPECT_FALSE((memos.find<two, char32_t>(21, 42)));
|
||||
EXPECT_FALSE((memos.find<one, char32_t>(21)));
|
||||
EXPECT_FALSE((memos.find<two, int>(21)));
|
||||
|
||||
detail::memos<size_t, size_t>::const_ref<char32_t> cref3 =
|
||||
memos.find<two, char32_t>(21);
|
||||
EXPECT_TRUE(cref3);
|
||||
EXPECT_EQ(cref3.get_kind(), success);
|
||||
EXPECT_EQ(cref3.valid, true);
|
||||
EXPECT_TRUE(cref3.value);
|
||||
EXPECT_EQ((unsigned int)*cref3.value, (unsigned int)U'c');
|
||||
EXPECT_NE(cref3.datum, nullptr);
|
||||
EXPECT_EQ(*cref3.datum, 0);
|
||||
|
||||
// three items
|
||||
EXPECT_EQ(memos.items(), 3u);
|
||||
// all three items use the same liked list for storage
|
||||
EXPECT_EQ(memos.item_stores(), 1u);
|
||||
}
|
||||
|
||||
// empty types
|
||||
{
|
||||
detail::memos<size_t, size_t> memos;
|
||||
detail::memos<size_t, size_t>::ref<std::monostate> ref =
|
||||
memos.insert<one, std::monostate>(success, 13);
|
||||
EXPECT_TRUE(ref);
|
||||
EXPECT_EQ(ref.get_kind(), success);
|
||||
EXPECT_EQ(ref.valid, true);
|
||||
EXPECT_EQ(*ref.value, std::monostate{});
|
||||
*ref.value = std::monostate{};
|
||||
EXPECT_NE(ref.datum, nullptr);
|
||||
EXPECT_EQ(*ref.datum, 0);
|
||||
|
||||
EXPECT_FALSE((memos.find<one, std::monostate>(12)));
|
||||
EXPECT_FALSE((memos.find<one, std::monostate>(13, 42)));
|
||||
EXPECT_FALSE((memos.find<two, std::monostate>(13)));
|
||||
EXPECT_FALSE((memos.find<one, double>(13)));
|
||||
|
||||
detail::memos<size_t, size_t>::const_ref<std::monostate> cref =
|
||||
memos.find<one, std::monostate>(13);
|
||||
EXPECT_TRUE(cref);
|
||||
EXPECT_EQ(cref.get_kind(), success);
|
||||
EXPECT_EQ(cref.valid, true);
|
||||
EXPECT_EQ(*cref.value, std::monostate{});
|
||||
EXPECT_NE(cref.datum, nullptr);
|
||||
EXPECT_EQ(*cref.datum, 0);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user