Skip to content

逐库函数参考 ​

本页覆盖 codecin/lib/<name>/src/ 下全部 41 个官方标准库(每个库一个 pic 包:pic.toml + src/<name>.cin), 每个库一节,先说明用途与 import 语句,再以表格列出该库的全部函数, 最后给出一个可直接运行的 CIN 示例。

约定与阅读提示:

  • 签名(参数个数、顺序、类型)与返回值直接取自 codecin/lib/<库>/src/<库>.cin 中的真实定义;
  • CIN 数组不携带长度,因此所有数组接口都要求显式传入元素个数 n;
  • void 返回值表示该函数只产生副作用(原地修改数组、写输出数组、打印、写文件),无返回值;
  • _sorted 结尾的函数要求输入已升序,否则结果无意义;矩阵类 _to 风格函数把结果写入调用方提供的输出数组;
  • 纯 CIN 库只调用语言内建,行为与运行方式无关; io / gui / termux / key / ffi / net 六库依赖宿主能力,由 Go 原生引擎实现, --sandbox 下调用会被拦截; cstd / cppstd / gostd 三个兼容层是纯 CIN(gostd 的 go_os_args_* 依赖命令行参数内建)。

array ​

整数数组工具库。CIN 数组不带长度,所有接口都要显式传元素个数 n。就地修改的接口返回值 是 void,调用后直接读原数组即可。

cin
import "array.cin"
函数名签名返回值说明与边界行为
a_suma_sum(int[] a, int n)int前 n 个元素求和;n <= 0 时为 0
a_maxa_max(int[] a, int n)int最大值;n <= 0 返回 0(不是错误码)
a_mina_min(int[] a, int n)int最小值;n <= 0 返回 0
a_avga_avg(int[] a, int n)float平均值,走 a_sum(a,n) / n 的浮点除法;n <= 0 返回 0.0
a_finda_find(int[] a, int n, int v)int线性查找首个等于 v 的下标;未找到返回 -1
a_containsa_contains(int[] a, int n, int v)int是否包含 v,返回 1/0
a_counta_count(int[] a, int n, int v)intv 出现次数
a_reversea_reverse(int[] a, int n)void原地反转前 n 个元素
a_filla_fill(int[] a, int n, int v)void把前 n 个元素全部置为 v
a_copya_copy(int[] src, int[] dst, int n)void把 src 前 n 个元素拷入 dst;长度不足会越界
a_index_of_maxa_index_of_max(int[] a, int n)int最大值下标(并列取最靠前);n <= 0 返回 -1
a_index_of_mina_index_of_min(int[] a, int n)int最小值下标(并列取最靠前);n <= 0 返回 -1
a_sum_rangea_sum_range(int[] a, int lo, int hi)int左闭右开区间 [lo, hi) 的和
a_lower_bounda_lower_bound(int[] a, int n, int v)int首个 >= v 的下标(数组需有序);无则 -1。实现是线性扫描,不是二分
cin
import "array.cin"

function main() -> int {
    int a[6] = {4, 8, 1, 8, 3, 6}
    println("sum=" + int_to_str(a_sum(a, 6)))              // 30
    println("avg=" + float_to_str(a_avg(a, 6)))            // 5
    println("find3=" + int_to_str(a_find(a, 6, 3)))        // 4
    a_reverse(a, 6)
    println("first=" + int_to_str(a[0]))                   // 6
    a_fill(a, 3, 0)
    println("count0=" + int_to_str(a_count(a, 6, 0)))      // 3
    return 0
}

bigint ​

任意精度整数库。用十进制数位数组表示整数(d[0] 是个位,n 是有效数位个数, neg 是符号位),整块数据装在 struct BigInt 的固长数组里,不使用任何动态内存, 也不依赖宿主能力内建。

容量常量 BIGINT_DIGITS = 64,即最多 64 位十进制数位(最大 10^64 - 1,约 1.8e64),足以精确表示 2^64 = 18446744073709551616 或 25! = 15511210043330985984000000。 超出容量时饱和:结果的绝对值变成 10^64 - 1(符号保留),同时把溢出标志置 1, 可用 bi_overflow() 查询、bi_reset_overflow() 清除;饱和值继续参与运算仍得到饱和值, 不会崩溃也不会静默给出错误的中间值。库内全局变量只有 BIGINT_DIGITS 与 bi_ovf 两个 (合计 16 字节)。

内存提示:BigInt 占 66 槽 = 528 字节。按 CIN 值语义写 BigInt r = bi_add(a, b) 时, 每个"返回新值"的调用会在堆上分配一块 struct 且不回收(默认 1 GiB 内存下常规使用不会触顶)。 库内所有长循环都改用 bi_xxx_into(a, b, out) 复用调用方提供的 out(bi_fact / bi_pow 因此只占固定几块内存);自己写长循环时请同样使用 *_into 形式,必要时用 --mem-size 加大内存。

cin
import "bigint.cin"
函数名签名返回值说明与边界行为
bi_capacitybi_capacity()int固定返回容量常量 64
bi_overflowbi_overflow()int是否发生过容量饱和,1/0(粘滞,需手动清除)
bi_reset_overflowbi_reset_overflow()void清除溢出标志
bi_clearbi_clear(BigInt a)void把 a 置为 0(清空全部数位、n = 1、neg = 0)
bi_normbi_norm(BigInt a)void规范化:收紧 n、去掉前导零、零的符号归 0;n 越界会被夹到 [1, 64]
bi_copybi_copy(BigInt dst, BigInt src)void槽级值拷贝(不是指针别名),拷贝后做规范化;dst 与 src 可以是同一结构体
bi_saturatebi_saturate(BigInt a, int s)void把 a 置为 10^64 - 1,s < 0 时取负号,并置溢出标志
bi_signbi_sign(BigInt a)int符号:-1 / 0 / 1(先规范化 a)
bi_is_zerobi_is_zero(BigInt a)int是否为零,1/0
bi_is_negativebi_is_negative(BigInt a)int是否为负数,1/0(零返回 0)
bi_digitsbi_digits(BigInt a)int去掉前导零后的十进制位数;零返回 1
bi_is_saturatedbi_is_saturated(BigInt a)int是否恰好等于容量上界 10^64 - 1(64 个 9),1/0
bi_zerobi_zero()BigInt构造零
bi_from_intbi_from_int(int v)BigInt由 64 位整数构造;int 最多 19 位十进制,因此永远不会溢出
bi_from_strbi_from_str(string s)BigInt解析十进制串:允许前导 +/-;遇到第一个非数字字符即停止解析("12ab" → 12,"abc"/""/"-" → 0);有效数字超过 64 位时饱和为 10^64 - 1 并置溢出标志
bi_to_strbi_to_str(BigInt a)string十进制字符串;零输出 "0",负数带前导 -
bi_cmp_magbi_cmp_mag(BigInt a, BigInt b)int比较绝对值:-1 / 0 / 1
bi_cmpbi_cmp(BigInt a, BigInt b)int与数学顺序一致的比较(负数小于零小于正数):-1 / 0 / 1
bi_add_mag_intobi_add_mag_into(BigInt a, BigInt b, BigInt out)voidout = |a| + |b|;out 必须与 a、b 为不同结构体;结果非负
bi_sub_mag_intobi_sub_mag_into(BigInt a, BigInt b, BigInt out)voidout = |a| - |b|,要求 |a| >= |b|;out 必须与 a、b 不同
bi_add_intobi_add_into(BigInt a, BigInt b, BigInt out)voidout = a + b(符号规则与数学一致);out 必须与 a、b 为不同结构体
bi_sub_intobi_sub_into(BigInt a, BigInt b, BigInt out)voidout = a - b;out 必须与 a、b 为不同结构体
bi_neg_intobi_neg_into(BigInt a, BigInt out)voidout = -a(零的相反数仍为 0)
bi_abs_intobi_abs_into(BigInt a, BigInt out)voidout = |a|
bi_mul_intobi_mul_into(BigInt a, BigInt b, BigInt out)voidout = a * b,逐位相乘 + 进位(不依赖原生 64 位乘法);out 必须与 a、b 为不同结构体
bi_mul_small_intobi_mul_small_into(BigInt a, int k, BigInt out)voidout = a * k;要求 |k| <= 10^17(更大请用 bi_mul_into),out 必须与 a 不同
bi_absbi_abs(BigInt a)BigInt绝对值
bi_negbi_neg(BigInt a)BigInt相反数(零的相反数仍为 0)
bi_addbi_add(BigInt a, BigInt b)BigInta + b
bi_subbi_sub(BigInt a, BigInt b)BigInta - b
bi_mulbi_mul(BigInt a, BigInt b)BigInta * b(逐位相乘 + 进位,单步中间量不超过 64 位)
bi_mul_smallbi_mul_small(BigInt a, int k)BigInta * k(快速乘以 64 位小整数)
bi_powbi_pow(BigInt a, int e)BigInta 的 e 次幂(快速幂);e < 0 视为 0,即返回 1;中途一旦饱和立即返回饱和值
bi_factbi_fact(int n)BigIntn 的阶乘(n < 0 视为 0! = 1);超过容量时饱和并置溢出标志,并立即停止迭代
cin
import "bigint.cin"

function main() -> int {
    BigInt a = bi_from_str("123456789012345678901234567890")
    BigInt b = bi_from_str("-98765432109876543210")
    println("a      = " + bi_to_str(a))
    println("b      = " + bi_to_str(b))
    println("a + b  = " + bi_to_str(bi_add(a, b)))
    println("a - b  = " + bi_to_str(bi_sub(a, b)))
    println("a * b  = " + bi_to_str(bi_mul(a, b)))
    println("20!    = " + bi_to_str(bi_fact(20)))
    println("2^64   = " + bi_to_str(bi_pow(bi_from_int(2), 64)))
    println("cmp    = " + int_to_str(bi_cmp(a, b)))
    println("digits = " + int_to_str(bi_digits(a)))
    println("ovf    = " + int_to_str(bi_overflow()))
    return 0
}

bits ​

64 位位运算库。内建 >> 是算术右移(负数补 1),因此本库所有涉及负数的位移都先做 符号位/掩码处理,保证结果与 64 位无符号语义一致。位下标合法范围是 0..63。

cin
import "bits.cin"
函数名签名返回值说明与边界行为
bits_maskbits_mask()int返回 64 位全 1 掩码 0xFFFFFFFFFFFFFFFF
bits_popcountbits_popcount(int x)int二进制中 1 的个数,含符号位;bits_popcount(-1) 为 64
bits_clzbits_clz(int x)int前导零个数(按 64 位);x < 0 返回 0,x == 0 返回 64
bits_ctzbits_ctz(int x)int末尾零个数;x == 0 返回 64
bits_is_pow2bits_is_pow2(int x)int是否为 2 的幂,仅正数成立;x <= 0 返回 0
bits_next_pow2bits_next_pow2(int x)int不小于 x 的最小 2 的幂;x <= 1 返回 1;溢出时循环提前结束
bits_testbits_test(int x, int i)int读取第 i 位,返回 0/1;i 越界返回 0
bits_setbits_set(int x, int i)int置位;i 越界时原样返回 x
bits_clearbits_clear(int x, int i)int清位;i 越界时原样返回 x
bits_togglebits_toggle(int x, int i)int取反某一位;i 越界时原样返回 x
bits_rotlbits_rotl(int x, int n)int循环左移,n 自动对 64 取模并归一为非负数;k == 0 返回 x
bits_rotrbits_rotr(int x, int n)int循环右移,等价于 bits_rotl(x, 64 - k)
bits_reversebits_reverse(int x)int64 位位序反转(低位变高位)
bits_range_maskbits_range_mask(int lo, int hi)int闭区间 [lo, hi] 掩码;lo < 0、hi > 63 或 hi < lo 返回 0
bits_extractbits_extract(int x, int lo, int hi)int取出 [lo, hi] 并右移到最低位;区间非法返回 0
bits_insertbits_insert(int x, int lo, int hi, int v)int用 v 的低位替换 x 的 [lo, hi];区间非法原样返回 x
bits_bswapbits_bswap(int x)int字节序翻转(bswap64);bits_bswap(0x0102) 为 0x0201000000000000
cin
import "bits.cin"

function main() -> int {
    println("pc=" + int_to_str(bits_popcount(0xFF)))        // 8
    println("clz=" + int_to_str(bits_clz(1)))               // 63
    println("ctz=" + int_to_str(bits_ctz(8)))               // 3
    println("pow2=" + int_to_str(bits_is_pow2(64)))         // 1
    println("next=" + int_to_str(bits_next_pow2(5)))        // 8
    println("mask=" + int_to_str(bits_range_mask(4, 7)))    // 240 (0xF0)
    println("ext=" + int_to_str(bits_extract(0xABCD, 4, 7)))// 12 (0xC)
    println("ins=" + int_to_str(bits_insert(0, 4, 7, 0xC))) // 192 (0xC0)
    return 0
}

bitset ​

多字位集合库。纯 CIN 实现,不做动态内存分配:位集合存放在库内全局数组 bs_data[16] (2 个槽 × 8 个 64 位字)里。容量常量:BS_WORDS = 8(每集合 8 个 64 位字)、 BS_BITS = 512(每集合 512 位,合法下标 0..511)、BS_SLOTS = 2(槽号 0/1)。 全局数据段只占 bs_data[16] + bs_cur = 17 槽 = 136 字节。本库与 bits.cin 的 单字(64 位)运算互补:bits.cin 运算作用在一个 int 值上,本库把一整套 512 位的位集合 放在全局状态里。

槽位模型(重要):

  • 库内有两个互相独立的位集合槽:槽 0 与槽 1;bs_cur 记录当前槽(初始为 0, bs_reset() 会把它复位为 0)。
  • 所有单槽操作(bs_set / bs_clear / bs_toggle / bs_test / bs_count / bs_not / bs_shift_left / bs_shift_right / bs_from_int / bs_to_int / bs_get_word / bs_set_word / bs_count_word / bs_first_set / bs_last_set / bs_next_set / bs_any / bs_none / bs_clear_all)只作用于当前槽。
  • bs_and / bs_or / bs_xor / bs_equals 的参数 other 是“另一操作数槽”的槽号: 读的是那个槽,三个逻辑运算把结果写回当前槽(原地),另一个槽保持不变; bs_equals 只比较,不改动任何槽。bs_copy_from(src) 把 src 槽复制到当前槽。

边界行为:

  • 位下标越界(i < 0 或 i > 511):bs_test 返回 0;bs_set / bs_clear / bs_toggle 返回 0 且不写内存;bs_next_set 返回 -1。
  • 槽号越界(不在 0..1):bs_select / bs_copy_from / bs_clear_slot / bs_and / bs_or / bs_xor / bs_equals 返回 0 且不改变任何状态。
  • bs_count_word(w) 的 w 越界返回 -1(合法计数是 0..64);bs_get_word(w) 的 w 越界 返回 0(64 位字的取值本身就是任意整数,没有无歧义的失败值);bs_set_word(w, v) 的 w 越界返回 0 且无操作。
  • 位移量 k < 0 视为非法(无操作),k == 0 无操作,k >= 512 时当前槽整体清零。
  • bs_not() 严格按 BS_BITS = 512 位取反(逐字与 64 位全 1 掩码异或,不用 ~ 直接取反 64 位字),因此空集取反得到 512 位全 1 的满集。
cin
import "bitset.cin"
函数名签名返回值说明与边界行为
bs_bitsbs_bits()int每个位集合的总位数,固定返回 512(BS_BITS)
bs_wordsbs_words()int每个位集合的 64 位字数,固定返回 8(BS_WORDS)
bs_slotsbs_slots()int可用槽数,固定返回 2(BS_SLOTS)
bs_selectbs_select(int which)int把当前槽切换为 which;1 成功,0 表示槽号非法(当前槽不变)
bs_selectedbs_selected()int当前槽号(0 或 1)
bs_resetbs_reset()void清空两个槽,并把当前槽复位为 0
bs_clear_allbs_clear_all()void清空当前槽的全部 512 位(另一个槽不受影响)
bs_clear_slotbs_clear_slot(int which)int清空指定槽 which 的全部 512 位;1 成功,0 表示槽号非法
bs_copy_frombs_copy_from(int src)int把槽 src 整体复制到当前槽;1 成功,0 表示槽号非法
bs_get_wordbs_get_word(int w)int读当前槽第 w 个 64 位字(w 合法范围 0..7);w 越界返回 0
bs_set_wordbs_set_word(int w, int v)int写当前槽第 w 个 64 位字;1 成功,0 表示 w 越界(无操作)
bs_count_wordbs_count_word(int w)int当前槽第 w 个字里 1 的个数(0..64);w 越界返回 -1
bs_setbs_set(int i)int置位第 i 位;1 成功,0 表示 i 越界(无操作)
bs_clearbs_clear(int i)int清位第 i 位;1 成功,0 表示 i 越界(无操作);该位本来为 0 也返回 1
bs_togglebs_toggle(int i)int反转第 i 位;1 成功,0 表示 i 越界(无操作)
bs_testbs_test(int i)int测试第 i 位,返回 0/1;i 越界返回 0
bs_notbs_not()void当前槽整 512 位取反(原地)
bs_countbs_count()int当前槽中 1 的总个数(0..512)
bs_anybs_any()int当前槽是否至少有一位为 1,1/0
bs_nonebs_none()int当前槽是否一位都没有(空集),1/0
bs_first_setbs_first_set()int最小置位下标;空集返回 -1
bs_last_setbs_last_set()int最大置位下标;空集返回 -1
bs_next_setbs_next_set(int from)int>= from 的下一个置位下标;没有则返回 -1;from 越界(不在 0..511)返回 -1
bs_andbs_and(int other)int当前槽与槽 other 按位与(结果写回当前槽);1 成功,0 表示 other 非法(无操作)
bs_orbs_or(int other)int当前槽与槽 other 按位或(结果写回当前槽);1 成功,0 表示 other 非法(无操作)
bs_xorbs_xor(int other)int当前槽与槽 other 按位异或(结果写回当前槽);1 成功,0 表示 other 非法(无操作)
bs_equalsbs_equals(int other)int当前槽是否与槽 other 完全相同,1/0;other 非法返回 0
bs_shift_leftbs_shift_left(int k)void当前槽整体左移 k 位(下标 i -> i + k),移出 511 的位丢弃;k < 0 或 k == 0 无操作;k >= 512 时清零
bs_shift_rightbs_shift_right(int k)void当前槽整体右移 k 位(下标 i -> i - k),移出 0 以下的位丢弃;k < 0 或 k == 0 无操作;k >= 512 时清零
bs_from_intbs_from_int(int v)void当前槽 = v 的低 64 位(其余 448 位清零,负数按补码展开)
bs_to_intbs_to_int()int当前槽的低 64 位(第 0 个字),高位丢弃
bs_validbs_valid(int which)int内部辅助:槽号是否在 0..1,非稳定接口
bs_popcount_wordbs_popcount_word(int x)int内部辅助:单个 64 位字的 popcount(含符号位),非稳定接口
bs_ctz_wordbs_ctz_word(int x)int内部辅助:非零 64 位字的最低置位下标(0..63),非稳定接口
bs_high_bitbs_high_bit(int x)int内部辅助:非零 64 位字的最高置位下标(0..63),x == 0 返回 -1,非稳定接口
cin
import "bitset.cin"

function main() -> int {
    bs_reset()                                              // 两个槽清零, 当前槽 = 0
    bs_set(0)
    bs_set(3)
    bs_set(64)
    println("count = " + int_to_str(bs_count()))            // count = 3
    println("first = " + int_to_str(bs_first_set()))        // first = 0
    println("last = " + int_to_str(bs_last_set()))          // last = 64
    println("next 2 = " + int_to_str(bs_next_set(2)))       // next 2 = 3
    println("test 64 = " + int_to_str(bs_test(64)))         // test 64 = 1
    println("word0 popcount = " + int_to_str(bs_count_word(0)))    // word0 popcount = 2

    bs_shift_left(64)
    println("after << 64: " + int_to_str(bs_first_set())
            + ".." + int_to_str(bs_last_set()))             // after << 64: 64..128
    bs_shift_right(64)
    println("back: " + int_to_str(bs_first_set())
            + ".." + int_to_str(bs_last_set()))             // back: 0..64

    bs_from_int(0xDEADBEEF)
    println("from_int count = " + int_to_str(bs_count()))   // from_int count = 24
    println("to_int = " + int_to_str(bs_to_int()))          // to_int = 3735928559

    bs_clear_all()
    bs_not()
    println("not(empty) count = " + int_to_str(bs_count())) // not(empty) count = 512

    if (bs_select(1) != 1) { return 1 }                     // 切到槽 1
    bs_from_int(0xFF)
    if (bs_select(0) != 1) { return 1 }                     // 切回槽 0
    bs_clear_all()
    bs_set(1)
    bs_and(1)
    println("and count = " + int_to_str(bs_count()))        // and count = 1
    println("equals slot1 = " + int_to_str(bs_equals(1)))   // equals slot1 = 0
    return 0
}

codec ​

纯 CIN 编解码与简单密码(不依赖宿主能力)。只用语言内建 (strlen / substr / strcmp / s[i] / int_to_str / idiv)。

两条必须先知道的限制

1. 字节 0 不可表示。 string 是 NUL 结尾的,所以 "\x00" 本身就是空串: codec_hex_encode("\x00") / codec_base64_encode("\x00") 都返回 ""(不是 "00" / "AA=="),XOR 结果里的字节 0 会被静默丢弃(codec_xor_cipher("hello","key") 只剩 4 字节)。 需要 0..255 全值域请用 int[]。

2. RLE 的计数是固定 3 位十进制(见下表 codec_rle_encode)。

cin
import "codec.cin"
函数名签名返回值说明与边界行为
codec_hex_encodecodec_hex_encode(string s)string字节串 → 小写十六进制,无分隔;空串返回 ""
codec_hex_decodecodec_hex_decode(string h)string长度奇数或含非法字符返回 "";"00" 解出的字节 0 无法表示
codec_hex_digitcodec_hex_digit(int c)int十六进制字符 → 数值;非法返回 -1
codec_url_encodecodec_url_encode(string s)string只保留 A-Za-z0-9-_.~,其余编码成 %XX(大写)
codec_url_decodecodec_url_decode(string s)string+ 视为空格;非法 % 序列返回 ""
codec_rot13codec_rot13(string s)string只转 ASCII 字母,大小写各自保持;自反
codec_caesarcodec_caesar(string s, int shift)stringshift 可为负,按 26 取模;非字母原样保留
codec_decaesarcodec_decaesar(string s, int shift)string等价 codec_caesar(s, -shift)
codec_xor_ciphercodec_xor_cipher(string s, string key)string逐字节异或,密钥循环;密钥为空返回原串;结果中的字节 0 被丢弃
codec_base64_encodecodec_base64_encode(string s)string标准字母表 + = 填充;空串返回 ""
codec_base64_decodecodec_base64_decode(string b)string长度/字符非法返回 "";解出的字节 0 无法表示
codec_rle_encodecodec_rle_encode(string s)string行程编码:连续 k>=2 次重复 → 3 位十进制计数 + 该字节(k>999 拆段);单次出现的数字字符也用 001 前缀;其余原样。"abc"→"abc"、"aa"→"002a"、"555"→"0035"、"aaabbc"→"003a002bc"
codec_rle_decodecodec_rle_decode(string s)string计数不足 3 位 / 含非数字 / 计数为 000 / 缺字节都返回 ""
codec_morse_encodecodec_morse_encode(string s)string字母/数字 → 摩尔斯码,字母间单空格、单词间 /;不支持的字节跳过
codec_reverse_bytescodec_reverse_bytes(string s)string按字节反转(会打乱非 ASCII 的多字节序列)
codec_char_atcodec_char_at(string s, int i)string第 i 个字节组成的单字符字符串;越界返回 ""(与内置 s[i] 不同:本函数做边界检查且返回字符串)

另有若干内部辅助(codec_chr_of / codec_hex_byte / codec_rle_count / codec_is_digit / codec_is_url_safe / codec_b64_ok / codec_morse_of 等), 属于非稳定接口,不保证跨版本兼容。

cin
import "codec.cin"

function main() -> int {
    println(codec_hex_encode("AB"))        // 4142
    println(codec_base64_encode("Man"))    // TWFu
    println(codec_url_encode("a b&c"))     // a%20b%26c
    println(codec_rot13("Hello, World!"))  // Uryyb, Jbeyq!
    string r = codec_rle_encode("aaabbc")
    println(r)                             // 003a002bc
    println(codec_rle_decode(r))           // aaabbc
    return 0
}

combin ​

数论与组合数学库 (codecin/lib/combin/src/combin.cin, 前缀 comb_)。纯 CIN 实现: 不调用任何 宿主能力内建 (无 file_* / path_* / mkdir), 只用 strlen / substr / strcmp / int_to_str / idiv / % / abs。没有动态内存分配: 素数筛用「定长全局数组 + 容量常量」的形式。

容量与全局数据:

常量 / 全局量值说明
COMB_SIEVE_MAX512筛表容量常量, 合法下标 0..511
comb_sieve_tab[512]—合数标记 (下标 0/1 恒为 1)
comb_primes[512]—素数列表 (升序, 供 comb_prime_at / comb_next_prime 使用)
comb_prime_n—最近一次 comb_sieve 找到的素数个数

全局数据段合计 512*8*2 + 8 = 8200 字节 (约 8.0 KiB), 远低于 1 GiB 默认内存的数据段上限; comb_sieve 只写全局表, 函数内不声明固长数组。

边界约定:

  • 「无定义」输入 (负数 / 越界 / 非法进制) 返回 0 或 "", 查询类函数用 -1 表示失败;
  • CIN 的 / 恒为浮点除, 本库整数除法一律用 idiv(a, b) 或 %;
  • 64 位乘法按硬件自然回绕: comb_fact / comb_perm 只在 n <= 20 时精确 (20! = 2432902008176640000 是 64 位内最大值); comb_choose 因内部按 k = min(k, n-k) 递推, n <= 62 仍精确; comb_catalan(n) 在 n <= 30 时精确; comb_fib(n) 的 F(91) 是 64 位内最后一个精确值;
  • comb_is_prime 用试除法 (试除到 sqrt(n), 用 d <= idiv(n, d) 判上界以避免乘法回绕), 与筛表容量无关, 可用于任意大的 n。
cin
import "combin.cin"
函数名签名返回值说明与边界行为
comb_gcdcomb_gcd(int a, int b)int最大公约数 (欧几里得, 先取绝对值); comb_gcd(a, 0) = abs(a), comb_gcd(0, 0) = 0, 负数同样可用
comb_lcmcomb_lcm(int a, int b)int最小公倍数 abs(idiv(a, g) * b); 任一参数为 0 返回 0
comb_gcd3comb_gcd3(int a, int b, int c)int三个数的最大公约数, 即 comb_gcd(comb_gcd(a, b), c)
comb_is_primecomb_is_prime(int n)int试除法判素, 返回 1/0; n < 2 为 0, n == 2 为 1, 偶数直接为 0; 与筛表容量无关
comb_sievecomb_sieve(int n)int埃氏筛出 [0, n] 的素数写入全局表, 返回素数个数; n < 2 返回 0 并清空表; n > 511 按 511 截断 (超出部分不保证); 每次调用都会先清空整张表
comb_prime_atcomb_prime_at(int i)int第 i 个素数 (0 起, 依据最近一次 comb_sieve); 越界 (含负数) 返回 -1
comb_prime_countcomb_prime_count()int最近一次 comb_sieve 的素数个数; 未筛过时为 0
comb_next_primecomb_next_prime(int n)int>= n 的最小素数 (n 本身是素数就返回 n); 表内找不到 (含超出 511) 返回 -1; 必须先调用过 comb_sieve
comb_factcomb_fact(int n)int阶乘 n!; 仅 n in [0, 20] 精确, n < 0 或 n > 20 返回 0
comb_permcomb_perm(int n, int k)int排列数 P(n, k); k == 0 返回 1; k < 0 或 k > n 或 n < 0 返回 0; 仅 n <= 20 精确
comb_choosecomb_choose(int n, int k)int组合数 C(n, k); k < 0 / k > n / n < 0 返回 0; k == 0 或 k == n 返回 1; 内部按 min(k, n-k) 递推, n <= 62 精确
comb_catalancomb_catalan(int n)int卡特兰数 C(2n, n) / (n + 1); n < 0 返回 0; n <= 30 精确
comb_fibcomb_fib(int n)int斐波那契 F(0) = 0、F(1) = 1, 迭代实现; n < 0 返回 0; F(91) 为 64 位内最后一个精确值
comb_digit_sumcomb_digit_sum(int n)int十进制数字和 (取绝对值); comb_digit_sum(-123) = 6, 0 为 0
comb_digit_countcomb_digit_count(int n)int十进制位数 (取绝对值); 0 记为 1 位
comb_reverse_intcomb_reverse_int(int n)int整数倒序并保留符号: 1230 -> 321, -120 -> -21; 结果超出 64 位时为回绕值
comb_is_palindromecomb_is_palindrome(int n)int回文数判定 (忽略符号), 返回 1/0; 0 与个位数都是回文
comb_is_armstrongcomb_is_armstrong(int n)int阿姆斯特朗数 (水仙花数) 判定, 取绝对值; 153 / 370 / 371 / 407 / 1634 / 9474 为真; 位数很多时幂和会回绕 (结果无意义)
comb_to_basecomb_to_base(int n, int base)string整数转 base 进制字符串, 用大写字母; base 非法 (< 2 或 > 36) 返回 ""; 负数带 - 前缀; 0 返回 "0" (按绝对值转换, 不是补码)
comb_from_basecomb_from_base(string s, int base)intbase 进制字符串转整数; 失败返回 0。允许前导空白与一个前导 +/-, 允许 0x/0X 前缀 (仅 base == 16), 大小写字母都接受; 出现 >= base 的数字或非法字符立即返回 0 (不返回部分结果); 空串、只有符号、只有 0x 都返回 0
comb_mod_powcomb_mod_pow(int base, int exp, int mod)int快速幂取模 (base ^ exp) mod mod;mod <= 0 或 exp < 0 返回 0; exp == 0 返回 1 % mod; base 为负时先归一化到 [0, mod); 保证 mod <= 2^31 且 abs(base) < 2^31 时精确
comb_collatz_stepscomb_collatz_steps(int n)int考拉兹 (3n+1) 到 1 的步数; n <= 1 返回 0; 循环有 100 万步上限 (防跑飞)
comb_is_perfectcomb_is_perfect(int n)int完全数判定 (真因子之和等于自身); n <= 1 返回 0; 6 / 28 / 496 / 8128 为真
comb_divisor_countcomb_divisor_count(int n)int正因子个数 (含 1 与自身); n <= 0 返回 0; comb_divisor_count(12) = 6
comb_divisor_sumcomb_divisor_sum(int n)int正因子之和 (含 1 与自身); n <= 0 返回 0; comb_divisor_sum(12) = 28

comb_int_pow(base, exp) 是本库内部使用的整数幂辅助函数 (exp < 0 返回 0), 未列在上表中。

cin
import "combin.cin"

function main() -> int {
    println("gcd(48,18) = " + int_to_str(comb_gcd(48, 18)))          // 6
    println("lcm(4,6) = " + int_to_str(comb_lcm(4, 6)))              // 12
    println("gcd3(12,18,30) = " + int_to_str(comb_gcd3(12, 18, 30))) // 6
    println("is_prime(97) = " + int_to_str(comb_is_prime(97)))       // 1

    println("sieve(100) = " + int_to_str(comb_sieve(100)))           // 25 (pi(100))
    println("prime_at(24) = " + int_to_str(comb_prime_at(24)))       // 97
    println("next_prime(8) = " + int_to_str(comb_next_prime(8)))     // 11
    println("prime_at(25) = " + int_to_str(comb_prime_at(25)))       // -1 (越界)

    println("fact(10) = " + int_to_str(comb_fact(10)))               // 3628800
    println("perm(5,2) = " + int_to_str(comb_perm(5, 2)))            // 20
    println("choose(5,2) = " + int_to_str(comb_choose(5, 2)))        // 10
    println("catalan(5) = " + int_to_str(comb_catalan(5)))           // 42
    println("fib(20) = " + int_to_str(comb_fib(20)))                 // 6765

    println("digit_sum(-123) = " + int_to_str(comb_digit_sum(-123))) // 6
    println("digit_count(1234) = " + int_to_str(comb_digit_count(1234)))  // 4
    println("reverse_int(-120) = " + int_to_str(comb_reverse_int(-120)))  // -21
    println("is_palindrome(121) = " + int_to_str(comb_is_palindrome(121)))  // 1
    println("is_armstrong(153) = " + int_to_str(comb_is_armstrong(153)))    // 1

    println("to_base(255,16) = " + comb_to_base(255, 16))            // FF
    println("to_base(-255,16) = " + comb_to_base(-255, 16))          // -FF
    println("to_base(5,1) = [" + comb_to_base(5, 1) + "]")           // []
    println("from_base(FF,16) = " + int_to_str(comb_from_base("FF", 16)))  // 255
    println("from_base(-1F,16) = " + int_to_str(comb_from_base("-1F", 16)))  // -31

    println("mod_pow(2,10,1000) = " + int_to_str(comb_mod_pow(2, 10, 1000)))  // 24
    println("collatz(27) = " + int_to_str(comb_collatz_steps(27)))   // 111
    println("is_perfect(28) = " + int_to_str(comb_is_perfect(28)))   // 1
    println("divisor_count(12) = " + int_to_str(comb_divisor_count(12)))  // 6
    println("divisor_sum(12) = " + int_to_str(comb_divisor_sum(12)))      // 28
    return 0
}

conv ​

进制转换与字符串格式化库。整数一律按 64 位无符号处理,负数的十六进制输出是 16 位补码形式。

cin
import "conv.cin"
函数名签名返回值说明与边界行为
c_hex_digitc_hex_digit(int ch)int十六进制字符 → 数值,支持 0-9 A-F a-f;非法返回 -1(参数是字符字节值)
c_to_hexc_to_hex(int v)string整数 → 大写十六进制字符串;0 返回 "0",无 0x 前缀,负数给出 16 位补码
c_parse_hexc_parse_hex(string s)int十六进制字符串 → 整数;可带 0x/0X 前缀,遇非法字符停止而非报错
c_to_binc_to_bin(int v)string整数 → 二进制字符串;0 返回 "0",负数按 64 位无符号展开
c_parse_binc_parse_bin(string s)int二进制字符串 → 整数;可带 0b/0B 前缀,遇非法字符停止
c_pad_leftc_pad_left(string s, int width, string fill)string左填充到宽度 width;fill 可多字符(长度不整除时结果可超过 width),fill 为空串时原样返回
c_pad_rightc_pad_right(string s, int width, string fill)string右填充到宽度 width,规则同上
c_pad_intc_pad_int(int v, int width)string用 0 左填充整数到 width;负数保留 - 号且只填充数字部分
c_repeatc_repeat(string s, int n)string字符串重复 n 次;n <= 0 返回空串
c_chrc_chr(int code)string字符编码 → 单字符字符串;特殊处理 10/9/13;覆盖常用可见 ASCII,未知返回空串
c_to_intc_to_int(string s)int十进制字符串 → 整数,是内建 atoi 的别名
c_parse_floatc_parse_float(string s)float字符串 → 浮点;支持可选负号与小数部分,遇非法字符停止,不解析指数形式
cin
import "conv.cin"

function main() -> int {
    println(c_to_hex(255))                  // FF
    println(int_to_str(c_parse_hex("0x1F")))// 31
    println(c_to_bin(10))                   // 1010
    println(int_to_str(c_parse_bin("0b1010")))  // 10
    println(c_pad_int(7, 3))                // 007
    println(c_pad_left("ab", 4, "-"))       // --ab
    println(c_repeat("xy", 3))              // xyxyxy
    println(float_to_str(c_parse_float("-3.25")))  // -3.25
    return 0
}

cppstd ​

C++ 标准库 (STL) 兼容层,以 std:: 命名习惯提供 std::string / std::vector / std::stack / std::queue 的常用方法与 <utility> / <algorithm> 工具。纯 CIN 实现, 行为与运行方式无关。CIN 没有模板与引用包装,容器以「数组 + 长度游标」表达:数组是引用传递, push/pop 返回新的长度,调用方把它存回自己的游标变量;push 前需自行保证数组容量。 查找类的 npos 统一以 -1 表示。

cin
import "cppstd.cin"
函数名签名返回值说明与边界行为
stl_str_size / stl_str_length(string s)intsize() / length(),即 strlen
stl_str_empty(string s)int1 空串 / 0
stl_str_find(string s, string sub)intfind() 首现下标,未找到 -1
stl_str_rfind(string s, string sub)intrfind() 末现下标,未找到 -1;空 sub 返回 strlen(s)
stl_str_substr(string s, int pos, int len)stringsubstr(pos, len)
stl_str_append(string a, string b)stringoperator+ / append()
stl_str_compare(string a, string b)intcompare():<0 / 0 / >0
stl_str_c_str(string s)stringc_str():CIN 字符串本身就是宿主字符串,恒等返回
stl_str_starts_with / stl_str_ends_with(string s, string pre/suf)intC++20 starts_with / ends_with;空前/后缀返回 1
stl_str_find_first_of / stl_str_find_last_of(string s, string chars)intchars 中任一字符的首/末现下标,未找到 -1
stl_str_at(string s, int i)intat(i) 字符码;越界返回 0(C++ 此处抛 out_of_range)
stl_str_front / stl_str_back(string s)int首/末字符码;空串返回 0
stl_str_insert(string s, int pos, string sub)string在 pos 前插入;pos 越界裁剪到 0 / 末尾
stl_str_erase(string s, int pos, int len)string删除 [pos, pos+len);越界裁剪,len<0 视为 0
stl_str_replace(string s, int pos, int len, string sub)string把 [pos, pos+len) 替换为 sub;越界裁剪
stl_to_string(int v)stringstd::to_string
stl_vec_push_back(int[] v, int len, int x)int追加并返回新长度
stl_vec_pop_back(int len)int返回新长度;空容器不变
stl_vec_back / stl_vec_front(int[] v, int len)int末/首元素;空容器返回 0
stl_vec_size / stl_vec_empty(int len)int长度 / 是否为空
stl_vec_clear()int返回 0(CIN 无动态内存,长度归零即可)
stl_vec_at(int[] v, int len, int i)int带边界检查;越界返回 0
stl_vec_insert(int[] v, int len, int i, int x)int在 i 处插入整体后移,返回新长度;i 越界视为尾部追加
stl_vec_erase(int[] v, int len, int i)int删除 i 处元素整体前移,返回新长度;越界不修改
stl_vec_find / stl_vec_count(int[] v, int len, int x)int首个等于 x 的下标(无则 -1)/ 等于 x 的个数
stl_vec_reverse / stl_vec_fill(int[] v, int len, ...)void原地反转 / 填充
stl_vec_sum / stl_vec_max / stl_vec_min(int[] v, int len)int求和 / 最大 / 最小(空容器返回 0)
stl_stack_push(int[] s, int top, int x)int压栈并返回新 top(0 = 空栈)
stl_stack_pop(int top)int弹栈并返回新 top;空栈不变
stl_stack_top(int[] s, int top)int栈顶(空栈 0)
stl_stack_size / stl_stack_empty(int top)int栈深 / 是否为空
stl_queue_push(int[] q, int tail, int x)int入队并返回新 tail(非循环数组队列,head <= tail)
stl_queue_pop(int head)int出队返回新 head(调用方保证非空)
stl_queue_front / stl_queue_back(int[] q, int head/tail)int队首 / 队尾
stl_queue_empty / stl_queue_size(int head, int tail)int是否为空 / 元素个数
stl_max / stl_min / stl_abs(int a, int b) / (int x)int<utility>
stl_swap(int[] v, int i, int j)void交换数组两个元素
stl_sort / stl_sort_desc(int[] v, int len)void冒泡升序 / 降序(CIN 无函数指针,固定序)
stl_find / stl_count(int[] v, int len, int x)int<algorithm> 馎查找 / 计数
stl_clamp(int x, int lo, int hi)int钳制到 [lo, hi]
cin
import "cppstd.cin"

function main() -> int {
    int v[8]
    int n = 0
    n = stl_vec_push_back(v, n, 3)
    n = stl_vec_push_back(v, n, 1)
    n = stl_vec_insert(v, n, 0, 2)      // {2, 3, 1}
    stl_sort(v, n)                       // {1, 2, 3}
    println(int_to_str(stl_vec_at(v, n, 1)))   // 2
    println(stl_str_starts_with("hello", "he") == 1 ? "yes" : "no")   // yes
    return 0
}

cstd ​

C 语言兼容层,语义对齐 <ctype.h> / <string.h> / <stdlib.h> / <math.h> / <stdio.h>,让 C 程序员以惯用的名字与约定操作 CIN 的内置类型。纯 CIN 实现, 行为与运行方式无关。 类型映射:C int/size_t → int、C char → 字符码 int(可用 'A' 字符字面量)、 C char* → string、C float/double → float、C bool → int(0/1)、 C EOF → -1。差异:CIN 无裸指针,「写入 dst」类 API 返回新串、 strchr 返回下标(C 返回指针);数组以引用传递并显式带长度。

cin
import "cstd.cin"
函数名签名返回值说明与边界行为
libc_isdigit / libc_islower / libc_isupper / libc_isalpha / libc_isalnum(int ch)int<ctype.h> 字符类别判定,1 / 0
libc_isspace / libc_isprint / libc_isgraph / libc_isblank / libc_iscntrl / libc_ispunct / libc_isxdigit(int ch)int其余字符类别(isblank 含空格与 \t)
libc_toupper / libc_tolower(int ch)int大小写转换(非字母原样返回)
libc_toascii(int ch)int清除高位(ch & 0x7F)
libc_strlen(string s)int字符串长度
libc_strcmp / libc_strncmp(string a, string b[, int n])int<0 / 0 / >0;strncmp 只比前 n 字节
libc_strdup(string s)string复制一份(CIN 堆字符串语义下即原样返回)
libc_strcat(string a, string b)string拼接(「写入 dst」改返回新串)
libc_strstr(string hay, string needle)int子串首现下标,未找到 -1
libc_strchr / libc_strrchr(string s, string ch)int单字符首/末现下标,未找到 -1
libc_strspn / libc_strcspn(string s, string accept/reject)int前缀中全部属于 accept 的长度 / 全部不属于 reject 的长度
libc_strpbrk(string s, string accept)intaccept 内任一字符首现下标,未找到 -1
libc_strlwr / libc_strupr(string s)stringASCII 小写 / 大写化(返回新串)
libc_strrev(string s)string字节反转
libc_memcpy / libc_memmove / libc_memset / libc_memcmp(int[] dst, ...)void / int数组(视为 int 内存块)拷贝 / 移动 / 填充 / 比较
libc_abs / libc_labs(int x)intint / long 绝对值
libc_atoi(string s)int十进制解析(非法为 0,与内建一致)
libc_max / libc_min(int a, int b)int最值
libc_qsort_asc(int[] a, int n)void快速排序升序(CIN 无比较函数指针,固定升序)
libc_rand / libc_srand() / (int seed)int / void伪随机数与播种(包装内建 rand / srand)
libc_fabs / libc_sqrt / libc_pow / libc_floor / libc_ceil / libc_fmod(float ...)float<math.h>;fmod 商向零截断,除零返回 0
libc_sin / libc_cos / libc_tan(float x)float弧度三角函数
libc_round / libc_trunc(float x)floatC 语义 round:半值远离零(round(2.5)=3,round(-2.5)=-3);trunc 向零取整
libc_puts(string s)int输出并换行,返回 0
libc_print(string s)int输出不换行
libc_putchar(int ch)int输出单个字符,返回字符码
cin
import "cstd.cin"

function main() -> int {
    if (libc_isdigit('7') == 1) { libc_puts("digit") }   // digit
    println(libc_strupr("hello"))                          // HELLO
    println(int_to_str(libc_strstr("haystack", "sta")))    // 3
    println(int_to_str(libc_abs(-42)))                     // 42
    println(float_to_str(libc_round(-2.5)))                // -3
    return 0
}

csv ​

单行 CSV 解析与生成库,风格与 json.cin 一致:面向"一行一条记录"的轻量场景,不做完整语法解析。纯 CIN 实现,只使用非宿主能力内建(strlen / substr / strcmp / indexof / int_to_str / trim / atoi)。

分隔符固定为 ,(44),字段转义规则与 RFC 4180 一致:需要时字段两端加双引号,字段内部的 " 写成 ""。解析侧同样识别引号字段(含 "" 转义),因此 csv_quote / csv_line_add 生成的字段能被 csv_get 原样读回。

本库是单行解析器

  • 不支持多行字段:引号内的换行不会被识别,\n 只会被当作普通字节(换行会触发 csv_quote 加引号,但读回来只剩同一行内的内容)。
  • 分隔符只能是 ,;需要别的分隔符用 csv_raw_count / csv_raw_get(按单字节切分,不做引号处理)。
  • 长度一律是字节语义,UTF-8 等非 ASCII 按字节处理;由于判定用的 , 与 " 都是单字节 ASCII,不会与 UTF-8 多字节序列撞车。

空行与空字段约定(csv_get 返回 "" 无法区分"越界"与"空字段",需要区分时先查 csv_has):

输入csv_count说明
""0空行 = 没有字段,便于跳过空记录
","2只有一个分隔符时是 2 个空字段
" "1只有空白的行是 1 个字段(字段内容就是空格)
"a,"2尾随空字段保留
"a,,b"3中间空字段保留

推论:只累积了一个空字段的 csv_line 缓冲内容也是 "",csv_get 读回来会被当成 0 个字段;需要区分时查 csv_line_count()。

全局状态(全局数据段,由运行时清零):行缓冲 string csv_buf = "" 与字段计数 int csv_buf_n = 0,合计 2 槽 = 16 字节;缓冲内容在堆上,上限 CSV_BUF_MAX = 1024 字节。库内只有一份全局实例。

cin
import "csv.cin"
函数名签名返回值说明与边界行为
csv_buf_capacitycsv_buf_capacity()int固定返回 1024,即 csv_line_add 能累积的字节上限
csv_countcsv_count(string line)int字段数(引号感知);"" 为 0,尾随 / 中间空字段都计入
csv_getcsv_get(string line, int idx)string第 idx 个字段(0 起),去掉外层引号并还原 "" → ";越界或 idx < 0 返回 ""(注意与空字段同形)。引号字段结束引号之后的字符被忽略;引号未闭合时取到行尾;未加引号的字段保留两侧空白
csv_hascsv_has(string line, int idx)intidx 是否是存在的字段(字段内容为空也算存在);1 / 0,idx < 0 或空行为 0
csv_get_intcsv_get_int(string line, int idx, int fallback)int整数字段;先按字节 trim 再校验(可带 + / -,至少一位数字);越界 / 空 / 非法("12a"、"3.5"、"+")都返回 fallback
csv_get_floatcsv_get_float(string line, int idx, float fallback)float浮点字段;去空白后允许可选正负号、至多一个小数点、至少一位数字(.5 与 5. 合法);不接受指数形式(1e3、1.5E2 非法);越界 / 空 / 非法返回 fallback
csv_trim_cellscsv_trim_cells(string line)string去掉每个字段两侧空白后原样拼接(不重新加引号,也不动引号内部);" a , b " → "a,b"," \"a, b\" , c" → "\"a, b\",c";空行返回 "",结果长度不会超过输入长度,引号字段的转义原样保留
csv_escapecsv_escape(string field)string只做转义不加引号:字段内每个 " 写成 "";csv_escape("a\"b") 为 "a\"\"b",空串返回 ""
csv_quotecsv_quote(string field)string需要时加双引号并转义内部 ",否则返回原串。需要加引号的条件:含 ,、含 "、含换行(\n / \r),或首尾是空白(空格 / \t);只在中间的 \t 不加引号;空串返回 ""
csv_line_startcsv_line_start()void开始新的一行:清空全局缓冲,字段计数归零
csv_line_addcsv_line_add(string field)int追加一个字段(自动补前导 , 并按需加引号);成功 1;若追加后缓冲会超过 1024 字节则返回 0 且缓冲与计数都不改动(不会越界写)
csv_line_getcsv_line_get()string当前累积的行(未调用 csv_line_start 前为空串)
csv_line_countcsv_line_count()int当前累积的字段个数(区分"0 个字段"与"一个空字段")
csv_raw_countcsv_raw_count(string line, int delim)int按单字节分隔符 delim(如 ';' 即 59)切分的字段数,不做引号处理;空行为 0;delim <= 0 时整行算 1 个字段
csv_raw_getcsv_raw_get(string line, int delim, int idx)string按 delim 取第 idx 个字段(0 起,原样返回、不还原引号);越界或 idx < 0 返回 "";delim <= 0 时只有 idx == 0 命中整行

内部辅助函数(csv_skip_ws / csv_quote_pos / csv_next_start / csv_val_at / csv_cell_trim / csv_is_int / csv_is_float / csv_parse_float)不是公开 API,后续版本可能调整。

堆与缓冲

字符串拼接产生不回收的堆块,csv_trim_cells 会按字段逐段重建结果串。默认 1 GiB 内存下常规使用不会触顶,但反复 csv_line_start / 拼接仍会持续吃堆(csv_line_add 单次最多累积 1024 字节),超长表请及时重用缓冲或加 --mem-size。

cin
import "csv.cin"

function main() -> int {
    string line = "id,\"Doe, John\",42,3.5,"
    println(int_to_str(csv_count(line)))             // 5  (尾随空字段保留)
    println("[" + csv_get(line, 1) + "]")            // [Doe, John]
    println(int_to_str(csv_get_int(line, 2, -1)))    // 42
    println(int_to_str(csv_get_int(line, 0, -1)))    // -1 (id 不是整数)
    println(int_to_str(csv_has(line, 4)))            // 1
    println("[" + csv_get(line, 4) + "]")            // []
    println("[" + csv_trim_cells(" a , b ") + "]")   // [a,b]
    println("[" + csv_quote("a,b") + "]")            // ["a,b"]
    println("[" + csv_escape("a\"b") + "]")          // [a""b]
    csv_line_start()
    csv_line_add("id")
    csv_line_add("Doe, John")
    csv_line_add("42")
    println("[" + csv_line_get() + "]")              // [id,"Doe, John",42]
    println(int_to_str(csv_line_count()))            // 3
    return 0
}

dp ​

经典动态规划教学库。纯 CIN 实现,不做动态内存分配:所有 DP 表都是库内全局定长数组 (滚动数组),容量上限如下,超限一律按上限截断(与 heap_build 的钳制风格一致): DP_STR_MAX = 128(字符串类 DP 处理的字节数)、DP_KNAP_CAP = 256(0/1 背包容量)、 DP_AMOUNT_MAX = 256(零钱问题金额)、DP_LIS_MAX = 64(LIS 元素个数,该算法是 O(n²),故意给小)、 DP_PATH_COLS = 256(网格列数)、DP_FIB_CACHE = 64(dp_fib_memo 自建缓存)。 全局数据段占用约 838 槽(6704 字节)。

  • 字符串一律按字节比较(s[i] 得到 0..255 的整数编码)。
  • 返回值都是 64 位 int,斐波那契 / 阶乘 / 组合数可能静默溢出回绕(不报错)。
  • 那些滚动数组是跨函数复用的内部暂存区,不要依赖它们在两次调用之间的内容, 也不要在本库的函数之间嵌套调用。
  • 库内只有一份全局实例,同一程序内共享。
cin
import "dp.cin"
函数名签名返回值说明与边界行为
dp_fibdp_fib(int n)int斐波那契数(迭代 O(n));fib(0)=0、fib(1)=1,n < 0 返回 0;n >= 93 溢出回绕
dp_fib_memodp_fib_memo(int n)int同上但带自建缓存,结果与 dp_fib 完全一致;n < 0 返回 0,n >= 64 时不做缓存直接走迭代实现
dp_factdp_fact(int n)int阶乘(迭代);fact(0)=1,n < 0 返回 0;n >= 21 溢出回绕(建议 n <= 20)
dp_stairsdp_stairs(int n)int爬楼梯方案数(每步 1 或 2 级);n < 0 返回 0,n == 0 返回 1(一步不走也算一种);等于 fib(n+1)
dp_knapsack01dp_knapsack01(int[] w, int[] v, int n, int cap)int0/1 背包最大价值;n <= 0 或 cap <= 0 返回 0;cap > 256 按 256 计算;重量 < 0 的物品按重量 0 处理(等价于白拿一件),重量 > cap 的物品自动跳过
dp_lcsdp_lcs(string a, string b)int最长公共子序列长度;任一空串返回 0;串长超过 DP_STR_MAX = 128 时只看前 128 字节
dp_edit_distancedp_edit_distance(string a, string b)int编辑距离(Levenshtein,插入/删除/替换代价都是 1);任一空串时返回另一个串的长度;串长超过 128 时只看前 128 字节
dp_longest_palindromedp_longest_palindrome(string s)int最长回文子串长度(中心扩展,等价于区间 DP 的空间优化写法);空串返回 0;长度超过 128 时只看前 128 字节
dp_coin_changedp_coin_change(int[] coins, int n, int amount)int最少硬币数(每种面额可用无限次);凑不出返回 -1;amount < 0 返回 -1,amount == 0 返回 0;面额 <= 0 的硬币被忽略;amount > 256 按 256 计算
dp_coin_waysdp_coin_ways(int[] coins, int n, int amount)int凑出 amount 的组合数(顺序不计,每种面额无限次);amount < 0 返回 0,amount == 0 返回 1(空组合);面额 <= 0 的硬币被忽略;amount > 256 按 256 计算;结果可能溢出回绕
dp_lisdp_lis(int[] a, int n)int最长严格递增子序列长度(O(n²));n <= 0 返回 0;n > 64 时只看前 64 个元素
dp_max_subarraydp_max_subarray(int[] a, int n)int最大子段和(Kadane,O(n));n <= 0 返回 0;至少取一个元素,全负数时返回其中最大的那个
dp_min_pathdp_min_path(int[] grid, int rows, int cols)int网格最小路径和(只能向右/向下),网格按行主序一维给出:grid[r * cols + c];起点与终点都计入和;rows <= 0 或 cols <= 0 返回 0;cols > 256 返回 -1(列数参与行主序下标,定长滚动数组放不下,明确失败)
cin
import "dp.cin"

function main() -> int {
    println("fib(10) = " + int_to_str(dp_fib(10)))                      // 55
    println("fib_memo(30) = " + int_to_str(dp_fib_memo(30)))            // 832040
    println("fact(10) = " + int_to_str(dp_fact(10)))                    // 3628800
    println("stairs(10) = " + int_to_str(dp_stairs(10)))                // 89

    int w[4] = {1, 3, 4, 5}
    int v[4] = {1, 4, 5, 7}
    println("knapsack01 = " + int_to_str(dp_knapsack01(w, v, 4, 7)))    // 9

    println("lcs = " + int_to_str(dp_lcs("ABCBDAB", "BDCABA")))         // 4
    println("edit_distance = " + int_to_str(dp_edit_distance("kitten", "sitting")))   // 3
    println("palindrome = " + int_to_str(dp_longest_palindrome("forgeeksskeegfor")))  // 10

    int coins[4] = {1, 5, 10, 25}
    println("coin_change(63) = " + int_to_str(dp_coin_change(coins, 4, 63)))   // 6
    println("coin_ways(63) = " + int_to_str(dp_coin_ways(coins, 4, 63)))       // 73

    int a[8] = {10, 9, 2, 5, 3, 7, 101, 18}
    println("lis = " + int_to_str(dp_lis(a, 8)))                        // 4

    int s[9] = {-2, 1, -3, 4, -1, 2, 1, -5, 4}
    println("max_subarray = " + int_to_str(dp_max_subarray(s, 9)))      // 6

    int g[9] = {1, 3, 1, 1, 5, 1, 4, 2, 1}
    println("min_path = " + int_to_str(dp_min_path(g, 3, 3)))           // 7
    println("unreachable = " + int_to_str(dp_coin_change(coins, 4, -1)))   // -1
    return 0
}

ffi ​

FFI 动态库调用便捷封装。封装内建 dlopen / dlsym / ffi_call / ffi_callf / lib_close (SYS 140-144,Go 引擎实现),必须运行在 Go 原生引擎上;--sandbox 下宿主调用会被拦截。 调用约定:最多 8 个参数、每个占 8 字节;整数参数走 ffi_call* 封装(int 数组槽即 int64 位模式),浮点参数走 ffi_callf* 封装(float 数组槽即 IEEE754 位模式,经 Windows x64 XMM0-3 / SysV XMM0-7 寄存器正确传参);两种参数混用暂无封装。

cin
import "ffi.cin"
函数名签名返回值说明与边界行为
ffi_loadffi_load(string path)int加载动态库,返回库句柄;失败返回 0(不抛异常,需自行判断)。路径平台相关:Windows foo.dll、Linux libfoo.so / libfoo.so.6、macOS libfoo.dylib
ffi_findffi_find(int lib, string name)int查找导出符号(函数/变量地址);失败返回 0
ffi_freeffi_free(int lib)int卸载动态库,0 成功 / -1 失败;卸载后其函数句柄全部失效
ffi_call0 .. ffi_call8ffi_callN(int fn, int a0, ...)int以 N(0..8)个 int 参数调用函数,返回 int64 整数结果
ffi_callf1 .. ffi_callf4ffi_callfN(int fn, float a0, ...)float以 N(1..4)个 float 参数调用函数,返回值按 double 位模式进 X0(CIN 的 float 本身就是位模式,可直接赋给 float 变量)

常量 ffi_max_args = 8 与引擎的参数上限一致(封装内部已固定,仅供检查)。 dlopen / dlsym 失败返回 0,调用前应检查句柄;无效句柄 / 参数越界由引擎报明确运行时错误。

cin
import "ffi.cin"

function main() -> int {
    int lib = ffi_load("kernel32.dll")        // Linux/macOS: libc.so.6 / libc.dylib
    if (lib == 0) { println("加载失败"); return 1 }
    int fn = ffi_find(lib, "GetTickCount64")
    if (fn == 0) { ffi_free(lib); return 1 }
    println("开机毫秒 = " + int_to_str(ffi_call0(fn)))
    ffi_free(lib)
    return 0
}

fmt ​

排版与格式化输出库。比 conv 更面向"排版"的一层:定点小数、千位分隔、对齐与居中、比例条、表格单元格与边框、定宽十六进制/二进制。纯 CIN 实现,只使用非宿主能力内建(strlen / substr / strcmp / indexof / int_to_str / float_to_str / floor / idiv / trim);与 conv(进制与基础填充 c_pad_* / c_to_hex / c_to_bin)不重叠、互不依赖,可同时导入。

长度与宽度一律是字节语义(与 strlen / substr / s[i] 一致):非 ASCII 按 UTF-8 字节序列计数,一个汉字算 3 字节、宽度算 3 列,fmt_cell 会在字节中间截断,不做码点解码。

库内没有全局变量,不占用数据段。局部变量全部显式赋值(CIN 局部标量不自动清零)。

统一边界约定:

  • 所有函数返回新字符串(新堆块,不回收),不要在无界循环里对超长串反复调用;
  • 重复/计数类参数统一钳制到 [0, 1024](fmt_repeat_limit()),宽度类参数各自钳制(见下表);
  • fmt_float_dec / fmt_float_pad / fmt_percent 的 digits 钳制到 [0, 9];digits == 0 时不输出小数点;
  • fmt_bar 的 ratio 钳制到 [0, 1],填充长度按 round(ratio * width) 计算;
  • width <= 0 一律返回 ""(fmt_cell / fmt_sep / fmt_bar / fmt_border),或者原样返回内容(fmt_int_width / fmt_int_zero / fmt_align);
  • fmt_float_dec 的 |v| >= 1e9 时退化为 float_to_str(v)(定点整数部分会溢出 64 位整数槽),该退化不做补零。
cin
import "fmt.cin"
函数名签名返回值说明与边界行为
fmt_repeat_limitfmt_repeat_limit()int固定返回 1024,是本库所有重复次数的上限
fmt_chrfmt_chr(int ch)string字节编码 → 单字符字符串;支持 32..126(可打印 ASCII)与 9 / 10 / 13;其余编码(含 0、>126)返回 "",不做多字节编码
fmt_int_widthfmt_int_width(int v, int width)string整数右对齐到 width 列,左侧补空格;负数保留 -;width <= strlen(int_to_str(v)) 时原样返回
fmt_int_zerofmt_int_zero(int v, int width)string补前导 0 到 width 列,width 是含符号的总宽度(fmt_int_zero(-42, 5) 为 "-0042");不足时原样返回
fmt_thousandsfmt_thousands(int v)string千位分隔,每 3 位一个 ,,负数保留 -;0 为 "0",-1000 为 "-1,000"
fmt_float_decfmt_float_dec(float v, int digits)string定点小数:四舍五入到 digits 位并补足尾随 0;fmt_float_dec(3.14159, 2) 为 "3.14",fmt_float_dec(2.0, 3) 为 "2.000",fmt_float_dec(9.999, 2) 为 "10.00"(进位贯穿整数部分)。digits 钳制到 [0, 9],负数按绝对值圆整后补号(-0.005 → "-0.01");`
fmt_float_padfmt_float_pad(float v, int int_width, int dec_digits)string定点小数并把整数部分补前导 0 到 int_width 位(不含符号与小数部分):fmt_float_pad(3.14159, 6, 2) 为 "000003.14",fmt_float_pad(-3.5, 4, 1) 为 "-0003.5";dec_digits 钳制到 [0, 9],整数部分已足够长时不补
fmt_percentfmt_percent(float ratio, int digits)string比例 → 百分数(ratio * 100 后定点到 digits 位):fmt_percent(0.1234, 1) 为 "12.3%",fmt_percent(1.0, 0) 为 "100%";digits 钳制到 [0, 9],ratio 不做钳制(2.0 → "200.0%")
fmt_alignfmt_align(string s, int width, int mode)string对齐到 width 列:mode 0 左对齐 / 1 右对齐 / 2 居中,其余取值(含负数)按左对齐;居中时余出的 1 列补在右侧;strlen(s) >= width 原样返回
fmt_centerfmt_center(string s, int width)string居中到 width 列,等价 fmt_align(s, width, 2)
fmt_repeatfmt_repeat(string s, int n)string字符串重复 n 次;n 钳制到 [0, 1024],n <= 0 或 s 为空返回 ""。内部用倍增法(O(log n) 次拼接),不会因逐次拼接撑爆堆
fmt_repeat_charfmt_repeat_char(int ch, int n)string单字符重复 n 次;ch 语义同 fmt_chr(非法编码返回 ""),n 钳制到 [0, 1024]
fmt_barfmt_bar(float ratio, int width)string比例条:# 为已用、- 为剩余,共 width 列;ratio 钳制到 [0, 1],填充长度四舍五入;width <= 0 返回 "",width > 1024 钳制为 1024。fmt_bar(0.5, 10) 为 "#####-----"
fmt_cellfmt_cell(string s, int width)string表格单元格:正好 width 列;不足右补空格,strlen(s) >= width 时按字节截断(不补省略号);width <= 0 返回 ""
fmt_sepfmt_sep(int width)stringwidth 个 - 组成的分隔线;width <= 0 返回 ""(width 同样钳制到 1024)
fmt_borderfmt_border(int cols, int col_width)string表格边框:cols 列、每列 col_width 个 -,形如 "+----+----+----+";cols <= 0 返回 "",cols 与 col_width 各自钳制到 [0, 256](col_width 为负当 0)
fmt_hexfmt_hex(int v, int width)string大写十六进制,前导 0 补到 width 位;v == 0 输出 "0",负数按 64 位补码展开(16 位);width 钳制到 [0, 64],不超过实际位数时不补
fmt_binfmt_bin(int v, int width)string二进制,前导 0 补到 width 位;v == 0 输出 "0",负数按 64 位补码展开(64 位);width 钳制到 [0, 64]
fmt_boolfmt_bool(bool b)string布尔 → "true" / "false"(本库选定与内建 bool_to_str 及打印一致的拼写,不是 "yes" / "no");非零为 true

内部辅助函数(fmt_rep / fmt_ascii_table)不是公开 API,后续版本可能调整。

堆与输出规模

每次调用都新建堆块且不回收。默认 1 GiB 内存下常规使用不会触顶;但堆块不回收,超大表格(fmt_border 的 cols * (col_width + 1)、超长 fmt_cell 内容)请自行分块或加 --mem-size,否则会报 Heap exhausted: need ...。

cin
import "fmt.cin"

function main() -> int {
    println("[" + fmt_int_width(42, 6) + "]")            // [    42]
    println("[" + fmt_int_zero(-42, 5) + "]")            // [-0042]
    println("[" + fmt_thousands(-1234567) + "]")         // [-1,234,567]
    println("[" + fmt_float_dec(9.999, 2) + "]")         // [10.00]
    println("[" + fmt_float_pad(3.14159, 6, 2) + "]")    // [000003.14]
    println("[" + fmt_percent(0.1234, 1) + "]")          // [12.3%]
    println("[" + fmt_align("CIN", 8, 2) + "]")          // [  CIN   ]
    println("[" + fmt_bar(0.4, 10) + "]")                // [####------]
    println(fmt_border(3, 4))                            // +----+----+----+
    println("|" + fmt_cell("id", 4) + "|" + fmt_cell("name", 4) + "|")  // |id  |name|
    println("[" + fmt_hex(-1, 0) + "]")                  // [FFFFFFFFFFFFFFFF]
    println("[" + fmt_bin(10, 8) + "]")                  // [00001010]
    println("[" + fmt_bool(1 > 2) + "]")                 // [false]
    return 0
}

frac ​

有理数(分数)库。struct Frac 只有两个 64 位 int 字段 num / den, 构造与每次运算后都会自动约分并把分母规范化为正数:2/4 → 1/2、3/-4 → -3/4、 -3/-4 → 3/4、0/5 → 0/1。零恒为 0/1,分母恒 >= 1;已规范化的分数比较与相等 判断都是精确的(不经过浮点)。

分母为 0(fr_make(x, 0)、fr_div(_, 0))时结果规范化为 0/1 并把全局错误标志置 1, 可用 fr_error() 查询、fr_reset_error() 清除。库内全局变量只有 fr_err 一个(8 字节), Frac 本身只占 2 槽 = 16 字节。

边界与限制:加减先用 fr_gcd 把分母降到最小公倍数、乘除先做交叉约分,以减少中间积溢出, 但分子分母的中间乘积仍然是原生 64 位整型运算,可能回绕(例如 1/10^10 * 1/10^10 的分母 10^20 超出 int 范围);本库不做大数处理,需要任意精度时请配合 bigint.cin。 约分只使用 idiv 与 %,gcd 由 fr_gcd 自行实现,不依赖其它库。

cin
import "frac.cin"
函数名签名返回值说明与边界行为
fr_errorfr_error()int是否发生过非法操作(除以零等),1/0(粘滞,需手动清除)
fr_reset_errorfr_reset_error()void清除错误标志
fr_gcdfr_gcd(int a, int b)int最大公约数(内部取绝对值);gcd(0, 0) = 0,gcd(0, 5) = 5
fr_normfr_norm(Frac f)void原地规范化 f:分母为 0 时置错误标志并归零,分母转正,约分,零写作 0/1
fr_makefr_make(int n, int d)Frac由分子分母构造并约分;d == 0 时返回 0/1 并置错误标志
fr_zerofr_zero()Frac零(0/1)
fr_numfr_num(Frac f)int分子
fr_denfr_den(Frac f)int分母(恒为正)
fr_addfr_add(Frac a, Frac b)Fraca + b,先把分母降到 lcm 再相加
fr_subfr_sub(Frac a, Frac b)Fraca - b,先把分母降到 lcm 再相减
fr_mulfr_mul(Frac a, Frac b)Fraca * b,先交叉约分
fr_divfr_div(Frac a, Frac b)Fraca / b;b 为 0 时返回 0/1 并置错误标志
fr_negfr_neg(Frac a)Frac-a(零的相反数仍为 0/1)
fr_absfr_abs(Frac a)Frac|a|
fr_cmpfr_cmp(Frac a, Frac b)int与数学顺序一致的比较:-1 / 0 / 1;内部为交叉相乘,极端数值下中间积可能回绕
fr_equalsfr_equals(Frac a, Frac b)int数值是否相等,1/0(2/4 与 1/2 相等)
fr_is_intfr_is_int(Frac a)int是否为整数,1/0(分母为 1,或分子能被分母整除)
fr_to_strfr_to_str(Frac a)string整数输出 "2",否则输出 "3/4";输出前先规范化
fr_to_floatfr_to_float(Frac a)float浮点近似 num / den;分母为 0 时置错误标志并返回 0.0
cin
import "frac.cin"

function main() -> int {
    Frac a = fr_make(1, 3)
    Frac b = fr_make(1, 6)
    println("a      = " + fr_to_str(a))
    println("b      = " + fr_to_str(b))
    println("a + b  = " + fr_to_str(fr_add(a, b)))
    println("a - b  = " + fr_to_str(fr_sub(a, b)))
    println("a * b  = " + fr_to_str(fr_mul(a, b)))
    println("a / b  = " + fr_to_str(fr_div(a, b)))
    println("2/4    = " + fr_to_str(fr_make(2, 4)))
    println("3/-4   = " + fr_to_str(fr_make(3, -4)))
    println("cmp    = " + int_to_str(fr_cmp(a, b)))
    println("float  = " + float_to_str(fr_to_float(a)))
    Frac z = fr_make(1, 0)
    println("1/0    = " + fr_to_str(z) + " err=" + int_to_str(fr_error()))
    return 0
}

gostd ​

Go 标准库兼容层,以 pkg.Func 命名习惯提供 Go strings / strconv / math / slices / os 的常用函数(go_strings_contains 对应 strings.Contains), 命名里的包段与 Go 文档一一对应,便于从 Go 移植或查阅语义。纯 CIN 实现; 唯一例外是 go_os_args_*(依赖命令行参数内建)。

cin
import "gostd.cin"
函数名签名返回值说明与边界行为
go_strings_contains / go_strings_index(string s, string sub)int是否包含(1/0)/ 首现下标(未找到 -1)
go_strings_last_index(string s, string sub)int末现下标(未找到 -1);空 sub 返回 strlen(s)
go_strings_contains_any / go_strings_index_any(string s, string chars)int / ints 是否含 chars 内任一字符 / 首个 chars 内字符的下标(-1 未找到)
go_strings_has_prefix / go_strings_has_suffix(string s, string pre/suf)int前缀 / 后缀判定
go_strings_to_upper / go_strings_to_lower(string s)stringASCII 大小写
go_strings_trim_space(string s)string去两端空白
go_strings_trim_left / go_strings_trim_right(string s, string cutset)string去前导 / 尾部 cutset 内字符(空 cutset 原样返回)
go_strings_trim_prefix / go_strings_trim_suffix(string s, string pre/suf)string有前 / 后缀则去掉,无则原样返回
go_strings_repeat(string s, int n)string重复 n 次(n <= 0 空串)
go_strings_count(string s, string sub)int非重叠子串计数;空 sub 返回 strlen(s)+1(与 Go 一致)
go_strings_replace_all(string s, string old, string new)string全量替换(空 old 原样返回)
go_strings_equal_fold(string a, string b)intASCII 大小写不敏感相等
go_strings_compare(string a, string b)intstrcmp:<0 / 0 / >0
go_len(string s)intlen(s) 字节长度
go_itoa / go_atoi(int v) / (string s)string / intstrconv.Itoa / Atoi(解析失败为 0)
go_format_float(float v)stringFormatFloat 默认精度替身(即 float_to_str)
go_format_int(int v, int base)stringstrconv.FormatInt:base 2..36(越界按 10);负数带 -,小写数字
go_parse_int(string s, int base)intstrconv.ParseInt 简化版:可选 - 前缀,0-9a-zA-Z,base 2..36;非法字符停在非法处
go_math_abs / go_math_max / go_math_min(int ...)int整数版
go_math_floor / go_math_ceil / go_math_round / go_math_trunc(float x)float取整族(round 为半值远离零)
go_math_sqrt / go_math_pow(float ...)float包装内建
go_slices_index / go_slices_last_index(int[] a, int n, int x)int首现 / 末现下标(未找到 -1)
go_slices_contains(int[] a, int n, int x)int是否包含
go_slices_max / go_slices_min / go_slices_sum(int[] a, int n)int最值 / 求和(空数组返回 0)
go_slices_reverse / go_slices_sort(int[] a, int n)void原地反转 / 升序排序
go_slices_equal(int[] a, int[] b, int n)int前 n 个元素逐位相等(1/0)
go_slices_clone(int[] dst, int[] src, int n)int拷贝到 dst,返回 n(调用方保证容量)
go_os_args_len()intlen(os.Args):CLI -- 之后传给 CIN 程序的参数个数;依赖命令行参数内建
go_os_args_get(int i)stringos.Args[i](越界空串;下标从 0 计 CIN 参数);依赖命令行参数内建
cin
import "gostd.cin"

function main() -> int {
    println(go_strings_repeat("ab", 3))              // ababab
    println(go_format_int(255, 16))                  // ff
    println(int_to_str(go_parse_int("101", 2)))      // 5
    println(go_strings_trim_suffix("x:suffix", ":suffix"))   // x
    int a[3] = {1, 2, 3}
    int b[3]
    go_slices_clone(b, a, 3)
    println(int_to_str(go_slices_equal(a, b, 3)))    // 1
    return 0
}

graph ​

定长图库。纯 CIN 实现,不做动态内存分配:图存放在库内全局的邻接矩阵里 (graph_edge[256] 存边是否存在、graph_w[256] 存边权,行主序一维数组, 下标 u * GRAPH_MAX + v),节点容量上限 GRAPH_MAX = 16, 权重是 int(可以为 0 或负数,因此判断"有没有边"请用 graph_has_edge, 不要用 graph_weight != 0)。

  • 节点编号 0..graph_nodes()-1;越界编号一律返回明确失败值,不会静默写内存: graph_has_edge / graph_weight 返回 0,graph_degree / graph_in_degree 返回 -1, graph_add_edge 返回 0,graph_bfs / graph_dfs / graph_dijkstra 返回 0, graph_topo_order 返回 -1。
  • graph_reset(n, directed) 的 n <= 0 钳制为 0,n > GRAPH_MAX 钳制为 GRAPH_MAX。
  • 无向图里 (u, v) 与 (v, u) 是同一条边;有向图按 u -> v 记录。
  • 自环 u == v 允许存在:无向图里算一条边、贡献 1 度,并且算一个环。
  • 邻接矩阵不支持平行边,重复加边返回 0。
  • 所有遍历都按节点编号升序扫描邻居,因此结果完全确定。
  • 全局数据段占用约 579 槽(4632 字节),只有一份全局实例, 需要多张图请用 struct 自行封装。
cin
import "graph.cin"
函数名签名返回值说明与边界行为
graph_maxgraph_max()int固定返回 16(GRAPH_MAX)
graph_nodesgraph_nodes()int当前节点数(graph_reset 设定并钳制后的值)
graph_is_directedgraph_is_directed()int1 有向图,0 无向图
graph_edge_countgraph_edge_count()int当前边数;无向图里 (u, v) 与 (v, u) 只算一条
graph_resetgraph_reset(int n, int directed)void重新设定节点数与方向并清空所有边;n <= 0 钳制为 0,n > 16 钳制为 16,directed 非零表示有向图
graph_cleargraph_clear()void只删除所有边,保留节点数与方向
graph_add_edgegraph_add_edge(int u, int v, int w)int加边 u -> v(无向图两侧都加);成功返回 1,节点越界或这条边已存在返回 0(状态不变)
graph_has_edgegraph_has_edge(int u, int v)intu 到 v 是否有边,1/0;节点越界返回 0
graph_weightgraph_weight(int u, int v)int边权;没有这条边或节点越界返回 0(权重本身可以是 0,判断边存在请用 graph_has_edge)
graph_degreegraph_degree(int u)int出度;无向图是邻居数(自环算 1);节点越界返回 -1
graph_in_degreegraph_in_degree(int u)int入度;无向图与 graph_degree 相同;节点越界返回 -1
graph_bfsgraph_bfs(int start, int[] order, int[] out_dist)int从 start 广度优先遍历(按出边方向,邻居编号升序入队);返回访问节点数 cnt,order[0..cnt-1] 写访问顺序,out_dist[0..graph_nodes()-1] 写距离(边数),不可达写 -1;start 越界或图为空返回 0 且 out_dist 全为 -1(out_dist 至少要能放 graph_nodes() 个元素)
graph_dfsgraph_dfs(int start, int[] order)int从 start 深度优先遍历,用显式栈(不递归,栈深不随图增长);返回访问节点数,order[0..cnt-1] 写访问顺序,邻居按编号降序压栈所以编号小的先访问;start 越界或图为空返回 0
graph_component_countgraph_component_count()int连通分量个数,按无向视角统计(有向图得到弱连通分量数);空图返回 0
graph_connectedgraph_connected()int是否连通(无向视角,有向图问的是弱连通);空图与单节点都返回 1
graph_is_cyclicgraph_is_cyclic()int是否存在环(自环算环),1/0;空图返回 0。无向图用「边数 > 节点数 - 分量数」判定,有向图用拓扑排序能否覆盖全部节点判定
graph_topo_ordergraph_topo_order(int[] order)int有向图拓扑排序(Kahn,每轮取编号最小的入度 0 节点,结果确定);成功返回节点数并写 order[0..n-1],有环返回 -1;无向图返回 -1(无向图没有拓扑序);空有向图返回 0
graph_dijkstragraph_dijkstra(int src, int[] dist)int单源最短路(O(n²) 邻接矩阵版);返回可达节点数(含 src),dist[0..graph_nodes()-1] 写最短距离,不可达写 -1;src 越界或图为空返回 0 且不写 dist。有向图按出边方向松弛,无向图两个方向都松弛;要求边权 >= 0,出现负权时「松弛结果 < 0」的边会被忽略(不报错,此时结果没有保证)
graph_aux_nodegraph_aux_node(int u)int内部辅助:节点编号是否合法,非稳定接口
graph_aux_arcgraph_aux_arc(int u, int v)int内部辅助:无向视角下 u、v 之间是否有边,非稳定接口
cin
import "graph.cin"

function main() -> int {
    graph_reset(6, 0)
    graph_add_edge(0, 1, 7)
    graph_add_edge(0, 2, 9)
    graph_add_edge(0, 5, 14)
    graph_add_edge(1, 2, 10)
    graph_add_edge(1, 3, 15)
    graph_add_edge(2, 3, 11)
    graph_add_edge(2, 5, 2)
    graph_add_edge(3, 4, 6)
    graph_add_edge(4, 5, 9)
    println("nodes = " + int_to_str(graph_nodes()))            // 6
    println("edges = " + int_to_str(graph_edge_count()))        // 9
    println("degree(0) = " + int_to_str(graph_degree(0)))       // 3
    println("weight(2, 5) = " + int_to_str(graph_weight(2, 5))) // 2

    int order[16]
    int dist[16]
    println("bfs = " + int_to_str(graph_bfs(0, order, dist)))   // 6
    println("bfs order = " + int_to_str(order[0]) + " " + int_to_str(order[1]) + " " + int_to_str(order[2]) + " " + int_to_str(order[3]) + " " + int_to_str(order[4]) + " " + int_to_str(order[5]))   // 0 1 2 5 3 4
    println("dijkstra = " + int_to_str(graph_dijkstra(0, dist)))   // 6
    println("dist = " + int_to_str(dist[0]) + " " + int_to_str(dist[1]) + " " + int_to_str(dist[2]) + " " + int_to_str(dist[3]) + " " + int_to_str(dist[4]) + " " + int_to_str(dist[5]))   // 0 7 9 20 20 11
    println("components = " + int_to_str(graph_component_count()))   // 1

    graph_reset(4, 1)
    graph_add_edge(0, 1, 1)
    graph_add_edge(0, 2, 1)
    graph_add_edge(1, 3, 1)
    graph_add_edge(2, 3, 1)
    int topo[16]
    println("topo = " + int_to_str(graph_topo_order(topo)) + ", first = " + int_to_str(topo[0]))   // topo = 4, first = 0
    println("cyclic = " + int_to_str(graph_is_cyclic()))        // 0
    graph_add_edge(3, 0, 1)
    println("cyclic = " + int_to_str(graph_is_cyclic()))        // 1
    println("topo = " + int_to_str(graph_topo_order(topo)))     // -1
    return 0
}

gui ​

画布绘图助手库。内部调用 canvas / set_color / fill_rect / fill_circle / draw_line / draw_text / save_png / show_canvas 等宿主能力内建,因此必须运行在 Go 原生引擎上。

cin
import "gui.cin"
函数名签名返回值说明与边界行为
g_rgbg_rgb(int r, int g, int b)int打包 RGB 为 0xRRGGBB;每个分量只取低 8 位(& 255)
g_newg_new(int w, int h)void新建白色画布 w × h,等价于内建 canvas(w, h)
g_clearg_clear(int w, int h, int rgb)void新建画布并整体填充为 rgb
g_rect_outlineg_rect_outline(int x, int y, int w, int h, int rgb)void画线宽 1 的矩形边框(四条 draw_line,不填充)
g_bar_chartg_bar_chart(int[] values, int n, int w, int h)void柱状图:先清成白底,按最大值自动缩放,柱子深蓝 (60,120,200),最后补黑边框;n <= 0 时只留白底
g_gridg_grid(int w, int h, int step)void浅灰 (200,200,200) 网格;step <= 0 会死循环,务必传正数
g_line_chartg_line_chart(int[] values, int n, int w, int h)void折线图:白底 + 深红 (200,40,40) 折线;n <= 1 时只留白底
g_saveg_save(string path)int导出 PNG,0 成功 / -1 失败,转调内建 save_png
g_showg_show()int调系统查看器弹出窗口,转调内建 show_canvas
cin
import "gui.cin"

function main() -> int {
    int a[5] = {3, 7, 2, 9, 5}
    g_bar_chart(a, 5, 50, 30)
    if (g_save("bar.png") != 0) { return 1 }
    println(int_to_str(g_rgb(255, 0, 0)))   // 16711680 (0xFF0000)
    g_line_chart(a, 5, 40, 20)
    g_save("line.png")
    return 0
}

hash ​

哈希函数库。全部为 64 位整数运算(自然溢出即取模 2^64),适合与 rand.cin 配合做简易哈希表 或布隆过滤器的散列函数。

cin
import "hash.cin"
函数名签名返回值说明与边界行为
hash_djb2hash_djb2(string s)intdjb2:h = h*33 + c,初值 5381;空串返回 5381
hash_fnv1ahash_fnv1a(string s)intFNV-1a(64 位);空串返回偏移基 0xCBF29CE484222325
hash_sdbmhash_sdbm(string s)intsdbm:h = c + (h<<6) + (h<<16) - h,初值 0
hash_inthash_int(int x)intsplitmix64 风格的整数位混合,用于打散规律性输入;hash_int(0) 为 0
hash_combinehash_combine(int h1, int h2)int组合两个哈希值,不可交换;用于把多个字段揉成一个哈希
hash_buckethash_bucket(int h, int buckets)int映射到 [0, buckets);buckets <= 0 返回 0,负数取模结果也归一到非负
hash_string_buckethash_string_bucket(string s, int buckets)int字符串 → 桶下标,即 hash_bucket(hash_fnv1a(s), buckets)
cin
import "hash.cin"

function main() -> int {
    println(int_to_str(hash_djb2("")))              // 5381
    println(int_to_str(hash_string_bucket("hello", 16)))  // 0..15
    println(int_to_str(hash_bucket(-3, 8)))         // 5
    int h = hash_combine(hash_djb2("user"), hash_fnv1a("42"))
    println(int_to_str(hash_bucket(h, 64)))
    if (hash_djb2("abc") == hash_djb2("abd")) { return 1 }
    return 0
}

heap ​

定长二叉堆库。纯 CIN 实现,不做动态内存分配:堆存放在库内全局数组 heap_data[64] 里, 容量上限 HEAP_CAP = 64,因此同一程序内只有一份全局实例,需要多个堆请用 struct 自行封装。 同一份实现同时支持最小堆与最大堆,由标志位 heap_is_max 选择:heap_is_max == 0 为最小堆,非零为最大堆。heap_sort 固定升序,并且直接在被排序数组上就地完成(内部自建最大堆, 不读写上面的全局堆),因此调用 heap_sort 不会破坏已有的堆状态。 空堆时 heap_pop / heap_peek / heap_replace 返回 0(无法区分“空”与“堆顶就是 0”, 需要区分时先查 heap_is_empty)。

cin
import "heap.cin"
函数名签名返回值说明与边界行为
heap_capacityheap_capacity()int固定返回 64(HEAP_CAP)
heap_resetheap_reset(int is_max)void清空并设置模式:is_max 非零为最大堆,否则最小堆
heap_sizeheap_size()int当前元素个数
heap_is_emptyheap_is_empty()int1 为空堆
heap_pushheap_push(int v)int入堆;成功返回 1,满时返回 0 且丢弃该值
heap_popheap_pop()int弹出并返回堆顶;空堆返回 0
heap_peekheap_peek()int查看堆顶(不出堆);空堆返回 0
heap_replaceheap_replace(int v)int弹出堆顶并压入 v,返回被弹出的值;空堆时等价于 heap_push(v) 并返回 0
heap_buildheap_build(int[] a, int n, int is_max)void用 a 的前 n 个元素重建堆并切换模式;n <= 0 钳制为 0,n > 64 钳制为 64(超出的元素被丢弃)
heap_is_validheap_is_valid()int校验堆性质(每个孩子都不比父节点更优先),1/0;空堆返回 1
heap_sortheap_sort(int[] a, int n)void就地升序排序(堆排序),n <= 1 直接返回;不依赖也不修改全局堆状态
heap_betterheap_better(int a, int b)int内部辅助:a 是否应排在 b 前面(按当前 heap_is_max),非稳定接口
heap_sift_downheap_sift_down(int i)void内部辅助:把全局堆下标 i 下沉,非稳定接口
heap_sift_maxheap_sift_max(int[] a, int m, int i)void内部辅助:在 a[0..m-1] 内按最大堆下沉,供 heap_sort 使用,非稳定接口
cin
import "heap.cin"

function main() -> int {
    heap_reset(0)                                          // 最小堆
    int v[6] = {5, 3, 8, 1, 9, 2}
    for (int i = 0; i < 6; i = i + 1) {
        heap_push(v[i])
    }
    println("min peek = " + int_to_str(heap_peek()))        // 1
    println("valid = " + int_to_str(heap_is_valid()))       // 1
    println("pop = " + int_to_str(heap_pop()))              // 1
    println("pop = " + int_to_str(heap_pop()))              // 2
    println("replace 0 = " + int_to_str(heap_replace(0)))   // 3 (弹回的堆顶)
    println("peek = " + int_to_str(heap_peek()))            // 0

    heap_reset(1)                                          // 最大堆
    heap_push(5)
    heap_push(9)
    heap_push(7)
    println("max peek = " + int_to_str(heap_peek()))        // 9

    int a[6] = {4, 8, 1, 8, 3, 6}
    heap_build(a, 6, 0)
    println("built peek = " + int_to_str(heap_peek()))      // 1

    heap_sort(a, 6)
    println("sorted = " + int_to_str(a[0]) + " "
            + int_to_str(a[1]) + " "
            + int_to_str(a[2]) + " "
            + int_to_str(a[3]) + " "
            + int_to_str(a[4]) + " "
            + int_to_str(a[5]))                            // 1 3 4 6 8 8
    return 0
}

io ​

文件与路径工具库。内部转调 file_read / file_write / file_append / file_exists / file_size / file_delete / mkdir / dir_list 等宿主能力内建,必须运行在 Go 原生引擎上; 文本处理部分(io_line_count / io_get_line / io_split_get / io_split_count)是纯 CIN 逻辑。

cin
import "io.cin"
函数名签名返回值说明与边界行为
io_readio_read(string path)string读取整个文本;失败返回空串(不抛错,需自行判断)
io_writeio_write(string path, string text)int覆盖写入,0 成功 / -1 失败
io_appendio_append(string path, string text)int追加写入,0 成功 / -1 失败
io_existsio_exists(string path)int是否存在,1/0
io_sizeio_size(string path)int文件字节数;失败返回 -1
io_removeio_remove(string path)int删除文件,0 成功 / -1 失败
io_mkdirio_mkdir(string path)int递归创建目录,0 成功 / -1 失败
io_listio_list(string path)string目录条目,换行分隔;目录名带 / 后缀
io_joinio_join(string a, string b)string路径拼接:任一侧为空则返回另一侧;已以 / 或 \ 结尾则直接相连,否则补 /。不做 .. 归一化
io_basenameio_basename(string path)string取最后一段(同时识别 / 与 \);无分隔符则原样返回
io_dirnameio_dirname(string path)string取目录部分;无分隔符返回空串,"/a" 返回空串
io_line_countio_line_count(string text)int按 \n 统计行数;空串返回 0,"a\nb" 返回 2
io_get_lineio_get_line(string text, int idx)string取第 idx 行(0 起,不含换行符);越界返回空串
io_split_getio_split_get(string text, string sep, int idx)string按分隔串切分,取第 idx 段;sep 为空串时 idx == 0 返回原文,否则空串;越界返回空串
io_split_countio_split_count(string text, string sep)int按分隔串切分的段数;sep 为空串时返回 1
cin
import "io.cin"

function main() -> int {
    if (io_write("note.txt", "a\nb\nc") != 0) { return 1 }
    println(int_to_str(io_size("note.txt")))                 // 5
    println(int_to_str(io_line_count(io_read("note.txt"))))  // 3
    println(io_get_line(io_read("note.txt"), 1))             // b
    println(io_basename("dir/note.txt"))                     // note.txt
    println(io_join("x", "y"))                               // x/y
    println(int_to_str(io_split_count("a,b,c", ",")))        // 3
    println(int_to_str(io_remove("note.txt")))
    return 0
}

json ​

极简 JSON 取值库。面向扁平对象(典型场景是 Termux API 返回的 JSON),不做完整语法解析, 只支持 "key": value 形式的字符串/数字/布尔/空值提取;嵌套对象内层字段不会被正确解析。

cin
import "json.cin"
函数名签名返回值说明与边界行为
j_rawj_raw(string json, string key)string取 key 对应的原始片段:字符串值去引号,数字/true/false/null 原样返回(两端 trim);找不到返回空串
j_strj_str(string json, string key)string取字符串字段,直接转调 j_raw
j_intj_int(string json, string key)int取整数字段,走 atoi(j_raw(...));无法解析为 0
j_floatj_float(string json, string key)float取浮点字段,支持可选负号与小数;无法解析为 0.0,不解析指数形式
j_hasj_has(string json, string key)int是否包含 "key" 字面量,1/0;只看引号包裹的键名,不做语法校验
j_boolj_bool(string json, string key)int取布尔字段:值为 true 或 1 时返回 1,其余(含 false、缺失)返回 0
cin
import "json.cin"

function main() -> int {
    string j = "{\"name\":\"cin\",\"level\":42,\"on\":true,\"temp\":30.5}"
    println(j_str(j, "name"))                       // cin
    println(int_to_str(j_int(j, "level")))          // 42
    println(int_to_str(j_bool(j, "on")))            // 1
    println(float_to_str(j_float(j, "temp")))       // 30.500000
    println(int_to_str(j_has(j, "missing")))        // 0
    return 0
}

key ​

键盘输入监听便捷封装。封装内建 key_hit / get_key / key_flush(非阻塞轮询), 需要真实终端与 Go 原生运行时;管道 / 重定向下 key_hit 恒为 0、get_key 恒为 -1。 首次调用会把终端切到原始输入(不回显、无行缓冲),程序退出自动恢复;监听期间 Ctrl+C 不再终止程序,表现为键码 k_ctrl(67) 即 3。

cin
import "key.cin"

enum Key 键码常量(扩展码与常用控制键):

常量值含义
K_UP / K_DOWN / K_LEFT / K_RIGHT1001..1004方向键
K_HOME / K_END / K_PGUP / K_PGDN1005..1008Home / End / PgUp / PgDn
K_INS / K_DEL1009 / 1010插入 / 删除
K_F1 .. K_F101021..1030功能键 F1..F10
K_ESC / K_ENTER / K_TAB / K_BACKSPACE27 / 13 / 9 / 8常用控制键
函数名签名返回值说明与边界行为
k_ctrlk_ctrl(int c)intCtrl 组合键码:c & 0x1F;如 k_ctrl(67)(字母 C)即 3(Ctrl+C)
k_is_specialk_is_special(int code)int扩展键码判定:1001..1030 返回 1,其余(含 0..255 原始字节)返回 0
key_waitkey_wait()int阻塞等待一个按键:内部以 10ms 轮询 get_key(),取到键码即返回
cin
import "key.cin"

function main() -> int {
    println("任意键开始, ESC 退出")
    while (1) {
        int k = key_wait()
        if (k == K_ESC) { break }
        if (k == K_UP)   { println("up") }
        if (k == K_DOWN) { println("down") }
        if (!k_is_special(k)) {
            println("键码 " + int_to_str(k))
        }
    }
    return 0
}

math ​

数学扩展库。注意 CIN 的 / 恒为浮点除法,本库提供的是显式的取整/最值/夹取辅助函数。 同一文件同时给出 f_(浮点)与 i_(整数)两组函数。

cin
import "math.cin"
函数名签名返回值说明与边界行为
f_absf_abs(float x)float绝对值
f_floorf_floor(float x)float向下取整,负数向 -inf(f_floor(-2.5) 为 -3.0)
f_ceilf_ceil(float x)float向上取整,实现为 -f_floor(-x)
f_roundf_round(float x)float四舍五入,实现为 f_floor(x + 0.5);.5 一律向上
f_minf_min(float a, float b)float两浮点较小者
f_maxf_max(float a, float b)float两浮点较大者
i_mini_min(int a, int b)int两整数较小者
i_maxi_max(int a, int b)int两整数较大者
i_clampi_clamp(int v, int lo, int hi)int夹取到 [lo, hi];lo > hi 时先命中 v < lo 分支
f_round↔内建见下方 tabs—f_round 与内建 round 语义一致,后者单条指令更快
cin
import "math.cin"

function main() -> int {
    println(float_to_str(f_round(2.5)))    // 3
    println(float_to_str(f_floor(-2.5)))   // -3
    println(int_to_str(i_clamp(99, 0, 10)))// 10
    return 0
}

matrix ​

方阵运算库。矩阵以一维数组行主序存放:m[i*n + j] 表示第 i 行第 j 列,因此可直接用 CIN 的 int[] 与固定数组,无需动态内存。所有 _to 形式把结果写入调用方提供的输出数组 out(out 与输入数组共用时结果不确定,mat_mul 明确要求 out 不得与 a/b 为同一数组)。

cin
import "matrix.cin"
函数名签名返回值说明与边界行为
mat_zeromat_zero(int[] m, int n)void把 n*n 个元素全部置 0
mat_identitymat_identity(int[] m, int n)void置为单位阵(对角线 1,其余 0)
mat_getmat_get(int[] m, int n, int i, int j)int逐元素取值;下标越界返回 0(不报错)
mat_setmat_set(int[] m, int n, int i, int j, int v)void逐元素赋值;下标越界静默不做任何事
mat_addmat_add(int[] a, int[] b, int[] out, int n)voidout = a + b
mat_submat_sub(int[] a, int[] b, int[] out, int n)voidout = a - b
mat_scalemat_scale(int[] a, int k, int[] out, int n)voidout = a * k(逐元素乘标量)
mat_mulmat_mul(int[] a, int[] b, int[] out, int n)voidout = a × b,经典三重循环;out 不得与 a/b 为同一数组
mat_transposemat_transpose(int[] a, int[] out, int n)voidout = a^T
mat_tracemat_trace(int[] a, int n)int迹(对角线之和)
mat_summat_sum(int[] a, int n)int所有 n*n 个元素之和
mat_equalsmat_equals(int[] a, int[] b, int n)int是否逐元素相等,1/0
mat_is_symmetricmat_is_symmetric(int[] a, int n)int是否为对称矩阵(只比较上三角),1/0
mat_detmat_det(int[] a, int n)int行列式,拉普拉斯递归展开;适合 n <= 6(内部 minor[36] 只够 (n-1)^2 <= 36 的余子式)。n <= 0 返回 0,n == 1 返回 a[0],n == 2 走闭式公式
mat_printmat_print(int[] a, int n)void调试打印,每行一个方括号,元素以空格分隔
cin
import "matrix.cin"

function main() -> int {
    int n = 2
    int a[4] = {1, 2, 3, 4}
    int b[4] = {5, 6, 7, 8}
    int out[4]
    mat_mul(a, b, out, n)
    println(int_to_str(out[0]))            // 19
    mat_transpose(a, out, n)
    println(int_to_str(out[1]))            // 3
    println(int_to_str(mat_trace(a, n)))   // 5
    println(int_to_str(mat_det(a, n)))     // -2
    int m3[9] = {2, 0, 0, 0, 3, 0, 0, 0, 4}
    println(int_to_str(mat_det(m3, 3)))    // 24
    mat_print(a, n)
    return 0
}

net ​

网络便捷封装。封装内建 http_req / http_code / tcp_* / udp_* / dns_lookup (SYS 145-157,Go 引擎实现),必须运行在 Go 原生引擎上;--sandbox 下宿主调用会被拦截。 缓冲约定:接收辅助函数收 int[] buf(CIN 数组每个元素占 8 字节,收到的字节流由引擎 原样写入缓冲内存),按小端逐字节重组字符串;调用前无需清零。逐字节重组是 O(n²) 堆拷贝,建议单次接收 <= 4096 字节;二进制 / 大流量场景直接用底层内建处理原始字节。

cin
import "net.cin"
函数名签名返回值说明与边界行为
http_get_headershttp_get_headers(string url, string headers)stringGET(可带自定义头,"Key: Value\n" 换行分隔,空串表示无头),返回响应体;失败空串
http_post_headershttp_post_headers(string url, string body, string headers)stringPOST(自定义头与 body,Content-Type 等头由调用方提供),返回响应体;失败空串
http_okhttp_ok()int最近一次 HTTP 请求是否 2xx(1/0);从未请求返回 0
tcp_send_strtcp_send_str(int fd, string s)int发送字符串(不含结尾 NUL),返回发送字节数 / -1
tcp_send_linetcp_send_line(int fd, string s)int发送一行(自动追加 \n),文本协议友好
tcp_recv_bytestcp_recv_bytes(int fd, int[] buf, int max)int原始接收:字节写入 buf(调用方自行解码),返回字节数 / 0 对端关闭 / -1
tcp_recv_strtcp_recv_str(int fd, int[] buf, int max)string接收并以字符串返回(遇 NUL 截断);n <= 0 返回空串
tcp_recv_linetcp_recv_line(int fd, int[] buf, int max)string接收一行(到 \n 为止,不含 \n,行尾 \r 一并去掉);缓冲区里 \n 之后的内容被丢弃,需保留请用 tcp_recv_bytes
tcp_roundtriptcp_roundtrip(string host, int port, string message)string连接 → 发送一行 → 收一行 → 关闭一步到位;任一步失败返回空串
tcp_servertcp_server(int port)int在端口上监听,返回监听句柄;失败 -1
tcp_server_accepttcp_server_accept(int lfd)int阻塞接受一个连接,返回连接句柄;失败 -1(用完 tcp_close)
udp_bindudp_bind(int port)int打开 UDP 套接字并绑定端口(0 = 系统分配),即 udp_open 的别名
udp_send_strudp_send_str(int fd, string host, int port, string s)int发送字符串数据报(host 支持主机名或 IP 字面量),返回发送字节数 / -1
udp_recv_bytesudp_recv_bytes(int fd, int[] buf, int max, int[] src)int原始接收:字节写入 buf,源地址 "ip:port" 写入 src(建议 >= 64 字节),返回字节数 / -1
udp_recv_strudp_recv_str(int fd, int[] buf, int max)string接收数据报并以字符串返回(遇 NUL 截断,不取源地址)
dns_resolvedns_resolve(string host)string解析主机名 → IP 字符串(dns_lookup 的语义别名);失败空串
dns_okdns_ok(string host)int主机名是否可解析(1/0)
cin
import "net.cin"

function main() -> int {
    string ip = dns_resolve("example.com")
    if (strcmp(ip, "") == 0) { println("DNS 解析失败"); return 1 }
    println("example.com = " + ip)

    int fd = tcp_dial("example.com", 80)
    if (fd <= 0) { println("连接失败"); return 1 }
    tcp_send_line(fd, "GET / HTTP/1.0")
    int buf[512]
    println(tcp_recv_line(fd, buf, 4096))    // 首行响应
    tcp_close(fd)
    return 0
}

path ​

纯字符串路径工具库 (codecin/lib/path/src/path.cin, 前缀 path_)。与 io 库的 io_join / io_basename / io_dirname 不同, 本库不访问文件系统、不依赖任何宿主能力: 只用 strlen / substr / strcmp / int_to_str, 不发起任何宿主调用。 / 与 \ 两种分隔符都识别 (等价), 输出统一用 /。

命名冲突: 必须用 path_str_* 而不是内建名

path_join / path_basename / path_dirname 是宿主能力内建名。CIN 编译器在 _gen_call 里先分派内建, 因此同名用户函数永远不会被调用: 它们会解析到 真实主机的 path_join / path_basename / path_dirname (在本机 Windows 上返回 a\b 这类系统分隔符结果)。所以本库把这三个纯字符串版本命名为 path_str_join / path_str_basename / path_str_dirname, 其余函数名与常规 path_ 命名一致。

容量与全局数据:

常量 / 全局量值说明
PATH_MAX_PARTS128规范化 / 分段时可处理的路径分段上限 (path_max_parts() 可读取)
path_parts_buf[128]—分段解析的全局暂存区, 1024 字节

path_str_dirname / path_common_prefix / path_within 会在函数内声明 string[128] 局部固长数组 (栈上 1 KiB 量级), 无动态内存分配。

明确不支持 (与真实文件系统语义不同):

  • 不支持 UNC 语义: \\server\share 的前导双反斜杠按普通分隔符处理, 会被折叠成单个 /, 不保留共享名语义;
  • 盘符只做字符串识别: path_is_absolute 认 C:\a / C:/a / C:, 不校验盘符是否为真实字母, 也不做大小写折叠;
  • path_normalize 的 .. 只做字符串层面折叠, 不访问文件系统, 不解析符号链接, 也不受真实目录结构约束;
  • 路径分段比较一律大小写敏感 ("A/b" 与 "a/b" 没有公共前缀)。
cin
import "path.cin"
函数名签名返回值说明与边界行为
path_sep_posixpath_sep_posix()string返回 "/"
path_sep_winpath_sep_win()string返回 "\\" (单字节反斜杠, 编码 92)
path_is_seppath_is_sep(int ch)int该字节是否为分隔符 (47 或 92), 返回 1/0
path_max_partspath_max_parts()int分段上限, 固定返回 128 (PATH_MAX_PARTS)
path_split_countpath_split_count(string p)int路径分段个数; 连续分隔符与尾随分隔符都不产生空段; "" / "/" / "///" 均为 0
path_split_getpath_split_get(string p, int idx)string第 idx 段 (0 起); 越界与负数返回 ""; 与 path_split_count 使用同一套分段规则
path_str_basenamepath_str_basename(string p)string最后一段 (文件名); "" 与 "/" 返回 "", "a/b/" 返回 "b" (折叠尾随分隔符); 内建 path_basename 是宿主能力, 故用此名
path_str_dirnamepath_str_dirname(string p)string去掉最后一段, 结果不带尾随分隔符: "/a/b/c.txt" -> "/a/b", "a" -> "", "/a" -> "/"; 不做 . / .. 折叠; 内建 path_dirname 是宿主能力, 故用此名
path_extpath_ext(string p)string最后一段的扩展名 (含点); 无扩展名返回 "" (没有点、点在最前如 .gitignore、.、..); 只看最后一段 ("dir.d/file" 为 ""); 点在最后 ("a.") 视为扩展名就是点本身, 返回 "."
path_stempath_stem(string p)string去掉扩展名的最后一段 (不含目录): "a/b/c.txt" -> "c", "a.tar.gz" -> "a.tar", ".gitignore" -> ".gitignore", "a." -> "a"; "." / ".." 原样返回
path_str_joinpath_str_join(string a, string b)string拼接: a 为空返回 b, b 为空返回 a; b 是绝对路径时忽略 a 直接返回 b; 否则 a 末尾已有分隔符就不重复添加, 否则补 '/'; 两侧都空返回 ""; 内建 path_join 是宿主能力 (用系统分隔符), 故用此名
path_normalizepath_normalize(string p)string字符串层面规范化: 折叠重复分隔符、去掉 . 段、.. 回退上一个段、保留前导分隔符、丢掉尾随分隔符、分隔符统一成 /; "a/b/../c" -> "a/c", "a/../../b" -> "../b", "/../a" -> "/a", "a/.." -> "."; 空串 / "." / "///" 都得到 "."; 超过 128 段的部分被丢弃
path_is_absolutepath_is_absolute(string p)int"/a"、"\\a" 返回 1; "C:\a" / "C:/a" / "C:" (第二个字符是 :) 也返回 1; ""、"a/b"、"."、".." 返回 0
path_trim_seppath_trim_sep(string p)string去掉首尾分隔符: "/a/b/" -> "a/b", "/" -> "", "///" -> ""; 中间重复分隔符不折叠
path_common_prefixpath_common_prefix(string a, string b)string最长公共分段前缀 (不把 "foo" 与 "foobar" 当公共前缀); "/a/b/c" 与 "/a/b/d" 得 "/a/b"; 一侧绝对一侧相对返回 "" (即使分段相同); 盘符路径保留盘符段 ("C:/a"), 只有 POSIX 根形式才补前导 /; 根 "/" 没有分段, 与 "/a" 得 ""; 无公共分段返回 ""
path_withinpath_within(string parent, string child)intchild 是否在 parent 之内, 按分段边界比较 (因此 "/a/b" 不包含 "/a/bc"); 相等也算在内; "" 作为 parent 返回 0; "/" 包含一切绝对路径, 但不包含相对路径; "a/" 与 "a\b" 视为 a 之下; 大小写敏感
path_change_extpath_change_ext(string p, string newext)string替换 / 补上最后一段的扩展名; newext 带点或不带点都行 ("md" 与 ".md" 等价); newext 为空串则删除扩展名; 没有扩展名时补上; "" / "." / ".." 以及以分隔符结尾的目录形式 ("/a/b/") 原样返回; 目录部分原样保留 (只丢掉尾随分隔符)

path_parts_into(string p) 是本库内部使用的分段辅助函数 (把分段写入全局 path_parts_buf 并返回段数), 上表未列出; 常规使用请用 path_split_count / path_split_get。

cin
import "path.cin"

function main() -> int {
    println("sep_posix = [" + path_sep_posix() + "]")                 // [/]
    println("is_sep(47) = " + int_to_str(path_is_sep(47)))            // 1
    println("is_sep('A') = " + int_to_str(path_is_sep(65)))           // 0

    println("basename = " + path_str_basename("/a/b/c.txt"))          // c.txt
    println("basename(a/b/) = " + path_str_basename("a/b/"))          // b
    println("dirname = " + path_str_dirname("/a/b/c.txt"))            // /a/b
    println("dirname(/a) = " + path_str_dirname("/a"))                // /
    println("ext = " + path_ext("/a/b/c.txt"))                        // .txt
    println("ext(.gitignore) = [" + path_ext(".gitignore") + "]")     // []
    println("stem = " + path_stem("/a/b/c.txt"))                      // c

    println("join = " + path_str_join("a/", "b"))                     // a/b
    println("join(abs) = " + path_str_join("a", "/b"))                // /b
    println("normalize = " + path_normalize("a//b/./c/../d"))         // a/b/d
    println("normalize(abs) = " + path_normalize("//a/b/"))           // /a/b
    println("normalize(..) = " + path_normalize("a/../../b"))         // ../b
    println("normalize(empty) = " + path_normalize(""))               // .

    println("is_abs(/a) = " + int_to_str(path_is_absolute("/a")))     // 1
    println("is_abs(a/b) = " + int_to_str(path_is_absolute("a/b")))   // 0
    println("is_abs(C:\\a) = " + int_to_str(path_is_absolute("C:\\a")))  // 1

    println("trim_sep = " + path_trim_sep("/a/b/"))                   // a/b
    println("split_count = " + int_to_str(path_split_count("a//b/c")))  // 3
    println("split_get(1) = " + path_split_get("a//b/c", 1))          // b
    println("common = " + path_common_prefix("/a/b/c", "/a/b/d"))     // /a/b
    println("common(drive) = " + path_common_prefix("C:\\a\\b", "C:\\a\\c"))  // C:/a
    println("within = " + int_to_str(path_within("/a/b", "/a/b/c.txt")))      // 1
    println("within(bc) = " + int_to_str(path_within("/a/b", "/a/bc")))       // 0
    println("change_ext = " + path_change_ext("a/b/c.txt", "md"))     // a/b/c.md
    println("change_ext(del) = " + path_change_ext("a/b/c.txt", ""))  // a/b/c
    return 0
}

queue ​

队列与栈库。提供定长环形队列(FIFO)与定长栈(LIFO),使用库内全局状态 (queue_ring[64]、queue_head、queue_tail、queue_len、stack_data[64]、stack_len), 因此同一程序内各只有一份实例;需要多实例时请用 struct 自行封装。 容量上限 QUEUE_CAP / STACK_CAP 均为 64。

cin
import "queue.cin"
函数名签名返回值说明与边界行为
queue_capacityqueue_capacity()int固定返回 64
queue_clearqueue_clear()void清空队列(头尾指针与长度归零)
queue_sizequeue_size()int当前元素个数
queue_is_emptyqueue_is_empty()int1 为空
queue_is_fullqueue_is_full()int1 为满(长度等于 64)
queue_pushqueue_push(int v)int入队;成功返回 1,满时返回 0 且丢弃该值
queue_popqueue_pop()int出队并返回;空时返回 0(无法区分“空”与“队首就是 0”,需先查 queue_is_empty)
queue_frontqueue_front()int查看队首(不出队);空时返回 0
queue_backqueue_back()int查看队尾;空时返回 0。实现为 tail-1,tail == 0 时回绕到下标 63
stack_capacitystack_capacity()int固定返回 64
stack_clearstack_clear()void清空栈
stack_sizestack_size()int当前元素个数
stack_is_emptystack_is_empty()int1 为空
stack_pushstack_push(int v)int入栈;成功返回 1,满时返回 0
stack_popstack_pop()int出栈并返回;空时返回 0
stack_peekstack_peek()int查看栈顶(不出栈);空时返回 0
cin
import "queue.cin"

function main() -> int {
    queue_clear()
    queue_push(1)
    queue_push(2)
    println(int_to_str(queue_size()))     // 2
    println(int_to_str(queue_front()))    // 1
    println(int_to_str(queue_back()))     // 2
    println(int_to_str(queue_pop()))      // 1

    stack_clear()
    stack_push(7)
    stack_push(8)
    println(int_to_str(stack_peek()))     // 8
    println(int_to_str(stack_pop()))      // 8
    println(int_to_str(stack_pop()))      // 7
    println(int_to_str(stack_pop()))      // 0 (已空)
    return 0
}

rand ​

随机工具库。基于内建 rand();需要可复现序列时先调用内建 srand(种子)(只种一次,别在循环里种)。

cin
import "rand.cin"
函数名签名返回值说明与边界行为
r_ranger_range(int lo, int hi)int闭区间 [lo, hi] 随机整数;hi <= lo 时直接返回 lo
r_boolr_bool()bool随机布尔,等价于 r_range(0, 1) == 1
r_floatr_float()float[0.0, 1.0) 随机浮点,实现为 rand() / 2147483648.0
r_float_ranger_float_range(float lo, float hi)float[lo, hi) 随机浮点;hi < lo 时区间反向,结果落在 (hi, lo]
r_shuffler_shuffle(int[] a, int n)void原地 Fisher-Yates 洗牌,元素多重集不变
r_choicer_choice(int[] a, int n)int随机取一个元素;n <= 0 返回 0,不做错误上报
r_chancer_chance(int p)int以 p(0..100 的百分比)概率返回 1;p <= 0 恒 0,p >= 100 恒 1
cin
import "rand.cin"

function main() -> int {
    srand(12345)                                  // 固定种子 -> 可复现
    for (int i = 0; i < 3; i = i + 1) {
        println(int_to_str(r_range(10, 20)))      // 10..20
    }
    int a[3] = {1, 2, 3}
    r_shuffle(a, 3)
    println(int_to_str(r_choice(a, 3)))           // 1 / 2 / 3
    println(int_to_str(r_chance(50)))             // 0 或 1
    return 0
}

set ​

整数集合库(位图实现)。纯 CIN 实现,不做动态内存分配:集合以位图形式存放在库内全局数组 set_data[6](3 个槽 × 2 个 64 位字)里,元素范围 0..SET_MAX-1,容量常量 SET_MAX = 128(set_capacity() 返回 128,set_max() 返回最大合法元素值 127)。 全局数据段只占 6 槽 = 48 字节。

槽位模型:所有接口的 which 只能是 0 / 1 / 2。0 是集合 A,1 是集合 B, 两者互相独立;2 是备用槽 C,给 set_*_into 存放结果。全局变量由运行时清零, 所以程序一开始三个槽都是空集。

边界行为(全局约定):

  • which 非法(不在 0..2):数值查询 set_size / set_is_empty / set_min / set_max_value / set_count_range 返回 -1;布尔查询 set_contains / set_is_subset / set_equals / set_is_full 返回 0;写入类 set_add / set_remove / set_reset / set_clear / set_fill / set_copy_into / set_union_into / set_intersect_into / set_diff_into 返回 0 且绝不写内存;set_to_str 返回空串 ""。set_reset_all() 无参数。
  • 元素 v 非法(v < 0 或 v >= 128):set_add / set_remove / set_contains 返回 0, 不写内存。
  • 空集:set_size 为 0,set_is_empty 为 1,set_is_full 为 0,set_min / set_max_value 为 -1,set_count_range 为 0,set_to_str 为 "{}"。
  • 集合运算允许 dst 与 a / b 是同一个槽(原地运算)。
  • set_clear(which) 与 set_reset(which) 完全等价。
cin
import "set.cin"
函数名签名返回值说明与边界行为
set_maxset_max()int最大合法元素值,固定返回 127(SET_MAX - 1)
set_capacityset_capacity()int元素个数上限,固定返回 128(SET_MAX)
set_slotsset_slots()int可用槽数,固定返回 3(which 的合法取值个数)
set_resetset_reset(int which)int清空槽 which;1 成功,0 表示 which 非法(无操作)
set_reset_allset_reset_all()void清空全部 3 个槽
set_clearset_clear(int which)intset_reset 的别名(按“清空集合”语义书写)
set_fillset_fill(int which)int把槽置满(全部 128 个元素);1 成功,0 表示 which 非法
set_copy_intoset_copy_into(int dst, int src)int把 src 槽整体复制到 dst 槽(允许 dst == src);1 成功,0 表示有非法槽
set_addset_add(int which, int v)int加入元素 v;成功 1,v 越界 / which 非法 / 已存在 均返回 0
set_removeset_remove(int which, int v)int删除元素 v;真正删掉返回 1,v 越界 / which 非法 / 本来不存在返回 0
set_containsset_contains(int which, int v)int是否包含 v,1/0;which 非法或 v 越界返回 0
set_sizeset_size(int which)int元素个数(0..128);which 非法返回 -1
set_is_emptyset_is_empty(int which)int空集返回 1,非空返回 0;which 非法返回 -1
set_is_fullset_is_full(int which)int128 个元素全在返回 1,否则 0;which 非法返回 0
set_minset_min(int which)int最小元素;空集或 which 非法返回 -1
set_max_valueset_max_value(int which)int最大元素;空集或 which 非法返回 -1
set_count_rangeset_count_range(int which, int lo, int hi)int闭区间 [lo, hi] 内的元素个数;lo/hi 自动钳制到 [0, 127],钳制后 hi < lo 返回 0;which 非法返回 -1
set_union_intoset_union_into(int dst, int a, int b)intdst = a | b;1 成功,0 表示有非法槽(dst 可与 a/b 同槽)
set_intersect_intoset_intersect_into(int dst, int a, int b)intdst = a & b;1 成功,0 表示有非法槽
set_diff_intoset_diff_into(int dst, int a, int b)intdst = a - b(差集);1 成功,0 表示有非法槽
set_is_subsetset_is_subset(int a, int b)inta 是否为 b 的子集,1/0;空集是任何集合的子集;有非法槽返回 0
set_equalsset_equals(int a, int b)int两个槽是否完全相同,1/0;有非法槽返回 0
set_to_strset_to_str(int which)string字符串形式,形如 {1, 3, 5};空集为 {};which 非法返回 ""
set_validset_valid(int which)int内部辅助:which 是否在 0..2,非稳定接口
set_popcount64set_popcount64(int x)int内部辅助:单个 64 位字的 popcount(含符号位),非稳定接口
set_raw_testset_raw_test(int which, int v)int内部辅助:直接读第 v 位,调用前须保证 which 合法且 0 <= v < 128,非稳定接口
cin
import "set.cin"

function main() -> int {
    set_reset_all()
    set_add(0, 1)
    set_add(0, 3)
    set_add(0, 5)
    println("A = " + set_to_str(0))                       // A = {1, 3, 5}

    set_add(1, 3)
    set_add(1, 4)
    println("B = " + set_to_str(1))                       // B = {3, 4}

    set_union_into(2, 0, 1)
    println("A|B = " + set_to_str(2))                     // A|B = {1, 3, 4, 5}
    set_intersect_into(2, 0, 1)
    println("A&B = " + set_to_str(2))                     // A&B = {3}
    set_diff_into(2, 0, 1)
    println("A-B = " + set_to_str(2))                     // A-B = {1, 5}

    println("size = " + int_to_str(set_size(0)))          // size = 3
    println("min = " + int_to_str(set_min(0)))            // min = 1
    println("max = " + int_to_str(set_max_value(0)))      // max = 5
    println("count [0,3] = " + int_to_str(set_count_range(0, 0, 3)))    // count [0,3] = 2
    println("B subset A = " + int_to_str(set_is_subset(1, 0)))          // B subset A = 0
    println("A == A = " + int_to_str(set_equals(0, 0)))                 // A == A = 1

    set_remove(0, 3)
    println("A after remove = " + set_to_str(0))          // A after remove = {1, 5}
    set_clear(0)
    println("A after clear = " + set_to_str(0))           // A after clear = {}
    return 0
}

sort ​

排序与查找库。三个基础排序 + 快速排序,全部原地升序;二分查找要求数组已升序。

cin
import "sort.cin"
函数名签名返回值说明与边界行为
sort_is_sortedsort_is_sorted(int[] a, int n)int是否已升序(相等视为有序),1/0;n <= 1 返回 1
sort_bubblesort_bubble(int[] a, int n)void冒泡排序,原地升序
sort_selectionsort_selection(int[] a, int n)void选择排序,原地升序
sort_insertionsort_insertion(int[] a, int n)void插入排序,原地升序;小数组通常最快
sort_quicksort_quick(int[] a, int lo, int hi)void快速排序闭区间 [lo, hi];取中点值为枢轴,lo >= hi 直接返回
sort_quick_allsort_quick_all(int[] a, int n)void整体入口,等价于 n > 1 时调用 sort_quick(a, 0, n - 1)
bin_searchbin_search(int[] a, int n, int v)int二分查找,返回命中下标或 -1;数组必须已升序,重复元素返回其中某个位置(不保证是第一个)
cin
import "sort.cin"

function main() -> int {
    int a[7] = {9, 2, 7, 1, 8, 3, 5}
    sort_quick_all(a, 7)
    println(int_to_str(sort_is_sorted(a, 7)))   // 1
    println(int_to_str(a[0]))                   // 1
    println(int_to_str(bin_search(a, 7, 7)))    // 4
    println(int_to_str(bin_search(a, 7, 100)))  // -1
    int b[5] = {5, 4, 3, 2, 1}
    sort_insertion(b, 5)
    println(int_to_str(b[0]))                   // 1
    return 0
}

stat ​

面向 int 数组的顺序统计量库(中位数/众数/百分位/直方图)与免排序的聚合量。 与 codecin/lib/vec/src/vec.cin(浮点统计)互补。需要升序输入的接口以 _sorted 结尾。

cin
import "stat.cin"
函数名签名返回值说明与边界行为
stat_sumstat_sum(int[] a, int n)int求和
stat_minstat_min(int[] a, int n)int最小值;n <= 0 返回 0
stat_maxstat_max(int[] a, int n)int最大值;n <= 0 返回 0
stat_rangestat_range(int[] a, int n)int极差 max - min;n <= 0 返回 0
stat_meanstat_mean(int[] a, int n)int整数均值,idiv 向零截断;n <= 0 返回 0
stat_countstat_count(int[] a, int n, int v)int等于 v 的元素个数
stat_median_sortedstat_median_sorted(int[] a, int n)int中位数,要求已升序;偶数个取中间两个的截断平均;n <= 0 返回 0
stat_modestat_mode(int[] a, int n)int众数(出现次数最多的值);并列时取较小值;O(n^2),无需排序;n <= 0 返回 0
stat_percentile_sortedstat_percentile_sorted(int[] a, int n, int p)int最近秩百分位,要求已升序,p 属于 0..100;p <= 0 返回 a[0],p >= 100 返回 a[n-1];内部秩为 ceil(n*p/100) 且至少为 1
stat_q1_sortedstat_q1_sorted(int[] a, int n)int下四分位,即 stat_percentile_sorted(a, n, 25);要求已升序
stat_q3_sortedstat_q3_sorted(int[] a, int n)int上四分位,即 stat_percentile_sorted(a, n, 75);要求已升序
stat_histogramstat_histogram(int[] a, int n, int[] hist, int bins)void直方图:先把 hist[0..bins-1] 清零,再把落在 [0, bins-1] 的值计数;负值与越界值被忽略
stat_variance_x1000stat_variance_x1000(int[] a, int n)int方差 ×1000(整数化,便于断言);公式 (n*sum(x^2) - sum(x)^2) / n^2 再乘 1000;n <= 0 返回 0
stat_stdev_x100stat_stdev_x100(int[] a, int n)int标准差 ×100(整数化),实现为 stat_variance_x1000(a, n) / 10
stat_is_sortedstat_is_sorted(int[] a, int n)int升序判定,1/0(与 sort_is_sorted 同语义)
cin
import "stat.cin"

function main() -> int {
    int a[6] = {4, 8, 1, 8, 3, 6}
    println(int_to_str(stat_sum(a, 6)))        // 30
    println(int_to_str(stat_mean(a, 6)))       // 5
    println(int_to_str(stat_mode(a, 6)))       // 8
    println(int_to_str(stat_variance_x1000(a, 6)))  // 6666
    int s[6] = {1, 3, 4, 6, 8, 8}
    println(int_to_str(stat_median_sorted(s, 6)))   // 5
    println(int_to_str(stat_q1_sorted(s, 6)))       // 3
    int h[10]
    stat_histogram(a, 6, h, 10)
    println(int_to_str(h[8]))                  // 2
    return 0
}

str ​

字符串变换库。依赖内建 upper / lower / substr / indexof / strlen / strcmp。 这些函数分配新堆块,大量循环拼接会消耗堆(64 位槽,不回收),长循环里请尽量减少拼接次数。

cin
import "str.cin"
函数名签名返回值说明与边界行为
s_uppers_upper(string s)string转大写,转调内建 upper
s_lowers_lower(string s)string转小写,转调内建 lower
s_containss_contains(string hay, string needle)int是否包含子串,1/0;空 needle 恒为 1
s_starts_withs_starts_with(string s, string prefix)int是否以 prefix 开头(indexof == 0);空 prefix 为 1
s_ends_withs_ends_with(string s, string suffix)int是否以 suffix 结尾;strlen(suffix) > strlen(s) 返回 0,空 suffix 为 1
s_counts_count(string hay, string needle)int不重叠出现次数(如 s_count("aaa","aa") 为 1);needle 为空串返回 0
s_repeats_repeat(string ch, int n)string把 ch 重复 n 次;n <= 0 返回空串。参数名是 ch 但可传任意字符串
cin
import "str.cin"

function main() -> int {
    println(s_upper("aBcDe"))                      // ABCDE
    println(s_lower("HeLLo"))                      // hello
    println(int_to_str(s_contains("banana", "nan")))    // 1
    println(int_to_str(s_starts_with("readme.txt", "read")))  // 1
    println(int_to_str(s_ends_with("readme.txt", ".txt")))    // 1
    println(int_to_str(s_count("aaa", "aa")))      // 1
    println(s_repeat("ab", 3))                     // ababab
    return 0
}

termux ​

Termux API 便捷封装库。内部 import "json.cin",并转调 termux_available / termux_notify / termux_clipboard_* / termux_battery / termux_location / termux_wifi_info 等宿主能力内建。 需要 termux-api 命令 + Termux:API 应用;非 Termux 环境下调用返回 -1 或空串。

cin
import "termux.cin"
函数名签名返回值说明与边界行为
tx_oktx_ok()intTermux API 是否可用,1/0;非 Termux 环境返回 0
tx_notifytx_notify(string title, string content)int发送系统通知
tx_toasttx_toast(string msg)int弹出 Toast
tx_copytx_copy(string s)int写入剪贴板
tx_pastetx_paste()string读取剪贴板;不可用时为空串
tx_vibratetx_vibrate(int ms)int振动 ms 毫秒
tx_saytx_say(string text)int文字转语音
tx_smstx_sms(string number, string text)int发送短信
tx_battery_jsontx_battery_json()string电池状态原始 JSON;不可用时为空串
tx_battery_leveltx_battery_level()int电池百分比;JSON 为空返回 -1,解析失败经 j_int 得 0
tx_battery_temptx_battery_temp()float电池温度;不可用返回 -1.0
tx_battery_pluggedtx_battery_plugged()int是否充电中,1/0;plugged 为 UNPLUGGED 或字段为空时 0
tx_location_jsontx_location_json()string定位原始 JSON
tx_latitudetx_latitude()float定位纬度;不可用为 0.0
tx_longitudetx_longitude()float定位经度;不可用为 0.0
tx_wifi_jsontx_wifi_json()stringWiFi 连接信息原始 JSON
tx_wifi_ssidtx_wifi_ssid()string当前 WiFi SSID;不可用为空串
tx_prompttx_prompt(string title)string弹出输入对话框并返回用户输入文本;不可用为空串
tx_alerttx_alert(string title, string content)int组合动作:通知 + 振动 200ms,返回通知的返回值
cin
import "termux.cin"

function main() -> int {
    if (tx_ok() == 0) {
        println("not termux")              // 非 Termux 环境
        return 0
    }
    tx_alert("Code CIN", "构建完成")        // 通知 + 振动
    println(int_to_str(tx_battery_level())) // 0..100
    println(float_to_str(tx_battery_temp()))
    println(int_to_str(tx_battery_plugged()))  // 1/0
    tx_toast("hello")
    return 0
}

test ​

轻量测试断言库。提供计数器(全局 T_PASS / T_FAIL)与断言;结束时调用 t_report() 输出汇总并返回失败数,因此可直接 return t_report() 作为 main 的退出码。

cin
import "test.cin"
函数名签名返回值说明与边界行为
t_eq_intt_eq_int(int got, int want, string label)int断言两整数相等;通过返回 1,失败打印 FAIL label: got=.. want=.. 并返回 0
t_eq_strt_eq_str(string got, string want, string label)int断言两字符串相等(strcmp);失败打印 got=[..] want=[..]
t_neart_near(float got, float want, float eps, string label)int断言浮点近似相等,判据是绝对差 d <= eps(闭区间)
t_truet_true(int cond, string label)int断言 cond != 0;失败打印 condition false
t_falset_false(int cond, string label)int断言 cond == 0,实现为 t_true(cond == 0, label)
t_resett_reset()void把 T_PASS / T_FAIL 归零
t_reportt_report()int输出汇总:全通过打印 OK: N assertions passed,否则 FAILED: F of T;返回失败数 T_FAIL
cin
import "test.cin"
import "array.cin"

function main() -> int {
    t_reset()
    int a[4] = {4, 8, 1, 8}
    t_eq_int(a_sum(a, 4), 21, "a_sum")
    t_eq_str("a", "a", "strcmp")
    t_near(1.0, 1.0001, 0.01, "near")
    t_true(a_count(a, 4, 8) == 2, "count8")
    t_false(a_contains(a, 4, 99), "no99")
    return t_report()          // 全通过时返回 0
}

text ​

纯 CIN 文本处理库。比 str 更进一步的字符串操作:大小写无关比较、字节反转、全量/首次替换、区间编辑(切片 / 插入 / 删除)、首字母与标题化、大小写互换、词数统计。只依赖非宿主内建(strlen / substr / indexof / upper / lower / strcmp)。

下标与长度一律是字节语义(与 strlen / substr / s[i] 一致):非 ASCII 按 UTF-8 字节序列逐个处理,不做码点解码;大小写转换只折叠 ASCII 字母(a-z / A-Z),其余字节原样保留。

cin
import "text.cin"
函数名签名返回值说明与边界行为
txt_is_emptytxt_is_empty(string s)int字节长度为 0 返回 1;空白串不算空(全空白可用 txt_word_count(s) == 0),"" 为 1
txt_equals_ignore_casetxt_equals_ignore_case(string a, string b)intASCII 大小写无关的整串相等,1/0;长度不同直接为 0,非 ASCII 字节必须逐一相同(如 a[ 与 A{ 不相等)
txt_startswith_ignore_casetxt_startswith_ignore_case(string s, string p)ints 是否以 p 开头(ASCII 大小写无关),1/0;空 p 恒为 1,strlen(p) > strlen(s) 返回 0
txt_reversetxt_reverse(string s)string按字节反转;空串返回空串。非 ASCII 会被切成单字节片段(纯字节语义,不做码点反转)
txt_index_fromtxt_index_from(string hay, string needle, int from)int从字节下标 from(含)起找 needle 的首次出现,返回绝对字节下标;未找到 -1。from 越界裁剪到 [0, strlen(hay)];needle 为空串返回裁剪后的 from
txt_last_index_oftxt_last_index_of(string hay, string needle)int最后一次出现的字节下标(允许重叠匹配,txt_last_index_of("aaaa", "aa") 为 2);未找到 -1;空 needle 返回 strlen(hay)
txt_replacetxt_replace(string s, string from, string to)string全部替换,从左到右扫描且不重叠(txt_replace("aaa", "aa", "b") 为 "ba");from 为空串时原样返回 s(不做插入);无匹配时返回内容相同的副本
txt_replace_firsttxt_replace_first(string s, string from, string to)string只替换首次出现;from 为空串或无匹配时原样返回 s(无匹配返回同一指针)
txt_removetxt_remove(string s, string sub)string删除全部 sub(等价 txt_replace(s, sub, ""));sub 为空串时原样返回 s
txt_slicetxt_slice(string s, int start, int end)string左闭右开切片 [start, end),越界自动裁剪;end <= start、负数区间或空串都返回 ""
txt_inserttxt_insert(string s, int pos, string sub)string在字节下标 pos 处插入 sub;pos 裁剪到 [0, strlen(s)](超过末尾追加到末尾,负数当 0);sub 为空串返回原串副本
txt_delete_rangetxt_delete_range(string s, int pos, int len)string删除 [pos, pos+len);pos 裁剪到 [0, strlen(s)],len < 0 当 0,越过末尾自动缩短;越界/空串都不报错
txt_capitalizetxt_capitalize(string s)string首个 ASCII 字母大写、其余 ASCII 字母小写(Python str.capitalize 风格);前导非字母字节原样保留;完全没有 ASCII 字母时原样返回;"" 返回 ""
txt_titletxt_title(string s)string每个单词首个字节大写、其余小写;单词 = 连续的 ASCII 字母/数字,其余都是分隔符。因此 "abc3def" 为 "Abc3def"(与 Python str.title 的 "Abc3Def" 不同),"it's" 为 "It'S"
txt_word_counttxt_word_count(string s)int空白分隔的单词个数;连续空白算一个,忽略首尾,全空白为 0;空白 = 空格 / \t / \n / \r,非 ASCII 字节算词内字节
txt_swap_casetxt_swap_case(string s)stringASCII 大小写互换(a↔A),非 ASCII 字节原样保留;"" 返回 ""

内部辅助函数(txt_case_range / txt_match_at / txt_is_alpha_byte / txt_is_alnum_byte / txt_is_space_byte / txt_lower_byte)不是公开 API,后续版本可能调整。

堆与输入规模

字符串拼接与 substr 都新建堆块且不回收,txt_reverse / txt_swap_case / txt_title 逐段重建结果串,n 字节约需 O(n²) 字节堆。默认 1 GiB 内存下常规文本不会触顶;超长串请分块调用以避免 O(n²) 重组,或加 --mem-size,否则会报 Heap exhausted: need ...。

cin
import "text.cin"

function main() -> int {
    string raw = "  The quick brown fox  "
    string t = trim(raw)                                     // "The quick brown fox"
    println(txt_reverse("Code CIN"))                         // NIC edoC
    println(txt_replace(t, "quick", "slow"))                 // The slow brown fox
    println(txt_replace_first("banana", "na", "NA"))         // baNAna
    println(txt_remove("a-b-c", "-"))                        // abc
    println(int_to_str(txt_index_from(t, "brown", 0)))       // 10
    println(int_to_str(txt_last_index_of("banana", "na")))   // 4
    println(txt_slice(t, 4, 9))                              // quick
    println(txt_insert("CIN", 0, "Code "))                   // Code CIN
    println(txt_delete_range("Code CIN", 4, 4))              // Code
    println(txt_capitalize("hELLO wORLD"))                   // Hello world
    println(txt_title("tHE qUICK brown fox"))                // The Quick Brown Fox
    println(txt_swap_case("Hello, World!"))                  // hELLO, wORLD!
    println(int_to_str(txt_word_count(t)))                   // 4
    if (txt_equals_ignore_case("CIN", "cin") == 1) { println("case-insensitive equal") }
    if (txt_startswith_ignore_case("CodeCIN", "code") == 1) { println("prefix ok") }
    if (txt_is_empty("") == 1) { println("empty") }
    return 0
}

time ​

时间工具库。依赖内建 time() 取当前 Unix 时间戳(秒)。字符串化依赖 int_to_str / idiv。

cin
import "time.cin"
函数名签名返回值说明与边界行为
t_nowt_now()int当前 Unix 时间戳(秒),转调内建 time()
t_twot_two(int v)string两位左补零;负数先取绝对值,>= 100 时原样输出(不截断)
t_hmst_hms(int secs)string秒 → "HH:MM:SS";负数按绝对值处理,小时不封顶(>= 100 时输出三位)
t_mst_ms(int secs)string秒 → "MM:SS";负数按绝对值处理,分钟不封顶
t_breakdownt_breakdown(int secs, int[] out)void拆解为天/时/分/秒写入 4 元素数组 out[0..3];负秒按绝对值处理
t_humant_human(int secs)string人性化时长 "1d 2h 3m 4s",省略为 0 的高位单位(t_human(5) 为 "5s",t_human(90061) 为 "1d 1h 1m 1s")
cin
import "time.cin"

function main() -> int {
    println(t_hms(3661))              // 01:01:01
    println(t_ms(125))                // 02:05
    println(t_human(90061))           // 1d 1h 1m 1s
    println(t_human(5))               // 5s
    int parts[4]
    t_breakdown(90061, parts)
    println(int_to_str(parts[0]))     // 1 (天)
    println(t_two(7))                 // 07
    if (t_now() <= 0) { return 1 }    // 时间戳应为正
    return 0
}

token ​

纯 CIN 切分/分词库。CIN 没有字符串数组类型,所以本库不返回数组,而是提供「按序号取第 n 个 token」的 API:计数、取内容、取长度、查序号、取首/尾 token,以及按空白切分的便捷封装。只依赖非宿主内建(strlen / substr / strcmp);因为拿不到字符串数组,本库不提供 join。

切分语义(与 Go strings.Split 一致):delim 按整串匹配(多字符分隔符算一个整体,不是字符集合);保留空 token —— 连续分隔符之间、串首/串尾分隔符旁边都会产生空 token;空串切分后是 1 个空 token;delim 为空串时整个串是唯一 token。下标与长度一律是字节语义(与 strlen / substr / s[i] 一致),非 ASCII 按 UTF-8 字节序列处理,分隔符请用完整字符。

cin
import "token.cin"
函数名签名返回值说明与边界行为
tok_counttok_count(string s, string delim)inttoken 个数,保留空 token:tok_count("a,,b", ",") 为 3、tok_count(",a,", ",") 为 3、tok_count(",", ",") 为 2、tok_count("", ",") 为 1;delim 为空串时固定返回 1
tok_gettok_get(string s, string delim, int idx)string第 idx 个 token(新堆块);idx 越界或为负返回 ""(空 token 也返回 "");delim 为空串时只有 idx == 0 有效,返回整个 s
tok_lentok_len(string s, string delim, int idx)int第 idx 个 token 的字节长度(不分配堆块);越界或为负返回 -1(空 token 返回 0);delim 为空串时只有 idx == 0 有效,返回 strlen(s)
tok_findtok_find(string s, string delim, string t)int第一个内容与 t 逐字节相同(区分大小写)的 token 序号;未找到 -1;空 token 可以被 t = "" 命中
tok_firsttok_first(string s, string delim)string第一个 token,等价 tok_get(s, delim, 0);空串或 delim 为空串时返回整个 s
tok_lasttok_last(string s, string delim)string最后一个 token(可能是空 token,如 tok_last("a,b,", ",") 为 "");空串返回 "";delim 为空串时返回整个 s
tok_word_counttok_word_count(string s)int空白分隔的单词个数;连续空白算一个分隔符,忽略首尾空白,全空白/空串为 0;空白 = 空格 / \t / \n / \r
tok_word_gettok_word_get(string s, int idx)string第 idx 个空白分隔单词(新堆块);连续空白算一个分隔、忽略首尾空白、不产生空词;idx 越界或为负返回 ""

内部辅助函数(tok_match_at / tok_is_space_byte)不是公开 API,后续版本可能调整。

cin
import "token.cin"

function main() -> int {
    string csv = "ann,42,bob,7,"
    println(int_to_str(tok_count(csv, ",")))          // 5 (保留末尾空 token)
    println(tok_get(csv, ",", 3))                     // 7
    println(int_to_str(tok_len(csv, ",", 4)))         // 0
    println(int_to_str(tok_find(csv, ",", "bob")))    // 2
    println(tok_first(csv, ","))                      // ann
    println(tok_last(csv, ",") + "|")                 // | (末尾是空 token)
    println(tok_get(csv, ",", 9) + "|")               // | (越界返回空串)

    string line = "  one   two  three "
    println(int_to_str(tok_word_count(line)))         // 3
    println(tok_word_get(line, 1))                    // two
    return 0
}

tree ​

定长二叉搜索树库。纯 CIN 实现,不做动态内存分配:节点存放在库内全局数组 (tree_key[64] / tree_left[64] / tree_right[64])里,容量上限 TREE_CAP = 64, 因此同一程序内只有一份全局实例,需要多棵树请用 struct 自行封装。 不支持删除节点,所以节点一旦分配就始终有效,已有节点恰好是下标 0..tree_size()-1; 拒绝重复键,树中不含重复键。遍历结果为空格分隔的字符串,空树时为空串 ""。

cin
import "tree.cin"
函数名签名返回值说明与边界行为
tree_capacitytree_capacity()int固定返回 64(TREE_CAP)
tree_resettree_reset()void重置为空树(根下标与节点计数归零)
tree_cleartree_clear()void清空,等价于 tree_reset()
tree_sizetree_size()int当前节点个数;空树为 0
tree_is_emptytree_is_empty()int1 为空树,否则 0
tree_inserttree_insert(int k)int插入键 k;成功返回 1,键已存在或已达容量 64 时返回 0(不修改树)
tree_containstree_contains(int k)int是否含键 k,1/0;空树返回 0
tree_mintree_min()int最小键;空树返回 0
tree_maxtree_max()int最大键;空树返回 0
tree_heighttree_height()int高度,按节点数计(空树 0,只有根 1,退化成链时为 tree_size())
tree_count_leavestree_count_leaves()int叶子(无左子且无右子)个数;空树返回 0
tree_inorder_strtree_inorder_str()string中序遍历(即升序键序列),空格分隔;空树返回 ""
tree_preorder_strtree_preorder_str()string前序遍历(根-左-右),空格分隔;空树返回 ""
tree_postorder_strtree_postorder_str()string后序遍历(左-右-根),空格分隔;空树返回 ""
tree_new_nodetree_new_node(int k)int内部辅助:分配一个叶子节点,返回新下标;满时返回 -1,非稳定接口
cin
import "tree.cin"

function main() -> int {
    tree_reset()
    tree_insert(50)
    tree_insert(30)
    tree_insert(70)
    tree_insert(20)
    tree_insert(40)
    tree_insert(60)
    tree_insert(80)
    println("size = " + int_to_str(tree_size()))              // 7
    println("min/max = " + int_to_str(tree_min()) + " " + int_to_str(tree_max()))   // 20 80
    println("height = " + int_to_str(tree_height()))          // 3
    println("leaves = " + int_to_str(tree_count_leaves()))    // 4
    println("inorder = " + tree_inorder_str())                // 20 30 40 50 60 70 80
    println("preorder = " + tree_preorder_str())              // 50 30 20 40 70 60 80
    println("postorder = " + tree_postorder_str())            // 20 40 30 60 80 70 50
    println("contains 40 = " + int_to_str(tree_contains(40))) // 1
    println("contains 41 = " + int_to_str(tree_contains(41))) // 0
    println("dup insert 40 = " + int_to_str(tree_insert(40))) // 0 (重复键被拒绝)
    tree_clear()
    println("after clear: size = " + int_to_str(tree_size())
            + " min = " + int_to_str(tree_min())
            + " height = " + int_to_str(tree_height()))
    return 0
}

unionfind ​

并查集(不相交集合)库。纯 CIN 实现,不做动态内存分配:状态存放在库内全局数组 (uf_parent[64] / uf_rank_arr[64] / uf_sz[64])里,容量上限 UF_CAP = 64, 因此同一程序内只有一份全局实例,需要多个并查集请用 struct 自行封装。 合并策略是按秩合并 + 路径压缩,单次操作近似 O(α(n))。 元素编号为 0..uf_n-1;调用 uf_reset(n) 之前 uf_n = 0,此时所有编号都是非法的。 越界编号是“非法元素”:uf_find / uf_rank 返回 -1,uf_size 返回 0, uf_connected / uf_union 只要有一个非法就返回 0。

cin
import "unionfind.cin"
函数名签名返回值说明与边界行为
uf_capacityuf_capacity()int固定返回 64(UF_CAP)
uf_resetuf_reset(int n)void初始化 0..n-1,每个元素自成一个集合;n <= 0 钳制为 0,n > 64 钳制为 64
uf_countuf_count()int当前连通分量个数;未初始化时为 0
uf_finduf_find(int x)intx 所在集合的代表元(带路径压缩);x 越界返回 -1
uf_sizeuf_size(int x)intx 所在集合的元素个数;x 越界返回 0
uf_rankuf_rank(int x)intx 所在集合的秩(合并启发式用);x 越界返回 -1,合法根节点的秩可以是 0
uf_connecteduf_connected(int a, int b)inta、b 是否属于同一集合,1/0;任一编号越界返回 0
uf_unionuf_union(int a, int b)int合并 a、b 所在集合;真正合并返回 1,已在同一集合返回 0,任一编号越界返回 0
cin
import "unionfind.cin"

function main() -> int {
    uf_reset(6)
    println("count = " + int_to_str(uf_count()))                    // 6
    uf_union(0, 1)
    uf_union(1, 2)
    uf_union(3, 4)
    println("connected 0,2 = " + int_to_str(uf_connected(0, 2)))    // 1
    println("connected 0,3 = " + int_to_str(uf_connected(0, 3)))    // 0
    println("count = " + int_to_str(uf_count()))                    // 3
    println("size of 2 = " + int_to_str(uf_size(2)))                // 3
    println("rank of 0 = " + int_to_str(uf_rank(0)))                // 1
    println("union 2,4 = " + int_to_str(uf_union(2, 4)))            // 1
    println("count = " + int_to_str(uf_count()))                    // 2
    println("union 2,4 again = " + int_to_str(uf_union(2, 4)))      // 0 (已同集合)
    println("find 9 = " + int_to_str(uf_find(9)))                   // -1 (越界编号)
    return 0
}

validate ​

字符/字符串校验库。与 codecin/lib/str/src/str.cin 互补:str.cin 做变换(大小写/包含/重复), 本库做判定与安全解析(字符类别、整数字符串、标识符、限幅、带 fallback 的解析)。

cin
import "validate.cin"
函数名签名返回值说明与边界行为
val_is_digitval_is_digit(int c)int是否 0-9;参数是字符的字节值,如 '7' 或 s[i]
val_is_upperval_is_upper(int c)int是否 A-Z
val_is_lowerval_is_lower(int c)int是否 a-z
val_is_alphaval_is_alpha(int c)int是否字母(大小写任一)
val_is_alnumval_is_alnum(int c)int是否字母或数字;下划线 _ 不算
val_is_hexval_is_hex(int c)int是否十六进制数字符(0-9 a-f A-F)
val_is_spaceval_is_space(int c)int是否空白:空格、\t、\n、\r
val_is_intval_is_int(string s)int整数字符串:可选 +/-(后面必须至少有一位数字),其余全是数字;空串、"+"、"4a" 均为 0
val_is_floatval_is_float(string s)int浮点字符串:可选符号 + 数字 + 至多一个小数点,至少一位数字;"."、"1.2.3" 为 0;不校验指数形式
val_is_identval_is_ident(string s)int标识符:[A-Za-z_][A-Za-z0-9_]*
val_count_charval_count_char(string s, int c)int字符 c 在 s 中出现的次数(同样传字节值)
val_is_blankval_is_blank(string s)int整个串是否全为空白(含空串为 1)
val_clamp_intval_clamp_int(int v, int lo, int hi)int限幅到 [lo, hi];lo > hi 时原样返回 v(与 i_clamp 的取舍不同)
val_parse_intval_parse_int(string s, int fallback)int安全解析:val_is_int 不通过时返回 fallback,否则 atoi(s)
val_is_hex_colorval_is_hex_color(string s)int是否 3 位或 6 位十六进制颜色,可带 #:"#ABC" / "A1B2C3" 通过,"#AB" / "#XYZ" 不通过
cin
import "validate.cin"

function main() -> int {
    println(int_to_str(val_is_digit('7')))          // 1
    println(int_to_str(val_is_int("-42")))          // 1
    println(int_to_str(val_is_int("4a")))           // 0
    println(int_to_str(val_is_float("3.14")))       // 1
    println(int_to_str(val_is_float("1.2.3")))      // 0
    println(int_to_str(val_is_ident("_x1")))        // 1
    println(int_to_str(val_parse_int("x", -1)))     // -1
    println(int_to_str(val_clamp_int(15, 0, 10)))   // 10
    println(int_to_str(val_is_hex_color("#A1B2C3")))// 1
    return 0
}

vec ​

浮点向量与统计库。与 codecin/lib/stat/src/stat.cin(整数顺序统计)互补;v_var / v_std 是 样本方差与样本标准差(除以 n-1),v_normalize 是原地操作。

cin
import "vec.cin"
函数名签名返回值说明与边界行为
v_sumv_sum(float[] a, int n)float求和;n <= 0 返回 0.0
v_meanv_mean(float[] a, int n)float均值;n <= 0 返回 0.0
v_varv_var(float[] a, int n)float样本方差(除以 n-1);n <= 1 返回 0.0
v_stdv_std(float[] a, int n)float样本标准差 sqrt(v_var(a, n))
v_dotv_dot(float[] a, float[] b, int n)float点积;两个数组都按前 n 个元素访问
v_minv_min(float[] a, int n)float最小值;n <= 0 返回 0.0
v_maxv_max(float[] a, int n)float最大值;n <= 0 返回 0.0
v_addv_add(float[] a, float[] b, float[] dst, int n)void逐元素相加写入 dst
v_scalev_scale(float[] a, float k, float[] dst, int n)void逐元素乘标量写入 dst;标量参数是 float
v_normalizev_normalize(float[] a, int n)void原地按 min/max 归一化到 [0, 1];span == 0 时全置 0.0;n <= 0 直接返回
v_normv_norm(float[] a, int n)float欧几里得范数 sqrt(v_dot(a, a, n))
v_lerpv_lerp(float a, float b, float t)float线性插值 a + (b - a) * t;t 不限制在 [0,1](可外插)
cin
import "vec.cin"

function main() -> int {
    float v[5] = {2.0, 4.0, 4.0, 4.0, 6.0}
    println(float_to_str(v_sum(v, 5)))    // 20
    println(float_to_str(v_mean(v, 5)))   // 4
    println(float_to_str(v_dot(v, v, 5))) // 88
    println(float_to_str(v_norm(v, 5)))   // 9.38083151964686 (sqrt(88))
    println(float_to_str(v_lerp(0.0, 10.0, 0.25)))  // 2.5
    v_normalize(v, 5)
    println(float_to_str(v[0]))           // 0
    println(float_to_str(v[4]))           // 1
    return 0
}

相关页面 ​

文档由 VitePress 构建