Boost logo

Boost :

Subject: Re: [boost] Variadic append for std::string
From: Richard Hodges (hodges.r_at_[hidden])
Date: 2017-01-19 08:53:28


I think this is looking good.

Some suggested separator flavours...

    join(separator(", "), ...) -- results in "a, b, c"
    join(prefix(", "), ...) -- results in ", a, b, c" (for appending to
an existing list)
    join(suffix(", "), ...) -- results in "a, b, c, "

and the start of an idea...

    join(wrapped_sequence(range, "[", "]", ",", " ")) -- results in "[ a,
b, c ]" or "[ ]" if the sequence is empty.

The last one would allow automatic generation of JSON...

On 19 January 2017 at 14:35, Christof Donat <cd_at_[hidden]> wrote:

> Hi,
>
> Am 18.01.2017 17:30, schrieb Richard Hodges:
>
>> Totally agree with returning a string factory. That makes perfect sense.
>> onto(x) could return the correct kind of wrapper, depending on the
>> argument
>> type of x. So it could cope with x being for example, std::string&,
>> std::string const&, std::string&& or std::ostream&.
>>
>
> How about this:
>
> auto s = concat(1, " ", 2).str(); // -> s = "1 2"
> concat(" ", 3).append_to(s); // -> s = "1 2 3"
> // reuse preallocated memory
> concat(4, " ", 5).overwrite(s); // -> s = "4 5"
>
> overwrite() could also take a std::string_view with C++17, or const char*
> and size_t with earlier versions of the standard library.
>
> As an observation, expressing the join as an iterator pair lends itself to
>> being implemented in terms of std::copy(first, last,
>> formatting_iterator<...>).
>>
>
> That definatelly is a possible implementation, yes. Though, of course
> having join(), concat() and maybe other functions return string factories
> instead of strings, enables generating the whole string in a single buffer
> without copying.
>
> concat(join(...), " ", 42, " - ", join(...), format("format string %1% %2%
> %3%", a, b, 42)).str();
>
> concat() will allocate a long enough string and call overwrite() on the
> results of join() and format() with string views on that string.
>
> Taking everything together, a string factory will have at least interface
> like this:
>
> template<typename T>
> constexpr bool string_factory() {
> return requires(T a, std::string& s, std::string_view v, const char*
> p, size_t len) {
> // estimate necessary memory to render the string
> { a.size() } const -> size_t;
>
> // render and return result
> { a.str() } const -> std::string;
>
> // render at the end of an existing string - return the number of
> generated chars
> { a.append_to(s) } -> size_t;
>
> // render into an existing string, reusing its preallocated memory
> { a.overwrite(s) } -> size_t;
>
> // render into a string view
> { a.overwrite(v) } -> size_t;
>
> // render into a character buffer
> { a.overwrite(p, len) } -> size_t;
> };
> }
>
> I hope, the constraint syntax is more or less correct. I haven't used
> constraints in real code up to now ;-)
>
> I think this is good for containers, but for a series of disjoint types, or
>> for joining words (as opposed to letters), you'd still need some
>> templatery.
>>
>
> Yes, sure. You might also want to have somthing like this:
>
> std::tuple<std::string, int, double> my_tuple{"asdf", 42, 2.5;
> join(separator(", "), my_tuple);
> // -> "asdf, 42, 2.5"
>
> I think, using C++17s std::apply() it should be a straight forward wrapper
> around concat().
>
> boost::range springs to mind as a reasonable helper for expressing to
>> concat (or join) that you want to treat each element of a container.
>>
>
> Yes, when I wrote about my idea of join(), I thought of ranges as well.
> With range adaptors, that will make up for a very powerfull and btw. fast
> library to generate strings:
>
> format("file names and sizes:\n%1%\n",
> join(separator('\n'),
> my_files |
> range::transformed([](const std::filesystem::path& f) -> auto {
> return concat(separator(": "),
> f.filename(),
>
> std::filesystem::file_size(f));
> })).str();
>
> format().str() will ask the join() string factory to render into the
> preallocated buffer. Then join() will walk through its range and find, that
> it has a range string factories, returned by concat(). Therefore it asks
> every string factory to render to the given buffer.
>
> We "just" need format(), join(), concat(), and the corresponding string
> factories.
>
>
> Christof
>
> _______________________________________________
> Unsubscribe & other changes: http://lists.boost.org/mailman
> /listinfo.cgi/boost
>


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk