diff --git a/lfs.c b/lfs.c index ce317787..acfb3d1e 100644 --- a/lfs.c +++ b/lfs.c @@ -1335,18 +1335,18 @@ static void lfs_rbyd_p_red( } else if (lfs_rtag_isparallel(p_alts[0], p_alts[2])) { lfs_rtag_t alt_ = p_alts[1]; lfs_off_t jump_ = p_jumps[1]; - p_alts[1] = p_alts[0]; + p_alts[1] = lfs_rtag_red(p_alts[0]); p_jumps[1] = p_jumps[0]; - p_alts[0] = alt_; + p_alts[0] = lfs_rtag_black(alt_); p_jumps[0] = jump_; } else if (lfs_rtag_isparallel(p_alts[0], p_alts[1])) { lfs_rtag_t alt_ = p_alts[2]; lfs_off_t jump_ = p_jumps[2]; - p_alts[2] = p_alts[1]; + p_alts[2] = lfs_rtag_red(p_alts[1]); p_jumps[2] = p_jumps[1]; - p_alts[1] = p_alts[0]; + p_alts[1] = lfs_rtag_red(p_alts[0]); p_jumps[1] = p_jumps[0]; - p_alts[0] = alt_; + p_alts[0] = lfs_rtag_black(alt_); p_jumps[0] = jump_; } else { LFS_ASSERT(false); @@ -1540,20 +1540,19 @@ static int lfs_rbyd_commit(lfs_t *lfs, lfs_rbyd_t *rbyd, if (tag_ != attr->tag) { // bias the weights so that lookups always find the // next biggest tag - lfs_rtag_t alt_; if (lfs_rtag_weight(tag_) < lfs_rtag_weight(attr->tag)) { - alt_ = LFS_MKRALT(B, LT, lt+1 + alt = LFS_MKRALT(B, LT, lt+1 + lfs_rtag_weight(tag_) - lfs_rtag_weight(attr->tag)); } else { - alt_ = LFS_MKRALT(B, GT, gt); + alt = LFS_MKRALT(B, GT, gt); } lfs_ssize_t delta = lfs_rbyd_p_push(lfs, &lfs->pcache, &lfs->rcache, block, off, p_alts, p_jumps, - alt_, branch, &crc); + alt, branch, &crc); if (delta < 0) { return delta; } diff --git a/tests/test_rbyd.toml b/tests/test_rbyd.toml index 06827bbe..034cbba7 100644 --- a/tests/test_rbyd.toml +++ b/tests/test_rbyd.toml @@ -1405,3 +1405,84 @@ code = ''' lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 6, 0), &off, &size) => LFS_MKRTAG(UATTR, 6, 0); ''' + +[cases.test_rbyd_permutations] +defines.N = 'range(1, 8)' +in = 'lfs.c' +code = ''' + lfs_t lfs; + lfs_init(&lfs, cfg) => 0; + + lfs_rbyd_t rbyd_init = { + .block = 0, + .trunk = 0, + .noff = 0, + .rev = 1, + .crc = 0, + .count = 0, + .erased = true, + }; + lfs_rbyd_t rbyd; + lfs_off_t off; + lfs_size_t size; + + // test all permutations of a given size + uint8_t perm[N]; + uint8_t stack[N]; + for (uint8_t i = 0; i < N; i++) { + perm[i] = i; + stack[i] = 0; + } + + uint8_t i = 1; + while (i < N) { + // print permutation to help debugging + printf("--- permutation: ["); + for (int j = 0; j < N; j++) { + if (j > 0) { + printf(", "); + } + printf("%d", perm[j]+1); + } + printf("] ---\n"); + + // build the attribute list for the current permutation + struct lfs_rattr attrs[N]; + for (int j = 0; j < N; j++) { + attrs[j] = *LFS_MKRATTR( + UATTR, perm[j]+1, 0, + &(uint32_t){0xaaaaaaaa}, 4, + (j+1 < N) ? &attrs[j+1] : NULL); + } + + // test the given permutation + rbyd = rbyd_init; + lfs_bd_erase(&lfs, rbyd.block) => 0; + lfs_rbyd_commit(&lfs, &rbyd, attrs) => 0; + + lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; + for (int j = 0; j < N; j++) { + lfs_rbyd_lookup(&lfs, &rbyd, + LFS_MKRTAG(UATTR, j+1, 0), &off, &size) + => LFS_MKRTAG(UATTR, j+1, 0); + } + + // next permutation using Heap's algorithm + if (stack[i] < i) { + if (i % 2 == 0) { + uint8_t t = perm[0]; + perm[0] = perm[i]; + perm[i] = t; + } else { + uint8_t t = perm[stack[i]]; + perm[stack[i]] = perm[i]; + perm[i] = t; + } + stack[i] += 1; + i = 1; + } else { + stack[i] = 0; + i += 1; + } + } +'''