6f4704474b
Generally, less implicit behavior => simpler systems, which is the goal here.
11393 lines
386 KiB
TOML
11393 lines
386 KiB
TOML
|
|
# Test this inner rbyd data-structure
|
|
|
|
# test with a number of different erase values
|
|
defines.ERASE_VALUE = [0xff, 0x00, 0x1b]
|
|
|
|
# set block_size to the full size of disk so we can test arbitrarily
|
|
# large rbyd trees, we don't really care about block sizes at this
|
|
# abstraction level
|
|
#
|
|
# ok not quite full disk size (we do use the full disk size in bench_rbyd),
|
|
# but a bit less since erasing the full disk takes time and we don't want to
|
|
# waste time when testing
|
|
defines.BLOCK_SIZE = 32768
|
|
|
|
[cases.test_rbyd_commit]
|
|
in = 'lfs.c'
|
|
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;
|
|
|
|
// try an empty commit
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, NULL) => 0;
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
|
|
// commit with one attribute
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(UATTR(1), -1, "\xaa\xaa\xaa\xaa", 4, NULL)) => 0;
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
|
|
// commit with two attributes
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(UATTR(1), -1, "\xaa\xaa\xaa\xaa", 4,
|
|
LFSR_ATTR(UATTR(2), -1, "\xbb\xbb\xbb\xbb", 4, NULL))) => 0;
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
'''
|
|
|
|
[cases.test_rbyd_multi_commit]
|
|
in = 'lfs.c'
|
|
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;
|
|
|
|
// try an empty commit
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, NULL) => 0;
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
|
|
// commit with one attribute
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(UATTR(1), -1, "\xaa\xaa\xaa\xaa", 4, NULL)) => 0;
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
|
|
// commit with two attributes
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(UATTR(1), -1, "\xaa\xaa\xaa\xaa", 4, NULL)) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(UATTR(2), -1, "\xbb\xbb\xbb\xbb", 4, NULL)) => 0;
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
'''
|
|
|
|
[cases.test_rbyd_commit_fetch_commit]
|
|
in = 'lfs.c'
|
|
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;
|
|
|
|
// commit with one attribute
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(UATTR(1), -1, "\xaa\xaa\xaa\xaa", 4, NULL)) => 0;
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
|
|
// commit with the second attribute
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(UATTR(2), -1, "\xbb\xbb\xbb\xbb", 4, NULL)) => 0;
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
'''
|
|
|
|
# [cases.test_rbyd_fetchmatch]
|
|
# [cases.test_rbyd_multi_fetchmatch]
|
|
|
|
# TODO we really need to test dense keys...
|
|
|
|
[cases.test_rbyd_lookup]
|
|
in = 'lfs.c'
|
|
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_;
|
|
lfs_ssize_t id_;
|
|
lfs_off_t off_;
|
|
lfs_size_t size_;
|
|
|
|
// try an empty commit
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, NULL) => 0;
|
|
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => LFS_ERR_NOENT;
|
|
|
|
// commit with one attribute
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(UATTR(1), -1, "\xaa\xaa\xaa\xaa", 4, NULL)) => 0;
|
|
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(2), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(2), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => LFS_ERR_NOENT;
|
|
|
|
// commit with two attributes
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(UATTR(1), -1, "\xaa\xaa\xaa\xaa", 4,
|
|
LFSR_ATTR(UATTR(2), -1, "\xbb\xbb\xbb\xbb", 4, NULL))) => 0;
|
|
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(2), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(3), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(2), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(3), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => LFS_ERR_NOENT;
|
|
|
|
// commit with two attributes, in the other direction
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(UATTR(2), -1, "\xbb\xbb\xbb\xbb", 4,
|
|
LFSR_ATTR(UATTR(1), -1, "\xaa\xaa\xaa\xaa", 4, NULL))) => 0;
|
|
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(2), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(3), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(2), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(3), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => LFS_ERR_NOENT;
|
|
'''
|
|
|
|
[cases.test_rbyd_multi_lookup]
|
|
in = 'lfs.c'
|
|
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_;
|
|
lfs_ssize_t id_;
|
|
lfs_off_t off_;
|
|
lfs_size_t size_;
|
|
|
|
// try an empty commit
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, NULL) => 0;
|
|
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => LFS_ERR_NOENT;
|
|
|
|
// commit with one attribute
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(UATTR(1), -1, "\xaa\xaa\xaa\xaa", 4, NULL)) => 0;
|
|
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(2), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(2), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => LFS_ERR_NOENT;
|
|
|
|
// commit with two attributes
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(UATTR(1), -1, "\xaa\xaa\xaa\xaa", 4, NULL)) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(UATTR(2), -1, "\xbb\xbb\xbb\xbb", 4, NULL)) => 0;
|
|
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(2), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(3), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(2), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(3), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => LFS_ERR_NOENT;
|
|
|
|
// commit with two attributes, in the other direction
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(UATTR(2), -1, "\xbb\xbb\xbb\xbb", 4, NULL)) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(UATTR(1), -1, "\xaa\xaa\xaa\xaa", 4, NULL)) => 0;
|
|
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(2), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(3), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(2), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(3), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => LFS_ERR_NOENT;
|
|
'''
|
|
|
|
[cases.test_rbyd_get]
|
|
in = 'lfs.c'
|
|
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;
|
|
uint8_t buffer[4];
|
|
|
|
// try an empty commit
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, NULL) => 0;
|
|
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(1), -1, buffer, 4)
|
|
=> LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(1), -1, buffer, 4)
|
|
=> LFS_ERR_NOENT;
|
|
|
|
// commit with one attribute
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(UATTR(1), -1, "\xaa\xaa\xaa\xaa", 4, NULL)) => 0;
|
|
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(1), -1, buffer, 4)
|
|
=> 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(2), -1, buffer, 4)
|
|
=> LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(1), -1, buffer, 4)
|
|
=> 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(2), -1, buffer, 4)
|
|
=> LFS_ERR_NOENT;
|
|
|
|
// commit with two attributes
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(UATTR(1), -1, "\xaa\xaa\xaa\xaa", 4,
|
|
LFSR_ATTR(UATTR(2), -1, "\xbb\xbb\xbb\xbb", 4, NULL))) => 0;
|
|
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(1), -1, buffer, 4)
|
|
=> 4;
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(2), -1, buffer, 4)
|
|
=> 4;
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(3), -1, buffer, 4)
|
|
=> LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(1), -1, buffer, 4)
|
|
=> 4;
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(2), -1, buffer, 4)
|
|
=> 4;
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(3), -1, buffer, 4)
|
|
=> LFS_ERR_NOENT;
|
|
|
|
// commit with two attributes, in the other direction
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(UATTR(2), -1, "\xbb\xbb\xbb\xbb", 4,
|
|
LFSR_ATTR(UATTR(1), -1, "\xaa\xaa\xaa\xaa", 4, NULL))) => 0;
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(1), -1, buffer, 4)
|
|
=> 4;
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(2), -1, buffer, 4)
|
|
=> 4;
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(3), -1, buffer, 4)
|
|
=> LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(1), -1, buffer, 4)
|
|
=> 4;
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(2), -1, buffer, 4)
|
|
=> 4;
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(3), -1, buffer, 4)
|
|
=> LFS_ERR_NOENT;
|
|
'''
|
|
|
|
[cases.test_rbyd_multi_get]
|
|
in = 'lfs.c'
|
|
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;
|
|
uint8_t buffer[4];
|
|
|
|
// try an empty commit
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, NULL) => 0;
|
|
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(1), -1, buffer, 4)
|
|
=> LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(1), -1, buffer, 4)
|
|
=> LFS_ERR_NOENT;
|
|
|
|
// commit with one attribute
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(UATTR(1), -1, "\xaa\xaa\xaa\xaa", 4, NULL)) => 0;
|
|
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(1), -1, buffer, 4)
|
|
=> 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(2), -1, buffer, 4)
|
|
=> LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(1), -1, buffer, 4)
|
|
=> 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(2), -1, buffer, 4)
|
|
=> LFS_ERR_NOENT;
|
|
|
|
// commit with two attributes
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(UATTR(1), -1, "\xaa\xaa\xaa\xaa", 4, NULL)) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(UATTR(2), -1, "\xbb\xbb\xbb\xbb", 4, NULL)) => 0;
|
|
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(1), -1, buffer, 4)
|
|
=> 4;
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(2), -1, buffer, 4)
|
|
=> 4;
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(3), -1, buffer, 4)
|
|
=> LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(1), -1, buffer, 4)
|
|
=> 4;
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(2), -1, buffer, 4)
|
|
=> 4;
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(3), -1, buffer, 4)
|
|
=> LFS_ERR_NOENT;
|
|
|
|
// commit with two attributes, in the other direction
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(UATTR(2), -1, "\xbb\xbb\xbb\xbb", 4, NULL)) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(UATTR(1), -1, "\xaa\xaa\xaa\xaa", 4, NULL)) => 0;
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(1), -1, buffer, 4)
|
|
=> 4;
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(2), -1, buffer, 4)
|
|
=> 4;
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(3), -1, buffer, 4)
|
|
=> LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(1), -1, buffer, 4)
|
|
=> 4;
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(2), -1, buffer, 4)
|
|
=> 4;
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(3), -1, buffer, 4)
|
|
=> LFS_ERR_NOENT;
|
|
'''
|
|
|
|
[cases.test_rbyd_bifoliate]
|
|
in = 'lfs.c'
|
|
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_;
|
|
lfs_ssize_t id_;
|
|
lfs_off_t off_;
|
|
lfs_size_t size_;
|
|
|
|
// create a split in the leaves
|
|
// <b
|
|
// => .-'|
|
|
// 1 1 2
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(UATTR(1), -1, "\xaa\xaa\xaa\xaa", 4,
|
|
LFSR_ATTR(UATTR(2), -1, "\xbb\xbb\xbb\xbb", 4, NULL))) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(2), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
|
|
// split the other direction
|
|
// >b
|
|
// => .-'|
|
|
// 2 2 1
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(UATTR(2), -1, "\xbb\xbb\xbb\xbb", 4,
|
|
LFSR_ATTR(UATTR(1), -1, "\xaa\xaa\xaa\xaa", 4, NULL))) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(2), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
'''
|
|
|
|
[cases.test_rbyd_bflips]
|
|
in = 'lfs.c'
|
|
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_;
|
|
lfs_ssize_t id_;
|
|
lfs_off_t off_;
|
|
lfs_size_t size_;
|
|
|
|
// ignore a black edge
|
|
// <b <b
|
|
// .-'| => .----'|
|
|
// 1 2 1 2 2
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(UATTR(1), -1, "\xaa\xaa\xaa\xaa", 4,
|
|
LFSR_ATTR(UATTR(2), -1, "\xbb\xbb\xbb\xbb", 4,
|
|
LFSR_ATTR(UATTR(2), -1, "\xbb\xbb\xbb\xbb", 4, NULL)))) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(2), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
|
|
// flip a black edge
|
|
// <b >b
|
|
// .-'| => .-'|
|
|
// 1 2 1 2 1
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(UATTR(1), -1, "\xaa\xaa\xaa\xaa", 4,
|
|
LFSR_ATTR(UATTR(2), -1, "\xbb\xbb\xbb\xbb", 4,
|
|
LFSR_ATTR(UATTR(1), -1, "\xaa\xaa\xaa\xaa", 4, NULL)))) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(2), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
'''
|
|
|
|
[cases.test_rbyd_trifoliate]
|
|
in = 'lfs.c'
|
|
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_;
|
|
lfs_ssize_t id_;
|
|
lfs_off_t off_;
|
|
lfs_size_t size_;
|
|
|
|
// ignore a black edge
|
|
// <r
|
|
// .----'|
|
|
// <b => | <b
|
|
// .-'| | .-'|
|
|
// 1 2 1 2 3
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(UATTR(1), -1, "\xaa\xaa\xaa\xaa", 4,
|
|
LFSR_ATTR(UATTR(2), -1, "\xbb\xbb\xbb\xbb", 4,
|
|
LFSR_ATTR(UATTR(3), -1, "\xcc\xcc\xcc\xcc", 4, NULL)))) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(2), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(3), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(3));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
|
|
// flip a black edge
|
|
// >r
|
|
// .-'|
|
|
// <b => | >b
|
|
// .-'| .--|-'|
|
|
// 2 3 2 3 1
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(UATTR(2), -1, "\xbb\xbb\xbb\xbb", 4,
|
|
LFSR_ATTR(UATTR(3), -1, "\xcc\xcc\xcc\xcc", 4,
|
|
LFSR_ATTR(UATTR(1), -1, "\xaa\xaa\xaa\xaa", 4, NULL)))) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(2), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(3), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(3));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
'''
|
|
|
|
[cases.test_rbyd_rflips]
|
|
in = 'lfs.c'
|
|
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_;
|
|
lfs_ssize_t id_;
|
|
lfs_off_t off_;
|
|
lfs_size_t size_;
|
|
|
|
// ignore a red edge and black edge
|
|
// <r <r
|
|
// .----'| .-------'|
|
|
// | <b => | <b
|
|
// | .-'| | .----'|
|
|
// 1 2 3 1 2 3 3
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(UATTR(1), -1, "\xaa\xaa\xaa\xaa", 4,
|
|
LFSR_ATTR(UATTR(2), -1, "\xbb\xbb\xbb\xbb", 4,
|
|
LFSR_ATTR(UATTR(3), -1, "\xcc\xcc\xcc\xcc", 4,
|
|
LFSR_ATTR(UATTR(3), -1, "\xcc\xcc\xcc\xcc", 4, NULL))))) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(2), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(3), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(3));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
|
|
// ignore a red edge, flip a black edge
|
|
// <r <r
|
|
// .----'| .-------'|
|
|
// | <b => | >b
|
|
// | .-'| | .-'|
|
|
// 1 2 3 1 2 3 2
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(UATTR(1), -1, "\xaa\xaa\xaa\xaa", 4,
|
|
LFSR_ATTR(UATTR(2), -1, "\xbb\xbb\xbb\xbb", 4,
|
|
LFSR_ATTR(UATTR(3), -1, "\xcc\xcc\xcc\xcc", 4,
|
|
LFSR_ATTR(UATTR(2), -1, "\xbb\xbb\xbb\xbb", 4, NULL))))) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(2), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(3), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(3));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
|
|
// flip a red edge and black edge
|
|
// <r >r
|
|
// .----'| .-'|
|
|
// | <b => | >b
|
|
// | .-'| .--|-'|
|
|
// 1 2 3 1 2 3 1
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(UATTR(1), -1, "\xaa\xaa\xaa\xaa", 4,
|
|
LFSR_ATTR(UATTR(2), -1, "\xbb\xbb\xbb\xbb", 4,
|
|
LFSR_ATTR(UATTR(3), -1, "\xcc\xcc\xcc\xcc", 4,
|
|
LFSR_ATTR(UATTR(1), -1, "\xaa\xaa\xaa\xaa", 4, NULL))))) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(2), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(3), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(3));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
|
|
// flip a red edge, ignore a black edge
|
|
// <r >r
|
|
// .-'| .-------'|
|
|
// | >b => | >b
|
|
// .--|-'| | .-'|
|
|
// 3 1 2 3 1 2 1
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(UATTR(3), -1, "\xcc\xcc\xcc\xcc", 4,
|
|
LFSR_ATTR(UATTR(1), -1, "\xaa\xaa\xaa\xaa", 4,
|
|
LFSR_ATTR(UATTR(2), -1, "\xbb\xbb\xbb\xbb", 4,
|
|
LFSR_ATTR(UATTR(1), -1, "\xaa\xaa\xaa\xaa", 4, NULL))))) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(2), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(3), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(3));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
'''
|
|
|
|
[cases.test_rbyd_quadrifoliate]
|
|
in = 'lfs.c'
|
|
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_;
|
|
lfs_ssize_t id_;
|
|
lfs_off_t off_;
|
|
lfs_size_t size_;
|
|
|
|
// ignore a red edge and black edge
|
|
// <y
|
|
// .-------'|
|
|
// <r | <r
|
|
// .----'| => | .----'|
|
|
// | <b | | <b
|
|
// | .-'| | | .-'|
|
|
// 1 2 3 1 2 3 4
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(UATTR(1), -1, "\xaa\xaa\xaa\xaa", 4,
|
|
LFSR_ATTR(UATTR(2), -1, "\xbb\xbb\xbb\xbb", 4,
|
|
LFSR_ATTR(UATTR(3), -1, "\xcc\xcc\xcc\xcc", 4,
|
|
LFSR_ATTR(UATTR(4), -1, "\xdd\xdd\xdd\xdd", 4, NULL))))) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(2), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(3), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(3));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(4), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(4));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
|
|
// ignore a red edge, flip a black edge
|
|
// <y >y
|
|
// .-------'| .-'|
|
|
// <r | >r | >r
|
|
// .----'| => | .-'| => .--|-'|
|
|
// | <b | | >b | | <b
|
|
// | .-'| | .--|-'| .--|--|-'|
|
|
// 1 3 4 1 3 4 2 1 3 4 2
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(UATTR(1), -1, "\xaa\xaa\xaa\xaa", 4,
|
|
LFSR_ATTR(UATTR(3), -1, "\xcc\xcc\xcc\xcc", 4,
|
|
LFSR_ATTR(UATTR(4), -1, "\xdd\xdd\xdd\xdd", 4,
|
|
LFSR_ATTR(UATTR(2), -1, "\xbb\xbb\xbb\xbb", 4, NULL))))) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(2), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(3), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(3));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(4), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(4));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
|
|
// flip a red edge and black edge
|
|
// >y
|
|
// .-'|
|
|
// <r | >b
|
|
// .----'| => .--|-'|
|
|
// | <b | | >b
|
|
// | .-'| .--|--|-'|
|
|
// 2 3 4 2 3 4 1
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(UATTR(2), -1, "\xbb\xbb\xbb\xbb", 4,
|
|
LFSR_ATTR(UATTR(3), -1, "\xcc\xcc\xcc\xcc", 4,
|
|
LFSR_ATTR(UATTR(4), -1, "\xdd\xdd\xdd\xdd", 4,
|
|
LFSR_ATTR(UATTR(1), -1, "\xaa\xaa\xaa\xaa", 4, NULL))))) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(2), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(3), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(3));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(4), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(4));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
|
|
// flip a red edge, ignore a black edge
|
|
// >y
|
|
// .-------'|
|
|
// <r | >r
|
|
// .-'| => | .-'|
|
|
// | >b | | <b
|
|
// .--|-'| | .--|-'|
|
|
// 4 2 3 4 2 3 1
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(UATTR(4), -1, "\xdd\xdd\xdd\xdd", 4,
|
|
LFSR_ATTR(UATTR(2), -1, "\xbb\xbb\xbb\xbb", 4,
|
|
LFSR_ATTR(UATTR(3), -1, "\xcc\xcc\xcc\xcc", 4,
|
|
LFSR_ATTR(UATTR(1), -1, "\xaa\xaa\xaa\xaa", 4, NULL))))) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(2), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(3), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(3));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(4), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(4));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
'''
|
|
|
|
[cases.test_rbyd_rotations]
|
|
in = 'lfs.c'
|
|
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_;
|
|
lfs_ssize_t id_;
|
|
lfs_off_t off_;
|
|
lfs_size_t size_;
|
|
|
|
// all three the same
|
|
// <y
|
|
// .-------'|
|
|
// <r | <r
|
|
// .----'| => | .----'|
|
|
// | <b | | <b
|
|
// | .-'| | | .-'|
|
|
// 1 2 3 1 2 3 4
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(UATTR(1), -1, "\xaa\xaa\xaa\xaa", 4,
|
|
LFSR_ATTR(UATTR(2), -1, "\xbb\xbb\xbb\xbb", 4,
|
|
LFSR_ATTR(UATTR(3), -1, "\xcc\xcc\xcc\xcc", 4,
|
|
LFSR_ATTR(UATTR(4), -1, "\xdd\xdd\xdd\xdd", 4, NULL))))) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(2), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(3), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(3));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(4), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(4));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
|
|
// yellow and red alt the same
|
|
// <y
|
|
// .-------'|
|
|
// <r | <r
|
|
// .----'| => | .----'|
|
|
// | <b | | >b
|
|
// | .-'| | | .-'|
|
|
// 1 2 4 1 2 4 3
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(UATTR(1), -1, "\xaa\xaa\xaa\xaa", 4,
|
|
LFSR_ATTR(UATTR(2), -1, "\xbb\xbb\xbb\xbb", 4,
|
|
LFSR_ATTR(UATTR(4), -1, "\xdd\xdd\xdd\xdd", 4,
|
|
LFSR_ATTR(UATTR(3), -1, "\xcc\xcc\xcc\xcc", 4, NULL))))) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(2), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(3), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(3));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(4), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(4));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
|
|
// yellow and black alt the same
|
|
// <y <y
|
|
// .-------'| .-------'|
|
|
// <r | >r | <r
|
|
// .----'| => | .----'| => | .-'|
|
|
// | >b | | <b | | >b
|
|
// | .-'| | | .-'| | .--|-'|
|
|
// 1 4 2 1 4 2 3 1 4 2 3
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(UATTR(1), -1, "\xaa\xaa\xaa\xaa", 4,
|
|
LFSR_ATTR(UATTR(4), -1, "\xdd\xdd\xdd\xdd", 4,
|
|
LFSR_ATTR(UATTR(2), -1, "\xbb\xbb\xbb\xbb", 4,
|
|
LFSR_ATTR(UATTR(3), -1, "\xcc\xcc\xcc\xcc", 4, NULL))))) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(2), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(3), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(3));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(4), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(4));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
|
|
// red and black alt the same
|
|
// >y <y
|
|
// .-------'| .----'|
|
|
// >r | <r | <r
|
|
// .----'| => | .----'| => | .-'|
|
|
// | <b | | <b | | >b
|
|
// | .-'| | | .-'| .--|--|-'|
|
|
// 4 1 2 4 1 2 3 4 1 2 3
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(UATTR(1), -1, "\xaa\xaa\xaa\xaa", 4,
|
|
LFSR_ATTR(UATTR(4), -1, "\xdd\xdd\xdd\xdd", 4,
|
|
LFSR_ATTR(UATTR(2), -1, "\xbb\xbb\xbb\xbb", 4,
|
|
LFSR_ATTR(UATTR(3), -1, "\xcc\xcc\xcc\xcc", 4, NULL))))) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(2), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(3), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(3));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(4), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(4));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
'''
|
|
|
|
[cases.test_rbyd_ysplits]
|
|
in = 'lfs.c'
|
|
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_;
|
|
lfs_ssize_t id_;
|
|
lfs_off_t off_;
|
|
lfs_size_t size_;
|
|
|
|
// split a yellow triple, not taking any alt
|
|
// <b
|
|
// .-'|
|
|
// <y <y |
|
|
// .-------'| .-------'| |
|
|
// | <r => | <r |
|
|
// | .----'| | .----' |
|
|
// | | <b | | <b
|
|
// | | .-'| | | .----'|
|
|
// 1 2 3 4 1 2 3 4 4
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(UATTR(1), -1, "\xaa\xaa\xaa\xaa", 4,
|
|
LFSR_ATTR(UATTR(2), -1, "\xbb\xbb\xbb\xbb", 4,
|
|
LFSR_ATTR(UATTR(3), -1, "\xcc\xcc\xcc\xcc", 4,
|
|
LFSR_ATTR(UATTR(4), -1, "\xdd\xdd\xdd\xdd", 4,
|
|
LFSR_ATTR(UATTR(4), -1, "\xdd\xdd\xdd\xdd", 4, NULL)))))) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(2), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(3), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(3));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(4), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(4));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
|
|
// split a yellow triple, taking the black alt
|
|
// <b
|
|
// .-'|
|
|
// <y <y |
|
|
// .-------'| .-------'| |
|
|
// | <r => | <r |
|
|
// | .----'| | .----' |
|
|
// | | <b | | >b
|
|
// | | .-'| | | .-'|
|
|
// 1 2 3 4 1 2 3 4 3
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(UATTR(1), -1, "\xaa\xaa\xaa\xaa", 4,
|
|
LFSR_ATTR(UATTR(2), -1, "\xbb\xbb\xbb\xbb", 4,
|
|
LFSR_ATTR(UATTR(3), -1, "\xcc\xcc\xcc\xcc", 4,
|
|
LFSR_ATTR(UATTR(4), -1, "\xdd\xdd\xdd\xdd", 4,
|
|
LFSR_ATTR(UATTR(3), -1, "\xcc\xcc\xcc\xcc", 4, NULL)))))) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(2), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(3), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(3));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(4), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(4));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
|
|
// split a yellow triple, taking the red alt
|
|
// <y >b
|
|
// .-------'| .-'|
|
|
// | <r | <b
|
|
// | .----'| => .--------|-'|
|
|
// | | <b | <b |
|
|
// | | .-'| | .-'| |
|
|
// 1 2 3 4 1 2 3 4 2
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(UATTR(1), -1, "\xaa\xaa\xaa\xaa", 4,
|
|
LFSR_ATTR(UATTR(2), -1, "\xbb\xbb\xbb\xbb", 4,
|
|
LFSR_ATTR(UATTR(3), -1, "\xcc\xcc\xcc\xcc", 4,
|
|
LFSR_ATTR(UATTR(4), -1, "\xdd\xdd\xdd\xdd", 4,
|
|
LFSR_ATTR(UATTR(2), -1, "\xbb\xbb\xbb\xbb", 4, NULL)))))) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(2), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(3), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(3));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(4), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(4));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
|
|
// split a yellow triple, taking the yellow alt
|
|
// <y >b
|
|
// .-------'| .-'|
|
|
// | <r | >b
|
|
// | .----'| => .-----|-'|
|
|
// | | <b | <b |
|
|
// | | .-'| | .-'| |
|
|
// 1 2 3 4 1 2 3 4 1
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(UATTR(1), -1, "\xaa\xaa\xaa\xaa", 4,
|
|
LFSR_ATTR(UATTR(2), -1, "\xbb\xbb\xbb\xbb", 4,
|
|
LFSR_ATTR(UATTR(3), -1, "\xcc\xcc\xcc\xcc", 4,
|
|
LFSR_ATTR(UATTR(4), -1, "\xdd\xdd\xdd\xdd", 4,
|
|
LFSR_ATTR(UATTR(1), -1, "\xaa\xaa\xaa\xaa", 4, NULL)))))) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(2), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(3), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(3));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(4), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(4));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
'''
|
|
|
|
[cases.test_rbyd_quintifoliate]
|
|
in = 'lfs.c'
|
|
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_;
|
|
lfs_ssize_t id_;
|
|
lfs_off_t off_;
|
|
lfs_size_t size_;
|
|
|
|
// split a yellow triple, not taking any alt
|
|
// <b
|
|
// .-'|
|
|
// <y |
|
|
// .-------'| |
|
|
// <y | <r |
|
|
// .-------'| => | .----' |
|
|
// | <r | | <r
|
|
// | .----'| | | .----'|
|
|
// | | <b | | | <b
|
|
// | | .-'| | | | .-'|
|
|
// 1 2 3 4 1 2 3 4 5
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(UATTR(1), -1, "\xaa\xaa\xaa\xaa", 4,
|
|
LFSR_ATTR(UATTR(2), -1, "\xbb\xbb\xbb\xbb", 4,
|
|
LFSR_ATTR(UATTR(3), -1, "\xcc\xcc\xcc\xcc", 4,
|
|
LFSR_ATTR(UATTR(4), -1, "\xdd\xdd\xdd\xdd", 4,
|
|
LFSR_ATTR(UATTR(5), -1, "\xee\xee\xee\xee", 4, NULL)))))) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(2), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(3), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(3));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(4), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(4));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(5), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(5));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
|
|
// split a yellow triple, taking the black alt
|
|
// <b
|
|
// .-'|
|
|
// <y |
|
|
// .-------'| |
|
|
// <y | <r |
|
|
// .-------'| => | .----' |
|
|
// | <r | | >r
|
|
// | .----'| | | .-'|
|
|
// | | <b | | | >b
|
|
// | | .-'| | | .--|-'|
|
|
// 1 2 4 5 1 2 4 5 3
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(UATTR(1), -1, "\xaa\xaa\xaa\xaa", 4,
|
|
LFSR_ATTR(UATTR(2), -1, "\xbb\xbb\xbb\xbb", 4,
|
|
LFSR_ATTR(UATTR(4), -1, "\xdd\xdd\xdd\xdd", 4,
|
|
LFSR_ATTR(UATTR(5), -1, "\xee\xee\xee\xee", 4,
|
|
LFSR_ATTR(UATTR(3), -1, "\xcc\xcc\xcc\xcc", 4, NULL)))))) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(2), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(3), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(3));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(4), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(4));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(5), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(5));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
|
|
// split a yellow triple, taking the red alt
|
|
// >b
|
|
// .-'|
|
|
// <y | <r
|
|
// .-------'| .--------|-'|
|
|
// | <r | | >b
|
|
// | .----'| => | .-----|-'|
|
|
// | | <b | | <b |
|
|
// | | .-'| | | .-'| |
|
|
// 1 3 4 5 1 3 4 5 2
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(UATTR(1), -1, "\xaa\xaa\xaa\xaa", 4,
|
|
LFSR_ATTR(UATTR(3), -1, "\xcc\xcc\xcc\xcc", 4,
|
|
LFSR_ATTR(UATTR(4), -1, "\xdd\xdd\xdd\xdd", 4,
|
|
LFSR_ATTR(UATTR(5), -1, "\xee\xee\xee\xee", 4,
|
|
LFSR_ATTR(UATTR(2), -1, "\xbb\xbb\xbb\xbb", 4, NULL)))))) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(2), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(3), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(3));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(4), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(4));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(5), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(5));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
|
|
// split a yellow triple, taking the yellow alt
|
|
// >b
|
|
// .-'|
|
|
// <y | >r
|
|
// .-------'| .-----|-'|
|
|
// | <r | | >b
|
|
// | .----'| => .--|-----|-'|
|
|
// | | <b | | <b |
|
|
// | | .-'| | | .-'| |
|
|
// 2 3 4 5 2 3 4 5 1
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(UATTR(2), -1, "\xbb\xbb\xbb\xbb", 4,
|
|
LFSR_ATTR(UATTR(3), -1, "\xcc\xcc\xcc\xcc", 4,
|
|
LFSR_ATTR(UATTR(4), -1, "\xdd\xdd\xdd\xdd", 4,
|
|
LFSR_ATTR(UATTR(5), -1, "\xee\xee\xee\xee", 4,
|
|
LFSR_ATTR(UATTR(1), -1, "\xaa\xaa\xaa\xaa", 4, NULL)))))) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(2), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(3), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(3));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(4), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(4));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(5), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(5));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
'''
|
|
|
|
[cases.test_rbyd_prunes]
|
|
in = 'lfs.c'
|
|
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_;
|
|
lfs_ssize_t id_;
|
|
lfs_off_t off_;
|
|
lfs_size_t size_;
|
|
|
|
// don't prune
|
|
// <b <b
|
|
// .-'| .----'|
|
|
// <y | <y |
|
|
// .-------'| | .-------'| |
|
|
// | <r | | <r |
|
|
// | .----' | => | .----' |
|
|
// | | <r | | <r
|
|
// | | .----'| | | .-------'|
|
|
// | | | <b | | | <b
|
|
// | | | .-'| | | | .----'|
|
|
// 1 2 3 4 5 1 2 3 4 5 5
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(UATTR(1), -1, "\xaa\xaa\xaa\xaa", 4,
|
|
LFSR_ATTR(UATTR(2), -1, "\xbb\xbb\xbb\xbb", 4,
|
|
LFSR_ATTR(UATTR(3), -1, "\xcc\xcc\xcc\xcc", 4,
|
|
LFSR_ATTR(UATTR(4), -1, "\xdd\xdd\xdd\xdd", 4,
|
|
LFSR_ATTR(UATTR(5), -1, "\xee\xee\xee\xee", 4,
|
|
LFSR_ATTR(UATTR(5), -1, "\xee\xee\xee\xee", 4, NULL))))))) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(2), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(3), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(3));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(4), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(4));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(5), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(5));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
|
|
// prune by taking a red alt
|
|
// <b
|
|
// .-'|
|
|
// <y | >b
|
|
// .-------'| | .-'|
|
|
// | <r | | <b
|
|
// | .----' | => .-----------|-'|
|
|
// | | <r | <r |
|
|
// | | .----'| | .----'| |
|
|
// | | | <b | | <b |
|
|
// | | | .-'| | | .-'| |
|
|
// 1 2 3 4 5 1 2 3 4 5 2
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(UATTR(1), -1, "\xaa\xaa\xaa\xaa", 4,
|
|
LFSR_ATTR(UATTR(2), -1, "\xbb\xbb\xbb\xbb", 4,
|
|
LFSR_ATTR(UATTR(3), -1, "\xcc\xcc\xcc\xcc", 4,
|
|
LFSR_ATTR(UATTR(4), -1, "\xdd\xdd\xdd\xdd", 4,
|
|
LFSR_ATTR(UATTR(5), -1, "\xee\xee\xee\xee", 4,
|
|
LFSR_ATTR(UATTR(2), -1, "\xbb\xbb\xbb\xbb", 4, NULL))))))) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(2), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(3), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(3));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(4), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(4));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(5), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(5));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
|
|
// prune by taking a yellow alt (this needs to prune during the rflip)
|
|
// <b
|
|
// .-'|
|
|
// <y | >b
|
|
// .-------'| | .-'|
|
|
// | <r | | >b
|
|
// | .----' | => .--------|-'|
|
|
// | | <r | <r |
|
|
// | | .----'| | .----'| |
|
|
// | | | <b | | <b |
|
|
// | | | .-'| | | .-'| |
|
|
// 1 2 3 4 5 1 2 3 4 5 1
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(UATTR(1), -1, "\xaa\xaa\xaa\xaa", 4,
|
|
LFSR_ATTR(UATTR(2), -1, "\xbb\xbb\xbb\xbb", 4,
|
|
LFSR_ATTR(UATTR(3), -1, "\xcc\xcc\xcc\xcc", 4,
|
|
LFSR_ATTR(UATTR(4), -1, "\xdd\xdd\xdd\xdd", 4,
|
|
LFSR_ATTR(UATTR(5), -1, "\xee\xee\xee\xee", 4,
|
|
LFSR_ATTR(UATTR(1), -1, "\xaa\xaa\xaa\xaa", 4, NULL))))))) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(2), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(3), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(3));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(4), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(4));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(5), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(5));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
'''
|
|
|
|
[cases.test_rbyd_sextifoliate]
|
|
in = 'lfs.c'
|
|
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_;
|
|
lfs_ssize_t id_;
|
|
lfs_off_t off_;
|
|
lfs_size_t size_;
|
|
|
|
// don't prune
|
|
// <b
|
|
// .----'|
|
|
// <b <y |
|
|
// .-'| .-------'| |
|
|
// <y | | <r |
|
|
// .-------'| | | .----' |
|
|
// | <r | | | <y
|
|
// | .----' | => | | .-------'|
|
|
// | | <r | | | <r
|
|
// | | .----'| | | | .----'|
|
|
// | | | <b | | | | <b
|
|
// | | | .-'| | | | | .-'|
|
|
// 1 2 3 4 5 1 2 3 4 5 6
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(UATTR(1), -1, "\xaa\xaa\xaa\xaa", 4,
|
|
LFSR_ATTR(UATTR(2), -1, "\xbb\xbb\xbb\xbb", 4,
|
|
LFSR_ATTR(UATTR(3), -1, "\xcc\xcc\xcc\xcc", 4,
|
|
LFSR_ATTR(UATTR(4), -1, "\xdd\xdd\xdd\xdd", 4,
|
|
LFSR_ATTR(UATTR(5), -1, "\xee\xee\xee\xee", 4,
|
|
LFSR_ATTR(UATTR(6), -1, "\xff\xff\xff\xff", 4, NULL))))))) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(2), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(3), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(3));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(4), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(4));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(5), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(5));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(6), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(6));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
|
|
// prune by taking a red alt
|
|
// <b >b
|
|
// .-'| .-'|
|
|
// <y | | <r
|
|
// .-------'| | .-----------|-'|
|
|
// | <r | | | >b
|
|
// | .----' | => | .--------|-'|
|
|
// | | <r | | <r |
|
|
// | | .----'| | | .----'| |
|
|
// | | | <b | | | <b |
|
|
// | | | .-'| | | | .-'| |
|
|
// 1 3 4 5 6 1 3 4 5 6 2
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(UATTR(1), -1, "\xaa\xaa\xaa\xaa", 4,
|
|
LFSR_ATTR(UATTR(3), -1, "\xcc\xcc\xcc\xcc", 4,
|
|
LFSR_ATTR(UATTR(4), -1, "\xdd\xdd\xdd\xdd", 4,
|
|
LFSR_ATTR(UATTR(5), -1, "\xee\xee\xee\xee", 4,
|
|
LFSR_ATTR(UATTR(6), -1, "\xff\xff\xff\xff", 4,
|
|
LFSR_ATTR(UATTR(2), -1, "\xbb\xbb\xbb\xbb", 4, NULL))))))) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(2), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(3), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(3));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(4), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(4));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(5), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(5));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(6), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(6));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
|
|
// prune by taking a yellow alt (this needs to prune during the rflip)
|
|
// <b >b
|
|
// .-'| .-'|
|
|
// <y | | >r
|
|
// .-------'| | .--------|-'|
|
|
// | <r | | | >b
|
|
// | .----' | => .--|--------|-'|
|
|
// | | <r | | <r |
|
|
// | | .----'| | | .----'| |
|
|
// | | | <b | | | <b |
|
|
// | | | .-'| | | | .-'| |
|
|
// 2 3 4 5 6 2 3 4 5 6 1
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(UATTR(2), -1, "\xbb\xbb\xbb\xbb", 4,
|
|
LFSR_ATTR(UATTR(3), -1, "\xcc\xcc\xcc\xcc", 4,
|
|
LFSR_ATTR(UATTR(4), -1, "\xdd\xdd\xdd\xdd", 4,
|
|
LFSR_ATTR(UATTR(5), -1, "\xee\xee\xee\xee", 4,
|
|
LFSR_ATTR(UATTR(6), -1, "\xff\xff\xff\xff", 4,
|
|
LFSR_ATTR(UATTR(1), -1, "\xaa\xaa\xaa\xaa", 4, NULL))))))) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(2), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(3), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(3));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(4), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(4));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(5), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(5));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(6), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(6));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
'''
|
|
|
|
[cases.test_rbyd_permutations]
|
|
defines.N = 'range(1, 8)'
|
|
in = 'lfs.c'
|
|
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_;
|
|
lfs_ssize_t id_;
|
|
lfs_off_t off_;
|
|
lfs_size_t size_;
|
|
|
|
// keep track of the worst case log size
|
|
lfs_size_t worst_size = 0;
|
|
|
|
// 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]);
|
|
}
|
|
printf("] ---\n");
|
|
|
|
// build the attribute list for the current permutation
|
|
struct lfsr_attr attrs[N];
|
|
for (unsigned j = 0; j < N; j++) {
|
|
attrs[j] = *LFSR_ATTR(
|
|
UATTR(perm[j]+1), -1,
|
|
"\xaa\xaa\xaa\xaa", 4,
|
|
(j+1 < N) ? &attrs[j+1] : NULL);
|
|
}
|
|
|
|
// test the given permutation
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, attrs) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
for (unsigned j = 0; j < N; j++) {
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(j+1), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(j+1));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
}
|
|
|
|
// keep track of the worst size
|
|
worst_size = lfs_max(worst_size, rbyd.off);
|
|
|
|
// 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;
|
|
}
|
|
}
|
|
|
|
// test that tree is self-balancing, we should be strictly bounded
|
|
// by height <= 2*log(n)+1, assume tags are strictly <=12 bytes
|
|
lfs_size_t n = 1 + N;
|
|
printf("worst size: %u B (N=%u, estimate=%u)\n",
|
|
worst_size, n, 12*n*(2*lfs_nlog2(n)+1)+4);
|
|
printf("avg height: %u B (N=%u, estimate=%u)\n",
|
|
worst_size / n, n, 12*(2*lfs_nlog2(n)+1)+4);
|
|
// note this only holds true with byte-level progs
|
|
if (PROG_SIZE == 1) {
|
|
assert(worst_size / n <= 12*(2*lfs_nlog2(n)+1)+4);
|
|
}
|
|
'''
|
|
|
|
[cases.test_rbyd_multi_permutations]
|
|
defines.N = 'range(1, 8)'
|
|
# large progs take too long for now
|
|
if = 'PROG_SIZE < 512'
|
|
in = 'lfs.c'
|
|
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_;
|
|
lfs_ssize_t id_;
|
|
lfs_off_t off_;
|
|
lfs_size_t size_;
|
|
|
|
// keep track of the worst case log size
|
|
lfs_size_t worst_size = 0;
|
|
|
|
// 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]);
|
|
}
|
|
printf("] ---\n");
|
|
|
|
// test the 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;
|
|
}
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
for (unsigned j = 0; j < N; j++) {
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(j+1), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(j+1));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
}
|
|
|
|
// keep track of the worst size
|
|
worst_size = lfs_max(worst_size, rbyd.off);
|
|
|
|
// 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;
|
|
}
|
|
}
|
|
|
|
// test that tree is self-balancing, we should be strictly bounded
|
|
// by height <= 2*log(n)+1, assume tags are strictly <=12 bytes
|
|
lfs_size_t n = 1 + N;
|
|
printf("worst size: %u B (N=%u, estimate=%u)\n",
|
|
worst_size, n, 12*n*(2*lfs_nlog2(n)+1)+4);
|
|
printf("avg height: %u B (N=%u, estimate=%u)\n",
|
|
worst_size / n, n, 12*(2*lfs_nlog2(n)+1)+4);
|
|
// note this only holds true with byte-level progs
|
|
if (PROG_SIZE == 1) {
|
|
assert(worst_size / n <= 12*(2*lfs_nlog2(n)+1)+4);
|
|
}
|
|
'''
|
|
|
|
[cases.test_rbyd_traverse]
|
|
in = 'lfs.c'
|
|
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_;
|
|
lfs_ssize_t id_;
|
|
lfs_off_t off_;
|
|
lfs_size_t size_;
|
|
|
|
// traverse requires correct biasing of the weights in the rbyd tree
|
|
// so that lookups return strictly the tag greater than or equal to
|
|
// the tag requested
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(UATTR(1), -1, "\xaa\xaa\xaa\xaa", 4,
|
|
LFSR_ATTR(UATTR(2), -1, "\xbb\xbb\xbb\xbb", 4, NULL))) => 0;
|
|
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(0), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, NULL, &off_, &size_) => LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(0), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, NULL, &off_, &size_) => LFS_ERR_NOENT;
|
|
|
|
// also try the other direction
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(UATTR(2), -1, "\xbb\xbb\xbb\xbb", 4,
|
|
LFSR_ATTR(UATTR(1), -1, "\xaa\xaa\xaa\xaa", 4, NULL))) => 0;
|
|
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(0), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, NULL, &off_, &size_) => LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(0), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, NULL, &off_, &size_) => LFS_ERR_NOENT;
|
|
'''
|
|
|
|
[cases.test_rbyd_multi_traverse]
|
|
in = 'lfs.c'
|
|
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_;
|
|
lfs_ssize_t id_;
|
|
lfs_off_t off_;
|
|
lfs_size_t size_;
|
|
|
|
// traverse requires correct biasing of the weights in the rbyd tree
|
|
// so that lookups return strictly the tag greater than or equal to
|
|
// the tag requested
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(UATTR(1), -1, "\xaa\xaa\xaa\xaa", 4, NULL)) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(UATTR(2), -1, "\xbb\xbb\xbb\xbb", 4, NULL)) => 0;
|
|
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(0), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, NULL, &off_, &size_) => LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(0), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, NULL, &off_, &size_) => LFS_ERR_NOENT;
|
|
|
|
// also try the other direction
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(UATTR(2), -1, "\xbb\xbb\xbb\xbb", 4, NULL)) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(UATTR(1), -1, "\xaa\xaa\xaa\xaa", 4, NULL)) => 0;
|
|
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(0), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, NULL, &off_, &size_) => LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(0), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, NULL, &off_, &size_) => LFS_ERR_NOENT;
|
|
'''
|
|
|
|
[cases.test_rbyd_traverse_permutations]
|
|
defines.N = 'range(1, 8)'
|
|
in = 'lfs.c'
|
|
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_;
|
|
lfs_ssize_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]);
|
|
}
|
|
printf("] ---\n");
|
|
|
|
// build the attribute list for the current permutation
|
|
struct lfsr_attr attrs[N];
|
|
for (unsigned j = 0; j < N; j++) {
|
|
attrs[j] = *LFSR_ATTR(
|
|
UATTR(perm[j]+1), -1,
|
|
"\xaa\xaa\xaa\xaa", 4,
|
|
(j+1 < N) ? &attrs[j+1] : NULL);
|
|
}
|
|
|
|
// test the given permutation
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, attrs) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
// try traversing all tags
|
|
tag_ = 0;
|
|
id_ = -1;
|
|
for (unsigned j = 0; j < N; j++) {
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(j+1));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
}
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, NULL, &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_multi_traverse_permutations]
|
|
defines.N = 'range(1, 8)'
|
|
# large progs take too long for now
|
|
if = 'PROG_SIZE < 512'
|
|
in = 'lfs.c'
|
|
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_;
|
|
lfs_ssize_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]);
|
|
}
|
|
printf("] ---\n");
|
|
|
|
|
|
// test the given permutation
|
|
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;
|
|
}
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
// try traversing all tags
|
|
tag_ = 0;
|
|
id_ = -1;
|
|
for (unsigned j = 0; j < N; j++) {
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(j+1));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
}
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, NULL, &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;
|
|
}
|
|
}
|
|
'''
|
|
|
|
# NOTE if we separate physical/logical block sizes we may be able to
|
|
# use emubd's copy-on-write copy to speed this up significantly
|
|
[cases.test_rbyd_update_permutations]
|
|
defines.N = 'range(1, 8)'
|
|
# large progs take too long for now
|
|
if = 'PROG_SIZE < 512'
|
|
in = 'lfs.c'
|
|
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_;
|
|
lfs_ssize_t id_;
|
|
lfs_off_t off_;
|
|
lfs_size_t size_;
|
|
|
|
// keep track of the worst case log size
|
|
lfs_size_t worst_size = 0;
|
|
|
|
// create one consistent block
|
|
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(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 = malloc(rbyd.off);
|
|
lfs_bd_read(&lfs, NULL, &lfs.rcache, rbyd.off,
|
|
rbyd.block, 0, backup_block, rbyd.off) => 0;
|
|
|
|
// 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]);
|
|
}
|
|
printf("] ---\n");
|
|
|
|
// restore backup
|
|
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;
|
|
|
|
// update each tag in permutation order
|
|
for (unsigned j = 0; j < N; j++) {
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(UATTR(perm[j]+1), -1,
|
|
"\xaa\xaa\xaa\xaa\xaa\xaa", 6,
|
|
NULL)) => 0;
|
|
}
|
|
|
|
// check that all tags have been updated
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
for (unsigned j = 0; j < N; j++) {
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(j+1), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(j+1));
|
|
assert(id_ == -1);
|
|
assert(size_ == 6);
|
|
}
|
|
|
|
// keep track of the worst size
|
|
worst_size = lfs_max(worst_size, rbyd.off);
|
|
|
|
// 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;
|
|
}
|
|
}
|
|
|
|
// cleanup
|
|
free(backup_block);
|
|
|
|
// test that tree is self-balancing, we should be strictly bounded
|
|
// by height <= 2*log(n)+1, assume tags are strictly <=12 bytes
|
|
lfs_size_t n = 1 + N + N;
|
|
printf("worst size: %u B (N=%u, estimate=%u)\n",
|
|
worst_size, n, 12*n*(2*lfs_nlog2(n)+1)+4);
|
|
printf("avg height: %u B (N=%u, estimate=%u)\n",
|
|
worst_size / n, n, 12*(2*lfs_nlog2(n)+1)+4);
|
|
// note this only holds true with byte-level progs
|
|
if (PROG_SIZE == 1) {
|
|
assert(worst_size / n <= 12*(2*lfs_nlog2(n)+1)+4);
|
|
}
|
|
'''
|
|
|
|
[cases.test_rbyd_large]
|
|
in = 'lfs.c'
|
|
# ORDER:
|
|
# 0 = in-order
|
|
# 1 = reverse-order
|
|
# 2 = random-order
|
|
defines.ORDER = [0, 1, 2]
|
|
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_;
|
|
lfs_ssize_t id_;
|
|
lfs_off_t off_;
|
|
lfs_size_t size_;
|
|
|
|
// create the rbyd tree
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
|
|
// keep appending tags until we run out of space
|
|
//
|
|
// note, this will likely repeat tags, but that's ok
|
|
//
|
|
lfs_size_t count = 0;
|
|
uint32_t prng = 42;
|
|
for (lfs_size_t i = 0;; i++) {
|
|
uint8_t x
|
|
= (ORDER == 0) ? (uint8_t)i
|
|
: (ORDER == 1) ? (uint8_t)(((lfs_size_t)-1) - i)
|
|
: (uint8_t)TEST_PRNG(&prng);
|
|
int err = lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(UATTR(x), -1, "\xaa\xaa\xaa\xaa", 4,
|
|
NULL));
|
|
if (err == LFS_ERR_RANGE) {
|
|
break;
|
|
}
|
|
assert(err == 0);
|
|
|
|
count = i;
|
|
}
|
|
|
|
// check that we can still lookup all the tags
|
|
prng = 42;
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
for (lfs_size_t i = 0; i < count; i++) {
|
|
uint8_t x
|
|
= (ORDER == 0) ? (uint8_t)i
|
|
: (ORDER == 1) ? (uint8_t)(((lfs_size_t)-1) - i)
|
|
: (uint8_t)TEST_PRNG(&prng);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(x), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(x));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
}
|
|
'''
|
|
|
|
|
|
### Removal testing ###
|
|
|
|
[cases.test_rbyd_remove]
|
|
in = 'lfs.c'
|
|
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_;
|
|
lfs_ssize_t id_;
|
|
lfs_off_t off_;
|
|
lfs_size_t size_;
|
|
|
|
// add and remove one attribute
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(UATTR(1), -1, "\xaa\xaa\xaa\xaa", 4, NULL)) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(RMUATTR(1), -1, NULL, 0, NULL)) => 0;
|
|
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => LFS_ERR_NOENT;
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(2), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => LFS_ERR_NOENT;
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(2), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => LFS_ERR_NOENT;
|
|
|
|
// commit with two attributes, remove the first one
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(UATTR(1), -1, "\xaa\xaa\xaa\xaa", 4,
|
|
LFSR_ATTR(UATTR(2), -1, "\xbb\xbb\xbb\xbb", 4, NULL))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(RMUATTR(1), -1, NULL, 0, NULL)) => 0;
|
|
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(2), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(3), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(2), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(3), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => LFS_ERR_NOENT;
|
|
|
|
// commit with two attributes, remove the second one
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(UATTR(1), -1, "\xaa\xaa\xaa\xaa", 4,
|
|
LFSR_ATTR(UATTR(2), -1, "\xbb\xbb\xbb\xbb", 4, NULL))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(RMUATTR(2), -1, NULL, 0, NULL)) => 0;
|
|
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(2), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => LFS_ERR_NOENT;
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(3), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(2), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => LFS_ERR_NOENT;
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(3), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => LFS_ERR_NOENT;
|
|
'''
|
|
|
|
# NOTE if we separate physical/logical block sizes we may be able to
|
|
# use emubd's copy-on-write copy to speed this up significantly
|
|
[cases.test_rbyd_remove_permutations]
|
|
defines.N = 'range(1, 7)'
|
|
# large progs take too long for now
|
|
if = 'PROG_SIZE < 512'
|
|
in = 'lfs.c'
|
|
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_;
|
|
lfs_ssize_t id_;
|
|
lfs_off_t off_;
|
|
lfs_size_t size_;
|
|
|
|
// keep track of the worst case log size
|
|
lfs_size_t worst_size = 0;
|
|
|
|
// 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]);
|
|
}
|
|
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 = malloc(rbyd.off);
|
|
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);
|
|
|
|
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;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block,
|
|
cfg->block_size, NULL) => 0;
|
|
for (unsigned k = 0; k < N; k++) {
|
|
int err = lfsr_rbyd_lookup(&lfs, &rbyd,
|
|
LFSR_TAG_UATTR(k+1), -1,
|
|
&tag_, &id_, NULL, &off_, &size_);
|
|
assert(!err || err == LFS_ERR_NOENT);
|
|
if (k == j) {
|
|
if (j == N-1) {
|
|
assert(err == LFS_ERR_NOENT);
|
|
} else {
|
|
assert(!err);
|
|
assert(tag_ == LFSR_TAG_UATTR(j+1+1));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
}
|
|
} else {
|
|
assert(tag_ == LFSR_TAG_UATTR(k+1));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
}
|
|
}
|
|
|
|
// try appending the tag back to make sure things still work
|
|
printf("--- append: %d ---\n", j);
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(UATTR(j+1), -1, "\xaa\xaa\xaa\xaa\xaa\xaa", 6,
|
|
NULL)) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block,
|
|
cfg->block_size, NULL) => 0;
|
|
for (unsigned k = 0; k < N; k++) {
|
|
lfsr_rbyd_lookup(&lfs, &rbyd,
|
|
LFSR_TAG_UATTR(k+1), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
if (k == j) {
|
|
assert(tag_ == LFSR_TAG_UATTR(k+1));
|
|
assert(id_ == -1);
|
|
assert(size_ == 6);
|
|
} else {
|
|
assert(tag_ == LFSR_TAG_UATTR(k+1));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
}
|
|
}
|
|
|
|
// keep track of the worst size
|
|
worst_size = lfs_max(worst_size, rbyd.off);
|
|
}
|
|
|
|
// cleanup
|
|
free(backup_block);
|
|
|
|
// 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;
|
|
}
|
|
}
|
|
|
|
// test that tree is self-balancing, we should be strictly bounded
|
|
// by height <= 2*log(n)+1, assume tags are strictly <=12 bytes
|
|
lfs_size_t n = 1 + N + 2;
|
|
printf("worst size: %u B (N=%u, estimate=%u)\n",
|
|
worst_size, n, 12*n*(2*lfs_nlog2(n)+1)+4);
|
|
printf("avg height: %u B (N=%u, estimate=%u)\n",
|
|
worst_size / n, n, 12*(2*lfs_nlog2(n)+1)+4);
|
|
// note this only holds true with byte-level progs
|
|
if (PROG_SIZE == 1) {
|
|
assert(worst_size / n <= 12*(2*lfs_nlog2(n)+1)+4);
|
|
}
|
|
'''
|
|
|
|
# NOTE if we separate physical/logical block sizes we may be able to
|
|
# use emubd's copy-on-write copy to speed this up significantly
|
|
[cases.test_rbyd_remove_traverse_permutations]
|
|
defines.N = 'range(1, 7)'
|
|
# large progs take too long for now
|
|
if = 'PROG_SIZE < 512'
|
|
in = 'lfs.c'
|
|
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_;
|
|
lfs_ssize_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]);
|
|
}
|
|
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 = malloc(rbyd.off);
|
|
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);
|
|
|
|
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_, NULL, &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_, NULL, &off_, &size_) => LFS_ERR_NOENT;
|
|
}
|
|
|
|
// cleanup
|
|
free(backup_block);
|
|
|
|
// 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]
|
|
in = 'lfs.c'
|
|
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_;
|
|
lfs_ssize_t id_;
|
|
lfs_off_t off_;
|
|
lfs_size_t size_;
|
|
|
|
// create a tree two attributes
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(UATTR(2), -1, "\xbb\xbb\xbb\xbb", 4,
|
|
LFSR_ATTR(UATTR(4), -1, "\xdd\xdd\xdd\xdd", 4,
|
|
NULL))) => 0;
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(2), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(3), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(4));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(4), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(4));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(5), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => LFS_ERR_NOENT;
|
|
|
|
// try to remove tags that aren't there, this should do nothing
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(RMUATTR(1), -1, NULL, 0, NULL)) => 0;
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(2), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(3), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(4));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(4), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(4));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(5), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(RMUATTR(3), -1, NULL, 0, NULL)) => 0;
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(2), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(3), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(4));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(4), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(4));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(5), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(RMUATTR(5), -1, NULL, 0, NULL)) => 0;
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(2), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(3), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(4));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(4), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(4));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(5), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => LFS_ERR_NOENT;
|
|
|
|
// one last fetch to make sure nothing was broken
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(2), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(3), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(4));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(4), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(4));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(5), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => LFS_ERR_NOENT;
|
|
'''
|
|
|
|
[cases.test_rbyd_remove_again]
|
|
in = 'lfs.c'
|
|
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_;
|
|
lfs_ssize_t id_;
|
|
lfs_off_t off_;
|
|
lfs_size_t size_;
|
|
|
|
// create a tree
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(UATTR(1), -1, "\xaa\xaa\xaa\xaa", 4,
|
|
LFSR_ATTR(UATTR(2), -1, "\xbb\xbb\xbb\xbb", 4,
|
|
LFSR_ATTR(UATTR(3), -1, "\xcc\xcc\xcc\xcc", 4,
|
|
LFSR_ATTR(UATTR(4), -1, "\xdd\xdd\xdd\xdd", 4,
|
|
LFSR_ATTR(UATTR(5), -1, "\xee\xee\xee\xee", 4,
|
|
NULL)))))) => 0;
|
|
// remove several attributes
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(RMUATTR(1), -1, NULL, 0,
|
|
LFSR_ATTR(RMUATTR(3), -1, NULL, 0,
|
|
LFSR_ATTR(RMUATTR(5), -1, NULL, 0, NULL)))) => 0;
|
|
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(2), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(3), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(4));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(4), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(4));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(5), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => LFS_ERR_NOENT;
|
|
|
|
// try to remove tags that aren't there, this should do nothing
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(RMUATTR(1), -1, NULL, 0, NULL)) => 0;
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(2), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(3), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(4));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(4), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(4));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(5), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(RMUATTR(3), -1, NULL, 0, NULL)) => 0;
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(2), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(3), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(4));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(4), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(4));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(5), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(RMUATTR(5), -1, NULL, 0, NULL)) => 0;
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(2), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(3), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(4));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(4), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(4));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(5), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => LFS_ERR_NOENT;
|
|
|
|
// try to remove the tags again, just to make sure (keep in mind
|
|
// these removes still commit to the rbyd)
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(RMUATTR(1), -1, NULL, 0, NULL)) => 0;
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(2), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(3), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(4));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(4), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(4));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(5), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(RMUATTR(3), -1, NULL, 0, NULL)) => 0;
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(2), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(3), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(4));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(4), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(4));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(5), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(RMUATTR(5), -1, NULL, 0, NULL)) => 0;
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(2), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(3), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(4));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(4), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(4));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(5), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => LFS_ERR_NOENT;
|
|
|
|
// one last fetch to make sure nothing was broken
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(2), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(3), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(4));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(4), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(4));
|
|
assert(id_ == -1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(5), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => LFS_ERR_NOENT;
|
|
'''
|
|
|
|
[cases.test_rbyd_remove_all]
|
|
in = 'lfs.c'
|
|
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_;
|
|
lfs_ssize_t id_;
|
|
lfs_off_t off_;
|
|
lfs_size_t size_;
|
|
|
|
// commit with one attribute, remove it
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(UATTR(1), -1, "\xaa\xaa\xaa\xaa", 4, NULL)) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(RMUATTR(1), -1, NULL, 0, NULL)) => 0;
|
|
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => LFS_ERR_NOENT;
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(2), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => LFS_ERR_NOENT;
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(2), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => LFS_ERR_NOENT;
|
|
|
|
// commit with two attributes, remove both
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(UATTR(1), -1, "\xaa\xaa\xaa\xaa", 4,
|
|
LFSR_ATTR(UATTR(2), -1, "\xbb\xbb\xbb\xbb", 4, NULL))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(RMUATTR(1), -1, NULL, 0,
|
|
LFSR_ATTR(RMUATTR(2), -1, NULL, 0, NULL))) => 0;
|
|
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => LFS_ERR_NOENT;
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(2), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => LFS_ERR_NOENT;
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(2), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => LFS_ERR_NOENT;
|
|
|
|
// commit with two attributes, remove both in the other order
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(UATTR(1), -1, "\xaa\xaa\xaa\xaa", 4,
|
|
LFSR_ATTR(UATTR(2), -1, "\xbb\xbb\xbb\xbb", 4, NULL))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(RMUATTR(2), -1, NULL, 0,
|
|
LFSR_ATTR(RMUATTR(1), -1, NULL, 0, NULL))) => 0;
|
|
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => LFS_ERR_NOENT;
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(2), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => LFS_ERR_NOENT;
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(2), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => LFS_ERR_NOENT;
|
|
'''
|
|
|
|
# NOTE if we separate physical/logical block sizes we may be able to
|
|
# use emubd's copy-on-write copy to speed this up significantly
|
|
[cases.test_rbyd_remove_all_permutations]
|
|
defines.N = 'range(1, 7)'
|
|
# large progs take too long for now
|
|
if = 'PROG_SIZE < 512'
|
|
in = 'lfs.c'
|
|
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_;
|
|
lfs_ssize_t id_;
|
|
lfs_off_t off_;
|
|
lfs_size_t size_;
|
|
|
|
// keep track of the worst case log size
|
|
lfs_size_t worst_size = 0;
|
|
|
|
// create one consistent block
|
|
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(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 = malloc(rbyd.off);
|
|
lfs_bd_read(&lfs, NULL, &lfs.rcache, rbyd.off,
|
|
rbyd.block, 0, backup_block, rbyd.off) => 0;
|
|
|
|
// 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]);
|
|
}
|
|
printf("] ---\n");
|
|
|
|
// restore backup
|
|
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;
|
|
|
|
// remove each tag in permutation order
|
|
for (unsigned j = 0; j < N; j++) {
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(RMUATTR(perm[j]+1), -1, NULL, 0, NULL)) => 0;
|
|
}
|
|
|
|
// check that all tags are now removed
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
for (unsigned j = 0; j < N; j++) {
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(j+1), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => LFS_ERR_NOENT;
|
|
}
|
|
|
|
// try resuming from all tags being removed
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(UATTR(1), -1, "\xaa\xaa\xaa\xaa\xaa\xaa", 6,
|
|
NULL)) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == -1);
|
|
assert(size_ == 6);
|
|
for (unsigned j = 1; j < N; j++) {
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(j+1), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => LFS_ERR_NOENT;
|
|
}
|
|
|
|
// keep track of the worst size
|
|
worst_size = lfs_max(worst_size, rbyd.off);
|
|
|
|
// 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;
|
|
}
|
|
}
|
|
|
|
// cleanup
|
|
free(backup_block);
|
|
|
|
// test that tree is self-balancing, we should be strictly bounded
|
|
// by height <= 2*log(n)+1, assume tags are strictly <=12 bytes
|
|
lfs_size_t n = 1 + N + N + 1;
|
|
printf("worst size: %u B (N=%u, estimate=%u)\n",
|
|
worst_size, n, 12*n*(2*lfs_nlog2(n)+1)+4);
|
|
printf("avg height: %u B (N=%u, estimate=%u)\n",
|
|
worst_size / n, n, 12*(2*lfs_nlog2(n)+1)+4);
|
|
// note this only holds true with byte-level progs
|
|
if (PROG_SIZE == 1) {
|
|
assert(worst_size / n <= 12*(2*lfs_nlog2(n)+1)+4);
|
|
}
|
|
'''
|
|
|
|
# the main purpose of this test is to try to fuzz for failures in the
|
|
# balancing algorithm
|
|
[cases.test_rbyd_random_append_removes]
|
|
defines.N = 'range(1, 33)'
|
|
defines.ITER = 1000
|
|
# large progs take too long for now
|
|
if = 'PROG_SIZE < 512'
|
|
in = 'lfs.c'
|
|
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 char *alpha = "abcdefghijklmnopqrstuvwxyz";
|
|
uint8_t buffer[4];
|
|
|
|
// keep track of the worst case size and seed
|
|
lfs_size_t worst_size = 0;
|
|
uint32_t worst_seed = 0;
|
|
|
|
// iterate through seeds so we can reproduce easily
|
|
for (uint32_t seed = 1; seed < ITER+1; seed++) {
|
|
printf("--- seed: %d ---\n", seed);
|
|
printf("perm: [");
|
|
uint32_t prng = seed;
|
|
for (unsigned i = 0; i < N; i++) {
|
|
// choose an attr
|
|
uint8_t attr = TEST_PRNG(&prng) % N;
|
|
// choose append or remove
|
|
if (TEST_PRNG(&prng) & 1) {
|
|
printf("a0x%02x=%c", attr, alpha[i % 26]);
|
|
} else {
|
|
printf("r0x%02x", attr);
|
|
}
|
|
if (i < N-1) {
|
|
printf(", ");
|
|
}
|
|
}
|
|
printf("]\n");
|
|
|
|
// set up a simulation to compare against
|
|
char *sim = malloc(N);
|
|
memset(sim, 0, N);
|
|
|
|
// set up rbyd block
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
|
|
prng = seed;
|
|
for (unsigned i = 0; i < N; i++) {
|
|
// choose an attr
|
|
uint8_t attr = TEST_PRNG(&prng) % N;
|
|
// choose append or remove
|
|
if (TEST_PRNG(&prng) & 1) {
|
|
// update our sim
|
|
sim[attr] = alpha[i % 26];
|
|
// update our rbyd
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(UATTR(attr), -1, &alpha[i % 26], 1,
|
|
NULL)) => 0;
|
|
} else {
|
|
// update our sim
|
|
sim[attr] = '\0';
|
|
// update our rbyd
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(RMUATTR(attr), -1, NULL, 0,
|
|
NULL)) => 0;
|
|
}
|
|
}
|
|
|
|
// compare rbyd vs simulation
|
|
printf("expd: [");
|
|
bool first = true;
|
|
for (unsigned attr = 0; attr < N; attr++) {
|
|
if (sim[attr]) {
|
|
if (!first) {
|
|
printf(", ");
|
|
}
|
|
first = false;
|
|
printf("0x%02x=%c", attr, sim[attr]);
|
|
}
|
|
}
|
|
printf("]\n");
|
|
printf("rbyd: [");
|
|
first = true;
|
|
for (unsigned attr = 0; attr < N; attr++) {
|
|
lfs_ssize_t size = lfsr_rbyd_get(&lfs, &rbyd,
|
|
LFSR_TAG_UATTR(attr), -1, buffer, 4);
|
|
if (size >= 0) {
|
|
if (!first) {
|
|
printf(", ");
|
|
}
|
|
first = false;
|
|
printf("0x%02x=%.*s", attr, size, buffer);
|
|
}
|
|
}
|
|
printf("]\n");
|
|
|
|
for (unsigned attr = 0; attr < N; attr++) {
|
|
lfs_ssize_t size = lfsr_rbyd_get(&lfs, &rbyd,
|
|
LFSR_TAG_UATTR(attr), -1, buffer, 4);
|
|
if (sim[attr]) {
|
|
assert(size == 1);
|
|
assert(memcmp(&sim[attr], buffer, 1) == 0);
|
|
} else {
|
|
assert(size == LFS_ERR_NOENT);
|
|
}
|
|
}
|
|
|
|
// keep track of the worst permutation
|
|
if (rbyd.off > worst_size) {
|
|
worst_size = rbyd.off;
|
|
worst_seed = seed;
|
|
}
|
|
|
|
// cleanup
|
|
free(sim);
|
|
}
|
|
|
|
// print the worst seed + size, and rerun it so it's left on the disk
|
|
// if used with -ddisk
|
|
printf("--- worst ---\n");
|
|
printf("worst_seed: %d\n", worst_seed);
|
|
printf("worst_size: %d\n", worst_size);
|
|
printf("worst_perm: [");
|
|
uint32_t prng = worst_seed;
|
|
for (unsigned i = 0; i < N; i++) {
|
|
// choose an attr
|
|
uint8_t attr = TEST_PRNG(&prng) % N;
|
|
// choose append or remove
|
|
if (TEST_PRNG(&prng) & 1) {
|
|
printf("a0x%02x=%c", attr, alpha[i % 26]);
|
|
} else {
|
|
printf("r0x%02x", attr);
|
|
}
|
|
if (i < N-1) {
|
|
printf(", ");
|
|
}
|
|
}
|
|
printf("]\n");
|
|
|
|
// set up rbyd block
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
|
|
prng = worst_seed;
|
|
for (unsigned i = 0; i < N; i++) {
|
|
// choose an attr
|
|
uint8_t attr = TEST_PRNG(&prng) % N;
|
|
// choose append or remove
|
|
if (TEST_PRNG(&prng) & 1) {
|
|
// update our rbyd
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(UATTR(attr), -1, &alpha[i % 26], 1,
|
|
NULL)) => 0;
|
|
} else {
|
|
// update our rbyd
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(RMUATTR(attr), -1, NULL, 0,
|
|
NULL)) => 0;
|
|
}
|
|
}
|
|
|
|
// our tree should be strictly <= 2*log(n)+1, assume tags are strictly
|
|
// <=12 bytes, note this only holds true with byte-level progs
|
|
if (PROG_SIZE == 1) {
|
|
assert(worst_size <= N*12*(2*lfs_nlog2(N)+1)+1);
|
|
}
|
|
'''
|
|
|
|
|
|
### Insertion testing ###
|
|
|
|
[cases.test_rbyd_create]
|
|
in = 'lfs.c'
|
|
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;
|
|
uint8_t buffer[4];
|
|
|
|
// try to create one id
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(GROW, 0, NULL, 1,
|
|
LFSR_ATTR(MKREG, 0, "\xaa\xaa\xaa\xaa", 4, NULL))) => 0;
|
|
|
|
assert(rbyd.weight == 1);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 0, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
assert(rbyd.weight == 1);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 0, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
|
|
// try to create two ids
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(GROW, 0, NULL, 1,
|
|
LFSR_ATTR(MKREG, 0, "\xaa\xaa\xaa\xaa", 4,
|
|
LFSR_ATTR(GROW, 1, NULL, 1,
|
|
LFSR_ATTR(MKREG, 1, "\xbb\xbb\xbb\xbb", 4, NULL))))) => 0;
|
|
|
|
assert(rbyd.weight == 2);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 0, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 1, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
assert(rbyd.weight == 2);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 0, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 1, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
|
|
// try to create two in the other direction
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(GROW, 0, NULL, 1,
|
|
LFSR_ATTR(MKREG, 0, "\xbb\xbb\xbb\xbb", 4,
|
|
LFSR_ATTR(GROW, 0, NULL, 1,
|
|
LFSR_ATTR(MKREG, 0, "\xaa\xaa\xaa\xaa", 4, NULL))))) => 0;
|
|
|
|
assert(rbyd.weight == 2);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 0, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 1, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
assert(rbyd.weight == 2);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 0, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 1, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
|
|
// create a third to the right
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(GROW, 0, NULL, 1,
|
|
LFSR_ATTR(MKREG, 0, "\xaa\xaa\xaa\xaa", 4,
|
|
LFSR_ATTR(GROW, 1, NULL, 1,
|
|
LFSR_ATTR(MKREG, 1, "\xbb\xbb\xbb\xbb", 4,
|
|
LFSR_ATTR(GROW, 2, NULL, 1,
|
|
LFSR_ATTR(MKREG, 2, "\xcc\xcc\xcc\xcc", 4, NULL))))))) => 0;
|
|
|
|
assert(rbyd.weight == 3);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 0, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 1, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 2, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
assert(rbyd.weight == 3);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 0, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 1, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 2, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
|
|
|
|
// create a third to the left
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(GROW, 0, NULL, 1,
|
|
LFSR_ATTR(MKREG, 0, "\xbb\xbb\xbb\xbb", 4,
|
|
LFSR_ATTR(GROW, 1, NULL, 1,
|
|
LFSR_ATTR(MKREG, 1, "\xcc\xcc\xcc\xcc", 4,
|
|
LFSR_ATTR(GROW, 0, NULL, 1,
|
|
LFSR_ATTR(MKREG, 0, "\xaa\xaa\xaa\xaa", 4, NULL))))))) => 0;
|
|
|
|
assert(rbyd.weight == 3);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 0, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 1, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 2, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
assert(rbyd.weight == 3);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 0, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 1, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 2, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
|
|
|
|
// create a third in the middle
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(GROW, 0, NULL, 1,
|
|
LFSR_ATTR(MKREG, 0, "\xaa\xaa\xaa\xaa", 4,
|
|
LFSR_ATTR(GROW, 1, NULL, 1,
|
|
LFSR_ATTR(MKREG, 1, "\xcc\xcc\xcc\xcc", 4,
|
|
LFSR_ATTR(GROW, 1, NULL, 1,
|
|
LFSR_ATTR(MKREG, 1, "\xbb\xbb\xbb\xbb", 4, NULL))))))) => 0;
|
|
|
|
assert(rbyd.weight == 3);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 0, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 1, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 2, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
assert(rbyd.weight == 3);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 0, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 1, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 2, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
|
|
'''
|
|
|
|
[cases.test_rbyd_multi_create]
|
|
in = 'lfs.c'
|
|
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;
|
|
uint8_t buffer[4];
|
|
|
|
// try to create one id
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(GROW, 0, NULL, 1,
|
|
LFSR_ATTR(MKREG, 0, "\xaa\xaa\xaa\xaa", 4, NULL))) => 0;
|
|
|
|
assert(rbyd.weight == 1);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 0, buffer, 4)
|
|
=> 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
assert(rbyd.weight == 1);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 0, buffer, 4)
|
|
=> 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
|
|
// try to create two ids
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(GROW, 0, NULL, 1,
|
|
LFSR_ATTR(MKREG, 0, "\xaa\xaa\xaa\xaa", 4, NULL))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(GROW, 1, NULL, 1,
|
|
LFSR_ATTR(MKREG, 1, "\xbb\xbb\xbb\xbb", 4, NULL))) => 0;
|
|
|
|
assert(rbyd.weight == 2);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 0, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 1, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
assert(rbyd.weight == 2);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 0, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 1, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
|
|
// try to create two in the other direction
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(GROW, 0, NULL, 1,
|
|
LFSR_ATTR(MKREG, 0, "\xbb\xbb\xbb\xbb", 4, NULL))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(GROW, 0, NULL, 1,
|
|
LFSR_ATTR(MKREG, 0, "\xaa\xaa\xaa\xaa", 4, NULL))) => 0;
|
|
|
|
assert(rbyd.weight == 2);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 0, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 1, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
assert(rbyd.weight == 2);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 0, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 1, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
|
|
// create a third to the right
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(GROW, 0, NULL, 1,
|
|
LFSR_ATTR(MKREG, 0, "\xaa\xaa\xaa\xaa", 4, NULL))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(GROW, 1, NULL, 1,
|
|
LFSR_ATTR(MKREG, 1, "\xbb\xbb\xbb\xbb", 4, NULL))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(GROW, 2, NULL, 1,
|
|
LFSR_ATTR(MKREG, 2, "\xcc\xcc\xcc\xcc", 4, NULL))) => 0;
|
|
|
|
assert(rbyd.weight == 3);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 0, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 1, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 2, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
assert(rbyd.weight == 3);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 0, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 1, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 2, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
|
|
|
|
// create a third to the left
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(GROW, 0, NULL, 1,
|
|
LFSR_ATTR(MKREG, 0, "\xbb\xbb\xbb\xbb", 4, NULL))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(GROW, 1, NULL, 1,
|
|
LFSR_ATTR(MKREG, 1, "\xcc\xcc\xcc\xcc", 4, NULL))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(GROW, 0, NULL, 1,
|
|
LFSR_ATTR(MKREG, 0, "\xaa\xaa\xaa\xaa", 4, NULL))) => 0;
|
|
|
|
assert(rbyd.weight == 3);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 0, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 1, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 2, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
assert(rbyd.weight == 3);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 0, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 1, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 2, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
|
|
|
|
// create a third in the middle
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(GROW, 0, NULL, 1,
|
|
LFSR_ATTR(MKREG, 0, "\xaa\xaa\xaa\xaa", 4, NULL))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(GROW, 1, NULL, 1,
|
|
LFSR_ATTR(MKREG, 1, "\xcc\xcc\xcc\xcc", 4, NULL))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(GROW, 1, NULL, 1,
|
|
LFSR_ATTR(MKREG, 1, "\xbb\xbb\xbb\xbb", 4, NULL))) => 0;
|
|
|
|
assert(rbyd.weight == 3);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 0, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 1, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 2, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
assert(rbyd.weight == 3);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 0, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 1, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 2, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
|
|
'''
|
|
|
|
[cases.test_rbyd_create_permutations]
|
|
defines.N = 'range(1, 8)'
|
|
in = 'lfs.c'
|
|
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",
|
|
};
|
|
uint8_t buffer[4];
|
|
|
|
// keep track of the worst case log size
|
|
lfs_size_t worst_size = 0;
|
|
|
|
// 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]);
|
|
}
|
|
printf("] ---\n");
|
|
|
|
// build the attribute list for the current permutation
|
|
struct lfsr_attr attrs[2*N];
|
|
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;
|
|
}
|
|
}
|
|
|
|
attrs[2*j+0] = *LFSR_ATTR(
|
|
GROW, id, NULL, 1,
|
|
(2*j+1 < 2*N) ? &attrs[2*j+1] : NULL);
|
|
attrs[2*j+1] = *LFSR_ATTR(
|
|
MKREG, id, names[perm[j] % 6], 4,
|
|
(2*j+2 < 2*N) ? &attrs[2*j+2] : NULL);
|
|
}
|
|
|
|
// test the given permutation
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, attrs) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
assert(rbyd.weight == N);
|
|
for (unsigned j = 0; j < N; j++) {
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, j, buffer, 4) => 4;
|
|
assert(memcmp(buffer, names[j % 6], 4) == 0);
|
|
}
|
|
|
|
// keep track of the worst size
|
|
worst_size = lfs_max(worst_size, rbyd.off);
|
|
|
|
// 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;
|
|
}
|
|
}
|
|
|
|
// test that tree is self-balancing, we should be strictly bounded
|
|
// by height <= 2*log(n)+1, assume tags are strictly <=12 bytes
|
|
lfs_size_t n = 1 + N;
|
|
printf("worst size: %u B (N=%u, estimate=%u)\n",
|
|
worst_size, n, 12*n*(2*lfs_nlog2(n)+1)+4);
|
|
printf("avg height: %u B (N=%u, estimate=%u)\n",
|
|
worst_size / n, n, 12*(2*lfs_nlog2(n)+1)+4);
|
|
// note this only holds true with byte-level progs
|
|
if (PROG_SIZE == 1) {
|
|
assert(worst_size / n <= 12*(2*lfs_nlog2(n)+1)+4);
|
|
}
|
|
'''
|
|
|
|
[cases.test_rbyd_multi_create_permutations]
|
|
defines.N = 'range(1, 8)'
|
|
# large progs take too long for now
|
|
if = 'PROG_SIZE < 512'
|
|
in = 'lfs.c'
|
|
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",
|
|
};
|
|
uint8_t buffer[4];
|
|
|
|
// keep track of the worst case log size
|
|
lfs_size_t worst_size = 0;
|
|
|
|
// 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]);
|
|
}
|
|
printf("] ---\n");
|
|
|
|
// test the 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(GROW, id, NULL, 1,
|
|
LFSR_ATTR(MKREG, id, names[perm[j] % 6], 4,
|
|
NULL))) => 0;
|
|
}
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
assert(rbyd.weight == N);
|
|
for (unsigned j = 0; j < N; j++) {
|
|
lfsr_rbyd_get(&lfs, &rbyd,
|
|
LFSR_TAG_MKREG, j, buffer, 4) => 4;
|
|
assert(memcmp(buffer, names[j % 6], 4) == 0);
|
|
}
|
|
|
|
// keep track of the worst size
|
|
worst_size = lfs_max(worst_size, rbyd.off);
|
|
|
|
// 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;
|
|
}
|
|
}
|
|
|
|
// test that tree is self-balancing, we should be strictly bounded
|
|
// by height <= 2*log(n)+1, assume tags are strictly <=12 bytes
|
|
lfs_size_t n = 1 + N;
|
|
printf("worst size: %u B (N=%u, estimate=%u)\n",
|
|
worst_size, n, 12*n*(2*lfs_nlog2(n)+1)+4);
|
|
printf("avg height: %u B (N=%u, estimate=%u)\n",
|
|
worst_size / n, n, 12*(2*lfs_nlog2(n)+1)+4);
|
|
// note this only holds true with byte-level progs
|
|
if (PROG_SIZE == 1) {
|
|
assert(worst_size / n <= 12*(2*lfs_nlog2(n)+1)+4);
|
|
}
|
|
'''
|
|
|
|
[cases.test_rbyd_create_traverse]
|
|
in = 'lfs.c'
|
|
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_;
|
|
lfs_ssize_t id_;
|
|
lfs_off_t off_;
|
|
lfs_size_t size_;
|
|
uint8_t buffer[4];
|
|
|
|
// traverse requires correct biasing of the weights in the rbyd tree
|
|
// so that lookups return strictly the tag greater than or equal to
|
|
// the tag requested
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(GROW, 0, NULL, 1,
|
|
LFSR_ATTR(MKREG, 0, "\xaa\xaa\xaa\xaa", 4,
|
|
LFSR_ATTR(GROW, 1, NULL, 1,
|
|
LFSR_ATTR(MKREG, 1, "\xbb\xbb\xbb\xbb", 4, NULL))))) => 0;
|
|
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(0), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 0);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_get(&lfs, &rbyd, tag_, id_, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_get(&lfs, &rbyd, tag_, id_, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, NULL, &off_, &size_) => LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(0), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 0);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_get(&lfs, &rbyd, tag_, id_, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_get(&lfs, &rbyd, tag_, id_, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, NULL, &off_, &size_) => LFS_ERR_NOENT;
|
|
|
|
// also try the other direction
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(GROW, 0, NULL, 1,
|
|
LFSR_ATTR(MKREG, 0, "\xbb\xbb\xbb\xbb", 4,
|
|
LFSR_ATTR(GROW, 0, NULL, 1,
|
|
LFSR_ATTR(MKREG, 0, "\xaa\xaa\xaa\xaa", 4, NULL))))) => 0;
|
|
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(0), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 0);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_get(&lfs, &rbyd, tag_, id_, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_get(&lfs, &rbyd, tag_, id_, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, NULL, &off_, &size_) => LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(0), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 0);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_get(&lfs, &rbyd, tag_, id_, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_get(&lfs, &rbyd, tag_, id_, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, NULL, &off_, &size_) => LFS_ERR_NOENT;
|
|
'''
|
|
|
|
[cases.test_rbyd_multi_create_traverse]
|
|
in = 'lfs.c'
|
|
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_;
|
|
lfs_ssize_t id_;
|
|
lfs_off_t off_;
|
|
lfs_size_t size_;
|
|
uint8_t buffer[4];
|
|
|
|
// traverse requires correct biasing of the weights in the rbyd tree
|
|
// so that lookups return strictly the tag greater than or equal to
|
|
// the tag requested
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(GROW, 0, NULL, 1,
|
|
LFSR_ATTR(MKREG, 0, "\xaa\xaa\xaa\xaa", 4, NULL))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(GROW, 1, NULL, 1,
|
|
LFSR_ATTR(MKREG, 1, "\xbb\xbb\xbb\xbb", 4, NULL))) => 0;
|
|
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(0), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 0);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_get(&lfs, &rbyd, tag_, id_, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_get(&lfs, &rbyd, tag_, id_, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, NULL, &off_, &size_) => LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(0), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 0);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_get(&lfs, &rbyd, tag_, id_, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_get(&lfs, &rbyd, tag_, id_, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, NULL, &off_, &size_) => LFS_ERR_NOENT;
|
|
|
|
// also try the other direction
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(GROW, 0, NULL, 1,
|
|
LFSR_ATTR(MKREG, 0, "\xbb\xbb\xbb\xbb", 4, NULL))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(GROW, 0, NULL, 1,
|
|
LFSR_ATTR(MKREG, 0, "\xaa\xaa\xaa\xaa", 4, NULL))) => 0;
|
|
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(0), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 0);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_get(&lfs, &rbyd, tag_, id_, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_get(&lfs, &rbyd, tag_, id_, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, NULL, &off_, &size_) => LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(0), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 0);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_get(&lfs, &rbyd, tag_, id_, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_get(&lfs, &rbyd, tag_, id_, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, NULL, &off_, &size_) => LFS_ERR_NOENT;
|
|
'''
|
|
|
|
[cases.test_rbyd_create_traverse_permutations]
|
|
defines.N = 'range(1, 8)'
|
|
in = 'lfs.c'
|
|
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_;
|
|
lfs_ssize_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]);
|
|
}
|
|
printf("] ---\n");
|
|
|
|
// build the attribute list for the current permutation
|
|
struct lfsr_attr attrs[2*N];
|
|
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;
|
|
}
|
|
}
|
|
|
|
attrs[2*j+0] = *LFSR_ATTR(
|
|
GROW, id, NULL, 1,
|
|
(2*j+1 < 2*N) ? &attrs[2*j+1] : NULL);
|
|
attrs[2*j+1] = *LFSR_ATTR(
|
|
MKREG, id, names[perm[j] % 6], 4,
|
|
(2*j+2 < 2*N) ? &attrs[2*j+2] : NULL);
|
|
}
|
|
|
|
// test the given permutation
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, attrs) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
assert(rbyd.weight == N);
|
|
// try traversing all tags
|
|
tag_ = 0;
|
|
id_ = -1;
|
|
for (unsigned j = 0; j < N; j++) {
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == j);
|
|
assert(size_ == 4);
|
|
|
|
lfsr_rbyd_get(&lfs, &rbyd, tag_, id_, buffer, 4) => 4;
|
|
assert(memcmp(buffer, names[j % 6], 4) == 0);
|
|
}
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, NULL, &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_multi_create_traverse_permutations]
|
|
defines.N = 'range(1, 8)'
|
|
# large progs take too long for now
|
|
if = 'PROG_SIZE < 512'
|
|
in = 'lfs.c'
|
|
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_;
|
|
lfs_ssize_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]);
|
|
}
|
|
printf("] ---\n");
|
|
|
|
// test the 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(GROW, id, NULL, 1,
|
|
LFSR_ATTR(MKREG, id, names[perm[j] % 6], 4,
|
|
NULL))) => 0;
|
|
}
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
assert(rbyd.weight == N);
|
|
// try traversing all tags
|
|
tag_ = 0;
|
|
id_ = -1;
|
|
for (unsigned j = 0; j < N; j++) {
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == j);
|
|
assert(size_ == 4);
|
|
|
|
lfsr_rbyd_get(&lfs, &rbyd, tag_, id_, buffer, 4) => 4;
|
|
assert(memcmp(buffer, names[j % 6], 4) == 0);
|
|
}
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, NULL, &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_create_large]
|
|
in = 'lfs.c'
|
|
# ORDER:
|
|
# 0 = in-order
|
|
# 1 = reverse-order
|
|
# 2 = random-order
|
|
defines.ORDER = [0, 1, 2]
|
|
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",
|
|
};
|
|
|
|
// create the rbyd tree
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
|
|
// keep inserting tags until we run out of space
|
|
//
|
|
// note, the ids we create this way are both sparse and sometimes
|
|
// repeated, so we need to mod our current rbyd size to avoid invalid
|
|
// insertions
|
|
//
|
|
uint32_t prng = 42;
|
|
for (lfs_size_t i = 0;; i++) {
|
|
uint16_t x
|
|
= (ORDER == 0) ? (uint16_t)i
|
|
: (ORDER == 1) ? (uint16_t)(((lfs_size_t)-1) - i)
|
|
: (uint16_t)TEST_PRNG(&prng);
|
|
x = x % (rbyd.weight+1);
|
|
|
|
int err = lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(GROW, x, NULL, 1,
|
|
LFSR_ATTR(MKREG, x, names[x % 6], 4, NULL)));
|
|
if (err == LFS_ERR_RANGE) {
|
|
break;
|
|
}
|
|
assert(err == 0);
|
|
}
|
|
|
|
// check that we can at least lookup all the tags
|
|
//
|
|
// note with random order we can't check that stored values reliably
|
|
lfsr_tag_t tag_;
|
|
lfs_ssize_t id_;
|
|
lfs_off_t off_;
|
|
lfs_size_t size_;
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
for (uint16_t x = 0; x < rbyd.weight; x++) {
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_MKREG, x,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == x);
|
|
assert(size_ == 4);
|
|
}
|
|
'''
|
|
|
|
|
|
### Mixed create and attr testing ###
|
|
|
|
[cases.test_rbyd_mixed]
|
|
in = 'lfs.c'
|
|
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;
|
|
uint8_t buffer[4];
|
|
|
|
// try to create one id
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(GROW, 0, NULL, 1,
|
|
LFSR_ATTR(MKREG, 0, "\xaa\xaa\xaa\xaa", 4,
|
|
LFSR_ATTR(UATTR(1), 0, "\xaa\xaa", 2, NULL)))) => 0;
|
|
|
|
assert(rbyd.weight == 1);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 0, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(1), 0, buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
assert(rbyd.weight == 1);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 0, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(1), 0, buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
|
|
|
|
// try to create two ids
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(GROW, 0, NULL, 1,
|
|
LFSR_ATTR(MKREG, 0, "\xaa\xaa\xaa\xaa", 4,
|
|
LFSR_ATTR(UATTR(1), 0, "\xaa\xaa", 2,
|
|
LFSR_ATTR(GROW, 1, NULL, 1,
|
|
LFSR_ATTR(MKREG, 1, "\xbb\xbb\xbb\xbb", 4,
|
|
LFSR_ATTR(UATTR(1), 1, "\xbb\xbb", 2, NULL))))))) => 0;
|
|
|
|
assert(rbyd.weight == 2);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 0, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(1), 0, buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 1, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(1), 1, buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
assert(rbyd.weight == 2);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 0, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(1), 0, buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 1, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(1), 1, buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
|
|
|
|
// try to create two in the other direction
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(GROW, 0, NULL, 1,
|
|
LFSR_ATTR(MKREG, 0, "\xbb\xbb\xbb\xbb", 4,
|
|
LFSR_ATTR(UATTR(1), 0, "\xbb\xbb", 2,
|
|
LFSR_ATTR(GROW, 0, NULL, 1,
|
|
LFSR_ATTR(MKREG, 0, "\xaa\xaa\xaa\xaa", 4,
|
|
LFSR_ATTR(UATTR(1), 0, "\xaa\xaa", 2, NULL))))))) => 0;
|
|
|
|
assert(rbyd.weight == 2);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 0, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(1), 0, buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 1, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(1), 1, buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
assert(rbyd.weight == 2);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 0, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(1), 0, buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 1, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(1), 1, buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
|
|
|
|
// create a third to the right
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(GROW, 0, NULL, 1,
|
|
LFSR_ATTR(MKREG, 0, "\xaa\xaa\xaa\xaa", 4,
|
|
LFSR_ATTR(UATTR(1), 0, "\xaa\xaa", 2,
|
|
LFSR_ATTR(GROW, 1, NULL, 1,
|
|
LFSR_ATTR(MKREG, 1, "\xbb\xbb\xbb\xbb", 4,
|
|
LFSR_ATTR(UATTR(1), 1, "\xbb\xbb", 2,
|
|
LFSR_ATTR(GROW, 2, NULL, 1,
|
|
LFSR_ATTR(MKREG, 2, "\xcc\xcc\xcc\xcc", 4,
|
|
LFSR_ATTR(UATTR(1), 2, "\xcc\xcc", 2, NULL)))))))))) => 0;
|
|
|
|
assert(rbyd.weight == 3);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 0, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 1, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 2, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
assert(rbyd.weight == 3);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 0, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 1, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 2, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
|
|
|
|
assert(rbyd.weight == 3);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 0, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(1), 0, buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 1, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(1), 1, buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 2, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(1), 2, buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xcc\xcc", 2) == 0);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
assert(rbyd.weight == 3);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 0, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(1), 0, buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 1, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(1), 1, buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 2, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(1), 2, buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xcc\xcc", 2) == 0);
|
|
|
|
// create a third to the left
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(GROW, 0, NULL, 1,
|
|
LFSR_ATTR(MKREG, 0, "\xbb\xbb\xbb\xbb", 4,
|
|
LFSR_ATTR(UATTR(1), 0, "\xbb\xbb", 2,
|
|
LFSR_ATTR(GROW, 1, NULL, 1,
|
|
LFSR_ATTR(MKREG, 1, "\xcc\xcc\xcc\xcc", 4,
|
|
LFSR_ATTR(UATTR(1), 1, "\xcc\xcc", 2,
|
|
LFSR_ATTR(GROW, 0, NULL, 1,
|
|
LFSR_ATTR(MKREG, 0, "\xaa\xaa\xaa\xaa", 4,
|
|
LFSR_ATTR(UATTR(1), 0, "\xaa\xaa", 2, NULL)))))))))) => 0;
|
|
|
|
assert(rbyd.weight == 3);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 0, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(1), 0, buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 1, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(1), 1, buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 2, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(1), 2, buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xcc\xcc", 2) == 0);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
assert(rbyd.weight == 3);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 0, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(1), 0, buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 1, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(1), 1, buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 2, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(1), 2, buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xcc\xcc", 2) == 0);
|
|
|
|
// create a third in the middle
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(GROW, 0, NULL, 1,
|
|
LFSR_ATTR(MKREG, 0, "\xaa\xaa\xaa\xaa", 4,
|
|
LFSR_ATTR(UATTR(1), 0, "\xaa\xaa", 2,
|
|
LFSR_ATTR(GROW, 1, NULL, 1,
|
|
LFSR_ATTR(MKREG, 1, "\xcc\xcc\xcc\xcc", 4,
|
|
LFSR_ATTR(UATTR(1), 1, "\xcc\xcc", 2,
|
|
LFSR_ATTR(GROW, 1, NULL, 1,
|
|
LFSR_ATTR(MKREG, 1, "\xbb\xbb\xbb\xbb", 4,
|
|
LFSR_ATTR(UATTR(1), 1, "\xbb\xbb", 2, NULL)))))))))) => 0;
|
|
|
|
assert(rbyd.weight == 3);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 0, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(1), 0, buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 1, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(1), 1, buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 2, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(1), 2, buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xcc\xcc", 2) == 0);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
assert(rbyd.weight == 3);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 0, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(1), 0, buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 1, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(1), 1, buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 2, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(1), 2, buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xcc\xcc", 2) == 0);
|
|
'''
|
|
|
|
[cases.test_rbyd_multi_mixed]
|
|
in = 'lfs.c'
|
|
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;
|
|
uint8_t buffer[4];
|
|
|
|
// try to create one id
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(GROW, 0, NULL, 1,
|
|
LFSR_ATTR(MKREG, 0, "\xaa\xaa\xaa\xaa", 4, NULL))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(UATTR(1), 0, "\xaa\xaa", 2, NULL)) => 0;
|
|
|
|
assert(rbyd.weight == 1);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 0, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(1), 0, buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
assert(rbyd.weight == 1);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 0, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(1), 0, buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
|
|
|
|
// try to create two ids
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(GROW, 0, NULL, 1,
|
|
LFSR_ATTR(MKREG, 0, "\xaa\xaa\xaa\xaa", 4, NULL))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(UATTR(1), 0, "\xaa\xaa", 2, NULL)) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(GROW, 1, NULL, 1,
|
|
LFSR_ATTR(MKREG, 1, "\xbb\xbb\xbb\xbb", 4, NULL))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(UATTR(1), 1, "\xbb\xbb", 2, NULL)) => 0;
|
|
|
|
assert(rbyd.weight == 2);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 0, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(1), 0, buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 1, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(1), 1, buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
assert(rbyd.weight == 2);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 0, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(1), 0, buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 1, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(1), 1, buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
|
|
|
|
// try to create two in the other direction
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(GROW, 0, NULL, 1,
|
|
LFSR_ATTR(MKREG, 0, "\xbb\xbb\xbb\xbb", 4, NULL))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(UATTR(1), 0, "\xbb\xbb", 2, NULL)) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(GROW, 0, NULL, 1,
|
|
LFSR_ATTR(MKREG, 0, "\xaa\xaa\xaa\xaa", 4, NULL))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(UATTR(1), 0, "\xaa\xaa", 2, NULL)) => 0;
|
|
|
|
assert(rbyd.weight == 2);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 0, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(1), 0, buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 1, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(1), 1, buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
assert(rbyd.weight == 2);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 0, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(1), 0, buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 1, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(1), 1, buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
|
|
|
|
// create a third to the right
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(GROW, 0, NULL, 1,
|
|
LFSR_ATTR(MKREG, 0, "\xaa\xaa\xaa\xaa", 4, NULL))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(UATTR(1), 0, "\xaa\xaa", 2, NULL)) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(GROW, 1, NULL, 1,
|
|
LFSR_ATTR(MKREG, 1, "\xbb\xbb\xbb\xbb", 4, NULL))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(UATTR(1), 1, "\xbb\xbb", 2, NULL)) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(GROW, 2, NULL, 1,
|
|
LFSR_ATTR(MKREG, 2, "\xcc\xcc\xcc\xcc", 4, NULL))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(UATTR(1), 2, "\xcc\xcc", 2, NULL)) => 0;
|
|
|
|
assert(rbyd.weight == 3);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 0, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 1, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 2, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
assert(rbyd.weight == 3);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 0, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 1, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 2, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
|
|
|
|
assert(rbyd.weight == 3);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 0, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(1), 0, buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 1, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(1), 1, buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 2, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(1), 2, buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xcc\xcc", 2) == 0);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
assert(rbyd.weight == 3);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 0, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(1), 0, buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 1, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(1), 1, buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 2, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(1), 2, buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xcc\xcc", 2) == 0);
|
|
|
|
// create a third to the left
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(GROW, 0, NULL, 1,
|
|
LFSR_ATTR(MKREG, 0, "\xbb\xbb\xbb\xbb", 4, NULL))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(UATTR(1), 0, "\xbb\xbb", 2, NULL)) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(GROW, 1, NULL, 1,
|
|
LFSR_ATTR(MKREG, 1, "\xcc\xcc\xcc\xcc", 4, NULL))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(UATTR(1), 1, "\xcc\xcc", 2, NULL)) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(GROW, 0, NULL, 1,
|
|
LFSR_ATTR(MKREG, 0, "\xaa\xaa\xaa\xaa", 4, NULL))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(UATTR(1), 0, "\xaa\xaa", 2, NULL)) => 0;
|
|
|
|
assert(rbyd.weight == 3);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 0, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(1), 0, buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 1, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(1), 1, buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 2, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(1), 2, buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xcc\xcc", 2) == 0);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
assert(rbyd.weight == 3);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 0, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(1), 0, buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 1, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(1), 1, buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 2, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(1), 2, buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xcc\xcc", 2) == 0);
|
|
|
|
// create a third in the middle
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(GROW, 0, NULL, 1,
|
|
LFSR_ATTR(MKREG, 0, "\xaa\xaa\xaa\xaa", 4, NULL))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(UATTR(1), 0, "\xaa\xaa", 2, NULL)) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(GROW, 1, NULL, 1,
|
|
LFSR_ATTR(MKREG, 1, "\xcc\xcc\xcc\xcc", 4, NULL))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(UATTR(1), 1, "\xcc\xcc", 2, NULL)) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(GROW, 1, NULL, 1,
|
|
LFSR_ATTR(MKREG, 1, "\xbb\xbb\xbb\xbb", 4, NULL))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(UATTR(1), 1, "\xbb\xbb", 2, NULL)) => 0;
|
|
|
|
assert(rbyd.weight == 3);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 0, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(1), 0, buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 1, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(1), 1, buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 2, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(1), 2, buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xcc\xcc", 2) == 0);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
assert(rbyd.weight == 3);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 0, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(1), 0, buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 1, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(1), 1, buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 2, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(1), 2, buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xcc\xcc", 2) == 0);
|
|
'''
|
|
|
|
[cases.test_rbyd_mixed_permutations]
|
|
defines.N = 'range(1, 7)'
|
|
defines.M = 'range(1, 4)'
|
|
in = 'lfs.c'
|
|
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",
|
|
};
|
|
uint8_t buffer[4];
|
|
|
|
// keep track of the worst case log size
|
|
lfs_size_t worst_size = 0;
|
|
|
|
// 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]);
|
|
}
|
|
printf("] ---\n");
|
|
|
|
// build the attribute list for the current permutation
|
|
struct lfsr_attr attrs[(2+M)*N];
|
|
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;
|
|
}
|
|
}
|
|
|
|
attrs[(2+M)*j+0] = *LFSR_ATTR(
|
|
GROW, id, NULL, 1,
|
|
((2+M)*j+1 < (2+M)*N) ? &attrs[(2+M)*j+1] : NULL);
|
|
attrs[(2+M)*j+1] = *LFSR_ATTR(
|
|
MKREG, id, names[perm[j] % 6], 4,
|
|
((2+M)*j+2 < (2+M)*N) ? &attrs[(2+M)*j+2] : NULL);
|
|
// note uattrs have a smaller size to help debugging
|
|
for (unsigned u = 0; u < M; u++) {
|
|
attrs[(2+M)*j+2+u] = *LFSR_ATTR(
|
|
UATTR(u+1), id, names[perm[j] % 6], 2,
|
|
((2+M)*j+2+u+1 < (2+M)*N)
|
|
? &attrs[(2+M)*j+2+u+1]
|
|
: NULL);
|
|
}
|
|
}
|
|
|
|
// test the given permutation
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, attrs) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
assert(rbyd.weight == N);
|
|
for (unsigned j = 0; j < N; j++) {
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, j, buffer, 4) => 4;
|
|
assert(memcmp(buffer, names[j % 6], 4) == 0);
|
|
|
|
for (unsigned u = 0; u < M; u++) {
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(u+1), j, buffer, 4)
|
|
=> 2;
|
|
assert(memcmp(buffer, names[j % 6], 2) == 0);
|
|
}
|
|
}
|
|
|
|
// keep track of the worst size
|
|
worst_size = lfs_max(worst_size, rbyd.off);
|
|
|
|
// 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;
|
|
}
|
|
}
|
|
|
|
// test that tree is self-balancing, we should be strictly bounded
|
|
// by height <= 2*log(n)+1, assume tags are strictly <=12 bytes
|
|
lfs_size_t n = 1 + N + N*M;
|
|
printf("worst size: %u B (N=%u, estimate=%u)\n",
|
|
worst_size, n, 12*n*(2*lfs_nlog2(n)+1)+4);
|
|
printf("avg height: %u B (N=%u, estimate=%u)\n",
|
|
worst_size / n, n, 12*(2*lfs_nlog2(n)+1)+4);
|
|
// note this only holds true with byte-level progs
|
|
if (PROG_SIZE == 1) {
|
|
assert(worst_size / n <= 12*(2*lfs_nlog2(n)+1)+4);
|
|
}
|
|
'''
|
|
|
|
[cases.test_rbyd_multi_mixed_permutations]
|
|
defines.N = 'range(1, 7)'
|
|
defines.M = 'range(1, 4)'
|
|
# large progs take too long for now
|
|
if = 'PROG_SIZE < 512'
|
|
in = 'lfs.c'
|
|
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",
|
|
};
|
|
uint8_t buffer[4];
|
|
|
|
// keep track of the worst case log size
|
|
lfs_size_t worst_size = 0;
|
|
|
|
// 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]);
|
|
}
|
|
printf("] ---\n");
|
|
|
|
// test the given permutation
|
|
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(GROW, id, NULL, 1,
|
|
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;
|
|
}
|
|
}
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
assert(rbyd.weight == N);
|
|
for (unsigned j = 0; j < N; j++) {
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, j, buffer, 4) => 4;
|
|
assert(memcmp(buffer, names[j % 6], 4) == 0);
|
|
|
|
for (unsigned u = 0; u < M; u++) {
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(u+1), j, buffer, 4)
|
|
=> 2;
|
|
assert(memcmp(buffer, names[j % 6], 2) == 0);
|
|
}
|
|
}
|
|
|
|
// keep track of the worst size
|
|
worst_size = lfs_max(worst_size, rbyd.off);
|
|
|
|
// 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;
|
|
}
|
|
}
|
|
|
|
// test that tree is self-balancing, we should be strictly bounded
|
|
// by height <= 2*log(n)+1, assume tags are strictly <=12 bytes
|
|
lfs_size_t n = 1 + N + N*M;
|
|
printf("worst size: %u B (N=%u, estimate=%u)\n",
|
|
worst_size, n, 12*n*(2*lfs_nlog2(n)+1)+4);
|
|
printf("avg height: %u B (N=%u, estimate=%u)\n",
|
|
worst_size / n, n, 12*(2*lfs_nlog2(n)+1)+4);
|
|
// note this only holds true with byte-level progs
|
|
if (PROG_SIZE == 1) {
|
|
assert(worst_size / n <= 12*(2*lfs_nlog2(n)+1)+4);
|
|
}
|
|
'''
|
|
|
|
[cases.test_rbyd_mixed_traverse]
|
|
in = 'lfs.c'
|
|
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_;
|
|
lfs_ssize_t id_;
|
|
lfs_off_t off_;
|
|
lfs_size_t size_;
|
|
uint8_t buffer[4];
|
|
|
|
// traverse requires correct biasing of the weights in the rbyd tree
|
|
// so that lookups return strictly the tag greater than or equal to
|
|
// the tag requested
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(GROW, 0, NULL, 1,
|
|
LFSR_ATTR(MKREG, 0, "\xaa\xaa\xaa\xaa", 4,
|
|
LFSR_ATTR(UATTR(1), 0, "\xaa\xaa", 2,
|
|
LFSR_ATTR(GROW, 1, NULL, 1,
|
|
LFSR_ATTR(MKREG, 1, "\xbb\xbb\xbb\xbb", 4,
|
|
LFSR_ATTR(UATTR(1), 1, "\xbb\xbb", 2, NULL))))))) => 0;
|
|
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(0), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 0);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_get(&lfs, &rbyd, tag_, id_, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == 0);
|
|
assert(size_ == 2);
|
|
lfsr_rbyd_get(&lfs, &rbyd, tag_, id_, buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_get(&lfs, &rbyd, tag_, id_, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == 1);
|
|
assert(size_ == 2);
|
|
lfsr_rbyd_get(&lfs, &rbyd, tag_, id_, buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, NULL, &off_, &size_) => LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(0), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 0);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_get(&lfs, &rbyd, tag_, id_, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == 0);
|
|
assert(size_ == 2);
|
|
lfsr_rbyd_get(&lfs, &rbyd, tag_, id_, buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_get(&lfs, &rbyd, tag_, id_, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == 1);
|
|
assert(size_ == 2);
|
|
lfsr_rbyd_get(&lfs, &rbyd, tag_, id_, buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, NULL, &off_, &size_) => LFS_ERR_NOENT;
|
|
|
|
// also try the other direction
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(GROW, 0, NULL, 1,
|
|
LFSR_ATTR(MKREG, 0, "\xbb\xbb\xbb\xbb", 4,
|
|
LFSR_ATTR(UATTR(1), 0, "\xbb\xbb", 2,
|
|
LFSR_ATTR(GROW, 0, NULL, 1,
|
|
LFSR_ATTR(MKREG, 0, "\xaa\xaa\xaa\xaa", 4,
|
|
LFSR_ATTR(UATTR(1), 0, "\xaa\xaa", 2, NULL))))))) => 0;
|
|
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(0), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 0);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_get(&lfs, &rbyd, tag_, id_, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == 0);
|
|
assert(size_ == 2);
|
|
lfsr_rbyd_get(&lfs, &rbyd, tag_, id_, buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_get(&lfs, &rbyd, tag_, id_, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == 1);
|
|
assert(size_ == 2);
|
|
lfsr_rbyd_get(&lfs, &rbyd, tag_, id_, buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, NULL, &off_, &size_) => LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(0), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 0);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_get(&lfs, &rbyd, tag_, id_, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == 0);
|
|
assert(size_ == 2);
|
|
lfsr_rbyd_get(&lfs, &rbyd, tag_, id_, buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_get(&lfs, &rbyd, tag_, id_, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == 1);
|
|
assert(size_ == 2);
|
|
lfsr_rbyd_get(&lfs, &rbyd, tag_, id_, buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, NULL, &off_, &size_) => LFS_ERR_NOENT;
|
|
'''
|
|
|
|
[cases.test_rbyd_multi_mixed_traverse]
|
|
in = 'lfs.c'
|
|
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_;
|
|
lfs_ssize_t id_;
|
|
lfs_off_t off_;
|
|
lfs_size_t size_;
|
|
uint8_t buffer[4];
|
|
|
|
// traverse requires correct biasing of the weights in the rbyd tree
|
|
// so that lookups return strictly the tag greater than or equal to
|
|
// the tag requested
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(GROW, 0, NULL, 1,
|
|
LFSR_ATTR(MKREG, 0, "\xaa\xaa\xaa\xaa", 4, NULL))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(UATTR(1), 0, "\xaa\xaa", 2, NULL)) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(GROW, 1, NULL, 1,
|
|
LFSR_ATTR(MKREG, 1, "\xbb\xbb\xbb\xbb", 4, NULL))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(UATTR(1), 1, "\xbb\xbb", 2, NULL)) => 0;
|
|
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(0), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 0);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_get(&lfs, &rbyd, tag_, id_, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == 0);
|
|
assert(size_ == 2);
|
|
lfsr_rbyd_get(&lfs, &rbyd, tag_, id_, buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_get(&lfs, &rbyd, tag_, id_, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == 1);
|
|
assert(size_ == 2);
|
|
lfsr_rbyd_get(&lfs, &rbyd, tag_, id_, buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, NULL, &off_, &size_) => LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(0), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 0);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_get(&lfs, &rbyd, tag_, id_, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == 0);
|
|
assert(size_ == 2);
|
|
lfsr_rbyd_get(&lfs, &rbyd, tag_, id_, buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_get(&lfs, &rbyd, tag_, id_, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == 1);
|
|
assert(size_ == 2);
|
|
lfsr_rbyd_get(&lfs, &rbyd, tag_, id_, buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, NULL, &off_, &size_) => LFS_ERR_NOENT;
|
|
|
|
// also try the other direction
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(GROW, 0, NULL, 1,
|
|
LFSR_ATTR(MKREG, 0, "\xbb\xbb\xbb\xbb", 4, NULL))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(UATTR(1), 0, "\xbb\xbb", 2, NULL)) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(GROW, 0, NULL, 1,
|
|
LFSR_ATTR(MKREG, 0, "\xaa\xaa\xaa\xaa", 4, NULL))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(UATTR(1), 0, "\xaa\xaa", 2, NULL)) => 0;
|
|
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(0), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 0);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_get(&lfs, &rbyd, tag_, id_, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == 0);
|
|
assert(size_ == 2);
|
|
lfsr_rbyd_get(&lfs, &rbyd, tag_, id_, buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_get(&lfs, &rbyd, tag_, id_, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == 1);
|
|
assert(size_ == 2);
|
|
lfsr_rbyd_get(&lfs, &rbyd, tag_, id_, buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, NULL, &off_, &size_) => LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(0), -1,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 0);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_get(&lfs, &rbyd, tag_, id_, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == 0);
|
|
assert(size_ == 2);
|
|
lfsr_rbyd_get(&lfs, &rbyd, tag_, id_, buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_get(&lfs, &rbyd, tag_, id_, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == 1);
|
|
assert(size_ == 2);
|
|
lfsr_rbyd_get(&lfs, &rbyd, tag_, id_, buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, NULL, &off_, &size_) => LFS_ERR_NOENT;
|
|
'''
|
|
|
|
[cases.test_rbyd_mixed_traverse_permutations]
|
|
defines.N = 'range(1, 7)'
|
|
defines.M = 'range(1, 4)'
|
|
in = 'lfs.c'
|
|
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_;
|
|
lfs_ssize_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]);
|
|
}
|
|
printf("] ---\n");
|
|
|
|
// build the attribute list for the current permutation
|
|
struct lfsr_attr attrs[N*(2+M)];
|
|
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;
|
|
}
|
|
}
|
|
|
|
attrs[(2+M)*j+0] = *LFSR_ATTR(
|
|
GROW, id, NULL, 1,
|
|
((2+M)*j+1 < N*(2+M)) ? &attrs[(2+M)*j+1] : NULL);
|
|
attrs[(2+M)*j+1] = *LFSR_ATTR(
|
|
MKREG, id, names[perm[j] % 6], 4,
|
|
((2+M)*j+2 < N*(2+M)) ? &attrs[(2+M)*j+2] : NULL);
|
|
// note uattrs have a smaller size to help debugging
|
|
for (unsigned u = 0; u < M; u++) {
|
|
attrs[(2+M)*j+2+u] = *LFSR_ATTR(
|
|
UATTR(u+1), id, names[perm[j] % 6], 2,
|
|
((2+M)*j+2+u+1 < N*(2+M))
|
|
? &attrs[(2+M)*j+2+u+1]
|
|
: NULL);
|
|
}
|
|
}
|
|
|
|
// test the given permutation
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, attrs) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
assert(rbyd.weight == N);
|
|
|
|
// try traversing all tags
|
|
tag_ = 0;
|
|
id_ = -1;
|
|
for (unsigned j = 0; j < N; j++) {
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == j);
|
|
assert(size_ == 4);
|
|
|
|
lfsr_rbyd_get(&lfs, &rbyd, tag_, id_, buffer, 4) => 4;
|
|
assert(memcmp(buffer, names[j % 6], 4) == 0);
|
|
|
|
for (unsigned u = 0; u < M; u++) {
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(u+1));
|
|
assert(id_ == j);
|
|
assert(size_ == 2);
|
|
|
|
lfsr_rbyd_get(&lfs, &rbyd, tag_, id_, buffer, 4) => 2;
|
|
assert(memcmp(buffer, names[j % 6], 2) == 0);
|
|
}
|
|
}
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, NULL, &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_multi_mixed_traverse_permutations]
|
|
defines.N = 'range(1, 7)'
|
|
defines.M = 'range(1, 4)'
|
|
# large progs take too long for now
|
|
if = 'PROG_SIZE < 512'
|
|
in = 'lfs.c'
|
|
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_;
|
|
lfs_ssize_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]);
|
|
}
|
|
printf("] ---\n");
|
|
|
|
// test the given permutation
|
|
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(GROW, id, NULL, 1,
|
|
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;
|
|
}
|
|
}
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
assert(rbyd.weight == N);
|
|
|
|
// try traversing all tags
|
|
tag_ = 0;
|
|
id_ = -1;
|
|
for (unsigned j = 0; j < N; j++) {
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == j);
|
|
assert(size_ == 4);
|
|
|
|
lfsr_rbyd_get(&lfs, &rbyd, tag_, id_, buffer, 4) => 4;
|
|
assert(memcmp(buffer, names[j % 6], 4) == 0);
|
|
|
|
for (unsigned u = 0; u < M; u++) {
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(u+1));
|
|
assert(id_ == j);
|
|
assert(size_ == 2);
|
|
|
|
lfsr_rbyd_get(&lfs, &rbyd, tag_, id_, buffer, 4) => 2;
|
|
assert(memcmp(buffer, names[j % 6], 2) == 0);
|
|
}
|
|
}
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, NULL, &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;
|
|
}
|
|
}
|
|
'''
|
|
|
|
# NOTE if we separate physical/logical block sizes we may be able to
|
|
# use emubd's copy-on-write copy to speed this up significantly
|
|
[cases.test_rbyd_mixed_update_permutations]
|
|
defines.N = 'range(1, 4)'
|
|
defines.M = 'range(1, 3)'
|
|
# large progs take too long for now
|
|
if = 'PROG_SIZE < 512'
|
|
in = 'lfs.c'
|
|
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,
|
|
};
|
|
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_rbyd_t rbyd;
|
|
uint8_t buffer[4];
|
|
|
|
// keep track of the worst case log size
|
|
lfs_size_t worst_size = 0;
|
|
|
|
// create one consistent block
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
|
|
for (unsigned j = 0; j < N; j++) {
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(GROW, j, NULL, 1,
|
|
LFSR_ATTR(MKREG, j, names[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), j, names[j % 6], 2,
|
|
NULL)) => 0;
|
|
}
|
|
}
|
|
|
|
// copy block so we can reset after each remove
|
|
lfsr_rbyd_t backup_rbyd = rbyd;
|
|
uint8_t *backup_block = malloc(rbyd.off);
|
|
lfs_bd_read(&lfs, NULL, &lfs.rcache, rbyd.off,
|
|
rbyd.block, 0, backup_block, rbyd.off) => 0;
|
|
|
|
// test all permutations of a given size
|
|
uint8_t perm[N*M];
|
|
unsigned stack[N*M];
|
|
for (uint8_t i = 0; i < N*M; i++) {
|
|
perm[i] = i;
|
|
stack[i] = 0;
|
|
}
|
|
|
|
unsigned i = 1;
|
|
while (i < N*M) {
|
|
// print permutation to help debugging
|
|
printf("--- permutation: [");
|
|
for (unsigned j = 0; j < N*M; j++) {
|
|
if (j > 0) {
|
|
printf(", ");
|
|
}
|
|
printf("%d", perm[j]);
|
|
}
|
|
printf("] ---\n");
|
|
|
|
// restore backup
|
|
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;
|
|
|
|
// update each tag in permutation order
|
|
for (unsigned j = 0; j < N*M; j++) {
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(UATTR(perm[j]%M+1), perm[j]/M,
|
|
names[(perm[j]/M) % 6], 3,
|
|
NULL)) => 0;
|
|
}
|
|
|
|
// check that all tags have been updated
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
for (unsigned j = 0; j < N; j++) {
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, j, buffer, 4) => 4;
|
|
assert(memcmp(buffer, names[j % 6], 4) == 0);
|
|
|
|
for (unsigned u = 0; u < M; u++) {
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(u+1), j, buffer, 4)
|
|
=> 3;
|
|
assert(memcmp(buffer, names[j % 6], 3) == 0);
|
|
}
|
|
}
|
|
|
|
// keep track of the worst size
|
|
worst_size = lfs_max(worst_size, rbyd.off);
|
|
|
|
// 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;
|
|
}
|
|
}
|
|
|
|
// cleanup
|
|
free(backup_block);
|
|
|
|
// test that tree is self-balancing, we should be strictly bounded
|
|
// by height <= 2*log(n)+1, assume tags are strictly <=12 bytes
|
|
lfs_size_t n = 1 + N + N*M + N*M;
|
|
printf("worst size: %u B (N=%u, estimate=%u)\n",
|
|
worst_size, n, 12*n*(2*lfs_nlog2(n)+1)+4);
|
|
printf("avg height: %u B (N=%u, estimate=%u)\n",
|
|
worst_size / n, n, 12*(2*lfs_nlog2(n)+1)+4);
|
|
// note this only holds true with byte-level progs
|
|
if (PROG_SIZE == 1) {
|
|
assert(worst_size / n <= 12*(2*lfs_nlog2(n)+1)+4);
|
|
}
|
|
'''
|
|
|
|
# NOTE if we separate physical/logical block sizes we may be able to
|
|
# use emubd's copy-on-write copy to speed this up significantly
|
|
[cases.test_rbyd_mixed_remove_permutations]
|
|
defines.N = 'range(1, 7)'
|
|
defines.M = 'range(1, 4)'
|
|
# large progs take too long for now
|
|
if = 'PROG_SIZE < 512'
|
|
in = 'lfs.c'
|
|
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,
|
|
};
|
|
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_rbyd_t rbyd;
|
|
lfsr_tag_t tag_;
|
|
lfs_ssize_t id_;
|
|
lfs_off_t off_;
|
|
lfs_size_t size_;
|
|
uint8_t buffer[4];
|
|
|
|
// keep track of the worst case log size
|
|
lfs_size_t worst_size = 0;
|
|
|
|
// 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]);
|
|
}
|
|
printf("] ---\n");
|
|
|
|
// create given permutation
|
|
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(GROW, id, NULL, 1,
|
|
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;
|
|
}
|
|
}
|
|
|
|
// copy block so we can reset after each remove
|
|
lfsr_rbyd_t backup_rbyd = rbyd;
|
|
uint8_t *backup_block = malloc(rbyd.off);
|
|
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*M; j++) {
|
|
// print what we are removing to help debugging
|
|
printf("--- remove: id%jd, %jd ---\n", j/M, (j%M)+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%M)+1), j/M, NULL, 0, NULL)) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block,
|
|
cfg->block_size, NULL) => 0;
|
|
for (unsigned k = 0; k < N; k++) {
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, k, buffer, 4) => 4;
|
|
assert(memcmp(buffer, names[k % 6], 4) == 0);
|
|
|
|
for (unsigned u = 0; u < M; u++) {
|
|
int err = lfsr_rbyd_lookup(&lfs, &rbyd,
|
|
LFSR_TAG_UATTR(u+1), k,
|
|
&tag_, &id_, NULL, &off_, &size_);
|
|
assert(!err || err == LFS_ERR_NOENT);
|
|
if (k == j/M && u == j%M) {
|
|
if (u == M-1 && k == N-1) {
|
|
assert(err == LFS_ERR_NOENT);
|
|
} else if (u == M-1) {
|
|
assert(!err);
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == k+1);
|
|
assert(size_ == 4);
|
|
} else {
|
|
assert(!err);
|
|
assert(tag_ == LFSR_TAG_UATTR(u+1+1));
|
|
assert(id_ == k);
|
|
assert(size_ == 2);
|
|
}
|
|
} else {
|
|
assert(tag_ == LFSR_TAG_UATTR(u+1));
|
|
assert(id_ == k);
|
|
assert(size_ == 2);
|
|
|
|
lfsr_rbyd_get(&lfs, &rbyd, tag_, id_, buffer, 4) => 2;
|
|
assert(memcmp(buffer, names[k % 6], 2) == 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
// try append the tag back to make sure things still work
|
|
printf("--- append: id%jd, %jd ---\n", j/M, (j%M)+1);
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(UATTR((j%M)+1), j/M, names[(j/M)%6], 3,
|
|
NULL)) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block,
|
|
cfg->block_size, NULL) => 0;
|
|
for (unsigned k = 0; k < N; k++) {
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, k, buffer, 4) => 4;
|
|
assert(memcmp(buffer, names[k % 6], 4) == 0);
|
|
|
|
for (unsigned u = 0; u < M; u++) {
|
|
lfsr_rbyd_lookup(&lfs, &rbyd,
|
|
LFSR_TAG_UATTR(u+1), k,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
if (k == j/M && u == j%M) {
|
|
assert(tag_ == LFSR_TAG_UATTR(u+1));
|
|
assert(id_ == k);
|
|
assert(size_ == 3);
|
|
|
|
lfsr_rbyd_get(&lfs, &rbyd, tag_, id_, buffer, 4) => 3;
|
|
assert(memcmp(buffer, names[k % 6], 3) == 0);
|
|
} else {
|
|
assert(tag_ == LFSR_TAG_UATTR(u+1));
|
|
assert(id_ == k);
|
|
assert(size_ == 2);
|
|
|
|
lfsr_rbyd_get(&lfs, &rbyd, tag_, id_, buffer, 4) => 2;
|
|
assert(memcmp(buffer, names[k % 6], 2) == 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
// keep track of the worst size
|
|
worst_size = lfs_max(worst_size, rbyd.off);
|
|
}
|
|
|
|
// cleanup
|
|
free(backup_block);
|
|
|
|
// 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;
|
|
}
|
|
}
|
|
|
|
// test that tree is self-balancing, we should be strictly bounded
|
|
// by height <= 2*log(n)+1, assume tags are strictly <=12 bytes
|
|
lfs_size_t n = 1 + N+N*M + 2;
|
|
printf("worst size: %u B (N=%u, estimate=%u)\n",
|
|
worst_size, n, 12*n*(2*lfs_nlog2(n)+1)+4);
|
|
printf("avg height: %u B (N=%u, estimate=%u)\n",
|
|
worst_size / n, n, 12*(2*lfs_nlog2(n)+1)+4);
|
|
// note this only holds true with byte-level progs
|
|
if (PROG_SIZE == 1) {
|
|
assert(worst_size / n <= 12*(2*lfs_nlog2(n)+1)+4);
|
|
}
|
|
'''
|
|
|
|
# NOTE if we separate physical/logical block sizes we may be able to
|
|
# use emubd's copy-on-write copy to speed this up significantly
|
|
[cases.test_rbyd_mixed_remove_all_permutations]
|
|
defines.N = 'range(1, 4)'
|
|
defines.M = 'range(1, 3)'
|
|
# large progs take too long for now
|
|
if = 'PROG_SIZE < 512'
|
|
in = 'lfs.c'
|
|
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,
|
|
};
|
|
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_rbyd_t rbyd;
|
|
uint8_t buffer[4];
|
|
|
|
// keep track of the worst case log size
|
|
lfs_size_t worst_size = 0;
|
|
|
|
// create one consistent block
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
|
|
for (unsigned j = 0; j < N; j++) {
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(GROW, j, NULL, 1,
|
|
LFSR_ATTR(MKREG, j, names[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), j, names[j % 6], 2,
|
|
NULL)) => 0;
|
|
}
|
|
}
|
|
|
|
// copy block so we can reset after each remove
|
|
lfsr_rbyd_t backup_rbyd = rbyd;
|
|
uint8_t *backup_block = malloc(rbyd.off);
|
|
lfs_bd_read(&lfs, NULL, &lfs.rcache, rbyd.off,
|
|
rbyd.block, 0, backup_block, rbyd.off) => 0;
|
|
|
|
// test all permutations of a given size
|
|
uint8_t perm[N*M];
|
|
unsigned stack[N*M];
|
|
for (uint8_t i = 0; i < N*M; i++) {
|
|
perm[i] = i;
|
|
stack[i] = 0;
|
|
}
|
|
|
|
unsigned i = 1;
|
|
while (i < N*M) {
|
|
// print permutation to help debugging
|
|
printf("--- permutation: [");
|
|
for (unsigned j = 0; j < N*M; j++) {
|
|
if (j > 0) {
|
|
printf(", ");
|
|
}
|
|
printf("%d", perm[j]);
|
|
}
|
|
printf("] ---\n");
|
|
|
|
// restore backup
|
|
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;
|
|
|
|
// remove each tag in permutation order
|
|
for (unsigned j = 0; j < N*M; j++) {
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(RMUATTR(perm[j]%M+1), perm[j]/M, NULL, 0,
|
|
NULL)) => 0;
|
|
}
|
|
|
|
// check that all tags have been removed
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
for (unsigned j = 0; j < N; j++) {
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, j, buffer, 4) => 4;
|
|
assert(memcmp(buffer, names[j % 6], 4) == 0);
|
|
|
|
for (unsigned u = 0; u < M; u++) {
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(u+1), j, buffer, 4)
|
|
=> LFS_ERR_NOENT;
|
|
}
|
|
}
|
|
|
|
// keep track of the worst size
|
|
worst_size = lfs_max(worst_size, rbyd.off);
|
|
|
|
// 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;
|
|
}
|
|
}
|
|
|
|
// cleanup
|
|
free(backup_block);
|
|
|
|
// test that tree is self-balancing, we should be strictly bounded
|
|
// by height <= 2*log(n)+1, assume tags are strictly <=12 bytes
|
|
lfs_size_t n = 1 + N + N*M + N*M;
|
|
printf("worst size: %u B (N=%u, estimate=%u)\n",
|
|
worst_size, n, 12*n*(2*lfs_nlog2(n)+1)+4);
|
|
printf("avg height: %u B (N=%u, estimate=%u)\n",
|
|
worst_size / n, n, 12*(2*lfs_nlog2(n)+1)+4);
|
|
// note this only holds true with byte-level progs
|
|
if (PROG_SIZE == 1) {
|
|
assert(worst_size / n <= 12*(2*lfs_nlog2(n)+1)+4);
|
|
}
|
|
'''
|
|
|
|
[cases.test_rbyd_mixed_large]
|
|
in = 'lfs.c'
|
|
# ORDER:
|
|
# 0 = in-order
|
|
# 1 = reverse-order
|
|
# 2 = random-order
|
|
defines.ORDER = [0, 1, 2]
|
|
defines.M = 'range(1, 4)'
|
|
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",
|
|
};
|
|
|
|
// create the rbyd tree
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
|
|
// keep inserting tags until we run out of space
|
|
//
|
|
// note, the ids we create this way are both sparse and sometimes
|
|
// repeated, so we need to mod our current rbyd size to avoid invalid
|
|
// insertions
|
|
//
|
|
uint32_t prng = 42;
|
|
for (lfs_size_t i = 0;; i++) {
|
|
uint16_t x
|
|
= (ORDER == 0) ? (uint16_t)i
|
|
: (ORDER == 1) ? (uint16_t)(((lfs_size_t)-1) - i)
|
|
: (uint16_t)TEST_PRNG(&prng);
|
|
x = x % (rbyd.weight+1);
|
|
|
|
// build a single attribute list with all attributes, if this fails
|
|
// it should fail atomically
|
|
struct lfsr_attr attrs[2+M];
|
|
attrs[0] = *LFSR_ATTR(
|
|
GROW, x, NULL, 1,
|
|
&attrs[1]);
|
|
attrs[1] = *LFSR_ATTR(
|
|
MKREG, x, names[x % 6], 4,
|
|
M > 0 ? &attrs[2] : NULL);
|
|
for (unsigned u = 0; u < M; u++) {
|
|
attrs[2+u] = *LFSR_ATTR(
|
|
UATTR(u+1), x, names[x % 6], 2,
|
|
(2+u+1 < 2+M) ? &attrs[2+u+1] : NULL);
|
|
}
|
|
|
|
int err = lfsr_rbyd_commit(&lfs, &rbyd, attrs);
|
|
if (err == LFS_ERR_RANGE) {
|
|
break;
|
|
}
|
|
assert(err == 0);
|
|
}
|
|
|
|
// check that we can at least lookup all the tags
|
|
//
|
|
// note with random order we can't check that stored values reliably
|
|
lfsr_tag_t tag_;
|
|
lfs_ssize_t id_;
|
|
lfs_off_t off_;
|
|
lfs_size_t size_;
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
for (uint16_t x = 0; x < rbyd.weight; x++) {
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_MKREG, x,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == x);
|
|
assert(size_ == 4);
|
|
|
|
for (unsigned u = 0; u < M; u++) {
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(u+1), x,
|
|
&tag_, &id_, NULL, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(u+1));
|
|
assert(id_ == x);
|
|
assert(size_ == 2);
|
|
}
|
|
}
|
|
'''
|
|
|
|
|
|
### Deletion testing ###
|
|
|
|
[cases.test_rbyd_delete]
|
|
in = 'lfs.c'
|
|
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;
|
|
uint8_t buffer[4];
|
|
|
|
// try to delete one id
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(GROW, 0, NULL, 1,
|
|
LFSR_ATTR(MKREG, 0, "\xaa\xaa\xaa\xaa", 4,
|
|
LFSR_ATTR(GROW, 1, NULL, 1,
|
|
LFSR_ATTR(MKREG, 1, "\xbb\xbb\xbb\xbb", 4, NULL))))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(SHRINK, 1, NULL, 1, NULL)) => 0;
|
|
|
|
assert(rbyd.weight == 1);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 0, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 1, buffer, 4) => LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
assert(rbyd.weight == 1);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 0, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 1, buffer, 4) => LFS_ERR_NOENT;
|
|
|
|
// try to delete the other id
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(GROW, 0, NULL, 1,
|
|
LFSR_ATTR(MKREG, 0, "\xaa\xaa\xaa\xaa", 4,
|
|
LFSR_ATTR(GROW, 1, NULL, 1,
|
|
LFSR_ATTR(MKREG, 1, "\xbb\xbb\xbb\xbb", 4, NULL))))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(SHRINK, 0, NULL, 1, NULL)) => 0;
|
|
|
|
assert(rbyd.weight == 1);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 0, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 1, buffer, 4) => LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
assert(rbyd.weight == 1);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 0, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 1, buffer, 4) => LFS_ERR_NOENT;
|
|
|
|
// try to delete the largest of three
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(GROW, 0, NULL, 1,
|
|
LFSR_ATTR(MKREG, 0, "\xaa\xaa\xaa\xaa", 4,
|
|
LFSR_ATTR(GROW, 1, NULL, 1,
|
|
LFSR_ATTR(MKREG, 1, "\xbb\xbb\xbb\xbb", 4,
|
|
LFSR_ATTR(GROW, 2, NULL, 1,
|
|
LFSR_ATTR(MKREG, 2, "\xcc\xcc\xcc\xcc", 4, NULL))))))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(SHRINK, 2, NULL, 1, NULL)) => 0;
|
|
|
|
assert(rbyd.weight == 2);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 0, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 1, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 2, buffer, 4) => LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 0, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 1, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 2, buffer, 4) => LFS_ERR_NOENT;
|
|
|
|
// try to delete the smallest of three
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(GROW, 0, NULL, 1,
|
|
LFSR_ATTR(MKREG, 0, "\xaa\xaa\xaa\xaa", 4,
|
|
LFSR_ATTR(GROW, 1, NULL, 1,
|
|
LFSR_ATTR(MKREG, 1, "\xbb\xbb\xbb\xbb", 4,
|
|
LFSR_ATTR(GROW, 2, NULL, 1,
|
|
LFSR_ATTR(MKREG, 2, "\xcc\xcc\xcc\xcc", 4, NULL))))))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(SHRINK, 0, NULL, 1, NULL)) => 0;
|
|
|
|
assert(rbyd.weight == 2);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 0, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 1, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 2, buffer, 4) => LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 0, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 1, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 2, buffer, 4) => LFS_ERR_NOENT;
|
|
|
|
// try to delete the middle
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(GROW, 0, NULL, 1,
|
|
LFSR_ATTR(MKREG, 0, "\xaa\xaa\xaa\xaa", 4,
|
|
LFSR_ATTR(GROW, 1, NULL, 1,
|
|
LFSR_ATTR(MKREG, 1, "\xbb\xbb\xbb\xbb", 4,
|
|
LFSR_ATTR(GROW, 2, NULL, 1,
|
|
LFSR_ATTR(MKREG, 2, "\xcc\xcc\xcc\xcc", 4, NULL))))))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(SHRINK, 1, NULL, 1, NULL)) => 0;
|
|
|
|
assert(rbyd.weight == 2);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 0, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 1, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 2, buffer, 4) => LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 0, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 1, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 2, buffer, 4) => LFS_ERR_NOENT;
|
|
'''
|
|
|
|
[cases.test_rbyd_delete_range]
|
|
in = 'lfs.c'
|
|
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;
|
|
uint8_t buffer[4];
|
|
|
|
// try to delete one id
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(GROW, 0, NULL, 1,
|
|
LFSR_ATTR(MKREG, 0, "\xaa\xaa\xaa\xaa", 4,
|
|
LFSR_ATTR(UATTR(1), 0, "\xaa\xaa", 2,
|
|
LFSR_ATTR(GROW, 1, NULL, 1,
|
|
LFSR_ATTR(MKREG, 1, "\xbb\xbb\xbb\xbb", 4,
|
|
LFSR_ATTR(UATTR(1), 1, "\xbb\xbb", 2, NULL))))))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(SHRINK, 1, NULL, 1, NULL)) => 0;
|
|
|
|
assert(rbyd.weight == 1);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 0, buffer, 4)
|
|
=> 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(1), 0, buffer, 4)
|
|
=> 2;
|
|
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 1, buffer, 4)
|
|
=> LFS_ERR_NOENT;
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(1), 1, buffer, 4)
|
|
=> LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
assert(rbyd.weight == 1);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 0, buffer, 4)
|
|
=> 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(1), 0, buffer, 4)
|
|
=> 2;
|
|
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 1, buffer, 4)
|
|
=> LFS_ERR_NOENT;
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(1), 1, buffer, 4)
|
|
=> LFS_ERR_NOENT;
|
|
|
|
// try to delete the other id
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(GROW, 0, NULL, 1,
|
|
LFSR_ATTR(MKREG, 0, "\xaa\xaa\xaa\xaa", 4,
|
|
LFSR_ATTR(UATTR(1), 0, "\xaa\xaa", 2,
|
|
LFSR_ATTR(GROW, 1, NULL, 1,
|
|
LFSR_ATTR(MKREG, 1, "\xbb\xbb\xbb\xbb", 4,
|
|
LFSR_ATTR(UATTR(1), 1, "\xbb\xbb", 2, NULL))))))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(SHRINK, 0, NULL, 1, NULL)) => 0;
|
|
|
|
assert(rbyd.weight == 1);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 0, buffer, 4)
|
|
=> 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(1), 0, buffer, 4)
|
|
=> 2;
|
|
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 1, buffer, 4)
|
|
=> LFS_ERR_NOENT;
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(1), 1, buffer, 4)
|
|
=> LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
assert(rbyd.weight == 1);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 0, buffer, 4)
|
|
=> 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(1), 0, buffer, 4)
|
|
=> 2;
|
|
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 1, buffer, 4)
|
|
=> LFS_ERR_NOENT;
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(1), 1, buffer, 4)
|
|
=> LFS_ERR_NOENT;
|
|
|
|
// try to delete the largest of three
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(GROW, 0, NULL, 1,
|
|
LFSR_ATTR(MKREG, 0, "\xaa\xaa\xaa\xaa", 4,
|
|
LFSR_ATTR(UATTR(1), 0, "\xaa\xaa", 2,
|
|
LFSR_ATTR(GROW, 1, NULL, 1,
|
|
LFSR_ATTR(MKREG, 1, "\xbb\xbb\xbb\xbb", 4,
|
|
LFSR_ATTR(UATTR(1), 1, "\xbb\xbb", 2,
|
|
LFSR_ATTR(GROW, 2, NULL, 1,
|
|
LFSR_ATTR(MKREG, 2, "\xcc\xcc\xcc\xcc", 4,
|
|
LFSR_ATTR(UATTR(1), 2, "\xcc\xcc", 2, NULL)))))))))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(SHRINK, 2, NULL, 1, NULL)) => 0;
|
|
|
|
assert(rbyd.weight == 2);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 0, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(1), 0, buffer, 4)
|
|
=> 2;
|
|
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 1, buffer, 4)
|
|
=> 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(1), 1, buffer, 4)
|
|
=> 2;
|
|
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 2, buffer, 4)
|
|
=> LFS_ERR_NOENT;
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(1), 2, buffer, 4)
|
|
=> LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
assert(rbyd.weight == 2);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 0, buffer, 4)
|
|
=> 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(1), 0, buffer, 4)
|
|
=> 2;
|
|
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 1, buffer, 4)
|
|
=> 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(1), 1, buffer, 4)
|
|
=> 2;
|
|
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 2, buffer, 4)
|
|
=> LFS_ERR_NOENT;
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(1), 2, buffer, 4)
|
|
=> LFS_ERR_NOENT;
|
|
|
|
// try to delete the smallest of three
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(GROW, 0, NULL, 1,
|
|
LFSR_ATTR(MKREG, 0, "\xaa\xaa\xaa\xaa", 4,
|
|
LFSR_ATTR(UATTR(1), 0, "\xaa\xaa", 2,
|
|
LFSR_ATTR(GROW, 1, NULL, 1,
|
|
LFSR_ATTR(MKREG, 1, "\xbb\xbb\xbb\xbb", 4,
|
|
LFSR_ATTR(UATTR(1), 1, "\xbb\xbb", 2,
|
|
LFSR_ATTR(GROW, 2, NULL, 1,
|
|
LFSR_ATTR(MKREG, 2, "\xcc\xcc\xcc\xcc", 4,
|
|
LFSR_ATTR(UATTR(1), 2, "\xcc\xcc", 2, NULL)))))))))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(SHRINK, 0, NULL, 1, NULL)) => 0;
|
|
|
|
assert(rbyd.weight == 2);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 0, buffer, 4)
|
|
=> 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(1), 0, buffer, 4)
|
|
=> 2;
|
|
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 1, buffer, 4)
|
|
=> 4;
|
|
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(1), 1, buffer, 4)
|
|
=> 2;
|
|
assert(memcmp(buffer, "\xcc\xcc", 2) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 2, buffer, 4)
|
|
=> LFS_ERR_NOENT;
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(1), 2, buffer, 4)
|
|
=> LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
assert(rbyd.weight == 2);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 0, buffer, 4)
|
|
=> 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(1), 0, buffer, 4)
|
|
=> 2;
|
|
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 1, buffer, 4)
|
|
=> 4;
|
|
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(1), 1, buffer, 4)
|
|
=> 2;
|
|
assert(memcmp(buffer, "\xcc\xcc", 2) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 2, buffer, 4)
|
|
=> LFS_ERR_NOENT;
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(1), 2, buffer, 4)
|
|
=> LFS_ERR_NOENT;
|
|
|
|
// try to delete the middle
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(GROW, 0, NULL, 1,
|
|
LFSR_ATTR(MKREG, 0, "\xaa\xaa\xaa\xaa", 4,
|
|
LFSR_ATTR(UATTR(1), 0, "\xaa\xaa", 2,
|
|
LFSR_ATTR(GROW, 1, NULL, 1,
|
|
LFSR_ATTR(MKREG, 1, "\xbb\xbb\xbb\xbb", 4,
|
|
LFSR_ATTR(UATTR(1), 1, "\xbb\xbb", 2,
|
|
LFSR_ATTR(GROW, 2, NULL, 1,
|
|
LFSR_ATTR(MKREG, 2, "\xcc\xcc\xcc\xcc", 4,
|
|
LFSR_ATTR(UATTR(1), 2, "\xcc\xcc", 2, NULL)))))))))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(SHRINK, 1, NULL, 1, NULL)) => 0;
|
|
|
|
assert(rbyd.weight == 2);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 0, buffer, 4)
|
|
=> 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(1), 0, buffer, 4)
|
|
=> 2;
|
|
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 1, buffer, 4)
|
|
=> 4;
|
|
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(1), 1, buffer, 4)
|
|
=> 2;
|
|
assert(memcmp(buffer, "\xcc\xcc", 2) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 2, buffer, 4)
|
|
=> LFS_ERR_NOENT;
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(1), 2, buffer, 4)
|
|
=> LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
assert(rbyd.weight == 2);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 0, buffer, 4)
|
|
=> 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(1), 0, buffer, 4)
|
|
=> 2;
|
|
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 1, buffer, 4)
|
|
=> 4;
|
|
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(1), 1, buffer, 4)
|
|
=> 2;
|
|
assert(memcmp(buffer, "\xcc\xcc", 2) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 2, buffer, 4)
|
|
=> LFS_ERR_NOENT;
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(1), 2, buffer, 4)
|
|
=> LFS_ERR_NOENT;
|
|
'''
|
|
|
|
# NOTE if we separate physical/logical block sizes we may be able to
|
|
# use emubd's copy-on-write copy to speed this up significantly
|
|
[cases.test_rbyd_delete_permutations]
|
|
defines.N = 'range(1, 7)'
|
|
# large progs take too long for now
|
|
if = 'PROG_SIZE < 512'
|
|
in = 'lfs.c'
|
|
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][6] = {
|
|
"\xaa\xaa\xaa\xaa\xaa\xaa",
|
|
"\xbb\xbb\xbb\xbb\xbb\xbb",
|
|
"\xcc\xcc\xcc\xcc\xcc\xcc",
|
|
"\xdd\xdd\xdd\xdd\xdd\xdd",
|
|
"\xee\xee\xee\xee\xee\xee",
|
|
"\xff\xff\xff\xff\xff\xff",
|
|
};
|
|
uint8_t buffer[6];
|
|
|
|
// keep track of the worst case log size
|
|
lfs_size_t worst_size = 0;
|
|
|
|
// 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]);
|
|
}
|
|
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(GROW, id, NULL, 1,
|
|
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 = malloc(rbyd.off);
|
|
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);
|
|
|
|
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(SHRINK, j, NULL, 1, NULL)) => 0;
|
|
assert(rbyd.weight == N-1);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block,
|
|
cfg->block_size, NULL) => 0;
|
|
assert(rbyd.weight == N-1);
|
|
for (unsigned k = 0; k < N-1; k++) {
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, k, 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_get(&lfs, &rbyd, LFSR_TAG_MKREG, N-1, buffer, 4)
|
|
=> LFS_ERR_NOENT;
|
|
|
|
// try recreating the id to make sure things still work
|
|
printf("--- create: %d ---\n", j);
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(GROW, j, NULL, 1,
|
|
LFSR_ATTR(MKREG, j, names[j % 6], 6, NULL))) => 0;
|
|
assert(rbyd.weight == N);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block,
|
|
cfg->block_size, NULL) => 0;
|
|
assert(rbyd.weight == N);
|
|
for (unsigned k = 0; k < N; k++) {
|
|
if (k == j) {
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, k, buffer, 6)
|
|
=> 6;
|
|
assert(memcmp(buffer, names[k % 6], 6) == 0);
|
|
} else {
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, k, buffer, 6)
|
|
=> 4;
|
|
assert(memcmp(buffer, names[k % 6], 4) == 0);
|
|
}
|
|
}
|
|
|
|
// keep track of the worst size
|
|
worst_size = lfs_max(worst_size, rbyd.off);
|
|
}
|
|
|
|
// cleanup
|
|
free(backup_block);
|
|
|
|
// 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;
|
|
}
|
|
}
|
|
|
|
// test that tree is self-balancing, we should be strictly bounded
|
|
// by height <= 2*log(n)+1, assume tags are strictly <=12 bytes
|
|
lfs_size_t n = 1 + N + 2;
|
|
printf("worst size: %u B (N=%u, estimate=%u)\n",
|
|
worst_size, n, 12*n*(2*lfs_nlog2(n)+1)+4);
|
|
printf("avg height: %u B (N=%u, estimate=%u)\n",
|
|
worst_size / n, n, 12*(2*lfs_nlog2(n)+1)+4);
|
|
// note this only holds true with byte-level progs
|
|
if (PROG_SIZE == 1) {
|
|
assert(worst_size / n <= 12*(2*lfs_nlog2(n)+1)+4);
|
|
}
|
|
'''
|
|
|
|
# NOTE if we separate physical/logical block sizes we may be able to
|
|
# use emubd's copy-on-write copy to speed this up significantly
|
|
[cases.test_rbyd_delete_range_permutations]
|
|
defines.N = 'range(1, 7)'
|
|
defines.M = 'range(1, 4)'
|
|
# large progs take too long for now
|
|
if = 'PROG_SIZE < 512'
|
|
in = 'lfs.c'
|
|
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][6] = {
|
|
"\xaa\xaa\xaa\xaa\xaa\xaa",
|
|
"\xbb\xbb\xbb\xbb\xbb\xbb",
|
|
"\xcc\xcc\xcc\xcc\xcc\xcc",
|
|
"\xdd\xdd\xdd\xdd\xdd\xdd",
|
|
"\xee\xee\xee\xee\xee\xee",
|
|
"\xff\xff\xff\xff\xff\xff",
|
|
};
|
|
uint8_t buffer[6];
|
|
|
|
// keep track of the worst case log size
|
|
lfs_size_t worst_size = 0;
|
|
|
|
// 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]);
|
|
}
|
|
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(GROW, id, NULL, 1,
|
|
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 = malloc(rbyd.off);
|
|
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);
|
|
|
|
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(SHRINK, j, NULL, 1, NULL)) => 0;
|
|
assert(rbyd.weight == N-1);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block,
|
|
cfg->block_size, NULL) => 0;
|
|
assert(rbyd.weight == N-1);
|
|
for (unsigned k = 0; k < N-1; k++) {
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, k, 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_get(&lfs, &rbyd,
|
|
LFSR_TAG_UATTR(u+1), k, 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_get(&lfs, &rbyd, LFSR_TAG_MKREG, N-1, buffer, 4)
|
|
=> LFS_ERR_NOENT;
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(1), N-1, buffer, 4)
|
|
=> LFS_ERR_NOENT;
|
|
|
|
// try recreating the id to make sure things still work
|
|
printf("--- create: %d ---\n", j);
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(GROW, j, NULL, 1,
|
|
LFSR_ATTR(MKREG, j, names[j % 6], 6, NULL))) => 0;
|
|
for (unsigned u = 0; u < M; u++) {
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(UATTR(u+1), j, names[j % 6], 3, NULL)) => 0;
|
|
}
|
|
assert(rbyd.weight == N);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block,
|
|
cfg->block_size, NULL) => 0;
|
|
assert(rbyd.weight == N);
|
|
for (unsigned k = 0; k < N; k++) {
|
|
if (k == j) {
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, k, buffer, 6)
|
|
=> 6;
|
|
assert(memcmp(buffer, names[k % 6], 6) == 0);
|
|
|
|
for (unsigned u = 0; u < M; u++) {
|
|
lfsr_rbyd_get(&lfs, &rbyd,
|
|
LFSR_TAG_UATTR(u+1), k, buffer, 6)
|
|
=> 3;
|
|
assert(memcmp(buffer, names[k % 6], 3) == 0);
|
|
}
|
|
} else {
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, k, buffer, 6)
|
|
=> 4;
|
|
assert(memcmp(buffer, names[k % 6], 4) == 0);
|
|
|
|
for (unsigned u = 0; u < M; u++) {
|
|
lfsr_rbyd_get(&lfs, &rbyd,
|
|
LFSR_TAG_UATTR(u+1), k, buffer, 6)
|
|
=> 2;
|
|
assert(memcmp(buffer, names[k % 6], 2) == 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
// keep track of the worst size
|
|
worst_size = lfs_max(worst_size, rbyd.off);
|
|
}
|
|
|
|
// cleanup
|
|
free(backup_block);
|
|
|
|
// 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;
|
|
}
|
|
}
|
|
|
|
// test that tree is self-balancing, we should be strictly bounded
|
|
// by height <= 2*log(n)+1, assume tags are strictly <=12 bytes
|
|
lfs_size_t n = 1 + N+N*M + 1 + 1+M;
|
|
printf("worst size: %u B (N=%u, estimate=%u)\n",
|
|
worst_size, n, 12*n*(2*lfs_nlog2(n)+1)+4);
|
|
printf("avg height: %u B (N=%u, estimate=%u)\n",
|
|
worst_size / n, n, 12*(2*lfs_nlog2(n)+1)+4);
|
|
// note this only holds true with byte-level progs
|
|
if (PROG_SIZE == 1) {
|
|
assert(worst_size / n <= 12*(2*lfs_nlog2(n)+1)+4);
|
|
}
|
|
'''
|
|
|
|
# NOTE if we separate physical/logical block sizes we may be able to
|
|
# use emubd's copy-on-write copy to speed this up significantly
|
|
[cases.test_rbyd_delete_traverse_permutations]
|
|
defines.N = 'range(1, 7)'
|
|
# large progs take too long for now
|
|
if = 'PROG_SIZE < 512'
|
|
in = 'lfs.c'
|
|
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_;
|
|
lfs_ssize_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]);
|
|
}
|
|
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(GROW, id, NULL, 1,
|
|
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 = malloc(rbyd.off);
|
|
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);
|
|
|
|
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(SHRINK, j, NULL, 1, 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_, NULL, &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_, NULL, &off_, &size_) => LFS_ERR_NOENT;
|
|
}
|
|
|
|
// cleanup
|
|
free(backup_block);
|
|
|
|
// 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;
|
|
}
|
|
}
|
|
'''
|
|
|
|
# NOTE if we separate physical/logical block sizes we may be able to
|
|
# use emubd's copy-on-write copy to speed this up significantly
|
|
[cases.test_rbyd_delete_traverse_range_permutations]
|
|
defines.N = 'range(1, 7)'
|
|
defines.M = 'range(1, 4)'
|
|
# large progs take too long for now
|
|
if = 'PROG_SIZE < 512'
|
|
in = 'lfs.c'
|
|
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_;
|
|
lfs_ssize_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]);
|
|
}
|
|
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(GROW, id, NULL, 1,
|
|
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 = malloc(rbyd.off);
|
|
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);
|
|
|
|
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(SHRINK, j, NULL, 1, 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_, NULL, &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_, NULL, &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_, NULL, &off_, &size_) => LFS_ERR_NOENT;
|
|
}
|
|
|
|
// cleanup
|
|
free(backup_block);
|
|
|
|
// 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;
|
|
}
|
|
}
|
|
'''
|
|
|
|
# Note, "delete_all" is a weird state for rbyd trees to be in, since they
|
|
# don't really have a trunk at this point
|
|
[cases.test_rbyd_delete_all]
|
|
in = 'lfs.c'
|
|
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;
|
|
uint8_t buffer[4];
|
|
|
|
// create and delete one id
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(GROW, 0, NULL, 1,
|
|
LFSR_ATTR(MKREG, 0, "\xaa\xaa\xaa\xaa", 4, NULL))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(SHRINK, 0, NULL, 1, NULL)) => 0;
|
|
|
|
assert(rbyd.weight == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 0, buffer, 4)
|
|
=> LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
assert(rbyd.weight == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 0, buffer, 4)
|
|
=> LFS_ERR_NOENT;
|
|
|
|
// create and delete two ids
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(GROW, 0, NULL, 1,
|
|
LFSR_ATTR(MKREG, 0, "\xaa\xaa\xaa\xaa", 4,
|
|
LFSR_ATTR(GROW, 1, NULL, 1,
|
|
LFSR_ATTR(MKREG, 1, "\xbb\xbb\xbb\xbb", 4, NULL))))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(SHRINK, 0, NULL, 1,
|
|
LFSR_ATTR(SHRINK, 0, NULL, 1, NULL))) => 0;
|
|
|
|
assert(rbyd.weight == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 0, buffer, 4)
|
|
=> LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
assert(rbyd.weight == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 0, buffer, 4)
|
|
=> LFS_ERR_NOENT;
|
|
|
|
// create and delete two ids in the other order
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(GROW, 0, NULL, 1,
|
|
LFSR_ATTR(MKREG, 0, "\xaa\xaa\xaa\xaa", 4,
|
|
LFSR_ATTR(GROW, 1, NULL, 1,
|
|
LFSR_ATTR(MKREG, 1, "\xbb\xbb\xbb\xbb", 4, NULL))))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(SHRINK, 1, NULL, 1,
|
|
LFSR_ATTR(SHRINK, 0, NULL, 1, NULL))) => 0;
|
|
|
|
assert(rbyd.weight == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 0, buffer, 4)
|
|
=> LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
assert(rbyd.weight == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 0, buffer, 4)
|
|
=> LFS_ERR_NOENT;
|
|
|
|
// create and delete three ids
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(GROW, 0, NULL, 1,
|
|
LFSR_ATTR(MKREG, 0, "\xaa\xaa\xaa\xaa", 4,
|
|
LFSR_ATTR(GROW, 1, NULL, 1,
|
|
LFSR_ATTR(MKREG, 1, "\xbb\xbb\xbb\xbb", 4,
|
|
LFSR_ATTR(GROW, 2, NULL, 1,
|
|
LFSR_ATTR(MKREG, 2, "\xcc\xcc\xcc\xcc", 4, NULL))))))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(SHRINK, 0, NULL, 1,
|
|
LFSR_ATTR(SHRINK, 0, NULL, 1,
|
|
LFSR_ATTR(SHRINK, 0, NULL, 1, NULL)))) => 0;
|
|
|
|
assert(rbyd.weight == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 0, buffer, 4)
|
|
=> LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
assert(rbyd.weight == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 0, buffer, 4)
|
|
=> LFS_ERR_NOENT;
|
|
|
|
// create and delete three ids in the other order
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(GROW, 0, NULL, 1,
|
|
LFSR_ATTR(MKREG, 0, "\xaa\xaa\xaa\xaa", 4,
|
|
LFSR_ATTR(GROW, 1, NULL, 1,
|
|
LFSR_ATTR(MKREG, 1, "\xbb\xbb\xbb\xbb", 4,
|
|
LFSR_ATTR(GROW, 2, NULL, 1,
|
|
LFSR_ATTR(MKREG, 2, "\xcc\xcc\xcc\xcc", 4, NULL))))))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(SHRINK, 2, NULL, 1,
|
|
LFSR_ATTR(SHRINK, 1, NULL, 1,
|
|
LFSR_ATTR(SHRINK, 0, NULL, 1, NULL)))) => 0;
|
|
|
|
assert(rbyd.weight == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 0, buffer, 4)
|
|
=> LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
assert(rbyd.weight == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 0, buffer, 4)
|
|
=> LFS_ERR_NOENT;
|
|
'''
|
|
|
|
[cases.test_rbyd_delete_all_range]
|
|
in = 'lfs.c'
|
|
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;
|
|
uint8_t buffer[4];
|
|
|
|
// create and delete one id
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(GROW, 0, NULL, 1,
|
|
LFSR_ATTR(MKREG, 0, "\xaa\xaa\xaa\xaa", 4,
|
|
LFSR_ATTR(UATTR(1), 0, "\xaa\xaa", 2, NULL)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(SHRINK, 0, NULL, 1, NULL)) => 0;
|
|
|
|
assert(rbyd.weight == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 0, buffer, 4)
|
|
=> LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
assert(rbyd.weight == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 0, buffer, 4)
|
|
=> LFS_ERR_NOENT;
|
|
|
|
// create and delete two ids
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(GROW, 0, NULL, 1,
|
|
LFSR_ATTR(MKREG, 0, "\xaa\xaa\xaa\xaa", 4,
|
|
LFSR_ATTR(UATTR(1), 0, "\xaa\xaa", 2,
|
|
LFSR_ATTR(GROW, 1, NULL, 1,
|
|
LFSR_ATTR(MKREG, 1, "\xbb\xbb\xbb\xbb", 4,
|
|
LFSR_ATTR(UATTR(1), 1, "\xbb\xbb", 2, NULL))))))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(SHRINK, 0, NULL, 1,
|
|
LFSR_ATTR(SHRINK, 0, NULL, 1, NULL))) => 0;
|
|
|
|
assert(rbyd.weight == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 0, buffer, 4)
|
|
=> LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
assert(rbyd.weight == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 0, buffer, 4)
|
|
=> LFS_ERR_NOENT;
|
|
|
|
// create and delete two ids in the other order
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(GROW, 0, NULL, 1,
|
|
LFSR_ATTR(MKREG, 0, "\xaa\xaa\xaa\xaa", 4,
|
|
LFSR_ATTR(UATTR(1), 0, "\xaa\xaa", 2,
|
|
LFSR_ATTR(GROW, 1, NULL, 1,
|
|
LFSR_ATTR(MKREG, 1, "\xbb\xbb\xbb\xbb", 4,
|
|
LFSR_ATTR(UATTR(1), 1, "\xbb\xbb", 2, NULL))))))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(SHRINK, 1, NULL, 1,
|
|
LFSR_ATTR(SHRINK, 0, NULL, 1, NULL))) => 0;
|
|
|
|
assert(rbyd.weight == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 0, buffer, 4)
|
|
=> LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
assert(rbyd.weight == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 0, buffer, 4)
|
|
=> LFS_ERR_NOENT;
|
|
|
|
// create and delete three ids
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(GROW, 0, NULL, 1,
|
|
LFSR_ATTR(MKREG, 0, "\xaa\xaa\xaa\xaa", 4,
|
|
LFSR_ATTR(UATTR(1), 0, "\xaa\xaa", 2,
|
|
LFSR_ATTR(GROW, 1, NULL, 1,
|
|
LFSR_ATTR(MKREG, 1, "\xbb\xbb\xbb\xbb", 4,
|
|
LFSR_ATTR(UATTR(1), 1, "\xbb\xbb", 2,
|
|
LFSR_ATTR(GROW, 2, NULL, 1,
|
|
LFSR_ATTR(MKREG, 2, "\xcc\xcc\xcc\xcc", 4,
|
|
LFSR_ATTR(UATTR(1), 2, "\xcc\xcc", 2, NULL)))))))))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(SHRINK, 0, NULL, 1,
|
|
LFSR_ATTR(SHRINK, 0, NULL, 1,
|
|
LFSR_ATTR(SHRINK, 0, NULL, 1, NULL)))) => 0;
|
|
|
|
assert(rbyd.weight == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 0, buffer, 4)
|
|
=> LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
assert(rbyd.weight == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 0, buffer, 4)
|
|
=> LFS_ERR_NOENT;
|
|
|
|
// create and delete three ids in the other order
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(GROW, 0, NULL, 1,
|
|
LFSR_ATTR(MKREG, 0, "\xaa\xaa\xaa\xaa", 4,
|
|
LFSR_ATTR(UATTR(1), 0, "\xaa\xaa", 2,
|
|
LFSR_ATTR(GROW, 1, NULL, 1,
|
|
LFSR_ATTR(MKREG, 1, "\xbb\xbb\xbb\xbb", 4,
|
|
LFSR_ATTR(UATTR(1), 1, "\xbb\xbb", 2,
|
|
LFSR_ATTR(GROW, 2, NULL, 1,
|
|
LFSR_ATTR(MKREG, 2, "\xcc\xcc\xcc\xcc", 4,
|
|
LFSR_ATTR(UATTR(1), 2, "\xcc\xcc", 2, NULL)))))))))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(SHRINK, 2, NULL, 1,
|
|
LFSR_ATTR(SHRINK, 1, NULL, 1,
|
|
LFSR_ATTR(SHRINK, 0, NULL, 1, NULL)))) => 0;
|
|
|
|
assert(rbyd.weight == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 0, buffer, 4)
|
|
=> LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
assert(rbyd.weight == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, 0, buffer, 4)
|
|
=> LFS_ERR_NOENT;
|
|
'''
|
|
|
|
# NOTE if we separate physical/logical block sizes we may be able to
|
|
# use emubd's copy-on-write copy to speed this up significantly
|
|
[cases.test_rbyd_delete_all_permutations]
|
|
defines.N = 'range(1, 7)'
|
|
# large progs take too long for now
|
|
if = 'PROG_SIZE < 512'
|
|
in = 'lfs.c'
|
|
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",
|
|
};
|
|
uint8_t buffer[6];
|
|
|
|
// keep track of the worst case log size
|
|
lfs_size_t worst_size = 0;
|
|
|
|
// create one consistent block
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
|
|
for (unsigned j = 0; j < N; j++) {
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(GROW, j, NULL, 1,
|
|
LFSR_ATTR(MKREG, j, names[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 = malloc(rbyd.off);
|
|
lfs_bd_read(&lfs, NULL, &lfs.rcache, rbyd.off,
|
|
rbyd.block, 0, backup_block, rbyd.off) => 0;
|
|
|
|
// 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]);
|
|
}
|
|
printf("] ---\n");
|
|
|
|
// restore backup
|
|
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;
|
|
|
|
// delete each id in permutation order
|
|
for (unsigned j = 0; j < N; j++) {
|
|
// adjust id based on previous deletions
|
|
uint16_t id = perm[j];
|
|
for (unsigned k = 0; k < j; k++) {
|
|
if (perm[k] < perm[j]) {
|
|
id -= 1;
|
|
}
|
|
}
|
|
|
|
lfs_size_t rbyd_weight_before = rbyd.weight;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(SHRINK, id, NULL, 1, NULL)) => 0;
|
|
assert(rbyd.weight == rbyd_weight_before-1);
|
|
}
|
|
|
|
// check that all tags are now removed
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
assert(rbyd.weight == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd,
|
|
LFSR_TAG_MKREG, 0, buffer, 4)
|
|
=> LFS_ERR_NOENT;
|
|
|
|
// try resuming from all tags being removed
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(GROW, 0, NULL, 1,
|
|
LFSR_ATTR(MKREG, 0, "\xaa\xaa\xaa\xaa\xaa\xaa", 6,
|
|
NULL))) => 0;
|
|
assert(rbyd.weight == 1);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
assert(rbyd.weight == 1);
|
|
lfsr_rbyd_get(&lfs, &rbyd,
|
|
LFSR_TAG_MKREG, 0, buffer, 6)
|
|
=> 6;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa\xaa\xaa", 6) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd,
|
|
LFSR_TAG_MKREG, 1, buffer, 6)
|
|
=> LFS_ERR_NOENT;
|
|
|
|
// keep track of the worst size
|
|
worst_size = lfs_max(worst_size, rbyd.off);
|
|
|
|
// 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;
|
|
}
|
|
}
|
|
|
|
// cleanup
|
|
free(backup_block);
|
|
|
|
// test that tree is self-balancing, we should be strictly bounded
|
|
// by height <= 2*log(n)+1, assume tags are strictly <=12 bytes
|
|
lfs_size_t n = 1 + 2*N + 1;
|
|
printf("worst size: %u B (N=%u, estimate=%u)\n",
|
|
worst_size, n, 12*n*(2*lfs_nlog2(n)+1)+4);
|
|
printf("avg height: %u B (N=%u, estimate=%u)\n",
|
|
worst_size / n, n, 12*(2*lfs_nlog2(n)+1)+4);
|
|
// note this only holds true with byte-level progs
|
|
if (PROG_SIZE == 1) {
|
|
assert(worst_size / n <= 12*(2*lfs_nlog2(n)+1)+4);
|
|
}
|
|
'''
|
|
|
|
# NOTE if we separate physical/logical block sizes we may be able to
|
|
# use emubd's copy-on-write copy to speed this up significantly
|
|
[cases.test_rbyd_delete_all_range_permutations]
|
|
defines.N = 'range(1, 7)'
|
|
defines.M = 'range(1, 4)'
|
|
# large progs take too long for now
|
|
if = 'PROG_SIZE < 512'
|
|
in = 'lfs.c'
|
|
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",
|
|
};
|
|
uint8_t buffer[6];
|
|
|
|
// keep track of the worst case log size
|
|
lfs_size_t worst_size = 0;
|
|
|
|
// create one consistent block
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
|
|
for (unsigned j = 0; j < N; j++) {
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(GROW, j, NULL, 1,
|
|
LFSR_ATTR(MKREG, j, names[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), j, names[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 = malloc(rbyd.off);
|
|
lfs_bd_read(&lfs, NULL, &lfs.rcache, rbyd.off,
|
|
rbyd.block, 0, backup_block, rbyd.off) => 0;
|
|
|
|
// 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]);
|
|
}
|
|
printf("] ---\n");
|
|
|
|
// restore backup
|
|
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;
|
|
|
|
// delete each id in permutation order
|
|
for (unsigned j = 0; j < N; j++) {
|
|
// adjust id based on previous deletions
|
|
uint16_t id = perm[j];
|
|
for (unsigned k = 0; k < j; k++) {
|
|
if (perm[k] < perm[j]) {
|
|
id -= 1;
|
|
}
|
|
}
|
|
|
|
lfs_size_t rbyd_weight_before = rbyd.weight;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(SHRINK, id, NULL, 1, NULL)) => 0;
|
|
assert(rbyd.weight == rbyd_weight_before-1);
|
|
}
|
|
|
|
// check that all tags are now removed
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
assert(rbyd.weight == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd,
|
|
LFSR_TAG_MKREG, 0, buffer, 4)
|
|
=> LFS_ERR_NOENT;
|
|
|
|
// try resuming from all tags being removed
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(GROW, 0, NULL, 1,
|
|
LFSR_ATTR(MKREG, 0, "\xaa\xaa\xaa\xaa\xaa\xaa", 6,
|
|
NULL))) => 0;
|
|
for (unsigned u = 0; u < M; u++) {
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(UATTR(u+1), 0, "\xaa\xaa\xaa", 3,
|
|
NULL)) => 0;
|
|
}
|
|
assert(rbyd.weight == 1);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
assert(rbyd.weight == 1);
|
|
lfsr_rbyd_get(&lfs, &rbyd,
|
|
LFSR_TAG_MKREG, 0, buffer, 6)
|
|
=> 6;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa\xaa\xaa", 6) == 0);
|
|
for (unsigned u = 0; u < M; u++) {
|
|
lfsr_rbyd_get(&lfs, &rbyd,
|
|
LFSR_TAG_UATTR(u+1), 0, buffer, 6)
|
|
=> 3;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa", 3) == 0);
|
|
}
|
|
lfsr_rbyd_get(&lfs, &rbyd,
|
|
LFSR_TAG_MKREG, 1, buffer, 6)
|
|
=> LFS_ERR_NOENT;
|
|
lfsr_rbyd_get(&lfs, &rbyd,
|
|
LFSR_TAG_UATTR(1), 1, buffer, 6)
|
|
=> LFS_ERR_NOENT;
|
|
|
|
// keep track of the worst size
|
|
worst_size = lfs_max(worst_size, rbyd.off);
|
|
|
|
// 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;
|
|
}
|
|
}
|
|
|
|
// cleanup
|
|
free(backup_block);
|
|
|
|
// test that tree is self-balancing, we should be strictly bounded
|
|
// by height <= 2*log(n)+1, assume tags are strictly <=12 bytes
|
|
lfs_size_t n = 1 + N+N*M + N + 1+M;
|
|
printf("worst size: %u B (N=%u, estimate=%u)\n",
|
|
worst_size, n, 12*n*(2*lfs_nlog2(n)+1)+4);
|
|
printf("avg height: %u B (N=%u, estimate=%u)\n",
|
|
worst_size / n, n, 12*(2*lfs_nlog2(n)+1)+4);
|
|
// note this only holds true with byte-level progs
|
|
if (PROG_SIZE == 1) {
|
|
assert(worst_size / n <= 12*(2*lfs_nlog2(n)+1)+4);
|
|
}
|
|
'''
|
|
|
|
# the main purpose of this test is to try to fuzz for failures in the
|
|
# balancing algorithm
|
|
[cases.test_rbyd_random_create_deletes]
|
|
defines.N = 'range(1, 33)'
|
|
defines.ITER = 1000
|
|
# large progs take too long for now
|
|
if = 'PROG_SIZE < 512'
|
|
in = 'lfs.c'
|
|
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 char *alpha = "abcdefghijklmnopqrstuvwxyz";
|
|
uint8_t buffer[4];
|
|
|
|
// keep track of the worst case size and seed
|
|
lfs_size_t worst_size = 0;
|
|
uint32_t worst_seed = 0;
|
|
|
|
// iterate through seeds so we can reproduce easily
|
|
for (uint32_t seed = 1; seed < ITER+1; seed++) {
|
|
printf("--- seed: %d ---\n", seed);
|
|
printf("perm: [");
|
|
uint32_t prng = seed;
|
|
lfs_size_t count = 0;
|
|
for (unsigned i = 0; i < N; i++) {
|
|
// choose an id
|
|
lfs_ssize_t id = TEST_PRNG(&prng) % (count+1);
|
|
// choose create or delete
|
|
if (id == (lfs_ssize_t)count || (TEST_PRNG(&prng) & 1)) {
|
|
printf("c%d=%c", id, alpha[i % 26]);
|
|
count += 1;
|
|
} else {
|
|
printf("d%d", id);
|
|
count -= 1;
|
|
}
|
|
if (i < N-1) {
|
|
printf(", ");
|
|
}
|
|
}
|
|
printf("]\n");
|
|
|
|
// set up a simulation to compare against, fun fact this performs
|
|
// worst than our actual rbyd block!
|
|
char *sim = malloc(N);
|
|
memset(sim, 0, N);
|
|
|
|
// set up rbyd block
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
|
|
prng = seed;
|
|
count = 0;
|
|
for (unsigned i = 0; i < N; i++) {
|
|
// choose an id
|
|
lfs_ssize_t id = TEST_PRNG(&prng) % (count+1);
|
|
// choose create or delete
|
|
if (id == (lfs_ssize_t)count || (TEST_PRNG(&prng) & 1)) {
|
|
// update our sim
|
|
memmove(sim+id+1, sim+id, count-id);
|
|
sim[id] = alpha[i % 26];
|
|
count += 1;
|
|
// update our rbyd
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(GROW, id, NULL, 1,
|
|
LFSR_ATTR(MKREG, id, &alpha[i % 26], 1,
|
|
NULL))) => 0;
|
|
} else {
|
|
// update our sim
|
|
memmove(sim+id, sim+id+1, count-id-1);
|
|
count -= 1;
|
|
// update our rbyd
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(SHRINK, id, NULL, 1,
|
|
NULL)) => 0;
|
|
}
|
|
}
|
|
|
|
// compare rbyd vs simulation
|
|
printf("expd: [");
|
|
for (lfs_ssize_t id = 0; id < (lfs_ssize_t)count; id++) {
|
|
printf("%c", sim[id]);
|
|
if (id < (lfs_ssize_t)count-1) {
|
|
printf(", ");
|
|
}
|
|
}
|
|
printf("]\n");
|
|
printf("rbyd: [");
|
|
for (lfs_ssize_t id = 0; id < (lfs_ssize_t)rbyd.weight; id++) {
|
|
lfs_ssize_t size = lfsr_rbyd_get(&lfs, &rbyd,
|
|
LFSR_TAG_MKREG, id, buffer, 4);
|
|
if (size >= 0) {
|
|
printf("%.*s", size, buffer);
|
|
} else {
|
|
printf("?");
|
|
}
|
|
if (id < (lfs_ssize_t)count-1) {
|
|
printf(", ");
|
|
}
|
|
}
|
|
printf("]\n");
|
|
|
|
assert(count == rbyd.weight);
|
|
for (lfs_ssize_t id = 0; id < (lfs_ssize_t)count; id++) {
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, id, buffer, 4) => 1;
|
|
assert(memcmp(&sim[id], buffer, 1) == 0);
|
|
}
|
|
|
|
// keep track of the worst permutation
|
|
if (rbyd.off > worst_size) {
|
|
worst_size = rbyd.off;
|
|
worst_seed = seed;
|
|
}
|
|
|
|
// cleanup
|
|
free(sim);
|
|
}
|
|
|
|
// print the worst seed + size, and rerun it so it's left on the disk
|
|
// if used with -ddisk
|
|
printf("--- worst ---\n");
|
|
printf("worst_seed: %d\n", worst_seed);
|
|
printf("worst_size: %d\n", worst_size);
|
|
printf("worst_perm: [");
|
|
uint32_t prng = worst_seed;
|
|
lfs_size_t count = 0;
|
|
for (unsigned i = 0; i < N; i++) {
|
|
// choose an id
|
|
lfs_ssize_t id = TEST_PRNG(&prng) % (count+1);
|
|
// choose create or delete
|
|
if (id == (lfs_ssize_t)count || (TEST_PRNG(&prng) & 1)) {
|
|
printf("c%d=%c", id, alpha[i % 26]);
|
|
count += 1;
|
|
} else {
|
|
printf("d%d", id);
|
|
count -= 1;
|
|
}
|
|
if (i < N-1) {
|
|
printf(", ");
|
|
}
|
|
}
|
|
printf("]\n");
|
|
|
|
// set up rbyd block
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
|
|
prng = worst_seed;
|
|
count = 0;
|
|
for (unsigned i = 0; i < N; i++) {
|
|
// choose an id
|
|
lfs_ssize_t id = TEST_PRNG(&prng) % (count+1);
|
|
// choose create or delete
|
|
if (id == (lfs_ssize_t)count || (TEST_PRNG(&prng) & 1)) {
|
|
count += 1;
|
|
// update our rbyd
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(GROW, id, NULL, 1,
|
|
LFSR_ATTR(MKREG, id, &alpha[i % 26], 1,
|
|
NULL))) => 0;
|
|
} else {
|
|
count -= 1;
|
|
// update our rbyd
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(SHRINK, id, NULL, 1,
|
|
NULL)) => 0;
|
|
}
|
|
}
|
|
|
|
// our tree should be strictly <= 2*log(n)+1, assume tags are strictly
|
|
// <=12 bytes, note this only holds true with byte-level progs
|
|
if (PROG_SIZE == 1) {
|
|
assert(worst_size <= 2*N*12*(2*lfs_nlog2(N)+1)+1);
|
|
}
|
|
'''
|
|
|
|
|
|
# Test rbyd weights
|
|
[cases.test_rbyd_grow]
|
|
in = 'lfs.c'
|
|
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_;
|
|
lfs_ssize_t id_;
|
|
lfs_size_t weight_;
|
|
lfs_off_t off_;
|
|
lfs_size_t size_;
|
|
|
|
// make id0 with weight w1
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(GROW, 0, NULL, 1,
|
|
LFSR_ATTR(MKREG, 0, "\xaa\xaa\xaa\xaa", 4, NULL))) => 0;
|
|
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_MKREG, 0,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 0);
|
|
assert(weight_ == 1);
|
|
assert(size_ == 4);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_MKREG, 0,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 0);
|
|
assert(weight_ == 1);
|
|
assert(size_ == 4);
|
|
|
|
// make id2 with weight w2
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(GROW, 1, NULL, 2,
|
|
LFSR_ATTR(MKREG, 2, "\xbb\xbb\xbb\xbb", 4,
|
|
NULL))) => 0;
|
|
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_MKREG, 0,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 0);
|
|
assert(weight_ == 1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_MKREG, 2,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 2);
|
|
assert(weight_ == 2);
|
|
assert(size_ == 4);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_MKREG, 0,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 0);
|
|
assert(weight_ == 1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_MKREG, 2,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 2);
|
|
assert(weight_ == 2);
|
|
assert(size_ == 4);
|
|
|
|
// make id5 with weight w3
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(GROW, 3, NULL, 3,
|
|
LFSR_ATTR(MKREG, 5, "\xcc\xcc\xcc\xcc", 4,
|
|
NULL))) => 0;
|
|
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_MKREG, 0,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 0);
|
|
assert(weight_ == 1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_MKREG, 2,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 2);
|
|
assert(weight_ == 2);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_MKREG, 5,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 5);
|
|
assert(weight_ == 3);
|
|
assert(size_ == 4);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_MKREG, 0,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 0);
|
|
assert(weight_ == 1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_MKREG, 2,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 2);
|
|
assert(weight_ == 2);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_MKREG, 5,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 5);
|
|
assert(weight_ == 3);
|
|
assert(size_ == 4);
|
|
|
|
// make id9 with weight w4
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(GROW, 6, NULL, 4,
|
|
LFSR_ATTR(MKREG, 9, "\xdd\xdd\xdd\xdd", 4,
|
|
NULL))) => 0;
|
|
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_MKREG, 0,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 0);
|
|
assert(weight_ == 1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_MKREG, 2,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 2);
|
|
assert(weight_ == 2);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_MKREG, 5,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 5);
|
|
assert(weight_ == 3);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_MKREG, 9,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 9);
|
|
assert(weight_ == 4);
|
|
assert(size_ == 4);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_MKREG, 0,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 0);
|
|
assert(weight_ == 1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_MKREG, 2,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 2);
|
|
assert(weight_ == 2);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_MKREG, 5,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 5);
|
|
assert(weight_ == 3);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_MKREG, 9,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 9);
|
|
assert(weight_ == 4);
|
|
assert(size_ == 4);
|
|
|
|
// make id14 with weight w5
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(GROW, 10, NULL, 5,
|
|
LFSR_ATTR(MKREG, 14, "\xee\xee\xee\xee", 4,
|
|
NULL))) => 0;
|
|
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_MKREG, 0,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 0);
|
|
assert(weight_ == 1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_MKREG, 2,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 2);
|
|
assert(weight_ == 2);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_MKREG, 5,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 5);
|
|
assert(weight_ == 3);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_MKREG, 9,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 9);
|
|
assert(weight_ == 4);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_MKREG, 14,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 14);
|
|
assert(weight_ == 5);
|
|
assert(size_ == 4);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_MKREG, 0,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 0);
|
|
assert(weight_ == 1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_MKREG, 2,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 2);
|
|
assert(weight_ == 2);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_MKREG, 5,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 5);
|
|
assert(weight_ == 3);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_MKREG, 9,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 9);
|
|
assert(weight_ == 4);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_MKREG, 14,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 14);
|
|
assert(weight_ == 5);
|
|
assert(size_ == 4);
|
|
'''
|
|
|
|
[cases.test_rbyd_grow_traverse]
|
|
in = 'lfs.c'
|
|
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_;
|
|
lfs_ssize_t id_;
|
|
lfs_size_t weight_;
|
|
lfs_off_t off_;
|
|
lfs_size_t size_;
|
|
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
// make id0 with weight w1
|
|
LFSR_ATTR(GROW, 0, NULL, 1,
|
|
LFSR_ATTR(MKREG, 0, "\xaa\xaa\xaa\xaa", 4,
|
|
// make id2 with weight w2
|
|
LFSR_ATTR(GROW, 1, NULL, 2,
|
|
LFSR_ATTR(MKREG, 2, "\xbb\xbb\xbb\xbb", 4,
|
|
// make id5 with weight w3
|
|
LFSR_ATTR(GROW, 3, NULL, 3,
|
|
LFSR_ATTR(MKREG, 5, "\xcc\xcc\xcc\xcc", 4,
|
|
// make id9 with weight w4
|
|
LFSR_ATTR(GROW, 6, NULL, 4,
|
|
LFSR_ATTR(MKREG, 9, "\xdd\xdd\xdd\xdd", 4,
|
|
// make id14 with weight w5
|
|
LFSR_ATTR(GROW, 10, NULL, 5,
|
|
LFSR_ATTR(MKREG, 14, "\xee\xee\xee\xee", 4,
|
|
NULL))))))))))) => 0;
|
|
|
|
// traverse, finding tags and weights
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(0), -1,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 0);
|
|
assert(weight_ == 1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 2);
|
|
assert(weight_ == 2);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 5);
|
|
assert(weight_ == 3);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 9);
|
|
assert(weight_ == 4);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 14);
|
|
assert(weight_ == 5);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, &weight_, &off_, &size_) => LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(0), -1,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 0);
|
|
assert(weight_ == 1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 2);
|
|
assert(weight_ == 2);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 5);
|
|
assert(weight_ == 3);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 9);
|
|
assert(weight_ == 4);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 14);
|
|
assert(weight_ == 5);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, &weight_, &off_, &size_) => LFS_ERR_NOENT;
|
|
'''
|
|
|
|
[cases.test_rbyd_grow_permutations]
|
|
defines.N = 'range(1, 8)'
|
|
defines.W = 5
|
|
# large progs take too long for now
|
|
if = 'PROG_SIZE < 512'
|
|
in = 'lfs.c'
|
|
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_;
|
|
lfs_ssize_t id_;
|
|
lfs_size_t weight_;
|
|
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]);
|
|
}
|
|
printf("] ---\n");
|
|
|
|
// test the 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(GROW, id*W, NULL, W,
|
|
LFSR_ATTR(MKREG, id*W+W-1, names[perm[j] % 6], 4,
|
|
NULL))) => 0;
|
|
}
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
assert(rbyd.weight == N*W);
|
|
for (unsigned j = 0; j < N; j++) {
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_MKREG, j*W+W-1,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == j*W+W-1);
|
|
assert(weight_ == W);
|
|
assert(size_ == 4);
|
|
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, j*W+W-1, buffer, 4) => 4;
|
|
assert(memcmp(buffer, names[j % 6], 4) == 0);
|
|
}
|
|
|
|
// 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_grow_traverse_permutations]
|
|
defines.N = 'range(1, 8)'
|
|
defines.W = 5
|
|
# large progs take too long for now
|
|
if = 'PROG_SIZE < 512'
|
|
in = 'lfs.c'
|
|
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_;
|
|
lfs_ssize_t id_;
|
|
lfs_size_t weight_;
|
|
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]);
|
|
}
|
|
printf("] ---\n");
|
|
|
|
// test the 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(GROW, id*W, NULL, W,
|
|
LFSR_ATTR(MKREG, id*W+W-1, names[perm[j] % 6], 4,
|
|
NULL))) => 0;
|
|
}
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
assert(rbyd.weight == N*W);
|
|
// try traversing all tags
|
|
tag_ = 0;
|
|
id_ = -1;
|
|
for (unsigned j = 0; j < N; j++) {
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == j*W+W-1);
|
|
assert(weight_ == W);
|
|
assert(size_ == 4);
|
|
|
|
lfsr_rbyd_get(&lfs, &rbyd, tag_, id_, buffer, 4) => 4;
|
|
assert(memcmp(buffer, names[j % 6], 4) == 0);
|
|
}
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, &weight_, &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;
|
|
}
|
|
}
|
|
'''
|
|
|
|
# Weights mixed with attributes
|
|
[cases.test_rbyd_mixed_grow]
|
|
in = 'lfs.c'
|
|
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_;
|
|
lfs_ssize_t id_;
|
|
lfs_size_t weight_;
|
|
lfs_off_t off_;
|
|
lfs_size_t size_;
|
|
|
|
// make id0 with weight w1
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(UATTR(3), -1, "unrelated", 9,
|
|
LFSR_ATTR(GROW, 0, NULL, 1,
|
|
LFSR_ATTR(MKREG, 0, "\xaa\xaa\xaa\xaa", 4,
|
|
LFSR_ATTR(UATTR(1), 0, "\xaa\xaa", 2,
|
|
LFSR_ATTR(UATTR(2), 0, "\xaa\xaa", 2, NULL)))))) => 0;
|
|
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(3), -1,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(3));
|
|
assert(id_ == -1);
|
|
assert(weight_ == 0);
|
|
assert(size_ == 9);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_MKREG, 0,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 0);
|
|
assert(weight_ == 1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), 0,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == 0);
|
|
assert(weight_ == 0);
|
|
assert(size_ == 2);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(2), 0,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == 0);
|
|
assert(weight_ == 0);
|
|
assert(size_ == 2);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(3), -1,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(3));
|
|
assert(id_ == -1);
|
|
assert(weight_ == 0);
|
|
assert(size_ == 9);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_MKREG, 0,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 0);
|
|
assert(weight_ == 1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), 0,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == 0);
|
|
assert(weight_ == 0);
|
|
assert(size_ == 2);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(2), 0,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == 0);
|
|
assert(weight_ == 0);
|
|
assert(size_ == 2);
|
|
|
|
// make id2 with weight w2
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(GROW, 1, NULL, 1,
|
|
LFSR_ATTR(MKREG, 1, "\xbb\xbb\xbb\xbb", 4,
|
|
LFSR_ATTR(UATTR(1), 1, "\xbb\xbb", 2,
|
|
LFSR_ATTR(GROW, 1, NULL, 1,
|
|
LFSR_ATTR(UATTR(2), 2, "\xbb\xbb", 2,
|
|
NULL)))))) => 0;
|
|
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(3), -1,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(3));
|
|
assert(id_ == -1);
|
|
assert(weight_ == 0);
|
|
assert(size_ == 9);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_MKREG, 0,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 0);
|
|
assert(weight_ == 1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), 0,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == 0);
|
|
assert(weight_ == 0);
|
|
assert(size_ == 2);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(2), 0,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == 0);
|
|
assert(weight_ == 0);
|
|
assert(size_ == 2);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_MKREG, 2,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 2);
|
|
assert(weight_ == 2);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), 2,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == 2);
|
|
assert(weight_ == 0);
|
|
assert(size_ == 2);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(2), 2,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == 2);
|
|
assert(weight_ == 0);
|
|
assert(size_ == 2);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(3), -1,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(3));
|
|
assert(id_ == -1);
|
|
assert(weight_ == 0);
|
|
assert(size_ == 9);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_MKREG, 0,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 0);
|
|
assert(weight_ == 1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), 0,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == 0);
|
|
assert(weight_ == 0);
|
|
assert(size_ == 2);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(2), 0,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == 0);
|
|
assert(weight_ == 0);
|
|
assert(size_ == 2);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_MKREG, 2,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 2);
|
|
assert(weight_ == 2);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), 2,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == 2);
|
|
assert(weight_ == 0);
|
|
assert(size_ == 2);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(2), 2,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == 2);
|
|
assert(weight_ == 0);
|
|
assert(size_ == 2);
|
|
|
|
// make id5 with weight w3
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(GROW, 3, NULL, 1,
|
|
LFSR_ATTR(MKREG, 3, "\xcc\xcc\xcc\xcc", 4,
|
|
LFSR_ATTR(UATTR(1), 3, "\xcc\xcc", 2,
|
|
LFSR_ATTR(GROW, 3, NULL, 2,
|
|
LFSR_ATTR(UATTR(2), 5, "\xcc\xcc", 2,
|
|
NULL)))))) => 0;
|
|
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(3), -1,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(3));
|
|
assert(id_ == -1);
|
|
assert(weight_ == 0);
|
|
assert(size_ == 9);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_MKREG, 0,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 0);
|
|
assert(weight_ == 1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), 0,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == 0);
|
|
assert(weight_ == 0);
|
|
assert(size_ == 2);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(2), 0,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == 0);
|
|
assert(weight_ == 0);
|
|
assert(size_ == 2);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_MKREG, 2,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 2);
|
|
assert(weight_ == 2);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), 2,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == 2);
|
|
assert(weight_ == 0);
|
|
assert(size_ == 2);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(2), 2,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == 2);
|
|
assert(weight_ == 0);
|
|
assert(size_ == 2);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_MKREG, 5,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 5);
|
|
assert(weight_ == 3);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), 5,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == 5);
|
|
assert(weight_ == 0);
|
|
assert(size_ == 2);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(2), 5,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == 5);
|
|
assert(weight_ == 0);
|
|
assert(size_ == 2);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(3), -1,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(3));
|
|
assert(id_ == -1);
|
|
assert(weight_ == 0);
|
|
assert(size_ == 9);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_MKREG, 0,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 0);
|
|
assert(weight_ == 1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), 0,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == 0);
|
|
assert(weight_ == 0);
|
|
assert(size_ == 2);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(2), 0,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == 0);
|
|
assert(weight_ == 0);
|
|
assert(size_ == 2);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_MKREG, 2,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 2);
|
|
assert(weight_ == 2);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), 2,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == 2);
|
|
assert(weight_ == 0);
|
|
assert(size_ == 2);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(2), 2,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == 2);
|
|
assert(weight_ == 0);
|
|
assert(size_ == 2);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_MKREG, 5,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 5);
|
|
assert(weight_ == 3);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), 5,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == 5);
|
|
assert(weight_ == 0);
|
|
assert(size_ == 2);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(2), 5,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == 5);
|
|
assert(weight_ == 0);
|
|
assert(size_ == 2);
|
|
|
|
// make id9 with weight w4
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(GROW, 6, NULL, 1,
|
|
LFSR_ATTR(MKREG, 6, "\xdd\xdd\xdd\xdd", 4,
|
|
LFSR_ATTR(UATTR(1), 6, "\xdd\xdd", 2,
|
|
LFSR_ATTR(GROW, 6, NULL, 3,
|
|
LFSR_ATTR(UATTR(2), 9, "\xdd\xdd", 2,
|
|
NULL)))))) => 0;
|
|
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(3), -1,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(3));
|
|
assert(id_ == -1);
|
|
assert(weight_ == 0);
|
|
assert(size_ == 9);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_MKREG, 0,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 0);
|
|
assert(weight_ == 1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), 0,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == 0);
|
|
assert(weight_ == 0);
|
|
assert(size_ == 2);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(2), 0,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == 0);
|
|
assert(weight_ == 0);
|
|
assert(size_ == 2);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_MKREG, 2,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 2);
|
|
assert(weight_ == 2);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), 2,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == 2);
|
|
assert(weight_ == 0);
|
|
assert(size_ == 2);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(2), 2,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == 2);
|
|
assert(weight_ == 0);
|
|
assert(size_ == 2);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_MKREG, 5,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 5);
|
|
assert(weight_ == 3);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), 5,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == 5);
|
|
assert(weight_ == 0);
|
|
assert(size_ == 2);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(2), 5,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == 5);
|
|
assert(weight_ == 0);
|
|
assert(size_ == 2);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_MKREG, 9,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 9);
|
|
assert(weight_ == 4);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), 9,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == 9);
|
|
assert(weight_ == 0);
|
|
assert(size_ == 2);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(2), 9,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == 9);
|
|
assert(weight_ == 0);
|
|
assert(size_ == 2);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(3), -1,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(3));
|
|
assert(id_ == -1);
|
|
assert(weight_ == 0);
|
|
assert(size_ == 9);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_MKREG, 0,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 0);
|
|
assert(weight_ == 1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), 0,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == 0);
|
|
assert(weight_ == 0);
|
|
assert(size_ == 2);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(2), 0,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == 0);
|
|
assert(weight_ == 0);
|
|
assert(size_ == 2);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_MKREG, 2,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 2);
|
|
assert(weight_ == 2);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), 2,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == 2);
|
|
assert(weight_ == 0);
|
|
assert(size_ == 2);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(2), 2,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == 2);
|
|
assert(weight_ == 0);
|
|
assert(size_ == 2);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_MKREG, 5,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 5);
|
|
assert(weight_ == 3);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), 5,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == 5);
|
|
assert(weight_ == 0);
|
|
assert(size_ == 2);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(2), 5,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == 5);
|
|
assert(weight_ == 0);
|
|
assert(size_ == 2);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_MKREG, 9,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 9);
|
|
assert(weight_ == 4);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), 9,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == 9);
|
|
assert(weight_ == 0);
|
|
assert(size_ == 2);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(2), 9,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == 9);
|
|
assert(weight_ == 0);
|
|
assert(size_ == 2);
|
|
|
|
// make id14 with weight w5
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(GROW, 10, NULL, 1,
|
|
LFSR_ATTR(MKREG, 10, "\xee\xee\xee\xee", 4,
|
|
LFSR_ATTR(UATTR(1), 10, "\xee\xee", 2,
|
|
LFSR_ATTR(GROW, 10, NULL, 4,
|
|
LFSR_ATTR(UATTR(2), 14, "\xee\xee", 2,
|
|
NULL)))))) => 0;
|
|
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(3), -1,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(3));
|
|
assert(id_ == -1);
|
|
assert(weight_ == 0);
|
|
assert(size_ == 9);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_MKREG, 0,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 0);
|
|
assert(weight_ == 1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), 0,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == 0);
|
|
assert(weight_ == 0);
|
|
assert(size_ == 2);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(2), 0,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == 0);
|
|
assert(weight_ == 0);
|
|
assert(size_ == 2);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_MKREG, 2,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 2);
|
|
assert(weight_ == 2);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), 2,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == 2);
|
|
assert(weight_ == 0);
|
|
assert(size_ == 2);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(2), 2,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == 2);
|
|
assert(weight_ == 0);
|
|
assert(size_ == 2);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_MKREG, 5,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 5);
|
|
assert(weight_ == 3);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), 5,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == 5);
|
|
assert(weight_ == 0);
|
|
assert(size_ == 2);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(2), 5,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == 5);
|
|
assert(weight_ == 0);
|
|
assert(size_ == 2);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_MKREG, 9,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 9);
|
|
assert(weight_ == 4);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), 9,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == 9);
|
|
assert(weight_ == 0);
|
|
assert(size_ == 2);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(2), 9,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == 9);
|
|
assert(weight_ == 0);
|
|
assert(size_ == 2);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_MKREG, 14,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 14);
|
|
assert(weight_ == 5);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), 14,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == 14);
|
|
assert(weight_ == 0);
|
|
assert(size_ == 2);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(2), 14,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == 14);
|
|
assert(weight_ == 0);
|
|
assert(size_ == 2);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(3), -1,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(3));
|
|
assert(id_ == -1);
|
|
assert(weight_ == 0);
|
|
assert(size_ == 9);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_MKREG, 0,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 0);
|
|
assert(weight_ == 1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), 0,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == 0);
|
|
assert(weight_ == 0);
|
|
assert(size_ == 2);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(2), 0,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == 0);
|
|
assert(weight_ == 0);
|
|
assert(size_ == 2);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_MKREG, 2,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 2);
|
|
assert(weight_ == 2);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), 2,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == 2);
|
|
assert(weight_ == 0);
|
|
assert(size_ == 2);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(2), 2,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == 2);
|
|
assert(weight_ == 0);
|
|
assert(size_ == 2);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_MKREG, 5,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 5);
|
|
assert(weight_ == 3);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), 5,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == 5);
|
|
assert(weight_ == 0);
|
|
assert(size_ == 2);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(2), 5,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == 5);
|
|
assert(weight_ == 0);
|
|
assert(size_ == 2);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_MKREG, 9,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 9);
|
|
assert(weight_ == 4);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), 9,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == 9);
|
|
assert(weight_ == 0);
|
|
assert(size_ == 2);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(2), 9,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == 9);
|
|
assert(weight_ == 0);
|
|
assert(size_ == 2);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_MKREG, 14,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 14);
|
|
assert(weight_ == 5);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), 14,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == 14);
|
|
assert(weight_ == 0);
|
|
assert(size_ == 2);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(2), 14,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == 14);
|
|
assert(weight_ == 0);
|
|
assert(size_ == 2);
|
|
'''
|
|
|
|
[cases.test_rbyd_mixed_grow_traverse]
|
|
in = 'lfs.c'
|
|
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_;
|
|
lfs_ssize_t id_;
|
|
lfs_size_t weight_;
|
|
lfs_off_t off_;
|
|
lfs_size_t size_;
|
|
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(UATTR(3), -1, "unrelated", 9,
|
|
// make id0 with weight w1
|
|
LFSR_ATTR(GROW, 0, NULL, 1,
|
|
LFSR_ATTR(MKREG, 0, "\xaa\xaa\xaa\xaa", 4,
|
|
LFSR_ATTR(UATTR(1), 0, "\xaa\xaa", 2,
|
|
LFSR_ATTR(UATTR(2), 0, "\xaa\xaa", 2,
|
|
// make id2 with weight w2
|
|
LFSR_ATTR(GROW, 1, NULL, 1,
|
|
LFSR_ATTR(MKREG, 1, "\xbb\xbb\xbb\xbb", 4,
|
|
LFSR_ATTR(UATTR(1), 1, "\xbb\xbb", 2,
|
|
LFSR_ATTR(GROW, 1, NULL, 1,
|
|
LFSR_ATTR(UATTR(2), 2, "\xbb\xbb", 2,
|
|
// make id5 with weight w3
|
|
LFSR_ATTR(GROW, 3, NULL, 1,
|
|
LFSR_ATTR(MKREG, 3, "\xcc\xcc\xcc\xcc", 4,
|
|
LFSR_ATTR(UATTR(1), 3, "\xcc\xcc", 2,
|
|
LFSR_ATTR(GROW, 3, NULL, 2,
|
|
LFSR_ATTR(UATTR(2), 5, "\xcc\xcc", 2,
|
|
// make id9 with weight w4
|
|
LFSR_ATTR(GROW, 6, NULL, 1,
|
|
LFSR_ATTR(MKREG, 6, "\xdd\xdd\xdd\xdd", 4,
|
|
LFSR_ATTR(UATTR(1), 6, "\xdd\xdd", 2,
|
|
LFSR_ATTR(GROW, 6, NULL, 3,
|
|
LFSR_ATTR(UATTR(2), 9, "\xdd\xdd", 2,
|
|
// make id14 with weight w5
|
|
LFSR_ATTR(GROW, 10, NULL, 1,
|
|
LFSR_ATTR(MKREG, 10, "\xee\xee\xee\xee", 4,
|
|
LFSR_ATTR(UATTR(1), 10, "\xee\xee", 2,
|
|
LFSR_ATTR(GROW, 10, NULL, 4,
|
|
LFSR_ATTR(UATTR(2), 14, "\xee\xee", 2,
|
|
NULL)))))))))))))))))))))))))) => 0;
|
|
|
|
// traverse, finding tags and weights
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(0), -1,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(3));
|
|
assert(id_ == -1);
|
|
assert(weight_ == 0);
|
|
assert(size_ == 9);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 0);
|
|
assert(weight_ == 1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == 0);
|
|
assert(weight_ == 0);
|
|
assert(size_ == 2);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == 0);
|
|
assert(weight_ == 0);
|
|
assert(size_ == 2);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 2);
|
|
assert(weight_ == 2);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == 2);
|
|
assert(weight_ == 0);
|
|
assert(size_ == 2);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == 2);
|
|
assert(weight_ == 0);
|
|
assert(size_ == 2);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 5);
|
|
assert(weight_ == 3);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == 5);
|
|
assert(weight_ == 0);
|
|
assert(size_ == 2);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == 5);
|
|
assert(weight_ == 0);
|
|
assert(size_ == 2);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 9);
|
|
assert(weight_ == 4);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == 9);
|
|
assert(weight_ == 0);
|
|
assert(size_ == 2);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == 9);
|
|
assert(weight_ == 0);
|
|
assert(size_ == 2);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 14);
|
|
assert(weight_ == 5);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == 14);
|
|
assert(weight_ == 0);
|
|
assert(size_ == 2);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == 14);
|
|
assert(weight_ == 0);
|
|
assert(size_ == 2);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, &weight_, &off_, &size_) => LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(0), -1,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(3));
|
|
assert(id_ == -1);
|
|
assert(weight_ == 0);
|
|
assert(size_ == 9);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 0);
|
|
assert(weight_ == 1);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == 0);
|
|
assert(weight_ == 0);
|
|
assert(size_ == 2);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == 0);
|
|
assert(weight_ == 0);
|
|
assert(size_ == 2);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 2);
|
|
assert(weight_ == 2);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == 2);
|
|
assert(weight_ == 0);
|
|
assert(size_ == 2);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == 2);
|
|
assert(weight_ == 0);
|
|
assert(size_ == 2);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 5);
|
|
assert(weight_ == 3);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == 5);
|
|
assert(weight_ == 0);
|
|
assert(size_ == 2);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == 5);
|
|
assert(weight_ == 0);
|
|
assert(size_ == 2);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 9);
|
|
assert(weight_ == 4);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == 9);
|
|
assert(weight_ == 0);
|
|
assert(size_ == 2);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == 9);
|
|
assert(weight_ == 0);
|
|
assert(size_ == 2);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == 14);
|
|
assert(weight_ == 5);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == 14);
|
|
assert(weight_ == 0);
|
|
assert(size_ == 2);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == 14);
|
|
assert(weight_ == 0);
|
|
assert(size_ == 2);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, &weight_, &off_, &size_) => LFS_ERR_NOENT;
|
|
'''
|
|
|
|
[cases.test_rbyd_mixed_grow_permutations]
|
|
defines.N = 'range(1, 8)'
|
|
defines.W = 5
|
|
# large progs take too long for now
|
|
if = 'PROG_SIZE < 512'
|
|
in = 'lfs.c'
|
|
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_;
|
|
lfs_ssize_t id_;
|
|
lfs_size_t weight_;
|
|
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]);
|
|
}
|
|
printf("] ---\n");
|
|
|
|
// test the given permutation with multiple commits
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(UATTR(3), -1, "unrelated", 9, NULL)) => 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(GROW, id*W, NULL, 1,
|
|
LFSR_ATTR(MKREG, id*W, names[perm[j] % 6], 4,
|
|
LFSR_ATTR(UATTR(1), id*W, names[perm[j] % 6], 2,
|
|
LFSR_ATTR(GROW, id*W, NULL, W-1,
|
|
LFSR_ATTR(UATTR(2), id*W+W-1, names[perm[j] % 6], 2,
|
|
NULL)))))) => 0;
|
|
}
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
assert(rbyd.weight == N*W);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(3), -1,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(3));
|
|
assert(id_ == -1);
|
|
assert(weight_ == 0);
|
|
assert(size_ == 9);
|
|
for (unsigned j = 0; j < N; j++) {
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_MKREG, j*W+W-1,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == j*W+W-1);
|
|
assert(weight_ == W);
|
|
assert(size_ == 4);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), j*W+W-1,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == j*W+W-1);
|
|
assert(weight_ == 0);
|
|
assert(size_ == 2);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(2), j*W+W-1,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == j*W+W-1);
|
|
assert(weight_ == 0);
|
|
assert(size_ == 2);
|
|
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_MKREG, j*W+W-1, buffer, 4) => 4;
|
|
assert(memcmp(buffer, names[j % 6], 4) == 0);
|
|
}
|
|
|
|
// 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_mixed_grow_traverse_permutations]
|
|
defines.N = 'range(1, 8)'
|
|
defines.W = 5
|
|
# large progs take too long for now
|
|
if = 'PROG_SIZE < 512'
|
|
in = 'lfs.c'
|
|
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_;
|
|
lfs_ssize_t id_;
|
|
lfs_size_t weight_;
|
|
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]);
|
|
}
|
|
printf("] ---\n");
|
|
|
|
// test the given permutation with multiple commits
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(UATTR(3), -1, "unrelated", 9, NULL)) => 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(GROW, id*W, NULL, 1,
|
|
LFSR_ATTR(MKREG, id*W, names[perm[j] % 6], 4,
|
|
LFSR_ATTR(UATTR(1), id*W, names[perm[j] % 6], 2,
|
|
LFSR_ATTR(GROW, id*W, NULL, W-1,
|
|
LFSR_ATTR(UATTR(2), id*W+W-1, names[perm[j] % 6], 2,
|
|
NULL)))))) => 0;
|
|
}
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
|
assert(rbyd.weight == N*W);
|
|
// try traversing all tags
|
|
tag_ = 0;
|
|
id_ = -1;
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(3));
|
|
assert(id_ == -1);
|
|
assert(weight_ == 0);
|
|
assert(size_ == 9);
|
|
for (unsigned j = 0; j < N; j++) {
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == j*W+W-1);
|
|
assert(weight_ == W);
|
|
assert(size_ == 4);
|
|
|
|
lfsr_rbyd_get(&lfs, &rbyd, tag_, id_, buffer, 4) => 4;
|
|
assert(memcmp(buffer, names[j % 6], 4) == 0);
|
|
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == j*W+W-1);
|
|
assert(weight_ == 0);
|
|
assert(size_ == 2);
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(id_ == j*W+W-1);
|
|
assert(weight_ == 0);
|
|
assert(size_ == 2);
|
|
}
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(tag_), id_,
|
|
&tag_, &id_, &weight_, &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_sparse_grow_permutations]
|
|
defines.N = 'range(1, 7)'
|
|
defines.W = 5
|
|
# large progs take too long for now
|
|
if = 'PROG_SIZE < 512'
|
|
in = 'lfs.c'
|
|
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_;
|
|
lfs_ssize_t id_;
|
|
lfs_size_t weight_;
|
|
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]);
|
|
}
|
|
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(GROW, id*W, NULL, W,
|
|
LFSR_ATTR(MKREG, id*W+W-1, names[perm[j] % 6], 4,
|
|
NULL))) => 0;
|
|
}
|
|
assert(rbyd.weight == N*W);
|
|
|
|
// copy block so we can reset after each remove
|
|
lfsr_rbyd_t backup_rbyd = rbyd;
|
|
uint8_t *backup_block = malloc(rbyd.off);
|
|
lfs_bd_read(&lfs, NULL, &lfs.rcache, rbyd.off,
|
|
rbyd.block, 0, backup_block, rbyd.off) => 0;
|
|
|
|
// try growing each id
|
|
for (unsigned j = 0; j < N; j++) {
|
|
// print what we are growing to help debugging
|
|
printf("--- growing: %d ---\n", j);
|
|
|
|
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(GROW, j*W, NULL, 1, NULL)) => 0;
|
|
assert(rbyd.weight == N*W+1);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block,
|
|
cfg->block_size, NULL) => 0;
|
|
assert(rbyd.weight == N*W+1);
|
|
for (unsigned k = 0; k < N; k++) {
|
|
if (k == j) {
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_MKREG, k*W+W-1+1,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == k*W+W-1+1);
|
|
assert(weight_ == W+1);
|
|
assert(size_ == 4);
|
|
} else if (k > j) {
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_MKREG, k*W+W-1+1,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == k*W+W-1+1);
|
|
assert(weight_ == W);
|
|
assert(size_ == 4);
|
|
} else {
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_MKREG, k*W+W-1,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == k*W+W-1);
|
|
assert(weight_ == W);
|
|
assert(size_ == 4);
|
|
}
|
|
|
|
lfsr_rbyd_get(&lfs, &rbyd, tag_, id_, buffer, 4) => 4;
|
|
assert(memcmp(buffer, names[k % 6], 4) == 0);
|
|
}
|
|
}
|
|
|
|
// 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_sparse_shrink_permutations]
|
|
defines.N = 'range(1, 7)'
|
|
defines.W = 5
|
|
# large progs take too long for now
|
|
if = 'PROG_SIZE < 512'
|
|
in = 'lfs.c'
|
|
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_;
|
|
lfs_ssize_t id_;
|
|
lfs_size_t weight_;
|
|
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]);
|
|
}
|
|
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(GROW, id*W, NULL, W,
|
|
LFSR_ATTR(MKREG, id*W+W-1, names[perm[j] % 6], 4,
|
|
NULL))) => 0;
|
|
}
|
|
assert(rbyd.weight == N*W);
|
|
|
|
// copy block so we can reset after each remove
|
|
lfsr_rbyd_t backup_rbyd = rbyd;
|
|
uint8_t *backup_block = malloc(rbyd.off);
|
|
lfs_bd_read(&lfs, NULL, &lfs.rcache, rbyd.off,
|
|
rbyd.block, 0, backup_block, rbyd.off) => 0;
|
|
|
|
// try shrinking each id
|
|
for (unsigned j = 0; j < N; j++) {
|
|
// print what we are shrinking to help debugging
|
|
printf("--- shrinking: %d ---\n", j);
|
|
|
|
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(SHRINK, j*W, NULL, 1, NULL)) => 0;
|
|
assert(rbyd.weight == N*W-1);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block,
|
|
cfg->block_size, NULL) => 0;
|
|
assert(rbyd.weight == N*W-1);
|
|
for (unsigned k = 0; k < N; k++) {
|
|
if (k == j) {
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_MKREG, k*W+W-1-1,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == k*W+W-1-1);
|
|
assert(weight_ == W-1);
|
|
assert(size_ == 4);
|
|
} else if (k > j) {
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_MKREG, k*W+W-1-1,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == k*W+W-1-1);
|
|
assert(weight_ == W);
|
|
assert(size_ == 4);
|
|
} else {
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_MKREG, k*W+W-1,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == k*W+W-1);
|
|
assert(weight_ == W);
|
|
assert(size_ == 4);
|
|
}
|
|
|
|
lfsr_rbyd_get(&lfs, &rbyd, tag_, id_, buffer, 4) => 4;
|
|
assert(memcmp(buffer, names[k % 6], 4) == 0);
|
|
}
|
|
}
|
|
|
|
// 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_sparse_delete_permutations]
|
|
defines.N = 'range(1, 7)'
|
|
defines.W = 5
|
|
# large progs take too long for now
|
|
if = 'PROG_SIZE < 512'
|
|
in = 'lfs.c'
|
|
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][6] = {
|
|
"\xaa\xaa\xaa\xaa\xaa\xaa",
|
|
"\xbb\xbb\xbb\xbb\xbb\xbb",
|
|
"\xcc\xcc\xcc\xcc\xcc\xcc",
|
|
"\xdd\xdd\xdd\xdd\xdd\xdd",
|
|
"\xee\xee\xee\xee\xee\xee",
|
|
"\xff\xff\xff\xff\xff\xff",
|
|
};
|
|
lfsr_tag_t tag_;
|
|
lfs_ssize_t id_;
|
|
lfs_size_t weight_;
|
|
lfs_off_t off_;
|
|
lfs_size_t size_;
|
|
uint8_t buffer[6];
|
|
|
|
// 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]);
|
|
}
|
|
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(GROW, id*W, NULL, W,
|
|
LFSR_ATTR(MKREG, id*W+W-1, names[perm[j] % 6], 4,
|
|
NULL))) => 0;
|
|
}
|
|
assert(rbyd.weight == N*W);
|
|
|
|
// copy block so we can reset after each remove
|
|
lfsr_rbyd_t backup_rbyd = rbyd;
|
|
uint8_t *backup_block = malloc(rbyd.off);
|
|
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("--- deleting: %d ---\n", j);
|
|
|
|
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(SHRINK, j*W, NULL, W, NULL)) => 0;
|
|
assert(rbyd.weight == (N-1)*W);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block,
|
|
cfg->block_size, NULL) => 0;
|
|
assert(rbyd.weight == (N-1)*W);
|
|
for (unsigned k = 0; k < N-1; k++) {
|
|
if (k >= j) {
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_MKREG, k*W+W-1,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == k*W+W-1);
|
|
assert(weight_ == W);
|
|
assert(size_ == 4);
|
|
|
|
lfsr_rbyd_get(&lfs, &rbyd, tag_, id_, buffer, 4) => 4;
|
|
assert(memcmp(buffer, names[(k+1) % 6], 4) == 0);
|
|
} else {
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_MKREG, k*W+W-1,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == k*W+W-1);
|
|
assert(weight_ == W);
|
|
assert(size_ == 4);
|
|
|
|
lfsr_rbyd_get(&lfs, &rbyd, tag_, id_, buffer, 4) => 4;
|
|
assert(memcmp(buffer, names[k % 6], 4) == 0);
|
|
}
|
|
}
|
|
|
|
// try recreating the id to make sure things still work
|
|
printf("--- create: %d ---\n", j);
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(GROW, j*W, NULL, W,
|
|
LFSR_ATTR(MKREG, j*W+W-1, names[j % 6], 6,
|
|
NULL))) => 0;
|
|
assert(rbyd.weight == N*W);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block,
|
|
cfg->block_size, NULL) => 0;
|
|
assert(rbyd.weight == N*W);
|
|
for (unsigned k = 0; k < N; k++) {
|
|
if (k == j) {
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_MKREG, k*W+W-1,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == k*W+W-1);
|
|
assert(weight_ == W);
|
|
assert(size_ == 6);
|
|
|
|
lfsr_rbyd_get(&lfs, &rbyd, tag_, id_, buffer, 6) => 6;
|
|
assert(memcmp(buffer, names[k % 6], 6) == 0);
|
|
} else {
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_MKREG, k*W+W-1,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == k*W+W-1);
|
|
assert(weight_ == W);
|
|
assert(size_ == 4);
|
|
|
|
lfsr_rbyd_get(&lfs, &rbyd, tag_, id_, buffer, 6) => 4;
|
|
assert(memcmp(buffer, names[k % 6], 4) == 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
// 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_sparse_attr_permutations]
|
|
defines.N = 'range(1, 7)'
|
|
defines.W = 5
|
|
# large progs take too long for now
|
|
if = 'PROG_SIZE < 512'
|
|
in = 'lfs.c'
|
|
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_;
|
|
lfs_ssize_t id_;
|
|
lfs_size_t weight_;
|
|
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]);
|
|
}
|
|
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(GROW, id*W, NULL, W,
|
|
LFSR_ATTR(MKREG, id*W+W-1, names[perm[j] % 6], 4,
|
|
NULL))) => 0;
|
|
}
|
|
assert(rbyd.weight == N*W);
|
|
|
|
// copy block so we can reset after each remove
|
|
lfsr_rbyd_t backup_rbyd = rbyd;
|
|
uint8_t *backup_block = malloc(rbyd.off);
|
|
lfs_bd_read(&lfs, NULL, &lfs.rcache, rbyd.off,
|
|
rbyd.block, 0, backup_block, rbyd.off) => 0;
|
|
|
|
// try appending an attr to each id, this should not affect
|
|
// weights at all!
|
|
for (unsigned j = 0; j < N; j++) {
|
|
// print what we are appending to help debugging
|
|
printf("--- appending: %d ---\n", j);
|
|
|
|
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(UATTR(1), j*W+W-1, names[j % 6], 2, NULL)) => 0;
|
|
assert(rbyd.weight == N*W);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block,
|
|
cfg->block_size, NULL) => 0;
|
|
assert(rbyd.weight == N*W);
|
|
for (unsigned k = 0; k < N; k++) {
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_MKREG, k*W+W-1,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == k*W+W-1);
|
|
assert(weight_ == W);
|
|
assert(size_ == 4);
|
|
|
|
lfsr_rbyd_get(&lfs, &rbyd, tag_, id_, buffer, 4) => 4;
|
|
assert(memcmp(buffer, names[k % 6], 4) == 0);
|
|
|
|
if (k == j) {
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), k*W+W-1,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == k*W+W-1);
|
|
assert(weight_ == 0);
|
|
assert(size_ == 2);
|
|
}
|
|
}
|
|
|
|
// now try removing the attr
|
|
printf("--- removing: %d ---\n", j);
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(RMUATTR(1), j*W+W-1, NULL, 0, NULL)) => 0;
|
|
assert(rbyd.weight == N*W);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block,
|
|
cfg->block_size, NULL) => 0;
|
|
assert(rbyd.weight == N*W);
|
|
for (unsigned k = 0; k < N; k++) {
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_MKREG, k*W+W-1,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == k*W+W-1);
|
|
assert(weight_ == W);
|
|
assert(size_ == 4);
|
|
|
|
lfsr_rbyd_get(&lfs, &rbyd, tag_, id_, buffer, 4) => 4;
|
|
assert(memcmp(buffer, names[k % 6], 4) == 0);
|
|
|
|
if (k == j) {
|
|
lfsr_rbyd_get(&lfs, &rbyd, LFSR_TAG_UATTR(1), k*W+W-1,
|
|
buffer, 4) => LFS_ERR_NOENT;
|
|
}
|
|
}
|
|
|
|
// and try putting the attr back just for good measure
|
|
printf("--- appending: %d ---\n", j);
|
|
lfsr_rbyd_commit(&lfs, &rbyd,
|
|
LFSR_ATTR(UATTR(1), j*W+W-1, names[j % 6], 2, NULL)) => 0;
|
|
assert(rbyd.weight == N*W);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block,
|
|
cfg->block_size, NULL) => 0;
|
|
assert(rbyd.weight == N*W);
|
|
for (unsigned k = 0; k < N; k++) {
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_MKREG, k*W+W-1,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_MKREG);
|
|
assert(id_ == k*W+W-1);
|
|
assert(weight_ == W);
|
|
assert(size_ == 4);
|
|
|
|
lfsr_rbyd_get(&lfs, &rbyd, tag_, id_, buffer, 4) => 4;
|
|
assert(memcmp(buffer, names[k % 6], 4) == 0);
|
|
|
|
if (k == j) {
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_UATTR(1), k*W+W-1,
|
|
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(id_ == k*W+W-1);
|
|
assert(weight_ == 0);
|
|
assert(size_ == 2);
|
|
}
|
|
}
|
|
}
|
|
|
|
// 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;
|
|
}
|
|
}
|
|
'''
|