SuperAPI AI 工具集

bitmask-event-wrapper

编程与开发

查看项目

更新于 10-17 16:16

技能介绍

用途

bitmask-event-wrapper 用于包装由底层(如播放器、权限系统、变更通知回调)向上传递的单个整数标志位集合。该整数每一位代表一种含义,若直接暴露原始整数,每个调用点都需要手写掩码,容易以不同方式出错。包装器本身足够小,可以做到显而易见地正确。

主要能力

包装器是一个单字段 value class,提供以下方法:

@JvmInline
value class EventSet(val flags: Int) {
    fun contains(event: Int): Boolean = flags and event != 0
    fun containsAny(vararg events: Int): Boolean = events.any { flags and it != 0 }
    fun containsAll(mask: Int): Boolean = flags and mask == mask
}

其核心价值有两点:调用点读起来像一个问题而非表达式,从而避免复制粘贴时遗漏 != 0;类型是独立的,接受 EventSet 的函数无法被传入位置、时长或状态常量,而接受 Int 的函数会静默接受。

使用方式

应保持其为 value class 而非 data class。围绕单个整数的 data class 会为每个交付的事件分配对象,而热回调上的事件会持续到达。单字段 value class 在常见情况下运行时表示为裸整数,但存在例外:当用作可空类型、泛型类型参数或通过接口使用时会被装箱。监听器签名 onEvents(events: EventSet) 保持不装箱,而 onEvents(events: EventSet?) 则不会。

适用场景

适用于底层以打包整数形式交付事件标志位、且上层需要以语义化方式查询位是否存在的场景。

限制与陷阱

  • and != 0 表示“任意这些位”,而非“全部”。若问题是“两者是否都发生”,应使用 flags and mask == mask。
  • 与掩码的相等比较询问的是第三种问题,几乎从不是想要的。flags == EVENT_A or EVENT_B 仅当没有其他位被设置时为真,底层一旦添加新标志位就会失效。修复方式是掩码,而非更长的相等比较。
  • 常量必须与包装器一起传递,但需先读取其值。若上游值确实是单个位,应在同一提交中于包装器旁定义为 1 shl n,绝不能将序数复制到标志位位置。若它们是序数,则没有打包整数可包装,包装器不应存在。
  • 来自相邻集合的常量会被接受并静默给出无意义结果。应为标志位赋予自己的类型,或至少将标志位与枚举分开声明,且名称不要相似。
  • 移位距离按宽度取模,超出末尾的标志位会静默别名到标志零。Int 的硬上限是 32 个标志位,应在达到之前迁移到 Long。
  • 有符号整数的最高位为负,掩码操作正常,但排序、十进制打印或带范围检查的存储会表现异常。调试时以十六进制或二进制打印标志位集合。
  • vararg 谓词每次调用都会分配数组。应提供掩码重载并在热路径上优先使用:fun containsAny(mask: Int): Boolean = flags and mask != 0。
  • 包装器不应增长解释逻辑。添加 isImportant() 或 shouldRefresh() 会将策略移入一个其全部价值在于机械性的类型。

验证方式

确认包装器确实被使用,可通过 grep 类型在构造和类型位置的出现,而非方法名。查找绕过它的原始位运算测试,查找与标志常量的相等比较,确认其为 value class,并检查标志常量与普通枚举不在同一对象中。