Code to support the combination kind of value constructor.


§1. Block Format. A combination is like a list, but simpler; it has a fixed, usually short, size. On the other hand, its entries are not all of the same kind as each other.

The short block for a combination is simply a pointer to the long block. This consists of one word to hold the strong kind ID, and then one word for each entry in the combination. Thus, a triple combination uses 4 words.

Constant COMBINATION_KIND_F = 0;    Strong kind ID
Constant COMBINATION_ITEM_BASE = 1; List items begin at this entry

§2. Creation. A combination is like a list, but simpler; it has a fixed, usually short, size. On the other hand, its entries are not all of the same kind as each other.

Combinations are stored as a fixed-sized block of word entries. The first block is the only header information: a pointer to a further structure in memory, describing the kind. The subsequent blocks are the actual records. Thus, a triple \((x, y, z)\) uses 4 words.

[ COMBINATION_TY_Create kind sb_address
    short_block long_block N i bk v;
    N = KindConstructorArity(kind);
    long_block = CreatePVLongBlockFlexible(COMBINATION_TY, COMBINATION_ITEM_BASE + N);
    InitialisePVLongBlockField(long_block, COMBINATION_KIND_F, kind);
    for (i=0: i<N: i++) {
        bk = KindConstructorTerm(kind, i);
        if (KindConformsTo_POINTER_VALUE_TY(bk)) v = CreatePV(bk);
        else v = KindDefaultValue(bk);
        InitialisePVLongBlockField(long_block, COMBINATION_ITEM_BASE+i, v);
    }

    short_block = CreatePVShortBlock(sb_address, kind);
    short_block-->0 = long_block;

    return short_block;
];

§3. Destruction. If the comb items are themselves block-values, they must all be freed before the comb itself can be freed.

[ COMBINATION_TY_Destroy comb kind no_items i bk;
    kind = PVField(comb, COMBINATION_KIND_F);
    no_items = KindConstructorArity(kind);
    for (i=0: i<no_items: i++) {
        bk = KindConstructorTerm(kind, i);
        if (KindConformsTo_POINTER_VALUE_TY(bk))
            DestroyPV(PVField(comb, i+COMBINATION_ITEM_BASE));
    }
];

§4. Copying. Again, if the comb contains block-values then they must be duplicated rather than bitwise copied as pointers.

[ COMBINATION_TY_Copy to_comb from_comb kind recycling
    precopied_comb_kov no_items i nv kind bk;
    precopied_comb_kov = PVField(to_comb, COMBINATION_KIND_F);
    CopyPVRawData(to_comb, from_comb, kind, recycling);
    no_items = KindConstructorArity(precopied_comb_kov);
    WritePVField(to_comb, COMBINATION_KIND_F, precopied_comb_kov);
    for (i=0: i<no_items: i++) {
        bk = KindConstructorTerm(kind, i);
        if (KindConformsTo_POINTER_VALUE_TY(bk)) {
            nv = CreatePV(bk);
            CopyPV(nv, PVField(from_comb, i+COMBINATION_ITEM_BASE));
            WritePVField(to_comb, i+COMBINATION_ITEM_BASE, nv);
        }
    }
];

§5. Comparison. This is a lexicographic comparison and assumes both combinations have the same kind.

[ COMBINATION_TY_Compare left_comb right_comb delta no_items i cf kind bk;
    kind = PVField(left_comb, COMBINATION_KIND_F);
    no_items = KindConstructorArity(kind);
    for (i=0: i<no_items: i++) {
        bk = KindConstructorTerm(kind, i);
        cf = KindComparisonFunction(bk);
        if (cf == 0 or UnsignedCompare) {
            delta = PVField(left_comb, i+COMBINATION_ITEM_BASE) -
                PVField(right_comb, i+COMBINATION_ITEM_BASE);
            if (delta) return delta;
        } else {
            delta = cf(PVField(left_comb, i+COMBINATION_ITEM_BASE),
                PVField(right_comb, i+COMBINATION_ITEM_BASE));
            if (delta) return delta;
        }
    }
    return 0;
];

[ COMBINATION_TY_Distinguish left_comb right_comb;
    if (COMBINATION_TY_Compare(left_comb, right_comb) == 0) rfalse;
    rtrue;
];

§6. Hashing.

[ COMBINATION_TY_Hash comb  kind rv no_items i bk;
    rv = 0;
    kind = PVField(comb, COMBINATION_KIND_F);
    no_items = KindConstructorArity(kind);
    for (i=0: i<no_items: i++) {
        bk = KindConstructorTerm(kind, i);
        rv = rv * 33 + HashKindValuePair(bk, PVField(comb, i+COMBINATION_ITEM_BASE));
    }
    return rv;
];

§7. Printing.

[ COMBINATION_TY_Say comb format no_items v i kind bk;
    if (WeakKindOfPV(comb) ~= COMBINATION_TY) return;
    kind = PVField(comb, COMBINATION_KIND_F);
    no_items = KindConstructorArity(kind);
    print "(";
    for (i=0: i<no_items: i++) {
        if (i>0) print ", ";
        bk = KindConstructorTerm(kind, i);
        v = PVField(comb, i+COMBINATION_ITEM_BASE);
        if (bk == LIST_OF_TY) LIST_OF_TY_Say(v, 1);
        else SayKindValuePair(bk, v);
    }
    print ")";
];