第26.1章:模块与四类概念
1. 模块就是 API 契约
fast_io 同时提供头文件和 C++20 模块接口。头文件暴露了几乎整个实现;
模块只暴露一份经过筛选的子集,也就是
share/fast_io/fast_io_inc/*.inc 里列出的名字。
导入者应该把这部分当作公开 API。
这份参考遵循的正是这个区分:只有模块导出的名字才会被当作模块 API 记录。 某个有用的、只在头文件里存在的辅助函数,会被明确标注为头文件接口, 而不会悄悄说成模块契约的一部分。
头文件接口仍然有效。#include <fast_io.h> 依然是本教程的构建方式,
也是模块不完整时的退路。但两者都存在时,模块导出列表是更小、更稳定的那一层。
2. 模块清单
| 模块 | 接口文件 | 增加什么 | 导入 |
|---|---|---|---|
fast_io |
fast_io.cppm |
总括模块:核心词汇、I/O 操作、设备、缓冲区、容器、freestanding 辅助、 网络与时间类型。 | 无 |
fast_io.floating |
fast_io_floating.cppm |
binary16、bfloat16、binary32、binary64、binary80 和 binary128 的最短往返
浮点转换。需要单独构建,并要求 #embed。 |
核心 fast_io 头文件 |
fast_io.i18n |
fast_io_i18n.cppm |
locale blob、lc_locale、lc_ctx、imbue、
locale 感知的 concat 和 lc_dump。loader 直接编译进模块。 |
fast_io |
fast_io_crypto |
fast_io_crypto.cppm |
CRC32/CRC32C、AES-128/192/256、Ed25519、X25519、NIST 椭圆曲线以及 签名/验签辅助。 | fast_io |
fast_io.tls |
fast_io_tls.cppm |
TLS 客户端、TLS socket 文件、根证书库、对端证书、平台 TLS 后端和 异步 TLS 定制点。 | fast_io、fast_io_crypto |
fast_io_legacy |
fast_io_legacy.cppm |
FILE* 互操作和 std::basic_filebuf 互操作。
新代码只读,不写。 |
fast_io |
fast_io.json |
fast_io_json.cppm |
流式 JSON handler 接口,以及建立在同一 parser 上的 DOM document。 | fast_io 容器与核心类型 |
命名并不统一:fast_io.floating、fast_io.i18n、
fast_io.tls 和 fast_io.json 用点号,
而 fast_io_crypto 和 fast_io_legacy 用下划线。
以表里的拼写为准,不要从这个现状推导出某种命名规律。
3. 四类概念
如果按类型满足的概念来分类,而不是按头文件位置来分类,fast_io 会好懂得多。 几乎所有东西都落在四类里:
| 类别 | 含义 | 典型名字 |
|---|---|---|
| 设备(Device) | 能提供输入字节、接受输出字节、定位,或参与 transmit 的东西。 设备是端点,不是格式化器。 | native_file、ibuf_file、obuf_file、
iobuf_file、native_pipe、iobuf_pipe、
iobuf_socket_file、c_file、
basic_iobuf |
| I/O 类型(I/O type) | 把值和操作连接起来的词汇:scatter 数组、alias、reserve 类型、状态值、
observer,以及 print/scan 使用的定制点。 |
basic_io_scatter_t、io_type_t、
io_reserve_type_t、io_alias_t、
io_scatter_status_t、流 observer 与引用 |
| 操纵器(Manipulator) | 改变单个参数格式的小值。它携带 manip_tag,不修改流,
调用结束后也不残留状态。 |
hex、fixed、left、
boolalpha、code_cvt、os_c_str、
lc_dump |
| 字符串类(Strlike) | 字符串形状的输出汇:连续字符存储,带
strlike_begin/strlike_curr/strlike_end、
reserve 和 append 定制。这就是 concat、locale 格式化和
“打印到内存”所使用的目标。 |
fast_io::string、basic_string_view、
basic_ostring_ref_fast_io、
io_strlike_reference_wrapper |
它们按一个方向组合:设备接收结果;结果是内存里的文本时, strlike 可以作为目标;I/O 类型承载中间表示; 操纵器在参数经过时改变它的格式。
::fast_io::println(device, ::fast_io::mnp::hex(value));
// ^device ^manipulator
那 transcoder 呢?
transcoder 是更老的一类。它描述的是有状态的编码转换管线。
它原本的大部分用途,现在由 code_cvt 操纵器和
code_cvt_os_c_str 别名表达:在一次 print 调用里转换一个值,
不需要单独的对象。把 transcoder 当作遗留接口、仍在评估的东西:
不要围绕它设计新 API,先确认 code_cvt 是否已经够用。
4. 总括模块导出了什么
导出列表就是这份库最好的目录。主要分组如下:
| 分组 | 导出示例 |
|---|---|
| I/O 函数 | print、println、perr、
perrln、panic、panicln、
scan、scan_some、debug_print、
debug_perr(未禁用时) |
| 设备与缓冲区 | ibuf_file、obuf_file、iobuf_file、
iobuf_pipe、iobuf_socket_file、可加锁变体、
basic_ibuf、basic_obuf、basic_iobuf |
| 容器 | string、vector、array、
span、string_view、list、
deque、queue、stack、
B 树和 Swiss 表的字符串容器 |
| 核心词汇 | basic_io_scatter_t、io_type_t、
io_reserve_type_t、io_alias_t、
print_reserve_define、scan_context_define、
parse_by_scan |
| 操作 | read_some、read_all、write_some、
write_all、pread_*、pwrite_*、
scatter 变体、print_freestanding |
| Freestanding 与工具 | 分配器适配器、freestanding 算法、位操作、endian/byte swap、
SIMD intrinsics、posix_timespec64、
iso8601_timestamp |
| Herbceptions | 定义 __HERBCEPTIONS__ 时,模块重新导出
std::error、std::errc、
std::parse_errc 和查询用操纵器。 |
5. 模块导出的操纵器
下面是 fast_io 模块目前导出的操纵器,按用途分组。
它们都在 ::fast_io::mnp(::fast_io::manipulators 的别名)里。
| 分组 | 名字 |
|---|---|
| 整数进制 | base<N>、baseupper<N>、
bin、oct、dec、hex、
hexupper、hex0x、hex0xupper |
| 浮点格式 | decimal、general、fixed、
scientific、hexfloat,以及带千位分组的
comma_decimal、comma_general、comma_fixed、
comma_scientific、comma_hexfloat |
| 布尔 | boolalpha(可选大写模板参数) |
| 宽度与对齐 | width、left、middle、right、
internal |
| 指针与句柄视图 | pointervw、handlevw、methodvw、
addrvw、dfvw、bitfieldvw |
| 字符串与范围视图 | os_c_str、os_c_str_carr、
os_c_str_null_terminated、
os_c_str_null_terminated_carr、
os_c_str_or_nullptr、os_c_str_with_known_size、
rgvw、strvw |
| 编码 | code_cvt、code_cvt_os_c_str |
| 二进制 | leb128_get、leb128_put |
| 网络 | ip_generic、ip_scan_generic |
| 源码与错误 | cur_src_loc、name、message、
name_message、posix_equivalent_name、
posix_equivalent_message、
posix_equivalent_name_message、
herbceptions_query_information |
| Locale | lc_dump(来自 fast_io.i18n) |
| 行跳过器 | lf、crlf、cr、
line_skipper_platform(来自 fast_io.tls) |
模块还导出这些值背后的类型:
scalar_flags、scalar_manip_t、scalar_placement、
floating_format、percentage_flag、lc_time_flag、
ip_flags、ip_manip_t、
ip_scan_manip_t、member_function_pointer_holder_t 和
whole_get_t。
ordinal、percentage_conventional、
percentage_sex_ratio 及其 comma/base 变体、
host、url、url_path、token、
header_value、sql_string、funcvw、
itervw、fieldptrvw、chvw、
enum_int_view、small_scatter 和 mtvw。
它们在头文件里存在;今天需要它们就用头文件接口。
6. Locale 模块
fast_io.i18n 单独成模块,是因为 locale 数据体积大且可选。
它导出 fast_io,并在上面增加 locale 层:
- 线格式类型。
l10n::lc_locale是一张扁平的、 位置无关的镜像。内部指针是lc_rva,字符串是lc_scatter,所以这份字节可以从文件映射、嵌入数组、 WebAssembly 模块或资源里直接使用。 - 加载。
l10n::load_l10n映射 locale blob, 检查 magic 和版本,验证一次镜像,然后返回lc_locale const *。 沙箱里的调用者可以直接传入自己已经拿到的镜像指针。 - 绑定。
imbue(loc, out)包装一个输出流。lc_ctx延迟构建,只有参数真的需要 locale 格式化时才建立。 - 格式化。
lc_concat/lc_concatln生成 locale 格式的字符串;mnp::lc_dump打印 locale 的文本转储;lc_time_flag选择时间格式。
import fast_io.i18n;
int main()
{
using namespace ::fast_io::io;
auto const *loc{::fast_io::l10n::load_l10n(u8"de_DE.UTF-8")};
// Grouping and separators come from LC_NUMERIC.
println(::fast_io::imbue(loc, ::fast_io::out()), 1234567);
// The whole locale as text, for inspection.
println(::fast_io::imbue(loc, ::fast_io::out()), ::fast_io::mnp::lc_dump(loc));
}
basic_lc_all 提供的 locale 类别有:identification、monetary、numeric、
time、messages、paper、telephone、name、address、measurement 和 keyboard。
数字层带千位分隔符和分组;时间层带 POSIX 格式串和替代数字。
没有分组的 locale 走普通格式化路径,根本不会构建 lc_ctx。
头文件接口是 #include <fast_io_i18n.h>。
模块把 loader 编译进自己里面,所以导入 fast_io.i18n
不需要额外链接 fast_io_i18n 库。
7. 导入与构建
模块文件位于 {fast_io}/share/fast_io。先构建
fast_io,再构建导入它的模块。依赖顺序是:
fast_io
├── fast_io.i18n
├── fast_io_crypto
│ └── fast_io.tls
├── fast_io_legacy
├── fast_io.json
└── fast_io.floating (separately compiled conversion support)
import fast_io;
int main()
{
::fast_io::io::println("Hello from the module");
::fast_io::vector<int> v{1, 2, 3};
for (auto x : v)
{
::fast_io::io::print(x, " ");
}
}
目前模块的可靠路径是 Clang;GCC 的模块支持仍是实验性的, 带 herbceptions 的 GCC 构建在某些 fast_io 模块单元上已知会 ICE。 MSVC 不受支持,因为它没有 herbceptions。具体的预编译和链接命令在 第1.8章。
要点
- 模块导出列表才是公开 API 契约;头文件暴露更多,但不是全部都被导出。
- 模块集合是
fast_io、fast_io.floating、fast_io.i18n、fast_io_crypto、fast_io.tls、fast_io_legacy和fast_io.json。 - 四类概念是 device、I/O type、manipulator 和 strlike; transcoder 是遗留类别,仍在评估。
- 操纵器是单参数的格式化包装,不是会残留的流状态。
fast_io.i18n拥有 locale blob、loader、imbue和 locale 感知的拼接。- 先构建
fast_io;目前可靠的模块编译器是 Clang。