Boost logo

Boost :

From: Christopher Kohlhoff (chris_at_[hidden])
Date: 2005-10-17 00:29:38

Hi Beman,

--- Beman Dawes <bdawes_at_[hidden]> wrote:
> There are still some void *'s in the public interface. The io_control
> helpers have data() members returning void *'s, for example.
> Any chance of wringing out the non-memory management void *'s before
> a
> submission? I know it sounds picky, but a lot of C++ programmers
> object
> strongly to void * in public interfaces for anything except the
> rawest of
> raw memory management.

Hmm, I'm not sure. Here are the current uses of void* and their

* buffer() and buffers() - so that arbitrary application data
structures can be sent without an additional buffer copy.

* const_buffer::data() and mutable_data::data() - to get a pointer to
pass to OS functions like send and recv.

* IO_Control_Command::data() - to get a pointer to pass to OS functions
like ioctl or WSAIOCtl.

* Socket_Option::data() - to get a pointer to be pass to OS functions
like setsocketopt and getsockopt.

The last 3 are similar, in that they involve getting a pointer to be
passed to a low-level OS function. (Note that the Endpoint concept has
a similar thing, except that it returns an implementation-defined type
rather than void*.)

I don't want to preclude user-defined IO_Control_Command or
Socket_Option types, so there has to be *some* way of getting a pointer
to the data in the public interface. However I'd be very happy to
change it if there's a better way of accomplishing the same thing.
> I also wonder if the interface could be thinned without reducing
> functionality. For example, could buffer() and buffers() be folded
> into one function, or at least overloads with the same name.

I had considered making the mutable_buffer/const_buffer classes also
implement the Mutable_Buffers/Const_Buffers concepts, but i found it
was confusing as to whether the begin()/end() functions applied to the
underlying memory.

What about this for an idea:

- Remove the buffer() functions.

- Rename buffers() to buffer().

- Have a specialisation for const_buffer<1> that supports conversion to

- Have a specialisation for mutable_buffer<1> that supports conversion
to mutable_buffer and const_buffer.

Then to send a single buffer you could write:

  sock.write(buffer(data, size));

and still use the chaining to send multiple buffers:

  sock.write(buffer(data1, size1)(data2, size2));

The conversion to the individual buffer classes should still let you

  std::vector<const_buffer> bufs;
  bufs.push_back(buffer(data1, size1));
  bufs.push_back(buffer(data2, size2));


  const_buffers<2> bufs = {
    buffer(data1, size1),
    buffer(data2, size2) };

> Likewise, could the 12
> free read/write functions be reduced to 2 names (presumably
> read/write) or 4
> names (presumably read, async_read, write, async_write) via folding
> and/or
> overloading?. Am I the only one who feels the large number of names
> makes the interface appear more complex than it really is?

No you're not, especially after I've had to type async_read_at_least_n
many times ;)

Reducing to 4 names might be feasible. One thing I realised recently is
that, in terms of behaviour, read() and read_n() are just special cases
of read_at_least_n(). The same obviously applies to write*() and the
async equivalents.

Could something be done by extending the Mutable_Buffers/Const_Buffers
concepts to have a desired_minimum_transfer() member function? Bad
name, I know, but it would return the minimum number of bytes to read
or write from the list of buffers.

It would have to be optional so that containers like std::vector can
still meet the concept requirements. It would probably have a default
of 0, i.e. same semantics as current asio::read() or asio::write().

You could then write:

  read(sock, bufs); // Same as existing read()

  read(sock, all_of(bufs)); // Same as read_n()

  read(sock, at_least(bufs, 42)); // Same as read_at_least_n().

I'm ready to take guidance here :)


Boost list run by bdawes at, gregod at, cpdaniel at, john at