Reputation: 5421
I don't think there's any getting away from the need to allocate a buffer to hold the span of string_views. So probably an intermediate std::vector<std::string_view>
? Any good overall pattern to crush it down to 1 line? If necessary, what kind of helper/util would be best?
std::vector<std::string> lineStorage;
std::span<std::string_view> lines = /*lineStorage */;
std::span<std::string_view, 3> linesFixed = /* lineStorage */;
Upvotes: 4
Views: 1316
Reputation: 275820
Spans are views into contiguous buffers of that specific object, not abstractions of covariance.
I'd just pass a span of strings. KISS.
Assuming I end up having a reason to be super fancy and need a single stable API, a span of foo is poor. You want multiple spans of foo that are provided on demand. If the spans are large enough, the overhead becomes cheap, but this permits caller to not allocate all data at once.
template<class T>
using ask_for=function_view<void(T)>;
template<class T>
using provide=ask_for<ask_for<T>>;
then we take:
void do_stuff(provide<std::span<std::string_view>> src){
src([](std::span<std::string_view>> strings){
// code consuming strings
});
}
on the provider side, we can make a fixed buffer of string views, wrapping pieces of the std vector of string, and repeatedly pass the fixed buffer (with new strings) to the callback.
void provide_strings(std::span<std::string> strings){
std::size_t count = 0;
do_stuff([&](ask_for<std::span<std::string_view>> sink){
std::array<std::string_view, 1024> views;
while(count<strings.size()){
for(std::size_t i = count; i <std::min(count+1024, strings.size());++i){
views[i-count]=strings; // I think this isn't legal, but you get the idea
}
sink( {views.data(), std::min(strings.size()-count, 1024ull)});
count += 1024;
}
});
}
ok a bit pseudocodey. But I hope you get the idea.
...
If you really want a one-liner at point of use:
struct string_view_helper_t:
std::vector<std::string_view>
{
string_view_helper_t(std::span<std::string> vec) {
views().reserve(vec.size());
for (auto&& str:vec)
views().push_back(str);
}
std::vector<std::string_view>& views() { return *this; }
std::vector<std::string_view> const& views()const { return *this; }
operator std::span<std::string_view>()&&{ return views(); }
};
string_view_helper_t as_span_of_views( std::span<std::string> vec ) {
return {vec};
}
then
void target_func(std::span<std::string_view> s) {
for (auto str:s)
std::cout << str << '\n';
}
can be called like this:
std::vector<std::string> vec={"a", "b", "c"};
target_func( as_span_of_views(vec) );
Upvotes: 0