第26.1章:模块与四类概念

English

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 层:


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章。

要点