Files
littlefs/tests/test_rbyd.toml
T
Christopher Haster 0a89d0c254 Fixed recoloring tail-recursion violations during range removals
I spoke too soon and made a mistake when reenabling color preservation
during range removals.

I assumed, that thanks to replacing the diverging alt with a new black
alt for stitching together diverging trunks, we would avoid the issue
where a deleted diverging alt violates our rbyd's tail-recursive
recoloring invariant.

Unfortunately, this is not the case. All the stitching alt did was make
this violation more difficult to reach, but still reachable. Arguable a
worse situation.

Now, for this violation to happen, in addition to all of the other
requirements, we need the lower-diverging trunk to become empty.

This is the only case where we have no stitching alt, because we don't
need to stitch an empty trunk. Which means if the upper-diverging trunk
has yellow nodes both before and after the diverging alt, our
tail-recursive recoloring invariant can break.

Here's an example:

     .-------------r-------------.
   .-o-.   .---+---y----.      .-o-.
  .o. .o. .o. .o. .o. .-y-+-. .o. .o.
  a a a a a a a a c c c e e e e e e e
                 '--+--'
                  remove

Again, this doesn't capture the alt-layout, which _is_ important, so
here's the dbgrbyd.py view:

                .-> aa                      .-> aa
              .-b-> a                     .-b-> a
              | .-> a                     | .-> a
  .-----------b-b-> a             .-------b-b-> a
  |             .-> a             |         .-> a
  |   .---------b-> a             |       .-b-> a
  |   |         .-> a             |       | .-> a
  |   | .-------b-> a             |     .-b-b-> a
  r-b-y-r-b-----b-> cc -.     =>  y-y-r-b-----> ee <- two yellows!
    |     |     '-> c   + rm        | '-----b-> e     different dirs!
    |     |     .-> c  -'           |       '-> e     should not happen!
    |     '-y-r-b-> ee              |       .-> e
    |       | '---> e               |     .-b-> e
    |       '-----> e               |     | .-> e
    |           .-> e               '-----b-b-> e
    |         .-b-> e
    |         | .-> e
    '---------b-b-> e

And the steps in our appendattr algorithm that led to this state, which
is insightful:

  read <r => [<r]
  read >b => [<r >b]
  read <r => [<r >b <r]
  read <r => [<r >b <r <r]
                     ^--^------ red + red implies yellow
  ysplit  => [<r >r <b]
  reorder => [<r <r >b]
              ^--^------------- yellow-same-dir invariant held
  read >b => [<r <r >b >b]
  diverge => [<r <r >b]
  read >r => [<r <r >b >r]
  read >r => <r [<r >b >r >r]
                ^-----------^-- our 4-alt fifo for flips/coloring
  ysplit  => <r [<r >r >b]
  reorder => <r [>r >r <b]
                 ^--^---------- yellow-same-dir invariant held
             ^---^------------- yellow-same-dir invariant NOT held
                                though 2 yellows is also a problem

The previous commit fixing this bug for the one-pass algorithm may also
be useful.

This tree is now tested in test_rbyd_delete_range_rydye and
test_rbyd_delete_range_rydye_backwards, though only
test_rbyd_delete_range_rydye_backwards reveals the bug, since the bug
requires _specifically_ the lower-diverging trunk to become empty (both
rydy and rydye now have in-order and backwards tests in case of other
chirality issues).

---

Taking a step back, and looking at this bug from a higher-level, the
core of the issue is that we are somewhat arbitrarily deleting nodes
after splitting nodes. This can break our tail-recursive recoloring
invariant.

What the heck is our tail-recursive recoloring invariant?

This is a property of 2-3-4 and greater B-trees, and transitively
red-black and red-black-yellow trees, that allows for tail-recursive,
self-balancing node insertion.

Basically, if you eagerly split any 4-nodes you encounter as you descend
down the tree, you will always be guaranteed to have an open slot in
your parent, so pushing up split nodes (or recoloring) only ever
propagates up a single level:

   .-----.        .-------.        .-------.
   |.a.h.|        |.a.c.h.|        |.a.c.h.|
   '|-|-|'        '|-|-|-|'        '|-|-|-|'
      |            .-' '-.          .-' '--.
      v            v     v          v      v
  .-------.      .---. .---.      .---. .-----.
  |.b.c.g.|  =>  |.b.| |.g.|  =>  |.b.| |.e.g.|
  '|-|-|-|'      '|-|' '|-|'      '|-|' '|-|-|'
       |                |              .-' '-.
       v                v              v     v
   .-------.        .-------.        .---. .---.
   |.d.e.f.|        |.d.e.f.|        |.d.| |.f.|
   '|-|-|-|'        '|-|-|-|'        '|-|' '|-|'

If you lazily split, you aren't guaranteed an open slot in your parent,
so you need recursion to solve splits. This is why 2-3 trees, though
self-balancing, are not tail-recursive:

   .-----.         .-----.
   |.a.h.|         |.a.h.|
   '|-|-|'         '|-|-|'
      |               |
      v               v
  .-------.      .'''''''''.
  |.b.c.g.|  =>  >.b.c.e.g.< 5!?
  '|-|-|-|'      '|.|.|.|.|'
       |            .-' '-.
       v            v     v
   .-------.      .---. .---.
   |.d.e.f.|      |.d.| |.f.|
   '|-|-|-|'      '|-|' '|-|'

But if you are eagerly splitting while also deleting nodes:

   .-----.        .-------.        .-------.              .'''''''''.
   |.a.h.|        |.a.c.h.|        |.a.c.h.|         5!?  >.a.c.e.h.<
   '|-|-|'        '|-|-|-|'        '|-|-|-|'              '|.|.|.|.|'
      |            .-' '-.          .-' '---.            .---' | '---.
      v            v     v          v       v            v     v     v
  .-------.      .---. .---.      .---. .-------.      .---. .---. .---.
  |.b.c.g.|  =>  |.b.| |.g.|  =>  |.b.| |.d.e.f.|  =>  |.b.| |.d.| |.g.|
  '|-|-|-|'      '|-|' '|-|'      '|-|' '|-|-|-|'      '|-|' '|-|' '|-|'
       | x              | x
       v                v
   .-------.        .-------.
   |.d.e.f.|        |.d.e.f.|
   '|-|-|-|'        '|-|-|-|'

Suddenly, recursion. This is a problem.

The workaround implemented here is to check during pruning if our parent
may risk recursion, and if so, recolor the last alt so nothing will
break.

This ends up equivalent to the following transformation:

   .-----.        .-------.        .-----.          .-----.
   |.a.h.|        |.a.c.h.|        |.a.c.|          |.a.c.|
   '|-|-|'        '|-|-|-|'        '|-|-|'          '|-|-|'
      |            .-' '-.          .-' '-.          .-' '--.
      v            v     v          v     v          v      v
  .-------.      .---. .---.      .---. .---.      .---. .-----.
  |.b.c.g.|  =>  |.b.| |.g.|  =>  |.b.| |.h.|  =>  |.b.| |.e.h.|
  '|-|-|-|'      '|-|' '|-|'      '|-|' '|-|'      '|-|' '|-|-|'
       | x              | x              |              .-' '-.
       v                v                v              v     v
   .-------.        .-------.        .-------.        .---. .---.
   |.d.e.f.|        |.d.e.f.|        |.d.e.f.|        |.d.| |.f.|
   '|-|-|-|'        '|-|-|-|'        '|-|-|-|'        '|-|' '|-|'

You may notice this isn't exactly optimal. The >h branch ends up one
level lower, making the balance of the tree off by one. But it at least
ends up with a functional tree.

I may try to find a better solution...

---

The test_rbyd_delete_range_rydy/rydye tests should cover the cases where
a diverging alt is deleted.

I also tried to write tests for the cases where an alt is pruned, the
closest I got is in test_rbyd_delete_range_dryy_backwards, but I
couldn't actually come up with a sequence that would break our rbyds.

In theory it's possible, but it would need this substructure:

      .-------> c      y-r-b-------> c
  y-r-b-y-r-b-> c  or  | | '-y-r-b-> c
  | |   | | |                | | |

Which, as far as I can tell, can't actually be created with our current
algorithm...

Note the inverse structure:

  .---------> c
  | .-y-r-b-> c
  y-r-  | |

Will be pruned before it has a chance to split. So there is no invariant
concerns there. We only have issues when it's the tail alts that get
pruned, because we decide to split before we know if we are pruning or
not. I don't think this can be avoided without additional read-ahead.

Also, even if we could create the above substructure, because we are on
a diverged trunk, and by definition all alts point the same direction,
we would never end up violating our same-dir yellow invariant/assert...

Code changes:

           code          stack
  before: 33880           2880
  after:  33912 (+0.1%)   2880 (+0.0%)
2024-03-15 00:30:43 -05:00

17116 lines
634 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
[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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
// commit with two attributes
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(2), 0,
LFSR_DATA_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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
// commit with two attributes
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(2), 0,
LFSR_DATA_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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_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(
LFSR_TAG_UATTR(2), 0,
LFSR_DATA_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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(2), 0,
LFSR_DATA_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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(2), 0,
LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(2), 0,
LFSR_DATA_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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(2), 0,
LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_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;
lfsr_data_t data;
uint8_t buffer[4];
// commit with one attribute
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
lfsr_rbyd_lookup(&lfs, &rbyd, -1, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, -1, LFSR_TAG_UATTR(2),
&data) => LFS_ERR_NOENT;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
lfsr_rbyd_lookup(&lfs, &rbyd, -1, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, -1, LFSR_TAG_UATTR(2),
&data) => LFS_ERR_NOENT;
// commit with two attributes
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(2), 0,
LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)))) => 0;
lfsr_rbyd_lookup(&lfs, &rbyd, -1, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
lfsr_rbyd_lookup(&lfs, &rbyd, -1, LFSR_TAG_UATTR(2), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
lfsr_rbyd_lookup(&lfs, &rbyd, -1, LFSR_TAG_UATTR(3),
&data) => LFS_ERR_NOENT;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
lfsr_rbyd_lookup(&lfs, &rbyd, -1, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
lfsr_rbyd_lookup(&lfs, &rbyd, -1, LFSR_TAG_UATTR(2), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
lfsr_rbyd_lookup(&lfs, &rbyd, -1, LFSR_TAG_UATTR(3),
&data) => LFS_ERR_NOENT;
// commit with two attributes, in the other direction
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(2), 0,
LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
lfsr_rbyd_lookup(&lfs, &rbyd, -1, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
lfsr_rbyd_lookup(&lfs, &rbyd, -1, LFSR_TAG_UATTR(2), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
lfsr_rbyd_lookup(&lfs, &rbyd, -1, LFSR_TAG_UATTR(3),
&data) => LFS_ERR_NOENT;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
lfsr_rbyd_lookup(&lfs, &rbyd, -1, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
lfsr_rbyd_lookup(&lfs, &rbyd, -1, LFSR_TAG_UATTR(2), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
lfsr_rbyd_lookup(&lfs, &rbyd, -1, LFSR_TAG_UATTR(3),
&data) => LFS_ERR_NOENT;
'''
[cases.test_rbyd_get]
in = 'lfs.c'
code = '''
lfs_t lfs;
lfs_init(&lfs, CFG) => 0;
lfsr_rbyd_t init_rbyd = {
.blocks[0] = 0,
.eoff = 0,
.cksum = 0,
.trunk = 0,
.weight = 0,
};
lfsr_rbyd_t rbyd;
lfsr_data_t data;
uint8_t buffer[4];
// commit with one attribute
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
lfsr_rbyd_lookup(&lfs, &rbyd, -1, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, -1, LFSR_TAG_UATTR(2),
&data) => LFS_ERR_NOENT;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
lfsr_rbyd_lookup(&lfs, &rbyd, -1, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, -1, LFSR_TAG_UATTR(2),
&data) => LFS_ERR_NOENT;
// commit with two attributes
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(2), 0,
LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)))) => 0;
lfsr_rbyd_lookup(&lfs, &rbyd, -1, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
lfsr_rbyd_lookup(&lfs, &rbyd, -1, LFSR_TAG_UATTR(2), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
lfsr_rbyd_lookup(&lfs, &rbyd, -1, LFSR_TAG_UATTR(3),
&data) => LFS_ERR_NOENT;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
lfsr_rbyd_lookup(&lfs, &rbyd, -1, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
lfsr_rbyd_lookup(&lfs, &rbyd, -1, LFSR_TAG_UATTR(2), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
lfsr_rbyd_lookup(&lfs, &rbyd, -1, LFSR_TAG_UATTR(3),
&data) => LFS_ERR_NOENT;
// commit with two attributes, in the other direction
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(2), 0,
LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
lfsr_rbyd_lookup(&lfs, &rbyd, -1, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
lfsr_rbyd_lookup(&lfs, &rbyd, -1, LFSR_TAG_UATTR(2), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
lfsr_rbyd_lookup(&lfs, &rbyd, -1, LFSR_TAG_UATTR(3),
&data) => LFS_ERR_NOENT;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
lfsr_rbyd_lookup(&lfs, &rbyd, -1, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
lfsr_rbyd_lookup(&lfs, &rbyd, -1, LFSR_TAG_UATTR(2), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
lfsr_rbyd_lookup(&lfs, &rbyd, -1, LFSR_TAG_UATTR(3),
&data) => 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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(2), 0,
LFSR_DATA_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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(2), 0,
LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(2), 0,
LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(2), 0,
LFSR_DATA_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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(2), 0,
LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(2), 0,
LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(3), 0,
LFSR_DATA_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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(2), 0,
LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(3), 0,
LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(2), 0,
LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(3), 0,
LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(3), 0,
LFSR_DATA_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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(2), 0,
LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(3), 0,
LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(2), 0,
LFSR_DATA_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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(2), 0,
LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(3), 0,
LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(3), 0,
LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(2), 0,
LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(2), 0,
LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(3), 0,
LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(4), 0,
LFSR_DATA_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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(3), 0,
LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(4), 0,
LFSR_DATA_BUF("\xdd\xdd\xdd\xdd", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(2), 0,
LFSR_DATA_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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(2), 0,
LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(3), 0,
LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(4), 0,
LFSR_DATA_BUF("\xdd\xdd\xdd\xdd", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(4), 0,
LFSR_DATA_BUF("\xdd\xdd\xdd\xdd", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(2), 0,
LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(3), 0,
LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(2), 0,
LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(3), 0,
LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(4), 0,
LFSR_DATA_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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(2), 0,
LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(4), 0,
LFSR_DATA_BUF("\xdd\xdd\xdd\xdd", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(3), 0,
LFSR_DATA_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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(4), 0,
LFSR_DATA_BUF("\xdd\xdd\xdd\xdd", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(2), 0,
LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(3), 0,
LFSR_DATA_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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(4), 0,
LFSR_DATA_BUF("\xdd\xdd\xdd\xdd", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(2), 0,
LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(3), 0,
LFSR_DATA_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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(2), 0,
LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(3), 0,
LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(4), 0,
LFSR_DATA_BUF("\xdd\xdd\xdd\xdd", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(4), 0,
LFSR_DATA_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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(2), 0,
LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(3), 0,
LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(4), 0,
LFSR_DATA_BUF("\xdd\xdd\xdd\xdd", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(3), 0,
LFSR_DATA_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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(2), 0,
LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(3), 0,
LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(4), 0,
LFSR_DATA_BUF("\xdd\xdd\xdd\xdd", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(2), 0,
LFSR_DATA_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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(2), 0,
LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(3), 0,
LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(4), 0,
LFSR_DATA_BUF("\xdd\xdd\xdd\xdd", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(2), 0,
LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(3), 0,
LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(4), 0,
LFSR_DATA_BUF("\xdd\xdd\xdd\xdd", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(5), 0,
LFSR_DATA_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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(2), 0,
LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(4), 0,
LFSR_DATA_BUF("\xdd\xdd\xdd\xdd", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(5), 0,
LFSR_DATA_BUF("\xee\xee\xee\xee", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(3), 0,
LFSR_DATA_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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(3), 0,
LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(4), 0,
LFSR_DATA_BUF("\xdd\xdd\xdd\xdd", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(5), 0,
LFSR_DATA_BUF("\xee\xee\xee\xee", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(2), 0,
LFSR_DATA_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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(2), 0,
LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(3), 0,
LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(4), 0,
LFSR_DATA_BUF("\xdd\xdd\xdd\xdd", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(5), 0,
LFSR_DATA_BUF("\xee\xee\xee\xee", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(2), 0,
LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(3), 0,
LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(4), 0,
LFSR_DATA_BUF("\xdd\xdd\xdd\xdd", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(5), 0,
LFSR_DATA_BUF("\xee\xee\xee\xee", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(5), 0,
LFSR_DATA_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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(2), 0,
LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(3), 0,
LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(4), 0,
LFSR_DATA_BUF("\xdd\xdd\xdd\xdd", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(5), 0,
LFSR_DATA_BUF("\xee\xee\xee\xee", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(2), 0,
LFSR_DATA_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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(2), 0,
LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(3), 0,
LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(4), 0,
LFSR_DATA_BUF("\xdd\xdd\xdd\xdd", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(5), 0,
LFSR_DATA_BUF("\xee\xee\xee\xee", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(2), 0,
LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(3), 0,
LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(4), 0,
LFSR_DATA_BUF("\xdd\xdd\xdd\xdd", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(5), 0,
LFSR_DATA_BUF("\xee\xee\xee\xee", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(6), 0,
LFSR_DATA_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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(3), 0,
LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(4), 0,
LFSR_DATA_BUF("\xdd\xdd\xdd\xdd", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(5), 0,
LFSR_DATA_BUF("\xee\xee\xee\xee", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(6), 0,
LFSR_DATA_BUF("\xff\xff\xff\xff", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(2), 0,
LFSR_DATA_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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(2), 0,
LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(3), 0,
LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(4), 0,
LFSR_DATA_BUF("\xdd\xdd\xdd\xdd", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(5), 0,
LFSR_DATA_BUF("\xee\xee\xee\xee", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(6), 0,
LFSR_DATA_BUF("\xff\xff\xff\xff", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_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)'
# PERMUTATION=-1 => exhaust all permutations
# PERMUTATION=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(
LFSR_TAG_UATTR(perm[j]+1), 0,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4));
}
// test the given permutation
rbyd = init_rbyd;
lfsr_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)'
# PERMUTATION=-1 => exhaust all permutations
# PERMUTATION=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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
for (unsigned j = 0; j < N; j++) {
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(perm[j]+1), 0,
LFSR_DATA_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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(2), 0,
LFSR_DATA_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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(2), 0,
LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(2), 0,
LFSR_DATA_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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(2), 0,
LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_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)'
# PERMUTATION=-1 => exhaust all permutations
# PERMUTATION=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(
LFSR_TAG_UATTR(perm[j]+1), 0,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4));
}
// test the given permutation
rbyd = init_rbyd;
lfsr_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)'
# PERMUTATION=-1 => exhaust all permutations
# PERMUTATION=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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
for (unsigned j = 0; j < N; j++) {
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(perm[j]+1), 0,
LFSR_DATA_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)'
# PERMUTATION=-1 => exhaust all permutations
# PERMUTATION=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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
for (unsigned j = 0; j < N; j++) {
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(j+1), 0,
LFSR_DATA_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);
lfsr_bd_read(&lfs, rbyd.blocks[0], 0, rbyd.eoff,
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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_bd_prog(&lfs, rbyd.blocks[0], 0, backup_block, rbyd.eoff,
NULL) => 0;
lfsr_bd_flush(&lfs,
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(
LFSR_TAG_UATTR(perm[j]+1), 0,
LFSR_DATA_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;
lfsr_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(
LFSR_TAG_UATTR(x & 0x7f), 0,
LFSR_DATA_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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_RM | LFSR_TAG_UATTR(1), 0,
LFSR_DATA_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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(2), 0,
LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_RM | LFSR_TAG_UATTR(1), 0,
LFSR_DATA_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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(2), 0,
LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_RM | LFSR_TAG_UATTR(2), 0,
LFSR_DATA_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)'
# PERMUTATION=-1 => exhaust all permutations
# PERMUTATION=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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
for (unsigned j = 0; j < N; j++) {
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(perm[j]+1), 0,
LFSR_DATA_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);
lfsr_bd_read(&lfs, rbyd.blocks[0], 0, rbyd.eoff,
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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_bd_prog(&lfs, rbyd.blocks[0], 0, backup_block, rbyd.eoff,
NULL) => 0;
lfsr_bd_flush(&lfs,
NULL) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_RM | LFSR_TAG_UATTR(j+1), 0,
LFSR_DATA_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(
LFSR_TAG_UATTR(j+1), 0,
LFSR_DATA_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)'
# PERMUTATION=-1 => exhaust all permutations
# PERMUTATION=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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
for (unsigned j = 0; j < N; j++) {
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(perm[j]+1), 0,
LFSR_DATA_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);
lfsr_bd_read(&lfs, rbyd.blocks[0], 0, rbyd.eoff,
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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_bd_prog(&lfs, rbyd.blocks[0], 0, backup_block, rbyd.eoff,
NULL) => 0;
lfsr_bd_flush(&lfs,
NULL) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_RM | LFSR_TAG_UATTR(j+1), 0,
LFSR_DATA_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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(2), 0,
LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(4), 0,
LFSR_DATA_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(
LFSR_TAG_RM | LFSR_TAG_UATTR(1), 0,
LFSR_DATA_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(
LFSR_TAG_RM | LFSR_TAG_UATTR(3), 0,
LFSR_DATA_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(
LFSR_TAG_RM | LFSR_TAG_UATTR(5), 0,
LFSR_DATA_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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(2), 0,
LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(3), 0,
LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(4), 0,
LFSR_DATA_BUF("\xdd\xdd\xdd\xdd", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(5), 0,
LFSR_DATA_BUF("\xee\xee\xee\xee", 4)))) => 0;
// remove several attributes
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_RM | LFSR_TAG_UATTR(1), 0,
LFSR_DATA_NULL()),
LFSR_ATTR(
LFSR_TAG_RM | LFSR_TAG_UATTR(3), 0,
LFSR_DATA_NULL()),
LFSR_ATTR(
LFSR_TAG_RM | LFSR_TAG_UATTR(5), 0,
LFSR_DATA_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(
LFSR_TAG_RM | LFSR_TAG_UATTR(1), 0,
LFSR_DATA_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(
LFSR_TAG_RM | LFSR_TAG_UATTR(3), 0,
LFSR_DATA_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(
LFSR_TAG_RM | LFSR_TAG_UATTR(5), 0,
LFSR_DATA_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(
LFSR_TAG_RM | LFSR_TAG_UATTR(1), 0,
LFSR_DATA_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(
LFSR_TAG_RM | LFSR_TAG_UATTR(3), 0,
LFSR_DATA_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(
LFSR_TAG_RM | LFSR_TAG_UATTR(5), 0,
LFSR_DATA_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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_RM | LFSR_TAG_UATTR(1), 0,
LFSR_DATA_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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(2), 0,
LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_RM | LFSR_TAG_UATTR(1), 0,
LFSR_DATA_NULL()),
LFSR_ATTR(
LFSR_TAG_RM | LFSR_TAG_UATTR(2), 0,
LFSR_DATA_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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(2), 0,
LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_RM | LFSR_TAG_UATTR(2), 0,
LFSR_DATA_NULL()),
LFSR_ATTR(
LFSR_TAG_RM | LFSR_TAG_UATTR(1), 0,
LFSR_DATA_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)'
# PERMUTATION=-1 => exhaust all permutations
# PERMUTATION=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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
for (unsigned j = 0; j < N; j++) {
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(j+1), 0,
LFSR_DATA_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);
lfsr_bd_read(&lfs, rbyd.blocks[0], 0, rbyd.eoff,
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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_bd_prog(&lfs, rbyd.blocks[0], 0, backup_block, rbyd.eoff,
NULL) => 0;
lfsr_bd_flush(&lfs,
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(
LFSR_TAG_RM | LFSR_TAG_UATTR(perm[j]+1), 0,
LFSR_DATA_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(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_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;
lfsr_data_t data;
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, 'a'+(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;
lfsr_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] = 'a'+(i % 26);
// update our rbyd
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(attr), 0,
LFSR_DATA_BUF(&(uint8_t){'a'+(i % 26)}, 1)))) => 0;
} else {
// update our sim
sim[attr] = '\0';
// update our rbyd
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_RM | LFSR_TAG_UATTR(attr), 0,
LFSR_DATA_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++) {
int err = lfsr_rbyd_lookup(&lfs, &rbyd, -1, LFSR_TAG_UATTR(attr),
&data);
if (!err) {
lfs_ssize_t size = lfsr_data_read(&lfs, &data, buffer, 4);
if (!first) {
printf(", ");
}
first = false;
printf("0x%02x=%.*s", attr, size, buffer);
}
}
printf("]\n");
for (unsigned attr = 0; attr < N; attr++) {
int err = lfsr_rbyd_lookup(&lfs, &rbyd, -1, LFSR_TAG_UATTR(attr),
&data);
if (sim[attr]) {
assert(!err);
lfs_ssize_t size = lfsr_data_read(&lfs, &data, buffer, 4);
assert(size == 1);
assert(memcmp(&sim[attr], buffer, 1) == 0);
} else {
assert(err == 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;
lfsr_data_t data;
uint8_t buffer[4];
// try to create one rid
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
assert(rbyd.weight == 1);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, 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_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
// try to create two ids
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)),
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)))) => 0;
assert(rbyd.weight == 2);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, 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_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
// create a third to the right
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)),
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)),
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)))) => 0;
assert(rbyd.weight == 3);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, 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_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, 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;
lfsr_data_t data;
uint8_t buffer[4];
// try to create one rid
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
assert(rbyd.weight == 1);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, 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_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
// try to create two ids
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)))) => 0;
assert(rbyd.weight == 2);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, 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_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
// try to create two in the other direction
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
assert(rbyd.weight == 2);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, 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_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
// create a third to the right
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 2, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)))) => 0;
assert(rbyd.weight == 3);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, 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_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
// create a third to the left
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
assert(rbyd.weight == 3);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, 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_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
// create a third in the middle
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)))) => 0;
assert(rbyd.weight == 3);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, 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_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
'''
[cases.test_rbyd_create_permutations]
defines.N = 'range(1, 8)'
# PERMUTATION=-1 => exhaust all permutations
# PERMUTATION=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_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");
// test the given permutation with multiple commits
rbyd = init_rbyd;
lfsr_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(
LFSR_TAG_REG, +1,
LFSR_DATA_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_lookup(&lfs, &rbyd,
j, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, 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_;
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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 00000000, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)),
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_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_lookup(&lfs, &rbyd, rid_, tag_, &data) => 0;
lfsr_data_read(&lfs, &data, 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_lookup(&lfs, &rbyd, rid_, tag_, &data) => 0;
lfsr_data_read(&lfs, &data, 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_lookup(&lfs, &rbyd, rid_, tag_, &data) => 0;
lfsr_data_read(&lfs, &data, 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_lookup(&lfs, &rbyd, rid_, tag_, &data) => 0;
lfsr_data_read(&lfs, &data, 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_;
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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_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_lookup(&lfs, &rbyd, rid_, tag_, &data) => 0;
lfsr_data_read(&lfs, &data, 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_lookup(&lfs, &rbyd, rid_, tag_, &data) => 0;
lfsr_data_read(&lfs, &data, 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_lookup(&lfs, &rbyd, rid_, tag_, &data) => 0;
lfsr_data_read(&lfs, &data, 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_lookup(&lfs, &rbyd, rid_, tag_, &data) => 0;
lfsr_data_read(&lfs, &data, 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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_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_lookup(&lfs, &rbyd, rid_, tag_, &data) => 0;
lfsr_data_read(&lfs, &data, 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_lookup(&lfs, &rbyd, rid_, tag_, &data) => 0;
lfsr_data_read(&lfs, &data, 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_lookup(&lfs, &rbyd, rid_, tag_, &data) => 0;
lfsr_data_read(&lfs, &data, 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_lookup(&lfs, &rbyd, rid_, tag_, &data) => 0;
lfsr_data_read(&lfs, &data, 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)'
# PERMUTATION=-1 => exhaust all permutations
# PERMUTATION=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_;
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;
lfsr_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(
LFSR_TAG_REG, +1,
LFSR_DATA_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_lookup(&lfs, &rbyd, rid_, tag_, &data) => 0;
lfsr_data_read(&lfs, &data, 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;
lfsr_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(LFSR_TAG_REG, +1, LFSR_DATA_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;
lfsr_data_t data;
uint8_t buffer[4];
// try to create one rid
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xaa\xaa", 2)))) => 0;
assert(rbyd.weight == 1);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, 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_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
// try to create two ids
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xaa\xaa", 2)),
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xbb\xbb", 2)))) => 0;
assert(rbyd.weight == 2);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, 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_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
// create a third to the right
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xaa\xaa", 2)),
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xbb\xbb", 2)),
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xcc\xcc", 2)))) => 0;
assert(rbyd.weight == 3);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, 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_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
assert(rbyd.weight == 3);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, 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_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, 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;
lfsr_data_t data;
uint8_t buffer[4];
// try to create one rid
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xaa\xaa", 2)))) => 0;
assert(rbyd.weight == 1);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, 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_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
// try to create two ids
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xaa\xaa", 2)))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xbb\xbb", 2)))) => 0;
assert(rbyd.weight == 2);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, 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_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
// try to create two in the other direction
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xbb\xbb", 2)))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xaa\xaa", 2)))) => 0;
assert(rbyd.weight == 2);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, 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_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
// create a third to the right
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xaa\xaa", 2)))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xbb\xbb", 2)))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 2, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 2, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xcc\xcc", 2)))) => 0;
assert(rbyd.weight == 3);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, 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_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
assert(rbyd.weight == 3);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, 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_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xcc\xcc", 2) == 0);
// create a third to the left
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xbb\xbb", 2)))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xcc\xcc", 2)))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xaa\xaa", 2)))) => 0;
assert(rbyd.weight == 3);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, 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_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xcc\xcc", 2) == 0);
// create a third in the middle
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xaa\xaa", 2)))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xcc\xcc", 2)))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xbb\xbb", 2)))) => 0;
assert(rbyd.weight == 3);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, 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_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, 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)'
# PERMUTATION=-1 => exhaust all permutations
# PERMUTATION=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_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");
// test the given permutation
rbyd = init_rbyd;
lfsr_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(
LFSR_TAG_REG, +1,
LFSR_DATA_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(
LFSR_TAG_UATTR(u+1), 0,
LFSR_DATA_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_lookup(&lfs, &rbyd, j, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, names[j % 6], 4) == 0);
for (unsigned u = 0; u < M; u++) {
lfsr_rbyd_lookup(&lfs, &rbyd, j, LFSR_TAG_UATTR(u+1),
&data) => 0;
lfsr_data_read(&lfs, &data, 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_;
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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xaa\xaa", 2)),
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_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_lookup(&lfs, &rbyd, rid_, tag_, &data) => 0;
lfsr_data_read(&lfs, &data, 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_lookup(&lfs, &rbyd, rid_, tag_, &data) => 0;
lfsr_data_read(&lfs, &data, 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_lookup(&lfs, &rbyd, rid_, tag_, &data) => 0;
lfsr_data_read(&lfs, &data, 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_lookup(&lfs, &rbyd, rid_, tag_, &data) => 0;
lfsr_data_read(&lfs, &data, 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_lookup(&lfs, &rbyd, rid_, tag_, &data) => 0;
lfsr_data_read(&lfs, &data, 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_lookup(&lfs, &rbyd, rid_, tag_, &data) => 0;
lfsr_data_read(&lfs, &data, 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_lookup(&lfs, &rbyd, rid_, tag_, &data) => 0;
lfsr_data_read(&lfs, &data, 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_lookup(&lfs, &rbyd, rid_, tag_, &data) => 0;
lfsr_data_read(&lfs, &data, 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_;
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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xaa\xaa", 2)))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_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_lookup(&lfs, &rbyd, rid_, tag_, &data) => 0;
lfsr_data_read(&lfs, &data, 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_lookup(&lfs, &rbyd, rid_, tag_, &data) => 0;
lfsr_data_read(&lfs, &data, 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_lookup(&lfs, &rbyd, rid_, tag_, &data) => 0;
lfsr_data_read(&lfs, &data, 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_lookup(&lfs, &rbyd, rid_, tag_, &data) => 0;
lfsr_data_read(&lfs, &data, 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_lookup(&lfs, &rbyd, rid_, tag_, &data) => 0;
lfsr_data_read(&lfs, &data, 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_lookup(&lfs, &rbyd, rid_, tag_, &data) => 0;
lfsr_data_read(&lfs, &data, 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_lookup(&lfs, &rbyd, rid_, tag_, &data) => 0;
lfsr_data_read(&lfs, &data, 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_lookup(&lfs, &rbyd, rid_, tag_, &data) => 0;
lfsr_data_read(&lfs, &data, 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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xbb\xbb", 2)))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_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_lookup(&lfs, &rbyd, rid_, tag_, &data) => 0;
lfsr_data_read(&lfs, &data, 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_lookup(&lfs, &rbyd, rid_, tag_, &data) => 0;
lfsr_data_read(&lfs, &data, 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_lookup(&lfs, &rbyd, rid_, tag_, &data) => 0;
lfsr_data_read(&lfs, &data, 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_lookup(&lfs, &rbyd, rid_, tag_, &data) => 0;
lfsr_data_read(&lfs, &data, 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_lookup(&lfs, &rbyd, rid_, tag_, &data) => 0;
lfsr_data_read(&lfs, &data, 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_lookup(&lfs, &rbyd, rid_, tag_, &data) => 0;
lfsr_data_read(&lfs, &data, 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_lookup(&lfs, &rbyd, rid_, tag_, &data) => 0;
lfsr_data_read(&lfs, &data, 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_lookup(&lfs, &rbyd, rid_, tag_, &data) => 0;
lfsr_data_read(&lfs, &data, 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)'
# PERMUTATION=-1 => exhaust all permutations
# PERMUTATION=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_;
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;
lfsr_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(
LFSR_TAG_REG, +1,
LFSR_DATA_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(
LFSR_TAG_UATTR(u+1), 0,
LFSR_DATA_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_lookup(&lfs, &rbyd, rid_, tag_, &data) => 0;
lfsr_data_read(&lfs, &data, 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_lookup(&lfs, &rbyd, rid_, tag_, &data) => 0;
lfsr_data_read(&lfs, &data, 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)'
# PERMUTATION=-1 => exhaust all permutations
# PERMUTATION=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_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;
// create one consistent block
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
for (unsigned j = 0; j < N; j++) {
lfsr_rbyd_commit(&lfs, &rbyd, j, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_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(
LFSR_TAG_UATTR(u+1), 0,
LFSR_DATA_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);
lfsr_bd_read(&lfs, rbyd.blocks[0], 0, rbyd.eoff,
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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_bd_prog(&lfs, rbyd.blocks[0], 0, backup_block, rbyd.eoff,
NULL) => 0;
lfsr_bd_flush(&lfs,
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(
LFSR_TAG_UATTR(perm[j]%M+1), 0,
LFSR_DATA_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_lookup(&lfs, &rbyd, j, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, names[j % 6], 4) == 0);
for (unsigned u = 0; u < M; u++) {
lfsr_rbyd_lookup(&lfs, &rbyd, j, LFSR_TAG_UATTR(u+1),
&data) => 0;
lfsr_data_read(&lfs, &data, 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)'
# PERMUTATION=-1 => exhaust all permutations
# PERMUTATION=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_;
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;
lfsr_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(
LFSR_TAG_REG, +1,
LFSR_DATA_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(
LFSR_TAG_UATTR(u+1), 0,
LFSR_DATA_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);
lfsr_bd_read(&lfs, rbyd.blocks[0], 0, rbyd.eoff,
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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_bd_prog(&lfs, rbyd.blocks[0], 0, backup_block, rbyd.eoff,
NULL) => 0;
lfsr_bd_flush(&lfs,
NULL) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, j/M, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_RM | LFSR_TAG_UATTR((j%M)+1), 0,
LFSR_DATA_NULL()))) => 0;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], CFG->block_size) => 0;
for (unsigned k = 0; k < N; k++) {
lfsr_rbyd_lookup(&lfs, &rbyd, k, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, 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_lookup(&lfs, &rbyd, rid_, tag_, &data) => 0;
lfsr_data_read(&lfs, &data, 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(
LFSR_TAG_UATTR((j%M)+1), 0,
LFSR_DATA_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_lookup(&lfs, &rbyd, k, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, 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_lookup(&lfs, &rbyd, rid_, tag_, &data) => 0;
lfsr_data_read(&lfs, &data, 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_lookup(&lfs, &rbyd, rid_, tag_, &data) => 0;
lfsr_data_read(&lfs, &data, 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)'
# PERMUTATION=-1 => exhaust all permutations
# PERMUTATION=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_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;
// create one consistent block
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
for (unsigned j = 0; j < N; j++) {
lfsr_rbyd_commit(&lfs, &rbyd, j, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_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(
LFSR_TAG_UATTR(u+1), 0,
LFSR_DATA_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);
lfsr_bd_read(&lfs, rbyd.blocks[0], 0, rbyd.eoff,
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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_bd_prog(&lfs, rbyd.blocks[0], 0, backup_block, rbyd.eoff,
NULL) => 0;
lfsr_bd_flush(&lfs,
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(
LFSR_TAG_RM | LFSR_TAG_UATTR(perm[j]%M+1), 0,
LFSR_DATA_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_lookup(&lfs, &rbyd, j, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, names[j % 6], 4) == 0);
for (unsigned u = 0; u < M; u++) {
lfsr_rbyd_lookup(&lfs, &rbyd, j, LFSR_TAG_UATTR(u+1),
&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*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;
lfsr_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(LFSR_TAG_REG, +1, LFSR_DATA_BUF(names[x % 6], 4));
for (unsigned u = 0; u < M; u++) {
attrs[1+u] = LFSR_ATTR(
LFSR_TAG_UATTR(u+1), 0,
LFSR_DATA_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)'
# PERMUTATION=-1 => exhaust all permutations
# PERMUTATION=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_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");
// test the given permutation with multiple commits
rbyd = init_rbyd;
lfsr_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(
LFSR_TAG_UATTR(perm[j]+1), 0,
LFSR_DATA_BUF(names[perm[j] % 6], 1)))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, rid, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_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_lookup(&lfs, &rbyd,
-1, LFSR_TAG_UATTR(j+1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 1;
assert(memcmp(buffer, names[j % 6], 1) == 0);
}
for (unsigned j = 0; j < N; j++) {
lfsr_rbyd_lookup(&lfs, &rbyd,
j, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, 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_lookup(&lfs, &rbyd, rid_, tag_, &data) => 0;
lfsr_data_read(&lfs, &data, 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_lookup(&lfs, &rbyd, rid_, tag_, &data) => 0;
lfsr_data_read(&lfs, &data, 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)'
# PERMUTATION=-1 => exhaust all permutations
# PERMUTATION=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_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");
// test the given permutation
rbyd = init_rbyd;
lfsr_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(
LFSR_TAG_UATTR(perm[j]+1), 0,
LFSR_DATA_BUF(names[perm[j] % 6], 1)))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, rid, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF(names[perm[j] % 6], 4)))) => 0;
for (unsigned u = 0; u < M; u++) {
lfsr_rbyd_commit(&lfs, &rbyd, rid, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(u+1), 0,
LFSR_DATA_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_lookup(&lfs, &rbyd,
-1, LFSR_TAG_UATTR(j+1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 1;
assert(memcmp(buffer, names[j % 6], 1) == 0);
}
for (unsigned j = 0; j < N; j++) {
lfsr_rbyd_lookup(&lfs, &rbyd, j, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, names[j % 6], 4) == 0);
for (unsigned u = 0; u < M; u++) {
lfsr_rbyd_lookup(&lfs, &rbyd, j, LFSR_TAG_UATTR(u+1),
&data) => 0;
lfsr_data_read(&lfs, &data, 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_lookup(&lfs, &rbyd, rid_, tag_, &data) => 0;
lfsr_data_read(&lfs, &data, 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_lookup(&lfs, &rbyd, rid_, tag_, &data) => 0;
lfsr_data_read(&lfs, &data, 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_lookup(&lfs, &rbyd, rid_, tag_, &data) => 0;
lfsr_data_read(&lfs, &data, 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;
lfsr_data_t data;
uint8_t buffer[4];
// try to delete one rid
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)),
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_ATTRS(
LFSR_ATTR(LFSR_TAG_RM, -1, LFSR_DATA_NULL()))) => 0;
assert(rbyd.weight == 1);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_REG,
&data) => LFS_ERR_NOENT;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
assert(rbyd.weight == 1);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_REG,
&data) => LFS_ERR_NOENT;
// try to delete the other rid
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)),
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
LFSR_ATTR(LFSR_TAG_RM, -1, LFSR_DATA_NULL()))) => 0;
assert(rbyd.weight == 1);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_REG,
&data) => LFS_ERR_NOENT;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
assert(rbyd.weight == 1);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_REG,
&data) => LFS_ERR_NOENT;
// try to delete the largest of three
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)),
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)),
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 2, LFSR_ATTRS(
LFSR_ATTR(LFSR_TAG_RM, -1, LFSR_DATA_NULL()))) => 0;
assert(rbyd.weight == 2);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_REG,
&data) => LFS_ERR_NOENT;
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_REG,
&data) => LFS_ERR_NOENT;
// try to delete the smallest of three
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)),
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)),
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
LFSR_ATTR(LFSR_TAG_RM, -1, LFSR_DATA_NULL()))) => 0;
assert(rbyd.weight == 2);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_REG,
&data) => LFS_ERR_NOENT;
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_REG,
&data) => LFS_ERR_NOENT;
// try to delete the middle
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)),
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)),
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_ATTRS(
LFSR_ATTR(LFSR_TAG_RM, -1, LFSR_DATA_NULL()))) => 0;
assert(rbyd.weight == 2);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_REG,
&data) => LFS_ERR_NOENT;
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_REG,
&data) => 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;
lfsr_data_t data;
uint8_t buffer[4];
// try to delete one rid
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xaa\xaa", 2)),
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xbb\xbb", 2)))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_ATTRS(
LFSR_ATTR(LFSR_TAG_RM, -1, LFSR_DATA_NULL()))) => 0;
assert(rbyd.weight == 1);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_REG,
&data) => LFS_ERR_NOENT;
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(1),
&data) => LFS_ERR_NOENT;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
assert(rbyd.weight == 1);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_REG,
&data) => LFS_ERR_NOENT;
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(1),
&data) => LFS_ERR_NOENT;
// try to delete the other rid
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xaa\xaa", 2)),
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xbb\xbb", 2)))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
LFSR_ATTR(LFSR_TAG_RM, -1, LFSR_DATA_NULL()))) => 0;
assert(rbyd.weight == 1);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_REG,
&data) => LFS_ERR_NOENT;
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(1),
&data) => LFS_ERR_NOENT;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
assert(rbyd.weight == 1);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_REG,
&data) => LFS_ERR_NOENT;
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(1),
&data) => LFS_ERR_NOENT;
// try to delete the largest of three
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xaa\xaa", 2)),
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xbb\xbb", 2)),
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xcc\xcc", 2)))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 2, LFSR_ATTRS(
LFSR_ATTR(LFSR_TAG_RM, -1, LFSR_DATA_NULL()))) => 0;
assert(rbyd.weight == 2);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_REG,
&data) => LFS_ERR_NOENT;
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(1),
&data) => LFS_ERR_NOENT;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
assert(rbyd.weight == 2);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_REG,
&data) => LFS_ERR_NOENT;
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(1),
&data) => LFS_ERR_NOENT;
// try to delete the smallest of three
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xaa\xaa", 2)),
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xbb\xbb", 2)),
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xcc\xcc", 2)))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
LFSR_ATTR(LFSR_TAG_RM, -1, LFSR_DATA_NULL()))) => 0;
assert(rbyd.weight == 2);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xcc\xcc", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_REG,
&data) => LFS_ERR_NOENT;
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(1),
&data) => LFS_ERR_NOENT;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
assert(rbyd.weight == 2);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xcc\xcc", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_REG,
&data) => LFS_ERR_NOENT;
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(1),
&data) => LFS_ERR_NOENT;
// try to delete the middle
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xaa\xaa", 2)),
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xbb\xbb", 2)),
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xcc\xcc", 2)))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_ATTRS(
LFSR_ATTR(LFSR_TAG_RM, -1, LFSR_DATA_NULL()))) => 0;
assert(rbyd.weight == 2);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xcc\xcc", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_REG,
&data) => LFS_ERR_NOENT;
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(1),
&data) => LFS_ERR_NOENT;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
assert(rbyd.weight == 2);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xcc\xcc", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_REG,
&data) => LFS_ERR_NOENT;
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(1),
&data) => LFS_ERR_NOENT;
'''
# some additional delete range special cases
[cases.test_rbyd_delete_range_b]
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_data_t data;
uint8_t buffer[4];
// delete inner branches
//
// .-------o-------.
// .---o---. .---o---.
// .-o-. .-o-. .-o-. .-o-.
// .o. .o. .o. .o. .o. .o. .o. .o.
// a a a a a a a c c e e e e e e e
// '-+-'
// remove
//
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xaa\xaa", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(2), 0,
LFSR_DATA_BUF("\xaa\xaa", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(3), 0,
LFSR_DATA_BUF("\xaa\xaa", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(4), 0,
LFSR_DATA_BUF("\xaa\xaa", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(5), 0,
LFSR_DATA_BUF("\xaa\xaa", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(6), 0,
LFSR_DATA_BUF("\xaa\xaa", 2)),
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xcc\xcc", 2)),
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xee\xee\xee\xee", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xee\xee", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(2), 0,
LFSR_DATA_BUF("\xee\xee", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(3), 0,
LFSR_DATA_BUF("\xee\xee", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(4), 0,
LFSR_DATA_BUF("\xee\xee", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(5), 0,
LFSR_DATA_BUF("\xee\xee", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(6), 0,
LFSR_DATA_BUF("\xee\xee", 2)),
// propagate yellow to the root
LFSR_ATTR(
LFSR_TAG_UATTR(6), 0,
LFSR_DATA_BUF("\xee\xee", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(6), 0,
LFSR_DATA_BUF("\xee\xee", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(6), 0,
LFSR_DATA_BUF("\xee\xee", 2)))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_ATTRS(
LFSR_ATTR(LFSR_TAG_RM, -1, LFSR_DATA_NULL()))) => 0;
assert(rbyd.weight == 2);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(2), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(3), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(3), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(3), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(3), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xee\xee\xee\xee", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(2), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(3), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(4), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(5), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(6), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_REG,
&data) => LFS_ERR_NOENT;
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(1),
&data) => LFS_ERR_NOENT;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
assert(rbyd.weight == 2);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(2), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(3), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(3), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(3), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(3), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xee\xee\xee\xee", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(2), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(3), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(4), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(5), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(6), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_REG,
&data) => LFS_ERR_NOENT;
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(1),
&data) => LFS_ERR_NOENT;
// try to recreate
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)))) => 0;
assert(rbyd.weight == 3);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(2), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(3), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(3), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(3), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(3), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xee\xee\xee\xee", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(2), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(3), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(4), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(5), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(6), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 3, LFSR_TAG_REG,
&data) => LFS_ERR_NOENT;
lfsr_rbyd_lookup(&lfs, &rbyd, 3, LFSR_TAG_UATTR(1),
&data) => LFS_ERR_NOENT;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
assert(rbyd.weight == 3);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(2), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(3), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(3), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(3), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(3), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xee\xee\xee\xee", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(2), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(3), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(4), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(5), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(6), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 3, LFSR_TAG_REG,
&data) => LFS_ERR_NOENT;
lfsr_rbyd_lookup(&lfs, &rbyd, 3, LFSR_TAG_UATTR(1),
&data) => LFS_ERR_NOENT;
'''
[cases.test_rbyd_delete_range_r]
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_data_t data;
uint8_t buffer[4];
// delete inner branches
//
// .-------o-------.
// .---r----. .----r---.
// .o. .o. .-r-. .-r-. .o. .o.
// a a a a a a c c e e e e e e
// '-+-'
// remove
//
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xaa\xaa", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(2), 0,
LFSR_DATA_BUF("\xaa\xaa", 2)),
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xcc\xcc", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(3), +1,
LFSR_DATA_BUF("\xee\xee", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(4), 0,
LFSR_DATA_BUF("\xee\xee", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(5), 0,
LFSR_DATA_BUF("\xee\xee", 2)),
// propagate yellow to the root
LFSR_ATTR(
LFSR_TAG_UATTR(5), 0,
LFSR_DATA_BUF("\xee\xee", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(5), 0,
LFSR_DATA_BUF("\xee\xee", 2)))) => 0;
// this gets a bit messy as we try to make the rbyd take the right shape
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(3), 0,
LFSR_DATA_BUF("\xaa\xaa", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(4), 0,
LFSR_DATA_BUF("\xaa\xaa", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(5), 0,
LFSR_DATA_BUF("\xaa\xaa", 2)))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 2, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(2), 0,
LFSR_DATA_BUF("\xee\xee", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xee\xee", 2)),
LFSR_ATTR(
LFSR_TAG_REG, 0,
LFSR_DATA_BUF("\xee\xee\xee\xee", 4)))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_ATTRS(
LFSR_ATTR(LFSR_TAG_RM, -1, LFSR_DATA_NULL()))) => 0;
assert(rbyd.weight == 2);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(2), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(3), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(4), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(5), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xee\xee\xee\xee", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(2), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(3), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(4), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(5), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_REG,
&data) => LFS_ERR_NOENT;
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(1),
&data) => LFS_ERR_NOENT;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
assert(rbyd.weight == 2);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(2), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(3), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(4), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(5), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xee\xee\xee\xee", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(2), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(3), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(4), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(5), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_REG,
&data) => LFS_ERR_NOENT;
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(1),
&data) => LFS_ERR_NOENT;
// try to recreate
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)))) => 0;
assert(rbyd.weight == 3);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(2), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(3), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(4), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(5), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xee\xee\xee\xee", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(2), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(3), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(4), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(5), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 3, LFSR_TAG_REG,
&data) => LFS_ERR_NOENT;
lfsr_rbyd_lookup(&lfs, &rbyd, 3, LFSR_TAG_UATTR(1),
&data) => LFS_ERR_NOENT;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
assert(rbyd.weight == 3);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(2), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(3), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(4), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(5), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xee\xee\xee\xee", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(2), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(3), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(4), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(5), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 3, LFSR_TAG_REG,
&data) => LFS_ERR_NOENT;
lfsr_rbyd_lookup(&lfs, &rbyd, 3, LFSR_TAG_UATTR(1),
&data) => LFS_ERR_NOENT;
'''
[cases.test_rbyd_delete_range_y]
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_data_t data;
uint8_t buffer[4];
// delete inner branches
//
// .-------------o-------------.
// .---y---+------. .------+---y---.
// .o. .o. .o. .-+-y-. .-y-+-. .o. .o. .o.
// a a a a a a a a a c c e e e e e e e e e
// '-+-'
// remove
//
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(3), 0,
LFSR_DATA_BUF("\xaa\xaa", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(4), 0,
LFSR_DATA_BUF("\xaa\xaa", 2)),
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xcc\xcc", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(4), +1,
LFSR_DATA_BUF("\xee\xee", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(5), 0,
LFSR_DATA_BUF("\xee\xee", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(6), 0,
LFSR_DATA_BUF("\xee\xee", 2)),
// propagate yellow to the root
LFSR_ATTR(
LFSR_TAG_UATTR(6), 0,
LFSR_DATA_BUF("\xee\xee", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(6), 0,
LFSR_DATA_BUF("\xee\xee", 2)))) => 0;
// this gets a bit messy as we try to make the rbyd take the right shape
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(5), 0,
LFSR_DATA_BUF("\xaa\xaa", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(6), 0,
LFSR_DATA_BUF("\xaa\xaa", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(7), 0,
LFSR_DATA_BUF("\xaa\xaa", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(8), 0,
LFSR_DATA_BUF("\xaa\xaa", 2)))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xaa\xaa", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(2), 0,
LFSR_DATA_BUF("\xaa\xaa", 2)),
// propagate yellow
LFSR_ATTR(
LFSR_TAG_UATTR(2), 0,
LFSR_DATA_BUF("\xaa\xaa", 2)))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 2, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(3), 0,
LFSR_DATA_BUF("\xee\xee", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(2), 0,
LFSR_DATA_BUF("\xee\xee", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xee\xee", 2)),
LFSR_ATTR(
LFSR_TAG_REG, 0,
LFSR_DATA_BUF("\xee\xee\xee\xee", 4)))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 2, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(8), 0,
LFSR_DATA_BUF("\xee\xee", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(7), 0,
LFSR_DATA_BUF("\xee\xee", 2)),
// propagate yellow
LFSR_ATTR(
LFSR_TAG_UATTR(7), 0,
LFSR_DATA_BUF("\xee\xee", 2)))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_ATTRS(
LFSR_ATTR(LFSR_TAG_RM, -1, LFSR_DATA_NULL()))) => 0;
assert(rbyd.weight == 2);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(2), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(3), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(4), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(5), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(6), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(7), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(8), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xee\xee\xee\xee", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(2), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(3), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(4), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(5), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(6), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(7), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(8), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_REG,
&data) => LFS_ERR_NOENT;
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(1),
&data) => LFS_ERR_NOENT;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
assert(rbyd.weight == 2);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(2), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(3), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(4), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(5), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(6), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(7), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(8), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xee\xee\xee\xee", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(2), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(3), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(4), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(5), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(6), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(7), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(8), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_REG,
&data) => LFS_ERR_NOENT;
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(1),
&data) => LFS_ERR_NOENT;
// try to recreate
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)))) => 0;
assert(rbyd.weight == 3);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(2), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(3), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(4), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(5), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(6), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(7), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(8), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xee\xee\xee\xee", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(2), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(3), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(4), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(5), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(6), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(7), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(8), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 3, LFSR_TAG_REG,
&data) => LFS_ERR_NOENT;
lfsr_rbyd_lookup(&lfs, &rbyd, 3, LFSR_TAG_UATTR(1),
&data) => LFS_ERR_NOENT;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
assert(rbyd.weight == 3);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(2), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(3), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(4), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(5), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(6), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(7), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(8), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xee\xee\xee\xee", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(2), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(3), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(4), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(5), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(6), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(7), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(8), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 3, LFSR_TAG_REG,
&data) => LFS_ERR_NOENT;
lfsr_rbyd_lookup(&lfs, &rbyd, 3, LFSR_TAG_UATTR(1),
&data) => LFS_ERR_NOENT;
'''
[cases.test_rbyd_delete_range_rydy]
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_data_t data;
uint8_t buffer[4];
// delete inner branches
//
// .-------------r-------------.
// .-o-. .----y---+---. .-o-.
// .o. .o. .-+-y-. .o. .o. .o. .o. .o.
// a a a a a a a c e e e e e e e e e e
// '+'
// remove
//
// this is a specific nasty case where tail-recursion can be
// violated if you preserve coloring during range removes
//
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xaa\xaa", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(2), 0,
LFSR_DATA_BUF("\xaa\xaa", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(3), 0,
LFSR_DATA_BUF("\xaa\xaa", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(4), 0,
LFSR_DATA_BUF("\xaa\xaa", 2)),
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(4), +1,
LFSR_DATA_BUF("\xee\xee", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(5), 0,
LFSR_DATA_BUF("\xee\xee", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(6), 0,
LFSR_DATA_BUF("\xee\xee", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(7), 0,
LFSR_DATA_BUF("\xee\xee", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(8), 0,
LFSR_DATA_BUF("\xee\xee", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(9), 0,
LFSR_DATA_BUF("\xee\xee", 2)),
// propagate yellow to the root
LFSR_ATTR(
LFSR_TAG_UATTR(9), 0,
LFSR_DATA_BUF("\xee\xee", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(9), 0,
LFSR_DATA_BUF("\xee\xee", 2)))) => 0;
// this gets a bit messy as we try to make the rbyd take the right shape
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(5), 0,
LFSR_DATA_BUF("\xaa\xaa", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(6), 0,
LFSR_DATA_BUF("\xaa\xaa", 2)))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 2, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(3), 0,
LFSR_DATA_BUF("\xee\xee", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(2), 0,
LFSR_DATA_BUF("\xee\xee", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xee\xee", 2)),
LFSR_ATTR(
LFSR_TAG_REG, 0,
LFSR_DATA_BUF("\xee\xee\xee\xee", 4)),
// propagate yellow
LFSR_ATTR(
LFSR_TAG_REG, 0,
LFSR_DATA_BUF("\xee\xee\xee\xee", 4)))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_ATTRS(
LFSR_ATTR(LFSR_TAG_RM, -1, LFSR_DATA_NULL()))) => 0;
assert(rbyd.weight == 2);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(2), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(3), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(4), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(5), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(6), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xee\xee\xee\xee", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(2), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(3), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(4), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(5), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(6), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(7), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(8), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(9), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_REG,
&data) => LFS_ERR_NOENT;
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(1),
&data) => LFS_ERR_NOENT;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
assert(rbyd.weight == 2);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(2), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(3), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(4), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(5), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(6), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xee\xee\xee\xee", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(2), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(3), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(4), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(5), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(6), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(7), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(8), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(9), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_REG,
&data) => LFS_ERR_NOENT;
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(1),
&data) => LFS_ERR_NOENT;
// try to recreate
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)))) => 0;
assert(rbyd.weight == 3);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(2), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(3), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(4), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(5), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(6), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xee\xee\xee\xee", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(2), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(3), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(4), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(5), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(6), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(7), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(8), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(9), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 3, LFSR_TAG_REG,
&data) => LFS_ERR_NOENT;
lfsr_rbyd_lookup(&lfs, &rbyd, 3, LFSR_TAG_UATTR(1),
&data) => LFS_ERR_NOENT;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
assert(rbyd.weight == 3);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(2), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(3), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(4), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(5), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(6), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xee\xee\xee\xee", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(2), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(3), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(4), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(5), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(6), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(7), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(8), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(9), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 3, LFSR_TAG_REG,
&data) => LFS_ERR_NOENT;
lfsr_rbyd_lookup(&lfs, &rbyd, 3, LFSR_TAG_UATTR(1),
&data) => LFS_ERR_NOENT;
'''
[cases.test_rbyd_delete_range_rydy_backwards]
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_data_t data;
uint8_t buffer[4];
// delete inner branches
//
// .-------------r-------------.
// .-o-. .---+---y----. .-o-.
// .o. .o. .o. .o. .o. .-y-+-. .o. .o.
// a a a a a a a a a a c e e e e e e e
// '+'
// remove
//
// this is a specific nasty case where tail-recursion can be
// violated if you preserve coloring during range removes
//
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xaa\xaa", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(2), 0,
LFSR_DATA_BUF("\xaa\xaa", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(3), 0,
LFSR_DATA_BUF("\xaa\xaa", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(4), 0,
LFSR_DATA_BUF("\xaa\xaa", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(9), 0,
LFSR_DATA_BUF("\xaa\xaa", 2)),
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(2), +1,
LFSR_DATA_BUF("\xee\xee", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(3), 0,
LFSR_DATA_BUF("\xee\xee", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(4), 0,
LFSR_DATA_BUF("\xee\xee", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(5), 0,
LFSR_DATA_BUF("\xee\xee", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(6), 0,
LFSR_DATA_BUF("\xee\xee", 2)),
// propagate yellow to the root
LFSR_ATTR(
LFSR_TAG_UATTR(6), 0,
LFSR_DATA_BUF("\xee\xee", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(6), 0,
LFSR_DATA_BUF("\xee\xee", 2)))) => 0;
// this gets a bit messy as we try to make the rbyd take the right shape
lfsr_rbyd_commit(&lfs, &rbyd, 2, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xee\xee", 2)),
LFSR_ATTR(
LFSR_TAG_REG, 0,
LFSR_DATA_BUF("\xee\xee\xee\xee", 4)))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(5), 0,
LFSR_DATA_BUF("\xaa\xaa", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(6), 0,
LFSR_DATA_BUF("\xaa\xaa", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(7), 0,
LFSR_DATA_BUF("\xaa\xaa", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(8), 0,
LFSR_DATA_BUF("\xaa\xaa", 2)),
// propagate yellow
LFSR_ATTR(
LFSR_TAG_UATTR(8), 0,
LFSR_DATA_BUF("\xaa\xaa", 2)))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_ATTRS(
LFSR_ATTR(LFSR_TAG_RM, -1, LFSR_DATA_NULL()))) => 0;
assert(rbyd.weight == 2);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(2), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(3), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(4), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(5), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(6), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(7), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(8), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(9), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xee\xee\xee\xee", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(2), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(3), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(4), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(5), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(6), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_REG,
&data) => LFS_ERR_NOENT;
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(1),
&data) => LFS_ERR_NOENT;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
assert(rbyd.weight == 2);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(2), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(3), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(4), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(5), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(6), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(7), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(8), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(9), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xee\xee\xee\xee", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(2), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(3), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(4), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(5), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(6), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_REG,
&data) => LFS_ERR_NOENT;
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(1),
&data) => LFS_ERR_NOENT;
// try to recreate
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)))) => 0;
assert(rbyd.weight == 3);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(2), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(3), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(4), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(5), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(6), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(7), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(8), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(9), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xee\xee\xee\xee", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(2), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(3), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(4), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(5), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(6), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 3, LFSR_TAG_REG,
&data) => LFS_ERR_NOENT;
lfsr_rbyd_lookup(&lfs, &rbyd, 3, LFSR_TAG_UATTR(1),
&data) => LFS_ERR_NOENT;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
assert(rbyd.weight == 3);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(2), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(3), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(4), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(5), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(6), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(7), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(8), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(9), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xee\xee\xee\xee", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(2), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(3), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(4), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(5), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(6), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 3, LFSR_TAG_REG,
&data) => LFS_ERR_NOENT;
lfsr_rbyd_lookup(&lfs, &rbyd, 3, LFSR_TAG_UATTR(1),
&data) => LFS_ERR_NOENT;
'''
[cases.test_rbyd_delete_range_rydye]
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_data_t data;
uint8_t buffer[4];
// delete inner branches
//
// .-------------r-------------.
// .-o-. .----y---+---. .-o-.
// .o. .o. .-+-y-. .o. .o. .o. .o. .o.
// a a a a a a a c c c e e e e e e e e
// '--+--'
// remove
//
// this is a specific nasty case where tail-recursion can be
// violated if you preserve coloring during range removes
//
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xaa\xaa", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(2), 0,
LFSR_DATA_BUF("\xaa\xaa", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(3), 0,
LFSR_DATA_BUF("\xaa\xaa", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(4), 0,
LFSR_DATA_BUF("\xaa\xaa", 2)),
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(2), +1,
LFSR_DATA_BUF("\xee\xee", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(3), 0,
LFSR_DATA_BUF("\xee\xee", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(4), 0,
LFSR_DATA_BUF("\xee\xee", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(5), 0,
LFSR_DATA_BUF("\xee\xee", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(6), 0,
LFSR_DATA_BUF("\xee\xee", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(7), 0,
LFSR_DATA_BUF("\xee\xee", 2)),
// propagate yellow to the root
LFSR_ATTR(
LFSR_TAG_UATTR(7), 0,
LFSR_DATA_BUF("\xee\xee", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(7), 0,
LFSR_DATA_BUF("\xee\xee", 2)))) => 0;
// this gets a bit messy as we try to make the rbyd take the right shape
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(5), 0,
LFSR_DATA_BUF("\xaa\xaa", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(6), 0,
LFSR_DATA_BUF("\xaa\xaa", 2)))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 2, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xee\xee", 2)),
LFSR_ATTR(
LFSR_TAG_REG, 0,
LFSR_DATA_BUF("\xee\xee\xee\xee", 4)))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(2), 0,
LFSR_DATA_BUF("\xcc\xcc", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xcc\xcc", 2)),
// propagate yellow
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xcc\xcc", 2)))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_ATTRS(
LFSR_ATTR(LFSR_TAG_RM, -1, LFSR_DATA_NULL()))) => 0;
assert(rbyd.weight == 2);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(2), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(3), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(4), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(5), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(6), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xee\xee\xee\xee", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(2), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(3), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(4), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(5), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(6), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(7), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_REG,
&data) => LFS_ERR_NOENT;
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(1),
&data) => LFS_ERR_NOENT;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
assert(rbyd.weight == 2);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(2), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(3), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(4), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(5), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(6), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xee\xee\xee\xee", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(2), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(3), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(4), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(5), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(6), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(7), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_REG,
&data) => LFS_ERR_NOENT;
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(1),
&data) => LFS_ERR_NOENT;
// try to recreate
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)))) => 0;
assert(rbyd.weight == 3);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(2), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(3), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(4), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(5), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(6), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xee\xee\xee\xee", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(2), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(3), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(4), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(5), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(6), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(7), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 3, LFSR_TAG_REG,
&data) => LFS_ERR_NOENT;
lfsr_rbyd_lookup(&lfs, &rbyd, 3, LFSR_TAG_UATTR(1),
&data) => LFS_ERR_NOENT;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
assert(rbyd.weight == 3);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(2), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(3), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(4), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(5), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(6), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xee\xee\xee\xee", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(2), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(3), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(4), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(5), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(6), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(7), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 3, LFSR_TAG_REG,
&data) => LFS_ERR_NOENT;
lfsr_rbyd_lookup(&lfs, &rbyd, 3, LFSR_TAG_UATTR(1),
&data) => LFS_ERR_NOENT;
'''
[cases.test_rbyd_delete_range_rydye_backwards]
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_data_t data;
uint8_t buffer[4];
// delete inner branches
//
// .-------------r-------------.
// .-o-. .---+---y----. .-o-.
// .o. .o. .o. .o. .o. .-y-+-. .o. .o.
// a a a a a a a a c c c e e e e e e e
// '--+--'
// remove
//
// this is a specific nasty case where tail-recursion can be
// violated if you preserve coloring during range removes
//
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xaa\xaa", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(2), 0,
LFSR_DATA_BUF("\xaa\xaa", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(3), 0,
LFSR_DATA_BUF("\xaa\xaa", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(4), 0,
LFSR_DATA_BUF("\xaa\xaa", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(1), +1,
LFSR_DATA_BUF("\xcc\xcc", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(2), 0,
LFSR_DATA_BUF("\xcc\xcc", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(2), +1,
LFSR_DATA_BUF("\xee\xee", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(3), 0,
LFSR_DATA_BUF("\xee\xee", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(4), 0,
LFSR_DATA_BUF("\xee\xee", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(5), 0,
LFSR_DATA_BUF("\xee\xee", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(6), 0,
LFSR_DATA_BUF("\xee\xee", 2)),
// propagate yellow to the root
LFSR_ATTR(
LFSR_TAG_UATTR(6), 0,
LFSR_DATA_BUF("\xee\xee", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(6), 0,
LFSR_DATA_BUF("\xee\xee", 2)))) => 0;
// this gets a bit messy as we try to make the rbyd take the right shape
lfsr_rbyd_commit(&lfs, &rbyd, 2, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xee\xee", 2)),
LFSR_ATTR(
LFSR_TAG_REG, 0,
LFSR_DATA_BUF("\xee\xee\xee\xee", 4)))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(5), 0,
LFSR_DATA_BUF("\xaa\xaa", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(6), 0,
LFSR_DATA_BUF("\xaa\xaa", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(7), 0,
LFSR_DATA_BUF("\xaa\xaa", 2)))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_REG, 0,
LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)),
// propagate yellow
LFSR_ATTR(
LFSR_TAG_REG, 0,
LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_ATTRS(
LFSR_ATTR(LFSR_TAG_RM, -1, LFSR_DATA_NULL()))) => 0;
assert(rbyd.weight == 2);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(2), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(3), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(4), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(5), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(6), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(7), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xee\xee\xee\xee", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(2), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(3), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(4), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(5), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(6), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_REG,
&data) => LFS_ERR_NOENT;
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(1),
&data) => LFS_ERR_NOENT;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
assert(rbyd.weight == 2);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(2), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(3), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(4), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(5), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(6), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(7), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xee\xee\xee\xee", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(2), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(3), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(4), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(5), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(6), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_REG,
&data) => LFS_ERR_NOENT;
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(1),
&data) => LFS_ERR_NOENT;
// try to recreate
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)))) => 0;
assert(rbyd.weight == 3);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(2), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(3), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(4), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(5), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(6), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(7), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xee\xee\xee\xee", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(2), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(3), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(4), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(5), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(6), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 3, LFSR_TAG_REG,
&data) => LFS_ERR_NOENT;
lfsr_rbyd_lookup(&lfs, &rbyd, 3, LFSR_TAG_UATTR(1),
&data) => LFS_ERR_NOENT;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
assert(rbyd.weight == 3);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(2), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(3), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(4), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(5), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(6), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(7), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xee\xee\xee\xee", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(2), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(3), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(4), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(5), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(6), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 3, LFSR_TAG_REG,
&data) => LFS_ERR_NOENT;
lfsr_rbyd_lookup(&lfs, &rbyd, 3, LFSR_TAG_UATTR(1),
&data) => LFS_ERR_NOENT;
'''
[cases.test_rbyd_delete_range_dryy]
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_data_t data;
uint8_t buffer[4];
// delete inner branches
//
// o---------------------.
// .-------+---------r .---o---.
// .-o-. .-o-. .---y------+----. .-o-. .-o-.
// .o. .o. .o. .o. .o. .o. .-+-y-. .o. .o. .o. .o. .o.
// a a a a a a a a a a a a a a a c c c c e e e e e e e
// '---+---'
// remove
//
// this is an attempt at colliding two splits by pruning after
// diverging, in theory this can lead to tail-recursion violations,
// but no violations have been found to be possible yet
//
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xaa\xaa", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(2), 0,
LFSR_DATA_BUF("\xaa\xaa", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(3), 0,
LFSR_DATA_BUF("\xaa\xaa", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(4), 0,
LFSR_DATA_BUF("\xaa\xaa", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(5), 0,
LFSR_DATA_BUF("\xaa\xaa", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(6), 0,
LFSR_DATA_BUF("\xaa\xaa", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(2), +1,
LFSR_DATA_BUF("\xcc\xcc", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(3), 0,
LFSR_DATA_BUF("\xcc\xcc", 2)),
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xee\xee\xee\xee", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xee\xee", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(2), 0,
LFSR_DATA_BUF("\xee\xee", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(3), 0,
LFSR_DATA_BUF("\xee\xee", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(4), 0,
LFSR_DATA_BUF("\xee\xee", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(5), 0,
LFSR_DATA_BUF("\xee\xee", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(6), 0,
LFSR_DATA_BUF("\xee\xee", 2)),
// propagate yellow to the root
LFSR_ATTR(
LFSR_TAG_UATTR(6), 0,
LFSR_DATA_BUF("\xee\xee", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(6), 0,
LFSR_DATA_BUF("\xee\xee", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(6), 0,
LFSR_DATA_BUF("\xee\xee", 2)))) => 0;
// this gets a bit messy as we try to make the rbyd take the right shape
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(7), 0,
LFSR_DATA_BUF("\xaa\xaa", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(8), 0,
LFSR_DATA_BUF("\xaa\xaa", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(11), 0,
LFSR_DATA_BUF("\xaa\xaa", 2)))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xcc\xcc", 2)),
// propagate yellow
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xcc\xcc", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xcc\xcc", 2)))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(12), 0,
LFSR_DATA_BUF("\xaa\xaa", 2)))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_REG, 0,
LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)),
// propagate yellow
LFSR_ATTR(
LFSR_TAG_REG, 0,
LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(13), 0,
LFSR_DATA_BUF("\xaa\xaa", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(14), 0,
LFSR_DATA_BUF("\xaa\xaa", 2)))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(9), 0,
LFSR_DATA_BUF("\xaa\xaa", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(10), 0,
LFSR_DATA_BUF("\xaa\xaa", 2)),
// propagate yellow
LFSR_ATTR(
LFSR_TAG_UATTR(10), 0,
LFSR_DATA_BUF("\xaa\xaa", 2)))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_ATTRS(
LFSR_ATTR(LFSR_TAG_RM, -1, LFSR_DATA_NULL()))) => 0;
assert(rbyd.weight == 2);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(2), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(3), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(4), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(5), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(6), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(7), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(8), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(9), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(10), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(11), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(12), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(13), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(14), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xee\xee\xee\xee", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(2), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(3), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(4), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(5), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(6), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_REG,
&data) => LFS_ERR_NOENT;
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(1),
&data) => LFS_ERR_NOENT;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
assert(rbyd.weight == 2);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(2), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(3), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(4), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(5), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(6), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(7), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(8), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(9), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(10), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(11), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(12), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(13), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(14), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xee\xee\xee\xee", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(2), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(3), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(4), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(5), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(6), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_REG,
&data) => LFS_ERR_NOENT;
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(1),
&data) => LFS_ERR_NOENT;
// try to recreate
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)))) => 0;
assert(rbyd.weight == 3);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(2), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(3), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(4), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(5), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(6), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(7), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(8), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(9), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(10), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(11), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(12), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(13), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(14), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xee\xee\xee\xee", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(2), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(3), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(4), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(5), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(6), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 3, LFSR_TAG_REG,
&data) => LFS_ERR_NOENT;
lfsr_rbyd_lookup(&lfs, &rbyd, 3, LFSR_TAG_UATTR(1),
&data) => LFS_ERR_NOENT;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
assert(rbyd.weight == 3);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(2), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(3), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(4), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(5), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(6), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(7), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(8), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(9), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(10), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(11), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(12), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(13), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(14), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xee\xee\xee\xee", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(2), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(3), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(4), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(5), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(6), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 3, LFSR_TAG_REG,
&data) => LFS_ERR_NOENT;
lfsr_rbyd_lookup(&lfs, &rbyd, 3, LFSR_TAG_UATTR(1),
&data) => LFS_ERR_NOENT;
'''
[cases.test_rbyd_delete_range_dryy_backwards]
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_data_t data;
uint8_t buffer[4];
// delete inner branches
//
// .---------------------o
// .---o---. r---------+-------.
// .-o-. .-o-. .----+------y---. .-o-. .-o-.
// .o. .o. .o. .o. .o. .-y-+-. .o. .o. .o. .o. .o. .o.
// a a a a a a a c c c c e e e e e e e e e e e e e e e
// '---+---'
// remove
//
// this is an attempt at colliding two splits by pruning after
// diverging, in theory this can lead to tail-recursion violations,
// but no violations have been found to be possible yet
//
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xaa\xaa", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(2), 0,
LFSR_DATA_BUF("\xaa\xaa", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(3), 0,
LFSR_DATA_BUF("\xaa\xaa", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(4), 0,
LFSR_DATA_BUF("\xaa\xaa", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(5), 0,
LFSR_DATA_BUF("\xaa\xaa", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(6), 0,
LFSR_DATA_BUF("\xaa\xaa", 2)),
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xcc\xcc", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(2), 0,
LFSR_DATA_BUF("\xcc\xcc", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(3), 0,
LFSR_DATA_BUF("\xcc\xcc", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(6), +1,
LFSR_DATA_BUF("\xee\xee", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(7), 0,
LFSR_DATA_BUF("\xee\xee", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(8), 0,
LFSR_DATA_BUF("\xee\xee", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(9), 0,
LFSR_DATA_BUF("\xee\xee", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(10), 0,
LFSR_DATA_BUF("\xee\xee", 2)),
// propagate yellow to the root
LFSR_ATTR(
LFSR_TAG_UATTR(10), 0,
LFSR_DATA_BUF("\xee\xee", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(10), 0,
LFSR_DATA_BUF("\xee\xee", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(10), 0,
LFSR_DATA_BUF("\xee\xee", 2)))) => 0;
// this gets a bit messy as we try to make the rbyd take the right shape
lfsr_rbyd_commit(&lfs, &rbyd, 2, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(11), 0,
LFSR_DATA_BUF("\xee\xee", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(12), 0,
LFSR_DATA_BUF("\xee\xee", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(13), 0,
LFSR_DATA_BUF("\xee\xee", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(14), 0,
LFSR_DATA_BUF("\xee\xee", 2)),
// propagate yellow
LFSR_ATTR(
LFSR_TAG_UATTR(14), 0,
LFSR_DATA_BUF("\xee\xee", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(14), 0,
LFSR_DATA_BUF("\xee\xee", 2)))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 2, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(2), 0,
LFSR_DATA_BUF("\xee\xee", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(3), 0,
LFSR_DATA_BUF("\xee\xee", 2)),
// propagate yellow
LFSR_ATTR(
LFSR_TAG_UATTR(3), 0,
LFSR_DATA_BUF("\xee\xee", 2)))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 2, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xee\xee", 2)),
LFSR_ATTR(
LFSR_TAG_REG, 0,
LFSR_DATA_BUF("\xee\xee\xee\xee", 4)))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 2, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(5), 0,
LFSR_DATA_BUF("\xee\xee", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(4), 0,
LFSR_DATA_BUF("\xee\xee", 2)),
// propagate yellow
LFSR_ATTR(
LFSR_TAG_UATTR(4), 0,
LFSR_DATA_BUF("\xee\xee", 2)))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_ATTRS(
LFSR_ATTR(LFSR_TAG_RM, -1, LFSR_DATA_NULL()))) => 0;
assert(rbyd.weight == 2);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(2), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(3), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(4), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(5), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(6), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xee\xee\xee\xee", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(2), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(3), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(4), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(5), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(6), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(7), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(8), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(9), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(10), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(11), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(12), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(13), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(14), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_REG,
&data) => LFS_ERR_NOENT;
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(1),
&data) => LFS_ERR_NOENT;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
assert(rbyd.weight == 2);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(2), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(3), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(4), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(5), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(6), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xee\xee\xee\xee", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(2), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(3), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(4), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(5), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(6), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(7), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(8), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(9), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(10), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(11), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(12), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(13), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(14), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_REG,
&data) => LFS_ERR_NOENT;
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(1),
&data) => LFS_ERR_NOENT;
// try to recreate
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)))) => 0;
assert(rbyd.weight == 3);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(2), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(3), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(4), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(5), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(6), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xee\xee\xee\xee", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(2), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(3), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(4), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(5), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(6), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(7), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(8), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(9), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(10), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(11), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(12), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(13), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(14), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 3, LFSR_TAG_REG,
&data) => LFS_ERR_NOENT;
lfsr_rbyd_lookup(&lfs, &rbyd, 3, LFSR_TAG_UATTR(1),
&data) => LFS_ERR_NOENT;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
assert(rbyd.weight == 3);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(2), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(3), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(4), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(5), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(6), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xee\xee\xee\xee", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(2), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(3), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(4), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(5), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(6), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(7), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(8), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(9), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(10), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(11), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(12), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(13), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(14), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xee\xee", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 3, LFSR_TAG_REG,
&data) => LFS_ERR_NOENT;
lfsr_rbyd_lookup(&lfs, &rbyd, 3, LFSR_TAG_UATTR(1),
&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_delete_permutations]
defines.N = 'range(1, 7)'
# PERMUTATION=-1 => exhaust all permutations
# PERMUTATION=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_data_t data;
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;
lfsr_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(
LFSR_TAG_REG, +1,
LFSR_DATA_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);
lfsr_bd_read(&lfs, rbyd.blocks[0], 0, rbyd.eoff,
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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_bd_prog(&lfs, rbyd.blocks[0], 0, backup_block, rbyd.eoff,
NULL) => 0;
lfsr_bd_flush(&lfs,
NULL) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, j, LFSR_ATTRS(
LFSR_ATTR(LFSR_TAG_RM, -1, LFSR_DATA_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_lookup(&lfs, &rbyd, k, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
if (k >= j) {
assert(memcmp(buffer, names[(k+1) % 6], 4) == 0);
} else {
assert(memcmp(buffer, names[k % 6], 4) == 0);
}
}
lfsr_rbyd_lookup(&lfs, &rbyd, N-1, LFSR_TAG_REG,
&data) => 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(
LFSR_TAG_REG, +1,
LFSR_DATA_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_lookup(&lfs, &rbyd, k, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 6) => 6;
assert(memcmp(buffer, names[k % 6], 6) == 0);
} else {
lfsr_rbyd_lookup(&lfs, &rbyd, k, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, 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)'
# PERMUTATION=-1 => exhaust all permutations
# PERMUTATION=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_data_t data;
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;
lfsr_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(
LFSR_TAG_REG, +1,
LFSR_DATA_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(
LFSR_TAG_UATTR(u+1), 0,
LFSR_DATA_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);
lfsr_bd_read(&lfs, rbyd.blocks[0], 0, rbyd.eoff,
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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_bd_prog(&lfs, rbyd.blocks[0], 0, backup_block, rbyd.eoff,
NULL) => 0;
lfsr_bd_flush(&lfs,
NULL) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, j, LFSR_ATTRS(
LFSR_ATTR(LFSR_TAG_RM, -1, LFSR_DATA_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_lookup(&lfs, &rbyd, k, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
if (k >= j) {
assert(memcmp(buffer, names[(k+1) % 6], 4) == 0);
} else {
assert(memcmp(buffer, names[k % 6], 4) == 0);
}
for (unsigned u = 0; u < M; u++) {
lfsr_rbyd_lookup(&lfs, &rbyd,
k, LFSR_TAG_UATTR(u+1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
if (k >= j) {
assert(memcmp(buffer, names[(k+1) % 6], 2) == 0);
} else {
assert(memcmp(buffer, names[k % 6], 2) == 0);
}
}
}
lfsr_rbyd_lookup(&lfs, &rbyd, N-1, LFSR_TAG_REG,
&data) => LFS_ERR_NOENT;
lfsr_rbyd_lookup(&lfs, &rbyd, N-1, LFSR_TAG_UATTR(1),
&data) => 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(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF(names[j % 6], 6)))) => 0;
for (unsigned u = 0; u < M; u++) {
lfsr_rbyd_commit(&lfs, &rbyd, j, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(u+1), 0,
LFSR_DATA_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_lookup(&lfs, &rbyd, k, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 6) => 6;
assert(memcmp(buffer, names[k % 6], 6) == 0);
for (unsigned u = 0; u < M; u++) {
lfsr_rbyd_lookup(&lfs, &rbyd,
k, LFSR_TAG_UATTR(u+1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 6) => 3;
assert(memcmp(buffer, names[k % 6], 3) == 0);
}
} else {
lfsr_rbyd_lookup(&lfs, &rbyd, k, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 6) => 4;
assert(memcmp(buffer, names[k % 6], 4) == 0);
for (unsigned u = 0; u < M; u++) {
lfsr_rbyd_lookup(&lfs, &rbyd,
k, LFSR_TAG_UATTR(u+1), &data) => 0;
lfsr_data_read(&lfs, &data, 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)'
# PERMUTATION=-1 => exhaust all permutations
# PERMUTATION=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_;
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;
lfsr_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(
LFSR_TAG_REG, +1,
LFSR_DATA_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);
lfsr_bd_read(&lfs, rbyd.blocks[0], 0, rbyd.eoff,
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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_bd_prog(&lfs, rbyd.blocks[0], 0, backup_block, rbyd.eoff,
NULL) => 0;
lfsr_bd_flush(&lfs,
NULL) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, j, LFSR_ATTRS(
LFSR_ATTR(LFSR_TAG_RM, -1, LFSR_DATA_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_lookup(&lfs, &rbyd, rid_, tag_, &data) => 0;
lfsr_data_read(&lfs, &data, 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)'
# PERMUTATION=-1 => exhaust all permutations
# PERMUTATION=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_;
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;
lfsr_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(
LFSR_TAG_REG, +1,
LFSR_DATA_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(
LFSR_TAG_UATTR(u+1), 0,
LFSR_DATA_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);
lfsr_bd_read(&lfs, rbyd.blocks[0], 0, rbyd.eoff,
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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_bd_prog(&lfs, rbyd.blocks[0], 0, backup_block, rbyd.eoff,
NULL) => 0;
lfsr_bd_flush(&lfs,
NULL) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, j, LFSR_ATTRS(
LFSR_ATTR(LFSR_TAG_RM, -1, LFSR_DATA_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_lookup(&lfs, &rbyd, rid_, tag_, &data) => 0;
lfsr_data_read(&lfs, &data, 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_lookup(&lfs, &rbyd, rid_, tag_, &data) => 0;
lfsr_data_read(&lfs, &data, 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;
lfsr_data_t data;
// create and delete one rid
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
LFSR_ATTR(LFSR_TAG_RM, -1, LFSR_DATA_NULL()))) => 0;
assert(rbyd.weight == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG,
&data) => LFS_ERR_NOENT;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
assert(rbyd.weight == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG,
&data) => LFS_ERR_NOENT;
// create and delete two ids
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)),
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_ATTRS(
LFSR_ATTR(LFSR_TAG_RM, -1, LFSR_DATA_NULL()),
LFSR_ATTR(LFSR_TAG_RM, -1, LFSR_DATA_NULL()))) => 0;
assert(rbyd.weight == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG,
&data) => LFS_ERR_NOENT;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
assert(rbyd.weight == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG,
&data) => LFS_ERR_NOENT;
// create and delete two ids in the other order
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)),
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
LFSR_ATTR(LFSR_TAG_RM, -1, LFSR_DATA_NULL()))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
LFSR_ATTR(LFSR_TAG_RM, -1, LFSR_DATA_NULL()))) => 0;
assert(rbyd.weight == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG,
&data) => LFS_ERR_NOENT;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
assert(rbyd.weight == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG,
&data) => LFS_ERR_NOENT;
// create and delete three ids
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)),
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)),
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 2, LFSR_ATTRS(
LFSR_ATTR(LFSR_TAG_RM, -1, LFSR_DATA_NULL()),
LFSR_ATTR(LFSR_TAG_RM, -1, LFSR_DATA_NULL()),
LFSR_ATTR(LFSR_TAG_RM, -1, LFSR_DATA_NULL()))) => 0;
assert(rbyd.weight == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG,
&data) => LFS_ERR_NOENT;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
assert(rbyd.weight == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG,
&data) => LFS_ERR_NOENT;
// create and delete three ids in the other order
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)),
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)),
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
LFSR_ATTR(LFSR_TAG_RM, -1, LFSR_DATA_NULL()))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
LFSR_ATTR(LFSR_TAG_RM, -1, LFSR_DATA_NULL()))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
LFSR_ATTR(LFSR_TAG_RM, -1, LFSR_DATA_NULL()))) => 0;
assert(rbyd.weight == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG,
&data) => LFS_ERR_NOENT;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
assert(rbyd.weight == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG,
&data) => 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;
lfsr_data_t data;
// create and delete one rid
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xaa\xaa", 2)))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
LFSR_ATTR(LFSR_TAG_RM, -1, LFSR_DATA_NULL()))) => 0;
assert(rbyd.weight == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG,
&data) => LFS_ERR_NOENT;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
assert(rbyd.weight == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG,
&data) => LFS_ERR_NOENT;
// create and delete two ids
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xaa\xaa", 2)),
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xbb\xbb", 2)))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_ATTRS(
LFSR_ATTR(LFSR_TAG_RM, -1, LFSR_DATA_NULL()),
LFSR_ATTR(LFSR_TAG_RM, -1, LFSR_DATA_NULL()))) => 0;
assert(rbyd.weight == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG,
&data) => LFS_ERR_NOENT;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
assert(rbyd.weight == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG,
&data) => LFS_ERR_NOENT;
// create and delete two ids in the other order
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xaa\xaa", 2)),
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xbb\xbb", 2)))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
LFSR_ATTR(LFSR_TAG_RM, -1, LFSR_DATA_NULL()))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
LFSR_ATTR(LFSR_TAG_RM, -1, LFSR_DATA_NULL()))) => 0;
assert(rbyd.weight == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG,
&data) => LFS_ERR_NOENT;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
assert(rbyd.weight == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG,
&data) => LFS_ERR_NOENT;
// create and delete three ids
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xaa\xaa", 2)),
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xbb\xbb", 2)),
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xcc\xcc", 2)))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 2, LFSR_ATTRS(
LFSR_ATTR(LFSR_TAG_RM, -1, LFSR_DATA_NULL()),
LFSR_ATTR(LFSR_TAG_RM, -1, LFSR_DATA_NULL()),
LFSR_ATTR(LFSR_TAG_RM, -1, LFSR_DATA_NULL()))) => 0;
assert(rbyd.weight == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG,
&data) => LFS_ERR_NOENT;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
assert(rbyd.weight == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG,
&data) => LFS_ERR_NOENT;
// create and delete three ids in the other order
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xaa\xaa", 2)),
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xbb\xbb", 2)),
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xcc\xcc", 2)))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
LFSR_ATTR(LFSR_TAG_RM, -1, LFSR_DATA_NULL()))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
LFSR_ATTR(LFSR_TAG_RM, -1, LFSR_DATA_NULL()))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
LFSR_ATTR(LFSR_TAG_RM, -1, LFSR_DATA_NULL()))) => 0;
assert(rbyd.weight == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG,
&data) => LFS_ERR_NOENT;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
assert(rbyd.weight == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG,
&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_delete_all_permutations]
defines.N = 'range(1, 7)'
# PERMUTATION=-1 => exhaust all permutations
# PERMUTATION=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_data_t data;
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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
for (unsigned j = 0; j < N; j++) {
lfsr_rbyd_commit(&lfs, &rbyd, j, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_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);
lfsr_bd_read(&lfs, rbyd.blocks[0], 0, rbyd.eoff,
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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_bd_prog(&lfs, rbyd.blocks[0], 0, backup_block, rbyd.eoff,
NULL) => 0;
lfsr_bd_flush(&lfs,
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(LFSR_TAG_RM, -1, LFSR_DATA_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_lookup(&lfs, &rbyd,
LFSR_TAG_REG, 0,
&data) => LFS_ERR_NOENT;
// try resuming from all tags being removed
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_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_lookup(&lfs, &rbyd,
0, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 6) => 6;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa\xaa\xaa", 6) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd,
1, LFSR_TAG_REG,
&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 + 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)'
# PERMUTATION=-1 => exhaust all permutations
# PERMUTATION=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_data_t data;
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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
for (unsigned j = 0; j < N; j++) {
lfsr_rbyd_commit(&lfs, &rbyd, j, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_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(
LFSR_TAG_UATTR(u+1), 0,
LFSR_DATA_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);
lfsr_bd_read(&lfs, rbyd.blocks[0], 0, rbyd.eoff,
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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_bd_prog(&lfs, rbyd.blocks[0], 0, backup_block, rbyd.eoff,
NULL) => 0;
lfsr_bd_flush(&lfs,
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(LFSR_TAG_RM, -1, LFSR_DATA_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_lookup(&lfs, &rbyd,
0, LFSR_TAG_REG,
&data) => LFS_ERR_NOENT;
// try resuming from all tags being removed
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_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(
LFSR_TAG_UATTR(u+1), 0,
LFSR_DATA_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_lookup(&lfs, &rbyd,
0, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 6) => 6;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa\xaa\xaa", 6) == 0);
for (unsigned u = 0; u < M; u++) {
lfsr_rbyd_lookup(&lfs, &rbyd,
0, LFSR_TAG_UATTR(u+1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 6) => 3;
assert(memcmp(buffer, "\xaa\xaa\xaa", 3) == 0);
}
lfsr_rbyd_lookup(&lfs, &rbyd,
1, LFSR_TAG_REG,
&data) => LFS_ERR_NOENT;
lfsr_rbyd_lookup(&lfs, &rbyd,
1, LFSR_TAG_UATTR(1),
&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*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;
lfsr_data_t data;
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, 'a'+(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;
lfsr_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] = 'a'+(i % 26);
count += 1;
// update our rbyd
lfsr_rbyd_commit(&lfs, &rbyd, rid, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF(&(uint8_t){'a'+(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(LFSR_TAG_RM, -1, LFSR_DATA_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++) {
int err = lfsr_rbyd_lookup(&lfs, &rbyd, rid, LFSR_TAG_REG,
&data);
if (!err) {
lfs_ssize_t size = lfsr_data_read(&lfs, &data, buffer, 4);
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_lookup(&lfs, &rbyd, rid, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, 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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_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(
LFSR_TAG_REG, +2,
LFSR_DATA_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(
LFSR_TAG_REG, +3,
LFSR_DATA_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(
LFSR_TAG_REG, +4,
LFSR_DATA_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(
LFSR_TAG_REG, +5,
LFSR_DATA_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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
// make id0 with weight w1
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)),
// make id2 with weight w2
LFSR_ATTR(
LFSR_TAG_REG, +2,
LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)),
// make id5 with weight w3
LFSR_ATTR(
LFSR_TAG_REG, +3,
LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)),
// make id9 with weight w4
LFSR_ATTR(
LFSR_TAG_REG, +4,
LFSR_DATA_BUF("\xdd\xdd\xdd\xdd", 4)),
// make id14 with weight w5
LFSR_ATTR(
LFSR_TAG_REG, +5,
LFSR_DATA_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
# PERMUTATION=-1 => exhaust all permutations
# PERMUTATION=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_;
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;
lfsr_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(
LFSR_TAG_REG, +W,
LFSR_DATA_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_lookup(&lfs, &rbyd, j*W+W-1, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, 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
# PERMUTATION=-1 => exhaust all permutations
# PERMUTATION=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_;
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;
lfsr_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(
LFSR_TAG_REG, +W,
LFSR_DATA_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_lookup(&lfs, &rbyd, rid_, tag_, &data) => 0;
lfsr_data_read(&lfs, &data, 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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(3), 0,
LFSR_DATA_BUF("unrelated", 9)),
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xaa\xaa", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(2), 0,
LFSR_DATA_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(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xbb\xbb", 2)),
LFSR_ATTR(
LFSR_TAG_GROW, +1,
LFSR_DATA_NULL()),
LFSR_ATTR(
LFSR_TAG_UATTR(2), 0,
LFSR_DATA_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(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xcc\xcc", 2)),
LFSR_ATTR(
LFSR_TAG_GROW, +2,
LFSR_DATA_NULL()),
LFSR_ATTR(
LFSR_TAG_UATTR(2), 0,
LFSR_DATA_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(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xdd\xdd\xdd\xdd", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xdd\xdd", 2)),
LFSR_ATTR(
LFSR_TAG_GROW, +3,
LFSR_DATA_NULL()),
LFSR_ATTR(
LFSR_TAG_UATTR(2), 0,
LFSR_DATA_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(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xee\xee\xee\xee", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xee\xee", 2)),
LFSR_ATTR(
LFSR_TAG_GROW, +4,
LFSR_DATA_NULL()),
LFSR_ATTR(
LFSR_TAG_UATTR(2), 0,
LFSR_DATA_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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(3), 0,
LFSR_DATA_BUF("unrelated", 9)),
// make id0 with weight w1
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xaa\xaa", 2)),
LFSR_ATTR(
LFSR_TAG_UATTR(2), 0,
LFSR_DATA_BUF("\xaa\xaa", 2)),
// make id2 with weight w2
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xbb\xbb", 2)),
LFSR_ATTR(
LFSR_TAG_GROW, +1,
LFSR_DATA_NULL()),
LFSR_ATTR(
LFSR_TAG_UATTR(2), 0,
LFSR_DATA_BUF("\xbb\xbb", 2)),
// make id5 with weight w3
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xcc\xcc", 2)),
LFSR_ATTR(
LFSR_TAG_GROW, +2,
LFSR_DATA_NULL()),
LFSR_ATTR(
LFSR_TAG_UATTR(2), 0,
LFSR_DATA_BUF("\xcc\xcc", 2)),
// make id9 with weight w4
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xdd\xdd\xdd\xdd", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xdd\xdd", 2)),
LFSR_ATTR(
LFSR_TAG_GROW, +3,
LFSR_DATA_NULL()),
LFSR_ATTR(
LFSR_TAG_UATTR(2), 0,
LFSR_DATA_BUF("\xdd\xdd", 2)),
// make id14 with weight w5
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xee\xee\xee\xee", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xee\xee", 2)),
LFSR_ATTR(
LFSR_TAG_GROW, +4,
LFSR_DATA_NULL()),
LFSR_ATTR(
LFSR_TAG_UATTR(2), 0,
LFSR_DATA_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
# PERMUTATION=-1 => exhaust all permutations
# PERMUTATION=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_;
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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(3), 0,
LFSR_DATA_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(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF(names[perm[j] % 6], 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF(names[perm[j] % 6], 2)),
LFSR_ATTR(
LFSR_TAG_GROW, +W-1,
LFSR_DATA_NULL()),
LFSR_ATTR(
LFSR_TAG_UATTR(2), 0,
LFSR_DATA_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_lookup(&lfs, &rbyd, j*W+W-1, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, 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
# PERMUTATION=-1 => exhaust all permutations
# PERMUTATION=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_;
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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(3), 0,
LFSR_DATA_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(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF(names[perm[j] % 6], 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF(names[perm[j] % 6], 2)),
LFSR_ATTR(
LFSR_TAG_GROW, +W-1,
LFSR_DATA_NULL()),
LFSR_ATTR(
LFSR_TAG_UATTR(2), 0,
LFSR_DATA_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_lookup(&lfs, &rbyd, rid_, tag_, &data) => 0;
lfsr_data_read(&lfs, &data, 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]
# PERMUTATION=-1 => exhaust all permutations
# PERMUTATION=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_;
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;
lfsr_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(
LFSR_TAG_REG, +W,
LFSR_DATA_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);
lfsr_bd_read(&lfs, rbyd.blocks[0], 0, rbyd.eoff,
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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_bd_prog(&lfs, rbyd.blocks[0], 0, backup_block, rbyd.eoff,
NULL) => 0;
lfsr_bd_flush(&lfs,
NULL) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, j*W+W-1, LFSR_ATTRS(
LFSR_ATTR(LFSR_TAG_GROW, +D, LFSR_DATA_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_lookup(&lfs, &rbyd, rid_, tag_, &data) => 0;
lfsr_data_read(&lfs, &data, 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]
# PERMUTATION=-1 => exhaust all permutations
# PERMUTATION=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_;
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;
lfsr_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(
LFSR_TAG_REG, +W,
LFSR_DATA_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);
lfsr_bd_read(&lfs, rbyd.blocks[0], 0, rbyd.eoff,
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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_bd_prog(&lfs, rbyd.blocks[0], 0, backup_block, rbyd.eoff,
NULL) => 0;
lfsr_bd_flush(&lfs,
NULL) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, j*W+W-1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_GROW | LFSR_TAG_REG, +D,
LFSR_DATA_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_lookup(&lfs, &rbyd, rid_, tag_, &data) => 0;
lfsr_data_read(&lfs, &data, 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_lookup(&lfs, &rbyd, rid_, tag_, &data) => 0;
lfsr_data_read(&lfs, &data, 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_lookup(&lfs, &rbyd, rid_, tag_, &data) => 0;
lfsr_data_read(&lfs, &data, 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]
# PERMUTATION=-1 => exhaust all permutations
# PERMUTATION=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_;
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;
lfsr_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(
LFSR_TAG_UATTR(2), +W,
LFSR_DATA_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);
lfsr_bd_read(&lfs, rbyd.blocks[0], 0, rbyd.eoff,
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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_bd_prog(&lfs, rbyd.blocks[0], 0, backup_block, rbyd.eoff,
NULL) => 0;
lfsr_bd_flush(&lfs,
NULL) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, j*W+W-1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_GROW | LFSR_TAG_UATTR(1), +D,
LFSR_DATA_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_lookup(&lfs, &rbyd, rid_, tag_, &data) => 0;
lfsr_data_read(&lfs, &data, 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_lookup(&lfs, &rbyd, rid_, tag_, &data) => 0;
lfsr_data_read(&lfs, &data, 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_lookup(&lfs, &rbyd, rid_, tag_, &data) => 0;
lfsr_data_read(&lfs, &data, 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_lookup(&lfs, &rbyd, rid_, tag_, &data) => 0;
lfsr_data_read(&lfs, &data, 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]
# PERMUTATION=-1 => exhaust all permutations
# PERMUTATION=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_;
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;
lfsr_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(
LFSR_TAG_REG, +W,
LFSR_DATA_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);
lfsr_bd_read(&lfs, rbyd.blocks[0], 0, rbyd.eoff,
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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_bd_prog(&lfs, rbyd.blocks[0], 0, backup_block, rbyd.eoff,
NULL) => 0;
lfsr_bd_flush(&lfs,
NULL) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, j*W+W-1, LFSR_ATTRS(
LFSR_ATTR(LFSR_TAG_GROW, -D, LFSR_DATA_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_lookup(&lfs, &rbyd, rid_, tag_, &data) => 0;
lfsr_data_read(&lfs, &data, 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]
# PERMUTATION=-1 => exhaust all permutations
# PERMUTATION=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_;
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;
lfsr_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(
LFSR_TAG_REG, +W,
LFSR_DATA_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);
lfsr_bd_read(&lfs, rbyd.blocks[0], 0, rbyd.eoff,
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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_bd_prog(&lfs, rbyd.blocks[0], 0, backup_block, rbyd.eoff,
NULL) => 0;
lfsr_bd_flush(&lfs,
NULL) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, j*W+W-1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_GROW | LFSR_TAG_REG, -D,
LFSR_DATA_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_lookup(&lfs, &rbyd, rid_, tag_, &data) => 0;
lfsr_data_read(&lfs, &data, 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_lookup(&lfs, &rbyd, rid_, tag_, &data) => 0;
lfsr_data_read(&lfs, &data, 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_lookup(&lfs, &rbyd, rid_, tag_, &data) => 0;
lfsr_data_read(&lfs, &data, 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]
# PERMUTATION=-1 => exhaust all permutations
# PERMUTATION=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_;
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;
lfsr_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(
LFSR_TAG_UATTR(2), +W,
LFSR_DATA_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);
lfsr_bd_read(&lfs, rbyd.blocks[0], 0, rbyd.eoff,
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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_bd_prog(&lfs, rbyd.blocks[0], 0, backup_block, rbyd.eoff,
NULL) => 0;
lfsr_bd_flush(&lfs,
NULL) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, j*W+W-1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_GROW | LFSR_TAG_UATTR(1), -D,
LFSR_DATA_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_lookup(&lfs, &rbyd, rid_, tag_, &data) => 0;
lfsr_data_read(&lfs, &data, 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_lookup(&lfs, &rbyd, rid_, tag_, &data) => 0;
lfsr_data_read(&lfs, &data, 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_lookup(&lfs, &rbyd, rid_, tag_, &data) => 0;
lfsr_data_read(&lfs, &data, 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_lookup(&lfs, &rbyd, rid_, tag_, &data) => 0;
lfsr_data_read(&lfs, &data, 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
# PERMUTATION=-1 => exhaust all permutations
# PERMUTATION=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_;
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;
lfsr_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(
LFSR_TAG_REG, +W,
LFSR_DATA_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);
lfsr_bd_read(&lfs, rbyd.blocks[0], 0, rbyd.eoff,
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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_bd_prog(&lfs, rbyd.blocks[0], 0, backup_block, rbyd.eoff,
NULL) => 0;
lfsr_bd_flush(&lfs,
NULL) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, j*W+W-1, LFSR_ATTRS(
LFSR_ATTR(LFSR_TAG_RM, -W, LFSR_DATA_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_lookup(&lfs, &rbyd, rid_, tag_, &data) => 0;
lfsr_data_read(&lfs, &data, 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_lookup(&lfs, &rbyd, rid_, tag_, &data) => 0;
lfsr_data_read(&lfs, &data, 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(
LFSR_TAG_REG, +W,
LFSR_DATA_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_lookup(&lfs, &rbyd, rid_, tag_, &data) => 0;
lfsr_data_read(&lfs, &data, 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_lookup(&lfs, &rbyd, rid_, tag_, &data) => 0;
lfsr_data_read(&lfs, &data, 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
# PERMUTATION=-1 => exhaust all permutations
# PERMUTATION=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_;
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;
lfsr_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(
LFSR_TAG_REG, +W,
LFSR_DATA_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);
lfsr_bd_read(&lfs, rbyd.blocks[0], 0, rbyd.eoff,
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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_bd_prog(&lfs, rbyd.blocks[0], 0, backup_block, rbyd.eoff,
NULL) => 0;
lfsr_bd_flush(&lfs,
NULL) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, j*W+W-1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_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_lookup(&lfs, &rbyd, rid_, tag_, &data) => 0;
lfsr_data_read(&lfs, &data, 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(
LFSR_TAG_RM | LFSR_TAG_UATTR(1), 0,
LFSR_DATA_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_lookup(&lfs, &rbyd, rid_, tag_, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, names[k % 6], 4) == 0);
if (k == j) {
lfsr_rbyd_lookup(&lfs, &rbyd, k*W+W-1, LFSR_TAG_UATTR(1),
&data) => 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(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_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_lookup(&lfs, &rbyd, rid_, tag_, &data) => 0;
lfsr_data_read(&lfs, &data, 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;
lfsr_data_t data;
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, 'a'+(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, 'a'+(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;
lfsr_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)] = 'a'+(i % 26);
count += 1;
// update our rbyd
lfsr_rbyd_commit(&lfs, &rbyd, rid, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF(&(uint8_t){'a'+(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(LFSR_TAG_RM, -1, LFSR_DATA_NULL()))) => 0;
} else if (op == 2) {
// update our sim
sim[rid*(M+1) + u+1] = 'a'+(i % 26);
// update our rbyd
lfsr_rbyd_commit(&lfs, &rbyd, rid, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_UATTR(u), 0,
LFSR_DATA_BUF(&(uint8_t){'a'+(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(
LFSR_TAG_RM | LFSR_TAG_UATTR(u), 0,
LFSR_DATA_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++) {
int err = lfsr_rbyd_lookup(&lfs, &rbyd, rid, LFSR_TAG_REG,
&data);
if (!err) {
lfs_ssize_t size = lfsr_data_read(&lfs, &data, buffer, 4);
printf("%.*s", size, buffer);
} else {
printf("?");
}
for (uint8_t u = 0; u < M; u++) {
err = lfsr_rbyd_lookup(&lfs, &rbyd, rid, LFSR_TAG_UATTR(u),
&data);
if (!err) {
lfs_ssize_t size = lfsr_data_read(&lfs, &data, buffer, 4);
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_lookup(&lfs, &rbyd, rid, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, 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_;
lfsr_data_t data;
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, 'a'+(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;
lfsr_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] = 'a'+(i % 26);
sim_weights[rid] = weight;
count += 1;
// update our rbyd
lfsr_rbyd_commit(&lfs, &rbyd, weighted_rid, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_REG, +weight,
LFSR_DATA_BUF(&(uint8_t){'a'+(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(LFSR_TAG_RM, -weight_, LFSR_DATA_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(LFSR_TAG_GROW, +weight, LFSR_DATA_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(LFSR_TAG_GROW, -weight, LFSR_DATA_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_data_read(&lfs, &data_, 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_lookup(&lfs, &rbyd, rid_, tag_, &data) => 0;
lfsr_data_read(&lfs, &data, 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]
# PERMUTATION=-1 => exhaust all permutations
# PERMUTATION=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;
lfsr_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(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF(names[perm[j] % 6], 4)),
LFSR_ATTR(
LFSR_TAG_UATTR((perm[j] + SHIFT) & 0x7f), 0,
LFSR_DATA_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]
# PERMUTATION=-1 => exhaust all permutations
# PERMUTATION=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;
lfsr_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(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF(names[perm[j] % 6], 4)),
LFSR_ATTR(
LFSR_TAG_UATTR((perm[j] + SHIFT) & 0x7f), 0,
LFSR_DATA_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);
lfsr_bd_read(&lfs, rbyd.blocks[0], 0, rbyd.eoff,
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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_bd_prog(&lfs, rbyd.blocks[0], 0, backup_block, rbyd.eoff,
NULL) => 0;
lfsr_bd_flush(&lfs,
NULL) => 0;
// remove with a wide tag
lfsr_rbyd_commit(&lfs, &rbyd, j, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_RM | LFSR_TAG_SUB | LFSR_TAG_UATTR, 0,
LFSR_DATA_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]
# PERMUTATION=-1 => exhaust all permutations
# PERMUTATION=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;
lfsr_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(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF(names[perm[j] % 6], 4)),
LFSR_ATTR(
LFSR_TAG_UATTR((perm[j] + SHIFT) & 0x7f), 0,
LFSR_DATA_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);
lfsr_bd_read(&lfs, rbyd.blocks[0], 0, rbyd.eoff,
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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_bd_prog(&lfs, rbyd.blocks[0], 0, backup_block, rbyd.eoff,
NULL) => 0;
lfsr_bd_flush(&lfs,
NULL) => 0;
// replace with bitwise inverse
lfsr_rbyd_commit(&lfs, &rbyd, j, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_SUB | LFSR_TAG_UATTR(~(j + SHIFT) & 0x7f),
0,
LFSR_DATA_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]
# PERMUTATION=-1 => exhaust all permutations
# PERMUTATION=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;
lfsr_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(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF(names[perm[j] % 6], 4)),
LFSR_ATTR(
LFSR_TAG_UATTR((perm[j] + SHIFT) & 0x7f), 0,
LFSR_DATA_BUF(names[perm[j] % 6], 2)),
LFSR_ATTR(
LFSR_TAG_SATTR(0), 0,
LFSR_DATA_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]
# PERMUTATION=-1 => exhaust all permutations
# PERMUTATION=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;
lfsr_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(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF(names[perm[j] % 6], 4)),
LFSR_ATTR(
LFSR_TAG_UATTR((perm[j] + SHIFT) & 0x7f), 0,
LFSR_DATA_BUF(names[perm[j] % 6], 2)),
LFSR_ATTR(
LFSR_TAG_SATTR(0), 0,
LFSR_DATA_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);
lfsr_bd_read(&lfs, rbyd.blocks[0], 0, rbyd.eoff,
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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_bd_prog(&lfs, rbyd.blocks[0], 0, backup_block, rbyd.eoff,
NULL) => 0;
lfsr_bd_flush(&lfs,
NULL) => 0;
// remove with a wide tag
lfsr_rbyd_commit(&lfs, &rbyd, j, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_RM | LFSR_TAG_SUB | LFSR_TAG_UATTR, 0,
LFSR_DATA_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]
# PERMUTATION=-1 => exhaust all permutations
# PERMUTATION=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;
lfsr_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(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF(names[perm[j] % 6], 4)),
LFSR_ATTR(
LFSR_TAG_UATTR((perm[j] + SHIFT) & 0x7f), 0,
LFSR_DATA_BUF(names[perm[j] % 6], 2)),
LFSR_ATTR(
LFSR_TAG_SATTR(0), 0,
LFSR_DATA_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);
lfsr_bd_read(&lfs, rbyd.blocks[0], 0, rbyd.eoff,
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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_bd_prog(&lfs, rbyd.blocks[0], 0, backup_block, rbyd.eoff,
NULL) => 0;
lfsr_bd_flush(&lfs,
NULL) => 0;
// replace with bitwise inverse
lfsr_rbyd_commit(&lfs, &rbyd, j, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_SUB | LFSR_TAG_UATTR(~(j + SHIFT) & 0x7f),
0,
LFSR_DATA_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]
# PERMUTATION=-1 => exhaust all permutations
# PERMUTATION=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;
lfsr_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(
LFSR_TAG_UATTR((perm[j] + SHIFT) & 0x7f), +1,
LFSR_DATA_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]
# PERMUTATION=-1 => exhaust all permutations
# PERMUTATION=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;
lfsr_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(
LFSR_TAG_UATTR((perm[j] + SHIFT) & 0x7f), +1,
LFSR_DATA_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);
lfsr_bd_read(&lfs, rbyd.blocks[0], 0, rbyd.eoff,
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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_bd_prog(&lfs, rbyd.blocks[0], 0, backup_block, rbyd.eoff,
NULL) => 0;
lfsr_bd_flush(&lfs,
NULL) => 0;
// remove with a wide tag
lfsr_rbyd_commit(&lfs, &rbyd, j, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_RM | LFSR_TAG_SUB | LFSR_TAG_UATTR, 0,
LFSR_DATA_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]
# PERMUTATION=-1 => exhaust all permutations
# PERMUTATION=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;
lfsr_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(
LFSR_TAG_UATTR((perm[j] + SHIFT) & 0x7f), +1,
LFSR_DATA_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);
lfsr_bd_read(&lfs, rbyd.blocks[0], 0, rbyd.eoff,
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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_bd_prog(&lfs, rbyd.blocks[0], 0, backup_block, rbyd.eoff,
NULL) => 0;
lfsr_bd_flush(&lfs,
NULL) => 0;
// replace with bitwise inverse
lfsr_rbyd_commit(&lfs, &rbyd, j, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_SUB | LFSR_TAG_UATTR(~(j + SHIFT) & 0x7f),
0,
LFSR_DATA_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]
# PERMUTATION=-1 => exhaust all permutations
# PERMUTATION=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;
lfsr_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(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF(names[perm[j] % 6], 4)),
LFSR_ATTR(
LFSR_TAG_UATTR((perm[j] + SHIFT) & 0x7f), 0,
LFSR_DATA_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]
# PERMUTATION=-1 => exhaust all permutations
# PERMUTATION=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;
lfsr_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(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF(names[perm[j] % 6], 4)),
LFSR_ATTR(
LFSR_TAG_UATTR((perm[j] + SHIFT) & 0x7f), 0,
LFSR_DATA_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);
lfsr_bd_read(&lfs, rbyd.blocks[0], 0, rbyd.eoff,
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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_bd_prog(&lfs, rbyd.blocks[0], 0, backup_block, rbyd.eoff,
NULL) => 0;
lfsr_bd_flush(&lfs,
NULL) => 0;
// remove with a wide tag
lfsr_rbyd_commit(&lfs, &rbyd, j, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_RM | LFSR_TAG_SUP | LFSR_TAG_UATTR, 0,
LFSR_DATA_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]
# PERMUTATION=-1 => exhaust all permutations
# PERMUTATION=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;
lfsr_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(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF(names[perm[j] % 6], 4)),
LFSR_ATTR(
LFSR_TAG_UATTR((perm[j] + SHIFT) & 0x7f), 0,
LFSR_DATA_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);
lfsr_bd_read(&lfs, rbyd.blocks[0], 0, rbyd.eoff,
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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_bd_prog(&lfs, rbyd.blocks[0], 0, backup_block, rbyd.eoff,
NULL) => 0;
lfsr_bd_flush(&lfs,
NULL) => 0;
// replace with bitwise inverse
lfsr_rbyd_commit(&lfs, &rbyd, j, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_SUP | LFSR_TAG_UATTR(~(j + SHIFT) & 0x7f),
0,
LFSR_DATA_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(
LFSR_TAG_UATTR(0), 0,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)),
LFSR_ATTR(
LFSR_TAG_RM | LFSR_TAG_UATTR(0), 0,
LFSR_DATA_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(
LFSR_TAG_UATTR(0), 0,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(2), 0,
LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)),
LFSR_ATTR(
LFSR_TAG_RM | LFSR_TAG_UATTR(0), 0,
LFSR_DATA_NULL()))) => 0;
assert(rbyd.weight == 0);
// remove a neighbor to the hole
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_RM | LFSR_TAG_UATTR(1), 0,
LFSR_DATA_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(
LFSR_TAG_UATTR(0), 0,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)),
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)),
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_RM | LFSR_TAG_UATTR(0), 0,
LFSR_DATA_NULL()))) => 0;
assert(rbyd.weight == 2);
// delete a neighbor to the hole
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS(
LFSR_ATTR(LFSR_TAG_RM, -1, LFSR_DATA_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(
LFSR_TAG_UATTR(0), 0,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)),
LFSR_ATTR(
LFSR_TAG_SATTR(0), 0,
LFSR_DATA_BUF("\xdd\xdd\xdd\xdd", 4)),
LFSR_ATTR(
LFSR_TAG_RM | LFSR_TAG_UATTR(0), 0,
LFSR_DATA_NULL()))) => 0;
assert(rbyd.weight == 0);
// subwide replace a neighbor to the hole
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_SUB | LFSR_TAG_UATTR(2), 0,
LFSR_DATA_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(
LFSR_TAG_UATTR(0), 0,
LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)),
LFSR_ATTR(
LFSR_TAG_UATTR(1), 0,
LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)),
LFSR_ATTR(
LFSR_TAG_REG, +1,
LFSR_DATA_BUF("\xdd\xdd\xdd\xdd", 4)))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_RM | LFSR_TAG_UATTR(0), 0,
LFSR_DATA_NULL()))) => 0;
assert(rbyd.weight == 1);
// supwide replace a neighbor to the hole
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS(
LFSR_ATTR(
LFSR_TAG_SUP | LFSR_TAG_UATTR(2), 0,
LFSR_DATA_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;
'''