Header lexy/callback/container.hpp
Callbacks and sinks for constructing containers.
Callback and sink lexy::as_list
and lexy::as_collection
lexy/callback/container.hpp
namespace lexy
{
template <typename Container>
struct as-container
{
//=== callback ===//
using return_type = Container;
constexpr Container operator()(lexy::nullopt) const;
constexpr Container operator()(Container&& container) const;
template <typename ... Args>
constexpr Container operator()(Args&&... args) const;
template <typename ... Args>
constexpr Container operator()(const Container::allocator_type& allocator,
Args&&... args) const;
//=== sink ===//
struct sink-callback
{
using return_type = Container;
template <typename T>
constexpr void operator()(T&& obj);
template <typename ... Args>
constexpr void operator()(Args&&... args);
constexpr Container finish() &&;
};
constexpr sink-callback sink() const;
constexpr sink-callback sink(const Container::allocator_type& allocator) const;
//=== allocator ===//
template <typename AllocatorFn>
constexpr auto allocator(AllocatorFn allocator_fn) const;
constexpr auto allocator() const
{
return allocator(identity-fn);
}
};
template <typename Container>
constexpr as-container<Container> as_list;
template <typename Collection>
constexpr as-container<Container> as_collection;
}
Callbacks and sink to construct the given Container
.
as_list
is used for positional containers like std::vector
.
It calls .push_back()
and .emplace_back()
.
as_collection
is used for non-positional containers like std::set
.
It calls .insert()
and .emplace()
.
As a callback, they have the following overloads:
(lexy::nullopt)
Returns an empty container by default constructing it.
(Container&& container)
Forwards an existing container unchanged.
(Args&&… args)
Repeatedly calls
.push_back()
/.insert()
on an empty container; if called withN
arguments, the resulting container will containN
items. If.reserve(sizeof…(args))
is well-formed, calls that first. The final container is returned.(const typename Container::allocator_type& allocator, Args&&… args)
Same as above, but constructs the empty container using the given
allocator
.
As a sink, .sink()
can be called with zero arguments or with one argument of type Container::allocator_type
.
In the first case, it default constructs an empty container.
In the second case, it constructs it using the allocator.
The resulting sink callback has the following overloads and returns the finished container:
(T&& object)
Calls
.push_back()
/.insert()
on the container.(Args&&… args)
Calls
.emplace_back()
/.emplace()
on the container.
The .allocator()
function takes a function that obtains the allocator from the parse state.
If the function is not provided, it uses the parse state itself as the allocator.
It returns a new callback and sink that accepts the parse state.
It then has the same overloads and behaviors, except that it will always use the allocator obtained via the allocator_fn
from the parse state.
As a callback, this behavior is similar to lexy::bind
where the allocator is bound via lexy::parse_state
.
As a sink, this behavior is similar to lexy::bind_sink
where the allocator is bound via lexy::parse_state
.
struct state
{
std::allocator<int> allocator; // The allocator that should be used.
// Potentially other members here.
};
struct production
{
static constexpr auto whitespace = dsl::ascii::space;
static constexpr auto rule = [] {
auto integer = dsl::integer<int>;
return dsl::list(integer, dsl::sep(dsl::comma));
}();
static constexpr auto value
// Pass the allocator to the sink.
= lexy::as_list<std::vector<int>>.allocator(&state::allocator);
};
Callback and sink lexy::concat
lexy/callback/container.hpp
namespace lexy
{
template <typename Container>
struct concat-impl
{
using return_type = Container;
constexpr Container operator()() const;
constexpr Container operator()(lexy::nullopt) const;
constexpr Container operator()(Container&& head, Container&&... tail) const;
constexpr sink auto sink() const;
};
template <typename Container>
constexpr concat-impl concat;
}
Callback and sink that concatenates multiple containers.
As a callback, it accepts zero or more existing containers, and will concatenate them together.
This is done by repeatedly calling .append()
or .push_back()
on the first container.
As a sink, it creates a default constructed container object as the current result.
It can then be invoked with a single container object.
If the current result is still empty, the new container is move assigned into it.
Otherwise, the new container is appended by calling .append()
or .push_back()
.
struct list
{
static constexpr auto rule = [] {
auto integer = dsl::integer<int>;
return dsl::list(integer, dsl::sep(dsl::comma));
}();
static constexpr auto value = lexy::as_list<std::vector<int>>;
};
struct production
{
static constexpr auto whitespace = dsl::ascii::space;
static constexpr auto rule = dsl::list(dsl::p<list>, dsl::sep(dsl::newline));
static constexpr auto value = lexy::concat<std::vector<int>>;
};
Sink lexy::collect
lexy/callback/container.hpp
namespace lexy
{
constexpr sink<> auto collect(callback auto&& callback)
requires std::is_void_v<callback-return-type>;
template <typename Container>
constexpr sink<> auto collect(callback auto&& callback);
requires !std::is_void_v<callback-return-type>;
}
Turns a callback into a sink by collecting all results.
The first overload requires that the callback
returns void
.
It returns a sink that repeatedly invokes callback
and produces the number of invocations as a std::size_t
.
The second overload requires that the callback
does not return void
.
.sink()
can be called with zero arguments or with one argument of type Container::allocator_type
.
In the first case, it default constructs an empty container; in the second case, it constructs it using the allocator.
The sink callback just forwards to callback
and adds the result to the container by calling .push_back()
.
The final container is returned.
Note | See lexy::callback for the inverse operation that turns a sink into a callback. |
Tip | Use collect for the error callback. It will collect all errors into a single container. |