3a90d1046b
Changing insert tags to append seems to have broken insertion into named
btrees in a subtle way.
Consider what happens when we insert immediately before a bid that
splits the btree:
1. namelookup returns the right rbyd, with rid=-1
2. converting this into a bid gives us the left rbyd, with rid=weight
3. the commit to insert the bid ends up inserting into the left rbyd
This doesn't initially seem like an issue, both entries are effectively
the same right? Well, not when you have names. The split name tells you
what _follows_, so this unintentional flipping causes the new name to
get placed in the wrong bucket.
It's not clear if it's possible to fix this, at least not without
inverting the split names to indicate what precedes, but that's a step
too far.
This was not detected earlier because I disabled the low-level
rbyd/btree/mtree tests temporarily due to high porting cost. Guess that
goes to show there's a cost to deferring test ports for too long.
---
This issue, along with being inconsistencies between rids/bids and mids,
and being a relatively unintuitive pattern, is the final nail in the
coffin for insert tags inserting after.
Now, insert tags insert before, like in most other systems, and insert
tags in attr-list just have an implicit +1 before them to allow splits
in attr-lists to work.
This is not a pure revert, as some of the changes with all the code
moving around revealed some better detail-level ideas.
And yes, rbyd/btree tests are up to date now. Unfortunately the mtree
tests require a bit more work.
---
One thing definitely worth noting, btree merges were broken! A mistake
in the has-parent condition meant we were never attempting to merge
btrees!
This hid some bugs in the actual btree merge code caused by mixing the
implicit swap of child rbyds to deduplicate code paths with btree commit
now needing to track bid/rid separately from the attr-list.
This should be fixed now. Interesting to note this bug has been in
lfsr_btree_commit_ for a while now! I think ever since we switched to
using trunks for the has-parent check. We just haven't been merging
btree nodes at all. But since not-merging isn't technically an error,
it's difficult to test for.
Code changes:
code stack
before: 33808 2896
after: 33964 (+0.5%) 2896 (+0.0%)
12640 lines
445 KiB
TOML
12640 lines
445 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, &data);
|
|
if (err) {
|
|
return err;
|
|
}
|
|
|
|
return lfsr_data_read(lfs, &data, buffer, size);
|
|
}
|
|
'''
|
|
|
|
[cases.test_rbyd_atomic_commit]
|
|
in = 'lfs.c'
|
|
code = '''
|
|
lfs_t lfs;
|
|
lfs_init(&lfs, CFG) => 0;
|
|
|
|
lfsr_rbyd_t init_rbyd = {
|
|
.blocks[0] = 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
|
|
|
|
// commit with two attributes
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)))) => 0;
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
|
|
'''
|
|
|
|
[cases.test_rbyd_commit]
|
|
in = 'lfs.c'
|
|
code = '''
|
|
lfs_t lfs;
|
|
lfs_init(&lfs, CFG) => 0;
|
|
|
|
lfsr_rbyd_t init_rbyd = {
|
|
.blocks[0] = 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
|
|
|
|
// commit with two attributes
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)))) => 0;
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 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 = {
|
|
.blocks[0] = 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
|
|
|
|
// fetch
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
|
|
|
|
// commit with the second attribute
|
|
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)))) => 0;
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
|
|
'''
|
|
|
|
# [cases.test_rbyd_atomic_fetchmatch]
|
|
# [cases.test_rbyd_fetchmatch]
|
|
|
|
# TODO we really need to test dense keys...
|
|
|
|
[cases.test_rbyd_atomic_lookup]
|
|
in = 'lfs.c'
|
|
code = '''
|
|
lfs_t lfs;
|
|
lfs_init(&lfs, CFG) => 0;
|
|
|
|
lfsr_rbyd_t init_rbyd = {
|
|
.blocks[0] = 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(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.blocks[0], 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(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.blocks[0], 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(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.blocks[0], 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_lookup]
|
|
in = 'lfs.c'
|
|
code = '''
|
|
lfs_t lfs;
|
|
lfs_init(&lfs, CFG) => 0;
|
|
|
|
lfsr_rbyd_t init_rbyd = {
|
|
.blocks[0] = 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(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.blocks[0], 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(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.blocks[0], 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(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.blocks[0], 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_atomic_get]
|
|
in = 'lfs.c'
|
|
code = '''
|
|
lfs_t lfs;
|
|
lfs_init(&lfs, CFG) => 0;
|
|
|
|
lfsr_rbyd_t init_rbyd = {
|
|
.blocks[0] = 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(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.blocks[0], 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(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.blocks[0], 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(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.blocks[0], 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_get]
|
|
in = 'lfs.c'
|
|
code = '''
|
|
lfs_t lfs;
|
|
lfs_init(&lfs, CFG) => 0;
|
|
|
|
lfsr_rbyd_t init_rbyd = {
|
|
.blocks[0] = 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(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.blocks[0], 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(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.blocks[0], 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(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.blocks[0], 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 = {
|
|
.blocks[0] = 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)))) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 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 = {
|
|
.blocks[0] = 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)))) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 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 = {
|
|
.blocks[0] = 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(UATTR(3), 0, BUF("\xcc\xcc\xcc\xcc", 4)))) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(UATTR(3), 0, BUF("\xcc\xcc\xcc\xcc", 4)),
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 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 = {
|
|
.blocks[0] = 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(UATTR(3), 0, BUF("\xcc\xcc\xcc\xcc", 4)),
|
|
LFSR_ATTR(UATTR(3), 0, BUF("\xcc\xcc\xcc\xcc", 4)))) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(UATTR(3), 0, BUF("\xcc\xcc\xcc\xcc", 4)),
|
|
LFSR_ATTR(UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)))) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(UATTR(3), 0, BUF("\xcc\xcc\xcc\xcc", 4)),
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(UATTR(3), 0, BUF("\xcc\xcc\xcc\xcc", 4)),
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 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 = {
|
|
.blocks[0] = 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(UATTR(3), 0, BUF("\xcc\xcc\xcc\xcc", 4)),
|
|
LFSR_ATTR(UATTR(4), 0, BUF("\xdd\xdd\xdd\xdd", 4)))) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(UATTR(3), 0, BUF("\xcc\xcc\xcc\xcc", 4)),
|
|
LFSR_ATTR(UATTR(4), 0, BUF("\xdd\xdd\xdd\xdd", 4)),
|
|
LFSR_ATTR(UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)))) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(UATTR(3), 0, BUF("\xcc\xcc\xcc\xcc", 4)),
|
|
LFSR_ATTR(UATTR(4), 0, BUF("\xdd\xdd\xdd\xdd", 4)),
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(UATTR(4), 0, BUF("\xdd\xdd\xdd\xdd", 4)),
|
|
LFSR_ATTR(UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(UATTR(3), 0, BUF("\xcc\xcc\xcc\xcc", 4)),
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 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 = {
|
|
.blocks[0] = 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(UATTR(3), 0, BUF("\xcc\xcc\xcc\xcc", 4)),
|
|
LFSR_ATTR(UATTR(4), 0, BUF("\xdd\xdd\xdd\xdd", 4)))) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(UATTR(4), 0, BUF("\xdd\xdd\xdd\xdd", 4)),
|
|
LFSR_ATTR(UATTR(3), 0, BUF("\xcc\xcc\xcc\xcc", 4)))) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(UATTR(4), 0, BUF("\xdd\xdd\xdd\xdd", 4)),
|
|
LFSR_ATTR(UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(UATTR(3), 0, BUF("\xcc\xcc\xcc\xcc", 4)))) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(UATTR(4), 0, BUF("\xdd\xdd\xdd\xdd", 4)),
|
|
LFSR_ATTR(UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(UATTR(3), 0, BUF("\xcc\xcc\xcc\xcc", 4)))) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 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 = {
|
|
.blocks[0] = 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(UATTR(3), 0, BUF("\xcc\xcc\xcc\xcc", 4)),
|
|
LFSR_ATTR(UATTR(4), 0, BUF("\xdd\xdd\xdd\xdd", 4)),
|
|
LFSR_ATTR(UATTR(4), 0, BUF("\xdd\xdd\xdd\xdd", 4)))) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(UATTR(3), 0, BUF("\xcc\xcc\xcc\xcc", 4)),
|
|
LFSR_ATTR(UATTR(4), 0, BUF("\xdd\xdd\xdd\xdd", 4)),
|
|
LFSR_ATTR(UATTR(3), 0, BUF("\xcc\xcc\xcc\xcc", 4)))) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(UATTR(3), 0, BUF("\xcc\xcc\xcc\xcc", 4)),
|
|
LFSR_ATTR(UATTR(4), 0, BUF("\xdd\xdd\xdd\xdd", 4)),
|
|
LFSR_ATTR(UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)))) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(UATTR(3), 0, BUF("\xcc\xcc\xcc\xcc", 4)),
|
|
LFSR_ATTR(UATTR(4), 0, BUF("\xdd\xdd\xdd\xdd", 4)),
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 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 = {
|
|
.blocks[0] = 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(UATTR(3), 0, BUF("\xcc\xcc\xcc\xcc", 4)),
|
|
LFSR_ATTR(UATTR(4), 0, BUF("\xdd\xdd\xdd\xdd", 4)),
|
|
LFSR_ATTR(UATTR(5), 0, BUF("\xee\xee\xee\xee", 4)))) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(UATTR(4), 0, BUF("\xdd\xdd\xdd\xdd", 4)),
|
|
LFSR_ATTR(UATTR(5), 0, BUF("\xee\xee\xee\xee", 4)),
|
|
LFSR_ATTR(UATTR(3), 0, BUF("\xcc\xcc\xcc\xcc", 4)))) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(UATTR(3), 0, BUF("\xcc\xcc\xcc\xcc", 4)),
|
|
LFSR_ATTR(UATTR(4), 0, BUF("\xdd\xdd\xdd\xdd", 4)),
|
|
LFSR_ATTR(UATTR(5), 0, BUF("\xee\xee\xee\xee", 4)),
|
|
LFSR_ATTR(UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)))) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(UATTR(3), 0, BUF("\xcc\xcc\xcc\xcc", 4)),
|
|
LFSR_ATTR(UATTR(4), 0, BUF("\xdd\xdd\xdd\xdd", 4)),
|
|
LFSR_ATTR(UATTR(5), 0, BUF("\xee\xee\xee\xee", 4)),
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 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 = {
|
|
.blocks[0] = 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(UATTR(3), 0, BUF("\xcc\xcc\xcc\xcc", 4)),
|
|
LFSR_ATTR(UATTR(4), 0, BUF("\xdd\xdd\xdd\xdd", 4)),
|
|
LFSR_ATTR(UATTR(5), 0, BUF("\xee\xee\xee\xee", 4)),
|
|
LFSR_ATTR(UATTR(5), 0, BUF("\xee\xee\xee\xee", 4)))) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(UATTR(3), 0, BUF("\xcc\xcc\xcc\xcc", 4)),
|
|
LFSR_ATTR(UATTR(4), 0, BUF("\xdd\xdd\xdd\xdd", 4)),
|
|
LFSR_ATTR(UATTR(5), 0, BUF("\xee\xee\xee\xee", 4)),
|
|
LFSR_ATTR(UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)))) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(UATTR(3), 0, BUF("\xcc\xcc\xcc\xcc", 4)),
|
|
LFSR_ATTR(UATTR(4), 0, BUF("\xdd\xdd\xdd\xdd", 4)),
|
|
LFSR_ATTR(UATTR(5), 0, BUF("\xee\xee\xee\xee", 4)),
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 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 = {
|
|
.blocks[0] = 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(UATTR(3), 0, BUF("\xcc\xcc\xcc\xcc", 4)),
|
|
LFSR_ATTR(UATTR(4), 0, BUF("\xdd\xdd\xdd\xdd", 4)),
|
|
LFSR_ATTR(UATTR(5), 0, BUF("\xee\xee\xee\xee", 4)),
|
|
LFSR_ATTR(UATTR(6), 0, BUF("\xff\xff\xff\xff", 4)))) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(UATTR(3), 0, BUF("\xcc\xcc\xcc\xcc", 4)),
|
|
LFSR_ATTR(UATTR(4), 0, BUF("\xdd\xdd\xdd\xdd", 4)),
|
|
LFSR_ATTR(UATTR(5), 0, BUF("\xee\xee\xee\xee", 4)),
|
|
LFSR_ATTR(UATTR(6), 0, BUF("\xff\xff\xff\xff", 4)),
|
|
LFSR_ATTR(UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)))) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(UATTR(3), 0, BUF("\xcc\xcc\xcc\xcc", 4)),
|
|
LFSR_ATTR(UATTR(4), 0, BUF("\xdd\xdd\xdd\xdd", 4)),
|
|
LFSR_ATTR(UATTR(5), 0, BUF("\xee\xee\xee\xee", 4)),
|
|
LFSR_ATTR(UATTR(6), 0, BUF("\xff\xff\xff\xff", 4)),
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 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_atomic_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 = {
|
|
.blocks[0] = 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(UATTR(perm[j]+1), 0,
|
|
BUF("\xaa\xaa\xaa\xaa", 4));
|
|
}
|
|
|
|
// test the given permutation
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, -1, attrs, N) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 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_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 = {
|
|
.blocks[0] = 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.blocks[0]) => 0;
|
|
for (unsigned j = 0; j < N; j++) {
|
|
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(UATTR(perm[j]+1), 0,
|
|
BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
|
|
}
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 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_atomic_traverse]
|
|
in = 'lfs.c'
|
|
code = '''
|
|
lfs_t lfs;
|
|
lfs_init(&lfs, CFG) => 0;
|
|
|
|
lfsr_rbyd_t init_rbyd = {
|
|
.blocks[0] = 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(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.blocks[0], 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(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.blocks[0], 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]
|
|
in = 'lfs.c'
|
|
code = '''
|
|
lfs_t lfs;
|
|
lfs_init(&lfs, CFG) => 0;
|
|
|
|
lfsr_rbyd_t init_rbyd = {
|
|
.blocks[0] = 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(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.blocks[0], 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(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.blocks[0], 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_atomic_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 = {
|
|
.blocks[0] = 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(UATTR(perm[j]+1), 0,
|
|
BUF("\xaa\xaa\xaa\xaa", 4));
|
|
}
|
|
|
|
// test the given permutation
|
|
rbyd = init_rbyd;
|
|
lfs_bd_erase(&lfs, rbyd.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, -1, attrs, N) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 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_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 = {
|
|
.blocks[0] = 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.blocks[0]) => 0;
|
|
for (unsigned j = 0; j < N; j++) {
|
|
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(UATTR(perm[j]+1), 0,
|
|
BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
|
|
}
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 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 = {
|
|
.blocks[0] = 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.blocks[0]) => 0;
|
|
|
|
for (unsigned j = 0; j < N; j++) {
|
|
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(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.blocks[0], 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.blocks[0]) => 0;
|
|
lfs_bd_prog(&lfs, &lfs.pcache, &lfs.rcache, false,
|
|
rbyd.blocks[0], 0, backup_block, rbyd.eoff,
|
|
NULL) => 0;
|
|
lfs_bd_flush(&lfs, &lfs.pcache, &lfs.rcache, false,
|
|
NULL) => 0;
|
|
|
|
// update each tag in permutation order
|
|
for (unsigned j = 0; j < N; j++) {
|
|
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(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.blocks[0], 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 = {
|
|
.blocks[0] = 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.blocks[0]) => 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, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(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.blocks[0], 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 = {
|
|
.blocks[0] = 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(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.blocks[0], 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(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.blocks[0], 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(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.blocks[0], 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 = {
|
|
.blocks[0] = 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.blocks[0]) => 0;
|
|
for (unsigned j = 0; j < N; j++) {
|
|
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(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.blocks[0], 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.blocks[0]) => 0;
|
|
lfs_bd_prog(&lfs, &lfs.pcache, &lfs.rcache, false,
|
|
rbyd.blocks[0], 0, backup_block, rbyd.eoff,
|
|
NULL) => 0;
|
|
lfs_bd_flush(&lfs, &lfs.pcache, &lfs.rcache, false,
|
|
NULL) => 0;
|
|
|
|
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(RM(UATTR(j+1)), 0, NULL())))
|
|
=> 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 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, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(UATTR(j+1), 0,
|
|
BUF("\xaa\xaa\xaa\xaa\xaa\xaa", 6)))) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 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 = {
|
|
.blocks[0] = 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.blocks[0]) => 0;
|
|
for (unsigned j = 0; j < N; j++) {
|
|
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(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.blocks[0], 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.blocks[0]) => 0;
|
|
lfs_bd_prog(&lfs, &lfs.pcache, &lfs.rcache, false,
|
|
rbyd.blocks[0], 0, backup_block, rbyd.eoff,
|
|
NULL) => 0;
|
|
lfs_bd_flush(&lfs, &lfs.pcache, &lfs.rcache, false,
|
|
NULL) => 0;
|
|
|
|
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(RM(UATTR(j+1)), 0, NULL()))) => 0;
|
|
|
|
// try traversing over the tags
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 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 = {
|
|
.blocks[0] = 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(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, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(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, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(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, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(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.blocks[0], 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 = {
|
|
.blocks[0] = 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(UATTR(3), 0, BUF("\xcc\xcc\xcc\xcc", 4)),
|
|
LFSR_ATTR(UATTR(4), 0, BUF("\xdd\xdd\xdd\xdd", 4)),
|
|
LFSR_ATTR(UATTR(5), 0, BUF("\xee\xee\xee\xee", 4)))) => 0;
|
|
// remove several attributes
|
|
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(RM(UATTR(1)), 0, NULL()),
|
|
LFSR_ATTR(RM(UATTR(3)), 0, NULL()),
|
|
LFSR_ATTR(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, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(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, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(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, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(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, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(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, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(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, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(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.blocks[0], 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 = {
|
|
.blocks[0] = 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(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.blocks[0], 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(RM(UATTR(1)), 0, NULL()),
|
|
LFSR_ATTR(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.blocks[0], 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(UATTR(2), 0, BUF("\xbb\xbb\xbb\xbb", 4)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(RM(UATTR(2)), 0, NULL()),
|
|
LFSR_ATTR(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.blocks[0], 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 = {
|
|
.blocks[0] = 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.blocks[0]) => 0;
|
|
|
|
for (unsigned j = 0; j < N; j++) {
|
|
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(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.blocks[0], 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.blocks[0]) => 0;
|
|
lfs_bd_prog(&lfs, &lfs.pcache, &lfs.rcache, false,
|
|
rbyd.blocks[0], 0, backup_block, rbyd.eoff,
|
|
NULL) => 0;
|
|
lfs_bd_flush(&lfs, &lfs.pcache, &lfs.rcache, false,
|
|
NULL) => 0;
|
|
|
|
// remove each tag in permutation order
|
|
for (unsigned j = 0; j < N; j++) {
|
|
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(RM(UATTR(perm[j]+1)), 0, NULL()))) => 0;
|
|
}
|
|
|
|
// check that all tags are now removed
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 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, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(UATTR(1), 0,
|
|
BUF("\xaa\xaa\xaa\xaa\xaa\xaa", 6)))) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 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 = {
|
|
.blocks[0] = 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.blocks[0]) => 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, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(UATTR(attr), 0,
|
|
BUF(&alpha[i % 26], 1)))) => 0;
|
|
} else {
|
|
// update our sim
|
|
sim[attr] = '\0';
|
|
// update our rbyd
|
|
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(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_atomic_create]
|
|
in = 'lfs.c'
|
|
code = '''
|
|
lfs_t lfs;
|
|
lfs_init(&lfs, CFG) => 0;
|
|
|
|
lfsr_rbyd_t init_rbyd = {
|
|
.blocks[0] = 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
|
|
LFSR_ATTR(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.blocks[0], 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
|
|
LFSR_ATTR(REG, +1, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(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.blocks[0], 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
|
|
LFSR_ATTR(REG, +1, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(REG, +1, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(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.blocks[0], 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]
|
|
in = 'lfs.c'
|
|
code = '''
|
|
lfs_t lfs;
|
|
lfs_init(&lfs, CFG) => 0;
|
|
|
|
lfsr_rbyd_t init_rbyd = {
|
|
.blocks[0] = 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
|
|
LFSR_ATTR(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.blocks[0], 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
|
|
LFSR_ATTR(REG, +1, BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_ATTRS(
|
|
LFSR_ATTR(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.blocks[0], 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
|
|
LFSR_ATTR(REG, +1, BUF("\xbb\xbb\xbb\xbb", 4)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
|
|
LFSR_ATTR(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.blocks[0], 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
|
|
LFSR_ATTR(REG, +1, BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_ATTRS(
|
|
LFSR_ATTR(REG, +1, BUF("\xbb\xbb\xbb\xbb", 4)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 2, LFSR_ATTRS(
|
|
LFSR_ATTR(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.blocks[0], 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
|
|
LFSR_ATTR(REG, +1, BUF("\xbb\xbb\xbb\xbb", 4)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_ATTRS(
|
|
LFSR_ATTR(REG, +1, BUF("\xcc\xcc\xcc\xcc", 4)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
|
|
LFSR_ATTR(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.blocks[0], 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
|
|
LFSR_ATTR(REG, +1, BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_ATTRS(
|
|
LFSR_ATTR(REG, +1, BUF("\xcc\xcc\xcc\xcc", 4)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_ATTRS(
|
|
LFSR_ATTR(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.blocks[0], 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
|
|
# 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 = {
|
|
.blocks[0] = 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.blocks[0]) => 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, rid, LFSR_ATTRS(
|
|
LFSR_ATTR(REG, +1, BUF(names[perm[j] % 6], 4)))) => 0;
|
|
}
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 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_atomic_create_traverse]
|
|
in = 'lfs.c'
|
|
code = '''
|
|
lfs_t lfs;
|
|
lfs_init(&lfs, CFG) => 0;
|
|
|
|
lfsr_rbyd_t init_rbyd = {
|
|
.blocks[0] = 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 00000000, LFSR_ATTRS(
|
|
LFSR_ATTR(REG, +1, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(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.blocks[0], 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]
|
|
in = 'lfs.c'
|
|
code = '''
|
|
lfs_t lfs;
|
|
lfs_init(&lfs, CFG) => 0;
|
|
|
|
lfsr_rbyd_t init_rbyd = {
|
|
.blocks[0] = 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
|
|
LFSR_ATTR(REG, +1, BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_ATTRS(
|
|
LFSR_ATTR(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.blocks[0], 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
|
|
LFSR_ATTR(REG, +1, BUF("\xbb\xbb\xbb\xbb", 4)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
|
|
LFSR_ATTR(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.blocks[0], 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
|
|
# 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 = {
|
|
.blocks[0] = 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.blocks[0]) => 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, rid, LFSR_ATTRS(
|
|
LFSR_ATTR(REG, +1, BUF(names[perm[j] % 6], 4)))) => 0;
|
|
}
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 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 = {
|
|
.blocks[0] = 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.blocks[0]) => 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, x, LFSR_ATTRS(
|
|
LFSR_ATTR(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.blocks[0], 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_atomic_mixed]
|
|
in = 'lfs.c'
|
|
code = '''
|
|
lfs_t lfs;
|
|
lfs_init(&lfs, CFG) => 0;
|
|
|
|
lfsr_rbyd_t init_rbyd = {
|
|
.blocks[0] = 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
|
|
LFSR_ATTR(REG, +1, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(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.blocks[0], 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
|
|
LFSR_ATTR(REG, +1, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xaa\xaa", 2)),
|
|
LFSR_ATTR(REG, +1, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(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.blocks[0], 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
|
|
LFSR_ATTR(REG, +1, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xaa\xaa", 2)),
|
|
LFSR_ATTR(REG, +1, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xbb\xbb", 2)),
|
|
LFSR_ATTR(REG, +1, BUF("\xcc\xcc\xcc\xcc", 4)),
|
|
LFSR_ATTR(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.blocks[0], 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.blocks[0], 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]
|
|
in = 'lfs.c'
|
|
code = '''
|
|
lfs_t lfs;
|
|
lfs_init(&lfs, CFG) => 0;
|
|
|
|
lfsr_rbyd_t init_rbyd = {
|
|
.blocks[0] = 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
|
|
LFSR_ATTR(REG, +1, BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
|
|
LFSR_ATTR(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.blocks[0], 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
|
|
LFSR_ATTR(REG, +1, BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xaa\xaa", 2)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_ATTRS(
|
|
LFSR_ATTR(REG, +1, BUF("\xbb\xbb\xbb\xbb", 4)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_ATTRS(
|
|
LFSR_ATTR(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.blocks[0], 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
|
|
LFSR_ATTR(REG, +1, BUF("\xbb\xbb\xbb\xbb", 4)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xbb\xbb", 2)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
|
|
LFSR_ATTR(REG, +1, BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
|
|
LFSR_ATTR(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.blocks[0], 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
|
|
LFSR_ATTR(REG, +1, BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xaa\xaa", 2)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_ATTRS(
|
|
LFSR_ATTR(REG, +1, BUF("\xbb\xbb\xbb\xbb", 4)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_ATTRS(
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xbb\xbb", 2)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 2, LFSR_ATTRS(
|
|
LFSR_ATTR(REG, +1, BUF("\xcc\xcc\xcc\xcc", 4)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 2, LFSR_ATTRS(
|
|
LFSR_ATTR(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.blocks[0], 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.blocks[0], 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
|
|
LFSR_ATTR(REG, +1, BUF("\xbb\xbb\xbb\xbb", 4)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xbb\xbb", 2)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_ATTRS(
|
|
LFSR_ATTR(REG, +1, BUF("\xcc\xcc\xcc\xcc", 4)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_ATTRS(
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xcc\xcc", 2)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
|
|
LFSR_ATTR(REG, +1, BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
|
|
LFSR_ATTR(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.blocks[0], 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
|
|
LFSR_ATTR(REG, +1, BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xaa\xaa", 2)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_ATTRS(
|
|
LFSR_ATTR(REG, +1, BUF("\xcc\xcc\xcc\xcc", 4)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_ATTRS(
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xcc\xcc", 2)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_ATTRS(
|
|
LFSR_ATTR(REG, +1, BUF("\xbb\xbb\xbb\xbb", 4)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_ATTRS(
|
|
LFSR_ATTR(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.blocks[0], 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
|
|
# 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 = {
|
|
.blocks[0] = 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.blocks[0]) => 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, rid, LFSR_ATTRS(
|
|
LFSR_ATTR(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, rid, LFSR_ATTRS(
|
|
LFSR_ATTR(UATTR(u+1), 0,
|
|
BUF(names[perm[j] % 6], 2)))) => 0;
|
|
}
|
|
}
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 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_atomic_mixed_traverse]
|
|
in = 'lfs.c'
|
|
code = '''
|
|
lfs_t lfs;
|
|
lfs_init(&lfs, CFG) => 0;
|
|
|
|
lfsr_rbyd_t init_rbyd = {
|
|
.blocks[0] = 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
|
|
LFSR_ATTR(REG, +1, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xaa\xaa", 2)),
|
|
LFSR_ATTR(REG, +1, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(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.blocks[0], 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]
|
|
in = 'lfs.c'
|
|
code = '''
|
|
lfs_t lfs;
|
|
lfs_init(&lfs, CFG) => 0;
|
|
|
|
lfsr_rbyd_t init_rbyd = {
|
|
.blocks[0] = 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
|
|
LFSR_ATTR(REG, +1, BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xaa\xaa", 2)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_ATTRS(
|
|
LFSR_ATTR(REG, +1, BUF("\xbb\xbb\xbb\xbb", 4)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_ATTRS(
|
|
LFSR_ATTR(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.blocks[0], 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
|
|
LFSR_ATTR(REG, +1, BUF("\xbb\xbb\xbb\xbb", 4)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xbb\xbb", 2)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
|
|
LFSR_ATTR(REG, +1, BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
|
|
LFSR_ATTR(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.blocks[0], 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
|
|
# 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 = {
|
|
.blocks[0] = 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.blocks[0]) => 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, rid, LFSR_ATTRS(
|
|
LFSR_ATTR(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, rid, LFSR_ATTRS(
|
|
LFSR_ATTR(UATTR(u+1), 0,
|
|
BUF(names[perm[j] % 6], 2)))) => 0;
|
|
}
|
|
}
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 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 = {
|
|
.blocks[0] = 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.blocks[0]) => 0;
|
|
|
|
for (unsigned j = 0; j < N; j++) {
|
|
lfsr_rbyd_commit(&lfs, &rbyd, j, LFSR_ATTRS(
|
|
LFSR_ATTR(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, j, LFSR_ATTRS(
|
|
LFSR_ATTR(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.blocks[0], 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.blocks[0]) => 0;
|
|
lfs_bd_prog(&lfs, &lfs.pcache, &lfs.rcache, false,
|
|
rbyd.blocks[0], 0, backup_block, rbyd.eoff,
|
|
NULL) => 0;
|
|
lfs_bd_flush(&lfs, &lfs.pcache, &lfs.rcache, false,
|
|
NULL) => 0;
|
|
|
|
// update each tag in permutation order
|
|
for (unsigned j = 0; j < N*M; j++) {
|
|
lfsr_rbyd_commit(&lfs, &rbyd, perm[j]/M, LFSR_ATTRS(
|
|
LFSR_ATTR(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.blocks[0], 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 = {
|
|
.blocks[0] = 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.blocks[0]) => 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, rid, LFSR_ATTRS(
|
|
LFSR_ATTR(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, rid, LFSR_ATTRS(
|
|
LFSR_ATTR(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.blocks[0], 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.blocks[0]) => 0;
|
|
lfs_bd_prog(&lfs, &lfs.pcache, &lfs.rcache, false,
|
|
rbyd.blocks[0], 0, backup_block, rbyd.eoff,
|
|
NULL) => 0;
|
|
lfs_bd_flush(&lfs, &lfs.pcache, &lfs.rcache, false,
|
|
NULL) => 0;
|
|
|
|
lfsr_rbyd_commit(&lfs, &rbyd, j/M, LFSR_ATTRS(
|
|
LFSR_ATTR(RM(UATTR((j%M)+1)), 0, NULL()))) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 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, j/M, LFSR_ATTRS(
|
|
LFSR_ATTR(UATTR((j%M)+1), 0,
|
|
BUF(names[(j/M)%6], 3)))) => 0;
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 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 = {
|
|
.blocks[0] = 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.blocks[0]) => 0;
|
|
|
|
for (unsigned j = 0; j < N; j++) {
|
|
lfsr_rbyd_commit(&lfs, &rbyd, j, LFSR_ATTRS(
|
|
LFSR_ATTR(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, j, LFSR_ATTRS(
|
|
LFSR_ATTR(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.blocks[0], 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.blocks[0]) => 0;
|
|
lfs_bd_prog(&lfs, &lfs.pcache, &lfs.rcache, false,
|
|
rbyd.blocks[0], 0, backup_block, rbyd.eoff,
|
|
NULL) => 0;
|
|
lfs_bd_flush(&lfs, &lfs.pcache, &lfs.rcache, false,
|
|
NULL) => 0;
|
|
|
|
// remove each tag in permutation order
|
|
for (unsigned j = 0; j < N*M; j++) {
|
|
lfsr_rbyd_commit(&lfs, &rbyd, perm[j]/M, LFSR_ATTRS(
|
|
LFSR_ATTR(RM(UATTR(perm[j]%M+1)),
|
|
0, NULL()))) => 0;
|
|
}
|
|
|
|
// check that all tags have been removed
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 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 = {
|
|
.blocks[0] = 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.blocks[0]) => 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(REG, +1, BUF(names[x % 6], 4));
|
|
for (unsigned u = 0; u < M; u++) {
|
|
attrs[1+u] = LFSR_ATTR(UATTR(u+1), 0, BUF(names[x % 6], 2));
|
|
}
|
|
|
|
int err = lfsr_rbyd_commit(&lfs, &rbyd, x, 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.blocks[0], 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 = {
|
|
.blocks[0] = 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.blocks[0]) => 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, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(UATTR(perm[j]+1), 0,
|
|
BUF(names[perm[j] % 6], 1)))) => 0;
|
|
|
|
lfsr_rbyd_commit(&lfs, &rbyd, rid, LFSR_ATTRS(
|
|
LFSR_ATTR(REG, +1,
|
|
BUF(names[perm[j] % 6], 4)))) => 0;
|
|
}
|
|
|
|
// try looking up each tag
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 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 = {
|
|
.blocks[0] = 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.blocks[0]) => 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, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(UATTR(perm[j]+1), 0,
|
|
BUF(names[perm[j] % 6], 1)))) => 0;
|
|
|
|
lfsr_rbyd_commit(&lfs, &rbyd, rid, LFSR_ATTRS(
|
|
LFSR_ATTR(REG, +1,
|
|
BUF(names[perm[j] % 6], 4)))) => 0;
|
|
for (unsigned u = 0; u < M; u++) {
|
|
lfsr_rbyd_commit(&lfs, &rbyd, rid, LFSR_ATTRS(
|
|
LFSR_ATTR(UATTR(u+1), 0,
|
|
BUF(names[perm[j] % 6], 2)))) => 0;
|
|
}
|
|
}
|
|
|
|
// try looking up each tag
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 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 = {
|
|
.blocks[0] = 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
|
|
LFSR_ATTR(REG, +1, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(REG, +1, BUF("\xbb\xbb\xbb\xbb", 4)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_ATTRS(
|
|
LFSR_ATTR(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.blocks[0], 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
|
|
LFSR_ATTR(REG, +1, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(REG, +1, BUF("\xbb\xbb\xbb\xbb", 4)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
|
|
LFSR_ATTR(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.blocks[0], 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
|
|
LFSR_ATTR(REG, +1, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(REG, +1, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(REG, +1, BUF("\xcc\xcc\xcc\xcc", 4)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 2, LFSR_ATTRS(
|
|
LFSR_ATTR(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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
|
|
LFSR_ATTR(REG, +1, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(REG, +1, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(REG, +1, BUF("\xcc\xcc\xcc\xcc", 4)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
|
|
LFSR_ATTR(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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
|
|
LFSR_ATTR(REG, +1, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(REG, +1, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(REG, +1, BUF("\xcc\xcc\xcc\xcc", 4)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_ATTRS(
|
|
LFSR_ATTR(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 = {
|
|
.blocks[0] = 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
|
|
LFSR_ATTR(REG, +1, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xaa\xaa", 2)),
|
|
LFSR_ATTR(REG, +1, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xbb\xbb", 2)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_ATTRS(
|
|
LFSR_ATTR(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.blocks[0], 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
|
|
LFSR_ATTR(REG, +1, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xaa\xaa", 2)),
|
|
LFSR_ATTR(REG, +1, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xbb\xbb", 2)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
|
|
LFSR_ATTR(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.blocks[0], 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
|
|
LFSR_ATTR(REG, +1, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xaa\xaa", 2)),
|
|
LFSR_ATTR(REG, +1, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xbb\xbb", 2)),
|
|
LFSR_ATTR(REG, +1, BUF("\xcc\xcc\xcc\xcc", 4)),
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xcc\xcc", 2)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 2, LFSR_ATTRS(
|
|
LFSR_ATTR(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.blocks[0], 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
|
|
LFSR_ATTR(REG, +1, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xaa\xaa", 2)),
|
|
LFSR_ATTR(REG, +1, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xbb\xbb", 2)),
|
|
LFSR_ATTR(REG, +1, BUF("\xcc\xcc\xcc\xcc", 4)),
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xcc\xcc", 2)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
|
|
LFSR_ATTR(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.blocks[0], 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
|
|
LFSR_ATTR(REG, +1, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xaa\xaa", 2)),
|
|
LFSR_ATTR(REG, +1, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xbb\xbb", 2)),
|
|
LFSR_ATTR(REG, +1, BUF("\xcc\xcc\xcc\xcc", 4)),
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xcc\xcc", 2)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_ATTRS(
|
|
LFSR_ATTR(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.blocks[0], 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 = {
|
|
.blocks[0] = 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.blocks[0]) => 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, rid, LFSR_ATTRS(
|
|
LFSR_ATTR(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.blocks[0], 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.blocks[0]) => 0;
|
|
lfs_bd_prog(&lfs, &lfs.pcache, &lfs.rcache, false,
|
|
rbyd.blocks[0], 0, backup_block, rbyd.eoff,
|
|
NULL) => 0;
|
|
lfs_bd_flush(&lfs, &lfs.pcache, &lfs.rcache, false,
|
|
NULL) => 0;
|
|
|
|
lfsr_rbyd_commit(&lfs, &rbyd, j, LFSR_ATTRS(
|
|
LFSR_ATTR(RM, -1, NULL()))) => 0;
|
|
assert(rbyd.weight == N-1);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 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, j, LFSR_ATTRS(
|
|
LFSR_ATTR(REG, +1, BUF(names[j % 6], 6)))) => 0;
|
|
assert(rbyd.weight == N);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 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 = {
|
|
.blocks[0] = 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.blocks[0]) => 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, rid, LFSR_ATTRS(
|
|
LFSR_ATTR(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, rid, LFSR_ATTRS(
|
|
LFSR_ATTR(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.blocks[0], 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.blocks[0]) => 0;
|
|
lfs_bd_prog(&lfs, &lfs.pcache, &lfs.rcache, false,
|
|
rbyd.blocks[0], 0, backup_block, rbyd.eoff,
|
|
NULL) => 0;
|
|
lfs_bd_flush(&lfs, &lfs.pcache, &lfs.rcache, false,
|
|
NULL) => 0;
|
|
|
|
lfsr_rbyd_commit(&lfs, &rbyd, j, LFSR_ATTRS(
|
|
LFSR_ATTR(RM, -1, NULL()))) => 0;
|
|
assert(rbyd.weight == N-1);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 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, j, LFSR_ATTRS(
|
|
LFSR_ATTR(REG, +1, BUF(names[j % 6], 6)))) => 0;
|
|
for (unsigned u = 0; u < M; u++) {
|
|
lfsr_rbyd_commit(&lfs, &rbyd, j, LFSR_ATTRS(
|
|
LFSR_ATTR(UATTR(u+1), 0,
|
|
BUF(names[j % 6], 3)))) => 0;
|
|
}
|
|
assert(rbyd.weight == N);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 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 = {
|
|
.blocks[0] = 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.blocks[0]) => 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, rid, LFSR_ATTRS(
|
|
LFSR_ATTR(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.blocks[0], 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.blocks[0]) => 0;
|
|
lfs_bd_prog(&lfs, &lfs.pcache, &lfs.rcache, false,
|
|
rbyd.blocks[0], 0, backup_block, rbyd.eoff,
|
|
NULL) => 0;
|
|
lfs_bd_flush(&lfs, &lfs.pcache, &lfs.rcache, false,
|
|
NULL) => 0;
|
|
|
|
lfsr_rbyd_commit(&lfs, &rbyd, j, LFSR_ATTRS(
|
|
LFSR_ATTR(RM, -1, NULL()))) => 0;
|
|
assert(rbyd.weight == N-1);
|
|
|
|
// try traversing over the tags
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 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 = {
|
|
.blocks[0] = 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.blocks[0]) => 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, rid, LFSR_ATTRS(
|
|
LFSR_ATTR(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, rid, LFSR_ATTRS(
|
|
LFSR_ATTR(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.blocks[0], 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.blocks[0]) => 0;
|
|
lfs_bd_prog(&lfs, &lfs.pcache, &lfs.rcache, false,
|
|
rbyd.blocks[0], 0, backup_block, rbyd.eoff,
|
|
NULL) => 0;
|
|
lfs_bd_flush(&lfs, &lfs.pcache, &lfs.rcache, false,
|
|
NULL) => 0;
|
|
|
|
lfsr_rbyd_commit(&lfs, &rbyd, j, LFSR_ATTRS(
|
|
LFSR_ATTR(RM, -1, NULL()))) => 0;
|
|
assert(rbyd.weight == N-1);
|
|
|
|
// try traversing over the tags
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 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 = {
|
|
.blocks[0] = 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
|
|
LFSR_ATTR(REG, +1, BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
|
|
LFSR_ATTR(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.blocks[0], 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
|
|
LFSR_ATTR(REG, +1, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(REG, +1, BUF("\xbb\xbb\xbb\xbb", 4)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_ATTRS(
|
|
LFSR_ATTR(RM, -1, NULL()),
|
|
LFSR_ATTR(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.blocks[0], 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
|
|
LFSR_ATTR(REG, +1, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(REG, +1, BUF("\xbb\xbb\xbb\xbb", 4)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
|
|
LFSR_ATTR(RM, -1, NULL()))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
|
|
LFSR_ATTR(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.blocks[0], 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
|
|
LFSR_ATTR(REG, +1, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(REG, +1, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(REG, +1, BUF("\xcc\xcc\xcc\xcc", 4)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 2, LFSR_ATTRS(
|
|
LFSR_ATTR(RM, -1, NULL()),
|
|
LFSR_ATTR(RM, -1, NULL()),
|
|
LFSR_ATTR(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.blocks[0], 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
|
|
LFSR_ATTR(REG, +1, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(REG, +1, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(REG, +1, BUF("\xcc\xcc\xcc\xcc", 4)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
|
|
LFSR_ATTR(RM, -1, NULL()))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
|
|
LFSR_ATTR(RM, -1, NULL()))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
|
|
LFSR_ATTR(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.blocks[0], 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 = {
|
|
.blocks[0] = 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
|
|
LFSR_ATTR(REG, +1, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xaa\xaa", 2)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
|
|
LFSR_ATTR(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.blocks[0], 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
|
|
LFSR_ATTR(REG, +1, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xaa\xaa", 2)),
|
|
LFSR_ATTR(REG, +1, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xbb\xbb", 2)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_ATTRS(
|
|
LFSR_ATTR(RM, -1, NULL()),
|
|
LFSR_ATTR(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.blocks[0], 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
|
|
LFSR_ATTR(REG, +1, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xaa\xaa", 2)),
|
|
LFSR_ATTR(REG, +1, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xbb\xbb", 2)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
|
|
LFSR_ATTR(RM, -1, NULL()))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
|
|
LFSR_ATTR(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.blocks[0], 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
|
|
LFSR_ATTR(REG, +1, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xaa\xaa", 2)),
|
|
LFSR_ATTR(REG, +1, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xbb\xbb", 2)),
|
|
LFSR_ATTR(REG, +1, BUF("\xcc\xcc\xcc\xcc", 4)),
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xcc\xcc", 2)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 2, LFSR_ATTRS(
|
|
LFSR_ATTR(RM, -1, NULL()),
|
|
LFSR_ATTR(RM, -1, NULL()),
|
|
LFSR_ATTR(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.blocks[0], 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
|
|
LFSR_ATTR(REG, +1, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xaa\xaa", 2)),
|
|
LFSR_ATTR(REG, +1, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xbb\xbb", 2)),
|
|
LFSR_ATTR(REG, +1, BUF("\xcc\xcc\xcc\xcc", 4)),
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xcc\xcc", 2)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
|
|
LFSR_ATTR(RM, -1, NULL()))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
|
|
LFSR_ATTR(RM, -1, NULL()))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
|
|
LFSR_ATTR(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.blocks[0], 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 = {
|
|
.blocks[0] = 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.blocks[0]) => 0;
|
|
|
|
for (unsigned j = 0; j < N; j++) {
|
|
lfsr_rbyd_commit(&lfs, &rbyd, j, LFSR_ATTRS(
|
|
LFSR_ATTR(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.blocks[0], 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.blocks[0]) => 0;
|
|
lfs_bd_prog(&lfs, &lfs.pcache, &lfs.rcache, false,
|
|
rbyd.blocks[0], 0, backup_block, rbyd.eoff,
|
|
NULL) => 0;
|
|
lfs_bd_flush(&lfs, &lfs.pcache, &lfs.rcache, false,
|
|
NULL) => 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, rid, LFSR_ATTRS(
|
|
LFSR_ATTR(RM, -1, NULL()))) => 0;
|
|
assert(rbyd.weight == rbyd_weight_before-1);
|
|
}
|
|
|
|
// check that all tags are now removed
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 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, 0, LFSR_ATTRS(
|
|
LFSR_ATTR(REG, +1,
|
|
BUF("\xaa\xaa\xaa\xaa\xaa\xaa", 6)))) => 0;
|
|
assert(rbyd.weight == 1);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 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 = {
|
|
.blocks[0] = 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.blocks[0]) => 0;
|
|
|
|
for (unsigned j = 0; j < N; j++) {
|
|
lfsr_rbyd_commit(&lfs, &rbyd, j, LFSR_ATTRS(
|
|
LFSR_ATTR(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, j, LFSR_ATTRS(
|
|
LFSR_ATTR(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.blocks[0], 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.blocks[0]) => 0;
|
|
lfs_bd_prog(&lfs, &lfs.pcache, &lfs.rcache, false,
|
|
rbyd.blocks[0], 0, backup_block, rbyd.eoff,
|
|
NULL) => 0;
|
|
lfs_bd_flush(&lfs, &lfs.pcache, &lfs.rcache, false,
|
|
NULL) => 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, rid, LFSR_ATTRS(
|
|
LFSR_ATTR(RM, -1, NULL()))) => 0;
|
|
assert(rbyd.weight == rbyd_weight_before-1);
|
|
}
|
|
|
|
// check that all tags are now removed
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 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, 0, LFSR_ATTRS(
|
|
LFSR_ATTR(REG, +1,
|
|
BUF("\xaa\xaa\xaa\xaa\xaa\xaa", 6)))) => 0;
|
|
for (unsigned u = 0; u < M; u++) {
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
|
|
LFSR_ATTR(UATTR(u+1), 0, BUF("\xaa\xaa\xaa", 3)))) => 0;
|
|
}
|
|
assert(rbyd.weight == 1);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 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 = {
|
|
.blocks[0] = 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.blocks[0]) => 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, rid, LFSR_ATTRS(
|
|
LFSR_ATTR(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, rid, LFSR_ATTRS(
|
|
LFSR_ATTR(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 = {
|
|
.blocks[0] = 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
|
|
LFSR_ATTR(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.blocks[0], 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, 1, LFSR_ATTRS(
|
|
LFSR_ATTR(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.blocks[0], 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, 3, LFSR_ATTRS(
|
|
LFSR_ATTR(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.blocks[0], 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, 6, LFSR_ATTRS(
|
|
LFSR_ATTR(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.blocks[0], 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, 10, LFSR_ATTRS(
|
|
LFSR_ATTR(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.blocks[0], 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 = {
|
|
.blocks[0] = 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
|
|
// make id0 with weight w1
|
|
LFSR_ATTR(REG, +1, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
// make id2 with weight w2
|
|
LFSR_ATTR(REG, +2, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
// make id5 with weight w3
|
|
LFSR_ATTR(REG, +3, BUF("\xcc\xcc\xcc\xcc", 4)),
|
|
// make id9 with weight w4
|
|
LFSR_ATTR(REG, +4, BUF("\xdd\xdd\xdd\xdd", 4)),
|
|
// make id14 with weight w5
|
|
LFSR_ATTR(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.blocks[0], 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 = {
|
|
.blocks[0] = 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.blocks[0]) => 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, rid*W, LFSR_ATTRS(
|
|
LFSR_ATTR(REG, +W,
|
|
BUF(names[perm[j] % 6], 4)))) => 0;
|
|
}
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 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 = {
|
|
.blocks[0] = 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.blocks[0]) => 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, rid*W, LFSR_ATTRS(
|
|
LFSR_ATTR(REG, +W,
|
|
BUF(names[perm[j] % 6], 4)))) => 0;
|
|
}
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 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 = {
|
|
.blocks[0] = 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(UATTR(3), 0, BUF("unrelated", 9)),
|
|
LFSR_ATTR(REG, +1, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xaa\xaa", 2)),
|
|
LFSR_ATTR(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.blocks[0], 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, 1, LFSR_ATTRS(
|
|
LFSR_ATTR(REG, +1, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xbb\xbb", 2)),
|
|
LFSR_ATTR(GROW, +1, NULL()),
|
|
LFSR_ATTR(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.blocks[0], 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, 3, LFSR_ATTRS(
|
|
LFSR_ATTR(REG, +1, BUF("\xcc\xcc\xcc\xcc", 4)),
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xcc\xcc", 2)),
|
|
LFSR_ATTR(GROW, +2, NULL()),
|
|
LFSR_ATTR(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.blocks[0], 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, 6, LFSR_ATTRS(
|
|
LFSR_ATTR(REG, +1, BUF("\xdd\xdd\xdd\xdd", 4)),
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xdd\xdd", 2)),
|
|
LFSR_ATTR(GROW, +3, NULL()),
|
|
LFSR_ATTR(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.blocks[0], 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, 10, LFSR_ATTRS(
|
|
LFSR_ATTR(REG, +1, BUF("\xee\xee\xee\xee", 4)),
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xee\xee", 2)),
|
|
LFSR_ATTR(GROW, +4, NULL()),
|
|
LFSR_ATTR(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.blocks[0], 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 = {
|
|
.blocks[0] = 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(UATTR(3), 0, BUF("unrelated", 9)),
|
|
// make id0 with weight w1
|
|
LFSR_ATTR(REG, +1, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xaa\xaa", 2)),
|
|
LFSR_ATTR(UATTR(2), 0, BUF("\xaa\xaa", 2)),
|
|
// make id2 with weight w2
|
|
LFSR_ATTR(REG, +1, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xbb\xbb", 2)),
|
|
LFSR_ATTR(GROW, +1, NULL()),
|
|
LFSR_ATTR(UATTR(2), 0, BUF("\xbb\xbb", 2)),
|
|
// make id5 with weight w3
|
|
LFSR_ATTR(REG, +1, BUF("\xcc\xcc\xcc\xcc", 4)),
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xcc\xcc", 2)),
|
|
LFSR_ATTR(GROW, +2, NULL()),
|
|
LFSR_ATTR(UATTR(2), 0, BUF("\xcc\xcc", 2)),
|
|
// make id9 with weight w4
|
|
LFSR_ATTR(REG, +1, BUF("\xdd\xdd\xdd\xdd", 4)),
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xdd\xdd", 2)),
|
|
LFSR_ATTR(GROW, +3, NULL()),
|
|
LFSR_ATTR(UATTR(2), 0, BUF("\xdd\xdd", 2)),
|
|
// make id14 with weight w5
|
|
LFSR_ATTR(REG, +1, BUF("\xee\xee\xee\xee", 4)),
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xee\xee", 2)),
|
|
LFSR_ATTR(GROW, +4, NULL()),
|
|
LFSR_ATTR(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.blocks[0], 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 = {
|
|
.blocks[0] = 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(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, rid*W, LFSR_ATTRS(
|
|
LFSR_ATTR(REG, +1, BUF(names[perm[j] % 6], 4)),
|
|
LFSR_ATTR(UATTR(1), 0, BUF(names[perm[j] % 6], 2)),
|
|
LFSR_ATTR(GROW, +W-1, NULL()),
|
|
LFSR_ATTR(UATTR(2), 0,
|
|
BUF(names[perm[j] % 6], 2)))) => 0;
|
|
}
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 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 = {
|
|
.blocks[0] = 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.blocks[0]) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(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, rid*W, LFSR_ATTRS(
|
|
LFSR_ATTR(REG, +1, BUF(names[perm[j] % 6], 4)),
|
|
LFSR_ATTR(UATTR(1), 0, BUF(names[perm[j] % 6], 2)),
|
|
LFSR_ATTR(GROW, +W-1, NULL()),
|
|
LFSR_ATTR(UATTR(2), 0,
|
|
BUF(names[perm[j] % 6], 2)))) => 0;
|
|
}
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 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 = {
|
|
.blocks[0] = 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.blocks[0]) => 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, rid*W, LFSR_ATTRS(
|
|
LFSR_ATTR(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.blocks[0], 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.blocks[0]) => 0;
|
|
lfs_bd_prog(&lfs, &lfs.pcache, &lfs.rcache, false,
|
|
rbyd.blocks[0], 0, backup_block, rbyd.eoff,
|
|
NULL) => 0;
|
|
lfs_bd_flush(&lfs, &lfs.pcache, &lfs.rcache, false,
|
|
NULL) => 0;
|
|
|
|
lfsr_rbyd_commit(&lfs, &rbyd, j*W+W-1, LFSR_ATTRS(
|
|
LFSR_ATTR(GROW, +D, NULL()))) => 0;
|
|
assert(rbyd.weight == N*W+D);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 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 = {
|
|
.blocks[0] = 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.blocks[0]) => 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, rid*W, LFSR_ATTRS(
|
|
LFSR_ATTR(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.blocks[0], 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.blocks[0]) => 0;
|
|
lfs_bd_prog(&lfs, &lfs.pcache, &lfs.rcache, false,
|
|
rbyd.blocks[0], 0, backup_block, rbyd.eoff,
|
|
NULL) => 0;
|
|
lfs_bd_flush(&lfs, &lfs.pcache, &lfs.rcache, false,
|
|
NULL) => 0;
|
|
|
|
lfsr_rbyd_commit(&lfs, &rbyd, j*W+W-1, LFSR_ATTRS(
|
|
LFSR_ATTR(GROW(REG), +D,
|
|
BUF(names[j % 6], 6)))) => 0;
|
|
assert(rbyd.weight == N*W+D);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 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 = {
|
|
.blocks[0] = 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.blocks[0]) => 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, rid*W, LFSR_ATTRS(
|
|
LFSR_ATTR(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.blocks[0], 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.blocks[0]) => 0;
|
|
lfs_bd_prog(&lfs, &lfs.pcache, &lfs.rcache, false,
|
|
rbyd.blocks[0], 0, backup_block, rbyd.eoff,
|
|
NULL) => 0;
|
|
lfs_bd_flush(&lfs, &lfs.pcache, &lfs.rcache, false,
|
|
NULL) => 0;
|
|
|
|
lfsr_rbyd_commit(&lfs, &rbyd, j*W+W-1, LFSR_ATTRS(
|
|
LFSR_ATTR(GROW(UATTR(1)), +D,
|
|
BUF(names[j % 6], 6)))) => 0;
|
|
assert(rbyd.weight == N*W+D);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 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 = {
|
|
.blocks[0] = 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.blocks[0]) => 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, rid*W, LFSR_ATTRS(
|
|
LFSR_ATTR(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.blocks[0], 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.blocks[0]) => 0;
|
|
lfs_bd_prog(&lfs, &lfs.pcache, &lfs.rcache, false,
|
|
rbyd.blocks[0], 0, backup_block, rbyd.eoff,
|
|
NULL) => 0;
|
|
lfs_bd_flush(&lfs, &lfs.pcache, &lfs.rcache, false,
|
|
NULL) => 0;
|
|
|
|
lfsr_rbyd_commit(&lfs, &rbyd, j*W+W-1, LFSR_ATTRS(
|
|
LFSR_ATTR(GROW, -D, NULL()))) => 0;
|
|
assert(rbyd.weight == N*W-D);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 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 = {
|
|
.blocks[0] = 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.blocks[0]) => 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, rid*W, LFSR_ATTRS(
|
|
LFSR_ATTR(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.blocks[0], 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.blocks[0]) => 0;
|
|
lfs_bd_prog(&lfs, &lfs.pcache, &lfs.rcache, false,
|
|
rbyd.blocks[0], 0, backup_block, rbyd.eoff,
|
|
NULL) => 0;
|
|
lfs_bd_flush(&lfs, &lfs.pcache, &lfs.rcache, false,
|
|
NULL) => 0;
|
|
|
|
lfsr_rbyd_commit(&lfs, &rbyd, j*W+W-1, LFSR_ATTRS(
|
|
LFSR_ATTR(GROW(REG), -D,
|
|
BUF(names[j % 6], 6)))) => 0;
|
|
assert(rbyd.weight == N*W-D);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 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 = {
|
|
.blocks[0] = 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.blocks[0]) => 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, rid*W, LFSR_ATTRS(
|
|
LFSR_ATTR(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.blocks[0], 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.blocks[0]) => 0;
|
|
lfs_bd_prog(&lfs, &lfs.pcache, &lfs.rcache, false,
|
|
rbyd.blocks[0], 0, backup_block, rbyd.eoff,
|
|
NULL) => 0;
|
|
lfs_bd_flush(&lfs, &lfs.pcache, &lfs.rcache, false,
|
|
NULL) => 0;
|
|
|
|
lfsr_rbyd_commit(&lfs, &rbyd, j*W+W-1, LFSR_ATTRS(
|
|
LFSR_ATTR(GROW(UATTR(1)), -D,
|
|
BUF(names[j % 6], 6)))) => 0;
|
|
assert(rbyd.weight == N*W-D);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 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 = {
|
|
.blocks[0] = 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.blocks[0]) => 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, rid*W, LFSR_ATTRS(
|
|
LFSR_ATTR(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.blocks[0], 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.blocks[0]) => 0;
|
|
lfs_bd_prog(&lfs, &lfs.pcache, &lfs.rcache, false,
|
|
rbyd.blocks[0], 0, backup_block, rbyd.eoff,
|
|
NULL) => 0;
|
|
lfs_bd_flush(&lfs, &lfs.pcache, &lfs.rcache, false,
|
|
NULL) => 0;
|
|
|
|
lfsr_rbyd_commit(&lfs, &rbyd, j*W+W-1, LFSR_ATTRS(
|
|
LFSR_ATTR(RM, -W, NULL()))) => 0;
|
|
assert(rbyd.weight == (N-1)*W);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 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, j*W, LFSR_ATTRS(
|
|
LFSR_ATTR(REG, +W, BUF(names[j % 6], 6)))) => 0;
|
|
assert(rbyd.weight == N*W);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 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 = {
|
|
.blocks[0] = 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.blocks[0]) => 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, rid*W, LFSR_ATTRS(
|
|
LFSR_ATTR(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.blocks[0], 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.blocks[0]) => 0;
|
|
lfs_bd_prog(&lfs, &lfs.pcache, &lfs.rcache, false,
|
|
rbyd.blocks[0], 0, backup_block, rbyd.eoff,
|
|
NULL) => 0;
|
|
lfs_bd_flush(&lfs, &lfs.pcache, &lfs.rcache, false,
|
|
NULL) => 0;
|
|
|
|
lfsr_rbyd_commit(&lfs, &rbyd, j*W+W-1, LFSR_ATTRS(
|
|
LFSR_ATTR(UATTR(1), 0,
|
|
BUF(names[j % 6], 2)))) => 0;
|
|
assert(rbyd.weight == N*W);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 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, j*W+W-1, LFSR_ATTRS(
|
|
LFSR_ATTR(RM(UATTR(1)), 0, NULL()))) => 0;
|
|
assert(rbyd.weight == N*W);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 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, j*W+W-1, LFSR_ATTRS(
|
|
LFSR_ATTR(UATTR(1), 0,
|
|
BUF(names[j % 6], 2)))) => 0;
|
|
assert(rbyd.weight == N*W);
|
|
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 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 = {
|
|
.blocks[0] = 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.blocks[0]) => 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, rid, LFSR_ATTRS(
|
|
LFSR_ATTR(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, rid, LFSR_ATTRS(
|
|
LFSR_ATTR(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, rid, LFSR_ATTRS(
|
|
LFSR_ATTR(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, rid, LFSR_ATTRS(
|
|
LFSR_ATTR(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 = {
|
|
.blocks[0] = 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.blocks[0]) => 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, weighted_rid, LFSR_ATTRS(
|
|
LFSR_ATTR(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, weighted_rid+weight_-1, LFSR_ATTRS(
|
|
LFSR_ATTR(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, weighted_rid+weight_-1, LFSR_ATTRS(
|
|
LFSR_ATTR(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, weighted_rid+weight_-1, LFSR_ATTRS(
|
|
LFSR_ATTR(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);
|
|
'''
|
|
|
|
|
|
### Supertype/subtype-wide things ###
|
|
|
|
# subtype-wide
|
|
[cases.test_rbyd_subwide_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 = {
|
|
.blocks[0] = 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.blocks[0]) => 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, rid, LFSR_ATTRS(
|
|
LFSR_ATTR(REG, +1, BUF(names[perm[j] % 6], 4)),
|
|
LFSR_ATTR(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.blocks[0], 0) => 0;
|
|
assert(rbyd.weight == N);
|
|
|
|
for (unsigned j = 0; j < N; j++) {
|
|
lfsr_tag_t tag_;
|
|
lfsr_data_t data_;
|
|
lfsr_rbyd_sublookup(&lfs, &rbyd, j, LFSR_TAG_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_subwide_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 = {
|
|
.blocks[0] = 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.blocks[0]) => 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, rid, LFSR_ATTRS(
|
|
LFSR_ATTR(REG, +1, BUF(names[perm[j] % 6], 4)),
|
|
LFSR_ATTR(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.blocks[0], 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.blocks[0]) => 0;
|
|
lfs_bd_prog(&lfs, &lfs.pcache, &lfs.rcache, false,
|
|
rbyd.blocks[0], 0, backup_block, rbyd.eoff,
|
|
NULL) => 0;
|
|
lfs_bd_flush(&lfs, &lfs.pcache, &lfs.rcache, false,
|
|
NULL) => 0;
|
|
|
|
// remove with a wide tag
|
|
lfsr_rbyd_commit(&lfs, &rbyd, j, LFSR_ATTRS(
|
|
LFSR_ATTR(RM(SUBMASK(UATTR)), 0, NULL()))) => 0;
|
|
|
|
// try traversing over the tags
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 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_sublookup(&lfs, &rbyd, k, LFSR_TAG_UATTR,
|
|
&tag_, &data_) => LFS_ERR_NOENT;
|
|
} else {
|
|
lfsr_rbyd_sublookup(&lfs, &rbyd, k, LFSR_TAG_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_subwide_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 = {
|
|
.blocks[0] = 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.blocks[0]) => 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, rid, LFSR_ATTRS(
|
|
LFSR_ATTR(REG, +1, BUF(names[perm[j] % 6], 4)),
|
|
LFSR_ATTR(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.blocks[0], 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.blocks[0]) => 0;
|
|
lfs_bd_prog(&lfs, &lfs.pcache, &lfs.rcache, false,
|
|
rbyd.blocks[0], 0, backup_block, rbyd.eoff,
|
|
NULL) => 0;
|
|
lfs_bd_flush(&lfs, &lfs.pcache, &lfs.rcache, false,
|
|
NULL) => 0;
|
|
|
|
// replace with bitwise inverse
|
|
lfsr_rbyd_commit(&lfs, &rbyd, j, LFSR_ATTRS(
|
|
LFSR_ATTR(SUBMASK(UATTR(~(j + SHIFT) & 0x7f)), 0,
|
|
BUF(names[j % 6], 3)))) => 0;
|
|
|
|
// try traversing over the tags
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 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_sublookup(&lfs, &rbyd, k, LFSR_TAG_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_subwide_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 = {
|
|
.blocks[0] = 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.blocks[0]) => 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, rid, LFSR_ATTRS(
|
|
LFSR_ATTR(REG, +1, BUF(names[perm[j] % 6], 4)),
|
|
LFSR_ATTR(UATTR((perm[j] + SHIFT) & 0x7f), 0,
|
|
BUF(names[perm[j] % 6], 2)),
|
|
LFSR_ATTR(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.blocks[0], 0) => 0;
|
|
assert(rbyd.weight == N);
|
|
|
|
for (unsigned j = 0; j < N; j++) {
|
|
lfsr_tag_t tag_;
|
|
lfsr_data_t data_;
|
|
lfsr_rbyd_sublookup(&lfs, &rbyd, j, LFSR_TAG_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_subwide_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 = {
|
|
.blocks[0] = 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.blocks[0]) => 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, rid, LFSR_ATTRS(
|
|
LFSR_ATTR(REG, +1, BUF(names[perm[j] % 6], 4)),
|
|
LFSR_ATTR(UATTR((perm[j] + SHIFT) & 0x7f), 0,
|
|
BUF(names[perm[j] % 6], 2)),
|
|
LFSR_ATTR(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.blocks[0], 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.blocks[0]) => 0;
|
|
lfs_bd_prog(&lfs, &lfs.pcache, &lfs.rcache, false,
|
|
rbyd.blocks[0], 0, backup_block, rbyd.eoff,
|
|
NULL) => 0;
|
|
lfs_bd_flush(&lfs, &lfs.pcache, &lfs.rcache, false,
|
|
NULL) => 0;
|
|
|
|
// remove with a wide tag
|
|
lfsr_rbyd_commit(&lfs, &rbyd, j, LFSR_ATTRS(
|
|
LFSR_ATTR(RM(SUBMASK(UATTR)), 0, NULL()))) => 0;
|
|
|
|
// try traversing over the tags
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 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_sublookup(&lfs, &rbyd, k, LFSR_TAG_UATTR,
|
|
&tag_, &data_) => LFS_ERR_NOENT;
|
|
} else {
|
|
lfsr_rbyd_sublookup(&lfs, &rbyd, k, LFSR_TAG_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_subwide_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 = {
|
|
.blocks[0] = 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.blocks[0]) => 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, rid, LFSR_ATTRS(
|
|
LFSR_ATTR(REG, +1, BUF(names[perm[j] % 6], 4)),
|
|
LFSR_ATTR(UATTR((perm[j] + SHIFT) & 0x7f), 0,
|
|
BUF(names[perm[j] % 6], 2)),
|
|
LFSR_ATTR(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.blocks[0], 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.blocks[0]) => 0;
|
|
lfs_bd_prog(&lfs, &lfs.pcache, &lfs.rcache, false,
|
|
rbyd.blocks[0], 0, backup_block, rbyd.eoff,
|
|
NULL) => 0;
|
|
lfs_bd_flush(&lfs, &lfs.pcache, &lfs.rcache, false,
|
|
NULL) => 0;
|
|
|
|
// replace with bitwise inverse
|
|
lfsr_rbyd_commit(&lfs, &rbyd, j, LFSR_ATTRS(
|
|
LFSR_ATTR(SUBMASK(UATTR(~(j + SHIFT) & 0x7f)), 0,
|
|
BUF(names[j % 6], 3)))) => 0;
|
|
|
|
// try traversing over the tags
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 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_sublookup(&lfs, &rbyd, k, LFSR_TAG_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_subwide_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 = {
|
|
.blocks[0] = 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.blocks[0]) => 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, rid, LFSR_ATTRS(
|
|
LFSR_ATTR(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.blocks[0], 0) => 0;
|
|
assert(rbyd.weight == N);
|
|
|
|
for (unsigned j = 0; j < N; j++) {
|
|
lfsr_tag_t tag_;
|
|
lfsr_data_t data_;
|
|
lfsr_rbyd_sublookup(&lfs, &rbyd, j, LFSR_TAG_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_subwide_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 = {
|
|
.blocks[0] = 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.blocks[0]) => 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, rid, LFSR_ATTRS(
|
|
LFSR_ATTR(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.blocks[0], 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.blocks[0]) => 0;
|
|
lfs_bd_prog(&lfs, &lfs.pcache, &lfs.rcache, false,
|
|
rbyd.blocks[0], 0, backup_block, rbyd.eoff,
|
|
NULL) => 0;
|
|
lfs_bd_flush(&lfs, &lfs.pcache, &lfs.rcache, false,
|
|
NULL) => 0;
|
|
|
|
// remove with a wide tag
|
|
lfsr_rbyd_commit(&lfs, &rbyd, j, LFSR_ATTRS(
|
|
LFSR_ATTR(RM(SUBMASK(UATTR)), 0, NULL()))) => 0;
|
|
|
|
// try traversing over the tags
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 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_sublookup(&lfs, &rbyd, k, LFSR_TAG_UATTR,
|
|
&tag_, &data_) => LFS_ERR_NOENT;
|
|
} else {
|
|
lfsr_rbyd_sublookup(&lfs, &rbyd, k, LFSR_TAG_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_subwide_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 = {
|
|
.blocks[0] = 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.blocks[0]) => 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, rid, LFSR_ATTRS(
|
|
LFSR_ATTR(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.blocks[0], 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.blocks[0]) => 0;
|
|
lfs_bd_prog(&lfs, &lfs.pcache, &lfs.rcache, false,
|
|
rbyd.blocks[0], 0, backup_block, rbyd.eoff,
|
|
NULL) => 0;
|
|
lfs_bd_flush(&lfs, &lfs.pcache, &lfs.rcache, false,
|
|
NULL) => 0;
|
|
|
|
// replace with bitwise inverse
|
|
lfsr_rbyd_commit(&lfs, &rbyd, j, LFSR_ATTRS(
|
|
LFSR_ATTR(SUBMASK(UATTR(~(j + SHIFT) & 0x7f)), 0,
|
|
BUF(names[j % 6], 6)))) => 0;
|
|
|
|
// try traversing over the tags
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 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_sublookup(&lfs, &rbyd, k, LFSR_TAG_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);
|
|
}
|
|
'''
|
|
|
|
# supertype-wide
|
|
[cases.test_rbyd_supwide_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 = {
|
|
.blocks[0] = 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.blocks[0]) => 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, rid, LFSR_ATTRS(
|
|
LFSR_ATTR(REG, +1, BUF(names[perm[j] % 6], 4)),
|
|
LFSR_ATTR(UATTR((perm[j] + SHIFT) & 0x7f), 0,
|
|
BUF(names[perm[j] % 6], 2)))) => 0;
|
|
}
|
|
assert(rbyd.weight == N);
|
|
|
|
// a supwide attr lookup only gets the file type
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
|
|
assert(rbyd.weight == N);
|
|
|
|
for (unsigned j = 0; j < N; j++) {
|
|
lfsr_tag_t tag_;
|
|
lfsr_data_t data_;
|
|
lfsr_rbyd_suplookup(&lfs, &rbyd, j,
|
|
&tag_, &data_) => 0;
|
|
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
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_supwide_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 = {
|
|
.blocks[0] = 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.blocks[0]) => 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, rid, LFSR_ATTRS(
|
|
LFSR_ATTR(REG, +1, BUF(names[perm[j] % 6], 4)),
|
|
LFSR_ATTR(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.blocks[0], 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.blocks[0]) => 0;
|
|
lfs_bd_prog(&lfs, &lfs.pcache, &lfs.rcache, false,
|
|
rbyd.blocks[0], 0, backup_block, rbyd.eoff,
|
|
NULL) => 0;
|
|
lfs_bd_flush(&lfs, &lfs.pcache, &lfs.rcache, false,
|
|
NULL) => 0;
|
|
|
|
// remove with a wide tag
|
|
lfsr_rbyd_commit(&lfs, &rbyd, j, LFSR_ATTRS(
|
|
LFSR_ATTR(RM(SUPMASK(UATTR)), 0, NULL()))) => 0;
|
|
|
|
// try traversing over the tags
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 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++) {
|
|
if (k != j) {
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(rid_ == k);
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(weight_ == ((k == j+1) ? 2 : 1));
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
|
|
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_sublookup(&lfs, &rbyd, k, LFSR_TAG_UATTR,
|
|
&tag_, &data_) => LFS_ERR_NOENT;
|
|
} else {
|
|
lfsr_rbyd_sublookup(&lfs, &rbyd, k, LFSR_TAG_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_supwide_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 = {
|
|
.blocks[0] = 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.blocks[0]) => 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, rid, LFSR_ATTRS(
|
|
LFSR_ATTR(REG, +1, BUF(names[perm[j] % 6], 4)),
|
|
LFSR_ATTR(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.blocks[0], 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.blocks[0]) => 0;
|
|
lfs_bd_prog(&lfs, &lfs.pcache, &lfs.rcache, false,
|
|
rbyd.blocks[0], 0, backup_block, rbyd.eoff,
|
|
NULL) => 0;
|
|
lfs_bd_flush(&lfs, &lfs.pcache, &lfs.rcache, false,
|
|
NULL) => 0;
|
|
|
|
// replace with bitwise inverse
|
|
lfsr_rbyd_commit(&lfs, &rbyd, j, LFSR_ATTRS(
|
|
LFSR_ATTR(SUPMASK(UATTR(~(j + SHIFT) & 0x7f)), 0,
|
|
BUF(names[j % 6], 3)))) => 0;
|
|
|
|
// try traversing over the tags
|
|
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 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++) {
|
|
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_ == 1);
|
|
assert(lfsr_data_size(&data_) == 3);
|
|
|
|
} else {
|
|
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;
|
|
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_sublookup(&lfs, &rbyd, k, LFSR_TAG_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);
|
|
}
|
|
'''
|
|
|
|
|
|
# Some very specific cases we want to cover
|
|
|
|
# One downside of having only altgt tags (not altge) is that we can end
|
|
# up with an awkward null tag in our rbyd. Need to test we handle this
|
|
# correctly.
|
|
[cases.test_rbyd_unreachable_hole]
|
|
in = 'lfs.c'
|
|
code = '''
|
|
lfs_t lfs;
|
|
lfs_init(&lfs, CFG) => 0;
|
|
|
|
lfsr_rbyd_t init_rbyd = {
|
|
.blocks[0] = 0,
|
|
.eoff = 0,
|
|
.cksum = 0,
|
|
.trunk = 0,
|
|
.weight = 0,
|
|
};
|
|
lfsr_rbyd_t rbyd;
|
|
|
|
// create a null tag hole
|
|
rbyd = init_rbyd;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(UATTR(0), 0, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(RM(UATTR(0)), 0, NULL()))) => 0;
|
|
assert(rbyd.weight == 0);
|
|
|
|
// can we still access things?
|
|
lfs_ssize_t rid_;
|
|
lfsr_tag_t tag_;
|
|
lfs_size_t weight_;
|
|
lfsr_data_t data_;
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, 0,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(rid_ == -1);
|
|
assert(tag_ == LFSR_TAG_UATTR(1));
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
uint8_t rbuf[32];
|
|
lfsr_data_read(&lfs, &data_, rbuf, 32) => 4;
|
|
assert(memcmp(rbuf, "\xbb\xbb\xbb\xbb", 4) == 0);
|
|
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(1)+1,
|
|
&rid_, &tag_, &weight_, &data_) => LFS_ERR_NOENT;
|
|
'''
|
|
|
|
[cases.test_rbyd_unreachable_hole_rm]
|
|
in = 'lfs.c'
|
|
code = '''
|
|
lfs_t lfs;
|
|
lfs_init(&lfs, CFG) => 0;
|
|
|
|
lfsr_rbyd_t init_rbyd = {
|
|
.blocks[0] = 0,
|
|
.eoff = 0,
|
|
.cksum = 0,
|
|
.trunk = 0,
|
|
.weight = 0,
|
|
};
|
|
lfsr_rbyd_t rbyd;
|
|
|
|
// create a null tag hole
|
|
rbyd = init_rbyd;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(UATTR(0), 0, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(UATTR(2), 0, BUF("\xcc\xcc\xcc\xcc", 4)),
|
|
LFSR_ATTR(RM(UATTR(0)), 0, NULL()))) => 0;
|
|
assert(rbyd.weight == 0);
|
|
|
|
// remove a neighbor to the hole
|
|
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(RM(UATTR(1)), 0, NULL()))) => 0;
|
|
assert(rbyd.weight == 0);
|
|
|
|
// can we still access things?
|
|
lfs_ssize_t rid_;
|
|
lfsr_tag_t tag_;
|
|
lfs_size_t weight_;
|
|
lfsr_data_t data_;
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, 0,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(rid_ == -1);
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
uint8_t rbuf[32];
|
|
lfsr_data_read(&lfs, &data_, rbuf, 32) => 4;
|
|
assert(memcmp(rbuf, "\xcc\xcc\xcc\xcc", 4) == 0);
|
|
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(2)+1,
|
|
&rid_, &tag_, &weight_, &data_) => LFS_ERR_NOENT;
|
|
'''
|
|
|
|
[cases.test_rbyd_unreachable_hole_delete]
|
|
in = 'lfs.c'
|
|
code = '''
|
|
lfs_t lfs;
|
|
lfs_init(&lfs, CFG) => 0;
|
|
|
|
lfsr_rbyd_t init_rbyd = {
|
|
.blocks[0] = 0,
|
|
.eoff = 0,
|
|
.cksum = 0,
|
|
.trunk = 0,
|
|
.weight = 0,
|
|
};
|
|
lfsr_rbyd_t rbyd;
|
|
|
|
// create a null tag hole
|
|
rbyd = init_rbyd;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(UATTR(0), 0, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(REG, +1, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(REG, +1, BUF("\xcc\xcc\xcc\xcc", 4)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(RM(UATTR(0)), 0, NULL()))) => 0;
|
|
assert(rbyd.weight == 2);
|
|
|
|
// delete a neighbor to the hole
|
|
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
|
|
LFSR_ATTR(RM, -1, NULL()))) => 0;
|
|
assert(rbyd.weight == 1);
|
|
|
|
// can we still access things?
|
|
lfs_ssize_t rid_;
|
|
lfsr_tag_t tag_;
|
|
lfs_size_t weight_;
|
|
lfsr_data_t data_;
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, 0,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(rid_ == 0);
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(weight_ == 1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
uint8_t rbuf[32];
|
|
lfsr_data_read(&lfs, &data_, rbuf, 32) => 4;
|
|
assert(memcmp(rbuf, "\xcc\xcc\xcc\xcc", 4) == 0);
|
|
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 0, LFSR_TAG_REG+1,
|
|
&rid_, &tag_, &weight_, &data_) => LFS_ERR_NOENT;
|
|
'''
|
|
|
|
[cases.test_rbyd_unreachable_hole_subwide]
|
|
in = 'lfs.c'
|
|
code = '''
|
|
lfs_t lfs;
|
|
lfs_init(&lfs, CFG) => 0;
|
|
|
|
lfsr_rbyd_t init_rbyd = {
|
|
.blocks[0] = 0,
|
|
.eoff = 0,
|
|
.cksum = 0,
|
|
.trunk = 0,
|
|
.weight = 0,
|
|
};
|
|
lfsr_rbyd_t rbyd;
|
|
|
|
// create a null tag hole
|
|
rbyd = init_rbyd;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(UATTR(0), 0, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(SATTR(0), 0, BUF("\xdd\xdd\xdd\xdd", 4)),
|
|
LFSR_ATTR(RM(UATTR(0)), 0, NULL()))) => 0;
|
|
assert(rbyd.weight == 0);
|
|
|
|
// subwide replace a neighbor to the hole
|
|
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(SUBMASK(UATTR(2)), 0,
|
|
BUF("\xcc\xcc\xcc\xcc", 4)))) => 0;
|
|
assert(rbyd.weight == 0);
|
|
|
|
// can we still access things?
|
|
lfs_ssize_t rid_;
|
|
lfsr_tag_t tag_;
|
|
lfs_size_t weight_;
|
|
lfsr_data_t data_;
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, 0,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(rid_ == -1);
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
uint8_t rbuf[32];
|
|
lfsr_data_read(&lfs, &data_, rbuf, 32) => 4;
|
|
assert(memcmp(rbuf, "\xcc\xcc\xcc\xcc", 4) == 0);
|
|
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(2)+1,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(rid_ == -1);
|
|
assert(tag_ == LFSR_TAG_SATTR(0));
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_data_read(&lfs, &data_, rbuf, 32) => 4;
|
|
assert(memcmp(rbuf, "\xdd\xdd\xdd\xdd", 4) == 0);
|
|
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_SATTR(0)+1,
|
|
&rid_, &tag_, &weight_, &data_) => LFS_ERR_NOENT;
|
|
'''
|
|
|
|
[cases.test_rbyd_unreachable_hole_supwide]
|
|
in = 'lfs.c'
|
|
code = '''
|
|
lfs_t lfs;
|
|
lfs_init(&lfs, CFG) => 0;
|
|
|
|
lfsr_rbyd_t init_rbyd = {
|
|
.blocks[0] = 0,
|
|
.eoff = 0,
|
|
.cksum = 0,
|
|
.trunk = 0,
|
|
.weight = 0,
|
|
};
|
|
lfsr_rbyd_t rbyd;
|
|
|
|
// create a null tag hole
|
|
rbyd = init_rbyd;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(UATTR(0), 0, BUF("\xaa\xaa\xaa\xaa", 4)),
|
|
LFSR_ATTR(UATTR(1), 0, BUF("\xbb\xbb\xbb\xbb", 4)),
|
|
LFSR_ATTR(REG, +1, BUF("\xdd\xdd\xdd\xdd", 4)))) => 0;
|
|
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(RM(UATTR(0)), 0, NULL()))) => 0;
|
|
assert(rbyd.weight == 1);
|
|
|
|
// supwide replace a neighbor to the hole
|
|
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
|
|
LFSR_ATTR(SUPMASK(UATTR(2)), 0,
|
|
BUF("\xcc\xcc\xcc\xcc", 4)))) => 0;
|
|
assert(rbyd.weight == 1);
|
|
|
|
// can we still access things?
|
|
lfs_ssize_t rid_;
|
|
lfsr_tag_t tag_;
|
|
lfs_size_t weight_;
|
|
lfsr_data_t data_;
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, 0,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(rid_ == -1);
|
|
assert(tag_ == LFSR_TAG_UATTR(2));
|
|
assert(weight_ == 0);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
uint8_t rbuf[32];
|
|
lfsr_data_read(&lfs, &data_, rbuf, 32) => 4;
|
|
assert(memcmp(rbuf, "\xcc\xcc\xcc\xcc", 4) == 0);
|
|
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_UATTR(2)+1,
|
|
&rid_, &tag_, &weight_, &data_) => 0;
|
|
assert(rid_ == 0);
|
|
assert(tag_ == LFSR_TAG_REG);
|
|
assert(weight_ == 1);
|
|
assert(lfsr_data_size(&data_) == 4);
|
|
lfsr_data_read(&lfs, &data_, rbuf, 32) => 4;
|
|
assert(memcmp(rbuf, "\xdd\xdd\xdd\xdd", 4) == 0);
|
|
|
|
lfsr_rbyd_lookupnext(&lfs, &rbyd, 0, LFSR_TAG_REG+1,
|
|
&rid_, &tag_, &weight_, &data_) => LFS_ERR_NOENT;
|
|
'''
|
|
|