Java8 将条件表达式表示为方法引用数组

Java8 expressing conditionals as an array of method reference

我代表了大量对象(特别是 MIPS32 指令)。我的最小工作示例将描述 R 格式的指令。

MIPS32背景(R型指令)

R型指令由组合唯一确定 它的操作码及其 funct (function) 字段。操作码是 当表示为 32 位时,指令最左边的 6 位 数字和最右边的 6 位组成 funct 字段。

R 型指令的常见分解是位域 长度(6、5、5、5、5、6)。然后位域代表 以下单位

--------------------------------------------------------
| 6 bits  | 5 bits | 5 bits | 5 bits | 5 bits | 6 bits |
|:-------:|:------:|:------:|:------:|:------:|:------:|
| op      | rs     | rt     | rd     | shamt  | funct  |
--------------------------------------------------------

因此,R 类指令的唯一标识符(键) 是具有一对一关系的元组 (opcode, funct) 使用 R 型指令

示例:mul

考虑 32 位数 0x71014802分解 根据 format 的不同长度的字段 说明。

对于 MIPS32 指令中的所有数字,设置最左边的六位 始终表示指令的操作码。单独的操作码是 并不总是足以识别特定指令, 但是 识别格式总是足够的 说明。

0x71014802最左边的六位是0x1c。这是 已知这个数字对应于 R格式。格式指定剩余位到哪些字段 分解成.

如前所述,所有指令可能无法被识别 他们的操作码。这适用于所有 R 型指令。

正在将 0x71014802 分解为中所示的字段 上述 table 产生 rs=8rt=1rd=9shamt=0funct=2。该指令的分解十六进制表示 因此,形式是 [0x1c 8 1 9 0 2]。相应的 十进制表示法[28 8 1 9 0 2].

识别由 0x71014802 funct 字段必须是 咨询过。将操作码 0x1c 和中的值配对 funct字段唯一标识指令a mul 说明。


在我的源代码中,我用以下方式表示 mul 指令

/**
 * Multiply (without overflow). Put the low-order 32 bits of
 * the product of rs and rt into register rd.
 */
// TODO: Validate that shamt is 0
MUL(0x1c, 2, R::rd, R::rs, R::rt),

方法引用 R::rd, R::rs, R::rt 用于通过从分解的表示中获取适当的字段并在 table 中查找寄存器名称来创建指令的人类可读表示(这是对我们来说并不重要,但它解释了为什么它在那里。

TODO 注释表示这些对象还应满足 0 个或多个条件才能被视为有效。如您所见,我们在一个地方存储了很多关于 MUL 的信息,它的操作码和唯一标识它的功能字段以及如何生成人类可读的表示形式。

剩下的就是包含验证步骤。

在Python我会用字典。

{'shamt': 0, 
 other conditions
}

我稍后会解析。

在 Java 中,我要么必须有一个静态初始化的 HashMap 来表示这个,或者可以想象一个二维数组 (Object[][]) 可以服务然后做一些内部解析和评估。 根据我的说法,Java 的冗长会使意图更难理解。

我想表达的是以某种方式声明当使用特定参数调用特定函数时我希望它 return true

我希望所有这些条件的计算结果都为 true,所以我可以稍后再对它们进行计算。

所以我在考虑某种形式的偏应用,假设我有一个函数

shamt(int expectedValue) {
    // Check that the value of shamt matched the expected value
}

然后类似于

new Supplier<Boolean>[] {
    0x00 -> RTypeInstruction::shamt
}

这显然行不通,但方向可能是正确的。 在这里以某种方式命名引用很重要,因为指定整数之间的排序关系是不够的,因为这不会给出任何关于哪个位域必须满足特定条件的指示。

我不希望有一个数组为每个位域指定一个条件,因为条件很少会影响一个或两个以上的位域,但它确实会发生。

可以说识别步骤(操作码、函数)也是条件,但这使得很难区分指令识别失败和指令只是半有效。这意味着即使 shamt 为非零,我们也希望能够将指令识别为 mul 指令,并通知用户输入有些格式错误(半有效)。

shamt 方法可以操作的值存储在 enum 内部。没有指定过多方法的原因是

boolean shamtIsZero() { ... }

因为有很多不同的条件。见后面的例子。 Java 是不是太不适合这个了?我应该改用 HashMap 并对其进行评估,还是周围有一些简洁的 FunctionalInterface 可以帮助我做到这一点?


示例:mtc1

还有一条指令,mtc1 由操作码 0x11 标识,功能字段设置为 0x00

/**
 * Move to coprocessor 0, move CPU register rt to register
 * fs in the FPU. fs occupies the rd field. Note the pattern that
 * the MTC and MTF operations share the same opcode and funct
 * field. The rs field distinguishes them.
 */
// TODO: Validate that rs = 4 and funct and shamt = 0
MTC1(0x11, 0x00, R::rt, R::fs)

正如您在这里看到的那样,我们必须满足几个条件,其中一个位域必须是 0 以外的值。正因为这个原因,我们不想像它们那样为每个条件使用单独的方法变得无数。

您可以在构造函数中传递多个条件 - 您甚至可以使它们 Predicates:

enum MIPS32Instructions {

    MUL("MUL", (v) -> v > 0),
    DIV("DIV", (v) -> v > 1, (v) -> v != 9);
    final String id;
    final Predicate<Integer>[] conditions;

    MIPS32Instructions(String id, Predicate<Integer>... conditions) {
        this.id = id;
        this.conditions = conditions;
    }

    public boolean checkConditions(int v) {
        return Arrays.stream(conditions)
                .allMatch((c) -> c.test(v));
    }

}