Ch26.5: Devices
1. What a Device Is
A device is the endpoint of an I/O operation. It is not a formatter and not a container. The concept is defined by the operations a type provides:
| Capability | Operation | Examples |
|---|---|---|
| Input | read_some, read_all, pread_*, scatter
variants |
native_file, ibuf_file, iobuf_file,
iobuf_pipe, socket files |
| Output | write_some, write_all, pwrite_*, scatter
variants |
native_file, obuf_file, iobuf_file,
console observers |
| Seek | position queries and seeks | files; not pipes or sockets |
| Transmit | transmit_some_bytes, transmit_all_bytes |
files, pipes and sockets with a transmit handle |
| Buffer | basic_ibuf, basic_obuf, basic_iobuf |
buffered wrappers around a device |
A type does not have to implement all capabilities. A socket is not seekable. A pipe is unidirectional. A console is not a regular file. The type system reports the missing capability at the point where you ask for it, instead of pretending every device is a file descriptor with the same behaviour.
2. Owning Device vs Observer
fast_io separates the thing that owns a handle from the thing that merely refers to one. The owning type closes the handle in its destructor; the observer type does not.
| Role | Examples | Lifetime rule |
|---|---|---|
| Owner | native_file, ibuf_file, obuf_file,
iobuf_file, iobuf_pipe, iobuf_socket_file,
c_file, filebuf_file |
Closes on destruction; move-only. |
| Observer | native_io_observer, c_io_observer,
filebuf_io_observer, the result of in(),
out(), err() |
Borrowed; must not outlive the owner. |
| Buffer wrapper | basic_ibuf, basic_obuf, basic_iobuf,
ibuf_file, obuf_file, iobuf_file |
Owns the underlying device and adds buffering. |
Returning an observer from a function is how fast_io exposes a device without transferring ownership. Returning an owner is how a factory hands you a resource you must close.
3. The File Family
| Type | Buffering | Direction | Use |
|---|---|---|---|
::fast_io::native_file |
Unbuffered | Bidirectional, seekable | Large bulk transfers, mmap, direct OS semantics. |
::fast_io::ibuf_file |
Buffered | Input | Line/token scanning, small reads. |
::fast_io::obuf_file |
Buffered | Output | Many small writes, formatted output. |
::fast_io::iobuf_file |
Buffered | Bidirectional | Read/write in one file, patching headers. |
::fast_io::ibuf_file_lockable etc. |
Buffered + mutex | Same as base | One shared stream across threads. |
::fast_io::c_file |
Legacy FILE* |
Bidirectional | C library interoperation; read-only for new code. |
::fast_io::filebuf_file |
Legacy basic_filebuf |
Bidirectional | iostream interoperation; read-only for new code. |
The five character variants exist for the buffered file types:
char, char8_t, char16_t, char32_t and
wchar_t. The native file type is byte-oriented; the buffered wrappers carry
the character type used by print/scan.
#include <fast_io.h>
int main()
{
using namespace ::fast_io::io;
::fast_io::obuf_file out("out.txt");
println(out, "value = ", 42);
::fast_io::ibuf_file in("out.txt");
::fast_io::string line;
scan(in, ::fast_io::mnp::strlike_line_get(line));
}
4. Buffering Is a Wrapper
basic_ibuf, basic_obuf and basic_iobuf are the
generic wrappers. The named file types are aliases that combine a native file with the
wrapper and choose a character type. This is why the same buffering rules apply to files,
pipes and sockets:
| Wrapper | Adds | Typical alias |
|---|---|---|
basic_ibuf<T> |
Input buffer and refill | ibuf_file |
basic_obuf<T> |
Output buffer and flush | obuf_file |
basic_iobuf<T> |
Both buffers | iobuf_file, iobuf_pipe,
iobuf_socket_file |
A wrapper is still a device. It satisfies the same input/output stream concepts as the
underlying type, plus buffer operations. That is why scan can require a
buffered input and accept ibuf_file while rejecting an unbuffered
native_file.
5. Pipes, Sockets and Consoles
| Device | Module | Notes |
|---|---|---|
native_pipe |
header-side | Unbuffered pair; in() and out() ends. Not in the
module export list yet. |
iobuf_pipe |
fast_io |
Buffered pipe for print/scan and process output. |
native_socket_file |
fast_io |
Raw socket handle; unidirectional or bidirectional depending on protocol. |
iobuf_socket_file |
fast_io |
Buffered socket for formatted protocols. |
tls_socket, iobuf_tls_socket_file |
fast_io.tls |
TLS layer over a socket; same I/O operations. |
in(), out(), err() |
fast_io |
Observers over the native standard streams. |
dir_file |
fast_io |
Directory handle; iterate or open files relative to it. |
Pipes and processes are covered in Ch11.20; sockets
in Ch11.10; TLS in the fast_io.tls
module.
6. Choosing a Device
- Do you need formatted text? Use
ibuf_file/obuf_file/iobuf_file. If you also need portability to a non-file stream, use the matching pipe or socket buffered type. - Are you moving a large blob? Use
native_fileandtransmit, or a memory map from Ch11.8. - Do you need a borrowed handle? Use the observer type, not the owner.
- Do you need one shared stream across threads? Use the lockable buffered alias, not a plain buffer plus an external lock.
- Are you reading C or iostream code? Use
c_fileorfilebuf_fileat the boundary; do not build new code on them.
7. What the Module Exports
The fast_io module exports the file family, the pipe family, socket files,
dir_file, the buffer wrappers and the lockable aliases. c_file
and filebuf_file come from fast_io_legacy. TLS socket types come
from fast_io.tls. Header-only device helpers that are not in
device.inc or io_buffer.inc are not part of the module surface.
in(), out(), err() or a
*_io_observer, it is a borrow. Do not store a borrow past the lifetime of the
owner.
Key Takeaways
- A device is defined by capabilities: input, output, seek, transmit and buffering.
- Owners close on destruction and are move-only; observers borrow a handle.
native_fileis unbuffered;ibuf_file,obuf_fileandiobuf_fileadd buffering.basic_ibuf,basic_obufandbasic_iobufare the generic wrappers behind the named aliases.- Pipes, sockets and TLS sockets are devices with the same operations, not a separate API universe.
c_fileandfilebuf_fileare legacy interoperation types;fast_io_legacyexports them.- Choose buffering by access pattern, not by file size alone.