a89b3e42ba
- Adopted *_IS* naming convention for sign-bit macros. - Made all struct initializing macros function-like, including the *_NULL() macros. - Renamed ggrm/dgrm -> grm_g/grm_d. - Renamed lfsr_mroot_commit_ -> lfsr_mroot_commit. - Renamed LFSR_FILE_BSPROUT -> LFSR_FILE_ISDIRECT. - Renamed LFSR_BSPROUT_NULL -> LFSR_FILE_BNULL(). - Dropped *_unerase functions for explicitly setting eoff=-1.
12648 lines
448 KiB
TOML
12648 lines
448 KiB
TOML
# Test the low-level rbyd data-structure
|
|
after = 'test_bd'
|
|
|
|
# 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
|
|
|
|
# TODO we should eventually replace these with lfsr_rbyd_lookup
|
|
# some internal helpers
|
|
in = 'lfs.c'
|
|
code = '''
|
|
static lfs_ssize_t lfsr_rbyd_get(lfs_t *lfs, const lfsr_rbyd_t *rbyd,
|
|
lfs_ssize_t rid, lfsr_tag_t tag, void *buffer, lfs_size_t size) {
|
|
lfsr_data_t data;
|
|
int err = lfsr_rbyd_lookup(lfs, rbyd, rid, tag, NULL, &data);
|
|
if (err) {
|
|
return err;
|
|
}
|
|
|
|
return lfsr_data_read(lfs, &data, buffer, size);
|
|
}
|
|
'''
|
|
|
|
[cases.test_rbyd_commit]
|
|
in = 'lfs.c'
|
|
code = '''
|
|
lfs_t lfs;
|
|
lfs_init(&lfs, CFG) => 0;
|
|
|
|
lfsr_rbyd_t init_rbyd = {
|
|
.block = 0,
|
|
.eoff = 0,
|
|
.cksum = 0,
|
|
.trunk = 0,
|
|
.weight = 0,
|
|
};
|
|
lfsr_rbyd_t rbyd;
|
|
|
|
// commit with one attribute
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(-1, UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
|
|
// commit with two attributes
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(-1, UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(-1, UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)))) => 0;
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 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,
|
|
.eoff = 0,
|
|
.cksum = 0,
|
|
.trunk = 0,
|
|
.weight = 0,
|
|
};
|
|
lfsr_rbyd_t rbyd;
|
|
|
|
// commit with one attribute
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(-1, UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
|
|
// commit with two attributes
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(-1, UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(-1, UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)))) => 0;
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 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,
|
|
.eoff = 0,
|
|
.cksum = 0,
|
|
.trunk = 0,
|
|
.weight = 0,
|
|
};
|
|
lfsr_rbyd_t rbyd;
|
|
|
|
// commit with one attribute
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(-1, UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
|
|
// commit with the second attribute
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(-1, UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)))) => 0;
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 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,
|
|
.eoff = 0,
|
|
.cksum = 0,
|
|
.trunk = 0,
|
|
.weight = 0,
|
|
};
|
|
lfsr_rbyd_t rbyd;
|
|
lfsr_tag_t tag_;
|
|
lfs_ssize_t rid_;
|
|
lfsr_data_t data_;
|
|
|
|
// commit with one attribute
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(-1, UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
|
|
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(1),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(2),
|
|
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(1),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(2),
|
|
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
|
|
|
|
// commit with two attributes
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(-1, UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(-1, UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)))) => 0;
|
|
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(1),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(2),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(3),
|
|
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(1),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(2),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(3),
|
|
&rid_, &tag_, NULL, &data_) => 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_ATTRS(
|
|
LFSR_ATTR(-1, UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(-1, UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
|
|
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(1),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(2),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(3),
|
|
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(1),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(2),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(3),
|
|
&rid_, &tag_, NULL, &data_) => 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,
|
|
.eoff = 0,
|
|
.cksum = 0,
|
|
.trunk = 0,
|
|
.weight = 0,
|
|
};
|
|
lfsr_rbyd_t rbyd;
|
|
lfsr_tag_t tag_;
|
|
lfs_ssize_t rid_;
|
|
lfsr_data_t data_;
|
|
|
|
// commit with one attribute
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(-1, UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
|
|
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(1),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(2),
|
|
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(1),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(2),
|
|
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
|
|
|
|
// commit with two attributes
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(-1, UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(-1, UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)))) => 0;
|
|
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(1),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(2),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(3),
|
|
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(1),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(2),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(3),
|
|
&rid_, &tag_, NULL, &data_) => 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_ATTRS(
|
|
LFSR_ATTR(-1, UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(-1, UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
|
|
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(1),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(2),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(3),
|
|
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(1),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(2),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(3),
|
|
&rid_, &tag_, NULL, &data_) => 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,
|
|
.eoff = 0,
|
|
.cksum = 0,
|
|
.trunk = 0,
|
|
.weight = 0,
|
|
};
|
|
lfsr_rbyd_t rbyd;
|
|
uint8_t buffer[4];
|
|
|
|
// commit with one attribute
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(-1, UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
|
|
|
|
lfsr_rbyd_get(&lfs, &rbyd, -1, LFSR_TAG_UATTR(1), buffer, 4)
|
|
=> 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, -1, LFSR_TAG_UATTR(2), buffer, 4)
|
|
=> LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
lfsr_rbyd_get(&lfs, &rbyd, -1, LFSR_TAG_UATTR(1), buffer, 4)
|
|
=> 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, -1, LFSR_TAG_UATTR(2), 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_ATTRS(
|
|
LFSR_ATTR(-1, UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(-1, UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)))) => 0;
|
|
|
|
lfsr_rbyd_get(&lfs, &rbyd, -1, LFSR_TAG_UATTR(1), buffer, 4)
|
|
=> 4;
|
|
lfsr_rbyd_get(&lfs, &rbyd, -1, LFSR_TAG_UATTR(2), buffer, 4)
|
|
=> 4;
|
|
lfsr_rbyd_get(&lfs, &rbyd, -1, LFSR_TAG_UATTR(3), buffer, 4)
|
|
=> LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
lfsr_rbyd_get(&lfs, &rbyd, -1, LFSR_TAG_UATTR(1), buffer, 4)
|
|
=> 4;
|
|
lfsr_rbyd_get(&lfs, &rbyd, -1, LFSR_TAG_UATTR(2), buffer, 4)
|
|
=> 4;
|
|
lfsr_rbyd_get(&lfs, &rbyd, -1, LFSR_TAG_UATTR(3), 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_ATTRS(
|
|
LFSR_ATTR(-1, UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(-1, UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
|
|
lfsr_rbyd_get(&lfs, &rbyd, -1, LFSR_TAG_UATTR(1), buffer, 4)
|
|
=> 4;
|
|
lfsr_rbyd_get(&lfs, &rbyd, -1, LFSR_TAG_UATTR(2), buffer, 4)
|
|
=> 4;
|
|
lfsr_rbyd_get(&lfs, &rbyd, -1, LFSR_TAG_UATTR(3), buffer, 4)
|
|
=> LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
lfsr_rbyd_get(&lfs, &rbyd, -1, LFSR_TAG_UATTR(1), buffer, 4)
|
|
=> 4;
|
|
lfsr_rbyd_get(&lfs, &rbyd, -1, LFSR_TAG_UATTR(2), buffer, 4)
|
|
=> 4;
|
|
lfsr_rbyd_get(&lfs, &rbyd, -1, LFSR_TAG_UATTR(3), 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,
|
|
.eoff = 0,
|
|
.cksum = 0,
|
|
.trunk = 0,
|
|
.weight = 0,
|
|
};
|
|
lfsr_rbyd_t rbyd;
|
|
uint8_t buffer[4];
|
|
|
|
// commit with one attribute
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(-1, UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
|
|
|
|
lfsr_rbyd_get(&lfs, &rbyd, -1, LFSR_TAG_UATTR(1), buffer, 4)
|
|
=> 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, -1, LFSR_TAG_UATTR(2), buffer, 4)
|
|
=> LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
lfsr_rbyd_get(&lfs, &rbyd, -1, LFSR_TAG_UATTR(1), buffer, 4)
|
|
=> 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, -1, LFSR_TAG_UATTR(2), 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_ATTRS(
|
|
LFSR_ATTR(-1, UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(-1, UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)))) => 0;
|
|
|
|
lfsr_rbyd_get(&lfs, &rbyd, -1, LFSR_TAG_UATTR(1), buffer, 4)
|
|
=> 4;
|
|
lfsr_rbyd_get(&lfs, &rbyd, -1, LFSR_TAG_UATTR(2), buffer, 4)
|
|
=> 4;
|
|
lfsr_rbyd_get(&lfs, &rbyd, -1, LFSR_TAG_UATTR(3), buffer, 4)
|
|
=> LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
lfsr_rbyd_get(&lfs, &rbyd, -1, LFSR_TAG_UATTR(1), buffer, 4)
|
|
=> 4;
|
|
lfsr_rbyd_get(&lfs, &rbyd, -1, LFSR_TAG_UATTR(2), buffer, 4)
|
|
=> 4;
|
|
lfsr_rbyd_get(&lfs, &rbyd, -1, LFSR_TAG_UATTR(3), 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_ATTRS(
|
|
LFSR_ATTR(-1, UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(-1, UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
|
|
lfsr_rbyd_get(&lfs, &rbyd, -1, LFSR_TAG_UATTR(1), buffer, 4)
|
|
=> 4;
|
|
lfsr_rbyd_get(&lfs, &rbyd, -1, LFSR_TAG_UATTR(2), buffer, 4)
|
|
=> 4;
|
|
lfsr_rbyd_get(&lfs, &rbyd, -1, LFSR_TAG_UATTR(3), buffer, 4)
|
|
=> LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
lfsr_rbyd_get(&lfs, &rbyd, -1, LFSR_TAG_UATTR(1), buffer, 4)
|
|
=> 4;
|
|
lfsr_rbyd_get(&lfs, &rbyd, -1, LFSR_TAG_UATTR(2), buffer, 4)
|
|
=> 4;
|
|
lfsr_rbyd_get(&lfs, &rbyd, -1, LFSR_TAG_UATTR(3), 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,
|
|
.eoff = 0,
|
|
.cksum = 0,
|
|
.trunk = 0,
|
|
.weight = 0,
|
|
};
|
|
lfsr_rbyd_t rbyd;
|
|
lfsr_tag_t tag_;
|
|
lfs_ssize_t rid_;
|
|
lfsr_data_t data_;
|
|
|
|
// 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_ATTRS(
|
|
LFSR_ATTR(-1, UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(-1, UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)))) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(1),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(2),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 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_ATTRS(
|
|
LFSR_ATTR(-1, UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(-1, UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(1),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(2),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
'''
|
|
|
|
[cases.test_rbyd_bflips]
|
|
in = 'lfs.c'
|
|
code = '''
|
|
lfs_t lfs;
|
|
lfs_init(&lfs, CFG) => 0;
|
|
|
|
lfsr_rbyd_t init_rbyd = {
|
|
.block = 0,
|
|
.eoff = 0,
|
|
.cksum = 0,
|
|
.trunk = 0,
|
|
.weight = 0,
|
|
};
|
|
lfsr_rbyd_t rbyd;
|
|
lfsr_tag_t tag_;
|
|
lfs_ssize_t rid_;
|
|
lfsr_data_t data_;
|
|
|
|
// 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_ATTRS(
|
|
LFSR_ATTR(-1, UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(-1, UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(-1, UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)))) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(1),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(2),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 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_ATTRS(
|
|
LFSR_ATTR(-1, UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(-1, UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(-1, UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(1),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(2),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
'''
|
|
|
|
[cases.test_rbyd_trifoliate]
|
|
in = 'lfs.c'
|
|
code = '''
|
|
lfs_t lfs;
|
|
lfs_init(&lfs, CFG) => 0;
|
|
|
|
lfsr_rbyd_t init_rbyd = {
|
|
.block = 0,
|
|
.eoff = 0,
|
|
.cksum = 0,
|
|
.trunk = 0,
|
|
.weight = 0,
|
|
};
|
|
lfsr_rbyd_t rbyd;
|
|
lfsr_tag_t tag_;
|
|
lfs_ssize_t rid_;
|
|
lfsr_data_t data_;
|
|
|
|
// 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_ATTRS(
|
|
LFSR_ATTR(-1, UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(-1, UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(-1, UATTR(3), 0, BUF("\xcc\xcc\xcc\xcc", 4)))) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(1),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(2),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(3),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(3));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 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_ATTRS(
|
|
LFSR_ATTR(-1, UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(-1, UATTR(3), 0, BUF("\xcc\xcc\xcc\xcc", 4)),
|
|
LFSR_ATTR(-1, UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(1),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(2),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(3),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(3));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
'''
|
|
|
|
[cases.test_rbyd_rflips]
|
|
in = 'lfs.c'
|
|
code = '''
|
|
lfs_t lfs;
|
|
lfs_init(&lfs, CFG) => 0;
|
|
|
|
lfsr_rbyd_t init_rbyd = {
|
|
.block = 0,
|
|
.eoff = 0,
|
|
.cksum = 0,
|
|
.trunk = 0,
|
|
.weight = 0,
|
|
};
|
|
lfsr_rbyd_t rbyd;
|
|
lfsr_tag_t tag_;
|
|
lfs_ssize_t rid_;
|
|
lfsr_data_t data_;
|
|
|
|
// 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_ATTRS(
|
|
LFSR_ATTR(-1, UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(-1, UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(-1, UATTR(3), 0, BUF("\xcc\xcc\xcc\xcc", 4)),
|
|
LFSR_ATTR(-1, UATTR(3), 0, BUF("\xcc\xcc\xcc\xcc", 4)))) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(1),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(2),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(3),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(3));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 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_ATTRS(
|
|
LFSR_ATTR(-1, UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(-1, UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(-1, UATTR(3), 0, BUF("\xcc\xcc\xcc\xcc", 4)),
|
|
LFSR_ATTR(-1, UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)))) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(1),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(2),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(3),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(3));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 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_ATTRS(
|
|
LFSR_ATTR(-1, UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(-1, UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(-1, UATTR(3), 0, BUF("\xcc\xcc\xcc\xcc", 4)),
|
|
LFSR_ATTR(-1, UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(1),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(2),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(3),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(3));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 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_ATTRS(
|
|
LFSR_ATTR(-1, UATTR(3), 0, BUF("\xcc\xcc\xcc\xcc", 4)),
|
|
LFSR_ATTR(-1, UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(-1, UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(-1, UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(1),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(2),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(3),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(3));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
'''
|
|
|
|
[cases.test_rbyd_quadrifoliate]
|
|
in = 'lfs.c'
|
|
code = '''
|
|
lfs_t lfs;
|
|
lfs_init(&lfs, CFG) => 0;
|
|
|
|
lfsr_rbyd_t init_rbyd = {
|
|
.block = 0,
|
|
.eoff = 0,
|
|
.cksum = 0,
|
|
.trunk = 0,
|
|
.weight = 0,
|
|
};
|
|
lfsr_rbyd_t rbyd;
|
|
lfsr_tag_t tag_;
|
|
lfs_ssize_t rid_;
|
|
lfsr_data_t data_;
|
|
|
|
// 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_ATTRS(
|
|
LFSR_ATTR(-1, UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(-1, UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(-1, UATTR(3), 0, BUF("\xcc\xcc\xcc\xcc", 4)),
|
|
LFSR_ATTR(-1, UATTR(4), 0, BUF("\xdd\xdd\xdd\xdd", 4)))) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(1),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(2),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(3),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(3));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(4),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(4));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 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_ATTRS(
|
|
LFSR_ATTR(-1, UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(-1, UATTR(3), 0, BUF("\xcc\xcc\xcc\xcc", 4)),
|
|
LFSR_ATTR(-1, UATTR(4), 0, BUF("\xdd\xdd\xdd\xdd", 4)),
|
|
LFSR_ATTR(-1, UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)))) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(1),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(2),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(3),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(3));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(4),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(4));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 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_ATTRS(
|
|
LFSR_ATTR(-1, UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(-1, UATTR(3), 0, BUF("\xcc\xcc\xcc\xcc", 4)),
|
|
LFSR_ATTR(-1, UATTR(4), 0, BUF("\xdd\xdd\xdd\xdd", 4)),
|
|
LFSR_ATTR(-1, UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(1),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(2),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(3),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(3));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(4),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(4));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 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_ATTRS(
|
|
LFSR_ATTR(-1, UATTR(4), 0, BUF("\xdd\xdd\xdd\xdd", 4)),
|
|
LFSR_ATTR(-1, UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(-1, UATTR(3), 0, BUF("\xcc\xcc\xcc\xcc", 4)),
|
|
LFSR_ATTR(-1, UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(1),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(2),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(3),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(3));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(4),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(4));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
'''
|
|
|
|
[cases.test_rbyd_rotations]
|
|
in = 'lfs.c'
|
|
code = '''
|
|
lfs_t lfs;
|
|
lfs_init(&lfs, CFG) => 0;
|
|
|
|
lfsr_rbyd_t init_rbyd = {
|
|
.block = 0,
|
|
.eoff = 0,
|
|
.cksum = 0,
|
|
.trunk = 0,
|
|
.weight = 0,
|
|
};
|
|
lfsr_rbyd_t rbyd;
|
|
lfsr_tag_t tag_;
|
|
lfs_ssize_t rid_;
|
|
lfsr_data_t data_;
|
|
|
|
// 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_ATTRS(
|
|
LFSR_ATTR(-1, UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(-1, UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(-1, UATTR(3), 0, BUF("\xcc\xcc\xcc\xcc", 4)),
|
|
LFSR_ATTR(-1, UATTR(4), 0, BUF("\xdd\xdd\xdd\xdd", 4)))) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(1),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(2),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(3),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(3));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(4),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(4));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 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_ATTRS(
|
|
LFSR_ATTR(-1, UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(-1, UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(-1, UATTR(4), 0, BUF("\xdd\xdd\xdd\xdd", 4)),
|
|
LFSR_ATTR(-1, UATTR(3), 0, BUF("\xcc\xcc\xcc\xcc", 4)))) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(1),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(2),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(3),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(3));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(4),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(4));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 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_ATTRS(
|
|
LFSR_ATTR(-1, UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(-1, UATTR(4), 0, BUF("\xdd\xdd\xdd\xdd", 4)),
|
|
LFSR_ATTR(-1, UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(-1, UATTR(3), 0, BUF("\xcc\xcc\xcc\xcc", 4)))) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(1),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(2),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(3),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(3));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(4),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(4));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 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_ATTRS(
|
|
LFSR_ATTR(-1, UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(-1, UATTR(4), 0, BUF("\xdd\xdd\xdd\xdd", 4)),
|
|
LFSR_ATTR(-1, UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(-1, UATTR(3), 0, BUF("\xcc\xcc\xcc\xcc", 4)))) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(1),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(2),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(3),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(3));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(4),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(4));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
'''
|
|
|
|
[cases.test_rbyd_ysplits]
|
|
in = 'lfs.c'
|
|
code = '''
|
|
lfs_t lfs;
|
|
lfs_init(&lfs, CFG) => 0;
|
|
|
|
lfsr_rbyd_t init_rbyd = {
|
|
.block = 0,
|
|
.eoff = 0,
|
|
.cksum = 0,
|
|
.trunk = 0,
|
|
.weight = 0,
|
|
};
|
|
lfsr_rbyd_t rbyd;
|
|
lfsr_tag_t tag_;
|
|
lfs_ssize_t rid_;
|
|
lfsr_data_t data_;
|
|
|
|
// 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_ATTRS(
|
|
LFSR_ATTR(-1, UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(-1, UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(-1, UATTR(3), 0, BUF("\xcc\xcc\xcc\xcc", 4)),
|
|
LFSR_ATTR(-1, UATTR(4), 0, BUF("\xdd\xdd\xdd\xdd", 4)),
|
|
LFSR_ATTR(-1, UATTR(4), 0, BUF("\xdd\xdd\xdd\xdd", 4)))) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(1),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(2),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(3),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(3));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(4),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(4));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 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_ATTRS(
|
|
LFSR_ATTR(-1, UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(-1, UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(-1, UATTR(3), 0, BUF("\xcc\xcc\xcc\xcc", 4)),
|
|
LFSR_ATTR(-1, UATTR(4), 0, BUF("\xdd\xdd\xdd\xdd", 4)),
|
|
LFSR_ATTR(-1, UATTR(3), 0, BUF("\xcc\xcc\xcc\xcc", 4)))) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(1),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(2),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(3),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(3));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(4),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(4));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 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_ATTRS(
|
|
LFSR_ATTR(-1, UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(-1, UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(-1, UATTR(3), 0, BUF("\xcc\xcc\xcc\xcc", 4)),
|
|
LFSR_ATTR(-1, UATTR(4), 0, BUF("\xdd\xdd\xdd\xdd", 4)),
|
|
LFSR_ATTR(-1, UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)))) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(1),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(2),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(3),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(3));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(4),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(4));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 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_ATTRS(
|
|
LFSR_ATTR(-1, UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(-1, UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(-1, UATTR(3), 0, BUF("\xcc\xcc\xcc\xcc", 4)),
|
|
LFSR_ATTR(-1, UATTR(4), 0, BUF("\xdd\xdd\xdd\xdd", 4)),
|
|
LFSR_ATTR(-1, UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(1),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(2),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(3),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(3));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(4),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(4));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
'''
|
|
|
|
[cases.test_rbyd_quintifoliate]
|
|
in = 'lfs.c'
|
|
code = '''
|
|
lfs_t lfs;
|
|
lfs_init(&lfs, CFG) => 0;
|
|
|
|
lfsr_rbyd_t init_rbyd = {
|
|
.block = 0,
|
|
.eoff = 0,
|
|
.cksum = 0,
|
|
.trunk = 0,
|
|
.weight = 0,
|
|
};
|
|
lfsr_rbyd_t rbyd;
|
|
lfsr_tag_t tag_;
|
|
lfs_ssize_t rid_;
|
|
lfsr_data_t data_;
|
|
|
|
// 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_ATTRS(
|
|
LFSR_ATTR(-1, UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(-1, UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(-1, UATTR(3), 0, BUF("\xcc\xcc\xcc\xcc", 4)),
|
|
LFSR_ATTR(-1, UATTR(4), 0, BUF("\xdd\xdd\xdd\xdd", 4)),
|
|
LFSR_ATTR(-1, UATTR(5), 0, BUF("\xee\xee\xee\xee", 4)))) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(1),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(2),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(3),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(3));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(4),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(4));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(5),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(5));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 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_ATTRS(
|
|
LFSR_ATTR(-1, UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(-1, UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(-1, UATTR(4), 0, BUF("\xdd\xdd\xdd\xdd", 4)),
|
|
LFSR_ATTR(-1, UATTR(5), 0, BUF("\xee\xee\xee\xee", 4)),
|
|
LFSR_ATTR(-1, UATTR(3), 0, BUF("\xcc\xcc\xcc\xcc", 4)))) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(1),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(2),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(3),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(3));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(4),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(4));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(5),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(5));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 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_ATTRS(
|
|
LFSR_ATTR(-1, UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(-1, UATTR(3), 0, BUF("\xcc\xcc\xcc\xcc", 4)),
|
|
LFSR_ATTR(-1, UATTR(4), 0, BUF("\xdd\xdd\xdd\xdd", 4)),
|
|
LFSR_ATTR(-1, UATTR(5), 0, BUF("\xee\xee\xee\xee", 4)),
|
|
LFSR_ATTR(-1, UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)))) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(1),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(2),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(3),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(3));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(4),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(4));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(5),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(5));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 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_ATTRS(
|
|
LFSR_ATTR(-1, UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(-1, UATTR(3), 0, BUF("\xcc\xcc\xcc\xcc", 4)),
|
|
LFSR_ATTR(-1, UATTR(4), 0, BUF("\xdd\xdd\xdd\xdd", 4)),
|
|
LFSR_ATTR(-1, UATTR(5), 0, BUF("\xee\xee\xee\xee", 4)),
|
|
LFSR_ATTR(-1, UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(1),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(2),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(3),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(3));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(4),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(4));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(5),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(5));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
'''
|
|
|
|
[cases.test_rbyd_prunes]
|
|
in = 'lfs.c'
|
|
code = '''
|
|
lfs_t lfs;
|
|
lfs_init(&lfs, CFG) => 0;
|
|
|
|
lfsr_rbyd_t init_rbyd = {
|
|
.block = 0,
|
|
.eoff = 0,
|
|
.cksum = 0,
|
|
.trunk = 0,
|
|
.weight = 0,
|
|
};
|
|
lfsr_rbyd_t rbyd;
|
|
lfsr_tag_t tag_;
|
|
lfs_ssize_t rid_;
|
|
lfsr_data_t data_;
|
|
|
|
// 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_ATTRS(
|
|
LFSR_ATTR(-1, UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(-1, UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(-1, UATTR(3), 0, BUF("\xcc\xcc\xcc\xcc", 4)),
|
|
LFSR_ATTR(-1, UATTR(4), 0, BUF("\xdd\xdd\xdd\xdd", 4)),
|
|
LFSR_ATTR(-1, UATTR(5), 0, BUF("\xee\xee\xee\xee", 4)),
|
|
LFSR_ATTR(-1, UATTR(5), 0, BUF("\xee\xee\xee\xee", 4)))) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(1),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(2),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(3),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(3));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(4),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(4));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(5),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(5));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 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_ATTRS(
|
|
LFSR_ATTR(-1, UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(-1, UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(-1, UATTR(3), 0, BUF("\xcc\xcc\xcc\xcc", 4)),
|
|
LFSR_ATTR(-1, UATTR(4), 0, BUF("\xdd\xdd\xdd\xdd", 4)),
|
|
LFSR_ATTR(-1, UATTR(5), 0, BUF("\xee\xee\xee\xee", 4)),
|
|
LFSR_ATTR(-1, UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)))) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(1),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(2),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(3),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(3));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(4),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(4));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(5),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(5));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 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_ATTRS(
|
|
LFSR_ATTR(-1, UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(-1, UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(-1, UATTR(3), 0, BUF("\xcc\xcc\xcc\xcc", 4)),
|
|
LFSR_ATTR(-1, UATTR(4), 0, BUF("\xdd\xdd\xdd\xdd", 4)),
|
|
LFSR_ATTR(-1, UATTR(5), 0, BUF("\xee\xee\xee\xee", 4)),
|
|
LFSR_ATTR(-1, UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(1),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(2),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(3),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(3));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(4),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(4));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(5),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(5));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
'''
|
|
|
|
[cases.test_rbyd_sextifoliate]
|
|
in = 'lfs.c'
|
|
code = '''
|
|
lfs_t lfs;
|
|
lfs_init(&lfs, CFG) => 0;
|
|
|
|
lfsr_rbyd_t init_rbyd = {
|
|
.block = 0,
|
|
.eoff = 0,
|
|
.cksum = 0,
|
|
.trunk = 0,
|
|
.weight = 0,
|
|
};
|
|
lfsr_rbyd_t rbyd;
|
|
lfsr_tag_t tag_;
|
|
lfs_ssize_t rid_;
|
|
lfsr_data_t data_;
|
|
|
|
// 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_ATTRS(
|
|
LFSR_ATTR(-1, UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(-1, UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(-1, UATTR(3), 0, BUF("\xcc\xcc\xcc\xcc", 4)),
|
|
LFSR_ATTR(-1, UATTR(4), 0, BUF("\xdd\xdd\xdd\xdd", 4)),
|
|
LFSR_ATTR(-1, UATTR(5), 0, BUF("\xee\xee\xee\xee", 4)),
|
|
LFSR_ATTR(-1, UATTR(6), 0, BUF("\xff\xff\xff\xff", 4)))) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(1),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(2),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(3),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(3));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(4),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(4));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(5),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(5));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(6),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(6));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 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_ATTRS(
|
|
LFSR_ATTR(-1, UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(-1, UATTR(3), 0, BUF("\xcc\xcc\xcc\xcc", 4)),
|
|
LFSR_ATTR(-1, UATTR(4), 0, BUF("\xdd\xdd\xdd\xdd", 4)),
|
|
LFSR_ATTR(-1, UATTR(5), 0, BUF("\xee\xee\xee\xee", 4)),
|
|
LFSR_ATTR(-1, UATTR(6), 0, BUF("\xff\xff\xff\xff", 4)),
|
|
LFSR_ATTR(-1, UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)))) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(1),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(2),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(3),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(3));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(4),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(4));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(5),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(5));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(6),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(6));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 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_ATTRS(
|
|
LFSR_ATTR(-1, UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(-1, UATTR(3), 0, BUF("\xcc\xcc\xcc\xcc", 4)),
|
|
LFSR_ATTR(-1, UATTR(4), 0, BUF("\xdd\xdd\xdd\xdd", 4)),
|
|
LFSR_ATTR(-1, UATTR(5), 0, BUF("\xee\xee\xee\xee", 4)),
|
|
LFSR_ATTR(-1, UATTR(6), 0, BUF("\xff\xff\xff\xff", 4)),
|
|
LFSR_ATTR(-1, UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(1),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(2),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(3),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(3));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(4),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(4));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(5),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(5));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(6),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(6));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
'''
|
|
|
|
[cases.test_rbyd_permutations]
|
|
defines.N = 'range(1, 8)'
|
|
# -1 => exhaust all permutations
|
|
# n => reproduce a specific permutation
|
|
defines.PERMUTATION = -1
|
|
in = 'lfs.c'
|
|
code = '''
|
|
lfs_t lfs;
|
|
lfs_init(&lfs, CFG) => 0;
|
|
|
|
lfsr_rbyd_t init_rbyd = {
|
|
.block = 0,
|
|
.eoff = 0,
|
|
.cksum = 0,
|
|
.trunk = 0,
|
|
.weight = 0,
|
|
};
|
|
lfsr_rbyd_t rbyd;
|
|
lfsr_tag_t tag_;
|
|
lfs_ssize_t rid_;
|
|
lfsr_data_t data_;
|
|
|
|
// keep track of the worst case log size
|
|
lfs_size_t worst_size = 0;
|
|
size_t worst_perm_i = 0;
|
|
|
|
// test all permutations of a given size
|
|
size_t perm_count = TEST_FACTORIAL(N);
|
|
for (size_t i = 0;
|
|
i < (PERMUTATION == -1 ? perm_count : 1);
|
|
i++) {
|
|
uint32_t perm[N];
|
|
size_t perm_i = PERMUTATION == -1 ? i : (size_t)PERMUTATION;
|
|
TEST_PERMUTATION(perm_i, perm, N);
|
|
|
|
// print permutation to help debugging
|
|
printf("--- permutation: %zd [", perm_i);
|
|
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(-1, UATTR(perm[j]+1), 0,
|
|
BUF("\xaa\xaa\xaa\xaa", 4));
|
|
}
|
|
|
|
// test the given permutation
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, attrs, N) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
for (unsigned j = 0; j < N; j++) {
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(j+1),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(j+1));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
}
|
|
|
|
// keep track of the worst size
|
|
if (rbyd.eoff > worst_size) {
|
|
worst_size = rbyd.eoff;
|
|
worst_perm_i = perm_i;
|
|
}
|
|
}
|
|
|
|
// 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("--- summary --\n");
|
|
printf("worst permutation: %zd\n", worst_perm_i);
|
|
printf("worst size: %u B (N=%u, estimate=%u)\n",
|
|
worst_size, n, 12*n*(2*lfs_nlog2(n)+1)+4);
|
|
printf("worst 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)'
|
|
# -1 => exhaust all permutations
|
|
# n => reproduce a specific permutation
|
|
defines.PERMUTATION = -1
|
|
# 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,
|
|
.eoff = 0,
|
|
.cksum = 0,
|
|
.trunk = 0,
|
|
.weight = 0,
|
|
};
|
|
lfsr_rbyd_t rbyd;
|
|
lfsr_tag_t tag_;
|
|
lfs_ssize_t rid_;
|
|
lfsr_data_t data_;
|
|
|
|
// keep track of the worst case log size
|
|
lfs_size_t worst_size = 0;
|
|
size_t worst_perm_i = 0;
|
|
|
|
// test all permutations of a given size
|
|
size_t perm_count = TEST_FACTORIAL(N);
|
|
for (size_t i = 0;
|
|
i < (PERMUTATION == -1 ? perm_count : 1);
|
|
i++) {
|
|
uint32_t perm[N];
|
|
size_t perm_i = PERMUTATION == -1 ? i : (size_t)PERMUTATION;
|
|
TEST_PERMUTATION(perm_i, perm, N);
|
|
|
|
// print permutation to help debugging
|
|
printf("--- permutation: %zd [", perm_i);
|
|
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_ATTRS(
|
|
LFSR_ATTR(-1, UATTR(perm[j]+1), 0,
|
|
BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
|
|
}
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
for (unsigned j = 0; j < N; j++) {
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(j+1),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(j+1));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
}
|
|
|
|
// keep track of the worst size
|
|
if (rbyd.eoff > worst_size) {
|
|
worst_size = rbyd.eoff;
|
|
worst_perm_i = perm_i;
|
|
}
|
|
}
|
|
|
|
// 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("--- summary --\n");
|
|
printf("worst permutation: %zd\n", worst_perm_i);
|
|
printf("worst size: %u B (N=%u, estimate=%u)\n",
|
|
worst_size, n, 12*n*(2*lfs_nlog2(n)+1)+4);
|
|
printf("worst 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,
|
|
.eoff = 0,
|
|
.cksum = 0,
|
|
.trunk = 0,
|
|
.weight = 0,
|
|
};
|
|
lfsr_rbyd_t rbyd;
|
|
lfsr_tag_t tag_;
|
|
lfs_ssize_t rid_;
|
|
lfsr_data_t data_;
|
|
|
|
// 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_ATTRS(
|
|
LFSR_ATTR(-1, UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(-1, UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)))) => 0;
|
|
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, 0,
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, 0,
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
|
|
|
|
// also try the other direction
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(-1, UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(-1, UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
|
|
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, 0,
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, 0,
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, NULL, &data_) => 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,
|
|
.eoff = 0,
|
|
.cksum = 0,
|
|
.trunk = 0,
|
|
.weight = 0,
|
|
};
|
|
lfsr_rbyd_t rbyd;
|
|
lfsr_tag_t tag_;
|
|
lfs_ssize_t rid_;
|
|
lfsr_data_t data_;
|
|
|
|
// 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_ATTRS(
|
|
LFSR_ATTR(-1, UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(-1, UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)))) => 0;
|
|
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, 0,
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, 0,
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
|
|
|
|
// also try the other direction
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(-1, UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(-1, UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
|
|
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, 0,
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, 0,
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
|
|
'''
|
|
|
|
[cases.test_rbyd_traverse_permutations]
|
|
defines.N = 'range(1, 8)'
|
|
# -1 => exhaust all permutations
|
|
# n => reproduce a specific permutation
|
|
defines.PERMUTATION = -1
|
|
in = 'lfs.c'
|
|
code = '''
|
|
lfs_t lfs;
|
|
lfs_init(&lfs, CFG) => 0;
|
|
|
|
lfsr_rbyd_t init_rbyd = {
|
|
.block = 0,
|
|
.eoff = 0,
|
|
.cksum = 0,
|
|
.trunk = 0,
|
|
.weight = 0,
|
|
};
|
|
lfsr_rbyd_t rbyd;
|
|
lfsr_tag_t tag_;
|
|
lfs_ssize_t rid_;
|
|
lfsr_data_t data_;
|
|
|
|
// test all permutations of a given size
|
|
size_t perm_count = TEST_FACTORIAL(N);
|
|
for (size_t i = 0;
|
|
i < (PERMUTATION == -1 ? perm_count : 1);
|
|
i++) {
|
|
uint32_t perm[N];
|
|
size_t perm_i = PERMUTATION == -1 ? i : (size_t)PERMUTATION;
|
|
TEST_PERMUTATION(perm_i, perm, N);
|
|
|
|
// print permutation to help debugging
|
|
printf("--- permutation: %zd [", perm_i);
|
|
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(-1, UATTR(perm[j]+1), 0,
|
|
BUF("\xaa\xaa\xaa\xaa", 4));
|
|
}
|
|
|
|
// test the given permutation
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, attrs, N) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
// try traversing all tags
|
|
tag_ = 0;
|
|
rid_ = -1;
|
|
for (unsigned j = 0; j < N; j++) {
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(j+1));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
}
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
|
|
}
|
|
'''
|
|
|
|
[cases.test_rbyd_multi_traverse_permutations]
|
|
defines.N = 'range(1, 8)'
|
|
# -1 => exhaust all permutations
|
|
# n => reproduce a specific permutation
|
|
defines.PERMUTATION = -1
|
|
# 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,
|
|
.eoff = 0,
|
|
.cksum = 0,
|
|
.trunk = 0,
|
|
.weight = 0,
|
|
};
|
|
lfsr_rbyd_t rbyd;
|
|
lfsr_tag_t tag_;
|
|
lfs_ssize_t rid_;
|
|
lfsr_data_t data_;
|
|
|
|
// test all permutations of a given size
|
|
size_t perm_count = TEST_FACTORIAL(N);
|
|
for (size_t i = 0;
|
|
i < (PERMUTATION == -1 ? perm_count : 1);
|
|
i++) {
|
|
uint32_t perm[N];
|
|
size_t perm_i = PERMUTATION == -1 ? i : (size_t)PERMUTATION;
|
|
TEST_PERMUTATION(perm_i, perm, N);
|
|
|
|
// print permutation to help debugging
|
|
printf("--- permutation: %zd [", perm_i);
|
|
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_ATTRS(
|
|
LFSR_ATTR(-1, UATTR(perm[j]+1), 0,
|
|
BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
|
|
}
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
// try traversing all tags
|
|
tag_ = 0;
|
|
rid_ = -1;
|
|
for (unsigned j = 0; j < N; j++) {
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(j+1));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
}
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, NULL, &data_) => 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_update_permutations]
|
|
defines.N = 'range(1, 8)'
|
|
# -1 => exhaust all permutations
|
|
# n => reproduce a specific permutation
|
|
defines.PERMUTATION = -1
|
|
# 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,
|
|
.eoff = 0,
|
|
.cksum = 0,
|
|
.trunk = 0,
|
|
.weight = 0,
|
|
};
|
|
lfsr_rbyd_t rbyd;
|
|
lfsr_tag_t tag_;
|
|
lfs_ssize_t rid_;
|
|
lfsr_data_t data_;
|
|
|
|
// keep track of the worst case log size
|
|
lfs_size_t worst_size = 0;
|
|
size_t worst_perm_i = 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_ATTRS(
|
|
LFSR_ATTR(-1, UATTR(j+1), 0, BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
|
|
}
|
|
|
|
// copy block so we can reset after each remove
|
|
lfsr_rbyd_t backup_rbyd = rbyd;
|
|
uint8_t *backup_block = malloc(rbyd.eoff);
|
|
lfs_bd_read(&lfs, NULL, &lfs.rcache, rbyd.eoff,
|
|
rbyd.block, 0, backup_block, rbyd.eoff) => 0;
|
|
|
|
// test all permutations of a given size
|
|
size_t perm_count = TEST_FACTORIAL(N);
|
|
for (size_t i = 0;
|
|
i < (PERMUTATION == -1 ? perm_count : 1);
|
|
i++) {
|
|
uint32_t perm[N];
|
|
size_t perm_i = PERMUTATION == -1 ? i : (size_t)PERMUTATION;
|
|
TEST_PERMUTATION(perm_i, perm, N);
|
|
|
|
// print permutation to help debugging
|
|
printf("--- permutation: %zd [", perm_i);
|
|
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.eoff) => 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_ATTRS(
|
|
LFSR_ATTR(-1, UATTR(perm[j]+1), 0,
|
|
BUF("\xaa\xaa\xaa\xaa\xaa\xaa", 6)))) => 0;
|
|
}
|
|
|
|
// check that all tags have been updated
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
for (unsigned j = 0; j < N; j++) {
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(j+1),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(j+1));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 6);
|
|
}
|
|
|
|
// keep track of the worst size
|
|
if (rbyd.eoff > worst_size) {
|
|
worst_size = rbyd.eoff;
|
|
worst_perm_i = perm_i;
|
|
}
|
|
}
|
|
|
|
// 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("--- summary --\n");
|
|
printf("worst permutation: %zd\n", worst_perm_i);
|
|
printf("worst size: %u B (N=%u, estimate=%u)\n",
|
|
worst_size, n, 12*n*(2*lfs_nlog2(n)+1)+4);
|
|
printf("worst 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,
|
|
.eoff = 0,
|
|
.cksum = 0,
|
|
.trunk = 0,
|
|
.weight = 0,
|
|
};
|
|
lfsr_rbyd_t rbyd;
|
|
lfsr_tag_t tag_;
|
|
lfs_ssize_t rid_;
|
|
lfsr_data_t data_;
|
|
|
|
// 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++) {
|
|
lfs_size_t x
|
|
= (ORDER == 0) ? i
|
|
: (ORDER == 1) ? (((lfs_size_t)-1) - i)
|
|
: TEST_PRNG(&prng);
|
|
int err = lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(-1, UATTR(x & 0x7f), 0, BUF("\xaa\xaa\xaa\xaa", 4))));
|
|
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, 0) => 0;
|
|
for (lfs_size_t i = 0; i < count; i++) {
|
|
lfs_size_t x
|
|
= (ORDER == 0) ? i
|
|
: (ORDER == 1) ? (((lfs_size_t)-1) - i)
|
|
: TEST_PRNG(&prng);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(x & 0x7f),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(x & 0x7f));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 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,
|
|
.eoff = 0,
|
|
.cksum = 0,
|
|
.trunk = 0,
|
|
.weight = 0,
|
|
};
|
|
lfsr_rbyd_t rbyd;
|
|
lfsr_tag_t tag_;
|
|
lfs_ssize_t rid_;
|
|
lfsr_data_t data_;
|
|
|
|
// add and remove one attribute
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(-1, UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(-1, RM(UATTR(1)), 0, NULL()))) => 0;
|
|
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(1),
|
|
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(2),
|
|
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(1),
|
|
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(2),
|
|
&rid_, &tag_, NULL, &data_) => 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_ATTRS(
|
|
LFSR_ATTR(-1, UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(-1, UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(-1, RM(UATTR(1)), 0, NULL()))) => 0;
|
|
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(1),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(2),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(3),
|
|
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(1),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(2),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(3),
|
|
&rid_, &tag_, NULL, &data_) => 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_ATTRS(
|
|
LFSR_ATTR(-1, UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(-1, UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(-1, RM(UATTR(2)), 0, NULL()))) => 0;
|
|
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(1),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(2),
|
|
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(3),
|
|
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(1),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(2),
|
|
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(3),
|
|
&rid_, &tag_, NULL, &data_) => 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)'
|
|
# -1 => exhaust all permutations
|
|
# n => reproduce a specific permutation
|
|
defines.PERMUTATION = -1
|
|
# 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,
|
|
.eoff = 0,
|
|
.cksum = 0,
|
|
.trunk = 0,
|
|
.weight = 0,
|
|
};
|
|
lfsr_rbyd_t rbyd;
|
|
lfsr_tag_t tag_;
|
|
lfs_ssize_t rid_;
|
|
lfsr_data_t data_;
|
|
|
|
// keep track of the worst case log size
|
|
lfs_size_t worst_size = 0;
|
|
size_t worst_perm_i = 0;
|
|
|
|
// test all permutations of a given size
|
|
size_t perm_count = TEST_FACTORIAL(N);
|
|
for (size_t i = 0;
|
|
i < (PERMUTATION == -1 ? perm_count : 1);
|
|
i++) {
|
|
uint32_t perm[N];
|
|
size_t perm_i = PERMUTATION == -1 ? i : (size_t)PERMUTATION;
|
|
TEST_PERMUTATION(perm_i, perm, N);
|
|
|
|
// print permutation to help debugging
|
|
printf("--- permutation: %zd [", perm_i);
|
|
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_ATTRS(
|
|
LFSR_ATTR(-1, UATTR(perm[j]+1), 0,
|
|
BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
|
|
}
|
|
|
|
// copy block so we can reset after each remove
|
|
lfsr_rbyd_t backup_rbyd = rbyd;
|
|
uint8_t *backup_block = malloc(rbyd.eoff);
|
|
lfs_bd_read(&lfs, NULL, &lfs.rcache, rbyd.eoff,
|
|
rbyd.block, 0, backup_block, rbyd.eoff) => 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.eoff) => 0;
|
|
lfs_bd_flush(&lfs, &lfs.pcache, &lfs.rcache, false) => 0;
|
|
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(-1, RM(UATTR(j+1)), 0, NULL())))
|
|
=> 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, CFG->block_size) => 0;
|
|
for (unsigned k = 0; k < N; k++) {
|
|
int err = lfsr_rbyd_lookupnext(&lfs, &rbyd,
|
|
-1, LFSR_TAG_UATTR(k+1),
|
|
&rid_, &tag_, NULL, &data_);
|
|
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(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
}
|
|
} else {
|
|
assert(tag_ == LFSR_TAG_UATTR(k+1));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
}
|
|
}
|
|
|
|
// try appending the tag back to make sure things still work
|
|
printf("--- append: %d ---\n", j);
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(-1, UATTR(j+1), 0,
|
|
BUF("\xaa\xaa\xaa\xaa\xaa\xaa", 6)))) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, CFG->block_size) => 0;
|
|
for (unsigned k = 0; k < N; k++) {
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd,
|
|
-1, LFSR_TAG_UATTR(k+1),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
if (k == j) {
|
|
assert(tag_ == LFSR_TAG_UATTR(k+1));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 6);
|
|
} else {
|
|
assert(tag_ == LFSR_TAG_UATTR(k+1));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
}
|
|
}
|
|
|
|
// keep track of the worst size
|
|
if (rbyd.eoff > worst_size) {
|
|
worst_size = rbyd.eoff;
|
|
worst_perm_i = perm_i;
|
|
}
|
|
}
|
|
|
|
// 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 + 2;
|
|
printf("--- summary --\n");
|
|
printf("worst permutation: %zd\n", worst_perm_i);
|
|
printf("worst size: %u B (N=%u, estimate=%u)\n",
|
|
worst_size, n, 12*n*(2*lfs_nlog2(n)+1)+4);
|
|
printf("worst 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)'
|
|
# -1 => exhaust all permutations
|
|
# n => reproduce a specific permutation
|
|
defines.PERMUTATION = -1
|
|
# 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,
|
|
.eoff = 0,
|
|
.cksum = 0,
|
|
.trunk = 0,
|
|
.weight = 0,
|
|
};
|
|
lfsr_rbyd_t rbyd;
|
|
lfsr_tag_t tag_;
|
|
lfs_ssize_t rid_;
|
|
lfsr_data_t data_;
|
|
|
|
// test all permutations of a given size
|
|
size_t perm_count = TEST_FACTORIAL(N);
|
|
for (size_t i = 0;
|
|
i < (PERMUTATION == -1 ? perm_count : 1);
|
|
i++) {
|
|
uint32_t perm[N];
|
|
size_t perm_i = PERMUTATION == -1 ? i : (size_t)PERMUTATION;
|
|
TEST_PERMUTATION(perm_i, perm, N);
|
|
|
|
// print permutation to help debugging
|
|
printf("--- permutation: %zd [", perm_i);
|
|
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_ATTRS(
|
|
LFSR_ATTR(-1, UATTR(perm[j]+1), 0,
|
|
BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
|
|
}
|
|
|
|
// copy block so we can reset after each remove
|
|
lfsr_rbyd_t backup_rbyd = rbyd;
|
|
uint8_t *backup_block = malloc(rbyd.eoff);
|
|
lfs_bd_read(&lfs, NULL, &lfs.rcache, rbyd.eoff,
|
|
rbyd.block, 0, backup_block, rbyd.eoff) => 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.eoff) => 0;
|
|
lfs_bd_flush(&lfs, &lfs.pcache, &lfs.rcache, false) => 0;
|
|
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(-1, RM(UATTR(j+1)), 0, NULL()))) => 0;
|
|
|
|
// try traversing over the tags
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, CFG->block_size) => 0;
|
|
|
|
tag_ = 0;
|
|
rid_ = -1;
|
|
for (unsigned k = 0; k < N-1; k++) {
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
if (k >= j) {
|
|
assert(tag_ == LFSR_TAG_UATTR(k+1+1));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
} else {
|
|
assert(tag_ == LFSR_TAG_UATTR(k+1));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
}
|
|
}
|
|
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
|
|
}
|
|
|
|
// cleanup
|
|
free(backup_block);
|
|
}
|
|
'''
|
|
|
|
[cases.test_rbyd_remove_missing]
|
|
in = 'lfs.c'
|
|
code = '''
|
|
lfs_t lfs;
|
|
lfs_init(&lfs, CFG) => 0;
|
|
|
|
lfsr_rbyd_t init_rbyd = {
|
|
.block = 0,
|
|
.eoff = 0,
|
|
.cksum = 0,
|
|
.trunk = 0,
|
|
.weight = 0,
|
|
};
|
|
lfsr_rbyd_t rbyd;
|
|
lfsr_tag_t tag_;
|
|
lfs_ssize_t rid_;
|
|
lfsr_data_t data_;
|
|
|
|
// create a tree two attributes
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(-1, UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(-1, UATTR(4), 0, BUF("\xdd\xdd\xdd\xdd", 4)))) => 0;
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(1),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(2),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(3),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(4));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(4),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(4));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(5),
|
|
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
|
|
|
|
// try to remove tags that aren't there, this should do nothing
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(-1, RM(UATTR(1)), 0, NULL()))) => 0;
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(1),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(2),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(3),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(4));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(4),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(4));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(5),
|
|
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(-1, RM(UATTR(3)), 0, NULL()))) => 0;
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(1),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(2),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(3),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(4));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(4),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(4));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(5),
|
|
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(-1, RM(UATTR(5)), 0, NULL()))) => 0;
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(1),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(2),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(3),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(4));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(4),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(4));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(5),
|
|
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
|
|
|
|
// one last fetch to make sure nothing was broken
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(1),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(2),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(3),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(4));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(4),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(4));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(5),
|
|
&rid_, &tag_, NULL, &data_) => 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,
|
|
.eoff = 0,
|
|
.cksum = 0,
|
|
.trunk = 0,
|
|
.weight = 0,
|
|
};
|
|
lfsr_rbyd_t rbyd;
|
|
lfsr_tag_t tag_;
|
|
lfs_ssize_t rid_;
|
|
lfsr_data_t data_;
|
|
|
|
// create a tree
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(-1, UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(-1, UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(-1, UATTR(3), 0, BUF("\xcc\xcc\xcc\xcc", 4)),
|
|
LFSR_ATTR(-1, UATTR(4), 0, BUF("\xdd\xdd\xdd\xdd", 4)),
|
|
LFSR_ATTR(-1, UATTR(5), 0, BUF("\xee\xee\xee\xee", 4)))) => 0;
|
|
// remove several attributes
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(-1, RM(UATTR(1)), 0, NULL()),
|
|
LFSR_ATTR(-1, RM(UATTR(3)), 0, NULL()),
|
|
LFSR_ATTR(-1, RM(UATTR(5)), 0, NULL()))) => 0;
|
|
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(1),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(2),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(3),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(4));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(4),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(4));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(5),
|
|
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
|
|
|
|
// try to remove tags that aren't there, this should do nothing
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(-1, RM(UATTR(1)), 0, NULL()))) => 0;
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(1),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(2),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(3),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(4));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(4),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(4));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(5),
|
|
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(-1, RM(UATTR(3)), 0, NULL()))) => 0;
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(1),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(2),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(3),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(4));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(4),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(4));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(5),
|
|
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(-1, RM(UATTR(5)), 0, NULL()))) => 0;
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(1),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(2),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(3),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(4));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(4),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(4));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(5),
|
|
&rid_, &tag_, NULL, &data_) => 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_ATTRS(
|
|
LFSR_ATTR(-1, RM(UATTR(1)), 0, NULL()))) => 0;
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(1),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(2),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(3),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(4));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(4),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(4));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(5),
|
|
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(-1, RM(UATTR(3)), 0, NULL()))) => 0;
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(1),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(2),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(3),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(4));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(4),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(4));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(5),
|
|
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(-1, RM(UATTR(5)), 0, NULL()))) => 0;
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(1),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(2),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(3),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(4));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(4),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(4));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(5),
|
|
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
|
|
|
|
// one last fetch to make sure nothing was broken
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(1),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(2),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(3),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(4));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(4),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(4));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(5),
|
|
&rid_, &tag_, NULL, &data_) => 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,
|
|
.eoff = 0,
|
|
.cksum = 0,
|
|
.trunk = 0,
|
|
.weight = 0,
|
|
};
|
|
lfsr_rbyd_t rbyd;
|
|
lfsr_tag_t tag_;
|
|
lfs_ssize_t rid_;
|
|
lfsr_data_t data_;
|
|
|
|
// commit with one attribute, remove it
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(-1, UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(-1, RM(UATTR(1)), 0, NULL()))) => 0;
|
|
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(1),
|
|
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(2),
|
|
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(1),
|
|
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(2),
|
|
&rid_, &tag_, NULL, &data_) => 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_ATTRS(
|
|
LFSR_ATTR(-1, UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(-1, UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(-1, RM(UATTR(1)), 0, NULL()),
|
|
LFSR_ATTR(-1, RM(UATTR(2)), 0, NULL()))) => 0;
|
|
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(1),
|
|
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(2),
|
|
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(1),
|
|
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(2),
|
|
&rid_, &tag_, NULL, &data_) => 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_ATTRS(
|
|
LFSR_ATTR(-1, UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(-1, UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(-1, RM(UATTR(2)), 0, NULL()),
|
|
LFSR_ATTR(-1, RM(UATTR(1)), 0, NULL()))) => 0;
|
|
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(1),
|
|
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(2),
|
|
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(1),
|
|
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(2),
|
|
&rid_, &tag_, NULL, &data_) => 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)'
|
|
# -1 => exhaust all permutations
|
|
# n => reproduce a specific permutation
|
|
defines.PERMUTATION = -1
|
|
# 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,
|
|
.eoff = 0,
|
|
.cksum = 0,
|
|
.trunk = 0,
|
|
.weight = 0,
|
|
};
|
|
lfsr_rbyd_t rbyd;
|
|
lfsr_tag_t tag_;
|
|
lfs_ssize_t rid_;
|
|
lfsr_data_t data_;
|
|
|
|
// keep track of the worst case log size
|
|
lfs_size_t worst_size = 0;
|
|
size_t worst_perm_i = 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_ATTRS(
|
|
LFSR_ATTR(-1, UATTR(j+1), 0, BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
|
|
}
|
|
|
|
// copy block so we can reset after each remove
|
|
lfsr_rbyd_t backup_rbyd = rbyd;
|
|
uint8_t *backup_block = malloc(rbyd.eoff);
|
|
lfs_bd_read(&lfs, NULL, &lfs.rcache, rbyd.eoff,
|
|
rbyd.block, 0, backup_block, rbyd.eoff) => 0;
|
|
|
|
// test all permutations of a given size
|
|
size_t perm_count = TEST_FACTORIAL(N);
|
|
for (size_t i = 0;
|
|
i < (PERMUTATION == -1 ? perm_count : 1);
|
|
i++) {
|
|
uint32_t perm[N];
|
|
size_t perm_i = PERMUTATION == -1 ? i : (size_t)PERMUTATION;
|
|
TEST_PERMUTATION(perm_i, perm, N);
|
|
|
|
// print permutation to help debugging
|
|
printf("--- permutation: %zd [", perm_i);
|
|
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.eoff) => 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_ATTRS(
|
|
LFSR_ATTR(-1, RM(UATTR(perm[j]+1)), 0, NULL()))) => 0;
|
|
}
|
|
|
|
// check that all tags are now removed
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
for (unsigned j = 0; j < N; j++) {
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(j+1),
|
|
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
|
|
}
|
|
|
|
// try resuming from all tags being removed
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(-1, UATTR(1), 0,
|
|
BUF("\xaa\xaa\xaa\xaa\xaa\xaa", 6)))) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(1),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 6);
|
|
for (unsigned j = 1; j < N; j++) {
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(j+1),
|
|
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
|
|
}
|
|
|
|
// keep track of the worst size
|
|
if (rbyd.eoff > worst_size) {
|
|
worst_size = rbyd.eoff;
|
|
worst_perm_i = perm_i;
|
|
}
|
|
}
|
|
|
|
// 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("--- summary --\n");
|
|
printf("worst permutation: %zd\n", worst_perm_i);
|
|
printf("worst size: %u B (N=%u, estimate=%u)\n",
|
|
worst_size, n, 12*n*(2*lfs_nlog2(n)+1)+4);
|
|
printf("worst 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_fuzz_append_removes]
|
|
defines.N = 'range(1, 33)'
|
|
defines.SEED = 'range(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,
|
|
.eoff = 0,
|
|
.cksum = 0,
|
|
.trunk = 0,
|
|
.weight = 0,
|
|
};
|
|
lfsr_rbyd_t rbyd;
|
|
const char *alpha = "abcdefghijklmnopqrstuvwxyz";
|
|
uint8_t buffer[4];
|
|
|
|
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_ATTRS(
|
|
LFSR_ATTR(-1, UATTR(attr), 0,
|
|
BUF(&alpha[i % 26], 1)))) => 0;
|
|
} else {
|
|
// update our sim
|
|
sim[attr] = '\0';
|
|
// update our rbyd
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(-1, RM(UATTR(attr)), 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,
|
|
-1, LFSR_TAG_UATTR(attr), 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,
|
|
-1, LFSR_TAG_UATTR(attr), buffer, 4);
|
|
if (sim[attr]) {
|
|
assert(size == 1);
|
|
assert(memcmp(&sim[attr], buffer, 1) == 0);
|
|
} else {
|
|
assert(size == LFS_ERR_NOENT);
|
|
}
|
|
}
|
|
|
|
// cleanup
|
|
free(sim);
|
|
'''
|
|
|
|
|
|
### 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,
|
|
.eoff = 0,
|
|
.cksum = 0,
|
|
.trunk = 0,
|
|
.weight = 0,
|
|
};
|
|
lfsr_rbyd_t rbyd;
|
|
uint8_t buffer[4];
|
|
|
|
// try to create one rid
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(0, REG, +1, BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
|
|
|
|
assert(rbyd.weight == 1);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
assert(rbyd.weight == 1);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_REG, 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_ATTRS(
|
|
LFSR_ATTR(0, REG, +1, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(1, REG, +1, BUF("\xbb\xbb\xbb\xbb", 4)))) => 0;
|
|
|
|
assert(rbyd.weight == 2);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 1, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
assert(rbyd.weight == 2);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 1, LFSR_TAG_REG, 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_ATTRS(
|
|
LFSR_ATTR(0, REG, +1, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(0, REG, +1, BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
|
|
|
|
assert(rbyd.weight == 2);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 1, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
assert(rbyd.weight == 2);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 1, LFSR_TAG_REG, 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_ATTRS(
|
|
LFSR_ATTR(0, REG, +1, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(1, REG, +1, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(2, REG, +1, BUF("\xcc\xcc\xcc\xcc", 4)))) => 0;
|
|
|
|
assert(rbyd.weight == 3);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 1, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 2, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
assert(rbyd.weight == 3);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 1, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 2, LFSR_TAG_REG, 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_ATTRS(
|
|
LFSR_ATTR(0, REG, +1, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(1, REG, +1, BUF("\xcc\xcc\xcc\xcc", 4)),
|
|
LFSR_ATTR(0, REG, +1, BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
|
|
|
|
assert(rbyd.weight == 3);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 1, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 2, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
assert(rbyd.weight == 3);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 1, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 2, LFSR_TAG_REG, 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_ATTRS(
|
|
LFSR_ATTR(0, REG, +1, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(1, REG, +1, BUF("\xcc\xcc\xcc\xcc", 4)),
|
|
LFSR_ATTR(1, REG, +1, BUF("\xbb\xbb\xbb\xbb", 4)))) => 0;
|
|
|
|
assert(rbyd.weight == 3);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 1, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 2, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
assert(rbyd.weight == 3);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 1, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 2, LFSR_TAG_REG, 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,
|
|
.eoff = 0,
|
|
.cksum = 0,
|
|
.trunk = 0,
|
|
.weight = 0,
|
|
};
|
|
lfsr_rbyd_t rbyd;
|
|
uint8_t buffer[4];
|
|
|
|
// try to create one rid
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(0, REG, +1, BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
|
|
|
|
assert(rbyd.weight == 1);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_REG, buffer, 4)
|
|
=> 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
assert(rbyd.weight == 1);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_REG, 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_ATTRS(
|
|
LFSR_ATTR(0, REG, +1, BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(1, REG, +1, BUF("\xbb\xbb\xbb\xbb", 4)))) => 0;
|
|
|
|
assert(rbyd.weight == 2);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 1, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
assert(rbyd.weight == 2);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 1, LFSR_TAG_REG, 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_ATTRS(
|
|
LFSR_ATTR(0, REG, +1, BUF("\xbb\xbb\xbb\xbb", 4)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(0, REG, +1, BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
|
|
|
|
assert(rbyd.weight == 2);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 1, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
assert(rbyd.weight == 2);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 1, LFSR_TAG_REG, 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_ATTRS(
|
|
LFSR_ATTR(0, REG, +1, BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(1, REG, +1, BUF("\xbb\xbb\xbb\xbb", 4)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(2, REG, +1, BUF("\xcc\xcc\xcc\xcc", 4)))) => 0;
|
|
|
|
assert(rbyd.weight == 3);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 1, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 2, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
assert(rbyd.weight == 3);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 1, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 2, LFSR_TAG_REG, 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_ATTRS(
|
|
LFSR_ATTR(0, REG, +1, BUF("\xbb\xbb\xbb\xbb", 4)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(1, REG, +1, BUF("\xcc\xcc\xcc\xcc", 4)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(0, REG, +1, BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
|
|
|
|
assert(rbyd.weight == 3);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 1, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 2, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
assert(rbyd.weight == 3);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 1, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 2, LFSR_TAG_REG, 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_ATTRS(
|
|
LFSR_ATTR(0, REG, +1, BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(1, REG, +1, BUF("\xcc\xcc\xcc\xcc", 4)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(1, REG, +1, BUF("\xbb\xbb\xbb\xbb", 4)))) => 0;
|
|
|
|
assert(rbyd.weight == 3);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 1, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 2, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
assert(rbyd.weight == 3);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 1, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 2, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
|
|
'''
|
|
|
|
[cases.test_rbyd_create_permutations]
|
|
defines.N = 'range(1, 8)'
|
|
# -1 => exhaust all permutations
|
|
# n => reproduce a specific permutation
|
|
defines.PERMUTATION = -1
|
|
in = 'lfs.c'
|
|
code = '''
|
|
lfs_t lfs;
|
|
lfs_init(&lfs, CFG) => 0;
|
|
|
|
lfsr_rbyd_t init_rbyd = {
|
|
.block = 0,
|
|
.eoff = 0,
|
|
.cksum = 0,
|
|
.trunk = 0,
|
|
.weight = 0,
|
|
};
|
|
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;
|
|
size_t worst_perm_i = 0;
|
|
|
|
// test all permutations of a given size
|
|
size_t perm_count = TEST_FACTORIAL(N);
|
|
for (size_t i = 0;
|
|
i < (PERMUTATION == -1 ? perm_count : 1);
|
|
i++) {
|
|
uint32_t perm[N];
|
|
size_t perm_i = PERMUTATION == -1 ? i : (size_t)PERMUTATION;
|
|
TEST_PERMUTATION(perm_i, perm, N);
|
|
|
|
// print permutation to help debugging
|
|
printf("--- permutation: %zd [", perm_i);
|
|
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++) {
|
|
// adjust rid based on future insertions
|
|
uint16_t rid = perm[j];
|
|
for (unsigned k = j+1; k < N; k++) {
|
|
if (perm[j] > perm[k]) {
|
|
rid -= 1;
|
|
}
|
|
}
|
|
|
|
attrs[j] = LFSR_ATTR(rid, REG, +1, BUF(names[perm[j] % 6], 4));
|
|
}
|
|
|
|
// test the given permutation
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, attrs, N) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
assert(rbyd.weight == N);
|
|
for (unsigned j = 0; j < N; j++) {
|
|
lfsr_rbyd_get(&lfs, &rbyd, j, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, names[j % 6], 4) == 0);
|
|
}
|
|
|
|
// keep track of the worst size
|
|
if (rbyd.eoff > worst_size) {
|
|
worst_size = rbyd.eoff;
|
|
worst_perm_i = perm_i;
|
|
}
|
|
}
|
|
|
|
// 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("--- summary ---\n");
|
|
printf("worst permutation: %zd\n", worst_perm_i);
|
|
printf("worst size: %u B (N=%u, estimate=%u)\n",
|
|
worst_size, n, 12*n*(2*lfs_nlog2(n)+1)+4);
|
|
printf("worst 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)'
|
|
# -1 => exhaust all permutations
|
|
# n => reproduce a specific permutation
|
|
defines.PERMUTATION = -1
|
|
# 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,
|
|
.eoff = 0,
|
|
.cksum = 0,
|
|
.trunk = 0,
|
|
.weight = 0,
|
|
};
|
|
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;
|
|
size_t worst_perm_i = 0;
|
|
|
|
// test all permutations of a given size
|
|
size_t perm_count = TEST_FACTORIAL(N);
|
|
for (size_t i = 0;
|
|
i < (PERMUTATION == -1 ? perm_count : 1);
|
|
i++) {
|
|
uint32_t perm[N];
|
|
size_t perm_i = PERMUTATION == -1 ? i : (size_t)PERMUTATION;
|
|
TEST_PERMUTATION(perm_i, perm, N);
|
|
|
|
// print permutation to help debugging
|
|
printf("--- permutation: %zd [", perm_i);
|
|
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 rid based on future insertions
|
|
uint16_t rid = perm[j];
|
|
for (unsigned k = j+1; k < N; k++) {
|
|
if (perm[j] > perm[k]) {
|
|
rid -= 1;
|
|
}
|
|
}
|
|
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(rid, REG, +1, BUF(names[perm[j] % 6], 4)))) => 0;
|
|
}
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
assert(rbyd.weight == N);
|
|
for (unsigned j = 0; j < N; j++) {
|
|
lfsr_rbyd_get(&lfs, &rbyd,
|
|
j, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, names[j % 6], 4) == 0);
|
|
}
|
|
|
|
// keep track of the worst size
|
|
if (rbyd.eoff > worst_size) {
|
|
worst_size = rbyd.eoff;
|
|
worst_perm_i = perm_i;
|
|
}
|
|
}
|
|
|
|
// 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("--- summary ---\n");
|
|
printf("worst permutation: %zd\n", worst_perm_i);
|
|
printf("worst size: %u B (N=%u, estimate=%u)\n",
|
|
worst_size, n, 12*n*(2*lfs_nlog2(n)+1)+4);
|
|
printf("worst 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,
|
|
.eoff = 0,
|
|
.cksum = 0,
|
|
.trunk = 0,
|
|
.weight = 0,
|
|
};
|
|
lfsr_rbyd_t rbyd;
|
|
lfsr_tag_t tag_;
|
|
lfs_ssize_t rid_;
|
|
lfsr_data_t data_;
|
|
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_ATTRS(
|
|
LFSR_ATTR(0, REG, +1, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(1, REG, +1, BUF("\xbb\xbb\xbb\xbb", 4)))) => 0;
|
|
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, 0,
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 0);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_get(&lfs, &rbyd, rid_, tag_, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_get(&lfs, &rbyd, rid_, tag_, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, 0,
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 0);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_get(&lfs, &rbyd, rid_, tag_, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_get(&lfs, &rbyd, rid_, tag_, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
|
|
|
|
// also try the other direction
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(0, REG, +1, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(0, REG, +1, BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
|
|
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, 0,
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 0);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_get(&lfs, &rbyd, rid_, tag_, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_get(&lfs, &rbyd, rid_, tag_, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, 0,
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 0);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_get(&lfs, &rbyd, rid_, tag_, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_get(&lfs, &rbyd, rid_, tag_, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, NULL, &data_) => 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,
|
|
.eoff = 0,
|
|
.cksum = 0,
|
|
.trunk = 0,
|
|
.weight = 0,
|
|
};
|
|
lfsr_rbyd_t rbyd;
|
|
lfsr_tag_t tag_;
|
|
lfs_ssize_t rid_;
|
|
lfsr_data_t data_;
|
|
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_ATTRS(
|
|
LFSR_ATTR(0, REG, +1, BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(1, REG, +1, BUF("\xbb\xbb\xbb\xbb", 4)))) => 0;
|
|
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, 0,
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 0);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_get(&lfs, &rbyd, rid_, tag_, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_get(&lfs, &rbyd, rid_, tag_, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, 0,
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 0);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_get(&lfs, &rbyd, rid_, tag_, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_get(&lfs, &rbyd, rid_, tag_, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
|
|
|
|
// also try the other direction
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(0, REG, +1, BUF("\xbb\xbb\xbb\xbb", 4)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(0, REG, +1, BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
|
|
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, 0,
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 0);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_get(&lfs, &rbyd, rid_, tag_, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_get(&lfs, &rbyd, rid_, tag_, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, 0,
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 0);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_get(&lfs, &rbyd, rid_, tag_, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_get(&lfs, &rbyd, rid_, tag_, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
|
|
'''
|
|
|
|
[cases.test_rbyd_create_traverse_permutations]
|
|
defines.N = 'range(1, 8)'
|
|
# -1 => exhaust all permutations
|
|
# n => reproduce a specific permutation
|
|
defines.PERMUTATION = -1
|
|
in = 'lfs.c'
|
|
code = '''
|
|
lfs_t lfs;
|
|
lfs_init(&lfs, CFG) => 0;
|
|
|
|
lfsr_rbyd_t init_rbyd = {
|
|
.block = 0,
|
|
.eoff = 0,
|
|
.cksum = 0,
|
|
.trunk = 0,
|
|
.weight = 0,
|
|
};
|
|
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 rid_;
|
|
lfsr_data_t data_;
|
|
uint8_t buffer[4];
|
|
|
|
// test all permutations of a given size
|
|
size_t perm_count = TEST_FACTORIAL(N);
|
|
for (size_t i = 0;
|
|
i < (PERMUTATION == -1 ? perm_count : 1);
|
|
i++) {
|
|
uint32_t perm[N];
|
|
size_t perm_i = PERMUTATION == -1 ? i : (size_t)PERMUTATION;
|
|
TEST_PERMUTATION(perm_i, perm, N);
|
|
|
|
// print permutation to help debugging
|
|
printf("--- permutation: %zd [", perm_i);
|
|
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++) {
|
|
// adjust rid based on future insertions
|
|
uint16_t rid = perm[j];
|
|
for (unsigned k = j+1; k < N; k++) {
|
|
if (perm[j] > perm[k]) {
|
|
rid -= 1;
|
|
}
|
|
}
|
|
|
|
attrs[j] = LFSR_ATTR(rid, REG, +1, BUF(names[perm[j] % 6], 4));
|
|
}
|
|
|
|
// test the given permutation
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, attrs, N) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
assert(rbyd.weight == N);
|
|
// try traversing all tags
|
|
tag_ = 0;
|
|
rid_ = -1;
|
|
for (unsigned j = 0; j < N; j++) {
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == j);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
|
|
lfsr_rbyd_get(&lfs, &rbyd, rid_, tag_, buffer, 4) => 4;
|
|
assert(memcmp(buffer, names[j % 6], 4) == 0);
|
|
}
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
|
|
}
|
|
'''
|
|
|
|
[cases.test_rbyd_multi_create_traverse_permutations]
|
|
defines.N = 'range(1, 8)'
|
|
# -1 => exhaust all permutations
|
|
# n => reproduce a specific permutation
|
|
defines.PERMUTATION = -1
|
|
# 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,
|
|
.eoff = 0,
|
|
.cksum = 0,
|
|
.trunk = 0,
|
|
.weight = 0,
|
|
};
|
|
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 rid_;
|
|
lfsr_data_t data_;
|
|
uint8_t buffer[4];
|
|
|
|
// test all permutations of a given size
|
|
size_t perm_count = TEST_FACTORIAL(N);
|
|
for (size_t i = 0;
|
|
i < (PERMUTATION == -1 ? perm_count : 1);
|
|
i++) {
|
|
uint32_t perm[N];
|
|
size_t perm_i = PERMUTATION == -1 ? i : (size_t)PERMUTATION;
|
|
TEST_PERMUTATION(perm_i, perm, N);
|
|
|
|
// print permutation to help debugging
|
|
printf("--- permutation: %zd [", perm_i);
|
|
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 rid based on future insertions
|
|
uint16_t rid = perm[j];
|
|
for (unsigned k = j+1; k < N; k++) {
|
|
if (perm[j] > perm[k]) {
|
|
rid -= 1;
|
|
}
|
|
}
|
|
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(rid, REG, +1, BUF(names[perm[j] % 6], 4)))) => 0;
|
|
}
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
assert(rbyd.weight == N);
|
|
// try traversing all tags
|
|
tag_ = 0;
|
|
rid_ = -1;
|
|
for (unsigned j = 0; j < N; j++) {
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == j);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
|
|
lfsr_rbyd_get(&lfs, &rbyd, rid_, tag_, buffer, 4) => 4;
|
|
assert(memcmp(buffer, names[j % 6], 4) == 0);
|
|
}
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
|
|
}
|
|
'''
|
|
|
|
[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,
|
|
.eoff = 0,
|
|
.cksum = 0,
|
|
.trunk = 0,
|
|
.weight = 0,
|
|
};
|
|
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_ATTRS(
|
|
LFSR_ATTR(x, REG, +1, BUF(names[x % 6], 4))));
|
|
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 rid_;
|
|
lfsr_data_t data_;
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
for (uint16_t x = 0; x < rbyd.weight; x++) {
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, x, LFSR_TAG_REG,
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == x);
|
|
assert(lfsr_data_size(&data_) == 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,
|
|
.eoff = 0,
|
|
.cksum = 0,
|
|
.trunk = 0,
|
|
.weight = 0,
|
|
};
|
|
lfsr_rbyd_t rbyd;
|
|
uint8_t buffer[4];
|
|
|
|
// try to create one rid
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(0, REG, +1, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(0, UATTR(1), 0, BUF( "\xaa\xaa", 2)))) => 0;
|
|
|
|
assert(rbyd.weight == 1);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
assert(rbyd.weight == 1);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), 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_ATTRS(
|
|
LFSR_ATTR(0, REG, +1, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(0, UATTR(1), 0, BUF( "\xaa\xaa", 2)),
|
|
LFSR_ATTR(1, REG, +1, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(1, UATTR(1), 0, BUF( "\xbb\xbb", 2)))) => 0;
|
|
|
|
assert(rbyd.weight == 2);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 1, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 1, LFSR_TAG_UATTR(1), buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
assert(rbyd.weight == 2);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 1, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 1, LFSR_TAG_UATTR(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_ATTRS(
|
|
LFSR_ATTR(0, REG, +1, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(0, UATTR(1), 0, BUF( "\xbb\xbb", 2)),
|
|
LFSR_ATTR(0, REG, +1, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(0, UATTR(1), 0, BUF( "\xaa\xaa", 2)))) => 0;
|
|
|
|
assert(rbyd.weight == 2);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 1, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 1, LFSR_TAG_UATTR(1), buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
assert(rbyd.weight == 2);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 1, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 1, LFSR_TAG_UATTR(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_ATTRS(
|
|
LFSR_ATTR(0, REG, +1, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(0, UATTR(1), 0, BUF( "\xaa\xaa", 2)),
|
|
LFSR_ATTR(1, REG, +1, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(1, UATTR(1), 0, BUF( "\xbb\xbb", 2)),
|
|
LFSR_ATTR(2, REG, +1, BUF("\xcc\xcc\xcc\xcc", 4)),
|
|
LFSR_ATTR(2, UATTR(1), 0, BUF( "\xcc\xcc", 2)))) => 0;
|
|
|
|
assert(rbyd.weight == 3);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 1, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 2, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
assert(rbyd.weight == 3);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 1, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 2, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
|
|
|
|
assert(rbyd.weight == 3);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 1, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 1, LFSR_TAG_UATTR(1), buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 2, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 2, LFSR_TAG_UATTR(1), buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xcc\xcc", 2) == 0);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
assert(rbyd.weight == 3);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 1, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 1, LFSR_TAG_UATTR(1), buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 2, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 2, LFSR_TAG_UATTR(1), 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_ATTRS(
|
|
LFSR_ATTR(0, REG, +1, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(0, UATTR(1), 0, BUF( "\xbb\xbb", 2)),
|
|
LFSR_ATTR(1, REG, +1, BUF("\xcc\xcc\xcc\xcc", 4)),
|
|
LFSR_ATTR(1, UATTR(1), 0, BUF( "\xcc\xcc", 2)),
|
|
LFSR_ATTR(0, REG, +1, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(0, UATTR(1), 0, BUF( "\xaa\xaa", 2)))) => 0;
|
|
|
|
assert(rbyd.weight == 3);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 1, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 1, LFSR_TAG_UATTR(1), buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 2, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 2, LFSR_TAG_UATTR(1), buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xcc\xcc", 2) == 0);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
assert(rbyd.weight == 3);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 1, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 1, LFSR_TAG_UATTR(1), buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 2, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 2, LFSR_TAG_UATTR(1), 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_ATTRS(
|
|
LFSR_ATTR(0, REG, +1, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(0, UATTR(1), 0, BUF( "\xaa\xaa", 2)),
|
|
LFSR_ATTR(1, REG, +1, BUF("\xcc\xcc\xcc\xcc", 4)),
|
|
LFSR_ATTR(1, UATTR(1), 0, BUF( "\xcc\xcc", 2)),
|
|
LFSR_ATTR(1, REG, +1, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(1, UATTR(1), 0, BUF( "\xbb\xbb", 2)))) => 0;
|
|
|
|
assert(rbyd.weight == 3);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 1, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 1, LFSR_TAG_UATTR(1), buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 2, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 2, LFSR_TAG_UATTR(1), buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xcc\xcc", 2) == 0);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
assert(rbyd.weight == 3);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 1, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 1, LFSR_TAG_UATTR(1), buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 2, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 2, LFSR_TAG_UATTR(1), 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,
|
|
.eoff = 0,
|
|
.cksum = 0,
|
|
.trunk = 0,
|
|
.weight = 0,
|
|
};
|
|
lfsr_rbyd_t rbyd;
|
|
uint8_t buffer[4];
|
|
|
|
// try to create one rid
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(0, REG, +1, BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(0, UATTR(1), 0, BUF( "\xaa\xaa", 2)))) => 0;
|
|
|
|
assert(rbyd.weight == 1);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
assert(rbyd.weight == 1);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), 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_ATTRS(
|
|
LFSR_ATTR(0, REG, +1, BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(0, UATTR(1), 0, BUF( "\xaa\xaa", 2)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(1, REG, +1, BUF("\xbb\xbb\xbb\xbb", 4)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(1, UATTR(1), 0, BUF( "\xbb\xbb", 2)))) => 0;
|
|
|
|
assert(rbyd.weight == 2);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 1, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 1, LFSR_TAG_UATTR(1), buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
assert(rbyd.weight == 2);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 1, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 1, LFSR_TAG_UATTR(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_ATTRS(
|
|
LFSR_ATTR(0, REG, +1, BUF("\xbb\xbb\xbb\xbb", 4)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(0, UATTR(1), 0, BUF( "\xbb\xbb", 2)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(0, REG, +1, BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(0, UATTR(1), 0, BUF( "\xaa\xaa", 2)))) => 0;
|
|
|
|
assert(rbyd.weight == 2);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 1, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 1, LFSR_TAG_UATTR(1), buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
assert(rbyd.weight == 2);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 1, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 1, LFSR_TAG_UATTR(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_ATTRS(
|
|
LFSR_ATTR(0, REG, +1, BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(0, UATTR(1), 0, BUF( "\xaa\xaa", 2)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(1, REG, +1, BUF("\xbb\xbb\xbb\xbb", 4)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(1, UATTR(1), 0, BUF( "\xbb\xbb", 2)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(2, REG, +1, BUF("\xcc\xcc\xcc\xcc", 4)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(2, UATTR(1), 0, BUF( "\xcc\xcc", 2)))) => 0;
|
|
|
|
assert(rbyd.weight == 3);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 1, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 2, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
assert(rbyd.weight == 3);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 1, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 2, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
|
|
|
|
assert(rbyd.weight == 3);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 1, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 1, LFSR_TAG_UATTR(1), buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 2, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 2, LFSR_TAG_UATTR(1), buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xcc\xcc", 2) == 0);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
assert(rbyd.weight == 3);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 1, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 1, LFSR_TAG_UATTR(1), buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 2, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 2, LFSR_TAG_UATTR(1), 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_ATTRS(
|
|
LFSR_ATTR(0, REG, +1, BUF("\xbb\xbb\xbb\xbb", 4)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(0, UATTR(1), 0, BUF( "\xbb\xbb", 2)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(1, REG, +1, BUF("\xcc\xcc\xcc\xcc", 4)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(1, UATTR(1), 0, BUF( "\xcc\xcc", 2)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(0, REG, +1, BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(0, UATTR(1), 0, BUF( "\xaa\xaa", 2)))) => 0;
|
|
|
|
assert(rbyd.weight == 3);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 1, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 1, LFSR_TAG_UATTR(1), buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 2, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 2, LFSR_TAG_UATTR(1), buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xcc\xcc", 2) == 0);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
assert(rbyd.weight == 3);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 1, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 1, LFSR_TAG_UATTR(1), buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 2, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 2, LFSR_TAG_UATTR(1), 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_ATTRS(
|
|
LFSR_ATTR(0, REG, +1, BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(0, UATTR(1), 0, BUF( "\xaa\xaa", 2)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(1, REG, +1, BUF("\xcc\xcc\xcc\xcc", 4)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(1, UATTR(1), 0, BUF( "\xcc\xcc", 2)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(1, REG, +1, BUF("\xbb\xbb\xbb\xbb", 4)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(1, UATTR(1), 0, BUF( "\xbb\xbb", 2)))) => 0;
|
|
|
|
assert(rbyd.weight == 3);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 1, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 1, LFSR_TAG_UATTR(1), buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 2, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 2, LFSR_TAG_UATTR(1), buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xcc\xcc", 2) == 0);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
assert(rbyd.weight == 3);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 1, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 1, LFSR_TAG_UATTR(1), buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 2, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 2, LFSR_TAG_UATTR(1), 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)'
|
|
# -1 => exhaust all permutations
|
|
# n => reproduce a specific permutation
|
|
defines.PERMUTATION = -1
|
|
in = 'lfs.c'
|
|
code = '''
|
|
lfs_t lfs;
|
|
lfs_init(&lfs, CFG) => 0;
|
|
|
|
lfsr_rbyd_t init_rbyd = {
|
|
.block = 0,
|
|
.eoff = 0,
|
|
.cksum = 0,
|
|
.trunk = 0,
|
|
.weight = 0,
|
|
};
|
|
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;
|
|
size_t worst_perm_i = 0;
|
|
|
|
// test all permutations of a given size
|
|
size_t perm_count = TEST_FACTORIAL(N);
|
|
for (size_t i = 0;
|
|
i < (PERMUTATION == -1 ? perm_count : 1);
|
|
i++) {
|
|
uint32_t perm[N];
|
|
size_t perm_i = PERMUTATION == -1 ? i : (size_t)PERMUTATION;
|
|
TEST_PERMUTATION(perm_i, perm, N);
|
|
|
|
// print permutation to help debugging
|
|
printf("--- permutation: %zd [", perm_i);
|
|
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[(1+M)*N];
|
|
for (unsigned j = 0; j < N; j++) {
|
|
// adjust rid based on future insertions
|
|
uint16_t rid = perm[j];
|
|
for (unsigned k = j+1; k < N; k++) {
|
|
if (perm[j] > perm[k]) {
|
|
rid -= 1;
|
|
}
|
|
}
|
|
|
|
attrs[(1+M)*j] = LFSR_ATTR(rid, REG, +1,
|
|
BUF(names[perm[j] % 6], 4));
|
|
// note uattrs have a smaller size to help debugging
|
|
for (unsigned u = 0; u < M; u++) {
|
|
attrs[(1+M)*j+1+u] = LFSR_ATTR(rid, UATTR(u+1), 0,
|
|
BUF(names[perm[j] % 6], 2));
|
|
}
|
|
}
|
|
|
|
// test the given permutation
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, attrs, (1+M)*N) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
assert(rbyd.weight == N);
|
|
for (unsigned j = 0; j < N; j++) {
|
|
lfsr_rbyd_get(&lfs, &rbyd, j, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, names[j % 6], 4) == 0);
|
|
|
|
for (unsigned u = 0; u < M; u++) {
|
|
lfsr_rbyd_get(&lfs, &rbyd, j, LFSR_TAG_UATTR(u+1), buffer, 4)
|
|
=> 2;
|
|
assert(memcmp(buffer, names[j % 6], 2) == 0);
|
|
}
|
|
}
|
|
|
|
// keep track of the worst size
|
|
if (rbyd.eoff > worst_size) {
|
|
worst_size = rbyd.eoff;
|
|
worst_perm_i = perm_i;
|
|
}
|
|
}
|
|
|
|
// 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("--- summary ---\n");
|
|
printf("worst permutation: %zd\n", worst_perm_i);
|
|
printf("worst size: %u B (N=%u, estimate=%u)\n",
|
|
worst_size, n, 12*n*(2*lfs_nlog2(n)+1)+4);
|
|
printf("worst 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)'
|
|
# -1 => exhaust all permutations
|
|
# n => reproduce a specific permutation
|
|
defines.PERMUTATION = -1
|
|
# 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,
|
|
.eoff = 0,
|
|
.cksum = 0,
|
|
.trunk = 0,
|
|
.weight = 0,
|
|
};
|
|
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;
|
|
size_t worst_perm_i = 0;
|
|
|
|
// test all permutations of a given size
|
|
size_t perm_count = TEST_FACTORIAL(N);
|
|
for (size_t i = 0;
|
|
i < (PERMUTATION == -1 ? perm_count : 1);
|
|
i++) {
|
|
uint32_t perm[N];
|
|
size_t perm_i = PERMUTATION == -1 ? i : (size_t)PERMUTATION;
|
|
TEST_PERMUTATION(perm_i, perm, N);
|
|
|
|
// print permutation to help debugging
|
|
printf("--- permutation: %zd [", perm_i);
|
|
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 rid based on future insertions
|
|
uint16_t rid = perm[j];
|
|
for (unsigned k = j+1; k < N; k++) {
|
|
if (perm[j] > perm[k]) {
|
|
rid -= 1;
|
|
}
|
|
}
|
|
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(rid, REG, +1, BUF(names[perm[j] % 6], 4)))) => 0;
|
|
// note uattrs have a smaller size to help debugging
|
|
for (unsigned u = 0; u < M; u++) {
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(rid, UATTR(u+1), 0,
|
|
BUF(names[perm[j] % 6], 2)))) => 0;
|
|
}
|
|
}
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
assert(rbyd.weight == N);
|
|
for (unsigned j = 0; j < N; j++) {
|
|
lfsr_rbyd_get(&lfs, &rbyd, j, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, names[j % 6], 4) == 0);
|
|
|
|
for (unsigned u = 0; u < M; u++) {
|
|
lfsr_rbyd_get(&lfs, &rbyd, j, LFSR_TAG_UATTR(u+1), buffer, 4)
|
|
=> 2;
|
|
assert(memcmp(buffer, names[j % 6], 2) == 0);
|
|
}
|
|
}
|
|
|
|
// keep track of the worst size
|
|
if (rbyd.eoff > worst_size) {
|
|
worst_size = rbyd.eoff;
|
|
worst_perm_i = perm_i;
|
|
}
|
|
}
|
|
|
|
// 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("--- summary ---\n");
|
|
printf("worst permutation: %zd\n", worst_perm_i);
|
|
printf("worst size: %u B (N=%u, estimate=%u)\n",
|
|
worst_size, n, 12*n*(2*lfs_nlog2(n)+1)+4);
|
|
printf("worst 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,
|
|
.eoff = 0,
|
|
.cksum = 0,
|
|
.trunk = 0,
|
|
.weight = 0,
|
|
};
|
|
lfsr_rbyd_t rbyd;
|
|
lfsr_tag_t tag_;
|
|
lfs_ssize_t rid_;
|
|
lfsr_data_t data_;
|
|
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_ATTRS(
|
|
LFSR_ATTR(0, REG, +1, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(0, UATTR(1), 0, BUF( "\xaa\xaa", 2)),
|
|
LFSR_ATTR(1, REG, +1, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(1, UATTR(1), 0, BUF( "\xbb\xbb", 2)))) => 0;
|
|
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, 0,
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 0);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_get(&lfs, &rbyd, rid_, tag_, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == 0);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
lfsr_rbyd_get(&lfs, &rbyd, rid_, tag_, buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_get(&lfs, &rbyd, rid_, tag_, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == 1);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
lfsr_rbyd_get(&lfs, &rbyd, rid_, tag_, buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, 0,
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 0);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_get(&lfs, &rbyd, rid_, tag_, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == 0);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
lfsr_rbyd_get(&lfs, &rbyd, rid_, tag_, buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_get(&lfs, &rbyd, rid_, tag_, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == 1);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
lfsr_rbyd_get(&lfs, &rbyd, rid_, tag_, buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
|
|
|
|
// also try the other direction
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(0, REG, +1, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(0, UATTR(1), 0, BUF( "\xbb\xbb", 2)),
|
|
LFSR_ATTR(0, REG, +1, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(0, UATTR(1), 0, BUF( "\xaa\xaa", 2)))) => 0;
|
|
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, 0,
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 0);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_get(&lfs, &rbyd, rid_, tag_, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == 0);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
lfsr_rbyd_get(&lfs, &rbyd, rid_, tag_, buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_get(&lfs, &rbyd, rid_, tag_, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == 1);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
lfsr_rbyd_get(&lfs, &rbyd, rid_, tag_, buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, 0,
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 0);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_get(&lfs, &rbyd, rid_, tag_, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == 0);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
lfsr_rbyd_get(&lfs, &rbyd, rid_, tag_, buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_get(&lfs, &rbyd, rid_, tag_, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == 1);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
lfsr_rbyd_get(&lfs, &rbyd, rid_, tag_, buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, NULL, &data_) => 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,
|
|
.eoff = 0,
|
|
.cksum = 0,
|
|
.trunk = 0,
|
|
.weight = 0,
|
|
};
|
|
lfsr_rbyd_t rbyd;
|
|
lfsr_tag_t tag_;
|
|
lfs_ssize_t rid_;
|
|
lfsr_data_t data_;
|
|
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_ATTRS(
|
|
LFSR_ATTR(0, REG, +1, BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(0, UATTR(1), 0, BUF( "\xaa\xaa", 2)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(1, REG, +1, BUF("\xbb\xbb\xbb\xbb", 4)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(1, UATTR(1), 0, BUF( "\xbb\xbb", 2)))) => 0;
|
|
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, 0,
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 0);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_get(&lfs, &rbyd, rid_, tag_, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == 0);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
lfsr_rbyd_get(&lfs, &rbyd, rid_, tag_, buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_get(&lfs, &rbyd, rid_, tag_, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == 1);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
lfsr_rbyd_get(&lfs, &rbyd, rid_, tag_, buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, 0,
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 0);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_get(&lfs, &rbyd, rid_, tag_, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == 0);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
lfsr_rbyd_get(&lfs, &rbyd, rid_, tag_, buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_get(&lfs, &rbyd, rid_, tag_, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == 1);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
lfsr_rbyd_get(&lfs, &rbyd, rid_, tag_, buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
|
|
|
|
// also try the other direction
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(0, REG, +1, BUF("\xbb\xbb\xbb\xbb", 4)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(0, UATTR(1), 0, BUF( "\xbb\xbb", 2)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(0, REG, +1, BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(0, UATTR(1), 0, BUF( "\xaa\xaa", 2)))) => 0;
|
|
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, 0,
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 0);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_get(&lfs, &rbyd, rid_, tag_, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == 0);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
lfsr_rbyd_get(&lfs, &rbyd, rid_, tag_, buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_get(&lfs, &rbyd, rid_, tag_, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == 1);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
lfsr_rbyd_get(&lfs, &rbyd, rid_, tag_, buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, 0,
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 0);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_get(&lfs, &rbyd, rid_, tag_, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == 0);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
lfsr_rbyd_get(&lfs, &rbyd, rid_, tag_, buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_get(&lfs, &rbyd, rid_, tag_, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == 1);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
lfsr_rbyd_get(&lfs, &rbyd, rid_, tag_, buffer, 4) => 2;
|
|
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
|
|
'''
|
|
|
|
[cases.test_rbyd_mixed_traverse_permutations]
|
|
defines.N = 'range(1, 7)'
|
|
defines.M = 'range(1, 4)'
|
|
# -1 => exhaust all permutations
|
|
# n => reproduce a specific permutation
|
|
defines.PERMUTATION = -1
|
|
in = 'lfs.c'
|
|
code = '''
|
|
lfs_t lfs;
|
|
lfs_init(&lfs, CFG) => 0;
|
|
|
|
lfsr_rbyd_t init_rbyd = {
|
|
.block = 0,
|
|
.eoff = 0,
|
|
.cksum = 0,
|
|
.trunk = 0,
|
|
.weight = 0,
|
|
};
|
|
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 rid_;
|
|
lfsr_data_t data_;
|
|
uint8_t buffer[4];
|
|
|
|
// test all permutations of a given size
|
|
size_t perm_count = TEST_FACTORIAL(N);
|
|
for (size_t i = 0;
|
|
i < (PERMUTATION == -1 ? perm_count : 1);
|
|
i++) {
|
|
uint32_t perm[N];
|
|
size_t perm_i = PERMUTATION == -1 ? i : (size_t)PERMUTATION;
|
|
TEST_PERMUTATION(perm_i, perm, N);
|
|
|
|
// print permutation to help debugging
|
|
printf("--- permutation: %zd [", perm_i);
|
|
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[(1+M)*N];
|
|
for (unsigned j = 0; j < N; j++) {
|
|
// adjust rid based on future insertions
|
|
uint16_t rid = perm[j];
|
|
for (unsigned k = j+1; k < N; k++) {
|
|
if (perm[j] > perm[k]) {
|
|
rid -= 1;
|
|
}
|
|
}
|
|
|
|
attrs[(1+M)*j] = LFSR_ATTR(rid, REG, +1,
|
|
BUF(names[perm[j] % 6], 4));
|
|
// note uattrs have a smaller size to help debugging
|
|
for (unsigned u = 0; u < M; u++) {
|
|
attrs[(1+M)*j+1+u] = LFSR_ATTR(rid, UATTR(u+1), 0,
|
|
BUF(names[perm[j] % 6], 2));
|
|
}
|
|
}
|
|
|
|
// test the given permutation
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, attrs, (1+M)*N) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
assert(rbyd.weight == N);
|
|
|
|
// try traversing all tags
|
|
tag_ = 0;
|
|
rid_ = -1;
|
|
for (unsigned j = 0; j < N; j++) {
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == j);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
|
|
lfsr_rbyd_get(&lfs, &rbyd, rid_, tag_, buffer, 4) => 4;
|
|
assert(memcmp(buffer, names[j % 6], 4) == 0);
|
|
|
|
for (unsigned u = 0; u < M; u++) {
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(u+1));
|
|
assert(rid_ == j);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
|
|
lfsr_rbyd_get(&lfs, &rbyd, rid_, tag_, buffer, 4) => 2;
|
|
assert(memcmp(buffer, names[j % 6], 2) == 0);
|
|
}
|
|
}
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
|
|
}
|
|
'''
|
|
|
|
[cases.test_rbyd_multi_mixed_traverse_permutations]
|
|
defines.N = 'range(1, 7)'
|
|
defines.M = 'range(1, 4)'
|
|
# -1 => exhaust all permutations
|
|
# n => reproduce a specific permutation
|
|
defines.PERMUTATION = -1
|
|
# 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,
|
|
.eoff = 0,
|
|
.cksum = 0,
|
|
.trunk = 0,
|
|
.weight = 0,
|
|
};
|
|
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 rid_;
|
|
lfsr_data_t data_;
|
|
uint8_t buffer[4];
|
|
|
|
// test all permutations of a given size
|
|
size_t perm_count = TEST_FACTORIAL(N);
|
|
for (size_t i = 0;
|
|
i < (PERMUTATION == -1 ? perm_count : 1);
|
|
i++) {
|
|
uint32_t perm[N];
|
|
size_t perm_i = PERMUTATION == -1 ? i : (size_t)PERMUTATION;
|
|
TEST_PERMUTATION(perm_i, perm, N);
|
|
|
|
// print permutation to help debugging
|
|
printf("--- permutation: %zd [", perm_i);
|
|
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 rid based on future insertions
|
|
uint16_t rid = perm[j];
|
|
for (unsigned k = j+1; k < N; k++) {
|
|
if (perm[j] > perm[k]) {
|
|
rid -= 1;
|
|
}
|
|
}
|
|
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(rid, REG, +1, BUF(names[perm[j] % 6], 4)))) => 0;
|
|
// note uattrs have a smaller size to help debugging
|
|
for (unsigned u = 0; u < M; u++) {
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(rid, UATTR(u+1), 0,
|
|
BUF(names[perm[j] % 6], 2)))) => 0;
|
|
}
|
|
}
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
assert(rbyd.weight == N);
|
|
|
|
// try traversing all tags
|
|
tag_ = 0;
|
|
rid_ = -1;
|
|
for (unsigned j = 0; j < N; j++) {
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == j);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
|
|
lfsr_rbyd_get(&lfs, &rbyd, rid_, tag_, buffer, 4) => 4;
|
|
assert(memcmp(buffer, names[j % 6], 4) == 0);
|
|
|
|
for (unsigned u = 0; u < M; u++) {
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(u+1));
|
|
assert(rid_ == j);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
|
|
lfsr_rbyd_get(&lfs, &rbyd, rid_, tag_, buffer, 4) => 2;
|
|
assert(memcmp(buffer, names[j % 6], 2) == 0);
|
|
}
|
|
}
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, NULL, &data_) => 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_mixed_update_permutations]
|
|
defines.N = 'range(1, 4)'
|
|
defines.M = 'range(1, 3)'
|
|
# -1 => exhaust all permutations
|
|
# n => reproduce a specific permutation
|
|
defines.PERMUTATION = -1
|
|
# 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,
|
|
.eoff = 0,
|
|
.cksum = 0,
|
|
.trunk = 0,
|
|
.weight = 0,
|
|
};
|
|
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;
|
|
size_t worst_perm_i = 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_ATTRS(
|
|
LFSR_ATTR(j, REG, +1, BUF(names[j % 6], 4)))) => 0;
|
|
// note uattrs have a smaller size to help debugging
|
|
for (unsigned u = 0; u < M; u++) {
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(j, UATTR(u+1), 0, BUF(names[j % 6], 2)))) => 0;
|
|
}
|
|
}
|
|
|
|
// copy block so we can reset after each remove
|
|
lfsr_rbyd_t backup_rbyd = rbyd;
|
|
uint8_t *backup_block = malloc(rbyd.eoff);
|
|
lfs_bd_read(&lfs, NULL, &lfs.rcache, rbyd.eoff,
|
|
rbyd.block, 0, backup_block, rbyd.eoff) => 0;
|
|
|
|
// test all permutations of a given size
|
|
size_t perm_count = TEST_FACTORIAL(N*M);
|
|
for (size_t i = 0;
|
|
i < (PERMUTATION == -1 ? perm_count : 1);
|
|
i++) {
|
|
uint32_t perm[N*M];
|
|
size_t perm_i = PERMUTATION == -1 ? i : (size_t)PERMUTATION;
|
|
TEST_PERMUTATION(perm_i, perm, N*M);
|
|
|
|
// print permutation to help debugging
|
|
printf("--- permutation: %zd [", perm_i);
|
|
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.eoff) => 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_ATTRS(
|
|
LFSR_ATTR(perm[j]/M, UATTR(perm[j]%M+1), 0,
|
|
BUF(names[(perm[j]/M) % 6], 3)))) => 0;
|
|
}
|
|
|
|
// check that all tags have been updated
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
for (unsigned j = 0; j < N; j++) {
|
|
lfsr_rbyd_get(&lfs, &rbyd, j, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, names[j % 6], 4) == 0);
|
|
|
|
for (unsigned u = 0; u < M; u++) {
|
|
lfsr_rbyd_get(&lfs, &rbyd, j, LFSR_TAG_UATTR(u+1), buffer, 4)
|
|
=> 3;
|
|
assert(memcmp(buffer, names[j % 6], 3) == 0);
|
|
}
|
|
}
|
|
|
|
// keep track of the worst size
|
|
if (rbyd.eoff > worst_size) {
|
|
worst_size = rbyd.eoff;
|
|
worst_perm_i = perm_i;
|
|
}
|
|
}
|
|
|
|
// 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("--- summary ---\n");
|
|
printf("worst permutation: %zd\n", worst_perm_i);
|
|
printf("worst size: %u B (N=%u, estimate=%u)\n",
|
|
worst_size, n, 12*n*(2*lfs_nlog2(n)+1)+4);
|
|
printf("worst 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)'
|
|
# -1 => exhaust all permutations
|
|
# n => reproduce a specific permutation
|
|
defines.PERMUTATION = -1
|
|
# 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,
|
|
.eoff = 0,
|
|
.cksum = 0,
|
|
.trunk = 0,
|
|
.weight = 0,
|
|
};
|
|
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 rid_;
|
|
lfsr_data_t data_;
|
|
uint8_t buffer[4];
|
|
|
|
// keep track of the worst case log size
|
|
lfs_size_t worst_size = 0;
|
|
size_t worst_perm_i = 0;
|
|
|
|
// test all permutations of a given size
|
|
size_t perm_count = TEST_FACTORIAL(N);
|
|
for (size_t i = 0;
|
|
i < (PERMUTATION == -1 ? perm_count : 1);
|
|
i++) {
|
|
uint32_t perm[N];
|
|
size_t perm_i = PERMUTATION == -1 ? i : (size_t)PERMUTATION;
|
|
TEST_PERMUTATION(perm_i, perm, N);
|
|
|
|
// print permutation to help debugging
|
|
printf("--- permutation: %zd [", perm_i);
|
|
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 rid based on future insertions
|
|
uint16_t rid = perm[j];
|
|
for (unsigned k = j+1; k < N; k++) {
|
|
if (perm[j] > perm[k]) {
|
|
rid -= 1;
|
|
}
|
|
}
|
|
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(rid, REG, +1, BUF(names[perm[j] % 6], 4)))) => 0;
|
|
// note uattrs have a smaller size to help debugging
|
|
for (unsigned u = 0; u < M; u++) {
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(rid, UATTR(u+1), 0,
|
|
BUF(names[perm[j] % 6], 2)))) => 0;
|
|
}
|
|
}
|
|
|
|
// copy block so we can reset after each remove
|
|
lfsr_rbyd_t backup_rbyd = rbyd;
|
|
uint8_t *backup_block = malloc(rbyd.eoff);
|
|
lfs_bd_read(&lfs, NULL, &lfs.rcache, rbyd.eoff,
|
|
rbyd.block, 0, backup_block, rbyd.eoff) => 0;
|
|
|
|
// try removing each tag
|
|
for (unsigned j = 0; j < N*M; j++) {
|
|
// print what we are removing to help debugging
|
|
printf("--- remove: rid%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.eoff) => 0;
|
|
lfs_bd_flush(&lfs, &lfs.pcache, &lfs.rcache, false) => 0;
|
|
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(j/M, RM(UATTR((j%M)+1)), 0, NULL()))) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, CFG->block_size) => 0;
|
|
for (unsigned k = 0; k < N; k++) {
|
|
lfsr_rbyd_get(&lfs, &rbyd, k, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, names[k % 6], 4) == 0);
|
|
|
|
for (unsigned u = 0; u < M; u++) {
|
|
int err = lfsr_rbyd_lookupnext(&lfs, &rbyd,
|
|
k, LFSR_TAG_UATTR(u+1),
|
|
&rid_, &tag_, NULL, &data_);
|
|
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_REG);
|
|
assert(rid_ == k+1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
} else {
|
|
assert(!err);
|
|
assert(tag_ == LFSR_TAG_UATTR(u+1+1));
|
|
assert(rid_ == k);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
}
|
|
} else {
|
|
assert(tag_ == LFSR_TAG_UATTR(u+1));
|
|
assert(rid_ == k);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
|
|
lfsr_rbyd_get(&lfs, &rbyd, rid_, tag_, buffer, 4) => 2;
|
|
assert(memcmp(buffer, names[k % 6], 2) == 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
// try append the tag back to make sure things still work
|
|
printf("--- append: rid%jd, %jd ---\n", j/M, (j%M)+1);
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(j/M, UATTR((j%M)+1), 0,
|
|
BUF(names[(j/M)%6], 3)))) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, CFG->block_size) => 0;
|
|
for (unsigned k = 0; k < N; k++) {
|
|
lfsr_rbyd_get(&lfs, &rbyd, k, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, names[k % 6], 4) == 0);
|
|
|
|
for (unsigned u = 0; u < M; u++) {
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd,
|
|
k, LFSR_TAG_UATTR(u+1),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
if (k == j/M && u == j%M) {
|
|
assert(tag_ == LFSR_TAG_UATTR(u+1));
|
|
assert(rid_ == k);
|
|
assert(lfsr_data_size(&data_) == 3);
|
|
|
|
lfsr_rbyd_get(&lfs, &rbyd, rid_, tag_, buffer, 4) => 3;
|
|
assert(memcmp(buffer, names[k % 6], 3) == 0);
|
|
} else {
|
|
assert(tag_ == LFSR_TAG_UATTR(u+1));
|
|
assert(rid_ == k);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
|
|
lfsr_rbyd_get(&lfs, &rbyd, rid_, tag_, buffer, 4) => 2;
|
|
assert(memcmp(buffer, names[k % 6], 2) == 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
// keep track of the worst size
|
|
if (rbyd.eoff > worst_size) {
|
|
worst_size = rbyd.eoff;
|
|
worst_perm_i = perm_i;
|
|
}
|
|
}
|
|
|
|
// 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 + 2;
|
|
printf("--- summary ---\n");
|
|
printf("worst permutation: %zd\n", worst_perm_i);
|
|
printf("worst size: %u B (N=%u, estimate=%u)\n",
|
|
worst_size, n, 12*n*(2*lfs_nlog2(n)+1)+4);
|
|
printf("worst 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)'
|
|
# -1 => exhaust all permutations
|
|
# n => reproduce a specific permutation
|
|
defines.PERMUTATION = -1
|
|
# 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,
|
|
.eoff = 0,
|
|
.cksum = 0,
|
|
.trunk = 0,
|
|
.weight = 0,
|
|
};
|
|
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;
|
|
size_t worst_perm_i = 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_ATTRS(
|
|
LFSR_ATTR(j, REG, +1, BUF(names[j % 6], 4)))) => 0;
|
|
// note uattrs have a smaller size to help debugging
|
|
for (unsigned u = 0; u < M; u++) {
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(j, UATTR(u+1), 0, BUF(names[j % 6], 2)))) => 0;
|
|
}
|
|
}
|
|
|
|
// copy block so we can reset after each remove
|
|
lfsr_rbyd_t backup_rbyd = rbyd;
|
|
uint8_t *backup_block = malloc(rbyd.eoff);
|
|
lfs_bd_read(&lfs, NULL, &lfs.rcache, rbyd.eoff,
|
|
rbyd.block, 0, backup_block, rbyd.eoff) => 0;
|
|
|
|
// test all permutations of a given size
|
|
size_t perm_count = TEST_FACTORIAL(N*M);
|
|
for (size_t i = 0;
|
|
i < (PERMUTATION == -1 ? perm_count : 1);
|
|
i++) {
|
|
uint32_t perm[N*M];
|
|
size_t perm_i = PERMUTATION == -1 ? i : (size_t)PERMUTATION;
|
|
TEST_PERMUTATION(perm_i, perm, N*M);
|
|
|
|
// print permutation to help debugging
|
|
printf("--- permutation: %zd [", perm_i);
|
|
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.eoff) => 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_ATTRS(
|
|
LFSR_ATTR(perm[j]/M, RM(UATTR(perm[j]%M+1)),
|
|
0, NULL()))) => 0;
|
|
}
|
|
|
|
// check that all tags have been removed
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
for (unsigned j = 0; j < N; j++) {
|
|
lfsr_rbyd_get(&lfs, &rbyd, j, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, names[j % 6], 4) == 0);
|
|
|
|
for (unsigned u = 0; u < M; u++) {
|
|
lfsr_rbyd_get(&lfs, &rbyd, j, LFSR_TAG_UATTR(u+1), buffer, 4)
|
|
=> LFS_ERR_NOENT;
|
|
}
|
|
}
|
|
|
|
// keep track of the worst size
|
|
if (rbyd.eoff > worst_size) {
|
|
worst_size = rbyd.eoff;
|
|
worst_perm_i = perm_i;
|
|
}
|
|
}
|
|
|
|
// 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("--- summary ---\n");
|
|
printf("worst permutation: %zd\n", worst_perm_i);
|
|
printf("worst size: %u B (N=%u, estimate=%u)\n",
|
|
worst_size, n, 12*n*(2*lfs_nlog2(n)+1)+4);
|
|
printf("worst 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,
|
|
.eoff = 0,
|
|
.cksum = 0,
|
|
.trunk = 0,
|
|
.weight = 0,
|
|
};
|
|
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[1+M];
|
|
attrs[0] = LFSR_ATTR(x, REG, +1, BUF(names[x % 6], 4));
|
|
for (unsigned u = 0; u < M; u++) {
|
|
attrs[1+u] = LFSR_ATTR(x, UATTR(u+1), 0, BUF(names[x % 6], 2));
|
|
}
|
|
|
|
int err = lfsr_rbyd_commit(&lfs, &rbyd, attrs, 1+M);
|
|
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 rid_;
|
|
lfsr_data_t data_;
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
for (uint16_t x = 0; x < rbyd.weight; x++) {
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, x, LFSR_TAG_REG,
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == x);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
|
|
for (unsigned u = 0; u < M; u++) {
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, x, LFSR_TAG_UATTR(u+1),
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(u+1));
|
|
assert(rid_ == x);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
}
|
|
}
|
|
'''
|
|
|
|
|
|
### Test unrelated no-rid tags ###
|
|
|
|
[cases.test_rbyd_unrelated_create_permutations]
|
|
defines.N = 'range(1, 8)'
|
|
# -1 => exhaust all permutations
|
|
# n => reproduce a specific permutation
|
|
defines.PERMUTATION = -1
|
|
# 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,
|
|
.eoff = 0,
|
|
.cksum = 0,
|
|
.trunk = 0,
|
|
.weight = 0,
|
|
};
|
|
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;
|
|
size_t worst_perm_i = 0;
|
|
|
|
// test all permutations of a given size
|
|
size_t perm_count = TEST_FACTORIAL(N);
|
|
for (size_t i = 0;
|
|
i < (PERMUTATION == -1 ? perm_count : 1);
|
|
i++) {
|
|
uint32_t perm[N];
|
|
size_t perm_i = PERMUTATION == -1 ? i : (size_t)PERMUTATION;
|
|
TEST_PERMUTATION(perm_i, perm, N);
|
|
|
|
// print permutation to help debugging
|
|
printf("--- permutation: %zd [", perm_i);
|
|
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 rid based on future insertions
|
|
uint16_t rid = perm[j];
|
|
for (unsigned k = j+1; k < N; k++) {
|
|
if (perm[j] > perm[k]) {
|
|
rid -= 1;
|
|
}
|
|
}
|
|
|
|
// note the data size differences here
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(-1, UATTR(perm[j]+1), 0,
|
|
BUF(names[perm[j] % 6], 1)))) => 0;
|
|
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(rid, REG, +1,
|
|
BUF(names[perm[j] % 6], 4)))) => 0;
|
|
}
|
|
|
|
// try looking up each tag
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
assert(rbyd.weight == N);
|
|
for (unsigned j = 0; j < N; j++) {
|
|
lfsr_rbyd_get(&lfs, &rbyd,
|
|
-1, LFSR_TAG_UATTR(j+1), buffer, 4) => 1;
|
|
assert(memcmp(buffer, names[j % 6], 1) == 0);
|
|
}
|
|
for (unsigned j = 0; j < N; j++) {
|
|
lfsr_rbyd_get(&lfs, &rbyd,
|
|
j, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, names[j % 6], 4) == 0);
|
|
}
|
|
|
|
// try traversing tags
|
|
lfsr_tag_t tag_ = 0;
|
|
lfs_ssize_t rid_ = -1;
|
|
lfsr_data_t data_;
|
|
for (unsigned j = 0; j < N; j++) {
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(j+1));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 1);
|
|
|
|
lfsr_rbyd_get(&lfs, &rbyd, rid_, tag_, buffer, 4) => 1;
|
|
assert(memcmp(buffer, names[j % 6], 1) == 0);
|
|
}
|
|
for (unsigned j = 0; j < N; j++) {
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == j);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
|
|
lfsr_rbyd_get(&lfs, &rbyd, rid_, tag_, buffer, 4) => 4;
|
|
assert(memcmp(buffer, names[j % 6], 4) == 0);
|
|
}
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
|
|
|
|
// keep track of the worst size
|
|
if (rbyd.eoff > worst_size) {
|
|
worst_size = rbyd.eoff;
|
|
worst_perm_i = perm_i;
|
|
}
|
|
}
|
|
|
|
// 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("--- summary ---\n");
|
|
printf("worst permutation: %zd\n", worst_perm_i);
|
|
printf("worst size: %u B (N=%u, estimate=%u)\n",
|
|
worst_size, n, 12*n*(2*lfs_nlog2(n)+1)+4);
|
|
printf("worst 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_unrelated_mixed_permutations]
|
|
defines.N = 'range(1, 7)'
|
|
defines.M = 'range(1, 4)'
|
|
# -1 => exhaust all permutations
|
|
# n => reproduce a specific permutation
|
|
defines.PERMUTATION = -1
|
|
# 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,
|
|
.eoff = 0,
|
|
.cksum = 0,
|
|
.trunk = 0,
|
|
.weight = 0,
|
|
};
|
|
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;
|
|
size_t worst_perm_i = 0;
|
|
|
|
// test all permutations of a given size
|
|
size_t perm_count = TEST_FACTORIAL(N);
|
|
for (size_t i = 0;
|
|
i < (PERMUTATION == -1 ? perm_count : 1);
|
|
i++) {
|
|
uint32_t perm[N];
|
|
size_t perm_i = PERMUTATION == -1 ? i : (size_t)PERMUTATION;
|
|
TEST_PERMUTATION(perm_i, perm, N);
|
|
|
|
// print permutation to help debugging
|
|
printf("--- permutation: %zd [", perm_i);
|
|
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 rid based on future insertions
|
|
uint16_t rid = perm[j];
|
|
for (unsigned k = j+1; k < N; k++) {
|
|
if (perm[j] > perm[k]) {
|
|
rid -= 1;
|
|
}
|
|
}
|
|
|
|
// note the data size differences here
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(-1, UATTR(perm[j]+1), 0,
|
|
BUF(names[perm[j] % 6], 1)))) => 0;
|
|
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(rid, REG, +1,
|
|
BUF(names[perm[j] % 6], 4)))) => 0;
|
|
for (unsigned u = 0; u < M; u++) {
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(rid, UATTR(u+1), 0,
|
|
BUF(names[perm[j] % 6], 2)))) => 0;
|
|
}
|
|
}
|
|
|
|
// try looking up each tag
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
assert(rbyd.weight == N);
|
|
for (unsigned j = 0; j < N; j++) {
|
|
lfsr_rbyd_get(&lfs, &rbyd,
|
|
-1, LFSR_TAG_UATTR(j+1), buffer, 4) => 1;
|
|
assert(memcmp(buffer, names[j % 6], 1) == 0);
|
|
}
|
|
for (unsigned j = 0; j < N; j++) {
|
|
lfsr_rbyd_get(&lfs, &rbyd, j, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, names[j % 6], 4) == 0);
|
|
|
|
for (unsigned u = 0; u < M; u++) {
|
|
lfsr_rbyd_get(&lfs, &rbyd, j, LFSR_TAG_UATTR(u+1), buffer, 4)
|
|
=> 2;
|
|
assert(memcmp(buffer, names[j % 6], 2) == 0);
|
|
}
|
|
}
|
|
|
|
// try traversing tags
|
|
lfsr_tag_t tag_ = 0;
|
|
lfs_ssize_t rid_ = -1;
|
|
lfsr_data_t data_;
|
|
for (unsigned j = 0; j < N; j++) {
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(j+1));
|
|
assert(rid_ == -1);
|
|
assert(lfsr_data_size(&data_) == 1);
|
|
|
|
lfsr_rbyd_get(&lfs, &rbyd, rid_, tag_, buffer, 4) => 1;
|
|
assert(memcmp(buffer, names[j % 6], 1) == 0);
|
|
}
|
|
for (unsigned j = 0; j < N; j++) {
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == j);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
|
|
lfsr_rbyd_get(&lfs, &rbyd, rid_, tag_, buffer, 4) => 4;
|
|
assert(memcmp(buffer, names[j % 6], 4) == 0);
|
|
|
|
for (unsigned u = 0; u < M; u++) {
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(u+1));
|
|
assert(rid_ == j);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
|
|
lfsr_rbyd_get(&lfs, &rbyd, rid_, tag_, buffer, 4) => 2;
|
|
assert(memcmp(buffer, names[j % 6], 2) == 0);
|
|
}
|
|
}
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
|
|
|
|
// keep track of the worst size
|
|
if (rbyd.eoff > worst_size) {
|
|
worst_size = rbyd.eoff;
|
|
worst_perm_i = perm_i;
|
|
}
|
|
}
|
|
|
|
// 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("--- summary ---\n");
|
|
printf("worst permutation: %zd\n", worst_perm_i);
|
|
printf("worst size: %u B (N=%u, estimate=%u)\n",
|
|
worst_size, n, 12*n*(2*lfs_nlog2(n)+1)+4);
|
|
printf("worst 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);
|
|
}
|
|
'''
|
|
|
|
|
|
### 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,
|
|
.eoff = 0,
|
|
.cksum = 0,
|
|
.trunk = 0,
|
|
.weight = 0,
|
|
};
|
|
lfsr_rbyd_t rbyd;
|
|
uint8_t buffer[4];
|
|
|
|
// try to delete one rid
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(0, REG, +1, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(1, REG, +1, BUF("\xbb\xbb\xbb\xbb", 4)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(1, RM, -1, NULL()))) => 0;
|
|
|
|
assert(rbyd.weight == 1);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 1, LFSR_TAG_REG, buffer, 4) => LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
assert(rbyd.weight == 1);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 1, LFSR_TAG_REG, buffer, 4) => LFS_ERR_NOENT;
|
|
|
|
// try to delete the other rid
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(0, REG, +1, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(1, REG, +1, BUF("\xbb\xbb\xbb\xbb", 4)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(0, RM, -1, NULL()))) => 0;
|
|
|
|
assert(rbyd.weight == 1);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 1, LFSR_TAG_REG, buffer, 4) => LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
assert(rbyd.weight == 1);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 1, LFSR_TAG_REG, 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_ATTRS(
|
|
LFSR_ATTR(0, REG, +1, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(1, REG, +1, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(2, REG, +1, BUF("\xcc\xcc\xcc\xcc", 4)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(2, RM, -1, NULL()))) => 0;
|
|
|
|
assert(rbyd.weight == 2);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 1, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 2, LFSR_TAG_REG, buffer, 4) => LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 1, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 2, LFSR_TAG_REG, 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_ATTRS(
|
|
LFSR_ATTR(0, REG, +1, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(1, REG, +1, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(2, REG, +1, BUF("\xcc\xcc\xcc\xcc", 4)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(0, RM, -1, NULL()))) => 0;
|
|
|
|
assert(rbyd.weight == 2);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 1, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 2, LFSR_TAG_REG, buffer, 4) => LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 1, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 2, LFSR_TAG_REG, 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_ATTRS(
|
|
LFSR_ATTR(0, REG, +1, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(1, REG, +1, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(2, REG, +1, BUF("\xcc\xcc\xcc\xcc", 4)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(1, RM, -1, NULL()))) => 0;
|
|
|
|
assert(rbyd.weight == 2);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 1, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 2, LFSR_TAG_REG, buffer, 4) => LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 1, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 2, LFSR_TAG_REG, 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,
|
|
.eoff = 0,
|
|
.cksum = 0,
|
|
.trunk = 0,
|
|
.weight = 0,
|
|
};
|
|
lfsr_rbyd_t rbyd;
|
|
uint8_t buffer[4];
|
|
|
|
// try to delete one rid
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(0, REG, +1, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(0, UATTR(1), 0, BUF( "\xaa\xaa", 2)),
|
|
LFSR_ATTR(1, REG, +1, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(1, UATTR(1), 0, BUF( "\xbb\xbb", 2)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(1, RM, -1, NULL()))) => 0;
|
|
|
|
assert(rbyd.weight == 1);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_REG, buffer, 4)
|
|
=> 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), buffer, 4)
|
|
=> 2;
|
|
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 1, LFSR_TAG_REG, buffer, 4)
|
|
=> LFS_ERR_NOENT;
|
|
lfsr_rbyd_get(&lfs, &rbyd, 1, LFSR_TAG_UATTR(1), buffer, 4)
|
|
=> LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
assert(rbyd.weight == 1);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_REG, buffer, 4)
|
|
=> 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), buffer, 4)
|
|
=> 2;
|
|
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 1, LFSR_TAG_REG, buffer, 4)
|
|
=> LFS_ERR_NOENT;
|
|
lfsr_rbyd_get(&lfs, &rbyd, 1, LFSR_TAG_UATTR(1), buffer, 4)
|
|
=> LFS_ERR_NOENT;
|
|
|
|
// try to delete the other rid
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(0, REG, +1, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(0, UATTR(1), 0, BUF( "\xaa\xaa", 2)),
|
|
LFSR_ATTR(1, REG, +1, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(1, UATTR(1), 0, BUF( "\xbb\xbb", 2)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(0, RM, -1, NULL()))) => 0;
|
|
|
|
assert(rbyd.weight == 1);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_REG, buffer, 4)
|
|
=> 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), buffer, 4)
|
|
=> 2;
|
|
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 1, LFSR_TAG_REG, buffer, 4)
|
|
=> LFS_ERR_NOENT;
|
|
lfsr_rbyd_get(&lfs, &rbyd, 1, LFSR_TAG_UATTR(1), buffer, 4)
|
|
=> LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
assert(rbyd.weight == 1);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_REG, buffer, 4)
|
|
=> 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), buffer, 4)
|
|
=> 2;
|
|
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 1, LFSR_TAG_REG, buffer, 4)
|
|
=> LFS_ERR_NOENT;
|
|
lfsr_rbyd_get(&lfs, &rbyd, 1, LFSR_TAG_UATTR(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_ATTRS(
|
|
LFSR_ATTR(0, REG, +1, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(0, UATTR(1), 0, BUF( "\xaa\xaa", 2)),
|
|
LFSR_ATTR(1, REG, +1, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(1, UATTR(1), 0, BUF( "\xbb\xbb", 2)),
|
|
LFSR_ATTR(2, REG, +1, BUF("\xcc\xcc\xcc\xcc", 4)),
|
|
LFSR_ATTR(2, UATTR(1), 0, BUF( "\xcc\xcc", 2)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(2, RM, -1, NULL()))) => 0;
|
|
|
|
assert(rbyd.weight == 2);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), buffer, 4)
|
|
=> 2;
|
|
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 1, LFSR_TAG_REG, buffer, 4)
|
|
=> 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 1, LFSR_TAG_UATTR(1), buffer, 4)
|
|
=> 2;
|
|
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 2, LFSR_TAG_REG, buffer, 4)
|
|
=> LFS_ERR_NOENT;
|
|
lfsr_rbyd_get(&lfs, &rbyd, 2, LFSR_TAG_UATTR(1), buffer, 4)
|
|
=> LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
assert(rbyd.weight == 2);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_REG, buffer, 4)
|
|
=> 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), buffer, 4)
|
|
=> 2;
|
|
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 1, LFSR_TAG_REG, buffer, 4)
|
|
=> 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 1, LFSR_TAG_UATTR(1), buffer, 4)
|
|
=> 2;
|
|
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 2, LFSR_TAG_REG, buffer, 4)
|
|
=> LFS_ERR_NOENT;
|
|
lfsr_rbyd_get(&lfs, &rbyd, 2, LFSR_TAG_UATTR(1), 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_ATTRS(
|
|
LFSR_ATTR(0, REG, +1, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(0, UATTR(1), 0, BUF( "\xaa\xaa", 2)),
|
|
LFSR_ATTR(1, REG, +1, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(1, UATTR(1), 0, BUF( "\xbb\xbb", 2)),
|
|
LFSR_ATTR(2, REG, +1, BUF("\xcc\xcc\xcc\xcc", 4)),
|
|
LFSR_ATTR(2, UATTR(1), 0, BUF( "\xcc\xcc", 2)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(0, RM, -1, NULL()))) => 0;
|
|
|
|
assert(rbyd.weight == 2);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_REG, buffer, 4)
|
|
=> 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), buffer, 4)
|
|
=> 2;
|
|
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 1, LFSR_TAG_REG, buffer, 4)
|
|
=> 4;
|
|
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 1, LFSR_TAG_UATTR(1), buffer, 4)
|
|
=> 2;
|
|
assert(memcmp(buffer, "\xcc\xcc", 2) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 2, LFSR_TAG_REG, buffer, 4)
|
|
=> LFS_ERR_NOENT;
|
|
lfsr_rbyd_get(&lfs, &rbyd, 2, LFSR_TAG_UATTR(1), buffer, 4)
|
|
=> LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
assert(rbyd.weight == 2);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_REG, buffer, 4)
|
|
=> 4;
|
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), buffer, 4)
|
|
=> 2;
|
|
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 1, LFSR_TAG_REG, buffer, 4)
|
|
=> 4;
|
|
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 1, LFSR_TAG_UATTR(1), buffer, 4)
|
|
=> 2;
|
|
assert(memcmp(buffer, "\xcc\xcc", 2) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 2, LFSR_TAG_REG, buffer, 4)
|
|
=> LFS_ERR_NOENT;
|
|
lfsr_rbyd_get(&lfs, &rbyd, 2, LFSR_TAG_UATTR(1), 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_ATTRS(
|
|
LFSR_ATTR(0, REG, +1, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(0, UATTR(1), 0, BUF( "\xaa\xaa", 2)),
|
|
LFSR_ATTR(1, REG, +1, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(1, UATTR(1), 0, BUF( "\xbb\xbb", 2)),
|
|
LFSR_ATTR(2, REG, +1, BUF("\xcc\xcc\xcc\xcc", 4)),
|
|
LFSR_ATTR(2, UATTR(1), 0, BUF( "\xcc\xcc", 2)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(1, RM, -1, NULL()))) => 0;
|
|
|
|
assert(rbyd.weight == 2);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_REG, buffer, 4)
|
|
=> 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), buffer, 4)
|
|
=> 2;
|
|
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 1, LFSR_TAG_REG, buffer, 4)
|
|
=> 4;
|
|
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 1, LFSR_TAG_UATTR(1), buffer, 4)
|
|
=> 2;
|
|
assert(memcmp(buffer, "\xcc\xcc", 2) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 2, LFSR_TAG_REG, buffer, 4)
|
|
=> LFS_ERR_NOENT;
|
|
lfsr_rbyd_get(&lfs, &rbyd, 2, LFSR_TAG_UATTR(1), buffer, 4)
|
|
=> LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
assert(rbyd.weight == 2);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_REG, buffer, 4)
|
|
=> 4;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), buffer, 4)
|
|
=> 2;
|
|
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 1, LFSR_TAG_REG, buffer, 4)
|
|
=> 4;
|
|
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 1, LFSR_TAG_UATTR(1), buffer, 4)
|
|
=> 2;
|
|
assert(memcmp(buffer, "\xcc\xcc", 2) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 2, LFSR_TAG_REG, buffer, 4)
|
|
=> LFS_ERR_NOENT;
|
|
lfsr_rbyd_get(&lfs, &rbyd, 2, LFSR_TAG_UATTR(1), 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)'
|
|
# -1 => exhaust all permutations
|
|
# n => reproduce a specific permutation
|
|
defines.PERMUTATION = -1
|
|
# 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,
|
|
.eoff = 0,
|
|
.cksum = 0,
|
|
.trunk = 0,
|
|
.weight = 0,
|
|
};
|
|
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;
|
|
size_t worst_perm_i = 0;
|
|
|
|
// test all permutations of a given size
|
|
size_t perm_count = TEST_FACTORIAL(N);
|
|
for (size_t i = 0;
|
|
i < (PERMUTATION == -1 ? perm_count : 1);
|
|
i++) {
|
|
uint32_t perm[N];
|
|
size_t perm_i = PERMUTATION == -1 ? i : (size_t)PERMUTATION;
|
|
TEST_PERMUTATION(perm_i, perm, N);
|
|
|
|
// print permutation to help debugging
|
|
printf("--- permutation: %zd [", perm_i);
|
|
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 rid based on future insertions
|
|
uint16_t rid = perm[j];
|
|
for (unsigned k = j+1; k < N; k++) {
|
|
if (perm[j] > perm[k]) {
|
|
rid -= 1;
|
|
}
|
|
}
|
|
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(rid, REG, +1, BUF(names[perm[j] % 6], 4)))) => 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.eoff);
|
|
lfs_bd_read(&lfs, NULL, &lfs.rcache, rbyd.eoff,
|
|
rbyd.block, 0, backup_block, rbyd.eoff) => 0;
|
|
|
|
// try deleting each rid
|
|
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.eoff) => 0;
|
|
lfs_bd_flush(&lfs, &lfs.pcache, &lfs.rcache, false) => 0;
|
|
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(j, RM, -1, NULL()))) => 0;
|
|
assert(rbyd.weight == N-1);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, CFG->block_size) => 0;
|
|
assert(rbyd.weight == N-1);
|
|
for (unsigned k = 0; k < N-1; k++) {
|
|
lfsr_rbyd_get(&lfs, &rbyd, k, LFSR_TAG_REG, 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, N-1, LFSR_TAG_REG, buffer, 4)
|
|
=> LFS_ERR_NOENT;
|
|
|
|
// try recreating the rid to make sure things still work
|
|
printf("--- create: %d ---\n", j);
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(j, REG, +1, BUF(names[j % 6], 6)))) => 0;
|
|
assert(rbyd.weight == N);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, CFG->block_size) => 0;
|
|
assert(rbyd.weight == N);
|
|
for (unsigned k = 0; k < N; k++) {
|
|
if (k == j) {
|
|
lfsr_rbyd_get(&lfs, &rbyd, k, LFSR_TAG_REG, buffer, 6)
|
|
=> 6;
|
|
assert(memcmp(buffer, names[k % 6], 6) == 0);
|
|
} else {
|
|
lfsr_rbyd_get(&lfs, &rbyd, k, LFSR_TAG_REG, buffer, 6)
|
|
=> 4;
|
|
assert(memcmp(buffer, names[k % 6], 4) == 0);
|
|
}
|
|
}
|
|
|
|
// keep track of the worst size
|
|
if (rbyd.eoff > worst_size) {
|
|
worst_size = rbyd.eoff;
|
|
worst_perm_i = perm_i;
|
|
}
|
|
}
|
|
|
|
// 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 + 2;
|
|
printf("--- summary ---\n");
|
|
printf("worst permutation: %zd\n", worst_perm_i);
|
|
printf("worst size: %u B (N=%u, estimate=%u)\n",
|
|
worst_size, n, 12*n*(2*lfs_nlog2(n)+1)+4);
|
|
printf("worst 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)'
|
|
# -1 => exhaust all permutations
|
|
# n => reproduce a specific permutation
|
|
defines.PERMUTATION = -1
|
|
# 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,
|
|
.eoff = 0,
|
|
.cksum = 0,
|
|
.trunk = 0,
|
|
.weight = 0,
|
|
};
|
|
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;
|
|
size_t worst_perm_i = 0;
|
|
|
|
// test all permutations of a given size
|
|
size_t perm_count = TEST_FACTORIAL(N);
|
|
for (size_t i = 0;
|
|
i < (PERMUTATION == -1 ? perm_count : 1);
|
|
i++) {
|
|
uint32_t perm[N];
|
|
size_t perm_i = PERMUTATION == -1 ? i : (size_t)PERMUTATION;
|
|
TEST_PERMUTATION(perm_i, perm, N);
|
|
|
|
// print permutation to help debugging
|
|
printf("--- permutation: %zd [", perm_i);
|
|
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 rid based on future insertions
|
|
uint16_t rid = perm[j];
|
|
for (unsigned k = j+1; k < N; k++) {
|
|
if (perm[j] > perm[k]) {
|
|
rid -= 1;
|
|
}
|
|
}
|
|
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(rid, REG, +1, BUF(names[perm[j] % 6], 4)))) => 0;
|
|
// note uattrs have a smaller size to help debugging
|
|
for (unsigned u = 0; u < M; u++) {
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(rid, UATTR(u+1), 0,
|
|
BUF(names[perm[j] % 6], 2)))) => 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.eoff);
|
|
lfs_bd_read(&lfs, NULL, &lfs.rcache, rbyd.eoff,
|
|
rbyd.block, 0, backup_block, rbyd.eoff) => 0;
|
|
|
|
// try deleting each rid
|
|
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.eoff) => 0;
|
|
lfs_bd_flush(&lfs, &lfs.pcache, &lfs.rcache, false) => 0;
|
|
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(j, RM, -1, NULL()))) => 0;
|
|
assert(rbyd.weight == N-1);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, CFG->block_size) => 0;
|
|
assert(rbyd.weight == N-1);
|
|
for (unsigned k = 0; k < N-1; k++) {
|
|
lfsr_rbyd_get(&lfs, &rbyd, k, LFSR_TAG_REG, 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,
|
|
k, LFSR_TAG_UATTR(u+1), 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, N-1, LFSR_TAG_REG, buffer, 4)
|
|
=> LFS_ERR_NOENT;
|
|
lfsr_rbyd_get(&lfs, &rbyd, N-1, LFSR_TAG_UATTR(1), buffer, 4)
|
|
=> LFS_ERR_NOENT;
|
|
|
|
// try recreating the rid to make sure things still work
|
|
printf("--- create: %d ---\n", j);
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(j, REG, +1, BUF(names[j % 6], 6)))) => 0;
|
|
for (unsigned u = 0; u < M; u++) {
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(j, UATTR(u+1), 0,
|
|
BUF(names[j % 6], 3)))) => 0;
|
|
}
|
|
assert(rbyd.weight == N);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, CFG->block_size) => 0;
|
|
assert(rbyd.weight == N);
|
|
for (unsigned k = 0; k < N; k++) {
|
|
if (k == j) {
|
|
lfsr_rbyd_get(&lfs, &rbyd, k, LFSR_TAG_REG, buffer, 6)
|
|
=> 6;
|
|
assert(memcmp(buffer, names[k % 6], 6) == 0);
|
|
|
|
for (unsigned u = 0; u < M; u++) {
|
|
lfsr_rbyd_get(&lfs, &rbyd,
|
|
k, LFSR_TAG_UATTR(u+1), buffer, 6)
|
|
=> 3;
|
|
assert(memcmp(buffer, names[k % 6], 3) == 0);
|
|
}
|
|
} else {
|
|
lfsr_rbyd_get(&lfs, &rbyd, k, LFSR_TAG_REG, buffer, 6)
|
|
=> 4;
|
|
assert(memcmp(buffer, names[k % 6], 4) == 0);
|
|
|
|
for (unsigned u = 0; u < M; u++) {
|
|
lfsr_rbyd_get(&lfs, &rbyd,
|
|
k, LFSR_TAG_UATTR(u+1), buffer, 6)
|
|
=> 2;
|
|
assert(memcmp(buffer, names[k % 6], 2) == 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
// keep track of the worst size
|
|
if (rbyd.eoff > worst_size) {
|
|
worst_size = rbyd.eoff;
|
|
worst_perm_i = perm_i;
|
|
}
|
|
}
|
|
|
|
// 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 + 1 + 1+M;
|
|
printf("--- summary ---\n");
|
|
printf("worst permutation: %zd\n", worst_perm_i);
|
|
printf("worst size: %u B (N=%u, estimate=%u)\n",
|
|
worst_size, n, 12*n*(2*lfs_nlog2(n)+1)+4);
|
|
printf("worst 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)'
|
|
# -1 => exhaust all permutations
|
|
# n => reproduce a specific permutation
|
|
defines.PERMUTATION = -1
|
|
# 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,
|
|
.eoff = 0,
|
|
.cksum = 0,
|
|
.trunk = 0,
|
|
.weight = 0,
|
|
};
|
|
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 rid_;
|
|
lfsr_data_t data_;
|
|
uint8_t buffer[4];
|
|
|
|
// test all permutations of a given size
|
|
size_t perm_count = TEST_FACTORIAL(N);
|
|
for (size_t i = 0;
|
|
i < (PERMUTATION == -1 ? perm_count : 1);
|
|
i++) {
|
|
uint32_t perm[N];
|
|
size_t perm_i = PERMUTATION == -1 ? i : (size_t)PERMUTATION;
|
|
TEST_PERMUTATION(perm_i, perm, N);
|
|
|
|
// print permutation to help debugging
|
|
printf("--- permutation: %zd [", perm_i);
|
|
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 rid based on future insertions
|
|
uint16_t rid = perm[j];
|
|
for (unsigned k = j+1; k < N; k++) {
|
|
if (perm[j] > perm[k]) {
|
|
rid -= 1;
|
|
}
|
|
}
|
|
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(rid, REG, +1, BUF(names[perm[j] % 6], 4)))) => 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.eoff);
|
|
lfs_bd_read(&lfs, NULL, &lfs.rcache, rbyd.eoff,
|
|
rbyd.block, 0, backup_block, rbyd.eoff) => 0;
|
|
|
|
// try deleting each rid
|
|
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.eoff) => 0;
|
|
lfs_bd_flush(&lfs, &lfs.pcache, &lfs.rcache, false) => 0;
|
|
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(j, RM, -1, NULL()))) => 0;
|
|
assert(rbyd.weight == N-1);
|
|
|
|
// try traversing over the tags
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, CFG->block_size) => 0;
|
|
assert(rbyd.weight == N-1);
|
|
|
|
tag_ = 0;
|
|
rid_ = -1;
|
|
for (unsigned k = 0; k < N-1; k++) {
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == k);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
|
|
lfsr_rbyd_get(&lfs, &rbyd, rid_, tag_, 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_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
|
|
}
|
|
|
|
// cleanup
|
|
free(backup_block);
|
|
}
|
|
'''
|
|
|
|
# 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)'
|
|
# -1 => exhaust all permutations
|
|
# n => reproduce a specific permutation
|
|
defines.PERMUTATION = -1
|
|
# 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,
|
|
.eoff = 0,
|
|
.cksum = 0,
|
|
.trunk = 0,
|
|
.weight = 0,
|
|
};
|
|
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 rid_;
|
|
lfsr_data_t data_;
|
|
uint8_t buffer[4];
|
|
|
|
// test all permutations of a given size
|
|
size_t perm_count = TEST_FACTORIAL(N);
|
|
for (size_t i = 0;
|
|
i < (PERMUTATION == -1 ? perm_count : 1);
|
|
i++) {
|
|
uint32_t perm[N];
|
|
size_t perm_i = PERMUTATION == -1 ? i : (size_t)PERMUTATION;
|
|
TEST_PERMUTATION(perm_i, perm, N);
|
|
|
|
// print permutation to help debugging
|
|
printf("--- permutation: %zd [", perm_i);
|
|
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 rid based on future insertions
|
|
uint16_t rid = perm[j];
|
|
for (unsigned k = j+1; k < N; k++) {
|
|
if (perm[j] > perm[k]) {
|
|
rid -= 1;
|
|
}
|
|
}
|
|
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(rid, REG, +1, BUF(names[perm[j] % 6], 4)))) => 0;
|
|
// note uattrs have a smaller size to help debugging
|
|
for (unsigned u = 0; u < M; u++) {
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(rid, UATTR(u+1), 0,
|
|
BUF(names[perm[j] % 6], 2)))) => 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.eoff);
|
|
lfs_bd_read(&lfs, NULL, &lfs.rcache, rbyd.eoff,
|
|
rbyd.block, 0, backup_block, rbyd.eoff) => 0;
|
|
|
|
// try deleting each rid
|
|
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.eoff) => 0;
|
|
lfs_bd_flush(&lfs, &lfs.pcache, &lfs.rcache, false) => 0;
|
|
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(j, RM, -1, NULL()))) => 0;
|
|
assert(rbyd.weight == N-1);
|
|
|
|
// try traversing over the tags
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, CFG->block_size) => 0;
|
|
assert(rbyd.weight == N-1);
|
|
|
|
tag_ = 0;
|
|
rid_ = -1;
|
|
for (unsigned k = 0; k < N-1; k++) {
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == k);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
|
|
lfsr_rbyd_get(&lfs, &rbyd, rid_, tag_, 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_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, NULL, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(u+1));
|
|
assert(rid_ == k);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
|
|
lfsr_rbyd_get(&lfs, &rbyd, rid_, tag_, 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_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
|
|
}
|
|
|
|
// cleanup
|
|
free(backup_block);
|
|
}
|
|
'''
|
|
|
|
# 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,
|
|
.eoff = 0,
|
|
.cksum = 0,
|
|
.trunk = 0,
|
|
.weight = 0,
|
|
};
|
|
lfsr_rbyd_t rbyd;
|
|
uint8_t buffer[4];
|
|
|
|
// create and delete one rid
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(0, REG, +1, BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(0, RM, -1, NULL()))) => 0;
|
|
|
|
assert(rbyd.weight == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_REG, buffer, 4)
|
|
=> LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
assert(rbyd.weight == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_REG, 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_ATTRS(
|
|
LFSR_ATTR(0, REG, +1, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(1, REG, +1, BUF("\xbb\xbb\xbb\xbb", 4)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(0, RM, -1, NULL()),
|
|
LFSR_ATTR(0, RM, -1, NULL()))) => 0;
|
|
|
|
assert(rbyd.weight == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_REG, buffer, 4)
|
|
=> LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
assert(rbyd.weight == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_REG, 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_ATTRS(
|
|
LFSR_ATTR(0, REG, +1, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(1, REG, +1, BUF("\xbb\xbb\xbb\xbb", 4)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(1, RM, -1, NULL()),
|
|
LFSR_ATTR(0, RM, -1, NULL()))) => 0;
|
|
|
|
assert(rbyd.weight == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_REG, buffer, 4)
|
|
=> LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
assert(rbyd.weight == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_REG, 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_ATTRS(
|
|
LFSR_ATTR(0, REG, +1, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(1, REG, +1, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(2, REG, +1, BUF("\xcc\xcc\xcc\xcc", 4)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(0, RM, -1, NULL()),
|
|
LFSR_ATTR(0, RM, -1, NULL()),
|
|
LFSR_ATTR(0, RM, -1, NULL()))) => 0;
|
|
|
|
assert(rbyd.weight == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_REG, buffer, 4)
|
|
=> LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
assert(rbyd.weight == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_REG, 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_ATTRS(
|
|
LFSR_ATTR(0, REG, +1, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(1, REG, +1, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(2, REG, +1, BUF("\xcc\xcc\xcc\xcc", 4)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(2, RM, -1, NULL()),
|
|
LFSR_ATTR(1, RM, -1, NULL()),
|
|
LFSR_ATTR(0, RM, -1, NULL()))) => 0;
|
|
|
|
assert(rbyd.weight == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_REG, buffer, 4)
|
|
=> LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
assert(rbyd.weight == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_REG, 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,
|
|
.eoff = 0,
|
|
.cksum = 0,
|
|
.trunk = 0,
|
|
.weight = 0,
|
|
};
|
|
lfsr_rbyd_t rbyd;
|
|
uint8_t buffer[4];
|
|
|
|
// create and delete one rid
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(0, REG, +1, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(0, UATTR(1), 0, BUF( "\xaa\xaa", 2)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(0, RM, -1, NULL()))) => 0;
|
|
|
|
assert(rbyd.weight == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_REG, buffer, 4)
|
|
=> LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
assert(rbyd.weight == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_REG, 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_ATTRS(
|
|
LFSR_ATTR(0, REG, +1, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(0, UATTR(1), 0, BUF( "\xaa\xaa", 2)),
|
|
LFSR_ATTR(1, REG, +1, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(1, UATTR(1), 0, BUF( "\xbb\xbb", 2)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(0, RM, -1, NULL()),
|
|
LFSR_ATTR(0, RM, -1, NULL()))) => 0;
|
|
|
|
assert(rbyd.weight == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_REG, buffer, 4)
|
|
=> LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
assert(rbyd.weight == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_REG, 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_ATTRS(
|
|
LFSR_ATTR(0, REG, +1, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(0, UATTR(1), 0, BUF( "\xaa\xaa", 2)),
|
|
LFSR_ATTR(1, REG, +1, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(1, UATTR(1), 0, BUF( "\xbb\xbb", 2)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(1, RM, -1, NULL()),
|
|
LFSR_ATTR(0, RM, -1, NULL()))) => 0;
|
|
|
|
assert(rbyd.weight == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_REG, buffer, 4)
|
|
=> LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
assert(rbyd.weight == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_REG, 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_ATTRS(
|
|
LFSR_ATTR(0, REG, +1, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(0, UATTR(1), 0, BUF( "\xaa\xaa", 2)),
|
|
LFSR_ATTR(1, REG, +1, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(1, UATTR(1), 0, BUF( "\xbb\xbb", 2)),
|
|
LFSR_ATTR(2, REG, +1, BUF("\xcc\xcc\xcc\xcc", 4)),
|
|
LFSR_ATTR(2, UATTR(1), 0, BUF( "\xcc\xcc", 2)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(0, RM, -1, NULL()),
|
|
LFSR_ATTR(0, RM, -1, NULL()),
|
|
LFSR_ATTR(0, RM, -1, NULL()))) => 0;
|
|
|
|
assert(rbyd.weight == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_REG, buffer, 4)
|
|
=> LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
assert(rbyd.weight == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_REG, 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_ATTRS(
|
|
LFSR_ATTR(0, REG, +1, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(0, UATTR(1), 0, BUF( "\xaa\xaa", 2)),
|
|
LFSR_ATTR(1, REG, +1, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(1, UATTR(1), 0, BUF( "\xbb\xbb", 2)),
|
|
LFSR_ATTR(2, REG, +1, BUF("\xcc\xcc\xcc\xcc", 4)),
|
|
LFSR_ATTR(2, UATTR(1), 0, BUF( "\xcc\xcc", 2)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(2, RM, -1, NULL()),
|
|
LFSR_ATTR(1, RM, -1, NULL()),
|
|
LFSR_ATTR(0, RM, -1, NULL()))) => 0;
|
|
|
|
assert(rbyd.weight == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_REG, buffer, 4)
|
|
=> LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
assert(rbyd.weight == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd, 0, LFSR_TAG_REG, 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)'
|
|
# -1 => exhaust all permutations
|
|
# n => reproduce a specific permutation
|
|
defines.PERMUTATION = -1
|
|
# 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,
|
|
.eoff = 0,
|
|
.cksum = 0,
|
|
.trunk = 0,
|
|
.weight = 0,
|
|
};
|
|
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;
|
|
size_t worst_perm_i = 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_ATTRS(
|
|
LFSR_ATTR(j, REG, +1, BUF(names[j % 6], 4)))) => 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.eoff);
|
|
lfs_bd_read(&lfs, NULL, &lfs.rcache, rbyd.eoff,
|
|
rbyd.block, 0, backup_block, rbyd.eoff) => 0;
|
|
|
|
// test all permutations of a given size
|
|
size_t perm_count = TEST_FACTORIAL(N);
|
|
for (size_t i = 0;
|
|
i < (PERMUTATION == -1 ? perm_count : 1);
|
|
i++) {
|
|
uint32_t perm[N];
|
|
size_t perm_i = PERMUTATION == -1 ? i : (size_t)PERMUTATION;
|
|
TEST_PERMUTATION(perm_i, perm, N);
|
|
|
|
// print permutation to help debugging
|
|
printf("--- permutation: %zd [", perm_i);
|
|
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.eoff) => 0;
|
|
lfs_bd_flush(&lfs, &lfs.pcache, &lfs.rcache, false) => 0;
|
|
|
|
// delete each rid in permutation order
|
|
for (unsigned j = 0; j < N; j++) {
|
|
// adjust rid based on previous deletions
|
|
uint16_t rid = perm[j];
|
|
for (unsigned k = 0; k < j; k++) {
|
|
if (perm[k] < perm[j]) {
|
|
rid -= 1;
|
|
}
|
|
}
|
|
|
|
lfs_size_t rbyd_weight_before = rbyd.weight;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(rid, RM, -1, NULL()))) => 0;
|
|
assert(rbyd.weight == rbyd_weight_before-1);
|
|
}
|
|
|
|
// check that all tags are now removed
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
assert(rbyd.weight == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd,
|
|
LFSR_TAG_REG, 0, buffer, 4)
|
|
=> LFS_ERR_NOENT;
|
|
|
|
// try resuming from all tags being removed
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(0, REG, +1,
|
|
BUF("\xaa\xaa\xaa\xaa\xaa\xaa", 6)))) => 0;
|
|
assert(rbyd.weight == 1);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
assert(rbyd.weight == 1);
|
|
lfsr_rbyd_get(&lfs, &rbyd,
|
|
0, LFSR_TAG_REG, buffer, 6)
|
|
=> 6;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa\xaa\xaa", 6) == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd,
|
|
1, LFSR_TAG_REG, buffer, 6)
|
|
=> LFS_ERR_NOENT;
|
|
|
|
// keep track of the worst size
|
|
if (rbyd.eoff > worst_size) {
|
|
worst_size = rbyd.eoff;
|
|
worst_perm_i = perm_i;
|
|
}
|
|
}
|
|
|
|
// 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("--- summary ---\n");
|
|
printf("worst permutation: %zd\n", worst_perm_i);
|
|
printf("worst size: %u B (N=%u, estimate=%u)\n",
|
|
worst_size, n, 12*n*(2*lfs_nlog2(n)+1)+4);
|
|
printf("worst 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)'
|
|
# -1 => exhaust all permutations
|
|
# n => reproduce a specific permutation
|
|
defines.PERMUTATION = -1
|
|
# 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,
|
|
.eoff = 0,
|
|
.cksum = 0,
|
|
.trunk = 0,
|
|
.weight = 0,
|
|
};
|
|
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;
|
|
size_t worst_perm_i = 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_ATTRS(
|
|
LFSR_ATTR(j, REG, +1, BUF(names[j % 6], 4)))) => 0;
|
|
// note uattrs have a smaller size to help debugging
|
|
for (unsigned u = 0; u < M; u++) {
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(j, UATTR(u+1), 0, BUF(names[j % 6], 2)))) => 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.eoff);
|
|
lfs_bd_read(&lfs, NULL, &lfs.rcache, rbyd.eoff,
|
|
rbyd.block, 0, backup_block, rbyd.eoff) => 0;
|
|
|
|
// test all permutations of a given size
|
|
size_t perm_count = TEST_FACTORIAL(N);
|
|
for (size_t i = 0;
|
|
i < (PERMUTATION == -1 ? perm_count : 1);
|
|
i++) {
|
|
uint32_t perm[N];
|
|
size_t perm_i = PERMUTATION == -1 ? i : (size_t)PERMUTATION;
|
|
TEST_PERMUTATION(perm_i, perm, N);
|
|
|
|
// print permutation to help debugging
|
|
printf("--- permutation: %zd [", perm_i);
|
|
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.eoff) => 0;
|
|
lfs_bd_flush(&lfs, &lfs.pcache, &lfs.rcache, false) => 0;
|
|
|
|
// delete each rid in permutation order
|
|
for (unsigned j = 0; j < N; j++) {
|
|
// adjust rid based on previous deletions
|
|
uint16_t rid = perm[j];
|
|
for (unsigned k = 0; k < j; k++) {
|
|
if (perm[k] < perm[j]) {
|
|
rid -= 1;
|
|
}
|
|
}
|
|
|
|
lfs_size_t rbyd_weight_before = rbyd.weight;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(rid, RM, -1, NULL()))) => 0;
|
|
assert(rbyd.weight == rbyd_weight_before-1);
|
|
}
|
|
|
|
// check that all tags are now removed
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
assert(rbyd.weight == 0);
|
|
lfsr_rbyd_get(&lfs, &rbyd,
|
|
0, LFSR_TAG_REG, buffer, 4)
|
|
=> LFS_ERR_NOENT;
|
|
|
|
// try resuming from all tags being removed
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(0, REG, +1,
|
|
BUF("\xaa\xaa\xaa\xaa\xaa\xaa", 6)))) => 0;
|
|
for (unsigned u = 0; u < M; u++) {
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(0, UATTR(u+1), 0, BUF("\xaa\xaa\xaa", 3)))) => 0;
|
|
}
|
|
assert(rbyd.weight == 1);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
assert(rbyd.weight == 1);
|
|
lfsr_rbyd_get(&lfs, &rbyd,
|
|
0, LFSR_TAG_REG, 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,
|
|
0, LFSR_TAG_UATTR(u+1), buffer, 6)
|
|
=> 3;
|
|
assert(memcmp(buffer, "\xaa\xaa\xaa", 3) == 0);
|
|
}
|
|
lfsr_rbyd_get(&lfs, &rbyd,
|
|
1, LFSR_TAG_REG, buffer, 6)
|
|
=> LFS_ERR_NOENT;
|
|
lfsr_rbyd_get(&lfs, &rbyd,
|
|
1, LFSR_TAG_UATTR(1), buffer, 6)
|
|
=> LFS_ERR_NOENT;
|
|
|
|
// keep track of the worst size
|
|
if (rbyd.eoff > worst_size) {
|
|
worst_size = rbyd.eoff;
|
|
worst_perm_i = perm_i;
|
|
}
|
|
}
|
|
|
|
// 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("--- summary ---\n");
|
|
printf("worst permutation: %zd\n", worst_perm_i);
|
|
printf("worst size: %u B (N=%u, estimate=%u)\n",
|
|
worst_size, n, 12*n*(2*lfs_nlog2(n)+1)+4);
|
|
printf("worst 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_fuzz_create_deletes]
|
|
defines.N = 'range(1, 33)'
|
|
defines.SEED = 'range(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,
|
|
.eoff = 0,
|
|
.cksum = 0,
|
|
.trunk = 0,
|
|
.weight = 0,
|
|
};
|
|
lfsr_rbyd_t rbyd;
|
|
const char *alpha = "abcdefghijklmnopqrstuvwxyz";
|
|
uint8_t buffer[4];
|
|
|
|
printf("perm: [");
|
|
uint32_t prng = SEED;
|
|
lfs_size_t count = 0;
|
|
for (unsigned i = 0; i < N; i++) {
|
|
// choose an rid
|
|
lfs_ssize_t rid = TEST_PRNG(&prng) % (count+1);
|
|
// choose create or delete
|
|
if (rid == (lfs_ssize_t)count || (TEST_PRNG(&prng) & 1)) {
|
|
printf("c%d=%c", rid, alpha[i % 26]);
|
|
count += 1;
|
|
} else {
|
|
printf("d%d", rid);
|
|
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 rid
|
|
lfs_ssize_t rid = TEST_PRNG(&prng) % (count+1);
|
|
// choose create or delete
|
|
if (rid == (lfs_ssize_t)count || (TEST_PRNG(&prng) & 1)) {
|
|
// update our sim
|
|
memmove(sim+rid+1, sim+rid, count-rid);
|
|
sim[rid] = alpha[i % 26];
|
|
count += 1;
|
|
// update our rbyd
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(rid, REG, +1, BUF(&alpha[i % 26], 1)))) => 0;
|
|
} else {
|
|
// update our sim
|
|
memmove(sim+rid, sim+rid+1, count-rid-1);
|
|
count -= 1;
|
|
// update our rbyd
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(rid, RM, -1, NULL()))) => 0;
|
|
}
|
|
}
|
|
|
|
// compare rbyd vs simulation
|
|
printf("expd: [");
|
|
for (lfs_ssize_t rid = 0; rid < (lfs_ssize_t)count; rid++) {
|
|
printf("%c", sim[rid]);
|
|
if (rid < (lfs_ssize_t)count-1) {
|
|
printf(", ");
|
|
}
|
|
}
|
|
printf("]\n");
|
|
printf("rbyd: [");
|
|
for (lfs_ssize_t rid = 0; rid < (lfs_ssize_t)rbyd.weight; rid++) {
|
|
lfs_ssize_t size = lfsr_rbyd_get(&lfs, &rbyd,
|
|
rid, LFSR_TAG_REG, buffer, 4);
|
|
if (size >= 0) {
|
|
printf("%.*s", size, buffer);
|
|
} else {
|
|
printf("?");
|
|
}
|
|
if (rid < (lfs_ssize_t)count-1) {
|
|
printf(", ");
|
|
}
|
|
}
|
|
printf("]\n");
|
|
|
|
assert(count == rbyd.weight);
|
|
for (lfs_ssize_t rid = 0; rid < (lfs_ssize_t)count; rid++) {
|
|
lfsr_rbyd_get(&lfs, &rbyd, rid, LFSR_TAG_REG, buffer, 4) => 1;
|
|
assert(memcmp(&sim[rid], buffer, 1) == 0);
|
|
}
|
|
|
|
// cleanup
|
|
free(sim);
|
|
'''
|
|
|
|
|
|
# Test rbyd weights
|
|
[cases.test_rbyd_sparse]
|
|
in = 'lfs.c'
|
|
code = '''
|
|
lfs_t lfs;
|
|
lfs_init(&lfs, CFG) => 0;
|
|
|
|
lfsr_rbyd_t init_rbyd = {
|
|
.block = 0,
|
|
.eoff = 0,
|
|
.cksum = 0,
|
|
.trunk = 0,
|
|
.weight = 0,
|
|
};
|
|
lfsr_rbyd_t rbyd;
|
|
lfsr_tag_t tag_;
|
|
lfs_ssize_t rid_;
|
|
lfs_size_t weight_;
|
|
lfsr_data_t data_;
|
|
|
|
// make id0 with weight w1
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(0, REG, +1, BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
|
|
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 0, LFSR_TAG_REG,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 0);
|
|
assert(weight_ == 1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 0, LFSR_TAG_REG,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 0);
|
|
assert(weight_ == 1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
|
|
// make id2 with weight w2
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(1, REG, +2, BUF("\xbb\xbb\xbb\xbb", 4)))) => 0;
|
|
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 0, LFSR_TAG_REG,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 0);
|
|
assert(weight_ == 1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 2, LFSR_TAG_REG,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 2);
|
|
assert(weight_ == 2);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 0, LFSR_TAG_REG,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 0);
|
|
assert(weight_ == 1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 2, LFSR_TAG_REG,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 2);
|
|
assert(weight_ == 2);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
|
|
// make id5 with weight w3
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(3, REG, +3, BUF("\xcc\xcc\xcc\xcc", 4)))) => 0;
|
|
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 0, LFSR_TAG_REG,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 0);
|
|
assert(weight_ == 1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 2, LFSR_TAG_REG,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 2);
|
|
assert(weight_ == 2);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 5, LFSR_TAG_REG,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 5);
|
|
assert(weight_ == 3);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 0, LFSR_TAG_REG,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 0);
|
|
assert(weight_ == 1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 2, LFSR_TAG_REG,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 2);
|
|
assert(weight_ == 2);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 5, LFSR_TAG_REG,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 5);
|
|
assert(weight_ == 3);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
|
|
// make id9 with weight w4
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(6, REG, +4, BUF("\xdd\xdd\xdd\xdd", 4)))) => 0;
|
|
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 0, LFSR_TAG_REG,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 0);
|
|
assert(weight_ == 1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 2, LFSR_TAG_REG,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 2);
|
|
assert(weight_ == 2);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 5, LFSR_TAG_REG,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 5);
|
|
assert(weight_ == 3);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 9, LFSR_TAG_REG,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 9);
|
|
assert(weight_ == 4);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 0, LFSR_TAG_REG,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 0);
|
|
assert(weight_ == 1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 2, LFSR_TAG_REG,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 2);
|
|
assert(weight_ == 2);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 5, LFSR_TAG_REG,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 5);
|
|
assert(weight_ == 3);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 9, LFSR_TAG_REG,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 9);
|
|
assert(weight_ == 4);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
|
|
// make id14 with weight w5
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(10, REG, +5, BUF("\xee\xee\xee\xee", 4)))) => 0;
|
|
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 0, LFSR_TAG_REG,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 0);
|
|
assert(weight_ == 1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 2, LFSR_TAG_REG,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 2);
|
|
assert(weight_ == 2);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 5, LFSR_TAG_REG,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 5);
|
|
assert(weight_ == 3);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 9, LFSR_TAG_REG,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 9);
|
|
assert(weight_ == 4);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 14, LFSR_TAG_REG,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 14);
|
|
assert(weight_ == 5);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 0, LFSR_TAG_REG,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 0);
|
|
assert(weight_ == 1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 2, LFSR_TAG_REG,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 2);
|
|
assert(weight_ == 2);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 5, LFSR_TAG_REG,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 5);
|
|
assert(weight_ == 3);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 9, LFSR_TAG_REG,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 9);
|
|
assert(weight_ == 4);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 14, LFSR_TAG_REG,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 14);
|
|
assert(weight_ == 5);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
'''
|
|
|
|
[cases.test_rbyd_sparse_traverse]
|
|
in = 'lfs.c'
|
|
code = '''
|
|
lfs_t lfs;
|
|
lfs_init(&lfs, CFG) => 0;
|
|
|
|
lfsr_rbyd_t init_rbyd = {
|
|
.block = 0,
|
|
.eoff = 0,
|
|
.cksum = 0,
|
|
.trunk = 0,
|
|
.weight = 0,
|
|
};
|
|
lfsr_rbyd_t rbyd;
|
|
lfsr_tag_t tag_;
|
|
lfs_ssize_t rid_;
|
|
lfs_size_t weight_;
|
|
lfsr_data_t data_;
|
|
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
// make id0 with weight w1
|
|
LFSR_ATTR(0, REG, +1, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
// make id2 with weight w2
|
|
LFSR_ATTR(1, REG, +2, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
// make id5 with weight w3
|
|
LFSR_ATTR(3, REG, +3, BUF("\xcc\xcc\xcc\xcc", 4)),
|
|
// make id9 with weight w4
|
|
LFSR_ATTR(6, REG, +4, BUF("\xdd\xdd\xdd\xdd", 4)),
|
|
// make id14 with weight w5
|
|
LFSR_ATTR(10, REG, +5, BUF("\xee\xee\xee\xee", 4)))) => 0;
|
|
|
|
// traverse, finding tags and weights
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, 0,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 0);
|
|
assert(weight_ == 1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 2);
|
|
assert(weight_ == 2);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 5);
|
|
assert(weight_ == 3);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 9);
|
|
assert(weight_ == 4);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 14);
|
|
assert(weight_ == 5);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, &weight_, &data_) => LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, 0,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 0);
|
|
assert(weight_ == 1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 2);
|
|
assert(weight_ == 2);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 5);
|
|
assert(weight_ == 3);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 9);
|
|
assert(weight_ == 4);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 14);
|
|
assert(weight_ == 5);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, &weight_, &data_) => LFS_ERR_NOENT;
|
|
'''
|
|
|
|
[cases.test_rbyd_sparse_permutations]
|
|
defines.N = 'range(1, 8)'
|
|
defines.W = 5
|
|
# -1 => exhaust all permutations
|
|
# n => reproduce a specific permutation
|
|
defines.PERMUTATION = -1
|
|
# 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,
|
|
.eoff = 0,
|
|
.cksum = 0,
|
|
.trunk = 0,
|
|
.weight = 0,
|
|
};
|
|
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 rid_;
|
|
lfs_size_t weight_;
|
|
lfsr_data_t data_;
|
|
uint8_t buffer[4];
|
|
|
|
// test all permutations of a given size
|
|
size_t perm_count = TEST_FACTORIAL(N);
|
|
for (size_t i = 0;
|
|
i < (PERMUTATION == -1 ? perm_count : 1);
|
|
i++) {
|
|
uint32_t perm[N];
|
|
size_t perm_i = PERMUTATION == -1 ? i : (size_t)PERMUTATION;
|
|
TEST_PERMUTATION(perm_i, perm, N);
|
|
|
|
// print permutation to help debugging
|
|
printf("--- permutation: %zd [", perm_i);
|
|
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 rid based on future insertions
|
|
uint16_t rid = perm[j];
|
|
for (unsigned k = j+1; k < N; k++) {
|
|
if (perm[j] > perm[k]) {
|
|
rid -= 1;
|
|
}
|
|
}
|
|
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(rid*W, REG, +W,
|
|
BUF(names[perm[j] % 6], 4)))) => 0;
|
|
}
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
assert(rbyd.weight == N*W);
|
|
for (unsigned j = 0; j < N; j++) {
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, j*W+W-1, LFSR_TAG_REG,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == j*W+W-1);
|
|
assert(weight_ == W);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
|
|
lfsr_rbyd_get(&lfs, &rbyd, j*W+W-1, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, names[j % 6], 4) == 0);
|
|
}
|
|
}
|
|
'''
|
|
|
|
[cases.test_rbyd_sparse_traverse_permutations]
|
|
defines.N = 'range(1, 8)'
|
|
defines.W = 5
|
|
# -1 => exhaust all permutations
|
|
# n => reproduce a specific permutation
|
|
defines.PERMUTATION = -1
|
|
# 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,
|
|
.eoff = 0,
|
|
.cksum = 0,
|
|
.trunk = 0,
|
|
.weight = 0,
|
|
};
|
|
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 rid_;
|
|
lfs_size_t weight_;
|
|
lfsr_data_t data_;
|
|
uint8_t buffer[4];
|
|
|
|
// test all permutations of a given size
|
|
size_t perm_count = TEST_FACTORIAL(N);
|
|
for (size_t i = 0;
|
|
i < (PERMUTATION == -1 ? perm_count : 1);
|
|
i++) {
|
|
uint32_t perm[N];
|
|
size_t perm_i = PERMUTATION == -1 ? i : (size_t)PERMUTATION;
|
|
TEST_PERMUTATION(perm_i, perm, N);
|
|
|
|
// print permutation to help debugging
|
|
printf("--- permutation: %zd [", perm_i);
|
|
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 rid based on future insertions
|
|
uint16_t rid = perm[j];
|
|
for (unsigned k = j+1; k < N; k++) {
|
|
if (perm[j] > perm[k]) {
|
|
rid -= 1;
|
|
}
|
|
}
|
|
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(rid*W, REG, +W,
|
|
BUF(names[perm[j] % 6], 4)))) => 0;
|
|
}
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
assert(rbyd.weight == N*W);
|
|
// try traversing all tags
|
|
tag_ = 0;
|
|
rid_ = -1;
|
|
for (unsigned j = 0; j < N; j++) {
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == j*W+W-1);
|
|
assert(weight_ == W);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
|
|
lfsr_rbyd_get(&lfs, &rbyd, rid_, tag_, buffer, 4) => 4;
|
|
assert(memcmp(buffer, names[j % 6], 4) == 0);
|
|
}
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, &weight_, &data_) => LFS_ERR_NOENT;
|
|
}
|
|
'''
|
|
|
|
# Weights mixed with attributes
|
|
[cases.test_rbyd_sparse_mixed]
|
|
in = 'lfs.c'
|
|
code = '''
|
|
lfs_t lfs;
|
|
lfs_init(&lfs, CFG) => 0;
|
|
|
|
lfsr_rbyd_t init_rbyd = {
|
|
.block = 0,
|
|
.eoff = 0,
|
|
.cksum = 0,
|
|
.trunk = 0,
|
|
.weight = 0,
|
|
};
|
|
lfsr_rbyd_t rbyd;
|
|
lfsr_tag_t tag_;
|
|
lfs_ssize_t rid_;
|
|
lfs_size_t weight_;
|
|
lfsr_data_t data_;
|
|
|
|
// make id0 with weight w1
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(-1, UATTR(3), 0, BUF("unrelated", 9)),
|
|
LFSR_ATTR(0, REG, +1, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(0, UATTR(1), 0, BUF("\xaa\xaa", 2)),
|
|
LFSR_ATTR(0, UATTR(2), 0, BUF("\xaa\xaa", 2)))) => 0;
|
|
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(3),
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(3));
|
|
assert(rid_ == -1);
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 9);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 0, LFSR_TAG_REG,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 0);
|
|
assert(weight_ == 1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1),
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == 0);
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 0, LFSR_TAG_UATTR(2),
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == 0);
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(3),
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(3));
|
|
assert(rid_ == -1);
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 9);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 0, LFSR_TAG_REG,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 0);
|
|
assert(weight_ == 1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1),
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == 0);
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 0, LFSR_TAG_UATTR(2),
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == 0);
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
|
|
// make id2 with weight w2
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(1, REG, +1, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(1, UATTR(1), 0, BUF("\xbb\xbb", 2)),
|
|
LFSR_ATTR(1, RM, +1, NULL()),
|
|
LFSR_ATTR(2, UATTR(2), 0, BUF("\xbb\xbb", 2)))) => 0;
|
|
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(3),
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(3));
|
|
assert(rid_ == -1);
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 9);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 0, LFSR_TAG_REG,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 0);
|
|
assert(weight_ == 1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1),
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == 0);
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 0, LFSR_TAG_UATTR(2),
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == 0);
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 2, LFSR_TAG_REG,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 2);
|
|
assert(weight_ == 2);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 2, LFSR_TAG_UATTR(1),
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == 2);
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 2, LFSR_TAG_UATTR(2),
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == 2);
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(3),
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(3));
|
|
assert(rid_ == -1);
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 9);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 0, LFSR_TAG_REG,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 0);
|
|
assert(weight_ == 1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1),
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == 0);
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 0, LFSR_TAG_UATTR(2),
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == 0);
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 2, LFSR_TAG_REG,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 2);
|
|
assert(weight_ == 2);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 2, LFSR_TAG_UATTR(1),
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == 2);
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 2, LFSR_TAG_UATTR(2),
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == 2);
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
|
|
// make id5 with weight w3
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(3, REG, +1, BUF("\xcc\xcc\xcc\xcc", 4)),
|
|
LFSR_ATTR(3, UATTR(1), 0, BUF("\xcc\xcc", 2)),
|
|
LFSR_ATTR(3, RM, +2, NULL()),
|
|
LFSR_ATTR(5, UATTR(2), 0, BUF("\xcc\xcc", 2)))) => 0;
|
|
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(3),
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(3));
|
|
assert(rid_ == -1);
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 9);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 0, LFSR_TAG_REG,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 0);
|
|
assert(weight_ == 1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1),
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == 0);
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 0, LFSR_TAG_UATTR(2),
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == 0);
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 2, LFSR_TAG_REG,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 2);
|
|
assert(weight_ == 2);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 2, LFSR_TAG_UATTR(1),
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == 2);
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 2, LFSR_TAG_UATTR(2),
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == 2);
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 5, LFSR_TAG_REG,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 5);
|
|
assert(weight_ == 3);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 5, LFSR_TAG_UATTR(1),
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == 5);
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 5, LFSR_TAG_UATTR(2),
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == 5);
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(3),
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(3));
|
|
assert(rid_ == -1);
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 9);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 0, LFSR_TAG_REG,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 0);
|
|
assert(weight_ == 1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1),
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == 0);
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 0, LFSR_TAG_UATTR(2),
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == 0);
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 2, LFSR_TAG_REG,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 2);
|
|
assert(weight_ == 2);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 2, LFSR_TAG_UATTR(1),
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == 2);
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 2, LFSR_TAG_UATTR(2),
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == 2);
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 5, LFSR_TAG_REG,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 5);
|
|
assert(weight_ == 3);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 5, LFSR_TAG_UATTR(1),
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == 5);
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 5, LFSR_TAG_UATTR(2),
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == 5);
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
|
|
// make id9 with weight w4
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(6, REG, +1, BUF("\xdd\xdd\xdd\xdd", 4)),
|
|
LFSR_ATTR(6, UATTR(1), 0, BUF("\xdd\xdd", 2)),
|
|
LFSR_ATTR(6, RM, +3, NULL()),
|
|
LFSR_ATTR(9, UATTR(2), 0, BUF("\xdd\xdd", 2)))) => 0;
|
|
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(3),
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(3));
|
|
assert(rid_ == -1);
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 9);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 0, LFSR_TAG_REG,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 0);
|
|
assert(weight_ == 1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1),
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == 0);
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 0, LFSR_TAG_UATTR(2),
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == 0);
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 2, LFSR_TAG_REG,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 2);
|
|
assert(weight_ == 2);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 2, LFSR_TAG_UATTR(1),
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == 2);
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 2, LFSR_TAG_UATTR(2),
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == 2);
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 5, LFSR_TAG_REG,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 5);
|
|
assert(weight_ == 3);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 5, LFSR_TAG_UATTR(1),
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == 5);
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 5, LFSR_TAG_UATTR(2),
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == 5);
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 9, LFSR_TAG_REG,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 9);
|
|
assert(weight_ == 4);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 9, LFSR_TAG_UATTR(1),
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == 9);
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 9, LFSR_TAG_UATTR(2),
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == 9);
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(3),
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(3));
|
|
assert(rid_ == -1);
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 9);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 0, LFSR_TAG_REG,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 0);
|
|
assert(weight_ == 1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1),
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == 0);
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 0, LFSR_TAG_UATTR(2),
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == 0);
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 2, LFSR_TAG_REG,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 2);
|
|
assert(weight_ == 2);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 2, LFSR_TAG_UATTR(1),
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == 2);
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 2, LFSR_TAG_UATTR(2),
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == 2);
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 5, LFSR_TAG_REG,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 5);
|
|
assert(weight_ == 3);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 5, LFSR_TAG_UATTR(1),
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == 5);
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 5, LFSR_TAG_UATTR(2),
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == 5);
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 9, LFSR_TAG_REG,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 9);
|
|
assert(weight_ == 4);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 9, LFSR_TAG_UATTR(1),
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == 9);
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 9, LFSR_TAG_UATTR(2),
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == 9);
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
|
|
// make id14 with weight w5
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(10, REG, +1, BUF("\xee\xee\xee\xee", 4)),
|
|
LFSR_ATTR(10, UATTR(1), 0, BUF("\xee\xee", 2)),
|
|
LFSR_ATTR(10, RM, +4, NULL()),
|
|
LFSR_ATTR(14, UATTR(2), 0, BUF("\xee\xee", 2)))) => 0;
|
|
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(3),
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(3));
|
|
assert(rid_ == -1);
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 9);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 0, LFSR_TAG_REG,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 0);
|
|
assert(weight_ == 1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1),
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == 0);
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 0, LFSR_TAG_UATTR(2),
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == 0);
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 2, LFSR_TAG_REG,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 2);
|
|
assert(weight_ == 2);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 2, LFSR_TAG_UATTR(1),
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == 2);
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 2, LFSR_TAG_UATTR(2),
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == 2);
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 5, LFSR_TAG_REG,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 5);
|
|
assert(weight_ == 3);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 5, LFSR_TAG_UATTR(1),
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == 5);
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 5, LFSR_TAG_UATTR(2),
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == 5);
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 9, LFSR_TAG_REG,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 9);
|
|
assert(weight_ == 4);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 9, LFSR_TAG_UATTR(1),
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == 9);
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 9, LFSR_TAG_UATTR(2),
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == 9);
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 14, LFSR_TAG_REG,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 14);
|
|
assert(weight_ == 5);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 14, LFSR_TAG_UATTR(1),
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == 14);
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 14, LFSR_TAG_UATTR(2),
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == 14);
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(3),
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(3));
|
|
assert(rid_ == -1);
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 9);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 0, LFSR_TAG_REG,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 0);
|
|
assert(weight_ == 1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1),
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == 0);
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 0, LFSR_TAG_UATTR(2),
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == 0);
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 2, LFSR_TAG_REG,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 2);
|
|
assert(weight_ == 2);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 2, LFSR_TAG_UATTR(1),
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == 2);
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 2, LFSR_TAG_UATTR(2),
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == 2);
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 5, LFSR_TAG_REG,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 5);
|
|
assert(weight_ == 3);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 5, LFSR_TAG_UATTR(1),
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == 5);
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 5, LFSR_TAG_UATTR(2),
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == 5);
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 9, LFSR_TAG_REG,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 9);
|
|
assert(weight_ == 4);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 9, LFSR_TAG_UATTR(1),
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == 9);
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 9, LFSR_TAG_UATTR(2),
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == 9);
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 14, LFSR_TAG_REG,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 14);
|
|
assert(weight_ == 5);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 14, LFSR_TAG_UATTR(1),
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == 14);
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 14, LFSR_TAG_UATTR(2),
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == 14);
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
'''
|
|
|
|
[cases.test_rbyd_sparse_mixed_traverse]
|
|
in = 'lfs.c'
|
|
code = '''
|
|
lfs_t lfs;
|
|
lfs_init(&lfs, CFG) => 0;
|
|
|
|
lfsr_rbyd_t init_rbyd = {
|
|
.block = 0,
|
|
.eoff = 0,
|
|
.cksum = 0,
|
|
.trunk = 0,
|
|
.weight = 0,
|
|
};
|
|
lfsr_rbyd_t rbyd;
|
|
lfsr_tag_t tag_;
|
|
lfs_ssize_t rid_;
|
|
lfs_size_t weight_;
|
|
lfsr_data_t data_;
|
|
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(-1, UATTR(3), 0, BUF("unrelated", 9)),
|
|
// make id0 with weight w1
|
|
LFSR_ATTR(0, REG, +1, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(0, UATTR(1), 0, BUF("\xaa\xaa", 2)),
|
|
LFSR_ATTR(0, UATTR(2), 0, BUF("\xaa\xaa", 2)),
|
|
// make id2 with weight w2
|
|
LFSR_ATTR(1, REG, +1, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(1, UATTR(1), 0, BUF("\xbb\xbb", 2)),
|
|
LFSR_ATTR(1, RM, +1, NULL()),
|
|
LFSR_ATTR(2, UATTR(2), 0, BUF("\xbb\xbb", 2)),
|
|
// make id5 with weight w3
|
|
LFSR_ATTR(3, REG, +1, BUF("\xcc\xcc\xcc\xcc", 4)),
|
|
LFSR_ATTR(3, UATTR(1), 0, BUF("\xcc\xcc", 2)),
|
|
LFSR_ATTR(3, RM, +2, NULL()),
|
|
LFSR_ATTR(5, UATTR(2), 0, BUF("\xcc\xcc", 2)),
|
|
// make id9 with weight w4
|
|
LFSR_ATTR(6, REG, +1, BUF("\xdd\xdd\xdd\xdd", 4)),
|
|
LFSR_ATTR(6, UATTR(1), 0, BUF("\xdd\xdd", 2)),
|
|
LFSR_ATTR(6, RM, +3, NULL()),
|
|
LFSR_ATTR(9, UATTR(2), 0, BUF("\xdd\xdd", 2)),
|
|
// make id14 with weight w5
|
|
LFSR_ATTR(10, REG, +1, BUF("\xee\xee\xee\xee", 4)),
|
|
LFSR_ATTR(10, UATTR(1), 0, BUF("\xee\xee", 2)),
|
|
LFSR_ATTR(10, RM, +4, NULL()),
|
|
LFSR_ATTR(14, UATTR(2), 0, BUF("\xee\xee", 2)))) => 0;
|
|
|
|
// traverse, finding tags and weights
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, 0,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(3));
|
|
assert(rid_ == -1);
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 9);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 0);
|
|
assert(weight_ == 1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == 0);
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == 0);
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 2);
|
|
assert(weight_ == 2);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == 2);
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == 2);
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 5);
|
|
assert(weight_ == 3);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == 5);
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == 5);
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 9);
|
|
assert(weight_ == 4);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == 9);
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == 9);
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 14);
|
|
assert(weight_ == 5);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == 14);
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == 14);
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, &weight_, &data_) => LFS_ERR_NOENT;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, 0,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(3));
|
|
assert(rid_ == -1);
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 9);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 0);
|
|
assert(weight_ == 1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == 0);
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == 0);
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 2);
|
|
assert(weight_ == 2);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == 2);
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == 2);
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 5);
|
|
assert(weight_ == 3);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == 5);
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == 5);
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 9);
|
|
assert(weight_ == 4);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == 9);
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == 9);
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == 14);
|
|
assert(weight_ == 5);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == 14);
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == 14);
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, &weight_, &data_) => LFS_ERR_NOENT;
|
|
'''
|
|
|
|
[cases.test_rbyd_sparse_mixed_permutations]
|
|
defines.N = 'range(1, 8)'
|
|
defines.W = 5
|
|
# -1 => exhaust all permutations
|
|
# n => reproduce a specific permutation
|
|
defines.PERMUTATION = -1
|
|
# 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,
|
|
.eoff = 0,
|
|
.cksum = 0,
|
|
.trunk = 0,
|
|
.weight = 0,
|
|
};
|
|
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 rid_;
|
|
lfs_size_t weight_;
|
|
lfsr_data_t data_;
|
|
uint8_t buffer[4];
|
|
|
|
// test all permutations of a given size
|
|
size_t perm_count = TEST_FACTORIAL(N);
|
|
for (size_t i = 0;
|
|
i < (PERMUTATION == -1 ? perm_count : 1);
|
|
i++) {
|
|
uint32_t perm[N];
|
|
size_t perm_i = PERMUTATION == -1 ? i : (size_t)PERMUTATION;
|
|
TEST_PERMUTATION(perm_i, perm, N);
|
|
|
|
// print permutation to help debugging
|
|
printf("--- permutation: %zd [", perm_i);
|
|
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_ATTRS(
|
|
LFSR_ATTR(-1, UATTR(3), 0, BUF("unrelated", 9)))) => 0;
|
|
|
|
for (unsigned j = 0; j < N; j++) {
|
|
// adjust rid based on future insertions
|
|
uint16_t rid = perm[j];
|
|
for (unsigned k = j+1; k < N; k++) {
|
|
if (perm[j] > perm[k]) {
|
|
rid -= 1;
|
|
}
|
|
}
|
|
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(rid*W, REG, +1, BUF(names[perm[j] % 6], 4)),
|
|
LFSR_ATTR(rid*W, UATTR(1), 0, BUF(names[perm[j] % 6], 2)),
|
|
LFSR_ATTR(rid*W, RM, +W-1, NULL()),
|
|
LFSR_ATTR(rid*W+W-1, UATTR(2), 0,
|
|
BUF(names[perm[j] % 6], 2)))) => 0;
|
|
}
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
assert(rbyd.weight == N*W);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(3),
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(3));
|
|
assert(rid_ == -1);
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 9);
|
|
for (unsigned j = 0; j < N; j++) {
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, j*W+W-1, LFSR_TAG_REG,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == j*W+W-1);
|
|
assert(weight_ == W);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, j*W+W-1, LFSR_TAG_UATTR(1),
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == j*W+W-1);
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, j*W+W-1, LFSR_TAG_UATTR(2),
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == j*W+W-1);
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
|
|
lfsr_rbyd_get(&lfs, &rbyd, j*W+W-1, LFSR_TAG_REG, buffer, 4) => 4;
|
|
assert(memcmp(buffer, names[j % 6], 4) == 0);
|
|
}
|
|
}
|
|
'''
|
|
|
|
[cases.test_rbyd_sparse_mixed_traverse_permutations]
|
|
defines.N = 'range(1, 8)'
|
|
defines.W = 5
|
|
# -1 => exhaust all permutations
|
|
# n => reproduce a specific permutation
|
|
defines.PERMUTATION = -1
|
|
# 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,
|
|
.eoff = 0,
|
|
.cksum = 0,
|
|
.trunk = 0,
|
|
.weight = 0,
|
|
};
|
|
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 rid_;
|
|
lfs_size_t weight_;
|
|
lfsr_data_t data_;
|
|
uint8_t buffer[4];
|
|
|
|
// test all permutations of a given size
|
|
size_t perm_count = TEST_FACTORIAL(N);
|
|
for (size_t i = 0;
|
|
i < (PERMUTATION == -1 ? perm_count : 1);
|
|
i++) {
|
|
uint32_t perm[N];
|
|
size_t perm_i = PERMUTATION == -1 ? i : (size_t)PERMUTATION;
|
|
TEST_PERMUTATION(perm_i, perm, N);
|
|
|
|
// print permutation to help debugging
|
|
printf("--- permutation: %zd [", perm_i);
|
|
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_ATTRS(
|
|
LFSR_ATTR(-1, UATTR(3), 0, BUF("unrelated", 9)))) => 0;
|
|
|
|
for (unsigned j = 0; j < N; j++) {
|
|
// adjust rid based on future insertions
|
|
uint16_t rid = perm[j];
|
|
for (unsigned k = j+1; k < N; k++) {
|
|
if (perm[j] > perm[k]) {
|
|
rid -= 1;
|
|
}
|
|
}
|
|
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(rid*W, REG, +1, BUF(names[perm[j] % 6], 4)),
|
|
LFSR_ATTR(rid*W, UATTR(1), 0, BUF(names[perm[j] % 6], 2)),
|
|
LFSR_ATTR(rid*W, RM, +W-1, NULL()),
|
|
LFSR_ATTR(rid*W+W-1, UATTR(2), 0,
|
|
BUF(names[perm[j] % 6], 2)))) => 0;
|
|
}
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
assert(rbyd.weight == N*W);
|
|
// try traversing all tags
|
|
tag_ = 0;
|
|
rid_ = -1;
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(3));
|
|
assert(rid_ == -1);
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 9);
|
|
for (unsigned j = 0; j < N; j++) {
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == j*W+W-1);
|
|
assert(weight_ == W);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
|
|
lfsr_rbyd_get(&lfs, &rbyd, rid_, tag_, buffer, 4) => 4;
|
|
assert(memcmp(buffer, names[j % 6], 4) == 0);
|
|
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == j*W+W-1);
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == j*W+W-1);
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
}
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, &weight_, &data_) => LFS_ERR_NOENT;
|
|
}
|
|
'''
|
|
|
|
|
|
# other sparse testing, various grow/shrink corner cases
|
|
|
|
[cases.test_rbyd_sparse_grow_permutations]
|
|
defines.N = 'range(1, 7)'
|
|
defines.W = 5
|
|
defines.D = [1, 2]
|
|
# -1 => exhaust all permutations
|
|
# n => reproduce a specific permutation
|
|
defines.PERMUTATION = -1
|
|
# 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,
|
|
.eoff = 0,
|
|
.cksum = 0,
|
|
.trunk = 0,
|
|
.weight = 0,
|
|
};
|
|
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 rid_;
|
|
lfs_size_t weight_;
|
|
lfsr_data_t data_;
|
|
uint8_t buffer[4];
|
|
|
|
// test all permutations of a given size
|
|
size_t perm_count = TEST_FACTORIAL(N);
|
|
for (size_t i = 0;
|
|
i < (PERMUTATION == -1 ? perm_count : 1);
|
|
i++) {
|
|
uint32_t perm[N];
|
|
size_t perm_i = PERMUTATION == -1 ? i : (size_t)PERMUTATION;
|
|
TEST_PERMUTATION(perm_i, perm, N);
|
|
|
|
// print permutation to help debugging
|
|
printf("--- permutation: %zd [", perm_i);
|
|
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 rid based on future insertions
|
|
uint16_t rid = perm[j];
|
|
for (unsigned k = j+1; k < N; k++) {
|
|
if (perm[j] > perm[k]) {
|
|
rid -= 1;
|
|
}
|
|
}
|
|
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(rid*W, REG, +W,
|
|
BUF(names[perm[j] % 6], 4)))) => 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.eoff);
|
|
lfs_bd_read(&lfs, NULL, &lfs.rcache, rbyd.eoff,
|
|
rbyd.block, 0, backup_block, rbyd.eoff) => 0;
|
|
|
|
// try growing each rid
|
|
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.eoff) => 0;
|
|
lfs_bd_flush(&lfs, &lfs.pcache, &lfs.rcache, false) => 0;
|
|
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(j*W+W-1, RM, +D, NULL()))) => 0;
|
|
assert(rbyd.weight == N*W+D);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, CFG->block_size) => 0;
|
|
assert(rbyd.weight == N*W+D);
|
|
for (unsigned k = 0; k < N; k++) {
|
|
if (k == j) {
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, k*W+W-1+D, LFSR_TAG_REG,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == k*W+W-1+D);
|
|
assert(weight_ == W+D);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
} else if (k > j) {
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, k*W+W-1+D, LFSR_TAG_REG,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == k*W+W-1+D);
|
|
assert(weight_ == W);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
} else {
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, k*W+W-1, LFSR_TAG_REG,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == k*W+W-1);
|
|
assert(weight_ == W);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
}
|
|
|
|
lfsr_rbyd_get(&lfs, &rbyd, rid_, tag_, buffer, 4) => 4;
|
|
assert(memcmp(buffer, names[k % 6], 4) == 0);
|
|
}
|
|
}
|
|
}
|
|
'''
|
|
|
|
[cases.test_rbyd_sparse_grupdate_permutations]
|
|
defines.N = 'range(1, 7)'
|
|
defines.W = 5
|
|
defines.D = [1, 2]
|
|
# -1 => exhaust all permutations
|
|
# n => reproduce a specific permutation
|
|
defines.PERMUTATION = -1
|
|
# 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,
|
|
.eoff = 0,
|
|
.cksum = 0,
|
|
.trunk = 0,
|
|
.weight = 0,
|
|
};
|
|
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 rid_;
|
|
lfs_size_t weight_;
|
|
lfsr_data_t data_;
|
|
uint8_t buffer[6];
|
|
|
|
// test all permutations of a given size
|
|
size_t perm_count = TEST_FACTORIAL(N);
|
|
for (size_t i = 0;
|
|
i < (PERMUTATION == -1 ? perm_count : 1);
|
|
i++) {
|
|
uint32_t perm[N];
|
|
size_t perm_i = PERMUTATION == -1 ? i : (size_t)PERMUTATION;
|
|
TEST_PERMUTATION(perm_i, perm, N);
|
|
|
|
// print permutation to help debugging
|
|
printf("--- permutation: %zd [", perm_i);
|
|
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 rid based on future insertions
|
|
uint16_t rid = perm[j];
|
|
for (unsigned k = j+1; k < N; k++) {
|
|
if (perm[j] > perm[k]) {
|
|
rid -= 1;
|
|
}
|
|
}
|
|
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(rid*W, REG, +W,
|
|
BUF(names[perm[j] % 6], 4)))) => 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.eoff);
|
|
lfs_bd_read(&lfs, NULL, &lfs.rcache, rbyd.eoff,
|
|
rbyd.block, 0, backup_block, rbyd.eoff) => 0;
|
|
|
|
// try growing each rid
|
|
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.eoff) => 0;
|
|
lfs_bd_flush(&lfs, &lfs.pcache, &lfs.rcache, false) => 0;
|
|
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(j*W+W-1, GROW(REG), +D,
|
|
BUF(names[j % 6], 6)))) => 0;
|
|
assert(rbyd.weight == N*W+D);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, CFG->block_size) => 0;
|
|
assert(rbyd.weight == N*W+D);
|
|
for (unsigned k = 0; k < N; k++) {
|
|
if (k == j) {
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, k*W+W-1+D, LFSR_TAG_REG,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == k*W+W-1+D);
|
|
assert(weight_ == W+D);
|
|
assert(lfsr_data_size(&data_) == 6);
|
|
|
|
lfsr_rbyd_get(&lfs, &rbyd, rid_, tag_, buffer, 6) => 6;
|
|
assert(memcmp(buffer, names[k % 6], 6) == 0);
|
|
} else if (k > j) {
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, k*W+W-1+D, LFSR_TAG_REG,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == k*W+W-1+D);
|
|
assert(weight_ == W);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
|
|
lfsr_rbyd_get(&lfs, &rbyd, rid_, tag_, buffer, 6) => 4;
|
|
assert(memcmp(buffer, names[k % 6], 4) == 0);
|
|
} else {
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, k*W+W-1, LFSR_TAG_REG,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == k*W+W-1);
|
|
assert(weight_ == W);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
|
|
lfsr_rbyd_get(&lfs, &rbyd, rid_, tag_, buffer, 6) => 4;
|
|
assert(memcmp(buffer, names[k % 6], 4) == 0);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
'''
|
|
|
|
# I don't know if this actually happens in littlefs, but this tests a specific
|
|
# code path in lfsr_rbyd_append (split altgt + shrinking)
|
|
[cases.test_rbyd_sparse_grappend_permutations]
|
|
defines.N = 'range(1, 7)'
|
|
defines.W = 5
|
|
defines.D = [1, 2]
|
|
# -1 => exhaust all permutations
|
|
# n => reproduce a specific permutation
|
|
defines.PERMUTATION = -1
|
|
# 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,
|
|
.eoff = 0,
|
|
.cksum = 0,
|
|
.trunk = 0,
|
|
.weight = 0,
|
|
};
|
|
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 rid_;
|
|
lfs_size_t weight_;
|
|
lfsr_data_t data_;
|
|
uint8_t buffer[6];
|
|
|
|
// test all permutations of a given size
|
|
size_t perm_count = TEST_FACTORIAL(N);
|
|
for (size_t i = 0;
|
|
i < (PERMUTATION == -1 ? perm_count : 1);
|
|
i++) {
|
|
uint32_t perm[N];
|
|
size_t perm_i = PERMUTATION == -1 ? i : (size_t)PERMUTATION;
|
|
TEST_PERMUTATION(perm_i, perm, N);
|
|
|
|
// print permutation to help debugging
|
|
printf("--- permutation: %zd [", perm_i);
|
|
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 rid based on future insertions
|
|
uint16_t rid = perm[j];
|
|
for (unsigned k = j+1; k < N; k++) {
|
|
if (perm[j] > perm[k]) {
|
|
rid -= 1;
|
|
}
|
|
}
|
|
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(rid*W, UATTR(2), +W,
|
|
BUF(names[perm[j] % 6], 4)))) => 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.eoff);
|
|
lfs_bd_read(&lfs, NULL, &lfs.rcache, rbyd.eoff,
|
|
rbyd.block, 0, backup_block, rbyd.eoff) => 0;
|
|
|
|
// try growing each rid
|
|
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.eoff) => 0;
|
|
lfs_bd_flush(&lfs, &lfs.pcache, &lfs.rcache, false) => 0;
|
|
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(j*W+W-1, GROW(UATTR(1)), +D,
|
|
BUF(names[j % 6], 6)))) => 0;
|
|
assert(rbyd.weight == N*W+D);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, CFG->block_size) => 0;
|
|
assert(rbyd.weight == N*W+D);
|
|
for (unsigned k = 0; k < N; k++) {
|
|
if (k == j) {
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd,
|
|
k*W+W-1+D, LFSR_TAG_UATTR(1),
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == k*W+W-1+D);
|
|
assert(weight_ == W+D);
|
|
assert(lfsr_data_size(&data_) == 6);
|
|
|
|
lfsr_rbyd_get(&lfs, &rbyd, rid_, tag_, buffer, 6) => 6;
|
|
assert(memcmp(buffer, names[k % 6], 6) == 0);
|
|
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd,
|
|
k*W+W-1+D, LFSR_TAG_UATTR(2),
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == k*W+W-1+D);
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
|
|
lfsr_rbyd_get(&lfs, &rbyd, rid_, tag_, buffer, 6) => 4;
|
|
assert(memcmp(buffer, names[k % 6], 4) == 0);
|
|
} else if (k > j) {
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd,
|
|
k*W+W-1+D, LFSR_TAG_UATTR(2),
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == k*W+W-1+D);
|
|
assert(weight_ == W);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
|
|
lfsr_rbyd_get(&lfs, &rbyd, rid_, tag_, buffer, 6) => 4;
|
|
assert(memcmp(buffer, names[k % 6], 4) == 0);
|
|
} else {
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd,
|
|
k*W+W-1, LFSR_TAG_UATTR(2),
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == k*W+W-1);
|
|
assert(weight_ == W);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
|
|
lfsr_rbyd_get(&lfs, &rbyd, rid_, tag_, buffer, 6) => 4;
|
|
assert(memcmp(buffer, names[k % 6], 4) == 0);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
'''
|
|
|
|
[cases.test_rbyd_sparse_shrink_permutations]
|
|
defines.N = 'range(1, 7)'
|
|
defines.W = 5
|
|
defines.D = [1, 2]
|
|
# -1 => exhaust all permutations
|
|
# n => reproduce a specific permutation
|
|
defines.PERMUTATION = -1
|
|
# 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,
|
|
.eoff = 0,
|
|
.cksum = 0,
|
|
.trunk = 0,
|
|
.weight = 0,
|
|
};
|
|
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 rid_;
|
|
lfs_size_t weight_;
|
|
lfsr_data_t data_;
|
|
uint8_t buffer[4];
|
|
|
|
// test all permutations of a given size
|
|
size_t perm_count = TEST_FACTORIAL(N);
|
|
for (size_t i = 0;
|
|
i < (PERMUTATION == -1 ? perm_count : 1);
|
|
i++) {
|
|
uint32_t perm[N];
|
|
size_t perm_i = PERMUTATION == -1 ? i : (size_t)PERMUTATION;
|
|
TEST_PERMUTATION(perm_i, perm, N);
|
|
|
|
// print permutation to help debugging
|
|
printf("--- permutation: %zd [", perm_i);
|
|
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 rid based on future insertions
|
|
uint16_t rid = perm[j];
|
|
for (unsigned k = j+1; k < N; k++) {
|
|
if (perm[j] > perm[k]) {
|
|
rid -= 1;
|
|
}
|
|
}
|
|
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(rid*W, REG, +W,
|
|
BUF(names[perm[j] % 6], 4)))) => 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.eoff);
|
|
lfs_bd_read(&lfs, NULL, &lfs.rcache, rbyd.eoff,
|
|
rbyd.block, 0, backup_block, rbyd.eoff) => 0;
|
|
|
|
// try shrinking each rid
|
|
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.eoff) => 0;
|
|
lfs_bd_flush(&lfs, &lfs.pcache, &lfs.rcache, false) => 0;
|
|
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(j*W+W-1, GROW, -D, NULL()))) => 0;
|
|
assert(rbyd.weight == N*W-D);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, CFG->block_size) => 0;
|
|
assert(rbyd.weight == N*W-D);
|
|
for (unsigned k = 0; k < N; k++) {
|
|
if (k == j) {
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, k*W+W-1-D, LFSR_TAG_REG,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == k*W+W-1-D);
|
|
assert(weight_ == W-D);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
} else if (k > j) {
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, k*W+W-1-D, LFSR_TAG_REG,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == k*W+W-1-D);
|
|
assert(weight_ == W);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
} else {
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, k*W+W-1, LFSR_TAG_REG,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == k*W+W-1);
|
|
assert(weight_ == W);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
}
|
|
|
|
lfsr_rbyd_get(&lfs, &rbyd, rid_, tag_, buffer, 4) => 4;
|
|
assert(memcmp(buffer, names[k % 6], 4) == 0);
|
|
}
|
|
}
|
|
}
|
|
'''
|
|
|
|
[cases.test_rbyd_sparse_shrupdate_permutations]
|
|
defines.N = 'range(1, 7)'
|
|
defines.W = 5
|
|
defines.D = [1, 2]
|
|
# -1 => exhaust all permutations
|
|
# n => reproduce a specific permutation
|
|
defines.PERMUTATION = -1
|
|
# 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,
|
|
.eoff = 0,
|
|
.cksum = 0,
|
|
.trunk = 0,
|
|
.weight = 0,
|
|
};
|
|
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 rid_;
|
|
lfs_size_t weight_;
|
|
lfsr_data_t data_;
|
|
uint8_t buffer[6];
|
|
|
|
// test all permutations of a given size
|
|
size_t perm_count = TEST_FACTORIAL(N);
|
|
for (size_t i = 0;
|
|
i < (PERMUTATION == -1 ? perm_count : 1);
|
|
i++) {
|
|
uint32_t perm[N];
|
|
size_t perm_i = PERMUTATION == -1 ? i : (size_t)PERMUTATION;
|
|
TEST_PERMUTATION(perm_i, perm, N);
|
|
|
|
// print permutation to help debugging
|
|
printf("--- permutation: %zd [", perm_i);
|
|
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 rid based on future insertions
|
|
uint16_t rid = perm[j];
|
|
for (unsigned k = j+1; k < N; k++) {
|
|
if (perm[j] > perm[k]) {
|
|
rid -= 1;
|
|
}
|
|
}
|
|
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(rid*W, REG, +W,
|
|
BUF(names[perm[j] % 6], 4)))) => 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.eoff);
|
|
lfs_bd_read(&lfs, NULL, &lfs.rcache, rbyd.eoff,
|
|
rbyd.block, 0, backup_block, rbyd.eoff) => 0;
|
|
|
|
// try shrinking each rid
|
|
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.eoff) => 0;
|
|
lfs_bd_flush(&lfs, &lfs.pcache, &lfs.rcache, false) => 0;
|
|
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(j*W+W-1, GROW(REG), -D,
|
|
BUF(names[j % 6], 6)))) => 0;
|
|
assert(rbyd.weight == N*W-D);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, CFG->block_size) => 0;
|
|
assert(rbyd.weight == N*W-D);
|
|
for (unsigned k = 0; k < N; k++) {
|
|
if (k == j) {
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, k*W+W-1-D, LFSR_TAG_REG,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == k*W+W-1-D);
|
|
assert(weight_ == W-D);
|
|
assert(lfsr_data_size(&data_) == 6);
|
|
|
|
lfsr_rbyd_get(&lfs, &rbyd, rid_, tag_, buffer, 6) => 6;
|
|
assert(memcmp(buffer, names[k % 6], 6) == 0);
|
|
} else if (k > j) {
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, k*W+W-1-D, LFSR_TAG_REG,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == k*W+W-1-D);
|
|
assert(weight_ == W);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
|
|
lfsr_rbyd_get(&lfs, &rbyd, rid_, tag_, buffer, 6) => 4;
|
|
assert(memcmp(buffer, names[k % 6], 4) == 0);
|
|
} else {
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, k*W+W-1, LFSR_TAG_REG,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == k*W+W-1);
|
|
assert(weight_ == W);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
|
|
lfsr_rbyd_get(&lfs, &rbyd, rid_, tag_, buffer, 6) => 4;
|
|
assert(memcmp(buffer, names[k % 6], 4) == 0);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
'''
|
|
|
|
# I don't know if this actually happens in littlefs, but this tests a specific
|
|
# code path in lfsr_rbyd_append (split altgt + shrinking)
|
|
[cases.test_rbyd_sparse_shrappend_permutations]
|
|
defines.N = 'range(1, 7)'
|
|
defines.W = 5
|
|
defines.D = [1, 2]
|
|
# -1 => exhaust all permutations
|
|
# n => reproduce a specific permutation
|
|
defines.PERMUTATION = -1
|
|
# 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,
|
|
.eoff = 0,
|
|
.cksum = 0,
|
|
.trunk = 0,
|
|
.weight = 0,
|
|
};
|
|
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 rid_;
|
|
lfs_size_t weight_;
|
|
lfsr_data_t data_;
|
|
uint8_t buffer[6];
|
|
|
|
// test all permutations of a given size
|
|
size_t perm_count = TEST_FACTORIAL(N);
|
|
for (size_t i = 0;
|
|
i < (PERMUTATION == -1 ? perm_count : 1);
|
|
i++) {
|
|
uint32_t perm[N];
|
|
size_t perm_i = PERMUTATION == -1 ? i : (size_t)PERMUTATION;
|
|
TEST_PERMUTATION(perm_i, perm, N);
|
|
|
|
// print permutation to help debugging
|
|
printf("--- permutation: %zd [", perm_i);
|
|
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 rid based on future insertions
|
|
uint16_t rid = perm[j];
|
|
for (unsigned k = j+1; k < N; k++) {
|
|
if (perm[j] > perm[k]) {
|
|
rid -= 1;
|
|
}
|
|
}
|
|
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(rid*W, UATTR(2), +W,
|
|
BUF(names[perm[j] % 6], 4)))) => 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.eoff);
|
|
lfs_bd_read(&lfs, NULL, &lfs.rcache, rbyd.eoff,
|
|
rbyd.block, 0, backup_block, rbyd.eoff) => 0;
|
|
|
|
// try shrinking each rid
|
|
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.eoff) => 0;
|
|
lfs_bd_flush(&lfs, &lfs.pcache, &lfs.rcache, false) => 0;
|
|
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(j*W+W-1, GROW(UATTR(1)), -D,
|
|
BUF(names[j % 6], 6)))) => 0;
|
|
assert(rbyd.weight == N*W-D);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, CFG->block_size) => 0;
|
|
assert(rbyd.weight == N*W-D);
|
|
for (unsigned k = 0; k < N; k++) {
|
|
if (k == j) {
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd,
|
|
k*W+W-1-D, LFSR_TAG_UATTR(1),
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == k*W+W-1-D);
|
|
assert(weight_ == W-D);
|
|
assert(lfsr_data_size(&data_) == 6);
|
|
|
|
lfsr_rbyd_get(&lfs, &rbyd, rid_, tag_, buffer, 6) => 6;
|
|
assert(memcmp(buffer, names[k % 6], 6) == 0);
|
|
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd,
|
|
k*W+W-1-D, LFSR_TAG_UATTR(2),
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == k*W+W-1-D);
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
|
|
lfsr_rbyd_get(&lfs, &rbyd, rid_, tag_, buffer, 6) => 4;
|
|
assert(memcmp(buffer, names[k % 6], 4) == 0);
|
|
} else if (k > j) {
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd,
|
|
k*W+W-1-D, LFSR_TAG_UATTR(2),
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == k*W+W-1-D);
|
|
assert(weight_ == W);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
|
|
lfsr_rbyd_get(&lfs, &rbyd, rid_, tag_, buffer, 6) => 4;
|
|
assert(memcmp(buffer, names[k % 6], 4) == 0);
|
|
} else {
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd,
|
|
k*W+W-1, LFSR_TAG_UATTR(2),
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(rid_ == k*W+W-1);
|
|
assert(weight_ == W);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
|
|
lfsr_rbyd_get(&lfs, &rbyd, rid_, tag_, buffer, 6) => 4;
|
|
assert(memcmp(buffer, names[k % 6], 4) == 0);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
'''
|
|
|
|
[cases.test_rbyd_sparse_delete_permutations]
|
|
defines.N = 'range(1, 7)'
|
|
defines.W = 5
|
|
# -1 => exhaust all permutations
|
|
# n => reproduce a specific permutation
|
|
defines.PERMUTATION = -1
|
|
# 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,
|
|
.eoff = 0,
|
|
.cksum = 0,
|
|
.trunk = 0,
|
|
.weight = 0,
|
|
};
|
|
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 rid_;
|
|
lfs_size_t weight_;
|
|
lfsr_data_t data_;
|
|
uint8_t buffer[6];
|
|
|
|
// test all permutations of a given size
|
|
size_t perm_count = TEST_FACTORIAL(N);
|
|
for (size_t i = 0;
|
|
i < (PERMUTATION == -1 ? perm_count : 1);
|
|
i++) {
|
|
uint32_t perm[N];
|
|
size_t perm_i = PERMUTATION == -1 ? i : (size_t)PERMUTATION;
|
|
TEST_PERMUTATION(perm_i, perm, N);
|
|
|
|
// print permutation to help debugging
|
|
printf("--- permutation: %zd [", perm_i);
|
|
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 rid based on future insertions
|
|
uint16_t rid = perm[j];
|
|
for (unsigned k = j+1; k < N; k++) {
|
|
if (perm[j] > perm[k]) {
|
|
rid -= 1;
|
|
}
|
|
}
|
|
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(rid*W, REG, +W,
|
|
BUF(names[perm[j] % 6], 4)))) => 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.eoff);
|
|
lfs_bd_read(&lfs, NULL, &lfs.rcache, rbyd.eoff,
|
|
rbyd.block, 0, backup_block, rbyd.eoff) => 0;
|
|
|
|
// try deleting each rid
|
|
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.eoff) => 0;
|
|
lfs_bd_flush(&lfs, &lfs.pcache, &lfs.rcache, false) => 0;
|
|
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(j*W+W-1, RM, -W, NULL()))) => 0;
|
|
assert(rbyd.weight == (N-1)*W);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, CFG->block_size) => 0;
|
|
assert(rbyd.weight == (N-1)*W);
|
|
for (unsigned k = 0; k < N-1; k++) {
|
|
if (k >= j) {
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, k*W+W-1, LFSR_TAG_REG,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == k*W+W-1);
|
|
assert(weight_ == W);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
|
|
lfsr_rbyd_get(&lfs, &rbyd, rid_, tag_, buffer, 4) => 4;
|
|
assert(memcmp(buffer, names[(k+1) % 6], 4) == 0);
|
|
} else {
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, k*W+W-1, LFSR_TAG_REG,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == k*W+W-1);
|
|
assert(weight_ == W);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
|
|
lfsr_rbyd_get(&lfs, &rbyd, rid_, tag_, buffer, 4) => 4;
|
|
assert(memcmp(buffer, names[k % 6], 4) == 0);
|
|
}
|
|
}
|
|
|
|
// try recreating the rid to make sure things still work
|
|
printf("--- create: %d ---\n", j);
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(j*W, REG, +W, BUF(names[j % 6], 6)))) => 0;
|
|
assert(rbyd.weight == N*W);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, CFG->block_size) => 0;
|
|
assert(rbyd.weight == N*W);
|
|
for (unsigned k = 0; k < N; k++) {
|
|
if (k == j) {
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, k*W+W-1, LFSR_TAG_REG,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == k*W+W-1);
|
|
assert(weight_ == W);
|
|
assert(lfsr_data_size(&data_) == 6);
|
|
|
|
lfsr_rbyd_get(&lfs, &rbyd, rid_, tag_, buffer, 6) => 6;
|
|
assert(memcmp(buffer, names[k % 6], 6) == 0);
|
|
} else {
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, k*W+W-1, LFSR_TAG_REG,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == k*W+W-1);
|
|
assert(weight_ == W);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
|
|
lfsr_rbyd_get(&lfs, &rbyd, rid_, tag_, buffer, 6) => 4;
|
|
assert(memcmp(buffer, names[k % 6], 4) == 0);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
'''
|
|
|
|
[cases.test_rbyd_sparse_attr_permutations]
|
|
defines.N = 'range(1, 7)'
|
|
defines.W = 5
|
|
# -1 => exhaust all permutations
|
|
# n => reproduce a specific permutation
|
|
defines.PERMUTATION = -1
|
|
# 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,
|
|
.eoff = 0,
|
|
.cksum = 0,
|
|
.trunk = 0,
|
|
.weight = 0,
|
|
};
|
|
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 rid_;
|
|
lfs_size_t weight_;
|
|
lfsr_data_t data_;
|
|
uint8_t buffer[4];
|
|
|
|
// test all permutations of a given size
|
|
size_t perm_count = TEST_FACTORIAL(N);
|
|
for (size_t i = 0;
|
|
i < (PERMUTATION == -1 ? perm_count : 1);
|
|
i++) {
|
|
uint32_t perm[N];
|
|
size_t perm_i = PERMUTATION == -1 ? i : (size_t)PERMUTATION;
|
|
TEST_PERMUTATION(perm_i, perm, N);
|
|
|
|
// print permutation to help debugging
|
|
printf("--- permutation: %zd [", perm_i);
|
|
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 rid based on future insertions
|
|
uint16_t rid = perm[j];
|
|
for (unsigned k = j+1; k < N; k++) {
|
|
if (perm[j] > perm[k]) {
|
|
rid -= 1;
|
|
}
|
|
}
|
|
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(rid*W, REG, +W,
|
|
BUF(names[perm[j] % 6], 4)))) => 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.eoff);
|
|
lfs_bd_read(&lfs, NULL, &lfs.rcache, rbyd.eoff,
|
|
rbyd.block, 0, backup_block, rbyd.eoff) => 0;
|
|
|
|
// try appending an attr to each rid, 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.eoff) => 0;
|
|
lfs_bd_flush(&lfs, &lfs.pcache, &lfs.rcache, false) => 0;
|
|
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(j*W+W-1, UATTR(1), 0,
|
|
BUF(names[j % 6], 2)))) => 0;
|
|
assert(rbyd.weight == N*W);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, CFG->block_size) => 0;
|
|
assert(rbyd.weight == N*W);
|
|
for (unsigned k = 0; k < N; k++) {
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, k*W+W-1, LFSR_TAG_REG,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == k*W+W-1);
|
|
assert(weight_ == W);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
|
|
lfsr_rbyd_get(&lfs, &rbyd, rid_, tag_, buffer, 4) => 4;
|
|
assert(memcmp(buffer, names[k % 6], 4) == 0);
|
|
|
|
if (k == j) {
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd,
|
|
k*W+W-1, LFSR_TAG_UATTR(1),
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == k*W+W-1);
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
}
|
|
}
|
|
|
|
// now try removing the attr
|
|
printf("--- removing: %d ---\n", j);
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(j*W+W-1, RM(UATTR(1)), 0, NULL()))) => 0;
|
|
assert(rbyd.weight == N*W);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, CFG->block_size) => 0;
|
|
assert(rbyd.weight == N*W);
|
|
for (unsigned k = 0; k < N; k++) {
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, k*W+W-1, LFSR_TAG_REG,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == k*W+W-1);
|
|
assert(weight_ == W);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
|
|
lfsr_rbyd_get(&lfs, &rbyd, rid_, tag_, buffer, 4) => 4;
|
|
assert(memcmp(buffer, names[k % 6], 4) == 0);
|
|
|
|
if (k == j) {
|
|
lfsr_rbyd_get(&lfs, &rbyd, k*W+W-1, LFSR_TAG_UATTR(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_ATTRS(
|
|
LFSR_ATTR(j*W+W-1, UATTR(1), 0,
|
|
BUF(names[j % 6], 2)))) => 0;
|
|
assert(rbyd.weight == N*W);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, CFG->block_size) => 0;
|
|
assert(rbyd.weight == N*W);
|
|
for (unsigned k = 0; k < N; k++) {
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, k*W+W-1, LFSR_TAG_REG,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(rid_ == k*W+W-1);
|
|
assert(weight_ == W);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
|
|
lfsr_rbyd_get(&lfs, &rbyd, rid_, tag_, buffer, 4) => 4;
|
|
assert(memcmp(buffer, names[k % 6], 4) == 0);
|
|
|
|
if (k == j) {
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd,
|
|
k*W+W-1, LFSR_TAG_UATTR(1),
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(rid_ == k*W+W-1);
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
'''
|
|
|
|
|
|
# Some more fuzzish testing
|
|
|
|
[cases.test_rbyd_fuzz_mixed]
|
|
defines.N = 'range(1, 33)'
|
|
defines.M = 3
|
|
defines.SEED = 'range(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,
|
|
.eoff = 0,
|
|
.cksum = 0,
|
|
.trunk = 0,
|
|
.weight = 0,
|
|
};
|
|
lfsr_rbyd_t rbyd;
|
|
const char *alpha = "abcdefghijklmnopqrstuvwxyz";
|
|
uint8_t buffer[4];
|
|
|
|
printf("perm: [");
|
|
uint32_t prng = SEED;
|
|
lfs_size_t count = 0;
|
|
for (unsigned i = 0; i < N; i++) {
|
|
// choose create/delete or attr append/remove
|
|
uint8_t op = TEST_PRNG(&prng) % 4;
|
|
// choose an rid
|
|
lfs_ssize_t rid = TEST_PRNG(&prng) % (count+1);
|
|
// choose an attr
|
|
uint8_t u = TEST_PRNG(&prng) % M;
|
|
|
|
if (rid == (lfs_ssize_t)count || op == 0) {
|
|
printf("c%d=%c", rid, alpha[i % 26]);
|
|
count += 1;
|
|
} else if (op == 1) {
|
|
printf("d%d", rid);
|
|
count -= 1;
|
|
} else if (op == 2) {
|
|
printf("a%d,%d=%c", rid, u, alpha[i % 26]);
|
|
} else if (op == 3) {
|
|
printf("r%d,%d", rid, u);
|
|
}
|
|
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*(M+1));
|
|
memset(sim, 0, N*(M+1));
|
|
|
|
// 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 create/delete or attr append/remove
|
|
uint8_t op = TEST_PRNG(&prng) % 4;
|
|
// choose an rid
|
|
lfs_ssize_t rid = TEST_PRNG(&prng) % (count+1);
|
|
// choose an attr
|
|
uint8_t u = TEST_PRNG(&prng) % M;
|
|
|
|
if (rid == (lfs_ssize_t)count || op == 0) {
|
|
// update our sim
|
|
memmove(sim+(rid+1)*(M+1), sim+rid*(M+1), (count-rid)*(M+1));
|
|
memset(&sim[rid*(M+1)], 0, M+1);
|
|
sim[rid*(M+1)] = alpha[i % 26];
|
|
count += 1;
|
|
// update our rbyd
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(rid, REG, +1, BUF(&alpha[i % 26], 1)))) => 0;
|
|
} else if (op == 1) {
|
|
// update our sim
|
|
memmove(sim+rid*(M+1), sim+(rid+1)*(M+1), (count-rid-1)*(M+1));
|
|
count -= 1;
|
|
// update our rbyd
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(rid, RM, -1, NULL()))) => 0;
|
|
} else if (op == 2) {
|
|
// update our sim
|
|
sim[rid*(M+1) + u+1] = alpha[i % 26];
|
|
// update our rbyd
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(rid, UATTR(u), 0, BUF(&alpha[i % 26], 1)))) => 0;
|
|
|
|
} else if (op == 3) {
|
|
// update our sim
|
|
sim[rid*(M+1) + u+1] = '\0';
|
|
// update our rbyd
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(rid, RM(UATTR(u)), 0, NULL()))) => 0;
|
|
}
|
|
}
|
|
|
|
// compare rbyd vs simulation
|
|
printf("expd: [");
|
|
for (lfs_ssize_t rid = 0; rid < (lfs_ssize_t)count; rid++) {
|
|
printf("%c", sim[rid*(M+1)]);
|
|
for (uint8_t u = 0; u < M; u++) {
|
|
if (sim[rid*(M+1) + u+1]) {
|
|
printf("%c", sim[rid*(M+1) + u+1]);
|
|
} else {
|
|
printf("_");
|
|
}
|
|
}
|
|
if (rid < (lfs_ssize_t)count-1) {
|
|
printf(", ");
|
|
}
|
|
}
|
|
printf("]\n");
|
|
printf("rbyd: [");
|
|
for (lfs_ssize_t rid = 0; rid < (lfs_ssize_t)rbyd.weight; rid++) {
|
|
lfs_ssize_t size = lfsr_rbyd_get(&lfs, &rbyd,
|
|
rid, LFSR_TAG_REG, buffer, 4);
|
|
if (size >= 0) {
|
|
printf("%.*s", size, buffer);
|
|
} else {
|
|
printf("?");
|
|
}
|
|
for (uint8_t u = 0; u < M; u++) {
|
|
lfs_ssize_t size = lfsr_rbyd_get(&lfs, &rbyd,
|
|
rid, LFSR_TAG_UATTR(u), buffer, 4);
|
|
if (size >= 0) {
|
|
printf("%.*s", size, buffer);
|
|
} else {
|
|
printf("_");
|
|
}
|
|
}
|
|
if (rid < (lfs_ssize_t)count-1) {
|
|
printf(", ");
|
|
}
|
|
}
|
|
printf("]\n");
|
|
|
|
assert(count == rbyd.weight);
|
|
for (lfs_ssize_t rid = 0; rid < (lfs_ssize_t)count; rid++) {
|
|
lfsr_rbyd_get(&lfs, &rbyd, rid, LFSR_TAG_REG, buffer, 4) => 1;
|
|
assert(memcmp(&sim[rid*(M+1)], buffer, 1) == 0);
|
|
}
|
|
|
|
// cleanup
|
|
free(sim);
|
|
'''
|
|
|
|
[cases.test_rbyd_fuzz_sparse]
|
|
defines.N = 'range(1, 33)'
|
|
defines.W = 5
|
|
defines.SEED = 'range(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,
|
|
.eoff = 0,
|
|
.cksum = 0,
|
|
.trunk = 0,
|
|
.weight = 0,
|
|
};
|
|
lfsr_rbyd_t rbyd;
|
|
lfsr_tag_t tag_;
|
|
lfs_ssize_t rid_;
|
|
lfs_size_t weight_;
|
|
lfsr_data_t data_;
|
|
const char *alpha = "abcdefghijklmnopqrstuvwxyz";
|
|
uint8_t buffer[4];
|
|
|
|
printf("perm: [");
|
|
uint32_t prng = SEED;
|
|
lfs_size_t count = 0;
|
|
for (unsigned i = 0; i < N; i++) {
|
|
// choose create/delete/grow/shrink
|
|
uint8_t op = TEST_PRNG(&prng) % 4;
|
|
// choose an rid
|
|
lfs_ssize_t rid = TEST_PRNG(&prng) % (count+1);
|
|
// choose a weight
|
|
lfs_size_t weight = 1 + (TEST_PRNG(&prng) % W);
|
|
|
|
if (rid == (lfs_ssize_t)count || op == 0) {
|
|
printf("c%dw%d=%c", rid, weight, alpha[i % 26]);
|
|
count += 1;
|
|
} else if (op == 1) {
|
|
printf("d%d", rid);
|
|
count -= 1;
|
|
} else if (op == 2) {
|
|
printf("g%dw%d", rid, weight);
|
|
} else if (op == 3) {
|
|
printf("s%dw%d", rid, weight);
|
|
}
|
|
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);
|
|
lfs_size_t *sim_weights = malloc(N*sizeof(lfs_size_t));
|
|
memset(sim, 0, N);
|
|
memset(sim_weights, 0, N*sizeof(lfs_size_t));
|
|
|
|
// 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 create/delete/grow/shrink
|
|
uint8_t op = TEST_PRNG(&prng) % 4;
|
|
// choose an rid
|
|
lfs_ssize_t rid = TEST_PRNG(&prng) % (count+1);
|
|
// choose a weight
|
|
lfs_size_t weight = 1 + (TEST_PRNG(&prng) % W);
|
|
|
|
// calculate actual rid in rbyd space
|
|
lfs_ssize_t weighted_rid = 0;
|
|
for (lfs_ssize_t j = 0; j < rid; j++) {
|
|
weighted_rid += sim_weights[j];
|
|
}
|
|
|
|
if (rid == (lfs_ssize_t)count || op == 0) {
|
|
// update our sim
|
|
memmove(sim+rid+1, sim+rid, count-rid);
|
|
memmove(sim_weights+rid+1, sim_weights+rid,
|
|
(count-rid)*sizeof(lfs_size_t));
|
|
sim[rid] = alpha[i % 26];
|
|
sim_weights[rid] = weight;
|
|
count += 1;
|
|
// update our rbyd
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(weighted_rid, REG, +weight,
|
|
BUF(&alpha[i % 26], 1)))) => 0;
|
|
} else if (op == 1) {
|
|
// get the correct weight from the sim
|
|
weight_ = sim_weights[rid];
|
|
// update our sim
|
|
memmove(sim+rid, sim+rid+1, count-rid-1);
|
|
memmove(sim_weights+rid, sim_weights+rid+1,
|
|
(count-rid-1)*sizeof(lfs_size_t));
|
|
count -= 1;
|
|
// update our rbyd
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(weighted_rid+weight_-1, RM, -weight_,
|
|
NULL()))) => 0;
|
|
} else if (op == 2) {
|
|
// get the correct weight from the sim
|
|
weight_ = sim_weights[rid];
|
|
// update our sim
|
|
sim_weights[rid] += weight;
|
|
// update our rbyd
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(weighted_rid+weight_-1, GROW, +weight,
|
|
NULL()))) => 0;
|
|
} else if (op == 3) {
|
|
// get the correct weight from the sim
|
|
weight_ = sim_weights[rid];
|
|
// don't let shrink go to zero here! this is already hard enough
|
|
// to simulate
|
|
weight = lfs_min(weight, weight_-1);
|
|
// update our sim
|
|
sim_weights[rid] -= weight;
|
|
// update our rbyd
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(weighted_rid+weight_-1, GROW, -weight,
|
|
NULL()))) => 0;
|
|
}
|
|
}
|
|
|
|
// compare rbyd vs simulation
|
|
printf("expd: [");
|
|
for (lfs_ssize_t rid = 0; rid < (lfs_ssize_t)count; rid++) {
|
|
printf("%cw%d", sim[rid], sim_weights[rid]);
|
|
if (rid < (lfs_ssize_t)count-1) {
|
|
printf(", ");
|
|
}
|
|
}
|
|
printf("]\n");
|
|
printf("rbyd: [");
|
|
for (lfs_ssize_t rid = 0; rid < (lfs_ssize_t)count; rid++) {
|
|
// calculate actual rid in rbyd space
|
|
lfs_ssize_t weighted_rid = 0;
|
|
for (lfs_ssize_t j = 0; j < rid; j++) {
|
|
weighted_rid += sim_weights[j];
|
|
}
|
|
|
|
int err = lfsr_rbyd_lookupnext(&lfs, &rbyd,
|
|
weighted_rid, LFSR_TAG_REG,
|
|
&rid_, &tag_, &weight_, &data_);
|
|
if (!err) {
|
|
lfs_ssize_t size = lfsr_rbyd_get(&lfs, &rbyd,
|
|
rid_, tag_, buffer, 4);
|
|
if (size >= 0) {
|
|
printf("%.*sw%d", size, buffer, weight_);
|
|
} else {
|
|
printf("?");
|
|
}
|
|
} else {
|
|
printf("?");
|
|
}
|
|
if (rid < (lfs_ssize_t)count-1) {
|
|
printf(", ");
|
|
}
|
|
}
|
|
printf("]\n");
|
|
|
|
// calculate total weight
|
|
lfs_size_t total_weight = 0;
|
|
for (lfs_ssize_t j = 0; j < (lfs_ssize_t)count; j++) {
|
|
total_weight += sim_weights[j];
|
|
}
|
|
assert(total_weight == rbyd.weight);
|
|
|
|
for (lfs_ssize_t rid = 0; rid < (lfs_ssize_t)count; rid++) {
|
|
// calculate actual rid in rbyd space
|
|
lfs_ssize_t weighted_rid = 0;
|
|
for (lfs_ssize_t j = 0; j < rid; j++) {
|
|
weighted_rid += sim_weights[j];
|
|
}
|
|
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd,
|
|
weighted_rid, LFSR_TAG_REG,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
lfsr_rbyd_get(&lfs, &rbyd, rid_, tag_, buffer, 4) => 1;
|
|
assert(memcmp(&sim[rid], buffer, 1) == 0);
|
|
}
|
|
|
|
// cleanup
|
|
free(sim);
|
|
free(sim_weights);
|
|
'''
|
|
|
|
|
|
### Wide-tag things ###
|
|
|
|
[cases.test_rbyd_wide_lookup_permutations]
|
|
defines.N = 'range(1, 7)'
|
|
defines.SHIFT = [0, 3, -3]
|
|
# -1 => exhaust all permutations
|
|
# n => reproduce a specific permutation
|
|
defines.PERMUTATION = -1
|
|
in = 'lfs.c'
|
|
code = '''
|
|
lfs_t lfs;
|
|
lfs_init(&lfs, CFG) => 0;
|
|
|
|
lfsr_rbyd_t init_rbyd = {
|
|
.block = 0,
|
|
.eoff = 0,
|
|
.cksum = 0,
|
|
.trunk = 0,
|
|
.weight = 0,
|
|
};
|
|
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",
|
|
};
|
|
|
|
// test all permutations of a given size
|
|
size_t perm_count = TEST_FACTORIAL(N);
|
|
for (size_t i = 0;
|
|
i < (PERMUTATION == -1 ? perm_count : 1);
|
|
i++) {
|
|
uint32_t perm[N];
|
|
size_t perm_i = PERMUTATION == -1 ? i : (size_t)PERMUTATION;
|
|
TEST_PERMUTATION(perm_i, perm, N);
|
|
|
|
// print permutation to help debugging
|
|
printf("--- permutation: %zd [", perm_i);
|
|
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
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
for (unsigned j = 0; j < N; j++) {
|
|
// adjust rid based on future insertions
|
|
uint16_t rid = perm[j];
|
|
for (unsigned k = j+1; k < N; k++) {
|
|
if (perm[j] > perm[k]) {
|
|
rid -= 1;
|
|
}
|
|
}
|
|
|
|
// give each attr a subtype based on its rid + SHIFT
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(rid, REG, +1, BUF(names[perm[j] % 6], 4)),
|
|
LFSR_ATTR(rid, UATTR((perm[j] + SHIFT) & 0x7f), 0,
|
|
BUF(names[perm[j] % 6], 2)))) => 0;
|
|
}
|
|
assert(rbyd.weight == N);
|
|
|
|
// test that we can lookup each attr with a wide lookup
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
assert(rbyd.weight == N);
|
|
|
|
for (unsigned j = 0; j < N; j++) {
|
|
lfsr_tag_t tag_;
|
|
lfsr_data_t data_;
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, j, LFSR_TAG_WIDE(UATTR),
|
|
&tag_, &data_) => 0;
|
|
|
|
assert(tag_ == LFSR_TAG_UATTR((j + SHIFT) & 0x7f));
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
}
|
|
}
|
|
'''
|
|
|
|
# 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_wide_remove_permutations]
|
|
defines.N = 'range(1, 7)'
|
|
defines.SHIFT = [0, 3, -3]
|
|
# -1 => exhaust all permutations
|
|
# n => reproduce a specific permutation
|
|
defines.PERMUTATION = -1
|
|
# 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,
|
|
.eoff = 0,
|
|
.cksum = 0,
|
|
.trunk = 0,
|
|
.weight = 0,
|
|
};
|
|
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",
|
|
};
|
|
|
|
// test all permutations of a given size
|
|
size_t perm_count = TEST_FACTORIAL(N);
|
|
for (size_t i = 0;
|
|
i < (PERMUTATION == -1 ? perm_count : 1);
|
|
i++) {
|
|
uint32_t perm[N];
|
|
size_t perm_i = PERMUTATION == -1 ? i : (size_t)PERMUTATION;
|
|
TEST_PERMUTATION(perm_i, perm, N);
|
|
|
|
// print permutation to help debugging
|
|
printf("--- permutation: %zd [", perm_i);
|
|
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 rid based on future insertions
|
|
uint16_t rid = perm[j];
|
|
for (unsigned k = j+1; k < N; k++) {
|
|
if (perm[j] > perm[k]) {
|
|
rid -= 1;
|
|
}
|
|
}
|
|
|
|
// give each attr a subtype based on its rid + SHIFT
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(rid, REG, +1, BUF(names[perm[j] % 6], 4)),
|
|
LFSR_ATTR(rid, UATTR((perm[j] + SHIFT) & 0x7f), 0,
|
|
BUF(names[perm[j] % 6], 2)))) => 0;
|
|
}
|
|
assert(rbyd.weight == N);
|
|
|
|
// copy block so we can reset after each remove
|
|
lfsr_rbyd_t backup_rbyd = rbyd;
|
|
uint8_t *backup_block = malloc(rbyd.eoff);
|
|
lfs_bd_read(&lfs, NULL, &lfs.rcache, rbyd.eoff,
|
|
rbyd.block, 0, backup_block, rbyd.eoff) => 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.eoff) => 0;
|
|
lfs_bd_flush(&lfs, &lfs.pcache, &lfs.rcache, false) => 0;
|
|
|
|
// remove with a wide tag
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(j, RM(WIDE(UATTR)), 0, NULL()))) => 0;
|
|
|
|
// try traversing over the tags
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, CFG->block_size) => 0;
|
|
lfsr_tag_t tag_ = 0;
|
|
lfs_ssize_t rid_ = -1;
|
|
lfs_size_t weight_;
|
|
lfsr_data_t data_;
|
|
for (unsigned k = 0; k < N; k++) {
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(rid_ == k);
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(weight_ == 1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
|
|
if (k != j) {
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(rid_ == k);
|
|
assert(tag_ == LFSR_TAG_UATTR((k + SHIFT) & 0x7f));
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
}
|
|
}
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, &weight_, &data_) => LFS_ERR_NOENT;
|
|
|
|
// also test that we can lookup each tag with a wide lookup
|
|
for (unsigned k = 0; k < N; k++) {
|
|
if (k == j) {
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, k, LFSR_TAG_WIDE(UATTR),
|
|
&tag_, &data_) => LFS_ERR_NOENT;
|
|
} else {
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, k, LFSR_TAG_WIDE(UATTR),
|
|
&tag_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR((k + SHIFT) & 0x7f));
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
}
|
|
}
|
|
}
|
|
|
|
// cleanup
|
|
free(backup_block);
|
|
}
|
|
'''
|
|
|
|
# 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_wide_replace_permutations]
|
|
defines.N = 'range(1, 7)'
|
|
defines.SHIFT = [0, 3, -3]
|
|
# -1 => exhaust all permutations
|
|
# n => reproduce a specific permutation
|
|
defines.PERMUTATION = -1
|
|
# 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,
|
|
.eoff = 0,
|
|
.cksum = 0,
|
|
.trunk = 0,
|
|
.weight = 0,
|
|
};
|
|
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",
|
|
};
|
|
|
|
// test all permutations of a given size
|
|
size_t perm_count = TEST_FACTORIAL(N);
|
|
for (size_t i = 0;
|
|
i < (PERMUTATION == -1 ? perm_count : 1);
|
|
i++) {
|
|
uint32_t perm[N];
|
|
size_t perm_i = PERMUTATION == -1 ? i : (size_t)PERMUTATION;
|
|
TEST_PERMUTATION(perm_i, perm, N);
|
|
|
|
// print permutation to help debugging
|
|
printf("--- permutation: %zd [", perm_i);
|
|
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 rid based on future insertions
|
|
uint16_t rid = perm[j];
|
|
for (unsigned k = j+1; k < N; k++) {
|
|
if (perm[j] > perm[k]) {
|
|
rid -= 1;
|
|
}
|
|
}
|
|
|
|
// give each attr a subtype based on its rid + SHIFT
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(rid, REG, +1, BUF(names[perm[j] % 6], 4)),
|
|
LFSR_ATTR(rid, UATTR((perm[j] + SHIFT) & 0x7f), 0,
|
|
BUF(names[perm[j] % 6], 2)))) => 0;
|
|
}
|
|
assert(rbyd.weight == N);
|
|
|
|
// copy block so we can reset after each remove
|
|
lfsr_rbyd_t backup_rbyd = rbyd;
|
|
uint8_t *backup_block = malloc(rbyd.eoff);
|
|
lfs_bd_read(&lfs, NULL, &lfs.rcache, rbyd.eoff,
|
|
rbyd.block, 0, backup_block, rbyd.eoff) => 0;
|
|
|
|
// try replacing each tag
|
|
for (unsigned j = 0; j < N; j++) {
|
|
// print what we are replacing to help debugging
|
|
printf("--- replace: %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.eoff) => 0;
|
|
lfs_bd_flush(&lfs, &lfs.pcache, &lfs.rcache, false) => 0;
|
|
|
|
// replace with bitwise inverse
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(j, WIDE(UATTR(~(j + SHIFT) & 0x7f)), 0,
|
|
BUF(names[j % 6], 3)))) => 0;
|
|
|
|
// try traversing over the tags
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, CFG->block_size) => 0;
|
|
lfsr_tag_t tag_ = 0;
|
|
lfs_ssize_t rid_ = -1;
|
|
lfs_size_t weight_;
|
|
lfsr_data_t data_;
|
|
for (unsigned k = 0; k < N; k++) {
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(rid_ == k);
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(weight_ == 1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
if (k == j) {
|
|
assert(rid_ == k);
|
|
assert(tag_ == LFSR_TAG_UATTR(~(k + SHIFT) & 0x7f));
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 3);
|
|
} else {
|
|
assert(rid_ == k);
|
|
assert(tag_ == LFSR_TAG_UATTR((k + SHIFT) & 0x7f));
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
}
|
|
}
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, &weight_, &data_) => LFS_ERR_NOENT;
|
|
|
|
// also test that we can lookup each tag with a wide lookup
|
|
for (unsigned k = 0; k < N; k++) {
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, k, LFSR_TAG_WIDE(UATTR),
|
|
&tag_, &data_) => 0;
|
|
if (k == j) {
|
|
assert(tag_ == LFSR_TAG_UATTR(~(k + SHIFT) & 0x7f));
|
|
assert(lfsr_data_size(&data_) == 3);
|
|
} else {
|
|
assert(tag_ == LFSR_TAG_UATTR((k + SHIFT) & 0x7f));
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
}
|
|
}
|
|
}
|
|
|
|
// cleanup
|
|
free(backup_block);
|
|
}
|
|
'''
|
|
|
|
[cases.test_rbyd_wide_mixed_lookup_permutations]
|
|
defines.N = 'range(1, 7)'
|
|
defines.SHIFT = [0, 3, -3]
|
|
# -1 => exhaust all permutations
|
|
# n => reproduce a specific permutation
|
|
defines.PERMUTATION = -1
|
|
in = 'lfs.c'
|
|
code = '''
|
|
lfs_t lfs;
|
|
lfs_init(&lfs, CFG) => 0;
|
|
|
|
lfsr_rbyd_t init_rbyd = {
|
|
.block = 0,
|
|
.eoff = 0,
|
|
.cksum = 0,
|
|
.trunk = 0,
|
|
.weight = 0,
|
|
};
|
|
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",
|
|
};
|
|
|
|
// test all permutations of a given size
|
|
size_t perm_count = TEST_FACTORIAL(N);
|
|
for (size_t i = 0;
|
|
i < (PERMUTATION == -1 ? perm_count : 1);
|
|
i++) {
|
|
uint32_t perm[N];
|
|
size_t perm_i = PERMUTATION == -1 ? i : (size_t)PERMUTATION;
|
|
TEST_PERMUTATION(perm_i, perm, N);
|
|
|
|
// print permutation to help debugging
|
|
printf("--- permutation: %zd [", perm_i);
|
|
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
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
for (unsigned j = 0; j < N; j++) {
|
|
// adjust rid based on future insertions
|
|
uint16_t rid = perm[j];
|
|
for (unsigned k = j+1; k < N; k++) {
|
|
if (perm[j] > perm[k]) {
|
|
rid -= 1;
|
|
}
|
|
}
|
|
|
|
// give each attr a subtype based on its rid + SHIFT
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(rid, REG, +1, BUF(names[perm[j] % 6], 4)),
|
|
LFSR_ATTR(rid, UATTR((perm[j] + SHIFT) & 0x7f), 0,
|
|
BUF(names[perm[j] % 6], 2)),
|
|
LFSR_ATTR(rid, SATTR(0), 0,
|
|
BUF(names[perm[j] % 6], 1)))) => 0;
|
|
}
|
|
assert(rbyd.weight == N);
|
|
|
|
// test that we can lookup each attr with a wide lookup
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
assert(rbyd.weight == N);
|
|
|
|
for (unsigned j = 0; j < N; j++) {
|
|
lfsr_tag_t tag_;
|
|
lfsr_data_t data_;
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, j, LFSR_TAG_WIDE(UATTR),
|
|
&tag_, &data_) => 0;
|
|
|
|
assert(tag_ == LFSR_TAG_UATTR((j + SHIFT) & 0x7f));
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
}
|
|
}
|
|
'''
|
|
|
|
# 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_wide_mixed_remove_permutations]
|
|
defines.N = 'range(1, 7)'
|
|
defines.SHIFT = [0, 3, -3]
|
|
# -1 => exhaust all permutations
|
|
# n => reproduce a specific permutation
|
|
defines.PERMUTATION = -1
|
|
# 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,
|
|
.eoff = 0,
|
|
.cksum = 0,
|
|
.trunk = 0,
|
|
.weight = 0,
|
|
};
|
|
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",
|
|
};
|
|
|
|
// test all permutations of a given size
|
|
size_t perm_count = TEST_FACTORIAL(N);
|
|
for (size_t i = 0;
|
|
i < (PERMUTATION == -1 ? perm_count : 1);
|
|
i++) {
|
|
uint32_t perm[N];
|
|
size_t perm_i = PERMUTATION == -1 ? i : (size_t)PERMUTATION;
|
|
TEST_PERMUTATION(perm_i, perm, N);
|
|
|
|
// print permutation to help debugging
|
|
printf("--- permutation: %zd [", perm_i);
|
|
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 rid based on future insertions
|
|
uint16_t rid = perm[j];
|
|
for (unsigned k = j+1; k < N; k++) {
|
|
if (perm[j] > perm[k]) {
|
|
rid -= 1;
|
|
}
|
|
}
|
|
|
|
// give each attr a subtype based on its rid + SHIFT
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(rid, REG, +1, BUF(names[perm[j] % 6], 4)),
|
|
LFSR_ATTR(rid, UATTR((perm[j] + SHIFT) & 0x7f), 0,
|
|
BUF(names[perm[j] % 6], 2)),
|
|
LFSR_ATTR(rid, SATTR(0), 0,
|
|
BUF(names[perm[j] % 6], 1)))) => 0;
|
|
}
|
|
assert(rbyd.weight == N);
|
|
|
|
// copy block so we can reset after each remove
|
|
lfsr_rbyd_t backup_rbyd = rbyd;
|
|
uint8_t *backup_block = malloc(rbyd.eoff);
|
|
lfs_bd_read(&lfs, NULL, &lfs.rcache, rbyd.eoff,
|
|
rbyd.block, 0, backup_block, rbyd.eoff) => 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.eoff) => 0;
|
|
lfs_bd_flush(&lfs, &lfs.pcache, &lfs.rcache, false) => 0;
|
|
|
|
// remove with a wide tag
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(j, RM(WIDE(UATTR)), 0, NULL()))) => 0;
|
|
|
|
// try traversing over the tags
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, CFG->block_size) => 0;
|
|
lfsr_tag_t tag_ = 0;
|
|
lfs_ssize_t rid_ = -1;
|
|
lfs_size_t weight_;
|
|
lfsr_data_t data_;
|
|
for (unsigned k = 0; k < N; k++) {
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(rid_ == k);
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(weight_ == 1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
|
|
if (k != j) {
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(rid_ == k);
|
|
assert(tag_ == LFSR_TAG_UATTR((k + SHIFT) & 0x7f));
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
}
|
|
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(rid_ == k);
|
|
assert(tag_ == LFSR_TAG_SATTR(0));
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 1);
|
|
}
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, &weight_, &data_) => LFS_ERR_NOENT;
|
|
|
|
// also test that we can lookup each tag with a wide lookup
|
|
for (unsigned k = 0; k < N; k++) {
|
|
if (k == j) {
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, k, LFSR_TAG_WIDE(UATTR),
|
|
&tag_, &data_) => LFS_ERR_NOENT;
|
|
} else {
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, k, LFSR_TAG_WIDE(UATTR),
|
|
&tag_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR((k + SHIFT) & 0x7f));
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
}
|
|
}
|
|
}
|
|
|
|
// cleanup
|
|
free(backup_block);
|
|
}
|
|
'''
|
|
|
|
# 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_wide_mixed_replace_permutations]
|
|
defines.N = 'range(1, 7)'
|
|
defines.SHIFT = [0, 3, -3]
|
|
# -1 => exhaust all permutations
|
|
# n => reproduce a specific permutation
|
|
defines.PERMUTATION = -1
|
|
# 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,
|
|
.eoff = 0,
|
|
.cksum = 0,
|
|
.trunk = 0,
|
|
.weight = 0,
|
|
};
|
|
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",
|
|
};
|
|
|
|
// test all permutations of a given size
|
|
size_t perm_count = TEST_FACTORIAL(N);
|
|
for (size_t i = 0;
|
|
i < (PERMUTATION == -1 ? perm_count : 1);
|
|
i++) {
|
|
uint32_t perm[N];
|
|
size_t perm_i = PERMUTATION == -1 ? i : (size_t)PERMUTATION;
|
|
TEST_PERMUTATION(perm_i, perm, N);
|
|
|
|
// print permutation to help debugging
|
|
printf("--- permutation: %zd [", perm_i);
|
|
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 rid based on future insertions
|
|
uint16_t rid = perm[j];
|
|
for (unsigned k = j+1; k < N; k++) {
|
|
if (perm[j] > perm[k]) {
|
|
rid -= 1;
|
|
}
|
|
}
|
|
|
|
// give each attr a subtype based on its rid + SHIFT
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(rid, REG, +1, BUF(names[perm[j] % 6], 4)),
|
|
LFSR_ATTR(rid, UATTR((perm[j] + SHIFT) & 0x7f), 0,
|
|
BUF(names[perm[j] % 6], 2)),
|
|
LFSR_ATTR(rid, SATTR(0), 0,
|
|
BUF(names[perm[j] % 6], 1)))) => 0;
|
|
}
|
|
assert(rbyd.weight == N);
|
|
|
|
// copy block so we can reset after each remove
|
|
lfsr_rbyd_t backup_rbyd = rbyd;
|
|
uint8_t *backup_block = malloc(rbyd.eoff);
|
|
lfs_bd_read(&lfs, NULL, &lfs.rcache, rbyd.eoff,
|
|
rbyd.block, 0, backup_block, rbyd.eoff) => 0;
|
|
|
|
// try replacing each tag
|
|
for (unsigned j = 0; j < N; j++) {
|
|
// print what we are replacing to help debugging
|
|
printf("--- replace: %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.eoff) => 0;
|
|
lfs_bd_flush(&lfs, &lfs.pcache, &lfs.rcache, false) => 0;
|
|
|
|
// replace with bitwise inverse
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(j, WIDE(UATTR(~(j + SHIFT) & 0x7f)), 0,
|
|
BUF(names[j % 6], 3)))) => 0;
|
|
|
|
// try traversing over the tags
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, CFG->block_size) => 0;
|
|
lfsr_tag_t tag_ = 0;
|
|
lfs_ssize_t rid_ = -1;
|
|
lfs_size_t weight_;
|
|
lfsr_data_t data_;
|
|
for (unsigned k = 0; k < N; k++) {
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(rid_ == k);
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(weight_ == 1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
if (k == j) {
|
|
assert(rid_ == k);
|
|
assert(tag_ == LFSR_TAG_UATTR(~(k + SHIFT) & 0x7f));
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 3);
|
|
} else {
|
|
assert(rid_ == k);
|
|
assert(tag_ == LFSR_TAG_UATTR((k + SHIFT) & 0x7f));
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
}
|
|
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(rid_ == k);
|
|
assert(tag_ == LFSR_TAG_SATTR(0));
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 1);
|
|
}
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, &weight_, &data_) => LFS_ERR_NOENT;
|
|
|
|
// also test that we can lookup each tag with a wide lookup
|
|
for (unsigned k = 0; k < N; k++) {
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, k, LFSR_TAG_WIDE(UATTR),
|
|
&tag_, &data_) => 0;
|
|
if (k == j) {
|
|
assert(tag_ == LFSR_TAG_UATTR(~(k + SHIFT) & 0x7f));
|
|
assert(lfsr_data_size(&data_) == 3);
|
|
} else {
|
|
assert(tag_ == LFSR_TAG_UATTR((k + SHIFT) & 0x7f));
|
|
assert(lfsr_data_size(&data_) == 2);
|
|
}
|
|
}
|
|
}
|
|
|
|
// cleanup
|
|
free(backup_block);
|
|
}
|
|
'''
|
|
|
|
[cases.test_rbyd_wide_weighted_lookup_permutations]
|
|
defines.N = 'range(1, 7)'
|
|
defines.SHIFT = [0, 3, -3]
|
|
# -1 => exhaust all permutations
|
|
# n => reproduce a specific permutation
|
|
defines.PERMUTATION = -1
|
|
in = 'lfs.c'
|
|
code = '''
|
|
lfs_t lfs;
|
|
lfs_init(&lfs, CFG) => 0;
|
|
|
|
lfsr_rbyd_t init_rbyd = {
|
|
.block = 0,
|
|
.eoff = 0,
|
|
.cksum = 0,
|
|
.trunk = 0,
|
|
.weight = 0,
|
|
};
|
|
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",
|
|
};
|
|
|
|
// test all permutations of a given size
|
|
size_t perm_count = TEST_FACTORIAL(N);
|
|
for (size_t i = 0;
|
|
i < (PERMUTATION == -1 ? perm_count : 1);
|
|
i++) {
|
|
uint32_t perm[N];
|
|
size_t perm_i = PERMUTATION == -1 ? i : (size_t)PERMUTATION;
|
|
TEST_PERMUTATION(perm_i, perm, N);
|
|
|
|
// print permutation to help debugging
|
|
printf("--- permutation: %zd [", perm_i);
|
|
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
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
|
for (unsigned j = 0; j < N; j++) {
|
|
// adjust rid based on future insertions
|
|
uint16_t rid = perm[j];
|
|
for (unsigned k = j+1; k < N; k++) {
|
|
if (perm[j] > perm[k]) {
|
|
rid -= 1;
|
|
}
|
|
}
|
|
|
|
// give each attr a subtype based on its rid + SHIFT
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(rid, UATTR((perm[j] + SHIFT) & 0x7f), +1,
|
|
BUF(names[perm[j] % 6], 4)))) => 0;
|
|
}
|
|
assert(rbyd.weight == N);
|
|
|
|
// test that we can lookup each attr with a wide lookup
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, 0) => 0;
|
|
assert(rbyd.weight == N);
|
|
|
|
for (unsigned j = 0; j < N; j++) {
|
|
lfsr_tag_t tag_;
|
|
lfsr_data_t data_;
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, j, LFSR_TAG_WIDE(UATTR),
|
|
&tag_, &data_) => 0;
|
|
|
|
assert(tag_ == LFSR_TAG_UATTR((j + SHIFT) & 0x7f));
|
|
assert(lfsr_data_size(&data_) == 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_wide_weighted_remove_permutations]
|
|
defines.N = 'range(1, 7)'
|
|
defines.SHIFT = [0, 3, -3]
|
|
# -1 => exhaust all permutations
|
|
# n => reproduce a specific permutation
|
|
defines.PERMUTATION = -1
|
|
# 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,
|
|
.eoff = 0,
|
|
.cksum = 0,
|
|
.trunk = 0,
|
|
.weight = 0,
|
|
};
|
|
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",
|
|
};
|
|
|
|
// test all permutations of a given size
|
|
size_t perm_count = TEST_FACTORIAL(N);
|
|
for (size_t i = 0;
|
|
i < (PERMUTATION == -1 ? perm_count : 1);
|
|
i++) {
|
|
uint32_t perm[N];
|
|
size_t perm_i = PERMUTATION == -1 ? i : (size_t)PERMUTATION;
|
|
TEST_PERMUTATION(perm_i, perm, N);
|
|
|
|
// print permutation to help debugging
|
|
printf("--- permutation: %zd [", perm_i);
|
|
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 rid based on future insertions
|
|
uint16_t rid = perm[j];
|
|
for (unsigned k = j+1; k < N; k++) {
|
|
if (perm[j] > perm[k]) {
|
|
rid -= 1;
|
|
}
|
|
}
|
|
|
|
// give each attr a subtype based on its rid + SHIFT
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(rid, UATTR((perm[j] + SHIFT) & 0x7f), +1,
|
|
BUF(names[perm[j] % 6], 4)))) => 0;
|
|
}
|
|
assert(rbyd.weight == N);
|
|
|
|
// copy block so we can reset after each remove
|
|
lfsr_rbyd_t backup_rbyd = rbyd;
|
|
uint8_t *backup_block = malloc(rbyd.eoff);
|
|
lfs_bd_read(&lfs, NULL, &lfs.rcache, rbyd.eoff,
|
|
rbyd.block, 0, backup_block, rbyd.eoff) => 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.eoff) => 0;
|
|
lfs_bd_flush(&lfs, &lfs.pcache, &lfs.rcache, false) => 0;
|
|
|
|
// remove with a wide tag
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(j, RM(WIDE(UATTR)), 0, NULL()))) => 0;
|
|
|
|
// try traversing over the tags
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, CFG->block_size) => 0;
|
|
lfsr_tag_t tag_ = 0;
|
|
lfs_ssize_t rid_ = -1;
|
|
lfs_size_t weight_;
|
|
lfsr_data_t data_;
|
|
for (unsigned k = 0; k < N-1; k++) {
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
if (k == j) {
|
|
assert(rid_ == k+1);
|
|
assert(tag_ == LFSR_TAG_UATTR((k+1 + SHIFT) & 0x7f));
|
|
assert(weight_ == 2);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
} else if (k > j) {
|
|
assert(rid_ == k+1);
|
|
assert(tag_ == LFSR_TAG_UATTR((k+1 + SHIFT) & 0x7f));
|
|
assert(weight_ == 1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
} else {
|
|
assert(rid_ == k);
|
|
assert(tag_ == LFSR_TAG_UATTR((k + SHIFT) & 0x7f));
|
|
assert(weight_ == 1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
}
|
|
}
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, &weight_, &data_) => LFS_ERR_NOENT;
|
|
|
|
// also test that we can lookup each tag with a wide lookup
|
|
for (unsigned k = 0; k < N; k++) {
|
|
if (k == j) {
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, k, LFSR_TAG_WIDE(UATTR),
|
|
&tag_, &data_) => LFS_ERR_NOENT;
|
|
} else {
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, k, LFSR_TAG_WIDE(UATTR),
|
|
&tag_, &data_) => 0;
|
|
assert(tag_ == LFSR_TAG_UATTR((k + SHIFT) & 0x7f));
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
}
|
|
}
|
|
}
|
|
|
|
// cleanup
|
|
free(backup_block);
|
|
}
|
|
'''
|
|
|
|
# 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_wide_weighted_replace_permutations]
|
|
defines.N = 'range(1, 7)'
|
|
defines.SHIFT = [0, 3, -3]
|
|
# -1 => exhaust all permutations
|
|
# n => reproduce a specific permutation
|
|
defines.PERMUTATION = -1
|
|
# 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,
|
|
.eoff = 0,
|
|
.cksum = 0,
|
|
.trunk = 0,
|
|
.weight = 0,
|
|
};
|
|
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",
|
|
};
|
|
|
|
// test all permutations of a given size
|
|
size_t perm_count = TEST_FACTORIAL(N);
|
|
for (size_t i = 0;
|
|
i < (PERMUTATION == -1 ? perm_count : 1);
|
|
i++) {
|
|
uint32_t perm[N];
|
|
size_t perm_i = PERMUTATION == -1 ? i : (size_t)PERMUTATION;
|
|
TEST_PERMUTATION(perm_i, perm, N);
|
|
|
|
// print permutation to help debugging
|
|
printf("--- permutation: %zd [", perm_i);
|
|
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 rid based on future insertions
|
|
uint16_t rid = perm[j];
|
|
for (unsigned k = j+1; k < N; k++) {
|
|
if (perm[j] > perm[k]) {
|
|
rid -= 1;
|
|
}
|
|
}
|
|
|
|
// give each attr a subtype based on its rid + SHIFT
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(rid, UATTR((perm[j] + SHIFT) & 0x7f), +1,
|
|
BUF(names[perm[j] % 6], 4)))) => 0;
|
|
}
|
|
assert(rbyd.weight == N);
|
|
|
|
// copy block so we can reset after each remove
|
|
lfsr_rbyd_t backup_rbyd = rbyd;
|
|
uint8_t *backup_block = malloc(rbyd.eoff);
|
|
lfs_bd_read(&lfs, NULL, &lfs.rcache, rbyd.eoff,
|
|
rbyd.block, 0, backup_block, rbyd.eoff) => 0;
|
|
|
|
// try replacing each tag
|
|
for (unsigned j = 0; j < N; j++) {
|
|
// print what we are replacing to help debugging
|
|
printf("--- replace: %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.eoff) => 0;
|
|
lfs_bd_flush(&lfs, &lfs.pcache, &lfs.rcache, false) => 0;
|
|
|
|
// replace with bitwise inverse
|
|
lfsr_rbyd_commit(&lfs, &rbyd, LFSR_ATTRS(
|
|
LFSR_ATTR(j, WIDE(UATTR(~(j + SHIFT) & 0x7f)), 0,
|
|
BUF(names[j % 6], 6)))) => 0;
|
|
|
|
// try traversing over the tags
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, CFG->block_size) => 0;
|
|
lfsr_tag_t tag_ = 0;
|
|
lfs_ssize_t rid_ = -1;
|
|
lfs_size_t weight_;
|
|
lfsr_data_t data_;
|
|
for (unsigned k = 0; k < N; k++) {
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
if (k == j) {
|
|
assert(rid_ == k);
|
|
assert(tag_ == LFSR_TAG_UATTR(~(k + SHIFT) & 0x7f));
|
|
assert(weight_ == 1);
|
|
assert(lfsr_data_size(&data_) == 6);
|
|
} else {
|
|
assert(rid_ == k);
|
|
assert(tag_ == LFSR_TAG_UATTR((k + SHIFT) & 0x7f));
|
|
assert(weight_ == 1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
}
|
|
}
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, &weight_, &data_) => LFS_ERR_NOENT;
|
|
|
|
// also test that we can lookup each tag with a wide lookup
|
|
for (unsigned k = 0; k < N; k++) {
|
|
lfsr_rbyd_lookup(&lfs, &rbyd, k, LFSR_TAG_WIDE(UATTR),
|
|
&tag_, &data_) => 0;
|
|
if (k == j) {
|
|
assert(tag_ == LFSR_TAG_UATTR(~(k + SHIFT) & 0x7f));
|
|
assert(lfsr_data_size(&data_) == 6);
|
|
} else {
|
|
assert(tag_ == LFSR_TAG_UATTR((k + SHIFT) & 0x7f));
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
}
|
|
}
|
|
}
|
|
|
|
// cleanup
|
|
free(backup_block);
|
|
}
|
|
'''
|