Fixed issue where looking up tag 0 fails after a delete id0
Well not really fixed, more just added an assert to make sure lfsr_rbyd_lookup is not called with tag 0. Because our alt tags only encode less-than-or-equal and greater-than, which can be flipped trivially, it's not possible to encode removal of tag 0 during deletes. Fortunately, this tag should already not exist for other pragmatic reasons, it was just used as the initial value for traversals, where it could cause this bug.
This commit is contained in:
@@ -1737,6 +1737,10 @@ static int lfsr_rbyd_fetch(lfs_t *lfs, lfsr_rbyd_t *rbyd,
|
|||||||
static int lfsr_rbyd_lookup(lfs_t *lfs, const lfsr_rbyd_t *rbyd,
|
static int lfsr_rbyd_lookup(lfs_t *lfs, const lfsr_rbyd_t *rbyd,
|
||||||
lfsr_tag_t tag, lfsr_sid_t id,
|
lfsr_tag_t tag, lfsr_sid_t id,
|
||||||
lfsr_tag_t *tag_, lfsr_sid_t *id_, lfs_off_t *off_, lfs_size_t *size_) {
|
lfsr_tag_t *tag_, lfsr_sid_t *id_, lfs_off_t *off_, lfs_size_t *size_) {
|
||||||
|
// tag must be non-zero! zero tags may deceptively look like they work but
|
||||||
|
// fail when the tree contains a deleted id0
|
||||||
|
LFS_ASSERT(tag != 0);
|
||||||
|
|
||||||
// no trunk yet?
|
// no trunk yet?
|
||||||
lfs_off_t branch = rbyd->trunk;
|
lfs_off_t branch = rbyd->trunk;
|
||||||
if (!branch) {
|
if (!branch) {
|
||||||
|
|||||||
+11
-14
@@ -330,7 +330,7 @@ def show_tree(block_size, data, rev, trunk, weight, *,
|
|||||||
while True:
|
while True:
|
||||||
_, alt, weight_, jump, delta = fromtag(data[j:])
|
_, alt, weight_, jump, delta = fromtag(data[j:])
|
||||||
|
|
||||||
# founat alt?
|
# found an alt?
|
||||||
if alt & 0x8:
|
if alt & 0x8:
|
||||||
weight_ += 1
|
weight_ += 1
|
||||||
# follow?
|
# follow?
|
||||||
@@ -371,22 +371,22 @@ def show_tree(block_size, data, rev, trunk, weight, *,
|
|||||||
else:
|
else:
|
||||||
tag_ = alt
|
tag_ = alt
|
||||||
id_ = upper-1
|
id_ = upper-1
|
||||||
return tag_, id_, j, delta, jump, path
|
|
||||||
|
done = (id_, tag_) < (id, tag) or tag_ & 2
|
||||||
|
|
||||||
|
return done, tag_, id_, j, delta, jump, path
|
||||||
|
|
||||||
# precompute tree
|
# precompute tree
|
||||||
if args.get('tree'):
|
if args.get('tree'):
|
||||||
tags = []
|
tags = []
|
||||||
paths = {}
|
paths = {}
|
||||||
|
|
||||||
tag_ = 0
|
tag, id = 0, -1
|
||||||
id_ = -1
|
|
||||||
while True:
|
while True:
|
||||||
tag, id, j, delta, size, path = lookup(tag_, id_)
|
done, tag, id, j, delta, size, path = lookup(tag+0x10, id)
|
||||||
# found end of tree?
|
# found end of tree?
|
||||||
if (id, tag) < (id_, tag_) or tag & 2:
|
if done:
|
||||||
break
|
break
|
||||||
tag_ = tag + 0x10
|
|
||||||
id_ = id
|
|
||||||
|
|
||||||
tags.append((j, tag, id))
|
tags.append((j, tag, id))
|
||||||
for x, (a, b, c) in enumerate(path):
|
for x, (a, b, c) in enumerate(path):
|
||||||
@@ -478,15 +478,12 @@ def show_tree(block_size, data, rev, trunk, weight, *,
|
|||||||
'data (truncated)'
|
'data (truncated)'
|
||||||
if not args.get('no_truncate') else ''))
|
if not args.get('no_truncate') else ''))
|
||||||
|
|
||||||
tag_ = 0
|
tag, id = 0, -1
|
||||||
id_ = -1
|
|
||||||
while True:
|
while True:
|
||||||
tag, id, j, delta, size, path = lookup(tag_, id_)
|
done, tag, id, j, delta, size, path = lookup(tag+0x10, id)
|
||||||
# found end of tree?
|
# found end of tree?
|
||||||
if (id, tag) < (id_, tag_) or tag & 2:
|
if done:
|
||||||
break
|
break
|
||||||
tag_ = tag + 0x10
|
|
||||||
id_ = id
|
|
||||||
|
|
||||||
# show human-readable tag representation
|
# show human-readable tag representation
|
||||||
print('%08x:%s %-57s' % (
|
print('%08x:%s %-57s' % (
|
||||||
|
|||||||
+441
-24
@@ -2251,7 +2251,7 @@ code = '''
|
|||||||
LFSR_ATTR(UATTR(1), -1, "\xaa\xaa\xaa\xaa", 4,
|
LFSR_ATTR(UATTR(1), -1, "\xaa\xaa\xaa\xaa", 4,
|
||||||
LFSR_ATTR(UATTR(2), -1, "\xbb\xbb\xbb\xbb", 4, NULL))) => 0;
|
LFSR_ATTR(UATTR(2), -1, "\xbb\xbb\xbb\xbb", 4, NULL))) => 0;
|
||||||
|
|
||||||
lfsr_rbyd_lookup(&lfs, &rbyd, 0, -1,
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(0), -1,
|
||||||
&tag_, &id_, &off_, &size_) => 0;
|
&tag_, &id_, &off_, &size_) => 0;
|
||||||
assert(tag_ == LFSR_TAG_UATTR(1));
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
||||||
assert(id_ == -1);
|
assert(id_ == -1);
|
||||||
@@ -2265,7 +2265,7 @@ code = '''
|
|||||||
&tag_, &id_, &off_, &size_) => LFS_ERR_NOENT;
|
&tag_, &id_, &off_, &size_) => LFS_ERR_NOENT;
|
||||||
|
|
||||||
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
||||||
lfsr_rbyd_lookup(&lfs, &rbyd, 0, -1,
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(0), -1,
|
||||||
&tag_, &id_, &off_, &size_) => 0;
|
&tag_, &id_, &off_, &size_) => 0;
|
||||||
assert(tag_ == LFSR_TAG_UATTR(1));
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
||||||
assert(id_ == -1);
|
assert(id_ == -1);
|
||||||
@@ -2285,7 +2285,7 @@ code = '''
|
|||||||
LFSR_ATTR(UATTR(2), -1, "\xbb\xbb\xbb\xbb", 4,
|
LFSR_ATTR(UATTR(2), -1, "\xbb\xbb\xbb\xbb", 4,
|
||||||
LFSR_ATTR(UATTR(1), -1, "\xaa\xaa\xaa\xaa", 4, NULL))) => 0;
|
LFSR_ATTR(UATTR(1), -1, "\xaa\xaa\xaa\xaa", 4, NULL))) => 0;
|
||||||
|
|
||||||
lfsr_rbyd_lookup(&lfs, &rbyd, 0, -1,
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(0), -1,
|
||||||
&tag_, &id_, &off_, &size_) => 0;
|
&tag_, &id_, &off_, &size_) => 0;
|
||||||
assert(tag_ == LFSR_TAG_UATTR(1));
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
||||||
assert(id_ == -1);
|
assert(id_ == -1);
|
||||||
@@ -2299,7 +2299,7 @@ code = '''
|
|||||||
&tag_, &id_, &off_, &size_) => LFS_ERR_NOENT;
|
&tag_, &id_, &off_, &size_) => LFS_ERR_NOENT;
|
||||||
|
|
||||||
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
||||||
lfsr_rbyd_lookup(&lfs, &rbyd, 0, -1,
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(0), -1,
|
||||||
&tag_, &id_, &off_, &size_) => 0;
|
&tag_, &id_, &off_, &size_) => 0;
|
||||||
assert(tag_ == LFSR_TAG_UATTR(1));
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
||||||
assert(id_ == -1);
|
assert(id_ == -1);
|
||||||
@@ -2345,7 +2345,7 @@ code = '''
|
|||||||
lfsr_rbyd_commit(&lfs, &rbyd,
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
||||||
LFSR_ATTR(UATTR(2), -1, "\xbb\xbb\xbb\xbb", 4, NULL)) => 0;
|
LFSR_ATTR(UATTR(2), -1, "\xbb\xbb\xbb\xbb", 4, NULL)) => 0;
|
||||||
|
|
||||||
lfsr_rbyd_lookup(&lfs, &rbyd, 0, -1,
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(0), -1,
|
||||||
&tag_, &id_, &off_, &size_) => 0;
|
&tag_, &id_, &off_, &size_) => 0;
|
||||||
assert(tag_ == LFSR_TAG_UATTR(1));
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
||||||
assert(id_ == -1);
|
assert(id_ == -1);
|
||||||
@@ -2359,7 +2359,7 @@ code = '''
|
|||||||
&tag_, &id_, &off_, &size_) => LFS_ERR_NOENT;
|
&tag_, &id_, &off_, &size_) => LFS_ERR_NOENT;
|
||||||
|
|
||||||
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
||||||
lfsr_rbyd_lookup(&lfs, &rbyd, 0, -1,
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(0), -1,
|
||||||
&tag_, &id_, &off_, &size_) => 0;
|
&tag_, &id_, &off_, &size_) => 0;
|
||||||
assert(tag_ == LFSR_TAG_UATTR(1));
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
||||||
assert(id_ == -1);
|
assert(id_ == -1);
|
||||||
@@ -2380,7 +2380,7 @@ code = '''
|
|||||||
lfsr_rbyd_commit(&lfs, &rbyd,
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
||||||
LFSR_ATTR(UATTR(1), -1, "\xaa\xaa\xaa\xaa", 4, NULL)) => 0;
|
LFSR_ATTR(UATTR(1), -1, "\xaa\xaa\xaa\xaa", 4, NULL)) => 0;
|
||||||
|
|
||||||
lfsr_rbyd_lookup(&lfs, &rbyd, 0, -1,
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(0), -1,
|
||||||
&tag_, &id_, &off_, &size_) => 0;
|
&tag_, &id_, &off_, &size_) => 0;
|
||||||
assert(tag_ == LFSR_TAG_UATTR(1));
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
||||||
assert(id_ == -1);
|
assert(id_ == -1);
|
||||||
@@ -2394,7 +2394,7 @@ code = '''
|
|||||||
&tag_, &id_, &off_, &size_) => LFS_ERR_NOENT;
|
&tag_, &id_, &off_, &size_) => LFS_ERR_NOENT;
|
||||||
|
|
||||||
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
||||||
lfsr_rbyd_lookup(&lfs, &rbyd, 0, -1,
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(0), -1,
|
||||||
&tag_, &id_, &off_, &size_) => 0;
|
&tag_, &id_, &off_, &size_) => 0;
|
||||||
assert(tag_ == LFSR_TAG_UATTR(1));
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
||||||
assert(id_ == -1);
|
assert(id_ == -1);
|
||||||
@@ -3044,6 +3044,122 @@ code = '''
|
|||||||
}
|
}
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
[cases.test_rbyd_remove_traverse_permutations]
|
||||||
|
defines.N = 'range(1, 7)'
|
||||||
|
in = 'lfs.c'
|
||||||
|
if = 'BLOCK_SIZE/PROG_SIZE >= N+1'
|
||||||
|
code = '''
|
||||||
|
lfs_t lfs;
|
||||||
|
lfs_init(&lfs, cfg) => 0;
|
||||||
|
|
||||||
|
lfsr_rbyd_t init_rbyd = {
|
||||||
|
.block = 0,
|
||||||
|
.rev = 1,
|
||||||
|
.off = 0,
|
||||||
|
.crc = 0,
|
||||||
|
.trunk = 0,
|
||||||
|
.weight = 0,
|
||||||
|
.erased = true,
|
||||||
|
};
|
||||||
|
lfsr_rbyd_t rbyd;
|
||||||
|
lfsr_tag_t tag_;
|
||||||
|
lfsr_sid_t id_;
|
||||||
|
lfs_off_t off_;
|
||||||
|
lfs_size_t size_;
|
||||||
|
|
||||||
|
// test all permutations of a given size
|
||||||
|
uint8_t perm[N];
|
||||||
|
unsigned stack[N];
|
||||||
|
for (uint8_t i = 0; i < N; i++) {
|
||||||
|
perm[i] = i;
|
||||||
|
stack[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned i = 1;
|
||||||
|
while (i < N) {
|
||||||
|
// print permutation to help debugging
|
||||||
|
printf("--- permutation: [");
|
||||||
|
for (unsigned j = 0; j < N; j++) {
|
||||||
|
if (j > 0) {
|
||||||
|
printf(", ");
|
||||||
|
}
|
||||||
|
printf("%d", perm[j]+1);
|
||||||
|
}
|
||||||
|
printf("] ---\n");
|
||||||
|
|
||||||
|
// create given permutation with multiple commits
|
||||||
|
rbyd = init_rbyd;
|
||||||
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
||||||
|
for (unsigned j = 0; j < N; j++) {
|
||||||
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
||||||
|
LFSR_ATTR(UATTR(perm[j]+1), -1, "\xaa\xaa\xaa\xaa", 4,
|
||||||
|
NULL)) => 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// copy block so we can reset after each remove
|
||||||
|
lfsr_rbyd_t backup_rbyd = rbyd;
|
||||||
|
uint8_t backup_block[BLOCK_SIZE];
|
||||||
|
lfs_bd_read(&lfs, NULL, &lfs.rcache, rbyd.off,
|
||||||
|
rbyd.block, 0, backup_block, rbyd.off) => 0;
|
||||||
|
|
||||||
|
// try removing each tag
|
||||||
|
for (unsigned j = 0; j < N; j++) {
|
||||||
|
// print what we are removing to help debugging
|
||||||
|
printf("--- remove: %d ---\n", j+1);
|
||||||
|
|
||||||
|
rbyd = backup_rbyd;
|
||||||
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
||||||
|
lfs_bd_prog(&lfs, &lfs.pcache, &lfs.rcache, false,
|
||||||
|
rbyd.block, 0, backup_block, rbyd.off) => 0;
|
||||||
|
lfs_bd_flush(&lfs, &lfs.pcache, &lfs.rcache, false) => 0;
|
||||||
|
|
||||||
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
||||||
|
LFSR_ATTR(RMUATTR(j+1), -1, NULL, 0, NULL)) => 0;
|
||||||
|
|
||||||
|
// try traversing over the tags
|
||||||
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block,
|
||||||
|
cfg->block_size, NULL) => 0;
|
||||||
|
|
||||||
|
tag_ = 0;
|
||||||
|
id_ = -1;
|
||||||
|
for (unsigned k = 0; k < N-1; k++) {
|
||||||
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
||||||
|
&tag_, &id_, &off_, &size_) => 0;
|
||||||
|
if (k >= j) {
|
||||||
|
assert(tag_ == LFSR_TAG_UATTR(k+1+1));
|
||||||
|
assert(id_ == -1);
|
||||||
|
assert(size_ == 4);
|
||||||
|
} else {
|
||||||
|
assert(tag_ == LFSR_TAG_UATTR(k+1));
|
||||||
|
assert(id_ == -1);
|
||||||
|
assert(size_ == 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
||||||
|
&tag_, &id_, &off_, &size_) => LFS_ERR_NOENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
'''
|
||||||
|
|
||||||
[cases.test_rbyd_remove_missing]
|
[cases.test_rbyd_remove_missing]
|
||||||
in = 'lfs.c'
|
in = 'lfs.c'
|
||||||
if = 'BLOCK_SIZE/PROG_SIZE >= 4'
|
if = 'BLOCK_SIZE/PROG_SIZE >= 4'
|
||||||
@@ -4547,7 +4663,7 @@ code = '''
|
|||||||
LFSR_ATTR(MKREG, 0, "\xaa\xaa\xaa\xaa", 4,
|
LFSR_ATTR(MKREG, 0, "\xaa\xaa\xaa\xaa", 4,
|
||||||
LFSR_ATTR(MKREG, 1, "\xbb\xbb\xbb\xbb", 4, NULL))) => 0;
|
LFSR_ATTR(MKREG, 1, "\xbb\xbb\xbb\xbb", 4, NULL))) => 0;
|
||||||
|
|
||||||
lfsr_rbyd_lookup(&lfs, &rbyd, 0, -1,
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(0), -1,
|
||||||
&tag_, &id_, &off_, &size_) => 0;
|
&tag_, &id_, &off_, &size_) => 0;
|
||||||
assert(tag_ == LFSR_TAG_MKREG);
|
assert(tag_ == LFSR_TAG_MKREG);
|
||||||
assert(id_ == 0);
|
assert(id_ == 0);
|
||||||
@@ -4565,7 +4681,7 @@ code = '''
|
|||||||
&tag_, &id_, &off_, &size_) => LFS_ERR_NOENT;
|
&tag_, &id_, &off_, &size_) => LFS_ERR_NOENT;
|
||||||
|
|
||||||
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
||||||
lfsr_rbyd_lookup(&lfs, &rbyd, 0, -1,
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(0), -1,
|
||||||
&tag_, &id_, &off_, &size_) => 0;
|
&tag_, &id_, &off_, &size_) => 0;
|
||||||
assert(tag_ == LFSR_TAG_MKREG);
|
assert(tag_ == LFSR_TAG_MKREG);
|
||||||
assert(id_ == 0);
|
assert(id_ == 0);
|
||||||
@@ -4589,7 +4705,7 @@ code = '''
|
|||||||
LFSR_ATTR(MKREG, 0, "\xbb\xbb\xbb\xbb", 4,
|
LFSR_ATTR(MKREG, 0, "\xbb\xbb\xbb\xbb", 4,
|
||||||
LFSR_ATTR(MKREG, 0, "\xaa\xaa\xaa\xaa", 4, NULL))) => 0;
|
LFSR_ATTR(MKREG, 0, "\xaa\xaa\xaa\xaa", 4, NULL))) => 0;
|
||||||
|
|
||||||
lfsr_rbyd_lookup(&lfs, &rbyd, 0, -1,
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(0), -1,
|
||||||
&tag_, &id_, &off_, &size_) => 0;
|
&tag_, &id_, &off_, &size_) => 0;
|
||||||
assert(tag_ == LFSR_TAG_MKREG);
|
assert(tag_ == LFSR_TAG_MKREG);
|
||||||
assert(id_ == 0);
|
assert(id_ == 0);
|
||||||
@@ -4607,7 +4723,7 @@ code = '''
|
|||||||
&tag_, &id_, &off_, &size_) => LFS_ERR_NOENT;
|
&tag_, &id_, &off_, &size_) => LFS_ERR_NOENT;
|
||||||
|
|
||||||
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
||||||
lfsr_rbyd_lookup(&lfs, &rbyd, 0, -1,
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(0), -1,
|
||||||
&tag_, &id_, &off_, &size_) => 0;
|
&tag_, &id_, &off_, &size_) => 0;
|
||||||
assert(tag_ == LFSR_TAG_MKREG);
|
assert(tag_ == LFSR_TAG_MKREG);
|
||||||
assert(id_ == 0);
|
assert(id_ == 0);
|
||||||
@@ -4658,7 +4774,7 @@ code = '''
|
|||||||
lfsr_rbyd_commit(&lfs, &rbyd,
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
||||||
LFSR_ATTR(MKREG, 1, "\xbb\xbb\xbb\xbb", 4, NULL)) => 0;
|
LFSR_ATTR(MKREG, 1, "\xbb\xbb\xbb\xbb", 4, NULL)) => 0;
|
||||||
|
|
||||||
lfsr_rbyd_lookup(&lfs, &rbyd, 0, -1,
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(0), -1,
|
||||||
&tag_, &id_, &off_, &size_) => 0;
|
&tag_, &id_, &off_, &size_) => 0;
|
||||||
assert(tag_ == LFSR_TAG_MKREG);
|
assert(tag_ == LFSR_TAG_MKREG);
|
||||||
assert(id_ == 0);
|
assert(id_ == 0);
|
||||||
@@ -4676,7 +4792,7 @@ code = '''
|
|||||||
&tag_, &id_, &off_, &size_) => LFS_ERR_NOENT;
|
&tag_, &id_, &off_, &size_) => LFS_ERR_NOENT;
|
||||||
|
|
||||||
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
||||||
lfsr_rbyd_lookup(&lfs, &rbyd, 0, -1,
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(0), -1,
|
||||||
&tag_, &id_, &off_, &size_) => 0;
|
&tag_, &id_, &off_, &size_) => 0;
|
||||||
assert(tag_ == LFSR_TAG_MKREG);
|
assert(tag_ == LFSR_TAG_MKREG);
|
||||||
assert(id_ == 0);
|
assert(id_ == 0);
|
||||||
@@ -4701,7 +4817,7 @@ code = '''
|
|||||||
lfsr_rbyd_commit(&lfs, &rbyd,
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
||||||
LFSR_ATTR(MKREG, 0, "\xaa\xaa\xaa\xaa", 4, NULL)) => 0;
|
LFSR_ATTR(MKREG, 0, "\xaa\xaa\xaa\xaa", 4, NULL)) => 0;
|
||||||
|
|
||||||
lfsr_rbyd_lookup(&lfs, &rbyd, 0, -1,
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(0), -1,
|
||||||
&tag_, &id_, &off_, &size_) => 0;
|
&tag_, &id_, &off_, &size_) => 0;
|
||||||
assert(tag_ == LFSR_TAG_MKREG);
|
assert(tag_ == LFSR_TAG_MKREG);
|
||||||
assert(id_ == 0);
|
assert(id_ == 0);
|
||||||
@@ -4719,7 +4835,7 @@ code = '''
|
|||||||
&tag_, &id_, &off_, &size_) => LFS_ERR_NOENT;
|
&tag_, &id_, &off_, &size_) => LFS_ERR_NOENT;
|
||||||
|
|
||||||
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
||||||
lfsr_rbyd_lookup(&lfs, &rbyd, 0, -1,
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(0), -1,
|
||||||
&tag_, &id_, &off_, &size_) => 0;
|
&tag_, &id_, &off_, &size_) => 0;
|
||||||
assert(tag_ == LFSR_TAG_MKREG);
|
assert(tag_ == LFSR_TAG_MKREG);
|
||||||
assert(id_ == 0);
|
assert(id_ == 0);
|
||||||
@@ -5809,7 +5925,7 @@ code = '''
|
|||||||
LFSR_ATTR(MKREG, 1, "\xbb\xbb\xbb\xbb", 4,
|
LFSR_ATTR(MKREG, 1, "\xbb\xbb\xbb\xbb", 4,
|
||||||
LFSR_ATTR(UATTR(1), 1, "\xbb\xbb", 2, NULL))))) => 0;
|
LFSR_ATTR(UATTR(1), 1, "\xbb\xbb", 2, NULL))))) => 0;
|
||||||
|
|
||||||
lfsr_rbyd_lookup(&lfs, &rbyd, 0, -1,
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(0), -1,
|
||||||
&tag_, &id_, &off_, &size_) => 0;
|
&tag_, &id_, &off_, &size_) => 0;
|
||||||
assert(tag_ == LFSR_TAG_MKREG);
|
assert(tag_ == LFSR_TAG_MKREG);
|
||||||
assert(id_ == 0);
|
assert(id_ == 0);
|
||||||
@@ -5841,7 +5957,7 @@ code = '''
|
|||||||
&tag_, &id_, &off_, &size_) => LFS_ERR_NOENT;
|
&tag_, &id_, &off_, &size_) => LFS_ERR_NOENT;
|
||||||
|
|
||||||
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
||||||
lfsr_rbyd_lookup(&lfs, &rbyd, 0, -1,
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(0), -1,
|
||||||
&tag_, &id_, &off_, &size_) => 0;
|
&tag_, &id_, &off_, &size_) => 0;
|
||||||
assert(tag_ == LFSR_TAG_MKREG);
|
assert(tag_ == LFSR_TAG_MKREG);
|
||||||
assert(id_ == 0);
|
assert(id_ == 0);
|
||||||
@@ -5881,7 +5997,7 @@ code = '''
|
|||||||
LFSR_ATTR(MKREG, 0, "\xaa\xaa\xaa\xaa", 4,
|
LFSR_ATTR(MKREG, 0, "\xaa\xaa\xaa\xaa", 4,
|
||||||
LFSR_ATTR(UATTR(1), 0, "\xaa\xaa", 2, NULL))))) => 0;
|
LFSR_ATTR(UATTR(1), 0, "\xaa\xaa", 2, NULL))))) => 0;
|
||||||
|
|
||||||
lfsr_rbyd_lookup(&lfs, &rbyd, 0, -1,
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(0), -1,
|
||||||
&tag_, &id_, &off_, &size_) => 0;
|
&tag_, &id_, &off_, &size_) => 0;
|
||||||
assert(tag_ == LFSR_TAG_MKREG);
|
assert(tag_ == LFSR_TAG_MKREG);
|
||||||
assert(id_ == 0);
|
assert(id_ == 0);
|
||||||
@@ -5913,7 +6029,7 @@ code = '''
|
|||||||
&tag_, &id_, &off_, &size_) => LFS_ERR_NOENT;
|
&tag_, &id_, &off_, &size_) => LFS_ERR_NOENT;
|
||||||
|
|
||||||
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
||||||
lfsr_rbyd_lookup(&lfs, &rbyd, 0, -1,
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(0), -1,
|
||||||
&tag_, &id_, &off_, &size_) => 0;
|
&tag_, &id_, &off_, &size_) => 0;
|
||||||
assert(tag_ == LFSR_TAG_MKREG);
|
assert(tag_ == LFSR_TAG_MKREG);
|
||||||
assert(id_ == 0);
|
assert(id_ == 0);
|
||||||
@@ -5981,7 +6097,7 @@ code = '''
|
|||||||
lfsr_rbyd_commit(&lfs, &rbyd,
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
||||||
LFSR_ATTR(UATTR(1), 1, "\xbb\xbb", 2, NULL)) => 0;
|
LFSR_ATTR(UATTR(1), 1, "\xbb\xbb", 2, NULL)) => 0;
|
||||||
|
|
||||||
lfsr_rbyd_lookup(&lfs, &rbyd, 0, -1,
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(0), -1,
|
||||||
&tag_, &id_, &off_, &size_) => 0;
|
&tag_, &id_, &off_, &size_) => 0;
|
||||||
assert(tag_ == LFSR_TAG_MKREG);
|
assert(tag_ == LFSR_TAG_MKREG);
|
||||||
assert(id_ == 0);
|
assert(id_ == 0);
|
||||||
@@ -6013,7 +6129,7 @@ code = '''
|
|||||||
&tag_, &id_, &off_, &size_) => LFS_ERR_NOENT;
|
&tag_, &id_, &off_, &size_) => LFS_ERR_NOENT;
|
||||||
|
|
||||||
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
||||||
lfsr_rbyd_lookup(&lfs, &rbyd, 0, -1,
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(0), -1,
|
||||||
&tag_, &id_, &off_, &size_) => 0;
|
&tag_, &id_, &off_, &size_) => 0;
|
||||||
assert(tag_ == LFSR_TAG_MKREG);
|
assert(tag_ == LFSR_TAG_MKREG);
|
||||||
assert(id_ == 0);
|
assert(id_ == 0);
|
||||||
@@ -6056,7 +6172,7 @@ code = '''
|
|||||||
lfsr_rbyd_commit(&lfs, &rbyd,
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
||||||
LFSR_ATTR(UATTR(1), 0, "\xaa\xaa", 2, NULL)) => 0;
|
LFSR_ATTR(UATTR(1), 0, "\xaa\xaa", 2, NULL)) => 0;
|
||||||
|
|
||||||
lfsr_rbyd_lookup(&lfs, &rbyd, 0, -1,
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(0), -1,
|
||||||
&tag_, &id_, &off_, &size_) => 0;
|
&tag_, &id_, &off_, &size_) => 0;
|
||||||
assert(tag_ == LFSR_TAG_MKREG);
|
assert(tag_ == LFSR_TAG_MKREG);
|
||||||
assert(id_ == 0);
|
assert(id_ == 0);
|
||||||
@@ -6088,7 +6204,7 @@ code = '''
|
|||||||
&tag_, &id_, &off_, &size_) => LFS_ERR_NOENT;
|
&tag_, &id_, &off_, &size_) => LFS_ERR_NOENT;
|
||||||
|
|
||||||
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
||||||
lfsr_rbyd_lookup(&lfs, &rbyd, 0, -1,
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(0), -1,
|
||||||
&tag_, &id_, &off_, &size_) => 0;
|
&tag_, &id_, &off_, &size_) => 0;
|
||||||
assert(tag_ == LFSR_TAG_MKREG);
|
assert(tag_ == LFSR_TAG_MKREG);
|
||||||
assert(id_ == 0);
|
assert(id_ == 0);
|
||||||
@@ -7686,6 +7802,307 @@ code = '''
|
|||||||
}
|
}
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
[cases.test_rbyd_delete_traverse_permutations]
|
||||||
|
defines.N = 'range(1, 7)'
|
||||||
|
in = 'lfs.c'
|
||||||
|
if = 'BLOCK_SIZE/PROG_SIZE >= N+1'
|
||||||
|
code = '''
|
||||||
|
lfs_t lfs;
|
||||||
|
lfs_init(&lfs, cfg) => 0;
|
||||||
|
|
||||||
|
lfsr_rbyd_t init_rbyd = {
|
||||||
|
.block = 0,
|
||||||
|
.rev = 1,
|
||||||
|
.off = 0,
|
||||||
|
.crc = 0,
|
||||||
|
.trunk = 0,
|
||||||
|
.weight = 0,
|
||||||
|
.erased = true,
|
||||||
|
};
|
||||||
|
lfsr_rbyd_t rbyd;
|
||||||
|
const uint8_t names[6][4] = {
|
||||||
|
"\xaa\xaa\xaa\xaa",
|
||||||
|
"\xbb\xbb\xbb\xbb",
|
||||||
|
"\xcc\xcc\xcc\xcc",
|
||||||
|
"\xdd\xdd\xdd\xdd",
|
||||||
|
"\xee\xee\xee\xee",
|
||||||
|
"\xff\xff\xff\xff",
|
||||||
|
};
|
||||||
|
lfsr_tag_t tag_;
|
||||||
|
lfsr_sid_t id_;
|
||||||
|
lfs_off_t off_;
|
||||||
|
lfs_size_t size_;
|
||||||
|
uint8_t buffer[4];
|
||||||
|
|
||||||
|
// test all permutations of a given size
|
||||||
|
uint16_t perm[N];
|
||||||
|
unsigned stack[N];
|
||||||
|
for (uint16_t i = 0; i < N; i++) {
|
||||||
|
perm[i] = i;
|
||||||
|
stack[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned i = 1;
|
||||||
|
while (i < N) {
|
||||||
|
// print permutation to help debugging
|
||||||
|
printf("--- permutation: [");
|
||||||
|
for (unsigned j = 0; j < N; j++) {
|
||||||
|
if (j > 0) {
|
||||||
|
printf(", ");
|
||||||
|
}
|
||||||
|
printf("%d", perm[j]+1);
|
||||||
|
}
|
||||||
|
printf("] ---\n");
|
||||||
|
|
||||||
|
// create given permutation with multiple commits
|
||||||
|
rbyd = init_rbyd;
|
||||||
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
||||||
|
|
||||||
|
for (unsigned j = 0; j < N; j++) {
|
||||||
|
// adjust id based on future insertions
|
||||||
|
uint16_t id = perm[j];
|
||||||
|
for (unsigned k = j+1; k < N; k++) {
|
||||||
|
if (perm[j] > perm[k]) {
|
||||||
|
id -= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
||||||
|
LFSR_ATTR(MKREG, id, names[perm[j] % 6], 4,
|
||||||
|
NULL)) => 0;
|
||||||
|
}
|
||||||
|
assert(rbyd.weight == N);
|
||||||
|
|
||||||
|
// copy block so we can reset after each delete
|
||||||
|
lfsr_rbyd_t backup_rbyd = rbyd;
|
||||||
|
uint8_t backup_block[BLOCK_SIZE];
|
||||||
|
lfs_bd_read(&lfs, NULL, &lfs.rcache, rbyd.off,
|
||||||
|
rbyd.block, 0, backup_block, rbyd.off) => 0;
|
||||||
|
|
||||||
|
// try deleting each id
|
||||||
|
for (unsigned j = 0; j < N; j++) {
|
||||||
|
// print what we are deleting to help debugging
|
||||||
|
printf("--- delete: %d ---\n", j+1);
|
||||||
|
|
||||||
|
rbyd = backup_rbyd;
|
||||||
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
||||||
|
lfs_bd_prog(&lfs, &lfs.pcache, &lfs.rcache, false,
|
||||||
|
rbyd.block, 0, backup_block, rbyd.off) => 0;
|
||||||
|
lfs_bd_flush(&lfs, &lfs.pcache, &lfs.rcache, false) => 0;
|
||||||
|
|
||||||
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
||||||
|
LFSR_ATTR(RM, j, NULL, 0, NULL)) => 0;
|
||||||
|
assert(rbyd.weight == N-1);
|
||||||
|
|
||||||
|
// try traversing over the tags
|
||||||
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block,
|
||||||
|
cfg->block_size, NULL) => 0;
|
||||||
|
assert(rbyd.weight == N-1);
|
||||||
|
|
||||||
|
tag_ = 0;
|
||||||
|
id_ = -1;
|
||||||
|
for (unsigned k = 0; k < N-1; k++) {
|
||||||
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
||||||
|
&tag_, &id_, &off_, &size_) => 0;
|
||||||
|
assert(tag_ == LFSR_TAG_MKREG);
|
||||||
|
assert(id_ == k);
|
||||||
|
assert(size_ == 4);
|
||||||
|
|
||||||
|
lfsr_rbyd_get(&lfs, &rbyd, tag_, id_, buffer, 4) => 4;
|
||||||
|
if (k >= j) {
|
||||||
|
assert(memcmp(buffer, names[(k+1) % 6], 4) == 0);
|
||||||
|
} else {
|
||||||
|
assert(memcmp(buffer, names[k % 6], 4) == 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
||||||
|
&tag_, &id_, &off_, &size_) => LFS_ERR_NOENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
// next permutation using Heap's algorithm
|
||||||
|
if (stack[i] < i) {
|
||||||
|
if (i % 2 == 0) {
|
||||||
|
uint16_t t = perm[0];
|
||||||
|
perm[0] = perm[i];
|
||||||
|
perm[i] = t;
|
||||||
|
} else {
|
||||||
|
uint16_t t = perm[stack[i]];
|
||||||
|
perm[stack[i]] = perm[i];
|
||||||
|
perm[i] = t;
|
||||||
|
}
|
||||||
|
stack[i] += 1;
|
||||||
|
i = 1;
|
||||||
|
} else {
|
||||||
|
stack[i] = 0;
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
'''
|
||||||
|
|
||||||
|
[cases.test_rbyd_delete_traverse_range_permutations]
|
||||||
|
defines.N = 'range(1, 7)'
|
||||||
|
defines.M = 'range(1, 4)'
|
||||||
|
in = 'lfs.c'
|
||||||
|
if = '''
|
||||||
|
BLOCK_SIZE/PROG_SIZE >= N+N*M+1
|
||||||
|
&& BLOCK_SIZE >= 4096
|
||||||
|
'''
|
||||||
|
code = '''
|
||||||
|
lfs_t lfs;
|
||||||
|
lfs_init(&lfs, cfg) => 0;
|
||||||
|
|
||||||
|
lfsr_rbyd_t init_rbyd = {
|
||||||
|
.block = 0,
|
||||||
|
.rev = 1,
|
||||||
|
.off = 0,
|
||||||
|
.crc = 0,
|
||||||
|
.trunk = 0,
|
||||||
|
.weight = 0,
|
||||||
|
.erased = true,
|
||||||
|
};
|
||||||
|
lfsr_rbyd_t rbyd;
|
||||||
|
const uint8_t names[6][4] = {
|
||||||
|
"\xaa\xaa\xaa\xaa",
|
||||||
|
"\xbb\xbb\xbb\xbb",
|
||||||
|
"\xcc\xcc\xcc\xcc",
|
||||||
|
"\xdd\xdd\xdd\xdd",
|
||||||
|
"\xee\xee\xee\xee",
|
||||||
|
"\xff\xff\xff\xff",
|
||||||
|
};
|
||||||
|
lfsr_tag_t tag_;
|
||||||
|
lfsr_sid_t id_;
|
||||||
|
lfs_off_t off_;
|
||||||
|
lfs_size_t size_;
|
||||||
|
uint8_t buffer[4];
|
||||||
|
|
||||||
|
// test all permutations of a given size
|
||||||
|
uint16_t perm[N];
|
||||||
|
unsigned stack[N];
|
||||||
|
for (uint16_t i = 0; i < N; i++) {
|
||||||
|
perm[i] = i;
|
||||||
|
stack[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned i = 1;
|
||||||
|
while (i < N) {
|
||||||
|
// print permutation to help debugging
|
||||||
|
printf("--- permutation: [");
|
||||||
|
for (unsigned j = 0; j < N; j++) {
|
||||||
|
if (j > 0) {
|
||||||
|
printf(", ");
|
||||||
|
}
|
||||||
|
printf("%d", perm[j]+1);
|
||||||
|
}
|
||||||
|
printf("] ---\n");
|
||||||
|
|
||||||
|
// create given permutation with multiple commits
|
||||||
|
rbyd = init_rbyd;
|
||||||
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
||||||
|
|
||||||
|
for (unsigned j = 0; j < N; j++) {
|
||||||
|
// adjust id based on future insertions
|
||||||
|
uint16_t id = perm[j];
|
||||||
|
for (unsigned k = j+1; k < N; k++) {
|
||||||
|
if (perm[j] > perm[k]) {
|
||||||
|
id -= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
||||||
|
LFSR_ATTR(MKREG, id, names[perm[j] % 6], 4,
|
||||||
|
NULL)) => 0;
|
||||||
|
// note uattrs have a smaller size to help debugging
|
||||||
|
for (unsigned u = 0; u < M; u++) {
|
||||||
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
||||||
|
LFSR_ATTR(UATTR(u+1), id, names[perm[j] % 6], 2,
|
||||||
|
NULL)) => 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert(rbyd.weight == N);
|
||||||
|
|
||||||
|
// copy block so we can reset after each delete
|
||||||
|
lfsr_rbyd_t backup_rbyd = rbyd;
|
||||||
|
uint8_t backup_block[BLOCK_SIZE];
|
||||||
|
lfs_bd_read(&lfs, NULL, &lfs.rcache, rbyd.off,
|
||||||
|
rbyd.block, 0, backup_block, rbyd.off) => 0;
|
||||||
|
|
||||||
|
// try deleting each id
|
||||||
|
for (unsigned j = 0; j < N; j++) {
|
||||||
|
// print what we are deleting to help debugging
|
||||||
|
printf("--- delete: %d ---\n", j+1);
|
||||||
|
|
||||||
|
rbyd = backup_rbyd;
|
||||||
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
||||||
|
lfs_bd_prog(&lfs, &lfs.pcache, &lfs.rcache, false,
|
||||||
|
rbyd.block, 0, backup_block, rbyd.off) => 0;
|
||||||
|
lfs_bd_flush(&lfs, &lfs.pcache, &lfs.rcache, false) => 0;
|
||||||
|
|
||||||
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
||||||
|
LFSR_ATTR(RM, j, NULL, 0, NULL)) => 0;
|
||||||
|
assert(rbyd.weight == N-1);
|
||||||
|
|
||||||
|
// try traversing over the tags
|
||||||
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block,
|
||||||
|
cfg->block_size, NULL) => 0;
|
||||||
|
assert(rbyd.weight == N-1);
|
||||||
|
|
||||||
|
tag_ = 0;
|
||||||
|
id_ = -1;
|
||||||
|
for (unsigned k = 0; k < N-1; k++) {
|
||||||
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
||||||
|
&tag_, &id_, &off_, &size_) => 0;
|
||||||
|
assert(tag_ == LFSR_TAG_MKREG);
|
||||||
|
assert(id_ == k);
|
||||||
|
assert(size_ == 4);
|
||||||
|
|
||||||
|
lfsr_rbyd_get(&lfs, &rbyd, tag_, id_, buffer, 4) => 4;
|
||||||
|
if (k >= j) {
|
||||||
|
assert(memcmp(buffer, names[(k+1) % 6], 4) == 0);
|
||||||
|
} else {
|
||||||
|
assert(memcmp(buffer, names[k % 6], 4) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (unsigned u = 0; u < M; u++) {
|
||||||
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
||||||
|
&tag_, &id_, &off_, &size_) => 0;
|
||||||
|
assert(tag_ == LFSR_TAG_UATTR(u+1));
|
||||||
|
assert(id_ == k);
|
||||||
|
assert(size_ == 2);
|
||||||
|
|
||||||
|
lfsr_rbyd_get(&lfs, &rbyd, tag_, id_, buffer, 4) => 2;
|
||||||
|
if (k >= j) {
|
||||||
|
assert(memcmp(buffer, names[(k+1) % 6], 2) == 0);
|
||||||
|
} else {
|
||||||
|
assert(memcmp(buffer, names[k % 6], 2) == 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
||||||
|
&tag_, &id_, &off_, &size_) => LFS_ERR_NOENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
// next permutation using Heap's algorithm
|
||||||
|
if (stack[i] < i) {
|
||||||
|
if (i % 2 == 0) {
|
||||||
|
uint16_t t = perm[0];
|
||||||
|
perm[0] = perm[i];
|
||||||
|
perm[i] = t;
|
||||||
|
} else {
|
||||||
|
uint16_t t = perm[stack[i]];
|
||||||
|
perm[stack[i]] = perm[i];
|
||||||
|
perm[i] = t;
|
||||||
|
}
|
||||||
|
stack[i] += 1;
|
||||||
|
i = 1;
|
||||||
|
} else {
|
||||||
|
stack[i] = 0;
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
'''
|
||||||
|
|
||||||
[cases.test_rbyd_delete_all]
|
[cases.test_rbyd_delete_all]
|
||||||
in = 'lfs.c'
|
in = 'lfs.c'
|
||||||
if = 'BLOCK_SIZE/PROG_SIZE >= 2'
|
if = 'BLOCK_SIZE/PROG_SIZE >= 2'
|
||||||
|
|||||||
Reference in New Issue
Block a user